diff -u --recursive --new-file v1.1.12/linux/MAGIC linux/MAGIC --- v1.1.12/linux/MAGIC Thu Jan 1 02:00:00 1970 +++ linux/MAGIC Mon May 23 07:55:16 1994 @@ -0,0 +1,42 @@ +This file is a registry of magic numbers which are in use. When you +add a magic number to a structure, you should also add it to this +file, since it is best if the magic numbers used by various structures +are unique. + +It is a *very* good idea to protect kernel data structures with magic +numbers. This allows you to check at run time whether (a) a structure +has been clobbered, or (b) you've passed the wrong structure to a +routine. This last is especially useful --- particlarly when you are +passing pointers to structures via a void * pointer. The tty code, +for example, does this frequently to pass driver-specific and line +discipline-specific structures back and forth. + +The way to use magic numbers is to declare then at the beginning of +the structure, like so: + +struct tty_ldisc { + int magic; + ... +}; + +Please follow this discpline when you are adding future enhancements +to the kernel! It has saved me countless hours of debugging, +especially in the screw cases where an array has been overrun and +structures following the array have been overwritten. Using this +discpline, these cases get detected quickly and safely. + + Theodore Ts'o + 31-Mar-94 + +Magic Name Number Structure File +=========================================================================== +FASYNC_MAGIC 0x4601 struct fasync_struct include/linux/fs.h +PTY_MAGIC 0x5001 struct pty_struct drivers/char/pty.c +PPP_MAGIC 0x5002 struct ppp_struct include/linux/ppp.h +TTY_MAGIC 0x5401 struct tty_struct include/linux/tty.h +TTY_DRIVER_MAGIC 0x5402 struct tty_driver include/linux/tty_driver.h +TTY_LDISC_MAGIC 0x5403 struct tty_ldisc include/linux/tty_ldisc.h +SERIAL_MAGIC 0x5301 struct async_struct include/linux/serial.h +SLIP_MAGIC 0x5302 struct slip drivers/net/slip.h + + diff -u --recursive --new-file v1.1.12/linux/Makefile linux/Makefile --- v1.1.12/linux/Makefile Mon May 23 12:14:21 1994 +++ linux/Makefile Mon May 23 08:41:12 1994 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 1 -SUBLEVEL = 12 +SUBLEVEL = 13 all: Version zImage diff -u --recursive --new-file v1.1.12/linux/config.in linux/config.in --- v1.1.12/linux/config.in Mon May 23 12:14:21 1994 +++ linux/config.in Mon May 23 11:43:20 1994 @@ -5,24 +5,24 @@ comment 'General setup' -bool 'Kernel math emulation' CONFIG_MATH_EMULATION y +bool 'Kernel math emulation' CONFIG_MATH_EMULATION n bool 'Normal harddisk support' CONFIG_BLK_DEV_HD y bool 'XT harddisk support' CONFIG_BLK_DEV_XD n -bool 'TCP/IP networking' CONFIG_INET y +bool 'Networking support' CONFIG_NET y bool 'Limit memory to low 16MB' CONFIG_MAX_16M n bool 'System V IPC' CONFIG_SYSVIPC y bool 'Use -m486 flag for 486-specific optimizations' CONFIG_M486 y -if [ "$CONFIG_INET" = "y" ]; then - +if [ "$CONFIG_NET" = "y" ]; then comment 'Networking options' +bool 'TCP/IP networking' CONFIG_INET y +if [ "$CONFIG_INET" "=" "y" ]; then comment '(it is safe to leave these untouched)' - -comment 'IP (required for now) y' -bool 'Reverse ARP' CONFIG_INET_RARP y +bool 'Reverse ARP' CONFIG_INET_RARP n bool 'Assume subnets are local' CONFIG_INET_SNARL y bool 'Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF n -#bool 'Novell IPX protocol' CONFIG_IPX n +fi +bool 'The IPX protocol' CONFIG_IPX y #bool 'Amateur Radio AX.25 Level 2' CONFIG_AX25 n fi @@ -62,10 +62,13 @@ bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST n fi + +if [ "$CONFIG_NET" = "y" ]; then + comment 'Network device support' -bool 'Network device support?' CONFIG_ETHERCARDS y -if [ "$CONFIG_ETHERCARDS" = "n" ]; then +bool 'Network device support?' CONFIG_NETDEVICES y +if [ "$CONFIG_NETDEVICES" = "n" ]; then comment 'Skipping ethercard configuration options...' @@ -76,15 +79,16 @@ # bool ' SLIP debugging on' SL_DUMP y fi #bool 'PPP (point-to-point) support' CONFIG_PPP n +bool 'Load balancing support (very experimental)' CONFIG_SLAVE_BALANCING n bool 'PLIP (parallel port) support' CONFIG_PLIP n bool 'NE2000/NE1000 support' CONFIG_NE2000 n -bool 'WD80*3 support' CONFIG_WD80x3 y +bool 'WD80*3 support' CONFIG_WD80x3 n bool 'SMC Ultra support' CONFIG_ULTRA n bool '3c501 support' CONFIG_EL1 n bool '3c503 support' CONFIG_EL2 n #bool '3c505 support' CONFIG_ELPLUS n #bool '3c507 support' CONFIG_EL16 n -bool '3c509/3c579 support' CONFIG_EL3 n +bool '3c509/3c579 support' CONFIG_EL3 y bool 'HP PCLAN support' CONFIG_HPLAN n bool 'AT1500 and NE2100 (LANCE and PCnet-ISA) support' CONFIG_LANCE n bool 'AT1700 support' CONFIG_AT1700 n @@ -98,6 +102,7 @@ bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n fi +fi comment 'CD-ROM drivers' @@ -113,7 +118,9 @@ bool 'xiafs filesystem support' CONFIG_XIA_FS n bool 'msdos fs support' CONFIG_MSDOS_FS y bool '/proc filesystem support' CONFIG_PROC_FS y +if [ "$CONFIG_INET" = "y" ]; then bool 'NFS filesystem support' CONFIG_NFS_FS y +fi bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n @@ -122,7 +129,7 @@ bool 'Parallel printer support' CONFIG_PRINTER n bool 'Logitech busmouse support' CONFIG_BUSMOUSE n -bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE y +bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE n if [ "$CONFIG_PSMOUSE" = "y" ]; then bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y fi diff -u --recursive --new-file v1.1.12/linux/drivers/FPU-emu/fpu_emu.h linux/drivers/FPU-emu/fpu_emu.h --- v1.1.12/linux/drivers/FPU-emu/fpu_emu.h Sat Mar 26 14:04:23 1994 +++ linux/drivers/FPU-emu/fpu_emu.h Mon May 23 10:04:05 1994 @@ -103,9 +103,9 @@ typedef struct fpu_reg FPU_REG; typedef struct { unsigned char address_size, operand_size, segment; } overrides; -/* This structure is 32 bits: */ +/* This structure is 48 bits: */ typedef struct { overrides override; - unsigned char vm86; } fpu_addr_modes; + unsigned char mode16, vm86, p286; } fpu_addr_modes; #define st(x) ( regs[((top+x) &7 )] ) diff -u --recursive --new-file v1.1.12/linux/drivers/FPU-emu/fpu_entry.c linux/drivers/FPU-emu/fpu_entry.c --- v1.1.12/linux/drivers/FPU-emu/fpu_entry.c Sat Mar 26 14:04:24 1994 +++ linux/drivers/FPU-emu/fpu_entry.c Mon May 23 10:04:05 1994 @@ -173,13 +173,20 @@ SETUP_DATA_AREA(arg); addr_modes.vm86 = (FPU_EFLAGS & 0x00020000) != 0; + addr_modes.p286 = (!addr_modes.vm86 + && current->ldt + && (current->ldt[FPU_CS >> 3].b & 0xf000) == 0xf000 + && (current->ldt[FPU_CS >> 3].b & (1 << 22)) == 0); + addr_modes.mode16 = addr_modes.vm86 | addr_modes.p286; if ( addr_modes.vm86 ) FPU_EIP += FPU_CS << 4; + else if ( addr_modes.p286 ) + FPU_EIP += LDT_BASE_ADDR(FPU_CS); FPU_ORIG_EIP = FPU_EIP; - if ( !addr_modes.vm86 ) + if ( !addr_modes.mode16 ) { /* user code space? */ if (FPU_CS == KERNEL_CS) @@ -283,6 +290,8 @@ if ( addr_modes.vm86 ) FPU_EIP -= FPU_CS << 4; + else if ( addr_modes.p286 ) + FPU_EIP -= LDT_BASE_ADDR(FPU_CS); RE_ENTRANT_CHECK_OFF; current->tss.trap_no = 16; @@ -552,6 +561,8 @@ if ( addr_modes.vm86 ) FPU_EIP -= FPU_CS << 4; + else if ( addr_modes.p286 ) + FPU_EIP -= LDT_BASE_ADDR(FPU_CS); RE_ENTRANT_CHECK_OFF; } diff -u --recursive --new-file v1.1.12/linux/drivers/FPU-emu/fpu_system.h linux/drivers/FPU-emu/fpu_system.h --- v1.1.12/linux/drivers/FPU-emu/fpu_system.h Wed Feb 16 13:07:56 1994 +++ linux/drivers/FPU-emu/fpu_system.h Mon May 23 10:04:05 1994 @@ -30,6 +30,10 @@ #define FPU_EIP (FPU_info->___eip) #define FPU_ORIG_EIP (FPU_info->___orig_eip) +#define LDT_BASE_ADDR(s) ((current->ldt[(s) >> 3].b & 0xff000000) \ + | ((current->ldt[(s) >> 3].b & 0xff) << 16) \ + | (current->ldt[(s) >> 3].a >> 16)) + #define FPU_lookahead (I387.soft.lookahead) #define FPU_entry_eip (I387.soft.entry_eip) diff -u --recursive --new-file v1.1.12/linux/drivers/FPU-emu/get_address.c linux/drivers/FPU-emu/get_address.c --- v1.1.12/linux/drivers/FPU-emu/get_address.c Sat Mar 26 14:04:24 1994 +++ linux/drivers/FPU-emu/get_address.c Mon May 23 10:04:05 1994 @@ -52,7 +52,20 @@ #define VM86_REG_(x) (*(unsigned short *) \ (reg_offset_vm86[((unsigned)x)]+(char *) FPU_info)) +static int reg_offset_p286[] = { + offsetof(struct info,___cs), + offsetof(struct info,___ds), + offsetof(struct info,___es), + offsetof(struct info,___fs), + offsetof(struct info,___gs), + offsetof(struct info,___ss), + offsetof(struct info,___ds) + }; +#define P286_REG_(x) (*(unsigned short *) \ + (reg_offset_p286[((unsigned)x)]+(char *) FPU_info)) + + /* Decode the SIB byte. This function assumes mod != 0 */ static void *sib(int mod, unsigned long *fpu_eip) { @@ -108,9 +121,10 @@ } -static unsigned long vm86_segment(unsigned char segment) +static unsigned long mode16_segment(fpu_addr_modes addr_modes) { - segment--; + int segment = addr_modes.override.segment - 1; + #ifdef PARANOID if ( segment > PREFIX_SS_ ) { @@ -118,7 +132,11 @@ math_abort(FPU_info,SIGSEGV); } #endif PARANOID - return (unsigned long)VM86_REG_(segment) << 4; + if ( addr_modes.vm86 ) + return (unsigned long)VM86_REG_(segment) << 4; + else if ( addr_modes.p286 ) + return (unsigned long)LDT_BASE_ADDR(P286_REG_(segment)); + return 0; } @@ -152,7 +170,7 @@ #endif PECULIAR_486 /* Memory accessed via the cs selector is write protected - in 32 bit protected mode. */ + in protected mode. */ #define FPU_WRITE_BIT 0x10 if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT) && (addr_modes.override.segment == PREFIX_CS_) ) @@ -210,9 +228,9 @@ EXCEPTION(EX_Invalid); } - if ( addr_modes.vm86 ) + if ( addr_modes.mode16 ) { - offset += vm86_segment(addr_modes.override.segment); + offset += mode16_segment(addr_modes); } FPU_data_address = offset + (char *)*cpu_reg_ptr; @@ -231,7 +249,7 @@ #endif PECULIAR_486 /* Memory accessed via the cs selector is write protected - in 32 bit protected mode. */ + in protected mode. */ #define FPU_WRITE_BIT 0x10 if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT) && (addr_modes.override.segment == PREFIX_CS_) ) @@ -313,9 +331,9 @@ add_segment: offset &= 0xffff; - if ( addr_modes.vm86 ) + if ( addr_modes.mode16 ) { - offset += vm86_segment(addr_modes.override.segment); + offset += mode16_segment(addr_modes); } FPU_data_address = (void *)offset ; diff -u --recursive --new-file v1.1.12/linux/drivers/FPU-emu/reg_ld_str.c linux/drivers/FPU-emu/reg_ld_str.c --- v1.1.12/linux/drivers/FPU-emu/reg_ld_str.c Wed Feb 16 13:07:56 1994 +++ linux/drivers/FPU-emu/reg_ld_str.c Mon May 23 10:04:05 1994 @@ -1170,7 +1170,7 @@ unsigned char tag; int i; - if ( addr_modes.vm86 + if ( addr_modes.mode16 || (addr_modes.override.operand_size == OP_SIZE_PREFIX) ) { RE_ENTRANT_CHECK_OFF; @@ -1189,6 +1189,11 @@ ip_offset += (cs_selector & 0xf000) << 4; data_operand_offset += (operand_selector & 0xf000) << 4; } + else if ( addr_modes.p286 ) + { + ip_offset += LDT_BASE_ADDR(cs_selector); + data_operand_offset += LDT_BASE_ADDR(operand_selector); + } } else { @@ -1317,7 +1322,7 @@ { char *d = (char *)FPU_data_address; - if ( addr_modes.vm86 + if ( addr_modes.mode16 || (addr_modes.override.operand_size == OP_SIZE_PREFIX) ) { RE_ENTRANT_CHECK_OFF; diff -u --recursive --new-file v1.1.12/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v1.1.12/linux/drivers/char/Makefile Sun Jan 9 15:14:58 1994 +++ linux/drivers/char/Makefile Mon May 23 07:55:12 1994 @@ -16,7 +16,7 @@ .c.o: $(CC) $(CFLAGS) -c $< -OBJS = tty_io.o console.o keyboard.o serial.o \ +OBJS = tty_io.o n_tty.o console.o keyboard.o serial.o \ tty_ioctl.o pty.o vt.o mem.o \ defkeymap.o diff -u --recursive --new-file v1.1.12/linux/drivers/char/console.c linux/drivers/char/console.c --- v1.1.12/linux/drivers/char/console.c Wed Feb 23 08:52:24 1994 +++ linux/drivers/char/console.c Mon May 23 07:55:12 1994 @@ -48,20 +48,34 @@ #include #include +#include #include +#include #include #include #include #include #include +#include #include #include #include +#include #include "kbd_kern.h" #include "vt_kern.h" +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +struct tty_driver console_driver; +static int console_refcount; +static struct tty_struct *console_table[NR_CONSOLES]; +static struct termios *console_termios[NR_CONSOLES]; +static struct termios *console_termios_locked[NR_CONSOLES]; + #ifdef CONFIG_SELECTION #include @@ -71,7 +85,7 @@ static void clear_selection(void); /* Variables for selection control. */ -#define SEL_BUFFER_SIZE TTY_BUF_SIZE +#define SEL_BUFFER_SIZE 4096 static int sel_cons; static int sel_start = -1; static int sel_end; @@ -156,7 +170,7 @@ #define bottom (vc_cons[currcons].vc_bottom) #define x (vc_cons[currcons].vc_x) #define y (vc_cons[currcons].vc_y) -#define state (vc_cons[currcons].vc_state) +#define vc_state (vc_cons[currcons].vc_state) #define npar (vc_cons[currcons].vc_npar) #define par (vc_cons[currcons].vc_par) #define ques (vc_cons[currcons].vc_ques) @@ -699,49 +713,31 @@ update_attr(currcons); } -static void respond_string(char * p, int currcons, struct tty_struct * tty) +static void respond_string(char * p, struct tty_struct * tty) { while (*p) { - put_tty_queue(*p, &tty->read_q); + tty_insert_flip_char(tty, *p, 0); p++; } - TTY_READ_FLUSH(tty); -} - -static void respond_num(unsigned int n, int currcons, struct tty_struct * tty) -{ - char buff[3]; - int i = 0; - - do { - buff[i++] = (n%10)+'0'; - n /= 10; - } while(n && i < 3); /* We'll take no chances */ - while (i--) { - put_tty_queue(buff[i], &tty->read_q); - } - /* caller must flush */ + tty_schedule_flip(tty); } static void cursor_report(int currcons, struct tty_struct * tty) { - put_tty_queue('\033', &tty->read_q); - put_tty_queue('[', &tty->read_q); - respond_num(y + (decom ? top+1 : 1), currcons, tty); - put_tty_queue(';', &tty->read_q); - respond_num(x+1, currcons, tty); - put_tty_queue('R', &tty->read_q); - TTY_READ_FLUSH(tty); + char buf[40]; + + sprintf(buf, "\033[%ld;%ldR", y + (decom ? top+1 : 1), x+1); + respond_string(buf, tty); } static inline void status_report(int currcons, struct tty_struct * tty) { - respond_string("\033[0n", currcons, tty); /* Terminal ok */ + respond_string("\033[0n", tty); /* Terminal ok */ } static inline void respond_ID(int currcons, struct tty_struct * tty) { - respond_string(VT102ID, currcons, tty); + respond_string(VT102ID, tty); } static void invert_screen(int currcons) { @@ -953,7 +949,7 @@ { top = 0; bottom = video_num_lines; - state = ESnormal; + vc_state = ESnormal; ques = 0; translate = NORM_TRANS; G0_charset = NORM_TRANS; @@ -991,25 +987,46 @@ } } -void con_write(struct tty_struct * tty) +/* + * Turn the Scroll-Lock LED on when the tty is stopped (with a ^S) + */ +static void con_stop(struct tty_struct *tty) +{ + set_vc_kbd_led(kbd_table + fg_console, VC_SCROLLOCK); + set_leds(); +} + +/* + * Turn the Scroll-Lock LED off when the console is started (with a ^Q) + */ +static void con_start(struct tty_struct *tty) +{ + clr_vc_kbd_led(kbd_table + fg_console, VC_SCROLLOCK); + set_leds(); +} + +static int con_write(struct tty_struct * tty, int from_user, + unsigned char *buf, int count) { - int c; + int c, n = 0; unsigned int currcons; + struct vt_struct *vt = tty->driver_data; - currcons = tty->line - 1; + currcons = vt->vc_num; if (currcons >= NR_CONSOLES) { - printk("con_write: illegal tty (%d)\n", currcons); - return; + printk("con_write: illegal vc index (%d)\n", currcons); + return 0; } #ifdef CONFIG_SELECTION - /* clear the selection as soon as any characters are to be written - out on the console holding the selection. */ - if (!EMPTY(&tty->write_q) && currcons == sel_cons) + /* clear the selection */ + if (currcons == sel_cons) clear_selection(); #endif /* CONFIG_SELECTION */ disable_bh(KEYBOARD_BH); - while (!tty->stopped && (c = get_tty_queue(&tty->write_q)) >= 0) { - if (state == ESnormal && translate[c]) { + while (!tty->stopped && count) { + c = from_user ? get_fs_byte(buf) : *buf; + buf++; n++; count--; + if (vc_state == ESnormal && translate[c]) { if (need_wrap) { cr(currcons); lf(currcons); @@ -1063,24 +1080,24 @@ translate = G0_charset; continue; case 24: case 26: - state = ESnormal; + vc_state = ESnormal; continue; case 27: - state = ESesc; + vc_state = ESesc; continue; case 127: del(currcons); continue; case 128+27: - state = ESsquare; + vc_state = ESsquare; continue; } - switch(state) { + switch(vc_state) { case ESesc: - state = ESnormal; + vc_state = ESnormal; switch (c) { case '[': - state = ESsquare; + vc_state = ESsquare; continue; case 'E': cr(currcons); @@ -1105,13 +1122,13 @@ restore_cur(currcons); continue; case '(': - state = ESsetG0; + vc_state = ESsetG0; continue; case ')': - state = ESsetG1; + vc_state = ESsetG1; continue; case '#': - state = EShash; + vc_state = EShash; continue; case 'c': reset_terminal(currcons,1); @@ -1128,9 +1145,9 @@ for(npar = 0 ; npar < NPAR ; npar++) par[npar] = 0; npar = 0; - state = ESgetpars; + vc_state = ESgetpars; if (c == '[') { /* Function key */ - state=ESfunckey; + vc_state=ESfunckey; continue; } ques = (c=='?'); @@ -1144,9 +1161,9 @@ par[npar] *= 10; par[npar] += c-'0'; continue; - } else state=ESgotpars; + } else vc_state=ESgotpars; case ESgotpars: - state = ESnormal; + vc_state = ESnormal; switch(c) { case 'h': set_mode(currcons,1); @@ -1265,10 +1282,10 @@ } continue; case ESfunckey: - state = ESnormal; + vc_state = ESnormal; continue; case EShash: - state = ESnormal; + vc_state = ESnormal; if (c == '8') { /* DEC screen alignment test. kludge :-) */ video_erase_char = @@ -1289,7 +1306,7 @@ G0_charset = USER_TRANS; if (charset == 0) translate = G0_charset; - state = ESnormal; + vc_state = ESnormal; continue; case ESsetG1: if (c == '0') @@ -1302,22 +1319,32 @@ G1_charset = USER_TRANS; if (charset == 1) translate = G1_charset; - state = ESnormal; + vc_state = ESnormal; continue; default: - state = ESnormal; + vc_state = ESnormal; } } if (vcmode != KD_GRAPHICS) set_cursor(currcons); enable_bh(KEYBOARD_BH); - if (LEFT(&tty->write_q) > WAKEUP_CHARS) - wake_up_interruptible(&tty->write_q.proc_list); + return n; +} + +static int con_write_room(struct tty_struct *tty) +{ + if (tty->stopped) + return 0; + return 4096; /* No limit, really; we're not buffering */ +} + +static int con_chars_in_buffer(struct tty_struct *tty) +{ + return 0; /* we're not buffering */ } -void do_keyboard_interrupt(void) +void poke_blanked_console(void) { - TTY_READ_FLUSH(TTY_TABLE(0)); timer_active &= ~(1<driver_data; + + wake_up_interruptible(&vt->paste_wait); +} + +/* * long con_init(long); * * This routine initalizes console interrupts, and does nothing @@ -1395,6 +1438,34 @@ int orig_x = ORIG_X; int orig_y = ORIG_Y; + memset(&console_driver, 0, sizeof(struct tty_driver)); + console_driver.magic = TTY_DRIVER_MAGIC; + console_driver.name = "tty"; + console_driver.name_base = 1; + console_driver.major = TTY_MAJOR; + console_driver.minor_start = 1; + console_driver.num = NR_CONSOLES; + console_driver.type = TTY_DRIVER_TYPE_CONSOLE; + console_driver.init_termios = tty_std_termios; + console_driver.flags = TTY_DRIVER_REAL_RAW; + console_driver.refcount = &console_refcount; + console_driver.table = console_table; + console_driver.termios = console_termios; + console_driver.termios_locked = console_termios_locked; + + console_driver.open = con_open; + console_driver.write = con_write; + console_driver.write_room = con_write_room; + console_driver.chars_in_buffer = con_chars_in_buffer; + console_driver.ioctl = vt_ioctl; + console_driver.stop = con_stop; + console_driver.start = con_start; + console_driver.throttle = con_throttle; + console_driver.unthrottle = con_unthrottle; + + if (tty_register_driver(&console_driver)) + panic("Couldn't register console driver\n"); + vc_scrmembuf = (unsigned short *) kmem_start; video_num_columns = ORIG_VIDEO_COLS; video_size_row = video_num_columns * 2; @@ -1466,6 +1537,7 @@ def_color = 0x07; /* white */ ulcolor = 0x0f; /* bold white */ halfcolor = 0x08; /* grey */ + vt_cons[currcons].paste_wait = 0; reset_terminal(currcons, currcons); } currcons = fg_console = 0; @@ -1613,15 +1685,24 @@ } /* - * All we do is set the write and ioctl subroutines; later on maybe we'll - * dynamically allocate the console screen memory. + * Later on maybe we'll dynamically allocate the console screen + * memory. */ int con_open(struct tty_struct *tty, struct file * filp) { - tty->write = con_write; - tty->ioctl = vt_ioctl; - if (tty->line > NR_CONSOLES) + int idx; + + idx = MINOR(tty->device) - tty->driver.minor_start; + + if (idx > NR_CONSOLES) return -ENODEV; + vt_cons[idx].vc_num = idx; + tty->driver_data = &vt_cons[idx]; + + if (!tty->winsize.ws_row && !tty->winsize.ws_col) { + tty->winsize.ws_row = video_num_lines; + tty->winsize.ws_col = video_num_columns; + } return 0; } @@ -1801,16 +1882,28 @@ tty associated with the current console. Invoked by ioctl(). */ int paste_selection(struct tty_struct *tty) { - char *bp = sel_buffer; - - if (! *bp) + struct wait_queue wait = { current, NULL }; + char *bp = sel_buffer; + int c, l; + struct vt_struct *vt = (struct vt_struct *) tty->driver_data; + + if (!sel_buffer[0]) return 0; unblank_screen(); - while (*bp) { - put_tty_queue(*bp, &tty->read_q); - bp++; - TTY_READ_FLUSH(tty); + c = strlen(sel_buffer); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&vt->paste_wait, &wait); + while (c) { + if (test_bit(TTY_THROTTLED, &tty->flags)) { + schedule(); + continue; + } + l = MIN(c, tty->ldisc.receive_room(tty)); + tty->ldisc.receive_buf(tty, bp, 0, l); + c -= l; + bp += l; } + current->state = TASK_RUNNING; return 0; } diff -u --recursive --new-file v1.1.12/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c --- v1.1.12/linux/drivers/char/keyboard.c Tue Apr 19 10:52:43 1994 +++ linux/drivers/char/keyboard.c Mon May 23 07:55:12 1994 @@ -14,10 +14,11 @@ #define KEYBOARD_IRQ 1 #include +#include #include +#include #include #include -#include #include #include #include @@ -26,6 +27,7 @@ #include "kbd_kern.h" #include "diacr.h" +#include "vt_kern.h" #define SIZE(x) (sizeof(x)/sizeof((x)[0])) @@ -59,7 +61,7 @@ #include #include -extern void do_keyboard_interrupt(void); +extern void poke_blanked_console(void); extern void ctrl_alt_del(void); extern void change_console(unsigned int new_console); extern void scrollback(int); @@ -89,6 +91,7 @@ static unsigned char diacr = 0; static char rep = 0; /* flag telling character repeat */ struct kbd_struct kbd_table[NR_CONSOLES]; +static struct tty_struct **ttytab; static struct kbd_struct * kbd = kbd_table; static struct tty_struct * tty = NULL; @@ -110,7 +113,7 @@ /* maximum values each key_handler can handle */ const int max_vals[] = { - 255, NR_FUNC - 1, 14, 17, 4, 255, 3, NR_SHIFT, + 255, NR_FUNC - 1, 15, 17, 4, 255, 3, NR_SHIFT, 255, 9, 3, 255 }; @@ -118,12 +121,11 @@ static void put_queue(int); static unsigned char handle_diacr(unsigned char); +static void SAK(void); /* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */ static struct pt_regs * pt_regs; -static int got_break = 0; - static inline void kb_wait(void) { int i; @@ -224,7 +226,7 @@ prev_scancode = 0; goto end_kbd_intr; } - tty = TTY_TABLE(0); + tty = ttytab[fg_console]; kbd = kbd_table + fg_console; if ((raw_mode = vc_kbd_mode(kbd,VC_RAW))) { put_queue(scancode); @@ -332,8 +334,7 @@ */ if (!rep || (vc_kbd_mode(kbd,VC_REPEAT) && tty && - (L_ECHO(tty) || (EMPTY(&tty->secondary) && EMPTY(&tty->read_q))))) - { + (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) { u_short key_code; u_char type; @@ -357,36 +358,24 @@ static void put_queue(int ch) { - struct tty_queue *qp; - wake_up(&keypress_wait); - if (!tty) - return; - qp = &tty->read_q; - - if (LEFT(qp)) { - qp->buf[qp->head] = ch; - INC(qp->head); + if (tty) { + tty_insert_flip_char(tty, ch, 0); + tty_schedule_flip(tty); } } static void puts_queue(char *cp) { - struct tty_queue *qp; - char ch; - - /* why interruptible here, plain wake_up above? */ - wake_up_interruptible(&keypress_wait); + wake_up(&keypress_wait); if (!tty) return; - qp = &tty->read_q; - while ((ch = *(cp++)) != 0) { - if (LEFT(qp)) { - qp->buf[qp->head] = ch; - INC(qp->head); - } + while (*cp) { + tty_insert_flip_char(tty, *cp, 0); + cp++; } + tty_schedule_flip(tty); } static void applkey(int key, char mode) @@ -479,7 +468,9 @@ static void send_intr(void) { - got_break = 1; + if (tty->termios && I_IGNBRK(tty)) + return; + tty_insert_flip_char(tty, 0, TTY_BREAK); } static void scrll_forw(void) @@ -502,6 +493,33 @@ dead_key_next = 1; } +static void SAK(void) +{ + do_SAK(tty); +#if 0 + /* + * Need to fix SAK handling to fix up RAW/MEDIUM_RAW and + * vt_cons modes before we can enable RAW/MEDIUM_RAW SAK + * handling. + * + * We should do this some day --- the whole point of a secure + * attention key is that it should be guaranteed to always + * work. + */ + clr_vc_kbd_flag(kbd, VC_RAW); + clr_vc_kbd_flag(kbd, VC_MEDIUMRAW); + vt_cons[fg_console].vc_mode = KD_TEXT; + vt_cons[fg_console].vt_mode.mode = VT_AUTO; + vt_cons[fg_console].vt_mode.waitv = 0; + vt_cons[fg_console].vt_mode.relsig = 0; + vt_cons[fg_console].vt_mode.acqsig = 0; + vt_cons[fg_console].vt_mode.frsig = 0; + vt_cons[fg_console].vt_pid = -1; + vt_cons[fg_console].vt_newvt = -1; + unblank_screen(); +#endif +} + static void do_spec(unsigned char value, char up_flag) { typedef void (*fnp)(void); @@ -509,7 +527,7 @@ NULL, enter, show_ptregs, show_mem, show_state, send_intr, lastcons, caps_toggle, num, hold, scrll_forw, scrll_back, - boot_it, caps_on, compose + boot_it, caps_on, compose, SAK }; if (up_flag) @@ -683,7 +701,8 @@ /* kludge... */ if (value == KVAL(K_CAPSSHIFT)) { value = KVAL(K_SHIFT); - clr_vc_kbd_led(kbd, VC_CAPSLOCK); + if (!up_flag) + clr_vc_kbd_led(kbd, VC_CAPSLOCK); } if (up_flag) { @@ -819,27 +838,7 @@ } want_console = -1; } - if (got_break) { - if (tty && !I_IGNBRK(tty)) { - if (I_BRKINT(tty)) { - flush_input(tty); - flush_output(tty); - if (tty->pgrp > 0) - kill_pg(tty->pgrp, SIGINT, 1); - } else { - cli(); - if (LEFT(&tty->read_q) >= 2) { - set_bit(tty->read_q.head, - &tty->readq_flags); - put_queue(TTY_BREAK); - put_queue(0); - } - sti(); - } - } - got_break = 0; - } - do_keyboard_interrupt(); + poke_blanked_console(); cli(); if ((inb_p(0x64) & kbd_read_mask) == 0x01) fake_keyboard_interrupt(); @@ -877,6 +876,7 @@ { int i; struct kbd_struct * kbd; + extern struct tty_driver console_driver; kbd = kbd_table + 0; for (i = 0 ; i < NR_CONSOLES ; i++,kbd++) { @@ -885,6 +885,7 @@ kbd->lockstate = KBD_DEFLOCK; kbd->modeflags = KBD_DEFMODE; } + ttytab = console_driver.table; bh_base[KEYBOARD_BH].routine = kbd_bh; request_irq(KEYBOARD_IRQ,keyboard_interrupt); diff -u --recursive --new-file v1.1.12/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c --- v1.1.12/linux/drivers/char/n_tty.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/char/n_tty.c Mon May 23 09:00:08 1994 @@ -0,0 +1,997 @@ +/* + * n_tty.c --- implements the N_TTY line discpline. + * + * This code used to be in tty_io.c, but things are getting hairy + * enough that it made sense to split things off. (The N_TTY + * processing has changed so much that it's hardly recognizable, + * anyway...) + * + * Note that the open routine for N_TTY is guaranteed never to return + * an error. This is because Linux will fall back to setting a line + * to N_TTY if it can not switch to any other line discpline. + * + * Written by Theodore Ts'o, Copyright 1994. + * + * This file also contains code originally written by Linus Torvalds, + * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994. + * + * This file may be redistributed under the terms of the GNU Public + * License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define CONSOLE_DEV MKDEV(TTY_MAJOR,0) + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* number of characters left in xmit buffer before select has we have room */ +#define WAKEUP_CHARS 256 + +/* + * This defines the low- and high-watermarks for throttling and + * unthrottling the TTY driver. These watermarks are used for + * controlling the space in the read buffer. + */ +#define TTY_THRESHOLD_THROTTLE (N_TTY_BUF_SIZE - 128) +#define TTY_THRESHOLD_UNTHROTTLE 128 + +static inline void put_tty_queue(unsigned char c, struct tty_struct *tty) +{ + if (tty->read_cnt < N_TTY_BUF_SIZE) { + tty->read_buf[tty->read_head] = c; + tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1); + tty->read_cnt++; + } +} + +/* + * Flush the input buffer + */ +void n_tty_flush_buffer(struct tty_struct * tty) +{ + tty->read_head = tty->read_tail = tty->read_cnt = 0; + tty->canon_head = tty->canon_data = tty->erasing = 0; + memset(&tty->read_flags, 0, sizeof tty->read_flags); + + if (!tty->link) + return; + + wake_up_interruptible(&tty->link->write_wait); + if (tty->link->packet) { + tty->ctrl_status |= TIOCPKT_FLUSHREAD; + wake_up_interruptible(&tty->link->read_wait); + } +} + +/* + * Return number of characters buffered to be delievered to user + */ +int n_tty_chars_in_buffer(struct tty_struct *tty) +{ + return tty->read_cnt; +} + +/* + * Perform OPOST processing. Returns -1 when the output device is + * full and the character must be retried. + */ +static int opost(unsigned char c, struct tty_struct *tty) +{ + int space, spaces; + + space = tty->driver.write_room(tty); + if (!space) + return -1; + + if (O_OPOST(tty)) { + switch (c) { + case '\n': + if (O_ONLRET(tty)) + tty->column = 0; + if (O_ONLCR(tty)) { + if (space < 2) + return -1; + tty->driver.write(tty, 0, "\r", 1); + tty->column = 0; + } + tty->canon_column = tty->column; + break; + case '\r': + if (O_ONOCR(tty) && tty->column == 0) + return 0; + if (O_OCRNL(tty)) { + c = '\n'; + if (O_ONLRET(tty)) + tty->canon_column = tty->column = 0; + break; + } + tty->canon_column = tty->column = 0; + break; + case '\t': + spaces = 8 - (tty->column & 7); + if (O_TABDLY(tty) == XTABS) { + if (space < spaces) + return -1; + tty->column += spaces; + tty->driver.write(tty, 0, " ", spaces); + return 0; + } + tty->column += spaces; + break; + case '\b': + if (tty->column > 0) + tty->column--; + break; + default: + if (O_OLCUC(tty)) + c = toupper(c); + if (!iscntrl(c)) + tty->column++; + break; + } + } + tty->driver.put_char(tty, c); + return 0; +} + +static inline void put_char(unsigned char c, struct tty_struct *tty) +{ + tty->driver.put_char(tty, c); +} + +/* Must be called only when L_ECHO(tty) is true. */ + +static void echo_char(unsigned char c, struct tty_struct *tty) +{ + if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') { + put_char('^', tty); + put_char(c ^ 0100, tty); + tty->column += 2; + } else + opost(c, tty); +} + +static inline void finish_erasing(struct tty_struct *tty) +{ + if (tty->erasing) { + put_char('/', tty); + tty->column += 2; + tty->erasing = 0; + } +} + +static void eraser(unsigned char c, struct tty_struct *tty) +{ + enum { ERASE, WERASE, KILL } kill_type; + int head, seen_alnums; + + if (tty->read_head == tty->canon_head) { + /* opost('\a', tty); */ /* what do you think? */ + return; + } + if (c == ERASE_CHAR(tty)) + kill_type = ERASE; + else if (c == WERASE_CHAR(tty)) + kill_type = WERASE; + else { + if (!L_ECHO(tty)) { + tty->read_cnt -= ((tty->read_head - tty->canon_head) & + (N_TTY_BUF_SIZE - 1)); + tty->read_head = tty->canon_head; + return; + } + if (!L_ECHOK(tty) || !L_ECHOKE(tty)) { + tty->read_cnt -= ((tty->read_head - tty->canon_head) & + (N_TTY_BUF_SIZE - 1)); + tty->read_head = tty->canon_head; + finish_erasing(tty); + echo_char(KILL_CHAR(tty), tty); + /* Add a newline if ECHOK is on and ECHOKE is off. */ + if (L_ECHOK(tty)) + opost('\n', tty); + return; + } + kill_type = KILL; + } + + seen_alnums = 0; + while (tty->read_head != tty->canon_head) { + head = (tty->read_head - 1) & (N_TTY_BUF_SIZE-1); + c = tty->read_buf[head]; + if (kill_type == WERASE) { + /* Equivalent to BSD's ALTWERASE. */ + if (isalnum(c) || c == '_') + seen_alnums++; + else if (seen_alnums) + break; + } + tty->read_head = head; + tty->read_cnt--; + if (L_ECHO(tty)) { + if (L_ECHOPRT(tty)) { + if (!tty->erasing) { + put_char('\\', tty); + tty->column++; + tty->erasing = 1; + } + echo_char(c, tty); + } else if (!L_ECHOE(tty)) { + echo_char(ERASE_CHAR(tty), tty); + } else if (c == '\t') { + unsigned int col = tty->canon_column; + unsigned long tail = tty->canon_head; + + /* Find the column of the last char. */ + while (tail != tty->read_head) { + c = tty->read_buf[tail]; + if (c == '\t') + col = (col | 7) + 1; + else if (iscntrl(c)) { + if (L_ECHOCTL(tty)) + col += 2; + } else + col++; + tail = (tail+1) & (N_TTY_BUF_SIZE-1); + } + + /* Now backup to that column. */ + while (tty->column > col) { + /* Can't use opost here. */ + put_char('\b', tty); + tty->column--; + } + } else { + if (iscntrl(c) && L_ECHOCTL(tty)) { + put_char('\b', tty); + put_char(' ', tty); + put_char('\b', tty); + tty->column--; + } + if (!iscntrl(c) || L_ECHOCTL(tty)) { + put_char('\b', tty); + put_char(' ', tty); + put_char('\b', tty); + tty->column--; + } + } + } + if (kill_type == ERASE) + break; + } + if (tty->read_head == tty->canon_head) + finish_erasing(tty); +} + +static void isig(int sig, struct tty_struct *tty) +{ + if (tty->pgrp > 0) + kill_pg(tty->pgrp, sig, 1); + if (!L_NOFLSH(tty)) { + n_tty_flush_buffer(tty); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + } +} + +static inline void n_tty_receive_break(struct tty_struct *tty) +{ + if (I_IGNBRK(tty)) + return; + if (I_BRKINT(tty)) { + isig(SIGINT, tty); + return; + } + if (I_PARMRK(tty)) { + put_tty_queue('\377', tty); + put_tty_queue('\0', tty); + } + put_tty_queue('\0', tty); + wake_up_interruptible(&tty->read_wait); +} + +static inline void n_tty_receive_overrun(struct tty_struct *tty) +{ + char buf[64]; + + tty->num_overrun++; + if (tty->overrun_time < (jiffies - HZ)) { + printk("%s: %d input overrun(s)\n", _tty_name(tty, buf), + tty->num_overrun); + tty->overrun_time = jiffies; + tty->num_overrun = 0; + } +} + +static inline void n_tty_receive_parity_error(struct tty_struct *tty, + unsigned char c) +{ + if (I_IGNPAR(tty)) { + return; + } + if (I_PARMRK(tty)) { + put_tty_queue('\377', tty); + put_tty_queue('\0', tty); + put_tty_queue(c, tty); + } else + put_tty_queue('\0', tty); + wake_up_interruptible(&tty->read_wait); +} + +static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) +{ + if (tty->raw) { + put_tty_queue(c, tty); + return; + } + + if (tty->stopped && I_IXON(tty) && I_IXANY(tty) && L_IEXTEN(tty)) { + start_tty(tty); + return; + } + + if (I_ISTRIP(tty)) + c &= 0x7f; + if (I_IUCLC(tty) && L_IEXTEN(tty)) + c=tolower(c); + + /* + * If the previous character was LNEXT, or we know that this + * character is not one of the characters that we'll have to + * handle specially, do shortcut processing to speed things + * up. + */ + if (!test_bit(c, &tty->process_char_map) || tty->lnext) { + finish_erasing(tty); + tty->lnext = 0; + if (L_ECHO(tty)) { + if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { + put_char('\a', tty); /* beep if no space */ + return; + } + /* Record the column of first canon char. */ + if (tty->canon_head == tty->read_head) + tty->canon_column = tty->column; + echo_char(c, tty); + } + if (I_PARMRK(tty) && c == (unsigned char) '\377') + put_tty_queue(c, tty); + put_tty_queue(c, tty); + return; + } + + if (c == '\r') { + if (I_IGNCR(tty)) + return; + if (I_ICRNL(tty)) + c = '\n'; + } else if (c == '\n' && I_INLCR(tty)) + c = '\r'; + if (I_IXON(tty)) { + if (c == START_CHAR(tty)) { + start_tty(tty); + return; + } + if (c == STOP_CHAR(tty)) { + stop_tty(tty); + return; + } + } + if (L_ISIG(tty)) { + if (c == INTR_CHAR(tty)) { + isig(SIGINT, tty); + return; + } + if (c == QUIT_CHAR(tty)) { + isig(SIGQUIT, tty); + return; + } + if (c == SUSP_CHAR(tty)) { + if (!is_orphaned_pgrp(tty->pgrp)) + isig(SIGTSTP, tty); + return; + } + } + if (L_ICANON(tty)) { + if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) || + (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) { + eraser(c, tty); + return; + } + if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) { + tty->lnext = 1; + if (L_ECHO(tty)) { + finish_erasing(tty); + if (L_ECHOCTL(tty)) { + put_char('^', tty); + put_char('\b', tty); + } + } + return; + } + if (c == REPRINT_CHAR(tty) && L_ECHO(tty) && + L_IEXTEN(tty)) { + unsigned long tail = tty->canon_head; + + finish_erasing(tty); + echo_char(c, tty); + opost('\n', tty); + while (tail != tty->read_head) { + echo_char(tty->read_buf[tail], tty); + tail = (tail+1) & (N_TTY_BUF_SIZE-1); + } + return; + } + if (c == '\n') { + if (L_ECHO(tty) || L_ECHONL(tty)) { + if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { + put_char('\a', tty); + return; + } + opost('\n', tty); + } + goto handle_newline; + } + if (c == EOF_CHAR(tty)) { + c = __DISABLED_CHAR; + goto handle_newline; + } + if ((c == EOL_CHAR(tty)) || + (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) { + /* + * XXX are EOL_CHAR and EOL2_CHAR echoed?!? + */ + if (L_ECHO(tty)) { + if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { + put_char('\a', tty); + return; + } + /* Record the column of first canon char. */ + if (tty->canon_head == tty->read_head) + tty->canon_column = tty->column; + echo_char(c, tty); + } + /* + * XXX does PARMRK doubling happen for + * EOL_CHAR and EOL2_CHAR? + */ + if (I_PARMRK(tty) && c == (unsigned char) '\377') + put_tty_queue(c, tty); + + handle_newline: + set_bit(tty->read_head, &tty->read_flags); + put_tty_queue(c, tty); + tty->canon_head = tty->read_head; + tty->canon_data++; + return; + } + } + + finish_erasing(tty); + if (L_ECHO(tty)) { + if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { + put_char('\a', tty); /* beep if no space */ + return; + } + if (c == '\n') + opost('\n', tty); + else { + /* Record the column of first canon char. */ + if (tty->canon_head == tty->read_head) + tty->canon_column = tty->column; + echo_char(c, tty); + } + } + + if (I_PARMRK(tty) && c == (unsigned char) '\377') + put_tty_queue(c, tty); + + put_tty_queue(c, tty); +} + +static void n_tty_receive_buf(struct tty_struct *tty, unsigned char *cp, + char *fp, int count) +{ + unsigned char *p; + char *f, flags = 0; + int i; + + if (!tty->read_buf) + return; + + if (tty->real_raw) { + i = MIN(count, MIN(N_TTY_BUF_SIZE - tty->read_cnt, + N_TTY_BUF_SIZE - tty->read_head)); + memcpy(tty->read_buf + tty->read_head, cp, i); + tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1); + tty->read_cnt += i; + cp += i; + count -= i; + + i = MIN(count, MIN(N_TTY_BUF_SIZE - tty->read_cnt, + N_TTY_BUF_SIZE - tty->read_head)); + memcpy(tty->read_buf + tty->read_head, cp, i); + tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1); + tty->read_cnt += i; + } else { + for (i=count, p = cp, f = fp; i; i--, p++) { + if (f) + flags = *f++; + switch (flags) { + case TTY_NORMAL: + n_tty_receive_char(tty, *p); + break; + case TTY_BREAK: + n_tty_receive_break(tty); + break; + case TTY_PARITY: + case TTY_FRAME: + n_tty_receive_parity_error(tty, *p); + break; + case TTY_OVERRUN: + n_tty_receive_overrun(tty); + break; + default: + printk("%s: unknown flag %d\n", tty_name(tty), + flags); + break; + } + } + if (tty->driver.flush_chars) + tty->driver.flush_chars(tty); + } + + if (tty->icanon ? tty->canon_data : + (tty->read_cnt >= tty->minimum_to_wake)) { + if (tty->fasync) + kill_fasync(tty->fasync, SIGIO); + if (tty->read_wait) + wake_up_interruptible(&tty->read_wait); + } + + if ((tty->read_cnt >= TTY_THRESHOLD_THROTTLE) && + tty->driver.throttle && + !set_bit(TTY_THROTTLED, &tty->flags)) + tty->driver.throttle(tty); +} + +static int n_tty_receive_room(struct tty_struct *tty) +{ + int left = N_TTY_BUF_SIZE - tty->read_cnt - 1; + + if (left > 0) + return left; + return 0; +} + +int is_ignored(int sig) +{ + return ((current->blocked & (1<<(sig-1))) || + (current->sigaction[sig-1].sa_handler == SIG_IGN)); +} + +static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) +{ + tty->icanon = (L_ICANON(tty) != 0); + if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) || + I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) || + I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) || + I_PARMRK(tty)) { + cli(); + memset(tty->process_char_map, 0, 256/32); + + if (I_IGNCR(tty) || I_ICRNL(tty)) + set_bit('\r', &tty->process_char_map); + if (I_INLCR(tty)) + set_bit('\n', &tty->process_char_map); + + if (L_ICANON(tty)) { + set_bit(ERASE_CHAR(tty), &tty->process_char_map); + set_bit(KILL_CHAR(tty), &tty->process_char_map); + set_bit(EOF_CHAR(tty), &tty->process_char_map); + set_bit('\n', &tty->process_char_map); + set_bit(EOL_CHAR(tty), &tty->process_char_map); + if (L_IEXTEN(tty)) { + set_bit(WERASE_CHAR(tty), + &tty->process_char_map); + set_bit(LNEXT_CHAR(tty), + &tty->process_char_map); + set_bit(EOL2_CHAR(tty), + &tty->process_char_map); + if (L_ECHO(tty)) + set_bit(REPRINT_CHAR(tty), + &tty->process_char_map); + } + } + if (I_IXON(tty)) { + set_bit(START_CHAR(tty), &tty->process_char_map); + set_bit(STOP_CHAR(tty), &tty->process_char_map); + } + if (L_ISIG(tty)) { + set_bit(INTR_CHAR(tty), &tty->process_char_map); + set_bit(QUIT_CHAR(tty), &tty->process_char_map); + set_bit(SUSP_CHAR(tty), &tty->process_char_map); + } + clear_bit(__DISABLED_CHAR, &tty->process_char_map); + sti(); + tty->raw = 0; + tty->real_raw = 0; + } else { + tty->raw = 1; + if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) && + (I_IGNPAR(tty) || !I_INPCK(tty)) && + (tty->driver.flags & TTY_DRIVER_REAL_RAW)) + tty->real_raw = 1; + else + tty->real_raw = 0; + } +} + +static void n_tty_close(struct tty_struct *tty) +{ + wait_until_sent(tty, 0); + n_tty_flush_buffer(tty); + if (tty->read_buf) { + free_page((unsigned long) tty->read_buf); + tty->read_buf = 0; + } +} + +static int n_tty_open(struct tty_struct *tty) +{ + if (!tty->read_buf) { + tty->read_buf = (unsigned char *) + get_free_page(intr_count ? GFP_ATOMIC : GFP_KERNEL); + if (!tty->read_buf) + return -ENOMEM; + } + memset(tty->read_buf, 0, N_TTY_BUF_SIZE); + tty->read_head = tty->read_tail = tty->read_cnt = 0; + memset(tty->read_flags, 0, sizeof(tty->read_flags)); + n_tty_set_termios(tty, 0); + tty->minimum_to_wake = 1; + return 0; +} + +static inline int input_available_p(struct tty_struct *tty, int amt) +{ + if (L_ICANON(tty)) { + if (tty->canon_data) + return 1; + } else if (tty->read_cnt >= (amt ? amt : 1)) + return 1; + + return 0; +} + +/* + * Helper function to speed up read_chan. It is only called when + * ICANON is off; it copies characters straight from the tty queue to + * user space directly. It can be profitably called twice; once to + * drain the space from the tail pointer to the (physical) end of the + * buffer, and once to drain the space from the (physical) beginning of + * the buffer to head pointer. + */ +static inline void copy_from_read_buf(struct tty_struct *tty, + unsigned char **b, + unsigned int *nr) + +{ + int n; + + n = MIN(*nr, MIN(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail)); + if (!n) + return; + memcpy_tofs(*b, &tty->read_buf[tty->read_tail], n); + tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1); + tty->read_cnt -= n; + *b += n; + *nr -= n; +} + +/* + * Called to gobble up an immediately following EOF when there is no + * more room in buf (this can happen if the user "pushes" some + * characters using ^D). This prevents the next read() from falsely + * returning EOF. + */ +static inline void gobble_eof(struct tty_struct *tty) +{ + cli(); + if ((tty->read_cnt) && + (tty->read_buf[tty->read_tail] == __DISABLED_CHAR) && + clear_bit(tty->read_tail, &tty->read_flags)) { + tty->read_tail = (tty->read_tail+1) & (N_TTY_BUF_SIZE-1); + tty->read_cnt--; + } + sti(); +} + +static int read_chan(struct tty_struct *tty, struct file *file, + unsigned char *buf, unsigned int nr) +{ + struct wait_queue wait = { current, NULL }; + int c; + unsigned char *b = buf; + int minimum, time; + int retval = 0; + + if (!tty->read_buf) { + printk("n_tty_read_chan: called with read_buf == NULL?!?\n"); + return -EIO; + } + + /* Job control check -- must be done at start and after + every sleep (POSIX.1 7.1.1.4). */ + /* NOTE: not yet done after every sleep pending a thorough + check of the logic of this change. -- jlc */ + /* don't stop on /dev/console */ + if (file->f_inode->i_rdev != CONSOLE_DEV && + current->tty == tty) { + if (tty->pgrp <= 0) + printk("read_chan: tty->pgrp <= 0!\n"); + else if (current->pgrp != tty->pgrp) { + if (is_ignored(SIGTTIN) || + is_orphaned_pgrp(current->pgrp)) + return -EIO; + kill_pg(current->pgrp, SIGTTIN, 1); + return -ERESTARTSYS; + } + } + + if (L_ICANON(tty)) { + minimum = time = 0; + current->timeout = (unsigned long) -1; + } else { + time = (HZ / 10) * TIME_CHAR(tty); + minimum = MIN_CHAR(tty); + if (minimum) { + current->timeout = (unsigned long) -1; + if (time) + tty->minimum_to_wake = 1; + else if (!tty->read_wait || + (tty->minimum_to_wake > minimum)) + tty->minimum_to_wake = minimum; + } else { + if (time) { + current->timeout = time + jiffies; + time = 0; + } else + current->timeout = 0; + tty->minimum_to_wake = minimum = 1; + } + } + + add_wait_queue(&tty->read_wait, &wait); + while (1) { + /* First test for status change. */ + if (tty->packet && tty->link->ctrl_status) { + if (b != buf) + break; + put_fs_byte(tty->link->ctrl_status, b++); + tty->link->ctrl_status = 0; + break; + } + /* This statement must be first before checking for input + so that any interrupt will set the state back to + TASK_RUNNING. */ + current->state = TASK_INTERRUPTIBLE; + + if (((minimum - (b - buf)) < tty->minimum_to_wake) && + ((minimum - (b - buf)) >= 1)) + tty->minimum_to_wake = (minimum - (b - buf)); + + if (!input_available_p(tty, 0)) { + if (tty->flags & (1 << TTY_SLAVE_CLOSED)) { + retval = -EIO; + break; + } + if (tty_hung_up_p(file)) + break; + if (!current->timeout) + break; + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (current->signal & ~current->blocked) { + retval = -ERESTARTSYS; + break; + } + schedule(); + continue; + } + current->state = TASK_RUNNING; + + /* Deal with packet mode. */ + if (tty->packet && b == buf) { + put_fs_byte(TIOCPKT_DATA, b++); + nr--; + } + + if (L_ICANON(tty)) { + while (1) { + int eol; + + disable_bh(TQUEUE_BH); + if (!tty->read_cnt) { + enable_bh(TQUEUE_BH); + break; + } + eol = clear_bit(tty->read_tail, + &tty->read_flags); + c = tty->read_buf[tty->read_tail]; + tty->read_tail = ((tty->read_tail+1) & + (N_TTY_BUF_SIZE-1)); + tty->read_cnt--; + enable_bh(TQUEUE_BH); + if (!eol) { + put_fs_byte(c, b++); + if (--nr) + continue; + gobble_eof(tty); + break; + } + if (--tty->canon_data < 0) { + tty->canon_data = 0; + } + if (c != __DISABLED_CHAR) { + put_fs_byte(c, b++); + nr--; + } + break; + } + } else { + disable_bh(TQUEUE_BH); + copy_from_read_buf(tty, &b, &nr); + copy_from_read_buf(tty, &b, &nr); + enable_bh(TQUEUE_BH); + } + + /* If there is enough space in the read buffer now, let the + low-level driver know. */ + if (tty->driver.unthrottle && + (tty->read_cnt <= TTY_THRESHOLD_UNTHROTTLE) + && clear_bit(TTY_THROTTLED, &tty->flags)) + tty->driver.unthrottle(tty); + + if (b - buf >= minimum || !nr) + break; + if (time) + current->timeout = time + jiffies; + } + remove_wait_queue(&tty->read_wait, &wait); + + if (!tty->read_wait) + tty->minimum_to_wake = minimum; + + current->state = TASK_RUNNING; + current->timeout = 0; + /* + * Hack for PTY's; we need to wake up the other tty if there's + * enough space. + */ + if (tty->link && tty->read_cnt <= TTY_THRESHOLD_UNTHROTTLE) + wake_up_interruptible(&tty->link->write_wait); + return (b - buf) ? b - buf : retval; +} + +static int write_chan(struct tty_struct * tty, struct file * file, + unsigned char * buf, unsigned int nr) +{ + struct wait_queue wait = { current, NULL }; + int c; + unsigned char *b = buf; + int retval = 0; + + /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */ + if (L_TOSTOP(tty) && file->f_inode->i_rdev != CONSOLE_DEV) { + retval = tty_check_change(tty); + if (retval) + return retval; + } + + add_wait_queue(&tty->write_wait, &wait); + while (1) { + current->state = TASK_INTERRUPTIBLE; + if (current->signal & ~current->blocked) { + retval = -ERESTARTSYS; + break; + } + if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) { + retval = -EIO; + break; + } + if (O_OPOST(tty)) { + while (nr > 0) { + c = get_fs_byte(b); + if (opost(c, tty) < 0) + break; + b++; nr--; + if (tty->driver.flush_chars) + tty->driver.flush_chars(tty); + } + } else { + c = tty->driver.write(tty, 1, b, nr); + b += c; + nr -= c; + } + if (!nr) + break; + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&tty->write_wait, &wait); + return (b - buf) ? b - buf : retval; +} + +static int normal_select(struct tty_struct * tty, struct inode * inode, + struct file * file, int sel_type, select_table *wait) +{ + switch (sel_type) { + case SEL_IN: + if (input_available_p(tty, MIN_CHAR(tty))) + return 1; + /* fall through */ + case SEL_EX: + if (tty->packet && tty->link->ctrl_status) + return 1; + if (tty->flags & (1 << TTY_SLAVE_CLOSED)) + return 1; + if (tty_hung_up_p(file)) + return 1; + if (!tty->read_wait) + tty->minimum_to_wake = MIN_CHAR(tty) ? + MIN_CHAR(tty) : 1; + select_wait(&tty->read_wait, wait); + return 0; + case SEL_OUT: + if (tty->driver.chars_in_buffer(tty) < WAKEUP_CHARS) + return 1; + select_wait(&tty->write_wait, wait); + return 0; + } + return 0; +} + +struct tty_ldisc tty_ldisc_N_TTY = { + TTY_LDISC_MAGIC, /* magic */ + 0, /* num */ + 0, /* flags */ + n_tty_open, /* open */ + n_tty_close, /* close */ + n_tty_flush_buffer, /* flush_buffer */ + n_tty_chars_in_buffer, /* chars_in_buffer */ + read_chan, /* read */ + write_chan, /* write */ + n_tty_ioctl, /* ioctl */ + n_tty_set_termios, /* set_termios */ + normal_select, /* select */ + n_tty_receive_buf, /* receive_buf */ + n_tty_receive_room, /* receive_room */ + 0 /* write_wakeup */ +}; + diff -u --recursive --new-file v1.1.12/linux/drivers/char/pty.c linux/drivers/char/pty.c --- v1.1.12/linux/drivers/char/pty.c Wed Feb 9 08:57:58 1994 +++ linux/drivers/char/pty.c Mon May 23 07:55:13 1994 @@ -14,36 +14,59 @@ #include #include +#include #include +#include #include -#include #include +#include +#include #include #include +struct pty_struct { + int magic; + struct wait_queue * open_wait; +}; + +#define PTY_MAGIC 0x5001 + +#define PTY_BUF_SIZE 1024 + +static unsigned char tmp_buf[PTY_BUF_SIZE]; + +struct tty_driver pty_driver, pty_slave_driver; +static int pty_refcount; + +static struct tty_struct *pty_table[NR_PTYS]; +static struct termios *pty_termios[NR_PTYS]; +static struct termios *pty_termios_locked[NR_PTYS]; +static struct tty_struct *ttyp_table[NR_PTYS]; +static struct termios *ttyp_termios[NR_PTYS]; +static struct termios *ttyp_termios_locked[NR_PTYS]; +static struct pty_struct pty_state[NR_PTYS]; + #define MIN(a,b) ((a) < (b) ? (a) : (b)) static void pty_close(struct tty_struct * tty, struct file * filp) { if (!tty) return; - if (IS_A_PTY_MASTER(tty->line)) { + if (tty->driver.subtype == PTY_TYPE_MASTER) { if (tty->count > 1) printk("master pty_close: count = %d!!\n", tty->count); } else { if (tty->count > 2) return; } - wake_up_interruptible(&tty->secondary.proc_list); - wake_up_interruptible(&tty->read_q.proc_list); - wake_up_interruptible(&tty->write_q.proc_list); + wake_up_interruptible(&tty->read_wait); + wake_up_interruptible(&tty->write_wait); if (!tty->link) return; - wake_up_interruptible(&tty->link->secondary.proc_list); - wake_up_interruptible(&tty->link->read_q.proc_list); - wake_up_interruptible(&tty->link->write_q.proc_list); - if (IS_A_PTY_MASTER(tty->line)) + wake_up_interruptible(&tty->link->read_wait); + wake_up_interruptible(&tty->link->write_wait); + if (tty->driver.subtype == PTY_TYPE_MASTER) tty_hangup(tty->link); else { start_tty(tty); @@ -51,58 +74,137 @@ } } -static inline void pty_copy(struct tty_struct * from, struct tty_struct * to) +static int pty_write(struct tty_struct * tty, int from_user, + unsigned char *buf, int count) { - unsigned long count, n; - struct tty_queue *fq, *tq; + struct tty_struct *to = tty->link; + int c, n; - if (from->stopped || EMPTY(&from->write_q)) - return; - fq = &from->write_q; - tq = &to->read_q; - count = MIN(CHARS(fq), LEFT(tq)); - while (count) { - n = MIN(MIN(TTY_BUF_SIZE - fq->tail, TTY_BUF_SIZE - tq->head), - count); - memcpy(&tq->buf[tq->head], &fq->buf[fq->tail], n); - count -= n; - fq->tail = (fq->tail + n) & (TTY_BUF_SIZE - 1); - tq->head = (tq->head + n) & (TTY_BUF_SIZE - 1); - } - TTY_READ_FLUSH(to); - if (LEFT(fq) > WAKEUP_CHARS) - wake_up_interruptible(&fq->proc_list); - if (from->write_data_cnt) { - set_bit(from->line, &tty_check_write); - mark_bh(TTY_BH); - } + if (!to || tty->stopped) + return 0; + + count = MIN(count, to->ldisc.receive_room(to)); + + if (from_user) { + for (c = count; c > 0; c -= n) { + n = MIN(c, PTY_BUF_SIZE); + memcpy_fromfs(tmp_buf, buf, n); + to->ldisc.receive_buf(to, tmp_buf, 0, n); + buf += n; + } + } else + to->ldisc.receive_buf(to, buf, 0, count); + + return count; +} + +static int pty_write_room(struct tty_struct *tty) +{ + struct tty_struct *to = tty->link; + + if (!to || tty->stopped) + return 0; + + return to->ldisc.receive_room(to); } -/* - * This routine gets called when tty_write has put something into - * the write_queue. It copies the input to the output-queue of its - * slave. - */ -static void pty_write(struct tty_struct * tty) +static int pty_chars_in_buffer(struct tty_struct *tty) { - if (tty->link) - pty_copy(tty,tty->link); + struct tty_struct *to = tty->link; + + if (!to) + return 0; + + return to->ldisc.chars_in_buffer(to); +} + +static void pty_flush_buffer(struct tty_struct *tty) +{ + struct tty_struct *to = tty->link; + + if (!to) + return; + + if (to->ldisc.flush_buffer) + to->ldisc.flush_buffer(to); + + if (to->packet) { + tty->ctrl_status |= TIOCPKT_FLUSHWRITE; + wake_up_interruptible(&to->read_wait); + } } int pty_open(struct tty_struct *tty, struct file * filp) { + int line; + struct pty_struct *pty; + if (!tty || !tty->link) return -ENODEV; - if (IS_A_PTY_SLAVE(tty->line)) + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= NR_PTYS)) + return -ENODEV; + pty = pty_state + line; + tty->driver_data = pty; + + if (tty->driver.subtype == PTY_TYPE_SLAVE) clear_bit(TTY_SLAVE_CLOSED, &tty->link->flags); - tty->write = tty->link->write = pty_write; - tty->close = tty->link->close = pty_close; - wake_up_interruptible(&tty->read_q.proc_list); + wake_up_interruptible(&pty->open_wait); if (filp->f_flags & O_NDELAY) return 0; while (!tty->link->count && !(current->signal & ~current->blocked)) - interruptible_sleep_on(&tty->link->read_q.proc_list); + interruptible_sleep_on(&pty->open_wait); if (!tty->link->count) return -ERESTARTSYS; return 0; } + +long pty_init(long kmem_start) +{ + memset(&pty_state, 0, sizeof(pty_state)); + memset(&pty_driver, 0, sizeof(struct tty_driver)); + pty_driver.magic = TTY_DRIVER_MAGIC; + pty_driver.name = "pty"; + pty_driver.major = TTY_MAJOR; + pty_driver.minor_start = 128; + pty_driver.num = NR_PTYS; + pty_driver.type = TTY_DRIVER_TYPE_PTY; + pty_driver.subtype = PTY_TYPE_MASTER; + pty_driver.init_termios = tty_std_termios; + pty_driver.init_termios.c_iflag = 0; + pty_driver.init_termios.c_oflag = 0; + pty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD; + pty_driver.init_termios.c_lflag = 0; + pty_driver.flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW; + pty_driver.refcount = &pty_refcount; + pty_driver.table = pty_table; + pty_driver.termios = pty_termios; + pty_driver.termios_locked = pty_termios_locked; + pty_driver.other = &pty_slave_driver; + + pty_driver.open = pty_open; + pty_driver.close = pty_close; + pty_driver.write = pty_write; + pty_driver.write_room = pty_write_room; + pty_driver.flush_buffer = pty_flush_buffer; + pty_driver.chars_in_buffer = pty_chars_in_buffer; + + pty_slave_driver = pty_driver; + pty_slave_driver.name = "ttyp"; + pty_slave_driver.subtype = PTY_TYPE_SLAVE; + pty_slave_driver.minor_start = 192; + pty_slave_driver.init_termios = tty_std_termios; + pty_slave_driver.table = ttyp_table; + pty_slave_driver.termios = ttyp_termios; + pty_slave_driver.termios_locked = ttyp_termios_locked; + pty_slave_driver.other = &pty_driver; + + if (tty_register_driver(&pty_driver)) + panic("Couldn't register pty driver\n"); + if (tty_register_driver(&pty_slave_driver)) + panic("Couldn't register pty slave driver\n"); + + return kmem_start; +} + + diff -u --recursive --new-file v1.1.12/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v1.1.12/linux/drivers/char/serial.c Mon Apr 25 10:04:32 1994 +++ linux/drivers/char/serial.c Mon May 23 07:55:13 1994 @@ -21,45 +21,70 @@ #include #include #include +#include #include +#include #include -#include +#include #include #include #include #include #include +#include #include #include #include #include -#undef ISR_HACK +DECLARE_TASK_QUEUE(tq_serial); + +struct tty_driver serial_driver, callout_driver; +static int serial_refcount; + +/* serial subtype definitions */ +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +/* + * Serial driver configuration section. Here are the various options: + * + * CONFIG_HUB6 + * Enables support for the venerable Bell Technologies + * HUB6 card. + * + * SERIAL_PARANOIA_CHECK + * Check the magic number for the async_structure where + * ever possible. + */ + +#define SERIAL_PARANOIA_CHECK +#define CONFIG_SERIAL_NOPAUSE_IO +#define SERIAL_DO_RESTART +#define CONFIG_SERIAL_NEW_ISR +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN + +#define _INLINE_ inline + /* - * rs_event - Bitfield of serial lines that events pending - * to be processed at the next clock tick. * IRQ_timeout - How long the timeout should be for each IRQ * should be after the IRQ has been active. - * IRQ_timer - Array of timeout values for each interrupt IRQ. - * This is based on jiffies; not offsets. - * - * We assume here that int's are 32 bits, so an array of two gives us - * 64 lines, which is the maximum we can support. */ -static int rs_event[2]; static struct async_struct *IRQ_ports[16]; -static int IRQ_active; -static unsigned long IRQ_timer[16]; static int IRQ_timeout[16]; static volatile int rs_irq_triggered; static volatile int rs_triggered; static int rs_wild_int_mask; static void autoconfig(struct async_struct * info); -static void change_speed(unsigned int line); +static void change_speed(struct async_struct *info); /* * This assumes you have a 1.8432 MHz clock for your UART. @@ -70,39 +95,14 @@ */ #define BASE_BAUD ( 1843200 / 16 ) -#ifdef CONFIG_AUTO_IRQ -#define AUTO_IRQ_FLAG ASYNC_AUTO_IRQ -#else -#define AUTO_IRQ_FLAG 0 -#endif - /* Standard COM flags (except for COM4, because of the 8514 problem) */ -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | AUTO_IRQ_FLAG) -#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | AUTO_IRQ_FLAG) - -#ifdef CONFIG_AST_FOURPORT -#define FOURPORT_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_FOURPORT | AUTO_IRQ_FLAG) -#else -#define FOURPORT_FLAGS (ASYNC_FOURPORT | AUTO_IRQ_FLAG) -#endif +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST ) +#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF -#ifdef CONFIG_ACCENT_ASYNC -#define ACCENT_FLAGS (ASYNC_BOOT_AUTOCONF | AUTO_IRQ_FLAG) -#else -#define ACCENT_FLAGS AUTO_IRQ_FLAG -#endif - -#ifdef CONFIG_BOCA -#define BOCA_FLAGS (ASYNC_BOOT_AUTOCONF | AUTO_IRQ_FLAG) -#else -#define BOCA_FLAGS AUTO_IRQ_FLAG -#endif - -#ifdef CONFIG_HUB6 -#define HUB6_FLAGS (ASYNC_BOOT_AUTOCONF) -#else +#define FOURPORT_FLAGS ASYNC_FOURPORT +#define ACCENT_FLAGS 0 +#define BOCA_FLAGS 0 #define HUB6_FLAGS 0 -#endif /* * The following define the access methods for the HUB6 card. All @@ -122,62 +122,91 @@ struct async_struct rs_table[] = { /* UART CLK PORT IRQ FLAGS */ - { BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ - { BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ - { BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ - { BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */ - - { BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, /* ttyS4 */ - { BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS }, /* ttyS5 */ - { BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS }, /* ttyS6 */ - { BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS }, /* ttyS7 */ - - { BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS }, /* ttyS8 */ - { BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS }, /* ttyS9 */ - { BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS }, /* ttyS10 */ - { BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS }, /* ttyS11 */ - - { BASE_BAUD, 0x330, 4, ACCENT_FLAGS }, /* ttyS12 */ - { BASE_BAUD, 0x338, 4, ACCENT_FLAGS }, /* ttyS13 */ - { BASE_BAUD, 0x000, 0, 0 }, /* ttyS14 (spare; user configurable) */ - { BASE_BAUD, 0x000, 0, 0 }, /* ttyS15 (spare; user configurable) */ - - { BASE_BAUD, 0x100, 12, BOCA_FLAGS }, /* ttyS16 */ - { BASE_BAUD, 0x108, 12, BOCA_FLAGS }, /* ttyS17 */ - { BASE_BAUD, 0x110, 12, BOCA_FLAGS }, /* ttyS18 */ - { BASE_BAUD, 0x118, 12, BOCA_FLAGS }, /* ttyS19 */ - { BASE_BAUD, 0x120, 12, BOCA_FLAGS }, /* ttyS20 */ - { BASE_BAUD, 0x128, 12, BOCA_FLAGS }, /* ttyS21 */ - { BASE_BAUD, 0x130, 12, BOCA_FLAGS }, /* ttyS22 */ - { BASE_BAUD, 0x138, 12, BOCA_FLAGS }, /* ttyS23 */ - { BASE_BAUD, 0x140, 12, BOCA_FLAGS }, /* ttyS24 */ - { BASE_BAUD, 0x148, 12, BOCA_FLAGS }, /* ttyS25 */ - { BASE_BAUD, 0x150, 12, BOCA_FLAGS }, /* ttyS26 */ - { BASE_BAUD, 0x158, 12, BOCA_FLAGS }, /* ttyS27 */ - { BASE_BAUD, 0x160, 12, BOCA_FLAGS }, /* ttyS28 */ - { BASE_BAUD, 0x168, 12, BOCA_FLAGS }, /* ttyS29 */ - { BASE_BAUD, 0x170, 12, BOCA_FLAGS }, /* ttyS30 */ - { BASE_BAUD, 0x178, 12, BOCA_FLAGS }, /* ttyS31 */ + { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ + { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ + { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ + { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */ + + { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, /* ttyS4 */ + { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS }, /* ttyS5 */ + { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS }, /* ttyS6 */ + { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS }, /* ttyS7 */ + + { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS }, /* ttyS8 */ + { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS }, /* ttyS9 */ + { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS }, /* ttyS10 */ + { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS }, /* ttyS11 */ + + { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS }, /* ttyS12 */ + { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS }, /* ttyS13 */ + { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS14 (spare; user configurable) */ + { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS15 (spare; user configurable) */ + + { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS }, /* ttyS16 */ + { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS }, /* ttyS17 */ + { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS }, /* ttyS18 */ + { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS }, /* ttyS19 */ + { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS }, /* ttyS20 */ + { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS }, /* ttyS21 */ + { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS }, /* ttyS22 */ + { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS }, /* ttyS23 */ + { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS }, /* ttyS24 */ + { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS }, /* ttyS25 */ + { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS }, /* ttyS26 */ + { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS }, /* ttyS27 */ + { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS }, /* ttyS28 */ + { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS }, /* ttyS29 */ + { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS }, /* ttyS30 */ + { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS }, /* ttyS31 */ /* You can have up to four HUB6's in the system, but I've only * included two cards here for a total of twelve ports. */ - { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) }, /* ttyS32 */ - { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) }, /* ttyS33 */ - { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) }, /* ttyS34 */ - { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) }, /* ttyS35 */ - { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) }, /* ttyS36 */ - { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) }, /* ttyS37 */ - { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) }, /* ttyS32 */ - { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) }, /* ttyS33 */ - { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) }, /* ttyS34 */ - { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) }, /* ttyS35 */ - { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) }, /* ttyS36 */ - { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) }, /* ttyS37 */ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) }, /* ttyS32 */ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) }, /* ttyS33 */ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) }, /* ttyS34 */ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) }, /* ttyS35 */ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) }, /* ttyS36 */ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) }, /* ttyS37 */ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) }, /* ttyS32 */ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) }, /* ttyS33 */ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) }, /* ttyS34 */ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) }, /* ttyS35 */ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) }, /* ttyS36 */ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) }, /* ttyS37 */ }; #define NR_PORTS (sizeof(rs_table)/sizeof(struct async_struct)) +static struct tty_struct *serial_table[NR_PORTS]; +static struct termios *serial_termios[NR_PORTS]; +static struct termios *serial_termios_locked[NR_PORTS]; + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +static inline int serial_paranoia_check(struct async_struct *info, + dev_t device, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for serial struct (%d, %d) in %s\n"; + static const char *badinfo = + "Warning: null async_struct for (%d, %d) in %s\n"; + + if (!info) { + printk(badinfo, MAJOR(device), MINOR(device), routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, MAJOR(device), MINOR(device), routine); + return 1; + } +#endif + return 0; +} + /* * This is used to figure out the divsor speeds and the timeouts */ @@ -185,43 +214,57 @@ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 0 }; -static void rs_throttle(struct tty_struct * tty, int status); - static inline unsigned int serial_in(struct async_struct *info, int offset) { +#ifdef CONFIG_HUB6 if (info->hub6) { outb(info->hub6 - 1 + offset, info->port); return inb(info->port+1); } else +#endif return inb(info->port + offset); } static inline unsigned int serial_inp(struct async_struct *info, int offset) { +#ifdef CONFIG_HUB6 if (info->hub6) { outb(info->hub6 - 1 + offset, info->port); return inb_p(info->port+1); } else +#endif +#ifdef CONFIG_SERIAL_NOPAUSE_IO + return inb(info->port + offset); +#else return inb_p(info->port + offset); +#endif } static inline void serial_out(struct async_struct *info, int offset, int value) { +#ifdef CONFIG_HUB6 if (info->hub6) { outb(info->hub6 - 1 + offset, info->port); outb(value, info->port+1); } else +#endif outb(value, info->port+offset); } static inline void serial_outp(struct async_struct *info, int offset, int value) { +#ifdef CONFIG_HUB6 if (info->hub6) { outb(info->hub6 - 1 + offset, info->port); outb_p(value, info->port+1); } else - outb_p(value, info->port+offset); +#endif +#ifdef CONFIG_SERIAL_NOPAUSE_IO + outb(value, info->port+offset); +#else + outb_p(value, info->port+offset); +#endif } /* @@ -234,33 +277,41 @@ */ static void rs_stop(struct tty_struct *tty) { - struct async_struct *info; - - info = rs_table + DEV_TO_SL(tty->line); + struct async_struct *info = tty->driver_data; + unsigned long flags; + if (serial_paranoia_check(info, tty->device, "rs_stop")) + return; + if (info->flags & ASYNC_CLOSING) { tty->stopped = 0; tty->hw_stopped = 0; return; } - info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; -#ifdef ISR_HACK - serial_out(info, UART_IER, info->IER); -#endif + save_flags(flags); cli(); + if (info->IER & UART_IER_THRI) { + info->IER &= ~UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } + restore_flags(flags); } static void rs_start(struct tty_struct *tty) { - struct async_struct *info; + struct async_struct *info = tty->driver_data; + unsigned long flags; - info = rs_table + DEV_TO_SL(tty->line); + if (serial_paranoia_check(info, tty->device, "rs_start")) + return; - info->IER = (UART_IER_MSI | UART_IER_RLSI | - UART_IER_THRI | UART_IER_RDI); -#ifdef ISR_HACK - serial_out(info, UART_IER, info->IER); -#endif + save_flags(flags); cli(); + if (info->xmit_cnt && !info->xmit_buf && + !(info->IER & UART_IER_THRI)) { + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } + restore_flags(flags); } /* @@ -299,115 +350,107 @@ * This routine is used by the interrupt handler to schedule * processing in the software interrupt portion of the driver. */ -static inline void rs_sched_event(struct async_struct *info, +static _INLINE_ void rs_sched_event(struct async_struct *info, int event) { info->event |= 1 << event; - set_bit(info->line, rs_event); + queue_task_irq_off(&info->tqueue, &tq_serial); mark_bh(SERIAL_BH); } -static inline void receive_chars(struct async_struct *info, +static _INLINE_ void receive_chars(struct async_struct *info, int *status) { - struct tty_queue * queue; - int head, tail, ch; + struct tty_struct *tty = info->tty; + unsigned char ch; -/* - * Just like the LEFT(x) macro, except it uses the loal tail - * and head variables. - */ -#define VLEFT ((tail-head-1)&(TTY_BUF_SIZE-1)) - - queue = &info->tty->read_q; - head = queue->head; - tail = queue->tail; do { ch = serial_inp(info, UART_RX); - /* - * There must be at least 2 characters - * free in the queue; otherwise we punt. - */ - if (VLEFT < 2) + if (*status & info->ignore_status_mask) + continue; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; + tty->flip.count++; if (*status & info->read_status_mask) { - set_bit(head, &info->tty->readq_flags); if (*status & (UART_LSR_BI)) { - queue->buf[head++]= TTY_BREAK; - rs_sched_event(info, RS_EVENT_BREAK); + *tty->flip.flag_buf_ptr++ = TTY_BREAK; + if (info->flags & ASYNC_SAK) + do_SAK(tty); } else if (*status & UART_LSR_PE) - queue->buf[head++]= TTY_PARITY; + *tty->flip.flag_buf_ptr++ = TTY_PARITY; else if (*status & UART_LSR_FE) - queue->buf[head++]= TTY_FRAME; - else if (*status & UART_LSR_OE) - queue->buf[head++]= TTY_OVERRUN; - head &= TTY_BUF_SIZE-1; - } - queue->buf[head++] = ch; - head &= TTY_BUF_SIZE-1; + *tty->flip.flag_buf_ptr++ = TTY_FRAME; + else if (*status & UART_LSR_OE) + *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; + else + *tty->flip.flag_buf_ptr++ = 0; + } else + *tty->flip.flag_buf_ptr++ = 0; + *tty->flip.char_buf_ptr++ = ch; } while ((*status = serial_inp(info, UART_LSR)) & UART_LSR_DR); - queue->head = head; - if ((VLEFT < RQ_THRESHOLD_LW) && !set_bit(TTY_RQ_THROTTLED, - &info->tty->flags)) - rs_throttle(info->tty, TTY_THROTTLE_RQ_FULL); - rs_sched_event(info, RS_EVENT_READ_PROCESS); + queue_task_irq_off(&tty->flip.tqueue, &tq_timer); #ifdef SERIAL_DEBUG_INTR printk("DR..."); #endif } -static inline void transmit_chars(struct async_struct *info, int *done_work) +static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done) { - struct tty_queue * queue; - int head, tail, count; + int count; - queue = &info->tty->write_q; - head = queue->head; - tail = queue->tail; - if (head==tail && !info->x_char) { - info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; -#ifdef ISR_HACK - serial_out(info, UART_IER, info->IER); -#endif - return; - } - count = info->xmit_fifo_size; if (info->x_char) { serial_outp(info, UART_TX, info->x_char); info->x_char = 0; - count--; + if (intr_done) + *intr_done = 0; + return; } - while (count-- && (tail != head)) { - serial_outp(info, UART_TX, queue->buf[tail++]); - tail &= TTY_BUF_SIZE-1; + if (!info->xmit_cnt || info->tty->stopped || info->tty->hw_stopped) { + info->IER &= ~UART_IER_THRI; +#ifdef CONFIG_SERIAL_NEW_ISR + serial_out(info, UART_IER, info->IER); +#endif + return; } - queue->tail = tail; - if (VLEFT > WAKEUP_CHARS) { + + count = info->xmit_fifo_size; + do { + serial_out(info, UART_TX, info->xmit_buf[info->xmit_tail++]); + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + if (--info->xmit_cnt == 0) + break; + } while (--count > 0); + + if (info->xmit_cnt < WAKEUP_CHARS) rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); - if (info->tty->write_data_cnt) { - set_bit(info->tty->line, &tty_check_write); - mark_bh(TTY_BH); - } - } + #ifdef SERIAL_DEBUG_INTR printk("THRE..."); #endif - (*done_work)++; + if (intr_done) + *intr_done = 0; + + if (info->xmit_cnt == 0) { + info->IER &= ~UART_IER_THRI; +#ifdef CONFIG_SERIAL_NEW_ISR + serial_out(info, UART_IER, info->IER); +#endif + } } -static inline int check_modem_status(struct async_struct *info) +static _INLINE_ void check_modem_status(struct async_struct *info) { int status; status = serial_in(info, UART_MSR); - - if ((status & UART_MSR_DDCD) && !C_CLOCAL(info->tty)) { + + if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) printk("ttys%d CD now %s...", info->line, (status & UART_MSR_DCD) ? "on" : "off"); #endif if (status & UART_MSR_DCD) - rs_sched_event(info, RS_EVENT_OPEN_WAKEUP); + wake_up_interruptible(&info->open_wait); else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && (info->flags & ASYNC_CALLOUT_NOHUP))) { #ifdef SERIAL_DEBUG_OPEN @@ -416,15 +459,19 @@ rs_sched_event(info, RS_EVENT_HANGUP); } } - if (C_CRTSCTS(info->tty) && !(info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CTS_FLOW) { if (info->tty->hw_stopped) { if (status & UART_MSR_CTS) { #ifdef SERIAL_DEBUG_INTR printk("CTS tx start..."); #endif info->tty->hw_stopped = 0; - rs_start(info->tty); - return 1; + info->IER |= UART_IER_THRI; +#ifdef CONFIG_SERIAL_NEW_ISR + serial_out(info, UART_IER, info->IER); +#endif + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + return; } } else { if (!(status & UART_MSR_CTS)) { @@ -432,30 +479,91 @@ printk("CTS tx stop..."); #endif info->tty->hw_stopped = 1; - rs_stop(info->tty); + info->IER &= ~UART_IER_THRI; +#ifdef CONFIG_SERIAL_NEW_ISR + serial_out(info, UART_IER, info->IER); +#endif } } } - return 0; } -static inline void figure_RS_timer(void) +#ifdef CONFIG_SERIAL_NEW_ISR +/* + * This is the serial driver's generic interrupt routine + */ +static void rs_interrupt(int irq) { - int timeout = jiffies + 60*HZ; /* 60 seconds; really big :-) */ - int i, mask; - - if (!IRQ_active) + int status; + struct async_struct * info; + int pass_counter = 0; + struct async_struct *end_mark = 0; + + info = IRQ_ports[irq]; + if (!info) return; - for (i=0, mask = 1; mask <= IRQ_active; i++, mask <<= 1) { - if (!(mask & IRQ_active)) + + do { + if (!info->tty || + (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) { + if (!end_mark) + end_mark = info; + goto next; + } + end_mark = 0; + + status = serial_inp(info, UART_LSR); + if (status & UART_LSR_DR) + receive_chars(info, &status); + check_modem_status(info); + if (status & UART_LSR_THRE) + transmit_chars(info, 0); + + next: + info = info->next_port; + if (!info) { + info = IRQ_ports[irq]; + if (pass_counter++ > 64) { +#if 0 + printk("rs loop break\n"); +#endif + break; /* Prevent infinite loops */ + } continue; - if (IRQ_timer[i] < timeout) - timeout = IRQ_timer[i]; - } - timer_table[RS_TIMER].expires = timeout; - timer_active |= 1 << RS_TIMER; + } + } while (end_mark != info); +} + +/* + * This is the serial driver's interrupt routine for a single port + */ +static void rs_interrupt_single(int irq) +{ + int status; + int pass_counter = 0; + struct async_struct * info; + + info = IRQ_ports[irq]; + if (!info || !info->tty) + return; + + do { + status = serial_inp(info, UART_LSR); + if (status & UART_LSR_DR) + receive_chars(info, &status); + check_modem_status(info); + if (status & UART_LSR_THRE) + transmit_chars(info, 0); + if (pass_counter++ > 64) { +#if 0 + printk("rs_single loop break.\n"); +#endif + break; + } + } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT)); } +#else /* CONFIG_SERIAL_NEW_ISR */ /* * This is the serial driver's generic interrupt routine @@ -464,94 +572,84 @@ { int status; struct async_struct * info; - int done, done_work, pass_number, recheck_count; + int done = 1, pass_counter = 0; - rs_irq_triggered = irq; - rs_triggered |= 1 << irq; - info = IRQ_ports[irq]; - done = 1; - done_work = 0; - pass_number = 0; - while (info) { - if (info->tty && - info->tty->termios && - (!pass_number || - !(serial_inp(info, UART_IIR) & UART_IIR_NO_INT))) { + if (!info) + return; + + while (1) { + if (!info->tty) + goto next; + + serial_outp(info, UART_IER, 0); + status = serial_inp(info, UART_LSR); + if (status & UART_LSR_DR) { + receive_chars(info, &status); done = 0; - status = serial_inp(info, UART_LSR); - if (status & UART_LSR_DR) { - receive_chars(info, &status); - done_work++; - } - recheck_count = 0; - recheck_write: - if (status & UART_LSR_THRE) { - wake_up_interruptible(&info->xmit_wait); - if (!info->tty->stopped && - !info->tty->hw_stopped) - transmit_chars(info, &done_work); - } - if (check_modem_status(info) && - (recheck_count++ <= 64)) - goto recheck_write; -#ifdef SERIAL_DEBUG_INTR - if (recheck_count > 16) - printk("recheck_count = %d\n", recheck_count); -#endif } -#ifdef ISR_HACK - serial_outp(info, UART_IER, 0); - serial_out(info, UART_IER, info->IER); -#endif - - info = info->next_port; - if (!info && !done) { + check_modem_status(info); + if (status & UART_LSR_THRE) + transmit_chars(info, &done); + + next: + info = info->next_port; + if (!info) { info = IRQ_ports[irq]; + if (done) + break; done = 1; - if (pass_number++ > 64) - break; /* Prevent infinite loops */ + if (pass_counter++ > 64) { +#if 0 + printk("rs loop break\n"); +#endif + break; /* Prevent infinite loops */ + } } } - if ((info = IRQ_ports[irq]) != NULL) { -#ifdef 0 - do { - serial_outp(info, UART_IER, 0); - serial_out(info, UART_IER, info->IER); - info = info->next_port; - } while (info); -#endif - if (irq && !done_work) - IRQ_timer[irq] = jiffies + 1500; - else - IRQ_timer[irq] = jiffies + IRQ_timeout[irq]; - IRQ_active |= 1 << irq; - } - figure_RS_timer(); + + /* + * Reset the IER registers; info is already set up from the + * above while loop. + */ + do + serial_outp(info, UART_IER, info->IER); + while ((info = info->next_port) != NULL); } /* - * ------------------------------------------------------------------- - * Here ends the serial interrupt routines. - * ------------------------------------------------------------------- + * This is the serial driver's interrupt routine for a single port */ +static void rs_interrupt_single(int irq) +{ + int status; + struct async_struct * info; + + info = IRQ_ports[irq]; + if (!info || !info->tty) + return; + + serial_outp(info, UART_IER, 0); + status = serial_inp(info, UART_LSR); + if (status & UART_LSR_DR) + receive_chars(info, &status); + check_modem_status(info); + if (status & UART_LSR_THRE) + transmit_chars(info, 0); + + /* + * Reset the IER register + */ + serial_outp(info, UART_IER, info->IER); +} +#endif /* CONFIG_SERIAL_NEW_ISR */ + /* - * This routine is called when we receive a break on a serial line. - * It is executed out of the software interrupt routine. + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- */ -static inline void handle_rs_break(struct async_struct *info) -{ - if (info->flags & ASYNC_SAK) - do_SAK(info->tty); - - if (!I_IGNBRK(info->tty) && I_BRKINT(info->tty)) { - flush_input(info->tty); - flush_output(info->tty); - if (info->tty->pgrp > 0) - kill_pg(info->tty->pgrp, SIGINT,1); - } -} /* * This routine is used to handle the "bottom half" processing for the @@ -562,65 +660,49 @@ * interrupt driver proper are done; the interrupt driver schedules * them using rs_sched_event(), and they get done here. */ -static void do_softint(void *unused) +static void do_serial_bh(void *unused) { - int i; - struct async_struct *info; + run_task_queue(&tq_serial); +} + +static void do_softint(void *private) +{ + struct async_struct *info = (struct async_struct *) private; + struct tty_struct *tty; - for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) { - if (clear_bit(i, rs_event)) { - if (!info->tty) - continue; - if (clear_bit(RS_EVENT_READ_PROCESS, &info->event)) { - TTY_READ_FLUSH(info->tty); - } - if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { - wake_up_interruptible(&info->tty->write_q.proc_list); - } - if (clear_bit(RS_EVENT_HANGUP, &info->event)) { - tty_hangup(info->tty); - wake_up_interruptible(&info->open_wait); - info->flags &= ~(ASYNC_NORMAL_ACTIVE| - ASYNC_CALLOUT_ACTIVE); - } - if (clear_bit(RS_EVENT_BREAK, &info->event)) - handle_rs_break(info); - if (clear_bit(RS_EVENT_OPEN_WAKEUP, &info->event)) { - wake_up_interruptible(&info->open_wait); - } - } + tty = info->tty; + if (!tty) + return; + + if (clear_bit(RS_EVENT_HANGUP, &info->event)) { + tty_hangup(tty); + wake_up_interruptible(&info->open_wait); + info->flags &= ~(ASYNC_NORMAL_ACTIVE| + ASYNC_CALLOUT_ACTIVE); } + if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } } /* * This subroutine is called when the RS_TIMER goes off. It is used - * by the serial driver to run the rs_interrupt routine at certain - * intervals, either because a serial interrupt might have been lost, - * or because (in the case of IRQ=0) the serial port does not have an - * interrupt, and is being checked only via the timer interrupts. + * by the serial driver to handle ports that do not have an interrupt + * (irq=0). This doesn't work very well for 16450's, but gives bearly + * passable results for a 16550A. (Although at the expense of much + * CPU overhead). */ static void rs_timer(void) { - int i, mask; - int timeout = 0; + if (IRQ_ports[0]) { + cli(); + rs_interrupt(0); + sti(); - for (i = 0, mask = 1; mask <= IRQ_active; i++, mask <<= 1) { - if ((mask & IRQ_active) && (IRQ_timer[i] <= jiffies)) { - IRQ_active &= ~mask; - cli(); -#ifdef SERIAL_DEBUG_TIMER - printk("rs_timer: rs_interrupt(%d)...", i); -#endif - rs_interrupt(i); - sti(); - } - if (mask & IRQ_active) { - if (!timeout || (IRQ_timer[i] < timeout)) - timeout = IRQ_timer[i]; - } - } - if (timeout) { - timer_table[RS_TIMER].expires = timeout; + timer_table[RS_TIMER].expires = jiffies + IRQ_timeout[0] - 2; timer_active |= 1 << RS_TIMER; } } @@ -697,12 +779,12 @@ IRQ_timeout[irq] = timeout ? timeout : 1; } -static int startup(struct async_struct * info, int get_irq) +static int startup(struct async_struct * info) { unsigned short ICP; unsigned long flags; - struct sigaction sa; int retval; + struct sigaction sa; if (info->flags & ASYNC_INITIALIZED) return 0; @@ -713,6 +795,12 @@ return 0; } + if (!info->xmit_buf) { + info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL); + if (!info->xmit_buf) + return ENOMEM; + } + save_flags(flags); cli(); #ifdef SERIAL_DEBUG_OPEN @@ -720,10 +808,37 @@ #endif /* + * Clear the FIFO buffers and disable them + * (they will be reenabled in change_speed()) + */ + if (info->type == PORT_16550A) { + serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT)); + info->xmit_fifo_size = 16; + } else + info->xmit_fifo_size = 1; + + /* + * At this point there's no way the LSR could still be 0xFF; + * if it is, then bail out, because there's likely no UART + * here. + */ + if (serial_inp(info, UART_LSR) == 0xff) { + restore_flags(flags); + return -ENODEV; + } + + /* * Allocate the IRQ if necessary */ - if (get_irq && info->irq && !IRQ_ports[info->irq]) { - sa.sa_handler = rs_interrupt; + if (info->irq && (!IRQ_ports[info->irq] || + !IRQ_ports[info->irq]->next_port)) { + if (IRQ_ports[info->irq]) { + free_irq(info->irq); + sa.sa_handler = rs_interrupt; + } else + sa.sa_handler = rs_interrupt_single; + sa.sa_flags = (SA_INTERRUPT); sa.sa_mask = 0; sa.sa_restorer = NULL; @@ -735,45 +850,32 @@ } /* - * Clear the FIFO buffers and disable them - * (they will be reenabled in change_speed()) - */ - if (info->type == PORT_16550A) { - serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT)); - info->xmit_fifo_size = 16; - } else - info->xmit_fifo_size = 1; - - /* * Clear the interrupt registers. */ - (void)serial_inp(info, UART_LSR); - (void)serial_inp(info, UART_RX); - (void)serial_inp(info, UART_IIR); - (void)serial_inp(info, UART_MSR); + /* (void) serial_inp(info, UART_LSR); */ /* (see above) */ + (void) serial_inp(info, UART_RX); + (void) serial_inp(info, UART_IIR); + (void) serial_inp(info, UART_MSR); /* * Now, initialize the UART */ serial_outp(info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ - if (info->flags & ASYNC_FOURPORT) - serial_outp(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); - else - serial_outp(info, UART_MCR, - UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); + if (info->flags & ASYNC_FOURPORT) { + info->MCR = UART_MCR_DTR | UART_MCR_RTS; + info->MCR_noint = UART_MCR_DTR | UART_MCR_OUT1; + } else { + info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; + info->MCR_noint = UART_MCR_DTR | UART_MCR_RTS; + } + serial_outp(info, UART_MCR, info->MCR); /* * Finally, enable interrupts */ -#ifdef ISR_HACK info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; serial_outp(info, UART_IER, info->IER); /* enable interrupts */ -#else - info->IER = (UART_IER_MSI | UART_IER_RLSI | - UART_IER_THRI | UART_IER_RDI); - serial_outp(info, UART_IER, info->IER); /* enable all intrs */ -#endif + if (info->flags & ASYNC_FOURPORT) { /* Enable interrupts on the AST Fourport board */ ICP = (info->port & 0xFE0) | 0x01F; @@ -791,15 +893,7 @@ if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); - /* - * Set up parity check flag - */ - if (info->tty && info->tty->termios && I_INPCK(info->tty)) - info->read_status_mask = (UART_LSR_OE | UART_LSR_BI | - UART_LSR_FE | UART_LSR_PE); - else - info->read_status_mask = (UART_LSR_OE | UART_LSR_BI | - UART_LSR_FE); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; /* * Insert serial port into IRQ chain. @@ -814,13 +908,15 @@ /* * Set up serial timers... */ - IRQ_active |= 1 << info->irq; - figure_RS_timer(); + if (info->irq == 0) { + timer_table[RS_TIMER].expires = jiffies + IRQ_timeout[0]; + timer_active |= 1 << RS_TIMER; + } /* * and set the speed of the serial port */ - change_speed(info->line); + change_speed(info); info->flags |= ASYNC_INITIALIZED; restore_flags(flags); @@ -831,9 +927,12 @@ * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */ -static void shutdown(struct async_struct * info, int do_free_irq) +static void shutdown(struct async_struct * info) { - unsigned long flags; + struct sigaction sa; + unsigned long flags; + unsigned long timeout; + int retval; if (!(info->flags & ASYNC_INITIALIZED)) return; @@ -859,20 +958,58 @@ /* * Free the IRQ, if necessary */ - if (do_free_irq && info->irq && !IRQ_ports[info->irq]) - free_irq(info->irq); - + if (info->irq && (!IRQ_ports[info->irq] || + !IRQ_ports[info->irq]->next_port)) { + if (IRQ_ports[info->irq]) { + free_irq(info->irq); + sa.sa_flags = (SA_INTERRUPT); + sa.sa_mask = 0; + sa.sa_restorer = NULL; + sa.sa_handler = rs_interrupt_single; + retval = irqaction(info->irq, &sa); + + if (retval) + printk("serial shutdown: irqaction: error %d" + " Couldn't reacquire IRQ.\n", retval); + } else + free_irq(info->irq); + } + + if (info->xmit_buf) { + free_page((unsigned long) info->xmit_buf); + info->xmit_buf = 0; + } + info->IER = 0; serial_outp(info, UART_IER, 0x00); /* disable all intrs */ if (info->flags & ASYNC_FOURPORT) { /* reset interrupts on the AST Fourport board */ (void) inb((info->port & 0xFE0) | 0x01F); } - if (info->tty && !(info->tty->termios->c_cflag & HUPCL)) - serial_outp(info, UART_MCR, UART_MCR_DTR); - else - /* reset DTR,RTS,OUT_2 */ - serial_outp(info, UART_MCR, 0x00); + + /* + * Bebore we drop DTR, make sure the UART transmitter has + * completely drained; this is especially important if there + * is a transmit FIFO! + * + * We busy loop here, which is not great; unfortunately the + * UART does not provide an interrupt for TEMT, and putting it + * in the interrupt handler would slow down normal accesses + * anyway. + */ + sti(); + timeout = jiffies + info->timeout; + while (!(serial_inp(info, UART_LSR) & UART_LSR_TEMT)) { + if (jiffies > timeout) + break; + } + cli(); + + if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { + info->MCR &= ~UART_MCR_DTR; + info->MCR_noint &= ~UART_MCR_DTR; + } + serial_outp(info, UART_MCR, info->MCR_noint); /* disable FIFO's */ serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR | @@ -890,17 +1027,13 @@ * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ -static void change_speed(unsigned int line) +static void change_speed(struct async_struct *info) { - struct async_struct * info; unsigned short port; int quot = 0; - unsigned cflag,cval,mcr,fcr; + unsigned cflag,cval,fcr; int i; - if (line >= NR_PORTS) - return; - info = rs_table + line; if (!info->tty || !info->tty->termios) return; cflag = info->tty->termios->c_cflag; @@ -928,16 +1061,20 @@ quot = 0; info->timeout = 0; } - cli(); - mcr = serial_in(info, UART_MCR); if (quot) { - serial_out(info, UART_MCR, mcr | UART_MCR_DTR); + info->MCR |= UART_MCR_DTR; + info->MCR_noint |= UART_MCR_DTR; + cli(); + serial_out(info, UART_MCR, info->MCR); + sti(); } else { - serial_out(info, UART_MCR, mcr & ~UART_MCR_DTR); + info->MCR &= ~UART_MCR_DTR; + info->MCR_noint &= ~UART_MCR_DTR; + cli(); + serial_out(info, UART_MCR, info->MCR); sti(); return; } - sti(); /* byte size and parity */ cval = cflag & (CSIZE | CSTOPB); cval >>= 4; @@ -953,6 +1090,38 @@ } else fcr = 0; + /* CTS flow control flag */ + if (cflag & CRTSCTS) + info->flags |= ASYNC_CTS_FLOW; + else + info->flags &= ~ASYNC_CTS_FLOW; + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else + info->flags |= ASYNC_CHECK_CD; + + /* + * Set up parity check flag + */ + info->read_status_mask = UART_LSR_OE; + if (I_INPCK(info->tty)) + info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + info->read_status_mask |= UART_LSR_BI; + + info->ignore_status_mask = 0; + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (I_IGNBRK(info->tty)) { + info->ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= UART_LSR_OE; + } + cli(); serial_outp(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ serial_outp(info, UART_DLL, quot & 0xff); /* LS of divisor */ @@ -962,70 +1131,115 @@ sti(); } -/* - * ------------------------------------------------------------ - * rs_write() and friends - * ------------------------------------------------------------ - */ +static void rs_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct async_struct *info = tty->driver_data; -/* - * This routine is used by rs_write to restart transmitter interrupts, - * which are disabled after we have a transmitter interrupt which went - * unacknowledged because we had run out of data to transmit. - * - * Note: this subroutine must be called with the interrupts *off* - */ -static inline void restart_port(struct async_struct *info) + if (serial_paranoia_check(info, tty->device, "rs_put_char")) + return; + + if (!tty || tty->stopped || tty->hw_stopped || !info->xmit_buf) + return; + + if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) + return; + + info->xmit_buf[info->xmit_head++] = ch; + info->xmit_head &= SERIAL_XMIT_SIZE-1; + info->xmit_cnt++; +} + +static void rs_flush_chars(struct tty_struct *tty) { - struct tty_queue * queue; - int head, tail, count; - - if (!info) + struct async_struct *info = tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) return; - if (serial_inp(info, UART_LSR) & UART_LSR_THRE) { - if (info->x_char) { - serial_outp(info, UART_TX, info->x_char); - info->x_char = 0; - } else { - queue = &info->tty->write_q; - head = queue->head; - tail = queue->tail; - count = info->xmit_fifo_size; - while (count--) { - if (tail == head) - break; - serial_outp(info, UART_TX, queue->buf[tail++]); - tail &= TTY_BUF_SIZE-1; - } - queue->tail = tail; - } + if (info->xmit_cnt == 0 || tty->stopped || tty->hw_stopped || + !info->xmit_buf) + return; + + save_flags(flags); cli(); + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + restore_flags(flags); +} + +static int rs_write(struct tty_struct * tty, int from_user, + unsigned char *buf, int count) +{ + int c, total = 0; + struct async_struct *info = tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_write")) + return 0; + + if (!tty || !info->xmit_buf) + return 0; + + while (1) { + c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (!c) + break; + + if (from_user) + memcpy_fromfs(info->xmit_buf + info->xmit_head, + buf, c); + else + memcpy(info->xmit_buf + info->xmit_head, buf, c); + info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + cli(); + info->xmit_cnt += c; + sti(); + buf += c; + count -= c; + total += c; } -} + save_flags(flags); cli(); + if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped && + !(info->IER & UART_IER_THRI)) { + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } + restore_flags(flags); + return total; +} -/* - * This routine gets called when tty_write has put something into - * the write_queue. - */ -void rs_write(struct tty_struct * tty) +static int rs_write_room(struct tty_struct *tty) { - struct async_struct *info; + struct async_struct *info = tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_write_room")) + return 0; + return SERIAL_XMIT_SIZE - info->xmit_cnt - 1; +} + +static int rs_chars_in_buffer(struct tty_struct *tty) +{ + struct async_struct *info = tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer")) + return 0; + return info->xmit_cnt; +} - if (!tty || tty->stopped || tty->hw_stopped) +static void rs_flush_buffer(struct tty_struct *tty) +{ + struct async_struct *info = tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) return; - info = rs_table + DEV_TO_SL(tty->line); cli(); - if (!info || !info->tty || !(info->flags & ASYNC_INITIALIZED)) { - sti(); - return; - } - restart_port(info); - info->IER = (UART_IER_MSI | UART_IER_RLSI | - UART_IER_THRI | UART_IER_RDI); -#ifdef ISR_HACK - serial_out(info, UART_IER, info->IER); -#endif + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; sti(); + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); } /* @@ -1033,47 +1247,56 @@ * rs_throttle() * * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled (and that the throttle - * should be released). + * incoming characters should be throttled. * ------------------------------------------------------------ */ -static void rs_throttle(struct tty_struct * tty, int status) +static void rs_throttle(struct tty_struct * tty) { - struct async_struct *info; - unsigned char mcr; - unsigned long flags; + struct async_struct *info = tty->driver_data; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %d....\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif - save_flags(flags); cli(); -#if SERIAL_DEBUG_THROTTLE - printk("throttle tty%d: %d (%d, %d)....\n", DEV_TO_SL(tty->line), - status, LEFT(&tty->read_q), LEFT(&tty->secondary)); -#endif - switch (status) { - case TTY_THROTTLE_RQ_FULL: - info = rs_table + DEV_TO_SL(tty->line); - if (I_IXOFF(tty)) { - info->x_char = STOP_CHAR(tty); - } else { - mcr = serial_inp(info, UART_MCR); - mcr &= ~UART_MCR_RTS; - serial_out(info, UART_MCR, mcr); - } - break; - case TTY_THROTTLE_RQ_AVAIL: - info = rs_table + DEV_TO_SL(tty->line); - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - info->x_char = START_CHAR(tty); - } else { - mcr = serial_in(info, UART_MCR); - mcr |= UART_MCR_RTS; - serial_out(info, UART_MCR, mcr); - } - break; + if (serial_paranoia_check(info, tty->device, "rs_throttle")) + return; + + if (I_IXOFF(tty)) + info->x_char = STOP_CHAR(tty); + + info->MCR &= ~UART_MCR_RTS; + info->MCR_noint &= ~UART_MCR_RTS; + cli(); + serial_out(info, UART_MCR, info->MCR); + sti(); +} + +static void rs_unthrottle(struct tty_struct * tty) +{ + struct async_struct *info = tty->driver_data; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("unthrottle %s: %d....\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_unthrottle")) + return; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + info->x_char = START_CHAR(tty); } - restore_flags(flags); + info->MCR |= UART_MCR_RTS; + info->MCR_noint |= UART_MCR_RTS; + cli(); + serial_out(info, UART_MCR, info->MCR); + sti(); } /* @@ -1109,8 +1332,7 @@ struct serial_struct new_serial; struct async_struct old_info; unsigned int i,change_irq,change_port; - int retval; - struct sigaction sa; + int retval = 0; if (!new_info) return -EFAULT; @@ -1148,24 +1370,6 @@ (rs_table[i].port == new_serial.port) && rs_table[i].type) return -EADDRINUSE; - /* - * If necessary, first we try to grab the new IRQ for serial - * interrupts. (We have to do this early, since we may get an - * error trying to do this.) - */ - if (new_serial.port && new_serial.type && new_serial.irq && - (change_irq || !(info->flags & ASYNC_INITIALIZED))) { - if (!IRQ_ports[new_serial.irq]) { - sa.sa_handler = rs_interrupt; - sa.sa_flags = (SA_INTERRUPT); - sa.sa_mask = 0; - sa.sa_restorer = NULL; - retval = irqaction(new_serial.irq,&sa); - if (retval) - return retval; - } - } - if ((change_port || change_irq) && (info->count > 1)) return -EBUSY; @@ -1186,7 +1390,7 @@ * We need to shutdown the serial port at the old * port/irq combination. */ - shutdown(info, change_irq); + shutdown(info); info->irq = new_serial.irq; info->port = new_serial.port; info->hub6 = new_serial.hub6; @@ -1199,10 +1403,10 @@ if (((old_info.flags & ASYNC_SPD_MASK) != (info->flags & ASYNC_SPD_MASK)) || (old_info.custom_divisor != info->custom_divisor)) - change_speed(info->line); + change_speed(info); } else - (void) startup(info, 0); - return 0; + retval = startup(info); + return retval; } static int get_modem_info(struct async_struct * info, unsigned int *value) @@ -1210,8 +1414,8 @@ unsigned char control, status; unsigned int result; + control = info->MCR; cli(); - control = serial_in(info, UART_MCR); status = serial_in(info, UART_MSR); sti(); result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) @@ -1227,36 +1431,43 @@ static int set_modem_info(struct async_struct * info, unsigned int cmd, unsigned int *value) { - unsigned char control; unsigned int arg = get_fs_long((unsigned long *) value); - - cli(); - control = serial_in(info, UART_MCR); - sti(); switch (cmd) { - case TIOCMBIS: - if (arg & TIOCM_RTS) - control |= UART_MCR_RTS; - if (arg & TIOCM_DTR) - control |= UART_MCR_DTR; - break; - case TIOCMBIC: - if (arg & TIOCM_RTS) - control &= ~UART_MCR_RTS; - if (arg & TIOCM_DTR) - control &= ~UART_MCR_DTR; - break; - case TIOCMSET: - control = (control & ~(UART_MCR_RTS | UART_MCR_DTR)) - | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) - | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0); - break; - default: - return -EINVAL; + case TIOCMBIS: + if (arg & TIOCM_RTS) { + info->MCR |= UART_MCR_RTS; + info->MCR_noint |= UART_MCR_RTS; + } + if (arg & TIOCM_DTR) { + info->MCR |= UART_MCR_DTR; + info->MCR_noint |= UART_MCR_DTR; + } + break; + case TIOCMBIC: + if (arg & TIOCM_RTS) { + info->MCR &= ~UART_MCR_RTS; + info->MCR_noint &= ~UART_MCR_RTS; + } + if (arg & TIOCM_DTR) { + info->MCR &= ~UART_MCR_DTR; + info->MCR_noint &= ~UART_MCR_DTR; + } + break; + case TIOCMSET: + info->MCR = ((info->MCR & ~(UART_MCR_RTS | UART_MCR_DTR)) + | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) + | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); + info->MCR_noint = ((info->MCR_noint + & ~(UART_MCR_RTS | UART_MCR_DTR)) + | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) + | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); + break; + default: + return -EINVAL; } cli(); - serial_out(info, UART_MCR, control); + serial_out(info, UART_MCR, info->MCR); sti(); return 0; } @@ -1271,13 +1482,13 @@ if (info->count > 1) return -EBUSY; - shutdown(info, 1); + shutdown(info); cli(); autoconfig(info); sti(); - retval = startup(info, 1); + retval = startup(info); if (retval) return retval; return 0; @@ -1347,20 +1558,27 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { - int error, line; - struct async_struct * info; + int error; + struct async_struct * info = tty->driver_data; + int retval; - line = DEV_TO_SL(tty->line); - if (line < 0 || line >= NR_PORTS) + if (serial_paranoia_check(info, tty->device, "rs_ioctl")) return -ENODEV; - info = rs_table + line; switch (cmd) { case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change(tty); + if (retval) + return retval; + wait_until_sent(tty, 0); if (!arg) send_break(info, HZ/4); /* 1/4 second */ return 0; case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return retval; + wait_until_sent(tty, 0); send_break(info, arg ? arg*(HZ/10) : HZ/4); return 0; case TIOCGSOFTCAR: @@ -1416,38 +1634,29 @@ return 0; default: - return -EINVAL; + return -ENOIOCTLCMD; } return 0; } static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) { - struct async_struct *info; + struct async_struct *info = tty->driver_data; if (tty->termios->c_cflag == old_termios->c_cflag) return; - info = &rs_table[DEV_TO_SL(tty->line)]; + change_speed(info); - change_speed(DEV_TO_SL(tty->line)); - if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { tty->hw_stopped = 0; - rs_write(tty); + rs_start(tty); } if (!(old_termios->c_cflag & CLOCAL) && (tty->termios->c_cflag & CLOCAL)) wake_up_interruptible(&info->open_wait); - - if (I_INPCK(tty)) - info->read_status_mask = (UART_LSR_OE | UART_LSR_BI | - UART_LSR_FE | UART_LSR_PE); - else - info->read_status_mask = (UART_LSR_OE | UART_LSR_BI | - UART_LSR_FE); } /* @@ -1462,16 +1671,14 @@ */ static void rs_close(struct tty_struct *tty, struct file * filp) { - struct async_struct * info; - int line; + struct async_struct * info = tty->driver_data; - if (tty_hung_up_p(filp)) + if (!info || serial_paranoia_check(info, tty->device, "rs_close")) return; - line = DEV_TO_SL(tty->line); - if ((line < 0) || (line >= NR_PORTS)) + if (tty_hung_up_p(filp)) return; - info = rs_table + line; + #ifdef SERIAL_DEBUG_OPEN printk("rs_close ttys%d, count = %d\n", info->line, info->count); #endif @@ -1495,6 +1702,7 @@ if (info->count) return; info->flags |= ASYNC_CLOSING; + info->flags &= ~ASYNC_CTS_FLOW; /* * Save the termios structure, since this port may have * separate termios for callout and dialin. @@ -1508,23 +1716,22 @@ if (info->flags & ASYNC_INITIALIZED) { rs_start(tty); wait_until_sent(tty, 6000); /* 60 seconds timeout */ - } else - flush_output(tty); - flush_input(tty); - cli(); - /* - * Make sure the UART transmitter has completely drained; this - * is especially important if there is a transmit FIFO! - */ - if (!(serial_inp(info, UART_LSR) & UART_LSR_THRE)) { - rs_start(tty); /* Make sure THRI interrupt enabled */ - interruptible_sleep_on(&info->xmit_wait); } - sti(); - shutdown(info, 1); - clear_bit(line, rs_event); + shutdown(info); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); info->event = 0; info->tty = 0; + if (tty->ldisc.num != ldiscs[N_TTY].num) { + if (tty->ldisc.close) + (tty->ldisc.close)(tty); + tty->ldisc = ldiscs[N_TTY]; + tty->termios->c_line = N_TTY; + if (tty->ldisc.open) + (tty->ldisc.open)(tty); + } if (info->blocked_open) { if (info->close_delay) { tty->count++; /* avoid race condition */ @@ -1545,16 +1752,12 @@ */ void rs_hangup(struct tty_struct *tty) { - struct async_struct * info; - int line; - - line = DEV_TO_SL(tty->line); - if ((line < 0) || (line >= NR_PORTS)) + struct async_struct * info = tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_hangup")) return; - info = rs_table + line; - shutdown(info, 1); - clear_bit(line, rs_event); + shutdown(info); info->event = 0; info->count = 0; info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); @@ -1594,7 +1797,7 @@ * If this is a callout device, then just make sure the normal * device isn't being used. */ - if (MAJOR(filp->f_rdev) == TTYAUX_MAJOR) { + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { if (info->flags & ASYNC_NORMAL_ACTIVE) return -EBUSY; if ((info->flags & ASYNC_CALLOUT_ACTIVE) && @@ -1649,7 +1852,7 @@ if (info->flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else - retval = -ERESTARTSYS; + retval = -ERESTARTSYS; #else retval = -EAGAIN; #endif @@ -1696,26 +1899,23 @@ struct async_struct *info; int retval, line; - line = DEV_TO_SL(tty->line); + line = MINOR(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= NR_PORTS)) return -ENODEV; info = rs_table + line; + if (serial_paranoia_check(info, tty->device, "rs_open")) + return -ENODEV; + #ifdef SERIAL_DEBUG_OPEN - printk("rs_open ttys%d, count = %d\n", info->line, info->count); + printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, + info->count); #endif info->count++; + tty->driver_data = info; info->tty = tty; - tty->write = rs_write; - tty->close = rs_close; - tty->ioctl = rs_ioctl; - tty->throttle = rs_throttle; - tty->set_termios = rs_set_termios; - tty->stop = rs_stop; - tty->start = rs_start; - tty->hangup = rs_hangup; if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (MAJOR(filp->f_rdev) == TTY_MAJOR) + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = info->normal_termios; else *tty->termios = info->callout_termios; @@ -1723,7 +1923,7 @@ /* * Start up serial port */ - retval = startup(info, 1); + retval = startup(info); if (retval) return retval; @@ -1760,23 +1960,11 @@ */ static void show_serial_version(void) { - printk("Serial driver version 3.99a with"); -#ifdef CONFIG_AST_FOURPORT - printk(" AST_FOURPORT"); -#define SERIAL_OPT -#endif -#ifdef CONFIG_ACCENT_ASYNC - printk(" ACCENT_ASYNC"); -#define SERIAL_OPT -#endif + printk("Serial driver version 4.00 with"); #ifdef CONFIG_HUB6 printk(" HUB-6"); #define SERIAL_OPT #endif -#ifdef CONFIG_AUTO_IRQ - printk (" AUTO_IRQ"); -#define SERIAL_OPT -#endif #ifdef SERIAL_OPT printk(" enabled\n"); #else @@ -1989,11 +2177,9 @@ int i; struct async_struct * info; - memset(&rs_event, 0, sizeof(rs_event)); - bh_base[SERIAL_BH].routine = do_softint; + bh_base[SERIAL_BH].routine = do_serial_bh; timer_table[RS_TIMER].fn = rs_timer; timer_table[RS_TIMER].expires = 0; - IRQ_active = 0; #ifdef CONFIG_AUTO_IRQ rs_wild_int_mask = check_wild_interrupts(1); #endif @@ -2004,7 +2190,58 @@ } show_serial_version(); + + /* Initialize the tty_driver structure */ + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.name = "ttyS"; + serial_driver.major = TTY_MAJOR; + serial_driver.minor_start = 64; + serial_driver.num = NR_PORTS; + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + serial_driver.init_termios = tty_std_termios; + serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW; + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = rs_open; + serial_driver.close = rs_close; + serial_driver.write = rs_write; + serial_driver.put_char = rs_put_char; + serial_driver.flush_chars = rs_flush_chars; + serial_driver.write_room = rs_write_room; + serial_driver.chars_in_buffer = rs_chars_in_buffer; + serial_driver.flush_buffer = rs_flush_buffer; + serial_driver.ioctl = rs_ioctl; + serial_driver.throttle = rs_throttle; + serial_driver.unthrottle = rs_unthrottle; + serial_driver.set_termios = rs_set_termios; + serial_driver.stop = rs_stop; + serial_driver.start = rs_start; + serial_driver.hangup = rs_hangup; + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; + callout_driver.name = "cua"; + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + + if (tty_register_driver(&serial_driver)) + panic("Couldn't register serial driver\n"); + if (tty_register_driver(&callout_driver)) + panic("Couldn't register callout driver\n"); + for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) { + info->magic = SERIAL_MAGIC; info->line = i; info->tty = 0; info->type = PORT_UNKNOWN; @@ -2014,10 +2251,11 @@ info->event = 0; info->count = 0; info->blocked_open = 0; - memset(&info->callout_termios, 0, sizeof(struct termios)); - memset(&info->normal_termios, 0, sizeof(struct termios)); + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->callout_termios =callout_driver.init_termios; + info->normal_termios = serial_driver.init_termios; info->open_wait = 0; - info->xmit_wait = 0; info->close_wait = 0; info->next_port = 0; info->prev_port = 0; diff -u --recursive --new-file v1.1.12/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v1.1.12/linux/drivers/char/tty_io.c Sat May 7 14:54:02 1994 +++ linux/drivers/char/tty_io.c Mon May 23 07:55:14 1994 @@ -43,7 +43,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -59,15 +61,19 @@ #include "vt_kern.h" #define CONSOLE_DEV MKDEV(TTY_MAJOR,0) +#define TTY_DEV MKDEV(TTYAUX_MAJOR,0) -#define MAX_TTYS 256 +#undef TTY_DEBUG_HANGUP -struct tty_struct *tty_table[MAX_TTYS]; -struct termios *tty_termios[MAX_TTYS]; /* We need to keep the termios state */ - /* around, even when a tty is closed */ -struct termios *termios_locked[MAX_TTYS]; /* Bitfield of locked termios flags*/ +#ifdef CONFIG_SELECTION +extern int set_selection(const int arg); +extern int paste_selection(struct tty_struct *tty); +#endif /* CONFIG_SELECTION */ +extern int do_screendump(int arg); + +struct termios tty_std_termios; /* for the benefit of tty drivers */ +struct tty_driver *tty_drivers; /* linked list of tty drivers */ struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */ -int tty_check_write[MAX_TTYS/32]; /* bitfield for the bh handler */ /* * fg_console is the current virtual console, @@ -78,14 +84,63 @@ struct tty_struct * redirect = NULL; struct wait_queue * keypress_wait = NULL; -static void initialize_tty_struct(int line, struct tty_struct *tty); -static void initialize_termios(int line, struct termios *tp); +static void initialize_tty_struct(struct tty_struct *tty); static int tty_read(struct inode *, struct file *, char *, int); static int tty_write(struct inode *, struct file *, char *, int); static int tty_select(struct inode *, struct file *, int, select_table *); static int tty_open(struct inode *, struct file *); static void tty_release(struct inode *, struct file *); +static int tty_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg); +static int tty_fasync(struct inode * inode, struct file * filp, int on); + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * These two routines return the name of tty. tty_name() should NOT + * be used in interrupt drivers, since it's not re-entrant. Use + * _tty_name() instead. + */ +char *_tty_name(struct tty_struct *tty, char *buf) +{ + sprintf(buf, "%s%d", tty->driver.name, + MINOR(tty->device) - tty->driver.minor_start + + tty->driver.name_base); + return buf; +} + +char *tty_name(struct tty_struct *tty) +{ + static char buf[64]; + + return(_tty_name(tty, buf)); +} + +#define TTY_PARANOIA_CHECK + +inline int tty_paranoia_check(struct tty_struct *tty, dev_t device, + const char *routine) +{ +#ifdef TTY_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for tty struct (%d, %d) in %s\n"; + static const char *badtty = + "Warning: null TTY for (%d, %d) in %s\n"; + + if (!tty) { + printk(badtty, MAJOR(device), MINOR(device), routine); + return 1; + } + if (tty->magic != TTY_MAGIC) { + printk(badmagic, MAJOR(device), MINOR(device), routine); + return 1; + } +#endif + return 0; +} int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) { @@ -95,94 +150,102 @@ if (new_ldisc) { ldiscs[disc] = *new_ldisc; ldiscs[disc].flags |= LDISC_FLAG_DEFINED; + ldiscs[disc].num = disc; } else memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc)); return 0; } -void put_tty_queue(unsigned char c, struct tty_queue * queue) +/* Set the discipline of a tty line. */ +static int tty_set_ldisc(struct tty_struct *tty, int ldisc) { - int head; - unsigned long flags; - - save_flags(flags); - cli(); - head = (queue->head + 1) & (TTY_BUF_SIZE-1); - if (head != queue->tail) { - queue->buf[queue->head] = c; - queue->head = head; - } - restore_flags(flags); -} + int retval; + struct tty_ldisc o_ldisc; -int get_tty_queue(struct tty_queue * queue) -{ - int result = -1; - unsigned long flags; + if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS) || + !(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) + return -EINVAL; - save_flags(flags); - cli(); - if (queue->tail != queue->head) { - result = queue->buf[queue->tail]; - INC(queue->tail); + if (tty->ldisc.num == ldisc) + return 0; /* We are already in the desired discipline */ + o_ldisc = tty->ldisc; + + /* Shutdown the current discipline. */ + if (tty->ldisc.close) + (tty->ldisc.close)(tty); + + /* Now set up the new line discipline. */ + tty->ldisc = ldiscs[ldisc]; + tty->termios->c_line = ldisc; + if (tty->ldisc.open) { + retval = (tty->ldisc.open)(tty); + if (!retval) + return 0; + + tty->ldisc = o_ldisc; + tty->termios->c_line = tty->ldisc.num; + if (tty->ldisc.open && tty->ldisc.open(tty)) { + tty->ldisc = ldiscs[N_TTY]; + tty->termios->c_line = N_TTY; + if (tty->ldisc.open) { + int r = tty->ldisc.open(tty); + + if (r) + panic("Couldn't open N_TTY ldisc for " + "%s --- error %d.", + tty_name(tty), r); + } + } + return retval; } - restore_flags(flags); - return result; + return 0; } /* - * This routine copies out a maximum of buflen characters from the - * read_q; it is a convenience for line disciplines so they can grab a - * large block of data without calling get_tty_char directly. It - * returns the number of characters actually read. Return terminates - * if an error character is read from the queue and the return value - * is negated. + * This routine returns a tty driver structure, given a device number */ -int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp, int buflen) +struct tty_driver *get_tty_driver(dev_t device) { - int result = 0; - unsigned char *p = bufp; - unsigned long flags; - int head, tail; - int ok = 1; + int major, minor; + struct tty_driver *p; + + minor = MINOR(device); + major = MAJOR(device); - save_flags(flags); - cli(); - tail = tty->read_q.tail; - head = tty->read_q.head; - while ((result < buflen) && (tail!=head) && ok) { - ok = !clear_bit (tail, &tty->readq_flags); - *p++ = tty->read_q.buf[tail++]; - tail &= TTY_BUF_SIZE-1; - result++; + for (p = tty_drivers; p; p = p->next) { + if (p->major != major) + continue; + if (minor < p->minor_start) + continue; + if (minor >= p->minor_start + p->num) + continue; + return p; } - tty->read_q.tail = tail; - restore_flags(flags); - return (ok) ? result : -result; + return NULL; } - -void tty_write_flush(struct tty_struct * tty) -{ - if (!tty->write || EMPTY(&tty->write_q)) - return; - if (set_bit(TTY_WRITE_BUSY,&tty->flags)) - return; - tty->write(tty); - if (!clear_bit(TTY_WRITE_BUSY,&tty->flags)) - printk("tty_write_flush: bit already cleared\n"); -} - -void tty_read_flush(struct tty_struct * tty) +/* + * If we try to write to, or set the state of, a terminal and we're + * not in the foreground, send a SIGTTOU. If the signal is blocked or + * ignored, go ahead and perform the operation. (POSIX 7.2) + */ +int tty_check_change(struct tty_struct * tty) { - if (!tty || EMPTY(&tty->read_q)) - return; - if (set_bit(TTY_READ_BUSY, &tty->flags)) - return; - ldiscs[tty->disc].handler(tty); - if (!clear_bit(TTY_READ_BUSY, &tty->flags)) - printk("tty_read_flush: bit already cleared\n"); + if (current->tty != tty) + return 0; + if (tty->pgrp <= 0) { + printk("tty_check_change: tty->pgrp <= 0!\n"); + return 0; + } + if (current->pgrp == tty->pgrp) + return 0; + if (is_ignored(SIGTTOU)) + return 0; + if (is_orphaned_pgrp(current->pgrp)) + return -EIO; + (void) kill_pg(current->pgrp,SIGTTOU,1); + return -ERESTARTSYS; } static int hung_up_tty_read(struct inode * inode, struct file * file, char * buf, int count) @@ -220,7 +283,9 @@ tty_ioctl, NULL, /* tty_mmap */ tty_open, - tty_release + tty_release, + NULL, /* tty_fsync */ + tty_fasync }; static struct file_operations hung_up_tty_fops = { @@ -232,7 +297,9 @@ hung_up_tty_ioctl, NULL, /* hung_up_tty_mmap */ NULL, /* hung_up_tty_open */ - tty_release /* hung_up_tty_release */ + tty_release, /* hung_up_tty_release */ + NULL, /* hung_up_tty_fsync */ + NULL /* hung_up_tty_fasync */ }; void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops) @@ -240,43 +307,68 @@ int i; struct file * filp; struct task_struct *p; - int dev; if (!tty) return; - dev = MKDEV(TTY_MAJOR,tty->line); for (filp = first_file, i=0; if_next) { if (!filp->f_count) continue; - if (filp->f_rdev != dev) + if (filp->private_data != tty) continue; if (filp->f_inode && filp->f_inode->i_rdev == CONSOLE_DEV) continue; if (filp->f_op != &tty_fops) continue; + tty_fasync(filp->f_inode, filp, 0); filp->f_op = fops; } - flush_input(tty); - flush_output(tty); - wake_up_interruptible(&tty->secondary.proc_list); + + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + wake_up_interruptible(&tty->read_wait); + + /* + * Shutdown the current line discipline, and reset it to + * N_TTY. + */ + if (tty->ldisc.num != ldiscs[N_TTY].num) { + if (tty->ldisc.close) + (tty->ldisc.close)(tty); + tty->ldisc = ldiscs[N_TTY]; + tty->termios->c_line = N_TTY; + if (tty->ldisc.open) { + i = (tty->ldisc.open)(tty); + if (i) + printk("do_tty_hangup: N_TTY open: error %d\n", + i); + } + } + if (tty->session > 0) { kill_sl(tty->session,SIGHUP,1); kill_sl(tty->session,SIGCONT,1); } + tty->flags = 0; tty->session = 0; tty->pgrp = -1; for_each_task(p) { - if (p->tty == tty->line) - p->tty = -1; + if (p->tty == tty) + p->tty = NULL; } - if (tty->hangup) - (tty->hangup)(tty); + if (tty->driver.hangup) + (tty->driver.hangup)(tty); } void tty_hangup(struct tty_struct * tty) { #ifdef TTY_DEBUG_HANGUP - printk("tty%d hangup...\n", tty->line); + printk("%s hangup...\n", tty_name(tty)); #endif do_tty_hangup(tty, &hung_up_tty_fops); } @@ -284,7 +376,7 @@ void tty_vhangup(struct tty_struct * tty) { #ifdef TTY_DEBUG_HANGUP - printk("tty%d vhangup...\n", tty->line); + printk("%s vhangup...\n", tty_name(tty)); #endif do_tty_hangup(tty, &hung_up_tty_fops); } @@ -306,25 +398,22 @@ */ void disassociate_ctty(int priv) { - struct tty_struct *tty; + struct tty_struct *tty = current->tty; struct task_struct *p; - if (current->tty >= 0) { - tty = tty_table[current->tty]; - if (tty) { - if (tty->pgrp > 0) { - kill_pg(tty->pgrp, SIGHUP, priv); - kill_pg(tty->pgrp, SIGCONT, priv); - } - tty->session = 0; - tty->pgrp = -1; - } else - printk("disassociate_ctty: ctty is NULL?!?"); + if (!tty) + return; + + if (tty->pgrp > 0) { + kill_pg(tty->pgrp, SIGHUP, priv); + kill_pg(tty->pgrp, SIGCONT, priv); } + tty->session = 0; + tty->pgrp = -1; for_each_task(p) if (p->session == current->session) - p->tty = -1; + p->tty = NULL; } /* @@ -516,14 +605,10 @@ if (tty->link && tty->link->packet) { tty->ctrl_status &= ~TIOCPKT_START; tty->ctrl_status |= TIOCPKT_STOP; - wake_up_interruptible(&tty->link->secondary.proc_list); - } - if (tty->stop) - (tty->stop)(tty); - if (IS_A_CONSOLE(tty->line)) { - set_vc_kbd_led(kbd_table + fg_console, VC_SCROLLOCK); - set_leds(); + wake_up_interruptible(&tty->link->read_wait); } + if (tty->driver.stop) + (tty->driver.stop)(tty); } void start_tty(struct tty_struct *tty) @@ -534,627 +619,24 @@ if (tty->link && tty->link->packet) { tty->ctrl_status &= ~TIOCPKT_STOP; tty->ctrl_status |= TIOCPKT_START; - wake_up_interruptible(&tty->link->secondary.proc_list); - } - if (tty->start) - (tty->start)(tty); - TTY_WRITE_FLUSH(tty); - if (IS_A_CONSOLE(tty->line)) { - clr_vc_kbd_led(kbd_table + fg_console, VC_SCROLLOCK); - set_leds(); - } -} - -/* Perform OPOST processing. Returns -1 when the write_q becomes full - and the character must be retried. */ - -static int opost(unsigned char c, struct tty_struct *tty) -{ - if (FULL(&tty->write_q)) - return -1; - if (O_OPOST(tty)) { - switch (c) { - case '\n': - if (O_ONLRET(tty)) - tty->column = 0; - if (O_ONLCR(tty)) { - if (LEFT(&tty->write_q) < 2) - return -1; - put_tty_queue('\r', &tty->write_q); - tty->column = 0; - } - tty->canon_column = tty->column; - break; - case '\r': - if (O_ONOCR(tty) && tty->column == 0) - return 0; - if (O_OCRNL(tty)) { - c = '\n'; - if (O_ONLRET(tty)) - tty->canon_column = tty->column = 0; - break; - } - tty->canon_column = tty->column = 0; - break; - case '\t': - if (O_TABDLY(tty) == XTABS) { - if (LEFT(&tty->write_q) < 8) - return -1; - do - put_tty_queue(' ', &tty->write_q); - while (++tty->column % 8); - return 0; - } - tty->column = (tty->column | 7) + 1; - break; - case '\b': - if (tty->column > 0) - tty->column--; - break; - default: - if (O_OLCUC(tty)) - c = toupper(c); - if (!iscntrl(c)) - tty->column++; - break; - } - } - put_tty_queue(c, &tty->write_q); - return 0; -} - -/* Must be called only when L_ECHO(tty) is true. */ - -static void echo_char(unsigned char c, struct tty_struct *tty) -{ - if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') { - opost('^', tty); - opost(c ^ 0100, tty); - } else - opost(c, tty); -} - -static void eraser(unsigned char c, struct tty_struct *tty) -{ - enum { ERASE, WERASE, KILL } kill_type; - int seen_alnums; - - if (tty->secondary.head == tty->canon_head) { - /* opost('\a', tty); */ /* what do you think? */ - return; - } - if (c == ERASE_CHAR(tty)) - kill_type = ERASE; - else if (c == WERASE_CHAR(tty)) - kill_type = WERASE; - else { - if (!L_ECHO(tty)) { - tty->secondary.head = tty->canon_head; - return; - } - if (!L_ECHOK(tty) || !L_ECHOKE(tty)) { - tty->secondary.head = tty->canon_head; - if (tty->erasing) { - opost('/', tty); - tty->erasing = 0; - } - echo_char(KILL_CHAR(tty), tty); - /* Add a newline if ECHOK is on and ECHOKE is off. */ - if (L_ECHOK(tty)) - opost('\n', tty); - return; - } - kill_type = KILL; - } - - seen_alnums = 0; - while (tty->secondary.head != tty->canon_head) { - c = LAST(&tty->secondary); - if (kill_type == WERASE) { - /* Equivalent to BSD's ALTWERASE. */ - if (isalnum(c) || c == '_') - seen_alnums++; - else if (seen_alnums) - break; - } - DEC(tty->secondary.head); - if (L_ECHO(tty)) { - if (L_ECHOPRT(tty)) { - if (!tty->erasing) { - opost('\\', tty); - tty->erasing = 1; - } - echo_char(c, tty); - } else if (!L_ECHOE(tty)) { - echo_char(ERASE_CHAR(tty), tty); - } else if (c == '\t') { - unsigned int col = tty->canon_column; - unsigned long tail = tty->canon_head; - - /* Find the column of the last char. */ - while (tail != tty->secondary.head) { - c = tty->secondary.buf[tail]; - if (c == '\t') - col = (col | 7) + 1; - else if (iscntrl(c)) { - if (L_ECHOCTL(tty)) - col += 2; - } else - col++; - INC(tail); - } - - /* Now backup to that column. */ - while (tty->column > col) { - /* Can't use opost here. */ - put_tty_queue('\b', &tty->write_q); - tty->column--; - } - } else { - if (iscntrl(c) && L_ECHOCTL(tty)) { - opost('\b', tty); - opost(' ', tty); - opost('\b', tty); - } - if (!iscntrl(c) || L_ECHOCTL(tty)) { - opost('\b', tty); - opost(' ', tty); - opost('\b', tty); - } - } - } - if (kill_type == ERASE) - break; - } - if (tty->erasing && tty->secondary.head == tty->canon_head) { - opost('/', tty); - tty->erasing = 0; - } -} - -static void isig(int sig, struct tty_struct *tty) -{ - kill_pg(tty->pgrp, sig, 1); - if (!L_NOFLSH(tty)) { - flush_input(tty); - flush_output(tty); - } -} - -static void copy_to_cooked(struct tty_struct * tty) -{ - int c, special_flag; - unsigned long flags; - - if (!tty) { - printk("copy_to_cooked: called with NULL tty\n"); - return; - } - if (!tty->write) { - printk("copy_to_cooked: tty %d has null write routine\n", - tty->line); - } - while (1) { - /* - * Check to see how much room we have left in the - * secondary queue. Send a throttle command or abort - * if necessary. - */ - c = LEFT(&tty->secondary); - if (tty->throttle && (c < SQ_THRESHOLD_LW) - && !set_bit(TTY_SQ_THROTTLED, &tty->flags)) - tty->throttle(tty, TTY_THROTTLE_SQ_FULL); - if (c == 0) - break; - save_flags(flags); cli(); - if (!EMPTY(&tty->read_q)) { - c = tty->read_q.buf[tty->read_q.tail]; - special_flag = clear_bit(tty->read_q.tail, - &tty->readq_flags); - INC(tty->read_q.tail); - restore_flags(flags); - } else { - restore_flags(flags); - break; - } - if (special_flag) { - tty->char_error = c; - continue; - } - if (tty->char_error) { - if (tty->char_error == TTY_BREAK) { - tty->char_error = 0; - if (I_IGNBRK(tty)) - continue; - /* A break is handled by the lower levels. */ - if (I_BRKINT(tty)) - continue; - if (I_PARMRK(tty)) { - put_tty_queue('\377', &tty->secondary); - put_tty_queue('\0', &tty->secondary); - } - put_tty_queue('\0', &tty->secondary); - continue; - } - if (tty->char_error == TTY_OVERRUN) { - tty->char_error = 0; - printk("tty%d: input overrun\n", tty->line); - continue; - } - /* Must be a parity or frame error */ - tty->char_error = 0; - if (I_IGNPAR(tty)) { - continue; - } - if (I_PARMRK(tty)) { - put_tty_queue('\377', &tty->secondary); - put_tty_queue('\0', &tty->secondary); - put_tty_queue(c, &tty->secondary); - } else - put_tty_queue('\0', &tty->secondary); - continue; - } - if (I_ISTRIP(tty)) - c &= 0x7f; - if (!tty->lnext) { - if (c == '\r') { - if (I_IGNCR(tty)) - continue; - if (I_ICRNL(tty)) - c = '\n'; - } else if (c == '\n' && I_INLCR(tty)) - c = '\r'; - } - if (I_IUCLC(tty) && L_IEXTEN(tty)) - c=tolower(c); - if (c == __DISABLED_CHAR) - tty->lnext = 1; - if (L_ICANON(tty) && !tty->lnext) { - if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) || - (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) { - eraser(c, tty); - continue; - } - if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) { - tty->lnext = 1; - if (L_ECHO(tty)) { - if (tty->erasing) { - opost('/', tty); - tty->erasing = 0; - } - if (L_ECHOCTL(tty)) { - opost('^', tty); - opost('\b', tty); - } - } - continue; - } - if (c == REPRINT_CHAR(tty) && L_ECHO(tty) && - L_IEXTEN(tty)) { - unsigned long tail = tty->canon_head; - - if (tty->erasing) { - opost('/', tty); - tty->erasing = 0; - } - echo_char(c, tty); - opost('\n', tty); - while (tail != tty->secondary.head) { - echo_char(tty->secondary.buf[tail], - tty); - INC(tail); - } - continue; - } - } - if (I_IXON(tty) && !tty->lnext) { - if ((tty->stopped && I_IXANY(tty) && L_IEXTEN(tty)) || - c == START_CHAR(tty)) { - start_tty(tty); - continue; - } - if (c == STOP_CHAR(tty)) { - stop_tty(tty); - continue; - } - } - if (L_ISIG(tty) && !tty->lnext) { - if (c == INTR_CHAR(tty)) { - isig(SIGINT, tty); - continue; - } - if (c == QUIT_CHAR(tty)) { - isig(SIGQUIT, tty); - continue; - } - if (c == SUSP_CHAR(tty)) { - if (!is_orphaned_pgrp(tty->pgrp)) - isig(SIGTSTP, tty); - continue; - } - } - - if (tty->erasing) { - opost('/', tty); - tty->erasing = 0; - } - if (c == '\n' && !tty->lnext) { - if (L_ECHO(tty) || (L_ICANON(tty) && L_ECHONL(tty))) - opost('\n', tty); - } else if (L_ECHO(tty)) { - /* Don't echo the EOF char in canonical mode. Sun - handles this differently by echoing the char and - then backspacing, but that's a hack. */ - if (c != EOF_CHAR(tty) || !L_ICANON(tty) || - tty->lnext) { - /* Record the column of first canon char. */ - if (tty->canon_head == tty->secondary.head) - tty->canon_column = tty->column; - echo_char(c, tty); - } - } - - if (I_PARMRK(tty) && c == (unsigned char) '\377' && - (c != EOF_CHAR(tty) || !L_ICANON(tty) || tty->lnext)) - put_tty_queue(c, &tty->secondary); - - if (L_ICANON(tty) && !tty->lnext && - (c == '\n' || c == EOF_CHAR(tty) || c == EOL_CHAR(tty) || - (c == EOL2_CHAR(tty) && L_IEXTEN(tty)))) { - if (c == EOF_CHAR(tty)) - c = __DISABLED_CHAR; - set_bit(tty->secondary.head, &tty->secondary_flags); - put_tty_queue(c, &tty->secondary); - tty->canon_head = tty->secondary.head; - tty->canon_data++; - } else - put_tty_queue(c, &tty->secondary); - tty->lnext = 0; - } - if (!EMPTY(&tty->write_q)) - TTY_WRITE_FLUSH(tty); - if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary)) - wake_up_interruptible(&tty->secondary.proc_list); - - if (tty->throttle && (LEFT(&tty->read_q) >= RQ_THRESHOLD_HW) - && clear_bit(TTY_RQ_THROTTLED, &tty->flags)) - tty->throttle(tty, TTY_THROTTLE_RQ_AVAIL); -} - -int is_ignored(int sig) -{ - return ((current->blocked & (1<<(sig-1))) || - (current->sigaction[sig-1].sa_handler == SIG_IGN)); -} - -static inline int input_available_p(struct tty_struct *tty) -{ - /* Avoid calling TTY_READ_FLUSH unnecessarily. */ - if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary)) - return 1; - - /* Shuffle any pending data down the queues. */ - TTY_READ_FLUSH(tty); - if (tty->link) - TTY_WRITE_FLUSH(tty->link); - - if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary)) - return 1; - return 0; -} - -static int read_chan(struct tty_struct *tty, struct file *file, - unsigned char *buf, unsigned int nr) -{ - struct wait_queue wait = { current, NULL }; - int c; - unsigned char *b = buf; - int minimum, time; - int retval = 0; - - /* Job control check -- must be done at start and after - every sleep (POSIX.1 7.1.1.4). */ - /* NOTE: not yet done after every sleep pending a thorough - check of the logic of this change. -- jlc */ - /* don't stop on /dev/console */ - if (file->f_inode->i_rdev != CONSOLE_DEV && - current->tty == tty->line) { - if (tty->pgrp <= 0) - printk("read_chan: tty->pgrp <= 0!\n"); - else if (current->pgrp != tty->pgrp) { - if (is_ignored(SIGTTIN) || - is_orphaned_pgrp(current->pgrp)) - return -EIO; - kill_pg(current->pgrp, SIGTTIN, 1); - return -ERESTARTSYS; - } - } - - if (L_ICANON(tty)) { - minimum = time = 0; - current->timeout = (unsigned long) -1; - } else { - time = (HZ / 10) * TIME_CHAR(tty); - minimum = MIN_CHAR(tty); - if (minimum) - current->timeout = (unsigned long) -1; - else { - if (time) { - current->timeout = time + jiffies; - time = 0; - } else - current->timeout = 0; - minimum = 1; - } - } - - add_wait_queue(&tty->secondary.proc_list, &wait); - while (1) { - /* First test for status change. */ - if (tty->packet && tty->link->ctrl_status) { - if (b != buf) - break; - put_fs_byte(tty->link->ctrl_status, b++); - tty->link->ctrl_status = 0; - break; - } - /* This statement must be first before checking for input - so that any interrupt will set the state back to - TASK_RUNNING. */ - current->state = TASK_INTERRUPTIBLE; - if (!input_available_p(tty)) { - if (tty->flags & (1 << TTY_SLAVE_CLOSED)) { - retval = -EIO; - break; - } - if (tty_hung_up_p(file)) - break; - if (!current->timeout) - break; - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - if (current->signal & ~current->blocked) { - retval = -ERESTARTSYS; - break; - } - schedule(); - continue; - } - current->state = TASK_RUNNING; - - /* Deal with packet mode. */ - if (tty->packet && b == buf) { - put_fs_byte(TIOCPKT_DATA, b++); - nr--; - } - - while (1) { - int eol; - - cli(); - if (EMPTY(&tty->secondary)) { - sti(); - break; - } - eol = clear_bit(tty->secondary.tail, - &tty->secondary_flags); - c = tty->secondary.buf[tty->secondary.tail]; - if (!nr) { - /* Gobble up an immediately following EOF if - there is no more room in buf (this can - happen if the user "pushes" some characters - using ^D). This prevents the next read() - from falsely returning EOF. */ - if (eol) { - if (c == __DISABLED_CHAR) { - tty->canon_data--; - INC(tty->secondary.tail); - } else { - set_bit(tty->secondary.tail, - &tty->secondary_flags); - } - } - sti(); - break; - } - INC(tty->secondary.tail); - sti(); - if (eol) { - if (--tty->canon_data < 0) { - printk("read_chan: canon_data < 0!\n"); - tty->canon_data = 0; - } - if (c == __DISABLED_CHAR) - break; - put_fs_byte(c, b++); - nr--; - break; - } - put_fs_byte(c, b++); - nr--; - } - - /* If there is enough space in the secondary queue now, let the - low-level driver know. */ - if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW) - && clear_bit(TTY_SQ_THROTTLED, &tty->flags)) - tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL); - - if (b - buf >= minimum || !nr) - break; - if (time) - current->timeout = time + jiffies; - } - remove_wait_queue(&tty->secondary.proc_list, &wait); - current->state = TASK_RUNNING; - current->timeout = 0; - return (b - buf) ? b - buf : retval; -} - -static int write_chan(struct tty_struct * tty, struct file * file, - unsigned char * buf, unsigned int nr) -{ - struct wait_queue wait = { current, NULL }; - int c; - unsigned char *b = buf; - int retval = 0; - - /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */ - if (L_TOSTOP(tty) && file->f_inode->i_rdev != CONSOLE_DEV) { - retval = check_change(tty, tty->line); - if (retval) - return retval; - } - - add_wait_queue(&tty->write_q.proc_list, &wait); - while (1) { - current->state = TASK_INTERRUPTIBLE; - if (current->signal & ~current->blocked) { - retval = -ERESTARTSYS; - break; - } - if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) { - retval = -EIO; - break; - } - while (nr > 0) { - c = get_fs_byte(b); - /* Care is needed here: opost() can abort even - if the write_q is not full. */ - if (opost(c, tty) < 0) - break; - b++; nr--; - } - TTY_WRITE_FLUSH(tty); - if (!nr) - break; - if (EMPTY(&tty->write_q) && !need_resched) - continue; - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - schedule(); + wake_up_interruptible(&tty->link->read_wait); } - current->state = TASK_RUNNING; - remove_wait_queue(&tty->write_q.proc_list, &wait); - return (b - buf) ? b - buf : retval; + if (tty->driver.start) + (tty->driver.start)(tty); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); } static int tty_read(struct inode * inode, struct file * file, char * buf, int count) { - int i, dev; + int i; struct tty_struct * tty; - dev = file->f_rdev; - if (MAJOR(dev) != TTY_MAJOR) { - printk("tty_read: bad pseudo-major nr #%d\n", MAJOR(dev)); - return -EINVAL; - } - dev = MINOR(dev); - tty = TTY_TABLE(dev); + tty = file->private_data; + if (tty_paranoia_check(tty, inode->i_rdev, "tty_read")) + return -EIO; if (!tty || (tty->flags & (1 << TTY_IO_ERROR))) return -EIO; @@ -1165,7 +647,7 @@ #if 0 if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */ (tty->pgrp > 0) && - (current->tty == dev) && + (current->tty == tty) && (tty->pgrp != current->pgrp)) if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp)) return -EIO; @@ -1174,9 +656,9 @@ return -ERESTARTSYS; } #endif - if (ldiscs[tty->disc].read) + if (tty->ldisc.read) /* XXX casts are for what kernel-wide prototypes should be. */ - i = (ldiscs[tty->disc].read)(tty,file,(unsigned char *)buf,(unsigned int)count); + i = (tty->ldisc.read)(tty,file,(unsigned char *)buf,(unsigned int)count); else i = -EIO; if (i > 0) @@ -1186,25 +668,22 @@ static int tty_write(struct inode * inode, struct file * file, char * buf, int count) { - int dev, i, is_console; + int i, is_console; struct tty_struct * tty; - dev = file->f_rdev; is_console = (inode->i_rdev == CONSOLE_DEV); - if (MAJOR(dev) != TTY_MAJOR) { - printk("tty_write: pseudo-major != TTY_MAJOR\n"); - return -EINVAL; - } - dev = MINOR(dev); + if (is_console && redirect) tty = redirect; else - tty = TTY_TABLE(dev); - if (!tty || !tty->write || (tty->flags & (1 << TTY_IO_ERROR))) + tty = file->private_data; + if (tty_paranoia_check(tty, inode->i_rdev, "tty_write")) return -EIO; + if (!tty || !tty->driver.write || (tty->flags & (1 << TTY_IO_ERROR))) + return -EIO; #if 0 if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) && - (current->tty == dev) && (tty->pgrp != current->pgrp)) { + (current->tty == tty) && (tty->pgrp != current->pgrp)) { if (is_orphaned_pgrp(current->pgrp)) return -EIO; if (!is_ignored(SIGTTOU)) { @@ -1213,9 +692,9 @@ } } #endif - if (ldiscs[tty->disc].write) + if (tty->ldisc.write) /* XXX casts are for what kernel-wide prototypes should be. */ - i = (ldiscs[tty->disc].write)(tty,file,(unsigned char *)buf,(unsigned int)count); + i = (tty->ldisc.write)(tty,file,(unsigned char *)buf,(unsigned int)count); else i = -EIO; if (i > 0) @@ -1228,37 +707,54 @@ * unless you know exactly what you are doing. All the changes have to be * made atomically, or there may be incorrect pointers all over the place. */ -static int init_dev(int dev) +static int init_dev(dev_t device, struct tty_struct **ret_tty) { - struct tty_struct *tty, *o_tty; - struct termios *tp, *o_tp, *ltp, *o_ltp; + struct tty_struct *tty, **tty_loc, *o_tty, **o_tty_loc; + struct termios *tp, **tp_loc, *o_tp, **o_tp_loc; + struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc; + struct tty_driver *driver; int retval; - int o_dev; + int idx; - o_dev = PTY_OTHER(dev); + driver = get_tty_driver(device); + if (!driver) + return -ENODEV; + + idx = MINOR(device) - driver->minor_start; tty = o_tty = NULL; tp = o_tp = NULL; ltp = o_ltp = NULL; -repeat: + o_tty_loc = NULL; + o_tp_loc = o_ltp_loc = NULL; + + tty_loc = &driver->table[idx]; + tp_loc = &driver->termios[idx]; + ltp_loc = &driver->termios_locked[idx]; + retval = -EAGAIN; - if (IS_A_PTY_MASTER(dev) && tty_table[dev] && tty_table[dev]->count) + if (driver->type == TTY_DRIVER_TYPE_PTY && + driver->subtype == PTY_TYPE_MASTER && + *tty_loc && (*tty_loc)->count) goto end_init; +repeat: retval = -ENOMEM; - if (!tty_table[dev] && !tty) { + if (!*tty_loc && !tty) { if (!(tty = (struct tty_struct*) get_free_page(GFP_KERNEL))) goto end_init; - initialize_tty_struct(dev, tty); + initialize_tty_struct(tty); + tty->device = device; + tty->driver = *driver; goto repeat; } - if (!tty_termios[dev] && !tp) { + if (!*tp_loc && !tp) { tp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!tp) goto end_init; - initialize_termios(dev, tp); + *tp = driver->init_termios; goto repeat; } - if (!termios_locked[dev] && !ltp) { + if (!*ltp_loc && !ltp) { ltp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!ltp) @@ -1266,24 +762,34 @@ memset(ltp, 0, sizeof(struct termios)); goto repeat; } - if (IS_A_PTY(dev)) { - if (!tty_table[o_dev] && !o_tty) { + if (driver->type == TTY_DRIVER_TYPE_PTY) { + o_tty_loc = &driver->other->table[idx]; + o_tp_loc = &driver->other->termios[idx]; + o_ltp_loc = &driver->other->termios_locked[idx]; + + if (!*o_tty_loc && !o_tty) { + dev_t o_device; + o_tty = (struct tty_struct *) get_free_page(GFP_KERNEL); if (!o_tty) goto end_init; - initialize_tty_struct(o_dev, o_tty); + o_device = MKDEV(driver->other->major, + driver->other->minor_start + idx); + initialize_tty_struct(o_tty); + o_tty->device = o_device; + o_tty->driver = *driver->other; goto repeat; } - if (!tty_termios[o_dev] && !o_tp) { + if (!*o_tp_loc && !o_tp) { o_tp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!o_tp) goto end_init; - initialize_termios(o_dev, o_tp); + *o_tp = driver->other->init_termios; goto repeat; } - if (!termios_locked[o_dev] && !o_ltp) { + if (!*o_ltp_loc && !o_ltp) { o_ltp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!o_ltp) @@ -1294,39 +800,56 @@ } /* Now we have allocated all the structures: update all the pointers.. */ - if (!tty_termios[dev]) { - tty_termios[dev] = tp; + if (!*tp_loc) { + *tp_loc = tp; tp = NULL; } - if (!tty_table[dev]) { - tty->termios = tty_termios[dev]; - tty_table[dev] = tty; - tty = NULL; - } - if (!termios_locked[dev]) { - termios_locked[dev] = ltp; + if (!*ltp_loc) { + *ltp_loc = ltp; ltp = NULL; } - if (IS_A_PTY(dev)) { - if (!tty_termios[o_dev]) { - tty_termios[o_dev] = o_tp; + if (!*tty_loc) { + tty->termios = *tp_loc; + tty->termios_locked = *ltp_loc; + *tty_loc = tty; + (*driver->refcount)++; + if (tty->ldisc.open) { + retval = (tty->ldisc.open)(tty); + if (retval) + goto end_init; + } + tty = NULL; + } + if (driver->type == TTY_DRIVER_TYPE_PTY) { + if (!*o_tp_loc) { + *o_tp_loc = o_tp; o_tp = NULL; } - if (!termios_locked[o_dev]) { - termios_locked[o_dev] = o_ltp; + if (!*o_ltp_loc) { + *o_ltp_loc = o_ltp; o_ltp = NULL; } - if (!tty_table[o_dev]) { - o_tty->termios = tty_termios[o_dev]; - tty_table[o_dev] = o_tty; + if (!*o_tty_loc) { + o_tty->termios = *o_tp_loc; + o_tty->termios_locked = *o_ltp_loc; + *o_tty_loc = o_tty; + (*driver->other->refcount)++; + if (o_tty->ldisc.open) { + retval = (o_tty->ldisc.open)(o_tty); + if (retval) + goto end_init; + } o_tty = NULL; } - tty_table[dev]->link = tty_table[o_dev]; - tty_table[o_dev]->link = tty_table[dev]; + (*tty_loc)->link = *o_tty_loc; + (*o_tty_loc)->link = *tty_loc; } - tty_table[dev]->count++; - if (IS_A_PTY_MASTER(dev)) - tty_table[o_dev]->count++; + (*tty_loc)->count++; + (*tty_loc)->driver = *driver; + if (driver->type == TTY_DRIVER_TYPE_PTY && + driver->subtype == PTY_TYPE_MASTER) + (*o_tty_loc)->count++; + *ret_tty = *tty_loc; retval = 0; end_init: if (tty) @@ -1349,103 +872,169 @@ * to be very careful that the structures are all released at the * same time, as interrupts might otherwise get the wrong pointers. */ -static void release_dev(int dev, struct file * filp) +static void release_dev(struct file * filp) { struct tty_struct *tty, *o_tty; - struct termios *tp, *o_tp; + struct termios *tp, *o_tp, *ltp, *o_ltp; struct task_struct **p; + int idx; + - tty = tty_table[dev]; - tp = tty_termios[dev]; - o_tty = NULL; - o_tp = NULL; - if (!tty) { - printk("release_dev: tty_table[%d] was NULL\n", dev); + tty = filp->private_data; + if (tty_paranoia_check(tty, filp->f_inode->i_rdev, "release_dev")) + return; + + tty_fasync(filp->f_inode, filp, 0); + + tp = tty->termios; + ltp = tty->termios_locked; + + idx = MINOR(tty->device) - tty->driver.minor_start; +#ifdef TTY_PARANOIA_CHECK + if (idx < 0 || idx >= tty->driver.num) { + printk("release_dev: bad idx when trying to free (%d, %d)\n", + MAJOR(tty->device), MINOR(tty->device)); + return; + } + if (tty != tty->driver.table[idx]) { + printk("release_dev: driver.table[%d] not tty for (%d, %d)\n", + idx, MAJOR(tty->device), MINOR(tty->device)); + return; + } + if (tp != tty->driver.termios[idx]) { + printk("release_dev: driver.termios[%d] not termios for (%d, %d)\n", + idx, MAJOR(tty->device), MINOR(tty->device)); return; } - if (!tp) { - printk("release_dev: tty_termios[%d] was NULL\n", dev); + if (ltp != tty->driver.termios_locked[idx]) { + printk("release_dev: driver.termios_locked[%d] not termios_locked for (%d, %d)\n", + idx, MAJOR(tty->device), MINOR(tty->device)); return; } +#endif + #ifdef TTY_DEBUG_HANGUP - printk("release_dev of tty%d (tty count=%d)...", dev, tty->count); + printk("release_dev of %s (tty count=%d)...", tty_name(tty), + tty->count); #endif - if (IS_A_PTY(dev)) { - o_tty = tty_table[PTY_OTHER(dev)]; - o_tp = tty_termios[PTY_OTHER(dev)]; - if (!o_tty) { - printk("release_dev: pty pair(%d) was NULL\n", dev); + + o_tty = tty->link; + o_tp = (o_tty) ? o_tty->termios : NULL; + o_ltp = (o_tty) ? o_tty->termios_locked : NULL; + +#ifdef TTY_PARANOIA_CHECK + if (tty->driver.other) { + if (o_tty != tty->driver.other->table[idx]) { + printk("release_dev: other->table[%d] not o_tty for (%d, %d)\n", + idx, MAJOR(tty->device), MINOR(tty->device)); return; } - if (!o_tp) { - printk("release_dev: pty pair(%d) termios was NULL\n", dev); + if (o_tp != tty->driver.other->termios[idx]) { + printk("release_dev: other->termios[%d] not o_termios for (%d, %d)\n", + idx, MAJOR(tty->device), MINOR(tty->device)); return; } - if (tty->link != o_tty || o_tty->link != tty) { + if (o_ltp != tty->driver.other->termios_locked[idx]) { + printk("release_dev: other->termios_locked[%d] not o_termios_locked for (%d, %d)\n", + idx, MAJOR(tty->device), MINOR(tty->device)); + return; + } + + if (o_tty->link != tty) { printk("release_dev: bad pty pointers\n"); return; } } - tty->write_data_cnt = 0; /* Clear out pending trash */ - if (tty->close) - tty->close(tty, filp); - if (IS_A_PTY_MASTER(dev)) { +#endif + + if (tty->driver.close) + tty->driver.close(tty, filp); + if (tty->driver.type == TTY_DRIVER_TYPE_PTY && + tty->driver.subtype == PTY_TYPE_MASTER) { if (--tty->link->count < 0) { - printk("release_dev: bad tty slave count (dev = %d): %d\n", - dev, tty->count); + printk("release_dev: bad pty slave count (%d) for %s\n", + tty->count, tty_name(tty)); tty->link->count = 0; } } if (--tty->count < 0) { - printk("release_dev: bad tty_table[%d]->count: %d\n", - dev, tty->count); + printk("release_dev: bad tty->count (%d) for %s\n", + tty->count, tty_name(tty)); tty->count = 0; } if (tty->count) return; -#ifdef TTY_DEBUG_HANGUP - printk("freeing tty structure..."); -#endif - /* * Make sure there aren't any processes that still think this * tty is their controlling tty. */ for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { - if ((*p) && (*p)->tty == tty->line) - (*p)->tty = -1; + if ((*p) && (*p)->tty == tty) + (*p)->tty = NULL; + } + + if (o_tty) { + if (o_tty->count) + return; + tty->driver.other->table[idx] = NULL; + tty->driver.other->termios[idx] = NULL; + tty->driver.other->termios_locked[idx] = NULL; } + +#ifdef TTY_DEBUG_HANGUP + printk("freeing tty structure..."); +#endif /* * Shutdown the current line discipline, and reset it to * N_TTY. */ - if (ldiscs[tty->disc].close != NULL) - ldiscs[tty->disc].close(tty); - tty->disc = N_TTY; + if (tty->ldisc.close) + (tty->ldisc.close)(tty); + tty->ldisc = ldiscs[N_TTY]; tty->termios->c_line = N_TTY; - if (o_tty) { - if (o_tty->count) - return; - else { - tty_table[PTY_OTHER(dev)] = NULL; - tty_termios[PTY_OTHER(dev)] = NULL; - } - } - tty_table[dev] = NULL; - if (IS_A_PTY(dev)) { - tty_termios[dev] = NULL; + tty->driver.table[idx] = NULL; + if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) { + tty->driver.termios[idx] = NULL; + tty->driver.termios_locked[idx] = NULL; kfree_s(tp, sizeof(struct termios)); + kfree_s(ltp, sizeof(struct termios)); } if (tty == redirect || o_tty == redirect) redirect = NULL; + /* + * Make sure that the tty's task queue isn't activated. If it + * is, take it out of the linked list. + */ + cli(); + if (tty->flip.tqueue.sync) { + struct tq_struct *tq, *prev; + + for (tq=tq_timer, prev=0; tq; prev=tq, tq=tq->next) { + if (tq == &tty->flip.tqueue) { + if (prev) + prev->next = tq->next; + else + tq_timer = tq->next; + break; + } + } + } + sti(); + tty->magic = 0; + (*tty->driver.refcount)--; free_page((unsigned long) tty); - if (o_tty) + if (o_tty) { + o_tty->magic = 0; + (*o_tty->driver.refcount)--; free_page((unsigned long) o_tty); + } if (o_tp) kfree_s(o_tp, sizeof(struct termios)); + if (o_ltp) + kfree_s(o_ltp, sizeof(struct termios)); } /* @@ -1463,87 +1052,67 @@ static int tty_open(struct inode * inode, struct file * filp) { struct tty_struct *tty; - int major, minor; + int minor; int noctty, retval; + dev_t device; retry_open: - minor = MINOR(inode->i_rdev); - major = MAJOR(inode->i_rdev); noctty = filp->f_flags & O_NOCTTY; - if (major == TTYAUX_MAJOR) { - if (!minor) { - major = TTY_MAJOR; - minor = current->tty; - } + device = inode->i_rdev; + if (device == TTY_DEV) { + if (!current->tty) + return -ENXIO; + device = current->tty->device; /* noctty = 1; */ - } else if (major == TTY_MAJOR) { - if (!minor) { - minor = fg_console + 1; - noctty = 1; - } - } else { - printk("Bad major #%d in tty_open\n", MAJOR(inode->i_rdev)); - return -ENODEV; } - if (minor <= 0) - return -ENXIO; - if (IS_A_PTY_MASTER(minor)) + if (device == CONSOLE_DEV) { + device = MKDEV(TTY_MAJOR, fg_console+1); noctty = 1; - filp->f_rdev = (major << 8) | minor; - retval = init_dev(minor); + } + minor = MINOR(device); + + retval = init_dev(device, &tty); + filp->private_data = tty; if (retval) return retval; - tty = tty_table[minor]; + if (tty->driver.type == TTY_DRIVER_TYPE_PTY && + tty->driver.subtype == PTY_TYPE_MASTER) + noctty = 1; #ifdef TTY_DEBUG_HANGUP - printk("opening tty%d...", tty->line); + printk("opening %s...", tty_name(tty)); #endif if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !suser()) - return -EBUSY; - -#if 0 - /* clean up the packet stuff. */ - /* - * Why is this not done in init_dev? Right here, if another - * process opens up a tty in packet mode, all the packet - * variables get cleared. Come to think of it, is anything - * using the packet mode at all??? - Ted, 1/27/93 - * - * Not to worry, a pty master can only be opened once. - * And rlogind and telnetd both use packet mode. -- jrs - * - * Not needed. These are cleared in initialize_tty_struct. -- jlc - */ - tty->ctrl_status = 0; - tty->packet = 0; -#endif - - if (tty->open) { - retval = tty->open(tty, filp); - } else { + retval = -EBUSY; + else if (tty->driver.open) + retval = tty->driver.open(tty, filp); + else retval = -ENODEV; - } + if (retval) { #ifdef TTY_DEBUG_HANGUP - printk("error %d in opening tty%d...", retval, tty->line); + printk("error %d in opening %s...", retval, tty_name(tty)); #endif - release_dev(minor, filp); + release_dev(filp); if (retval != -ERESTARTSYS) return retval; if (current->signal & ~current->blocked) return retval; schedule(); + /* + * Need to reset f_op in case a hangup happened. + */ + filp->f_op = &tty_fops; goto retry_open; } if (!noctty && current->leader && - current->tty<0 && - tty->session==0) { - current->tty = minor; + !current->tty && + tty->session == 0) { + current->tty = tty; tty->session = current->session; tty->pgrp = current->pgrp; } - filp->f_rdev = MKDEV(TTY_MAJOR,minor); /* Set it to something normal */ return 0; } @@ -1554,69 +1123,285 @@ */ static void tty_release(struct inode * inode, struct file * filp) { - int dev; - - dev = filp->f_rdev; - if (MAJOR(dev) != TTY_MAJOR) { - printk("tty_release: tty pseudo-major != TTY_MAJOR\n"); - return; - } - dev = MINOR(filp->f_rdev); - if (!dev) { - printk("tty_release: bad f_rdev\n"); - return; - } - release_dev(dev, filp); + release_dev(filp); } static int tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait) { - int dev; struct tty_struct * tty; - dev = filp->f_rdev; - if (MAJOR(dev) != TTY_MAJOR) { - printk("tty_select: tty pseudo-major != TTY_MAJOR\n"); - return 0; - } - dev = MINOR(filp->f_rdev); - tty = TTY_TABLE(dev); - if (!tty) { - printk("tty_select: tty struct for dev %d was NULL\n", dev); + tty = filp->private_data; + if (tty_paranoia_check(tty, inode->i_rdev, "tty_select")) return 0; - } - if (ldiscs[tty->disc].select) - return (ldiscs[tty->disc].select)(tty, inode, filp, - sel_type, wait); + + if (tty->ldisc.select) + return (tty->ldisc.select)(tty, inode, filp, sel_type, wait); return 0; } -static int normal_select(struct tty_struct * tty, struct inode * inode, - struct file * file, int sel_type, select_table *wait) +static int tty_fasync(struct inode * inode, struct file * filp, int on) { - switch (sel_type) { - case SEL_IN: - if (input_available_p(tty)) - return 1; - /* fall through */ - case SEL_EX: - if (tty->packet && tty->link->ctrl_status) - return 1; - if (tty->flags & (1 << TTY_SLAVE_CLOSED)) - return 1; - if (tty_hung_up_p(file)) - return 1; - select_wait(&tty->secondary.proc_list, wait); + struct tty_struct * tty; + struct fasync_struct *fa, *prev; + + tty = filp->private_data; + if (tty_paranoia_check(tty, inode->i_rdev, "tty_fasync")) + return 0; + + for (fa = tty->fasync, prev = 0; fa; prev= fa, fa = fa->fa_next) { + if (fa->fa_file == filp) + break; + } + + if (on) { + if (fa) return 0; - case SEL_OUT: - if (LEFT(&tty->write_q) > WAKEUP_CHARS) - return 1; - select_wait(&tty->write_q.proc_list, wait); + fa = kmalloc(sizeof(struct fasync_struct), GFP_KERNEL); + if (!fa) + return -ENOMEM; + fa->magic = FASYNC_MAGIC; + fa->fa_file = filp; + fa->fa_next = tty->fasync; + tty->fasync = fa; + if (!tty->read_wait) + tty->minimum_to_wake = 1; + } else { + if (!fa) return 0; + if (prev) + prev->fa_next = fa->fa_next; + else + tty->fasync = fa->fa_next; + kfree_s(fa, sizeof(struct fasync_struct)); + if (!tty->fasync && !tty->read_wait) + tty->minimum_to_wake = N_TTY_BUF_SIZE; } - return 0; + return 0; +} + +/* + * XXX does anyone use this anymore?!? + */ +static int do_get_ps_info(int arg) +{ + struct tstruct { + int flag; + int present[NR_TASKS]; + struct task_struct tasks[NR_TASKS]; + }; + struct tstruct *ts = (struct tstruct *)arg; + struct task_struct **p; + char *c, *d; + int i, n = 0; + + i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct tstruct)); + if (i) + return i; + for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++) + if (*p) + { + c = (char *)(*p); + d = (char *)(ts->tasks+n); + for (i=0 ; ipresent+n)); + } + else + put_fs_long(0, (unsigned long *)(ts->present+n)); + return(0); +} + +static int tty_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int retval; + struct tty_struct * tty; + struct tty_struct * real_tty; + struct winsize tmp_ws; + pid_t pgrp; + unsigned char ch; + char mbz = 0; + + tty = file->private_data; + if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl")) + return -EINVAL; + + if (tty->driver.type == TTY_DRIVER_TYPE_PTY && + tty->driver.subtype == PTY_TYPE_MASTER) + real_tty = tty->link; + else + real_tty = tty; + + switch (cmd) { + case TIOCSTI: + if ((current->tty != tty) && !suser()) + return -EPERM; + ch = get_fs_byte((char *) arg); + tty->ldisc.receive_buf(tty, &ch, &mbz, 1); + return 0; + case TIOCGWINSZ: + retval = verify_area(VERIFY_WRITE, (void *) arg, + sizeof (struct winsize)); + if (retval) + return retval; + memcpy_tofs((struct winsize *) arg, &tty->winsize, + sizeof (struct winsize)); + return 0; + case TIOCSWINSZ: + memcpy_fromfs(&tmp_ws, (struct winsize *) arg, + sizeof (struct winsize)); + if (memcmp(&tmp_ws, &tty->winsize, + sizeof(struct winsize))) { + if (tty->pgrp > 0) + kill_pg(tty->pgrp, SIGWINCH, 1); + if ((real_tty->pgrp != tty->pgrp) && + (real_tty->pgrp > 0)) + kill_pg(real_tty->pgrp, SIGWINCH, 1); + } + tty->winsize = tmp_ws; + real_tty->winsize = tmp_ws; + return 0; + case TIOCCONS: + if (tty->driver.type == TTY_DRIVER_TYPE_CONSOLE) { + if (!suser()) + return -EPERM; + redirect = NULL; + return 0; + } + if (redirect) + return -EBUSY; + redirect = real_tty; + return 0; + case FIONBIO: + arg = get_fs_long((unsigned long *) arg); + if (arg) + file->f_flags |= O_NONBLOCK; + else + file->f_flags &= ~O_NONBLOCK; + return 0; + case TIOCEXCL: + set_bit(TTY_EXCLUSIVE, &tty->flags); + return 0; + case TIOCNXCL: + clear_bit(TTY_EXCLUSIVE, &tty->flags); + return 0; + case TIOCNOTTY: + if (current->tty != tty) + return -ENOTTY; + if (current->leader) + disassociate_ctty(0); + current->tty = NULL; + return 0; + case TIOCSCTTY: + if (current->leader && + (current->session == tty->session)) + return 0; + /* + * The process must be a session leader and + * not have a controlling tty already. + */ + if (!current->leader || current->tty) + return -EPERM; + if (tty->session > 0) { + /* + * This tty is already the controlling + * tty for another session group! + */ + if ((arg == 1) && suser()) { + /* + * Steal it away + */ + struct task_struct *p; + + for_each_task(p) + if (p->tty == tty) + p->tty = NULL; + } else + return -EPERM; + } + current->tty = tty; + tty->session = current->session; + tty->pgrp = current->pgrp; + return 0; + case TIOCGPGRP: + /* + * (tty == real_tty) is a cheap way of + * testing if the tty is NOT a master pty. + */ + if (tty == real_tty && current->tty != real_tty) + return -ENOTTY; + retval = verify_area(VERIFY_WRITE, (void *) arg, + sizeof (pid_t)); + if (retval) + return retval; + put_fs_long(real_tty->pgrp, (pid_t *) arg); + return 0; + case TIOCSPGRP: + retval = tty_check_change(real_tty); + if (retval) + return retval; + if (!current->tty || + (current->tty != real_tty) || + (real_tty->session != current->session)) + return -ENOTTY; + pgrp = get_fs_long((pid_t *) arg); + if (pgrp < 0) + return -EINVAL; + if (session_of_pgrp(pgrp) != current->session) + return -EPERM; + real_tty->pgrp = pgrp; + return 0; + case TIOCGETD: + retval = verify_area(VERIFY_WRITE, (void *) arg, + sizeof (unsigned long)); + if (retval) + return retval; + put_fs_long(tty->ldisc.num, (unsigned long *) arg); + return 0; + case TIOCSETD: + retval = tty_check_change(tty); + if (retval) + return retval; + arg = get_fs_long((unsigned long *) arg); + return tty_set_ldisc(tty, arg); + case TIOCLINUX: + switch (get_fs_byte((char *)arg)) + { + case 0: + return do_screendump(arg); + case 1: + printk("Deprecated TIOCLINUX (1) ioctl\n"); + return do_get_ps_info(arg); +#ifdef CONFIG_SELECTION + case 2: + return set_selection(arg); + case 3: + return paste_selection(tty); + case 4: + unblank_screen(); + return 0; +#endif /* CONFIG_SELECTION */ + default: + return -EINVAL; + } + default: + if (tty->driver.ioctl) { + retval = (tty->driver.ioctl)(tty, file, + cmd, arg); + if (retval != -ENOIOCTLCMD) + return retval; + } + if (tty->ldisc.ioctl) { + retval = (tty->ldisc.ioctl)(tty, file, + cmd, arg); + if (retval != -ENOIOCTLCMD) + return retval; + } + return -EINVAL; + } } + /* * This implements the "Secure Attention Key" --- the idea is to * prevent trojan horses by killing all processes associated with this @@ -1635,24 +1420,25 @@ tty_hangup(tty); #else struct task_struct **p; - int line = tty->line; int session = tty->session; int i; struct file *filp; - flush_input(tty); - flush_output(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { if (!(*p)) continue; - if (((*p)->tty == line) || + if (((*p)->tty == tty) || ((session > 0) && ((*p)->session == session))) send_sig(SIGKILL, *p, 1); else { for (i=0; i < NR_OPEN; i++) { filp = (*p)->files->fd[i]; if (filp && (filp->f_op == &tty_fops) && - (MINOR(filp->f_rdev) == line)) { + (filp->private_data == tty)) { send_sig(SIGKILL, *p, 1); break; } @@ -1663,183 +1449,119 @@ } /* - * This routine allows a kernel routine to send a large chunk of data - * to a particular tty; if all of the data can be queued up for ouput - * immediately, tty_write_data() will return 0. If, however, not all - * of the data can be immediately queued for delivery, the number of - * bytes left to be queued up will be returned, and the rest of the - * data will be queued up when there is room. The callback function - * will be called (with the argument callarg) when the last of the - * data is finally in the queue. - * - * Note that the callback routine will _not_ be called if all of the - * data could be queued immediately. This is to avoid a problem with - * the kernel stack getting too deep, which might happen if the - * callback routine calls tty_write_data with itself as an argument. + * This routine is called out of the software interrupt to flush data + * from the flip buffer to the line discpline. */ -int tty_write_data(struct tty_struct *tty, char *bufp, int buflen, - void (*callback)(void * data), void * callarg) +static void flush_to_ldisc(void *private) { - int head, tail, count; - unsigned long flags; - char *p; - -#define VLEFT ((tail-head-1)&(TTY_BUF_SIZE-1)) - - save_flags(flags); - cli(); - if (tty->write_data_cnt) { - restore_flags(flags); - return -EBUSY; - } - - head = tty->write_q.head; - tail = tty->write_q.tail; - count = buflen; - p = bufp; - - while (count && VLEFT > 0) { - tty->write_q.buf[head++] = *p++; - head &= TTY_BUF_SIZE-1; - count--; - } - tty->write_q.head = head; - if (count) { - tty->write_data_cnt = count; - tty->write_data_ptr = (unsigned char *) p; - tty->write_data_callback = callback; - tty->write_data_arg = callarg; - } - restore_flags(flags); - tty->write(tty); - return count; + struct tty_struct *tty = private; + unsigned char *cp; + char *fp; + int count; + + if (tty->flip.buf_num) { + cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE; + fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; + tty->flip.buf_num = 0; + + cli(); + tty->flip.char_buf_ptr = tty->flip.char_buf; + tty->flip.flag_buf_ptr = tty->flip.flag_buf; + } else { + cp = tty->flip.char_buf; + fp = tty->flip.flag_buf; + tty->flip.buf_num = 1; + + cli(); + tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE; + tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; + } + count = tty->flip.count; + tty->flip.count = 0; + sti(); + +#if 0 + if (count > tty->max_flip_cnt) + tty->max_flip_cnt = count; +#endif + tty->ldisc.receive_buf(tty, cp, fp, count); } /* - * This routine routine is called after an interrupt has drained a - * tty's write queue, so that there is more space for data waiting to - * be sent in tty->write_data_ptr. - * - * tty_check_write[8] is a bitstring which indicates which ttys - * needs to be processed. + * This subroutine initializes a tty structure. */ -void tty_bh_routine(void * unused) +static void initialize_tty_struct(struct tty_struct *tty) { - int i, j, line, mask; - int head, tail, count; - unsigned char * p; - struct tty_struct * tty; - - for (i = 0, line = 0; i < MAX_TTYS / 32; i++) { - if (!tty_check_write[i]) { - line += 32; - continue; - } - for (j=0, mask=0; j < 32; j++, line++, mask <<= 1) { - if (clear_bit(j, &tty_check_write[i])) { - tty = tty_table[line]; - if (!tty || !tty->write_data_cnt) - continue; - cli(); - head = tty->write_q.head; - tail = tty->write_q.tail; - count = tty->write_data_cnt; - p = tty->write_data_ptr; - - while (count && VLEFT > 0) { - tty->write_q.buf[head++] = *p++; - head &= TTY_BUF_SIZE-1; - count--; - } - tty->write_q.head = head; - tty->write_data_ptr = p; - tty->write_data_cnt = count; - sti(); - if (!count) - (tty->write_data_callback) - (tty->write_data_arg); - } - } - } - + memset(tty, 0, sizeof(struct tty_struct)); + tty->magic = TTY_MAGIC; + tty->ldisc = ldiscs[N_TTY]; + tty->pgrp = -1; + tty->flip.char_buf_ptr = tty->flip.char_buf; + tty->flip.flag_buf_ptr = tty->flip.flag_buf; + tty->flip.tqueue.routine = flush_to_ldisc; + tty->flip.tqueue.data = tty; } /* - * This subroutine initializes a tty structure. We have to set up - * things correctly for each different type of tty. + * The default put_char routine if the driver did not define one. */ -static void initialize_tty_struct(int line, struct tty_struct *tty) +void tty_default_put_char(struct tty_struct *tty, unsigned char ch) { - memset(tty, 0, sizeof(struct tty_struct)); - tty->line = line; - tty->disc = N_TTY; - tty->pgrp = -1; - if (IS_A_CONSOLE(line)) { - tty->open = con_open; - tty->winsize.ws_row = video_num_lines; - tty->winsize.ws_col = video_num_columns; - } else if IS_A_SERIAL(line) { - tty->open = rs_open; - } else if IS_A_PTY(line) { - tty->open = pty_open; - } + tty->driver.write(tty, 0, &ch, 1); } -static void initialize_termios(int line, struct termios * tp) -{ - memset(tp, 0, sizeof(struct termios)); - memcpy(tp->c_cc, INIT_C_CC, NCCS); - if (IS_A_CONSOLE(line) || IS_A_PTY_SLAVE(line)) { - tp->c_iflag = ICRNL | IXON; - tp->c_oflag = OPOST | ONLCR; - tp->c_cflag = B38400 | CS8 | CREAD; - tp->c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | - ECHOCTL | ECHOKE | IEXTEN; - } else if (IS_A_SERIAL(line)) { - tp->c_iflag = ICRNL | IXON; - tp->c_oflag = OPOST | ONLCR | XTABS; - tp->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - tp->c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | - ECHOCTL | ECHOKE | IEXTEN; - } else if (IS_A_PTY_MASTER(line)) - tp->c_cflag = B9600 | CS8 | CREAD; -} - -static struct tty_ldisc tty_ldisc_N_TTY = { - 0, /* flags */ - NULL, /* open */ - NULL, /* close */ - read_chan, /* read */ - write_chan, /* write */ - NULL, /* ioctl */ - normal_select, /* select */ - copy_to_cooked /* handler */ -}; +/* + * Called by a tty driver to register itself. + */ +int tty_register_driver(struct tty_driver *driver) +{ + if (driver->flags & TTY_DRIVER_INSTALLED) + return 0; + /* + * XXX need to check to see if major device already + * registered, and then handle error checking. + */ + (void) register_chrdev(driver->major, driver->name, &tty_fops); + if (!driver->put_char) + driver->put_char = tty_default_put_char; + driver->prev = 0; + driver->next = tty_drivers; + tty_drivers->prev = driver; + tty_drivers = driver; + return 0; +} + long tty_init(long kmem_start) { - int i; - if (sizeof(struct tty_struct) > PAGE_SIZE) panic("size of tty structure > PAGE_SIZE!"); if (register_chrdev(TTY_MAJOR,"tty",&tty_fops)) panic("unable to get major %d for tty device", TTY_MAJOR); if (register_chrdev(TTYAUX_MAJOR,"tty",&tty_fops)) panic("unable to get major %d for tty device", TTYAUX_MAJOR); - for (i=0 ; i< MAX_TTYS ; i++) { - tty_table[i] = 0; - tty_termios[i] = 0; - } - memset(tty_check_write, 0, sizeof(tty_check_write)); - bh_base[TTY_BH].routine = tty_bh_routine; + tty_drivers = 0; /* Setup the default TTY line discipline. */ memset(ldiscs, 0, sizeof(ldiscs)); (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); - kmem_start = kbd_init(kmem_start); + /* + * Set up the standard termios. Individual tty drivers may + * deviate from this; this is used as a template. + */ + memset(&tty_std_termios, 0, sizeof(struct termios)); + memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS); + tty_std_termios.c_iflag = ICRNL | IXON; + tty_std_termios.c_oflag = OPOST | ONLCR; + tty_std_termios.c_cflag = B38400 | CS8 | CREAD; + tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | + ECHOCTL | ECHOKE | IEXTEN; + kmem_start = con_init(kmem_start); + kmem_start = kbd_init(kmem_start); kmem_start = rs_init(kmem_start); + kmem_start = pty_init(kmem_start); return kmem_start; } diff -u --recursive --new-file v1.1.12/linux/drivers/char/tty_ioctl.c linux/drivers/char/tty_ioctl.c --- v1.1.12/linux/drivers/char/tty_ioctl.c Sat Mar 26 15:13:09 1994 +++ linux/drivers/char/tty_ioctl.c Mon May 23 07:55:14 1994 @@ -32,64 +32,16 @@ #endif extern int session_of_pgrp(int pgrp); -extern int do_screendump(int arg); extern int kill_pg(int pgrp, int sig, int priv); -#ifdef CONFIG_SELECTION -extern int set_selection(const int arg); -extern int paste_selection(struct tty_struct *tty); -#endif /* CONFIG_SELECTION */ - -static int tty_set_ldisc(struct tty_struct *tty, int ldisc); - -void flush_input(struct tty_struct * tty) -{ - cli(); - tty->read_q.head = tty->read_q.tail = 0; - tty->secondary.head = tty->secondary.tail = 0; - tty->canon_head = tty->canon_data = tty->erasing = 0; - memset(&tty->readq_flags, 0, sizeof tty->readq_flags); - memset(&tty->secondary_flags, 0, sizeof tty->secondary_flags); - sti(); - if (!tty->link) - return; - /* No cli() since ptys don't use interrupts. */ - tty->link->write_q.head = tty->link->write_q.tail = 0; - wake_up_interruptible(&tty->link->write_q.proc_list); - if (tty->link->packet) { - tty->ctrl_status |= TIOCPKT_FLUSHREAD; - wake_up_interruptible(&tty->link->secondary.proc_list); - } -} - -void flush_output(struct tty_struct * tty) -{ - cli(); - tty->write_q.head = tty->write_q.tail = 0; - sti(); - wake_up_interruptible(&tty->write_q.proc_list); - if (!tty->link) - return; - /* No cli() since ptys don't use interrupts. */ - tty->link->read_q.head = tty->link->read_q.tail = 0; - tty->link->secondary.head = tty->link->secondary.tail = 0; - tty->link->canon_head = tty->link->canon_data = tty->link->erasing = 0; - memset(&tty->link->readq_flags, 0, sizeof tty->readq_flags); - memset(&tty->link->secondary_flags, 0, sizeof tty->secondary_flags); - if (tty->link->packet) { - tty->ctrl_status |= TIOCPKT_FLUSHWRITE; - wake_up_interruptible(&tty->link->secondary.proc_list); - } -} - void wait_until_sent(struct tty_struct * tty, int timeout) { struct wait_queue wait = { current, NULL }; - TTY_WRITE_FLUSH(tty); - if (EMPTY(&tty->write_q)) + if (!tty->driver.chars_in_buffer || + !tty->driver.chars_in_buffer(tty)) return; - add_wait_queue(&tty->write_q.proc_list, &wait); + add_wait_queue(&tty->write_wait, &wait); current->counter = 0; /* make us low-priority */ if (timeout) current->timeout = timeout + jiffies; @@ -99,42 +51,12 @@ current->state = TASK_INTERRUPTIBLE; if (current->signal & ~current->blocked) break; - TTY_WRITE_FLUSH(tty); - if (EMPTY(&tty->write_q)) + if (!tty->driver.chars_in_buffer(tty)) break; schedule(); } while (current->timeout); current->state = TASK_RUNNING; - remove_wait_queue(&tty->write_q.proc_list, &wait); -} - -static int do_get_ps_info(int arg) -{ - struct tstruct { - int flag; - int present[NR_TASKS]; - struct task_struct tasks[NR_TASKS]; - }; - struct tstruct *ts = (struct tstruct *)arg; - struct task_struct **p; - char *c, *d; - int i, n = 0; - - i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct tstruct)); - if (i) - return i; - for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++) - if (*p) - { - c = (char *)(*p); - d = (char *)(ts->tasks+n); - for (i=0 ; ipresent+n)); - } - else - put_fs_long(0, (unsigned long *)(ts->present+n)); - return(0); + remove_wait_queue(&tty->write_wait, &wait); } static void unset_locked_termios(struct termios *termios, @@ -160,45 +82,25 @@ old->c_cc[i] : termios->c_cc[i]; } -int check_change(struct tty_struct * tty, int channel) -{ - /* If we try to set the state of terminal and we're not in the - foreground, send a SIGTTOU. If the signal is blocked or - ignored, go ahead and perform the operation. POSIX 7.2) */ - if (current->tty != channel) - return 0; - if (tty->pgrp <= 0) { - printk("check_change: tty->pgrp <= 0!\n"); - return 0; - } - if (current->pgrp == tty->pgrp) - return 0; - if (is_ignored(SIGTTOU)) - return 0; - if (is_orphaned_pgrp(current->pgrp)) - return -EIO; - (void) kill_pg(current->pgrp,SIGTTOU,1); - return -ERESTARTSYS; -} - static int set_termios_2(struct tty_struct * tty, struct termios * termios) { struct termios old_termios = *tty->termios; int canon_change; - canon_change = (old_termios.c_lflag ^ termios->c_lflag) & ICANON; cli(); *tty->termios = *termios; + unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); + canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON; if (canon_change) { - memset(&tty->secondary_flags, 0, sizeof tty->secondary_flags); - tty->canon_head = tty->secondary.tail; + memset(&tty->read_flags, 0, sizeof tty->read_flags); + tty->canon_head = tty->read_tail; tty->canon_data = 0; tty->erasing = 0; } sti(); - if (canon_change && !L_ICANON(tty) && !EMPTY(&tty->secondary)) + if (canon_change && !L_ICANON(tty) && tty->read_cnt) /* Get characters left over from canonical mode. */ - wake_up_interruptible(&tty->secondary.proc_list); + wake_up_interruptible(&tty->read_wait); /* see if packet mode change of state */ @@ -215,21 +117,20 @@ tty->ctrl_status |= TIOCPKT_DOSTOP; else tty->ctrl_status |= TIOCPKT_NOSTOP; - wake_up_interruptible(&tty->link->secondary.proc_list); + wake_up_interruptible(&tty->link->read_wait); } } - unset_locked_termios(tty->termios, &old_termios, - termios_locked[tty->line]); + if (tty->driver.set_termios) + (*tty->driver.set_termios)(tty, &old_termios); - if (tty->set_termios) - (*tty->set_termios)(tty, &old_termios); - + if (tty->ldisc.set_termios) + (*tty->ldisc.set_termios)(tty, &old_termios); + return 0; } -static int set_termios(struct tty_struct * tty, struct termios * termios, - int channel) +static int set_termios(struct tty_struct * tty, struct termios * termios) { struct termios tmp_termios; @@ -256,8 +157,7 @@ return 0; } -static int set_termio(struct tty_struct * tty, struct termio * termio, - int channel) +static int set_termio(struct tty_struct * tty, struct termio * termio) { struct termio tmp_termio; struct termios tmp_termios; @@ -278,92 +178,37 @@ return set_termios_2(tty, &tmp_termios); } -static int set_window_size(struct tty_struct * tty, struct winsize * ws) -{ - struct winsize tmp_ws; - - memcpy_fromfs(&tmp_ws, ws, sizeof (struct winsize)); - if (memcmp(&tmp_ws, &tty->winsize, sizeof (struct winsize)) && - tty->pgrp > 0) - kill_pg(tty->pgrp, SIGWINCH, 1); - tty->winsize = tmp_ws; - return 0; -} - -/* Set the discipline of a tty line. */ -static int tty_set_ldisc(struct tty_struct *tty, int ldisc) -{ - if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS) || - !(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) - return -EINVAL; - - if (tty->disc == ldisc) - return 0; /* We are already in the desired discipline */ - - /* Shutdown the current discipline. */ - wait_until_sent(tty, 0); - flush_input(tty); - if (ldiscs[tty->disc].close) - ldiscs[tty->disc].close(tty); - - /* Now set up the new line discipline. */ - tty->disc = ldisc; - tty->termios->c_line = ldisc; - if (ldiscs[tty->disc].open) - return(ldiscs[tty->disc].open(tty)); - else - return 0; -} - static unsigned long inq_canon(struct tty_struct * tty) { int nr, head, tail; - if (!tty->canon_data) + if (!tty->canon_data || !tty->read_buf) return 0; head = tty->canon_head; - tail = tty->secondary.tail; - nr = (head - tail) & (TTY_BUF_SIZE-1); + tail = tty->read_tail; + nr = (head - tail) & (N_TTY_BUF_SIZE-1); /* Skip EOF-chars.. */ while (head != tail) { - if (test_bit(tail, &tty->secondary_flags) && - tty->secondary.buf[tail] == __DISABLED_CHAR) + if (test_bit(tail, &tty->read_flags) && + tty->read_buf[tail] == __DISABLED_CHAR) nr--; - INC(tail); + tail = (tail+1) & (N_TTY_BUF_SIZE-1); } return nr; } -int tty_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) +int n_tty_ioctl(struct tty_struct * tty, struct file * file, + unsigned int cmd, unsigned long arg) { - struct tty_struct * tty; - struct tty_struct * other_tty; - struct tty_struct * termios_tty; - pid_t pgrp; - int dev; - int termios_dev; + struct tty_struct * real_tty; int retval; - if (MAJOR(file->f_rdev) != TTY_MAJOR) { - printk("tty_ioctl: tty pseudo-major != TTY_MAJOR\n"); - return -EINVAL; - } - dev = MINOR(file->f_rdev); - tty = TTY_TABLE(dev); - if (!tty) - return -EINVAL; - if (IS_A_PTY(dev)) - other_tty = tty_table[PTY_OTHER(dev)]; + if (tty->driver.type == TTY_DRIVER_TYPE_PTY && + tty->driver.subtype == PTY_TYPE_MASTER) + real_tty = tty->link; else - other_tty = NULL; - if (IS_A_PTY_MASTER(dev)) { - termios_tty = other_tty; - termios_dev = PTY_OTHER(dev); - } else { - termios_tty = tty; - termios_dev = dev; - } + real_tty = tty; + switch (cmd) { case TCGETS: retval = verify_area(VERIFY_WRITE, (void *) arg, @@ -371,39 +216,40 @@ if (retval) return retval; memcpy_tofs((struct termios *) arg, - termios_tty->termios, + real_tty->termios, sizeof (struct termios)); return 0; case TCSETSF: case TCSETSW: case TCSETS: - retval = check_change(termios_tty, termios_dev); + retval = tty_check_change(real_tty); if (retval) return retval; if (cmd == TCSETSF || cmd == TCSETSW) { - if (cmd == TCSETSF) - flush_input(termios_tty); - wait_until_sent(termios_tty, 0); + if (cmd == TCSETSF && + real_tty->ldisc.flush_buffer) + real_tty->ldisc.flush_buffer(real_tty); + wait_until_sent(real_tty, 0); } - return set_termios(termios_tty, (struct termios *) arg, - termios_dev); + return set_termios(real_tty, + (struct termios *) arg); case TCGETA: - return get_termio(termios_tty,(struct termio *) arg); + return get_termio(real_tty,(struct termio *) arg); case TCSETAF: case TCSETAW: case TCSETA: - retval = check_change(termios_tty, termios_dev); + retval = tty_check_change(real_tty); if (retval) return retval; if (cmd == TCSETAF || cmd == TCSETAW) { - if (cmd == TCSETAF) - flush_input(termios_tty); - wait_until_sent(termios_tty, 0); + if (cmd == TCSETAF && + real_tty->ldisc.flush_buffer) + real_tty->ldisc.flush_buffer(real_tty); + wait_until_sent(real_tty, 0); } - return set_termio(termios_tty, (struct termio *) arg, - termios_dev); + return set_termio(real_tty, (struct termio *) arg); case TCXONC: - retval = check_change(tty, dev); + retval = tty_check_change(tty); if (retval) return retval; switch (arg) { @@ -415,107 +261,49 @@ break; case TCIOFF: if (STOP_CHAR(tty) != __DISABLED_CHAR) - put_tty_queue(STOP_CHAR(tty), - &tty->write_q); + tty->driver.write(tty, 0, + &STOP_CHAR(tty), 1); break; case TCION: if (START_CHAR(tty) != __DISABLED_CHAR) - put_tty_queue(START_CHAR(tty), - &tty->write_q); + tty->driver.write(tty, 0, + &START_CHAR(tty), 1); break; default: return -EINVAL; } return 0; case TCFLSH: - retval = check_change(tty, dev); + retval = tty_check_change(tty); if (retval) return retval; switch (arg) { case TCIFLUSH: - flush_input(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); break; case TCIOFLUSH: - flush_input(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); /* fall through */ case TCOFLUSH: - flush_output(tty); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); break; default: return -EINVAL; } return 0; - case TIOCEXCL: - set_bit(TTY_EXCLUSIVE, &tty->flags); - return 0; - case TIOCNXCL: - clear_bit(TTY_EXCLUSIVE, &tty->flags); - return 0; - case TIOCSCTTY: - if (current->leader && - (current->session == tty->session)) - return 0; - /* - * The process must be a session leader and - * not have a controlling tty already. - */ - if (!current->leader || (current->tty >= 0)) - return -EPERM; - if (tty->session > 0) { - /* - * This tty is already the controlling - * tty for another session group! - */ - if ((arg == 1) && suser()) { - /* - * Steal it away - */ - struct task_struct *p; - - for_each_task(p) - if (p->tty == dev) - p->tty = -1; - } else - return -EPERM; - } - current->tty = dev; - tty->session = current->session; - tty->pgrp = current->pgrp; - return 0; - case TIOCGPGRP: - retval = verify_area(VERIFY_WRITE, (void *) arg, - sizeof (pid_t)); - if (retval) - return retval; - /* If a master pty, return the slave's tpgid. - If not, only return the tpgid if this is - the controlling tty. */ - if (tty == termios_tty && current->tty != dev) - return -ENOTTY; - put_fs_long(termios_tty->pgrp, (pid_t *) arg); - return 0; - case TIOCSPGRP: - retval = check_change(termios_tty, termios_dev); - if (retval) - return retval; - if ((current->tty < 0) || - (current->tty != termios_dev) || - (termios_tty->session != current->session)) - return -ENOTTY; - pgrp = get_fs_long((pid_t *) arg); - if (pgrp < 0) - return -EINVAL; - if (session_of_pgrp(pgrp) != current->session) - return -EPERM; - termios_tty->pgrp = pgrp; - return 0; case TIOCOUTQ: retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof (unsigned long)); if (retval) return retval; - put_fs_long(CHARS(&tty->write_q), - (unsigned long *) arg); + if (tty->driver.chars_in_buffer) + put_fs_long(tty->driver.chars_in_buffer(tty), + (unsigned long *) arg); + else + put_fs_long(0, (unsigned long *) arg); return 0; case TIOCINQ: retval = verify_area(VERIFY_WRITE, (void *) arg, @@ -526,94 +314,9 @@ put_fs_long(inq_canon(tty), (unsigned long *) arg); else - put_fs_long(CHARS(&tty->secondary), - (unsigned long *) arg); - return 0; - case TIOCSTI: - if ((current->tty != dev) && !suser()) - return -EPERM; - retval = verify_area(VERIFY_READ, (void *) arg, 1); - if (retval) - return retval; - put_tty_queue(get_fs_byte((char *) arg), &tty->read_q); - TTY_READ_FLUSH(tty); - return 0; - case TIOCGWINSZ: - retval = verify_area(VERIFY_WRITE, (void *) arg, - sizeof (struct winsize)); - if (retval) - return retval; - memcpy_tofs((struct winsize *) arg, &tty->winsize, - sizeof (struct winsize)); - return 0; - case TIOCSWINSZ: - if (IS_A_PTY_MASTER(dev)) - set_window_size(other_tty,(struct winsize *) arg); - return set_window_size(tty,(struct winsize *) arg); - case TIOCLINUX: - switch (get_fs_byte((char *)arg)) - { - case 0: - return do_screendump(arg); - case 1: - return do_get_ps_info(arg); -#ifdef CONFIG_SELECTION - case 2: - return set_selection(arg); - case 3: - return paste_selection(tty); - case 4: - unblank_screen(); - return 0; -#endif /* CONFIG_SELECTION */ - default: - return -EINVAL; - } - case TIOCCONS: - if (IS_A_CONSOLE(dev)) { - if (!suser()) - return -EPERM; - redirect = NULL; - return 0; - } - if (redirect) - return -EBUSY; - if (!suser()) - return -EPERM; - if (IS_A_PTY_MASTER(dev)) - redirect = other_tty; - else if (IS_A_PTY_SLAVE(dev)) - redirect = tty; - else - return -ENOTTY; - return 0; - case FIONBIO: - arg = get_fs_long((unsigned long *) arg); - if (arg) - file->f_flags |= O_NONBLOCK; - else - file->f_flags &= ~O_NONBLOCK; - return 0; - case TIOCNOTTY: - if (current->tty != dev) - return -ENOTTY; - if (current->leader) - disassociate_ctty(0); - current->tty = -1; - return 0; - case TIOCGETD: - retval = verify_area(VERIFY_WRITE, (void *) arg, - sizeof (unsigned long)); - if (retval) - return retval; - put_fs_long(tty->disc, (unsigned long *) arg); + put_fs_long(tty->read_cnt, + (unsigned long *) arg); return 0; - case TIOCSETD: - retval = check_change(tty, dev); - if (retval) - return retval; - arg = get_fs_long((unsigned long *) arg); - return tty_set_ldisc(tty, arg); case TIOCGLCKTRMIOS: arg = get_fs_long((unsigned long *) arg); retval = verify_area(VERIFY_WRITE, (void *) arg, @@ -621,19 +324,20 @@ if (retval) return retval; memcpy_tofs((struct termios *) arg, - &termios_locked[termios_dev], + &real_tty->termios_locked, sizeof (struct termios)); return 0; case TIOCSLCKTRMIOS: if (!suser()) return -EPERM; arg = get_fs_long((unsigned long *) arg); - memcpy_fromfs(&termios_locked[termios_dev], + memcpy_fromfs(&real_tty->termios_locked, (struct termios *) arg, sizeof (struct termios)); return 0; case TIOCPKT: - if (!IS_A_PTY_MASTER(dev)) + if (tty->driver.type != TTY_DRIVER_TYPE_PTY || + tty->driver.subtype != PTY_TYPE_MASTER) return -ENOTTY; retval = verify_area(VERIFY_READ, (void *) arg, sizeof (unsigned long)); @@ -647,26 +351,18 @@ } else tty->packet = 0; return 0; + /* These two ioctl's always return success; even if */ + /* the driver doesn't support them. */ case TCSBRK: case TCSBRKP: - retval = check_change(tty, dev); + retval = tty_check_change(tty); if (retval) return retval; wait_until_sent(tty, 0); - if (!tty->ioctl) + if (!tty->driver.ioctl) return 0; - tty->ioctl(tty, file, cmd, arg); + tty->driver.ioctl(tty, file, cmd, arg); return 0; default: - if (tty->ioctl) { - retval = (tty->ioctl)(tty, file, cmd, arg); - if (retval != -EINVAL) - return retval; - } - if (ldiscs[tty->disc].ioctl) { - retval = (ldiscs[tty->disc].ioctl) - (tty, file, cmd, arg); - return retval; - } - return -EINVAL; - } + return -ENOIOCTLCMD; + } } diff -u --recursive --new-file v1.1.12/linux/drivers/char/vt.c linux/drivers/char/vt.c --- v1.1.12/linux/drivers/char/vt.c Fri Feb 11 13:06:42 1994 +++ linux/drivers/char/vt.c Mon May 23 07:55:14 1994 @@ -22,6 +22,8 @@ #include "vt_kern.h" #include "diacr.h" +extern struct tty_driver console_driver; + /* * Console (vt and kd) routines, as defined by USL SVR4 manual, and by * experimentation and study of X386 SYSV handling. @@ -119,11 +121,12 @@ int console, i; unsigned char ucval; struct kbd_struct * kbd; + struct vt_struct *vt = tty->driver_data; - console = tty->line - 1; + console = vt->vc_num; if (console < 0 || console >= NR_CONSOLES) - return -EINVAL; + return -ENOIOCTLCMD; kbd = kbd_table + console; switch (cmd) { @@ -234,7 +237,8 @@ default: return -EINVAL; } - flush_input(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); return 0; case KDGKBMODE: @@ -304,6 +308,13 @@ return -EINVAL; if (KVAL(v) > max_vals[KTYP(v)]) return -EINVAL; + /* + * Only the Superuser can set or unset the Secure + * Attention Key. + */ + if (((key_map[s][i] == K_SAK) || (v == K_SAK)) && + !suser()) + return -EPERM; key_map[s][i] = v; return 0; } @@ -473,8 +484,9 @@ return i; put_fs_word(fg_console + 1, &vtstat->v_active); state = 1; /* /dev/tty0 is always open */ - for (i = 1, mask = 2; i <= NR_CONSOLES; ++i, mask <<= 1) - if (tty_table[i] && tty_table[i]->count > 0) + for (i = 0, mask = 2; i < NR_CONSOLES; ++i, mask <<= 1) + if (console_driver.table[i] && + console_driver.table[i]->count > 0) state |= mask; put_fs_word(state, &vtstat->v_state); return 0; @@ -487,10 +499,12 @@ i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long)); if (i) return i; - for (i = 1; i <= NR_CONSOLES; ++i) - if (!tty_table[i] || tty_table[i]->count == 0) + for (i = 0; i < NR_CONSOLES; ++i) + if (!console_driver.table[i] || + console_driver.table[i]->count == 0) break; - put_fs_long(i <= NR_CONSOLES ? i : -1, (unsigned long *)arg); + put_fs_long(i < NR_CONSOLES ? (i+1) : -1, + (unsigned long *)arg); return 0; /* @@ -586,6 +600,6 @@ /* con_get_trans() defined in console.c */ default: - return -EINVAL; + return -ENOIOCTLCMD; } } diff -u --recursive --new-file v1.1.12/linux/drivers/char/vt_kern.h linux/drivers/char/vt_kern.h --- v1.1.12/linux/drivers/char/vt_kern.h Wed Dec 1 14:44:15 1993 +++ linux/drivers/char/vt_kern.h Mon May 23 07:55:14 1994 @@ -9,6 +9,7 @@ #include extern struct vt_struct { + int vc_num; /* The console number */ unsigned char vc_mode; /* KD_TEXT, ... */ unsigned char vc_kbdraw; unsigned char vc_kbde0; @@ -16,6 +17,7 @@ struct vt_mode vt_mode; int vt_pid; int vt_newvt; + struct wait_queue *paste_wait; } vt_cons[NR_CONSOLES]; void kd_mksound(unsigned int count, unsigned int ticks); diff -u --recursive --new-file v1.1.12/linux/drivers/net/3c501.c linux/drivers/net/3c501.c --- v1.1.12/linux/drivers/net/3c501.c Tue Apr 19 10:53:40 1994 +++ linux/drivers/net/3c501.c Mon May 23 08:16:49 1994 @@ -327,7 +327,7 @@ " gp=%03x rp=%03x.\n", dev->name, txsr, axsr, inw(ioaddr + EL1_DATAPTR), inw(ioaddr + EL1_RXPTR)); dev->tbusy = 0; - mark_bh(INET_BH); + mark_bh(NET_BH); } else if (txsr & TX_16COLLISIONS) { if (el_debug) printk("%s: Transmit failed 16 times, ethernet jammed?\n", @@ -349,7 +349,7 @@ printk(" Tx succeeded %s\n", (txsr & TX_RDY) ? "." : "but tx is busy!"); dev->tbusy = 0; - mark_bh(INET_BH); + mark_bh(NET_BH); } } else { int rxsr = inb(RX_STATUS); diff -u --recursive --new-file v1.1.12/linux/drivers/net/3c507.c linux/drivers/net/3c507.c --- v1.1.12/linux/drivers/net/3c507.c Tue Apr 19 10:53:41 1994 +++ linux/drivers/net/3c507.c Mon May 23 08:16:49 1994 @@ -530,7 +530,7 @@ lp->stats.tx_packets++; lp->stats.collisions += tx_status & 0xf; dev->tbusy = 0; - mark_bh(INET_BH); /* Inform upper layers. */ + mark_bh(NET_BH); /* Inform upper layers. */ } else { lp->stats.tx_errors++; if (tx_status & 0x0600) lp->stats.tx_carrier_errors++; diff -u --recursive --new-file v1.1.12/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v1.1.12/linux/drivers/net/3c509.c Sun May 1 12:12:22 1994 +++ linux/drivers/net/3c509.c Mon May 23 08:16:49 1994 @@ -31,6 +31,10 @@ #include #include #include +#ifdef MODULE +#include +#include "../../tools/version.h" +#endif @@ -312,6 +316,9 @@ printk("%s: Opened 3c509 IRQ %d status %4.4x.\n", dev->name, dev->irq, inw(ioaddr + EL3_STATUS)); +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif return 0; /* Always succeed */ } @@ -436,7 +443,7 @@ /* There's room in the FIFO for a full-sized packet. */ outw(0x6808, ioaddr + EL3_CMD); /* Ack IRQ */ dev->tbusy = 0; - mark_bh(INET_BH); + mark_bh(NET_BH); } if (status & 0x80) /* Statistics full. */ update_stats(ioaddr, dev); @@ -645,6 +652,9 @@ irq2dev_map[dev->irq] = 0; update_stats(ioaddr, dev); +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif return 0; } @@ -656,3 +666,29 @@ * tab-width: 4 * End: */ +#ifdef MODULE +char kernel_version[] = UTS_RELEASE; +static struct device dev_3c509 = { + "" /*"3c509"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, el3_probe }; + +int +init_module(void) +{ + if (register_netdev(&dev_3c509) != 0) + return -EIO; + return 0; +} + +void +cleanup_module(void) +{ + if (MOD_IN_USE) + printk("3c509: device busy, remove delayed\n"); + else + { + unregister_netdev(&dev_3c509); + kfree_s(dev_3c509.priv,sizeof(struct el3_private)); + dev_3c509.priv=NULL; + } +} +#endif /* MODULE */ diff -u --recursive --new-file v1.1.12/linux/drivers/net/8390.c linux/drivers/net/8390.c --- v1.1.12/linux/drivers/net/8390.c Tue Apr 19 10:53:41 1994 +++ linux/drivers/net/8390.c Mon May 23 08:16:50 1994 @@ -373,7 +373,7 @@ if (status & ENTSR_OWC) ei_local->stat.tx_window_errors++; } - mark_bh (INET_BH); + mark_bh (NET_BH); } /* We have a good packet(s), get it/them out of the buffers. */ @@ -476,7 +476,7 @@ outb(next_frame-1, e8390_base+EN0_BOUNDARY); } /* If any worth-while packets have been received, dev_rint() - has done a mark_bh(INET_BH) for us and will work on them + has done a mark_bh(NET_BH) for us and will work on them when we get to the bottom-half routine. */ /* Record the maximum Rx packet queue. */ diff -u --recursive --new-file v1.1.12/linux/drivers/net/CONFIG linux/drivers/net/CONFIG --- v1.1.12/linux/drivers/net/CONFIG Tue Feb 22 08:40:09 1994 +++ linux/drivers/net/CONFIG Mon May 23 08:16:50 1994 @@ -26,10 +26,10 @@ # CONFIG_PLIP The Crynwr-protocol PL/IP driver # INITIALTIMEOUTFACTOR Timing parameters. # MAXTIMEOUTFACTOR -# D_LINK The D-Link DE-600 Portable Ethernet Adaptor. -# D_LINK_IO The D-Link I/O address (0x378 == typical) -# D_LINK_IRQ The D-Link IRQ number to use (IRQ7 == typical) -# D_LINK_DEBUG Enable or disable D-Link debugging +# DE600 The D-Link DE-600 Portable Ethernet Adaptor. +# DE600_IO The DE600 I/O-port address (0x378 == default) +# DE600_IRQ The DE600 IRQ number to use (IRQ7 == default) +# DE600_DEBUG Enable or disable DE600 debugging (default off) # DEPCA The DIGITAL series of AT Ethernet Cards (DE100, DE200) # DEPCA_IRQ Set the desired IRQ (=0, for autoprobe) # DEPCA_DEBUG Set the desired debug level @@ -54,6 +54,3 @@ HP_OPTS = PLIP_OPTS = DEPCA_OPTS = -DDEPCA_IRQ=0 -DDEPCA_DEBUG=1 - -# The following are the only parameters that must be set in this file. -DL_OPTS = -DD_LINK_IO=0x378 -DD_LINK_IRQ=7 -UD_LINK_DEBUG diff -u --recursive --new-file v1.1.12/linux/drivers/net/MODULES linux/drivers/net/MODULES --- v1.1.12/linux/drivers/net/MODULES Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/MODULES Mon May 23 08:16:50 1994 @@ -0,0 +1,3 @@ +MODULES = \ + 3c509.o \ + de600.o diff -u --recursive --new-file v1.1.12/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v1.1.12/linux/drivers/net/Makefile Tue Apr 19 10:53:41 1994 +++ linux/drivers/net/Makefile Mon May 23 08:16:50 1994 @@ -6,16 +6,17 @@ # This will go away in some future future: hidden configuration files # are difficult for users to deal with. include CONFIG +include MODULES NETDRV_OBJS := net.a(Space.o) net.a(auto_irq.o) net.a(net_init.o) net.a(loopback.o) CFLAGS := $(CFLAGS) -I../../net/inet CPP := $(CPP) -I../../net/inet # The point of the makefile... -all: net.a +all: net.a modules Space.o: Space.c ../../include/linux/autoconf.h - $(CC) $(CFLAGS) $(OPTS) $(DL_OPTS) -c $< -o $@ + $(CC) $(CFLAGS) $(OPTS) -c $< -o $@ net_init.o: ../../include/linux/autoconf.h @@ -74,11 +75,8 @@ endif ifdef CONFIG_DE600 -NETDRV_OBJS := $(NETDRV_OBJS) net.a(d_link.o) -d_link.o: d_link.c CONFIG - $(CC) $(CPPFLAGS) $(CFLAGS) $(DL_OPTS) -c $< +NETDRV_OBJS := $(NETDRV_OBJS) net.a(de600.o) endif - ifdef CONFIG_AT1500 NETDRV_OBJS := $(NETDRV_OBJS) net.a(lance.o) endif @@ -129,8 +127,11 @@ NETDRV_OBJS := $(NETDRV_OBJS) net.a(8390.o) endif -ifdef CONFIG_IP_DEFRAG -NETDRV_OBJS := $(NETDRV_OBJS) net.a(ip-frag.o) +ifdef CONFIG_PI +NETDRV_OBJS := $(NETDRV_OBJS) net.a(pi2.o) +CONFIG_PI = CONFIG_PI +pi2.o: pi2.c CONFIG + $(CC) $(CPPFLAGS) $(CFLAGS) $(PI_OPTS) -c $< endif net.a: $(NETDRV_OBJS) @@ -144,6 +145,18 @@ tar: +ifdef MODULES + +modules: + echo $(MODULES) > ../../modules/NET_MODULES + $(MAKE) CFLAGS="$(CFLAGS) -DMODULE" $(MODULES) + (cd ../../modules;for i in $(MODULES); do ln -sf ../drivers/net/$$i .; done) + +else + +modules: + +endif # include a dependency file if one exists diff -u --recursive --new-file v1.1.12/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v1.1.12/linux/drivers/net/Space.c Tue Apr 19 10:53:42 1994 +++ linux/drivers/net/Space.c Mon May 23 08:16:50 1994 @@ -25,7 +25,6 @@ * 2 of the License, or (at your option) any later version. */ #include -#include #include #define LOOPBACK /* always present, right? */ @@ -56,7 +55,7 @@ /* Detachable devices ("pocket adaptors" and special PCMCIA drivers). */ extern int atp_init(struct device *); -extern int d_link_init(struct device *); +extern int de600_probe(struct device *); static int ethif_probe(struct device *dev) @@ -115,20 +114,15 @@ #ifdef CONFIG_E2100 /* Cabletron E21xx series. */ && e2100_probe(dev) #endif +#ifdef CONFIG_DE600 + && de600_probe(dev) +#endif && 1 ) { return 1; /* -ENODEV or -EAGAIN would be more accurate. */ } return 0; } - -/* This remains seperate because it requires the addr and IRQ to be set. */ -#if defined(D_LINK) || defined(CONFIG_DE600) -static struct device d_link_dev = { - "dl0", 0, 0, 0, 0, D_LINK_IO, D_LINK_IRQ, 0, 0, 0, NEXT_DEV, d_link_init }; -# undef NEXT_DEV -# define NEXT_DEV (&d_link_dev) -#endif /* Run-time ATtachable (Pocket) devices have a different (not "eth#") name. */ #ifdef CONFIG_ATP /* AT-LAN-TEC (RealTek) pocket adaptor. */ diff -u --recursive --new-file v1.1.12/linux/drivers/net/at1700.c linux/drivers/net/at1700.c --- v1.1.12/linux/drivers/net/at1700.c Tue Apr 19 10:53:42 1994 +++ linux/drivers/net/at1700.c Mon May 23 08:16:50 1994 @@ -448,7 +448,7 @@ lp->tx_queue_len = 0; dev->trans_start = jiffies; dev->tbusy = 0; - mark_bh(INET_BH); /* Inform upper layers. */ + mark_bh(NET_BH); /* Inform upper layers. */ } else { lp->tx_started = 0; /* Turn on Tx interrupts off. */ @@ -529,7 +529,7 @@ } /* If any worth-while packets have been received, dev_rint() - has done a mark_bh(INET_BH) for us and will work on them + has done a mark_bh(NET_BH) for us and will work on them when we get to the bottom-half routine. */ { int i; diff -u --recursive --new-file v1.1.12/linux/drivers/net/atp.c linux/drivers/net/atp.c --- v1.1.12/linux/drivers/net/atp.c Tue Apr 19 10:53:42 1994 +++ linux/drivers/net/atp.c Mon May 23 08:16:50 1994 @@ -558,7 +558,7 @@ } else lp->tx_unit_busy = 0; dev->tbusy = 0; - mark_bh(INET_BH); /* Inform upper layers. */ + mark_bh(NET_BH); /* Inform upper layers. */ } num_tx_since_rx++; } else if (num_tx_since_rx > 8 diff -u --recursive --new-file v1.1.12/linux/drivers/net/de600.c linux/drivers/net/de600.c --- v1.1.12/linux/drivers/net/de600.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/de600.c Mon May 23 08:16:51 1994 @@ -0,0 +1,772 @@ +static char *version = + "de600.c: $Revision: 1.35 $, Bjorn Ekwall (bj0rn@blox.se)\n"; +/* + * de600.c + * + * Linux driver for the D-Link DE-600 Ethernet pocket adapter. + * + * Portions (C) Copyright 1993 by Bjorn Ekwall + * The Author may be reached as bj0rn@blox.se + * + * Based on adapter information gathered from DE600.ASM by D-Link Inc., + * as included on disk C in the v.2.11 of PC/TCP from FTP Software. + * For DE600.asm: + * Portions (C) Copyright 1990 D-Link, Inc. + * Copyright, 1988-1992, Russell Nelson, Crynwr Software + * + * Adapted to the sample network driver core for linux, + * written by: Donald Becker + * C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 + * + * compile-command: + * "gcc -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer \ + * -m486 -c de600.c + * + **************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + **************************************************************/ +/* Add another "; SLOW_DOWN_IO" here if your adapter won't work OK: */ +#define DE600_SLOW_DOWN SLOW_DOWN_IO; SLOW_DOWN_IO; SLOW_DOWN_IO + + /* + * If you still have trouble reading/writing to the adapter, + * modify the following "#define": (see for more info) +#define REALLY_SLOW_IO + */ +#define SLOW_IO_BY_JUMPING /* Looks "better" than dummy write to port 0x80 :-) */ + +/* + * For fix to TCP "slowdown", take a look at the "#define DE600_MAX_WINDOW" + * near the end of the file... + */ + +/* use 0 for production, 1 for verification, >2 for debug */ +#ifdef DE600_DEBUG +#define PRINTK(x) if (de600_debug >= 2) printk x +#else +#define DE600_DEBUG 0 +#define PRINTK(x) /**/ +#endif +static unsigned int de600_debug = DE600_DEBUG; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef MODULE +#include +#include "../../tools/version.h" +#endif + +#define netstats enet_statistics + +/************************************************** + * * + * Definition of D-Link Ethernet Pocket adapter * + * * + **************************************************/ +/* + * D-Link Ethernet pocket adapter ports + */ +/* + * OK, so I'm cheating, but there are an awful lot of + * reads and writes in order to get anything in and out + * of the DE-600 with 4 bits at a time in the parallel port, + * so every saved instruction really helps :-) + * + * That is, I don't care what the device struct says + * but hope that Space.c will keep the rest of the drivers happy. + */ +#ifndef DE600_IO +#define DE600_IO 0x378 +#endif + +#define DATA_PORT (DE600_IO) +#define STATUS_PORT (DE600_IO + 1) +#define COMMAND_PORT (DE600_IO + 2) + +#ifndef DE600_IRQ +#define DE600_IRQ 7 +#endif +/* + * It really should look like this, and autoprobing as well... + * +#define DATA_PORT (dev->base_addr + 0) +#define STATUS_PORT (dev->base_addr + 1) +#define COMMAND_PORT (dev->base_addr + 2) +#define DE600_IRQ dev->irq + */ + +/* + * D-Link COMMAND_PORT commands + */ +#define SELECT_NIC 0x04 /* select Network Interface Card */ +#define SELECT_PRN 0x1c /* select Printer */ +#define NML_PRN 0xec /* normal Printer situation */ +#define IRQEN 0x10 /* enable IRQ line */ + +/* + * D-Link STATUS_PORT + */ +#define RX_BUSY 0x80 +#define RX_GOOD 0x40 +#define TX_FAILED16 0x10 +#define TX_BUSY 0x08 + +/* + * D-Link DATA_PORT commands + * command in low 4 bits + * data in high 4 bits + * select current data nibble with HI_NIBBLE bit + */ +#define WRITE_DATA 0x00 /* write memory */ +#define READ_DATA 0x01 /* read memory */ +#define STATUS 0x02 /* read status register */ +#define COMMAND 0x03 /* write command register (see COMMAND below) */ +#define NULL_COMMAND 0x04 /* null command */ +#define RX_LEN 0x05 /* read received packet length */ +#define TX_ADDR 0x06 /* set adapter transmit memory address */ +#define RW_ADDR 0x07 /* set adapter read/write memory address */ +#define HI_NIBBLE 0x08 /* read/write the high nibble of data, + or-ed with rest of command */ + +/* + * command register, accessed through DATA_PORT with low bits = COMMAND + */ +#define RX_ALL 0x01 /* PROMISCIOUS */ +#define RX_BP 0x02 /* default: BROADCAST & PHYSICAL ADRESS */ +#define RX_MBP 0x03 /* MULTICAST, BROADCAST & PHYSICAL ADRESS */ + +#define TX_ENABLE 0x04 /* bit 2 */ +#define RX_ENABLE 0x08 /* bit 3 */ + +#define RESET 0x80 /* set bit 7 high */ +#define STOP_RESET 0x00 /* set bit 7 low */ + +/* + * data to command register + * (high 4 bits in write to DATA_PORT) + */ +#define RX_PAGE2_SELECT 0x10 /* bit 4, only 2 pages to select */ +#define RX_BASE_PAGE 0x20 /* bit 5, always set when specifying RX_ADDR */ +#define FLIP_IRQ 0x40 /* bit 6 */ + +/* + * D-Link adapter internal memory: + * + * 0-2K 1:st transmit page (send from pointer up to 2K) + * 2-4K 2:nd transmit page (send from pointer up to 4K) + * + * 4-6K 1:st receive page (data from 4K upwards) + * 6-8K 2:nd receive page (data from 6K upwards) + * + * 8K+ Adapter ROM (contains magic code and last 3 bytes of Ethernet address) + */ +#define MEM_2K 0x0800 /* 2048 */ +#define MEM_4K 0x1000 /* 4096 */ +#define MEM_6K 0x1800 /* 6144 */ +#define NODE_ADDRESS 0x2000 /* 8192 */ + +#define RUNT 60 /* Too small Ethernet packet */ + +/************************************************** + * * + * End of definition * + * * + **************************************************/ + +/* + * Index to functions, as function prototypes. + */ +#if 0 +/* For tricking tcp.c to announce a small max window (max 2 fast packets please :-) */ +static unsigned long de600_rspace(struct sock *sk); +#endif + +/* Routines used internally. (See "convenience macros") */ +static int de600_read_status(struct device *dev); +static unsigned char de600_read_byte(unsigned char type, struct device *dev); + +/* Put in the device structure. */ +static int de600_open(struct device *dev); +static int de600_close(struct device *dev); +static struct netstats *get_stats(struct device *dev); +static int de600_start_xmit(struct sk_buff *skb, struct device *dev); + +/* Dispatch from interrupts. */ +static void de600_interrupt(int reg_ptr); +static int de600_tx_intr(struct device *dev, int irq_status); +static void de600_rx_intr(struct device *dev); + +/* Initialization */ +static void trigger_interrupt(struct device *dev); +int de600_probe(struct device *dev); +static void adapter_init(struct device *dev); + +/* + * D-Link driver variables: + */ +extern struct device *irq2dev_map[16]; +static volatile int rx_page = 0; + +#define TX_PAGES 2 +static volatile int tx_fifo[TX_PAGES]; +static volatile int tx_fifo_in = 0; +static volatile int tx_fifo_out = 0; +static volatile int free_tx_pages = TX_PAGES; + +/* + * Convenience macros/functions for D-Link adapter + */ + +#define select_prn() outb_p(SELECT_PRN, COMMAND_PORT); DE600_SLOW_DOWN +#define select_nic() outb_p(SELECT_NIC, COMMAND_PORT); DE600_SLOW_DOWN + +/* Thanks for hints from Mark Burton */ +#define de600_put_byte(data) ( \ + outb_p(((data) << 4) | WRITE_DATA , DATA_PORT), \ + outb_p(((data) & 0xf0) | WRITE_DATA | HI_NIBBLE, DATA_PORT)) + +/* + * The first two outb_p()'s below could perhaps be deleted if there + * would be more delay in the last two. Not certain about it yet... + */ +#define de600_put_command(cmd) ( \ + outb_p(( rx_page << 4) | COMMAND , DATA_PORT), \ + outb_p(( rx_page & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT), \ + outb_p(((rx_page | cmd) << 4) | COMMAND , DATA_PORT), \ + outb_p(((rx_page | cmd) & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT)) + +#define de600_setup_address(addr,type) ( \ + outb_p((((addr) << 4) & 0xf0) | type , DATA_PORT), \ + outb_p(( (addr) & 0xf0) | type | HI_NIBBLE, DATA_PORT), \ + outb_p((((addr) >> 4) & 0xf0) | type , DATA_PORT), \ + outb_p((((addr) >> 8) & 0xf0) | type | HI_NIBBLE, DATA_PORT)) + +#define rx_page_adr() ((rx_page & RX_PAGE2_SELECT)?(MEM_6K):(MEM_4K)) + +/* Flip bit, only 2 pages */ +#define next_rx_page() (rx_page ^= RX_PAGE2_SELECT) + +#define tx_page_adr(a) (((a) + 1) * MEM_2K) + +static inline int +de600_read_status(struct device *dev) +{ + int status; + + outb_p(STATUS, DATA_PORT); + status = inb(STATUS_PORT); + outb_p(NULL_COMMAND | HI_NIBBLE, DATA_PORT); + + return status; +} + +static inline unsigned char +de600_read_byte(unsigned char type, struct device *dev) { /* dev used by macros */ + unsigned char lo; + + (void)outb_p((type), DATA_PORT); + lo = ((unsigned char)inb(STATUS_PORT)) >> 4; + (void)outb_p((type) | HI_NIBBLE, DATA_PORT); + return ((unsigned char)inb(STATUS_PORT) & (unsigned char)0xf0) | lo; +} + +/* + * Open/initialize the board. This is called (in the current kernel) + * after booting when 'ifconfig name> $IP_ADDR' is run (in rc.inet1). + * + * This routine should set everything up anew at each open, even + * registers that "should" only need to be set once at boot, so that + * there is a non-reboot way to recover if something goes wrong. + */ +static int +de600_open(struct device *dev) +{ +#if 0 + extern struct proto tcp_prot; +#endif + + if (request_irq(DE600_IRQ, de600_interrupt)) { + printk ("%s: unable to get IRQ %d\n", dev->name, DE600_IRQ); + return 1; + } + irq2dev_map[DE600_IRQ] = dev; + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + adapter_init(dev); + + /* + * Yes, I know! + * This is really not nice, but since a machine that uses DE-600 + * rarely uses any other TCP/IP connection device simultaneously, + * this hack shouldn't really slow anything up. + * (I don't know about slip though... but it won't break it) + * + * This fix is better than changing in tcp.h IMHO + */ +#if 0 + tcp_prot.rspace = de600_rspace; /* was: sock_rspace */ +#endif + + + return 0; +} + +/* + * The inverse routine to de600_open(). + */ +static int +de600_close(struct device *dev) +{ + select_nic(); + rx_page = 0; + de600_put_command(RESET); + de600_put_command(STOP_RESET); + de600_put_command(0); + select_prn(); + + free_irq(DE600_IRQ); + irq2dev_map[DE600_IRQ] = NULL; + dev->start = 0; +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +#if 0 + tcp_prot.rspace = sock_rspace; /* see comment above! */ +#endif + return 0; +} + +static struct netstats * +get_stats(struct device *dev) +{ + return (struct netstats *)(dev->priv); +} + +static inline void +trigger_interrupt(struct device *dev) +{ + de600_put_command(FLIP_IRQ); + select_prn(); + DE600_SLOW_DOWN; + select_nic(); + de600_put_command(0); +} + +/* + * Copy a buffer to the adapter transmit page memory. + * Start sending. + */ +static int +de600_start_xmit(struct sk_buff *skb, struct device *dev) +{ + int transmit_from; + int len; + int tickssofar; + unsigned char *buffer = skb->data; + + /* + * If some higher layer thinks we've missed a + * tx-done interrupt we are passed NULL. + * Caution: dev_tint() handles the cli()/sti() itself. + */ + + if (skb == NULL) { + dev_tint(dev); + return 0; + } + + if (free_tx_pages <= 0) { /* Do timeouts, to avoid hangs. */ + tickssofar = jiffies - dev->trans_start; + + if (tickssofar < 5) + return 1; + + /* else */ + printk("%s: transmit timed out (%d), %s?\n", + dev->name, + tickssofar, + "network cable problem" + ); + /* Restart the adapter. */ + adapter_init(dev); + } + + /* Start real output */ + PRINTK(("de600_start_xmit:len=%d, page %d/%d\n", skb->len, tx_fifo_in, free_tx_pages)); + + if ((len = skb->len) < RUNT) + len = RUNT; + + cli(); + select_nic(); + + tx_fifo[tx_fifo_in] = transmit_from = tx_page_adr(tx_fifo_in) - len; + tx_fifo_in = (tx_fifo_in + 1) % TX_PAGES; /* Next free tx page */ + + de600_setup_address(transmit_from, RW_ADDR); + for ( ; len > 0; --len, ++buffer) + de600_put_byte(*buffer); + + if (free_tx_pages-- == TX_PAGES) { /* No transmission going on */ + dev->trans_start = jiffies; + dev->tbusy = 0; /* allow more packets into adapter */ + /* Send page and generate an interrupt */ + de600_setup_address(transmit_from, TX_ADDR); + de600_put_command(TX_ENABLE); + } + else { + dev->tbusy = !free_tx_pages; + select_prn(); + } + + sti(); /* interrupts back on */ + + if (skb->free) + kfree_skb (skb, FREE_WRITE); + + return 0; +} + +/* + * The typical workload of the driver: + * Handle the network interface interrupts. + */ +static void +de600_interrupt(int reg_ptr) +{ + int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2); + struct device *dev = irq2dev_map[irq]; + unsigned char irq_status; + int retrig = 0; + int boguscount = 0; + + /* This might just as well be deleted now, no crummy drivers present :-) */ + if ((dev == NULL) || (dev->start == 0) || (DE600_IRQ != irq)) { + printk("%s: bogus interrupt %d\n", dev?dev->name:"DE-600", irq); + return; + } + + dev->interrupt = 1; + select_nic(); + irq_status = de600_read_status(dev); + + do { + PRINTK(("de600_interrupt (%2.2X)\n", irq_status)); + + if (irq_status & RX_GOOD) + de600_rx_intr(dev); + else if (!(irq_status & RX_BUSY)) + de600_put_command(RX_ENABLE); + + /* Any transmission in progress? */ + if (free_tx_pages < TX_PAGES) + retrig = de600_tx_intr(dev, irq_status); + else + retrig = 0; + + irq_status = de600_read_status(dev); + } while ( (irq_status & RX_GOOD) || ((++boguscount < 10) && retrig) ); + /* + * Yeah, it _looks_ like busy waiting, smells like busy waiting + * and I know it's not PC, but please, it will only occur once + * in a while and then only for a loop or so (< 1ms for sure!) + */ + + /* Enable adapter interrupts */ + dev->interrupt = 0; + select_prn(); + + if (retrig) + trigger_interrupt(dev); + + sti(); + return; +} + +static int +de600_tx_intr(struct device *dev, int irq_status) +{ + /* + * Returns 1 if tx still not done + */ + + mark_bh(NET_BH); + /* Check if current transmission is done yet */ + if (irq_status & TX_BUSY) + return 1; /* tx not done, try again */ + + /* else */ + /* If last transmission OK then bump fifo index */ + if (!(irq_status & TX_FAILED16)) { + tx_fifo_out = (tx_fifo_out + 1) % TX_PAGES; + ++free_tx_pages; + ((struct netstats *)(dev->priv))->tx_packets++; + dev->tbusy = 0; + } + + /* More to send, or resend last packet? */ + if ((free_tx_pages < TX_PAGES) || (irq_status & TX_FAILED16)) { + dev->trans_start = jiffies; + de600_setup_address(tx_fifo[tx_fifo_out], TX_ADDR); + de600_put_command(TX_ENABLE); + return 1; + } + /* else */ + + return 0; +} + +/* + * We have a good packet, get it out of the adapter. + */ +static void +de600_rx_intr(struct device *dev) +{ + struct sk_buff *skb; + int i; + int read_from; + int size; + register unsigned char *buffer; + + cli(); + /* Get size of received packet */ + size = de600_read_byte(RX_LEN, dev); /* low byte */ + size += (de600_read_byte(RX_LEN, dev) << 8); /* high byte */ + size -= 4; /* Ignore trailing 4 CRC-bytes */ + + /* Tell adapter where to store next incoming packet, enable receiver */ + read_from = rx_page_adr(); + next_rx_page(); + de600_put_command(RX_ENABLE); + sti(); + + if ((size < 32) || (size > 1535)) + printk("%s: Bogus packet size %d.\n", dev->name, size); + + skb = alloc_skb(size, GFP_ATOMIC); + sti(); + if (skb == NULL) { + printk("%s: Couldn't allocate a sk_buff of size %d.\n", + dev->name, size); + return; + } + /* else */ + + skb->lock = 0; + /* 'skb->data' points to the start of sk_buff data area. */ + buffer = skb->data; + + /* copy the packet into the buffer */ + de600_setup_address(read_from, RW_ADDR); + for (i = size; i > 0; --i, ++buffer) + *buffer = de600_read_byte(READ_DATA, dev); + + ((struct netstats *)(dev->priv))->rx_packets++; /* count all receives */ + + if (dev_rint((unsigned char *)skb, size, IN_SKBUFF, dev)) + printk("%s: receive buffers full.\n", dev->name); + /* + * If any worth-while packets have been received, dev_rint() + * has done a mark_bh(INET_BH) for us and will work on them + * when we get to the bottom-half routine. + */ +} + +int +de600_probe(struct device *dev) +{ + int i; + static struct netstats de600_netstats; + /*dev->priv = kmalloc(sizeof(struct netstats), GFP_KERNEL);*/ + + printk("%s: D-Link DE-600 pocket adapter", dev->name); + /* Alpha testers must have the version number to report bugs. */ + if (de600_debug > 1) + printk(version); + + /* probe for adapter */ + rx_page = 0; + select_nic(); + (void)de600_read_status(dev); + de600_put_command(RESET); + de600_put_command(STOP_RESET); + if (de600_read_status(dev) & 0xf0) { + printk(": not at I/O %#3x.\n", DATA_PORT); + return ENODEV; + } + + /* + * Maybe we found one, + * have to check if it is a D-Link DE-600 adapter... + */ + + /* Get the adapter ethernet address from the ROM */ + de600_setup_address(NODE_ADDRESS, RW_ADDR); + for (i = 0; i < ETH_ALEN; i++) { + dev->dev_addr[i] = de600_read_byte(READ_DATA, dev); + dev->broadcast[i] = 0xff; + } + + /* Check magic code */ + if ((dev->dev_addr[1] == 0xde) && (dev->dev_addr[2] == 0x15)) { + /* OK, install real address */ + dev->dev_addr[0] = 0x00; + dev->dev_addr[1] = 0x80; + dev->dev_addr[2] = 0xc8; + dev->dev_addr[3] &= 0x0f; + dev->dev_addr[3] |= 0x70; + } else { + printk(" not identified in the printer port\n"); + return ENODEV; + } + + printk(", Ethernet Address: %2.2X", dev->dev_addr[0]); + for (i = 1; i < ETH_ALEN; i++) + printk(":%2.2X",dev->dev_addr[i]); + printk("\n"); + + /* Initialize the device structure. */ + /*dev->priv = kmalloc(sizeof(struct netstats), GFP_KERNEL);*/ + dev->priv = &de600_netstats; + + memset(dev->priv, 0, sizeof(struct netstats)); + dev->get_stats = get_stats; + + dev->open = de600_open; + dev->stop = de600_close; + dev->hard_start_xmit = &de600_start_xmit; + + ether_setup(dev); + + select_prn(); + return 0; +} + +static void +adapter_init(struct device *dev) +{ + int i; + + cli(); + dev->tbusy = 0; /* Transmit busy... */ + dev->interrupt = 0; + dev->start = 1; + + select_nic(); + rx_page = 0; /* used by RESET */ + de600_put_command(RESET); + de600_put_command(STOP_RESET); + + tx_fifo_in = 0; + tx_fifo_out = 0; + free_tx_pages = TX_PAGES; + + /* set the ether address. */ + de600_setup_address(NODE_ADDRESS, RW_ADDR); + for (i = 0; i < ETH_ALEN; i++) + de600_put_byte(dev->dev_addr[i]); + + /* where to start saving incoming packets */ + rx_page = RX_BP | RX_BASE_PAGE; + de600_setup_address(MEM_4K, RW_ADDR); + /* Enable receiver */ + de600_put_command(RX_ENABLE); + select_prn(); + sti(); +} + +#if 0 +/* + * The new router code (coming soon 8-) ) will fix this properly. + */ +#define DE600_MIN_WINDOW 1024 +#define DE600_MAX_WINDOW 2048 +#define DE600_TCP_WINDOW_DIFF 1024 +/* + * Copied from sock.c + * + * Sets a lower max receive window in order to achieve <= 2 + * packets arriving at the adapter in fast succession. + * (No way that a DE-600 can cope with an ethernet saturated with its packets :-) + * + * Since there are only 2 receive buffers in the DE-600 + * and it takes some time to copy from the adapter, + * this is absolutely necessary for any TCP performance whatsoever! + * + */ +#define min(a,b) ((a)<(b)?(a):(b)) +static unsigned long +de600_rspace(struct sock *sk) +{ + int amt; + + if (sk != NULL) { +/* + * Hack! You might want to play with commenting away the following line, + * if you know what you do! + */ + sk->max_unacked = DE600_MAX_WINDOW - DE600_TCP_WINDOW_DIFF; + + if (sk->rmem_alloc >= SK_RMEM_MAX-2*DE600_MIN_WINDOW) return(0); + amt = min((SK_RMEM_MAX-sk->rmem_alloc)/2-DE600_MIN_WINDOW, DE600_MAX_WINDOW); + if (amt < 0) return(0); + return(amt); + } + return(0); +} +#endif + +#ifdef MODULE +char kernel_version[] = UTS_RELEASE; +static struct device de600_dev = { + "" /*"de600"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, de600_probe }; + +int +init_module(void) +{ + if (register_netdev(&de600_dev) != 0) + return -EIO; + return 0; +} + +void +cleanup_module(void) +{ + if (MOD_IN_USE) + printk("de600: device busy, remove delayed\n"); + else + unregister_netdev(&de600_dev); +} +#endif /* MODULE */ diff -u --recursive --new-file v1.1.12/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c --- v1.1.12/linux/drivers/net/eexpress.c Tue Apr 19 10:53:43 1994 +++ linux/drivers/net/eexpress.c Mon May 23 08:16:51 1994 @@ -545,7 +545,7 @@ lp->stats.tx_packets++; lp->stats.collisions += tx_status & 0xf; dev->tbusy = 0; - mark_bh(INET_BH); /* Inform upper layers. */ + mark_bh(NET_BH); /* Inform upper layers. */ } else { lp->stats.tx_errors++; if (tx_status & 0x0600) lp->stats.tx_carrier_errors++; diff -u --recursive --new-file v1.1.12/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v1.1.12/linux/drivers/net/lance.c Tue Apr 19 10:53:44 1994 +++ linux/drivers/net/lance.c Mon May 23 08:16:51 1994 @@ -196,6 +196,7 @@ int dma; struct enet_statistics stats; char old_lance; + char lock; int pad0, pad1; /* Used for alignment */ }; @@ -434,6 +435,7 @@ struct lance_private *lp = (struct lance_private *)dev->priv; int i; + lp->lock = 0; lp->cur_rx = lp->cur_tx = 0; lp->dirty_rx = lp->dirty_tx = 0; @@ -515,8 +517,17 @@ /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); + return 1; + } + + if (set_bit(0, (void*)&lp->lock) != 0) { + if (lance_debug > 2) + printk("%s: tx queue lock!.\n", dev->name); + /* don't clear dev->tbusy flag. */ + return 1; + } /* Fill in a Tx ring entry */ @@ -549,8 +560,9 @@ } else { /* We can't free the packet yet, so we inform the memory management code that we are still using it. */ - if(skb->free==0) - skb_kept_by_device(skb); + + skb_kept_by_device(skb); + lp->tx_ring[entry].base = (int)(skb->data) | 0x83000000; } lp->cur_tx++; @@ -561,8 +573,11 @@ dev->trans_start = jiffies; + cli(); + lp->lock = 0; if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0) dev->tbusy=0; + sti(); return 0; } @@ -635,10 +650,8 @@ if (databuff >= (void*)(&lp->tx_bounce_buffs[TX_RING_SIZE]) || databuff < (void*)(lp->tx_bounce_buffs)) { struct sk_buff *skb = ((struct sk_buff *)databuff) - 1; - if (skb->free) - kfree_skb(skb, FREE_WRITE); - else - skb_device_release(skb,FREE_WRITE); + skb_device_release(skb,FREE_WRITE); + /* Warning: skb may well vanish at the point you call device_release! */ } @@ -656,7 +669,7 @@ if (dev->tbusy && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { /* The ring is no longer full, clear tbusy. */ dev->tbusy = 0; - mark_bh(INET_BH); + mark_bh(NET_BH); } lp->dirty_tx = dirty_tx; @@ -685,6 +698,7 @@ { struct lance_private *lp = (struct lance_private *)dev->priv; int entry = lp->cur_rx & RX_RING_MOD_MASK; + int i; /* If we own the next entry, it's a new packet. Send it up. */ while (lp->rx_ring[entry].base >= 0) { @@ -701,6 +715,7 @@ if (status & 0x10) lp->stats.rx_over_errors++; if (status & 0x08) lp->stats.rx_crc_errors++; if (status & 0x04) lp->stats.rx_fifo_errors++; + lp->rx_ring[entry].base &= 0x03ffffff; } else { /* Malloc up new buffer, compatible with net-2e. */ short pkt_len = lp->rx_ring[entry].msg_length; @@ -709,7 +724,15 @@ skb = alloc_skb(pkt_len, GFP_ATOMIC); if (skb == NULL) { printk("%s: Memory squeeze, deferring packet.\n", dev->name); - lp->stats.rx_dropped++; /* Really, deferred. */ + for (i=0; i < RX_RING_SIZE; i++) + if (lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].base < 0) + break; + + if (i > RX_RING_SIZE -2) { + lp->stats.rx_dropped++; + lp->rx_ring[entry].base |= 0x80000000; + lp->cur_rx++; + } break; } skb->len = pkt_len; diff -u --recursive --new-file v1.1.12/linux/drivers/net/loopback.c linux/drivers/net/loopback.c --- v1.1.12/linux/drivers/net/loopback.c Tue Apr 19 10:54:16 1994 +++ linux/drivers/net/loopback.c Mon May 23 08:16:52 1994 @@ -11,6 +11,8 @@ * Fred N. van Kempen, * Donald Becker, * + * Alan Cox : Fixed oddments for NET3.014 + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -44,7 +46,6 @@ struct enet_statistics *stats = (struct enet_statistics *)dev->priv; int done; - DPRINTF((DBG_LOOPB, "loopback_xmit(dev=%X, skb=%X)\n", dev, skb)); if (skb == NULL || dev == NULL) return(0); cli(); @@ -90,6 +91,12 @@ return (struct enet_statistics *)dev->priv; } +static int loopback_open(struct device *dev) +{ + dev->flags|=IFF_LOOPBACK; + return 0; +} + /* Initialize the rest of the LOOPBACK device. */ int loopback_init(struct device *dev) @@ -107,6 +114,7 @@ dev->type = ARPHRD_ETHER; /* 0x0001 */ dev->type_trans = eth_type_trans; dev->rebuild_header = eth_rebuild_header; + dev->open = loopback_open; #else dev->hard_header_length = 0; dev->addr_len = 0; @@ -119,10 +127,12 @@ /* New-style flags. */ dev->flags = IFF_LOOPBACK; dev->family = AF_INET; +#ifdef CONFIG_INET dev->pa_addr = in_aton("127.0.0.1"); dev->pa_brdaddr = in_aton("127.255.255.255"); dev->pa_mask = in_aton("255.0.0.0"); dev->pa_alen = sizeof(unsigned long); +#endif dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL); memset(dev->priv, 0, sizeof(struct enet_statistics)); dev->get_stats = get_stats; diff -u --recursive --new-file v1.1.12/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v1.1.12/linux/drivers/net/net_init.c Tue Apr 19 10:53:44 1994 +++ linux/drivers/net/net_init.c Mon May 23 08:16:52 1994 @@ -14,6 +14,8 @@ It's primary advantage is that it's able to allocate low-memory buffers. A secondary advantage is that the dangerous NE*000 netcards can reserve their I/O port region before the SCSI probes start. + + register_netdev()/unregister_netdev() by Bjorn Ekwall */ #include @@ -60,7 +62,9 @@ #if defined(CONFIG_LANCE) /* Note this is _not_ CONFIG_AT1500. */ mem_start = lance_init(mem_start, mem_end); #endif - +#if defined(CONFIG_PI) + mem_start = pi_init(mem_start, mem_end); +#endif return mem_start; } @@ -161,6 +165,73 @@ dev->pa_alen = sizeof(unsigned long); } +int register_netdev(struct device *dev) +{ + struct device *d = dev_base; + unsigned long flags; + + save_flags(flags); + cli(); + + if (dev && dev->init) + { + if (dev->init(dev) != 0) + { + restore_flags(flags); + return -EIO; + } + + if (dev->name && dev->name[0] == '\0') + sprintf(dev->name, "eth%d", next_ethdev_number++); + + /* Add device to end of chain */ + if (dev_base) + { + while (d->next) + d = d->next; + d->next = dev; + } + else + dev_base = dev; + dev->next = NULL; + } + restore_flags(flags); + return 0; +} + +void unregister_netdev(struct device *dev) +{ + struct device *d = dev_base; + unsigned long flags; + + save_flags(flags); + cli(); + + printk("unregister_netdev: device "); + if (dev) { + if (dev->start) + printk("'%s' busy", dev->name); + else { + if (dev_base == dev) + dev_base = dev->next; + else { + while (d && (d->next != dev)) + d = d->next; + + if (d && (d->next == dev)) { + d->next = dev->next; + printk("'%s' unlinked", dev->name); + } + else + printk("'%s' not found", dev->name); + } + } + } + else + printk("was NULL"); + printk("\n"); + restore_flags(flags); +} /* diff -u --recursive --new-file v1.1.12/linux/drivers/net/plip.c linux/drivers/net/plip.c --- v1.1.12/linux/drivers/net/plip.c Tue Apr 19 10:53:45 1994 +++ linux/drivers/net/plip.c Mon May 23 08:16:52 1994 @@ -282,7 +282,7 @@ if (skb->free) kfree_skb (skb, FREE_WRITE); dev->tbusy = 0; - mark_bh (INET_BH); + mark_bh (NET_BH); return 0/*ret_val*/; } diff -u --recursive --new-file v1.1.12/linux/drivers/net/ppp.c linux/drivers/net/ppp.c --- v1.1.12/linux/drivers/net/ppp.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/ppp.c Mon May 23 08:16:53 1994 @@ -0,0 +1,1998 @@ +/* + PPP for Linux +*/ + +/* + Sources: + + slip.c + + RFC1331: The Point-to-Point Protocol (PPP) for the Transmission of + Multi-protocol Datagrams over Point-to-Point Links + + RFC1332: IPCP + + ppp-2.0 + + Flags for this module (any combination is acceptable for testing.): + + NET02D - Define if using Net-2-Debugged in kernels earler + than v1.1.4. + + NEW_TTY_DRIVERS - Define if using new Ted Ts'o's alpha TTY drivers + from tsx-11.mit.edu. From Ted Ts'o. + + OPTIMIZE_FLAG_TIME - Number of jiffies to force sending of leading flag + character. This is normally set to ((HZ * 3) / 2). + This is 1.5 seconds. If not defined then the leading + flag is always sent. +*/ + +/* #define NET02D -* */ +#define NEW_TTY_DRIVERS /* */ +#define OPTIMIZE_FLAG_TIME ((HZ * 3)/2) /* */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* to get the struct task_struct */ +#include /* used in new tty drivers */ +#include /* used in new tty drivers */ +#include +#include +#include + +#ifdef NET02D /* v1.1.4 net code and earlier */ +#include +#include +#include +#define skb_queue_head_init(buf) *(buf) = NULL +#else /* v1.1.5 and later */ +#include +#include +#include +#endif + +#include + +#include +#include + +#include "slhc.h" + +#include +#ifndef ARPHRD_PPP +#define ARPHRD_PPP 0 +#endif + +#define PRINTK(p) printk p ; +#define ASSERT(p) if (!p) PRINTK ((KERN_CRIT "assertion failed: " # p)) +#define PRINTKN(n,p) {if (ppp_debug >= n) PRINTK (p)} +#define CHECK_PPP(a) if (!ppp->inuse) { PRINTK ((ppp_warning, __LINE__)) return a;} +#define CHECK_PPP_VOID() if (!ppp->inuse) { PRINTK ((ppp_warning, __LINE__)) return;} + +#define in_xmap(ppp,c) (ppp->xmit_async_map[(c) >> 5] & (1 << ((c) & 0x1f))) +#define in_rmap(ppp,c) ((((unsigned int) (unsigned char) (c)) < 0x20) && \ + ppp->recv_async_map & (1 << (c))) + +#define bset(p,b) ((p)[(b) >> 5] |= (1 << ((b) & 0x1f))) + +int ppp_debug = 2; +int ppp_debug_netpackets = 0; + +/* Define this string only once for all macro envocations */ +static char ppp_warning[] = KERN_WARNING "PPP: ALERT! not INUSE! %d\n"; + +int ppp_init(struct device *); +static void ppp_init_ctrl_blk(struct ppp *); +static int ppp_dev_open(struct device *); +static int ppp_dev_close(struct device *); +static void ppp_kick_tty(struct ppp *); + +#ifdef NEW_TTY_DRIVERS +#define ppp_find(tty) ((struct ppp *) tty->disc_data) +#else +static void ppp_output_done(void *); +static void ppp_unesc(struct ppp *ppp, unsigned char *c, int n); +static struct ppp *ppp_find(struct tty_struct *); +#endif + +static void ppp_doframe(struct ppp *); +static int ppp_do_ip(struct ppp *, unsigned short, unsigned char *, int); +static int ppp_us_queue(struct ppp *, unsigned short, unsigned char *, int); +static int ppp_xmit(struct sk_buff *, struct device *); +static unsigned short ppp_type_trans(struct sk_buff *, struct device *); + +#ifdef NET02D +static int ppp_header(unsigned char *buff, struct device *dev, + unsigned short type, unsigned long daddr, + unsigned long saddr, unsigned len); +static int ppp_rebuild_header(void *buff, struct device *dev); +static void ppp_add_arp(unsigned long addr, struct sk_buff *skb, + struct device *dev); +#else +static int ppp_header(unsigned char *, struct device *, unsigned short, + void *, void *, unsigned, struct sk_buff *); +static int ppp_rebuild_header(void *, struct device *, unsigned long, + struct sk_buff *); +#endif + +static struct enet_statistics *ppp_get_stats (struct device *); +static struct ppp *ppp_alloc(void); +static int ppp_lock(struct ppp *); +static void ppp_unlock(struct ppp *); +static void ppp_add_fcs(struct ppp *); +static int ppp_check_fcs(struct ppp *); +static void ppp_print_buffer(const char *,char *,int,int); + +static int ppp_read(struct tty_struct *, struct file *, unsigned char *, + unsigned int); +static int ppp_write(struct tty_struct *, struct file *, unsigned char *, + unsigned int); +static int ppp_ioctl(struct tty_struct *, struct file *, unsigned int, + unsigned long); +static int ppp_select(struct tty_struct *tty, struct inode * inode, + struct file * filp, int sel_type, select_table * wait); +static int ppp_open(struct tty_struct *); +static void ppp_close(struct tty_struct *); + +#ifdef NEW_TTY_DRIVERS +static void ppp_receive_buf(struct tty_struct *tty, unsigned char *cp, + char *fp, int count); +static void ppp_write_wakeup(struct tty_struct *tty); +#else +static void ppp_tty_input_ready(struct tty_struct *); +#endif + +/* FCS table from RFC1331 */ + +static unsigned short fcstab[256] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 + }; + +struct tty_ldisc ppp_ldisc; + +static struct ppp ppp_ctrl[PPP_NRUNIT]; + +/************************************************************* + * INITIALIZATION + *************************************************************/ + +static int first_time = 1; + +/* called at boot time for each ppp device */ + +int +ppp_init(struct device *dev) +{ + struct ppp *ppp; + int i; + + ppp = &ppp_ctrl[dev->base_addr]; + + if (first_time) { + first_time = 0; + + printk (KERN_INFO "PPP: version %s (%d channels)" +#ifdef NET02D + " NET02D" +#endif +#ifdef NEW_TTY_DRIVERS + " NEW_TTY_DRIVERS" +#endif +#ifdef OPTIMIZE_FLAG_TIME + " OPTIMIZE_FLAGS" +#endif + "\n", PPP_VERSION, PPP_NRUNIT); + + printk (KERN_INFO + "TCP compression code copyright 1989 Regents of the " + "University of California\n"); + + (void) memset(&ppp_ldisc, 0, sizeof(ppp_ldisc)); + ppp_ldisc.open = ppp_open; + ppp_ldisc.close = ppp_close; + ppp_ldisc.read = ppp_read; + ppp_ldisc.write = ppp_write; + ppp_ldisc.ioctl = ppp_ioctl; + ppp_ldisc.select = ppp_select; + +#ifdef NEW_TTY_DRIVERS + ppp_ldisc.magic = TTY_LDISC_MAGIC; + ppp_ldisc.receive_buf = ppp_receive_buf; + ppp_ldisc.write_wakeup = ppp_write_wakeup; +#else + ppp_ldisc.handler = ppp_tty_input_ready; +#endif + + if ((i = tty_register_ldisc(N_PPP, &ppp_ldisc)) == 0) + printk(KERN_INFO "PPP line discipline registered.\n"); + else + printk(KERN_ERR "error registering line discipline: %d\n", i); + } + + /* initialize PPP control block */ + ppp_init_ctrl_blk (ppp); + ppp->inuse = 0; + ppp->line = dev->base_addr; + ppp->tty = NULL; + ppp->dev = dev; + + /* clear statistics */ + memset (&ppp->stats, '\0', sizeof (struct ppp_stats)); + + /* device INFO */ + dev->mtu = PPP_MTU; + dev->hard_start_xmit = ppp_xmit; + dev->open = ppp_dev_open; + dev->stop = ppp_dev_close; + dev->get_stats = ppp_get_stats; + dev->hard_header = ppp_header; + dev->type_trans = ppp_type_trans; + dev->rebuild_header = ppp_rebuild_header; + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->type = ARPHRD_PPP; + +#ifdef NET02D + dev->add_arp = ppp_add_arp; + dev->queue_xmit = dev_queue_xmit; +#endif + + for (i = 0; i < DEV_NUMBUFFS; i++) + skb_queue_head_init(&dev->buffs[i]); /* = NULL if NET02D */ + + /* New-style flags */ + dev->flags = IFF_POINTOPOINT; + dev->family = AF_INET; + dev->pa_addr = 0; + dev->pa_brdaddr = 0; + dev->pa_mask = 0; + dev->pa_alen = sizeof(unsigned long); + + return 0; +} + +static void +ppp_init_ctrl_blk(struct ppp *ppp) +{ + ppp->magic = PPP_MAGIC; + ppp->sending = 0; + ppp->toss = 0xFE; + ppp->escape = 0; + + ppp->flags = 0; + ppp->mtu = PPP_MTU; + ppp->mru = PPP_MRU; + ppp->fcs = 0; + + memset (ppp->xmit_async_map, 0, sizeof (ppp->xmit_async_map)); + ppp->xmit_async_map[0] = 0xffffffff; + ppp->xmit_async_map[3] = 0x60000000; + ppp->recv_async_map = 0x00000000; + + ppp->slcomp = NULL; + ppp->rbuff = NULL; + ppp->xbuff = NULL; + ppp->cbuff = NULL; + + ppp->rhead = NULL; + ppp->rend = NULL; + ppp->rcount = 0; + ppp->xhead = NULL; + ppp->xtail = NULL; + + ppp->us_rbuff = NULL; + ppp->us_rbuff_end = NULL; + ppp->us_rbuff_head = NULL; + ppp->us_rbuff_tail = NULL; + ppp->read_wait = NULL; + ppp->write_wait = NULL; + ppp->us_rbuff_lock = 0; + ppp->inp_sig = 0; + ppp->inp_sig_pid = 0; + +#ifdef OPTIMIZE_FLAG_TIME /* ensure flag will always be sent first time */ + ppp->last_xmit = jiffies - OPTIMIZE_FLAG_TIME; +#else + ppp->last_xmit = 0; +#endif + + /* clear statistics */ + memset (&ppp->stats, '\0', sizeof (struct ppp_stats)); + + /* Reset the demand dial information */ + ppp->ddinfo.ip_sjiffies = + ppp->ddinfo.ip_rjiffies = + ppp->ddinfo.nip_sjiffies = + ppp->ddinfo.nip_rjiffies = jiffies; +} + +/* + * MTU has been changed by the IP layer. Unfortunately we are not told + * about this, but we spot it ourselves and fix things up. We could be + * in an upcall from the tty driver, or in an ip packet queue. + */ + +static void +ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru) +{ + struct device *dev; + unsigned char *new_rbuff, *new_xbuff, *new_cbuff; + unsigned char *old_rbuff, *old_xbuff, *old_cbuff; + int mtu, mru; +/* + * Allocate the buffer from the kernel for the data + */ + dev = ppp->dev; + mru = new_mru; + mtu = new_mtu; + + /* RFC 1331, section 7.2 says the minimum value is 1500 bytes */ + if (mru < PPP_MRU) + mru = PPP_MRU; + + mtu = (mtu * 2) + 20; + mru = (mru * 2) + 20; + + PRINTKN (2,(KERN_INFO "ppp: channel %s mtu = %d, mru = %d\n", + dev->name, new_mtu, new_mru)); + + new_xbuff = (unsigned char *) kmalloc(mtu + 4, GFP_KERNEL); + new_rbuff = (unsigned char *) kmalloc(mru + 4, GFP_KERNEL); + new_cbuff = (unsigned char *) kmalloc(mru + 4, GFP_KERNEL); +/* + * If the buffers failed to allocate then complain. + */ + if (new_xbuff == NULL || new_rbuff == NULL || new_cbuff == NULL) + { + PRINTKN (2,(KERN_ERR "ppp: failed to allocate new buffers\n")); +/* + * Release new buffer pointers if the updates were not performed + */ + if (new_rbuff != NULL) + kfree (new_rbuff); + + if (new_xbuff != NULL) + kfree (new_xbuff); + + if (new_cbuff != NULL) + kfree (new_cbuff); + } +/* + * Update the pointers to the new buffer structures. + */ + else + { + cli(); + old_xbuff = ppp->xbuff; + old_rbuff = ppp->rbuff; + old_cbuff = ppp->cbuff; + + ppp->xbuff = new_xbuff; + ppp->rbuff = new_rbuff; + ppp->cbuff = new_cbuff; + + dev->mem_start = (unsigned long) new_xbuff; + dev->mem_end = (unsigned long) (dev->mem_start + mtu); + + dev->rmem_start = (unsigned long) new_rbuff; + ppp->rend = (unsigned char *) + dev->rmem_end = (unsigned long) (dev->rmem_start + mru); + + ppp->rhead = new_rbuff; +/* + * Update the parameters for the new buffer sizes + */ + ppp->toss = 0xFE; + ppp->escape = 0; + ppp->sending = 0; + ppp->rcount = 0; + + ppp->mru = new_mru; + + ppp->mtu = + dev->mtu = new_mtu; + + sti(); +/* + * Release old buffer pointers + */ + if (old_rbuff != NULL) + kfree (old_rbuff); + + if (old_xbuff != NULL) + kfree (old_xbuff); + + if (old_cbuff != NULL) + kfree (old_cbuff); + } +} + +/* called when we abandon the PPP line discipline */ + +static void +ppp_release(struct ppp *ppp) +{ +#ifdef NEW_TTY_DRIVERS + if (ppp->tty != NULL && ppp->tty->disc_data == ppp) + ppp->tty->disc_data = NULL; /* Break the tty->ppp link */ +#endif + + if (ppp->dev) { + ppp->dev->flags &= ~IFF_UP; /* down the device */ + ppp->dev->flags |= IFF_POINTOPOINT; + } + + kfree (ppp->xbuff); + kfree (ppp->cbuff); + kfree (ppp->rbuff); + kfree (ppp->us_rbuff); + + ppp->xbuff = + ppp->cbuff = + ppp->rbuff = + ppp->us_rbuff = NULL; + + if (ppp->slcomp) { + slhc_free(ppp->slcomp); + ppp->slcomp = NULL; + } + + ppp->inuse = 0; + ppp->tty = NULL; +} + +static void +ppp_close(struct tty_struct *tty) +{ + struct ppp *ppp = ppp_find(tty); + + if (ppp == NULL || ppp->magic != PPP_MAGIC) { + PRINTKN (1,(KERN_WARNING "ppp: trying to close unopened tty!\n")); + } else { + CHECK_PPP_VOID(); + ppp_release (ppp); + + PRINTKN (2,(KERN_INFO "ppp: channel %s closing.\n", ppp->dev->name)); + } +} + +/* called when PPP line discipline is selected on a tty */ +static int +ppp_open(struct tty_struct *tty) +{ + struct ppp *ppp = ppp_find(tty); + + if (ppp) { + PRINTKN (1,(KERN_ERR "ppp_open: gack! tty already associated to %s!\n", + ppp->magic == PPP_MAGIC ? ppp->dev->name : "unknown")); + return -EEXIST; + } + + ppp = ppp_alloc(); + if (ppp == NULL) { + PRINTKN (1,(KERN_ERR "ppp_open: couldn't allocate ppp channel\n")); + return -ENFILE; + } + + /* make sure the channel is actually open */ + ppp_init_ctrl_blk (ppp); + + ppp->tty = tty; + +#ifdef NEW_TTY_DRIVERS + tty->disc_data = ppp; + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); +#else + tty_read_flush (tty); + tty_write_flush (tty); +#endif + + if ((ppp->slcomp = slhc_init(16, 16)) == NULL) { + PRINTKN (1,(KERN_ERR "ppp: no space for compression buffers!\n")); + ppp_release (ppp); + return -ENOMEM; + } + + /* Define the buffers for operation */ + ppp_changedmtu (ppp, ppp->dev->mtu, ppp->mru); + if (ppp->rbuff == NULL) { + ppp_release (ppp); + return -ENOMEM; + } + + /* Allocate a user-level receive buffer */ + ppp->us_rbuff = kmalloc (RBUFSIZE, GFP_KERNEL); + if (ppp->us_rbuff == NULL) { + PRINTKN (1,(KERN_ERR "ppp: no space for user receive buffer\n")); + ppp_release (ppp); + return -ENOMEM; + } + + ppp->us_rbuff_head = + ppp->us_rbuff_tail = ppp->us_rbuff; + ppp->us_rbuff_end = ppp->us_rbuff + RBUFSIZE; + + PRINTKN (2,(KERN_INFO "ppp: channel %s open\n", ppp->dev->name)); + +#ifdef NEW_TTY_DRIVERS + return (0); +#else + return (ppp->line); +#endif +} + +/* called when ppp interface goes "up". here this just means we start + passing IP packets */ +static int +ppp_dev_open(struct device *dev) +{ + struct ppp *ppp = &ppp_ctrl[dev->base_addr]; + + /* reset POINTOPOINT every time, since dev_close zaps it! */ + dev->flags |= IFF_POINTOPOINT; + + if (ppp->tty == NULL) { + PRINTKN (1,(KERN_ERR "ppp: %s not connected to a TTY! can't go open!\n", + dev->name)); + return -ENXIO; + } + + PRINTKN (2,(KERN_INFO "ppp: channel %s going up for IP packets!\n", + dev->name)); + + CHECK_PPP(-ENXIO); + return 0; +} + +static int +ppp_dev_close(struct device *dev) +{ + struct ppp *ppp = &ppp_ctrl[dev->base_addr]; + + if (ppp->tty == NULL) { + PRINTKN (1,(KERN_ERR "ppp: %s not connected to a TTY! can't go down!\n", + dev->name)); + return -ENXIO; + } + + PRINTKN (2,(KERN_INFO "ppp: channel %s going down for IP packets!\n", + dev->name)); + CHECK_PPP(-ENXIO); + return 0; +} + +/************************************************************* + * TTY OUTPUT + * The following function delivers a fully-formed PPP + * frame in ppp->xbuff to the TTY for output. + *************************************************************/ + +#ifdef NEW_TTY_DRIVERS +static inline void +#else +static void +#endif +ppp_output_done (void *ppp) +{ + /* unlock the transmitter queue */ + ppp_unlock ((struct ppp *) ppp); + + /* If the device is still up then enable the transmitter of the + next frame. */ + if (((struct ppp *) ppp)->dev->flags & IFF_UP) + dev_tint (((struct ppp *) ppp)->dev); + + /* enable any blocked process pending transmission */ + wake_up_interruptible (&((struct ppp *) ppp)->write_wait); +} + +#ifndef NEW_TTY_DRIVERS +static void +ppp_kick_tty (struct ppp *ppp) +{ + register int count = ppp->xhead - ppp->xbuff; + register int answer; + + ppp->stats.sbytes += count; + + answer = tty_write_data (ppp->tty, + ppp->xbuff, + count, + ppp_output_done, + (void *) ppp); + + if (answer == 0) + ppp_output_done (ppp); /* Should not happen */ + else + if (answer < 0) { + ppp->stats.serrors++; + ppp_output_done (ppp); /* unlock the transmitter */ + } +} + +#else + +static void +ppp_kick_tty (struct ppp *ppp) +{ + register int count, actual; + + count = ppp->xhead - ppp->xbuff; + + actual = ppp->tty->driver.write(ppp->tty, 0, ppp->xbuff, count); + ppp->stats.sbytes += actual; + if (actual == count) { + ppp_output_done(ppp); + } else { + ppp->xtail = ppp->xbuff + actual; + ppp->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + } +} + +static void ppp_write_wakeup(struct tty_struct *tty) +{ + register int count, actual; + struct ppp *ppp = ppp_find(tty); + + if (!ppp || ppp->magic != PPP_MAGIC) { + PRINTKN (1, + (KERN_ERR "PPP: write_wakeup called but couldn't " + "find PPP struct.\n")); + return; + } + + if (!ppp->xtail || (ppp->flags & SC_XMIT_BUSY)) + return; + + cli(); + if (ppp->flags & SC_XMIT_BUSY) + return; + ppp->flags |= SC_XMIT_BUSY; + sti(); + + count = ppp->xhead - ppp->xtail; + + actual = tty->driver.write(tty, 0, ppp->xtail, count); + ppp->stats.sbytes += actual; + if (actual == count) { + ppp->xtail = 0; + tty->flags &= ~TTY_DO_WRITE_WAKEUP; + + ppp_output_done(ppp); + } else { + ppp->xtail += actual; + } + ppp->flags &= ~SC_XMIT_BUSY; +} +#endif + +/************************************************************* + * TTY INPUT + * The following functions handle input that arrives from + * the TTY. It recognizes PPP frames and either hands them + * to the network layer or queues them for delivery to a + * user process reading this TTY. + *************************************************************/ + +/* stuff a single character into the receive buffer */ + +inline void +ppp_enqueue(struct ppp *ppp, unsigned char c) +{ + unsigned long flags; + + save_flags(flags); + cli(); + if (ppp->rhead < ppp->rend) { + *ppp->rhead = c; + ppp->rhead++; + ppp->rcount++; + } else + ppp->stats.roverrun++; + restore_flags(flags); +} + +#ifdef CHECK_CHARACTERS +static unsigned paritytab[8] = { + 0x96696996, 0x69969669, 0x69969669, 0x96696996, + 0x69969669, 0x96696996, 0x96696996, 0x69969669 +}; +#endif + +#ifndef NEW_TTY_DRIVERS +static void +ppp_dump_inqueue(struct tty_struct *tty) +{ + int head = tty->read_q.head, + tail = tty->read_q.tail, + i, count; + char buffer[8]; + + PRINTK ((KERN_DEBUG "INQUEUE: head %d tail %d imode %x:\n", head, tail, + (unsigned int) tty->termios->c_iflag)) + + i = tail; + count = 0; + + while (i != head) { + buffer [count] = tty->read_q.buf[i]; + if (++count == 8) { + ppp_print_buffer (NULL, buffer, 8, KERNEL_DS); + count = 0; + } + i = (i + 1) & (TTY_BUF_SIZE - 1); + } + ppp_print_buffer (NULL, buffer, count, KERNEL_DS); +} + +/* called by lower levels of TTY driver when data becomes available. + all incoming data comes through this function. */ + +void ppp_tty_input_ready(struct tty_struct *tty) +{ + struct ppp *ppp = ppp_find(tty); + int n, error; + unsigned char buff[128]; + +/* PRINTK( (KERN_DEBUG "PPP: handler called.\n") ) */ + if (!ppp || ppp->magic != PPP_MAGIC) { + PRINTKN (1, + (KERN_ERR "PPP: handler called but couldn't find PPP struct.\n")); + return; + } + + CHECK_PPP_VOID(); + + /* ZZZ */ + if (ppp_debug >= 5) + ppp_dump_inqueue(ppp->tty); + + do { + n = tty_read_raw_data(tty, buff, 128); + if ( n == 0 ) /* nothing there */ + break; + + if (ppp_debug >= 5) + ppp_print_buffer ("receive buffer", buff, n > 0 ? n : -n, KERNEL_DS); + + if ( n < 0 ) { + /* Last character is error flag. + Process the previous characters, then set toss flag. */ + n = (-n) - 1; + error = buff[n]; + } else error = 0; + ppp->stats.rbytes += n; + ppp_unesc(ppp,buff,n); + if (error) + ppp->toss = error; + } while (1); +} + +/* recover frame by undoing PPP escape mechanism; + copies N chars of input data from C into PPP->rbuff + calls ppp_doframe to dispose of any frames it finds +*/ + +static void +ppp_unesc(struct ppp *ppp, unsigned char *c, int n) +{ + int i; + + for (i = 0; i < n; i++, c++) { + PRINTKN (6,(KERN_DEBUG "(%x)", (unsigned int) *c)); + +#ifdef CHECK_CHARACTERS + if (*c & 0x80) + sc->sc_flags |= SC_RCV_B7_1; + else + sc->sc_flags |= SC_RCV_B7_0; + + if (paritytab[*c >> 5] & (1 << (*c & 0x1F))) + sc->sc_flags |= SC_RCV_ODDP; + else + sc->sc_flags |= SC_RCV_EVNP; +#endif + + switch (*c) { + case PPP_ESC: /* PPP_ESC: invert 0x20 in next character */ + ppp->escape = PPP_TRANS; + break; + + case PPP_FLAG: /* PPP_FLAG: end of frame */ + if (ppp->escape) /* PPP_ESC just before PPP_FLAG is illegal */ + ppp->toss = 0xFF; + + if ((ppp->toss & 0x80) == 0) + ppp_doframe(ppp); /* pass frame on to next layers */ + + ppp->rcount = 0; + ppp->rhead = ppp->rbuff; + ppp->escape = 0; + ppp->toss = 0; + break; + + default: /* regular character */ + if (!in_rmap (ppp, *c)) { + if (ppp->toss == 0) + ppp_enqueue (ppp, *c ^ ppp->escape); + ppp->escape = 0; + } + break; + } + } +} + +#else +static void ppp_receive_buf(struct tty_struct *tty, unsigned char *cp, + char *fp, int count) +{ + register struct ppp *ppp = ppp_find (tty); + unsigned char c; + +/* PRINTK( ("PPP: handler called.\n") ); */ + + if (!ppp || ppp->magic != PPP_MAGIC) { + PRINTKN (1,("PPP: handler called but couldn't find " + "PPP struct.\n")); + return; + } + + CHECK_PPP_VOID(); + + if (ppp_debug >= 5) { + ppp_print_buffer ("receive buffer", cp, count, KERNEL_DS); + } + + while (count-- > 0) { + c = *cp++; + + if (fp) { + if (*fp && ppp->toss == 0) + ppp->toss = *fp; + fp++; + } + +#ifdef CHECK_CHARACTERS + if (c & 0x80) + sc->sc_flags |= SC_RCV_B7_1; + else + sc->sc_flags |= SC_RCV_B7_0; + + if (paritytab[c >> 5] & (1 << (c & 0x1F))) + sc->sc_flags |= SC_RCV_ODDP; + else + sc->sc_flags |= SC_RCV_EVNP; +#endif + + switch (c) { + case PPP_ESC: /* PPP_ESC: invert 0x20 in next character */ + ppp->escape = PPP_TRANS; + break; + + case PPP_FLAG: /* PPP_FLAG: end of frame */ + if (ppp->escape) /* PPP_ESC just before PPP_FLAG is "cancel"*/ + ppp->toss = 0xFF; + + if ((ppp->toss & 0x80) == 0) + ppp_doframe(ppp); /* pass frame on to next layers */ + + ppp->rcount = 0; + ppp->rhead = ppp->rbuff; + ppp->escape = 0; + ppp->toss = 0; + break; + + default: /* regular character */ + if (!in_rmap (ppp, c)) { + if (ppp->toss == 0) + ppp_enqueue (ppp, c ^ ppp->escape); + ppp->escape = 0; + } + } + } +} +#endif + +/* on entry, a received frame is in ppp->rbuff + check it and dispose as appropriate */ +static void +ppp_doframe(struct ppp *ppp) +{ + u_char *c = ppp->rbuff; + u_short proto; + int count = ppp->rcount; + + /* forget it if we've already noticed an error */ + if (ppp->toss) { + PRINTKN (1, (KERN_WARNING "ppp_toss: tossing frame, reason = %d\n", + ppp->toss)); + ppp->stats.rerrors++; + return; + } + + /* do this before printing buffer to avoid generating copious output */ + if (count == 0) + return; + + if (ppp_debug >= 3) + ppp_print_buffer ("receive frame", c, count, KERNEL_DS); + + if (count < 4) { + PRINTKN (1,(KERN_WARNING "ppp: got runt ppp frame, %d chars\n", count)); + ppp->stats.runts++; + return; + } + + /* check PPP error detection field */ + if (!ppp_check_fcs(ppp)) { + PRINTKN (1,(KERN_WARNING "ppp: frame with bad fcs\n")); + ppp->stats.rerrors++; + return; + } + + count -= 2; /* ignore last two characters */ + + /* now we have a good frame */ + /* figure out the protocol field */ + if ((c[0] == PPP_ADDRESS) && (c[1] == PPP_CONTROL)) { + c = c + 2; /* ADDR/CTRL not compressed, so skip */ + count -= 2; + } + + proto = (u_short) *c++; /* PROTO compressed */ + if (proto & 1) { + count--; + } else { + proto = (proto << 8) | (u_short) *c++; /* PROTO uncompressed */ + count -= 2; + } + + /* Send the frame to the network if the ppp device is up */ + if ((ppp->dev->flags & IFF_UP) && ppp_do_ip(ppp, proto, c, count)) { + ppp->ddinfo.ip_rjiffies = jiffies; + return; + } + + /* If we got here, it has to go to a user process doing a read, + so queue it. + + User process expects to get whole frame (for some reason), so + use count+2 so as to include FCS field. */ + + if (ppp_us_queue (ppp, proto, c, count+2)) { + ppp->ddinfo.nip_rjiffies = jiffies; + ppp->stats.rothers++; + return; + } + + /* couldn't cope. */ + PRINTKN (1,(KERN_WARNING + "ppp: dropping packet on the floor: nobody could take it.\n")); + ppp->stats.tossed++; +} + +/* Examine packet at C, attempt to pass up to net layer. + PROTO is the protocol field from the PPP frame. + Return 1 if could handle it, 0 otherwise. */ + +static int +ppp_do_ip (struct ppp *ppp, unsigned short proto, unsigned char *c, + int count) +{ + int flags, done; + + PRINTKN (4,(KERN_DEBUG "ppp_do_ip: proto %x len %d first byte %x\n", + (int) proto, count, c[0])); + + if (ppp_debug_netpackets) { + PRINTK (("KERN_DEBUG %s <-- proto %x len %d\n", ppp->dev->name, + (int) proto, count)); + } + + if (proto == PROTO_IP) { + ppp->stats.runcomp++; + goto sendit; + } + + if ((proto == PROTO_VJCOMP) && !(ppp->flags & SC_REJ_COMP_TCP)) { + /* get space for uncompressing the header */ + done = 0; + save_flags (flags); + cli(); + if ((ppp->rhead + 80) < ppp->rend) { + ppp->rhead += 80; + ppp->rcount += 80; + done = 1; + } + restore_flags(flags); + + if (! done) { + PRINTKN (1,(KERN_NOTICE + "ppp: no space to decompress VJ compressed TCP header.\n")); + ppp->stats.roverrun++; + return 1; + } + + count = slhc_uncompress(ppp->slcomp, c, count); + if (count <= 0) { + ppp->stats.rerrors++; + PRINTKN (1,(KERN_NOTICE "ppp: error in VJ decompression\n")); + return 1; + } + ppp->stats.rcomp++; + goto sendit; + } + + if ((proto == PROTO_VJUNCOMP) && !(ppp->flags & SC_REJ_COMP_TCP)) { + if (slhc_remember(ppp->slcomp, c, count) <= 0) { + ppp->stats.rerrors++; + PRINTKN (1,(KERN_NOTICE "ppp: error in VJ memorizing\n")); + return 1; + } + ppp->stats.runcomp++; + goto sendit; + } + + /* not ours */ + return 0; + + sendit: + if (ppp_debug_netpackets) { + struct iphdr *iph = (struct iphdr *) c; + PRINTK ((KERN_INFO "%s <-- src %lx dst %lx len %d\n", ppp->dev->name, + iph->saddr, iph->daddr, count)) + } + + /* receive the frame through the network software */ + while ((dev_rint(c, count, 0, ppp->dev) & ~1) != 0) + ; + + return 1; +} + +/* stuff packet at BUF, length LEN, into the us_rbuff buffer + prepend PROTO information */ + +#define PUTC(c,label) *ppp->us_rbuff_head++ = c; \ + if (ppp->us_rbuff_head == ppp->us_rbuff_end) \ + ppp->us_rbuff_head = ppp->us_rbuff; \ + if (ppp->us_rbuff_head == ppp->us_rbuff_tail) \ + goto label; +#define GETC(c) c = *ppp->us_rbuff_tail++; \ + if (ppp->us_rbuff_tail == ppp->us_rbuff_end) \ + ppp->us_rbuff_tail = ppp->us_rbuff; + +static int +ppp_us_queue(struct ppp *ppp, unsigned short proto, + unsigned char *buf, int len) +{ + int totlen; + unsigned char *saved_head; + + totlen = len+2; /* including protocol */ + + if (set_bit(1, &ppp->us_rbuff_lock)) { + PRINTKN (1, (KERN_NOTICE "ppp_us_queue: can't get lock\n")); + return 0; + } + saved_head = ppp->us_rbuff_head; + + PUTC((totlen & 0xff00) >> 8, failure); + PUTC(totlen & 0x00ff, failure); + PUTC((proto & 0xff00) >> 8, failure); + PUTC(proto & 0x00ff, failure); + + while (len-- > 0) { + PUTC(*buf++, failure); + } + + PRINTKN (3, (KERN_INFO "ppp: successfully queued %d bytes\n", totlen)); + clear_bit(1, &ppp->us_rbuff_lock); + wake_up_interruptible (&ppp->read_wait); + +#ifdef NEW_TTY_DRIVERS + kill_fasync(ppp->tty->fasync, SIGIO); +#endif + + if (ppp->inp_sig && ppp->inp_sig_pid) + if (kill_proc (ppp->inp_sig_pid, ppp->inp_sig, 1) != 0) { + /* process is gone */ + PRINTKN (2,(KERN_NOTICE + "ppp: process that requested notification is gone\n")); + ppp->inp_sig = 0; + ppp->inp_sig_pid = 0; + } + return 1; + + failure: + ppp->us_rbuff_head = saved_head; + clear_bit(1, &ppp->us_rbuff_lock); + + PRINTKN (1, (KERN_NOTICE "ppp_us_queue: ran out of buffer space.\n")); + + return 0; +} + +/************************************************************* + * LINE DISCIPLINE SUPPORT + * The following functions form support user programs + * which read and write data on a TTY with the PPP line + * discipline. Reading is done from a circular queue, + * filled by the lower TTY levels. + *************************************************************/ + +/* read a PPP frame from the us_rbuff circular buffer, + waiting if necessary +*/ + +static int +ppp_read(struct tty_struct *tty, struct file *file, unsigned char *buf, unsigned int nr) +{ + struct ppp *ppp = ppp_find(tty); + unsigned char c; + int len, i; + + if (!ppp || ppp->magic != PPP_MAGIC) { + PRINTKN (1,(KERN_ERR "ppp_read: cannnot find ppp channel\n")); + return -EIO; + } + + CHECK_PPP(-ENXIO); + + PRINTKN (4,(KERN_DEBUG "ppp_read: called %x num %u\n", + (unsigned int) buf, + nr)); + + do { + /* try to acquire read lock */ + if (set_bit(0, &ppp->us_rbuff_lock) == 0) { + /* got lock */ + if (ppp->us_rbuff_head == ppp->us_rbuff_tail) { + /* no data */ + PRINTKN (4,(KERN_DEBUG "ppp_read: no data\n")); + clear_bit(0, &ppp->us_rbuff_lock); + if (ppp->inp_sig) { + PRINTKN (4,(KERN_DEBUG "ppp_read: EWOULDBLOCK\n")); + return -EWOULDBLOCK; + } else goto wait; + } + + /* reset the time of the last read operation */ + ppp->ddinfo.nip_rjiffies = jiffies; + + GETC (c); len = c << 8; GETC (c); len += c; + + PRINTKN (4,(KERN_DEBUG "ppp_read: len = %d\n", len)); + + if (len + 2 > nr) { + /* frame too big; can't copy it, but do update us_rbuff_head */ + PRINTKN (1,(KERN_DEBUG + "ppp: read of %u bytes too small for %d frame\n", + nr, len+2)); + ppp->us_rbuff_head += len; + if (ppp->us_rbuff_head > ppp->us_rbuff_end) + ppp->us_rbuff_head += - (ppp->us_rbuff_end - ppp->us_rbuff); + clear_bit(0, &ppp->us_rbuff_lock); + wake_up_interruptible (&ppp->read_wait); + ppp->stats.rgiants++; + return -EOVERFLOW; /* ZZZ; HACK! */ + } else { + /* have the space: copy the packet, faking the first two bytes */ + put_fs_byte (PPP_ADDRESS, buf++); + put_fs_byte (PPP_CONTROL, buf++); + i = len; + while (i-- > 0) { + GETC (c); + put_fs_byte (c, buf++); + } + } + + clear_bit(0, &ppp->us_rbuff_lock); + PRINTKN (3,(KERN_DEBUG "ppp_read: passing %d bytes up\n", len + 2)); + ppp->stats.rothers++; + return len + 2; + } + + /* need to wait */ + wait: + current->timeout = 0; + PRINTKN (3,(KERN_DEBUG "ppp_read: sleeping\n")); + interruptible_sleep_on (&ppp->read_wait); + if (current->signal & ~current->blocked) + return -EINTR; + } while (1); +} + +/* stuff a character into the transmit buffer, using PPP's way of escaping + special characters. + also, update ppp->fcs to take account of new character */ +static inline void +ppp_stuff_char(struct ppp *ppp, unsigned char c) +{ + int curpt = ppp->xhead - ppp->xbuff; + if ((curpt < 0) || (curpt > 3000)) { + PRINTK ((KERN_DEBUG "ppp_stuff_char: %x %x %d\n", + (unsigned int) ppp->xbuff, (unsigned int) ppp->xhead, curpt)) + } + if (in_xmap (ppp, c)) { + *ppp->xhead++ = PPP_ESC; + *ppp->xhead++ = c ^ PPP_TRANS; + } else + *ppp->xhead++ = c; + ppp->fcs = (ppp->fcs >> 8) ^ fcstab[(ppp->fcs ^ c) & 0xff]; +} + +/* write a frame with NR chars from BUF to TTY + we have to put the FCS field on ourselves +*/ + +static int +ppp_write(struct tty_struct *tty, struct file *file, unsigned char *buf, unsigned int nr) +{ + struct ppp *ppp = ppp_find(tty); + int i; + + if (!ppp || ppp->magic != PPP_MAGIC) { + PRINTKN (1,(KERN_ERR "ppp_write: cannot find ppp unit\n")); + return -EIO; + } + + CHECK_PPP(-ENXIO); + + if (ppp->mtu != ppp->dev->mtu) /* Someone has been ifconfigging */ + ppp_changedmtu (ppp, ppp->dev->mtu, ppp->mru); + + if (nr > ppp->mtu) { + PRINTKN (1,(KERN_WARNING + "ppp_write: truncating user packet from %u to mtu %d\n", + nr, ppp->mtu)); + nr = ppp->mtu; + } + + if (ppp_debug >= 3) + ppp_print_buffer ("write frame", buf, nr, USER_DS); + + /* lock this PPP unit so we will be the only writer; + sleep if necessary */ + while ((ppp->sending == 1) || !ppp_lock(ppp)) { + current->timeout = 0; + PRINTKN (3,(KERN_DEBUG "ppp_write: sleeping\n")); + interruptible_sleep_on(&ppp->write_wait); + if (current->signal & ~current->blocked) + return -EINTR; + } + + /* OK, locked. Stuff the given bytes into the buffer. */ + + PRINTKN(4,(KERN_DEBUG "ppp_write: acquired write lock\n")); + ppp->xhead = ppp->xbuff; + +#ifdef OPTIMIZE_FLAG_TIME + if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME) + *ppp->xhead++ = PPP_FLAG; + ppp->last_xmit = jiffies; +#else + *ppp->xhead++ = PPP_FLAG; +#endif + + ppp->fcs = PPP_FCS_INIT; + i = nr; + while (i-- > 0) + ppp_stuff_char(ppp,get_fs_byte(buf++)); + + ppp_add_fcs(ppp); /* concatenate FCS at end */ + + *ppp->xhead++ = PPP_FLAG; + + /* reset the time of the last write operation */ + ppp->ddinfo.nip_sjiffies = jiffies; + + if (ppp_debug >= 6) + ppp_print_buffer ("xmit buffer", ppp->xbuff, ppp->xhead - ppp->xbuff, KERNEL_DS); + else { + PRINTKN (4,(KERN_DEBUG + "ppp_write: writing %d chars\n", ppp->xhead - ppp->xbuff)); + } + + /* packet is ready-to-go */ + ++ppp->stats.sothers; + ppp_kick_tty(ppp); + + return((int)nr); +} + +static int +ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i, + unsigned long l) +{ + struct ppp *ppp = ppp_find(tty); + register int temp_i = 0; + int error; + + if (!ppp || ppp->magic != PPP_MAGIC) { + PRINTK ((KERN_ERR "ppp_ioctl: can't find PPP block from tty!\n")) + return -EBADF; + } + + CHECK_PPP(-ENXIO); + + /* This must be root user */ + if (!suser()) + return -EPERM; + + switch (i) { + case PPPIOCSMRU: + error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i)); + if (error == 0) { + PRINTKN (3,(KERN_INFO "ppp_ioctl: set mru to %x\n", temp_i)); + temp_i = (int) get_fs_long (l); + if (ppp->mru != temp_i) + ppp_changedmtu (ppp, ppp->mtu, temp_i); + } + break; + + case PPPIOCGFLAGS: + error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i)); + if (error == 0) { + temp_i = (ppp->flags & SC_MASK); +#ifndef CHECK_CHARACTERS /* Don't generate errors if we don't check chars. */ + temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 | SC_RCV_ODDP | SC_RCV_EVNP; +#endif + put_fs_long ((long) temp_i, l); + PRINTKN (3,(KERN_DEBUG "ppp_ioctl: get flags: addr %lx flags %x\n", + l, + temp_i)); + } + break; + + case PPPIOCSFLAGS: + error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i)); + if (error == 0) { + temp_i = (int) get_fs_long (l); + ppp->flags ^= ((ppp->flags ^ temp_i) & SC_MASK); + PRINTKN (3,(KERN_INFO "ppp_ioctl: set flags to %x\n", temp_i)); + } + break; + + case PPPIOCGASYNCMAP: + error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i)); + if (error == 0) { + put_fs_long (ppp->xmit_async_map[0], l); + PRINTKN (3,(KERN_INFO "ppp_ioctl: get asyncmap: addr %lx asyncmap %lx\n", + l, ppp->xmit_async_map[0])); + } + break; + + case PPPIOCSASYNCMAP: + error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i)); + if (error == 0) { + memset (ppp->xmit_async_map, 0, sizeof (ppp->xmit_async_map)); + ppp->xmit_async_map[0] = get_fs_long (l); + bset (ppp->xmit_async_map, PPP_FLAG); + bset (ppp->xmit_async_map, PPP_ESC); + PRINTKN (3,(KERN_INFO "ppp_ioctl: set xmit asyncmap %lx\n", + ppp->xmit_async_map[0])); + } + break; + + case PPPIOCRASYNCMAP: + error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i)); + if (error == 0) { + ppp->recv_async_map = get_fs_long (l); + PRINTKN (3,(KERN_INFO "ppp_ioctl: set recv asyncmap %lx\n", + ppp->recv_async_map)); + } + break; + + case PPPIOCGUNIT: + error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i)); + if (error == 0) { + put_fs_long (ppp->dev->base_addr, l); + PRINTKN (3,(KERN_INFO "ppp_ioctl: get unit: %d", ppp->dev->base_addr)); + } + break; + + case PPPIOCSINPSIG: + error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i)); + if (error == 0) { + ppp->inp_sig = (int) get_fs_long (l); + ppp->inp_sig_pid = current->pid; + PRINTKN (3,(KERN_INFO "ppp_ioctl: set input signal %d\n", ppp->inp_sig)); + } + break; + + case PPPIOCSDEBUG: + error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i)); + if (error == 0) { + ppp_debug = (int) get_fs_long (l); + ppp_debug_netpackets = (ppp_debug & 0xff00) >> 8; + ppp_debug &= 0xff; + PRINTKN (1, (KERN_INFO "ppp_ioctl: set debug level %d, netpacket %d\n", + ppp_debug, ppp_debug_netpackets)); + } + break; + + case PPPIOCGDEBUG: + error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i)); + if (error == 0) { + put_fs_long ((long) (ppp_debug | (ppp_debug_netpackets << 8)), l); + PRINTKN (3,(KERN_INFO "ppp_ioctl: get debug level %d\n", + ppp_debug | (ppp_debug_netpackets << 8))); + } + break; + + case PPPIOCGSTAT: + error = verify_area (VERIFY_WRITE, (void *) l, sizeof (struct ppp_stats)); + if (error == 0) { + memcpy_tofs ((void *) l, &ppp->stats, sizeof (struct ppp_stats)); + PRINTKN (3,(KERN_INFO "ppp_ioctl: read statistics\n")); + } + break; + + case PPPIOCGTIME: + error = verify_area (VERIFY_WRITE, (void *) l, sizeof (struct ppp_ddinfo)); + if (error == 0) { + struct ppp_ddinfo cur_ddinfo; + unsigned long cur_jiffies = jiffies; + + /* change absolute times to relative times. */ + cur_ddinfo.ip_sjiffies = cur_jiffies - ppp->ddinfo.ip_sjiffies; + cur_ddinfo.ip_rjiffies = cur_jiffies - ppp->ddinfo.ip_rjiffies; + cur_ddinfo.nip_sjiffies = cur_jiffies - ppp->ddinfo.nip_sjiffies; + cur_ddinfo.nip_rjiffies = cur_jiffies - ppp->ddinfo.nip_rjiffies; + + memcpy_tofs ((void *) l, &cur_ddinfo, sizeof (struct ppp_ddinfo)); + PRINTKN (3,(KERN_INFO "ppp_ioctl: read demand dial info\n")); + } + break; + + case PPPIOCGXASYNCMAP: + error = verify_area (VERIFY_WRITE, + (void *) l, + sizeof (ppp->xmit_async_map)); + if (error == 0) { + memcpy_tofs ((void *) l, + ppp->xmit_async_map, + sizeof (ppp->xmit_async_map)); + PRINTKN (3,(KERN_INFO "ppp_ioctl: get xasyncmap: addr %lx\n", l)); + } + break; + + case PPPIOCSXASYNCMAP: + error = verify_area (VERIFY_READ, (void *) l, + sizeof (ppp->xmit_async_map)); + if (error == 0) { + unsigned long temp_tbl [8]; + + memcpy_fromfs (temp_tbl, (void *) l, sizeof (ppp->xmit_async_map)); + temp_tbl[1] = 0x00000000; /* must not escape 0x20 - 0x3f */ + temp_tbl[2] &= ~0x40000000; /* must not escape 0x5e */ + temp_tbl[3] |= 0x60000000; /* must escape 0x7d and 0x7e */ + + if ((temp_tbl[2] & temp_tbl[3]) != 0 || + (temp_tbl[4] & temp_tbl[5]) != 0 || + (temp_tbl[6] & temp_tbl[7]) != 0) + error = -EINVAL; + else { + memcpy (ppp->xmit_async_map, temp_tbl, sizeof (ppp->xmit_async_map)); + PRINTKN (3,(KERN_INFO "ppp_ioctl: set xasyncmap\n")); + } + } + break; + + case PPPIOCSMAXCID: + error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i)); + if (error == 0) { + temp_i = (int) get_fs_long (l) + 1; + PRINTKN (3,(KERN_INFO "ppp_ioctl: set maxcid to %d\n", temp_i)); + if (ppp->slcomp != NULL) + slhc_free (ppp->slcomp); + + ppp->slcomp = slhc_init (temp_i, temp_i); + + if (ppp->slcomp == NULL) { + PRINTKN (1,(KERN_ERR "ppp: no space for compression buffers!\n")); + ppp_release (ppp); + error = -ENOMEM; + } + } + break; + +#ifdef NEW_TTY_DRIVERS + /* Allow stty to read, but not set, the serial port */ + case TCGETS: + case TCGETA: + error = n_tty_ioctl(tty, file, i, l); + break; +#endif + +/* + * All other ioctl() events will come here. + */ + + default: + PRINTKN (1,(KERN_ERR "ppp_ioctl: invalid ioctl: %x, addr %lx\n", + i, + l)); +#ifdef NEW_TTY_DRIVERS + error = -ENOIOCTLCMD; +#else + error = -EINVAL; +#endif + break; + } + return error; +} + +static int +ppp_select (struct tty_struct *tty, struct inode * inode, + struct file * filp, int sel_type, select_table * wait) +{ + struct ppp *ppp = ppp_find (tty); + + if (!ppp || ppp->magic != PPP_MAGIC) { + PRINTK ((KERN_ERR "ppp_select: can't find PPP block from tty!\n")) + return -EBADF; + } + + /* If the PPP protocol is no longer active, return false */ + CHECK_PPP (0); + + /* Process the request based upon the type desired */ + switch (sel_type) { + case SEL_IN: + if (set_bit(0, &ppp->us_rbuff_lock) == 0) { + /* Test for the presence of data in the queue */ + if (ppp->us_rbuff_head != ppp->us_rbuff_tail) { + clear_bit (0, &ppp->us_rbuff_lock); + return 1; + } + clear_bit (0, &ppp->us_rbuff_lock); + } /* fall through */ + + case SEL_EX: + /* Is there a pending error condition? */ + if (tty->packet && tty->link->ctrl_status) + return 1; + + /* closed? */ + if (tty->flags & (1 << TTY_SLAVE_CLOSED)) + return 1; + + /* If the tty is disconnected, then this is an exception too */ + if (tty_hung_up_p(filp)) + return 1; + + select_wait (&ppp->read_wait, wait); + break; + + case SEL_OUT: + if (ppp_lock (ppp)) { + if (ppp->sending == 0) { + ppp_unlock (ppp); + return 1; + } + ppp_unlock (ppp); + } + select_wait (&ppp->write_wait, wait); + break; + } + return 0; +} + +/************************************************************* + * NETWORK OUTPUT + * This routine accepts requests from the network layer + * and attempts to deliver the packets. + * It also includes various routines we are compelled to + * have to make the network layer work (arp, etc...). + *************************************************************/ + +int +ppp_xmit(struct sk_buff *skb, struct device *dev) +{ + struct tty_struct *tty; + struct ppp *ppp; + unsigned char *p; + unsigned short proto; + int len; + + /* just a little sanity check. */ + if (skb == NULL) { + PRINTKN(3,(KERN_WARNING "ppp_xmit: null packet!\n")); + return 0; + } + + /* Get pointers to the various components */ + ppp = &ppp_ctrl[dev->base_addr]; + tty = ppp->tty; + p = (unsigned char *) (skb + 1); + len = skb->len; + proto = PROTO_IP; + + PRINTKN(4,(KERN_DEBUG "ppp_xmit [%s]: skb %lX busy %d\n", dev->name, + (unsigned long int) skb, ppp->sending)); + + CHECK_PPP(0); + + if (tty == NULL) { + PRINTKN(1,(KERN_ERR "ppp_xmit: %s not connected to a TTY!\n", dev->name)); + goto done; + } + + if (!(dev->flags & IFF_UP)) { + PRINTKN(1,(KERN_WARNING + "ppp_xmit: packet sent on interface %s, which is down for IP\n", + dev->name)); + goto done; + } + + /* get length from IP header as per Alan Cox bugfix for slip.c */ + if (len < sizeof(struct iphdr)) { + PRINTKN(0,(KERN_ERR "ppp_xmit: given runt packet, ignoring\n")); + return 1; + } + len = ntohs( ((struct iphdr *)(skb->data)) -> tot_len ); + + /* If doing demand dial then divert the first frame to pppd. */ + if (ppp->flags & SC_IP_DOWN) { + if (ppp->flags & SC_IP_FLUSH == 0) { + if (ppp_us_queue (ppp, proto, p, len)) + ppp->flags |= SC_IP_FLUSH; + } + goto done; + } + + /* Attempt to acquire send lock */ + if (ppp->sending || !ppp_lock(ppp)) { + PRINTKN(3,(KERN_WARNING "ppp_xmit: busy\n")); + ppp->stats.sbusy++; + return 1; + } + + ppp->xhead = ppp->xbuff; + + /* try to compress, if VJ compression mode is on */ + if (ppp->flags & SC_COMP_TCP) { + /* NOTE: last 0 argument says never to compress connection ID */ + len = slhc_compress(ppp->slcomp, p, len, ppp->cbuff, &p, 0); + if (p[0] & SL_TYPE_COMPRESSED_TCP) + proto = PROTO_VJCOMP; + else { + if (p[0] >= SL_TYPE_UNCOMPRESSED_TCP) { + proto = PROTO_VJUNCOMP; + p[0] = (p[0] & 0x0f) | 0x40; + } + } + } + + /* increment appropriate counter */ + if (proto == PROTO_VJCOMP) + ++ppp->stats.scomp; + else + ++ppp->stats.suncomp; + + if (ppp_debug_netpackets) { + struct iphdr *iph = (struct iphdr *) (skb + 1); + PRINTK ((KERN_DEBUG "%s ==> proto %x len %d src %x dst %x proto %d\n", + dev->name, (int) proto, (int) len, (int) iph->saddr, + (int) iph->daddr, (int) iph->protocol)) + } + + /* start of frame: FLAG ALL_STATIONS CONTROL */ +#ifdef OPTIMIZE_FLAG_TIME + if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME) + *ppp->xhead++ = PPP_FLAG; + ppp->last_xmit = jiffies; +#else + *ppp->xhead++ = PPP_FLAG; +#endif + + ppp->fcs = PPP_FCS_INIT; + if (!(ppp->flags & SC_COMP_AC)) { + ppp_stuff_char(ppp, PPP_ADDRESS); + ppp_stuff_char(ppp, PPP_CONTROL); + } + + if (!(ppp->flags & SC_COMP_PROT) || (proto & 0xff00)) + ppp_stuff_char(ppp, proto>>8); + ppp_stuff_char(ppp, proto&0xff); + + /* data part */ + while (len-- > 0) + ppp_stuff_char(ppp, *p++); + + /* fcs and flag */ + ppp_add_fcs(ppp); + *ppp->xhead++ = PPP_FLAG; + + /* update the time for demand dial function */ + ppp->ddinfo.ip_sjiffies = jiffies; + + /* send it! */ + if (ppp_debug >= 6) + ppp_print_buffer ("xmit buffer", ppp->xbuff, ppp->xhead - ppp->xbuff, KERNEL_DS); + else { + PRINTKN (4,(KERN_DEBUG + "ppp_write: writing %d chars\n", ppp->xhead - ppp->xbuff)); + } + + ppp_kick_tty(ppp); + + done: + if (skb->free) + kfree_skb(skb, FREE_WRITE); + return 0; +} + +static unsigned short +ppp_type_trans (struct sk_buff *skb, struct device *dev) +{ + return(htons(ETH_P_IP)); +} + +#ifdef NET02D +static int +ppp_header(unsigned char *buff, struct device *dev, unsigned short type, + unsigned long daddr, unsigned long saddr, unsigned len) +{ + return(0); +} + +static int +ppp_rebuild_header(void *buff, struct device *dev) +{ + return(0); +} + +static void +ppp_add_arp(unsigned long addr, struct sk_buff *skb, struct device *dev) +{ +} + +#else + +static int +ppp_header(unsigned char *buff, struct device *dev, unsigned short type, + void *daddr, void *saddr, unsigned len, struct sk_buff *skb) +{ + return(0); +} + +static int +ppp_rebuild_header(void *buff, struct device *dev, unsigned long raddr, + struct sk_buff *skb) +{ + return(0); +} +#endif + +static struct enet_statistics * +ppp_get_stats (struct device *dev) +{ + struct ppp *ppp = &ppp_ctrl[dev->base_addr]; + static struct enet_statistics ppp_stats; + + ppp_stats.rx_packets = ppp->stats.rcomp + ppp->stats.runcomp; + ppp_stats.rx_errors = ppp->stats.rerrors; + ppp_stats.rx_dropped = ppp->stats.tossed; + ppp_stats.rx_fifo_errors = 0; + ppp_stats.rx_length_errors = ppp->stats.runts; + ppp_stats.rx_over_errors = ppp->stats.roverrun; + ppp_stats.rx_crc_errors = 0; + ppp_stats.rx_frame_errors = 0; + ppp_stats.tx_packets = ppp->stats.scomp + ppp->stats.suncomp; + ppp_stats.tx_errors = ppp->stats.serrors; + ppp_stats.tx_dropped = 0; + ppp_stats.tx_fifo_errors = 0; + ppp_stats.collisions = ppp->stats.sbusy; + ppp_stats.tx_carrier_errors = 0; + ppp_stats.tx_aborted_errors = 0; + ppp_stats.tx_window_errors = 0; + ppp_stats.tx_heartbeat_errors = 0; + + PRINTKN (3, (KERN_INFO "ppp_get_stats called")); + return &ppp_stats; +} + +/************************************************************* + * UTILITIES + * Miscellany called by various functions above. + *************************************************************/ + +#ifndef NEW_TTY_DRIVERS +/* find a PPP channel given a TTY */ +struct ppp * +ppp_find(struct tty_struct *tty) +{ + int i; + for (i = 0; i < PPP_NRUNIT; i++) + if (ppp_ctrl[i].inuse && (ppp_ctrl[i].tty == tty)) return &ppp_ctrl[i]; + + return NULL; +} +#endif + +/* allocate a PPP channel */ +static struct ppp * +ppp_alloc(void) +{ + int i; + for (i = 0; i < PPP_NRUNIT; i++) + if (!set_bit(0, &ppp_ctrl[i].inuse)) return &ppp_ctrl[i]; + + return NULL; +} + +/* marks a PPP interface 'busy'. user processes will wait, if + they try to write, and the network code will refrain from sending + return nonzero if succeeded in acquiring lock +*/ + +static int +ppp_lock(struct ppp *ppp) +{ + int flags, locked; + save_flags(flags); + cli(); + locked = ppp->sending; + ppp->sending = 1; + if (ppp->dev->flags & IFF_UP) + ppp->dev->tbusy = 1; + restore_flags(flags); + return locked == 0; +} + +static void +ppp_unlock(struct ppp *ppp) +{ + int flags; + save_flags(flags); + cli(); + ppp->sending = 0; + if (ppp->dev->flags & IFF_UP) + ppp->dev->tbusy = 0; + restore_flags(flags); +} + +/* FCS support functions */ + +static void +ppp_add_fcs(struct ppp *ppp) +{ + unsigned short fcs = ppp->fcs; + + fcs ^= 0xffff; + ppp_stuff_char(ppp, fcs & 0x00ff); + ppp_stuff_char(ppp, (fcs & 0xff00) >> 8); + ASSERT (ppp->fcs == PPP_FCS_GOOD); + PRINTKN (4,(KERN_DEBUG "ppp_add_fcs: fcs is %lx\n", + (long) (unsigned long) fcs)); +} + +static int +ppp_check_fcs(struct ppp *ppp) +{ + unsigned short fcs = PPP_FCS_INIT, msgfcs; + unsigned char *c = ppp->rbuff; + int i; + + for (i = 0; i < ppp->rcount - 2; i++, c++) + fcs = (fcs >> 8) ^ fcstab[(fcs ^ *c) & 0xff]; + + fcs ^= 0xffff; + msgfcs = (c[1] << 8) + c[0]; + PRINTKN (4,(KERN_INFO "ppp_check_fcs: got %lx want %lx\n", + (unsigned long) msgfcs, (unsigned long) fcs)); + return fcs == msgfcs; +} + +static char hex[] = "0123456789ABCDEF"; + +inline void ppp_print_hex (register char *out, char *in, int count); +inline void ppp_print_hex (register char *out, char *in, int count) +{ + register unsigned char next_ch; + + while (count-- > 0) { + next_ch = (unsigned char) get_fs_byte (in); + + *out++ = hex[(next_ch >> 4) & 0x0F]; + *out++ = hex[next_ch & 0x0F]; + ++out; + ++in; + } +} + +inline void ppp_print_char (register char *out, char *in, int count); +inline void ppp_print_char (register char *out, char *in, int count) +{ + register unsigned char next_ch; + + while (count-- > 0) { + next_ch = (unsigned char) get_fs_byte (in); + + if (next_ch < 0x20 || next_ch > 0x7e) + *out++ = '.'; + else { + *out++ = next_ch; + if (next_ch == '%') /* printk/syslogd has a bug !! */ + *out++ = '%'; + } + ++in; + } + *out = '\0'; +} + +static void ppp_print_buffer(const char *name, char *buf, int count, int seg) +{ + char line [44]; + int old_fs = get_fs(); + + set_fs (seg); + + if (name != (char *) NULL) + PRINTK ((KERN_DEBUG "ppp: %s, count = %d\n", name, count)); + + while (count > 8) { + memset (line, ' ', sizeof (line)); + ppp_print_hex (line, buf, 8); + ppp_print_char (&line[8 * 3], buf, 8); + PRINTK ((KERN_DEBUG "%s\n", line)); + count -= 8; + buf += 8; + } + + if (count > 0) { + memset (line, ' ', sizeof (line)); + ppp_print_hex (line, buf, count); + ppp_print_char (&line[8 * 3], buf, count); + PRINTK ((KERN_DEBUG "%s\n", line)); + } + + set_fs (old_fs); +} diff -u --recursive --new-file v1.1.12/linux/drivers/net/skeleton.c linux/drivers/net/skeleton.c --- v1.1.12/linux/drivers/net/skeleton.c Tue Apr 19 10:53:45 1994 +++ linux/drivers/net/skeleton.c Mon May 23 08:16:53 1994 @@ -330,7 +330,7 @@ if (status /*& TX_INTR*/) { lp->stats.tx_packets++; dev->tbusy = 0; - mark_bh(INET_BH); /* Inform upper layers. */ + mark_bh(NET_BH); /* Inform upper layers. */ } if (status /*& COUNTERS_INTR*/) { /* Increment the appropriate 'localstats' field. */ @@ -387,7 +387,7 @@ } while (--boguscount); /* If any worth-while packets have been received, dev_rint() - has done a mark_bh(INET_BH) for us and will work on them + has done a mark_bh(NET_BH) for us and will work on them when we get to the bottom-half routine. */ return; } diff -u --recursive --new-file v1.1.12/linux/drivers/net/slhc.c linux/drivers/net/slhc.c --- v1.1.12/linux/drivers/net/slhc.c Wed Apr 27 09:46:06 1994 +++ linux/drivers/net/slhc.c Mon May 23 08:16:53 1994 @@ -69,8 +69,6 @@ #include #include "slhc.h" -#define DPRINT(x) - int last_retran; static unsigned char *encode(unsigned char *cp, unsigned short n); @@ -236,8 +234,6 @@ /* Bail if this packet isn't TCP, or is an IP fragment */ if(ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x1fff) || (ip->frag_off & 32)){ - DPRINT(("comp: noncomp 1 %d %d %d\n", ip->protocol, - ntohs(ip->frag_off), ip->frag_off)); /* Send as regular IP */ if(ip->protocol != IPPROTO_TCP) comp->sls_o_nontcp++; @@ -255,8 +251,6 @@ */ if(th->syn || th->fin || th->rst || ! (th->ack)){ - DPRINT(("comp: noncomp 2 %x %x %d %d %d %d\n", ip, th, - th->syn, th->fin, th->rst, th->ack)); /* TCP connection stuff; send as regular IP */ comp->sls_o_tcp++; return isize; @@ -300,7 +294,6 @@ */ comp->sls_o_misses++; comp->xmit_oldest = lcs->cs_this; - DPRINT(("comp: not found\n")); goto uncompressed; found: @@ -341,7 +334,6 @@ || th->doff != cs->cs_tcp.doff || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4 != 0))){ - DPRINT(("comp: incompat\n")); goto uncompressed; } @@ -360,7 +352,6 @@ * implementation should never do this but RFC793 * doesn't prohibit the change so we have to deal * with it. */ - DPRINT(("comp: urg incompat\n")); goto uncompressed; } if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ @@ -391,7 +382,6 @@ if(ip->tot_len != cs->cs_ip.tot_len && ntohs(cs->cs_ip.tot_len) == hlen) break; - DPRINT(("comp: retrans\n")); goto uncompressed; break; case SPECIAL_I: @@ -399,7 +389,6 @@ /* actual changes match one of our special case encodings -- * send packet uncompressed. */ - DPRINT(("comp: special\n")); goto uncompressed; case NEW_S|NEW_A: if(deltaS == deltaA && @@ -450,7 +439,6 @@ } cp = put16(cp,(short)deltaA); /* Write TCP checksum */ /* deltaS is now the size of the change section of the compressed header */ - DPRINT(("comp: %x %x %x %d %d\n", icp, cp, new_seq, hlen, deltaS)); memcpy(cp,new_seq,deltaS); /* Write list of deltas */ memcpy(cp+deltaS,icp+hlen,isize-hlen); comp->sls_o_compressed++; @@ -493,7 +481,6 @@ comp->sls_i_compressed++; if(isize < 3){ comp->sls_i_error++; - DPRINT(("uncomp: runt\n")); return 0; } changes = *cp++; @@ -513,7 +500,6 @@ * explicit state index, we have to toss the packet. */ if(comp->flags & SLF_TOSS){ comp->sls_i_tossed++; - DPRINT(("uncomp: toss\n")); return 0; } } @@ -522,7 +508,6 @@ ip = &cs->cs_ip; if((x = pull16(&cp)) == -1) { /* Read the TCP checksum */ - DPRINT(("uncomp: bad tcp chk\n")); goto bad; } thp->check = htons(x); @@ -555,7 +540,6 @@ if(changes & NEW_U){ thp->urg = 1; if((x = decode(&cp)) == -1) { - DPRINT(("uncomp: bad U\n")); goto bad; } thp->urg_ptr = htons(x); @@ -563,21 +547,18 @@ thp->urg = 0; if(changes & NEW_W){ if((x = decode(&cp)) == -1) { - DPRINT(("uncomp: bad W\n")); goto bad; } thp->window = htons( ntohs(thp->window) + x); } if(changes & NEW_A){ if((x = decode(&cp)) == -1) { - DPRINT(("uncomp: bad A\n")); goto bad; } thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); } if(changes & NEW_S){ if((x = decode(&cp)) == -1) { - DPRINT(("uncomp: bad S\n")); goto bad; } thp->seq = htonl( ntohl(thp->seq) + x); @@ -586,7 +567,6 @@ } if(changes & NEW_I){ if((x = decode(&cp)) == -1) { - DPRINT(("uncomp: bad I\n")); goto bad; } ip->id = htons (ntohs (ip->id) + x); @@ -606,8 +586,6 @@ ip->tot_len = htons(len); ip->check = 0; - DPRINT(("uncomp: %d %d %d %d\n", cp - icp, hdrlen, isize, len)); - memmove(icp + hdrlen, cp, len - hdrlen); cp = icp; @@ -629,7 +607,6 @@ cp += ((thp->doff) - 5) * 4; } -if (inet_debug == DBG_SLIP) printk("\runcomp: change %x len %d\n", changes, len); return len; bad: comp->sls_i_error++; diff -u --recursive --new-file v1.1.12/linux/drivers/net/slip.c linux/drivers/net/slip.c --- v1.1.12/linux/drivers/net/slip.c Mon May 23 12:14:22 1994 +++ linux/drivers/net/slip.c Mon May 23 08:16:53 1994 @@ -64,83 +64,18 @@ #include "slhc.h" #endif -#define SLIP_VERSION "0.7.5" +#define SLIP_VERSION "0.7.5-NET3.014-NEWTTY" -/* Define some IP layer stuff. Not all systems have it. */ -#ifdef SL_DUMP -# define IP_VERSION 4 /* version# of our IP software */ -# define IPF_F_OFFSET 0x1fff /* Offset field */ -# define IPF_DF 0x4000 /* Don't fragment flag */ -# define IPF_MF 0x2000 /* More Fragments flag */ -# define IP_OF_COPIED 0x80 /* Copied-on-fragmentation flag */ -# define IP_OF_CLASS 0x60 /* Option class */ -# define IP_OF_NUMBER 0x1f /* Option number */ -#endif - static struct slip sl_ctrl[SL_NRUNIT]; static struct tty_ldisc sl_ldisc; static int already = 0; - -/* Dump the contents of an IP datagram. */ -static void -ip_dump(unsigned char *ptr, int len) -{ -#ifdef SL_DUMP - struct iphdr *ip; - struct tcphdr *th; - int dlen, doff; - - if (inet_debug != DBG_SLIP) return; - - ip = (struct iphdr *) ptr; - th = (struct tcphdr *) (ptr + ip->ihl * 4); - printk("\r%s -> %s seq %lx ack %lx len %d\n", - in_ntoa(ip->saddr), in_ntoa(ip->daddr), - ntohl(th->seq), ntohl(th->ack_seq), ntohs(ip->tot_len)); - return; - - printk("\r*****\n"); - printk("%p %d\n", ptr, len); - ip = (struct iphdr *) ptr; - dlen = ntohs(ip->tot_len); - doff = ((ntohs(ip->frag_off) & IPF_F_OFFSET) << 3); - - - printk("SLIP: %s->", in_ntoa(ip->saddr)); - printk("%s\n", in_ntoa(ip->daddr)); - printk(" len %u ihl %u ver %u ttl %u prot %u", - dlen, ip->ihl, ip->version, ip->ttl, ip->protocol); - - if (ip->tos != 0) printk(" tos %u", ip->tos); - if (doff != 0 || (ntohs(ip->frag_off) & IPF_MF)) - printk(" id %u offs %u", ntohs(ip->id), doff); - - if (ntohs(ip->frag_off) & IPF_DF) printk(" DF"); - if (ntohs(ip->frag_off) & IPF_MF) printk(" MF"); - printk("\n*****\n"); -#endif -} - -#if 0 -void clh_dump(unsigned char *cp, int len) -{ - if (len > 60) - len = 60; - printk("%d:", len); - while (len > 0) { - printk(" %x", *cp++); - len--; - } - printk("\n\n"); -} -#endif - /* Initialize a SLIP control block for use. */ static void sl_initialize(struct slip *sl, struct device *dev) { + sl->magic = SLIP_MAGIC; sl->inuse = 0; sl->sending = 0; sl->escape = 0; @@ -172,25 +107,10 @@ dev->mem_end = (unsigned long) NULL; dev->mem_start = (unsigned long) NULL; dev->type = ARPHRD_SLIP + sl->mode; + if(dev->type == 260) /* KISS */ + dev->type=ARPHRD_AX25; } - -/* Find a SLIP channel from its `tty' link. */ -static struct slip * -sl_find(struct tty_struct *tty) -{ - struct slip *sl; - int i; - - if (tty == NULL) return(NULL); - for (i = 0; i < SL_NRUNIT; i++) { - sl = &sl_ctrl[i]; - if (sl->tty == tty) return(sl); - } - return(NULL); -} - - /* Find a free SLIP channel, and link in this `tty' line. */ static inline struct slip * sl_alloc(void) @@ -251,8 +171,6 @@ if (l < (576 * 2)) l = 576 * 2; - DPRINTF((DBG_SLIP,"SLIP: mtu changed!\n")); - tb= (unsigned char *) kmalloc(l + 4, GFP_ATOMIC); rb= (unsigned char *) kmalloc(l + 4, GFP_ATOMIC); cb= (unsigned char *) kmalloc(l + 4, GFP_ATOMIC); @@ -417,13 +335,9 @@ } } - DPRINTF((DBG_SLIP, "<< \"%s\" recv:\r\n", sl->dev->name)); - ip_dump(sl->rbuff, sl->rcount); #endif /* Bump the datagram to the upper layers... */ do { - DPRINTF((DBG_SLIP, "SLIP: packet is %d at 0x%X\n", - sl->rcount, sl->rbuff)); /* clh_dump(sl->rbuff, count); */ done = dev_rint(sl->rbuff, count, 0, sl->dev); if (done == 0 || done == 1) break; @@ -432,28 +346,13 @@ sl->rpacket++; } - -/* TTY finished sending a datagram, so clean up. */ -static void -sl_next(struct slip *sl) -{ - DPRINTF((DBG_SLIP, "SLIP: sl_next(0x%X) called!\n", sl)); - sl_unlock(sl); - dev_tint(sl->dev); -} - - /* Encapsulate one IP datagram and stuff into a TTY queue. */ static void sl_encaps(struct slip *sl, unsigned char *icp, int len) { - unsigned char *bp, *p; - int count; + unsigned char *p; + int actual, count; - DPRINTF((DBG_SLIP, "SLIP: sl_encaps(0x%X, %d) called\n", icp, len)); - DPRINTF((DBG_SLIP, ">> \"%s\" sent:\r\n", sl->dev->name)); - - ip_dump(icp, len); if(sl->mtu != sl->dev->mtu) /* Someone has been ifconfigging */ sl_changedmtu(sl); @@ -474,17 +373,57 @@ else count=slip_esc(p, (unsigned char *)sl->xbuff,len); sl->spacket++; - bp = sl->xbuff; /* Tell TTY to send it on its way. */ - DPRINTF((DBG_SLIP, "SLIP: kicking TTY for %d bytes at 0x%X\n", count, bp)); - if (tty_write_data(sl->tty, (char *) bp, count, - (void (*)(void *))sl_next, (void *) sl) == 0) { - DPRINTF((DBG_SLIP, "SLIP: TTY already done with %d bytes!\n", count)); - sl_next(sl); + actual = sl->tty->driver.write(sl->tty, 0, sl->xbuff, count); + if (actual == count) { + sl_unlock(sl); + dev_tint(sl->dev); + } else { + sl->xhead = sl->xbuff + count; + sl->xtail = sl->xbuff + actual; + sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); } } +/* + * Called by the driver when there's room for more data. If we have + * more packets to send, we send them here. + */ +static void slip_write_wakeup(struct tty_struct *tty) +{ + register int count, answer; + struct slip *sl = (struct slip *) tty->disc_data; + + /* First make sure we're connected. */ + if (!sl || sl->magic != SLIP_MAGIC) { + return; + } + + if (!sl->xtail || (sl->flags & SLF_XMIT_BUSY)) + return; + + cli(); + if (sl->flags & SLF_XMIT_BUSY) + return; + sl->flags |= SLF_XMIT_BUSY; + sti(); + + count = sl->xhead - sl->xtail; + + answer = tty->driver.write(tty, 0, sl->xtail, count); + if (answer == count) { + sl->xtail = 0; + tty->flags &= ~TTY_DO_WRITE_WAKEUP; + + sl_unlock(sl); + dev_tint(sl->dev); + } else { + sl->xtail += answer; + } + sl->flags &= ~SLF_XMIT_BUSY; +} + /*static void sl_hex_dump(unsigned char *x,int l) { int n=0; @@ -512,8 +451,6 @@ /* Find the correct SLIP channel to use. */ sl = &sl_ctrl[dev->base_addr]; tty = sl->tty; - DPRINTF((DBG_SLIP, "SLIP: sl_xmit(\"%s\") skb=0x%X busy=%d\n", - dev->name, skb, sl->sending)); /* * If we are busy already- too bad. We ought to be able @@ -521,7 +458,6 @@ * frame buffer. Oh well... */ if (sl->sending) { - DPRINTF((DBG_SLIP, "SLIP: sl_xmit: BUSY\r\n")); sl->sbusy++; return(1); } @@ -545,7 +481,7 @@ sl_lock(sl); size=skb->len; - +#if 0 if(!(sl->mode&SL_MODE_AX25)) { if(sizedata,skb->len);*/ } } +#endif sl_encaps(sl, skb->data, size); if (skb->free) kfree_skb(skb, FREE_WRITE); @@ -586,10 +523,12 @@ void *daddr, void *saddr, unsigned len, struct sk_buff *skb) { #ifdef CONFIG_AX25 +#ifdef CONFIG_INET struct slip *sl=&sl_ctrl[dev->base_addr]; if((sl->mode&SL_MODE_AX25) && type!=htons(ETH_P_AX25)) return ax25_encapsulate(buff,dev,type,daddr,saddr,len,skb); #endif +#endif return(0); } @@ -601,10 +540,12 @@ struct sk_buff *skb) { #ifdef CONFIG_AX25 +#ifdef CONFIG_INET struct slip *sl=&sl_ctrl[dev->base_addr]; if(sl->mode&SL_MODE_AX25) return ax25_rebuild_header(buff,dev,raddr, skb); +#endif #endif return(0); } @@ -620,7 +561,6 @@ sl = &sl_ctrl[dev->base_addr]; if (sl->tty == NULL) { - DPRINTF((DBG_SLIP, "SLIP: channel %d not connected!\n", sl->line)); return(-ENXIO); } sl->dev = dev; @@ -644,7 +584,6 @@ p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL); if (p == NULL) { - DPRINTF((DBG_SLIP, "SLIP: no memory for SLIP XMIT buffer!\n")); return(-ENOMEM); } @@ -654,7 +593,7 @@ p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL); if (p == NULL) { - DPRINTF((DBG_SLIP, "SLIP: no memory for SLIP RECV buffer!\n")); + kfree_s((void *)sl->dev->mem_start,l+4); return(-ENOMEM); } sl->dev->rmem_start = (unsigned long) p; @@ -672,25 +611,22 @@ p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL); if (p == NULL) { kfree((unsigned char *)sl->dev->mem_start); - DPRINTF((DBG_SLIP, "SLIP: no memory for SLIP COMPRESS buffer!\n")); return(-ENOMEM); } sl->cbuff = p; - +#ifdef CONFIG_INET sl->slcomp = slhc_init(16, 16); if (sl->slcomp == NULL) { kfree((unsigned char *)sl->dev->mem_start); kfree((unsigned char *)sl->dev->rmem_start); kfree(sl->cbuff); - DPRINTF((DBG_SLIP, "SLIP: no memory for SLCOMP!\n")); return(-ENOMEM); } - +#endif dev->flags|=IFF_UP; /* Needed because address '0' is special */ if(dev->pa_addr==0) dev->pa_addr=ntohl(0xC0000001); - DPRINTF((DBG_SLIP, "SLIP: channel %d opened.\n", sl->line)); return(0); } @@ -703,20 +639,20 @@ sl = &sl_ctrl[dev->base_addr]; if (sl->tty == NULL) { - DPRINTF((DBG_SLIP, "SLIP: channel %d not connected!\n", sl->line)); return(-EBUSY); } + sl->tty->disc_data = 0; sl_free(sl); /* Free all SLIP frame buffers. */ kfree(sl->rbuff); kfree(sl->xbuff); kfree(sl->cbuff); +#ifdef CONFIG_INET slhc_free(sl->slcomp); - +#endif sl_initialize(sl, dev); - DPRINTF((DBG_SLIP, "SLIP: channel %d closed.\n", sl->line)); return(0); } @@ -727,40 +663,35 @@ * a block of SLIP data has been received, which can now be decapsulated * and sent on to some IP layer for further processing. */ -static void -slip_recv(struct tty_struct *tty) +static void slip_receive_buf(struct tty_struct *tty, unsigned char *cp, + char *fp, int count) { - unsigned char buff[128]; - unsigned char *p; - struct slip *sl; - int count, error=0; + struct slip *sl = (struct slip *) tty->disc_data; - DPRINTF((DBG_SLIP, "SLIP: slip_recv(%d) called\n", tty->line)); - if ((sl = sl_find(tty)) == NULL) return; /* not connected */ - - if(sl->mtu!=sl->dev->mtu) /* Argh! mtu change time! - costs us the packet part received at the change */ - sl_changedmtu(sl); + if (!sl || sl->magic != SLIP_MAGIC) + return; + + /* + * Argh! mtu change time! - costs us the packet part received + * at the change + */ + if(sl->mtu!=sl->dev->mtu) + sl_changedmtu(sl); - /* Suck the bytes out of the TTY queues. */ - do { - count = tty_read_raw_data(tty, buff, 128); - if (count <= 0) - { - count= - count; - if(count) - error=1; - break; + /* Read the characters out of the buffer */ + while (count--) { + if (*fp++) { + sl->flags |= SLF_ERROR; + cp++; + continue; + } + if (sl->mode & SL_MODE_SLIP6) + slip_unesc6(sl,*cp++); + else + slip_unesc(sl,*cp++); } - p = buff; - if(sl->mode & SL_MODE_SLIP6) - slip_unesc6(sl,buff,count,error); - else - slip_unesc(sl,buff,count,error); - } while(1); - } - /* * Open the high-level part of the SLIP channel. * This function is called by the TTY module when the @@ -771,29 +702,26 @@ static int slip_open(struct tty_struct *tty) { - struct slip *sl; + struct slip *sl = (struct slip *) tty->disc_data; /* First make sure we're not already connected. */ - if ((sl = sl_find(tty)) != NULL) { - DPRINTF((DBG_SLIP, "SLIP: TTY %d already connected to %s !\n", - tty->line, sl->dev->name)); + if (sl && sl->magic == SLIP_MAGIC) { return(-EEXIST); } /* OK. Find a free SLIP channel to use. */ if ((sl = sl_alloc()) == NULL) { - DPRINTF((DBG_SLIP, "SLIP: TTY %d not connected: all channels in use!\n", - tty->line)); return(-ENFILE); } sl->tty = tty; - tty_read_flush(tty); - tty_write_flush(tty); + tty->disc_data = sl; + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); /* Perform the low-level SLIP initialization. */ (void) sl_open(sl->dev); - DPRINTF((DBG_SLIP, "SLIP: TTY %d connected to %s.\n", - tty->line, sl->dev->name)); /* Done. We have linked the TTY line to a channel. */ return(sl->line); @@ -819,7 +747,7 @@ stats.tx_packets = sl->spacket; stats.tx_dropped = sl->sbusy; stats.rx_errors = sl->errors; - +#ifdef CONFIG_INET comp = sl->slcomp; if (comp) { stats.rx_fifo_errors = comp->sls_i_compressed; @@ -827,7 +755,7 @@ stats.tx_fifo_errors = comp->sls_o_compressed; stats.collisions = comp->sls_o_misses; } - +#endif return (&stats); } @@ -840,20 +768,17 @@ static void slip_close(struct tty_struct *tty) { - struct slip *sl; + struct slip *sl = (struct slip *) tty->disc_data; /* First make sure we're connected. */ - if ((sl = sl_find(tty)) == NULL) { - DPRINTF((DBG_SLIP, "SLIP: TTY %d not connected !\n", tty->line)); - return; + if (!sl || sl->magic != SLIP_MAGIC) { + return; } (void) dev_close(sl->dev); - DPRINTF((DBG_SLIP, "SLIP: TTY %d disconnected from %s.\n", - tty->line, sl->dev->name)); } - + /************************************************************************ * STANDARD SLIP ENCAPSULATION * ************************************************************************ @@ -898,44 +823,39 @@ } void - slip_unesc(struct slip *sl, unsigned char *s, int count, int error) + slip_unesc(struct slip *sl, unsigned char s) { - int i; - - for (i = 0; i < count; ++i, ++s) { - switch(*s) { - case ESC: - sl->flags |= SLF_ESCAPE; - break; - case ESC_ESC: - if (sl->flags & SLF_ESCAPE) - sl_enqueue(sl, ESC); - else - sl_enqueue(sl, *s); - sl->flags &= ~SLF_ESCAPE; - break; - case ESC_END: - if (sl->flags & SLF_ESCAPE) - sl_enqueue(sl, END); - else - sl_enqueue(sl, *s); - sl->flags &= ~SLF_ESCAPE; - break; - case END: - if (sl->rcount > 2) - sl_bump(sl); - sl_dequeue(sl, sl->rcount); - sl->rcount = 0; - sl->flags &= ~(SLF_ESCAPE | SLF_ERROR); - break; - default: - sl_enqueue(sl, *s); - sl->flags &= ~SLF_ESCAPE; - } + switch(s) { + case ESC: + sl->flags |= SLF_ESCAPE; + break; + case ESC_ESC: + if (sl->flags & SLF_ESCAPE) + sl_enqueue(sl, ESC); + else + sl_enqueue(sl, s); + sl->flags &= ~SLF_ESCAPE; + break; + case ESC_END: + if (sl->flags & SLF_ESCAPE) + sl_enqueue(sl, END); + else + sl_enqueue(sl, s); + sl->flags &= ~SLF_ESCAPE; + break; + case END: + if (sl->rcount > 2) + sl_bump(sl); + sl_dequeue(sl, sl->rcount); + sl->rcount = 0; + sl->flags &= ~(SLF_ESCAPE | SLF_ERROR); + break; + default: + sl_enqueue(sl, s); + sl->flags &= ~SLF_ESCAPE; } - if (error) - sl->flags |= SLF_ERROR; } + /************************************************************************ * 6 BIT SLIP ENCAPSULATION * @@ -985,44 +905,39 @@ } void - slip_unesc6(struct slip *sl, unsigned char *s, int count, int error) + slip_unesc6(struct slip *sl, unsigned char s) { - int i; unsigned char c; - for (i = 0; i < count; ++i, ++s) { - if (*s == 0x70) { - if (sl->rcount > 8) { /* XXX must be 2 for compressed slip */ + if (s == 0x70) { + if (sl->rcount > 8) { /* XXX must be 2 for compressed slip */ #ifdef NOTDEF - printk("rbuff %02x %02x %02x %02x\n", - sl->rbuff[0], - sl->rbuff[1], - sl->rbuff[2], - sl->rbuff[3] - ); + printk("rbuff %02x %02x %02x %02x\n", + sl->rbuff[0], + sl->rbuff[1], + sl->rbuff[2], + sl->rbuff[3] + ); #endif - sl_bump(sl); - } + sl_bump(sl); + } sl_dequeue(sl, sl->rcount); sl->rcount = 0; sl->flags &= ~(SLF_ESCAPE | SLF_ERROR); /* SLF_ESCAPE not used */ sl->xbits = 0; - } else if (*s >= 0x30 && *s < 0x70) { - sl->xdata = (sl->xdata << 6) | ((*s - 0x30) & 0x3F); - sl->xbits += 6; - if (sl->xbits >= 8) { - sl->xbits -= 8; - c = (unsigned char)(sl->xdata >> sl->xbits); - sl_enqueue(sl, c); - } - + } else if (s >= 0x30 && s < 0x70) { + sl->xdata = (sl->xdata << 6) | ((s - 0x30) & 0x3F); + sl->xbits += 6; + if (sl->xbits >= 8) { + sl->xbits -= 8; + c = (unsigned char)(sl->xdata >> sl->xbits); + sl_enqueue(sl, c); + } } - } - if (error) - sl->flags |= SLF_ERROR; } + #ifdef CONFIG_AX25 int sl_set_mac_address(struct device *dev, void *addr) @@ -1046,16 +961,14 @@ static int slip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg) { - struct slip *sl; + struct slip *sl = (struct slip *) tty->disc_data; int err; /* First make sure we're connected. */ - if ((sl = sl_find(tty)) == NULL) { - DPRINTF((DBG_SLIP, "SLIP: ioctl: TTY %d not connected !\n", tty->line)); + if (!sl || sl->magic != SLIP_MAGIC) { return(-EINVAL); } - DPRINTF((DBG_SLIP, "SLIP: ioctl(%d, 0x%X, 0x%X)\n", tty->line, cmd, arg)); switch(cmd) { case SIOCGIFNAME: err=verify_area(VERIFY_WRITE, arg, 16); @@ -1083,15 +996,21 @@ } #endif sl->dev->type=ARPHRD_SLIP+sl->mode; + if(sl->dev->type==260) + sl->dev->type=ARPHRD_AX25; return(0); case SIOCSIFHWADDR: #ifdef CONFIG_AX25 return sl_set_mac_address(sl->dev,arg); #endif + /* Allow stty to read, but not set, the serial port */ + case TCGETS: + case TCGETA: + return n_tty_ioctl(tty, file, cmd, (unsigned long) arg); + default: - return(-EINVAL); + return -ENOIOCTLCMD; } - return(-EINVAL); } @@ -1118,6 +1037,8 @@ printk("AX25: KISS encapsulation enabled\n"); #endif /* Fill in our LDISC request block. */ + memset(&sl_ldisc, 0, sizeof(sl_ldisc)); + sl_ldisc.magic = TTY_LDISC_MAGIC; sl_ldisc.flags = 0; sl_ldisc.open = slip_open; sl_ldisc.close = slip_close; @@ -1126,7 +1047,8 @@ sl_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, unsigned int, unsigned long)) slip_ioctl; sl_ldisc.select = NULL; - sl_ldisc.handler = slip_recv; + sl_ldisc.receive_buf = slip_receive_buf; + sl_ldisc.write_wakeup = slip_write_wakeup; if ((i = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) printk("ERROR: %d\n", i); } diff -u --recursive --new-file v1.1.12/linux/drivers/net/slip.h linux/drivers/net/slip.h --- v1.1.12/linux/drivers/net/slip.h Sat Jan 8 14:35:09 1994 +++ linux/drivers/net/slip.h Mon May 23 07:55:14 1994 @@ -27,6 +27,7 @@ struct slip { + int magic; /* Bitmapped flag fields. */ char inuse; /* are we allocated? */ char sending; /* "channel busy" indicator */ @@ -48,6 +49,8 @@ unsigned char *rhead; /* RECV buffer pointer (head) */ unsigned char *rend; /* RECV buffer pointer (end) */ int rcount; /* SLIP receive counter */ + unsigned char *xhead; /* XMIT buffer pointer (head) */ + unsigned char *xtail; /* XMIT buffer pointer (tail) */ /* SLIP interface statistics. */ unsigned long rpacket; /* inbound frame counter */ @@ -62,6 +65,7 @@ #define SLF_ERROR 4 #define SLF_COMP 16 #define SLF_EXPN 32 +#define SLF_XMIT_BUSY 64 unsigned char mode; /* SLIP mode */ #define SL_MODE_SLIP 0 #define SL_MODE_CSLIP 1 @@ -72,12 +76,12 @@ int xdata,xbits; /* 6 bit slip controls */ }; +#define SLIP_MAGIC 0x5302 extern int slip_init(struct device *dev); extern int slip_esc(unsigned char *s, unsigned char *d, int len); extern int slip_esc6(unsigned char *s, unsigned char *d, int len); -extern void slip_unesc(struct slip *sl, unsigned char *s, int count, int error); -extern void slip_unesc6(struct slip *sl, unsigned char *s, int count, int error); - +extern void slip_unesc(struct slip *sl, unsigned char s); +extern void slip_unesc6(struct slip *sl, unsigned char s); #endif /* _LINUX_SLIP.H */ diff -u --recursive --new-file v1.1.12/linux/fs/fcntl.c linux/fs/fcntl.c --- v1.1.12/linux/fs/fcntl.c Sat May 7 14:54:06 1994 +++ linux/fs/fcntl.c Mon May 23 07:55:11 1994 @@ -83,8 +83,15 @@ case F_GETFL: return filp->f_flags; case F_SETFL: - filp->f_flags &= ~(O_APPEND | O_NONBLOCK); - filp->f_flags |= arg & (O_APPEND | O_NONBLOCK); + if ((arg & FASYNC) && !(filp->f_flags & FASYNC) && + filp->f_op->fasync) + filp->f_op->fasync(filp->f_inode, filp, 1); + if (!(arg & FASYNC) && (filp->f_flags & FASYNC) && + filp->f_op->fasync) + filp->f_op->fasync(filp->f_inode, filp, 0); + filp->f_flags &= ~(O_APPEND | O_NONBLOCK | FASYNC); + filp->f_flags |= arg & (O_APPEND | O_NONBLOCK | + FASYNC); return 0; case F_GETLK: return fcntl_getlk(fd, (struct flock *) arg); @@ -92,6 +99,20 @@ return fcntl_setlk(fd, cmd, (struct flock *) arg); case F_SETLKW: return fcntl_setlk(fd, cmd, (struct flock *) arg); + case F_GETOWN: + /* + * XXX If f_owner is a process group, the + * negative return value will get converted + * into an error. Oops. If we keep the the + * current syscall conventions, the only way + * to fix this will be in libc. + */ + return filp->f_owner; + case F_SETOWN: + filp->f_owner = arg; /* XXX security implications? */ + if (S_ISSOCK (filp->f_inode->i_mode)) + sock_fcntl (filp, F_SETOWN, arg); + return 0; default: /* sockets need a few special fcntls. */ if (S_ISSOCK (filp->f_inode->i_mode)) @@ -99,5 +120,21 @@ return (sock_fcntl (filp, cmd, arg)); } return -EINVAL; + } +} + +void kill_fasync(struct fasync_struct *fa, int sig) +{ + while (fa) { + if (fa->magic != FASYNC_MAGIC) { + printk("kill_fasync: bad magic number in " + "fasync_struct!\n"); + return; + } + if (fa->fa_file->f_owner > 0) + kill_proc(fa->fa_file->f_owner, sig, 1); + else + kill_pg(-fa->fa_file->f_owner, sig, 1); + fa = fa->fa_next; } } diff -u --recursive --new-file v1.1.12/linux/fs/nfs/proc.c linux/fs/nfs/proc.c --- v1.1.12/linux/fs/nfs/proc.c Mon Feb 14 12:48:36 1994 +++ linux/fs/nfs/proc.c Mon May 23 08:17:42 1994 @@ -4,6 +4,16 @@ * Copyright (C) 1992, 1993, 1994 Rick Sladkey * * OS-independent nfs remote procedure call functions + * + * Tuned by Alan Cox for >3K buffers + * so at last we can have decent(ish) throughput off a + * Sun server. + * + * FixMe: We ought to define a sensible small max size for + * things like getattr that are tiny packets and use the + * old get_free_page stuff with it. + * + * Feel free to fix it and mail me the diffs if it worries you. */ /* @@ -20,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -48,15 +59,18 @@ /* * Our memory allocation and release functions. */ + +#define NFS_SLACK_SPACE 1024 /* Total overkill */ -static inline int *nfs_rpc_alloc(void) +static inline int *nfs_rpc_alloc(int size) { - return (int *) __get_free_page(GFP_KERNEL); + size+=NFS_SLACK_SPACE; /* Allow for the NFS crap as well as buffer */ + return (int *)kmalloc(size,GFP_KERNEL); } static inline void nfs_rpc_free(int *p) { - free_page((long) p); + kfree((void *)p); } /* @@ -195,7 +209,7 @@ int ruid = 0; PRINTK("NFS call getattr\n"); - if (!(p0 = nfs_rpc_alloc())) + if (!(p0 = nfs_rpc_alloc(server->rsize))) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_GETATTR, ruid); @@ -229,7 +243,7 @@ int ruid = 0; PRINTK("NFS call setattr\n"); - if (!(p0 = nfs_rpc_alloc())) + if (!(p0 = nfs_rpc_alloc(server->wsize))) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_SETATTR, ruid); @@ -268,7 +282,7 @@ if (!strcmp(name, "xyzzy")) proc_debug = 1 - proc_debug; #endif - if (!(p0 = nfs_rpc_alloc())) + if (!(p0 = nfs_rpc_alloc(server->rsize))) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_LOOKUP, ruid); @@ -304,7 +318,7 @@ int ruid = 0; PRINTK("NFS call readlink\n"); - if (!(p0 = nfs_rpc_alloc())) + if (!(p0 = nfs_rpc_alloc(server->rsize))) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_READLINK, ruid); @@ -343,7 +357,7 @@ int len = 0; /* = 0 is for gcc */ PRINTK("NFS call read %d @ %d\n", count, offset); - if (!(p0 = nfs_rpc_alloc())) + if (!(p0 = nfs_rpc_alloc(server->rsize))) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_READ, ruid); @@ -385,7 +399,7 @@ int ruid = 0; PRINTK("NFS call write %d @ %d\n", count, offset); - if (!(p0 = nfs_rpc_alloc())) + if (!(p0 = nfs_rpc_alloc(server->wsize))) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_WRITE, ruid); @@ -424,7 +438,7 @@ int ruid = 0; PRINTK("NFS call create %s\n", name); - if (!(p0 = nfs_rpc_alloc())) + if (!(p0 = nfs_rpc_alloc(server->wsize))) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_CREATE, ruid); @@ -460,7 +474,7 @@ int ruid = 0; PRINTK("NFS call remove %s\n", name); - if (!(p0 = nfs_rpc_alloc())) + if (!(p0 = nfs_rpc_alloc(server->wsize))) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_REMOVE, ruid); @@ -495,7 +509,7 @@ int ruid = 0; PRINTK("NFS call rename %s -> %s\n", old_name, new_name); - if (!(p0 = nfs_rpc_alloc())) + if (!(p0 = nfs_rpc_alloc(server->wsize))) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_RENAME, ruid); @@ -531,7 +545,7 @@ int ruid = 0; PRINTK("NFS call link %s\n", name); - if (!(p0 = nfs_rpc_alloc())) + if (!(p0 = nfs_rpc_alloc(server->wsize))) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_LINK, ruid); @@ -566,7 +580,7 @@ int ruid = 0; PRINTK("NFS call symlink %s -> %s\n", name, path); - if (!(p0 = nfs_rpc_alloc())) + if (!(p0 = nfs_rpc_alloc(server->wsize))) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_SYMLINK, ruid); @@ -603,7 +617,7 @@ int ruid = 0; PRINTK("NFS call mkdir %s\n", name); - if (!(p0 = nfs_rpc_alloc())) + if (!(p0 = nfs_rpc_alloc(server->wsize))) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_MKDIR, ruid); @@ -639,7 +653,7 @@ int ruid = 0; PRINTK("NFS call rmdir %s\n", name); - if (!(p0 = nfs_rpc_alloc())) + if (!(p0 = nfs_rpc_alloc(server->wsize))) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_RMDIR, ruid); @@ -677,7 +691,7 @@ PRINTK("NFS call readdir %d @ %d\n", count, cookie); size = server->rsize; - if (!(p0 = nfs_rpc_alloc())) + if (!(p0 = nfs_rpc_alloc(server->rsize))) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_READDIR, ruid); @@ -727,7 +741,7 @@ int ruid = 0; PRINTK("NFS call statfs\n"); - if (!(p0 = nfs_rpc_alloc())) + if (!(p0 = nfs_rpc_alloc(server->rsize))) return -EIO; retry: p = nfs_rpc_header(p0, NFSPROC_STATFS, ruid); diff -u --recursive --new-file v1.1.12/linux/fs/open.c linux/fs/open.c --- v1.1.12/linux/fs/open.c Sat May 7 14:54:09 1994 +++ linux/fs/open.c Mon May 23 07:55:11 1994 @@ -481,14 +481,10 @@ */ asmlinkage int sys_vhangup(void) { - struct tty_struct *tty; - if (!suser()) return -EPERM; - /* See if there is a controlling tty. */ - if (current->tty < 0) - return 0; - tty = TTY_TABLE(MINOR(current->tty)); - tty_vhangup(tty); + /* If there is a controlling tty, hang it up */ + if (current->tty) + tty_vhangup(current->tty); return 0; } diff -u --recursive --new-file v1.1.12/linux/fs/proc/array.c linux/fs/proc/array.c --- v1.1.12/linux/fs/proc/array.c Sat May 7 14:54:10 1994 +++ linux/fs/proc/array.c Mon May 23 07:55:11 1994 @@ -306,9 +306,8 @@ default: sigcatch |= bit; } bit <<= 1; } - tty_pgrp = (*p)->tty; - if (tty_pgrp > 0 && tty_table[tty_pgrp]) - tty_pgrp = tty_table[tty_pgrp]->pgrp; + if ((*p)->tty) + tty_pgrp = (*p)->tty->pgrp; else tty_pgrp = -1; return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ @@ -320,7 +319,7 @@ (*p)->p_pptr->pid, (*p)->pgrp, (*p)->session, - (*p)->tty, + (*p)->tty ? (*p)->tty->device : 0, tty_pgrp, (*p)->flags, (*p)->mm->min_flt, diff -u --recursive --new-file v1.1.12/linux/fs/proc/net.c linux/fs/proc/net.c --- v1.1.12/linux/fs/proc/net.c Mon May 23 12:14:24 1994 +++ linux/fs/proc/net.c Mon May 23 08:17:42 1994 @@ -52,7 +52,17 @@ extern int ipx_get_info(char *, char **, off_t, int); extern int ipx_rt_get_info(char *, char **, off_t, int); #endif /* CONFIG_IPX */ +#ifdef CONFIG_AX25 +extern int ax25_get_info(char *, char **, off_t, int); +extern int ax25_rt_get_info(char *, char **, off_t, int); +#ifdef CONFIG_NETROM +extern int nr_get_info(char *, char **, off_t, int); +extern int nr_nodes_get_info(char *, char **, off_t, int); +extern int nr_neigh_get_info(char *, char **, off_t, int); +#endif /* CONFIG_NETROM */ +#endif /* CONFIG_AX25 */ + static struct file_operations proc_net_operations = { NULL, /* lseek - default */ proc_readnet, /* read - bad */ @@ -97,15 +107,24 @@ { 131,3,"dev" }, { 132,3,"raw" }, { 133,3,"tcp" }, - { 134,3,"udp" }, + { 134,3,"udp" } #ifdef CONFIG_INET_RARP - { 135,4,"rarp"} + ,{ 135,4,"rarp"} #endif #endif /* CONFIG_INET */ #ifdef CONFIG_IPX ,{ 136,9,"ipx_route" }, { 137,3,"ipx" } #endif /* CONFIG_IPX */ +#ifdef CONFIG_AX25 + ,{ 138,10,"ax25_route" }, + { 139,4,"ax25" } +#ifdef CONFIG_NETROM + ,{ 140,8,"nr_nodes" }, + { 141,8,"nr_neigh" }, + { 142,2,"nr" } +#endif /* CONFIG_NETROM */ +#endif /* CONFIG_AX25 */ }; #define NR_NET_DIRENTRY ((sizeof (net_dir))/(sizeof (net_dir[0]))) @@ -216,9 +235,11 @@ case 134: length = udp_get_info(page,&start,file->f_pos,thistime); break; +#ifdef CONFIG_INET_RARP case 135: length = rarp_get_info(page,&start,file->f_pos,thistime); break; +#endif /* CONFIG_INET_RARP */ #endif /* CONFIG_INET */ #ifdef CONFIG_IPX case 136: @@ -228,6 +249,26 @@ length = ipx_get_info(page,&start,file->f_pos,thistime); break; #endif /* CONFIG_IPX */ +#ifdef CONFIG_AX25 + case 138: + length = ax25_rt_get_info(page,&start,file->f_pos,thistime); + break; + case 139: + length = ax25_get_info(page,&start,file->f_pos,thistime); + break; +#ifdef CONFIG_NETROM + case 140: + length = nr_nodes_get_info(page,&start,file->f_pos,thistime); + break; + case 141: + length = nr_neigh_get_info(page,&start,file->f_pos,thistime); + break; + case 142: + length = nr_get_info(page,&start,file->f_pos,thistime); + break; +#endif /* CONFIG_NETROM */ +#endif /* CONFIG_AX25 */ + default: free_page((unsigned long) page); return -EBADF; diff -u --recursive --new-file v1.1.12/linux/include/linux/ddi.h linux/include/linux/ddi.h --- v1.1.12/linux/include/linux/ddi.h Wed Dec 1 14:44:15 1993 +++ linux/include/linux/ddi.h Mon May 23 08:17:42 1994 @@ -1,79 +0,0 @@ -/* - * ddi.h Define the structure for linking in I/O drivers into the - * operating system kernel. This method is currently only - * used by NET layer drivers, but it will be expanded into - * a link methos for ALL kernel-resident device drivers. - * - * Version: @(#)ddi.h 1.0.2 04/22/93 - * - * Author: Fred N. van Kempen, - */ -#ifndef _LINUX_DDI_H -#define _LINUX_DDI_H - - -/* DDI control block flags. */ -#define DDI_FREADY 0x10000000 /* device is initialized */ -#define DDI_FPRESENT 0x20000000 /* device hardware is present */ -#define DDI_FBLKDEV 0x00000001 /* device has a BLK spec. file */ -#define DDI_FCHRDEV 0x00000002 /* device has a CHR spec. file */ - -/* Various constants. */ -#define DDI_MAXNAME 16 /* length of a DDI ID string */ - - -/* This structure is used to set up a DDI driver. */ -struct ddconf { - int ioaddr; /* main I/O (port) address */ - int ioaux; /* auxiliary I/O (HD, AST) */ - int irq; /* IRQ channel */ - int dma; /* DMA channel to use */ - unsigned long memsize; /* size of onboard memory */ - unsigned long memaddr; /* base address of memory */ -}; - - -/* The DDI device control block. */ -struct ddi_device { - char *title; /* title of the driver */ - char name[DDI_MAXNAME]; /* unit name of the I/O driver */ - short int unit; /* unit number of this driver */ - short int nunits; /* number of units in driver */ - int (*init)(struct ddi_device *); /* initialization func */ - int (*handler)(int, ...); /* command handler */ - short int major; /* driver major dev number */ - short int minor; /* driver minor dev number */ - unsigned long flags; /* various flags */ - struct ddconf config; /* driver HW setup */ -}; - - -/* This structure is used to set up networking protocols. */ -struct ddi_proto { - char *name; /* protocol name */ - void (*init)(struct ddi_proto *); /* initialization func */ -}; - - -/* This structure is used to link a STREAMS interface. */ -struct iflink { - char id[DDI_MAXNAME]; /* DDI ID string */ - char stream[DDI_MAXNAME]; /* STREAMS interface name */ - int family; /* address (protocol) family */ - unsigned int flags; /* any flags needed (unused) */ -}; - - -/* DDI control requests. */ -#define DDIOCSDBG 0x9000 /* set DDI debug level */ -#define DDIOCGNAME 0x9001 /* get DDI ID name */ -#define DDIOCGCONF 0x9002 /* get DDI HW config */ -#define DDIOCSCONF 0x9003 /* set DDI HW config */ - - -/* DDI global functions. */ -extern void ddi_init(void); -extern struct ddi_device *ddi_map(const char *id); - - -#endif /* _LINUX_DDI_H */ diff -u --recursive --new-file v1.1.12/linux/include/linux/errno.h linux/include/linux/errno.h --- v1.1.12/linux/include/linux/errno.h Wed Dec 1 14:44:15 1993 +++ linux/include/linux/errno.h Mon May 23 07:55:10 1994 @@ -128,5 +128,6 @@ #define ERESTARTSYS 512 #define ERESTARTNOINTR 513 #define ERESTARTNOHAND 514 /* restart if no handler.. */ +#define ENOIOCTLCMD 515 /* No ioctl command */ #endif diff -u --recursive --new-file v1.1.12/linux/include/linux/fcntl.h linux/include/linux/fcntl.h --- v1.1.12/linux/include/linux/fcntl.h Wed Dec 1 14:44:15 1993 +++ linux/include/linux/fcntl.h Mon May 23 07:55:11 1994 @@ -14,6 +14,7 @@ #define O_NONBLOCK 04000 #define O_NDELAY O_NONBLOCK #define O_SYNC 010000 +#define FASYNC 020000 /* fcntl, for BSD compatibility */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get f_flags */ diff -u --recursive --new-file v1.1.12/linux/include/linux/fs.h linux/include/linux/fs.h --- v1.1.12/linux/include/linux/fs.h Mon Apr 25 10:04:34 1994 +++ linux/include/linux/fs.h Mon May 23 07:55:11 1994 @@ -49,6 +49,7 @@ #define MAJOR(a) (int)((unsigned short)(a) >> 8) #define MINOR(a) (int)((unsigned short)(a) & 0xFF) #define MKDEV(a,b) ((int)((((a) & 0xff) << 8) | ((b) & 0xff))) +#define NODEV MKDEV(0,0) #ifndef NULL #define NULL ((void *) 0) @@ -211,14 +212,15 @@ struct file { mode_t f_mode; - dev_t f_rdev; /* needed for /dev/tty */ off_t f_pos; unsigned short f_flags; unsigned short f_count; off_t f_reada; struct file *f_next, *f_prev; + int f_owner; /* pid or -pgrp where SIGIO should be sent */ struct inode * f_inode; struct file_operations * f_op; + void *private_data; /* needed for tty driver, and maybe others */ }; struct file_lock { @@ -232,6 +234,14 @@ off_t fl_end; }; +struct fasync_struct { + int magic; + struct fasync_struct *fa_next; /* singly linked list */ + struct file *fa_file; +}; + +#define FASYNC_MAGIC 0x4601 + #include #include #include @@ -281,6 +291,7 @@ int (*open) (struct inode *, struct file *); void (*release) (struct inode *, struct file *); int (*fsync) (struct inode *, struct file *); + int (*fasync) (struct inode *, struct file *, int); }; struct inode_operations { @@ -326,6 +337,8 @@ asmlinkage int sys_open(const char *, int, int); asmlinkage int sys_close(unsigned int); /* yes, it's really unsigned */ + +extern void kill_fasync(struct fasync_struct *fa, int sig); extern int getname(const char * filename, char **result); extern void putname(char * name); diff -u --recursive --new-file v1.1.12/linux/include/linux/if.h linux/include/linux/if.h --- v1.1.12/linux/include/linux/if.h Tue Apr 19 10:53:48 1994 +++ linux/include/linux/if.h Mon May 23 08:17:43 1994 @@ -31,11 +31,12 @@ #define IFF_NOTRAILERS 0x20 /* avoid use of trailers */ #define IFF_RUNNING 0x40 /* resources allocated */ #define IFF_NOARP 0x80 /* no ARP protocol */ - -/* These are not yet used: */ #define IFF_PROMISC 0x100 /* recve all packets */ +/* These are not yet used: */ #define IFF_ALLMULTI 0x200 /* recve all multicast packets */ +#define IFF_MASTER 0x400 /* master of a load balancer */ +#define IFF_SLAVE 0x800 /* slave of a load balancer */ /* * The ifaddr structure contains information about one address @@ -57,6 +58,26 @@ #define ifa_dstaddr ifa_ifu.ifu_dstaddr /* other end of link */ /* + * Device mapping structure. I'd just gone off and designed a + * beautiful scheme using only loadable modules with arguments + * for driver options and along come the PCMICA people 8) + * + * Ah well. The get() side of this is good for WDSETUP, and it'll + * be handy for debugging things. The set side is fine for now and + * being very small might be worth keeping for clean configuration. + */ + +struct ifmap { + unsigned long mem_start; + unsigned long mem_end; + unsigned short base_addr; + unsigned char irq; + unsigned char dma; + unsigned char port; + /* 3 bytes spare */ +}; + +/* * Interface request structure used for socket * ioctl's. All interface ioctl's must have parameter * definitions which begin with ifr_name. The @@ -80,6 +101,8 @@ short ifru_flags; int ifru_metric; int ifru_mtu; + struct ifmap ifru_map; + char ifru_slave[IFNAMSIZ]; /* Just fits the size */ caddr_t ifru_data; } ifr_ifru; }; @@ -94,6 +117,8 @@ #define ifr_flags ifr_ifru.ifru_flags /* flags */ #define ifr_metric ifr_ifru.ifru_metric /* metric */ #define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ +#define ifr_map ifr_ifru.ifru_map /* device map */ +#define ifr_slave ifr_ifru.ifru_slave /* slave device */ #define ifr_data ifr_ifru.ifru_data /* for use by interface */ /* diff -u --recursive --new-file v1.1.12/linux/include/linux/if_arp.h linux/include/linux/if_arp.h --- v1.1.12/linux/include/linux/if_arp.h Mon May 23 12:14:25 1994 +++ linux/include/linux/if_arp.h Mon May 23 08:17:43 1994 @@ -35,7 +35,7 @@ #define ARPHRD_CSLIP 257 #define ARPHRD_SLIP6 258 #define ARPHRD_CSLIP6 259 -#define ARPHRD_KISS 260 +#define ARPHRD_RSRVD 260 /* Notional KISS type */ #define ARPHRD_ADAPT 264 /* ARP protocol opcodes. */ diff -u --recursive --new-file v1.1.12/linux/include/linux/if_ether.h linux/include/linux/if_ether.h --- v1.1.12/linux/include/linux/if_ether.h Fri Feb 18 11:20:46 1994 +++ linux/include/linux/if_ether.h Mon May 23 08:17:43 1994 @@ -40,6 +40,8 @@ #define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */ #define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */ #define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ +#define ETH_P_802_2 0x0004 /* 802.2 frames */ +#define ETH_P_SNAP 0x0005 /* 802.2 SNAP frames */ /* This is an Ethernet frame header. */ struct ethhdr { diff -u --recursive --new-file v1.1.12/linux/include/linux/inet.h linux/include/linux/inet.h --- v1.1.12/linux/include/linux/inet.h Tue Apr 19 10:53:49 1994 +++ linux/include/linux/inet.h Mon May 23 08:17:43 1994 @@ -42,49 +42,19 @@ #ifndef _LINUX_INET_H #define _LINUX_INET_H - -#include - - -#undef INET_DEBUG -#ifdef INET_DEBUG -# define DPRINTF(x) dprintf x -#else -# define DPRINTF(x) do ; while (0) +#ifdef __i386__ +#define NET16(x) ((((x) >> 8) & 0x00FF) | (((x) << 8) & 0xFF00)) #endif - -/* Debug levels. One per module. */ -#define DBG_OFF 0 /* no debugging */ -#define DBG_INET 1 /* sock.c */ -#define DBG_RT 2 /* route.c */ -#define DBG_DEV 3 /* dev.c */ -#define DBG_ETH 4 /* eth.c */ -#define DBG_PROTO 5 /* protocol.c */ -#define DBG_TMR 6 /* timer.c */ -#define DBG_PKT 7 /* packet.c */ -#define DBG_RAW 8 /* raw.c */ - -#define DBG_LOOPB 10 /* loopback.c */ -#define DBG_SLIP 11 /* slip.c */ - -#define DBG_ARP 20 /* arp.c */ -#define DBG_IP 21 /* ip.c */ -#define DBG_ICMP 22 /* icmp.c */ -#define DBG_TCP 23 /* tcp.c */ -#define DBG_UDP 24 /* udp.c */ +#ifdef __mc680x0__ +#define NET16(x) (x) +#endif #ifdef __KERNEL__ -extern int inet_debug; - -extern void inet_proto_init(struct ddi_proto *pro); +extern void inet_proto_init(struct net_proto *pro); extern char *in_ntoa(unsigned long in); extern unsigned long in_aton(char *str); - -extern void dprintf(int level, char *fmt, ...); - -extern int dbg_ioctl(void *arg, int level); #endif #endif /* _LINUX_INET_H */ diff -u --recursive --new-file v1.1.12/linux/include/linux/interrupt.h linux/include/linux/interrupt.h --- v1.1.12/linux/include/linux/interrupt.h Mon Mar 7 14:34:14 1994 +++ linux/include/linux/interrupt.h Mon May 23 08:17:43 1994 @@ -12,13 +12,14 @@ extern struct bh_struct bh_base[32]; /* Who gets which entry in bh_base. Things which will occur most often - should come first. */ + should come first - in which case NET should be up the top with SERIAL/TQUEUE! */ + enum { TIMER_BH = 0, CONSOLE_BH, + TQUEUE_BH, SERIAL_BH, - TTY_BH, - INET_BH, + NET_BH, KEYBOARD_BH }; diff -u --recursive --new-file v1.1.12/linux/include/linux/ipx.h linux/include/linux/ipx.h --- v1.1.12/linux/include/linux/ipx.h Tue Apr 19 10:53:49 1994 +++ linux/include/linux/ipx.h Mon May 23 08:17:43 1994 @@ -1,9 +1,13 @@ +#ifndef _IPX_H_ +#define _IPX_H_ + struct sockaddr_ipx { short sipx_family; unsigned long sipx_network; unsigned char sipx_node[6]; short sipx_port; + unsigned char sipx_type; }; struct ipx_route_def @@ -14,10 +18,13 @@ unsigned char ipx_router_node[6]; unsigned char ipx_device[16]; unsigned short ipx_flags; +#define IPX_RT_SNAP 8 +#define IPX_RT_8022 4 #define IPX_RT_BLUEBOOK 2 #define IPX_RT_ROUTED 1 }; #define IPX_MTU 576 +#endif diff -u --recursive --new-file v1.1.12/linux/include/linux/keyboard.h linux/include/linux/keyboard.h --- v1.1.12/linux/include/linux/keyboard.h Thu Mar 3 08:05:22 1994 +++ linux/include/linux/keyboard.h Mon May 23 07:55:11 1994 @@ -84,6 +84,7 @@ #define K_BOOT K(KT_SPEC,12) #define K_CAPSON K(KT_SPEC,13) #define K_COMPOSE K(KT_SPEC,14) +#define K_SAK K(KT_SPEC,15) #define K_P0 K(KT_PAD,0) #define K_P1 K(KT_PAD,1) diff -u --recursive --new-file v1.1.12/linux/include/linux/net.h linux/include/linux/net.h --- v1.1.12/linux/include/linux/net.h Fri Mar 18 10:46:45 1994 +++ linux/include/linux/net.h Mon May 23 08:17:43 1994 @@ -56,7 +56,7 @@ /* - * Internel representation of a socket. not all the fields are used by + * Internal representation of a socket. not all the fields are used by * all configurations: * * server client @@ -122,6 +122,10 @@ unsigned long arg); }; +struct net_proto { + char *name; /* Protocol name */ + void (*init_func)(struct net_proto *); /* Bootstrap */ +}; extern int sock_awaitconn(struct socket *mysock, struct socket *servsock); extern int sock_register(int family, struct proto_ops *ops); diff -u --recursive --new-file v1.1.12/linux/include/linux/netdevice.h linux/include/linux/netdevice.h --- v1.1.12/linux/include/linux/netdevice.h Mon May 23 12:14:25 1994 +++ linux/include/linux/netdevice.h Mon May 23 08:17:43 1994 @@ -12,6 +12,7 @@ * Corey Minyard * Donald J. Becker, * Alan Cox, + * Bjorn Ekwall. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -53,7 +54,7 @@ */ char *name; - /* I/O specific fields. */ + /* I/O specific fields - FIXME: Merge these and struct ifmap into one */ unsigned long rmem_end; /* shmem "recv" end */ unsigned long rmem_start; /* shmem "recv" start */ unsigned long mem_end; /* sahared mem end */ @@ -105,6 +106,12 @@ unsigned long pa_dstaddr; /* protocol P-P other side addr */ unsigned long pa_mask; /* protocol netmask */ unsigned short pa_alen; /* protocol address length */ + + /* For load balancing driver pair support */ + + unsigned long pkt_queue; /* Packets queued */ + struct device *slave; /* Slave device */ + /* Pointer to the interface buffers. */ struct sk_buff_head buffs[DEV_NUMBUFFS]; @@ -132,6 +139,9 @@ int (*set_mac_address)(struct device *dev, void *addr); #define HAVE_PRIVATE_IOCTL int (*do_ioctl)(struct device *dev, struct ifreq *ifr); +#define HAVE_SET_CONFIG + int (*set_config)(struct device *dev, struct ifmap *map); + }; @@ -175,8 +185,8 @@ extern int dev_rint(unsigned char *buff, long len, int flags, struct device * dev); extern void dev_transmit(void); -extern int in_inet_bh(void); -extern void inet_bh(void *tmp); +extern int in_net_bh(void); +extern void net_bh(void *tmp); extern void dev_tint(struct device *dev); extern int dev_get_info(char *buffer, char **start, off_t offset, int length); extern int dev_ioctl(unsigned int cmd, void *); @@ -186,6 +196,9 @@ /* This function lives elsewhere (drivers/net/net_init.c but is related) */ extern void ether_setup(struct device *dev); +/* Support for loadable net-drivers */ +extern int register_netdev(struct device *dev); +extern void unregister_netdev(struct device *dev); #endif /* __KERNEL__ */ diff -u --recursive --new-file v1.1.12/linux/include/linux/ppp.h linux/include/linux/ppp.h --- v1.1.12/linux/include/linux/ppp.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/ppp.h Mon May 23 07:55:15 1994 @@ -0,0 +1,233 @@ +#ifndef _LINUX_PPP_H +#define _LINUX_PPP_H + +/* definitions for kernel PPP module + Michael Callahan + Nov. 4 1993 */ + +/* how many PPP units? */ +#define PPP_NRUNIT 4 + +#define PPP_VERSION "0.2.7" + +/* line discipline number */ +#define N_PPP 3 + +/* Magic value for the ppp structure */ +#define PPP_MAGIC 0x5002 + +#define PPPIOCGFLAGS 0x5490 /* get configuration flags */ +#define PPPIOCSFLAGS 0x5491 /* set configuration flags */ +#define PPPIOCGASYNCMAP 0x5492 /* get async map */ +#define PPPIOCSASYNCMAP 0x5493 /* set async map */ +#define PPPIOCGUNIT 0x5494 /* get ppp unit number */ +#define PPPIOCSINPSIG 0x5495 /* set input ready signal */ +#define PPPIOCSDEBUG 0x5497 /* set debug level */ +#define PPPIOCGDEBUG 0x5498 /* get debug level */ +#define PPPIOCGSTAT 0x5499 /* read PPP statistic information */ +#define PPPIOCGTIME 0x549A /* read time delta information */ +#define PPPIOCGXASYNCMAP 0x549B /* get async table */ +#define PPPIOCSXASYNCMAP 0x549C /* set async table */ +#define PPPIOCSMRU 0x549D /* set receive unit size for PPP */ +#define PPPIOCRASYNCMAP 0x549E /* set receive async map */ +#define PPPIOCSMAXCID 0x549F /* set the maximum compression slot id */ + +/* special characters in the framing protocol */ +#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ +#define PPP_UI 0x03 /* Unnumbered Information */ +#define PPP_FLAG 0x7E /* frame delimiter -- marks frame boundaries */ +#define PPP_ADDRESS 0xFF /* first character of frame <-- (may be */ +#define PPP_CONTROL 0x03 /* second character of frame <-- compressed)*/ +#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */ +#define PPP_ESC 0x7d /* escape charecter -- next character is + data, and the PPP_TRANS bit should be + toggled. PPP_ESC PPP_FLAG is illegal */ + +/* protocol numbers */ +#define PROTO_IP 0x0021 +#define PROTO_VJCOMP 0x002d +#define PROTO_VJUNCOMP 0x002f + +/* FCS support */ +#define PPP_FCS_INIT 0xffff +#define PPP_FCS_GOOD 0xf0b8 + +/* initial MTU */ +#define PPP_MTU 1500 + +/* initial MRU */ +#define PPP_MRU PPP_MTU + +/* flags */ +#define SC_COMP_PROT 0x00000001 /* protocol compression (output) */ +#define SC_COMP_AC 0x00000002 /* header compression (output) */ +#define SC_COMP_TCP 0x00000004 /* TCP (VJ) compression (output) */ +#define SC_NO_TCP_CCID 0x00000008 /* disable VJ connection-id comp. */ +#define SC_REJ_COMP_AC 0x00000010 /* reject adrs/ctrl comp. on input */ +#define SC_REJ_COMP_TCP 0x00000020 /* reject TCP (VJ) comp. on input */ +#define SC_ENABLE_IP 0x00000100 /* IP packets may be exchanged */ +#define SC_IP_DOWN 0x00000200 /* give ip frames to pppd */ +#define SC_IP_FLUSH 0x00000400 /* "next time" flag for IP_DOWN */ +#define SC_DEBUG 0x00010000 /* enable debug messages */ +#define SC_LOG_INPKT 0x00020000 /* log contents of good pkts recvd */ +#define SC_LOG_OUTPKT 0x00040000 /* log contents of pkts sent */ +#define SC_LOG_RAWIN 0x00080000 /* log all chars received */ +#define SC_LOG_FLUSH 0x00100000 /* log all chars flushed */ + +/* Flag bits to determine state of input characters */ +#define SC_RCV_B7_0 0x01000000 /* have rcvd char with bit 7 = 0 */ +#define SC_RCV_B7_1 0x02000000 /* have rcvd char with bit 7 = 0 */ +#define SC_RCV_EVNP 0x04000000 /* have rcvd char with even parity */ +#define SC_RCV_ODDP 0x08000000 /* have rcvd char with odd parity */ + +#define SC_MASK 0x0fffffff /* bits that user can change */ + +/* flag for doing transmitter lockout */ +#define SC_XMIT_BUSY 0x10000000 /* ppp_write_wakeup is active */ + +/* + * This is the format of the data buffer of a LQP packet. The packet data + * is sent/received to the peer. + */ + +struct ppp_lqp_packet_hdr { + unsigned long LastOutLQRs; /* Copied from PeerOutLQRs */ + unsigned long LastOutPackets; /* Copied from PeerOutPackets */ + unsigned long LastOutOctets; /* Copied from PeerOutOctets */ + unsigned long PeerInLQRs; /* Copied from SavedInLQRs */ + unsigned long PeerInPackets; /* Copied from SavedInPackets */ + unsigned long PeerInDiscards; /* Copied from SavedInDiscards */ + unsigned long PeerInErrors; /* Copied from SavedInErrors */ + unsigned long PeerInOctets; /* Copeid from SavedInOctets */ + unsigned long PeerOutLQRs; /* Copied from OutLQRs, plus 1 */ + unsigned long PeerOutPackets; /* Current ifOutUniPackets, + 1 */ + unsigned long PeerOutOctets; /* Current ifOutOctets + LQR */ + }; + +/* + * This data is not sent to the remote. It is updated by the driver when + * a packet is received. + */ + +struct ppp_lqp_packet_trailer { + unsigned long SaveInLQRs; /* Current InLQRs on receiption */ + unsigned long SaveInPackets; /* Current ifInUniPackets */ + unsigned long SaveInDiscards; /* Current ifInDiscards */ + unsigned long SaveInErrors; /* Current ifInErrors */ + unsigned long SaveInOctets; /* Current ifInOctects */ +}; + +/* + * PPP LQP packet. The packet is changed by the driver immediately prior + * to transmission and updated upon receiption with the current values. + * So, it must be known to the driver as well as the pppd software. + */ + +struct ppp_lpq_packet { + unsigned long magic; /* current magic value */ + struct ppp_lqp_packet_hdr hdr; /* Header fields for structure */ + struct ppp_lqp_packet_trailer tail; /* Trailer fields (not sent) */ +}; + +/* + * PPP interface statistics. (used by LQP / pppstats) + */ + +struct ppp_stats { + unsigned long rbytes; /* bytes received */ + unsigned long rcomp; /* compressed packets received */ + unsigned long runcomp; /* uncompressed packets received */ + unsigned long rothers; /* non-ip frames received */ + unsigned long rerrors; /* received errors */ + unsigned long roverrun; /* "buffer overrun" counter */ + unsigned long tossed; /* packets discarded */ + unsigned long runts; /* frames too short to process */ + unsigned long rgiants; /* frames too large to process */ + unsigned long sbytes; /* bytes sent */ + unsigned long scomp; /* compressed packets sent */ + unsigned long suncomp; /* uncompressed packets sent */ + unsigned long sothers; /* non-ip frames sent */ + unsigned long serrors; /* transmitter errors */ + unsigned long sbusy; /* "transmitter busy" counter */ +}; + +/* + * Demand dial fields + */ + +struct ppp_ddinfo { + unsigned long ip_sjiffies; /* time when last IP frame sent */ + unsigned long ip_rjiffies; /* time when last IP frame recvd*/ + unsigned long nip_sjiffies; /* time when last NON-IP sent */ + unsigned long nip_rjiffies; /* time when last NON-IP recvd */ +}; + +#ifdef __KERNEL__ + +struct ppp { + int magic; /* magic value for structure */ + + /* Bitmapped flag fields. */ + char inuse; /* are we allocated? */ + char sending; /* "channel busy" indicator */ + char escape; /* 0x20 if prev char was PPP_ESC*/ + char toss; /* toss this frame */ + + unsigned int flags; /* miscellany */ + + unsigned long xmit_async_map[8]; /* 1 bit means that given control + character is quoted on output*/ + + unsigned long recv_async_map; /* 1 bit means that given control + character is ignored on input*/ + int mtu; /* maximum xmit frame size */ + int mru; /* maximum receive frame size */ + unsigned short fcs; /* FCS field of current frame */ + + /* Various fields. */ + int line; /* PPP channel number */ + struct tty_struct *tty; /* ptr to TTY structure */ + struct device *dev; /* easy for intr handling */ + struct slcompress *slcomp; /* for header compression */ + unsigned long last_xmit; /* time of last transmission */ + + /* These are pointers to the malloc()ed frame buffers. + These buffers are used while processing a packet. If a packet + has to hang around for the user process to read it, it lingers in + the user buffers below. */ + unsigned char *rbuff; /* receiver buffer */ + unsigned char *xbuff; /* transmitter buffer */ + unsigned char *cbuff; /* compression buffer */ + + /* These are the various pointers into the buffers. */ + unsigned char *rhead; /* RECV buffer pointer (head) */ + unsigned char *rend; /* RECV buffer pointer (end) */ + int rcount; /* PPP receive counter */ + unsigned char *xhead; /* XMIT buffer pointer (head) */ + unsigned char *xtail; /* XMIT buffer pointer (end) */ + + /* Structures for interfacing with the user process. */ +#define RBUFSIZE 4000 + unsigned char *us_rbuff; /* circular incoming packet buf.*/ + unsigned char *us_rbuff_end; /* end of allocated space */ + unsigned char *us_rbuff_head; /* head of waiting packets */ + unsigned char *us_rbuff_tail; /* tail of waiting packets */ + unsigned char us_rbuff_lock; /* lock: bit 0 head bit 1 tail */ + int inp_sig; /* input ready signal for pgrp */ + int inp_sig_pid; /* process to get notified */ + + /* items to support the select() function */ + struct wait_queue *write_wait; /* queue for reading processes */ + struct wait_queue *read_wait; /* queue for writing processes */ + + /* PPP interface statistics. */ + struct ppp_stats stats; /* statistic information */ + + /* PPP demand dial information. */ + struct ppp_ddinfo ddinfo; /* demand dial information */ +}; + +#endif /* __KERNEL__ */ +#endif /* _LINUX_PPP_H */ + + diff -u --recursive --new-file v1.1.12/linux/include/linux/route.h linux/include/linux/route.h --- v1.1.12/linux/include/linux/route.h Sun Feb 13 17:16:51 1994 +++ linux/include/linux/route.h Mon May 23 08:17:44 1994 @@ -44,14 +44,15 @@ struct ifnet *rt_ifp; short rt_metric; /* +1 for binary compatibility! */ char *rt_dev; /* forcing the device at add */ + unsigned long rt_mtu; /* per route MTU/Window */ }; -#define RTF_UP 0x0001 /* route useable */ -#define RTF_GATEWAY 0x0002 /* destination is a gateway */ -#define RTF_HOST 0x0004 /* host entry (net otherwise) */ -#define RTF_REINSTATE 0x0008 /* re-instate route after tmout */ -#define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */ -#define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */ - +#define RTF_UP 0x0001 /* route useable */ +#define RTF_GATEWAY 0x0002 /* destination is a gateway */ +#define RTF_HOST 0x0004 /* host entry (net otherwise) */ +#define RTF_REINSTATE 0x0008 /* re-instate route after tmout */ +#define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */ +#define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */ +#define RTF_MTU 0x0040 /* specific MSS for this route */ #endif /* _LINUX_ROUTE_H */ diff -u --recursive --new-file v1.1.12/linux/include/linux/sched.h linux/include/linux/sched.h --- v1.1.12/linux/include/linux/sched.h Sat May 7 14:54:12 1994 +++ linux/include/linux/sched.h Mon May 23 07:55:11 1994 @@ -284,7 +284,7 @@ unsigned long v86flags, v86mask, v86mode; /* file system info */ int link_count; - int tty; /* -1 if no tty, so it must be signed */ + struct tty_struct *tty; /* NULL if no tty */ struct inode * executable; struct shm_desc *shm; struct sem_undo *semun; @@ -337,7 +337,7 @@ /* math */ 0, \ /* comm */ "swapper", \ /* vm86_info */ NULL, 0, 0, 0, 0, \ -/* fs info */ 0,-1,NULL, \ +/* fs info */ 0,NULL,NULL, \ /* ipc */ NULL, NULL, \ /* ldt */ NULL, \ /* tss */ INIT_TSS, \ diff -u --recursive --new-file v1.1.12/linux/include/linux/serial.h linux/include/linux/serial.h --- v1.1.12/linux/include/linux/serial.h Thu Dec 23 11:17:30 1993 +++ linux/include/linux/serial.h Mon May 23 07:55:11 1994 @@ -7,7 +7,70 @@ * Public License (GPL) */ +#ifndef _LINUX_SERIAL_H +#define _LINUX_SERIAL_H + +struct serial_struct { + int type; + int line; + int port; + int irq; + int flags; + int xmit_fifo_size; + int custom_divisor; + int baud_base; + unsigned short close_delay; + char reserved_char[2]; + int hub6; + int reserved[5]; +}; + /* + * These are the supported serial types. + */ +#define PORT_UNKNOWN 0 +#define PORT_8250 1 +#define PORT_16450 2 +#define PORT_16550 3 +#define PORT_16550A 4 +#define PORT_MAX 4 + +/* + * Definitions for async_struct (and serial_struct) flags field + */ +#define ASYNC_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes + on the callout port */ +#define ASYNC_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */ +#define ASYNC_SAK 0x0004 /* Secure Attention Key (Orange book) */ +#define ASYNC_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ + +#define ASYNC_SPD_MASK 0x0030 +#define ASYNC_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */ + +#define ASYNC_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */ +#define ASYNC_SPD_CUST 0x0030 /* Use user-specified divisor */ + +#define ASYNC_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */ +#define ASYNC_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */ +#define ASYNC_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ +#define ASYNC_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */ +#define ASYNC_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */ + +#define ASYNC_FLAGS 0x0FFF /* Possible legal async flags */ +#define ASYNC_USR_MASK 0x0430 /* Legal flags that non-privileged + * users can set or reset */ + +/* Internal flags used only by kernel/chr_drv/serial.c */ +#define ASYNC_INITIALIZED 0x80000000 /* Serial port was initialized */ +#define ASYNC_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ +#define ASYNC_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ +#define ASYNC_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ +#define ASYNC_CLOSING 0x08000000 /* Serial port is closing */ +#define ASYNC_CTS_FLOW 0x04000000 /* Do CTS flow control */ +#define ASYNC_CHECK_CD 0x02000000 /* i.e., CLOCAL */ + +#ifdef __KERNEL__ +/* * This is our internal structure for each serial port's state. * * Many fields are paralleled by the structure used by the serial_struct @@ -15,10 +78,9 @@ * * For definitions of the flags field, see tty.h */ -#ifndef _LINUX_SERIAL_H -#define _LINUX_SERIAL_H struct async_struct { + int magic; int baud_base; int port; int irq; @@ -27,135 +89,47 @@ int type; /* UART type */ struct tty_struct *tty; int read_status_mask; + int ignore_status_mask; int timeout; int xmit_fifo_size; int custom_divisor; int x_char; /* xon/xoff characater */ int close_delay; int IER; /* Interrupt Enable Register */ + int MCR; /* Modem control register */ + int MCR_noint; /* MCR with interrupts off */ int event; int line; int count; /* # of fd on device */ int blocked_open; /* # of blocked opens */ long session; /* Session of opening process */ long pgrp; /* pgrp of opening process */ + unsigned char *xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; + struct tq_struct tqueue; struct termios normal_termios; struct termios callout_termios; struct wait_queue *open_wait; struct wait_queue *close_wait; - struct wait_queue *xmit_wait; struct async_struct *next_port; /* For the linked list */ struct async_struct *prev_port; }; -/* - * Events are used to schedule things to happen at timer-interrupt - * time, instead of at rs interrupt time. - */ -#define RS_EVENT_READ_PROCESS 0 -#define RS_EVENT_WRITE_WAKEUP 1 -#define RS_EVENT_HANGUP 2 -#define RS_EVENT_BREAK 3 -#define RS_EVENT_OPEN_WAKEUP 4 - -/* - * These are the UART port assignments, expressed as offsets from the base - * register. These assignments should hold for any serial port based on - * a 8250, 16450, or 16550(A). - */ -#define UART_RX 0 /* In: Receive buffer (DLAB=0) */ -#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */ -#define UART_DLL 0 /* Out: Devisor Latch Low (DLAB=1) */ -#define UART_DLM 1 /* Out: Devisor Latch High (DLAB=1) */ -#define UART_IER 1 /* Out: Interrupt Enable Register */ -#define UART_IIR 2 /* In: Interrupt ID Register */ -#define UART_FCR 2 /* Out: FIFO Control Register */ -#define UART_LCR 3 /* Out: Line Control Register */ -#define UART_MCR 4 /* Out: Modem Control Register */ -#define UART_LSR 5 /* In: Line Status Register */ -#define UART_MSR 6 /* In: Modem Status Register */ -#define UART_SCR 7 /* I/O: Scratch Register */ - -/* - * These are the definitions for the FIFO Control Register - */ -#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */ -#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */ -#define UART_FCR_CLEAR_XMIT 0x04 /* Clear the XMIT FIFO */ -#define UART_FCR_DMA_SELECT 0x08 /* For DMA applications */ -#define UART_FCR_TRIGGER_MASK 0xC0 /* Mask for the FIFO trigger range */ -#define UART_FCR_TRIGGER_1 0x00 /* Mask for trigger set at 1 */ -#define UART_FCR_TRIGGER_4 0x40 /* Mask for trigger set at 4 */ -#define UART_FCR_TRIGGER_8 0x80 /* Mask for trigger set at 8 */ -#define UART_FCR_TRIGGER_14 0xC0 /* Mask for trigger set at 14 */ - -/* - * These are the definitions for the Line Control Register - * - * Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting - * UART_LCR_STOP will select 1.5 stop bits, not 2 stop bits. - */ -#define UART_LCR_DLAB 0x80 /* Devisor latch access bit */ -#define UART_LCR_SBC 0x40 /* Set break control */ -#define UART_LCR_SPAR 0x20 /* Stick parity (?) */ -#define UART_LCR_EPAR 0x10 /* Even paraity select */ -#define UART_LCR_PARITY 0x08 /* Parity Enable */ -#define UART_LCR_STOP 0x04 /* Stop bits: 0=1 stop bit, 1= 2 stop bits */ -#define UART_LCR_WLEN5 0x00 /* Wordlength: 5 bits */ -#define UART_LCR_WLEN6 0x01 /* Wordlength: 6 bits */ -#define UART_LCR_WLEN7 0x02 /* Wordlength: 7 bits */ -#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */ - -/* - * These are the definitions for the Line Status Register - */ -#define UART_LSR_TEMT 0x40 /* Transmitter empty */ -#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ -#define UART_LSR_BI 0x10 /* Break interrupt indicator */ -#define UART_LSR_FE 0x08 /* Frame error indicator */ -#define UART_LSR_PE 0x04 /* Parity error indicator */ -#define UART_LSR_OE 0x02 /* Overrun error indicator */ -#define UART_LSR_DR 0x01 /* Receiver data ready */ +#define SERIAL_MAGIC 0x5301 /* - * These are the definitions for the Interrupt Indentification Register + * The size of the serial xmit buffer is 1 page, or 4096 bytes */ -#define UART_IIR_NO_INT 0x01 /* No interrupts pending */ -#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ +#define SERIAL_XMIT_SIZE 4096 -#define UART_IIR_MSI 0x00 /* Modem status interrupt */ -#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ -#define UART_IIR_RDI 0x04 /* Receiver data interrupt */ -#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ - -/* - * These are the definitions for the Interrupt Enable Register - */ -#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */ -#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */ -#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */ -#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */ - -/* - * These are the definitions for the Modem Control Register - */ -#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ -#define UART_MCR_OUT2 0x08 /* Out2 complement */ -#define UART_MCR_OUT1 0x04 /* Out1 complement */ -#define UART_MCR_RTS 0x02 /* RTS complement */ -#define UART_MCR_DTR 0x01 /* DTR complement */ - /* - * These are the definitions for the Modem Status Register + * Events are used to schedule things to happen at timer-interrupt + * time, instead of at rs interrupt time. */ -#define UART_MSR_DCD 0x80 /* Data Carrier Detect */ -#define UART_MSR_RI 0x40 /* Ring Indicator */ -#define UART_MSR_DSR 0x20 /* Data Set Ready */ -#define UART_MSR_CTS 0x10 /* Clear to Send */ -#define UART_MSR_DDCD 0x08 /* Delta DCD */ -#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */ -#define UART_MSR_DDSR 0x02 /* Delta DSR */ -#define UART_MSR_DCTS 0x01 /* Delta CTS */ -#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */ +#define RS_EVENT_WRITE_WAKEUP 0 +#define RS_EVENT_HANGUP 1 +#endif /* __KERNEL__ */ #endif /* _LINUX_SERIAL_H */ diff -u --recursive --new-file v1.1.12/linux/include/linux/serial_reg.h linux/include/linux/serial_reg.h --- v1.1.12/linux/include/linux/serial_reg.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/serial_reg.h Mon May 23 07:55:15 1994 @@ -0,0 +1,113 @@ +/* + * include/linux/serial.h + * + * Copyright (C) 1992, 1994 by Theodore Ts'o. + * + * Redistribution of this file is permitted under the terms of the GNU + * Public License (GPL) + * + * These are the UART port assignments, expressed as offsets from the base + * register. These assignments should hold for any serial port based on + * a 8250, 16450, or 16550(A). + */ + +#ifndef _LINUX_SERIAL_REG_H +#define _LINUX_SERIAL_REG_H + +#define UART_RX 0 /* In: Receive buffer (DLAB=0) */ +#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */ +#define UART_DLL 0 /* Out: Devisor Latch Low (DLAB=1) */ +#define UART_DLM 1 /* Out: Devisor Latch High (DLAB=1) */ +#define UART_IER 1 /* Out: Interrupt Enable Register */ +#define UART_IIR 2 /* In: Interrupt ID Register */ +#define UART_FCR 2 /* Out: FIFO Control Register */ +#define UART_LCR 3 /* Out: Line Control Register */ +#define UART_MCR 4 /* Out: Modem Control Register */ +#define UART_LSR 5 /* In: Line Status Register */ +#define UART_MSR 6 /* In: Modem Status Register */ +#define UART_SCR 7 /* I/O: Scratch Register */ + +/* + * These are the definitions for the FIFO Control Register + */ +#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */ +#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */ +#define UART_FCR_CLEAR_XMIT 0x04 /* Clear the XMIT FIFO */ +#define UART_FCR_DMA_SELECT 0x08 /* For DMA applications */ +#define UART_FCR_TRIGGER_MASK 0xC0 /* Mask for the FIFO trigger range */ +#define UART_FCR_TRIGGER_1 0x00 /* Mask for trigger set at 1 */ +#define UART_FCR_TRIGGER_4 0x40 /* Mask for trigger set at 4 */ +#define UART_FCR_TRIGGER_8 0x80 /* Mask for trigger set at 8 */ +#define UART_FCR_TRIGGER_14 0xC0 /* Mask for trigger set at 14 */ + +/* + * These are the definitions for the Line Control Register + * + * Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting + * UART_LCR_STOP will select 1.5 stop bits, not 2 stop bits. + */ +#define UART_LCR_DLAB 0x80 /* Devisor latch access bit */ +#define UART_LCR_SBC 0x40 /* Set break control */ +#define UART_LCR_SPAR 0x20 /* Stick parity (?) */ +#define UART_LCR_EPAR 0x10 /* Even paraity select */ +#define UART_LCR_PARITY 0x08 /* Parity Enable */ +#define UART_LCR_STOP 0x04 /* Stop bits: 0=1 stop bit, 1= 2 stop bits */ +#define UART_LCR_WLEN5 0x00 /* Wordlength: 5 bits */ +#define UART_LCR_WLEN6 0x01 /* Wordlength: 6 bits */ +#define UART_LCR_WLEN7 0x02 /* Wordlength: 7 bits */ +#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */ + +/* + * These are the definitions for the Line Status Register + */ +#define UART_LSR_TEMT 0x40 /* Transmitter empty */ +#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ +#define UART_LSR_BI 0x10 /* Break interrupt indicator */ +#define UART_LSR_FE 0x08 /* Frame error indicator */ +#define UART_LSR_PE 0x04 /* Parity error indicator */ +#define UART_LSR_OE 0x02 /* Overrun error indicator */ +#define UART_LSR_DR 0x01 /* Receiver data ready */ + +/* + * These are the definitions for the Interrupt Indentification Register + */ +#define UART_IIR_NO_INT 0x01 /* No interrupts pending */ +#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ + +#define UART_IIR_MSI 0x00 /* Modem status interrupt */ +#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ +#define UART_IIR_RDI 0x04 /* Receiver data interrupt */ +#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ + +/* + * These are the definitions for the Interrupt Enable Register + */ +#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */ +#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */ +#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */ +#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */ + +/* + * These are the definitions for the Modem Control Register + */ +#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ +#define UART_MCR_OUT2 0x08 /* Out2 complement */ +#define UART_MCR_OUT1 0x04 /* Out1 complement */ +#define UART_MCR_RTS 0x02 /* RTS complement */ +#define UART_MCR_DTR 0x01 /* DTR complement */ + +/* + * These are the definitions for the Modem Status Register + */ +#define UART_MSR_DCD 0x80 /* Data Carrier Detect */ +#define UART_MSR_RI 0x40 /* Ring Indicator */ +#define UART_MSR_DSR 0x20 /* Data Set Ready */ +#define UART_MSR_CTS 0x10 /* Clear to Send */ +#define UART_MSR_DDCD 0x08 /* Delta DCD */ +#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */ +#define UART_MSR_DDSR 0x02 /* Delta DSR */ +#define UART_MSR_DCTS 0x01 /* Delta CTS */ +#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */ + +#endif /* _LINUX_SERIAL_REG_H */ + diff -u --recursive --new-file v1.1.12/linux/include/linux/skbuff.h linux/include/linux/skbuff.h --- v1.1.12/linux/include/linux/skbuff.h Tue Apr 19 22:20:34 1994 +++ linux/include/linux/skbuff.h Mon May 23 08:17:44 1994 @@ -70,6 +70,9 @@ arp; unsigned char tries,lock,localroute; unsigned short users; /* User count - see datagram.c (and soon seqpacket.c/stream.c) */ +#ifdef CONFIG_SLAVE_BALANCING + unsigned short in_dev_queue; +#endif unsigned long padding[0]; unsigned char data[0]; }; diff -u --recursive --new-file v1.1.12/linux/include/linux/sockios.h linux/include/linux/sockios.h --- v1.1.12/linux/include/linux/sockios.h Mon May 23 12:14:25 1994 +++ linux/include/linux/sockios.h Mon May 23 08:17:44 1994 @@ -57,6 +57,8 @@ #define SIOCGIFENCAP 0x8925 /* get/set slip encapsulation */ #define SIOCSIFENCAP 0x8926 #define SIOCGIFHWADDR 0x8927 /* Get hardware address */ +#define SIOCGIFSLAVE 0x8929 /* Driver slaving support */ +#define SIOCSIFSLAVE 0x8930 /* Routing table calls (oldrtent - don't use) */ #define SIOCADDRTOLD 0x8940 /* add routing table entry */ @@ -71,6 +73,11 @@ #define SIOCDRARP 0x8960 /* delete RARP table entry */ #define SIOCGRARP 0x8961 /* get RARP table entry */ #define SIOCSRARP 0x8962 /* set RARP table entry */ + +/* Driver configuration calls */ + +#define SIOCGIFMAP 0x8970 /* Get device parameters */ +#define SIOCSIFMAP 0x8971 /* Set device parameters */ /* Device private ioctl calls */ diff -u --recursive --new-file v1.1.12/linux/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h --- v1.1.12/linux/include/linux/sysv_fs.h Wed Jul 21 22:41:47 1993 +++ linux/include/linux/sysv_fs.h Mon May 23 10:04:06 1994 @@ -316,6 +316,8 @@ #define SYSV_DIRSIZE sizeof(struct sysv_dir_entry) /* size of every directory entry */ +#ifdef __KERNEL__ + /* Operations */ /* ========== */ @@ -432,6 +434,8 @@ extern struct inode_operations sysv_file_inode_operations_with_bmap; extern struct inode_operations sysv_dir_inode_operations; extern struct inode_operations sysv_symlink_inode_operations; + +#endif /* __KERNEL__ */ #endif diff -u --recursive --new-file v1.1.12/linux/include/linux/tqueue.h linux/include/linux/tqueue.h --- v1.1.12/linux/include/linux/tqueue.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/tqueue.h Mon May 23 07:55:15 1994 @@ -0,0 +1,179 @@ +/* + * tqueue.h --- task queue handling for Linux. + * + * Mostly based on a proposed bottom-half replacement code written by + * Kai Petzke, wpp@marie.physik.tu-berlin.de. + * + * Modified for use in the Linux kernel by Theodore Ts'o, + * tytso@mit.edu. Any bugs are my fault, not Kai's. + * + * The original comment follows below. + */ + +#ifndef _LINUX_TQUEUE_H +#define _LINUX_TQUEUE_H + +#ifdef INCLUDE_INLINE_FUNCS +#define _INLINE_ extern +#else +#define _INLINE_ extern __inline__ +#endif + +/* + * New proposed "bottom half" handlers: + * (C) 1994 Kai Petzke, wpp@marie.physik.tu-berlin.de + * + * Advantages: + * - Bottom halfs are implemented as a linked list. You can have as many + * of them, as you want. + * - No more scanning of a bit field is required upon call of a bottom half. + * - Support for chained bottom half lists. The run_task_queue() function can be + * used as a bottom half handler. This is for example usefull for bottom + * halfs, which want to be delayed until the next clock tick. + * + * Problems: + * - The queue_task_irq() inline function is only atomic with respect to itself. + * Problems can occur, when queue_task_irq() is called from a normal system + * call, and an interrupt comes in. No problems occur, when queue_task_irq() + * is called from an interrupt or bottom half, and interrupted, as run_task_queue() + * will not be executed/continued before the last interrupt returns. If in + * doubt, use queue_task(), not queue_task_irq(). + * - Bottom halfs are called in the reverse order that they were linked into + * the list. + */ + +struct tq_struct { + struct tq_struct *next; /* linked list of active bh's */ + int sync; /* must be initialized to zero */ + void (*routine)(void *); /* function to call */ + void *data; /* argument to function */ +}; + +typedef struct tq_struct * task_queue; + +#define DECLARE_TASK_QUEUE(q) task_queue q = &tq_last + +extern struct tq_struct tq_last; +extern task_queue tq_timer; + +#ifdef INCLUDE_INLINE_FUNCS +struct tq_struct tq_last = { + &tq_last, 0, 0, 0 +}; +#endif + +/* + * To implement your own list of active bottom halfs, use the following + * two definitions: + * + * struct tq_struct *my_bh = &tq_last; + * struct tq_struct run_my_bh = { + * 0, 0, (void *)(void *) run_task_queue, &my_bh + * }; + * + * To activate a bottom half on your list, use: + * + * queue_task(tq_pointer, &my_bh); + * + * To run the bottom halfs on your list put them on the immediate list by: + * + * queue_task(&run_my_bh, &tq_immediate); + * + * This allows you to do deferred procession. For example, you could + * have a bottom half list tq_timer, which is marked active by the timer + * interrupt. + */ + +/* + * queue_task_irq: put the bottom half handler "bh_pointer" on the list + * "bh_list". You may call this function only from an interrupt + * handler or a bottom half handler. + */ +_INLINE_ void queue_task_irq(struct tq_struct *bh_pointer, + task_queue *bh_list) +{ + int l1; + + __asm__ __volatile__ ( + "btsl $0,%1\n\t" /* bottom half already marked? */ + "jc 1f\n\t" + "leal %2,%3\n\t" /* address of the "next" field of bh_struct */ + "xchgl %3,%0\n\t" /* link bottom half into list */ + "movl %3,%2\n1:" /* save the pointer to next bottom half */ + : "=m" (*bh_list), "=m" (bh_pointer -> sync), "=m" (bh_pointer -> next), + "=r" (l1) ); +} + +/* + * queue_task_irq_off: put the bottom half handler "bh_pointer" on the list + * "bh_list". You may call this function only when interrupts are off. + */ +_INLINE_ void queue_task_irq_off(struct tq_struct *bh_pointer, + task_queue *bh_list) +{ + int l1; + + __asm__ __volatile__ ( + "testl $1,%1\n\t" /* bottom half already marked? */ + "jne 1f\n\t" + "movl $1,%1\n\t" + "leal %2,%3\n\t" /* address of the "next" field of bh_struct */ + "xchgl %3,%0\n\t" /* link bottom half into list */ + "movl %3,%2\n1:" /* save the pointer to next bottom half */ + : "=m" (*bh_list), "=m" (bh_pointer -> sync), "=m" (bh_pointer -> next), + "=r" (l1) ); +} + + +/* + * queue_task: as queue_task_irq, but can be called from anywhere. + */ +_INLINE_ void queue_task(struct tq_struct *bh_pointer, + task_queue *bh_list) +{ + int l1; + + __asm__ __volatile__ ( + "btsl $0,%1\n\t" + "jc 1f\n\t" + "leal %2,%3\n\t" + "pushfl\n\t" /* save interrupt flag */ + "cli\n\t" /* turn off interrupts */ + "xchgl %3,%0\n\t" + "movl %3,%2\n\t" /* now the linking step is really atomic! */ + "popfl\n1:" /* restore interrupt flag */ + : "=m" (*bh_list), "=m" (bh_pointer -> sync), "=m" (bh_pointer -> next), + "=r" (l1) ); +} + +/* + * Call all "bottom halfs" on a given list. + */ +_INLINE_ void run_task_queue(task_queue *list) +{ + register struct tq_struct *save_p; + register struct tq_struct *p; + void *arg; + void (*f) (void *); + + while(1) { + p = &tq_last; + __asm__ __volatile__("xchgl %0,%2" : "=r" (p) : + "0" (p), "m" (*list) : "memory"); + if(p == &tq_last) + break; + + do { + arg = p -> data; + f = p -> routine; + save_p = p -> next; + p -> sync = 0; + (*f)(arg); + p = save_p; + } while(p != &tq_last); + } +} + +#undef _INLINE_ + +#endif /* _LINUX_TQUEUE_H */ diff -u --recursive --new-file v1.1.12/linux/include/linux/tty.h linux/include/linux/tty.h --- v1.1.12/linux/include/linux/tty.h Fri Feb 18 11:08:41 1994 +++ linux/include/linux/tty.h Mon May 23 07:55:11 1994 @@ -6,10 +6,18 @@ */ #include +#include +#include +#include #include +/* + * Note: don't mess with NR_PTYS until you understand the tty minor + * number allocation game... + */ #define NR_CONSOLES 8 +#define NR_PTYS 64 #define NR_LDISCS 16 /* @@ -54,96 +62,31 @@ #define __DISABLED_CHAR '\0' /* - * See comment for the tty_struct structure before changing - * TTY_BUF_SIZE. Actually, there should be different sized tty_queue - * structures for different purposes. 1024 bytes for the transmit - * queue is way overkill. TYT, 9/14/92 + * This is the flip buffer used for the tty driver. The buffer is + * located in the tty structure, and is used as a high speed interface + * between the tty driver and the tty line discpline. */ -#define TTY_BUF_SIZE 1024 /* Must be a power of 2 */ - -struct tty_queue { - unsigned long head; - unsigned long tail; - struct wait_queue * proc_list; - unsigned char buf[TTY_BUF_SIZE]; -}; +#define TTY_FLIPBUF_SIZE 512 -struct serial_struct { - int type; - int line; - int port; - int irq; - int flags; - int xmit_fifo_size; - int custom_divisor; - int baud_base; - unsigned short close_delay; - char reserved_char[2]; - int hub6; - int reserved[5]; +struct tty_flip_buffer { + struct tq_struct tqueue; + unsigned char char_buf[2*TTY_FLIPBUF_SIZE]; + char flag_buf[2*TTY_FLIPBUF_SIZE]; + char *char_buf_ptr; + unsigned char *flag_buf_ptr; + int count; + int buf_num; }; /* - * These are the supported serial types. - */ -#define PORT_UNKNOWN 0 -#define PORT_8250 1 -#define PORT_16450 2 -#define PORT_16550 3 -#define PORT_16550A 4 -#define PORT_MAX 4 - -/* - * Definitions for async_struct (and serial_struct) flags field + * When a break, frame error, or parity error happens, these codes are + * stuffed into the flags buffer. */ -#define ASYNC_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes - on the callout port */ -#define ASYNC_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */ -#define ASYNC_SAK 0x0004 /* Secure Attention Key (Orange book) */ -#define ASYNC_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ - -#define ASYNC_SPD_MASK 0x0030 -#define ASYNC_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */ -#define ASYNC_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */ -#define ASYNC_SPD_CUST 0x0030 /* Use user-specified divisor */ - -#define ASYNC_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */ -#define ASYNC_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */ -#define ASYNC_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ -#define ASYNC_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */ -#define ASYNC_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */ - -#define ASYNC_FLAGS 0x0FFF /* Possible legal async flags */ -#define ASYNC_USR_MASK 0x0430 /* Legal flags that non-privileged - * users can set or reset */ - -/* Internal flags used only by kernel/chr_drv/serial.c */ -#define ASYNC_INITIALIZED 0x80000000 /* Serial port was initialized */ -#define ASYNC_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ -#define ASYNC_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ -#define ASYNC_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ -#define ASYNC_CLOSING 0x08000000 /* Serial port is closing */ - -#define IS_A_CONSOLE(min) (((min) & 0xC0) == 0x00) -#define IS_A_SERIAL(min) (((min) & 0xC0) == 0x40) -#define IS_A_PTY(min) ((min) & 0x80) -#define IS_A_PTY_MASTER(min) (((min) & 0xC0) == 0x80) -#define IS_A_PTY_SLAVE(min) (((min) & 0xC0) == 0xC0) -#define PTY_OTHER(min) ((min) ^ 0x40) - -#define SL_TO_DEV(line) ((line) | 0x40) -#define DEV_TO_SL(min) ((min) & 0x3F) - -#define INC(a) ((a) = ((a)+1) & (TTY_BUF_SIZE-1)) -#define DEC(a) ((a) = ((a)-1) & (TTY_BUF_SIZE-1)) -#define EMPTY(a) ((a)->head == (a)->tail) -#define LEFT(a) (((a)->tail-(a)->head-1)&(TTY_BUF_SIZE-1)) -#define LAST(a) ((a)->buf[(TTY_BUF_SIZE-1)&((a)->head-1)]) -#define FULL(a) (!LEFT(a)) -#define CHARS(a) (((a)->head-(a)->tail)&(TTY_BUF_SIZE-1)) - -extern void put_tty_queue(unsigned char c, struct tty_queue * queue); -extern int get_tty_queue(struct tty_queue * queue); +#define TTY_NORMAL 0 +#define TTY_BREAK 1 +#define TTY_FRAME 2 +#define TTY_PARITY 3 +#define TTY_OVERRUN 4 #define INTR_CHAR(tty) ((tty)->termios->c_cc[VINTR]) #define QUIT_CHAR(tty) ((tty)->termios->c_cc[VQUIT]) @@ -240,99 +183,52 @@ * - TYT, 9/14/92 */ struct tty_struct { - struct termios *termios; + int magic; + struct tty_driver driver; + struct tty_ldisc ldisc; + struct termios *termios, *termios_locked; int pgrp; int session; - unsigned char stopped:1, hw_stopped:1, packet:1, lnext:1; - unsigned char char_error:3; - unsigned char erasing:1; - unsigned char ctrl_status; - short line; - int disc; + dev_t device; int flags; int count; - unsigned int column; struct winsize winsize; - int (*open)(struct tty_struct * tty, struct file * filp); - void (*close)(struct tty_struct * tty, struct file * filp); - void (*write)(struct tty_struct * tty); - int (*ioctl)(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg); - void (*throttle)(struct tty_struct * tty, int status); - void (*set_termios)(struct tty_struct *tty, struct termios * old); - void (*stop)(struct tty_struct *tty); - void (*start)(struct tty_struct *tty); - void (*hangup)(struct tty_struct *tty); + unsigned char stopped:1, hw_stopped:1, packet:1; + unsigned char ctrl_status; + struct tty_struct *link; - unsigned char *write_data_ptr; - int write_data_cnt; - void (*write_data_callback)(void * data); - void * write_data_arg; - int readq_flags[TTY_BUF_SIZE/32]; - int secondary_flags[TTY_BUF_SIZE/32]; - int canon_data; - unsigned long canon_head; - unsigned int canon_column; - struct tty_queue read_q; - struct tty_queue write_q; - struct tty_queue secondary; + struct fasync_struct *fasync; + struct tty_flip_buffer flip; + int max_flip_cnt; + struct wait_queue *write_wait; + struct wait_queue *read_wait; void *disc_data; -}; + void *driver_data; -struct tty_ldisc { - int flags; +#define N_TTY_BUF_SIZE 4096 + /* - * The following routines are called from above. + * The following is data for the N_TTY line discpline. For + * historical reasons, this is included in the tty structure. */ - int (*open)(struct tty_struct *); - void (*close)(struct tty_struct *); - int (*read)(struct tty_struct * tty, struct file * file, - unsigned char * buf, unsigned int nr); - int (*write)(struct tty_struct * tty, struct file * file, - unsigned char * buf, unsigned int nr); - int (*ioctl)(struct tty_struct * tty, struct file * file, - unsigned int cmd, unsigned long arg); - int (*select)(struct tty_struct * tty, struct inode * inode, - struct file * file, int sel_type, - struct select_table_struct *wait); - /* - * The following routines are called from below. - */ - void (*handler)(struct tty_struct *); + unsigned int column; + unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1; + unsigned short minimum_to_wake; + unsigned overrun_time; + int num_overrun; + int process_char_map[256/32]; + char *read_buf; + int read_head; + int read_tail; + int read_cnt; + int read_flags[N_TTY_BUF_SIZE/32]; + int canon_data; + unsigned long canon_head; + unsigned int canon_column; }; -#define LDISC_FLAG_DEFINED 0x00000001 - -/* - * These are the different types of thottle status which can be sent - * to the low-level tty driver. The tty_io.c layer is responsible for - * notifying the low-level tty driver of the following conditions: - * secondary queue full, secondary queue available, and read queue - * available. The low-level driver must send the read queue full - * command to itself, if it is interested in that condition. - * - * Note that the low-level tty driver may elect to ignore one or both - * of these conditions; normally, however, it will use ^S/^Q or some - * sort of hardware flow control to regulate the input to try to avoid - * overflow. While the low-level driver is responsible for all - * receiving flow control, note that the ^S/^Q handling (but not - * hardware flow control) is handled by the upper layer, in - * copy_to_cooked. - */ -#define TTY_THROTTLE_SQ_FULL 1 -#define TTY_THROTTLE_SQ_AVAIL 2 -#define TTY_THROTTLE_RQ_FULL 3 -#define TTY_THROTTLE_RQ_AVAIL 4 - -/* - * This defines the low- and high-watermarks for the various conditions. - * Again, the low-level driver is free to ignore any of these, and has - * to implement RQ_THREHOLD_LW for itself if it wants it. - */ -#define SQ_THRESHOLD_LW 16 -#define SQ_THRESHOLD_HW 768 -#define RQ_THRESHOLD_LW 16 -#define RQ_THRESHOLD_HW 768 +/* tty magic number */ +#define TTY_MAGIC 0x5401 /* * These bits are used in the flags field of the tty structure. @@ -342,38 +238,18 @@ * tty->write. Thus, you must use the inline functions set_bit() and * clear_bit() to make things atomic. */ -#define TTY_WRITE_BUSY 0 -#define TTY_READ_BUSY 1 -#define TTY_SQ_THROTTLED 2 -#define TTY_RQ_THROTTLED 3 -#define TTY_IO_ERROR 4 -#define TTY_SLAVE_CLOSED 5 -#define TTY_EXCLUSIVE 6 - -/* - * When a break, frame error, or parity error happens, these codes are - * stuffed into the read queue, and the relevant bit in readq_flag bit - * array is set. - */ -#define TTY_BREAK 1 -#define TTY_FRAME 2 -#define TTY_PARITY 3 -#define TTY_OVERRUN 4 +#define TTY_THROTTLED 0 +#define TTY_IO_ERROR 1 +#define TTY_SLAVE_CLOSED 2 +#define TTY_EXCLUSIVE 3 +#define TTY_DEBUG 4 +#define TTY_DO_WRITE_WAKEUP 5 #define TTY_WRITE_FLUSH(tty) tty_write_flush((tty)) -#define TTY_READ_FLUSH(tty) tty_read_flush((tty)) extern void tty_write_flush(struct tty_struct *); -extern void tty_read_flush(struct tty_struct *); -/* Number of chars that must be available in a write queue before - the queue is awakened. */ -#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4) - -extern struct tty_struct *tty_table[]; -extern struct termios *tty_termios[]; -extern struct termios *termios_locked[]; -extern int tty_check_write[]; +extern struct termios tty_std_termios; extern struct tty_struct * redirect; extern struct tty_ldisc ldiscs[]; extern int fg_console; @@ -381,9 +257,6 @@ extern unsigned long video_num_lines; extern struct wait_queue * keypress_wait; -#define TTY_TABLE_IDX(nr) ((nr) ? (nr) : (fg_console+1)) -#define TTY_TABLE(nr) (tty_table[TTY_TABLE_IDX(nr)]) - /* intr=^C quit=^| erase=del kill=^U eof=^D vtime=\0 vmin=\1 sxtc=\0 start=^Q stop=^S susp=^Z eol=\0 @@ -395,21 +268,22 @@ extern long rs_init(long); extern long lp_init(long); extern long con_init(long); +extern long pty_init(long); extern long tty_init(long); -extern void flush_input(struct tty_struct * tty); -extern void flush_output(struct tty_struct * tty); +extern int tty_paranoia_check(struct tty_struct *tty, dev_t device, + const char *routine); +extern char *_tty_name(struct tty_struct *tty, char *buf); +extern char *tty_name(struct tty_struct *tty); extern void wait_until_sent(struct tty_struct * tty, int timeout); -extern int check_change(struct tty_struct * tty, int channel); +extern int tty_check_change(struct tty_struct * tty); extern void stop_tty(struct tty_struct * tty); extern void start_tty(struct tty_struct * tty); extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc); +extern int tty_register_driver(struct tty_driver *driver); extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp, int buflen); -extern int tty_write_data(struct tty_struct *tty, char *bufp, int buflen, - void (*callback)(void * data), void * callarg); -extern int tty_ioctl(struct inode *, struct file *, unsigned int, unsigned long); extern int is_orphaned_pgrp(int pgrp); extern int is_ignored(int sig); extern int tty_signal(int sig, struct tty_struct *tty); @@ -420,10 +294,12 @@ extern void do_SAK(struct tty_struct *tty); extern void disassociate_ctty(int priv); -/* tty write functions */ +/* n_tty.c */ +extern struct tty_ldisc tty_ldisc_N_TTY; -extern void rs_write(struct tty_struct * tty); -extern void con_write(struct tty_struct * tty); +/* tty_ioctl.c */ +extern int n_tty_ioctl(struct tty_struct * tty, struct file * file, + unsigned int cmd, unsigned long arg); /* serial.c */ diff -u --recursive --new-file v1.1.12/linux/include/linux/tty_driver.h linux/include/linux/tty_driver.h --- v1.1.12/linux/include/linux/tty_driver.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/tty_driver.h Mon May 23 07:55:15 1994 @@ -0,0 +1,178 @@ +#ifndef _LINUX_TTY_DRIVER_H +#define _LINUX_TTY_DRIVER_H + +/* + * This structure defines the interface between the low-level tty + * driver and the tty routines. The following routines can be + * defined; unless noted otherwise, they are optional, and can be + * filled in with a null pointer. + * + * int (*open)(struct tty_struct * tty, struct file * filp); + * + * This routine is called when a particular tty device is opened. + * This routine is mandatory; if this routine is not filled in, + * the attempted open will fail with ENODEV. + * + * void (*close)(struct tty_struct * tty, struct file * filp); + * + * This routine is called when a particular tty device is closed. + * + * int (*write)(struct tty_struct * tty, int from_user, + * unsigned char *buf, int count); + * + * This routine is called by the kernel to write a series of + * characters to the tty device. The characters may come from + * user space or kernel space. This routine will return the + * number of characters actually accepted for writing. This + * routine is mandatory. + * + * void (*put_char)(struct tty_struct *tty, unsigned char ch); + * + * This routine is called by the kernel to write a single + * character to the tty device. If the kernel uses this routine, + * it must call the flush_chars() routine (if defined) when it is + * done stuffing characters into the driver. If there is no room + * in the queue, the character is ignored. + * + * void (*flush_chars)(struct tty_struct *tty); + * + * This routine is called by the kernel after it has written a + * series of characters to the tty device using put_char(). + * + * int (*write_room)(struct tty_struct *tty); + * + * This routine returns the numbers of characters the tty driver + * will accept for queueing to be writen. This number is subject + * to change as output buffers get emptied, or if the output flow + * control is acted. + * + * int (*ioctl)(struct tty_struct *tty, struct file * file, + * unsigned int cmd, unsigned long arg); + * + * This routine allows the tty driver to implement + * device-specific iotctl's. If the ioctl number passed in cmd + * is not recognized by the driver, it should return ENOIOCTLCMD. + * + * void (*set_termios)(struct tty_struct *tty, struct termios * old); + * + * This routine allows the tty driver to be notified when + * device's termios settings have changed. + * + * void (*throttle)(struct tty_struct * tty); + * + * This routine notifies the tty driver that input buffers for + * the line discpline are close to full, and it should somehow + * signal that no more characters should be sent to the tty. + * + * void (*unthrottle)(struct tty_struct * tty); + * + * This routine notifies the tty drivers that it should signals + * that characters can now be sent to the tty without fear of + * overrunning the input buffers of the line discplines. + * + * void (*stop)(struct tty_struct *tty); + * + * This routine notfies the tty driver that it should stop + * outputting characters to the tty device. + * + * void (*start)(struct tty_struct *tty); + * + * This routine notifies the tty driver that it resume sending + * characters to the tty device. + * + * void (*hangup)(struct tty_struct *tty); + * + * This routine notifies the tty driver that it should hangup the + * tty device. + * + */ + +struct tty_driver { + int magic; /* magic number for this structure */ + char *name; + int name_base; /* offset of printed name */ + short major; /* major device number */ + short minor_start; /* start of minor device number*/ + short num; /* number of devices */ + short type; /* type of tty driver */ + short subtype; /* subtype of tty driver */ + struct termios init_termios; /* Initial termios */ + int flags; /* tty driver flags */ + int *refcount; /* for loadable tty drivers */ + struct tty_driver *other; /* only used for the PTY driver */ + + /* + * Pointer to the tty data structures + */ + struct tty_struct **table; + struct termios **termios; + struct termios **termios_locked; + + /* + * Interface routines from the upper tty layer to the tty + * driver. + */ + int (*open)(struct tty_struct * tty, struct file * filp); + void (*close)(struct tty_struct * tty, struct file * filp); + int (*write)(struct tty_struct * tty, int from_user, + unsigned char *buf, int count); + void (*put_char)(struct tty_struct *tty, unsigned char ch); + void (*flush_chars)(struct tty_struct *tty); + int (*write_room)(struct tty_struct *tty); + int (*chars_in_buffer)(struct tty_struct *tty); + int (*ioctl)(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg); + void (*set_termios)(struct tty_struct *tty, struct termios * old); + void (*throttle)(struct tty_struct * tty); + void (*unthrottle)(struct tty_struct * tty); + void (*stop)(struct tty_struct *tty); + void (*start)(struct tty_struct *tty); + void (*hangup)(struct tty_struct *tty); + void (*flush_buffer)(struct tty_struct *tty); + + /* + * linked list pointers + */ + struct tty_driver *next; + struct tty_driver *prev; +}; + +/* tty driver magic number */ +#define TTY_DRIVER_MAGIC 0x5402 + +/* + * tty driver flags + * + * TTY_DRIVER_RESET_TERMIOS --- requests the tty layer to reset the + * termios setting when the last process has closed the device. + * Used for PTY's, in particular. + * + * TTY_DRIVER_REAL_RAW --- if set, indicates that the driver will + * guarantee never not to set any special character handling + * flags if ((IGNBRK || (!BRKINT && !PARMRK)) && (IGNPAR || + * !INPCK)). That is, if there is no reason for the driver to + * send notifications of parity and break characters up to the + * line driver, it won't do so. This allows the line driver to + * optimize for this case if this flag is set. (Note that there + * is also a promise, if the above case is true, not to signal + * overruns, either.) + */ +#define TTY_DRIVER_INSTALLED 0x0001 +#define TTY_DRIVER_RESET_TERMIOS 0x0002 +#define TTY_DRIVER_REAL_RAW 0x0004 + +/* tty driver types */ +#define TTY_DRIVER_TYPE_SYSTEM 0x0001 +#define TTY_DRIVER_TYPE_CONSOLE 0x0002 +#define TTY_DRIVER_TYPE_SERIAL 0x0003 +#define TTY_DRIVER_TYPE_PTY 0x0004 + +/* system subtypes (magic, used by tty_io.c) */ +#define SYSTEM_TYPE_TTY 0x0001 +#define SYSTEM_TYPE_CONSOLE 0x0002 + +/* pty subtypes (magic, used by tty_io.c) */ +#define PTY_TYPE_MASTER 0x0001 +#define PTY_TYPE_SLAVE 0x0002 + +#endif /* #ifdef _LINUX_TTY_DRIVER_H */ diff -u --recursive --new-file v1.1.12/linux/include/linux/tty_flip.h linux/include/linux/tty_flip.h --- v1.1.12/linux/include/linux/tty_flip.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/tty_flip.h Mon May 23 07:55:15 1994 @@ -0,0 +1,34 @@ +#ifndef _LINUX_TTY_FLIP_H +#define _LINUX_TTY_FLIP_H + +#ifdef INCLUDE_INLINE_FUNCS +#define _INLINE_ extern +#else +#define _INLINE_ extern __inline__ +#endif + +_INLINE_ void tty_insert_flip_char(struct tty_struct *tty, + unsigned char ch, char flag) +{ + if (tty->flip.count++ >= TTY_FLIPBUF_SIZE) + return; + *tty->flip.flag_buf_ptr++ = flag; + *tty->flip.char_buf_ptr++ = ch; +} + +_INLINE_ void tty_schedule_flip(struct tty_struct *tty) +{ + queue_task(&tty->flip.tqueue, &tq_timer); +} + +#undef _INLINE_ + + +#endif /* _LINUX_TTY_FLIP_H */ + + + + + + + diff -u --recursive --new-file v1.1.12/linux/include/linux/tty_ldisc.h linux/include/linux/tty_ldisc.h --- v1.1.12/linux/include/linux/tty_ldisc.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/tty_ldisc.h Mon May 23 07:55:15 1994 @@ -0,0 +1,43 @@ +#ifndef _LINUX_TTY_LDISC_H +#define _LINUX_TTY_LDISC_H + +/* + * Definitions for the tty line discipline + */ + +struct tty_ldisc { + int magic; + int num; + int flags; + /* + * The following routines are called from above. + */ + int (*open)(struct tty_struct *); + void (*close)(struct tty_struct *); + void (*flush_buffer)(struct tty_struct *tty); + int (*chars_in_buffer)(struct tty_struct *tty); + int (*read)(struct tty_struct * tty, struct file * file, + unsigned char * buf, unsigned int nr); + int (*write)(struct tty_struct * tty, struct file * file, + unsigned char * buf, unsigned int nr); + int (*ioctl)(struct tty_struct * tty, struct file * file, + unsigned int cmd, unsigned long arg); + void (*set_termios)(struct tty_struct *tty, struct termios * old); + int (*select)(struct tty_struct * tty, struct inode * inode, + struct file * file, int sel_type, + struct select_table_struct *wait); + + /* + * The following routines are called from below. + */ + void (*receive_buf)(struct tty_struct *, unsigned char *cp, + char *fp, int count); + int (*receive_room)(struct tty_struct *); + void (*write_wakeup)(struct tty_struct *); +}; + +#define TTY_LDISC_MAGIC 0x5403 + +#define LDISC_FLAG_DEFINED 0x00000001 + +#endif /* _LINUX_TTY_LDISC_H */ diff -u --recursive --new-file v1.1.12/linux/kernel/Makefile linux/kernel/Makefile --- v1.1.12/linux/kernel/Makefile Mon Apr 25 10:04:36 1994 +++ linux/kernel/Makefile Mon May 23 07:55:11 1994 @@ -19,7 +19,7 @@ OBJS = sched.o sys_call.o traps.o irq.o dma.o fork.o \ panic.o printk.o vsprintf.o sys.o module.o ksyms.o exit.o \ signal.o mktime.o ptrace.o ioport.o itimer.o \ - info.o ldt.o time.o vm86.o + info.o ldt.o time.o tqueue.o vm86.o all: kernel.o diff -u --recursive --new-file v1.1.12/linux/kernel/exit.c linux/kernel/exit.c --- v1.1.12/linux/kernel/exit.c Sat May 7 14:54:13 1994 +++ linux/kernel/exit.c Mon May 23 10:04:04 1994 @@ -52,6 +52,11 @@ return -EPERM; if (!sig) return 0; + /* + * Forget it if the process is already zombie'd. + */ + if (p->state == TASK_ZOMBIE) + return 0; if ((sig == SIGKILL) || (sig == SIGCONT)) { if (p->state == TASK_STOPPED) p->state = TASK_RUNNING; diff -u --recursive --new-file v1.1.12/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v1.1.12/linux/kernel/ksyms.c Sat May 7 14:54:15 1994 +++ linux/kernel/ksyms.c Mon May 23 10:00:22 1994 @@ -14,6 +14,10 @@ #include #include #include +#include +#ifdef CONFIG_INET +#include +#endif extern void *sys_call_table; @@ -38,6 +42,18 @@ extern void (* iABI_hook)(struct pt_regs * regs); #endif +#ifdef CONFIG_INET +extern int register_netdev(struct device *); +extern void unregister_netdev(struct device *); +extern void ether_setup(struct device *); +extern struct sk_buff *alloc_skb(unsigned int,int); +extern void kfree_skb(struct sk_buff *, int); +extern void snarf_region(unsigned int, unsigned int); +extern void netif_rx(struct sk_buff *); +extern int dev_rint(unsigned char *, long, int, struct device *); +extern void dev_tint(struct device *); +extern struct device *irq2dev_map[]; +#endif struct { void *addr; @@ -81,6 +97,8 @@ /* interrupt handling */ X(request_irq), X(free_irq), + X(bh_active), + X(bh_mask), /* process management */ X(wake_up), @@ -131,6 +149,20 @@ /* Miscellaneous access points */ X(si_meminfo), +#endif + +#ifdef CONFIG_INET + /* support for loadable net drivers */ + X(register_netdev), + X(unregister_netdev), + X(ether_setup), + X(alloc_skb), + X(kfree_skb), + X(snarf_region), + X(netif_rx), + X(dev_rint), + X(dev_tint), + X(irq2dev_map), #endif }; diff -u --recursive --new-file v1.1.12/linux/kernel/sched.c linux/kernel/sched.c --- v1.1.12/linux/kernel/sched.c Sun May 1 12:12:49 1994 +++ linux/kernel/sched.c Mon May 23 07:55:11 1994 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,8 @@ volatile struct timeval xtime; /* The current time */ int tickadj = 500/HZ; /* microsecs */ +DECLARE_TASK_QUEUE(tq_timer); + /* * phase-lock loop variables */ @@ -548,6 +551,11 @@ } } +void tqueue_bh(void * unused) +{ + run_task_queue(&tq_timer); +} + /* * The int argument is really a (struct pt_regs *), in case the * interrupt wants to know from where it was called. The timer @@ -667,6 +675,8 @@ mark_bh(TIMER_BH); } } + if (tq_timer != &tq_last) + mark_bh(TQUEUE_BH); sti(); } @@ -776,6 +786,7 @@ struct desc_struct * p; bh_base[TIMER_BH].routine = timer_bh; + bh_base[TQUEUE_BH].routine = tqueue_bh; if (sizeof(struct sigaction) != 16) panic("Struct sigaction MUST be 16 bytes"); set_tss_desc(gdt+FIRST_TSS_ENTRY,&init_task.tss); diff -u --recursive --new-file v1.1.12/linux/kernel/sys.c linux/kernel/sys.c --- v1.1.12/linux/kernel/sys.c Mon May 23 12:14:25 1994 +++ linux/kernel/sys.c Mon May 23 07:55:12 1994 @@ -490,7 +490,7 @@ return -EPERM; current->leader = 1; current->session = current->pgrp = current->pid; - current->tty = -1; + current->tty = NULL; return current->pgrp; } diff -u --recursive --new-file v1.1.12/linux/kernel/tqueue.c linux/kernel/tqueue.c --- v1.1.12/linux/kernel/tqueue.c Thu Jan 1 02:00:00 1970 +++ linux/kernel/tqueue.c Mon May 23 07:55:15 1994 @@ -0,0 +1,10 @@ +/* + * tqueue.c --- task queue handling for Linux. + * + * This routine merely draws in the static portion of the task queue + * inline functions. Look in tqueue.h for the relevant functions. + */ + +#define INCLUDE_INLINE_FUNCS + +#include diff -u --recursive --new-file v1.1.12/linux/kernel/vm86.c linux/kernel/vm86.c --- v1.1.12/linux/kernel/vm86.c Mon May 23 12:14:25 1994 +++ linux/kernel/vm86.c Mon May 23 07:45:07 1994 @@ -250,7 +250,7 @@ __asm__ __volatile__( \ "movb %%fs:0(%1,%0),%b2\n\t" \ "incw %w0" \ - : "=r" (ptr), "=r" (base), "=r" (__res) \ + : "=r" (ptr), "=r" (base), "=q" (__res) \ : "0" (ptr), "1" (base), "2" (0)); \ __res; }) @@ -261,7 +261,7 @@ "incw %w0\n\t" \ "movb %%fs:0(%1,%0),%h2\n\t" \ "incw %w0" \ - : "=r" (ptr), "=r" (base), "=r" (__res) \ + : "=r" (ptr), "=r" (base), "=q" (__res) \ : "0" (ptr), "1" (base), "2" (0)); \ __res; }) @@ -278,7 +278,7 @@ "movb %%fs:0(%1,%0),%h2\n\t" \ "incw %w0\n\t" \ "rorl $16,%2" \ - : "=r" (ptr), "=r" (base), "=r" (__res) \ + : "=r" (ptr), "=r" (base), "=q" (__res) \ : "0" (ptr), "1" (base)); \ __res; }) diff -u --recursive --new-file v1.1.12/linux/modules/NET_MODULES linux/modules/NET_MODULES --- v1.1.12/linux/modules/NET_MODULES Thu Jan 1 02:00:00 1970 +++ linux/modules/NET_MODULES Mon May 23 11:53:54 1994 @@ -0,0 +1 @@ +3c509.o de600.o diff -u --recursive --new-file v1.1.12/linux/net/Makefile linux/net/Makefile --- v1.1.12/linux/net/Makefile Wed Dec 1 14:44:15 1993 +++ linux/net/Makefile Mon May 23 08:17:45 1994 @@ -21,7 +21,7 @@ .c.s: $(CC) $(CFLAGS) -S $< -OBJS = Space.o ddi.o socket.o +OBJS = socket.o protocols.o all: subdirs net.o diff -u --recursive --new-file v1.1.12/linux/net/Space.c linux/net/Space.c --- v1.1.12/linux/net/Space.c Tue Apr 19 10:53:50 1994 +++ linux/net/Space.c Mon May 23 08:17:45 1994 @@ -1,59 +0,0 @@ -/* - * Space.c Defines which protocol modules and I/O device drivers get - * linked into the LINUX kernel. Currently, this is only used - * by the NET layer of LINUX, but it eventually might move to - * an upper directory of the system. - * - * Version: @(#)Space.c 1.0.2 04/22/93 - * - * Author: Fred N. van Kempen, - * - * Please see the comments in ddi.c - Alan - * - */ - -#include -#include -#include -#include - - -#define CONFIG_UNIX YES /* always present... */ - - -/* - * Section A: Networking Protocol Handlers. - * This section defines which networking protocols get - * linked into the SOCKET layer of the Linux kernel. - * Currently, these are AF_UNIX (always) and AF_INET. - */ -#ifdef CONFIG_UNIX -# include "unix/unix.h" -#endif -#ifdef CONFIG_INET -# include -#endif -#ifdef CONFIG_IPX -#include "inet/ipxcall.h" -#endif -#ifdef CONFIG_AX25 -#include "inet/ax25call.h" -#endif - -struct ddi_proto protocols[] = { -#ifdef CONFIG_UNIX - { "UNIX", unix_proto_init }, -#endif -#ifdef CONFIG_IPX - { "IPX", ipx_proto_init }, -#endif -#ifdef CONFIG_AX25 - { "AX.25", ax25_proto_init }, -#endif -#ifdef CONFIG_INET - { "INET", inet_proto_init }, -#endif - { NULL, NULL } -}; - - diff -u --recursive --new-file v1.1.12/linux/net/inet/Makefile linux/net/inet/Makefile --- v1.1.12/linux/net/inet/Makefile Tue Apr 19 10:53:50 1994 +++ linux/net/inet/Makefile Mon May 23 08:29:50 1994 @@ -15,23 +15,34 @@ $(CC) $(CFLAGS) -S -o $*.s $< -OBJS = sock.o utils.o route.o proc.o timer.o protocol.o \ - eth.o packet.o arp.o dev.o ip.o raw.o icmp.o tcp.o udp.o \ - datagram.o skbuff.o devinet.o +OBJS := sock.o eth.o dev.o skbuff.o datagram.o +ifdef CONFIG_INET + +OBJS := $(OBJS) utils.o route.o proc.o timer.o protocol.o packet.o \ + arp.o ip.o raw.o icmp.o tcp.o udp.o devinet.o af_inet.o + +endif + +ifdef CONFIG_INET_RARP + +OBJS := $(OBJS) rarp.o + +endif + ifdef CONFIG_AX25 -OBJS := $(OBJS) ax25.o ax25_in.o ax25_out.o ax25_subr.o ax25_timer.o +OBJS := $(OBJS) ax25.o ax25_in.o ax25_out.o ax25_route.o ax25_subr.o ax25_timer.o endif ifdef CONFIG_IPX -OBJS := $(OBJS) ipx.o +OBJS := $(OBJS) ipx.o pe2.o p8022.o p8023.o endif -ifdef CONFIG_INET +ifdef CONFIG_NET inet.o: $(OBJS) $(LD) -r -o inet.o $(OBJS) diff -u --recursive --new-file v1.1.12/linux/net/inet/README linux/net/inet/README --- v1.1.12/linux/net/inet/README Tue Apr 19 10:53:50 1994 +++ linux/net/inet/README Mon May 23 08:17:45 1994 @@ -1,92 +1,37 @@ +This is snapshot 014 -This is snapshot 010 +This fixes the following from the 1.1.12 release (see the relevant files +for the credits to authors). -Notes: -ARP - As of snapshot 006, ARP should compile and work correctly - for any protocol that has the right build_header support. - -AX25 - This is an ALPHA release. It will not be a standard part - of the real release module. Please read the copyrights on - the AX.25 code carefully. When AX.25 is finished it will - be part of a seperatly available amateur radio add on. Also - please rememeber this is ALPHA code. It works well for a lot - of people but I know for a fact it is currently buggy. - -IPX - The IPX module in here is fairly complete, and certainly - usable for things. The IPX user code isn't yet very useful - (nobody has written a RIP/SAP daemon!). - -NetROM - I'm slowly doing bits of this code, but its not even fit - to include here. - - -Status: - -Done: - Replaced ARP with Florian la Roche's ARP. - Replaced/improved sk_buff handlers (again from Florian) - Removed surplus DDI code. - Reformatted most modules. - Fixed ICMP handling bugs (ICMP error to ICMP error). - Fixed fragmentation bugs (both memory and mtu). - Moved some includes. - Drivers now build correctly with no IP layer. - Merged Linus 1.0.1 diffs and my patches 1-3. - Further fixups on clean driver build. - Loopback driver now lives where it belongs. - UDP verified against specification (passes). - IP verified against specification (two errors: Incorrect forwarding and - no mandatory option handling). - ARP verified against specification (passes: recommendation that ARP - rejects MAC broadcast/multicast addresses - this needs - driver changes doing). - All surplus skb->sk assignment and skb->mem_len skb->mem_addr removed. - eth.h became linux/etherdevice.h. - alloc_skb nows adds the sizeof(struct sk_buff) itself. - Now relative to Linux 1.0.4. - All IP wakeups are now callbacks. - IPX and AX.25 callbacks now use wake_up_interruptible correctly. - ICMP,IP and UDP collect snmp statistics. - Removed the 4K limit from the /proc/net/* files. - Routing bugs. - Cleaned up skb duplication. - IPX /proc from Mark Evans. - Driver packet ordering now enforced. - AX.25 unused SSID bits now set. - -In Progress: - Module by module validation against specifications. - TCP delayed ACK [RFC1122 requires this]. - Byte-order fixes. - Core code restructure to enable a working non IP build - Trying to fix /proc to do >4K correctly, as well as dynamic addition - of /proc/ and /proc/net/ objects (for module protocol layers). - Adding the extra NET2E driver ioctl() support. - SNMP MIB statistic capture - finish TCP and add device layer when - Donald is ready. - Donald Beckers latest driver mods. - Adding the ICMP_TIMESTAMP support patch. - Routing bugs. - Packet level time stamping. - Merging in support for the I^2IT 'TICK' time synchronisation chip. - Crynwyr compliant PLIP driver. - -To Do: - Merge in sk_buff data handling module. - Socket family/protocol seperation. - Additional BSD options (SO_LOWAT etc). - IP option handling, especially on ip forwards. - AX.25 /proc support. - SNMP /proc support. - TCP MSS/Window and route metrics in the routing table. - TCP mtu discovery support. - NetROM. - TCP closing side state machine bug fixes. - NetBEUI (Lan Manager) [ie IEE802.3/IEE802.2/NetBIOS]. - Make drivers record type and addressing category(Multicast/Broadcast..) - Speed it up. - Unix domain cleanup/rewrite. +o RARP compiles in properly +o Using new Tytso TTY drivers +o IP forwarding is configurable +o PC/TCP support +o AX.25 builds fine without SLIP driver (just PI) +o MTU recognized in routing table (but only by TCP currently) +o AX.25 PI driver merged into AX.25 code and kernel stubs +o UNIX /proc trap hopefully fixed +o DDI removed totally ready to use the PCMICA people's stuff +o Unix domain lock/unlock now static (needlessly visible before) +o Split net/inet/sock.c into generic and IP components +o NFS client works correctly with 8K NFS +o Non IP builds work correctly +o Renamed inet_bh etc to net_bh to reflect true nature +o TCP handling of poor routes much improved +o TCP connect timing fixed +o Incredibly unlikely SLIP memory leak removed +o Loopback maintains IFF_LOOPBACK flag +o Johnathon Naylor(G4KLX) AX.25 changes +o Out of sync bug in lance driver fixed. +o First cut at ethernet loadable modules +o PCMICA people have ifmap stuff. Will extend this to other drivers. +o New de600.c +o Clean up of IP layer - sorted a lot of redundant and duplicated code + out. +o Removed all the old non working debugging junk from the kernel. +o Removed all the devices the kernel used to use as a legacy from + FvK's days writing the linux networking. +o Greg Page's latest and greatest IPX fixes (including 802.2). Now + I've got the stuff to write a free Netware client too and some + volunteers to do it. +o Fixed the 1.1.12 ARP fragment bug. diff -u --recursive --new-file v1.1.12/linux/net/inet/af_inet.c linux/net/inet/af_inet.c --- v1.1.12/linux/net/inet/af_inet.c Thu Jan 1 02:00:00 1970 +++ linux/net/inet/af_inet.c Mon May 23 08:17:46 1994 @@ -0,0 +1,1391 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * AF_INET protocol family socket handler. + * + * Version: @(#)af_inet.c (from sock.c) 1.0.17 06/02/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Florian La Roche, + * Alan Cox, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include "ip.h" +#include "protocol.h" +#include "arp.h" +#include "rarp.h" +#include "route.h" +#include "tcp.h" +#include "udp.h" +#include +#include "sock.h" +#include "raw.h" +#include "icmp.h" + +#define min(a,b) ((a)<(b)?(a):(b)) + +extern struct proto packet_prot; + + +/* + * See if a socket number is in use. + */ + +static int sk_inuse(struct proto *prot, int num) +{ + struct sock *sk; + + for(sk = prot->sock_array[num & (SOCK_ARRAY_SIZE -1 )]; + sk != NULL; sk=sk->next) + { + if (sk->num == num) + return(1); + } + return(0); +} + + +/* + * Pick a new socket number + */ + +unsigned short get_new_socknum(struct proto *prot, unsigned short base) +{ + static int start=0; + + /* + * Used to cycle through the port numbers so the + * chances of a confused connection drop. + */ + + int i, j; + int best = 0; + int size = 32767; /* a big num. */ + struct sock *sk; + + if (base == 0) + base = PROT_SOCK+1+(start % 1024); + if (base <= PROT_SOCK) + { + base += PROT_SOCK+(start % 1024); + } + + /* Now look through the entire array and try to find an empty ptr. */ + for(i=0; i < SOCK_ARRAY_SIZE; i++) + { + j = 0; + sk = prot->sock_array[(i+base+1) &(SOCK_ARRAY_SIZE -1)]; + while(sk != NULL) + { + sk = sk->next; + j++; + } + if (j == 0) + { + start =(i+1+start )%1024; + return(i+base+1); + } + if (j < size) + { + best = i; + size = j; + } + } + + /* Now make sure the one we want is not in use. */ + + while(sk_inuse(prot, base +best+1)) + { + best += SOCK_ARRAY_SIZE; + } + return(best+base+1); +} + +/* + * Add a socket into the socket tables by number. + */ + +void put_sock(unsigned short num, struct sock *sk) +{ + struct sock *sk1; + struct sock *sk2; + int mask; + + sk->num = num; + sk->next = NULL; + num = num &(SOCK_ARRAY_SIZE -1); + + /* We can't have an interupt re-enter here. */ + cli(); + if (sk->prot->sock_array[num] == NULL) + { + sk->prot->sock_array[num] = sk; + sti(); + return; + } + sti(); + for(mask = 0xff000000; mask != 0xffffffff; mask = (mask >> 8) | mask) + { + if ((mask & sk->saddr) && + (mask & sk->saddr) != (mask & 0xffffffff)) + { + mask = mask << 8; + break; + } + } + cli(); + sk1 = sk->prot->sock_array[num]; + for(sk2 = sk1; sk2 != NULL; sk2=sk2->next) + { + if (!(sk2->saddr & mask)) + { + if (sk2 == sk1) + { + sk->next = sk->prot->sock_array[num]; + sk->prot->sock_array[num] = sk; + sti(); + return; + } + sk->next = sk2; + sk1->next= sk; + sti(); + return; + } + sk1 = sk2; + } + + /* Goes at the end. */ + sk->next = NULL; + sk1->next = sk; + sti(); +} + +/* + * Remove a socket from the socket tables. + */ + +static void remove_sock(struct sock *sk1) +{ + struct sock *sk2; + + if (!sk1->prot) + { + printk("sock.c: remove_sock: sk1->prot == NULL\n"); + return; + } + + /* We can't have this changing out from under us. */ + cli(); + sk2 = sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)]; + if (sk2 == sk1) + { + sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)] = sk1->next; + sti(); + return; + } + + while(sk2 && sk2->next != sk1) + { + sk2 = sk2->next; + } + + if (sk2) + { + sk2->next = sk1->next; + sti(); + return; + } + sti(); +} + +/* + * Destroy an AF_INET socket + */ + +void destroy_sock(struct sock *sk) +{ + struct sk_buff *skb; + + sk->inuse = 1; /* just to be safe. */ + + /* Incase it's sleeping somewhere. */ + if (!sk->dead) + sk->write_space(sk); + + remove_sock(sk); + + /* Now we can no longer get new packets. */ + delete_timer(sk); + + while ((skb = tcp_dequeue_partial(sk)) != NULL) { + IS_SKB(skb); + kfree_skb(skb, FREE_WRITE); + } + + /* Cleanup up the write buffer. */ + while((skb = skb_dequeue(&sk->write_queue)) != NULL) { + IS_SKB(skb); + kfree_skb(skb, FREE_WRITE); + } + + while((skb=skb_dequeue(&sk->receive_queue))!=NULL) { + /* + * This will take care of closing sockets that were + * listening and didn't accept everything. + */ + if (skb->sk != NULL && skb->sk != sk) + { + IS_SKB(skb); + skb->sk->dead = 1; + skb->sk->prot->close(skb->sk, 0); + } + IS_SKB(skb); + kfree_skb(skb, FREE_READ); + } + + /* Now we need to clean up the send head. */ + cli(); + for(skb = sk->send_head; skb != NULL; ) + { + struct sk_buff *skb2; + + /* + * We need to remove skb from the transmit queue, + * or maybe the arp queue. + */ + if (skb->next && skb->prev) { +/* printk("destroy_sock: unlinked skb\n");*/ + IS_SKB(skb); + skb_unlink(skb); + } + skb->dev = NULL; + skb2 = skb->link3; + kfree_skb(skb, FREE_WRITE); + skb = skb2; + } + sk->send_head = NULL; + sti(); + + /* And now the backlog. */ + while((skb=skb_dequeue(&sk->back_log))!=NULL) + { + /* this should never happen. */ +/* printk("cleaning back_log\n");*/ + kfree_skb(skb, FREE_READ); + } + + /* Now if it has a half accepted/ closed socket. */ + if (sk->pair) + { + sk->pair->dead = 1; + sk->pair->prot->close(sk->pair, 0); + sk->pair = NULL; + } + + /* + * Now if everything is gone we can free the socket + * structure, otherwise we need to keep it around until + * everything is gone. + */ + + if (sk->dead && sk->rmem_alloc == 0 && sk->wmem_alloc == 0) + { + kfree_s((void *)sk,sizeof(*sk)); + } + else + { + /* this should never happen. */ + /* actually it can if an ack has just been sent. */ + sk->destroy = 1; + sk->ack_backlog = 0; + sk->inuse = 0; + reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME); + } +} + +/* + * The routines beyond this point handle the behaviour of an AF_INET + * socket object. Mostly it punts to the subprotocols of IP to do + * the work. + */ + +static int inet_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + struct sock *sk; + + sk = (struct sock *) sock->data; + + switch(cmd) + { + case F_SETOWN: + /* + * This is a little restrictive, but it's the only + * way to make sure that you can't send a sigurg to + * another process. + */ + if (!suser() && current->pgrp != -arg && + current->pid != arg) return(-EPERM); + sk->proc = arg; + return(0); + case F_GETOWN: + return(sk->proc); + default: + return(-EINVAL); + } +} + +/* + * Set socket options on an inet socket. + */ + +static int inet_setsockopt(struct socket *sock, int level, int optname, + char *optval, int optlen) +{ + struct sock *sk = (struct sock *) sock->data; + if (level == SOL_SOCKET) + return sock_setsockopt(sk,level,optname,optval,optlen); + if (sk->prot->setsockopt==NULL) + return(-EOPNOTSUPP); + else + return sk->prot->setsockopt(sk,level,optname,optval,optlen); +} + + + +static int inet_getsockopt(struct socket *sock, int level, int optname, + char *optval, int *optlen) +{ + struct sock *sk = (struct sock *) sock->data; + if (level == SOL_SOCKET) + return sock_getsockopt(sk,level,optname,optval,optlen); + if(sk->prot->getsockopt==NULL) + return(-EOPNOTSUPP); + else + return sk->prot->getsockopt(sk,level,optname,optval,optlen); +} + + +static int inet_autobind(struct sock *sk) +{ + /* We may need to bind the socket. */ + if (sk->num == 0) + { + sk->num = get_new_socknum(sk->prot, 0); + if (sk->num == 0) + return(-EAGAIN); + put_sock(sk->num, sk); + sk->dummy_th.source = ntohs(sk->num); + } + return 0; +} + +static int inet_listen(struct socket *sock, int backlog) +{ + struct sock *sk = (struct sock *) sock->data; + + if(inet_autobind(sk)!=0) + return -EAGAIN; + + /* We might as well re use these. */ + sk->max_ack_backlog = backlog; + if (sk->state != TCP_LISTEN) + { + sk->ack_backlog = 0; + sk->state = TCP_LISTEN; + } + return(0); +} + +/* + * Default callbacks for user INET sockets. These just wake up + * the user owning the socket. + */ + +static void def_callback1(struct sock *sk) +{ + if(!sk->dead) + wake_up_interruptible(sk->sleep); +} + +static void def_callback2(struct sock *sk,int len) +{ + if(!sk->dead) + wake_up_interruptible(sk->sleep); +} + + +/* + * Create an inet socket. + * + * FIXME: Gcc would generate much better code if we set the parameters + * up in in-memory structure order. Gcc68K even more so + */ + +static int inet_create(struct socket *sock, int protocol) +{ + struct sock *sk; + struct proto *prot; + int err; + + sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL); + if (sk == NULL) + return(-ENOBUFS); + sk->num = 0; + sk->reuse = 0; + switch(sock->type) + { + case SOCK_STREAM: + case SOCK_SEQPACKET: + if (protocol && protocol != IPPROTO_TCP) + { + kfree_s((void *)sk, sizeof(*sk)); + return(-EPROTONOSUPPORT); + } + protocol = IPPROTO_TCP; + sk->no_check = TCP_NO_CHECK; + prot = &tcp_prot; + break; + + case SOCK_DGRAM: + if (protocol && protocol != IPPROTO_UDP) + { + kfree_s((void *)sk, sizeof(*sk)); + return(-EPROTONOSUPPORT); + } + protocol = IPPROTO_UDP; + sk->no_check = UDP_NO_CHECK; + prot=&udp_prot; + break; + + case SOCK_RAW: + if (!suser()) + { + kfree_s((void *)sk, sizeof(*sk)); + return(-EPERM); + } + if (!protocol) + { + kfree_s((void *)sk, sizeof(*sk)); + return(-EPROTONOSUPPORT); + } + prot = &raw_prot; + sk->reuse = 1; + sk->no_check = 0; /* + * Doesn't matter no checksum is + * preformed anyway. + */ + sk->num = protocol; + break; + + case SOCK_PACKET: + if (!suser()) + { + kfree_s((void *)sk, sizeof(*sk)); + return(-EPERM); + } + if (!protocol) + { + kfree_s((void *)sk, sizeof(*sk)); + return(-EPROTONOSUPPORT); + } + prot = &packet_prot; + sk->reuse = 1; + sk->no_check = 0; /* Doesn't matter no checksum is + * preformed anyway. + */ + sk->num = protocol; + break; + + default: + kfree_s((void *)sk, sizeof(*sk)); + return(-ESOCKTNOSUPPORT); + } + sk->socket = sock; +#ifdef CONFIG_TCP_NAGLE_OFF + sk->nonagle = 1; +#else + sk->nonagle = 0; +#endif + sk->type = sock->type; + sk->stamp.tv_sec=0; + sk->protocol = protocol; + sk->wmem_alloc = 0; + sk->rmem_alloc = 0; + sk->sndbuf = SK_WMEM_MAX; + sk->rcvbuf = SK_RMEM_MAX; + sk->pair = NULL; + sk->opt = NULL; + sk->write_seq = 0; + sk->acked_seq = 0; + sk->copied_seq = 0; + sk->fin_seq = 0; + sk->urg_seq = 0; + sk->urg_data = 0; + sk->proc = 0; + sk->rtt = 0; /*TCP_WRITE_TIME << 3;*/ + sk->rto = TCP_TIMEOUT_INIT; /*TCP_WRITE_TIME*/ + sk->mdev = 0; + sk->backoff = 0; + sk->packets_out = 0; + sk->cong_window = 1; /* start with only sending one packet at a time. */ + sk->cong_count = 0; + sk->ssthresh = 0; + sk->max_window = 0; + sk->urginline = 0; + sk->intr = 0; + sk->linger = 0; + sk->destroy = 0; + sk->priority = 1; + sk->shutdown = 0; + sk->keepopen = 0; + sk->zapped = 0; + sk->done = 0; + sk->ack_backlog = 0; + sk->window = 0; + sk->bytes_rcv = 0; + sk->state = TCP_CLOSE; + sk->dead = 0; + sk->ack_timed = 0; + sk->partial = NULL; + sk->user_mss = 0; + sk->debug = 0; + + /* this is how many unacked bytes we will accept for this socket. */ + sk->max_unacked = 2048; /* needs to be at most 2 full packets. */ + + /* how many packets we should send before forcing an ack. + if this is set to zero it is the same as sk->delay_acks = 0 */ + sk->max_ack_backlog = 0; + sk->inuse = 0; + sk->delay_acks = 0; + skb_queue_head_init(&sk->write_queue); + skb_queue_head_init(&sk->receive_queue); + sk->mtu = 576; + sk->prot = prot; + sk->sleep = sock->wait; + sk->daddr = 0; + sk->saddr = ip_my_addr(); + sk->err = 0; + sk->next = NULL; + sk->pair = NULL; + sk->send_tail = NULL; + sk->send_head = NULL; + sk->timeout = 0; + sk->broadcast = 0; + sk->localroute = 0; + sk->timer.data = (unsigned long)sk; + sk->timer.function = &net_timer; + skb_queue_head_init(&sk->back_log); + sk->blog = 0; + sock->data =(void *) sk; + sk->dummy_th.doff = sizeof(sk->dummy_th)/4; + sk->dummy_th.res1=0; + sk->dummy_th.res2=0; + sk->dummy_th.urg_ptr = 0; + sk->dummy_th.fin = 0; + sk->dummy_th.syn = 0; + sk->dummy_th.rst = 0; + sk->dummy_th.psh = 0; + sk->dummy_th.ack = 0; + sk->dummy_th.urg = 0; + sk->dummy_th.dest = 0; + sk->ip_tos=0; + sk->ip_ttl=64; + + sk->state_change = def_callback1; + sk->data_ready = def_callback2; + sk->write_space = def_callback1; + sk->error_report = def_callback1; + + if (sk->num) + { + /* + * It assumes that any protocol which allows + * the user to assign a number at socket + * creation time automatically + * shares. + */ + put_sock(sk->num, sk); + sk->dummy_th.source = ntohs(sk->num); + } + + if (sk->prot->init) + { + err = sk->prot->init(sk); + if (err != 0) + { + destroy_sock(sk); + return(err); + } + } + return(0); +} + + +/* + * Duplicate a socket. + */ + +static int inet_dup(struct socket *newsock, struct socket *oldsock) +{ + return(inet_create(newsock,((struct sock *)(oldsock->data))->protocol)); +} + + +/* + * The peer socket should always be NULL (or else). When we call this + * function we are destroying the object and from then on nobody + * should refer to it. + */ + +static int inet_release(struct socket *sock, struct socket *peer) +{ + struct sock *sk = (struct sock *) sock->data; + if (sk == NULL) + return(0); + + sk->state_change(sk); + + /* Start closing the connection. This may take a while. */ + + /* + * If linger is set, we don't return until the close + * is complete. Other wise we return immediately. The + * actually closing is done the same either way. + */ + + if (sk->linger == 0) + { + sk->prot->close(sk,0); + sk->dead = 1; + } + else + { + sk->prot->close(sk, 0); + cli(); + if (sk->lingertime) + current->timeout = jiffies + HZ*sk->lingertime; + while(sk->state != TCP_CLOSE && current->timeout>0) + { + interruptible_sleep_on(sk->sleep); + if (current->signal & ~current->blocked) + { + break; +#if 0 + /* not working now - closes can't be restarted */ + sti(); + current->timeout=0; + return(-ERESTARTSYS); +#endif + } + } + current->timeout=0; + sti(); + sk->dead = 1; + } + sk->inuse = 1; + + /* This will destroy it. */ + release_sock(sk); + sock->data = NULL; + return(0); +} + + +/* this needs to be changed to dissallow + the rebinding of sockets. What error + should it return? */ + +static int inet_bind(struct socket *sock, struct sockaddr *uaddr, + int addr_len) +{ + struct sockaddr_in addr; + struct sock *sk=(struct sock *)sock->data, *sk2; + unsigned short snum; + int err; + int chk_addr_ret; + + /* check this error. */ + if (sk->state != TCP_CLOSE) + return(-EIO); + if (sk->num != 0) + return(-EINVAL); + + err=verify_area(VERIFY_READ, uaddr, addr_len); + if(err) + return err; + memcpy_fromfs(&addr, uaddr, min(sizeof(addr), addr_len)); + + snum = ntohs(addr.sin_port); + + /* + * We can't just leave the socket bound wherever it is, it might + * be bound to a privileged port. However, since there seems to + * be a bug here, we will leave it if the port is not privileged. + */ + if (snum == 0) + { + snum = get_new_socknum(sk->prot, 0); + } + if (snum < PROT_SOCK && !suser()) + return(-EACCES); + + chk_addr_ret = ip_chk_addr(addr.sin_addr.s_addr); + if (addr.sin_addr.s_addr != 0 && chk_addr_ret != IS_MYADDR) + return(-EADDRNOTAVAIL); /* Source address MUST be ours! */ + + if (chk_addr_ret || addr.sin_addr.s_addr == 0) + sk->saddr = addr.sin_addr.s_addr; + + /* Make sure we are allowed to bind here. */ + cli(); +outside_loop: + for(sk2 = sk->prot->sock_array[snum & (SOCK_ARRAY_SIZE -1)]; + sk2 != NULL; sk2 = sk2->next) + { +/* should be below! */ + if (sk2->num != snum) continue; + if (sk2->dead) + { + destroy_sock(sk2); + goto outside_loop; + } + if (!sk->reuse) + { + sti(); + return(-EADDRINUSE); + } + + if (sk2->num != snum) + continue; /* more than one */ + if (sk2->saddr != sk->saddr) + continue; /* socket per slot ! -FB */ + if (!sk2->reuse) + { + sti(); + return(-EADDRINUSE); + } + } + sti(); + + remove_sock(sk); + put_sock(snum, sk); + sk->dummy_th.source = ntohs(sk->num); + sk->daddr = 0; + sk->dummy_th.dest = 0; + return(0); +} + +/* + * Handle sk->err properly. The cli/sti matter. + */ + +static int inet_error(struct sock *sk) +{ + unsigned long flags; + int err; + save_flags(flags); + cli(); + err=sk->err; + sk->err=0; + sti(); + return -err; +} + +/* + * Connect to a remote host. There is regretably still a little + * TCP 'magic' in here. + */ + +static int inet_connect(struct socket *sock, struct sockaddr * uaddr, + int addr_len, int flags) +{ + struct sock *sk=(struct sock *)sock->data; + int err; + sock->conn = NULL; + + if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED) + { + sock->state = SS_CONNECTED; + /* Connection completing after a connect/EINPROGRESS/select/connect */ + return 0; /* Rock and roll */ + } + + if (sock->state == SS_CONNECTING && sk->protocol == IPPROTO_TCP && (flags & O_NONBLOCK)) + return -EALREADY; /* Connecting is currently in progress */ + + if (sock->state != SS_CONNECTING) + { + /* We may need to bind the socket. */ + if(inet_autobind(sk)!=0) + return(-EAGAIN); + if (sk->prot->connect == NULL) + return(-EOPNOTSUPP); + err = sk->prot->connect(sk, (struct sockaddr_in *)uaddr, addr_len); + if (err < 0) + return(err); + sock->state = SS_CONNECTING; + } + + if (sk->state != TCP_ESTABLISHED &&(flags & O_NONBLOCK)) + return(-EINPROGRESS); + + cli(); /* avoid the race condition */ + while(sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) + { + interruptible_sleep_on(sk->sleep); + if (current->signal & ~current->blocked) + { + sti(); + return(-ERESTARTSYS); + } + /* This fixes a nasty in the tcp/ip code. There is a hideous hassle with + icmp error packets wanting to close a tcp or udp socket. */ + if(sk->err && sk->protocol == IPPROTO_TCP) + { + sti(); + sock->state = SS_UNCONNECTED; + err = -sk->err; + sk->err=0; + return err; /* set by tcp_err() */ + } + } + sti(); + sock->state = SS_CONNECTED; + + if (sk->state != TCP_ESTABLISHED && sk->err) + { + sock->state = SS_UNCONNECTED; + err=sk->err; + sk->err=0; + return(-err); + } + return(0); +} + + +static int inet_socketpair(struct socket *sock1, struct socket *sock2) +{ + return(-EOPNOTSUPP); +} + + +/* + * FIXME: Get BSD behaviour + */ + +static int inet_accept(struct socket *sock, struct socket *newsock, int flags) +{ + struct sock *sk1, *sk2; + int err; + + sk1 = (struct sock *) sock->data; + + /* + * We've been passed an extra socket. + * We need to free it up because the tcp module creates + * it's own when it accepts one. + */ + if (newsock->data) + { + struct sock *sk=(struct sock *)newsock->data; + newsock->data=NULL; + sk->dead = 1; + destroy_sock(sk); + } + + if (sk1->prot->accept == NULL) + return(-EOPNOTSUPP); + + /* Restore the state if we have been interrupted, and then returned. */ + if (sk1->pair != NULL ) + { + sk2 = sk1->pair; + sk1->pair = NULL; + } + else + { + sk2 = sk1->prot->accept(sk1,flags); + if (sk2 == NULL) + { + if (sk1->err <= 0) + printk("Warning sock.c:sk1->err <= 0. Returning non-error.\n"); + err=sk1->err; + sk1->err=0; + return(-err); + } + } + newsock->data = (void *)sk2; + sk2->sleep = newsock->wait; + newsock->conn = NULL; + if (flags & O_NONBLOCK) + return(0); + + cli(); /* avoid the race. */ + while(sk2->state == TCP_SYN_RECV) + { + interruptible_sleep_on(sk2->sleep); + if (current->signal & ~current->blocked) + { + sti(); + sk1->pair = sk2; + sk2->sleep = NULL; + newsock->data = NULL; + return(-ERESTARTSYS); + } + } + sti(); + + if (sk2->state != TCP_ESTABLISHED && sk2->err > 0) + { + err = -sk2->err; + sk2->err=0; + destroy_sock(sk2); + newsock->data = NULL; + return(err); + } + newsock->state = SS_CONNECTED; + return(0); +} + + +/* + * This does both peername and sockname. + */ + +static int inet_getname(struct socket *sock, struct sockaddr *uaddr, + int *uaddr_len, int peer) +{ + struct sockaddr_in sin; + struct sock *sk; + int len; + int err; + + + err = verify_area(VERIFY_WRITE,uaddr_len,sizeof(long)); + if(err) + return err; + + len=get_fs_long(uaddr_len); + + err = verify_area(VERIFY_WRITE, uaddr, len); + if(err) + return err; + + /* Check this error. */ + if (len < sizeof(sin)) + return(-EINVAL); + + sin.sin_family = AF_INET; + sk = (struct sock *) sock->data; + if (peer) + { + if (!tcp_connected(sk->state)) + return(-ENOTCONN); + sin.sin_port = sk->dummy_th.dest; + sin.sin_addr.s_addr = sk->daddr; + } + else + { + sin.sin_port = sk->dummy_th.source; + if (sk->saddr == 0) + sin.sin_addr.s_addr = ip_my_addr(); + else + sin.sin_addr.s_addr = sk->saddr; + } + len = sizeof(sin); + memcpy_tofs(uaddr, &sin, sizeof(sin)); + put_fs_long(len, uaddr_len); + return(0); +} + + +/* + * The assorted BSD I/O operations + */ + + +static int inet_recv(struct socket *sock, void *ubuf, int size, int noblock, + unsigned flags) +{ + struct sock *sk = (struct sock *) sock->data; + int err; + + if(sk->err) + return inet_error(sk); + if(size<0) + return -EINVAL; + if(size==0) + return 0; + err=verify_area(VERIFY_WRITE,ubuf,size); + if(err) + return err; + + /* We may need to bind the socket. */ + if(inet_autobind(sk)) + return(-EAGAIN); + return(sk->prot->read(sk, (unsigned char *) ubuf, size, noblock, flags)); +} + + +static int inet_read(struct socket *sock, char *ubuf, int size, int noblock) +{ + return inet_recv(sock,ubuf,size,noblock,0); +} + +static int inet_send(struct socket *sock, void *ubuf, int size, int noblock, + unsigned flags) +{ + struct sock *sk = (struct sock *) sock->data; + int err; + if (sk->shutdown & SEND_SHUTDOWN) + { + send_sig(SIGPIPE, current, 1); + return(-EPIPE); + } + if(sk->err) + return inet_error(sk); + if(size<0) + return -EINVAL; + if(size==0) + return 0; + err=verify_area(VERIFY_READ,ubuf,size); + if(err) + return err; + /* We may need to bind the socket. */ + if(inet_autobind(sk)!=0) + return(-EAGAIN); + return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, flags)); +} + +static int inet_write(struct socket *sock, char *ubuf, int size, int noblock) +{ + return inet_send(sock,ubuf,size,noblock,0); +} + +static int inet_sendto(struct socket *sock, void *ubuf, int size, int noblock, + unsigned flags, struct sockaddr *sin, int addr_len) +{ + int err; + struct sock *sk = (struct sock *) sock->data; + if (sk->shutdown & SEND_SHUTDOWN) + { + send_sig(SIGPIPE, current, 1); + return(-EPIPE); + } + if (sk->prot->sendto == NULL) + return(-EOPNOTSUPP); + if(sk->err) + return inet_error(sk); + if(size<0) + return -EINVAL; + if(size==0) + return 0; + err=verify_area(VERIFY_READ,ubuf,size); + if(err) + return err; + + /* We may need to bind the socket. */ + + if(inet_autobind(sk)!=0) + return -EAGAIN; + return(sk->prot->sendto(sk, (unsigned char *) ubuf, size, noblock, flags, + (struct sockaddr_in *)sin, addr_len)); +} + + +static int inet_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, + unsigned flags, struct sockaddr *sin, int *addr_len ) +{ + struct sock *sk = (struct sock *) sock->data; + int err; + + if (sk->prot->recvfrom == NULL) + return(-EOPNOTSUPP); + if(sk->err) + return inet_error(sk); + if(size<0) + return -EINVAL; + if(size==0) + return 0; + err=verify_area(VERIFY_READ,ubuf,size); + if(err) + return err; + + /* We may need to bind the socket. */ + if(inet_autobind(sk)!=0) + return(-EAGAIN); + return(sk->prot->recvfrom(sk, (unsigned char *) ubuf, size, noblock, flags, + (struct sockaddr_in*)sin, addr_len)); +} + + +static int inet_shutdown(struct socket *sock, int how) +{ + struct sock *sk=(struct sock*)sock->data; + + /* + * This should really check to make sure + * the socket is a TCP socket. (WHY AC...) + */ + how++; /* maps 0->1 has the advantage of making bit 1 rcvs and + 1->2 bit 2 snds. + 2->3 */ + if ((how & ~SHUTDOWN_MASK) || how==0) /* MAXINT->0 */ + return(-EINVAL); + if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED) + sock->state = SS_CONNECTED; + if (!tcp_connected(sk->state)) + return(-ENOTCONN); + sk->shutdown |= how; + if (sk->prot->shutdown) + sk->prot->shutdown(sk, how); + return(0); +} + + +static int inet_select(struct socket *sock, int sel_type, select_table *wait ) +{ + struct sock *sk=(struct sock *) sock->data; + if (sk->prot->select == NULL) + { + return(0); + } + return(sk->prot->select(sk, sel_type, wait)); +} + +/* + * ioctl() calls you can issue on an INET socket. Most of these are + * device configuration and stuff and very rarely used. Some ioctls + * pass on to the socket itself. + * + * NOTE: I like the idea of a module for the config stuff. ie ifconfig + * loads the devconfigure module does its configuring and unloads it. + * Theres a good 20K of config code hanging around the kernel. + */ + +static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + struct sock *sk=(struct sock *)sock->data; + int err; + + switch(cmd) + { + case FIOSETOWN: + case SIOCSPGRP: + err=verify_area(VERIFY_READ,(int *)arg,sizeof(long)); + if(err) + return err; + sk->proc = get_fs_long((int *) arg); + return(0); + case FIOGETOWN: + case SIOCGPGRP: + err=verify_area(VERIFY_WRITE,(void *) arg, sizeof(long)); + if(err) + return err; + put_fs_long(sk->proc,(int *)arg); + return(0); + case SIOCGSTAMP: + if(sk->stamp.tv_sec==0) + return -ENOENT; + err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval)); + if(err) + return err; + memcpy_tofs((void *)arg,&sk->stamp,sizeof(struct timeval)); + return 0; + case SIOCADDRT: case SIOCADDRTOLD: + case SIOCDELRT: case SIOCDELRTOLD: + return(ip_rt_ioctl(cmd,(void *) arg)); + case SIOCDARP: + case SIOCGARP: + case SIOCSARP: + return(arp_ioctl(cmd,(void *) arg)); +#ifdef CONFIG_INET_RARP + case SIOCDRARP: + case SIOCGRARP: + case SIOCSRARP: + return(rarp_ioctl(cmd,(void *) arg)); +#endif + case SIOCGIFCONF: + case SIOCGIFFLAGS: + case SIOCSIFFLAGS: + case SIOCGIFADDR: + case SIOCSIFADDR: + case SIOCGIFDSTADDR: + case SIOCSIFDSTADDR: + case SIOCGIFBRDADDR: + case SIOCSIFBRDADDR: + case SIOCGIFNETMASK: + case SIOCSIFNETMASK: + case SIOCGIFMETRIC: + case SIOCSIFMETRIC: + case SIOCGIFMEM: + case SIOCSIFMEM: + case SIOCGIFMTU: + case SIOCSIFMTU: + case SIOCSIFLINK: + case SIOCGIFHWADDR: + case SIOCSIFHWADDR: + case OLD_SIOCGIFHWADDR: + case SIOCSIFMAP: + case SIOCGIFMAP: + case SIOCDEVPRIVATE: + return(dev_ioctl(cmd,(void *) arg)); + + default: + if (sk->prot->ioctl==NULL) + return(-EINVAL); + return(sk->prot->ioctl(sk, cmd, arg)); + } + /*NOTREACHED*/ + return(0); +} + +/* + * This routine must find a socket given a TCP or UDP header. + * Everyhting is assumed to be in net order. + */ + +struct sock *get_sock(struct proto *prot, unsigned short num, + unsigned long raddr, + unsigned short rnum, unsigned long laddr) +{ + struct sock *s; + unsigned short hnum; + + hnum = ntohs(num); + + /* + * SOCK_ARRAY_SIZE must be a power of two. This will work better + * than a prime unless 3 or more sockets end up using the same + * array entry. This should not be a problem because most + * well known sockets don't overlap that much, and for + * the other ones, we can just be careful about picking our + * socket number when we choose an arbitrary one. + */ + + for(s = prot->sock_array[hnum & (SOCK_ARRAY_SIZE - 1)]; + s != NULL; s = s->next) + { + if (s->num != hnum) + continue; + if(s->dead && (s->state == TCP_CLOSE)) + continue; + if(prot == &udp_prot) + return s; + if(ip_addr_match(s->daddr,raddr)==0) + continue; + if (s->dummy_th.dest != rnum && s->dummy_th.dest != 0) + continue; + if(ip_addr_match(s->saddr,laddr) == 0) + continue; + return(s); + } + return(NULL); +} + +static struct proto_ops inet_proto_ops = { + AF_INET, + + inet_create, + inet_dup, + inet_release, + inet_bind, + inet_connect, + inet_socketpair, + inet_accept, + inet_getname, + inet_read, + inet_write, + inet_select, + inet_ioctl, + inet_listen, + inet_send, + inet_recv, + inet_sendto, + inet_recvfrom, + inet_shutdown, + inet_setsockopt, + inet_getsockopt, + inet_fcntl, +}; + +extern unsigned long seq_offset; + +/* + * Called by socket.c on kernel startup. + */ + +void inet_proto_init(struct net_proto *pro) +{ + struct inet_protocol *p; + int i; + + printk("Swansea University Computer Society NET3.014\n"); + + /* + * Tell SOCKET that we are alive... + */ + + (void) sock_register(inet_proto_ops.family, &inet_proto_ops); + + seq_offset = CURRENT_TIME*250; + + /* + * Add all the protocols. + */ + + for(i = 0; i < SOCK_ARRAY_SIZE; i++) + { + tcp_prot.sock_array[i] = NULL; + udp_prot.sock_array[i] = NULL; + raw_prot.sock_array[i] = NULL; + } + + printk("IP Protocols: "); + for(p = inet_protocol_base; p != NULL;) + { + struct inet_protocol *tmp = (struct inet_protocol *) p->next; + inet_add_protocol(p); + printk("%s%s",p->name,tmp?", ":"\n"); + p = tmp; + } + /* + * Set the ARP module up + */ + arp_init(); + /* + * Set the IP module up + */ + ip_init(); +} + diff -u --recursive --new-file v1.1.12/linux/net/inet/arp.c linux/net/inet/arp.c --- v1.1.12/linux/net/inet/arp.c Mon May 23 12:14:26 1994 +++ linux/net/inet/arp.c Mon May 23 08:17:46 1994 @@ -722,7 +722,17 @@ { struct arp_table *entry; unsigned long hash; - +/* SHOULD BE FIXED NOW */ + if(paddr==0) + { + printk("ADDRESS BOTCH 0\n"); + if(skb) + { + printk("skb(saddr=%lx, daddr=%lx, raddr=%lx)\n", + skb->saddr,skb->daddr,skb->raddr); + } + } +/* ------------- */ switch (ip_chk_addr(paddr)) { case IS_MYADDR: @@ -1075,8 +1085,6 @@ switch(cmd) { - case DDIOCSDBG: - return dbg_ioctl(arg, DBG_ARP); case SIOCDARP: if (!suser()) return -EPERM; diff -u --recursive --new-file v1.1.12/linux/net/inet/datalink.h linux/net/inet/datalink.h --- v1.1.12/linux/net/inet/datalink.h Thu Jan 1 02:00:00 1970 +++ linux/net/inet/datalink.h Mon May 23 08:17:46 1994 @@ -0,0 +1,17 @@ +#ifndef _NET_INET_DATALINK_H_ +#define _NET_INET_DATALINK_H_ + +struct datalink_proto { + unsigned short type_len; + unsigned char type[8]; + unsigned short datalink_type; + unsigned short header_length; + int (*rcvfunc)(struct sk_buff *, struct device *, + struct packet_type *); + void (*datalink_header)(struct datalink_proto *, struct sk_buff *, + unsigned char *); + struct datalink_proto *next; +}; + +#endif + diff -u --recursive --new-file v1.1.12/linux/net/inet/dev.c linux/net/inet/dev.c --- v1.1.12/linux/net/inet/dev.c Tue Apr 19 22:20:35 1994 +++ linux/net/inet/dev.c Mon May 23 08:17:47 1994 @@ -14,6 +14,7 @@ * Additional Authors: * Florian la Roche * Alan Cox + * David Hinds * * Cleaned up and recommented by Alan Cox 2nd April 1994. I hope to have * the rest as well commented in the end. @@ -136,7 +137,7 @@ } /* - * NIT taps must go at the end or inet_bh will leak! + * NIT taps must go at the end or net_bh will leak! */ if (pt->type == htons(ETH_P_ALL)) @@ -289,7 +290,9 @@ /* * Delete the route to the device. */ +#ifdef CONFIG_INET ip_rt_flush(dev); +#endif /* * Blank the IP addresses */ @@ -324,14 +327,19 @@ /* at the front or the back of the */ /* queue. */ - DPRINTF((DBG_DEV, "dev_queue_xmit(skb=%X, dev=%X, pri = %d)\n", - skb, dev, pri)); - if (dev == NULL) { printk("dev.c: dev_queue_xmit: dev = NULL\n"); return; } +#ifdef CONFIG_SLAVE_BALANCING + save_flags(flags); + cli(); + if(dev->slave!=NULL && dev->slave->pkt_queue < dev->pkt_queue && + (dev->slave->flags & IFF_UP)) + dev=dev->slave; + restore_flags(flags); +#endif IS_SKB(skb); @@ -370,8 +378,8 @@ } /* - * If the address has not been resolved called the device header rebuilder. - * This can cover all protocols and technically no just ARP either. + * If the address has not been resolved. Call the device header rebuilder. + * This can cover all protocols and technically not just ARP either. */ if (!skb->arp && dev->rebuild_header(skb->data, dev, skb->raddr, skb)) { @@ -381,12 +389,21 @@ save_flags(flags); cli(); if (!where) { +#ifdef CONFIG_SLAVE_BALANCING + skb->in_dev_queue=1; +#endif skb_queue_tail(dev->buffs + pri,skb); skb = skb_dequeue(dev->buffs + pri); +#ifdef CONFIG_SLAVE_BALANCING + skb->in_dev_queue=0; +#endif } restore_flags(flags); if (dev->hard_start_xmit(skb, dev) == 0) { +#ifdef CONFIG_SLAVE_BALANCING + dev->pkt_queue--; +#endif return; } @@ -394,6 +411,10 @@ * Transmission failed, put skb back into a list. */ cli(); +#ifdef CONFIG_SLAVE_BALANCING + skb->in_dev_queue=1; + dev->pkt_queue++; +#endif skb_queue_head(dev->buffs + pri,skb); restore_flags(flags); } @@ -447,7 +468,7 @@ * hardware interrupt returns. */ - mark_bh(INET_BH); + mark_bh(NET_BH); return; } @@ -573,7 +594,7 @@ volatile char in_bh = 0; /* Non-rentrant remember */ -int in_inet_bh() /* Used by timer.c */ +int in_net_bh() /* Used by timer.c */ { return(in_bh==0?0:1); } @@ -583,10 +604,10 @@ * on and hardware can interrupt and queue to the receive queue a we * run with no problems. * This is run as a bottom half after an interrupt handler that does - * mark_bh(INET_BH); + * mark_bh(NET_BH); */ -void inet_bh(void *tmp) +void net_bh(void *tmp) { struct sk_buff *skb; struct packet_type *ptype; @@ -724,7 +745,6 @@ if (!flag) { - DPRINTF((DBG_DEV,"INET: unknown packet type 0x%04X (ignored)\n", type)); kfree_skb(skb, FREE_WRITE); } @@ -995,10 +1015,21 @@ case SIOCSIFFLAGS: /* Set interface flags */ { int old_flags = dev->flags; +#ifdef CONFIG_SLAVE_BALANCING + if(dev->flags&IFF_SLAVE) + return -EBUSY; +#endif dev->flags = ifr.ifr_flags & ( IFF_UP | IFF_BROADCAST | IFF_DEBUG | IFF_LOOPBACK | IFF_POINTOPOINT | IFF_NOTRAILERS | IFF_RUNNING | - IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI); + IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI | IFF_SLAVE | IFF_MASTER); +#ifdef CONFIG_SLAVE_BALANCING + if(!(dev->flags&IFF_MASTER) && dev->slave) + { + dev->slave->flags&=~IFF_SLAVE; + dev->slave=NULL; + } +#endif /* * Has promiscuous mode been turned off @@ -1053,7 +1084,12 @@ dev->pa_addr = (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr; dev->family = ifr.ifr_addr.sa_family; + +#ifdef CONFIG_INET + /* This is naughty. When net-032e comes out It wants moving into the net032 + code not the kernel. Till then it can sit here (SIGH) */ dev->pa_mask = ip_get_mask(dev->pa_addr); +#endif dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask; ret = 0; break; @@ -1179,7 +1215,83 @@ return -EINVAL; ret=dev->set_mac_address(dev,ifr.ifr_hwaddr.sa_data); break; + + case SIOCDEVPRIVATE: + if(dev->do_ioctl==NULL) + return -EOPNOTSUPP; + return dev->do_ioctl(dev, &ifr); + + case SIOCGIFMAP: + ifr.ifr_map.mem_start=dev->mem_start; + ifr.ifr_map.mem_end=dev->mem_end; + ifr.ifr_map.base_addr=dev->base_addr; + ifr.ifr_map.irq=dev->irq; + ifr.ifr_map.dma=dev->dma; + ifr.ifr_map.port=dev->if_port; + memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); + ret=0; + break; + case SIOCSIFMAP: + if(dev->set_config==NULL) + return -EOPNOTSUPP; + return dev->set_config(dev,&ifr.ifr_map); + + case SIOCGIFSLAVE: +#ifdef CONFIG_SLAVE_BALANCING + if(dev->slave==NULL) + return -ENOENT; + strncpy(ifr.ifr_name,dev->name,sizeof(ifr.ifr_name)); + memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); + ret=0; +#else + return -ENOENT; +#endif + break; +#ifdef CONFIG_SLAVE_BALANCING + case SIOCSIFSLAVE: + { + + /* + * Fun game. Get the device up and the flags right without + * letting some scummy user confuse us. + */ + unsigned long flags; + struct device *slave=dev_get(ifr.ifr_slave); + save_flags(flags); + if(slave==NULL) + { + return -ENODEV; + } + cli(); + if(slave->flags&(IFF_UP|IFF_RUNNING)!=(IFF_UP|IFF_RUNNING)) + { + restore_flags(flags); + return -EINVAL; + } + if(dev->flags&IFF_SLAVE) + { + restore_flags(flags); + return -EINVAL; + } + if(dev->slave!=NULL) + { + restore_flags(flags); + return -EBUSY; + } + if(slave->flags&IFF_SLAVE) + { + restore_flags(flags); + return -EBUSY; + } + dev->slave=slave; + slave->flags|=IFF_SLAVE; + dev->flags|=IFF_MASTER; + restore_flags(flags); + ret=0; + } + break; +#endif /* * Unknown ioctl */ @@ -1224,6 +1336,8 @@ case SIOCGIFHWADDR: case SIOCSIFHWADDR: case OLD_SIOCGIFHWADDR: + case SIOCGIFSLAVE: + case SIOCGIFMAP: return dev_ifsioc(arg, cmd); /* @@ -1238,6 +1352,9 @@ case SIOCSIFMETRIC: case SIOCSIFMTU: case SIOCSIFMEM: + case SIOCSIFMAP: + case SIOCSIFSLAVE: + case SIOCDEVPRIVATE: if (!suser()) return -EPERM; return dev_ifsioc(arg, cmd); diff -u --recursive --new-file v1.1.12/linux/net/inet/dev.h linux/net/inet/dev.h --- v1.1.12/linux/net/inet/dev.h Tue Dec 14 12:12:07 1993 +++ linux/net/inet/dev.h Mon May 23 08:17:47 1994 @@ -1,191 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the Interfaces handler. - * - * Version: @(#)dev.h 1.0.10 08/12/93 - * - * Authors: Ross Biro, - * Fred N. van Kempen, - * Corey Minyard - * Donald J. Becker, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _DEV_H -#define _DEV_H - -#include -#include - - -/* for future expansion when we will have different priorities. */ -#define DEV_NUMBUFFS 3 -#define MAX_ADDR_LEN 7 -#define MAX_HEADER 18 - -#define IS_MYADDR 1 /* address is (one of) our own */ -#define IS_LOOPBACK 2 /* address is for LOOPBACK */ -#define IS_BROADCAST 3 /* address is a valid broadcast */ -#define IS_INVBCAST 4 /* Wrong netmask bcast not for us */ - -/* - * The DEVICE structure. - * Actually, this whole structure is a big mistake. It mixes I/O - * data with strictly "high-level" data, and it has to know about - * almost every data structure used in the INET module. We will - * gradually phase out this structure, and replace it with the - * more general (but stolen :-) BSD "ifnet" structure. -FvK - */ -struct device { - - /* - * This is the first field of the "visible" part of this structure - * (i.e. as seen by users in the "Space.c" file). It is the name - * the interface. - */ - char *name; - - /* I/O specific fields. These will be moved to DDI soon. */ - unsigned long rmem_end; /* shmem "recv" end */ - unsigned long rmem_start; /* shmem "recv" start */ - unsigned long mem_end; /* sahared mem end */ - unsigned long mem_start; /* shared mem start */ - unsigned short base_addr; /* device I/O address */ - unsigned char irq; /* device IRQ number */ - - /* Low-level status flags. */ - volatile unsigned char start, /* start an operation */ - tbusy, /* transmitter busy */ - interrupt; /* interrupt arrived */ - - /* - * Another mistake. - * This points to the next device in the "dev" chain. It will - * be moved to the "invisible" part of the structure as soon as - * it has been cleaned up. -FvK - */ - struct device *next; - - /* The device initialization function. Called only once. */ - int (*init)(struct device *dev); - - /* Some hardware also needs these fields, but they are not part of the - usual set specified in Space.c. */ - unsigned char if_port; /* Selectable AUI, TP,..*/ - unsigned char dma; /* DMA channel */ - - struct enet_statistics* (*get_stats)(struct device *dev); - - /* - * This marks the end of the "visible" part of the structure. All - * fields hereafter are internal to the system, and may change at - * will (read: may be cleaned up at will). - */ - - /* These may be needed for future network-power-down code. */ - unsigned long trans_start; /* Time (in jiffies) of last Tx */ - unsigned long last_rx; /* Time of last Rx */ - - unsigned short flags; /* interface flags (a la BSD) */ - unsigned short family; /* address family ID (AF_INET) */ - unsigned short metric; /* routing metric (not used) */ - unsigned short mtu; /* interface MTU value */ - unsigned short type; /* interface hardware type */ - unsigned short hard_header_len; /* hardware hdr length */ - void *priv; /* pointer to private data */ - - /* Interface address info. */ - unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */ - unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address */ - unsigned char addr_len; /* harfware address length */ - unsigned long pa_addr; /* protocol address */ - unsigned long pa_brdaddr; /* protocol broadcast addr */ - unsigned long pa_dstaddr; /* protocol P-P other side addr */ - unsigned long pa_mask; /* protocol netmask */ - unsigned short pa_alen; /* protocol address length */ - - /* Pointer to the interface buffers. */ - struct sk_buff *volatile buffs[DEV_NUMBUFFS]; - - /* Pointers to interface service routines. */ - int (*open)(struct device *dev); - int (*stop)(struct device *dev); - int (*hard_start_xmit) (struct sk_buff *skb, - struct device *dev); - int (*hard_header) (unsigned char *buff, - struct device *dev, - unsigned short type, - unsigned long daddr, - unsigned long saddr, - unsigned len); - void (*add_arp) (unsigned long addr, - struct sk_buff *skb, - struct device *dev); - void (*queue_xmit)(struct sk_buff *skb, - struct device *dev, int pri); - int (*rebuild_header)(void *eth, struct device *dev); - unsigned short (*type_trans) (struct sk_buff *skb, - struct device *dev); -#define HAVE_MULTICAST - void (*set_multicast_list)(struct device *dev, - int num_addrs, void *addrs); -#define HAVE_SET_MAC_ADDR - int (*set_mac_address)(struct device *dev, void *addr); -}; - - -struct packet_type { - unsigned short type; /* This is really NET16(ether_type) other - * devices will have to translate - * appropriately. - */ - unsigned short copy:1; - int (*func) (struct sk_buff *, struct device *, - struct packet_type *); - void *data; - struct packet_type *next; -}; - - -/* Used by dev_rint */ -#define IN_SKBUFF 1 -#define DEV_QUEUE_MAGIC 0x17432895 - - -extern struct device *dev_base; -extern struct packet_type *ptype_base; - - -extern int ip_addr_match(unsigned long addr1, unsigned long addr2); -extern int chk_addr(unsigned long addr); -extern struct device *dev_check(unsigned long daddr); -extern unsigned long my_addr(void); - -extern void dev_add_pack(struct packet_type *pt); -extern void dev_remove_pack(struct packet_type *pt); -extern struct device *dev_get(char *name); -extern int dev_open(struct device *dev); -extern int dev_close(struct device *dev); -extern void dev_queue_xmit(struct sk_buff *skb, struct device *dev, - int pri); -#define HAVE_NETIF_RX 1 -extern void netif_rx(struct sk_buff *skb); -/* The old interface to netif_rx(). */ -extern int dev_rint(unsigned char *buff, long len, int flags, - struct device * dev); -extern void dev_transmit(void); -extern int in_inet_bh(void); -extern void inet_bh(void *tmp); -extern void dev_tint(struct device *dev); -extern int dev_get_info(char *buffer); -extern int dev_ioctl(unsigned int cmd, void *); - -extern void dev_init(void); - -#endif /* _DEV_H */ diff -u --recursive --new-file v1.1.12/linux/net/inet/devinet.c linux/net/inet/devinet.c --- v1.1.12/linux/net/inet/devinet.c Tue Apr 19 10:53:55 1994 +++ linux/net/inet/devinet.c Mon May 23 08:17:47 1994 @@ -75,8 +75,6 @@ { int i; unsigned long mask=0xFFFFFFFF; - DPRINTF((DBG_DEV, "ip_addr_match(%s, ", in_ntoa(me))); - DPRINTF((DBG_DEV, "%s)\n", in_ntoa(him))); /* * Simple case @@ -196,7 +194,7 @@ * * Because the loopback address (127.0.0.1) is already recognized * automatically, we can use the loopback interface's address as - * our "primary" interface. This is the addressed used by IP et + * our "primary" interface. This is the address used by IP et * al when it doesn't know which address to use (i.e. it does not * yet know from or to which interface to go...). */ diff -u --recursive --new-file v1.1.12/linux/net/inet/eth.c linux/net/inet/eth.c --- v1.1.12/linux/net/inet/eth.c Tue Apr 19 10:53:55 1994 +++ linux/net/inet/eth.c Mon May 23 08:17:47 1994 @@ -23,6 +23,8 @@ * Florian : Removed many unnecessary functions, code cleanup * and changes for new arp and skbuff. * Alan Cox : Redid header building to reflect new format. + * Alan Cox : ARP only when compiled with CONFIG_INET + * Greg Page : 802.2 and SNAP stuff * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -147,8 +149,11 @@ /* * Try and get ARP to resolve the header. */ - +#ifdef CONFIG_INET return arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb)? 1 : 0; +#else + return 0; +#endif } @@ -161,10 +166,17 @@ unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev) { struct ethhdr *eth = (struct ethhdr *) skb->data; + char *rawp; - if (ntohs(eth->h_proto) < 1536) + if (ntohs(eth->h_proto) >= 1536) + return eth->h_proto; + + rawp = (unsigned char *)(eth + 1); + + if (*(unsigned short *)rawp == 0xFFFF) return htons(ETH_P_802_3); - - return eth->h_proto; + if (*(unsigned short *)rawp == 0xAAAA) + return htons(ETH_P_SNAP); + + return htons(ETH_P_802_2); } - diff -u --recursive --new-file v1.1.12/linux/net/inet/icmp.c linux/net/inet/icmp.c --- v1.1.12/linux/net/inet/icmp.c Sun May 1 12:12:52 1994 +++ linux/net/inet/icmp.c Mon May 23 08:17:47 1994 @@ -19,12 +19,11 @@ * Alan Cox : Protocol violations * Alan Cox : SNMP Statistics * Alan Cox : Routing errors + * Alan Cox : Changes for newer routing code + * Alan Cox : Removed old debugging junk * * - * FIXME: - * When 1.0.6 is out merge in the NET channel diffs for TIMESTAMP * - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -82,21 +81,6 @@ }; -/* - * Display the contents of an ICMP header. - */ - -static void print_icmp(struct icmphdr *icmph) -{ - if (inet_debug != DBG_ICMP) - return; - - printk("ICMP: type = %d, code = %d, checksum = %X\n", - icmph->type, icmph->code, icmph->checksum); - printk(" gateway = %s\n", in_ntoa(icmph->un.gateway)); -} - - /* * Send an ICMP message in response to a situation * @@ -112,9 +96,6 @@ int len; struct device *ndev=NULL; /* Make this =dev to force replies on the same interface */ - DPRINTF((DBG_ICMP, "icmp_send(skb_in = %X, type = %d, code = %d, dev=%X)\n", - skb_in, type, code, dev)); - /* * Find the original IP header. */ @@ -223,9 +204,6 @@ icmph->checksum = ip_compute_csum((unsigned char *)icmph, sizeof(struct icmphdr) + sizeof(struct iphdr) + 8); - DPRINTF((DBG_ICMP, ">>\n")); - print_icmp(icmph); - /* * Send it and free it once sent. */ @@ -250,20 +228,14 @@ switch(icmph->code & 7) { case ICMP_NET_UNREACH: - DPRINTF((DBG_ICMP, "ICMP: %s: network unreachable.\n", - in_ntoa(iph->daddr))); break; case ICMP_HOST_UNREACH: - DPRINTF((DBG_ICMP, "ICMP: %s: host unreachable.\n", - in_ntoa(iph->daddr))); break; case ICMP_PROT_UNREACH: printk("ICMP: %s:%d: protocol unreachable.\n", in_ntoa(iph->daddr), ntohs(iph->protocol)); break; case ICMP_PORT_UNREACH: - DPRINTF((DBG_ICMP, "ICMP: %s:%d: port unreachable.\n", - in_ntoa(iph->daddr), -1 /* FIXME: ntohs(iph->port) */)); break; case ICMP_FRAG_NEEDED: printk("ICMP: %s: fragmentation needed and DF set.\n", @@ -273,8 +245,6 @@ printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr)); break; default: - DPRINTF((DBG_ICMP, "ICMP: Unreachable: CODE=%d from %s\n", - (icmph->code & 7), in_ntoa(iph->daddr))); break; } @@ -338,7 +308,7 @@ */ #ifdef not_a_good_idea ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY), - ip, 0, icmph->un.gateway, dev); + ip, 0, icmph->un.gateway, dev,0); break; #endif case ICMP_REDIR_HOST: @@ -354,16 +324,14 @@ break; printk("redirect from %08lx\n", source); ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY), - ip, 0, icmph->un.gateway, dev); + ip, 0, icmph->un.gateway, dev,0); break; case ICMP_REDIR_NETTOS: case ICMP_REDIR_HOSTTOS: printk("ICMP: cannot handle TOS redirects yet!\n"); break; default: - DPRINTF((DBG_ICMP, "ICMP: Unreach: CODE=%d\n", - (icmph->code & 7))); - break; + break; } /* @@ -620,8 +588,6 @@ if (ip_chk_addr(daddr) == IS_BROADCAST) { - DPRINTF((DBG_ICMP, "ICMP: Discarded broadcast from %s\n", - in_ntoa(saddr))); icmp_statistics.IcmpInErrors++; kfree_skb(skb1, FREE_READ); return(0); @@ -646,7 +612,6 @@ kfree_skb(skb1, FREE_READ); return(0); } - print_icmp(icmph); /* * Parse the ICMP message @@ -708,9 +673,6 @@ return(0); default: icmp_statistics.IcmpInErrors++; - DPRINTF((DBG_ICMP, - "ICMP: Unsupported ICMP from %s, type = 0x%X\n", - in_ntoa(saddr), icmph->type)); kfree_skb(skb1, FREE_READ); return(0); } @@ -729,8 +691,6 @@ { switch(cmd) { - case DDIOCSDBG: - return(dbg_ioctl((void *) arg, DBG_ICMP)); default: return(-EINVAL); } diff -u --recursive --new-file v1.1.12/linux/net/inet/inet.h linux/net/inet/inet.h --- v1.1.12/linux/net/inet/inet.h Thu Dec 30 14:17:28 1993 +++ linux/net/inet/inet.h Mon May 23 08:17:48 1994 @@ -1,97 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * General Definitions for the TCP/IP (INET) module. This is - * mostly a bunch of "general" macros, plus the PROTOCOL link - * code and data. - * - * Version: @(#)inet.h 1.0.6 05/25/93 - * - * Author: Fred N. van Kempen, - * - * This work was derived friom Ross Biro's inspirational work - * for the LINUX operating system. His version numbers were: - * - * $Id: Space.c,v 0.8.4.5 1992/12/12 19:25:04 bir7 Exp $ - * $Id: arp.c,v 0.8.4.6 1993/01/28 22:30:00 bir7 Exp $ - * $Id: arp.h,v 0.8.4.6 1993/01/28 22:30:00 bir7 Exp $ - * $Id: dev.c,v 0.8.4.13 1993/01/23 18:00:11 bir7 Exp $ - * $Id: dev.h,v 0.8.4.7 1993/01/23 18:00:11 bir7 Exp $ - * $Id: eth.c,v 0.8.4.4 1993/01/22 23:21:38 bir7 Exp $ - * $Id: eth.h,v 0.8.4.1 1992/11/10 00:17:18 bir7 Exp $ - * $Id: icmp.c,v 0.8.4.9 1993/01/23 18:00:11 bir7 Exp $ - * $Id: icmp.h,v 0.8.4.2 1992/11/15 14:55:30 bir7 Exp $ - * $Id: ip.c,v 0.8.4.8 1992/12/12 19:25:04 bir7 Exp $ - * $Id: ip.h,v 0.8.4.2 1993/01/23 18:00:11 bir7 Exp $ - * $Id: loopback.c,v 0.8.4.8 1993/01/23 18:00:11 bir7 Exp $ - * $Id: packet.c,v 0.8.4.7 1993/01/26 22:04:00 bir7 Exp $ - * $Id: protocols.c,v 0.8.4.3 1992/11/15 14:55:30 bir7 Exp $ - * $Id: raw.c,v 0.8.4.12 1993/01/26 22:04:00 bir7 Exp $ - * $Id: sock.c,v 0.8.4.6 1993/01/28 22:30:00 bir7 Exp $ - * $Id: sock.h,v 0.8.4.7 1993/01/26 22:04:00 bir7 Exp $ - * $Id: tcp.c,v 0.8.4.16 1993/01/26 22:04:00 bir7 Exp $ - * $Id: tcp.h,v 0.8.4.7 1993/01/22 22:58:08 bir7 Exp $ - * $Id: timer.c,v 0.8.4.8 1993/01/23 18:00:11 bir7 Exp $ - * $Id: timer.h,v 0.8.4.2 1993/01/23 18:00:11 bir7 Exp $ - * $Id: udp.c,v 0.8.4.12 1993/01/26 22:04:00 bir7 Exp $ - * $Id: udp.h,v 0.8.4.1 1992/11/10 00:17:18 bir7 Exp $ - * $Id: we.c,v 0.8.4.10 1993/01/23 18:00:11 bir7 Exp $ - * $Id: wereg.h,v 0.8.4.1 1992/11/10 00:17:18 bir7 Exp $ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _INET_H -#define _INET_H - - -#include - - -#define NET16(x) ((((x) >> 8) & 0x00FF) | (((x) << 8) & 0xFF00)) - - -#undef INET_DEBUG -#ifdef INET_DEBUG -# define DPRINTF(x) dprintf x -#else -# define DPRINTF(x) do ; while (0) -#endif - -/* Debug levels. One per module. */ -#define DBG_OFF 0 /* no debugging */ -#define DBG_INET 1 /* sock.c */ -#define DBG_RT 2 /* route.c */ -#define DBG_DEV 3 /* dev.c */ -#define DBG_ETH 4 /* eth.c */ -#define DBG_PROTO 5 /* protocol.c */ -#define DBG_TMR 6 /* timer.c */ -#define DBG_PKT 7 /* packet.c */ -#define DBG_RAW 8 /* raw.c */ - -#define DBG_LOOPB 10 /* loopback.c */ -#define DBG_SLIP 11 /* slip.c */ - -#define DBG_ARP 20 /* arp.c */ -#define DBG_IP 21 /* ip.c */ -#define DBG_ICMP 22 /* icmp.c */ -#define DBG_TCP 23 /* tcp.c */ -#define DBG_UDP 24 /* udp.c */ - - -extern int inet_debug; - - -extern void inet_proto_init(struct ddi_proto *pro); -extern char *in_ntoa(unsigned long in); -extern unsigned long in_aton(char *str); - -extern void dprintf(int level, char *fmt, ...); - -extern int dbg_ioctl(void *arg, int level); - -#endif /* _INET_H */ diff -u --recursive --new-file v1.1.12/linux/net/inet/ip.c linux/net/inet/ip.c --- v1.1.12/linux/net/inet/ip.c Mon May 23 12:14:26 1994 +++ linux/net/inet/ip.c Mon May 23 08:17:48 1994 @@ -50,10 +50,11 @@ * Alan Cox : BSD address rule semantics. Also see * UDP as there is a nasty checksum issue * if you do things the wrong way. + * Alan Cox : Always defrag, moved IP_FORWARD to the config.in file * * To Fix: * IP option processing is mostly not needed. ip_forward needs to know about routing rules - * and time stamp but that's about all. + * and time stamp but that's about all. Use the route mtu field here too * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -83,7 +84,6 @@ #include "arp.h" #include "icmp.h" -#define CONFIG_IP_FORWARD #define CONFIG_IP_DEFRAG extern int last_retran; @@ -97,67 +97,6 @@ struct ip_mib ip_statistics={1,64,}; /* Forwarding=Yes, Default TTL=64 */ -/* - * Print an IP packet for debugging purposes. - * - * This function is exported for the IP - * upper layers to use also. - */ - -void ip_print(const struct iphdr *ip) -{ - unsigned char buff[32]; - unsigned char *ptr; - int addr; - int len; - int i; - - /* Are we debugging IP frames */ - - if (inet_debug != DBG_IP) - return; - - /* Dump the IP header. */ - printk("IP: ihl=%d, version=%d, tos=%d, tot_len=%d\n", - ip->ihl, ip->version, ip->tos, ntohs(ip->tot_len)); - printk(" id=%X, ttl=%d, prot=%d, check=%X\n", - ip->id, ip->ttl, ip->protocol, ip->check); - printk(" frag_off=%d\n", ip->frag_off); - printk(" soucre=%s ", in_ntoa(ip->saddr)); - printk("dest=%s\n", in_ntoa(ip->daddr)); - printk(" ----\n"); - - /* Dump the data. */ - ptr = (unsigned char *)(ip + 1); - addr = 0; - len = ntohs(ip->tot_len) - (4 * ip->ihl); - - while (len > 0) - { - printk(" %04X: ", addr); - for(i = 0; i < 16; i++) - { - if (len > 0) - { - printk("%02X ", (*ptr & 0xFF)); - buff[i] = *ptr++; - if (buff[i] < 32 || buff[i] > 126) - buff[i] = '.'; - } - else - { - printk(" "); - buff[i] = ' '; - } - addr++; - len--; - }; - buff[i] = '\0'; - printk(" \"%s\"\n", buff); - } - printk(" ----\n\n"); -} - /* * Handle the issuing of an ioctl() request * for the ip device. This is scheduled to @@ -168,8 +107,6 @@ { switch(cmd) { - case DDIOCSDBG: - return(dbg_ioctl((void *) arg, DBG_IP)); default: return(-EINVAL); } @@ -190,12 +127,6 @@ } -static void -print_ipprot(struct inet_protocol *ipprot) -{ - DPRINTF((DBG_IP, "handler = %X, protocol = %d, copy=%d \n", - ipprot->handler, ipprot->protocol, ipprot->copy)); -} /* This routine will check to see if we have lost a gateway. */ @@ -272,10 +203,6 @@ if (saddr == 0) saddr = ip_my_addr(); - DPRINTF((DBG_IP, "ip_build_header (skb=%X, saddr=%X, daddr=%X, *dev=%X,\n" - " type=%d, opt=%X, len = %d)\n", - skb, saddr, daddr, *dev, type, opt, len)); - buff = skb->data; /* @@ -303,7 +230,6 @@ saddr = src;/*rt->rt_dev->pa_addr;*/ raddr = rt->rt_gateway; - DPRINTF((DBG_IP, "ip_build_header: saddr set to %s\n", in_ntoa(saddr))); opt = &optmem; } else @@ -754,8 +680,7 @@ struct ipq *qp; qp = (struct ipq *)arg; - DPRINTF((DBG_IP, "IP: queue_expire: fragment queue 0x%X timed out!\n", qp)); - + /* * Send an ICMP "Fragment Reassembly Timeout" message. */ @@ -1063,7 +988,6 @@ i = prev->end - offset; offset += i; /* ptr into datagram */ ptr += i; /* ptr into fragment data */ - DPRINTF((DBG_IP, "IP: defrag: fixed low overlap %d bytes\n", i)); } /* @@ -1088,8 +1012,6 @@ */ if (next->len <= 0) { - DPRINTF((DBG_IP, "IP: defrag: removing frag 0x%X (len %d)\n", - next, next->len)); if (next->prev != NULL) next->prev->next = next->next; else @@ -1101,7 +1023,6 @@ kfree_skb(next->skb,FREE_READ); kfree_s(next, sizeof(struct ipfrag)); } - DPRINTF((DBG_IP, "IP: defrag: fixed high overlap %d bytes\n", i)); } /* @@ -1188,22 +1109,12 @@ mtu = (dev->mtu - hlen); /* Size of data space */ ptr = (raw + hlen); /* Where to start from */ - DPRINTF((DBG_IP, "IP: Fragmentation Desired\n")); - DPRINTF((DBG_IP, " DEV=%s, MTU=%d, LEN=%d SRC=%s", - dev->name, dev->mtu, left, in_ntoa(iph->saddr))); - DPRINTF((DBG_IP, " DST=%s\n", in_ntoa(iph->daddr))); - /* * Check for any "DF" flag. [DF means do not fragment] */ if (ntohs(iph->frag_off) & IP_DF) { - DPRINTF((DBG_IP, "IP: Fragmentation Desired, but DF set !\n")); - DPRINTF((DBG_IP, " DEV=%s, MTU=%d, LEN=%d SRC=%s", - dev->name, dev->mtu, left, in_ntoa(iph->saddr))); - DPRINTF((DBG_IP, " DST=%s\n", in_ntoa(iph->daddr))); - ip_statistics.IpFragFails++; icmp_send(skb,ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, dev); return; @@ -1255,9 +1166,6 @@ len/=8; len*=8; } - DPRINTF((DBG_IP,"IP: frag: creating fragment of %d bytes (%d total)\n", - len, len + hlen)); - /* * Allocate buffer. */ @@ -1277,7 +1185,7 @@ skb2->free = skb->free; skb2->len = len + hlen; skb2->h.raw=(char *) skb2->data; - + skb2->raddr = skb->raddr; /* For rebuild_header */ /* * Charge the memory for the fragment to any owner * it might posess @@ -1345,14 +1253,20 @@ /* * Only forward packets that were fired at us when we are in promiscuous * mode. In standard mode we rely on the driver to filter for us. + * + * This is a mess. When the drivers class packets on the upcall this + * will tidy up! */ if(dev->flags&IFF_PROMISC) { - if(memcmp((char *)&skb[1],dev->dev_addr,dev->addr_len)) + if(memcmp(skb->data,dev->dev_addr,dev->addr_len)) return; } + if(memcmp(skb->data,dev->broadcast, dev->addr_len)) + return; + /* @@ -1370,10 +1284,6 @@ iph->ttl--; if (iph->ttl <= 0) { - DPRINTF((DBG_IP, "\nIP: *** datagram expired: TTL=0 (ignored) ***\n")); - DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr))); - DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr))); - /* Tell the sender its packet died... */ icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, dev); return; @@ -1395,8 +1305,6 @@ rt = ip_rt_route(iph->daddr, NULL, NULL); if (rt == NULL) { - DPRINTF((DBG_IP, "\nIP: *** routing (phase I) failed ***\n")); - /* * Tell the sender its packet cannot be delivered. Again * ICMP is screened later. @@ -1425,8 +1333,6 @@ rt = ip_rt_route(raddr, NULL, NULL); if (rt == NULL) { - DPRINTF((DBG_IP, "\nIP: *** routing (phase II) failed ***\n")); - /* * Tell the sender its packet cannot be delivered... */ @@ -1460,10 +1366,6 @@ * If the indicated interface is up and running, kick it. */ - DPRINTF((DBG_IP, "\nIP: *** fwd %s -> ", in_ntoa(iph->saddr))); - DPRINTF((DBG_IP, "%s (via %s), LEN=%d\n", - in_ntoa(raddr), dev2->name, skb->len)); - if (dev2->flags & IFF_UP) { @@ -1548,8 +1450,6 @@ ip_statistics.IpInReceives++; - DPRINTF((DBG_IP, "<<\n")); - /* * Tag the ip header of this packet so we can find it */ @@ -1568,9 +1468,6 @@ if (skb->lenihl<5 || iph->version != 4 || ip_fast_csum((unsigned char *)iph, iph->ihl) !=0) { ip_statistics.IpInHdrErrors++; - DPRINTF((DBG_IP, "\nIP: *** datagram error ***\n")); - DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr))); - DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr))); kfree_skb(skb, FREE_WRITE); return(0); } @@ -1589,7 +1486,6 @@ if (iph->ihl != 5) { /* Fast path for the typical optionless IP packet. */ - ip_print(iph); /* Bogus, only for debugging. */ memset((char *) &opt, 0, sizeof(opt)); if (do_options(iph, &opt) != 0) return 0; @@ -1628,7 +1524,7 @@ #ifdef CONFIG_IP_FORWARD ip_forward(skb, dev, is_frag); #else - printk("Machine %x tried to use us as a forwarder to %x but we have forwarding disabled!\n", + printk("Machine %lx tried to use us as a forwarder to %lx but we have forwarding disabled!\n", iph->saddr,iph->daddr); ip_statistics.IpInAddrErrors++; #endif @@ -1647,20 +1543,11 @@ if(is_frag) { -#ifdef CONFIG_IP_DEFRAG /* Defragment. Obtain the complete packet if there is one */ skb=ip_defrag(iph,skb,dev); if(skb==NULL) return 0; iph=skb->h.iph; -#else - printk("\nIP: *** datagram fragmentation not yet implemented ***\n"); - printk(" SRC = %s ", in_ntoa(iph->saddr)); - printk(" DST = %s (ignored)\n", in_ntoa(iph->daddr)); - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev); - kfree_skb(skb, FREE_WRITE); - return(0); -#endif } /* @@ -1681,9 +1568,6 @@ if (ipprot->protocol != iph->protocol) continue; - DPRINTF((DBG_IP, "Using protocol = %X:\n", ipprot)); - print_ipprot(ipprot); - /* * See if we need to make a copy of it. This will * only be set if more than one protocol wants it. @@ -1786,8 +1670,6 @@ skb->dev = dev; skb->when = jiffies; - DPRINTF((DBG_IP, ">>\n")); - /* * Find the IP header and set the length. This is bad * but once we get the skb data handling code in the @@ -1825,7 +1707,6 @@ /* * Print the frame when debugging */ - ip_print(iph); /* * More debugging. You cannot queue a packet already on a list diff -u --recursive --new-file v1.1.12/linux/net/inet/ipx.c linux/net/inet/ipx.c --- v1.1.12/linux/net/inet/ipx.c Tue Apr 19 22:20:35 1994 +++ linux/net/inet/ipx.c Mon May 23 08:17:49 1994 @@ -22,6 +22,10 @@ * Adding a route will overwrite any existing route to the same * network. * Revision 0.24: Supports new /proc with no 4K limit + * Revision 0.25: Add ephemeral sockets, passive local network + * identification, support for local net 0 and + * multiple datalinks + * * */ @@ -46,6 +50,7 @@ #include #include #include +#include "p8022.h" #ifdef CONFIG_IPX /***********************************************************************************************************************\ @@ -184,7 +189,40 @@ \*******************************************************************************************************************/ +static struct datalink_proto *p8022_datalink = NULL; +static struct datalink_proto *pEII_datalink = NULL; +static struct datalink_proto *p8023_datalink = NULL; +static struct datalink_proto *pSNAP_datalink = NULL; + static ipx_route *ipx_router_list=NULL; +static ipx_route *ipx_localnet_list=NULL; + +static ipx_route * +ipxrtr_get_local_net(struct device *dev, unsigned short datalink) +{ + ipx_route *r; + unsigned long flags; + save_flags(flags); + cli(); + r=ipx_localnet_list; + while(r!=NULL) + { + if((r->dev==dev) && (r->dlink_type == datalink)) + { + restore_flags(flags); + return r; + } + r=r->next; + } + restore_flags(flags); + return NULL; +} + +static ipx_route * +ipxrtr_get_default_net(void) +{ + return ipx_localnet_list; +} static ipx_route *ipxrtr_get_dev(long net) { @@ -206,10 +244,55 @@ return NULL; } +static void ipxrtr_add_localnet(ipx_route *newnet) +{ + ipx_route *r; + unsigned long flags; + save_flags(flags); + cli(); + + newnet->nextlocal = NULL; + if (ipx_localnet_list == NULL) { + ipx_localnet_list = newnet; + restore_flags(flags); + return; + } + + r=ipx_localnet_list; + while(r->nextlocal!=NULL) + r=r->nextlocal; + + r->nextlocal = newnet; + + restore_flags(flags); + return; +} + static int ipxrtr_create(struct ipx_route_def *r) { ipx_route *rt=ipxrtr_get_dev(r->ipx_network); struct device *dev; + unsigned short dlink_type; + struct datalink_proto *datalink = NULL; + + if (r->ipx_flags & IPX_RT_BLUEBOOK) { + dlink_type = htons(ETH_P_IPX); + datalink = pEII_datalink; + } else if (r->ipx_flags & IPX_RT_8022) { + dlink_type = htons(ETH_P_802_2); + datalink = p8022_datalink; + } else if (r->ipx_flags & IPX_RT_SNAP) { + dlink_type = htons(ETH_P_SNAP); + datalink = pSNAP_datalink; + } else { + dlink_type = htons(ETH_P_802_3); + datalink = p8023_datalink; + } + + if (datalink == NULL) { + printk("IPX: Unsupported datalink protocol.\n"); + return -EPROTONOSUPPORT; + } if(r->ipx_router_network!=0) { @@ -230,7 +313,9 @@ rt->net=r->ipx_network; rt->router_net=r->ipx_router_network; memcpy(rt->router_node,r->ipx_router_node,sizeof(rt->router_node)); - rt->flags=(rt1->flags&IPX_RT_BLUEBOOK)|IPX_RT_ROUTED; + rt->flags=IPX_RT_ROUTED; + rt->dlink_type = dlink_type; + rt->datalink = datalink; rt->dev=rt1->dev; return 0; } @@ -243,29 +328,53 @@ return -EINVAL; if(dev->addr_len<2) return -EINVAL; + if (ipxrtr_get_local_net(dev, dlink_type) != NULL) + return -EEXIST; /* Ok now create */ - if (rt==NULL) - { - rt=(ipx_route *)kmalloc(sizeof(ipx_route),GFP_ATOMIC); /* Because we are brave and don't lock the table! */ - if(rt==NULL) - return -EAGAIN; - rt->next=ipx_router_list; - ipx_router_list=rt; - } + rt=(ipx_route *)kmalloc(sizeof(ipx_route),GFP_ATOMIC); /* Because we are brave and don't lock the table! */ + if(rt==NULL) + return -EAGAIN; + rt->next=ipx_router_list; + ipx_router_list=rt; rt->router_net=0; memset(rt->router_node,0,sizeof(rt->router_node)); rt->dev=dev; rt->net=r->ipx_network; - rt->flags=r->ipx_flags&IPX_RT_BLUEBOOK; + rt->flags=0; + rt->dlink_type = dlink_type; + rt->datalink = datalink; + ipxrtr_add_localnet(rt); return 0; } + +static int ipxrtr_delete_localnet(ipx_route *d) +{ + ipx_route *r=ipx_localnet_list; + if(r==d) + { + ipx_localnet_list=r->next; + return 0; + } + while(r->next!=NULL) + { + if(r->nextlocal==d) + { + r->nextlocal=d->nextlocal; + return 0; + } + r=r->nextlocal; + } + return -ENOENT; +} + static int ipxrtr_delete(long net) { ipx_route *r=ipx_router_list; if(r->net==net) { ipx_router_list=r->next; + kfree_s(r,sizeof(ipx_route)); return 0; } while(r->next!=NULL) @@ -274,6 +383,9 @@ { ipx_route *d=r->next; r->next=d->next; + if (d->router_net == 0) { + ipxrtr_delete_localnet(d); + } kfree_s(d,sizeof(ipx_route)); return 0; } @@ -479,8 +591,6 @@ kfree_s((void *)sk,sizeof(*sk)); return(-ESOCKTNOSUPPORT); } - sk->stamp.tv_sec=0; - sk->rmem_alloc=0; sk->dead=0; sk->next=NULL; sk->broadcast=0; @@ -489,7 +599,7 @@ sk->wmem_alloc=0; sk->rmem_alloc=0; sk->inuse=0; - sk->dead=0; + sk->shutdown=0; sk->prot=NULL; /* So we use default free mechanisms */ sk->broadcast=0; sk->err=0; @@ -497,13 +607,11 @@ skb_queue_head_init(&sk->write_queue); sk->send_head=NULL; skb_queue_head_init(&sk->back_log); - sk->mtu=512; sk->state=TCP_CLOSE; sk->socket=sock; sk->type=sock->type; sk->ipx_type=0; /* General user level IPX */ sk->debug=0; - sk->localroute=0; memset(&sk->ipx_dest_addr,'\0',sizeof(sk->ipx_dest_addr)); memset(&sk->ipx_source_addr,'\0',sizeof(sk->ipx_source_addr)); @@ -542,12 +650,30 @@ return(0); } +static unsigned short first_free_socketnum(void) +{ + static unsigned short socketNum = 0x4000; + unsigned short startNum, foundNum = 0; + + startNum = socketNum; + do { + if (ipx_find_socket(htons(socketNum)) == NULL) { + foundNum = socketNum; + } + socketNum++; + if (socketNum > 0x7ffc) socketNum = 0x4000; + } while (!foundNum && (socketNum != startNum)); + + return htons(foundNum); +} + static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len) { ipx_socket *sk; int err; struct sockaddr_ipx addr; struct ipx_route *rt; + unsigned char *nodestart; sk=(ipx_socket *)sock->data; if(sk==NULL) @@ -555,7 +681,7 @@ printk("IPX:bind:sock->data=NULL\n"); return 0; } - + if(sk->zapped==0) return(-EIO); @@ -566,6 +692,11 @@ return -EINVAL; memcpy_fromfs(&addr,uaddr,addr_len); + if (addr.sipx_port == 0) { + addr.sipx_port = first_free_socketnum(); + if (addr.sipx_port == 0) return -EINVAL; + } + if(ntohs(addr.sipx_port)<0x4000 && !suser()) return(-EPERM); /* protect IPX system stuff like routing/sap */ @@ -577,20 +708,32 @@ if(sk->debug) printk("IPX: bind failed because port %X in use.\n", (int)addr.sipx_port); - return(-EADDRINUSE); + return -EADDRINUSE; } + sk->ipx_source_addr.sock=addr.sipx_port; - memcpy(sk->ipx_source_addr.node,addr.sipx_node,sizeof(sk->ipx_source_addr.node)); - sk->ipx_source_addr.net=addr.sipx_network; - if((rt=ipxrtr_get_dev(sk->ipx_source_addr.net))==NULL) + + if (addr.sipx_network == 0L) { + rt = ipxrtr_get_default_net(); + } else { + rt = ipxrtr_get_dev(addr.sipx_network); + } + + if(rt == NULL) { if(sk->debug) printk("IPX: bind failed (no device for net %lX)\n", sk->ipx_source_addr.net); - return(-EADDRNOTAVAIL); + return -EADDRNOTAVAIL; } + + sk->ipx_source_addr.net=rt->net; + + /* IPX addresses zero pad physical addresses less than 6 */ memset(sk->ipx_source_addr.node,'\0',6); - memcpy(sk->ipx_source_addr.node,rt->dev->dev_addr,rt->dev->addr_len); + nodestart = sk->ipx_source_addr.node + (6 - rt->dev->addr_len); + memcpy(nodestart,rt->dev->dev_addr,rt->dev->addr_len); + ipx_insert_socket(sk); sk->zapped=0; if(sk->debug) @@ -621,8 +764,6 @@ return err; memcpy_fromfs(&addr,uaddr,sizeof(addr)); - if(ntohs(addr.sipx_port)<0x4000 && !suser()) - return -EPERM; if(sk->ipx_source_addr.net==0) /* Must bind first - no autobinding in this */ return -EINVAL; @@ -691,18 +832,16 @@ return(0); } - int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) { /* NULL here for pt means the packet was looped back */ ipx_socket *sock; - unsigned char *buff; ipx_packet *ipx; ipx_route *rt; + ipx_route *ln; + unsigned char IPXaddr[6]; - buff=skb->data; - buff+=dev->hard_header_len; - ipx=(ipx_packet *)buff; + ipx=(ipx_packet *)skb->h.raw; if(ipx->ipx_checksum!=IPX_NO_CHECKSUM) { @@ -714,7 +853,7 @@ } /* Too small */ - if(htons(ipx->ipx_pktsize)hard_header_len) + if(htons(ipx->ipx_pktsize)type); + if (ln == NULL) + { + kfree_skb(skb,FREE_READ); + return(0); + } + + memset(IPXaddr, '\0', 6); + memcpy(IPXaddr+(6 - dev->addr_len), dev->dev_addr, dev->addr_len); + /* Not us/broadcast */ - if(memcmp(dev->dev_addr,ipx->ipx_dest.node,dev->addr_len)!=0 - && memcmp(ipx_broadcast_node,ipx->ipx_dest.node,dev->addr_len)!=0) + if(memcmp(IPXaddr,ipx->ipx_dest.node,6)!=0 + && memcmp(ipx_broadcast_node,ipx->ipx_dest.node,6)!=0) { /********************************************************************************************** @@ -739,6 +889,8 @@ ***********************************************************************************************/ + int incoming_size; + int outgoing_size; struct sk_buff *skb2; int free_it=0; @@ -749,6 +901,7 @@ return(0); } + ipx->ipx_tctrl++; /* Don't forward if we don't have a route. We ought to go off and start hunting out routes but if someone needs this _THEY_ can add it */ rt=ipxrtr_get_dev(ipx->ipx_dest.net); @@ -757,11 +910,16 @@ kfree_skb(skb,FREE_READ); return(0); } - if(rt->dev->hard_header_len!=dev->hard_header_len) + + /* Check for differences in outgoing and incoming packet size */ + incoming_size = skb->len - ntohs(ipx->ipx_pktsize); + outgoing_size = rt->datalink->header_length + rt->dev->hard_header_len; + if(incoming_size != outgoing_size) { /* A different header length causes a copy. Awkward to avoid with the current sk_buff stuff. */ - skb2=alloc_skb(skb->len,GFP_ATOMIC); + skb2=alloc_skb(ntohs(ipx->ipx_pktsize) + outgoing_size, + GFP_ATOMIC); if(skb2==NULL) { kfree_skb(skb,FREE_READ); @@ -769,30 +927,31 @@ } free_it=1; skb2->free=1; - skb2->len=skb->len; - memcpy((char *)(skb2+1),(char *)(skb+1),skb->len); - buff=(char *)(skb2+1); - ipx=(ipx_packet *)(buff+dev->hard_header_len); + skb2->len=ntohs(ipx->ipx_pktsize) + outgoing_size; + skb2->mem_addr = skb2; + skb2->arp = 1; + skb2->sk = NULL; + + /* Need to copy with appropriate offsets */ + memcpy((char *)(skb2+1)+outgoing_size, + (char *)(skb+1)+incoming_size, + ntohs(ipx->ipx_pktsize)); } else { skb2=skb; - buff=(char *)(skb+1); } + /* Now operate on the buffer */ /* Increase hop count */ - ipx->ipx_tctrl++; - /* If the route is a gateway then forward to it */ - dev->hard_header(buff, dev, - (rt->flags&IPX_RT_BLUEBOOK)?ntohs(ETH_P_IPX):ntohs(skb2->len), - (rt->flags&IPX_RT_ROUTED)?rt->router_node:ipx->ipx_dest.node, - NULL, /* Our source */ - skb2->len, - skb2); - - dev_queue_xmit(skb2,dev,SOPRI_NORMAL); + skb2->dev = rt->dev; + rt->datalink->datalink_header(rt->datalink, skb2, + (rt->flags&IPX_RT_ROUTED)?rt->router_node + :ipx->ipx_dest.node); + dev_queue_xmit(skb2,rt->dev,SOPRI_NORMAL); + if(free_it) kfree_skb(skb,FREE_READ); return(0); @@ -800,13 +959,22 @@ /************ End of router: Now sanity check stuff for us ***************/ /* Ok its for us ! */ - + if (ln->net == 0L) { + printk("IPX: Registering local net %lx\n", ipx->ipx_dest.net); + ln->net = ipx->ipx_dest.net; + } + sock=ipx_find_socket(ipx->ipx_dest.sock); if(sock==NULL) /* But not one of our sockets */ { kfree_skb(skb,FREE_READ); return(0); } + + /* Check to see if this socket needs its network number */ + ln = ipxrtr_get_default_net(); + if (sock->ipx_source_addr.net == 0L) + sock->ipx_source_addr.net = ln->net; if(sock->rmem_alloc>=sock->rcvbuf) { @@ -815,15 +983,14 @@ } sock->rmem_alloc+=skb->mem_len; + skb->sk = sock; + skb_queue_tail(&sock->receive_queue,skb); if(!sock->dead) sock->data_ready(sock,skb->len); return(0); } - - - static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock, unsigned flags, struct sockaddr *usip, int addr_len) { @@ -836,8 +1003,12 @@ struct ipx_packet *ipx; int size; ipx_route *rt; + struct datalink_proto *dl = NULL; + unsigned char IPXaddr[6]; + int self_addressing = 0; + int broadcast = 0; - if(flags&~MSG_DONTROUTE) + if(flags) return -EINVAL; if(len<0) return -EINVAL; @@ -869,8 +1040,13 @@ if(sk->debug) printk("IPX: sendto: Addresses built.\n"); - if(!sk->broadcast && memcmp(&sipx.sipx_node,&ipx_broadcast_node,6)==0) - return -ENETUNREACH; + + if(memcmp(&sipx.sipx_node,&ipx_broadcast_node,6)==0) { + if (!sk->broadcast) + return -ENETUNREACH; + broadcast = 1; + } + /* Build a packet */ if(sk->debug) @@ -882,57 +1058,70 @@ size=sizeof(ipx_packet)+len; /* For mac headers */ /* Find out where this has to go */ - rt=ipxrtr_get_dev(sipx.sipx_network); - /* No suitable route - no gateways when not routing */ - if(rt==NULL || ((flags&IPX_RT_ROUTED)&& ((flags&MSG_DONTROUTE)||sk->localroute))) + if (sipx.sipx_network == 0L) { + rt = ipxrtr_get_default_net(); + if (rt != NULL) + sipx.sipx_network = rt->net; + } else + rt=ipxrtr_get_dev(sipx.sipx_network); + + if(rt==NULL) { return -ENETUNREACH; } dev=rt->dev; + dl = rt->datalink; - size+=dev->hard_header_len; - + size += dev->hard_header_len; + size += dl->header_length; + if(sk->debug) - printk("IPX: sendto: allocating buffer (%d)\n",size-sizeof(struct sk_buff)); + printk("IPX: sendto: allocating buffer (%d)\n",size); - if(size+sk->wmem_alloc>sk->sndbuf) + if(size+sk->wmem_alloc>sk->sndbuf) { return -EAGAIN; + } skb=alloc_skb(size,GFP_KERNEL); if(skb==NULL) return -ENOMEM; - if(skb->mem_len+sk->wmem_alloc>sk->sndbuf) - { - kfree_skb(skb,FREE_WRITE); - return -EAGAIN; - } - - sk->wmem_alloc+=skb->mem_len; + + skb->mem_addr=skb; skb->sk=sk; skb->free=1; skb->arp=1; - skb->len=size-sizeof(struct sk_buff); + skb->len=size; + + sk->wmem_alloc+=skb->mem_len; if(sk->debug) printk("Building MAC header.\n"); skb->dev=rt->dev; - dev->hard_header(skb->data,skb->dev, - (rt->flags&IPX_RT_BLUEBOOK)?ETH_P_IPX:ETH_P_802_3), - (rt->flags&IPX_RT_ROUTED)?rt->router_node:sipx.sipx_node, - NULL, - len+sizeof(ipx_packet), - skb); + /* Build Data Link header */ + dl->datalink_header(dl, skb, + (rt->flags&IPX_RT_ROUTED)?rt->router_node:sipx.sipx_node); + + /* See if we are sending to ourself */ + memset(IPXaddr, '\0', 6); + memcpy(IPXaddr+(6 - skb->dev->addr_len), skb->dev->dev_addr, + skb->dev->addr_len); + + self_addressing = !memcmp(IPXaddr, + (rt->flags&IPX_RT_ROUTED)?rt->router_node + :sipx.sipx_node, + 6); /* Now the IPX */ if(sk->debug) printk("Building IPX Header.\n"); - ipx=(ipx_packet *)skb->data+skb->dev->hard_header_len; + ipx=(ipx_packet *)skb->h.raw; ipx->ipx_checksum=0xFFFF; ipx->ipx_pktsize=htons(len+sizeof(ipx_packet)); ipx->ipx_tctrl=0; - ipx->ipx_type=sk->ipx_type; + ipx->ipx_type=sipx.sipx_type; + memcpy(&ipx->ipx_source,&sk->ipx_source_addr,sizeof(ipx->ipx_source)); ipx->ipx_dest.net=sipx.sipx_network; memcpy(ipx->ipx_dest.node,sipx.sipx_node,sizeof(ipx->ipx_dest.node)); @@ -943,11 +1132,35 @@ memcpy_fromfs((char *)(ipx+1),ubuf,len); if(sk->debug) printk("IPX: Transmitting buffer\n"); - if(dev->flags&IFF_LOOPBACK) + if((dev->flags&IFF_LOOPBACK) || self_addressing) { + struct packet_type pt; + /* loop back */ - ipx_rcv(skb,dev,NULL); - else + pt.type = rt->dlink_type; + sk->wmem_alloc-=skb->mem_len; + skb->sk = NULL; + ipx_rcv(skb,dev,&pt); + } else { + if (broadcast) { + struct packet_type pt; + struct sk_buff *skb2; + + /* loop back */ + pt.type = rt->dlink_type; + + skb2=alloc_skb(skb->len, GFP_ATOMIC); + skb2->mem_addr=skb2; + skb2->free=1; + skb2->arp=1; + skb2->len=skb->len; + skb2->sk = NULL; + skb2->h.raw = skb2->data + rt->datalink->header_length + + dev->hard_header_len; + memcpy(skb2->data, skb->data, skb->len); + ipx_rcv(skb2,dev,&pt); + } dev_queue_xmit(skb,dev,SOPRI_NORMAL); + } return len; } @@ -956,21 +1169,17 @@ return ipx_sendto(sock,ubuf,size,noblock,flags,NULL,0); } -static int ipx_write(struct socket *sock, char *ubuf, int size, int noblock) -{ - return ipx_send(sock,ubuf,size,noblock,0); -} - static int ipx_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags, struct sockaddr *sip, int *addr_len) { ipx_socket *sk=(ipx_socket *)sock->data; struct sockaddr_ipx *sipx=(struct sockaddr_ipx *)sip; + struct ipx_packet *ipx = NULL; /* FILL ME IN */ int copied = 0; struct sk_buff *skb; int er; - + if(sk->err) { er= -sk->err; @@ -1001,24 +1210,33 @@ skb=skb_recv_datagram(sk,flags,noblock,&er); if(skb==NULL) return er; - copied=(sizelen)?size:skb->len; + + ipx = (ipx_packet *)(skb->h.raw); + copied=ntohs(ipx->ipx_pktsize) - sizeof(ipx_packet); skb_copy_datagram(skb,sizeof(struct ipx_packet),ubuf,copied); - sk->stamp=skb->stamp; if(sipx) { struct sockaddr_ipx addr; addr.sipx_family=AF_IPX; - addr.sipx_port=((ipx_packet*)skb->h.raw)->ipx_source.sock; - memcpy(addr.sipx_node,((ipx_packet*)skb->h.raw)->ipx_source.node,sizeof(addr.sipx_node)); - addr.sipx_network=((ipx_packet*)skb->h.raw)->ipx_source.net; + addr.sipx_port=ipx->ipx_source.sock; + memcpy(addr.sipx_node,ipx->ipx_source.node,sizeof(addr.sipx_node)); + addr.sipx_network=ipx->ipx_source.net; + addr.sipx_type = ipx->ipx_type; memcpy_tofs(sipx,&addr,sizeof(*sipx)); } skb_free_datagram(skb); return(copied); } + +static int ipx_write(struct socket *sock, char *ubuf, int size, int noblock) +{ + return ipx_send(sock,ubuf,size,noblock,0); +} + + static int ipx_recv(struct socket *sock, void *ubuf, int size , int noblock, unsigned flags) { @@ -1110,16 +1328,26 @@ }; -void ipx_proto_init(struct ddi_proto *pro) +extern struct datalink_proto *make_EII_client(void); +extern struct datalink_proto *make_8023_client(void); + +void ipx_proto_init(struct net_proto *pro) { + unsigned char val = 0xE0; (void) sock_register(ipx_proto_ops.family, &ipx_proto_ops); + + pEII_datalink = make_EII_client(); ipx_dix_packet_type.type=htons(ETH_P_IPX); dev_add_pack(&ipx_dix_packet_type); + + p8023_datalink = make_8023_client(); ipx_8023_packet_type.type=htons(ETH_P_802_3); dev_add_pack(&ipx_8023_packet_type); - printk("Swansea University Computer Society IPX 0.24 BETA for NET3 ALPHA.008\n"); + if ((p8022_datalink = register_8022_client(val, ipx_rcv)) == NULL) + printk("IPX: Unable to register with 802.2\n"); + printk("Swansea University Computer Society IPX 0.25 BETA for NET3 014\n"); + } - #endif diff -u --recursive --new-file v1.1.12/linux/net/inet/ipx.h linux/net/inet/ipx.h --- v1.1.12/linux/net/inet/ipx.h Tue Apr 19 10:53:59 1994 +++ linux/net/inet/ipx.h Mon May 23 08:17:49 1994 @@ -8,10 +8,11 @@ * Which is available from ftp.novell.com */ -#ifndef _IPX_H -#define _IPX_H +#ifndef _NET_INET_IPX_H_ +#define _NET_INET_IPX_H_ -#include +#include +#include "datalink.h" typedef struct { @@ -46,10 +47,15 @@ unsigned char router_node[6]; unsigned long router_net; unsigned short flags; - struct device *dev; #define IPX_RT_ROUTED 1 /* This isn't a direct route. Send via this if to node router_node */ -#define IPX_RT_BLUEBOOK 2 /* Use DIX 8137 frames not IEE802.3 */ +#define IPX_RT_BLUEBOOK 2 +#define IPX_RT_8022 4 +#define IPX_RT_SNAP 8 + unsigned short dlink_type; + struct device *dev; + struct datalink_proto *datalink; struct ipx_route *next; + struct ipx_route *nextlocal; } ipx_route; diff -u --recursive --new-file v1.1.12/linux/net/inet/ipxcall.h linux/net/inet/ipxcall.h --- v1.1.12/linux/net/inet/ipxcall.h Tue Apr 19 10:54:00 1994 +++ linux/net/inet/ipxcall.h Mon May 23 08:17:49 1994 @@ -1,2 +1,2 @@ -/* Seperate to keep compilation of Space.c simpler */ -extern void ipx_proto_init(struct ddi_proto *pro); +/* Seperate to keep compilation of protocols.c simpler */ +extern void ipx_proto_init(struct net_proto *pro); diff -u --recursive --new-file v1.1.12/linux/net/inet/p8022.c linux/net/inet/p8022.c --- v1.1.12/linux/net/inet/p8022.c Thu Jan 1 02:00:00 1970 +++ linux/net/inet/p8022.c Mon May 23 08:17:49 1994 @@ -0,0 +1,98 @@ +#include +#include +#include "datalink.h" +#include +#include +#include + +static struct datalink_proto *p8022_list = NULL; + +static struct datalink_proto * +find_8022_client(unsigned char type) +{ + struct datalink_proto *proto; + + for (proto = p8022_list; + ((proto != NULL) && (*(proto->type) != type)); + proto = proto->next) + ; + + return proto; +} + +int +p8022_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) +{ + struct datalink_proto *proto; + + proto = find_8022_client(*(skb->h.raw)); + if (proto != NULL) { + skb->h.raw += 3; + return proto->rcvfunc(skb, dev, pt); + } + + skb->sk = NULL; + kfree_skb(skb, FREE_READ); + return 0; +} + +static void +p8022_datalink_header(struct datalink_proto *dl, + struct sk_buff *skb, unsigned char *dest_node) +{ + struct device *dev = skb->dev; + unsigned long len = skb->len; + unsigned long hard_len = dev->hard_header_len; + unsigned char *rawp; + + dev->hard_header(skb->data, dev, len - hard_len, + dest_node, NULL, len - hard_len, skb); + rawp = skb->data + hard_len; + *rawp = dl->type[0]; + rawp++; + *rawp = dl->type[0]; + rawp++; + *rawp = 0x03; /* UI */ + rawp++; + skb->h.raw = rawp; +} + +static struct packet_type p8022_packet_type = +{ + 0, /* MUTTER ntohs(ETH_P_IPX),*/ + 0, /* copy */ + p8022_rcv, + NULL, + NULL, +}; + + +void p8022_proto_init(struct net_proto *pro) +{ + p8022_packet_type.type=htons(ETH_P_802_2); + dev_add_pack(&p8022_packet_type); +} + +struct datalink_proto * +register_8022_client(unsigned char type, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *)) +{ + struct datalink_proto *proto; + + if (find_8022_client(type) != NULL) + return NULL; + + proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC); + if (proto != NULL) { + proto->type[0] = type; + proto->type_len = 1; + proto->rcvfunc = rcvfunc; + proto->header_length = 3; + proto->datalink_header = p8022_datalink_header; + } + + proto->next = p8022_list; + p8022_list = proto; + + return proto; +} + diff -u --recursive --new-file v1.1.12/linux/net/inet/p8022.h linux/net/inet/p8022.h --- v1.1.12/linux/net/inet/p8022.h Thu Jan 1 02:00:00 1970 +++ linux/net/inet/p8022.h Mon May 23 08:17:49 1994 @@ -0,0 +1,2 @@ +struct datalink_proto *register_8022_client(unsigned char type, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *)); + diff -u --recursive --new-file v1.1.12/linux/net/inet/p8022call.h linux/net/inet/p8022call.h --- v1.1.12/linux/net/inet/p8022call.h Thu Jan 1 02:00:00 1970 +++ linux/net/inet/p8022call.h Mon May 23 08:17:49 1994 @@ -0,0 +1,2 @@ +/* Seperate to keep compilation of Space.c simpler */ +extern void p8022_proto_init(struct net_proto *); diff -u --recursive --new-file v1.1.12/linux/net/inet/p8023.c linux/net/inet/p8023.c --- v1.1.12/linux/net/inet/p8023.c Thu Jan 1 02:00:00 1970 +++ linux/net/inet/p8023.c Mon May 23 08:17:49 1994 @@ -0,0 +1,34 @@ +#include +#include +#include "datalink.h" +#include +#include + +static void +p8023_datalink_header(struct datalink_proto *dl, + struct sk_buff *skb, unsigned char *dest_node) +{ + struct device *dev = skb->dev; + unsigned long len = skb->len; + unsigned long hard_len = dev->hard_header_len; + + dev->hard_header(skb->data, dev, len - hard_len, + dest_node, NULL, len - hard_len, skb); + skb->h.raw = skb->data + hard_len; +} + +struct datalink_proto * +make_8023_client(void) +{ + struct datalink_proto *proto; + + proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC); + if (proto != NULL) { + proto->type_len = 0; + proto->header_length = 0; + proto->datalink_header = p8023_datalink_header; + } + + return proto; +} + diff -u --recursive --new-file v1.1.12/linux/net/inet/packet.c linux/net/inet/packet.c --- v1.1.12/linux/net/inet/packet.c Tue Apr 19 10:54:00 1994 +++ linux/net/inet/packet.c Mon May 23 08:17:49 1994 @@ -193,8 +193,7 @@ if (skb == NULL) { - DPRINTF((DBG_PKT, "packet_sendto: write buffer full?\n")); - return(-ENOMEM); + return(-ENOBUFS); } /* diff -u --recursive --new-file v1.1.12/linux/net/inet/pe2.c linux/net/inet/pe2.c --- v1.1.12/linux/net/inet/pe2.c Thu Jan 1 02:00:00 1970 +++ linux/net/inet/pe2.c Mon May 23 08:17:50 1994 @@ -0,0 +1,34 @@ +#include +#include +#include "datalink.h" +#include +#include + +static void +pEII_datalink_header(struct datalink_proto *dl, + struct sk_buff *skb, unsigned char *dest_node) +{ + struct device *dev = skb->dev; + unsigned long len = skb->len; + unsigned long hard_len = dev->hard_header_len; + + dev->hard_header(skb->data, dev, ETH_P_IPX, + dest_node, NULL, len - hard_len, skb); + skb->h.raw = skb->data + hard_len; +} + +struct datalink_proto * +make_EII_client(void) +{ + struct datalink_proto *proto; + + proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC); + if (proto != NULL) { + proto->type_len = 0; + proto->header_length = 0; + proto->datalink_header = pEII_datalink_header; + } + + return proto; +} + diff -u --recursive --new-file v1.1.12/linux/net/inet/protocol.c linux/net/inet/protocol.c --- v1.1.12/linux/net/inet/protocol.c Tue Apr 19 10:54:01 1994 +++ linux/net/inet/protocol.c Mon May 23 08:17:50 1994 @@ -88,10 +88,8 @@ unsigned char hash; struct inet_protocol *p; - DPRINTF((DBG_PROTO, "get_protocol (%d)\n ", prot)); hash = prot & (MAX_INET_PROTOS - 1); for (p = inet_protos[hash] ; p != NULL; p=p->next) { - DPRINTF((DBG_PROTO, "trying protocol %d\n", p->protocol)); if (p->protocol == prot) return((struct inet_protocol *) p); } return(NULL); diff -u --recursive --new-file v1.1.12/linux/net/inet/raw.c linux/net/inet/raw.c --- v1.1.12/linux/net/inet/raw.c Thu Apr 21 09:46:35 1994 +++ linux/net/inet/raw.c Mon May 23 08:17:50 1994 @@ -23,6 +23,7 @@ * Alan Cox : Fixed error return for broadcasts * Alan Cox : Removed wake_up calls * Alan Cox : Use ttl/tos + * Alan Cox : Cleaned up old debugging * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -44,9 +45,6 @@ #include #include "ip.h" #include "protocol.h" -#if 0 -#include "tcp.h" -#endif #include #include "sock.h" #include "icmp.h" @@ -68,9 +66,6 @@ { struct sock *sk; - DPRINTF((DBG_RAW, "raw_err(err=%d, hdr=%X, daddr=%X, saddr=%X, protocl=%X)\n", - err, header, daddr, saddr, protocol)); - if (protocol == NULL) return; sk = (struct sock *) protocol->data; if (sk == NULL) return; @@ -99,10 +94,6 @@ { struct sock *sk; - DPRINTF((DBG_RAW, "raw_rcv(skb=%X, dev=%X, opt=%X, daddr=%X,\n" - " len=%d, saddr=%X, redo=%d, protocol=%X)\n", - skb, dev, opt, daddr, len, saddr, redo, protocol)); - if (skb == NULL) return(0); @@ -155,22 +146,12 @@ int tmp; int err; - DPRINTF((DBG_RAW, "raw_sendto(sk=%X, from=%X, len=%d, noblock=%d, flags=%X,\n" - " usin=%X, addr_len = %d)\n", sk, from, len, noblock, - flags, usin, addr_len)); - /* * Check the flags. Only MSG_DONTROUTE is permitted. */ if (flags&MSG_DONTROUTE) return(-EINVAL); - if (len < 0) - return(-EINVAL); - - err=verify_area(VERIFY_READ,from,len); - if(err) - return err; /* * Get and verify the address. */ @@ -222,7 +203,6 @@ { int tmp; - DPRINTF((DBG_RAW, "raw_sendto: write buffer full?\n")); if (noblock) return(-EAGAIN); tmp = sk->wmem_alloc; @@ -248,7 +228,6 @@ sk->protocol, sk->opt, skb->mem_len, sk->ip_tos,sk->ip_ttl); if (tmp < 0) { - DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n")); kfree_skb(skb,FREE_WRITE); release_sock(sk); return(tmp); @@ -293,11 +272,7 @@ sk->inuse = 1; sk->state = TCP_CLOSE; - DPRINTF((DBG_RAW, "raw_close: deleting protocol %d\n", - ((struct inet_protocol *)sk->pair)->protocol)); - - if (inet_del_protocol((struct inet_protocol *)sk->pair) < 0) - DPRINTF((DBG_RAW, "raw_close: del_protocol failed.\n")); + inet_del_protocol((struct inet_protocol *)sk->pair); kfree_s((void *)sk->pair, sizeof (struct inet_protocol)); sk->pair = NULL; release_sock(sk); @@ -323,8 +298,6 @@ /* We need to remember this somewhere. */ sk->pair = (struct sock *)p; - DPRINTF((DBG_RAW, "raw init added protocol %d\n", sk->protocol)); - return(0); } @@ -341,10 +314,6 @@ int copied=0; struct sk_buff *skb; int err; - - DPRINTF((DBG_RAW, "raw_recvfrom (sk=%X, to=%X, len=%d, noblock=%d, flags=%X,\n" - " sin=%X, addr_len=%X)\n", - sk, to, len, noblock, flags, sin, addr_len)); if (len == 0) return(0); if (len < 0) return(-EINVAL); diff -u --recursive --new-file v1.1.12/linux/net/inet/route.c linux/net/inet/route.c --- v1.1.12/linux/net/inet/route.c Tue Apr 19 22:20:35 1994 +++ linux/net/inet/route.c Mon May 23 08:17:50 1994 @@ -20,6 +20,7 @@ * Linus Torvalds : Rewrote bits to be sensible * Alan Cox : Added BSD route gw semantics * Alan Cox : Super /proc >4K + * Alan Cox : MTU in route table * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -60,26 +61,6 @@ static struct rtable *rt_loopback = NULL; /* - * Dump the contents of a routing table entry. - */ - -static void rt_print(struct rtable *rt) -{ - - if (rt == NULL || inet_debug != DBG_RT) - return; - - printk("RT: %06lx NXT=%06lx FLAGS=0x%02x\n", - (long) rt, (long) rt->rt_next, rt->rt_flags); - printk(" TARGET=%s ", in_ntoa(rt->rt_dst)); - printk("GW=%s ", in_ntoa(rt->rt_gateway)); - printk(" DEV=%s USE=%ld REF=%d\n", - (rt->rt_dev == NULL) ? "NONE" : rt->rt_dev->name, - rt->rt_use, rt->rt_refcnt); -} - - -/* * Remove a routing table entry. */ @@ -88,7 +69,6 @@ struct rtable *r, **rp; unsigned long flags; - DPRINTF((DBG_RT, "RT: flushing for dst %s\n", in_ntoa(dst))); rp = &rt_base; /* @@ -130,7 +110,6 @@ struct rtable **rp; unsigned long flags; - DPRINTF((DBG_RT, "RT: flushing for dev 0x%08lx (%s)\n", (long)dev, dev->name)); rp = &rt_base; cli(); save_flags(flags); @@ -216,7 +195,7 @@ */ void ip_rt_add(short flags, unsigned long dst, unsigned long mask, - unsigned long gw, struct device *dev) + unsigned long gw, struct device *dev, unsigned short mtu) { struct rtable *r, *rt; struct rtable **rp; @@ -280,7 +259,6 @@ rt = (struct rtable *) kmalloc(sizeof(struct rtable), GFP_ATOMIC); if (rt == NULL) { - DPRINTF((DBG_RT, "RT: no memory for new route!\n")); return; } memset(rt, 0, sizeof(struct rtable)); @@ -290,8 +268,12 @@ rt->rt_gateway = gw; rt->rt_mask = mask; rt->rt_mtu = dev->mtu; - rt_print(rt); + /* Are the MSS/Window valid ? */ + + if(rt->rt_flags & RTF_MTU) + rt->rt_mtu = mtu; + /* * What we have to do is loop though this until we have * found the first address which has a higher generality than @@ -467,7 +449,7 @@ * Add the route */ - ip_rt_add(flags, daddr, mask, gw, dev); + ip_rt_add(flags, daddr, mask, gw, dev, r->rt_mtu); return 0; } @@ -499,7 +481,7 @@ int size; len += sprintf(buffer, - "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\n"); + "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\tMTU\n"); pos=len; /* @@ -508,10 +490,10 @@ for (r = rt_base; r != NULL; r = r->rt_next) { - size = sprintf(buffer+len, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\n", + size = sprintf(buffer+len, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\t%d\n", r->rt_dev->name, r->rt_dst, r->rt_gateway, r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric, - r->rt_mask); + r->rt_mask, (int)r->rt_mtu); len+=size; pos+=size; if(pos * Fixes: * Alan Cox : Reformatted. Added ip_rt_local() + * Alan Cox : Support for TCP parameters. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -42,7 +43,7 @@ extern void ip_rt_flush(struct device *dev); extern void ip_rt_add(short flags, unsigned long addr, unsigned long mask, - unsigned long gw, struct device *dev); + unsigned long gw, struct device *dev, unsigned short); extern struct rtable *ip_rt_route(unsigned long daddr, struct options *opt, unsigned long *src_addr); extern struct rtable *ip_rt_local(unsigned long daddr, struct options *opt, unsigned long *src_addr); extern int rt_get_info(char * buffer, char **start, off_t offset, int length); diff -u --recursive --new-file v1.1.12/linux/net/inet/skbuff.c linux/net/inet/skbuff.c --- v1.1.12/linux/net/inet/skbuff.c Sun May 1 12:12:52 1994 +++ linux/net/inet/skbuff.c Mon May 23 09:43:14 1994 @@ -421,12 +421,22 @@ else skb->sk->wmem_alloc-=skb->mem_len; if(!skb->sk->dead) - wake_up_interruptible(skb->sk->sleep); + skb->sk->write_space(skb->sk); +#ifdef CONFIG_SLAVE_BALANCING + if(skb->in_dev_queue && skb->dev!=NULL) + skb->dev->pkt_queue--; +#endif kfree_skbmem(skb->mem_addr,skb->mem_len); } } else + { +#ifdef CONFIG_SLAVE_BALANCING + if(skb->in_dev_queue && skb->dev!=NULL) + skb->dev->pkt_queue--; +#endif kfree_skbmem(skb->mem_addr, skb->mem_len); + } } /* @@ -457,6 +467,9 @@ skb->truesize = size; skb->mem_len = size; skb->mem_addr = skb; +#ifdef CONFIG_SLAVE_BALANCING + skb->in_dev_queue = 0; +#endif skb->fraglist = NULL; skb->prev = skb->next = NULL; skb->link3 = NULL; @@ -477,8 +490,19 @@ void kfree_skbmem(void *mem,unsigned size) { +#ifdef CONFIG_SLAVE_BALANCING + struct sk_buff *x = mem; + unsigned long flags; + save_flags(flags); + cli(); + if(x->in_dev_queue && x->dev!=NULL) + x->dev->pkt_queue--; + restore_flags(flags); +#endif #if CONFIG_SKB_CHECK +#ifndef CONFIG_SLAVE_BALANCING struct sk_buff *x = mem; +#endif IS_SKB(x); if(x->magic_debug_cookie == SK_GOOD_SKB) { diff -u --recursive --new-file v1.1.12/linux/net/inet/sock.c linux/net/inet/sock.c --- v1.1.12/linux/net/inet/sock.c Mon May 23 12:14:27 1994 +++ linux/net/inet/sock.c Mon May 23 08:17:51 1994 @@ -3,13 +3,16 @@ * operating system. INET is implemented using the BSD Socket * interface as the means of communication with the user level. * - * SOCK - AF_INET protocol family socket handler. + * Generic socket support routines. Memory allocators, sk->inuse/release + * handler for protocols to use and generic option handler. * + * * Version: @(#)sock.c 1.0.17 06/02/93 * * Authors: Ross Biro, * Fred N. van Kempen, * Florian La Roche, + * Alan Cox, * * Fixes: * Alan Cox : Numerous verify_area() problems @@ -53,6 +56,10 @@ * Alan Cox : Callbacks * Alan Cox : Nagle flag for Charles & Johannes stuff * Alex : Removed restriction on inet fioctl + * Alan Cox : Splitting INET from NET core + * Alan Cox : Fixed bogus SO_TYPE handling in getsockopt() + * Adam Caldwell : Missing return in SO_DONTROUTE/SO_DEBUG code + * Alan Cox : Split IP from generic code * * To Fix: * @@ -96,373 +103,8 @@ #include "raw.h" #include "icmp.h" - -int inet_debug = DBG_OFF; /* INET module debug flag */ - - #define min(a,b) ((a)<(b)?(a):(b)) -extern struct proto packet_prot; - - -void -print_sk(struct sock *sk) -{ - if (!sk) { - printk(" print_sk(NULL)\n"); - return; - } - printk(" wmem_alloc = %lu\n", sk->wmem_alloc); - printk(" rmem_alloc = %lu\n", sk->rmem_alloc); - printk(" state = %d\n",sk->state); - printk(" daddr = %lX, saddr = %lX\n", sk->daddr,sk->saddr); - printk(" num = %d", sk->num); - printk(" next = %p\n", sk->next); - printk(" write_seq = %ld, acked_seq = %ld, copied_seq = %ld\n", - sk->write_seq, sk->acked_seq, sk->copied_seq); - printk(" rcv_ack_seq = %ld, window_seq = %ld, fin_seq = %ld\n", - sk->rcv_ack_seq, sk->window_seq, sk->fin_seq); - printk(" prot = %p\n", sk->prot); - printk(" pair = %p\n", sk->pair); - printk(" inuse = %d , blog = %d\n", sk->inuse, sk->blog); - printk(" dead = %d delay_acks=%d\n", sk->dead, sk->delay_acks); - printk(" retransmits = %ld, timeout = %d\n", sk->retransmits, sk->timeout); - printk(" cong_window = %d, packets_out = %d\n", sk->cong_window, - sk->packets_out); - printk(" shutdown=%d\n", sk->shutdown); -} - - -#if 0 -void -print_skb(struct sk_buff *skb) -{ - if (!skb) { - printk(" print_skb(NULL)\n"); - return; - } - printk(" prev = %p, next = %p\n", skb->prev, skb->next); - printk(" sk = %p link3 = %p\n", skb->sk, skb->link3); - printk(" mem_addr = %p, mem_len = %lu\n", skb->mem_addr, skb->mem_len); - printk(" used = %d free = %d\n", skb->used,skb->free); -} -#endif - - - -static int -sk_inuse(struct proto *prot, int num) -{ - struct sock *sk; - - for(sk = prot->sock_array[num & (SOCK_ARRAY_SIZE -1 )]; - sk != NULL; - sk=sk->next) { - if (sk->num == num) return(1); - } - return(0); -} - - -unsigned short -get_new_socknum(struct proto *prot, unsigned short base) -{ - static int start=0; - - /* - * Used to cycle through the port numbers so the - * chances of a confused connection drop. - */ - int i, j; - int best = 0; - int size = 32767; /* a big num. */ - struct sock *sk; - - if (base == 0) base = PROT_SOCK+1+(start % 1024); - if (base <= PROT_SOCK) { - base += PROT_SOCK+(start % 1024); - } - - /* Now look through the entire array and try to find an empty ptr. */ - for(i=0; i < SOCK_ARRAY_SIZE; i++) { - j = 0; - sk = prot->sock_array[(i+base+1) &(SOCK_ARRAY_SIZE -1)]; - while(sk != NULL) { - sk = sk->next; - j++; - } - if (j == 0) { - start =(i+1+start )%1024; - DPRINTF((DBG_INET, "get_new_socknum returning %d, start = %d\n", - i + base + 1, start)); - return(i+base+1); - } - if (j < size) { - best = i; - size = j; - } - } - - /* Now make sure the one we want is not in use. */ - while(sk_inuse(prot, base +best+1)) { - best += SOCK_ARRAY_SIZE; - } - DPRINTF((DBG_INET, "get_new_socknum returning %d, start = %d\n", - best + base + 1, start)); - return(best+base+1); -} - - -void -put_sock(unsigned short num, struct sock *sk) -{ - struct sock *sk1; - struct sock *sk2; - int mask; - - DPRINTF((DBG_INET, "put_sock(num = %d, sk = %X\n", num, sk)); - sk->num = num; - sk->next = NULL; - num = num &(SOCK_ARRAY_SIZE -1); - - /* We can't have an interupt re-enter here. */ - cli(); - if (sk->prot->sock_array[num] == NULL) { - sk->prot->sock_array[num] = sk; - sti(); - return; - } - sti(); - for(mask = 0xff000000; mask != 0xffffffff; mask = (mask >> 8) | mask) { - if ((mask & sk->saddr) && - (mask & sk->saddr) != (mask & 0xffffffff)) { - mask = mask << 8; - break; - } - } - DPRINTF((DBG_INET, "mask = %X\n", mask)); - - cli(); - sk1 = sk->prot->sock_array[num]; - for(sk2 = sk1; sk2 != NULL; sk2=sk2->next) { - if (!(sk2->saddr & mask)) { - if (sk2 == sk1) { - sk->next = sk->prot->sock_array[num]; - sk->prot->sock_array[num] = sk; - sti(); - return; - } - sk->next = sk2; - sk1->next= sk; - sti(); - return; - } - sk1 = sk2; - } - - /* Goes at the end. */ - sk->next = NULL; - sk1->next = sk; - sti(); -} - - -static void -remove_sock(struct sock *sk1) -{ - struct sock *sk2; - - DPRINTF((DBG_INET, "remove_sock(sk1=%X)\n", sk1)); - - if (!sk1->prot) { - printk("sock.c: remove_sock: sk1->prot == NULL\n"); - return; - } - - /* We can't have this changing out from under us. */ - cli(); - sk2 = sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)]; - if (sk2 == sk1) { - sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)] = sk1->next; - sti(); - return; - } - - while(sk2 && sk2->next != sk1) { - sk2 = sk2->next; - } - - if (sk2) { - sk2->next = sk1->next; - sti(); - return; - } - sti(); - - if (sk1->num != 0) DPRINTF((DBG_INET, "remove_sock: sock not found.\n")); -} - - -void -destroy_sock(struct sock *sk) -{ - struct sk_buff *skb; - - DPRINTF((DBG_INET, "destroying socket %X\n", sk)); - sk->inuse = 1; /* just to be safe. */ - - /* Incase it's sleeping somewhere. */ - if (!sk->dead) - sk->write_space(sk); - - remove_sock(sk); - - /* Now we can no longer get new packets. */ - delete_timer(sk); - - while ((skb = tcp_dequeue_partial(sk)) != NULL) { - IS_SKB(skb); - kfree_skb(skb, FREE_WRITE); - } - - /* Cleanup up the write buffer. */ - while((skb = skb_dequeue(&sk->write_queue)) != NULL) { - IS_SKB(skb); - kfree_skb(skb, FREE_WRITE); - } - - while((skb=skb_dequeue(&sk->receive_queue))!=NULL) { - /* - * This will take care of closing sockets that were - * listening and didn't accept everything. - */ - if (skb->sk != NULL && skb->sk != sk) - { - IS_SKB(skb); - skb->sk->dead = 1; - skb->sk->prot->close(skb->sk, 0); - } - IS_SKB(skb); - kfree_skb(skb, FREE_READ); - } - - /* Now we need to clean up the send head. */ - cli(); - for(skb = sk->send_head; skb != NULL; ) - { - struct sk_buff *skb2; - - /* - * We need to remove skb from the transmit queue, - * or maybe the arp queue. - */ - if (skb->next && skb->prev) { - printk("destroy_sock: unlinked skb\n"); - IS_SKB(skb); - skb_unlink(skb); - } - skb->dev = NULL; - skb2 = skb->link3; - kfree_skb(skb, FREE_WRITE); - skb = skb2; - } - sk->send_head = NULL; - sti(); - - /* And now the backlog. */ - while((skb=skb_dequeue(&sk->back_log))!=NULL) { - /* this should never happen. */ - printk("cleaning back_log\n"); - kfree_skb(skb, FREE_READ); - } - - /* Now if it has a half accepted/ closed socket. */ - if (sk->pair) - { - sk->pair->dead = 1; - sk->pair->prot->close(sk->pair, 0); - sk->pair = NULL; - } - - /* - * Now if everything is gone we can free the socket - * structure, otherwise we need to keep it around until - * everything is gone. - */ - if (sk->dead && sk->rmem_alloc == 0 && sk->wmem_alloc == 0) - { - kfree_s((void *)sk,sizeof(*sk)); - } - else - { - /* this should never happen. */ - /* actually it can if an ack has just been sent. */ - DPRINTF((DBG_INET, "possible memory leak in socket = %X\n", sk)); - sk->destroy = 1; - sk->ack_backlog = 0; - sk->inuse = 0; - reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME); - } - DPRINTF((DBG_INET, "leaving destroy_sock\n")); -} - - -static int -inet_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - struct sock *sk; - - sk = (struct sock *) sock->data; - - switch(cmd) { - case F_SETOWN: - /* - * This is a little restrictive, but it's the only - * way to make sure that you can't send a sigurg to - * another process. - */ - if (!suser() && current->pgrp != -arg && - current->pid != arg) return(-EPERM); - sk->proc = arg; - return(0); - case F_GETOWN: - return(sk->proc); - default: - return(-EINVAL); - } -} - -/* - * Set socket options on an inet socket. - */ - -static int inet_setsockopt(struct socket *sock, int level, int optname, - char *optval, int optlen) -{ - struct sock *sk = (struct sock *) sock->data; - if (level == SOL_SOCKET) - return sock_setsockopt(sk,level,optname,optval,optlen); - if (sk->prot->setsockopt==NULL) - return(-EOPNOTSUPP); - else - return sk->prot->setsockopt(sk,level,optname,optval,optlen); -} - - - - -static int inet_getsockopt(struct socket *sock, int level, int optname, - char *optval, int *optlen) -{ - struct sock *sk = (struct sock *) sock->data; - if (level == SOL_SOCKET) - return sock_getsockopt(sk,level,optname,optval,optlen); - if(sk->prot->getsockopt==NULL) - return(-EOPNOTSUPP); - else - return sk->prot->getsockopt(sk,level,optname,optval,optlen); -} - /* * This is meant for all protocols to use and covers goings on * at the socket level. Everything here is generic. @@ -491,9 +133,10 @@ case SO_DEBUG: sk->debug=val?1:0; + return 0; case SO_DONTROUTE: sk->localroute=val?1:0; - return(0); + return 0; case SO_BROADCAST: sk->broadcast=val?1:0; return 0; @@ -621,10 +264,13 @@ break; case SO_TYPE: +#if 0 if (sk->prot == &tcp_prot) val = SOCK_STREAM; else val = SOCK_DGRAM; +#endif + val = sk->type; break; case SO_ERROR: @@ -661,866 +307,6 @@ } - - -static int -inet_listen(struct socket *sock, int backlog) -{ - struct sock *sk; - - sk = (struct sock *) sock->data; - if (sk == NULL) { - printk("Warning: sock->data = NULL: %d\n" ,__LINE__); - return(0); - } - - /* We may need to bind the socket. */ - if (sk->num == 0) { - sk->num = get_new_socknum(sk->prot, 0); - if (sk->num == 0) return(-EAGAIN); - put_sock(sk->num, sk); - sk->dummy_th.source = ntohs(sk->num); - } - - /* We might as well re use these. */ - sk->max_ack_backlog = backlog; - if (sk->state != TCP_LISTEN) { - sk->ack_backlog = 0; - sk->state = TCP_LISTEN; - } - return(0); -} - -/* - * Default callbacks for user INET sockets. These just wake up - * the user owning the socket. - */ - -static void def_callback1(struct sock *sk) -{ - if(!sk->dead) - wake_up_interruptible(sk->sleep); -} - -static void def_callback2(struct sock *sk,int len) -{ - if(!sk->dead) - wake_up_interruptible(sk->sleep); -} - - -static int -inet_create(struct socket *sock, int protocol) -{ - struct sock *sk; - struct proto *prot; - int err; - - sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL); - if (sk == NULL) - return(-ENOMEM); - sk->num = 0; - sk->reuse = 0; - switch(sock->type) { - case SOCK_STREAM: - case SOCK_SEQPACKET: - if (protocol && protocol != IPPROTO_TCP) { - kfree_s((void *)sk, sizeof(*sk)); - return(-EPROTONOSUPPORT); - } - protocol = IPPROTO_TCP; - sk->no_check = TCP_NO_CHECK; - prot = &tcp_prot; - break; - - case SOCK_DGRAM: - if (protocol && protocol != IPPROTO_UDP) { - kfree_s((void *)sk, sizeof(*sk)); - return(-EPROTONOSUPPORT); - } - protocol = IPPROTO_UDP; - sk->no_check = UDP_NO_CHECK; - prot=&udp_prot; - break; - - case SOCK_RAW: - if (!suser()) { - kfree_s((void *)sk, sizeof(*sk)); - return(-EPERM); - } - if (!protocol) { - kfree_s((void *)sk, sizeof(*sk)); - return(-EPROTONOSUPPORT); - } - prot = &raw_prot; - sk->reuse = 1; - sk->no_check = 0; /* - * Doesn't matter no checksum is - * preformed anyway. - */ - sk->num = protocol; - break; - - case SOCK_PACKET: - if (!suser()) { - kfree_s((void *)sk, sizeof(*sk)); - return(-EPERM); - } - if (!protocol) { - kfree_s((void *)sk, sizeof(*sk)); - return(-EPROTONOSUPPORT); - } - prot = &packet_prot; - sk->reuse = 1; - sk->no_check = 0; /* Doesn't matter no checksum is - * preformed anyway. - */ - sk->num = protocol; - break; - - default: - kfree_s((void *)sk, sizeof(*sk)); - return(-ESOCKTNOSUPPORT); - } - sk->socket = sock; -#ifdef CONFIG_TCP_NAGLE_OFF - sk->nonagle = 1; -#else - sk->nonagle = 0; -#endif - sk->type = sock->type; - sk->stamp.tv_sec=0; - sk->protocol = protocol; - sk->wmem_alloc = 0; - sk->rmem_alloc = 0; - sk->sndbuf = SK_WMEM_MAX; - sk->rcvbuf = SK_RMEM_MAX; - sk->pair = NULL; - sk->opt = NULL; - sk->write_seq = 0; - sk->acked_seq = 0; - sk->copied_seq = 0; - sk->fin_seq = 0; - sk->urg_seq = 0; - sk->urg_data = 0; - sk->proc = 0; - sk->rtt = TCP_WRITE_TIME << 3; - sk->rto = TCP_WRITE_TIME; - sk->mdev = 0; - sk->backoff = 0; - sk->packets_out = 0; - sk->cong_window = 1; /* start with only sending one packet at a time. */ - sk->cong_count = 0; - sk->ssthresh = 0; - sk->max_window = 0; - sk->urginline = 0; - sk->intr = 0; - sk->linger = 0; - sk->destroy = 0; - - sk->priority = 1; - sk->shutdown = 0; - sk->keepopen = 0; - sk->zapped = 0; - sk->done = 0; - sk->ack_backlog = 0; - sk->window = 0; - sk->bytes_rcv = 0; - sk->state = TCP_CLOSE; - sk->dead = 0; - sk->ack_timed = 0; - sk->partial = NULL; - sk->user_mss = 0; - sk->debug = 0; - - /* this is how many unacked bytes we will accept for this socket. */ - sk->max_unacked = 2048; /* needs to be at most 2 full packets. */ - - /* how many packets we should send before forcing an ack. - if this is set to zero it is the same as sk->delay_acks = 0 */ - sk->max_ack_backlog = 0; - sk->inuse = 0; - sk->delay_acks = 0; - skb_queue_head_init(&sk->write_queue); - skb_queue_head_init(&sk->receive_queue); - sk->mtu = 576; - sk->prot = prot; - sk->sleep = sock->wait; - sk->daddr = 0; - sk->saddr = ip_my_addr(); - sk->err = 0; - sk->next = NULL; - sk->pair = NULL; - sk->send_tail = NULL; - sk->send_head = NULL; - sk->timeout = 0; - sk->broadcast = 0; - sk->localroute = 0; - sk->timer.data = (unsigned long)sk; - sk->timer.function = &net_timer; - skb_queue_head_init(&sk->back_log); - sk->blog = 0; - sock->data =(void *) sk; - sk->dummy_th.doff = sizeof(sk->dummy_th)/4; - sk->dummy_th.res1=0; - sk->dummy_th.res2=0; - sk->dummy_th.urg_ptr = 0; - sk->dummy_th.fin = 0; - sk->dummy_th.syn = 0; - sk->dummy_th.rst = 0; - sk->dummy_th.psh = 0; - sk->dummy_th.ack = 0; - sk->dummy_th.urg = 0; - sk->dummy_th.dest = 0; - - sk->ip_tos=0; - sk->ip_ttl=64; - - sk->state_change = def_callback1; - sk->data_ready = def_callback2; - sk->write_space = def_callback1; - sk->error_report = def_callback1; - - if (sk->num) { - /* - * It assumes that any protocol which allows - * the user to assign a number at socket - * creation time automatically - * shares. - */ - put_sock(sk->num, sk); - sk->dummy_th.source = ntohs(sk->num); - } - - if (sk->prot->init) { - err = sk->prot->init(sk); - if (err != 0) { - destroy_sock(sk); - return(err); - } - } - return(0); -} - - -static int -inet_dup(struct socket *newsock, struct socket *oldsock) -{ - return(inet_create(newsock, - ((struct sock *)(oldsock->data))->protocol)); -} - - -/* The peer socket should always be NULL. */ -static int -inet_release(struct socket *sock, struct socket *peer) -{ - struct sock *sk; - - sk = (struct sock *) sock->data; - if (sk == NULL) return(0); - - DPRINTF((DBG_INET, "inet_release(sock = %X, peer = %X)\n", sock, peer)); - sk->state_change(sk); - - /* Start closing the connection. This may take a while. */ - /* - * If linger is set, we don't return until the close - * is complete. Other wise we return immediately. The - * actually closing is done the same either way. - */ - if (sk->linger == 0) { - sk->prot->close(sk,0); - sk->dead = 1; - } else { - DPRINTF((DBG_INET, "sk->linger set.\n")); - sk->prot->close(sk, 0); - cli(); - if (sk->lingertime) - current->timeout = jiffies + HZ*sk->lingertime; - while(sk->state != TCP_CLOSE && current->timeout>0) { - interruptible_sleep_on(sk->sleep); - if (current->signal & ~current->blocked) { - break; -#if 0 - /* not working now - closes can't be restarted */ - sti(); - current->timeout=0; - return(-ERESTARTSYS); -#endif - } - } - current->timeout=0; - sti(); - sk->dead = 1; - } - sk->inuse = 1; - - /* This will destroy it. */ - release_sock(sk); - sock->data = NULL; - DPRINTF((DBG_INET, "inet_release returning\n")); - return(0); -} - - -/* this needs to be changed to dissallow - the rebinding of sockets. What error - should it return? */ - -static int -inet_bind(struct socket *sock, struct sockaddr *uaddr, - int addr_len) -{ - struct sockaddr_in addr; - struct sock *sk, *sk2; - unsigned short snum; - int err; - int chk_addr_ret; - - sk = (struct sock *) sock->data; - /* check this error. */ - if (sk->state != TCP_CLOSE) return(-EIO); - if (sk->num != 0) return(-EINVAL); - - err=verify_area(VERIFY_READ, uaddr, addr_len); - if(err) - return err; - memcpy_fromfs(&addr, uaddr, min(sizeof(addr), addr_len)); - - snum = ntohs(addr.sin_port); - DPRINTF((DBG_INET, "bind sk =%X to port = %d\n", sk, snum)); - sk = (struct sock *) sock->data; - - /* - * We can't just leave the socket bound wherever it is, it might - * be bound to a privileged port. However, since there seems to - * be a bug here, we will leave it if the port is not privileged. - */ - if (snum == 0) { - snum = get_new_socknum(sk->prot, 0); - } - if (snum < PROT_SOCK && !suser()) return(-EACCES); - - chk_addr_ret = ip_chk_addr(addr.sin_addr.s_addr); - if (addr.sin_addr.s_addr != 0 && chk_addr_ret != IS_MYADDR) - return(-EADDRNOTAVAIL); /* Source address MUST be ours! */ - - if (chk_addr_ret || addr.sin_addr.s_addr == 0) - sk->saddr = addr.sin_addr.s_addr; - - DPRINTF((DBG_INET, "sock_array[%d] = %X:\n", snum &(SOCK_ARRAY_SIZE -1), - sk->prot->sock_array[snum &(SOCK_ARRAY_SIZE -1)])); - - /* Make sure we are allowed to bind here. */ - cli(); -outside_loop: - for(sk2 = sk->prot->sock_array[snum & (SOCK_ARRAY_SIZE -1)]; - sk2 != NULL; sk2 = sk2->next) { -#if 1 /* should be below! */ - if (sk2->num != snum) continue; -/* if (sk2->saddr != sk->saddr) continue; */ -#endif - if (sk2->dead) { - destroy_sock(sk2); - goto outside_loop; - } - if (!sk->reuse) { - sti(); - return(-EADDRINUSE); - } - if (sk2->num != snum) continue; /* more than one */ - if (sk2->saddr != sk->saddr) continue; /* socket per slot ! -FB */ - if (!sk2->reuse) { - sti(); - return(-EADDRINUSE); - } - } - sti(); - - remove_sock(sk); - put_sock(snum, sk); - sk->dummy_th.source = ntohs(sk->num); - sk->daddr = 0; - sk->dummy_th.dest = 0; - return(0); -} - - -static int -inet_connect(struct socket *sock, struct sockaddr * uaddr, - int addr_len, int flags) -{ - struct sock *sk; - int err; - - sock->conn = NULL; - sk = (struct sock *) sock->data; - - if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED) - { - sock->state = SS_CONNECTED; - /* Connection completing after a connect/EINPROGRESS/select/connect */ - return 0; /* Rock and roll */ - } - - if (sock->state == SS_CONNECTING && sk->protocol == IPPROTO_TCP && - (flags & O_NONBLOCK)) - return -EALREADY; /* Connecting is currently in progress */ - - if (sock->state != SS_CONNECTING) { - /* We may need to bind the socket. */ - if (sk->num == 0) { - sk->num = get_new_socknum(sk->prot, 0); - if (sk->num == 0) - return(-EAGAIN); - put_sock(sk->num, sk); - sk->dummy_th.source = htons(sk->num); - } - - if (sk->prot->connect == NULL) - return(-EOPNOTSUPP); - - err = sk->prot->connect(sk, (struct sockaddr_in *)uaddr, addr_len); - if (err < 0) return(err); - - sock->state = SS_CONNECTING; - } - - if (sk->state != TCP_ESTABLISHED &&(flags & O_NONBLOCK)) - return(-EINPROGRESS); - - cli(); /* avoid the race condition */ - while(sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) - { - interruptible_sleep_on(sk->sleep); - if (current->signal & ~current->blocked) { - sti(); - return(-ERESTARTSYS); - } - /* This fixes a nasty in the tcp/ip code. There is a hideous hassle with - icmp error packets wanting to close a tcp or udp socket. */ - if(sk->err && sk->protocol == IPPROTO_TCP) - { - sti(); - sock->state = SS_UNCONNECTED; - err = -sk->err; - sk->err=0; - return err; /* set by tcp_err() */ - } - } - sti(); - sock->state = SS_CONNECTED; - - if (sk->state != TCP_ESTABLISHED && sk->err) { - sock->state = SS_UNCONNECTED; - err=sk->err; - sk->err=0; - return(-err); - } - return(0); -} - - -static int -inet_socketpair(struct socket *sock1, struct socket *sock2) -{ - return(-EOPNOTSUPP); -} - - -static int -inet_accept(struct socket *sock, struct socket *newsock, int flags) -{ - struct sock *sk1, *sk2; - int err; - - sk1 = (struct sock *) sock->data; - - /* - * We've been passed an extra socket. - * We need to free it up because the tcp module creates - * it's own when it accepts one. - */ - if (newsock->data) - { - struct sock *sk=(struct sock *)newsock->data; - newsock->data=NULL; - sk->dead = 1; - destroy_sock(sk); - } - - if (sk1->prot->accept == NULL) return(-EOPNOTSUPP); - - /* Restore the state if we have been interrupted, and then returned. */ - if (sk1->pair != NULL ) { - sk2 = sk1->pair; - sk1->pair = NULL; - } else { - sk2 = sk1->prot->accept(sk1,flags); - if (sk2 == NULL) { - if (sk1->err <= 0) - printk("Warning sock.c:sk1->err <= 0. Returning non-error.\n"); - err=sk1->err; - sk1->err=0; - return(-err); - } - } - newsock->data = (void *)sk2; - sk2->sleep = newsock->wait; - newsock->conn = NULL; - if (flags & O_NONBLOCK) return(0); - - cli(); /* avoid the race. */ - while(sk2->state == TCP_SYN_RECV) { - interruptible_sleep_on(sk2->sleep); - if (current->signal & ~current->blocked) { - sti(); - sk1->pair = sk2; - sk2->sleep = NULL; - newsock->data = NULL; - return(-ERESTARTSYS); - } - } - sti(); - - if (sk2->state != TCP_ESTABLISHED && sk2->err > 0) { - - err = -sk2->err; - sk2->err=0; - destroy_sock(sk2); - newsock->data = NULL; - return(err); - } - newsock->state = SS_CONNECTED; - return(0); -} - - -static int -inet_getname(struct socket *sock, struct sockaddr *uaddr, - int *uaddr_len, int peer) -{ - struct sockaddr_in sin; - struct sock *sk; - int len; - int err; - - - err = verify_area(VERIFY_WRITE,uaddr_len,sizeof(long)); - if(err) - return err; - - len=get_fs_long(uaddr_len); - - err = verify_area(VERIFY_WRITE, uaddr, len); - if(err) - return err; - - /* Check this error. */ - if (len < sizeof(sin)) return(-EINVAL); - - sin.sin_family = AF_INET; - sk = (struct sock *) sock->data; - if (sk == NULL) { - printk("Warning: sock->data = NULL: %d\n" ,__LINE__); - return(0); - } - if (peer) { - if (!tcp_connected(sk->state)) return(-ENOTCONN); - sin.sin_port = sk->dummy_th.dest; - sin.sin_addr.s_addr = sk->daddr; - } else { - sin.sin_port = sk->dummy_th.source; - if (sk->saddr == 0) sin.sin_addr.s_addr = ip_my_addr(); - else sin.sin_addr.s_addr = sk->saddr; - } - len = sizeof(sin); -/* verify_area(VERIFY_WRITE, uaddr, len); NOW DONE ABOVE */ - memcpy_tofs(uaddr, &sin, sizeof(sin)); -/* verify_area(VERIFY_WRITE, uaddr_len, sizeof(len)); NOW DONE ABOVE */ - put_fs_long(len, uaddr_len); - return(0); -} - - -static int -inet_read(struct socket *sock, char *ubuf, int size, int noblock) -{ - struct sock *sk; - - sk = (struct sock *) sock->data; - - /* We may need to bind the socket. */ - if (sk->num == 0) { - sk->num = get_new_socknum(sk->prot, 0); - if (sk->num == 0) return(-EAGAIN); - put_sock(sk->num, sk); - sk->dummy_th.source = ntohs(sk->num); - } - return(sk->prot->read(sk, (unsigned char *) ubuf, size, noblock,0)); -} - - -static int -inet_recv(struct socket *sock, void *ubuf, int size, int noblock, - unsigned flags) -{ - struct sock *sk; - - sk = (struct sock *) sock->data; - - /* We may need to bind the socket. */ - if (sk->num == 0) { - sk->num = get_new_socknum(sk->prot, 0); - if (sk->num == 0) return(-EAGAIN); - put_sock(sk->num, sk); - sk->dummy_th.source = ntohs(sk->num); - } - return(sk->prot->read(sk, (unsigned char *) ubuf, size, noblock, flags)); -} - - -static int -inet_write(struct socket *sock, char *ubuf, int size, int noblock) -{ - struct sock *sk; - - sk = (struct sock *) sock->data; - if (sk->shutdown & SEND_SHUTDOWN) { - send_sig(SIGPIPE, current, 1); - return(-EPIPE); - } - - /* We may need to bind the socket. */ - if (sk->num == 0) { - sk->num = get_new_socknum(sk->prot, 0); - if (sk->num == 0) return(-EAGAIN); - put_sock(sk->num, sk); - sk->dummy_th.source = ntohs(sk->num); - } - - return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, 0)); -} - - -static int -inet_send(struct socket *sock, void *ubuf, int size, int noblock, - unsigned flags) -{ - struct sock *sk; - - sk = (struct sock *) sock->data; - if (sk->shutdown & SEND_SHUTDOWN) { - send_sig(SIGPIPE, current, 1); - return(-EPIPE); - } - - /* We may need to bind the socket. */ - if (sk->num == 0) { - sk->num = get_new_socknum(sk->prot, 0); - if (sk->num == 0) return(-EAGAIN); - put_sock(sk->num, sk); - sk->dummy_th.source = ntohs(sk->num); - } - - return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, flags)); -} - - -static int -inet_sendto(struct socket *sock, void *ubuf, int size, int noblock, - unsigned flags, struct sockaddr *sin, int addr_len) -{ - struct sock *sk; - - sk = (struct sock *) sock->data; - if (sk->shutdown & SEND_SHUTDOWN) { - send_sig(SIGPIPE, current, 1); - return(-EPIPE); - } - - if (sk->prot->sendto == NULL) return(-EOPNOTSUPP); - - /* We may need to bind the socket. */ - if (sk->num == 0) { - sk->num = get_new_socknum(sk->prot, 0); - if (sk->num == 0) return(-EAGAIN); - put_sock(sk->num, sk); - sk->dummy_th.source = ntohs(sk->num); - } - - return(sk->prot->sendto(sk, (unsigned char *) ubuf, size, noblock, flags, - (struct sockaddr_in *)sin, addr_len)); -} - - -static int -inet_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, - unsigned flags, struct sockaddr *sin, int *addr_len ) -{ - struct sock *sk; - - sk = (struct sock *) sock->data; - - if (sk->prot->recvfrom == NULL) return(-EOPNOTSUPP); - - /* We may need to bind the socket. */ - if (sk->num == 0) { - sk->num = get_new_socknum(sk->prot, 0); - if (sk->num == 0) return(-EAGAIN); - put_sock(sk->num, sk); - sk->dummy_th.source = ntohs(sk->num); - } - - return(sk->prot->recvfrom(sk, (unsigned char *) ubuf, size, noblock, flags, - (struct sockaddr_in*)sin, addr_len)); -} - - -static int -inet_shutdown(struct socket *sock, int how) -{ - struct sock *sk; - - /* - * This should really check to make sure - * the socket is a TCP socket. - */ - how++; /* maps 0->1 has the advantage of making bit 1 rcvs and - 1->2 bit 2 snds. - 2->3 */ - if (how & ~SHUTDOWN_MASK) return(-EINVAL); - sk = (struct sock *) sock->data; - if (sk == NULL) { - printk("Warning: sock->data = NULL: %d\n" ,__LINE__); - return(0); - } - if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED) - sock->state = SS_CONNECTED; - - if (!tcp_connected(sk->state)) return(-ENOTCONN); - sk->shutdown |= how; - if (sk->prot->shutdown) sk->prot->shutdown(sk, how); - return(0); -} - - -static int -inet_select(struct socket *sock, int sel_type, select_table *wait ) -{ - struct sock *sk; - - sk = (struct sock *) sock->data; - - if (sk->prot->select == NULL) { - DPRINTF((DBG_INET, "select on non-selectable socket.\n")); - return(0); - } - return(sk->prot->select(sk, sel_type, wait)); -} - - -static int -inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - struct sock *sk; - int err; - - DPRINTF((DBG_INET, "INET: in inet_ioctl\n")); - sk = NULL; - if (sock && (sk = (struct sock *) sock->data) == NULL) { - printk("AF_INET: Warning: sock->data = NULL: %d\n" , __LINE__); - return(0); - } - - switch(cmd) { - case FIOSETOWN: - case SIOCSPGRP: - err=verify_area(VERIFY_READ,(int *)arg,sizeof(long)); - if(err) - return err; - if (sk) - sk->proc = get_fs_long((int *) arg); - return(0); - case FIOGETOWN: - case SIOCGPGRP: - if (sk) { - err=verify_area(VERIFY_WRITE,(void *) arg, sizeof(long)); - if(err) - return err; - put_fs_long(sk->proc,(int *)arg); - } - return(0); - - case SIOCGSTAMP: - if (sk) - { - if(sk->stamp.tv_sec==0) - return -ENOENT; - err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval)); - if(err) - return err; - memcpy_tofs((void *)arg,&sk->stamp,sizeof(struct timeval)); - return 0; - } - return -EINVAL; - -#if 0 /* FIXME: */ - case SIOCATMARK: - printk("AF_INET: ioctl(SIOCATMARK, 0x%08X)\n",(void *) arg); - return(-EINVAL); -#endif - - case DDIOCSDBG: - return(dbg_ioctl((void *) arg, DBG_INET)); - - case SIOCADDRT: case SIOCADDRTOLD: - case SIOCDELRT: case SIOCDELRTOLD: - return(ip_rt_ioctl(cmd,(void *) arg)); - - case SIOCDARP: - case SIOCGARP: - case SIOCSARP: - return(arp_ioctl(cmd,(void *) arg)); - - case SIOCDRARP: - case SIOCGRARP: - case SIOCSRARP: - return(rarp_ioctl(cmd,(void *) arg)); - - case SIOCGIFCONF: - case SIOCGIFFLAGS: - case SIOCSIFFLAGS: - case SIOCGIFADDR: - case SIOCSIFADDR: - case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: - case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: - case SIOCGIFNETMASK: - case SIOCSIFNETMASK: - case SIOCGIFMETRIC: - case SIOCSIFMETRIC: - case SIOCGIFMEM: - case SIOCSIFMEM: - case SIOCGIFMTU: - case SIOCSIFMTU: - case SIOCSIFLINK: - case SIOCGIFHWADDR: - case SIOCSIFHWADDR: - case OLD_SIOCGIFHWADDR: - return(dev_ioctl(cmd,(void *) arg)); - - default: - if (!sk || !sk->prot->ioctl) return(-EINVAL); - return(sk->prot->ioctl(sk, cmd, arg)); - } - /*NOTREACHED*/ - return(0); -} - - struct sk_buff * sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority) @@ -1535,8 +321,6 @@ } return c; } - DPRINTF((DBG_INET, "sock_wmalloc(%X,%d,%d,%d) returning NULL\n", - sk, size, force, priority)); return(NULL); } return(alloc_skb(size, priority)); @@ -1556,8 +340,6 @@ } return(c); } - DPRINTF((DBG_INET, "sock_rmalloc(%X,%d,%d,%d) returning NULL\n", - sk,size,force, priority)); return(NULL); } return(alloc_skb(size, priority)); @@ -1594,8 +376,6 @@ void sock_wfree(struct sock *sk, void *mem, unsigned long size) { - DPRINTF((DBG_INET, "sock_wfree(sk=%X, mem=%X, size=%d)\n", sk, mem, size)); - IS_SKB(mem); kfree_skbmem(mem, size); if (sk) { @@ -1603,10 +383,6 @@ /* In case it might be waiting for more memory. */ if (!sk->dead) sk->write_space(sk); - if (sk->destroy && sk->wmem_alloc == 0 && sk->rmem_alloc == 0) { - DPRINTF((DBG_INET, - "recovered lost memory, sock = %X\n", sk)); - } return; } } @@ -1615,60 +391,11 @@ void sock_rfree(struct sock *sk, void *mem, unsigned long size) { - DPRINTF((DBG_INET, "sock_rfree(sk=%X, mem=%X, size=%d)\n", sk, mem, size)); IS_SKB(mem); kfree_skbmem(mem, size); if (sk) { sk->rmem_alloc -= size; - if (sk->destroy && sk->wmem_alloc == 0 && sk->rmem_alloc == 0) { - DPRINTF((DBG_INET, - "recovered lot memory, sock = %X\n", sk)); - } - } -} - - -/* - * This routine must find a socket given a TCP or UDP header. - * Everyhting is assumed to be in net order. - */ -struct sock *get_sock(struct proto *prot, unsigned short num, - unsigned long raddr, - unsigned short rnum, unsigned long laddr) -{ - struct sock *s; - unsigned short hnum; - - hnum = ntohs(num); - DPRINTF((DBG_INET, "get_sock(prot=%X, num=%d, raddr=%X, rnum=%d, laddr=%X)\n", - prot, num, raddr, rnum, laddr)); - - /* - * SOCK_ARRAY_SIZE must be a power of two. This will work better - * than a prime unless 3 or more sockets end up using the same - * array entry. This should not be a problem because most - * well known sockets don't overlap that much, and for - * the other ones, we can just be careful about picking our - * socket number when we choose an arbitrary one. - */ - for(s = prot->sock_array[hnum & (SOCK_ARRAY_SIZE - 1)]; - s != NULL; s = s->next) - { - if (s->num != hnum) - continue; - if(s->dead && (s->state == TCP_CLOSE)) - continue; - if(prot == &udp_prot) - return s; - if(ip_addr_match(s->daddr,raddr)==0) - continue; - if (s->dummy_th.dest != rnum && s->dummy_th.dest != 0) - continue; - if(ip_addr_match(s->saddr,laddr) == 0) - continue; - return(s); } - return(NULL); } @@ -1680,170 +407,25 @@ return; if (sk->blog) return; - +#ifdef CONFIG_INET /* See if we have any packets built up. */ sk->inuse = 1; while((skb = skb_dequeue(&sk->back_log)) != NULL) { sk->blog = 1; - DPRINTF((DBG_INET, "release_sock: skb = %X:\n", skb)); if (sk->prot->rcv) sk->prot->rcv(skb, skb->dev, sk->opt, skb->saddr, skb->len, skb->daddr, 1, /* Only used for/by raw sockets. */ (struct inet_protocol *)sk->pair); } +#endif sk->blog = 0; sk->inuse = 0; +#ifdef CONFIG_INET if (sk->dead && sk->state == TCP_CLOSE) { /* Should be about 2 rtt's */ reset_timer(sk, TIME_DONE, min(sk->rtt * 2, TCP_DONE_TIME)); } -} - - -static int -inet_fioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int minor, ret; - - /* Extract the minor number on which we work. */ - minor = MINOR(inode->i_rdev); - - /* Now dispatch on the minor device. */ - switch(minor) { - case 0: /* INET */ - ret = inet_ioctl(NULL, cmd, arg); - break; - case 1: /* IP */ - ret = ip_ioctl(NULL, cmd, arg); - break; - case 2: /* ICMP */ - ret = icmp_ioctl(NULL, cmd, arg); - break; - case 3: /* TCP */ - ret = tcp_ioctl(NULL, cmd, arg); - break; - case 4: /* UDP */ - ret = udp_ioctl(NULL, cmd, arg); - break; - default: - ret = -ENODEV; - } - - return(ret); +#endif } - - -static struct file_operations inet_fops = { - NULL, /* LSEEK */ - NULL, /* READ */ - NULL, /* WRITE */ - NULL, /* READDIR */ - NULL, /* SELECT */ - inet_fioctl, /* IOCTL */ - NULL, /* MMAP */ - NULL, /* OPEN */ - NULL /* CLOSE */ -}; - - -static struct proto_ops inet_proto_ops = { - AF_INET, - - inet_create, - inet_dup, - inet_release, - inet_bind, - inet_connect, - inet_socketpair, - inet_accept, - inet_getname, - inet_read, - inet_write, - inet_select, - inet_ioctl, - inet_listen, - inet_send, - inet_recv, - inet_sendto, - inet_recvfrom, - inet_shutdown, - inet_setsockopt, - inet_getsockopt, - inet_fcntl, -}; - -extern unsigned long seq_offset; - -/* - * Called by ddi.c on kernel startup. - */ - -void inet_proto_init(struct ddi_proto *pro) -{ - struct inet_protocol *p; - int i; - - printk("Swansea University Computer Society NET3.012\n"); - /* - * Set up our UNIX VFS major device. (compatibility) - */ - - if (register_chrdev(AF_INET_MAJOR, "af_inet", &inet_fops) < 0) - { - printk("%s: cannot register major device %d!\n", - pro->name, AF_INET_MAJOR); - return; - } - - /* - * Tell SOCKET that we are alive... - */ - - (void) sock_register(inet_proto_ops.family, &inet_proto_ops); - - seq_offset = CURRENT_TIME*250; - - /* - * Add all the protocols. - */ - - for(i = 0; i < SOCK_ARRAY_SIZE; i++) - { - tcp_prot.sock_array[i] = NULL; - udp_prot.sock_array[i] = NULL; - raw_prot.sock_array[i] = NULL; - } - - printk("IP Protocols: "); - for(p = inet_protocol_base; p != NULL;) - { - struct inet_protocol *tmp; - - tmp = (struct inet_protocol *) p->next; - inet_add_protocol(p); - printk("%s%s",p->name,tmp?", ":"\n"); - p = tmp; - } - - /* - * Initialize the DEV module. - */ - dev_init(); - /* - * Set the ARP module up - */ - arp_init(); - /* - * Set the IP module up - */ - ip_init(); - - /* - * Initialize the "Buffer Head" pointers. - */ - - bh_base[INET_BH].routine = inet_bh; -} diff -u --recursive --new-file v1.1.12/linux/net/inet/tcp.c linux/net/inet/tcp.c --- v1.1.12/linux/net/inet/tcp.c Mon May 23 12:14:28 1994 +++ linux/net/inet/tcp.c Mon May 23 11:45:53 1994 @@ -69,6 +69,8 @@ * completely * Gerhard Koerting: Fixed some missing timer handling * Matthew Dillon : Reworked TCP machine states as per RFC + * Gerhard Koerting: PC/TCP workarounds + * Adam Caldwell : Assorted timer/timing errors * * * To Fix: @@ -135,6 +137,7 @@ #include "tcp.h" #include #include "sock.h" +#include "route.h" #include #include #include @@ -154,31 +157,6 @@ } -static void __print_th(struct tcphdr *th) -{ - unsigned char *ptr; - - printk("TCP header:\n"); - printk(" source=%d, dest=%d, seq =%ld, ack_seq = %ld\n", - ntohs(th->source), ntohs(th->dest), - ntohl(th->seq), ntohl(th->ack_seq)); - printk(" fin=%d, syn=%d, rst=%d, psh=%d, ack=%d, urg=%d res1=%d res2=%d\n", - th->fin, th->syn, th->rst, th->psh, th->ack, - th->urg, th->res1, th->res2); - printk(" window = %d, check = %d urg_ptr = %d\n", - ntohs(th->window), ntohs(th->check), ntohs(th->urg_ptr)); - printk(" doff = %d\n", th->doff); - ptr =(unsigned char *)(th + 1); - printk(" options = %d %d %d %d\n", ptr[0], ptr[1], ptr[2], ptr[3]); -} - -static inline void print_th(struct tcphdr *th) -{ - if (inet_debug == DBG_TCP) - __print_th(th); -} - - /* This routine picks a TCP windows for a socket based on the following constraints @@ -197,7 +175,7 @@ static int tcp_select_window(struct sock *sk) { int new_window = sk->prot->rspace(sk); - + /* * two things are going on here. First, we don't ever offer a * window less than min(sk->mss, MAX_WINDOW/2). This is the @@ -268,12 +246,9 @@ header+=4*iph->ihl; - DPRINTF((DBG_TCP, "TCP: tcp_err(%d, hdr=%X, daddr=%X saddr=%X, protocol=%X)\n", - err, header, daddr, saddr, protocol)); th =(struct tcphdr *)header; sk = get_sock(&tcp_prot, th->source/*dest*/, daddr, th->dest/*source*/, saddr); - print_th(th); if (sk == NULL) return; @@ -294,7 +269,6 @@ return; } - DPRINTF((DBG_TCP, "TCP: icmp_err got error\n")); sk->err = icmp_err_convert[err & 0xff].errno; /* @@ -326,7 +300,6 @@ int sum; unsigned long flags; - DPRINTF((DBG_TCP, "tcp_readable(sk=%X)\n", sk)); if(sk && sk->debug) printk("tcp_readable: %p - ",sk); @@ -362,7 +335,6 @@ (sk->urg_seq - sk->copied_seq) <= (counted - sk->copied_seq)) amount--; /* don't count urg data */ restore_flags(flags); - DPRINTF((DBG_TCP, "tcp readable returning %d bytes\n", amount)); if(sk->debug) printk("got %lu bytes.\n",amount); return(amount); @@ -377,9 +349,6 @@ static int tcp_select(struct sock *sk, int sel_type, select_table *wait) { - DPRINTF((DBG_TCP, "tcp_select(sk=%X, sel_type = %d, wait = %X)\n", - sk, sel_type, wait)); - sk->inuse = 1; switch(sel_type) { case SEL_IN: @@ -417,9 +386,6 @@ case SEL_OUT: select_wait(sk->sleep, wait); if (sk->shutdown & SEND_SHUTDOWN) { - DPRINTF((DBG_TCP, - "write select on shutdown socket.\n")); - /* FIXME: should this return an error? */ release_sock(sk); return(0); @@ -437,13 +403,6 @@ sk->state == TCP_SYN_SENT) return(0); return(1); } - DPRINTF((DBG_TCP, - "tcp_select: sleeping on write sk->wmem_alloc = %d, " - "sk->packets_out = %d\n" - "sk->write_seq = %u, sk->window_seq=%u\n", - sk->wmem_alloc, sk->packets_out, - sk->write_seq, sk->window_seq)); - release_sock(sk); return(0); case SEL_EX: @@ -465,10 +424,7 @@ tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) { int err; - DPRINTF((DBG_TCP, "tcp_ioctl(sk=%X, cmd = %d, arg=%X)\n", sk, cmd, arg)); switch(cmd) { - case DDIOCSDBG: - return(dbg_ioctl((void *) arg, DBG_TCP)); case TIOCINQ: #ifdef FIXME /* FIXME: */ @@ -482,7 +438,6 @@ sk->inuse = 1; amount = tcp_readable(sk); release_sock(sk); - DPRINTF((DBG_TCP, "returning %d\n", amount)); err=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long)); if(err) @@ -528,7 +483,6 @@ unsigned long sum; if (saddr == 0) saddr = ip_my_addr(); - print_th(th); __asm__("\t addl %%ecx,%%ebx\n" "\t adcl %%edx,%%ebx\n" "\t adcl $0, %%ebx\n" @@ -625,10 +579,6 @@ if (after(skb->h.seq, sk->window_seq) || (sk->retransmits && sk->timeout == TIME_WRITE) || sk->packets_out >= sk->cong_window) { - DPRINTF((DBG_TCP, "sk->cong_window = %d, sk->packets_out = %d\n", - sk->cong_window, sk->packets_out)); - DPRINTF((DBG_TCP, "sk->write_seq = %d, sk->window_seq = %d\n", - sk->write_seq, sk->window_seq)); if (skb->next != NULL) { printk("tcp_send_partial: next != NULL\n"); skb_unlink(skb); @@ -718,8 +668,6 @@ { reset_timer(sk, TIME_WRITE, 10); } - if (inet_debug == DBG_SLIP) - printk("\rtcp_ack: malloc failed\n"); return; } @@ -735,8 +683,6 @@ { buff->free=1; sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); - if (inet_debug == DBG_SLIP) - printk("\rtcp_ack: build_header failed\n"); return; } buff->len += tmp; @@ -823,9 +769,6 @@ struct proto *prot; struct device *dev = NULL; - DPRINTF((DBG_TCP, "tcp_write(sk=%X, from=%X, len=%d, nonblock=%d, flags=%X)\n", - sk, from, len, nonblock, flags)); - sk->inuse=1; prot = sk->prot; while(len > 0) @@ -874,7 +817,6 @@ if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV) { release_sock(sk); - DPRINTF((DBG_TCP, "tcp_write: return 1\n")); if (copied) return(copied); @@ -895,7 +837,6 @@ if (nonblock || copied) { release_sock(sk); - DPRINTF((DBG_TCP, "tcp_write: return 2\n")); if (copied) return(copied); return(-EAGAIN); @@ -911,7 +852,6 @@ if (current->signal & ~current->blocked) { sti(); - DPRINTF((DBG_TCP, "tcp_write: return 3\n")); if (copied) return(copied); return(-ERESTARTSYS); @@ -1027,7 +967,6 @@ if (nonblock /* || copied */) { release_sock(sk); - DPRINTF((DBG_TCP, "tcp_write: return 4\n")); if (copied) return(copied); return(-EAGAIN); @@ -1051,7 +990,6 @@ if (current->signal & ~current->blocked) { sti(); - DPRINTF((DBG_TCP, "tcp_write: return 5\n")); if (copied) return(copied); return(-ERESTARTSYS); @@ -1080,7 +1018,6 @@ { prot->wfree(sk, skb->mem_addr, skb->mem_len); release_sock(sk); - DPRINTF((DBG_TCP, "tcp_write: return 6\n")); if (copied) return(copied); return(tmp); @@ -1094,7 +1031,6 @@ { prot->wfree(sk, skb->mem_addr, skb->mem_len); release_sock(sk); - DPRINTF((DBG_TCP, "tcp_write: return 7\n")); if (copied) return(copied); return(tmp); @@ -1142,7 +1078,6 @@ tcp_send_partial(sk); release_sock(sk); - DPRINTF((DBG_TCP, "tcp_write: return 8\n")); return(copied); } @@ -1176,7 +1111,6 @@ struct tcphdr *t1; struct sk_buff *buff; - DPRINTF((DBG_TCP, "in tcp read wakeup\n")); if (!sk->ack_backlog) return; @@ -1284,9 +1218,6 @@ * TCP_WINDOW_DIFF. */ - DPRINTF((DBG_TCP, "sk->window left = %d, sk->prot->rspace(sk)=%d\n", - sk->window - sk->bytes_rcv, sk->prot->rspace(sk))); - if(sk->debug) printk("sk->rspace = %lu, was %d\n", sk->prot->rspace(sk), left); @@ -1396,18 +1327,7 @@ unsigned long peek_seq; unsigned long *seq; unsigned long used; - int err; - - if (len == 0) - return 0; - - if (len < 0) - return -EINVAL; - err = verify_area(VERIFY_WRITE, to, len); - if (err) - return err; - /* This error should be checked. */ if (sk->state == TCP_LISTEN) return -ENOTCONN; @@ -1527,7 +1447,6 @@ /* Clean up data we have read: This will do ACK frames */ cleanup_rbuf(sk); release_sock(sk); - DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied)); return copied; } @@ -1591,7 +1510,6 @@ return; sk->inuse = 1; - DPRINTF((DBG_TCP, "tcp_shutdown_send buff = %X\n", buff)); buff->sk = sk; buff->len = sizeof(*t1); buff->localroute = sk->localroute; @@ -1627,7 +1545,6 @@ sk->state = TCP_FIN_WAIT2; release_sock(sk); - DPRINTF((DBG_TCP, "Unable to build header for fin.\n")); return; } @@ -1736,7 +1653,6 @@ if (buff == NULL) return; - DPRINTF((DBG_TCP, "tcp_reset buff = %X\n", buff)); buff->len = sizeof(*t1); buff->sk = NULL; buff->dev = dev; @@ -1848,7 +1764,11 @@ if (! mss_seen) sk->mtu=min(sk->mtu, 536); /* default MSS if none sent */ } +#ifdef CONFIG_INET_PCTCP + sk->mss = min(sk->max_window >> 1, sk->mtu); +#else sk->mss = min(sk->max_window, sk->mtu); +#endif } static inline unsigned long default_mask(unsigned long dst) @@ -1880,10 +1800,7 @@ struct tcphdr *th; struct device *ndev=NULL; int tmp; - - DPRINTF((DBG_TCP, "tcp_conn_request(sk = %X, skb = %X, daddr = %X, sadd4= %X, \n" - " opt = %X, dev = %X)\n", - sk, skb, daddr, saddr, opt, dev)); + struct rtable *rt; th = skb->h.th; @@ -1891,7 +1808,6 @@ if (!sk->dead) { sk->data_ready(sk,0); } else { - DPRINTF((DBG_TCP, "tcp_conn_request on dead socket\n")); tcp_reset(daddr, saddr, th, sk->prot, opt, dev, sk->ip_tos,sk->ip_ttl); tcp_statistics.TcpAttemptFails++; kfree_skb(skb, FREE_READ); @@ -1923,15 +1839,14 @@ return; } - DPRINTF((DBG_TCP, "newsk = %X\n", newsk)); memcpy(newsk, sk, sizeof(*newsk)); skb_queue_head_init(&newsk->write_queue); skb_queue_head_init(&newsk->receive_queue); newsk->send_head = NULL; newsk->send_tail = NULL; skb_queue_head_init(&newsk->back_log); - newsk->rtt = TCP_CONNECT_TIME << 3; - newsk->rto = TCP_CONNECT_TIME; + newsk->rtt = 0; /*TCP_CONNECT_TIME<<3*/ + newsk->rto = TCP_TIMEOUT_INIT; newsk->mdev = 0; newsk->max_window = 0; newsk->cong_window = 1; @@ -1992,8 +1907,11 @@ /* use 512 or whatever user asked for */ /* note use of sk->user_mss, since user has no direct access to newsk */ + rt=ip_rt_route(saddr, NULL,NULL); if (sk->user_mss) newsk->mtu = sk->user_mss; + else if(rt!=NULL && (rt->rt_flags&RTF_MTU)) + newsk->mtu = rt->rt_mtu - HEADER_SIZE; else { #ifdef CONFIG_INET_SNARL /* Sub Nets ARe Local */ if ((saddr ^ daddr) & default_mask(saddr)) @@ -2075,7 +1993,7 @@ tcp_send_check(t1, daddr, saddr, sizeof(*t1)+4, newsk); newsk->prot->queue_xmit(newsk, dev, buff, 0); - reset_timer(newsk, TIME_WRITE /* -1 ? FIXME ??? */, TCP_CONNECT_TIME); + reset_timer(newsk, TIME_WRITE /* -1 ? FIXME ??? */, TCP_TIMEOUT_INIT); skb->sk = newsk; /* Charge the sock_buff to newsk. */ @@ -2102,7 +2020,6 @@ * We need to grab some memory, and put together a FIN, * and then put it into the queue to be sent. */ - DPRINTF((DBG_TCP, "tcp_close((struct sock *)%X, %d)\n",sk, timeout)); sk->inuse = 1; sk->keepopen = 1; sk->shutdown = SHUTDOWN_MASK; @@ -2231,7 +2148,6 @@ if(timeout) tcp_time_wait(sk); - DPRINTF((DBG_TCP, "Unable to build header for fin.\n")); release_sock(sk); return; } @@ -2302,8 +2218,6 @@ { struct sk_buff *skb; - DPRINTF((DBG_TCP, "tcp_write_xmit(sk=%X)\n", sk)); - /* The bytes will have to remain here. In time closedown will empty the write queue and all will be happy */ if(sk->zapped) @@ -2317,8 +2231,6 @@ && sk->packets_out < sk->cong_window) { IS_SKB(skb); skb_unlink(skb); - DPRINTF((DBG_TCP, "Sending a packet.\n")); - /* See if we really need to send the packet. */ if (before(skb->h.seq, sk->rcv_ack_seq +1)) { sk->retransmits = 0; @@ -2384,13 +2296,13 @@ return(1); /* Dead, cant ack any more so why bother */ ack = ntohl(th->ack_seq); - DPRINTF((DBG_TCP, "tcp_ack ack=%d, window=%d, " - "sk->rcv_ack_seq=%d, sk->window_seq = %d\n", - ack, ntohs(th->window), sk->rcv_ack_seq, sk->window_seq)); - if (ntohs(th->window) > sk->max_window) { sk->max_window = ntohs(th->window); +#ifdef CONFIG_INET_PCTCP + sk->mss = min(sk->max_window>>1, sk->mtu); +#else sk->mss = min(sk->max_window, sk->mtu); +#endif } if (sk->retransmits && sk->timeout == TIME_KEEPOPEN) @@ -2496,7 +2408,6 @@ } } - DPRINTF((DBG_TCP, "tcp_ack: Updating rcv ack sequence.\n")); sk->rcv_ack_seq = ack; /* @@ -2513,8 +2424,8 @@ sk->rto = ((sk->rtt >> 2) + sk->mdev) >> 1; if (sk->rto > 120*HZ) sk->rto = 120*HZ; - if (sk->rto < 1*HZ) - sk->rto = 1*HZ; + if (sk->rto < 2) /* Was 1*HZ */ + sk->rto = 2; } } @@ -2564,9 +2475,6 @@ /* We have one less packet out there. */ if (sk->packets_out > 0) sk->packets_out --; - DPRINTF((DBG_TCP, "skb=%X skb->h.seq = %d acked ack=%d\n", - sk->send_head, sk->send_head->h.seq, ack)); - /* Wake up the process, it can probably write more. */ if (!sk->dead) sk->write_space(sk); @@ -2583,6 +2491,8 @@ */ m = jiffies - oskb->when; /* RTT */ + if(m<=0) + m=1; /* IS THIS RIGHT FOR <0 ??? */ m -= (sk->rtt >> 3); /* m is now error in rtt est */ sk->rtt += m; /* rtt = 7/8 rtt + 1/8 new */ if (m < 0) @@ -2594,8 +2504,8 @@ sk->rto = ((sk->rtt >> 2) + sk->mdev) >> 1; if (sk->rto > 120*HZ) sk->rto = 120*HZ; - if (sk->rto < 1*HZ) - sk->rto = 1*HZ; + if (sk->rto < 2) /* Was 1*HZ */ + sk->rto = 2; sk->backoff = 0; } @@ -2642,7 +2552,6 @@ } else { if (sk->send_head == NULL && sk->ack_backlog == 0 && sk->state != TCP_TIME_WAIT && !sk->keepopen) { - DPRINTF((DBG_TCP, "Nothing to do, going to sleep.\n")); if (!sk->dead) sk->write_space(sk); if (sk->keepopen) @@ -2676,16 +2585,7 @@ if (sk->state == TCP_LAST_ACK) { if (!sk->dead) sk->state_change(sk); - DPRINTF((DBG_TCP, "TCP_LAST_ACK-A: %d/%d %d/%d ack/sent %d %d\n", - sk->rcv_ack_seq, - sk->write_seq, - sk->acked_seq, - sk->fin_seq, - ack, - sk->sent_seq - )); if (sk->rcv_ack_seq == sk->write_seq && sk->acked_seq == sk->fin_seq) { - DPRINTF((DBG_TCP, "tcp_ack closing socket - %X\n", sk)); flag |= 1; sk->state = TCP_CLOSE; sk->shutdown = SHUTDOWN_MASK; @@ -2763,7 +2663,6 @@ reset_timer(sk, TIME_WRITE, sk->rto); } - DPRINTF((DBG_TCP, "leaving tcp_ack\n")); return(1); } @@ -2782,11 +2681,8 @@ int dup_dumped=0; th = skb->h.th; - print_th(th); skb->len = len -(th->doff*4); - DPRINTF((DBG_TCP, "tcp_data len = %d sk = %X:\n", skb->len, sk)); - sk->bytes_rcv += skb->len; if (skb->len == 0 && !th->fin && !th->urg && !th->psh) { /* Don't want to keep passing ack's back and forth. */ @@ -2795,7 +2691,7 @@ return(0); } - if (sk->shutdown & RCV_SHUTDOWN) { + if (sk->shutdown & RCV_SHUTDOWN && skb->len!=0 /* Added AGC */) { sk->acked_seq = th->seq + skb->len + th->syn + th->fin; tcp_reset(sk->saddr, sk->daddr, skb->h.th, sk->prot, NULL, skb->dev, sk->ip_tos, sk->ip_ttl); @@ -2803,7 +2699,6 @@ sk->state = TCP_CLOSE; sk->err = EPIPE; sk->shutdown = SHUTDOWN_MASK; - DPRINTF((DBG_TCP, "tcp_data: closing socket - %X\n", sk)); kfree_skb(skb, FREE_READ); if (!sk->dead) sk->state_change(sk); return(0); @@ -2819,11 +2714,9 @@ /* This should start at the last one, and then go around forwards. */ if (skb_peek(&sk->receive_queue) == NULL) { - DPRINTF((DBG_TCP, "tcp_data: skb = %X:\n", skb)); skb_queue_head(&sk->receive_queue,skb); skb1= NULL; } else { - DPRINTF((DBG_TCP, "tcp_data adding to chain sk = %X:\n", sk)); for(skb1=sk->receive_queue.prev; ; skb1 = skb1->prev) { if(sk->debug) { @@ -2853,7 +2746,6 @@ break; } } - DPRINTF((DBG_TCP, "skb = %X:\n", skb)); } th->ack_seq = th->seq + skb->len; @@ -2973,16 +2865,12 @@ if(sk->debug) printk("Data wakeup.\n"); sk->data_ready(sk,0); - } else { - DPRINTF((DBG_TCP, "data received on dead socket.\n")); - } + } #ifdef NOTDEF /* say what? this is handled by tcp_ack() */ if (sk->state == TCP_FIN_WAIT2 && sk->acked_seq == sk->fin_seq && sk->rcv_ack_seq == sk->write_seq) { - DPRINTF((DBG_TCP, "tcp_data: entering last_ack state sk = %X\n", sk)); - /* tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr); */ sk->shutdown = SHUTDOWN_MASK; sk->state = TCP_LAST_ACK; @@ -3065,9 +2953,6 @@ static int tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th, unsigned long saddr, struct device *dev) { - DPRINTF((DBG_TCP, "tcp_fin(sk=%X, th=%X, saddr=%X, dev=%X)\n", - sk, th, saddr, dev)); - sk->fin_seq = th->seq + skb->len + th->syn + th->fin; if (!sk->dead) @@ -3152,9 +3037,6 @@ struct sock *newsk; struct sk_buff *skb; - DPRINTF((DBG_TCP, "tcp_accept(sk=%X, flags=%X, addr=%s)\n", - sk, flags, in_ntoa(sk->saddr))); - /* * We need to make sure that this socket is listening, * and that it has something pending. @@ -3209,6 +3091,7 @@ int tmp; struct tcphdr *t1; int err; + struct rtable *rt; if (sk->state != TCP_CLOSE) return(-EISCONN); @@ -3224,8 +3107,6 @@ if (sin.sin_family && sin.sin_family != AF_INET) return(-EAFNOSUPPORT); - DPRINTF((DBG_TCP, "TCP connect daddr=%s\n", in_ntoa(sin.sin_addr.s_addr))); - /* * connect() to INADDR_ANY means loopback (BSD'ism). */ @@ -3239,8 +3120,7 @@ if (ip_chk_addr(sin.sin_addr.s_addr) == IS_BROADCAST) { - DPRINTF((DBG_TCP, "TCP connection to broadcast address not allowed\n")); - return(-ENETUNREACH); + return -ENETUNREACH; } /* @@ -3275,6 +3155,9 @@ /* * Put in the IP header and routing stuff. */ + + rt=ip_rt_route(sk->daddr, NULL, NULL); + /* * We need to build the routing stuff fromt the things saved in skb. @@ -3310,6 +3193,8 @@ if (sk->user_mss) sk->mtu = sk->user_mss; + else if(rt!=NULL && rt->rt_flags&RTF_MTU) + sk->mtu = rt->rt_mtu; else { #ifdef SUBNETSARELOCAL @@ -3325,8 +3210,11 @@ * but not bigger than device MTU */ + if(sk->mtu <32) + sk->mtu = 32; /* Sanity limit */ + sk->mtu = min(sk->mtu, dev->mtu - HEADER_SIZE); - + /* * Put in the TCP options to say MTU. */ @@ -3344,8 +3232,9 @@ */ sk->state = TCP_SYN_SENT; - sk->rtt = TCP_CONNECT_TIME; - reset_timer(sk, TIME_WRITE, TCP_CONNECT_TIME); /* Timer for repeating the SYN until an answer */ +/* sk->rtt = TCP_CONNECT_TIME;*/ + sk->rto = TCP_TIMEOUT_INIT; + reset_timer(sk, TIME_WRITE, sk->rto); /* Timer for repeating the SYN until an answer */ sk->retransmits = TCP_RETR2 - TCP_SYN_RETRIES; sk->prot->queue_xmit(sk, dev, buff, 0); @@ -3390,8 +3279,6 @@ return 1; ignore_it: - DPRINTF((DBG_TCP, "tcp_sequence: rejecting packet.\n")); - if (th->rst) return 0; @@ -3422,13 +3309,11 @@ struct sock *sk; if (!skb) { - DPRINTF((DBG_TCP, "tcp.c: tcp_rcv skb = NULL\n")); return(0); } if (!dev) { - DPRINTF((DBG_TCP, "tcp.c: tcp_rcv dev = NULL\n")); return(0); } @@ -3438,23 +3323,14 @@ /* Find the socket. */ sk = get_sock(&tcp_prot, th->dest, saddr, th->source, daddr); - DPRINTF((DBG_TCP, "<<\n")); - DPRINTF((DBG_TCP, "len = %d, redo = %d, skb=%X\n", len, redo, skb)); - /* If this socket has got a reset its to all intents and purposes really dead */ if (sk!=NULL && sk->zapped) sk=NULL; - if (sk) { - DPRINTF((DBG_TCP, "sk = %X:\n", sk)); - } - if (!redo) { if (tcp_check(th, len, saddr, daddr )) { skb->sk = NULL; - DPRINTF((DBG_TCP, "packet dropped with bad checksum.\n")); -if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n"); kfree_skb(skb,FREE_READ); /* * We don't release the socket because it was @@ -3493,27 +3369,23 @@ sti(); } else { if (!sk) { - DPRINTF((DBG_TCP, "tcp.c: tcp_rcv bug sk=NULL redo = 1\n")); return(0); } } if (!sk->prot) { - DPRINTF((DBG_TCP, "tcp.c: tcp_rcv sk->prot = NULL \n")); return(0); } /* Charge the memory to the socket. */ if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) { skb->sk = NULL; - DPRINTF((DBG_TCP, "dropping packet due to lack of buffer space.\n")); kfree_skb(skb, FREE_READ); release_sock(sk); return(0); } sk->rmem_alloc += skb->mem_len; - DPRINTF((DBG_TCP, "About to do switch.\n")); /* Now deal with it. */ switch(sk->state) { @@ -3542,8 +3414,6 @@ case TCP_FIN_WAIT2: case TCP_TIME_WAIT: if (!tcp_sequence(sk, th, len, opt, saddr,dev)) { - if (inet_debug == DBG_SLIP) - printk("\rtcp_rcv: not in seq\n"); kfree_skb(skb, FREE_READ); release_sock(sk); return(0); @@ -3622,7 +3492,6 @@ case TCP_CLOSE: if (sk->dead || sk->daddr) { - DPRINTF((DBG_TCP, "packet received for closed,dead socket\n")); kfree_skb(skb, FREE_READ); release_sock(sk); return(0); @@ -3864,7 +3733,6 @@ buff->sk = sk; buff->localroute = sk->localroute; - DPRINTF((DBG_TCP, "in tcp_write_wakeup\n")); t1 = (struct tcphdr *) buff->data; /* Put in the IP header and routing stuff. */ diff -u --recursive --new-file v1.1.12/linux/net/inet/tcp.h linux/net/inet/tcp.h --- v1.1.12/linux/net/inet/tcp.h Tue Apr 19 10:54:06 1994 +++ linux/net/inet/tcp.h Mon May 23 08:17:53 1994 @@ -49,13 +49,13 @@ #define TCP_TIMEOUT_LEN (15*60*HZ) /* should be about 15 mins */ #define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to sucessfully * close the socket, about 60 seconds */ -#define TCP_ACK_TIME 3000 /* time to delay before sending an ACK */ +#define TCP_ACK_TIME (3*HZ) /* time to delay before sending an ACK */ #define TCP_DONE_TIME 250 /* maximum time to wait before actually * destroying a socket */ #define TCP_WRITE_TIME 3000 /* initial time to wait for an ACK, * after last transmit */ -#define TCP_CONNECT_TIME 2000 /* time to retransmit first SYN */ -#define TCP_SYN_RETRIES 5 /* number of times to retry openning a +#define TCP_TIMEOUT_INIT (3*HZ) /* RFC 1122 initial timeout value */ +#define TCP_SYN_RETRIES 5 /* number of times to retry opening a * connection */ #define TCP_PROBEWAIT_LEN 100 /* time to wait between probes when * I've got something to write and diff -u --recursive --new-file v1.1.12/linux/net/inet/timer.c linux/net/inet/timer.c --- v1.1.12/linux/net/inet/timer.c Mon May 23 12:14:29 1994 +++ linux/net/inet/timer.c Mon May 23 08:17:53 1994 @@ -3,7 +3,7 @@ * operating system. INET is implemented using the BSD Socket * interface as the means of communication with the user level. * - * TIMER - implementation of software timers. + * TIMER - implementation of software timers for IP. * * Version: @(#)timer.c 1.0.7 05/25/93 * @@ -22,7 +22,7 @@ * the socket will get removed BEFORE this is called * otherwise if the timer TIME_DESTROY occurs inside * of inet_bh() with this socket being handled it goes - * BOOM! Have to stop timer going off if inet_bh is + * BOOM! Have to stop timer going off if net_bh is * active or the destroy causes crashes. * * This program is free software; you can redistribute it and/or @@ -49,202 +49,213 @@ #include "sock.h" #include "arp.h" -void -delete_timer (struct sock *t) +void delete_timer (struct sock *t) { - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli(); + save_flags (flags); + cli(); - t->timeout = 0; - del_timer (&t->timer); + t->timeout = 0; + del_timer (&t->timer); - restore_flags (flags); + restore_flags (flags); } -void -reset_timer (struct sock *t, int timeout, unsigned long len) +void reset_timer (struct sock *t, int timeout, unsigned long len) { - delete_timer (t); - - t->timeout = timeout; - + delete_timer (t); + t->timeout = timeout; #if 1 /* FIXME: ??? */ - if ((int) len < 0) /* prevent close to infinite timers. THEY _DO_ */ - len = 3; /* happen (negative values ?) - don't ask me why ! -FB */ + if ((int) len < 0) /* prevent close to infinite timers. THEY _DO_ */ + len = 3; /* happen (negative values ?) - don't ask me why ! -FB */ #endif - t->timer.expires = len; - add_timer (&t->timer); + t->timer.expires = len; + add_timer (&t->timer); } /* - * Now we will only be called whenever we need to do - * something, but we must be sure to process all of the - * sockets that need it. + * Now we will only be called whenever we need to do + * something, but we must be sure to process all of the + * sockets that need it. */ -void -net_timer (unsigned long data) + +void net_timer (unsigned long data) { - struct sock *sk = (struct sock*)data; - int why = sk->timeout; - /* timeout is overwritten by 'delete_timer' and 'reset_timer' */ - - cli(); - if (sk->inuse || in_bh) { - sk->timer.expires = 10; - add_timer(&sk->timer); - sti(); - return; - } - sk->inuse = 1; - sti(); - - DPRINTF ((DBG_TMR, "net_timer: found sk=%X why = %d\n", sk, why)); - if (skb_peek(&sk->write_queue) && - before(sk->window_seq, sk->write_queue.next->h.seq) && - sk->send_head == NULL && - sk->ack_backlog == 0 && - sk->state != TCP_TIME_WAIT) - reset_timer(sk, TIME_PROBE0, sk->rto); - else if (sk->keepopen) - reset_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN); - - /* Always see if we need to send an ack. */ - if (sk->ack_backlog) { - sk->prot->read_wakeup (sk); - if (! sk->dead) - sk->data_ready(sk,0); - } - - /* Now we need to figure out why the socket was on the timer. */ - switch (why) { - case TIME_DONE: - if (! sk->dead || sk->state != TCP_CLOSE) { - printk ("non dead socket in time_done\n"); - release_sock (sk); - break; - } - destroy_sock (sk); - break; - case TIME_DESTROY: - /* We've waited for a while for all the memory associated with - * the socket to be freed. We need to print an error message. - */ - if(sk->wmem_alloc!=0 || sk->rmem_alloc!=0) - { - DPRINTF ((DBG_TMR, "possible memory leak. sk = %X\n", sk)); - sk->wmem_alloc++; /* So it DOESNT go away */ - destroy_sock (sk); - sk->wmem_alloc--; /* Might now have hit 0 - fall through and do it again if so */ - sk->inuse = 0; /* This will be ok, the destroy won't totally work */ - } - if(sk->wmem_alloc==0 && sk->rmem_alloc==0) - destroy_sock(sk); /* Socket gone, DONT update sk->inuse! */ - break; - case TIME_CLOSE: - /* We've waited long enough, close the socket. */ - sk->state = TCP_CLOSE; - delete_timer (sk); - /* Kill the ARP entry in case the hardware has changed. */ - arp_destroy (sk->daddr, 0); - if (!sk->dead) - sk->state_change(sk); - sk->shutdown = SHUTDOWN_MASK; - reset_timer (sk, TIME_DESTROY, TCP_DONE_TIME); - release_sock (sk); - break; - case TIME_PROBE0: - tcp_send_probe0(sk); - release_sock (sk); - break; - case TIME_WRITE: /* try to retransmit. */ - /* It could be we got here because we needed to send an ack. - * So we need to check for that. - */ - { - struct sk_buff *skb; - unsigned long flags; + struct sock *sk = (struct sock*)data; + int why = sk->timeout; + /* timeout is overwritten by 'delete_timer' and 'reset_timer' */ - save_flags(flags); cli(); - skb = sk->send_head; - if (!skb) { - restore_flags(flags); - } else { - if (jiffies < skb->when + sk->rto) { - reset_timer (sk, TIME_WRITE, skb->when + sk->rto - jiffies); - restore_flags(flags); - release_sock (sk); - break; - } - restore_flags(flags); - /* printk("timer: seq %d retrans %d out %d cong %d\n", sk->send_head->h.seq, - sk->retransmits, sk->packets_out, sk->cong_window); */ - DPRINTF ((DBG_TMR, "retransmitting.\n")); - sk->prot->retransmit (sk, 0); - if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) - || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) { - DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 1\n")); - arp_destroy (sk->daddr, 0); - ip_route_check (sk->daddr); - } - if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) { - DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 2\n")); - sk->err = ETIMEDOUT; - if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2 - || sk->state == TCP_CLOSING) { - sk->state = TCP_TIME_WAIT; - reset_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); - } else { - sk->prot->close (sk, 1); - break; - } - } - } - release_sock (sk); - break; - } - case TIME_KEEPOPEN: - /* Send something to keep the connection open. */ - if (sk->prot->write_wakeup) - sk->prot->write_wakeup (sk); - sk->retransmits++; - if (sk->shutdown == SHUTDOWN_MASK) { - sk->prot->close (sk, 1); - sk->state = TCP_CLOSE; - } + if (sk->inuse || in_bh) + { + sk->timer.expires = 10; + add_timer(&sk->timer); + sti(); + return; + } + + sk->inuse = 1; + sti(); + + if (skb_peek(&sk->write_queue) && + before(sk->window_seq, sk->write_queue.next->h.seq) && + sk->send_head == NULL && + sk->ack_backlog == 0 && + sk->state != TCP_TIME_WAIT) + reset_timer(sk, TIME_PROBE0, sk->rto); + else if (sk->keepopen) + reset_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN); + + /* Always see if we need to send an ack. */ - if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) - || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) { - DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 1\n")); - arp_destroy (sk->daddr, 0); - ip_route_check (sk->daddr); - release_sock (sk); - break; + if (sk->ack_backlog) + { + sk->prot->read_wakeup (sk); + if (! sk->dead) + sk->data_ready(sk,0); } - if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) { - DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 2\n")); - arp_destroy (sk->daddr, 0); - sk->err = ETIMEDOUT; - if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) { - sk->state = TCP_TIME_WAIT; - if (!sk->dead) - sk->state_change(sk); - release_sock (sk); - } else { - sk->prot->close (sk, 1); - } - break; + + /* Now we need to figure out why the socket was on the timer. */ + + switch (why) + { + case TIME_DONE: + if (! sk->dead || sk->state != TCP_CLOSE) + { + printk ("non dead socket in time_done\n"); + release_sock (sk); + break; + } + destroy_sock (sk); + break; + + case TIME_DESTROY: + /* + * We've waited for a while for all the memory associated with + * the socket to be freed. + */ + if(sk->wmem_alloc!=0 || sk->rmem_alloc!=0) + { + sk->wmem_alloc++; /* So it DOESNT go away */ + destroy_sock (sk); + sk->wmem_alloc--; /* Might now have hit 0 - fall through and do it again if so */ + sk->inuse = 0; /* This will be ok, the destroy won't totally work */ + } + if(sk->wmem_alloc==0 && sk->rmem_alloc==0) + destroy_sock(sk); /* Socket gone, DONT update sk->inuse! */ + break; + case TIME_CLOSE: + /* We've waited long enough, close the socket. */ + sk->state = TCP_CLOSE; + delete_timer (sk); + /* Kill the ARP entry in case the hardware has changed. */ + arp_destroy (sk->daddr, 0); + if (!sk->dead) + sk->state_change(sk); + sk->shutdown = SHUTDOWN_MASK; + reset_timer (sk, TIME_DESTROY, TCP_DONE_TIME); + release_sock (sk); + break; + case TIME_PROBE0: + tcp_send_probe0(sk); + release_sock (sk); + break; + case TIME_WRITE: /* try to retransmit. */ + /* It could be we got here because we needed to send an ack. + * So we need to check for that. + */ + { + struct sk_buff *skb; + unsigned long flags; + + save_flags(flags); + cli(); + skb = sk->send_head; + if (!skb) + { + restore_flags(flags); + } + else + { + if (jiffies < skb->when + sk->rto) + { + reset_timer (sk, TIME_WRITE, skb->when + sk->rto - jiffies); + restore_flags(flags); + release_sock (sk); + break; + } + restore_flags(flags); + /* printk("timer: seq %d retrans %d out %d cong %d\n", sk->send_head->h.seq, + sk->retransmits, sk->packets_out, sk->cong_window); */ + sk->prot->retransmit (sk, 0); + if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) + || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) + { + arp_destroy (sk->daddr, 0); + ip_route_check (sk->daddr); + } + if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) + { + sk->err = ETIMEDOUT; + if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2 || sk->state == TCP_CLOSING) + { + sk->state = TCP_TIME_WAIT; + reset_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); + } + else + { + sk->prot->close (sk, 1); + break; + } + } + } + release_sock (sk); + break; + } + case TIME_KEEPOPEN: + /* Send something to keep the connection open. */ + if (sk->prot->write_wakeup) + sk->prot->write_wakeup (sk); + sk->retransmits++; + if (sk->shutdown == SHUTDOWN_MASK) + { + sk->prot->close (sk, 1); + sk->state = TCP_CLOSE; + } + if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) + || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) + { + arp_destroy (sk->daddr, 0); + ip_route_check (sk->daddr); + release_sock (sk); + break; + } + if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) + { + arp_destroy (sk->daddr, 0); + sk->err = ETIMEDOUT; + if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) + { + sk->state = TCP_TIME_WAIT; + if (!sk->dead) + sk->state_change(sk); + release_sock (sk); + } + else + { + sk->prot->close (sk, 1); + } + break; + } + release_sock (sk); + break; + default: + printk ("net_timer: timer expired - reason unknown\n"); + release_sock (sk); + break; } - release_sock (sk); - break; - default: - printk ("net_timer: timer expired - reason unknown\n"); - release_sock (sk); - break; - } } diff -u --recursive --new-file v1.1.12/linux/net/inet/udp.c linux/net/inet/udp.c --- v1.1.12/linux/net/inet/udp.c Mon May 23 12:14:29 1994 +++ linux/net/inet/udp.c Mon May 23 09:59:41 1994 @@ -37,6 +37,7 @@ * Alan Cox : SNMP Mibs * Alan Cox : MSG_DONTROUTE, and 0.0.0.0 support. * Matt Dillon : UDP length checks. + * Alan Cox : Smarter af_inet used properly. * * * This program is free software; you can redistribute it and/or @@ -79,20 +80,6 @@ #define min(a,b) ((a)<(b)?(a):(b)) -static void print_udp(struct udphdr *uh) -{ - if (inet_debug != DBG_UDP) - return; - - if (uh == NULL) - { - printk("(NULL)\n"); - return; - } - printk("UDP: source = %d, dest = %d\n", ntohs(uh->source), ntohs(uh->dest)); - printk(" len = %d, check = %d\n", ntohs(uh->len), ntohs(uh->check)); -} - /* * This routine is called by the ICMP module when it gets some @@ -119,9 +106,6 @@ */ th = (struct udphdr *)header; - DPRINTF((DBG_UDP,"UDP: err(err=%d, header=%X, daddr=%X, saddr=%X, protocl=%X)\n\ - sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th->dest)); - sk = get_sock(&udp_prot, th->source, daddr, th->dest, saddr); if (sk == NULL) @@ -134,8 +118,6 @@ return; } - sk->err = icmp_err_convert[err & 0xff].errno; - /* * It's only fatal if we have connected to them. I'm not happy * with this code. Some BSD comparisons need doing. @@ -143,7 +125,8 @@ if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED) { - sk->err=ECONNREFUSED; + sk->err = icmp_err_convert[err & 0xff].errno; +/* sk->err=ECONNREFUSED;*/ } sk->error_report(sk); @@ -154,11 +137,6 @@ { unsigned long sum; - DPRINTF((DBG_UDP, "UDP: check(uh=%X, len = %d, saddr = %X, daddr = %X)\n", - uh, len, saddr, daddr)); - - print_udp(uh); - __asm__( "\t addl %%ecx,%%ebx\n" "\t adcl %%edx,%%ebx\n" "\t adcl $0, %%ebx\n" @@ -260,16 +238,7 @@ unsigned char *buff; unsigned long saddr; int size, tmp; - int err; - DPRINTF((DBG_UDP, "UDP: send(dst=%s:%d buff=%X len=%d)\n", - in_ntoa(sin->sin_addr.s_addr), ntohs(sin->sin_port), - from, len)); - - err=verify_area(VERIFY_READ, from, len); - if(err) - return(err); - /* * Allocate an sk_buff copy of the packet. */ @@ -279,7 +248,7 @@ if (skb == NULL) - return(-ENOMEM); + return(-ENOBUFS); skb->sk = NULL; /* to avoid changing sk->saddr */ skb->free = 1; @@ -292,8 +261,6 @@ buff = skb->data; saddr = 0; dev = NULL; - DPRINTF((DBG_UDP, "UDP: >> IP_Header: %X -> %X dev=%X prot=%X len=%d\n", - saddr, sin->sin_addr.s_addr, dev, IPPROTO_UDP, skb->mem_len)); tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr, &dev, IPPROTO_UDP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl); skb->sk=sk; /* So memory is freed correctly */ @@ -310,8 +277,6 @@ buff += tmp; saddr = skb->saddr; /*dev->pa_addr;*/ - DPRINTF((DBG_UDP, "UDP: >> MAC+IP len=%d\n", tmp)); - skb->len = tmp + sizeof(struct udphdr) + len; /* len + UDP + IP + MAC */ skb->dev = dev; @@ -355,18 +320,11 @@ int tmp; int err; - DPRINTF((DBG_UDP, "UDP: sendto(len=%d, flags=%X)\n", len, flags)); - /* * Check the flags. We support no flags for UDP sending */ if (flags&~MSG_DONTROUTE) return(-EINVAL); - if (len < 0) - return(-EINVAL); - if (len == 0) - return(0); - /* * Get and verify the address. */ @@ -434,27 +392,6 @@ int err; switch(cmd) { - case DDIOCSDBG: - { - int val; - - if (!suser()) return(-EPERM); - err=verify_area(VERIFY_READ, (void *)arg, sizeof(int)); - if(err) - return err; - val = get_fs_long((int *)arg); - switch(val) { - case 0: - inet_debug = 0; - break; - case 1: - inet_debug = DBG_UDP; - break; - default: - return(-EINVAL); - } - } - break; case TIOCOUTQ: { unsigned long amount; @@ -513,26 +450,6 @@ struct sk_buff *skb; int er; - - /* - * This will pick up errors that occured while the program - * was doing something else. - */ - - if (sk->err) - { - int err; - - err = -sk->err; - sk->err = 0; - return(err); - } - - if (len == 0) - return(0); - if (len < 0) - return(-EINVAL); - /* * Check any passed addresses */ @@ -552,14 +469,6 @@ return(er); } - /* - * Check the buffer we were given - */ - - er=verify_area(VERIFY_WRITE,to,len); - if(er) - return er; - /* * From here the generic datagram does a lot of the work. Come * the finished NET3, it will do _ALL_ the work! @@ -672,7 +581,6 @@ if (ulen > len || len < sizeof(*uh) || ulen < sizeof(*uh)) { printk("UDP: short packet: %d/%d\n", ulen, len); - DPRINTF((DBG_UDP, "UDP: short packet %d/%d\n", ulen, len)); udp_statistics.UdpInErrors++; kfree_skb(skb, FREE_WRITE); return(0); @@ -699,7 +607,6 @@ if (uh->check && udp_check(uh, len, saddr, daddr)) { printk("UDP: bad checksum.\n"); - DPRINTF((DBG_UDP, "UDP: bad checksum\n")); udp_statistics.UdpInErrors++; kfree_skb(skb, FREE_WRITE); return(0); @@ -733,13 +640,6 @@ } sk->rmem_alloc += skb->mem_len; udp_statistics.UdpInDatagrams++; - - /* - * At this point we should print the thing out. - */ - - DPRINTF((DBG_UDP, "<< \n")); - print_udp(uh); /* * Now add it to the data chain and wake things up. diff -u --recursive --new-file v1.1.12/linux/net/inet/utils.c linux/net/inet/utils.c --- v1.1.12/linux/net/inet/utils.c Tue Apr 19 10:54:08 1994 +++ linux/net/inet/utils.c Mon May 23 08:17:54 1994 @@ -12,6 +12,7 @@ * * Fixes: * Alan Cox : verify_area check. + * Alan Cox : removed old debugging. * * * This program is free software; you can redistribute it and/or @@ -88,80 +89,3 @@ return(htonl(l)); } - -/* - * Debugging print out - */ - -void dprintf(int level, char *fmt, ...) -{ - va_list args; - char *buff; - extern int vsprintf(char * buf, const char * fmt, va_list args); - - if (level != inet_debug) - return; - - buff = (char *) kmalloc(256, GFP_ATOMIC); - if (buff != NULL) - { - va_start(args, fmt); - vsprintf(buff, fmt, args); - va_end(args); - printk(buff); - kfree(buff); - } - else - printk("Debugging output lost: No free memory.\n"); -} - -/* - * Debugging ioctl() requests - */ - -int dbg_ioctl(void *arg, int level) -{ - int val; - int err; - - if (!suser()) - return(-EPERM); - err=verify_area(VERIFY_READ, (void *)arg, sizeof(int)); - if(err) - return err; - val = get_fs_long((int *)arg); - switch(val) - { - case 0: /* OFF */ - inet_debug = DBG_OFF; - break; - case 1: /* ON, INET */ - inet_debug = level; - break; - - case DBG_RT: /* modules */ - case DBG_DEV: - case DBG_ETH: - case DBG_PROTO: - case DBG_TMR: - case DBG_PKT: - case DBG_RAW: - - case DBG_LOOPB: /* drivers */ - case DBG_SLIP: - - case DBG_ARP: /* protocols */ - case DBG_IP: - case DBG_ICMP: - case DBG_TCP: - case DBG_UDP: - - inet_debug = val; - break; - - default: - return(-EINVAL); - } - - return(0); -} diff -u --recursive --new-file v1.1.12/linux/net/protocols.c linux/net/protocols.c --- v1.1.12/linux/net/protocols.c Thu Jan 1 02:00:00 1970 +++ linux/net/protocols.c Mon May 23 08:17:54 1994 @@ -0,0 +1,50 @@ +/* + * Protocol intialiser table. Here seperately for convenience + * + */ + + +#include +#include +#include +#include + + +#define CONFIG_UNIX /* always present... */ + +#ifdef CONFIG_UNIX +#include "unix/unix.h" +#endif +#ifdef CONFIG_INET +#include +#endif +#ifdef CONFIG_IPX +#include "inet/ipxcall.h" +#include "inet/p8022call.h" +#endif +#ifdef CONFIG_AX25 +#include "inet/ax25call.h" +#endif + +/* + * Protocol Table + */ + +struct net_proto protocols[] = { +#ifdef CONFIG_UNIX + { "UNIX", unix_proto_init }, +#endif +#ifdef CONFIG_IPX + { "IPX", ipx_proto_init }, + { "802.2", p8022_proto_init }, +#endif +#ifdef CONFIG_AX25 + { "AX.25", ax25_proto_init }, +#endif +#ifdef CONFIG_INET + { "INET", inet_proto_init }, +#endif + { NULL, NULL } +}; + + diff -u --recursive --new-file v1.1.12/linux/net/socket.c linux/net/socket.c --- v1.1.12/linux/net/socket.c Sat May 7 14:54:18 1994 +++ linux/net/socket.c Mon May 23 08:17:54 1994 @@ -11,6 +11,8 @@ * Anonymous : NOTSOCK/BADF cleanup. Error fix in * shutdown() * Alan Cox : verify_area() fixes + * Alan Cox : Removed DDI + * Jonathan Kamens : SOCK_DGRAM reconnect bug * * * This program is free software; you can redistribute it and/or @@ -37,20 +39,12 @@ #include #include #include -#include +#include +#include #include #include -#undef SOCK_DEBUG - -#ifdef SOCK_DEBUG -#include -#define DPRINTF(x) dprintf x -#else -#define DPRINTF(x) /**/ -#endif - static int sock_lseek(struct inode *inode, struct file *file, off_t offset, int whence); static int sock_read(struct inode *inode, struct file *file, char *buf, @@ -80,27 +74,9 @@ static struct socket sockets[NSOCKETS]; static struct wait_queue *socket_wait_free = NULL; static struct proto_ops *pops[NPROTO]; -static int net_debug = 0; #define last_socket (sockets + NSOCKETS - 1) -#ifdef SOCK_DEBUG -/* Module debugging. */ -static void -dprintf(int level, char *fmt, ...) -{ - char buff[1024]; - va_list args; - extern int vsprintf(char * buf, const char * fmt, va_list args); - - if (level == 0) return; - va_start(args, fmt); - vsprintf(buff, fmt, args); - va_end(args); - printk(buff); -} -#endif - /* Obtains the first available file descriptor and sets it up for use. */ static int get_fd(struct inode *inode) @@ -207,21 +183,15 @@ SOCK_INODE(sock)->i_socket = sock; sock->wait = &SOCK_INODE(sock)->i_wait; - DPRINTF((net_debug, - "NET: sock_alloc: sk 0x%x, ino 0x%x\n", - sock, SOCK_INODE(sock))); return(sock); } } sti(); if (!wait) return(NULL); - DPRINTF((net_debug, "NET: sock_alloc: no free sockets, sleeping...\n")); interruptible_sleep_on(&socket_wait_free); if (current->signal & ~current->blocked) { - DPRINTF((net_debug, "NET: sock_alloc: sleep was interrupted\n")); return(NULL); } - DPRINTF((net_debug, "NET: sock_alloc: wakeup... trying again...\n")); } } @@ -241,8 +211,6 @@ struct inode *inode; struct socket *peersock, *nextsock; - DPRINTF((net_debug, "NET: sock_release: socket 0x%x, inode 0x%x\n", - sock, SOCK_INODE(sock))); if ((oldstate = sock->state) != SS_UNCONNECTED) sock->state = SS_DISCONNECTING; @@ -271,7 +239,6 @@ static int sock_lseek(struct inode *inode, struct file *file, off_t offset, int whence) { - DPRINTF((net_debug, "NET: sock_lseek: huh?\n")); return(-ESPIPE); } @@ -281,7 +248,6 @@ { struct socket *sock; - DPRINTF((net_debug, "NET: sock_read: buf=0x%x, size=%d\n", ubuf, size)); if (!(sock = socki_lookup(inode))) { printk("NET: sock_read: can't find socket for inode!\n"); return(-EBADF); @@ -296,7 +262,6 @@ { struct socket *sock; - DPRINTF((net_debug, "NET: sock_write: buf=0x%x, size=%d\n", ubuf, size)); if (!(sock = socki_lookup(inode))) { printk("NET: sock_write: can't find socket for inode!\n"); return(-EBADF); @@ -310,7 +275,6 @@ sock_readdir(struct inode *inode, struct file *file, struct dirent *dirent, int count) { - DPRINTF((net_debug, "NET: sock_readdir: huh?\n")); return(-EBADF); } @@ -321,8 +285,6 @@ { struct socket *sock; - DPRINTF((net_debug, "NET: sock_ioctl: inode=0x%x cmd=0x%x arg=%d\n", - inode, cmd, arg)); if (!(sock = socki_lookup(inode))) { printk("NET: sock_ioctl: can't find socket for inode!\n"); return(-EBADF); @@ -336,9 +298,6 @@ { struct socket *sock; - DPRINTF((net_debug, "NET: sock_select: inode = 0x%x, kind = %s\n", inode, - (sel_type == SEL_IN) ? "in" : - (sel_type == SEL_OUT) ? "out" : "ex")); if (!(sock = socki_lookup(inode))) { printk("NET: sock_select: can't find socket for inode!\n"); return(0); @@ -356,9 +315,6 @@ { struct socket *sock; - DPRINTF((net_debug, "NET: sock_close: inode=0x%x (cnt=%d)\n", - inode, inode->i_count)); - /* It's possible the inode is NULL if we're closing an unfinished socket. */ if (!inode) return; if (!(sock = socki_lookup(inode))) { @@ -374,12 +330,7 @@ { struct socket *last; - DPRINTF((net_debug, - "NET: sock_awaitconn: trying to connect socket 0x%x to 0x%x\n", - mysock, servsock)); if (!(servsock->flags & SO_ACCEPTCON)) { - DPRINTF((net_debug, - "NET: sock_awaitconn: server not accepting connections\n")); return(-EINVAL); } @@ -439,18 +390,13 @@ struct socket *sock; struct proto_ops *ops; - DPRINTF((net_debug, - "NET: sock_socket: family = %d, type = %d, protocol = %d\n", - family, type, protocol)); - /* Locate the correct protocol family. */ for (i = 0; i < NPROTO; ++i) { if (pops[i] == NULL) continue; if (pops[i]->family == family) break; } if (i == NPROTO) { - DPRINTF((net_debug, "NET: sock_socket: family not found\n")); - return(-EINVAL); + return -EINVAL; } ops = pops[i]; @@ -496,10 +442,6 @@ struct socket *sock1, *sock2; int er; - DPRINTF((net_debug, - "NET: sock_socketpair: family = %d, type = %d, protocol = %d\n", - family, type, protocol)); - /* * Obtain the first socket and check if the underlying protocol * supports the socketpair call. @@ -547,12 +489,10 @@ struct socket *sock; int i; - DPRINTF((net_debug, "NET: sock_bind: fd = %d\n", fd)); if (fd < 0 || fd >= NR_OPEN || current->files->fd[fd] == NULL) return(-EBADF); if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); if ((i = sock->ops->bind(sock, umyaddr, addrlen)) < 0) { - DPRINTF((net_debug, "NET: sock_bind: bind failed\n")); return(i); } return(0); @@ -569,12 +509,10 @@ { struct socket *sock; - DPRINTF((net_debug, "NET: sock_listen: fd = %d\n", fd)); if (fd < 0 || fd >= NR_OPEN || current->files->fd[fd] == NULL) return(-EBADF); if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); if (sock->state != SS_UNCONNECTED) { - DPRINTF((net_debug, "NET: sock_listen: socket isn't unconnected\n")); return(-EINVAL); } if (sock->ops && sock->ops->listen) sock->ops->listen(sock, backlog); @@ -595,18 +533,14 @@ struct socket *sock, *newsock; int i; - DPRINTF((net_debug, "NET: sock_accept: fd = %d\n", fd)); if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL)) return(-EBADF); if (!(sock = sockfd_lookup(fd, &file))) return(-ENOTSOCK); if (sock->state != SS_UNCONNECTED) { - DPRINTF((net_debug, "NET: sock_accept: socket isn't unconnected\n")); return(-EINVAL); } if (!(sock->flags & SO_ACCEPTCON)) { - DPRINTF((net_debug, - "NET: sock_accept: socket not accepting connections!\n")); return(-EINVAL); } @@ -632,9 +566,6 @@ return(-EINVAL); } - DPRINTF((net_debug, "NET: sock_accept: connected socket 0x%x via 0x%x\n", - sock, newsock)); - if (upeer_sockaddr) newsock->ops->getname(newsock, upeer_sockaddr, upeer_addrlen, 1); @@ -650,7 +581,6 @@ struct file *file; int i; - DPRINTF((net_debug, "NET: sock_connect: fd = %d\n", fd)); if (fd < 0 || fd >= NR_OPEN || (file=current->files->fd[fd]) == NULL) return(-EBADF); @@ -661,19 +591,24 @@ break; case SS_CONNECTED: /* Socket is already connected */ + if(sock->type == SOCK_DGRAM) /* Hack for now - move this all into the protocol */ + break; return -EISCONN; case SS_CONNECTING: /* Not yet connected... we will check this. */ + + /* + * FIXME: for all protocols what happens if you start + * an async connect fork and both children connect. Clean + * this up in the protocols! + */ return(sock->ops->connect(sock, uservaddr, addrlen, file->f_flags)); default: - DPRINTF((net_debug, - "NET: sock_connect: socket not unconnected\n")); return(-EINVAL); } i = sock->ops->connect(sock, uservaddr, addrlen, file->f_flags); if (i < 0) { - DPRINTF((net_debug, "NET: sock_connect: connect failed\n")); return(i); } return(0); @@ -685,7 +620,6 @@ { struct socket *sock; - DPRINTF((net_debug, "NET: sock_getsockname: fd = %d\n", fd)); if (fd < 0 || fd >= NR_OPEN || current->files->fd[fd] == NULL) return(-EBADF); if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); @@ -698,7 +632,6 @@ { struct socket *sock; - DPRINTF((net_debug, "NET: sock_getpeername: fd = %d\n", fd)); if (fd < 0 || fd >= NR_OPEN || current->files->fd[fd] == NULL) return(-EBADF); if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); @@ -712,10 +645,6 @@ struct socket *sock; struct file *file; - DPRINTF((net_debug, - "NET: sock_send(fd = %d, buff = %X, len = %d, flags = %X)\n", - fd, buff, len, flags)); - if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL)) return(-EBADF); if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); @@ -731,10 +660,6 @@ struct socket *sock; struct file *file; - DPRINTF((net_debug, - "NET: sock_sendto(fd = %d, buff = %X, len = %d, flags = %X," - " addr=%X, alen = %d\n", fd, buff, len, flags, addr, addr_len)); - if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL)) return(-EBADF); if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); @@ -750,10 +675,6 @@ struct socket *sock; struct file *file; - DPRINTF((net_debug, - "NET: sock_recv(fd = %d, buff = %X, len = %d, flags = %X)\n", - fd, buff, len, flags)); - if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL)) return(-EBADF); if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); @@ -769,10 +690,6 @@ struct socket *sock; struct file *file; - DPRINTF((net_debug, - "NET: sock_recvfrom(fd = %d, buff = %X, len = %d, flags = %X," - " addr=%X, alen=%X\n", fd, buff, len, flags, addr, addr_len)); - if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL)) return(-EBADF); if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); @@ -788,11 +705,6 @@ struct socket *sock; struct file *file; - DPRINTF((net_debug, "NET: sock_setsockopt(fd=%d, level=%d, optname=%d,\n", - fd, level, optname)); - DPRINTF((net_debug, " optval = %X, optlen = %d)\n", - optval, optlen)); - if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL)) return(-EBADF); if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); @@ -807,11 +719,6 @@ struct socket *sock; struct file *file; - DPRINTF((net_debug, "NET: sock_getsockopt(fd=%d, level=%d, optname=%d,\n", - fd, level, optname)); - DPRINTF((net_debug, " optval = %X, optlen = %X)\n", - optval, optlen)); - if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL)) return(-EBADF); if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); @@ -827,8 +734,6 @@ struct socket *sock; struct file *file; - DPRINTF((net_debug, "NET: sock_shutdown(fd = %d, how = %d)\n", fd, how)); - if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL)) return(-EBADF); @@ -981,74 +886,6 @@ } } - -static int -net_ioctl(unsigned int cmd, unsigned long arg) -{ - int er; - switch(cmd) { - case DDIOCSDBG: - er=verify_area(VERIFY_READ, (void *)arg, sizeof(long)); - if(er) - return er; - net_debug = get_fs_long((long *)arg); - if (net_debug != 0 && net_debug != 1) { - net_debug = 0; - return(-EINVAL); - } - return(0); - default: - return(-EINVAL); - } - /*NOTREACHED*/ - return(0); -} - - -/* - * Handle the IOCTL system call for the NET devices. This basically - * means I/O control for the SOCKET layer (future expansions could be - * a variable number of socket table entries, et al), and for the more - * general protocols like ARP. The latter currently lives in the INET - * module, so we have to get ugly a tiny little bit. Later... -FvK - */ -static int -net_fioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - extern int arp_ioctl(unsigned int, void *); - - /* Dispatch on the minor device. */ - switch(MINOR(inode->i_rdev)) { - case 0: /* NET (SOCKET) */ - DPRINTF((net_debug, "NET: SOCKET level I/O control request.\n")); - return(net_ioctl(cmd, arg)); -#ifdef CONFIG_INET - case 1: /* ARP */ - DPRINTF((net_debug, "NET: ARP level I/O control request.\n")); - return(arp_ioctl(cmd, (void *) arg)); -#endif - default: - return(-ENODEV); - } - /*NOTREACHED*/ - return(-EINVAL); -} - - -static struct file_operations net_fops = { - NULL, /* LSEEK */ - NULL, /* READ */ - NULL, /* WRITE */ - NULL, /* READDIR */ - NULL, /* SELECT */ - net_fioctl, /* IOCTL */ - NULL, /* MMAP */ - NULL, /* OPEN */ - NULL /* CLOSE */ -}; - - /* * This function is called by a protocol handler that wants to * advertise its address family, and have it linked into the @@ -1065,38 +902,46 @@ pops[i] = ops; pops[i]->family = family; sti(); - DPRINTF((net_debug, "NET: Installed protocol %d in slot %d (0x%X)\n", - family, i, (long)ops)); return(i); } sti(); return(-ENOMEM); } +void proto_init(void) +{ + extern struct net_proto protocols[]; /* Network protocols */ + struct net_proto *pro; + + /* Kick all configured protocols. */ + pro = protocols; + while (pro->name != NULL) + { + (*pro->init_func)(pro); + pro++; + } + /* We're all done... */ +} + void sock_init(void) { struct socket *sock; int i; - - /* Set up our SOCKET VFS major device. */ - if (register_chrdev(SOCKET_MAJOR, "socket", &net_fops) < 0) { - printk("NET: cannot register major device %d!\n", SOCKET_MAJOR); - return; - } - /* Release all sockets. */ for (sock = sockets; sock <= last_socket; ++sock) sock->state = SS_FREE; /* Initialize all address (protocol) families. */ for (i = 0; i < NPROTO; ++i) pops[i] = NULL; - /* Initialize the DDI module. */ - ddi_init(); + /* Initialize the protocols module. */ + proto_init(); - /* Initialize the ARP module. */ -#if 0 - arp_init(); -#endif + /* Initialize the DEV module. */ + dev_init(); + + /* And the bottom half handler */ + bh_base[NET_BH].routine= net_bh; + } diff -u --recursive --new-file v1.1.12/linux/net/unix/proc.c linux/net/unix/proc.c --- v1.1.12/linux/net/unix/proc.c Tue Apr 19 10:54:08 1994 +++ linux/net/unix/proc.c Mon May 23 08:17:54 1994 @@ -17,6 +17,8 @@ * * Fixes: * Dmitry Gorodchanin : /proc locking fix + * Mathijs Maassen : unbound /proc fix. + * Alan Cox : Fix sock=NULL race * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -28,7 +30,6 @@ #include #include #include -#include #include #include #include "unix.h" @@ -41,19 +42,30 @@ off_t begin=0; int len=0; int i; - + unsigned long flags; + socket_state s_state; + short s_type; + long s_flags; + len += sprintf(buffer, "Num RefCount Protocol Flags Type St Path\n"); for(i = 0; i < NSOCKETS; i++) { - if (unix_datas[i].refcnt>0) + save_flags(flags); + cli(); + if (unix_datas[i].refcnt>0 && unix_datas[i].socket!=NULL) { + /* sprintf is slow... lock only for the variable reads */ + s_type=unix_datas[i].socket->type; + s_flags=unix_datas[i].socket->flags; + s_state=unix_datas[i].socket->state; + restore_flags(flags); len += sprintf(buffer+len, "%2d: %08X %08X %08lX %04X %02X", i, unix_datas[i].refcnt, unix_datas[i].protocol, - unix_datas[i].socket->flags, - unix_datas[i].socket->type, - unix_datas[i].socket->state + s_flags, + s_type, + s_state ); /* If socket is bound to a filename, we'll print it. */ @@ -65,7 +77,6 @@ else { /* just add a newline */ buffer[len++]='\n'; - buffer[len++]='\0'; } pos=begin+len; @@ -77,6 +88,8 @@ if(pos>offset+length) break; } + else + restore_flags(flags); } *start=buffer+(offset-begin); diff -u --recursive --new-file v1.1.12/linux/net/unix/sock.c linux/net/unix/sock.c --- v1.1.12/linux/net/unix/sock.c Tue Apr 19 10:54:08 1994 +++ linux/net/unix/sock.c Mon May 23 08:17:55 1994 @@ -42,7 +42,6 @@ #include #include #include -#include #include #include @@ -53,9 +52,7 @@ #include "unix.h" struct unix_proto_data unix_datas[NSOCKETS]; -static int unix_debug = 0; - static int unix_proto_create(struct socket *sock, int protocol); static int unix_proto_dup(struct socket *newsock, struct socket *oldsock); static int unix_proto_release(struct socket *sock, struct socket *peer); @@ -95,26 +92,6 @@ char *optval, int *optlen); -static void -dprintf(int level, char *fmt, ...) -{ - va_list args; - char *buff; - extern int vsprintf(char * buf, const char * fmt, va_list args); - - if (level != unix_debug) return; - - buff = (char *) kmalloc(256, GFP_KERNEL); - if (buff != NULL) { - va_start(args, fmt); - vsprintf(buff, fmt, args); - va_end(args); - printk(buff); - kfree(buff); - } -} - - static inline int min(int a, int b) { @@ -123,25 +100,6 @@ } -void -sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len) -{ - char buf[sizeof(sockun->sun_path) + 1]; - - if (unix_debug == 0) return; - - sockaddr_len -= UN_PATH_OFFSET; - if (sockun->sun_family != AF_UNIX) - printk("UNIX: Badd addr family %d>\n", sockun->sun_family); - else if (sockaddr_len <= 0 || sockaddr_len >= sizeof(buf)) - printk("UNIX: Bad addr len %d>\n", sockaddr_len); - else { - memcpy(buf, sockun->sun_path, sockaddr_len); - buf[sockaddr_len] = '\0'; - printk("\"%s\"[%lu]\n", buf, sockaddr_len + UN_PATH_OFFSET); - } -} - /* Support routines doing anti page fault locking * FvK & Matt Dillon (borrowed From NET2E3) @@ -152,7 +110,7 @@ * wait queue because it is allowed to 'go away' outside of our control, * whereas unix_proto_data structures stick around. */ -void unix_lock(struct unix_proto_data *upd) +static void unix_lock(struct unix_proto_data *upd) { while (upd->lock_flag) sleep_on(&upd->wait); @@ -160,7 +118,7 @@ } -void unix_unlock(struct unix_proto_data *upd) +static void unix_unlock(struct unix_proto_data *upd) { upd->lock_flag = 0; wake_up(&upd->wait); @@ -276,11 +234,9 @@ unix_data_ref(struct unix_proto_data *upd) { if (!upd) { - dprintf(1, "UNIX: data_ref: upd = NULL\n"); return; } ++upd->refcnt; - dprintf(1, "UNIX: data_ref: refing data 0x%x(%d)\n", upd, upd->refcnt); } @@ -288,11 +244,9 @@ unix_data_deref(struct unix_proto_data *upd) { if (!upd) { - dprintf(1, "UNIX: data_deref: upd = NULL\n"); return; } if (upd->refcnt == 1) { - dprintf(1, "UNIX: data_deref: releasing data 0x%x\n", upd); if (upd->buf) { free_page((unsigned long)upd->buf); upd->buf = NULL; @@ -312,9 +266,7 @@ { struct unix_proto_data *upd; - dprintf(1, "UNIX: create: socket 0x%x, proto %d\n", sock, protocol); if (protocol != 0) { - dprintf(1, "UNIX: create: protocol != 0\n"); return(-EINVAL); } if (!(upd = unix_data_alloc())) { @@ -330,7 +282,6 @@ upd->socket = sock; UN_DATA(sock) = upd; upd->refcnt = 1; /* Now its complete - bgm */ - dprintf(1, "UNIX: create: allocated data 0x%x\n", upd); return(0); } @@ -349,14 +300,12 @@ { struct unix_proto_data *upd = UN_DATA(sock); - dprintf(1, "UNIX: release: socket 0x%x, unix_data 0x%x\n", sock, upd); if (!upd) return(0); if (upd->socket != sock) { printk("UNIX: release: socket link mismatch!\n"); return(-EINVAL); } if (upd->inode) { - dprintf(1, "UNIX: release: releasing inode 0x%x\n", upd->inode); iput(upd->inode); upd->inode = NULL; } @@ -387,10 +336,8 @@ int i; int er; - dprintf(1, "UNIX: bind: socket 0x%x, len=%d\n", sock, sockaddr_len); if (sockaddr_len <= UN_PATH_OFFSET || sockaddr_len > sizeof(struct sockaddr_un)) { - dprintf(1, "UNIX: bind: bad length %d\n", sockaddr_len); return(-EINVAL); } if (upd->sockaddr_len || upd->inode) { @@ -403,8 +350,6 @@ memcpy_fromfs(&upd->sockaddr_un, umyaddr, sockaddr_len); upd->sockaddr_un.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0'; if (upd->sockaddr_un.sun_family != AF_UNIX) { - dprintf(1, "UNIX: bind: family is %d, not AF_UNIX(%d)\n", - upd->sockaddr_un.sun_family, AF_UNIX); return(-EINVAL); } @@ -421,9 +366,6 @@ } upd->sockaddr_len = sockaddr_len; /* now its legal */ - dprintf(1, "UNIX: bind: bound socket address: "); - sockaddr_un_printk(&upd->sockaddr_un, upd->sockaddr_len); - dprintf(1, "to inode 0x%x\n", upd->inode); return(0); } @@ -445,11 +387,8 @@ int i; int er; - dprintf(1, "UNIX: connect: socket 0x%x, servlen=%d\n", sock, sockaddr_len); - if (sockaddr_len <= UN_PATH_OFFSET || sockaddr_len > sizeof(struct sockaddr_un)) { - dprintf(1, "UNIX: connect: bad length %d\n", sockaddr_len); return(-EINVAL); } if (sock->state == SS_CONNECTING) return(-EINPROGRESS); @@ -461,8 +400,6 @@ memcpy_fromfs(&sockun, uservaddr, sockaddr_len); sockun.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0'; if (sockun.sun_family != AF_UNIX) { - dprintf(1, "UNIX: connect: family is %d, not AF_UNIX(%d)\n", - sockun.sun_family, AF_UNIX); return(-EINVAL); } @@ -479,18 +416,15 @@ i = open_namei(fname, 0, S_IFSOCK, &inode, NULL); set_fs(old_fs); if (i < 0) { - dprintf(1, "UNIX: connect: can't open socket %s\n", fname); return(i); } + serv_upd = unix_data_lookup(&sockun, sockaddr_len, inode); iput(inode); if (!serv_upd) { - dprintf(1, "UNIX: connect: can't locate peer %s at inode 0x%x\n", - fname, inode); return(-EINVAL); } if ((i = sock_awaitconn(sock, serv_upd->socket)) < 0) { - dprintf(1, "UNIX: connect: can't await connection\n"); return(i); } if (sock->conn) { @@ -526,9 +460,6 @@ { struct socket *clientsock; - dprintf(1, "UNIX: accept: socket 0x%x accepted via socket 0x%x\n", - sock, newsock); - /* * If there aren't any sockets awaiting connection, * then wait for one, unless nonblocking. @@ -537,7 +468,6 @@ if (flags & O_NONBLOCK) return(-EAGAIN); interruptible_sleep_on(sock->wait); if (current->signal & ~current->blocked) { - dprintf(1, "UNIX: accept: sleep was interrupted\n"); return(-ERESTARTSYS); } } @@ -570,10 +500,8 @@ int len; int er; - dprintf(1, "UNIX: getname: socket 0x%x for %s\n", sock, peer?"peer":"self"); if (peer) { if (sock->state != SS_CONNECTED) { - dprintf(1, "UNIX: getname: socket not connected\n"); return(-EINVAL); } upd = UN_DATA(sock->conn); @@ -608,14 +536,11 @@ upd = UN_DATA(sock); while(!(avail = UN_BUF_AVAIL(upd))) { if (sock->state != SS_CONNECTED) { - dprintf(1, "UNIX: read: socket not connected\n"); return((sock->state == SS_DISCONNECTING) ? 0 : -EINVAL); } - dprintf(1, "UNIX: read: no data available...\n"); if (nonblock) return(-EAGAIN); interruptible_sleep_on(sock->wait); if (current->signal & ~current->blocked) { - dprintf(1, "UNIX: read: interrupted\n"); return(-ERESTARTSYS); } } @@ -637,8 +562,6 @@ if ((cando = todo) > avail) cando = avail; if (cando >(part = BUF_SIZE - upd->bp_tail)) cando = part; - dprintf(1, "UNIX: read: avail=%d, todo=%d, cando=%d\n", - avail, todo, cando); if((er=verify_area(VERIFY_WRITE,ubuf,cando))<0) { unix_unlock(upd); @@ -671,7 +594,6 @@ if ((todo = size) <= 0) return(0); if (sock->state != SS_CONNECTED) { - dprintf(1, "UNIX: write: socket not connected\n"); if (sock->state == SS_DISCONNECTING) { send_sig(SIGPIPE, current, 1); return(-EPIPE); @@ -681,15 +603,12 @@ pupd = UN_DATA(sock)->peerupd; /* safer than sock->conn */ while(!(space = UN_BUF_SPACE(pupd))) { - dprintf(1, "UNIX: write: no space left...\n"); if (nonblock) return(-EAGAIN); interruptible_sleep_on(sock->wait); if (current->signal & ~current->blocked) { - dprintf(1, "UNIX: write: interrupted\n"); return(-ERESTARTSYS); } if (sock->state == SS_DISCONNECTING) { - dprintf(1, "UNIX: write: disconnected(SIGPIPE)\n"); send_sig(SIGPIPE, current, 1); return(-EPIPE); } @@ -722,8 +641,6 @@ } if ((cando = todo) > space) cando = space; if (cando >(part = BUF_SIZE - pupd->bp_head)) cando = part; - dprintf(1, "UNIX: write: space=%d, todo=%d, cando=%d\n", - space, todo, cando); er=verify_area(VERIFY_READ, ubuf, cando); if(er) { @@ -751,25 +668,19 @@ /* Handle server sockets specially. */ if (sock->flags & SO_ACCEPTCON) { if (sel_type == SEL_IN) { - dprintf(1, "UNIX: select: %sconnections pending\n", - sock->iconn ? "" : "no "); if (sock->iconn) return(1); select_wait(sock->wait, wait); return(sock->iconn ? 1 : 0); } - dprintf(1, "UNIX: select: nothing else for server socket\n"); select_wait(sock->wait, wait); return(0); } if (sel_type == SEL_IN) { upd = UN_DATA(sock); - dprintf(1, "UNIX: select: there is%s data available\n", - UN_BUF_AVAIL(upd) ? "" : " no"); if (UN_BUF_AVAIL(upd)) /* even if disconnected */ return(1); else if (sock->state != SS_CONNECTED) { - dprintf(1, "UNIX: select: socket not connected(read EOF)\n"); return(1); } select_wait(sock->wait,wait); @@ -777,19 +688,15 @@ } if (sel_type == SEL_OUT) { if (sock->state != SS_CONNECTED) { - dprintf(1, "UNIX: select: socket not connected(write EOF)\n"); return(1); } peerupd = UN_DATA(sock->conn); - dprintf(1, "UNIX: select: there is%s space available\n", - UN_BUF_SPACE(peerupd) ? "" : " no"); if (UN_BUF_SPACE(peerupd) > 0) return(1); select_wait(sock->wait,wait); return(0); } /* SEL_EX */ - dprintf(1, "UNIX: select: there are no exceptions here?!\n"); return(0); } @@ -831,74 +738,6 @@ } -static int -unix_open(struct inode * inode, struct file * file) -{ - int minor; - - dprintf(1, "UNIX: open\n"); - minor = MINOR(inode->i_rdev); - if (minor != 0) return(-ENODEV); - - return(0); -} - - -static void -unix_close(struct inode * inode, struct file * file) -{ - dprintf(1, "UNIX: close\n"); -} - - -static int -unix_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int minor, ret; - int er; - - dprintf(1, "UNIX: ioctl(0x%X, 0x%X)\n", cmd, arg); - minor = MINOR(inode->i_rdev); - if (minor != 0) return(-ENODEV); - - ret = -EINVAL; - switch(cmd) { - case DDIOCSDBG: - er=verify_area(VERIFY_READ,(void *)arg, sizeof(int)); - if(er) - return er; - unix_debug = get_fs_long((int *)arg); - if (unix_debug != 0 && unix_debug != 1) { - unix_debug = 0; - return(-EINVAL); - } - return(0); - case SIOCSIFLINK: - printk("UNIX: cannot link streams!\n"); - break; - default: - break; - } - return(ret); -} - - - - -static struct file_operations unix_fops = { - NULL, /* LSEEK */ - NULL, /* READ */ - NULL, /* WRITE */ - NULL, /* READDIR */ - NULL, /* SELECT */ - unix_ioctl, /* IOCTL */ - NULL, /* MMAP */ - unix_open, /* OPEN */ - unix_close /* CLOSE */ -}; - - static struct proto_ops unix_proto_ops = { AF_UNIX, unix_proto_create, @@ -926,16 +765,9 @@ void -unix_proto_init(struct ddi_proto *pro) +unix_proto_init(struct net_proto *pro) { struct unix_proto_data *upd; - - dprintf(1, "%s: init: initializing...\n", pro->name); - if (register_chrdev(AF_UNIX_MAJOR, "af_unix", &unix_fops) < 0) { - printk("%s: cannot register major device %d!\n", - pro->name, AF_UNIX_MAJOR); - return; - } /* Tell SOCKET that we are alive... */ (void) sock_register(unix_proto_ops.family, &unix_proto_ops); diff -u --recursive --new-file v1.1.12/linux/net/unix/unix.h linux/net/unix/unix.h --- v1.1.12/linux/net/unix/unix.h Fri Mar 4 09:25:21 1994 +++ linux/net/unix/unix.h Mon May 23 08:17:55 1994 @@ -66,4 +66,4 @@ #endif /* _LINUX_UN_H */ -extern void unix_proto_init(struct ddi_proto *pro); +extern void unix_proto_init(struct net_proto *pro);