diff -u --recursive --new-file v1.3.80/linux/CREDITS linux/CREDITS --- v1.3.80/linux/CREDITS Mon Mar 25 08:58:19 1996 +++ linux/CREDITS Fri Mar 29 09:38:46 1996 @@ -1129,10 +1129,10 @@ S: USA N: Simmule Turner -E: simmy@digex.com +E: sturner@tele-tv.com D: Added swapping to filesystem -S: 8504 16th Street #406 -S: Silver Spring, Maryland 20910 +S: 4226 Landgreen Street +S: Rockville, Maryland 20853 S: USA N: Stephen Tweedie diff -u --recursive --new-file v1.3.80/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v1.3.80/linux/Documentation/Configure.help Wed Mar 27 08:19:28 1996 +++ linux/Documentation/Configure.help Sat Mar 30 13:20:33 1996 @@ -2815,6 +2815,13 @@ plugging in a COM port (9 or 25 pins) which is supported automatically. +Support for user miscellaneous modules +CONFIG_UMISC + This option forces generic miscellaneous minor device support in the + kernel, and allows later loading of user miscellaneous device modules, + such as drivers for optic pens and touchscreens. Unless you need such + specific modules, or are willing to write/test one, just say N. + QIC-02 tape support CONFIG_QIC02_TAPE If you have a non-SCSI tape drive like that, say Y. diff -u --recursive --new-file v1.3.80/linux/Documentation/framerelay.txt linux/Documentation/framerelay.txt --- v1.3.80/linux/Documentation/framerelay.txt Mon Mar 25 08:58:20 1996 +++ linux/Documentation/framerelay.txt Thu Jan 1 02:00:00 1970 @@ -1,33 +0,0 @@ -Frame Relay (FR) support for linux is built into a two tiered system of device -drivers. The upper layer implements RFC1490 FR specification, and uses the -Data Link Connection Identifier (DLCI) as it's hardware address. Usually these -are assigned by your network supplier, they give you the number/numbers of -the Virtual Connections (VC) assigned to you. - -Each DLCI is a point-to-point link between your machine and a remote one. -As such, a seperate device is needed to accomodate the routing. Within the -net-tools archives is 'dlcicfg'. This program will communicate with the -base "DLCI" device, and create new net devices named 'dlci00', 'dlci01'... -The configuration script will ask you how many DLCI's you need, as well as -how many DLCI's you want to assign to each Frame Relay Access Device (FRAD). - -The DLCI uses a number of function calls to communicate with the FRAD, all -of which are stored in the FRAD's private data area. assoc/deassoc, -activate/deactivate and dlci_config. The DLCI supplies a receive function -to the FRAD to accept incoming packets. - -With this initial offering, only 1 FRAD driver is available. With many thanks -to Sangoma Technologies, David Mandelstam & Gene Kozin, the S502A, S502E & -S508 are supported. This driver is currently set up for only FR, but as -Sangoma makes more firmware modules available, it can be updated to provide -them as well. - -Configuration of the FRAD makes use of another net-tools program, 'fradcfg'. -This program makes use of a configuration file (which dlcicfg can also read) -to specify the types of boards to be configured as FRADs, as well as perform -any board specific configuration. The Sangoma module of fradcfg loads the -FR firmware into the card, sets the irq/port/memory information, and provides -an initial configuration. - -Additional FRAD device drivers can be added as hardware is available. - diff -u --recursive --new-file v1.3.80/linux/Documentation/networking/framerelay.txt linux/Documentation/networking/framerelay.txt --- v1.3.80/linux/Documentation/networking/framerelay.txt Thu Jan 1 02:00:00 1970 +++ linux/Documentation/networking/framerelay.txt Sat Mar 30 13:20:33 1996 @@ -0,0 +1,33 @@ +Frame Relay (FR) support for linux is built into a two tiered system of device +drivers. The upper layer implements RFC1490 FR specification, and uses the +Data Link Connection Identifier (DLCI) as it's hardware address. Usually these +are assigned by your network supplier, they give you the number/numbers of +the Virtual Connections (VC) assigned to you. + +Each DLCI is a point-to-point link between your machine and a remote one. +As such, a seperate device is needed to accomodate the routing. Within the +net-tools archives is 'dlcicfg'. This program will communicate with the +base "DLCI" device, and create new net devices named 'dlci00', 'dlci01'... +The configuration script will ask you how many DLCI's you need, as well as +how many DLCI's you want to assign to each Frame Relay Access Device (FRAD). + +The DLCI uses a number of function calls to communicate with the FRAD, all +of which are stored in the FRAD's private data area. assoc/deassoc, +activate/deactivate and dlci_config. The DLCI supplies a receive function +to the FRAD to accept incoming packets. + +With this initial offering, only 1 FRAD driver is available. With many thanks +to Sangoma Technologies, David Mandelstam & Gene Kozin, the S502A, S502E & +S508 are supported. This driver is currently set up for only FR, but as +Sangoma makes more firmware modules available, it can be updated to provide +them as well. + +Configuration of the FRAD makes use of another net-tools program, 'fradcfg'. +This program makes use of a configuration file (which dlcicfg can also read) +to specify the types of boards to be configured as FRADs, as well as perform +any board specific configuration. The Sangoma module of fradcfg loads the +FR firmware into the card, sets the irq/port/memory information, and provides +an initial configuration. + +Additional FRAD device drivers can be added as hardware is available. + diff -u --recursive --new-file v1.3.80/linux/MAINTAINERS linux/MAINTAINERS --- v1.3.80/linux/MAINTAINERS Mon Mar 25 08:58:20 1996 +++ linux/MAINTAINERS Sat Mar 30 12:14:55 1996 @@ -102,6 +102,12 @@ L: linux-scsi@vger.rutgers.edu S: Odd fixes (e.g., new signatures) +SCSI TAPE DRIVER +P: Kai Mdkisara +M: Kai.Makisara@metla.fi +L: linux-scsi@vger.rutgers.edu +S: Maintained + FTAPE/QIC-117: P: Kai Harrekilde-Petersen M: khp@@dolphinics.no diff -u --recursive --new-file v1.3.80/linux/Makefile linux/Makefile --- v1.3.80/linux/Makefile Thu Mar 28 17:34:33 1996 +++ linux/Makefile Fri Mar 29 13:06:45 1996 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 80 +SUBLEVEL = 81 ARCH = i386 diff -u --recursive --new-file v1.3.80/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v1.3.80/linux/arch/alpha/config.in Sun Mar 24 12:09:35 1996 +++ linux/arch/alpha/config.in Sat Mar 30 11:48:51 1996 @@ -43,10 +43,17 @@ define_bool CONFIG_PCI y define_bool CONFIG_ALPHA_LCA y fi +if [ "$CONFIG_ALPHA_AVANTI" = "y" ] +then + bool 'Is it really a true XL' CONFIG_ALPHA_XL +fi if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \ -o "$CONFIG_ALPHA_EB64P" = "y" ] then - bool 'Using SRM as bootloader' CONFIG_ALPHA_SRM + if [ "$CONFIG_ALPHA_XL" = "n" ] + then + bool 'Using SRM as bootloader' CONFIG_ALPHA_SRM + fi define_bool CONFIG_PCI y define_bool CONFIG_ALPHA_APECS y fi diff -u --recursive --new-file v1.3.80/linux/arch/alpha/kernel/apecs.c linux/arch/alpha/kernel/apecs.c --- v1.3.80/linux/arch/alpha/kernel/apecs.c Sat Feb 17 09:19:36 1996 +++ linux/arch/alpha/kernel/apecs.c Sat Mar 30 11:48:51 1996 @@ -393,10 +393,34 @@ unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end) { + +#ifdef CONFIG_ALPHA_XL + /* + * Set up the PCI->physical memory translation windows. + * For the XL we *must* use both windows, in order to + * maximize the amount of physical memory that can be used + * to DMA from the ISA bus, and still allow PCI bus devices + * access to all of host memory. + * + * see for window bases and sizes. + * + * this restriction due to the true XL motherboards' 82379AB SIO + * PCI<->ISA bridge chip which passes only 27 bits of address... + */ + + *(vuip)APECS_IOC_PB1R = 1U<<19 | (APECS_XL_DMA_WIN1_BASE & 0xfff00000U); + *(vuip)APECS_IOC_PM1R = (APECS_XL_DMA_WIN1_SIZE - 1) & 0xfff00000U; + *(vuip)APECS_IOC_TB1R = 0; + + *(vuip)APECS_IOC_PB2R = 1U<<19 | (APECS_XL_DMA_WIN2_BASE & 0xfff00000U); + *(vuip)APECS_IOC_PM2R = (APECS_XL_DMA_WIN2_SIZE - 1) & 0xfff00000U; + *(vuip)APECS_IOC_TB2R = 0; + +#else /* CONFIG_ALPHA_XL */ /* * Set up the PCI->physical memory translation windows. - * For now, window 1 is disabled. In the future, we may - * want to use it to do scatter/gather DMA. Window 0 + * For now, window 2 is disabled. In the future, we may + * want to use it to do scatter/gather DMA. Window 1 * goes at 1 GB and is 1 GB large. */ *(vuip)APECS_IOC_PB2R = 0U; /* disable window 2 */ @@ -404,6 +428,7 @@ *(vuip)APECS_IOC_PB1R = 1U<<19 | (APECS_DMA_WIN_BASE & 0xfff00000U); *(vuip)APECS_IOC_PM1R = (APECS_DMA_WIN_SIZE - 1) & 0xfff00000U; *(vuip)APECS_IOC_TB1R = 0; +#endif /* CONFIG_ALPHA_XL */ #ifdef CONFIG_ALPHA_CABRIOLET /* diff -u --recursive --new-file v1.3.80/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c --- v1.3.80/linux/arch/alpha/kernel/bios32.c Thu Feb 29 08:35:24 1996 +++ linux/arch/alpha/kernel/bios32.c Sat Mar 30 11:48:51 1996 @@ -82,7 +82,20 @@ #if PCI_MODIFY static unsigned int io_base = 64*KB; /* <64KB are (E)ISA ports */ + +#if defined(CONFIG_ALPHA_XL) +/* + an AVANTI *might* be an XL, and an XL has only 27 bits of ISA address + that get passed through the PCI<->ISA bridge chip. Because this causes + us to set the PCI->Mem window bases lower than normal, we've gotta allocate + PCI bus devices' memory addresses *above* the PCI<->memory mapping windows, + so that CPU memory DMA addresses issued by a bus device don't conflict + with bus memory addresses, like frame buffer memory for graphics cards. +*/ +static unsigned int mem_base = 1024*MB; +#else /* CONFIG_ALPHA_XL */ static unsigned int mem_base = 16*MB; /* <16MB is ISA memory */ +#endif /* CONFIG_ALPHA_XL */ /* * Disable PCI device DEV so that it does not respond to I/O or memory @@ -418,7 +431,7 @@ * or 0x398/0x399. Unfortunately, autodetecting which base address is * in use works only once (right after a reset). The Super I/O chip * has the additional quirk that configuration register data must be - * written twice (I believe this is a saftey feature to prevent + * written twice (I believe this is a safety feature to prevent * accidental modification---fun, isn't it?). */ static inline void enable_ide(long ide_base) diff -u --recursive --new-file v1.3.80/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c --- v1.3.80/linux/arch/alpha/mm/init.c Wed Mar 13 18:57:48 1996 +++ linux/arch/alpha/mm/init.c Sat Mar 30 11:48:51 1996 @@ -21,6 +21,7 @@ #include #include #include +#include extern void die_if_kernel(char *,struct pt_regs *,long); extern void show_net_buffers(void); @@ -156,6 +157,8 @@ } for (tmp = PAGE_OFFSET ; tmp < high_memory ; tmp += PAGE_SIZE) { + if (tmp >= MAX_DMA_ADDRESS) + mem_map[MAP_NR(tmp)].dma = 0; if (mem_map[MAP_NR(tmp)].reserved) continue; mem_map[MAP_NR(tmp)].count = 1; diff -u --recursive --new-file v1.3.80/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v1.3.80/linux/arch/i386/defconfig Mon Mar 25 10:00:22 1996 +++ linux/arch/i386/defconfig Sat Mar 30 13:49:11 1996 @@ -147,6 +147,7 @@ # CONFIG_PSMOUSE is not set # CONFIG_MS_BUSMOUSE is not set # CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_UMISC is not set # CONFIG_QIC02_TAPE is not set # CONFIG_FTAPE is not set # CONFIG_APM is not set diff -u --recursive --new-file v1.3.80/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v1.3.80/linux/drivers/block/ll_rw_blk.c Thu Mar 28 17:34:34 1996 +++ linux/drivers/block/ll_rw_blk.c Fri Mar 29 13:06:04 1996 @@ -306,7 +306,7 @@ return; } kstat.pgpgin++; - max_req = NR_REQUEST; /* reads take precedence */ + max_req = (major == MD_MAJOR) ? NR_REQUEST/2 : NR_REQUEST; /* reads take precedence */ break; case WRITEA: rw_ahead = 1; @@ -322,7 +322,7 @@ * requests are only for reads. */ kstat.pgpgout++; - max_req = (NR_REQUEST * 2) / 3; + max_req = (major == MD_MAJOR) ? NR_REQUEST/3 : (NR_REQUEST * 2) / 3; break; default: printk("make_request: bad block dev cmd, must be R/W/RA/WA\n"); diff -u --recursive --new-file v1.3.80/linux/drivers/block/xd.c linux/drivers/block/xd.c --- v1.3.80/linux/drivers/block/xd.c Fri Mar 1 07:50:39 1996 +++ linux/drivers/block/xd.c Fri Mar 29 13:06:11 1996 @@ -70,7 +70,7 @@ { 0x0008,"06/24/88(C) Copyright 1988 Western Digital Corp.",xd_wd_init_controller,xd_wd_init_drive," Western Digital WDXT-GEN2" }, /* Dan Newcombe, newcombe@aa.csc.peachnet.edu */ { 0x0015,"SEAGATE ST11 BIOS REVISION",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Salvador Abreu, spa@fct.unl.pt */ { 0x0010,"ST11R BIOS",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Risto Kankkunen, risto.kankkunen@cs.helsinki.fi */ - { 0x0010,"ST11 BIOS V1.7",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11R" }, /* Alan Hourihane, alanh@fairlite.demon.co.uk */ + { 0x0010,"ST11 BIOS v1.7",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11R" }, /* Alan Hourihane, alanh@fairlite.demon.co.uk */ { 0x1000,"(c)Copyright 1987 SMS",xd_omti_init_controller,xd_omti_init_drive,"n OMTI 5520" }, /* Dirk Melchers, dirk@merlin.nbg.sub.org */ }; static u_char *xd_bases[] = diff -u --recursive --new-file v1.3.80/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v1.3.80/linux/drivers/char/Config.in Wed Mar 6 15:07:18 1996 +++ linux/drivers/char/Config.in Sat Mar 30 13:20:33 1996 @@ -19,6 +19,7 @@ fi tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE +bool 'Support for user misc device modules' CONFIG_UMISC bool 'QIC-02 tape support' CONFIG_QIC02_TAPE if [ "$CONFIG_QIC02_TAPE" = "y" ]; then diff -u --recursive --new-file v1.3.80/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v1.3.80/linux/drivers/char/Makefile Wed Mar 6 15:07:18 1996 +++ linux/drivers/char/Makefile Sat Mar 30 13:20:33 1996 @@ -100,10 +100,15 @@ endif endif +ifeq ($(CONFIG_UMISC),y) +# To support third-party modules, misc.c must reside in the kernel +M = y +endif + ifdef CONFIG_SOFT_WATCHDOG L_OBJS += softdog.o M = y -# This is not modularized, so if configured then "mouse.c" will be resident +# This is not modularized, so if configured then "misc.c" will be resident endif ifeq ($(CONFIG_WDT),y) @@ -134,10 +139,10 @@ endif ifdef M -LX_OBJS += mouse.o +LX_OBJS += misc.o else ifdef MM - MX_OBJS += mouse.o + MX_OBJS += misc.o endif endif diff -u --recursive --new-file v1.3.80/linux/drivers/char/atixlmouse.c linux/drivers/char/atixlmouse.c --- v1.3.80/linux/drivers/char/atixlmouse.c Fri Mar 1 07:50:40 1996 +++ linux/drivers/char/atixlmouse.c Sat Mar 30 13:20:33 1996 @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include @@ -194,7 +194,7 @@ fasync_mouse, }; -static struct mouse atixl_mouse = { +static struct miscdevice atixl_mouse = { ATIXL_BUSMOUSE, "atixl", &atixl_busmouse_fops }; @@ -222,7 +222,7 @@ mouse.dx = mouse.dy = 0; mouse.wait = NULL; printk("Bus mouse detected and installed.\n"); - mouse_register(&atixl_mouse); + misc_register(&atixl_mouse); return 0; } @@ -235,6 +235,6 @@ void cleanup_module(void) { - mouse_deregister(&atixl_mouse); + misc_deregister(&atixl_mouse); } #endif diff -u --recursive --new-file v1.3.80/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c --- v1.3.80/linux/drivers/char/busmouse.c Fri Mar 1 07:50:40 1996 +++ linux/drivers/char/busmouse.c Sat Mar 30 13:20:33 1996 @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include @@ -240,7 +240,7 @@ fasync_mouse, }; -static struct mouse bus_mouse = { +static struct miscdevice bus_mouse = { LOGITECH_BUSMOUSE, "busmouse", &bus_mouse_fops }; @@ -272,7 +272,7 @@ mouse.wait = NULL; printk("Logitech bus mouse detected, using IRQ %d.\n", mouse_irq); - mouse_register(&bus_mouse); + misc_register(&bus_mouse); return 0; } @@ -285,7 +285,7 @@ void cleanup_module(void) { - mouse_deregister(&bus_mouse); + misc_deregister(&bus_mouse); release_region(LOGIBM_BASE, LOGIBM_EXTENT); } #endif diff -u --recursive --new-file v1.3.80/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c --- v1.3.80/linux/drivers/char/keyboard.c Sun Mar 3 15:31:52 1996 +++ linux/drivers/char/keyboard.c Sat Mar 30 11:48:51 1996 @@ -343,12 +343,30 @@ static unsigned int prev_scancode = 0; /* remember E0, E1 */ char up_flag; /* 0 or 0200 */ char raw_mode; + int status; pt_regs = regs; send_cmd(0xAD); /* disable keyboard */ kb_wait(); - if ((inb_p(0x64) & kbd_read_mask) != 0x01) - goto end_kbd_intr; + status = inb_p(0x64); + if ((status & kbd_read_mask) != 0x01) { + /* + * On some platforms (Alpha XL for one), the init code may leave + * an interrupt hanging, yet with status indicating no data. + * After making sure that there's no data indicated and its not a + * mouse interrupt, we will read the data register to clear it. + * If we don't do this, the data reg stays full and will not + * allow new data or interrupt from the keyboard. Sigh... + */ + if (!(status & 0x21)) { /* neither ODS nor OBF */ + scancode = inb(0x60); /* read data anyway */ +#if 0 + printk("keyboard: status 0x%x mask 0x%x data 0x%x\n", + status, kbd_read_mask, scancode); +#endif + } + goto end_kbd_intr; + } scancode = inb(0x60); mark_bh(KEYBOARD_BH); if (reply_expected) { diff -u --recursive --new-file v1.3.80/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v1.3.80/linux/drivers/char/mem.c Thu Mar 7 15:59:02 1996 +++ linux/drivers/char/mem.c Sat Mar 30 13:20:33 1996 @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include @@ -387,10 +387,10 @@ #ifdef CONFIG_PRINTER lp_init(); #endif -#if defined (CONFIG_BUSMOUSE) || \ +#if defined (CONFIG_BUSMOUSE) || defined(CONFIG_UMISC) || \ defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \ defined (CONFIG_ATIXL_BUSMOUSE) || defined(CONFIG_SOFT_WATCHDOG) - mouse_init(); + misc_init(); #endif #ifdef CONFIG_SOUND soundcard_init(); diff -u --recursive --new-file v1.3.80/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v1.3.80/linux/drivers/char/misc.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/char/misc.c Sat Mar 30 13:20:33 1996 @@ -0,0 +1,204 @@ +/* + * linux/drivers/char/misc.c + * + * Generic misc open routine by Johan Myreen + * + * Based on code from Linus + * + * Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's + * changes incorporated into 0.97pl4 + * by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92) + * See busmouse.c for particulars. + * + * Made things a lot mode modular - easy to compile in just one or two + * of the misc drivers, as they are now completely independent. Linus. + * + * Support for loadable modules. 8-Sep-95 Philip Blundell + * + * Fixed a failing symbol register to free the device registration + * Alan Cox 21-Jan-96 + * + * Dynamic minors and /proc/mice by Alessandro Rubini. 26-Mar-96 + * + * Renamed to misc and miscdevice to be more accurate. Alan Cox 26-May-96 + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* needed by selection.h */ +#include "selection.h" /* export its symbols */ + +/* + * Head entry for the doubly linked miscdevice list + */ +static struct miscdevice misc_list = { 0, "head", NULL, &misc_list, &misc_list }; + +/* + * Assigned numbers, used for dynamic minors + */ +#define DYNAMIC_MINORS 64 /* like dynamic majors */ +static unsigned char misc_minors[DYNAMIC_MINORS / 8]; + +#ifndef MODULE +extern int bus_mouse_init(void); +extern int psaux_init(void); +extern int ms_bus_mouse_init(void); +extern int atixl_busmouse_init(void); +extern void watchdog_init(void); + +#ifdef CONFIG_PROC_FS +static int proc_misc_read(char *buf, char **start, off_t offset, int len, int unused) +{ + struct miscdevice *p; + + len=0; + for (p = misc_list.next; p != &misc_list; p = p->next) + len += sprintf(buf+len, "%3i %s\n",p->minor, p->name ?: ""); + return len; +} + +#endif /* PROC_FS */ +#endif /* !MODULE */ + +static int misc_open(struct inode * inode, struct file * file) +{ + int minor = MINOR(inode->i_rdev); + struct miscdevice *c = misc_list.next; + file->f_op = NULL; + + while (c != &misc_list) { + if (c->minor == minor) { + file->f_op = c->fops; + break; + } + c = c->next; + } + + if (file->f_op == NULL) + return -ENODEV; + return file->f_op->open(inode,file); +} + +static struct file_operations misc_fops = { + NULL, /* seek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + misc_open, + NULL /* release */ +}; + +int misc_register(struct miscdevice * misc) +{ + if (misc->next || misc->prev) + return -EBUSY; + if (misc->minor == MISC_DYNAMIC_MINOR) { + int i = DYNAMIC_MINORS; + while (--i >= 0) + if ( (misc_minors[i>>3] & (1 << (i&7))) == 0) + break; + if (i<0) return -EBUSY; + misc->minor = i; + } + if (misc->minor < DYNAMIC_MINORS) + misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7); + MOD_INC_USE_COUNT; + misc->next = &misc_list; + misc->prev = misc_list.prev; + misc->prev->next = misc; + misc->next->prev = misc; + return 0; +} + +int misc_deregister(struct miscdevice * misc) +{ + int i = misc->minor; + if (!misc->next || !misc->prev) + return -EINVAL; + MOD_DEC_USE_COUNT; + misc->prev->next = misc->next; + misc->next->prev = misc->prev; + misc->next = NULL; + misc->prev = NULL; + if (i < DYNAMIC_MINORS && i>0) { + misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); + } + return 0; +} + +#ifdef MODULE + +#define misc_init init_module + +void cleanup_module(void) +{ + unregister_chrdev(MOUSE_MAJOR, "misc"); +} + +#endif + +static struct symbol_table misc_syms = { +/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */ +#include + X(misc_register), + X(misc_deregister), +#ifndef MODULE + X(set_selection), /* used by the kmisc module, can only */ + X(clear_selection), /* be exported if misc.c is in linked in */ +#endif +#include +}; + +int misc_init(void) +{ +#ifndef MODULE +#ifdef CONFIG_PROC_FS + proc_register_dynamic(&proc_root, &(struct proc_dir_entry) { + 0, 4, "misc", + S_IRUGO, 1, 0, 0, + 0, NULL /* ops -- default to array */, + &proc_misc_read /* get_info */, + }); +#endif /* PROC_FS */ +#ifdef CONFIG_BUSMOUSE + bus_mouse_init(); +#endif +#if defined CONFIG_PSMOUSE || defined CONFIG_82C710_MOUSE + psaux_init(); +#endif +#ifdef CONFIG_MS_BUSMOUSE + ms_bus_mouse_init(); +#endif +#ifdef CONFIG_ATIXL_BUSMOUSE + atixl_busmouse_init(); +#endif +#ifdef CONFIG_SOFT_WATCHDOG + watchdog_init(); +#endif +#endif /* !MODULE */ + if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { + printk("unable to get major %d for misc devices\n", + MISC_MAJOR); + return -EIO; + } + + if(register_symtab(&misc_syms)!=0) + { + unregister_chrdev(MISC_MAJOR, "misc"); + return -EIO; + } + return 0; +} diff -u --recursive --new-file v1.3.80/linux/drivers/char/mouse.c linux/drivers/char/mouse.c --- v1.3.80/linux/drivers/char/mouse.c Wed Feb 7 08:55:35 1996 +++ linux/drivers/char/mouse.c Thu Jan 1 02:00:00 1970 @@ -1,149 +0,0 @@ -/* - * linux/drivers/char/mouse.c - * - * Generic mouse open routine by Johan Myreen - * - * Based on code from Linus - * - * Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's - * changes incorporated into 0.97pl4 - * by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92) - * See busmouse.c for particulars. - * - * Made things a lot mode modular - easy to compile in just one or two - * of the mouse drivers, as they are now completely independent. Linus. - * - * Support for loadable modules. 8-Sep-95 Philip Blundell - * - * Fixed a failing symbol register to free the device registration - * Alan Cox 21-Jan-96 - */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -/* - * Head entry for the doubly linked mouse list - */ -static struct mouse mouse_list = { 0, "head", NULL, &mouse_list, &mouse_list }; - -#ifndef MODULE -extern int bus_mouse_init(void); -extern int psaux_init(void); -extern int ms_bus_mouse_init(void); -extern int atixl_busmouse_init(void); -#endif - -static int mouse_open(struct inode * inode, struct file * file) -{ - int minor = MINOR(inode->i_rdev); - struct mouse *c = mouse_list.next; - file->f_op = NULL; - - while (c != &mouse_list) { - if (c->minor == minor) { - file->f_op = c->fops; - break; - } - c = c->next; - } - - if (file->f_op == NULL) - return -ENODEV; - return file->f_op->open(inode,file); -} - -static struct file_operations mouse_fops = { - NULL, /* seek */ - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* select */ - NULL, /* ioctl */ - NULL, /* mmap */ - mouse_open, - NULL /* release */ -}; - -int mouse_register(struct mouse * mouse) -{ - if (mouse->next || mouse->prev) - return -EBUSY; - MOD_INC_USE_COUNT; - mouse->next = &mouse_list; - mouse->prev = mouse_list.prev; - mouse->prev->next = mouse; - mouse->next->prev = mouse; - return 0; -} - -int mouse_deregister(struct mouse * mouse) -{ - if (!mouse->next || !mouse->prev) - return -EINVAL; - MOD_DEC_USE_COUNT; - mouse->prev->next = mouse->next; - mouse->next->prev = mouse->prev; - mouse->next = NULL; - mouse->prev = NULL; - return 0; -} - -#ifdef MODULE - -#define mouse_init init_module - -void cleanup_module(void) -{ - unregister_chrdev(MOUSE_MAJOR, "mouse"); -} - -#endif - -static struct symbol_table mouse_syms = { -/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */ -#include - X(mouse_register), - X(mouse_deregister), -#include -}; - -int mouse_init(void) -{ -#ifndef MODULE -#ifdef CONFIG_BUSMOUSE - bus_mouse_init(); -#endif -#if defined CONFIG_PSMOUSE || defined CONFIG_82C710_MOUSE - psaux_init(); -#endif -#ifdef CONFIG_MS_BUSMOUSE - ms_bus_mouse_init(); -#endif -#ifdef CONFIG_ATIXL_BUSMOUSE - atixl_busmouse_init(); -#endif -#ifdef CONFIG_SOFT_WATCHDOG - watchdog_init(); -#endif -#endif /* !MODULE */ - if (register_chrdev(MOUSE_MAJOR,"mouse",&mouse_fops)) { - printk("unable to get major %d for mouse devices\n", - MOUSE_MAJOR); - return -EIO; - } - - if(register_symtab(&mouse_syms)!=0) - { - unregister_chrdev(MOUSE_MAJOR, "mouse"); - return -EIO; - } - return 0; -} diff -u --recursive --new-file v1.3.80/linux/drivers/char/msbusmouse.c linux/drivers/char/msbusmouse.c --- v1.3.80/linux/drivers/char/msbusmouse.c Fri Mar 1 07:50:40 1996 +++ linux/drivers/char/msbusmouse.c Sat Mar 30 13:20:33 1996 @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include @@ -170,7 +170,7 @@ fasync_mouse, }; -static struct mouse ms_bus_mouse = { +static struct miscdevice ms_bus_mouse = { MICROSOFT_BUSMOUSE, "msbusmouse", &ms_bus_mouse_fops }; @@ -205,7 +205,7 @@ MS_MSE_INT_OFF(); request_region(MS_MSE_CONTROL_PORT, 0x04, "MS Busmouse"); printk("Microsoft BusMouse detected and installed.\n"); - mouse_register(&ms_bus_mouse); + misc_register(&ms_bus_mouse); return 0; } @@ -217,7 +217,7 @@ void cleanup_module(void) { - mouse_deregister(&ms_bus_mouse); + misc_deregister(&ms_bus_mouse); release_region(MS_MSE_CONTROL_PORT, 0x04); } #endif diff -u --recursive --new-file v1.3.80/linux/drivers/char/psaux.c linux/drivers/char/psaux.c --- v1.3.80/linux/drivers/char/psaux.c Fri Mar 1 07:50:40 1996 +++ linux/drivers/char/psaux.c Sat Mar 30 13:20:33 1996 @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include @@ -481,7 +481,7 @@ * Initialize driver. First check for a 82C710 chip; if found * forget about the Aux port and use the *_qp functions. */ -static struct mouse psaux_mouse = { +static struct miscdevice psaux_mouse = { PSMOUSE_MINOR, "ps2aux", &psaux_fops }; @@ -506,7 +506,7 @@ } else { return -EIO; } - mouse_register(&psaux_mouse); + misc_register(&psaux_mouse); queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); memset(queue, 0, sizeof(*queue)); queue->head = queue->tail = 0; @@ -538,7 +538,7 @@ void cleanup_module(void) { - mouse_deregister(&psaux_mouse); + misc_deregister(&psaux_mouse); } #endif diff -u --recursive --new-file v1.3.80/linux/drivers/char/selection.c linux/drivers/char/selection.c --- v1.3.80/linux/drivers/char/selection.c Mon Sep 18 07:42:44 1995 +++ linux/drivers/char/selection.c Sat Mar 30 13:20:33 1996 @@ -110,8 +110,8 @@ return v; } -/* set the current selection. Invoked by ioctl(). */ -int set_selection(const unsigned long arg, struct tty_struct *tty) +/* set the current selection. Invoked by ioctl() or by kernel code. */ +int set_selection(const unsigned long arg, struct tty_struct *tty, int user) { int sel_mode, new_sel_start, new_sel_end, spc; char *bp, *obp; @@ -122,12 +122,19 @@ { unsigned short *args, xs, ys, xe, ye; args = (unsigned short *)(arg + 1); - xs = get_user(args++) - 1; - ys = get_user(args++) - 1; - xe = get_user(args++) - 1; - ye = get_user(args++) - 1; - sel_mode = get_user(args); - + if (user) { + xs = get_user(args++) - 1; + ys = get_user(args++) - 1; + xe = get_user(args++) - 1; + ye = get_user(args++) - 1; + sel_mode = get_user(args); + } else { + xs = *(args++) - 1; /* set selection from kernel */ + ys = *(args++) - 1; + xe = *(args++) - 1; + ye = *(args++) - 1; + sel_mode = *args; + } xs = limit(xs, video_num_columns - 1); ys = limit(ys, video_num_lines - 1); xe = limit(xe, video_num_columns - 1); diff -u --recursive --new-file v1.3.80/linux/drivers/char/selection.h linux/drivers/char/selection.h --- v1.3.80/linux/drivers/char/selection.h Mon Mar 25 10:05:37 1996 +++ linux/drivers/char/selection.h Sat Mar 30 13:59:07 1996 @@ -6,7 +6,7 @@ extern int sel_cons; extern void clear_selection(void); -extern int set_selection(const unsigned long arg, struct tty_struct *tty); +extern int set_selection(const unsigned long arg, struct tty_struct *tty, int user); extern int paste_selection(struct tty_struct *tty); extern int sel_loadlut(const unsigned long arg); extern int mouse_reporting(void); diff -u --recursive --new-file v1.3.80/linux/drivers/char/softdog.c linux/drivers/char/softdog.c --- v1.3.80/linux/drivers/char/softdog.c Wed Feb 21 13:12:18 1996 +++ linux/drivers/char/softdog.c Sat Mar 30 13:20:33 1996 @@ -23,7 +23,7 @@ #include #include #include -#include +#include #define WATCHDOG_MINOR 130 #define TIMER_MARGIN (60*HZ) /* Allow 1 minute */ @@ -106,13 +106,13 @@ NULL, NULL /* Fasync */ }; - static struct mouse softdog_mouse={ + static struct miscdevice softdog_mouse={ WATCHDOG_MINOR, "softdog", &softdog_fops }; - mouse_register(&softdog_mouse); + misc_register(&softdog_mouse); init_timer(&watchdog_ticktock); watchdog_ticktock.function=watchdog_fire; printk("Software Watchdog Timer: 0.03\n"); diff -u --recursive --new-file v1.3.80/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v1.3.80/linux/drivers/char/tty_io.c Sat Mar 16 20:17:23 1996 +++ linux/drivers/char/tty_io.c Sat Mar 30 13:20:33 1996 @@ -1543,7 +1543,7 @@ return do_get_ps_info(arg); #endif case 2: - return set_selection(arg, tty); + return set_selection(arg, tty, 1); case 3: return paste_selection(tty); case 4: diff -u --recursive --new-file v1.3.80/linux/drivers/char/wdt.c linux/drivers/char/wdt.c --- v1.3.80/linux/drivers/char/wdt.c Fri Mar 1 07:50:41 1996 +++ linux/drivers/char/wdt.c Sat Mar 30 13:20:33 1996 @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include "wd501p.h" #include #include @@ -213,7 +213,7 @@ wdt_release }; -static struct mouse wdt_mouse= +static struct miscdevice wdt_mouse= { WATCHDOG_MINOR, "wdt", @@ -221,7 +221,7 @@ }; #ifdef CONFIG_WDT_501 -static struct mouse temp_mouse= +static struct miscdevice temp_mouse= { TEMP_MINOR, "temperature", @@ -251,7 +251,7 @@ { mouse_deregister(&wdt_mouse); #ifdef CONFIG_WDT_501 - mouse_deregister(&temp_mouse); + misc_deregister(&temp_mouse); #endif release_region(io,8); free_irq(irq, NULL); @@ -269,7 +269,7 @@ } mouse_register(&wdt_mouse); #ifdef CONFIG_WDT_501 - mouse_register(&temp_mouse); + misc_register(&temp_mouse); #endif request_region(io, 8, "wdt501"); return 0; diff -u --recursive --new-file v1.3.80/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v1.3.80/linux/drivers/net/Makefile Mon Mar 25 08:58:20 1996 +++ linux/drivers/net/Makefile Sat Mar 30 13:20:33 1996 @@ -166,10 +166,14 @@ ifeq ($(CONFIG_SLIP),y) L_OBJS += slip.o -CONFIG_SLHC_BUILTIN = y + ifeq ($(CONFIG_SLIP_COMPRESSED),y) + CONFIG_SLHC_BUILTIN = y + endif else ifeq ($(CONFIG_SLIP),m) - CONFIG_SLHC_MODULE = y + ifeq ($(CONFIG_SLIP_COMPRESSED),y) + CONFIG_SLHC_MODULE = y + endif M_OBJS += slip.o endif endif diff -u --recursive --new-file v1.3.80/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c --- v1.3.80/linux/drivers/net/ibmtr.c Wed Mar 27 08:19:28 1996 +++ linux/drivers/net/ibmtr.c Sat Mar 30 13:20:33 1996 @@ -1158,6 +1158,7 @@ __u32 dhb; unsigned char xmit_command; int i; + struct trllc *llc; if (readb(ti->asb + offsetof(struct asb_xmit_resp, ret_code))!=0xFF) DPRINTK("ASB not free !!!\n"); @@ -1169,13 +1170,14 @@ effective address where we will place data.*/ dhb=ti->sram +ntohs(readw(ti->arb + offsetof(struct arb_xmit_req, dhb_address))); + llc = (struct trllc *) &(ti->current_skb->data[sizeof(struct trh_hdr)]); xmit_command = readb(ti->srb + offsetof(struct srb_xmit, command)); writeb(xmit_command, ti->asb + offsetof(struct asb_xmit_resp, command)); writew(readb(ti->srb + offsetof(struct srb_xmit, station_id)), ti->asb + offsetof(struct asb_xmit_resp, station_id)); - writeb(EXTENDED_SAP, ti->asb + offsetof(struct asb_xmit_resp, rsap_value)); + writeb(llc->ssap, ti->asb + offsetof(struct asb_xmit_resp, rsap_value)); writeb(readb(ti->srb + offsetof(struct srb_xmit, cmd_corr)), ti->asb + offsetof(struct asb_xmit_resp, cmd_corr)); writeb(0, ti->asb + offsetof(struct asb_xmit_resp, ret_code)); @@ -1248,6 +1250,8 @@ unsigned int rbuffer_len, lan_hdr_len; unsigned int arb_frame_len; struct sk_buff *skb; + unsigned int skb_size = 0; + int is8022 = 0; rbuffer=(ti->sram +ntohs(readw(ti->arb + offsetof(struct arb_rec_req, rec_buf_addr)))); @@ -1293,6 +1297,11 @@ return; } + if ((readb(llc + offsetof(struct trllc, dsap))!=0xAA) || + (readb(llc + offsetof(struct trllc, ssap))!=0xAA)) { + is8022 = 1; + } + #if TR_VERBOSE if ((readb(llc + offsetof(struct trllc, dsap))!=0xAA) || (readb(llc + offsetof(struct trllc, ssap))!=0xAA)) { @@ -1322,8 +1331,12 @@ #endif arb_frame_len=ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len))); + skb_size = arb_frame_len-lan_hdr_len+sizeof(struct trh_hdr); + if (is8022) { + skb_size += sizeof(struct trllc); + } - if (!(skb=dev_alloc_skb(arb_frame_len-lan_hdr_len+sizeof(struct trh_hdr)))) { + if (!(skb=dev_alloc_skb(skb_size))) { DPRINTK("out of memory. frame dropped.\n"); ti->tr_stats.rx_dropped++; writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code)); @@ -1331,7 +1344,7 @@ return; } - skb_put(skb, arb_frame_len-lan_hdr_len+sizeof(struct trh_hdr)); + skb_put(skb, skb_size); skb->dev=dev; data=skb->data; @@ -1344,6 +1357,12 @@ data+=sizeof(struct trh_hdr); rbuffer_len=ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len))) -lan_hdr_len; + if (is8022) { + struct trllc *local_llc = (struct trllc *)data; + memset(local_llc, 0, sizeof(*local_llc)); + local_llc->ethertype = htons(ETH_P_TR_802_2); + data += sizeof(struct trllc); + } #if TR_VERBOSE DPRINTK("rbuffer_len: %d, data: %p\n", rbuffer_len, data); diff -u --recursive --new-file v1.3.80/linux/drivers/net/sdla.c linux/drivers/net/sdla.c --- v1.3.80/linux/drivers/net/sdla.c Mon Mar 25 10:06:28 1996 +++ linux/drivers/net/sdla.c Sat Mar 30 13:20:33 1996 @@ -344,24 +344,24 @@ case SDLA_RET_MODEM: state = data; if (*state & SDLA_MODEM_DCD_LOW) - printk(KERN_NOTICE "%s: Modem DCD unexpectedly low!\n", dev->name); + printk(KERN_INFO "%s: Modem DCD unexpectedly low!\n", dev->name); if (*state & SDLA_MODEM_CTS_LOW) - printk(KERN_NOTICE "%s: Modem CTS unexpectedly low!\n", dev->name); + printk(KERN_INFO "%s: Modem CTS unexpectedly low!\n", dev->name); /* I should probably do something about this! */ break; case SDLA_RET_CHANNEL_OFF: - printk(KERN_NOTICE "%s: Channel became inoperative!\n", dev->name); + printk(KERN_INFO "%s: Channel became inoperative!\n", dev->name); /* same here */ break; case SDLA_RET_CHANNEL_ON: - printk(KERN_NOTICE "%s: Channel became operative!\n", dev->name); + printk(KERN_INFO "%s: Channel became operative!\n", dev->name); /* same here */ break; case SDLA_RET_DLCI_STATUS: - printk(KERN_NOTICE "%s: Status change reported by Access Node.\n", dev->name); + printk(KERN_INFO "%s: Status change reported by Access Node.\n", dev->name); len /= sizeof(struct _dlci_stat); for(pstatus = data, i=0;i < len;i++,pstatus++) { @@ -376,14 +376,14 @@ else state = "unknown status"; - printk(KERN_NOTICE "%s: DLCI %i: %s.\n", dev->name, pstatus->dlci, state); + printk(KERN_INFO "%s: DLCI %i: %s.\n", dev->name, pstatus->dlci, state); /* same here */ } break; case SDLA_RET_DLCI_UNKNOWN: - printk(KERN_DEBUG "%s: Received unknown DLCIs:", dev->name); - len /= 2; + printk(KERN_INFO "%s: Received unknown DLCIs:", dev->name); + len /= sizeof(short); for(pdlci = data,i=0;i < len;i++,pdlci++) printk(" %i", *pdlci); printk("\n"); @@ -1058,6 +1058,7 @@ struct frad_local *flp; struct conf_data data; int i, err; + short size; if (dev->type == 0xFFFF) return(-EUNATCH); @@ -1127,11 +1128,22 @@ if (err) return(err); - sdla_cmd(dev, SDLA_READ_DLCI_CONFIGURATION, 0, 0, &data, sizeof(data), NULL, NULL); - memcpy(&flp->config, &data.config, sizeof(struct frad_conf)); + /* no sense reading if the CPU isnt' started */ + if (dev->start) + { + size = sizeof(data); + if (sdla_cmd(dev, SDLA_READ_DLCI_CONFIGURATION, 0, 0, NULL, 0, &data, &size) != SDLA_RET_OK) + return(-EIO); + } + else + if (flp->configured) + memcpy(&data.config, &flp->config, sizeof(struct frad_conf)); + else + memset(&data.config, 0, sizeof(struct frad_conf)); + memcpy(&flp->config, &data.config, sizeof(struct frad_conf)); data.config.flags &= ~SDLA_DIRECT_RECV; - data.config.mtu -= sizeof(struct fradhdr); + data.config.mtu -= data.config.mtu > sizeof(struct fradhdr) ? sizeof(struct fradhdr) : data.config.mtu; memcpy_tofs(conf, &data.config, sizeof(struct frad_conf)); } diff -u --recursive --new-file v1.3.80/linux/drivers/scsi/g_NCR5380.c linux/drivers/scsi/g_NCR5380.c --- v1.3.80/linux/drivers/scsi/g_NCR5380.c Wed Mar 20 10:50:02 1996 +++ linux/drivers/scsi/g_NCR5380.c Sat Mar 30 13:13:29 1996 @@ -553,7 +553,7 @@ static int sprint_Scsi_Cmnd (char* buffer, int len, Scsi_Cmnd *cmd) { int start = len; - PRINTP("destination target %d, lun %d\n" ANDP + PRINTP("host number %d destination target %d, lun %d\n" ANDP cmd->host->host_no ANDP cmd->target ANDP cmd->lun); @@ -562,7 +562,7 @@ return len-start; } -const char *const scsi_device_types[] = +const char *const private_scsi_device_types[] = { "Direct-Access ", "Sequential-Access", @@ -575,7 +575,7 @@ "Medium Changer ", "Communications " }; -#define MAX_SCSI_DEVICE_CODE sizeof(scsi_device_types)/sizeof(char*) +#define MAX_SCSI_DEVICE_CODE sizeof(private_scsi_device_types)/sizeof(char*) int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout) { @@ -630,7 +630,7 @@ long tr = hostdata->time_read[dev->id] / HZ; long tw = hostdata->time_write[dev->id] / HZ; - PRINTP(" T:%d %s " ANDP dev->id ANDP (dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int)dev->type] : "Unknown"); + PRINTP(" T:%d %s " ANDP dev->id ANDP (dev->type < MAX_SCSI_DEVICE_CODE) ? private_scsi_device_types[(int)dev->type] : "Unknown"); for (i=0; i<8; i++) if (dev->vendor[i] >= 0x20) *(buffer+(len++)) = dev->vendor[i]; @@ -644,13 +644,13 @@ *(buffer+(len++)) = dev->rev[i]; *(buffer+(len++)) = ' '; - PRINTP("\n%10d kb read in %5d secs" ANDP br/1024 ANDP tr); + PRINTP("\n%10ld kb read in %5ld secs" ANDP br/1024 ANDP tr); if (tr) - PRINTP(" @ %5d bps" ANDP br / tr); + PRINTP(" @ %5ld bps" ANDP br / tr); - PRINTP("\n%10d kb written in %5d secs" ANDP bw/1024 ANDP tw); + PRINTP("\n%10ld kb written in %5ld secs" ANDP bw/1024 ANDP tw); if (tw) - PRINTP(" @ %5d bps" ANDP bw / tw); + PRINTP(" @ %5ld bps" ANDP bw / tw); PRINTP("\n"); } } diff -u --recursive --new-file v1.3.80/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c --- v1.3.80/linux/drivers/scsi/seagate.c Fri Mar 1 07:50:54 1996 +++ linux/drivers/scsi/seagate.c Fri Mar 29 13:06:17 1996 @@ -1638,6 +1638,7 @@ unsigned char buf[256 + sizeof(int) * 2], cmd[6], *data, *page; int *sizes, result, formatted_sectors, total_sectors; int cylinders, heads, sectors; + int capacity; /* * Only SCSI-I CCS drives and later implement the necessary mode sense @@ -1718,12 +1719,22 @@ */ if ((cylinders > 1024) || (sectors > 64)) - result = -1; - else { - ip[0] = heads; - ip[1] = sectors; - ip[2] = cylinders; + /* The Seagate's seem to have some mapping + * Multiple heads * sectors * cyl to get capacity + * Then start rounding down. */ + capacity = heads * sectors * cylinders; + sectors = 17; /* Old MFM Drives use this, so does the Seagate */ + heads = 2; + capacity = capacity / sectors; + while (cylinders > 1024) + { + heads *= 2; /* For some reason, they go in multiples */ + cylinders = capacity / heads; + }; } + ip[0] = heads; + ip[1] = sectors; + ip[2] = cylinders; /* * There should be an alternate mapping for things the seagate doesn't diff -u --recursive --new-file v1.3.80/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v1.3.80/linux/drivers/scsi/sr.c Mon Mar 18 11:54:26 1996 +++ linux/drivers/scsi/sr.c Fri Mar 29 13:05:03 1996 @@ -1016,8 +1016,10 @@ scsi_CDs[i].sector_size = 2048; /* A guess, just in case */ scsi_CDs[i].needs_sector_size = 1; } else { - scsi_CDs[i].capacity = (buffer[0] << 24) | - (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; + scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) | + (buffer[1] << 16) | + (buffer[2] << 8) | + buffer[3]); scsi_CDs[i].sector_size = (buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; switch (scsi_CDs[i].sector_size) { @@ -1042,7 +1044,7 @@ scsi_CDs[i].needs_sector_size = 1; } scsi_CDs[i].needs_sector_size = 0; - sr_sizes[i] = scsi_CDs[i].capacity; + sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9); }; scsi_free(buffer, 512); } @@ -1103,7 +1105,7 @@ scsi_CDs[i].ten = 1; scsi_CDs[i].remap = 1; scsi_CDs[i].auto_eject = 0; /* Default is not to eject upon unmount. */ - sr_sizes[i] = scsi_CDs[i].capacity; + sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9); } diff -u --recursive --new-file v1.3.80/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v1.3.80/linux/drivers/scsi/st.c Wed Mar 13 08:38:54 1996 +++ linux/drivers/scsi/st.c Sat Mar 30 12:18:07 1996 @@ -11,7 +11,7 @@ Copyright 1992, 1993, 1994, 1995 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Mon Jan 29 21:18:12 1996 by root@kai.makisara.fi + Last modified: Fri Mar 29 20:55:05 1996 by root@kai.makisara.fi Some small formal changes - aeb, 950809 */ @@ -84,8 +84,8 @@ Scsi_Tape * scsi_tapes = NULL; -static ST_buffer *new_tape_buffer(int); -static int enlarge_buffer(ST_buffer *, int); +static ST_buffer *new_tape_buffer(int, int); +static int enlarge_buffer(ST_buffer *, int, int); static void normalize_buffer(ST_buffer *); static int st_init(void); @@ -171,7 +171,8 @@ scsi_tapes[dev].recover_count); } #endif - return 0; + if ((sense[2] & 0xe0) == 0) + return 0; } return (-EIO); } @@ -453,7 +454,7 @@ scsi_tape_open(struct inode * inode, struct file * filp) { unsigned short flags; - int i; + int i, need_dma_buffer; unsigned char cmd[10]; Scsi_Cmnd * SCpnt; Scsi_Tape * STp; @@ -471,13 +472,15 @@ STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0; /* Allocate buffer for this user */ + need_dma_buffer = STp->restr_dma; for (i=0; i < st_nbr_buffers; i++) - if (!st_buffers[i]->in_use) + if (!st_buffers[i]->in_use && + (!need_dma_buffer || st_buffers[i]->dma)) break; if (i >= st_nbr_buffers) { - STp->buffer = new_tape_buffer(FALSE); + STp->buffer = new_tape_buffer(FALSE, need_dma_buffer); if (STp->buffer == NULL) { - printk(KERN_WARNING "st%d: No free buffers.\n", dev); + printk(KERN_WARNING "st%d: Can't allocate tape buffer.\n", dev); return (-EBUSY); } } @@ -608,7 +611,7 @@ } if (STp->block_size > (STp->buffer)->buffer_size && - !enlarge_buffer(STp->buffer, STp->block_size)) { + !enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) { printk(KERN_NOTICE "st%d: Blocksize %d too large for buffer.\n", dev, STp->block_size); (STp->buffer)->in_use = 0; @@ -775,7 +778,7 @@ if (STp->block_size == 0 && count > (STp->buffer)->buffer_size && - !enlarge_buffer(STp->buffer, count)) + !enlarge_buffer(STp->buffer, count, STp->restr_dma)) return (-EOVERFLOW); if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && @@ -1016,7 +1019,7 @@ if (STp->block_size == 0 && count > (STp->buffer)->buffer_size && - !enlarge_buffer(STp->buffer, count)) + !enlarge_buffer(STp->buffer, count, STp->restr_dma)) return (-EOVERFLOW); if (!(STp->do_read_ahead) && STp->block_size != 0 && @@ -1968,7 +1971,7 @@ /* Try to allocate a new tape buffer */ static ST_buffer * -new_tape_buffer( int from_initialization ) +new_tape_buffer( int from_initialization, int need_dma ) { int priority, a_size; ST_buffer *tb; @@ -1977,16 +1980,18 @@ return NULL; /* Should never happen */ if (from_initialization) { - priority = GFP_ATOMIC | GFP_DMA; + priority = GFP_ATOMIC; a_size = st_buffer_size; } else { - priority = GFP_KERNEL | GFP_DMA; + priority = GFP_KERNEL; for (a_size = PAGE_SIZE; a_size < st_buffer_size; a_size <<= 1) ; /* Make sure we allocate efficiently */ } tb = (ST_buffer *)scsi_init_malloc(sizeof(ST_buffer), priority); if (tb) { + if (need_dma) + priority |= GFP_DMA; tb->b_data = (unsigned char *)scsi_init_malloc(a_size, priority); if (!tb->b_data) { scsi_init_free((char *)tb, sizeof(ST_buffer)); @@ -1998,13 +2003,14 @@ st_nbr_buffers); return NULL; } - #if DEBUG if (debugging) - printk(ST_DEB_MSG "st: Allocated tape buffer %d (%d bytes).\n", - st_nbr_buffers, a_size); + printk(ST_DEB_MSG + "st: Allocated tape buffer %d (%d bytes, dma: %d, a: %p).\n", + st_nbr_buffers, a_size, need_dma, tb->b_data); #endif tb->in_use = 0; + tb->dma = need_dma; tb->buffer_size = a_size; tb->writing = 0; tb->orig_b_data = NULL; @@ -2015,9 +2021,9 @@ /* Try to allocate a temporary enlarged tape buffer */ static int -enlarge_buffer(ST_buffer *STbuffer, int new_size) +enlarge_buffer(ST_buffer *STbuffer, int new_size, int need_dma) { - int a_size; + int a_size, priority; unsigned char *tbd; normalize_buffer(STbuffer); @@ -2025,13 +2031,17 @@ for (a_size = PAGE_SIZE; a_size < new_size; a_size <<= 1) ; /* Make sure that we allocate efficiently */ - tbd = (unsigned char *)scsi_init_malloc(a_size, GFP_DMA | GFP_KERNEL); + priority = GFP_KERNEL; + if (need_dma) + priority |= GFP_DMA; + tbd = (unsigned char *)scsi_init_malloc(a_size, priority); if (!tbd) return FALSE; - #if DEBUG if (debugging) - printk(ST_DEB_MSG "st: Buffer enlarged to %d bytes.\n", a_size); + printk(ST_DEB_MSG + "st: Buffer at %p enlarged to %d bytes (dma: %d, a: %p).\n", + STbuffer->b_data, a_size, need_dma, tbd); #endif STbuffer->orig_b_data = STbuffer->b_data; @@ -2056,8 +2066,8 @@ #if DEBUG if (debugging) - printk(ST_DEB_MSG "st: Buffer normalized to %d bytes.\n", - STbuffer->buffer_size); + printk(ST_DEB_MSG "st: Buffer at %p normalized to %d bytes.\n", + STbuffer->b_data, STbuffer->buffer_size); #endif } @@ -2123,6 +2133,7 @@ tpnt->waiting = NULL; tpnt->in_use = 0; tpnt->drv_buffer = 1; /* Try buffering if no mode sense */ + tpnt->restr_dma = (SDp->host)->unchecked_isa_dma; tpnt->density = 0; tpnt->do_buffer_writes = ST_BUFFER_WRITES; tpnt->do_async_writes = ST_ASYNC_WRITES; @@ -2131,9 +2142,10 @@ tpnt->two_fm = ST_TWO_FM; tpnt->fast_mteom = ST_FAST_MTEOM; tpnt->write_threshold = st_write_threshold; - tpnt->drv_block = 0; + tpnt->drv_block = (-1); tpnt->moves_after_eof = 1; tpnt->at_sm = 0; + (tpnt->mt_status)->mt_fileno = (tpnt->mt_status)->mt_blkno = (-1); st_template.nr_dev++; return 0; @@ -2238,8 +2250,9 @@ target_nbr = st_max_buffers; for (i=st_nbr_buffers=0; i < target_nbr; i++) { - if (!new_tape_buffer(TRUE)) { + if (!new_tape_buffer(TRUE, TRUE)) { if (i == 0) { +#if 0 printk(KERN_ERR "Can't continue without at least one tape buffer.\n"); unregister_chrdev(SCSI_TAPE_MAJOR, "st"); scsi_init_free((char *) st_buffers, @@ -2247,6 +2260,10 @@ scsi_init_free((char *) scsi_tapes, st_template.dev_max * sizeof(Scsi_Tape)); return 1; +#else + printk(KERN_INFO "No tape buffers allocated at initialization.\n"); + break; +#endif } printk(KERN_INFO "Number of tape buffers adjusted.\n"); break; diff -u --recursive --new-file v1.3.80/linux/drivers/scsi/st.h linux/drivers/scsi/st.h --- v1.3.80/linux/drivers/scsi/st.h Sun Dec 17 10:59:24 1995 +++ linux/drivers/scsi/st.h Sat Mar 30 12:18:07 1996 @@ -10,7 +10,8 @@ #endif typedef struct { - int in_use; + unsigned char in_use; + unsigned char dma; /* DMA-able buffer */ int buffer_size; int buffer_blocks; int buffer_bytes; @@ -37,6 +38,7 @@ unsigned char in_use; unsigned char eof_hit; unsigned char drv_buffer; + unsigned char restr_dma; unsigned char do_buffer_writes; unsigned char do_async_writes; unsigned char do_read_ahead; diff -u --recursive --new-file v1.3.80/linux/drivers/sound/.version linux/drivers/sound/.version --- v1.3.80/linux/drivers/sound/.version Sun Mar 24 22:56:00 1996 +++ linux/drivers/sound/.version Sat Mar 30 13:38:31 1996 @@ -1,2 +1,2 @@ -3.5.1 +3.5.2 0x030500 diff -u --recursive --new-file v1.3.80/linux/drivers/sound/.version.orig linux/drivers/sound/.version.orig --- v1.3.80/linux/drivers/sound/.version.orig Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/.version.orig Sun Mar 24 22:56:00 1996 @@ -0,0 +1,2 @@ +3.5.1 +0x030500 diff -u --recursive --new-file v1.3.80/linux/drivers/sound/CHANGELOG linux/drivers/sound/CHANGELOG --- v1.3.80/linux/drivers/sound/CHANGELOG Sun Mar 24 22:55:28 1996 +++ linux/drivers/sound/CHANGELOG Sat Mar 30 13:38:31 1996 @@ -1,6 +1,8 @@ -Changelog for version 3.5.1 +Changelog for version 3.5.2 --------------------------- +Since 3.5.1 +- TB Maui initialization support Since 3.5 - Improved handling of playback underrunt situations. diff -u --recursive --new-file v1.3.80/linux/drivers/sound/Readme linux/drivers/sound/Readme --- v1.3.80/linux/drivers/sound/Readme Sun Mar 24 22:55:43 1996 +++ linux/drivers/sound/Readme Sat Mar 30 13:38:31 1996 @@ -1,5 +1,5 @@ -Version 3.5.1 release notes ---------------------------- +Version 3.5.2 release notes +-------------------------------- Most up to date information about this driver is available from http://personal.eunet.fi/pp/voxware. diff -u --recursive --new-file v1.3.80/linux/drivers/sound/Readme.cards linux/drivers/sound/Readme.cards --- v1.3.80/linux/drivers/sound/Readme.cards Mon Mar 25 09:25:26 1996 +++ linux/drivers/sound/Readme.cards Sat Mar 30 13:38:31 1996 @@ -34,8 +34,6 @@ (Early 3.6-alpha versions?) - Sound Galaxy Washington/Waverider (3.6-alpha versions. Can't promise the waverider synth). - - TB Maui - (v3.6) - Yamaha OPL4 (on cards having _RAM_ for samples) (Late 96?. Works as OPL3 with current driver versions) @@ -180,8 +178,8 @@ Turtle Beach Maui and Tropez This driver version supports sample, patch and program loading commands - described in the Maui/Tropez User's manual. There is no initialization - code for Maui so it must be initialized with DOS. The audio side of + described in the Maui/Tropez User's manual. + There is now full initialization support too. The audio side of the Tropez is based on the MAD16 chip (see above). Jumpers and software configuration @@ -385,9 +383,8 @@ cards made by known manufacturers such as Turtle Beach (Tropez), Reveal (some models) and Diamond (some recent models). "Support for TB Maui" - - This is just an experimental extension to the MPU401 driver. - Don't enable this option unless you are writing a .MOD - player for Maui. + - This enables TB Maui spesific initialization. Works with TB Maui + and TB Tropez (may not work with Tropez Plus). "Audio Excel DSP 16 initialization support", - Don't know much about this card. Look at aedsp16.c for more info. diff -u --recursive --new-file v1.3.80/linux/drivers/sound/configure.c linux/drivers/sound/configure.c --- v1.3.80/linux/drivers/sound/configure.c Sun Mar 24 22:49:55 1996 +++ linux/drivers/sound/configure.c Sat Mar 30 13:38:31 1996 @@ -1470,6 +1470,39 @@ } } + if (selected_options & B (OPT_MAUI)) + { + oswf_again: + if (think_positively ( + "Do you have access to the OSWF.MOT file", 1, + "TB Maui and Tropez have a microcontroller which needs to be initialized\n" + "prior use. OSWF.MOT is a file distributed with card's DOS/Windows drivers\n" + "which is required during initialization\n")) + { + char path[512]; + + fprintf (stderr, + "Enter full name of the OSWF.MOT file (pwd is sound): "); + scanf ("%s", path); + fprintf (stderr, "including microcode file %s\n", path); + + if (!bin2hex (path, "maui_boot.h", "maui_os")) + { + fprintf (stderr, "Couldn't open file %s\n", + path); + if (think_positively ("Try again with correct path", 1, + "The specified file could not be opened. Enter the correct path to the\n" + "file.\n")) + goto oswf_again; + } + else + { + printf ("#define HAVE_MAUI_BOOT\n"); + printf ("/*build bin2hex %s maui_boot.h maui_os */\n", path); + } + } + } + if (!(selected_options & ANY_DEVS)) { printf ("invalid_configuration__run_make_config_again\n"); diff -u --recursive --new-file v1.3.80/linux/drivers/sound/maui.c linux/drivers/sound/maui.c --- v1.3.80/linux/drivers/sound/maui.c Sun Mar 24 22:50:06 1996 +++ linux/drivers/sound/maui.c Sat Mar 30 13:38:31 1996 @@ -55,6 +55,10 @@ static int (*orig_load_patch) (int dev, int format, const char *addr, int offs, int count, int pmgr_flag) = NULL; +#ifdef HAVE_MAUI_BOOT +#include "maui_boot.h" +#endif + static wait_handle *maui_sleeper = NULL; static volatile struct snd_wait maui_sleep_flag = {0}; @@ -139,6 +143,158 @@ irq_ok = 1; } +static int +download_code (void) +{ + int i, lines = 0; + int eol_seen = 0, done = 0; + int skip = 1; + + printk ("Code download (%d bytes): ", maui_osLen); + + for (i = 0; i < maui_osLen; i++) + { + if (maui_os[i] != '\r') + if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n'))) + { + skip = 0; + + if (maui_os[i] == '\n') + eol_seen = skip = 1; + else if (maui_os[i] == 'S') + { + if (maui_os[i + 1] == '8') + done = 1; + if (!maui_write (0xF1)) + goto failure; + if (!maui_write ('S')) + goto failure; + } + else + { + if (!maui_write (maui_os[i])) + goto failure; + } + + if (eol_seen) + { + int c = 0; + + int n; + + eol_seen = 0; + + for (n = 0; n < 2; n++) + if (maui_wait (STAT_RX_AVAIL)) + { + c = inb (HOST_DATA_PORT); + break; + } + + if (c != 0x80) + { + printk ("Doanload not acknowledged\n"); + return 0; + } + else if (!(lines++ % 10)) + printk ("."); + + if (done) + { + printk ("\nDownload complete\n"); + return 1; + } + } + } + } + +failure: + + printk ("\nDownload failed!!!\n"); + return 0; +} + +static int +maui_init (int irq) +{ + int i; + unsigned char bits; + + switch (irq) + { + case 9: + bits = 0x00; + break; + case 5: + bits = 0x08; + break; + case 12: + bits = 0x10; + break; + case 15: + bits = 0x18; + break; + + default: + printk ("Maui: Invalid IRQ %d\n", irq); + return 0; + } + + outb (0x00, HOST_CTRL_PORT); /* Reset */ + + outb (bits, HOST_DATA_PORT); /* Set the IRQ bits */ + outb (bits | 0x80, HOST_DATA_PORT); /* Set the IRQ bits again? */ + + outb (0x80, HOST_CTRL_PORT); /* Leave reset */ + outb (0x80, HOST_CTRL_PORT); /* Leave reset */ + + outb (0xD0, HOST_CTRL_PORT); /* Cause interrupt */ + + for (i = 0; i < 1000000 && !irq_ok; i++); + + if (!irq_ok) + return 0; + + outb (0x80, HOST_CTRL_PORT); /* Leave reset */ + + printk ("Turtle Beach Maui initialization\n"); + + if (!download_code ()) + return 0; + + outb (0xE0, HOST_CTRL_PORT); /* Normal operation */ + + /* Select mpu401 mode */ + + maui_write (0xf0); + maui_write (1); + if (maui_read () != 0x80) + { + maui_write (0xf0); + maui_write (1); + if (maui_read () != 0x80) + printk ("Maui didn't acknowledge set HW mode command\n"); + } + + printk ("Maui initialized OK\n"); + return 1; +} + +static int +maui_short_wait (int mask) +{ + int i; + + for (i = 0; i < 1000; i++) + { + if (inb (HOST_STAT_PORT) & mask) + { + return 1; + } + } + + return 0; +} int maui_load_patch (int dev, int format, const char *addr, @@ -222,6 +378,22 @@ return 0; maui_sleep_flag.mode = WK_NONE; +/* + * Initialize the processor if necessary + */ + + if (maui_osLen > 0) + { + if (!(inb (HOST_STAT_PORT) & STAT_TX_AVAIL) || + !maui_write (0x9F) || /* Report firmware version */ + !maui_short_wait (STAT_RX_AVAIL) || + maui_read () == -1 || maui_read () == -1) + if (!maui_init (hw_config->irq)) + { + snd_release_irq (hw_config->irq); + return 0; + } + } if (!maui_write (0xCF)) /* Report hardware version */ { diff -u --recursive --new-file v1.3.80/linux/drivers/sound/soundvers.h linux/drivers/sound/soundvers.h --- v1.3.80/linux/drivers/sound/soundvers.h Sun Mar 24 22:56:08 1996 +++ linux/drivers/sound/soundvers.h Sat Mar 30 13:38:31 1996 @@ -1,2 +1,2 @@ -#define SOUND_VERSION_STRING "3.5.1-960324" +#define SOUND_VERSION_STRING "3.5.2-960330" #define SOUND_INTERNAL_VERSION 0x030500 diff -u --recursive --new-file v1.3.80/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c --- v1.3.80/linux/drivers/sound/sscape.c Sun Mar 24 22:50:27 1996 +++ linux/drivers/sound/sscape.c Sat Mar 30 13:38:31 1996 @@ -1196,7 +1196,9 @@ void unload_sscape (struct address_info *hw_config) { +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) unload_mpu401 (hw_config); +#endif snd_release_irq (hw_config->irq); sound_free_dma (hw_config->dma); } diff -u --recursive --new-file v1.3.80/linux/fs/Config.in linux/fs/Config.in --- v1.3.80/linux/fs/Config.in Tue Mar 19 09:05:23 1996 +++ linux/fs/Config.in Fri Mar 29 09:10:17 1996 @@ -28,7 +28,7 @@ fi tristate 'SMB filesystem support (to mount WfW shares etc..)' CONFIG_SMB_FS fi -if [ "$CONFIG_IPX" = "y" ]; then +if [ "$CONFIG_IPX" != "n" ]; then tristate 'NCP filesystem support (to mount NetWare volumes)' CONFIG_NCP_FS fi tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS diff -u --recursive --new-file v1.3.80/linux/fs/pipe.c linux/fs/pipe.c --- v1.3.80/linux/fs/pipe.c Mon Feb 19 13:29:08 1996 +++ linux/fs/pipe.c Sat Mar 30 12:12:14 1996 @@ -14,6 +14,11 @@ #include #include +/* + * Define this if you want SunOS compatibility wrt braindead + * select behaviour on FIFO's. + */ +#undef FIFO_SUNOS_BRAINDAMAGE /* We don't use the head/tail construction any more. Now we use the start/len*/ /* construction providing full use of PIPE_BUF (multiple of PAGE_SIZE) */ @@ -169,6 +174,7 @@ return 0; } +#ifdef FIFO_SUNOS_BRAINDAMAGE /* * Arggh. Why does SunOS have to have different select() behaviour * for pipes and fifos? Hate-Hate-Hate. See difference in SEL_IN.. @@ -194,6 +200,11 @@ } return 0; } +#else + +#define fifo_select pipe_select + +#endif /* FIFO_SUNOS_BRAINDAMAGE */ /* * The 'connect_xxx()' functions are needed for named pipes when diff -u --recursive --new-file v1.3.80/linux/fs/proc/array.c linux/fs/proc/array.c --- v1.3.80/linux/fs/proc/array.c Thu Mar 21 08:55:09 1996 +++ linux/fs/proc/array.c Sat Mar 30 13:20:33 1996 @@ -1074,6 +1074,7 @@ int length; int end; unsigned int type, pid; + struct proc_dir_entry *dp; if (count < 0) return -EINVAL; @@ -1085,8 +1086,13 @@ pid = type >> 16; type &= 0x0000ffff; start = NULL; - length = fill_array((char *) page, pid, type, - &start, file->f_pos, count); + dp = (struct proc_dir_entry *) inode->u.generic_ip; + if (dp->get_info) + length = dp->get_info((char *)page, &start, file->f_pos, + count, 0); + else + length = fill_array((char *) page, pid, type, + &start, file->f_pos, count); if (length < 0) { free_page(page); return length; diff -u --recursive --new-file v1.3.80/linux/include/asm-alpha/apecs.h linux/include/asm-alpha/apecs.h --- v1.3.80/linux/include/asm-alpha/apecs.h Sun Mar 24 12:09:36 1996 +++ linux/include/asm-alpha/apecs.h Sat Mar 30 11:48:51 1996 @@ -18,10 +18,61 @@ * david.rusling@reo.mts.dec.com Initial Version. * */ +#include +#ifdef CONFIG_ALPHA_XL +/* + An AVANTI *might* be an XL, and an XL has only 27 bits of ISA address + that get passed through the PCI<->ISA bridge chip. So we've gotta use + both windows to max out the physical memory we can DMA to. Sigh... + + If we try a window at 0 for 1GB as a work-around, we run into conflicts + with ISA/PCI bus memory which can't be relocated, like VGA aperture and + BIOS ROMs. So we must put the windows high enough to avoid these areas. + + We put window 1 at BUS 64Mb for 64Mb, mapping physical 0 to 64Mb-1, + and window 2 at BUS 512Mb for 512Mb, mapping physical 0 to 512Mb-1. + Yes, this does map 0 to 64Mb-1 twice, but only window 1 will actually + be used for that range (via virt_to_bus()). + + Window 1 will be used for all DMA from the ISA bus; yes, that does + limit what memory an ISA floppy or soundcard or Ethernet can touch, but + it's also a known limitation on other platforms as well. We use the + same technique that is used on INTEL platforms with similar limitation: + set MAX_DMA_ADDRESS and clear some pages' DMAable flags during mem_init(). + We trust that any ISA bus device drivers will *always* ask for DMAable + memory explicitly via kmalloc()/get_free_pages() flags arguments. + + Note that most PCI bus devices' drivers do *not* explicitly ask for + DMAable memory; they count on being able to DMA to any memory they + get from kmalloc()/get_free_pages(). They will also use window 1 for + any physical memory accesses below 64Mb; the rest will be handled by + window 2, maxing out at 512Mb of memory. I trust this is enough... :-) + + Finally, the reason we make window 2 start at 512Mb for 512Mb, is so that + we can allocate PCI bus devices' memory starting at 1Gb and up, to ensure + that no conflicts occur and bookkeeping is simplified (ie we don't + try to fill the gap between the two windows, we just go above the top). + + Note that the XL is treated differently from the AVANTI, even though + for most other things they are identical. It didn't seem reasonable to + make the AVANTI support pay for the limitations of the XL. It is true, + however, that an XL kernel will run on an AVANTI without problems. + +*/ +#define APECS_XL_DMA_WIN1_BASE (64*1024*1024) +#define APECS_XL_DMA_WIN1_SIZE (64*1024*1024) +#define APECS_XL_DMA_WIN2_BASE (512*1024*1024) +#define APECS_XL_DMA_WIN2_SIZE (512*1024*1024) + +#else /* CONFIG_ALPHA_XL */ + +/* these are for normal APECS family machines, AVANTI/MUSTANG/EB64/PC64 */ #define APECS_DMA_WIN_BASE (1024*1024*1024) #define APECS_DMA_WIN_SIZE (1024*1024*1024) +#endif /* CONFIG_ALPHA_XL */ + /* * 21071-DA Control and Status registers. * These are used for PCI memory access. @@ -165,7 +216,15 @@ */ extern inline unsigned long virt_to_bus(void * address) { - return virt_to_phys(address) + APECS_DMA_WIN_BASE; + unsigned long paddr = virt_to_phys(address); +#ifdef CONFIG_ALPHA_XL + if (paddr < APECS_XL_DMA_WIN1_SIZE) + return paddr + APECS_XL_DMA_WIN1_BASE; + else + return paddr + APECS_XL_DMA_WIN2_BASE; /* win 2 xlates to 0 also */ +#else /* CONFIG_ALPHA_XL */ + return paddr + APECS_DMA_WIN_BASE; +#endif /* CONFIG_ALPHA_XL */ } extern inline void * bus_to_virt(unsigned long address) @@ -176,9 +235,18 @@ * detect null "pointers" (the NCR driver is much simpler if * NULL pointers are preserved). */ +#ifdef CONFIG_ALPHA_XL + if (address < APECS_XL_DMA_WIN1_BASE) + return 0; + else if (address < (APECS_XL_DMA_WIN1_BASE + APECS_XL_DMA_WIN1_SIZE)) + return phys_to_virt(address - APECS_XL_DMA_WIN1_BASE); + else /* should be more checking here, maybe? */ + return phys_to_virt(address - APECS_XL_DMA_WIN2_BASE); +#else /* CONFIG_ALPHA_XL */ if (address < APECS_DMA_WIN_BASE) return 0; return phys_to_virt(address - APECS_DMA_WIN_BASE); +#endif /* CONFIG_ALPHA_XL */ } /* diff -u --recursive --new-file v1.3.80/linux/include/asm-alpha/dma.h linux/include/asm-alpha/dma.h --- v1.3.80/linux/include/asm-alpha/dma.h Tue Aug 1 10:02:44 1995 +++ linux/include/asm-alpha/dma.h Sat Mar 30 13:50:12 1996 @@ -18,6 +18,8 @@ #ifndef _ASM_DMA_H #define _ASM_DMA_H +#include + #include /* need byte IO */ #define dma_outb outb @@ -73,8 +75,16 @@ #define MAX_DMA_CHANNELS 8 -/* The maximum address that we can perform a DMA transfer to on this platform */ +#ifdef CONFIG_ALPHA_XL +/* The maximum address that we can perform a DMA transfer to on Alpha XL, + due to a hardware SIO (PCI<->ISA bus bridge) chip limitation, is 64MB. + see for more info */ +#define MAX_DMA_ADDRESS (0xfffffc0004000000UL) +#else /* CONFIG_ALPHA_XL */ +/* The maximum address that we can perform a DMA transfer to on normal + Alpha platforms */ #define MAX_DMA_ADDRESS (~0UL) +#endif /* CONFIG_ALPHA_XL */ /* 8237 DMA controllers */ #define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */ diff -u --recursive --new-file v1.3.80/linux/include/asm-alpha/floppy.h linux/include/asm-alpha/floppy.h --- v1.3.80/linux/include/asm-alpha/floppy.h Fri Mar 1 07:50:55 1996 +++ linux/include/asm-alpha/floppy.h Sat Mar 30 11:48:51 1996 @@ -10,6 +10,8 @@ #ifndef __ASM_ALPHA_FLOPPY_H #define __ASM_ALPHA_FLOPPY_H +#include + #define fd_inb(port) inb_p(port) #define fd_outb(port,value) outb_p(port,value) @@ -47,8 +49,13 @@ #define N_DRIVE 8 /* - * The Alpha has no problems with floppy DMA crossing 64k borders. + * Most Alphas have no problems with floppy DMA crossing 64k borders. Sigh... */ -#define CROSS_64KB(a,s) (0) +#ifdef CONFIG_ALPHA_XL +#define CROSS_64KB(a,s) \ + ((unsigned long)(a)/0x10000 != ((unsigned long)(a) + (s) - 1) / 0x10000) +#else /* CONFIG_ALPHA_XL */ +#define CROSS_64KB(a,s) (0) +#endif /* CONFIG_ALPHA_XL */ #endif /* __ASM_ALPHA_FLOPPY_H */ diff -u --recursive --new-file v1.3.80/linux/include/asm-i386/bitops.h linux/include/asm-i386/bitops.h --- v1.3.80/linux/include/asm-i386/bitops.h Sat Mar 16 13:52:10 1996 +++ linux/include/asm-i386/bitops.h Fri Mar 29 11:01:55 1996 @@ -78,18 +78,17 @@ if (!size) return 0; - __asm__(" - cld - movl $-1,%%eax - xorl %%edx,%%edx - repe; scasl - je 1f - xorl -4(%%edi),%%eax - subl $4,%%edi - bsfl %%eax,%%edx -1: subl %%ebx,%%edi - shll $3,%%edi - addl %%edi,%%edx" + __asm__("cld\n\t" + "movl $-1,%%eax\n\t" + "xorl %%edx,%%edx\n\t" + "repe; scasl\n\t" + "je 1f\n\t" + "xorl -4(%%edi),%%eax\n\t" + "subl $4,%%edi\n\t" + "bsfl %%eax,%%edx\n" + "1:\tsubl %%ebx,%%edi\n\t" + "shll $3,%%edi\n\t" + "addl %%edi,%%edx" :"=d" (res) :"c" ((size + 31) >> 5), "D" (addr), "b" (addr) :"ax", "cx", "di"); @@ -105,11 +104,10 @@ /* * Look for zero in first byte */ - __asm__(" - bsfl %1,%0 - jne 1f - movl $32, %0 -1: " + __asm__("bsfl %1,%0\n\t" + "jne 1f\n\t" + "movl $32, %0\n" + "1:" : "=r" (set) : "r" (~(*p >> bit))); if (set < (32 - bit)) diff -u --recursive --new-file v1.3.80/linux/include/linux/if_ether.h linux/include/linux/if_ether.h --- v1.3.80/linux/include/linux/if_ether.h Mon Mar 25 08:58:22 1996 +++ linux/include/linux/if_ether.h Sat Mar 30 13:20:33 1996 @@ -71,6 +71,7 @@ #define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */ #define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudeo type */ #define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/ +#define ETH_P_TR_802_2 0x0011 /* 802.2 frames */ /* * This is an Ethernet frame header. diff -u --recursive --new-file v1.3.80/linux/include/linux/ip_fw.h linux/include/linux/ip_fw.h --- v1.3.80/linux/include/linux/ip_fw.h Mon Mar 25 10:13:10 1996 +++ linux/include/linux/ip_fw.h Sat Mar 30 14:03:16 1996 @@ -174,24 +174,6 @@ #ifdef __KERNEL__ #include - -#ifdef CONFIG_IP_MASQUERADE -struct ip_masq { - struct ip_masq *next; /* next member in list */ - struct timer_list timer; /* Expiration timer */ - __u16 protocol; /* Which protocol are we talking? */ - __u32 src, dst; /* Source and destination IP addresses */ - __u16 sport,dport; /* Source and destination ports */ - __u16 mport; /* Masquaraded port */ - __u32 init_seq; /* Add delta from this seq. on */ - short delta; /* Delta in sequence numbers */ - short previous_delta; /* Delta in sequence numbers before last resized PORT command */ - char sawfin; /* Did we saw an FIN packet? */ -}; -extern struct ip_masq *ip_msq_hosts; -extern void ip_fw_masquerade(struct sk_buff **, struct device *); -extern int ip_fw_demasquerade(struct sk_buff *); -#endif #ifdef CONFIG_IP_FIREWALL extern struct ip_fw *ip_fw_in_chain; extern struct ip_fw *ip_fw_out_chain; @@ -212,21 +194,5 @@ extern void ip_fw_init(void); #endif /* KERNEL */ -#ifdef CONFIG_IP_MASQUERADE - -#undef DEBUG_MASQ - -#define MASQUERADE_EXPIRE_TCP 15*60*HZ -#define MASQUERADE_EXPIRE_TCP_FIN 2*60*HZ -#define MASQUERADE_EXPIRE_UDP 5*60*HZ - -/* - * Linux ports don't normally get allocated above 32K. I used an extra 4K port-space - */ - -#define PORT_MASQ_BEGIN 60000 -#define PORT_MASQ_END (PORT_MASQ_BEGIN+4096) -#define FTP_DPORT_TBD (PORT_MASQ_END+1) /* Avoid using hardcoded port 20 for ftp data connection */ -#endif #endif /* _IP_FW_H */ diff -u --recursive --new-file v1.3.80/linux/include/linux/ipx.h linux/include/linux/ipx.h --- v1.3.80/linux/include/linux/ipx.h Sun Mar 24 13:33:25 1996 +++ linux/include/linux/ipx.h Sat Mar 30 13:20:33 1996 @@ -40,6 +40,7 @@ #define IPX_FRAME_8022 2 #define IPX_FRAME_ETHERII 3 #define IPX_FRAME_8023 4 +#define IPX_FRAME_TR_8022 5 unsigned char ipx_special; #define IPX_SPECIAL_NONE 0 #define IPX_PRIMARY 1 diff -u --recursive --new-file v1.3.80/linux/include/linux/major.h linux/include/linux/major.h --- v1.3.80/linux/include/linux/major.h Mon Mar 4 11:25:49 1996 +++ linux/include/linux/major.h Sat Mar 30 13:20:33 1996 @@ -27,17 +27,14 @@ #define SCSI_DISK_MAJOR 8 #define SCSI_TAPE_MAJOR 9 #define MD_MAJOR 9 -#define MOUSE_MAJOR 10 +#define MISC_MAJOR 10 #define SCSI_CDROM_MAJOR 11 #define QIC02_TAPE_MAJOR 12 #define XT_DISK_MAJOR 13 #define SOUND_MAJOR 14 #define CDU31A_CDROM_MAJOR 15 -#define SOCKET_MAJOR 16 #define GOLDSTAR_CDROM_MAJOR 16 -#define AF_UNIX_MAJOR 17 #define OPTICS_CDROM_MAJOR 17 -#define AF_INET_MAJOR 18 #define SANYO_CDROM_MAJOR 18 #define CYCLADES_MAJOR 19 #define CYCLADESAUX_MAJOR 20 diff -u --recursive --new-file v1.3.80/linux/include/linux/miscdevice.h linux/include/linux/miscdevice.h --- v1.3.80/linux/include/linux/miscdevice.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/miscdevice.h Sat Mar 30 13:20:33 1996 @@ -0,0 +1,23 @@ +#ifndef _LINUX_MISCDEVICE_H +#define _LINUX_MISCDEVICE_H + +#define BUSMOUSE_MINOR 0 +#define PSMOUSE_MINOR 1 +#define MS_BUSMOUSE_MINOR 2 +#define ATIXL_BUSMOUSE_MINOR 3 +#define MISC_DYNAMIC_MINOR 255 + +extern int misc_init(void); + +struct miscdevice +{ + int minor; + const char *name; + struct file_operations *fops; + struct miscdevice * next, * prev; +}; + +extern int mouse_register(struct miscdevice * misc); +extern int mouse_deregister(struct miscdevice * misc); + +#endif diff -u --recursive --new-file v1.3.80/linux/include/linux/mouse.h linux/include/linux/mouse.h --- v1.3.80/linux/include/linux/mouse.h Tue Oct 10 14:59:19 1995 +++ linux/include/linux/mouse.h Thu Jan 1 02:00:00 1970 @@ -1,21 +0,0 @@ -#ifndef _LINUX_MOUSE_H -#define _LINUX_MOUSE_H - -#define BUSMOUSE_MINOR 0 -#define PSMOUSE_MINOR 1 -#define MS_BUSMOUSE_MINOR 2 -#define ATIXL_BUSMOUSE_MINOR 3 - -extern int mouse_init(void); - -struct mouse { - int minor; - const char *name; - struct file_operations *fops; - struct mouse * next, * prev; -}; - -extern int mouse_register(struct mouse * mouse); -extern int mouse_deregister(struct mouse * mouse); - -#endif diff -u --recursive --new-file v1.3.80/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h --- v1.3.80/linux/include/linux/proc_fs.h Mon Mar 25 10:22:51 1996 +++ linux/include/linux/proc_fs.h Sat Mar 30 13:58:07 1996 @@ -100,6 +100,7 @@ PROC_NET_AX25_BPQETHER, PROC_NET_ALIAS_TYPES, PROC_NET_ALIASES, + PROC_NET_IP_MASQ_APP, PROC_NET_LAST }; diff -u --recursive --new-file v1.3.80/linux/include/linux/socket.h linux/include/linux/socket.h --- v1.3.80/linux/include/linux/socket.h Sun Mar 24 13:33:16 1996 +++ linux/include/linux/socket.h Fri Mar 29 12:52:06 1996 @@ -96,8 +96,6 @@ #define SOL_TCP 6 #define SOL_UDP 17 -#ifdef __KERNEL__ - /* IP options */ #define IP_TOS 1 #define IPTOS_LOWDELAY 0x10 @@ -112,8 +110,6 @@ #define IP_MULTICAST_LOOP 34 #define IP_ADD_MEMBERSHIP 35 #define IP_DROP_MEMBERSHIP 36 - -#endif /* __KERNEL__ */ /* These need to appear somewhere around here */ #define IP_DEFAULT_MULTICAST_TTL 1 diff -u --recursive --new-file v1.3.80/linux/include/net/ip_masq.h linux/include/net/ip_masq.h --- v1.3.80/linux/include/net/ip_masq.h Thu Jan 1 02:00:00 1970 +++ linux/include/net/ip_masq.h Sat Mar 30 14:03:16 1996 @@ -0,0 +1,146 @@ +/* + * IP masquerading functionality definitions + */ + +#ifndef _IP_MASQ_H +#define _IP_MASQ_H + +#include +#include +#include + +/* + * Linux ports don't normally get allocated above 32K. + * I used an extra 4K port-space + */ + +#define PORT_MASQ_BEGIN 60000 +#define PORT_MASQ_END (PORT_MASQ_BEGIN+4096) + +#define MASQUERADE_EXPIRE_TCP 15*60*HZ +#define MASQUERADE_EXPIRE_TCP_FIN 2*60*HZ +#define MASQUERADE_EXPIRE_UDP 5*60*HZ + +#define IP_MASQ_F_OUT_SEQ 0x01 /* must do output seq adjust */ +#define IP_MASQ_F_IN_SEQ 0x02 /* must do input seq adjust */ +#define IP_MASQ_F_NO_DPORT 0x04 /* no dport set yet */ +#define IP_MASQ_F_NO_DADDR 0x08 /* no daddr yet */ +#define IP_MASQ_F_HASHED 0x10 /* hashed entry */ +#define IP_MASQ_F_SAW_FIN 0x20 /* tcp fin pkt seen */ + +#ifdef __KERNEL__ + +/* + * Delta seq. info structure + * Each MASQ struct has 2 (output AND input seq. changes). + */ + +struct ip_masq_seq { + __u32 init_seq; /* Add delta from this seq */ + short delta; /* Delta in sequence numbers */ + short previous_delta; /* Delta in sequence numbers before last resized pkt */ +}; + +/* + * MASQ structure allocated for each masqueraded association + */ +struct ip_masq { + struct ip_masq *m_link, *s_link; /* hashed link ptrs */ + struct timer_list timer; /* Expiration timer */ + __u16 protocol; /* Which protocol are we talking? */ + __u16 sport, dport, mport; /* src, dst & masq ports */ + __u32 saddr, daddr, maddr; /* src, dst & masq addresses */ + struct ip_masq_seq out_seq, in_seq; + struct ip_masq_app *app; /* bound ip_masq_app object */ + unsigned flags; /* status flags */ +}; + +/* + * [0]: UDP free_ports + * [1]: TCP free_ports + */ + +extern int ip_masq_free_ports[2]; + +/* + * ip_masq initializer (registers symbols and /proc/net entries) + */ +extern int ip_masq_init(void); + +/* + * functions called from ip layer + */ +extern void ip_fw_masquerade(struct sk_buff **, struct device *); +extern int ip_fw_demasquerade(struct sk_buff **, struct device *); + +/* + * ip_masq obj creation/deletion functions. + */ +extern struct ip_masq *ip_masq_new(struct device *dev, int proto, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned flags); +extern void ip_masq_set_expire(struct ip_masq *ms, unsigned long tout); + + +/* + * + * IP_MASQ_APP: IP application masquerading definitions + * + */ + +struct ip_masq_app +{ + struct ip_masq_app *next; + unsigned type; /* type = proto<<16 | port (host byte order)*/ + int n_attach; + int (*masq_init_1) /* ip_masq initializer */ + (struct ip_masq_app *, struct ip_masq *); + int (*masq_done_1) /* ip_masq fin. */ + (struct ip_masq_app *, struct ip_masq *); + int (*pkt_out) /* output (masquerading) hook */ + (struct ip_masq_app *, struct ip_masq *, struct sk_buff **, struct device *); + int (*pkt_in) /* input (demasq) hook */ + (struct ip_masq_app *, struct ip_masq *, struct sk_buff **, struct device *); +}; + +/* + * ip_masq_app initializer + */ +extern int ip_masq_app_init(void); + +/* + * ip_masq_app object registration functions (port: host byte order) + */ +extern int register_ip_masq_app(struct ip_masq_app *mapp, unsigned short proto, __u16 port); +extern int unregister_ip_masq_app(struct ip_masq_app *mapp); + +/* + * get ip_masq_app obj by proto,port(net_byte_order) + */ +extern struct ip_masq_app * ip_masq_app_get(unsigned short proto, __u16 port); + +/* + * ip_masq TO ip_masq_app (un)binding functions. + */ +extern struct ip_masq_app * ip_masq_bind_app(struct ip_masq *ms); +extern int ip_masq_unbind_app(struct ip_masq *ms); + +/* + * output and input app. masquerading hooks. + * + */ +extern int ip_masq_app_pkt_out(struct ip_masq *, struct sk_buff **skb_p, struct device *dev); +extern int ip_masq_app_pkt_in(struct ip_masq *, struct sk_buff **skb_p, struct device *dev); + +/* + * /proc/net entry + */ +extern int ip_masq_app_getinfo(char *buffer, char **start, off_t offset, int length, int dummy); + +/* + * skb_replace function used by "client" modules to replace + * a segment of skb. + */ +extern struct sk_buff * ip_masq_skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len); + +#endif /* __KERNEL__ */ + +#endif /* _IP_MASQ_H */ diff -u --recursive --new-file v1.3.80/linux/include/net/p8022tr.h linux/include/net/p8022tr.h --- v1.3.80/linux/include/net/p8022tr.h Thu Jan 1 02:00:00 1970 +++ linux/include/net/p8022tr.h Sat Mar 30 13:20:33 1996 @@ -0,0 +1,8 @@ +#ifndef _NET_P8022TR_H +#define _NET_P8022TR_H + +extern struct datalink_proto *register_8022tr_client(unsigned char type, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *)); +extern void unregister_8022tr_client(unsigned char type); + +#endif + diff -u --recursive --new-file v1.3.80/linux/include/net/p8022trcall.h linux/include/net/p8022trcall.h --- v1.3.80/linux/include/net/p8022trcall.h Thu Jan 1 02:00:00 1970 +++ linux/include/net/p8022trcall.h Sat Mar 30 13:20:33 1996 @@ -0,0 +1,3 @@ +/* Separate to keep compilation of Space.c simpler */ +extern void p8022tr_proto_init(struct net_proto *); + diff -u --recursive --new-file v1.3.80/linux/kernel/sched.c linux/kernel/sched.c --- v1.3.80/linux/kernel/sched.c Thu Mar 28 17:34:35 1996 +++ linux/kernel/sched.c Fri Mar 29 12:58:04 1996 @@ -861,11 +861,6 @@ long psecs; p->utime += user; - if (p->priority < DEF_PRIORITY) - kstat.cpu_nice += user; - else - kstat.cpu_user += user; - kstat.cpu_system += system; p->stime += system; psecs = (p->stime + p->utime) / HZ; @@ -917,14 +912,20 @@ { #ifndef __SMP__ struct task_struct * p = current; + unsigned long user = ticks - system; if (p->pid) { p->counter -= ticks; if (p->counter < 0) { p->counter = 0; need_resched = 1; } + if (p->priority < DEF_PRIORITY) + kstat.cpu_nice += user; + else + kstat.cpu_user += user; + kstat.cpu_system += system; } - update_one_process(p, ticks, ticks-system, system); + update_one_process(p, ticks, user, system); #else int cpu,j; cpu = smp_processor_id(); diff -u --recursive --new-file v1.3.80/linux/net/802/Makefile linux/net/802/Makefile --- v1.3.80/linux/net/802/Makefile Mon Mar 25 08:58:23 1996 +++ linux/net/802/Makefile Sat Mar 30 13:20:33 1996 @@ -15,12 +15,12 @@ endif ifdef CONFIG_IPX -OX_OBJS += p8022.o psnap.o +O_OBJS += p8022.o psnap.o p8022tr.o endif ifdef CONFIG_ATALK ifndef CONFIG_IPX -OX_OBJS += p8022.o psnap.o +O_OBJS += p8022.o psnap.o p8022tr.o endif endif diff -u --recursive --new-file v1.3.80/linux/net/802/p8022tr.c linux/net/802/p8022tr.c --- v1.3.80/linux/net/802/p8022tr.c Thu Jan 1 02:00:00 1970 +++ linux/net/802/p8022tr.c Sat Mar 30 13:20:33 1996 @@ -0,0 +1,137 @@ +#include +#include +#include +#include +#include +#include +#include + +#define SNAP_HEADER_LEN 8 + +static struct datalink_proto *p8022tr_list = NULL; + +/* + * We don't handle the loopback SAP stuff, the extended + * 802.2 command set, multicast SAP identifiers and non UI + * frames. We have the absolute minimum needed for IPX, + * IP and Appletalk phase 2. + */ + +static struct datalink_proto * +find_8022tr_client(unsigned char type) +{ + struct datalink_proto *proto; + + for (proto = p8022tr_list; + ((proto != NULL) && (*(proto->type) != type)); + proto = proto->next) + ; + + return proto; +} + +int +p8022tr_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) +{ + struct datalink_proto *proto; + + proto = find_8022tr_client(*(skb->h.raw)); + if (proto != NULL) { + skb->h.raw += 3; + skb_pull(skb,3); + return proto->rcvfunc(skb, dev, pt); + } + + skb->sk = NULL; + kfree_skb(skb, FREE_READ); + return 0; +} + +static void +p8022tr_datalink_header(struct datalink_proto *dl, + struct sk_buff *skb, unsigned char *dest_node) +{ + struct device *dev = skb->dev; + unsigned char *rawp; + unsigned char *olddata; + unsigned char *newdata; + + rawp = skb_push(skb,3); + *rawp++ = dl->type[0]; + *rawp++ = dl->type[0]; + *rawp = 0x03; /* UI */ + dev->hard_header(skb, dev, ETH_P_802_3, dest_node, NULL, skb->len); + olddata = skb->data; + newdata = skb_pull(skb, SNAP_HEADER_LEN); + memmove(newdata, olddata, dev->hard_header_len - SNAP_HEADER_LEN); +} + +static struct packet_type p8022tr_packet_type = +{ + 0, + NULL, /* All devices */ + p8022tr_rcv, + NULL, + NULL, +}; + + +static struct symbol_table p8022tr_proto_syms = { +#include + X(register_8022tr_client), + X(unregister_8022tr_client), +#include +}; + +void p8022tr_proto_init(struct net_proto *pro) +{ + p8022tr_packet_type.type=htons(ETH_P_TR_802_2); + dev_add_pack(&p8022tr_packet_type); + register_symtab(&p8022tr_proto_syms); +} + +struct datalink_proto * +register_8022tr_client(unsigned char type, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *)) +{ + struct datalink_proto *proto; + + if (find_8022tr_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 = p8022tr_datalink_header; + proto->string_name = "802.2TR"; + proto->next = p8022tr_list; + p8022tr_list = proto; + } + + return proto; +} + +void unregister_8022tr_client(unsigned char type) +{ + struct datalink_proto *tmp, **clients = &p8022tr_list; + unsigned long flags; + + save_flags(flags); + cli(); + + while ((tmp = *clients) != NULL) + { + if (tmp->type[0] == type) { + *clients = tmp->next; + kfree_s(tmp, sizeof(struct datalink_proto)); + break; + } else { + clients = &tmp->next; + } + } + + restore_flags(flags); +} + diff -u --recursive --new-file v1.3.80/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c --- v1.3.80/linux/net/appletalk/ddp.c Mon Mar 25 09:00:04 1996 +++ linux/net/appletalk/ddp.c Sat Mar 30 13:20:33 1996 @@ -151,7 +151,8 @@ } if ( to->sat_addr.s_net == s->protinfo.af_at.src_net && - to->sat_addr.s_node == s->protinfo.af_at.src_node ) + (to->sat_addr.s_node == s->protinfo.af_at.src_node + ||to->sat_addr.s_node == ATADDR_BCAST )) { break; } diff -u --recursive --new-file v1.3.80/linux/net/core/dev.c linux/net/core/dev.c --- v1.3.80/linux/net/core/dev.c Mon Mar 25 08:58:24 1996 +++ linux/net/core/dev.c Sat Mar 30 13:20:34 1996 @@ -1349,7 +1349,9 @@ * SLHC if present needs attaching so other people see it * even if not opened. */ -#if (defined(CONFIG_SLIP_COMPRESSED) || defined(CONFIG_PPP)) && defined(CONFIG_SLHC_BUILTIN) +#if (defined(CONFIG_SLIP) && defined(CONFIG_SLIP_COMPRESSED)) \ + || defined(CONFIG_PPP) \ + || (defined(CONFIG_ISDN) && defined(CONFIG_ISDN_PPP)) slhc_install(); #endif diff -u --recursive --new-file v1.3.80/linux/net/ipv4/Makefile linux/net/ipv4/Makefile --- v1.3.80/linux/net/ipv4/Makefile Sun Feb 11 13:28:37 1996 +++ linux/net/ipv4/Makefile Sat Mar 30 13:20:34 1996 @@ -37,6 +37,11 @@ endif endif +ifeq ($(CONFIG_IP_MASQUERADE),y) +IPV4_OBJS += ip_masq.o ip_masq_app.o +M_OBJS += ip_masq_ftp.o ip_masq_irc.o +endif + ifeq ($(CONFIG_IP_ALIAS),y) IPV4_OBJS += ip_alias.o else diff -u --recursive --new-file v1.3.80/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v1.3.80/linux/net/ipv4/af_inet.c Mon Mar 25 08:58:24 1996 +++ linux/net/ipv4/af_inet.c Sat Mar 30 13:20:34 1996 @@ -90,6 +90,9 @@ #include #include #include +#ifdef CONFIG_IP_MASQUERADE +#include +#endif #ifdef CONFIG_IP_ALIAS #include #endif diff -u --recursive --new-file v1.3.80/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v1.3.80/linux/net/ipv4/arp.c Mon Mar 25 08:58:24 1996 +++ linux/net/ipv4/arp.c Sat Mar 30 13:20:34 1996 @@ -1115,7 +1115,6 @@ * check if that someone else is one of our proxies. If it isn't, * we can toss it. */ - grat = (sip == tip) && (sha == tha); arp_fast_lock(); for (proxy_entry=arp_proxy_list; @@ -1137,12 +1136,6 @@ } if (proxy_entry) { - if (grat) - { - if(!(proxy_entry->flags&ATF_PERM)) - arp_destroy(proxy_entry); - goto gratuitous; - } memcpy(ha, proxy_entry->ha, dev->addr_len); arp_unlock(); arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,ha, sha); @@ -1151,11 +1144,7 @@ } else { - if (grat) - goto gratuitous; arp_unlock(); - kfree_skb(skb, FREE_READ); - return 0; } } else @@ -1165,6 +1154,8 @@ */ arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha); } + grat = 1; + goto gratuitous; } /* * It is now an arp reply. @@ -1182,13 +1173,13 @@ * needs to be added to the arp cache, or have its entry updated if it is * there. */ + +gratuitous: arp_fast_lock(); -gratuitous: hash = HASH(sip); - for (entry=arp_tables[hash]; entry; entry=entry->next) if (entry->ip == sip && entry->dev == dev) break; @@ -1198,8 +1189,14 @@ /* * Entry found; update it only if it is not a permanent entry. */ - if (!(entry->flags & ATF_PERM)) { - memcpy(entry->ha, sha, dev->addr_len); + if (!(entry->flags & ATF_PERM)) + { + if(memcmp(entry->ha, sha,dev->addr_len)!=0) + { + memcpy(entry->ha, sha, dev->addr_len); + if(entry->flags & ATF_COM) + arp_update_hhs(entry); + } entry->last_updated = jiffies; arpd_update(entry, __LINE__); } diff -u --recursive --new-file v1.3.80/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c --- v1.3.80/linux/net/ipv4/igmp.c Wed Feb 21 08:33:26 1996 +++ linux/net/ipv4/igmp.c Sat Mar 30 13:20:34 1996 @@ -517,15 +517,14 @@ { if((*i)->multiaddr==addr) { - if(--((*i)->users)) - return; - else + if(--((*i)->users) == 0) { struct ip_mc_list *tmp= *i; igmp_group_dropped(tmp); *i=(*i)->next; kfree_s(tmp,sizeof(*tmp)); } + return; } } } diff -u --recursive --new-file v1.3.80/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c --- v1.3.80/linux/net/ipv4/ip_forward.c Mon Mar 25 08:58:25 1996 +++ linux/net/ipv4/ip_forward.c Sat Mar 30 13:20:34 1996 @@ -29,6 +29,9 @@ #include #include #include +#ifdef CONFIG_IP_MASQUERADE +#include +#endif #include #include #include @@ -210,7 +213,10 @@ #ifndef CONFIG_IP_NO_ICMP_REDIRECT if (dev == dev2 && !((iph->saddr^dev->pa_addr)&dev->pa_mask) && - (rt->rt_flags&RTF_MODIFIED) && !opt->srr) + /* The daddr!=raddr test isnt obvious - what its doing + is avoiding sending a frame the receiver will not + believe anyway.. */ + iph->daddr != raddr/*ANK*/ && !opt->srr) icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, raddr, dev); #endif #ifdef CONFIG_IP_MROUTE diff -u --recursive --new-file v1.3.80/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c --- v1.3.80/linux/net/ipv4/ip_fw.c Tue Mar 19 12:51:42 1996 +++ linux/net/ipv4/ip_fw.c Sat Mar 30 13:20:34 1996 @@ -34,6 +34,7 @@ * Add support for matching on device names. * Jos Vos 15/2/1996. * + * * Masquerading functionality * * Copyright (c) 1994 Pauline Middelink @@ -52,6 +53,8 @@ * Alan Cox : Cleaned up length setting. * Wouter Gadeyne : Fixed masquerading support of ftp PORT commands * + * Juan Jose Ciarlante : Masquerading code moved to ip_masq.c + * * All the real work was done by ..... * */ @@ -98,6 +101,11 @@ #include #include #include + +#ifdef CONFIG_IP_MASQUERADE +#include +#endif + #include #include #include @@ -148,17 +156,6 @@ #endif -#ifdef CONFIG_IP_MASQUERADE -/* - * Implement IP packet masquerading - */ - -static unsigned short masq_port = PORT_MASQ_BEGIN; -static const char *strProt[] = {"UDP","TCP"}; -struct ip_masq *ip_msq_hosts; - -#endif - /* * Returns 1 if the port is matched by the vector, 0 otherwise */ @@ -522,517 +519,6 @@ return 0; } -#ifdef CONFIG_IP_MASQUERADE - -static void masq_expire(unsigned long data) -{ - struct ip_masq *ms = (struct ip_masq *)data; - struct ip_masq *old,*cur; - unsigned long flags; - -#ifdef DEBUG_MASQ - printk("Masqueraded %s %lX:%X expired\n", - strProt[ms->protocol==IPPROTO_TCP], - ntohl(ms->src),ntohs(ms->sport)); -#endif - - save_flags(flags); - cli(); - - /* delete from list of hosts */ - old = NULL; - cur = ip_msq_hosts; - while (cur!=NULL) { - if (cur==ms) { - if (old==NULL) ip_msq_hosts = ms->next; - else old->next = ms->next; - kfree_s(ms,sizeof(*ms)); - break; - } - old = cur; - cur=cur->next; - } - restore_flags(flags); -} - -/* - * Create a new masquerade list entry, also allocate an - * unused mport, keeping the portnumber between the - * given boundaries MASQ_BEGIN and MASQ_END. - * - * FIXME: possible deadlock if all free ports are exhausted! - */ -static struct ip_masq *alloc_masq_entry(void) -{ - struct ip_masq *ms, *mst; - unsigned long flags; - - ms = (struct ip_masq *) kmalloc(sizeof(struct ip_masq), GFP_ATOMIC); - if (ms==NULL) - return NULL; - - memset(ms,0,sizeof(*ms)); - init_timer(&ms->timer); - ms->timer.data = (unsigned long)ms; - ms->timer.function = masq_expire; - - save_flags(flags); - cli(); - do - { - /* Try the next available port number */ - ms->mport = htons(masq_port++); - if (masq_port==PORT_MASQ_END) - masq_port = PORT_MASQ_BEGIN; - - /* Now hunt through the used ports to see if - * this port is in use... */ - mst = ip_msq_hosts; - while (mst && mst->mport!=ms->mport) - mst = mst->next; - } - while (mst!=NULL); - - /* add new entry in front of list to minimize lookup-time */ - ms->next = ip_msq_hosts; - ip_msq_hosts = ms; - restore_flags(flags); - - return ms; -} - -/* - * When passing an FTP 'PORT' command, try to replace the IP - * address with an newly assigned (masquereded) port on this - * host, so the ftp-data connect FROM the site will succeed... - * - * Also, when the size of the packet changes, create an delta - * offset, which will be added to every th->seq (and subtracted for - * (th->acqseq) whose seq > init_seq. - * - * Not for the faint of heart! - */ - -static struct sk_buff *revamp(struct sk_buff *skb, struct device *dev, struct ip_masq *ftp) -{ - struct iphdr *iph = skb->h.iph; - struct tcphdr *th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); - struct sk_buff *skb2; - char *p, *data = (char *)&th[1]; - unsigned char p1,p2,p3,p4,p5,p6; - unsigned long from; - unsigned short port; - struct ip_masq *ms; - char buf[24]; /* xxx.xxx.xxx.xxx,ppp,ppp\000 */ - int diff; - __u32 seq; - - /* - * Adjust seq with delta-offset for all packets after the most recent resized PORT command - * and with previous_delta offset for all packets before most recent resized PORT - */ - - /* - * seq & seq_ack are in network byte order; need conversion before comparing - */ - seq=ntohl(th->seq); - if (ftp->delta || ftp->previous_delta) - { - if(after(seq,ftp->init_seq) ) - { - th->seq = htonl(seq + ftp->delta); -#ifdef DEBUG_MASQ - printk("masq_revamp : added delta (%d) to seq\n",ftp->delta); -#endif - } - else - { - th->seq = htonl(seq + ftp->previous_delta); -#ifdef DEBUG_MASQ - printk("masq_revamp : added previous_delta (%d) to seq\n",ftp->previous_delta); -#endif - } - } - - while (skb->len - ((unsigned char *)data - skb->h.raw) > 18) - { - if (memcmp(data,"PORT ",5) && memcmp(data,"port ",5)) - { - data ++; - continue; - } - p = data+5; - p1 = simple_strtoul(data+5,&data,10); - if (*data!=',') - continue; - p2 = simple_strtoul(data+1,&data,10); - if (*data!=',') - continue; - p3 = simple_strtoul(data+1,&data,10); - if (*data!=',') - continue; - p4 = simple_strtoul(data+1,&data,10); - if (*data!=',') - continue; - p5 = simple_strtoul(data+1,&data,10); - if (*data!=',') - continue; - p6 = simple_strtoul(data+1,&data,10); - if (*data!='\r' && *data!='\n') - continue; - - from = (p1<<24) | (p2<<16) | (p3<<8) | p4; - port = (p5<<8) | p6; -#ifdef MASQ_DEBUG - printk("PORT %lX:%X detected\n",from,port); -#endif - /* - * Now create an masquerade entry for it - */ - ms = alloc_masq_entry(); - if (ms==NULL) - return skb; - ms->protocol = IPPROTO_TCP; - ms->src = htonl(from); /* derived from PORT cmd */ - ms->sport = htons(port); /* derived from PORT cmd */ - ms->dst = iph->daddr; - /* - * Hardcoding 20 as dport is not always correct - * At least 1 Windows ftpd uses a random port number instead of 20 - * Leave it undefined for now & wait for the first connection request to fill it out - */ - ms->dport = htons(FTP_DPORT_TBD); /* ftp-data */ - ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP_FIN; - add_timer(&ms->timer); - - /* - * Replace the old PORT with the new one - */ - from = ntohl(dev->pa_addr); - port = ntohs(ms->mport); - sprintf(buf,"%ld,%ld,%ld,%ld,%d,%d", - from>>24&255,from>>16&255,from>>8&255,from&255, - port>>8&255,port&255); - - /* - * Calculate required delta-offset to keep TCP happy - */ - - diff = strlen(buf) - (data-p); - - /* - * No shift. - */ - - if (diff==0) - { - /* - * simple case, just replace the old PORT cmd - */ - memcpy(p,buf,strlen(buf)); - return skb; - } - - /* - * If the PORT command we have fiddled is the first, or is a - * resend don't do the delta shift again. Doesn't work for - * pathological cases, but we would need a history for that. - * Also fails if you send 2^31 bytes of data down the link - * after the first port command. - * - * FIXME: use ftp->init_seq_valid - 0 is a valid sequence. - */ - - if(!ftp->init_seq || after(seq,ftp->init_seq) ) - { - ftp->previous_delta=ftp->delta; - ftp->delta+=diff; - ftp->init_seq = seq; - } - - /* - * Sizes differ, make a copy - */ -#ifdef DEBUG_MASQ - printk("MASQUERADE: resizing needed for %d bytes (%ld)\n",diff, skb->len); -#endif - skb2 = alloc_skb(MAX_HEADER + skb->len+diff, GFP_ATOMIC); - if (skb2 == NULL) { - printk("MASQUERADE: No memory available\n"); - return skb; - } - skb2->free = skb->free; - skb_reserve(skb2,MAX_HEADER); - skb_put(skb2,skb->len + diff); - skb2->h.raw = skb2->data + (skb->h.raw - skb->data); - iph=skb2->h.iph; - /* - * Mend the IP header too - */ - iph->tot_len = htons(diff+ntohs(iph->tot_len)); - iph->check = 0; - iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); - - /* - * Copy the packet data into the new buffer. - * Thereby replacing the PORT cmd. - */ - memcpy(skb2->data, skb->data, (p - (char *)skb->data)); - memcpy(&skb2->data[(p - (char *)skb->data)], buf, strlen(buf)); - memcpy(&skb2->data[(p - (char *)skb->data) + strlen(buf)], data, - skb->len - (data-(char *)skb->data)); - - /* - * Update tot_len field in ip header ! - * Sequence numbers were allready modified in original packet - */ - iph->tot_len = htons(skb->len + diff); - - /* - * Problem, how to replace the new skb with old one, - * preferably inplace, so all the pointers in the - * calling tree keep ok :( - */ - kfree_skb(skb, FREE_WRITE); - return skb2; - } - return skb; -} - -static void recalc_check(struct udphdr *uh, unsigned long saddr, - unsigned long daddr, int len) -{ - uh->check=0; - uh->check=csum_tcpudp_magic(saddr,daddr,len, - IPPROTO_UDP, csum_partial((char *)uh,len,0)); - if(uh->check==0) - uh->check=0xFFFF; -} - -void ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev) -{ - struct sk_buff *skb=*skb_ptr; - struct iphdr *iph = skb->h.iph; - unsigned short *portptr; - struct ip_masq *ms; - int size; - - /* - * We can only masquerade protocols with ports... - */ - - if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP) - return; - - /* - * Now hunt the list to see if we have an old entry - */ - - portptr = (unsigned short *)&(((char *)iph)[iph->ihl*4]); - ms = ip_msq_hosts; - -#ifdef DEBUG_MASQ - printk("Outgoing %s %lX:%X -> %lX:%X\n", - strProt[iph->protocol==IPPROTO_TCP], - ntohl(iph->saddr), ntohs(portptr[0]), - ntohl(iph->daddr), ntohs(portptr[1])); -#endif - while (ms!=NULL) - { - if (iph->protocol == ms->protocol && - iph->saddr == ms->src && iph->daddr == ms->dst && - portptr[0] == ms->sport && portptr[1] == ms->dport) - { - del_timer(&ms->timer); - break; - } - ms = ms->next; - } - - /* - * Nope, not found, create a new entry for it - */ - - if (ms==NULL) - { - ms = alloc_masq_entry(); - if (ms==NULL) - { - printk("MASQUERADE: no memory left !\n"); - return; - } - ms->protocol = iph->protocol; - ms->src = iph->saddr; - ms->dst = iph->daddr; - ms->sport = portptr[0]; - ms->dport = portptr[1]; - } - - /* - * Change the fragments origin - */ - - size = skb->len - ((unsigned char *)portptr - skb->h.raw); - iph->saddr = dev->pa_addr; /* my own address */ - portptr[0] = ms->mport; - - /* - * Adjust packet accordingly to protocol - */ - - if (iph->protocol==IPPROTO_UDP) - { - ms->timer.expires = jiffies+MASQUERADE_EXPIRE_UDP; - recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size); - } - else - { - struct tcphdr *th; - if (portptr[1]==htons(21)) - { - skb = revamp(*skb_ptr, dev, ms); - *skb_ptr = skb; - iph = skb->h.iph; - portptr = (unsigned short *)&(((char *)iph)[iph->ihl*4]); - size = skb->len - ((unsigned char *)portptr-skb->h.raw); - } - th = (struct tcphdr *)portptr; - - /* - * Timeout depends if FIN packet was seen - */ - if (ms->sawfin || th->fin) - { - ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP_FIN; - ms->sawfin = 1; - } - else ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP; - - skb->csum = csum_partial((void *)(th + 1), size - sizeof(*th), 0); - tcp_send_check(th,iph->saddr,iph->daddr,size,skb); - } - add_timer(&ms->timer); - ip_send_check(iph); - - #ifdef DEBUG_MASQ - printk("O-routed from %lX:%X over %s\n",ntohl(dev->pa_addr),ntohs(ms->mport),dev->name); - #endif - } - - /* - * Check if it's an masqueraded port, look it up, - * and send it on it's way... - * - * Better not have many hosts using the designated portrange - * as 'normal' ports, or you'll be spending lots of time in - * this function. - */ - -int ip_fw_demasquerade(struct sk_buff *skb) -{ - struct iphdr *iph = skb->h.iph; - unsigned short *portptr; - struct ip_masq *ms; - struct tcphdr *th = (struct tcphdr *)(skb->h.raw+(iph->ihl<<2)); - - if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP) - return 0; - - portptr = (unsigned short *)&(((char *)iph)[iph->ihl*4]); - if (ntohs(portptr[1]) < PORT_MASQ_BEGIN || - ntohs(portptr[1]) > PORT_MASQ_END) - return 0; - -#ifdef DEBUG_MASQ - printk("Incoming %s %lX:%X -> %lX:%X\n", - strProt[iph->protocol==IPPROTO_TCP], - ntohl(iph->saddr), ntohs(portptr[0]), - ntohl(iph->daddr), ntohs(portptr[1])); -#endif - - /* - * reroute to original host:port if found... - * - * NB. Cannot check destination address, just for the incoming port. - * reason: archie.doc.ac.uk has 6 interfaces, you send to - * phoenix and get a reply from any other interface(==dst)! - * - * [Only for UDP] - AC - */ - ms = ip_msq_hosts; - while (ms!=NULL) - { - if (iph->protocol==ms->protocol && - (iph->saddr==ms->dst || iph->protocol==IPPROTO_UDP) && - (ms->dport==htons(FTP_DPORT_TBD) || portptr[0]==ms->dport) && - portptr[1]==ms->mport) - { - - int size = skb->len - ((unsigned char *)portptr - skb->h.raw); - iph->daddr = ms->src; - portptr[1] = ms->sport; - - if(ms->dport==htons(FTP_DPORT_TBD)) - { - ms->dport=portptr[0]; -#ifdef DEBUG_MASQ - printk("demasq : Filled out dport entry (%d) based on initial connect attempt from FTP deamon\n",ntohs(ms->dport)); -#endif - } - - /* - * Yug! adjust UDP/TCP and IP checksums - */ - if (iph->protocol==IPPROTO_UDP) - recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size); - else - { - __u32 ack_seq; - /* - * Adjust ack_seq with delta-offset for - * the packets AFTER most recent PORT command has caused a shift - * for packets before most recent PORT command, use previous_delta - */ -#ifdef DEBUG_MASQ - printk("demasq : delta=%d ; previous_delta=%d ; init_seq=%lX ; ack_seq=%lX ; after=%d\n",ms->delta,ms->previous_delta,ntohl(ms->init_seq),ntohl(th->ack_seq),after(ntohl(th->ack_seq),ntohl(ms->init_seq))); -#endif - ack_seq=ntohl(th->ack_seq); - if (ms->delta || ms->previous_delta) - { - if(after(ack_seq,ms->init_seq)) - { - th->ack_seq = htonl(ack_seq-ms->delta); -#ifdef DEBUG_MASQ - printk("demasq : substracted delta (%d) from ack_seq\n",ms->delta); -#endif - } - else - { - th->ack_seq = htonl(ack_seq-ms->previous_delta); -#ifdef DEBUG_MASQ - printk("demasq : substracted previous_delta (%d) from ack_seq\n",ms->previous_delta); -#endif - } - } - skb->csum = csum_partial((void *)(((struct tcphdr *)portptr) + 1), - size - sizeof(struct tcphdr), 0); - tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,size,skb); - } - ip_send_check(iph); -#ifdef DEBUG_MASQ - printk("I-routed to %lX:%X\n",ntohl(iph->daddr),ntohs(portptr[1])); -#endif - return 1; - } - ms = ms->next; - } - - /* sorry, all this trouble for a no-hit :) */ - return 0; -} -#endif - - static void zero_fw_chain(struct ip_fw *chainptr) { @@ -1079,8 +565,12 @@ } memcpy(ftmp, frwl, len); - ftmp->fw_tosand |= 0x03; - ftmp->fw_tosxor &= 0xFC; + /* + * Allow the more recent "minimise cost" flag to be + * set. [Rob van Nieuwkerk] + */ + ftmp->fw_tosand |= 0x01; + ftmp->fw_tosxor &= 0xFE; ftmp->fw_pcnt=0L; ftmp->fw_bcnt=0L; @@ -1567,54 +1057,6 @@ } #endif -#ifdef CONFIG_IP_MASQUERADE - -static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset, - int length, int unused) -{ - off_t pos=0, begin=0; - struct ip_masq *ms; - unsigned long flags; - int len=0; - - len=sprintf(buffer,"Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta PDelta Expires\n"); - save_flags(flags); - cli(); - - ms=ip_msq_hosts; - while (ms!=NULL) - { - int timer_active = del_timer(&ms->timer); - if (!timer_active) - ms->timer.expires = jiffies; - len+=sprintf(buffer+len,"%s %08lX:%04X %08lX:%04X %04X %08X %6d %6d %lu\n", - strProt[ms->protocol==IPPROTO_TCP], - ntohl(ms->src),ntohs(ms->sport), - ntohl(ms->dst),ntohs(ms->dport), - ntohs(ms->mport), - ms->init_seq,ms->delta,ms->previous_delta,ms->timer.expires-jiffies); - if (timer_active) - add_timer(&ms->timer); - - pos=begin+len; - if(posoffset+length) - break; - ms=ms->next; - } - restore_flags(flags); - *start=buffer+(offset-begin); - len-=(offset-begin); - if(len>length) - len=length; - return len; -} - -#endif #ifdef CONFIG_IP_FIREWALL /* @@ -1722,14 +1164,16 @@ ip_fw_fwd_procinfo }); #endif + #ifdef CONFIG_IP_MASQUERADE - proc_net_register(&(struct proc_dir_entry) { - PROC_NET_IPMSQHST, 13, "ip_masquerade", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_net_inode_operations, - ip_msqhst_procinfo - }); + + /* + * Initialize masquerading. + */ + + ip_masq_init(); #endif + #if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL) /* Register for device up/down reports */ register_netdevice_notifier(&ipfw_dev_notifier); diff -u --recursive --new-file v1.3.80/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c --- v1.3.80/linux/net/ipv4/ip_input.c Mon Mar 25 08:58:25 1996 +++ linux/net/ipv4/ip_input.c Sat Mar 30 13:20:34 1996 @@ -149,6 +149,9 @@ #include #include #include +#ifdef CONFIG_IP_MASQUERADE +#include +#endif #include #include #include @@ -423,7 +426,7 @@ /* * Do we need to de-masquerade this fragment? */ - if (ip_fw_demasquerade(skb)) + if (ip_fw_demasquerade(&skb,dev)) { struct iphdr *iph=skb->h.iph; if (ip_forward(skb, dev, is_frag|IPFWD_MASQUERADED, iph->daddr)) diff -u --recursive --new-file v1.3.80/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c --- v1.3.80/linux/net/ipv4/ip_masq.c Thu Jan 1 02:00:00 1970 +++ linux/net/ipv4/ip_masq.c Sat Mar 30 13:20:34 1996 @@ -0,0 +1,672 @@ +/* + * + * Masquerading functionality + * + * Copyright (c) 1994 Pauline Middelink + * + * See ip_fw.c for original log + * + * Fixes: + * Juan Jose Ciarlante : Modularized application masquerading (see ip_masq_app.c) + * Juan Jose Ciarlante : New struct ip_masq_seq that holds output/input delta seq. + * Juan Jose Ciarlante : Added hashed lookup by proto,maddr,mport and proto,saddr,sport + * Juan Jose Ciarlante : Fixed deadlock if free ports get exhausted + * Juan Jose Ciarlante : Added NO_ADDR status flag. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IP_MASQ_TAB_SIZE 256 /* must be power of 2 */ + +/* + * Implement IP packet masquerading + */ + +static const char *strProt[] = {"UDP","TCP"}; + +static __inline__ const char * masq_proto_name(unsigned proto) +{ + return strProt[proto==IPPROTO_TCP]; +} + +/* + * Last masq_port number in use. + * Will cycle in MASQ_PORT boundaries. + */ +static __u16 masq_port = PORT_MASQ_BEGIN; + +/* + * free ports counters (UDP & TCP) + * + * Their value is _less_ or _equal_ to actual free ports: + * same masq port, diff masq addr (firewall iface address) allocated + * entries are accounted but their actually don't eat a more than 1 port. + * + * Greater values could lower MASQ_EXPIRATION setting as a way to + * manage 'masq_entries resource'. + * + */ + +int ip_masq_free_ports[2] = { + PORT_MASQ_END - PORT_MASQ_BEGIN, /* UDP */ + PORT_MASQ_END - PORT_MASQ_BEGIN /* TCP */ +}; + +static struct symbol_table ip_masq_syms = { +#include + X(ip_masq_new), + X(ip_masq_set_expire), + X(ip_masq_free_ports), +#include +}; + +/* + * 2 ip_masq hash tables: for input and output pkts lookups. + */ + +struct ip_masq *ip_masq_m_tab[IP_MASQ_TAB_SIZE]; +struct ip_masq *ip_masq_s_tab[IP_MASQ_TAB_SIZE]; + +/* + * Returns hash value + */ + +static __inline__ unsigned + +ip_masq_hash_key(unsigned proto, __u32 addr, __u16 port) +{ + return (proto^ntohl(addr)^ntohs(port)) & (IP_MASQ_TAB_SIZE-1); +} + +/* + * Hashes ip_masq by its proto,addrs,ports. + * should be called with masked interrupts. + * returns bool success. + */ + +static __inline__ int +ip_masq_hash(struct ip_masq *ms) +{ + unsigned hash; + + if (ms->flags & IP_MASQ_F_HASHED) { + printk("ip_masq_hash(): request for already hashed\n"); + return 0; + } + /* + * Hash by proto,m{addr,port} + */ + hash = ip_masq_hash_key(ms->protocol, ms->maddr, ms->mport); + ms->m_link = ip_masq_m_tab[hash]; + ip_masq_m_tab[hash] = ms; + + /* + * Hash by proto,s{addr,port} + */ + hash = ip_masq_hash_key(ms->protocol, ms->saddr, ms->sport); + ms->s_link = ip_masq_s_tab[hash]; + ip_masq_s_tab[hash] = ms; + + + ms->flags |= IP_MASQ_F_HASHED; + return 1; +} + +/* + * UNhashes ip_masq from ip_masq_[ms]_tables. + * should be called with masked interrupts. + * returns bool success. + */ + +static __inline__ int ip_masq_unhash(struct ip_masq *ms) +{ + unsigned hash; + struct ip_masq ** ms_p; + if (!(ms->flags & IP_MASQ_F_HASHED)) { + printk("ip_masq_unhash(): request for unhash flagged\n"); + return 0; + } + /* + * UNhash by m{addr,port} + */ + hash = ip_masq_hash_key(ms->protocol, ms->maddr, ms->mport); + for (ms_p = &ip_masq_m_tab[hash]; *ms_p ; ms_p = &(*ms_p)->m_link) + if (ms == (*ms_p)) { + *ms_p = ms->m_link; + break; + } + /* + * UNhash by s{addr,port} + */ + hash = ip_masq_hash_key(ms->protocol, ms->saddr, ms->sport); + for (ms_p = &ip_masq_s_tab[hash]; *ms_p ; ms_p = &(*ms_p)->s_link) + if (ms == (*ms_p)) { + *ms_p = ms->s_link; + break; + } + + ms->flags &= ~IP_MASQ_F_HASHED; + return 1; +} + +/* + * Returns ip_masq associated with addresses found in iph. + * called for pkts coming from outside-to-INside the firewall + * + * NB. Cannot check destination address, just for the incoming port. + * reason: archie.doc.ac.uk has 6 interfaces, you send to + * phoenix and get a reply from any other interface(==dst)! + * + * [Only for UDP] - AC + */ + +struct ip_masq * +ip_masq_in_get(struct iphdr *iph) +{ + unsigned hash; + struct ip_masq *ms; + __u16 *portptr; + int protocol; + __u32 s_addr, d_addr; + __u16 s_port, d_port; + + portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]); + protocol = iph->protocol; + s_addr = iph->saddr; + s_port = portptr[0]; + d_addr = iph->daddr; + d_port = portptr[1]; + + hash = ip_masq_hash_key(protocol, d_addr, d_port); + for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) { + if ( protocol==ms->protocol && + (s_addr==ms->daddr || ms->flags & IP_MASQ_F_NO_DADDR) && + (s_port==ms->dport || ms->flags & IP_MASQ_F_NO_DPORT) && + (d_addr==ms->maddr && d_port==ms->mport)) + return ms; + } + return NULL; +} + +/* + * Returns ip_masq associated with addresses found in iph. + * called for pkts coming from inside-to-OUTside the firewall. + */ + +struct ip_masq * +ip_masq_out_get(struct iphdr *iph) +{ + unsigned hash; + struct ip_masq *ms; + __u16 *portptr; + int protocol; + __u32 s_addr, d_addr; + __u16 s_port, d_port; + + portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]); + protocol = iph->protocol; + s_addr = iph->saddr; + s_port = portptr[0]; + d_addr = iph->daddr; + d_port = portptr[1]; + + hash = ip_masq_hash_key(protocol, s_addr, s_port); + for(ms = ip_masq_s_tab[hash]; ms ; ms = ms->s_link) { + if (protocol == ms->protocol && + s_addr == ms->saddr && s_port == ms->sport && + d_addr == ms->daddr && d_port == ms->dport ) + return ms; + } + + return NULL; +} + +/* + * Returns ip_masq for given proto,m_addr,m_port. + * called by allocation routine to find an unused m_port. + */ + +struct ip_masq * +ip_masq_getbym(int protocol, __u32 m_addr, __u16 m_port) +{ + unsigned hash; + struct ip_masq *ms; + + hash = ip_masq_hash_key(protocol, m_addr, m_port); + for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) { + if ( protocol==ms->protocol && + (m_addr==ms->maddr && m_port==ms->mport)) + return ms; + } + return NULL; +} + +static void masq_expire(unsigned long data) +{ + struct ip_masq *ms = (struct ip_masq *)data; + unsigned long flags; + +#ifdef DEBUG_CONFIG_IP_MASQUERADE + printk("Masqueraded %s %lX:%X expired\n", + masq_proto_name(ms->protocol), + ntohl(ms->src),ntohs(ms->sport)); +#endif + + save_flags(flags); + cli(); + + if (ip_masq_unhash(ms)) { + ip_masq_free_ports[ms->protocol==IPPROTO_TCP]++; + ip_masq_unbind_app(ms); + kfree_s(ms,sizeof(*ms)); + } + + restore_flags(flags); +} + +/* + * Create a new masquerade list entry, also allocate an + * unused mport, keeping the portnumber between the + * given boundaries MASQ_BEGIN and MASQ_END. + */ + +struct ip_masq * ip_masq_new(struct device *dev, int proto, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned mflags) +{ + struct ip_masq *ms, *mst; + int ports_tried, *free_ports_p; + unsigned long flags; + static int n_fails = 0; + + free_ports_p = &ip_masq_free_ports[proto==IPPROTO_TCP]; + + if (*free_ports_p == 0) { + if (++n_fails < 5) + printk("ip_masq_new(proto=%s): no free ports.\n", + masq_proto_name(proto)); + return NULL; + } + ms = (struct ip_masq *) kmalloc(sizeof(struct ip_masq), GFP_ATOMIC); + if (ms == NULL) { + if (++n_fails < 5) + printk("ip_masq_new(proto=%s): no memory available.\n", + masq_proto_name(proto)); + return NULL; + } + memset(ms, 0, sizeof(*ms)); + init_timer(&ms->timer); + ms->timer.data = (unsigned long)ms; + ms->timer.function = masq_expire; + ms->protocol = proto; + ms->saddr = saddr; + ms->sport = sport; + ms->daddr = daddr; + ms->dport = dport; + ms->flags = mflags; + + if (proto == IPPROTO_UDP) + ms->flags |= IP_MASQ_F_NO_DADDR; + + /* get masq address from rif */ + ms->maddr = dev->pa_addr; + + for (ports_tried = 0; ports_tried < *free_ports_p; ports_tried++){ + save_flags(flags); + cli(); + + /* + * Try the next available port number + */ + + ms->mport = htons(masq_port++); + if (masq_port==PORT_MASQ_END) masq_port = PORT_MASQ_BEGIN; + + restore_flags(flags); + + /* + * lookup to find out if this port is used. + */ + + mst = ip_masq_getbym(proto, ms->maddr, ms->mport); + if (mst == NULL) { + save_flags(flags); + cli(); + + if (ip_masq_free_ports == 0) { + restore_flags(flags); + break; + } + (*free_ports_p)--; + ip_masq_hash(ms); + + restore_flags(flags); + + ip_masq_bind_app(ms); + n_fails = 0; + return ms; + } + } + + if (++n_fails < 5) + printk("ip_masq_new(proto=%s): could not get free masq entry (free=%d).\n", + masq_proto_name(ms->protocol), *free_ports_p); + kfree_s(ms, sizeof(*ms)); + return NULL; +} + +/* + * Set masq expiration (deletion) and adds timer, + * if timeout==0 cancel expiration. + * Warning: it does not check/delete previous timer! + */ + +void ip_masq_set_expire(struct ip_masq *ms, unsigned long tout) +{ + if (tout) { + ms->timer.expires = jiffies+tout; + add_timer(&ms->timer); + } else { + del_timer(&ms->timer); + } +} + +static void recalc_check(struct udphdr *uh, __u32 saddr, + __u32 daddr, int len) +{ + uh->check=0; + uh->check=csum_tcpudp_magic(saddr,daddr,len, + IPPROTO_UDP, csum_partial((char *)uh,len,0)); + if(uh->check==0) + uh->check=0xFFFF; +} + +void ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev) +{ + struct sk_buff *skb=*skb_ptr; + struct iphdr *iph = skb->h.iph; + __u16 *portptr; + struct ip_masq *ms; + int size; + unsigned long timeout; + + /* + * We can only masquerade protocols with ports... + */ + + if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP) + return; + + /* + * Now hunt the list to see if we have an old entry + */ + + portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]); +#ifdef DEBUG_CONFIG_IP_MASQUERADE + printk("Outgoing %s %lX:%X -> %lX:%X\n", + masq_proto_name(iph->protocol), + ntohl(iph->saddr), ntohs(portptr[0]), + ntohl(iph->daddr), ntohs(portptr[1])); +#endif + + ms = ip_masq_out_get(iph); + if (ms!=NULL) + ip_masq_set_expire(ms,0); + + /* + * Nope, not found, create a new entry for it + */ + + if (ms==NULL) + { + ms = ip_masq_new(dev, iph->protocol, + iph->saddr, portptr[0], + iph->daddr, portptr[1], + 0); + if (ms == NULL) + return; + } + + /* + * Change the fragments origin + */ + + size = skb->len - ((unsigned char *)portptr - skb->h.raw); + /* + * Set iph addr and port from ip_masq obj. + */ + iph->saddr = ms->maddr; + portptr[0] = ms->mport; + + /* + * Attempt ip_masq_app call. + * will fix ip_masq and iph seq stuff + */ + if (ip_masq_app_pkt_out(ms, skb_ptr, dev) != 0) + { + /* + * skb has possibly changed, update pointers. + */ + skb = *skb_ptr; + iph = skb->h.iph; + portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]); + size = skb->len - ((unsigned char *)portptr-skb->h.raw); + } + + /* + * Adjust packet accordingly to protocol + */ + + if (iph->protocol==IPPROTO_UDP) + { + timeout = MASQUERADE_EXPIRE_UDP; + recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size); + } + else + { + struct tcphdr *th; + th = (struct tcphdr *)portptr; + + /* + * Timeout depends if FIN packet was seen + */ + if (ms->flags & IP_MASQ_F_SAW_FIN || th->fin) + { + timeout = MASQUERADE_EXPIRE_TCP_FIN; + ms->flags |= IP_MASQ_F_SAW_FIN; + } + else timeout = MASQUERADE_EXPIRE_TCP; + + skb->csum = csum_partial((void *)(th + 1), size - sizeof(*th), 0); + tcp_send_check(th,iph->saddr,iph->daddr,size,skb); + } + ip_masq_set_expire(ms, timeout); + ip_send_check(iph); + + #ifdef DEBUG_CONFIG_IP_MASQUERADE + printk("O-routed from %lX:%X over %s\n",ntohl(ms->maddr),ntohs(ms->mport),dev->name); + #endif + } + + /* + * Check if it's an masqueraded port, look it up, + * and send it on it's way... + * + * Better not have many hosts using the designated portrange + * as 'normal' ports, or you'll be spending many time in + * this function. + */ + +int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev) +{ + struct sk_buff *skb = *skb_p; + struct iphdr *iph = skb->h.iph; + __u16 *portptr; + struct ip_masq *ms; + + if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP) + return 0; + + portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]); + if (ntohs(portptr[1]) < PORT_MASQ_BEGIN || + ntohs(portptr[1]) > PORT_MASQ_END) + return 0; + +#ifdef DEBUG_CONFIG_IP_MASQUERADE + printk("Incoming %s %lX:%X -> %lX:%X\n", + masq_proto_name(iph->protocol), + ntohl(iph->saddr), ntohs(portptr[0]), + ntohl(iph->daddr), ntohs(portptr[1])); +#endif + /* + * reroute to original host:port if found... + */ + + ms = ip_masq_in_get(iph); + + if (ms != NULL) + { + int size; + + /* + * Set dport if not defined yet. + */ + + if ( ms->flags & IP_MASQ_F_NO_DPORT && ms->protocol == IPPROTO_TCP ) { + ms->flags &= ~IP_MASQ_F_NO_DPORT; + ms->dport = portptr[0]; +#if DEBUG_CONFIG_IP_MASQUERADE + printk("ip_fw_demasquerade(): filled dport=%d\n", + ntohs(ms->dport)); +#endif + } + if (ms->flags & IP_MASQ_F_NO_DADDR && ms->protocol == IPPROTO_TCP) { + ms->flags &= ~IP_MASQ_F_NO_DADDR; + ms->daddr = iph->saddr; +#if DEBUG_CONFIG_IP_MASQUERADE + printk("ip_fw_demasquerade(): filled daddr=%X\n", + ntohs(ms->daddr)); +#endif + } + size = skb->len - ((unsigned char *)portptr - skb->h.raw); + iph->daddr = ms->saddr; + portptr[1] = ms->sport; + + /* + * Attempt ip_masq_app call. + * will fix ip_masq and iph ack_seq stuff + */ + + if (ip_masq_app_pkt_in(ms, skb_p, dev) != 0) + { + /* + * skb has changed, update pointers. + */ + + skb = *skb_p; + iph = skb->h.iph; + portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]); + size = skb->len - ((unsigned char *)portptr-skb->h.raw); + } + + /* + * Yug! adjust UDP/TCP and IP checksums + */ + if (iph->protocol==IPPROTO_UDP) + recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size); + else + { + skb->csum = csum_partial((void *)(((struct tcphdr *)portptr) + 1), + size - sizeof(struct tcphdr), 0); + tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,size,skb); + } + ip_send_check(iph); +#ifdef DEBUG_CONFIG_IP_MASQUERADE + printk("I-routed to %lX:%X\n",ntohl(iph->daddr),ntohs(portptr[1])); +#endif + return 1; + } + + /* sorry, all this trouble for a no-hit :) */ + return 0; +} + +/* + * /proc/net entry + */ + +static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset, + int length, int unused) +{ + off_t pos=0, begin=0; + struct ip_masq *ms; + unsigned long flags; + int idx = 0; + int len=0; + + len=sprintf(buffer,"Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta PDelta Expires (free=%d,%d)\n", + ip_masq_free_ports[0], ip_masq_free_ports[1]); + save_flags(flags); + cli(); + + for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++) + for(ms = ip_masq_m_tab[idx]; ms ; ms = ms->m_link) + { + int timer_active = del_timer(&ms->timer); + if (!timer_active) + ms->timer.expires = jiffies; + len+=sprintf(buffer+len,"%s %08lX:%04X %08lX:%04X %04X %08X %6d %6d %lu\n", + masq_proto_name(ms->protocol), + ntohl(ms->saddr),ntohs(ms->sport), + ntohl(ms->daddr),ntohs(ms->dport), + ntohs(ms->mport), + ms->out_seq.init_seq,ms->out_seq.delta,ms->out_seq.previous_delta,ms->timer.expires-jiffies); + if (timer_active) + add_timer(&ms->timer); + + pos=begin+len; + if(posoffset+length) + break; + } + restore_flags(flags); + *start=buffer+(offset-begin); + len-=(offset-begin); + if(len>length) + len=length; + return len; +} + +/* + * Initialize ip masquerading + */ +int ip_masq_init(void) +{ + register_symtab (&ip_masq_syms); + proc_net_register(&(struct proc_dir_entry) { + PROC_NET_IPMSQHST, 13, "ip_masquerade", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_net_inode_operations, + ip_msqhst_procinfo + }); + ip_masq_app_init(); + + return 0; +} diff -u --recursive --new-file v1.3.80/linux/net/ipv4/ip_masq_app.c linux/net/ipv4/ip_masq_app.c --- v1.3.80/linux/net/ipv4/ip_masq_app.c Thu Jan 1 02:00:00 1970 +++ linux/net/ipv4/ip_masq_app.c Sat Mar 30 13:20:34 1996 @@ -0,0 +1,570 @@ +/* + * IP_MASQ_APP application masquerading module + * + * + * Version: @(#)ip_masq_app.c 0.03 03/96 + * + * Author: Juan Jose Ciarlante, + * + * + * 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. + * + * Fixes: + * JJC : Implemented also input pkt hook + * + * + * FIXME: + * - ip_masq_skb_replace(): use same skb if space available. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char *strProt[] = {"UDP","TCP"}; + +static __inline__ const char * masq_proto_name(unsigned proto) +{ + return strProt[proto==IPPROTO_TCP]; +} + +#define IP_MASQ_APP_TAB_SIZE 16 /* must be power of 2 */ + +#define IP_MASQ_APP_HASH(proto, port) ((port^proto) & (IP_MASQ_APP_TAB_SIZE-1)) +#define IP_MASQ_APP_TYPE(proto, port) ( proto<<16 | port ) +#define IP_MASQ_APP_PORT(type) ( type & 0xffff ) +#define IP_MASQ_APP_PROTO(type) ( (type>>16) & 0x00ff ) + + +static struct symbol_table ip_masq_app_syms = { +#include + X(register_ip_masq_app), + X(unregister_ip_masq_app), + X(ip_masq_skb_replace), +#include +}; + +/* + * will hold masq app. hashed list heads + */ + +struct ip_masq_app *ip_masq_app_base[IP_MASQ_APP_TAB_SIZE]; + +/* + * ip_masq_app registration routine + * port: host byte order. + */ + +int register_ip_masq_app(struct ip_masq_app *mapp, unsigned short proto, __u16 port) +{ + unsigned long flags; + unsigned hash; + if (!mapp) { + printk("register_ip_masq_app(): NULL arg\n"); + return -EINVAL; + } + mapp->type = IP_MASQ_APP_TYPE(proto, port); + mapp->n_attach = 0; + hash = IP_MASQ_APP_HASH(proto, port); + + save_flags(flags); + cli(); + mapp->next = ip_masq_app_base[hash]; + ip_masq_app_base[hash] = mapp; + restore_flags(flags); + + return 0; +} + +/* + * ip_masq_app unreg. routine. + */ + +int unregister_ip_masq_app(struct ip_masq_app *mapp) +{ + struct ip_masq_app **mapp_p; + unsigned hash; + unsigned long flags; + if (!mapp) { + printk("unregister_ip_masq_app(): NULL arg\n"); + return -EINVAL; + } + /* + * only allow unregistration if it has no attachments + */ + if (mapp->n_attach) { + printk("unregister_ip_masq_app(): has %d attachments. failed\n", + mapp->n_attach); + return -EINVAL; + } + hash = IP_MASQ_APP_HASH(IP_MASQ_APP_PROTO(mapp->type), IP_MASQ_APP_PORT(mapp->type)); + + save_flags(flags); + cli(); + for (mapp_p = &ip_masq_app_base[hash]; *mapp_p ; mapp_p = &(*mapp_p)->next) + if (mapp == (*mapp_p)) { + *mapp_p = mapp->next; + restore_flags(flags); + return 0; + } + + restore_flags(flags); + printk("unregister_ip_masq_app(proto=%s,port=%u): not hashed!\n", + masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)), IP_MASQ_APP_PORT(mapp->type)); + return -EINVAL; +} + +/* + * get ip_masq_app object by its proto and port (net byte order). + */ + +struct ip_masq_app * ip_masq_app_get(unsigned short proto, __u16 port) +{ + struct ip_masq_app *mapp; + unsigned hash; + unsigned type; + + port = ntohs(port); + type = IP_MASQ_APP_TYPE(proto,port); + hash = IP_MASQ_APP_HASH(proto,port); + for(mapp = ip_masq_app_base[hash]; mapp ; mapp = mapp->next) { + if (type == mapp->type) return mapp; + } + return NULL; +} + +/* + * ip_masq_app object binding related funcs. + */ + +/* + * change ip_masq_app object's number of bindings + */ + +static __inline__ int ip_masq_app_bind_chg(struct ip_masq_app *mapp, int delta) +{ + unsigned long flags; + int n_at; + if (!mapp) return -1; + save_flags(flags); + cli(); + n_at = mapp->n_attach + delta; + if (n_at < 0) { + restore_flags(flags); + printk("ip_masq_app: tried to set n_attach < 0 for (proto=%s,port==%d) ip_masq_app object.\n", + masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)), + IP_MASQ_APP_PORT(mapp->type)); + return -1; + } + mapp->n_attach = n_at; + restore_flags(flags); + return 0; +} + +/* + * Bind ip_masq to its ip_masq_app based on proto and dport ALREADY + * set in ip_masq struct. Also calls constructor. + */ + +struct ip_masq_app * ip_masq_bind_app(struct ip_masq *ms) +{ + struct ip_masq_app * mapp; + mapp = ip_masq_app_get(ms->protocol, ms->dport); + if (mapp != NULL) { + /* + * don't allow binding if already bound + */ + + if (ms->app != NULL) { + printk("ip_masq_bind_app() called for already bound object.\n"); + return ms->app; + } + + ms->app = mapp; + if (mapp->masq_init_1) mapp->masq_init_1(mapp, ms); + ip_masq_app_bind_chg(mapp, +1); + } + return mapp; +} + +/* + * Unbind ms from type object and call ms destructor (does not kfree()). + */ + +int ip_masq_unbind_app(struct ip_masq *ms) +{ + struct ip_masq_app * mapp; + mapp = ms->app; + if (mapp != NULL) { + if (mapp->masq_done_1) mapp->masq_done_1(mapp, ms); + ms->app = NULL; + ip_masq_app_bind_chg(mapp, -1); + } + return (mapp != NULL); +} + +/* + * Fixes th->seq based on ip_masq_seq info. + */ + +static __inline__ void masq_fix_seq(const struct ip_masq_seq *ms_seq, struct tcphdr *th) +{ + __u32 seq; + + seq = ntohl(th->seq); + + /* + * Adjust seq with delta-offset for all packets after + * the most recent resized pkt seq and with previous_delta offset + * for all packets before most recent resized pkt seq. + */ + + if (ms_seq->delta || ms_seq->previous_delta) { + if(after(seq,ms_seq->init_seq) ) { + th->seq = htonl(seq + ms_seq->delta); +#if DEBUG_CONFIG_IP_MASQ_APP + printk("masq_fix_seq() : added delta (%d) to seq\n",ms_seq->delta); +#endif + } else { + th->seq = htonl(seq + ms_seq->previous_delta); +#if DEBUG_CONFIG_IP_MASQ_APP + printk("masq_fix_seq() : added previous_delta (%d) to seq\n",ms_seq->previous_delta); +#endif + } + } + + +} + +/* + * Fixes th->ack_seq based on ip_masq_seq info. + */ + +static __inline__ void masq_fix_ack_seq(const struct ip_masq_seq *ms_seq, struct tcphdr *th) +{ + __u32 ack_seq; + + ack_seq=ntohl(th->ack_seq); + + /* + * Adjust ack_seq with delta-offset for + * the packets AFTER most recent resized pkt has caused a shift + * for packets before most recent resized pkt, use previous_delta + */ + + if (ms_seq->delta || ms_seq->previous_delta) { + if(after(ack_seq,ms_seq->init_seq)) { + th->ack_seq = htonl(ack_seq-ms_seq->delta); +#if DEBUG_CONFIG_IP_MASQ_APP + printk("masq_fix_ack_seq() : substracted delta (%d) from ack_seq\n",ms_seq->delta); +#endif + } else { + th->ack_seq = htonl(ack_seq-ms_seq->previous_delta); +#if DEBUG_CONFIG_IP_MASQ_APP + printk("masq_fix_ack_seq() : substracted previous_delta (%d) from ack_seq\n",ms_seq->previous_delta); +#endif + } + } + +} + +/* + * Updates ip_masq_seq if pkt has been resized + * Assumes already checked proto==IPPROTO_TCP and diff!=0. + */ + +static __inline__ void masq_seq_update(struct ip_masq *ms, struct ip_masq_seq *ms_seq, unsigned mflag, __u32 seq, int diff) +{ + /* if (diff == 0) return; */ + + if ( !(ms->flags & mflag) || after(seq, ms_seq->init_seq)) + { + ms_seq->previous_delta=ms_seq->delta; + ms_seq->delta+=diff; + ms_seq->init_seq=seq; + ms->flags |= mflag; + } +} + +/* + * Output pkt hook. Will call bound ip_masq_app specific function + * called by ip_fw_masquerade(), assumes previously checked ms!=NULL + * returns (new - old) skb->len diff. + */ + +int ip_masq_app_pkt_out(struct ip_masq *ms, struct sk_buff **skb_p, struct device *dev) +{ + struct ip_masq_app * mapp; + struct iphdr *iph; + struct tcphdr *th; + int diff; + __u32 seq; + + /* + * check if application masquerading is bound to + * this ip_masq. + * assumes that once an ip_masq is bound, + * it will not be unbound during its life. + */ + + if ( (mapp = ms->app) == NULL) + return 0; + + iph = (*skb_p)->h.iph; + th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); + + /* + * Remember seq number in case this pkt gets resized + */ + + seq = ntohl(th->seq); + + /* + * Fix seq stuff if flagged as so. + */ + + if (ms->protocol == IPPROTO_TCP) { + if (ms->flags & IP_MASQ_F_OUT_SEQ) + masq_fix_seq(&ms->out_seq, th); + if (ms->flags & IP_MASQ_F_IN_SEQ) + masq_fix_ack_seq(&ms->in_seq, th); + } + + /* + * Call private output hook function + */ + + if ( mapp->pkt_out == NULL ) + return 0; + + diff = mapp->pkt_out(mapp, ms, skb_p, dev); + + /* + * Update ip_masq seq stuff if len has changed. + */ + + if (diff != 0 && ms->protocol == IPPROTO_TCP) + masq_seq_update(ms, &ms->out_seq, IP_MASQ_F_OUT_SEQ, seq, diff); + + return diff; +} + +/* + * Input pkt hook. Will call bound ip_masq_app specific function + * called by ip_fw_demasquerade(), assumes previously checked ms!=NULL. + * returns (new - old) skb->len diff. + */ + +int ip_masq_app_pkt_in(struct ip_masq *ms, struct sk_buff **skb_p, struct device *dev) +{ + struct ip_masq_app * mapp; + struct iphdr *iph; + struct tcphdr *th; + int diff; + __u32 seq; + + /* + * check if application masquerading is bound to + * this ip_masq. + * assumes that once an ip_masq is bound, + * it will not be unbound during its life. + */ + + if ( (mapp = ms->app) == NULL) + return 0; + + iph = (*skb_p)->h.iph; + th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); + + /* + * Remember seq number in case this pkt gets resized + */ + + seq = ntohl(th->seq); + + /* + * Fix seq stuff if flagged as so. + */ + + if (ms->protocol == IPPROTO_TCP) { + if (ms->flags & IP_MASQ_F_IN_SEQ) + masq_fix_seq(&ms->in_seq, th); + if (ms->flags & IP_MASQ_F_OUT_SEQ) + masq_fix_ack_seq(&ms->out_seq, th); + } + + /* + * Call private input hook function + */ + + if ( mapp->pkt_in == NULL ) + return 0; + + diff = mapp->pkt_in(mapp, ms, skb_p, dev); + + /* + * Update ip_masq seq stuff if len has changed. + */ + + if (diff != 0 && ms->protocol == IPPROTO_TCP) + masq_seq_update(ms, &ms->in_seq, IP_MASQ_F_IN_SEQ, seq, diff); + + return diff; +} + +/* + * /proc/ip_masq_app entry function + */ + +int ip_masq_app_getinfo(char *buffer, char **start, off_t offset, int length, int dummy) +{ + off_t pos=0, begin=0; + int len=0; + struct ip_masq_app * mapp; + unsigned idx; + len=sprintf(buffer,"prot port n_attach\n"); + for (idx=0 ; idx < IP_MASQ_APP_TAB_SIZE; idx++) + for (mapp = ip_masq_app_base[idx]; mapp ; mapp = mapp->next) { + len += sprintf(buffer+len, "%s %-7u %-7d\n", + masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)), + IP_MASQ_APP_PORT(mapp->type), mapp->n_attach); + pos=begin+len; + if(posoffset+length) + break; + } + *start=buffer+(offset-begin); + len-=(offset-begin); + if(len>length) + len=length; + return len; +} + + +/* + * Initialization routine + */ + +int ip_masq_app_init(void) +{ + + register_symtab (&ip_masq_app_syms); + + proc_net_register(&(struct proc_dir_entry) { + PROC_NET_IP_MASQ_APP, 11, "ip_masq_app", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_net_inode_operations, + ip_masq_app_getinfo + }); + + return 0; +} + +/* + * Replace a segment (of skb->data) with a new one. + * FIXME: Should re-use same skb if space available, this could + * be done if n_len < o_len, unless some extra space + * were already allocated at driver level :P . + */ + +static struct sk_buff * skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len) +{ + int diff, o_offset; + struct sk_buff *n_skb; + + diff = n_len - o_len; + o_offset = o_buf - (char*) skb->data; + + if (diff != 0) { + + /* + * Sizes differ, make a copy + */ + + n_skb = alloc_skb(MAX_HEADER + skb->len + diff, pri); + if (n_skb == NULL) { + printk("skb_replace(): no room left (from %p)\n", + __builtin_return_address(0)); + return skb; + + } + n_skb->free = skb->free; + skb_reserve(n_skb, MAX_HEADER); + skb_put(n_skb, skb->len + diff); + n_skb->h.raw = n_skb->data + (skb->h.raw - skb->data); + + /* + * Copy pkt in new buffer + */ + + memcpy(n_skb->data, skb->data, o_offset); + memcpy(n_skb->data + o_offset, n_buf, n_len); + memcpy(n_skb->data + o_offset + n_len, o_buf + o_len, + skb->len - (o_offset + o_len) ); + + /* + * Problem, how to replace the new skb with old one, + * preferably inplace + */ + + kfree_skb(skb, FREE_WRITE); + + } else { + + /* + * Same len, just copy + */ + n_skb = skb; + memcpy(n_skb->data + o_offset, n_buf, n_len); + } + return n_skb; +} + +/* + * calls skb_replace() and update ip header if new skb was allocated + */ + +struct sk_buff * ip_masq_skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len) +{ + int diff; + struct sk_buff *n_skb; + unsigned skb_len; + + diff = n_len - o_len; + n_skb = skb_replace(skb, pri, o_buf, o_len, n_buf, n_len); + skb_len = skb->len; + + if (diff) + { + struct iphdr *iph; +#if DEBUG_CONFIG_IP_MASQ_APP + printk("masq_skb_replace(): pkt resized for %d bytes (len=%ld)\n", diff, skb->len); +#endif + /* + * update ip header + */ + iph = n_skb->h.iph; + iph->check = 0; + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); + iph->tot_len = htons(skb_len + diff); + } + return n_skb; +} diff -u --recursive --new-file v1.3.80/linux/net/ipv4/ip_masq_ftp.c linux/net/ipv4/ip_masq_ftp.c --- v1.3.80/linux/net/ipv4/ip_masq_ftp.c Thu Jan 1 02:00:00 1970 +++ linux/net/ipv4/ip_masq_ftp.c Sat Mar 30 13:20:34 1996 @@ -0,0 +1,198 @@ +/* + * IP_MASQ_FTP ftp masquerading module + * + * + * Version: @(#)ip_masq_ftp.c 0.01 02/05/96 + * + * Author: Wouter Gadeyne + * + * + * Fixes: + * Wouter Gadeyne : Fixed masquerading support of ftp PORT commands + * Juan Jose Ciarlante : Code moved and adapted from ip_fw.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 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_CONFIG_IP_MASQ_FTP 0 + +static int +masq_ftp_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static int +masq_ftp_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +int +masq_ftp_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, struct device *dev) +{ + struct sk_buff *skb; + struct iphdr *iph; + struct tcphdr *th; + char *p, *data, *data_limit; + unsigned char p1,p2,p3,p4,p5,p6; + __u32 from; + __u16 port; + struct ip_masq *n_ms; + char buf[24]; /* xxx.xxx.xxx.xxx,ppp,ppp\000 */ + unsigned buf_len; + int diff; + + skb = *skb_p; + iph = skb->h.iph; + th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); + data = (char *)&th[1]; + + data_limit = skb->h.raw + skb->len - 18; + + while (data < data_limit) + { + if (memcmp(data,"PORT ",5) && memcmp(data,"port ",5)) + { + data ++; + continue; + } + p = data+5; + p1 = simple_strtoul(data+5,&data,10); + if (*data!=',') + continue; + p2 = simple_strtoul(data+1,&data,10); + if (*data!=',') + continue; + p3 = simple_strtoul(data+1,&data,10); + if (*data!=',') + continue; + p4 = simple_strtoul(data+1,&data,10); + if (*data!=',') + continue; + p5 = simple_strtoul(data+1,&data,10); + if (*data!=',') + continue; + p6 = simple_strtoul(data+1,&data,10); + if (*data!='\r' && *data!='\n') + continue; + + from = (p1<<24) | (p2<<16) | (p3<<8) | p4; + port = (p5<<8) | p6; +#if DEBUG_CONFIG_IP_MASQ_FTP + printk("PORT %lX:%X detected\n",from,port); +#endif + /* + * Now create an masquerade entry for it + */ + n_ms = ip_masq_new(dev, IPPROTO_TCP, + htonl(from), htons(port), + iph->daddr, 0, + IP_MASQ_F_NO_DPORT); + + if (n_ms==NULL) + return 0; + + ip_masq_set_expire(n_ms, MASQUERADE_EXPIRE_TCP_FIN); + + /* + * Replace the old PORT with the new one + */ + from = ntohl(n_ms->maddr); + port = ntohs(n_ms->mport); + sprintf(buf,"%d,%d,%d,%d,%d,%d", + from>>24&255,from>>16&255,from>>8&255,from&255, + port>>8&255,port&255); + buf_len = strlen(buf); + + /* + * Calculate required delta-offset to keep TCP happy + */ + + diff = buf_len - (data-p); + + /* + * No shift. + */ + + if (diff==0) + { + /* + * simple case, just replace the old PORT cmd + */ + memcpy(p,buf,buf_len); + return 0; + } + + *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC, p, data-p, buf, buf_len); + return diff; + + } + return 0; + +} + +struct ip_masq_app ip_masq_ftp = { + NULL, /* next */ + 0, /* type */ + 0, /* n_attach */ + masq_ftp_init_1, /* ip_masq_init_1 */ + masq_ftp_done_1, /* ip_masq_done_1 */ + masq_ftp_out, /* pkt_out */ + NULL /* pkt_in */ +}; + +/* + * ip_masq_ftp initialization + */ + +int ip_masq_ftp_init(void) +{ + return register_ip_masq_app(&ip_masq_ftp, IPPROTO_TCP, 21); +} + +/* + * ip_masq_ftp fin. + */ + +int ip_masq_ftp_done(void) +{ + return unregister_ip_masq_app(&ip_masq_ftp); +} + +#ifdef MODULE + +int init_module(void) +{ + if (ip_masq_ftp_init() != 0) + return -EIO; + register_symtab(0); + return 0; +} + +void cleanup_module(void) +{ + if (ip_masq_ftp_done() != 0) + printk("ip_masq_ftp: can't remove module"); +} + +#endif /* MODULE */ diff -u --recursive --new-file v1.3.80/linux/net/ipv4/ip_masq_irc.c linux/net/ipv4/ip_masq_irc.c --- v1.3.80/linux/net/ipv4/ip_masq_irc.c Thu Jan 1 02:00:00 1970 +++ linux/net/ipv4/ip_masq_irc.c Sat Mar 30 13:20:34 1996 @@ -0,0 +1,269 @@ +/* + * IP_MASQ_IRC irc masquerading module + * + * + * Version: @(#)ip_masq_irc.c 0.01 03/20/96 + * + * Author: Juan Jose Ciarlante + * + * + * Fixes: + * - set NO_DADDR flag in ip_masq_new(). + * + * FIXME: + * - detect also previous "PRIVMSG" string ?. + * + * 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 + +#define DEBUG_CONFIG_IP_MASQ_IRC 0 + +static int +masq_irc_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static int +masq_irc_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +int +masq_irc_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, struct device *dev) +{ + struct sk_buff *skb; + struct iphdr *iph; + struct tcphdr *th; + char *data, *data_limit; + __u32 s_addr; + __u16 s_port; + struct ip_masq *n_ms; + char buf[20]; /* "m_addr m_port" (dec base)*/ + unsigned buf_len; + int diff; + int xtra_args = 0; /* extra int args wanted after addr */ + char *dcc_p, *addr_beg_p, *addr_end_p; + + skb = *skb_p; + iph = skb->h.iph; + th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); + data = (char *)&th[1]; + + /* + * Hunt irc DCC string, the _shortest_: + * + * strlen("DCC CHAT chat AAAAAAAA P\x01\n")=26 + * strlen("DCC SEND F AAAAAAAA P S\x01\n")=25 + * AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits) + * P: bound port (min 1 d ) + * F: filename (min 1 d ) + * S: size (min 1 d ) + * 0x01, \n: terminators + */ + + data_limit = skb->h.raw + skb->len; + + while (data < (data_limit - 25) ) + { + if (memcmp(data,"DCC ",4)) { + data ++; + continue; + } + + dcc_p = data; + data += 4; /* point to DCC cmd */ + + if (memcmp(data, "CHAT ", 5) == 0 || + memcmp(data, "SEND ", 5) == 0) + { + /* + * extra arg (file_size) req. for "SEND" + */ + + if (*data == 'S') xtra_args++; + data += 5; + } + else + continue; + + /* + * skip next string. + */ + + while( *data++ != ' ') + + /* + * must still parse, at least, "AAAAAAAA P\x01\n", + * 12 bytes left. + */ + if (data > (data_limit-12)) return 0; + + + addr_beg_p = data; + + /* + * client bound address in dec base + */ + + s_addr = simple_strtoul(data,&data,10); + if (*data++ !=' ') + continue; + + /* + * client bound port in dec base + */ + + s_port = simple_strtoul(data,&data,10); + addr_end_p = data; + + /* + * should check args consistency? + */ + + while(xtra_args) { + if (*data != ' ') + break; + data++; + simple_strtoul(data,&data,10); + xtra_args--; + } + + if (xtra_args != 0) continue; + + /* + * terminators. + */ + + if (data[0] != 0x01) + continue; + if (data[1]!='\r' && data[1]!='\n') + continue; + + /* + * Now create an masquerade entry for it + * must set NO_DPORT and NO_DADDR because + * connection is requested by another client. + */ + + n_ms = ip_masq_new(dev, IPPROTO_TCP, + htonl(s_addr),htons(s_port), + 0, 0, + IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR + ); + if (n_ms==NULL) + return 0; + + ip_masq_set_expire(n_ms, MASQUERADE_EXPIRE_TCP_FIN); + + /* + * Replace the old "address port" with the new one + */ + + buf_len = sprintf(buf,"%lu %u", + ntohl(n_ms->maddr),ntohs(n_ms->mport)); + + /* + * Calculate required delta-offset to keep TCP happy + */ + + diff = buf_len - (addr_end_p-addr_beg_p); + +#if DEBUG_CONFIG_IP_MASQ_IRC + *addr_beg_p = '\0'; + printk("masq_irc_out(): '%s' %X:%X detected (diff=%d)\n", dcc_p, s_addr,s_port, diff); +#endif + /* + * No shift. + */ + + if (diff==0) + { + /* + * simple case, just copy. + */ + memcpy(addr_beg_p,buf,buf_len); + return 0; + } + + *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC, + addr_beg_p, addr_end_p-addr_beg_p, + buf, buf_len); + return diff; + } + return 0; + +} + +/* + * Main irc object + * You need 1 object per port in case you need + * to offer also other used irc ports (6665,6666,etc), + * they will share methods but they need own space for + * data. + */ + +struct ip_masq_app ip_masq_irc = { + NULL, /* next */ + 0, /* type */ + 0, /* n_attach */ + masq_irc_init_1, /* init_1 */ + masq_irc_done_1, /* done_1 */ + masq_irc_out, /* pkt_out */ + NULL /* pkt_in */ +}; + +/* + * ip_masq_irc initialization + */ + +int ip_masq_irc_init(void) +{ + return register_ip_masq_app(&ip_masq_irc, IPPROTO_TCP, 6667); +} + +/* + * ip_masq_irc fin. + */ + +int ip_masq_irc_done(void) +{ + return unregister_ip_masq_app(&ip_masq_irc); +} + +#ifdef MODULE + +int init_module(void) +{ + if (ip_masq_irc_init() != 0) + return -EIO; + register_symtab(NULL); + return 0; +} + +void cleanup_module(void) +{ + if (ip_masq_irc_done() != 0) + printk("ip_masq_irc: can't remove module"); +} + +#endif /* MODULE */ diff -u --recursive --new-file v1.3.80/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c --- v1.3.80/linux/net/ipv4/ip_output.c Sun Mar 10 09:28:57 1996 +++ linux/net/ipv4/ip_output.c Sat Mar 30 13:20:34 1996 @@ -239,7 +239,7 @@ if ((LOOPBACK(saddr) && !LOOPBACK(daddr)) || !saddr) saddr = rt ? rt->rt_src : (*dev)->pa_addr; - raddr = rt ? rt->rt_gateway : 0; + raddr = rt ? rt->rt_gateway : daddr; if (opt && opt->is_strictroute && rt && (rt->rt_flags & RTF_GATEWAY)) { @@ -247,13 +247,6 @@ ip_statistics.IpOutNoRoutes++; return -ENETUNREACH; } - - /* - * No gateway so aim at the real destination - */ - - if (raddr == 0) - raddr = daddr; /* * Now build the MAC header. diff -u --recursive --new-file v1.3.80/linux/net/ipv4/route.c linux/net/ipv4/route.c --- v1.3.80/linux/net/ipv4/route.c Sat Mar 16 13:52:12 1996 +++ linux/net/ipv4/route.c Sat Mar 30 13:20:34 1996 @@ -41,6 +41,7 @@ * Olaf Erb : irtt wasnt being copied right. * Bjorn Ekwall : Kerneld route support. * Alan Cox : Multicast fixed (I hope) + * Pavel Krauz : Limited broadcast fixed * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -1558,9 +1559,9 @@ if (!(rth->rt_flags & RTF_GATEWAY)) rth->rt_gateway = rth->rt_dst; /* - * Multicast is never gatewayed. + * Multicast or limited broadcast is never gatewayed. */ - if (MULTICAST(daddr)) + if (MULTICAST(daddr) || daddr == 0xFFFFFFFF) rth->rt_gateway = rth->rt_dst; if (ip_rt_lock == 1) diff -u --recursive --new-file v1.3.80/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c --- v1.3.80/linux/net/ipx/af_ipx.c Mon Mar 25 08:58:25 1996 +++ linux/net/ipx/af_ipx.c Sat Mar 30 13:20:34 1996 @@ -74,6 +74,7 @@ #include /* For TIOCOUTQ/INQ */ #include #include +#include #include #include #include @@ -90,6 +91,7 @@ /* Global Variables */ static struct datalink_proto *p8022_datalink = NULL; +static struct datalink_proto *p8022tr_datalink = NULL; static struct datalink_proto *pEII_datalink = NULL; static struct datalink_proto *p8023_datalink = NULL; static struct datalink_proto *pSNAP_datalink = NULL; @@ -840,6 +842,7 @@ switch (type) { case IPX_FRAME_ETHERII: return htons(ETH_P_IPX); case IPX_FRAME_8022: return htons(ETH_P_802_2); + case IPX_FRAME_TR_8022: return htons(ETH_P_TR_802_2); case IPX_FRAME_SNAP: return htons(ETH_P_SNAP); case IPX_FRAME_8023: return htons(ETH_P_802_3); } @@ -869,6 +872,10 @@ dlink_type = htons(ETH_P_IPX); datalink = pEII_datalink; break; + case IPX_FRAME_TR_8022: + dlink_type = htons(ETH_P_TR_802_2); + datalink = p8022tr_datalink; + break; case IPX_FRAME_8022: dlink_type = htons(ETH_P_802_2); datalink = p8022_datalink; @@ -969,6 +976,7 @@ switch (htons(dlink_type)) { case ETH_P_IPX: datalink = pEII_datalink; break; case ETH_P_802_2: datalink = p8022_datalink; break; + case ETH_P_TR_802_2: datalink = p8022tr_datalink; break; case ETH_P_SNAP: datalink = pSNAP_datalink; break; case ETH_P_802_3: datalink = p8023_datalink; break; default: return NULL; @@ -1318,6 +1326,7 @@ case ETH_P_802_2: return "802.2"; case ETH_P_SNAP: return "SNAP"; case ETH_P_802_3: return "802.3"; + case ETH_P_TR_802_2: return "802.2TR"; default: return "None"; } } @@ -2257,6 +2266,9 @@ if ((p8022_datalink = register_8022_client(ipx_8022_type, ipx_rcv)) == NULL) printk("IPX: Unable to register with 802.2\n"); + if ((p8022tr_datalink = register_8022tr_client(ipx_8022_type, ipx_rcv)) == NULL) + printk("IPX: Unable to register with 802.2TR\n"); + if ((pSNAP_datalink = register_snap_client(ipx_snap_id, ipx_rcv)) == NULL) printk("IPX: Unable to register with SNAP\n"); diff -u --recursive --new-file v1.3.80/linux/net/netsyms.c linux/net/netsyms.c --- v1.3.80/linux/net/netsyms.c Thu Mar 28 17:34:35 1996 +++ linux/net/netsyms.c Sat Mar 30 13:20:34 1996 @@ -56,11 +56,11 @@ static struct symbol_table net_syms = { #include - /* Socket layer registration */ - X(sock_register), - X(sock_unregister), + /* Socket layer registration */ + X(sock_register), + X(sock_unregister), - /* Socket layer support routines */ + /* Socket layer support routines */ X(memcpy_fromiovec), X(sock_setsockopt), X(sock_getsockopt), @@ -116,8 +116,8 @@ #endif #ifdef CONFIG_TR - X(tr_setup), - X(tr_type_trans), + X(tr_setup), + X(tr_type_trans), #endif #ifdef CONFIG_NET_ALIAS diff -u --recursive --new-file v1.3.80/linux/net/protocols.c linux/net/protocols.c --- v1.3.80/linux/net/protocols.c Mon Mar 25 08:58:28 1996 +++ linux/net/protocols.c Sat Mar 30 13:20:34 1996 @@ -21,6 +21,7 @@ #if defined(CONFIG_IPX) || defined(CONFIG_IPX_MODULE) #include #include +#include #endif #ifdef CONFIG_AX25 #include @@ -31,6 +32,7 @@ #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) #if ! ( defined(CONFIG_IPX) || defined(CONFIG_IPX_MODULE) ) #include +#include #endif #include #endif @@ -51,6 +53,7 @@ #if defined(CONFIG_IPX) || defined(CONFIG_IPX_MODULE) || \ defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) { "802.2", p8022_proto_init }, /* 802.2 demultiplexor */ + { "802.2TR", p8022tr_proto_init }, /* 802.2 demultiplexor */ { "SNAP", snap_proto_init }, /* SNAP demultiplexor */ #endif #ifdef CONFIG_TR diff -u --recursive --new-file v1.3.80/linux/net/socket.c linux/net/socket.c --- v1.3.80/linux/net/socket.c Mon Mar 25 08:58:28 1996 +++ linux/net/socket.c Sat Mar 30 13:44:15 1996 @@ -65,7 +65,10 @@ #include #include #include + +#ifdef CONFIG_KERNELD #include +#endif #include @@ -1027,7 +1030,7 @@ return err; msg.msg_accrights=NULL; - msg.msg_iovlen=0; + msg.msg_iovlen=1; msg.msg_iov=&iov; iov.iov_len=size; iov.iov_base=ubuf;