diff -u --recursive --new-file v2.1.10/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.10/linux/Documentation/Configure.help Fri Nov 15 23:49:06 1996 +++ linux/Documentation/Configure.help Mon Nov 18 11:31:30 1996 @@ -1,7 +1,7 @@ # Maintained by Axel Boldt (boldt@math.ucsb.edu) # # This version of the Linux kernel configuration help texts -# corresponds to the kernel versions 2.0.x. +# corresponds to the kernel versions 2.1.x. # # International versions of this file available on the WWW: # - http://jf.gee.kyoto-u.ac.jp/JF/JF-ftp/euc/Configure.help.euc @@ -847,6 +847,13 @@ network think they're talking to a remote computer, while in reality the traffic is redirected by your Linux firewall to a local proxy server). + +IP: firewall packet netlink device +CONFIG_IP_FIREWALL_NETLINK + When packets hit the firewall and are blocked the first 128 bytes of each + datagram is passed to optional user space monitoring software that can + then look for attacks and take actions such as paging the administrator of + the site. IP: accounting CONFIG_IP_ACCT diff -u --recursive --new-file v2.1.10/linux/Makefile linux/Makefile --- v2.1.10/linux/Makefile Fri Nov 15 23:49:06 1996 +++ linux/Makefile Mon Nov 18 11:59:10 1996 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 10 +SUBLEVEL = 11 ARCH = i386 diff -u --recursive --new-file v2.1.10/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c --- v2.1.10/linux/arch/alpha/kernel/bios32.c Wed Aug 7 12:31:21 1996 +++ linux/arch/alpha/kernel/bios32.c Mon Nov 18 10:18:58 1996 @@ -37,6 +37,14 @@ { return 0; } +asmlinkage int sys_pciconfig_read() +{ + return 0; +} +asmlinkage int sys_pciconfig_write() +{ + return 0; +} #else /* CONFIG_PCI */ @@ -48,6 +56,7 @@ #include #include +#include #define KB 1024 @@ -1193,4 +1202,81 @@ } } +asmlinkage int sys_pciconfig_read( + unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf) +{ + unsigned char ubyte; + unsigned short ushort; + unsigned int uint; + long err = 0; + + switch (len) { + case 1: + err = pcibios_read_config_byte(bus, dfn, off, &ubyte); + if (err != PCIBIOS_SUCCESSFUL) + ubyte = 0xff; + put_user(ubyte, buf); + break; + case 2: + err = pcibios_read_config_word(bus, dfn, off, &ushort); + if (err != PCIBIOS_SUCCESSFUL) + ushort = 0xffff; + put_user(ushort, (unsigned short *)buf); + break; + case 4: + err = pcibios_read_config_dword(bus, dfn, off, &uint); + if (err != PCIBIOS_SUCCESSFUL) + uint = 0xffffffff; + put_user(uint, (unsigned int *)buf); + break; + default: + err = -EINVAL; + break; + } + return err; +} +asmlinkage int sys_pciconfig_write( + unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf) +{ + unsigned char ubyte; + unsigned short ushort; + unsigned int uint; + long err = 0; + + switch (len) { + case 1: + ubyte = get_user(buf); + err = pcibios_write_config_byte(bus, dfn, off, ubyte); + if (err != PCIBIOS_SUCCESSFUL) { + err = -EFAULT; + } + break; + case 2: + ushort = get_user((unsigned short *)buf); + err = pcibios_write_config_word(bus, dfn, off, ushort); + if (err != PCIBIOS_SUCCESSFUL) { + err = -EFAULT; + } + break; + case 4: + uint = get_user((unsigned int *)buf); + err = pcibios_write_config_dword(bus, dfn, off, uint); + if (err != PCIBIOS_SUCCESSFUL) { + err = -EFAULT; + } + break; + default: + err = -EINVAL; + break; + } + return err; +} #endif /* CONFIG_PCI */ diff -u --recursive --new-file v2.1.10/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.1.10/linux/arch/alpha/kernel/entry.S Fri Nov 1 17:13:14 1996 +++ linux/arch/alpha/kernel/entry.S Mon Nov 18 23:51:30 1996 @@ -777,4 +777,4 @@ .quad sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler, sys_sched_yield .quad sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, do_entSys /* sys_afs_syscall */, sys_newuname .quad sys_nanosleep, sys_mremap, do_entSys, sys_setresuid, sys_getresuid - .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad sys_pciconfig_read, sys_pciconfig_write, do_entSys, do_entSys, do_entSys diff -u --recursive --new-file v2.1.10/linux/arch/alpha/lib/strlen_user.S linux/arch/alpha/lib/strlen_user.S --- v2.1.10/linux/arch/alpha/lib/strlen_user.S Fri Nov 15 23:49:06 1996 +++ linux/arch/alpha/lib/strlen_user.S Fri Nov 15 22:30:13 1996 @@ -1,8 +1,8 @@ /* - * arch/alpha/lib/__strlen_user.S + * arch/alpha/lib/strlen_user.S * - * Just like strlen except returns -EFAULT if an exception occurs - * before the terminator is found. + * Return the length of the string including the NUL terminator + * (strlen+1) or zero if an error occured. */ #include @@ -13,7 +13,7 @@ 99: x,##y; \ .section __ex_table,"a"; \ .gprel32 99b; \ - lda zero, $exception-99b(zero); \ + lda v0, $exception-99b(zero); \ .text @@ -34,7 +34,7 @@ insqh t1, a0, t1 andnot a0, 7, v0 or t1, t0, t0 - subq a0, 1, a0 # return "1+strlen" (0 for exception) + subq a0, 1, a0 # get our +1 for the return cmpbge zero, t0, t1 # t1 <- bitmask: bit i == 1 <==> i-th byte == 0 bne t1, $found @@ -56,12 +56,8 @@ addq v0, t4, v0 addq v0, t2, v0 nop # dual issue next two on ev4 and ev5 - subq v0, a0, v0 - ret - $exception: - mov zero, v0 ret .end __strlen_user diff -u --recursive --new-file v2.1.10/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.1.10/linux/arch/i386/defconfig Tue Nov 12 15:56:02 1996 +++ linux/arch/i386/defconfig Mon Nov 18 12:01:48 1996 @@ -62,6 +62,7 @@ # # Networking options # +# CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set # CONFIG_NET_ALIAS is not set CONFIG_INET=y @@ -84,7 +85,6 @@ # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_AX25 is not set -# CONFIG_NETLINK is not set # # SCSI support @@ -95,12 +95,9 @@ # Network device support # CONFIG_NETDEVICES=y +# CONFIG_ARCNET is not set CONFIG_DUMMY=m # CONFIG_EQUALIZER is not set -# CONFIG_PLIP is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set -# CONFIG_NET_RADIO is not set CONFIG_NET_ETHERNET=y CONFIG_NET_VENDOR_3COM=y # CONFIG_EL1 is not set @@ -112,8 +109,12 @@ # CONFIG_NET_ISA is not set # CONFIG_NET_EISA is not set # CONFIG_NET_POCKET is not set +# CONFIG_FDDI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_NET_RADIO is not set +# CONFIG_SLIP is not set # CONFIG_TR is not set -# CONFIG_ARCNET is not set # # ISDN subsystem diff -u --recursive --new-file v2.1.10/linux/arch/i386/kernel/ksyms.c linux/arch/i386/kernel/ksyms.c --- v2.1.10/linux/arch/i386/kernel/ksyms.c Fri Nov 15 23:49:06 1996 +++ linux/arch/i386/kernel/ksyms.c Mon Nov 18 11:31:30 1996 @@ -27,6 +27,10 @@ X(apic_reg), /* Needed internally for the I386 inlines */ X(cpu_data), X(syscall_count), + X(kernel_flag), + X(kernel_counter), + X(active_kernel_processor), + X(smp_invalidate_needed), #endif #include }; diff -u --recursive --new-file v2.1.10/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v2.1.10/linux/drivers/block/loop.c Tue Oct 29 19:58:03 1996 +++ linux/drivers/block/loop.c Mon Nov 18 11:31:30 1996 @@ -431,7 +431,7 @@ unsigned int cmd, unsigned long arg) { struct loop_device *lo; - int dev, err; + int dev; if (!inode) return -EINVAL; diff -u --recursive --new-file v2.1.10/linux/drivers/block/md.c linux/drivers/block/md.c --- v2.1.10/linux/drivers/block/md.c Fri Nov 1 17:13:14 1996 +++ linux/drivers/block/md.c Mon Nov 18 11:31:30 1996 @@ -372,7 +372,7 @@ static long md_read (struct inode *inode, struct file *file, - char *buf, int count) + char *buf, unsigned long count) { int minor=MINOR(inode->i_rdev); @@ -383,7 +383,7 @@ } static long md_write (struct inode *inode, struct file *file, - const char *buf, int count) + const char *buf, unsigned long count) { int minor=MINOR(inode->i_rdev); diff -u --recursive --new-file v2.1.10/linux/drivers/cdrom/cm206.c linux/drivers/cdrom/cm206.c --- v2.1.10/linux/drivers/cdrom/cm206.c Wed Aug 14 10:21:03 1996 +++ linux/drivers/cdrom/cm206.c Mon Nov 18 11:31:30 1996 @@ -580,7 +580,7 @@ /* The new open. The real opening strategy is defined in cdrom.c. */ -static int cm206_open(kdev_t dev, int purpose) +static int cm206_open(struct cdrom_device_info *i, int purpose) { if (!cd->openfiles) { /* reset only first time */ cd->background=0; @@ -593,7 +593,7 @@ return 0; } -static void cm206_release(kdev_t dev) +static void cm206_release(struct cdrom_device_info *i) { if (cd->openfiles==1) { if (cd->background) { @@ -885,7 +885,7 @@ * upon success. Memory checking has been done by cdrom_ioctl(), the * calling function, as well as LBA/MSF sanitization. */ -int cm206_audio_ioctl(kdev_t dev, unsigned int cmd, void * arg) +int cm206_audio_ioctl(struct cdrom_device_info *i, unsigned int cmd, void * arg) { switch (cmd) { case CDROMREADTOCHDR: @@ -930,7 +930,7 @@ some driver statistics accessible through ioctl calls. */ -static int cm206_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg) +static int cm206_ioctl(struct cdrom_device_info *i, unsigned int cmd, unsigned long arg) { switch (cmd) { #ifdef STATISTICS @@ -947,7 +947,7 @@ } } -int cm206_media_changed(kdev_t dev) +int cm206_media_changed(struct cdrom_device_info *i, int n) { if (cd != NULL) { int r; @@ -963,14 +963,14 @@ the logic should be in cdrom.c */ /* returns number of times device is in use */ -int cm206_open_files(kdev_t dev) +int cm206_open_files(struct cdrom_device_info *i) { if (cd) return cd->openfiles; return -1; } /* controls tray movement */ -int cm206_tray_move(kdev_t dev, int position) +int cm206_tray_move(struct cdrom_device_info *i, int position) { if (position) { /* 1: eject */ type_0_command(c_open_tray,1); @@ -981,7 +981,7 @@ } /* gives current state of the drive */ -int cm206_drive_status(kdev_t dev) +int cm206_drive_status(struct cdrom_device_info *i, int n) { get_drive_status(); if (cd->dsb & dsb_tray_not_closed) return CDS_TRAY_OPEN; @@ -991,7 +991,7 @@ } /* gives current state of disc in drive */ -int cm206_disc_status(kdev_t dev) +int cm206_disc_status(struct cdrom_device_info *i) { uch xa; get_drive_status(); @@ -1009,7 +1009,7 @@ } /* locks or unlocks door lock==1: lock; return 0 upon success */ -int cm206_lock_door(kdev_t dev, int lock) +int cm206_lock_door(struct cdrom_device_info *i, int lock) { uch command = (lock) ? c_lock_tray : c_unlock_tray; type_0_command(command, 1); /* wait and get dsb */ @@ -1020,7 +1020,7 @@ /* Although a session start should be in LBA format, we return it in MSF format because it is slightly easier, and the new generic ioctl will take care of the necessary conversion. */ -int cm206_get_last_session(kdev_t dev, struct cdrom_multisession * mssp) +int cm206_get_last_session(struct cdrom_device_info *i, struct cdrom_multisession * mssp) { if (!FIRST_TRACK) get_disc_status(); if (mssp != NULL) { @@ -1038,7 +1038,7 @@ return 0; } -int cm206_get_upc(kdev_t dev, struct cdrom_mcn * mcn) +int cm206_get_upc(struct cdrom_device_info *info, struct cdrom_mcn * mcn) { uch upc[10]; char * ret = mcn->medium_catalog_number; @@ -1054,7 +1054,7 @@ return 0; } -int cm206_reset(kdev_t dev) +int cm206_reset(struct cdrom_device_info *i) { stop_read(); reset_cm260(); @@ -1070,7 +1070,6 @@ static struct cdrom_device_ops cm206_dops = { cm206_open, /* open */ cm206_release, /* release */ - cm206_open_files, /* number of open_files */ cm206_drive_status, /* drive status */ cm206_disc_status, /* disc status */ cm206_media_changed, /* media changed */ @@ -1085,21 +1084,30 @@ cm206_ioctl, /* device-specific ioctl */ CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_MULTI_SESSION | CDC_MEDIA_CHANGED | CDC_MCN | CDC_PLAY_AUDIO, /* capability */ - 0, /* mask flags */ - 2, /* maximum speed */ 1, /* number of minor devices */ - 1, /* number of discs */ - 0, /* options, ignored */ - 0 /* mc_flags, ignored */ }; +static struct cdrom_device_info cm206_info= { + &cm206_dops, + NULL, + NULL, + CM206_CDROM_MAJOR, + CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_MULTI_SESSION | + CDC_MEDIA_CHANGED | CDC_MCN | CDC_PLAY_AUDIO, /* capability */ + 2, /* maximum speed */ + 1, /* number of discs */ + 0, /* options, ignored */ + 0, /* mc_flags, ignored */ + 0 +}; + /* This routine gets called during init if thing go wrong, can be used * in cleanup_module as well. */ void cleanup(int level) { switch (level) { case 4: - if (unregister_cdrom(MAJOR_NR, "cm206")) { + if (unregister_cdrom(&cm206_info)) { printk("Can't unregister cdrom cm206\n"); return; } @@ -1221,7 +1229,7 @@ cleanup(3); return -EIO; } - if (register_cdrom(MAJOR_NR, "cm206", &cm206_dops) != 0) { + if (register_cdrom(&cm206_info,"cm206") != 0) { printk("Cannot register for cdrom %d!\n", MAJOR_NR); cleanup(3); return -EIO; diff -u --recursive --new-file v2.1.10/linux/drivers/cdrom/optcd.c linux/drivers/cdrom/optcd.c --- v2.1.10/linux/drivers/cdrom/optcd.c Wed Oct 16 10:48:10 1996 +++ linux/drivers/cdrom/optcd.c Mon Nov 18 11:31:30 1996 @@ -73,6 +73,8 @@ #include #include +#include + /* Debug support */ diff -u --recursive --new-file v2.1.10/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c --- v2.1.10/linux/drivers/char/cyclades.c Tue Oct 29 19:58:05 1996 +++ linux/drivers/char/cyclades.c Mon Nov 18 11:44:51 1996 @@ -1929,7 +1929,7 @@ | ((status & CyRI) ? TIOCM_RNG : 0) | ((status & CyDSR) ? TIOCM_DSR : 0) | ((status & CyCTS) ? TIOCM_CTS : 0); - put_fs_long(result,(unsigned long *) value); + put_user(result,(unsigned int *) value); return 0; } /* get_modem_info */ @@ -1940,7 +1940,9 @@ int card,chip,channel,index; unsigned char *base_addr; unsigned long flags; - unsigned int arg = get_fs_long((unsigned long *) value); + unsigned int arg; + + get_user(arg,(unsigned int *) value); card = info->card; channel = (info->line) - (cy_card[card].first_line); @@ -2085,7 +2087,7 @@ (cy_card[card].base_addr + (cy_chip_offset[chip]<default_threshold,value); + put_user(info->default_threshold,value); return 0; } @@ -2137,7 +2139,7 @@ (cy_card[card].base_addr + (cy_chip_offset[chip]<default_timeout,value); + put_user(info->default_timeout,value); return 0; } @@ -2254,8 +2256,8 @@ ret_val = error; break; } - put_fs_long(C_CLOCAL(tty) ? 1 : 0, - (unsigned long *) arg); + put_user(C_CLOCAL(tty) ? 1 : 0, + (unsigned int *) arg); break; case TIOCSSOFTCAR: error = verify_area(VERIFY_READ, (void *) arg @@ -2265,7 +2267,7 @@ break; } - arg = get_fs_long((unsigned long *) arg); + get_user(arg,(unsigned int *) arg); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); diff -u --recursive --new-file v2.1.10/linux/drivers/char/istallion.c linux/drivers/char/istallion.c --- v2.1.10/linux/drivers/char/istallion.c Wed Oct 16 10:48:12 1996 +++ linux/drivers/char/istallion.c Mon Nov 18 11:53:10 1996 @@ -44,7 +44,9 @@ #include #include #include +#include #include +#include /*****************************************************************************/ @@ -157,7 +159,7 @@ * all the local structures required by a serial tty driver. */ static char *stli_drvname = "Stallion Intelligent Multiport Serial Driver"; -static char *stli_drvversion = "1.1.3"; +static char *stli_drvversion = "1.1.4"; static char *stli_serialname = "ttyE"; static char *stli_calloutname = "cue"; @@ -1790,11 +1792,11 @@ break; case TIOCGSOFTCAR: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long))) == 0) - put_fs_long(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), (unsigned long *) arg); + put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), (unsigned long *) arg); break; case TIOCSSOFTCAR: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) { - arg = get_fs_long((unsigned long *) arg); + get_user(arg, (unsigned long *) arg); tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0); } break; @@ -1803,26 +1805,26 @@ if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS, &portp->asig, sizeof(asysigs_t), 1)) < 0) return(rc); val = stli_mktiocm(portp->asig.sigvalue); - put_fs_long(val, (unsigned long *) arg); + put_user(val, (unsigned int *) arg); } break; case TIOCMBIS: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) { - arg = get_fs_long((unsigned long *) arg); + get_user(arg, (unsigned long *) arg); stli_mkasysigs(&portp->asig, ((arg & TIOCM_DTR) ? 1 : -1), ((arg & TIOCM_RTS) ? 1 : -1)); rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0); } break; case TIOCMBIC: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) { - arg = get_fs_long((unsigned long *) arg); + get_user(arg, (unsigned long *) arg); stli_mkasysigs(&portp->asig, ((arg & TIOCM_DTR) ? 0 : -1), ((arg & TIOCM_RTS) ? 0 : -1)); rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0); } break; case TIOCMSET: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) { - arg = get_fs_long((unsigned long *) arg); + get_user(arg, (unsigned long *) arg); stli_mkasysigs(&portp->asig, ((arg & TIOCM_DTR) ? 1 : 0), ((arg & TIOCM_RTS) ? 1 : 0)); rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0); } @@ -1837,11 +1839,11 @@ break; case STL_GETPFLAG: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long))) == 0) - put_fs_long(portp->pflag, (unsigned long *) arg); + put_user(portp->pflag, (unsigned int *) arg); break; case STL_SETPFLAG: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned long))) == 0) { - portp->pflag = get_fs_long((unsigned long *) arg); + get_user(portp->pflag, (unsigned int *) arg); stli_setport(portp); } break; diff -u --recursive --new-file v2.1.10/linux/drivers/char/riscom8.c linux/drivers/char/riscom8.c --- v2.1.10/linux/drivers/char/riscom8.c Wed Oct 16 10:48:13 1996 +++ linux/drivers/char/riscom8.c Mon Nov 18 11:31:30 1996 @@ -41,6 +41,8 @@ #include #include +#include + #include "riscom8.h" #include "riscom8_reg.h" @@ -1369,7 +1371,7 @@ error = verify_area(VERIFY_READ, value, sizeof(int)); if (error) return error; - arg = get_fs_long((unsigned long *) value); + get_user(arg,(unsigned int *) value); switch (cmd) { case TIOCMBIS: if (arg & TIOCM_RTS) @@ -1528,7 +1530,7 @@ (unsigned long *) arg); return 0; case TIOCSSOFTCAR: - arg = get_user((unsigned long *) arg); + get_user(arg,(unsigned int *) arg); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); diff -u --recursive --new-file v2.1.10/linux/drivers/char/stallion.c linux/drivers/char/stallion.c --- v2.1.10/linux/drivers/char/stallion.c Tue Oct 29 19:58:07 1996 +++ linux/drivers/char/stallion.c Mon Nov 18 11:53:10 1996 @@ -140,7 +140,7 @@ * all the local structures required by a serial tty driver. */ static char *stl_drvname = "Stallion Multiport Serial Driver"; -static char *stl_drvversion = "1.1.3"; +static char *stl_drvversion = "1.1.4"; static char *stl_serialname = "ttyE"; static char *stl_calloutname = "cue"; @@ -1153,35 +1153,35 @@ break; case TIOCGSOFTCAR: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long))) == 0) - put_fs_long(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), (unsigned long *) arg); + put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), (unsigned long *) arg); break; case TIOCSSOFTCAR: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) { - arg = get_fs_long((unsigned long *) arg); + get_user(arg, (unsigned long *) arg); tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0); } break; case TIOCMGET: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int))) == 0) { val = (unsigned long) stl_getsignals(portp); - put_fs_long(val, (unsigned long *) arg); + put_user(val, (unsigned long *) arg); } break; case TIOCMBIS: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) { - arg = get_fs_long((unsigned long *) arg); + get_user(arg, (unsigned long *) arg); stl_setsignals(portp, ((arg & TIOCM_DTR) ? 1 : -1), ((arg & TIOCM_RTS) ? 1 : -1)); } break; case TIOCMBIC: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) { - arg = get_fs_long((unsigned long *) arg); + get_user(arg, (unsigned long *) arg); stl_setsignals(portp, ((arg & TIOCM_DTR) ? 0 : -1), ((arg & TIOCM_RTS) ? 0 : -1)); } break; case TIOCMSET: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) { - arg = get_fs_long((unsigned long *) arg); + get_user(arg, (unsigned long *) arg); stl_setsignals(portp, ((arg & TIOCM_DTR) ? 1 : 0), ((arg & TIOCM_RTS) ? 1 : 0)); } break; diff -u --recursive --new-file v2.1.10/linux/drivers/char/wdt.c linux/drivers/char/wdt.c --- v2.1.10/linux/drivers/char/wdt.c Tue Oct 29 19:58:10 1996 +++ linux/drivers/char/wdt.c Mon Nov 18 11:31:30 1996 @@ -105,13 +105,13 @@ } -static int wdt_lseek(struct inode *inode, struct file *file, off_t offset, +static long long wdt_llseek(struct inode *inode, struct file *file, long long offset, int origin) { return -ESPIPE; } -static int wdt_write(struct inode *inode, struct file *file, const char *buf, int count) +static long wdt_write(struct inode *inode, struct file *file, const char *buf, unsigned long count) { /* Write a watchdog value */ inb_p(WDT_DC); @@ -125,7 +125,7 @@ * Read reports the temperature in farenheit */ -static int wdt_read(struct inode *inode, struct file *file, char *buf, int count) +static long wdt_read(struct inode *inode, struct file *file, char *buf, unsigned long count) { unsigned short c=inb_p(WDT_RT); unsigned char cp; @@ -202,7 +202,7 @@ static struct file_operations wdt_fops = { - wdt_lseek, + wdt_llseek, wdt_read, wdt_write, NULL, /* No Readdir */ diff -u --recursive --new-file v2.1.10/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c --- v2.1.10/linux/drivers/isdn/icn/icn.c Sat Aug 31 19:01:48 1996 +++ linux/drivers/isdn/icn/icn.c Mon Nov 18 11:31:31 1996 @@ -842,7 +842,8 @@ icn_lock_channel(card,0); /* Lock Bank 0 */ restore_flags(flags); SLEEP(1); - memcpy_fromfs(codebuf, buffer, ICN_CODE_STAGE1); + if (copy_from_user(codebuf, buffer, ICN_CODE_STAGE1)) + return -EFAULT; memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */ #ifdef BOOT_DEBUG printk(KERN_DEBUG "Bootloader transfered\n"); @@ -913,7 +914,8 @@ while (left) { if (sbfree) { /* If there is a free buffer... */ cnt = MIN(256, left); - memcpy_fromfs(codebuf, p, cnt); + if (copy_from_user(codebuf, p, cnt)) + /* FIXME -WRONG */return -EFAULT; memcpy_toio(&sbuf_l, codebuf, cnt); /* copy data */ sbnext; /* switch to next buffer */ p += cnt; @@ -995,7 +997,7 @@ if (card->msg_buf_read == card->msg_buf_write) return count; if (user) - put_fs_byte(*card->msg_buf_read++, p); + put_user(*card->msg_buf_read++, p); else *p = *card->msg_buf_read++; if (card->msg_buf_read > card->msg_buf_end) @@ -1023,7 +1025,13 @@ avail = cmd_free; count = MIN(avail, len); if (user) - memcpy_fromfs(msg, buf, count); + { + if (copy_from_user(msg, buf, count) != 0) + { + icn_release_channel(); + return -EFAULT; + } + } else memcpy(msg, buf, count); save_flags(flags); @@ -1175,13 +1183,15 @@ (void *) a, sizeof(ulong) * 2))) return i; - memcpy_tofs((char *)a, - (char *)&card, sizeof(ulong)); + if (copy_to_user((char *)a, + (char *)&card, sizeof(ulong))) + return -EFAULT; a += sizeof(ulong); { ulong l = (ulong)&dev; - memcpy_tofs((char *)a, - (char *)&l, sizeof(ulong)); + if (copy_to_user((char *)a, + (char *)&l, sizeof(ulong))) + return -EFAULT; } return 0; case ICN_IOCTL_LOADBOOT: @@ -1198,7 +1208,8 @@ case ICN_IOCTL_ADDCARD: if ((i = verify_area(VERIFY_READ, (void *) a, sizeof(icn_cdef)))) return i; - memcpy_fromfs((char *)&cdef, (char *)a, sizeof(cdef)); + if (copy_from_user((char *)&cdef, (char *)a, sizeof(cdef))) + return -EFAULT; return (icn_addcard(cdef.port, cdef.id1, cdef.id2)); break; case ICN_IOCTL_LEASEDCFG: diff -u --recursive --new-file v2.1.10/linux/drivers/isdn/icn/icn.h linux/drivers/isdn/icn/icn.h --- v2.1.10/linux/drivers/isdn/icn/icn.h Sat Aug 31 19:01:48 1996 +++ linux/drivers/isdn/icn/icn.h Mon Nov 18 11:31:31 1996 @@ -118,6 +118,7 @@ #if defined(__KERNEL__) || defined(__DEBUGVAR__) #ifdef __KERNEL__ + /* Kernel includes */ #include @@ -127,6 +128,7 @@ #include #include #include +#include #include #include #include @@ -136,6 +138,7 @@ #include #include #include + #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.1.10/linux/drivers/isdn/pcbit/drv.c linux/drivers/isdn/pcbit/drv.c --- v2.1.10/linux/drivers/isdn/pcbit/drv.c Sat Jun 29 20:36:22 1996 +++ linux/drivers/isdn/pcbit/drv.c Mon Nov 18 11:31:31 1996 @@ -37,6 +37,7 @@ #include #include #include +#include #include "pcbit.h" #include "edss1.h" @@ -428,7 +429,8 @@ { u_char cbuf[1024]; - memcpy_fromfs(cbuf, buf, len); + if (copy_from_user(cbuf, buf, len)) + return -EFAULT; for (i=0; ish_mem + i); } @@ -446,7 +448,11 @@ /* get it into kernel space */ if ((ptr = kmalloc(len, GFP_KERNEL))==NULL) return -ENOMEM; - memcpy_fromfs(ptr, buf, len); + if (copy_from_user(ptr, buf, len)) + { + kfree(ptr); + return -EFAULT; + } loadbuf = ptr; } else @@ -761,8 +767,13 @@ static int stat_end = 0; -#define memcpy_to_COND(flag, d, s, len) \ -(flag ? memcpy_tofs(d, s, len) : memcpy(d, s, len)) +extern inline int memcpy_to_COND(int flag, void *d, void *s, int len) +{ + if (flag) + return copy_to_user(d, s, len); + memcpy(d, s, len); + return 0; +} int pcbit_stat(u_char* buf, int len, int user, int driver, int channel) @@ -779,24 +790,27 @@ if (stat_st < stat_end) { - memcpy_to_COND(user, buf, statbuf + stat_st, len); + if (memcpy_to_COND(user, buf, statbuf + stat_st, len)) + return -EFAULT; stat_st += len; } else { if (len > STATBUF_LEN - stat_st) { - memcpy_to_COND(user, buf, statbuf + stat_st, - STATBUF_LEN - stat_st); - memcpy_to_COND(user, buf, statbuf, - len - (STATBUF_LEN - stat_st)); - + if (memcpy_to_COND(user, buf, statbuf + stat_st, + STATBUF_LEN - stat_st)) + return -EFAULT; + if (memcpy_to_COND(user, buf, statbuf, + len - (STATBUF_LEN - stat_st))) + return -EFAULT; stat_st = len - (STATBUF_LEN - stat_st); } else { - memcpy_to_COND(user, buf, statbuf + stat_st, - len); + if (memcpy_to_COND(user, buf, statbuf + stat_st, + len)) + return -EFAULT; stat_st += len; diff -u --recursive --new-file v2.1.10/linux/drivers/net/3c505.c linux/drivers/net/3c505.c --- v2.1.10/linux/drivers/net/3c505.c Wed Oct 16 10:48:17 1996 +++ linux/drivers/net/3c505.c Mon Nov 18 11:31:31 1996 @@ -1657,13 +1657,14 @@ #ifdef MODULE #define NAMELEN 9 -static char devicename[ELP_MAX_CARDS][NAMELEN] = {0,}; +static char devicename[ELP_MAX_CARDS][NAMELEN] = {{0,}}; static struct device dev_3c505[ELP_MAX_CARDS] = { - NULL, /* device name is inserted by net_init.c */ + { NULL, /* device name is inserted by net_init.c */ 0, 0, 0, 0, 0, 0, - 0, 0, 0, NULL, elplus_probe}; + 0, 0, 0, NULL, elplus_probe}, +}; static int io[ELP_MAX_CARDS] = { 0, }; static int irq[ELP_MAX_CARDS] = { 0, }; diff -u --recursive --new-file v2.1.10/linux/drivers/net/8390.c linux/drivers/net/8390.c --- v2.1.10/linux/drivers/net/8390.c Tue Oct 29 19:58:11 1996 +++ linux/drivers/net/8390.c Mon Nov 18 11:31:31 1996 @@ -30,6 +30,7 @@ Paul Gortmaker : exchange static int ei_pingpong for a #define, also add better Tx error handling. Paul Gortmaker : rewrite Rx overrun handling as per NS specs. + Alexey Kuznetsov : use the software multicast filter. Sources: @@ -679,8 +680,45 @@ /* * Set or clear the multicast filter for this adaptor. + * (Don't assume 8bit char..) */ +extern inline __u32 upd_8390_crc(__u8 b, __u32 x) +{ + int i; + __u8 ah=0; + for(i=0;i<8;i++) + { + __u8 carry = (x>>31); + x<<=1; + ah = ((ah<<1)|carry)^b; + + if(ah&1) + x^=0x04C11DB7; + ah>>=1; + b>>=1; + } + return x; +} + +extern __inline void make_8390_mc_bits(__u8 *bits, struct device *dev) +{ + struct dev_mc_list *dmi; + memset(bits,0,8); + + for(dmi=dev->mc_list;dmi!=NULL;dmi=dmi->next) + { + int i; + __u32 x; + if(dmi->dmi_addrlen!=6) + continue; /* !! */ + x=0xFFFFFFFFUL; + for(i=0;i<6;i++) + x = upd_8390_crc(dmi->dmi_addr[i],x); + bits[x>>29] |= (1<<((x>>26)&7)); + } +} + static void set_multicast_list(struct device *dev) { short ioaddr = dev->base_addr; @@ -691,9 +729,22 @@ } else if((dev->flags&IFF_ALLMULTI)||dev->mc_list) { - /* The multicast-accept list is initialized to accept-all, and we - rely on higher-level filtering for now. */ + unsigned long flags; + __u8 mc_bits[8]; + int i; + + if(dev->flags&IFF_ALLMULTI) + memset(mc_bits,0xFF,8); + else + make_8390_mc_bits(mc_bits,dev); + save_flags(flags); + cli(); + outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, ioaddr); + for(i = 0; i < 8; i++) + outb_p(mc_bits[i], ioaddr + EN1_MULT + i); + outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, ioaddr); outb_p(E8390_RXCONFIG | 0x08, ioaddr + EN0_RXCR); + restore_flags(flags); } else outb_p(E8390_RXCONFIG, ioaddr + EN0_RXCR); diff -u --recursive --new-file v2.1.10/linux/drivers/net/CONFIG linux/drivers/net/CONFIG --- v2.1.10/linux/drivers/net/CONFIG Thu May 16 20:12:56 1996 +++ linux/drivers/net/CONFIG Mon Nov 18 11:31:31 1996 @@ -62,6 +62,10 @@ # DE4X5_DO_MEMCPY Forces the Intels to use memory copies into sk_buffs # rather than straight DMA. # +# DEFXX The DIGITAL series of FDDI EISA (DEFEA) and PCI (DEFPA) +# controllers +# DEFXX_DEBUG Set the desired debug level +# # TULIP Tulip (dc21040/dc21041/ds21140) driver # TULIP_PORT specify default if_port # 0: 10TP @@ -92,5 +96,6 @@ DEPCA_OPTS = EWRK3_OPTS = DE4X5_OPTS = -DDE4X5_AUTOSENSE=AUTO +DEFXX_OPTS = ELP_OPTS = TULIP_OPTS = diff -u --recursive --new-file v2.1.10/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.1.10/linux/drivers/net/Config.in Tue Nov 12 15:56:06 1996 +++ linux/drivers/net/Config.in Mon Nov 18 11:50:17 1996 @@ -1,44 +1,15 @@ # # Network device configuration # + +tristate 'ARCnet support' CONFIG_ARCNET +if [ "$CONFIG_ARCNET" != "n" ]; then + bool ' Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH + bool ' Enable arc0s (ARCnet RFC1051 packet format)' CONFIG_ARCNET_1051 +fi tristate 'Dummy net driver support' CONFIG_DUMMY tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Frame relay DLCI support (EXPERIMENTAL)' CONFIG_DLCI - if [ "$CONFIG_DLCI" = "y" -o "$CONFIG_DLCI" = "m" ]; then - int ' Max open DLCI' CONFIG_DLCI_COUNT 24 - int ' Max DLCI per device' CONFIG_DLCI_MAX 8 - dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI - fi -fi -tristate 'PLIP (parallel port) support' CONFIG_PLIP -tristate 'PPP (point-to-point) support' CONFIG_PPP -if [ ! "$CONFIG_PPP" = "n" ]; then - comment 'CCP compressors for PPP are only built as modules.' -fi -tristate 'SLIP (serial line) support' CONFIG_SLIP -if [ "$CONFIG_SLIP" != "n" ]; then - bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED - bool ' Keepalive and linefill' CONFIG_SLIP_SMART - bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6 -fi -bool 'Radio network interfaces' CONFIG_NET_RADIO -if [ "$CONFIG_NET_RADIO" != "n" ]; then - if [ "$CONFIG_AX25" != "n" ]; then - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'BAYCOM ser12 and par96 driver for AX.25' CONFIG_BAYCOM - tristate 'Soundcard modem driver for AX.25' CONFIG_SOUNDMODEM - fi - dep_tristate 'Serial port KISS driver for AX.25' CONFIG_MKISS $CONFIG_AX25 - dep_tristate 'BPQ Ethernet driver for AX.25' CONFIG_BPQETHER $CONFIG_AX25 - dep_tristate 'Gracilis PackeTwin support' CONFIG_PT $CONFIG_AX25 - dep_tristate 'Ottawa PI and PI/2 support' CONFIG_PI $CONFIG_AX25 - fi - tristate 'Z8530 SCC KISS emulation driver for AX.25' CONFIG_SCC - tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP - tristate 'WaveLAN support' CONFIG_WAVELAN - tristate 'WIC Radio IP bridge (EXPERIMENTAL)' CONFIG_WIC -fi + # # Ethernet # @@ -113,13 +84,54 @@ fi fi +bool 'FDDI driver support' CONFIG_FDDI +if [ "$CONFIG_FDDI" = "y" ]; then + bool 'Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX +fi + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Frame relay DLCI support (EXPERIMENTAL)' CONFIG_DLCI + if [ "$CONFIG_DLCI" = "y" -o "$CONFIG_DLCI" = "m" ]; then + int ' Max open DLCI' CONFIG_DLCI_COUNT 24 + int ' Max DLCI per device' CONFIG_DLCI_MAX 8 + dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI + fi +fi + +tristate 'PLIP (parallel port) support' CONFIG_PLIP + +tristate 'PPP (point-to-point) support' CONFIG_PPP +if [ ! "$CONFIG_PPP" = "n" ]; then + comment 'CCP compressors for PPP are only built as modules.' +fi + +bool 'Radio network interfaces' CONFIG_NET_RADIO +if [ "$CONFIG_NET_RADIO" != "n" ]; then + if [ "$CONFIG_AX25" != "n" ]; then + tristate 'Serial port KISS driver for AX.25' CONFIG_MKISS + tristate 'BPQ Ethernet driver for AX.25' CONFIG_BPQETHER + tristate 'Gracilis PackeTwin driver for AX.25' CONFIG_PT + tristate 'Ottawa PI and PI2 driver for AX.25' CONFIG_PI + tristate 'Z8530 SCC driver for AX.25' CONFIG_SCC + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'BAYCOM ser12 and par96 driver for AX.25' CONFIG_BAYCOM + tristate 'Soundcard modem driver for AX.25' CONFIG_SOUNDMODEM + fi + tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP + tristate 'WaveLAN support' CONFIG_WAVELAN + tristate 'WIC Radio IP bridge (EXPERIMENTAL)' CONFIG_WIC +fi + +tristate 'SLIP (serial line) support' CONFIG_SLIP +if [ "$CONFIG_SLIP" != "n" ]; then + bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED + bool ' Keepalive and linefill' CONFIG_SLIP_SMART + bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6 +fi + bool 'Token Ring driver support' CONFIG_TR if [ "$CONFIG_TR" = "y" ]; then tristate 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR -fi -tristate 'ARCnet support' CONFIG_ARCNET -if [ "$CONFIG_ARCNET" != "n" ]; then - bool ' Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH - bool ' Enable arc0s (ARCnet RFC1051 packet format)' CONFIG_ARCNET_1051 fi diff -u --recursive --new-file v2.1.10/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.1.10/linux/drivers/net/Makefile Tue Nov 12 15:56:06 1996 +++ linux/drivers/net/Makefile Mon Nov 18 11:31:31 1996 @@ -233,8 +233,20 @@ endif endif +ifeq ($(CONFIG_DE620),y) +L_OBJS += de620.o +else + ifeq ($(CONFIG_DE620),m) + M_OBJS += de620.o + endif +endif + ifeq ($(CONFIG_AT1500),y) L_OBJS += lance.o +endif + +ifeq ($(CONFIG_DEFXX),y) +L_OBJS += defxx.o endif ifeq ($(CONFIG_LANCE),y) diff -u --recursive --new-file v2.1.10/linux/drivers/net/README.multicast linux/drivers/net/README.multicast --- v2.1.10/linux/drivers/net/README.multicast Fri Nov 24 16:39:53 1995 +++ linux/drivers/net/README.multicast Mon Nov 18 11:31:31 1996 @@ -15,11 +15,12 @@ Board Multicast AllMulti Promisc Filter ------------------------------------------------------------------------ 3c501 YES YES YES Software -3c503 YES YES YES Software(#) +3c503 YES YES YES Hardware 3c505 YES NO YES Hardware 3c507 NO NO NO N/A 3c509 YES YES YES Software -ac3200 YES YES YES Software(#) +3c59x YES YES YES Software +ac3200 YES YES YES Hardware apricot YES PROMISC YES Hardware arcnet NO NO NO N/A at1700 PROMISC PROMISC YES Software @@ -28,29 +29,28 @@ de600 NO NO NO N/A de620 PROMISC PROMISC YES Software depca YES PROMISC YES Hardware -e2100 YES YES YES Software(#) +e2100 YES YES YES Hardware eepro YES PROMISC YES Hardware eexpress NO NO NO N/A ewrk3 YES PROMISC YES Hardware -hp-plus YES YES YES Software(#) -hp YES YES YES Software(#) -hp100 YES YES YES Software(#) +hp-plus YES YES YES Hardware +hp YES YES YES Hardware +hp100 YES YES YES Hardware ibmtr NO NO NO N/A lance YES YES YES Software(#) -ne YES YES YES Software(#) -ni52 -ni65 NO NO NO N/A +ne YES YES YES Hardware +ni52 <------------------ Buggy ------------------> +ni65 YES YES YES Software(#) seeq NO NO NO N/A sk_g16 NO NO YES N/A -smc-ultra YES YES YES Software(#) +smc-ultra YES YES YES Hardware +sunlance YES YES YES Software(#) tulip YES YES YES Hardware wavelan --------Buggy-------- YES N/A -wd YES YES YES Software(#) +wd YES YES YES Hardware znet YES YES YES Software PROMISC = This multicasts mode is in fact promiscuous mode. Avoid using cards who go PROMISC on any multicast in a multicast kernel. (#) = Hardware multicast support is not used yet. - - diff -u --recursive --new-file v2.1.10/linux/drivers/net/defxx.c linux/drivers/net/defxx.c --- v2.1.10/linux/drivers/net/defxx.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/defxx.c Mon Nov 18 11:31:31 1996 @@ -0,0 +1,3421 @@ +/* + * File Name: + * defxx.c + * + * Copyright Information: + * Copyright Digital Equipment Corporation 1996. + * + * This software may be used and distributed according to the terms of + * the GNU Public License, incorporated herein by reference. + * + * Abstract: + * A Linux device driver supporting the Digital Equipment Corporation + * FDDI EISA and PCI controller families. Supported adapters include: + * + * DEC FDDIcontroller/EISA (DEFEA) + * DEC FDDIcontroller/PCI (DEFPA) + * + * Maintainers: + * LVS Lawrence V. Stefani + * + * Contact: + * The author may be reached at: + * + * Inet: stefani@lkg.dec.com + * Mail: Digital Equipment Corporation + * 550 King Street + * M/S: LKG1-3/M07 + * Littleton, MA 01460 + * + * Credits: + * I'd like to thank Patricia Cross for helping me get started with + * Linux, David Davies for a lot of help upgrading and configuring + * my development system and for answering many OS and driver + * development questions, and Alan Cox for recommendations and + * integration help on getting FDDI support into Linux. LVS + * + * Driver Architecture: + * The driver architecture is largely based on previous driver work + * for other operating systems. The upper edge interface and + * functions were largely taken from existing Linux device drivers + * such as David Davies' DE4X5.C driver and Donald Becker's TULIP.C + * driver. + * + * Adapter Probe - + * The driver scans for supported EISA adapters by reading the + * SLOT ID register for each EISA slot and making a match + * against the expected value. The supported PCI adapters are + * discovered using successive calls to pcibios_find_device. + * The first time the probe routine is called, all supported + * devices are discovered and initialized. The adapters aren't + * brought up to an operational state until the open routine is + * called. + * + * Bus-Specific Initialization - + * This driver currently supports both EISA and PCI controller + * families. While the custom DMA chip and FDDI logic is similar + * or identical, the bus logic is very different. After + * initialization, the only bus-specific differences is in how the + * driver enables and disables interrupts. Other than that, the + * run-time critical code behaves the same on both families. + * It's important to note that both adapter families are configured + * to I/O map, rather than memory map, the adapter registers. + * + * Driver Open/Close - + * In the driver open routine, the driver ISR (interrupt service + * routine) is registered and the adapter is brought to an + * operational state. In the driver close routine, the opposite + * occurs; the driver ISR is deregistered and the adapter is + * brought to a safe, but closed state. Users may use consecutive + * commands to bring the adapter up and down as in the following + * example: + * ifconfig fddi0 up + * ifconfig fddi0 down + * ifconfig fddi0 up + * + * Driver Shutdown - + * Apparently, there is no shutdown or halt routine support under + * Linux. This routine would be called during "reboot" or + * "shutdown" to allow the driver to place the adapter in a safe + * state before a warm reboot occurs. To be really safe, the user + * should close the adapter before shutdown (eg. ifconfig fddi0 down) + * to ensure that the adapter DMA engine is taken off-line. However, + * the current driver code anticipates this problem and always issues + * a soft reset of the adapter at the beginning of driver initialization. + * A future driver enhancement in this area may occur in 2.1.X where + * Alan indicated that a shutdown handler may be implemented. + * + * Interrupt Service Routine - + * The driver supports shared interrupts, so the ISR is registered for + * each board with the appropriate flag and the pointer to that board's + * device structure. This provides the context during interrupt + * processing to support shared interrupts and multiple boards. + * + * Interrupt enabling/disabling can occur at many levels. At the host + * end, you can disable system interrupts, or disable interrupts at the + * PIC (on Intel systems). Across the bus, both EISA and PCI adapters + * have a bus-logic chip interrupt enable/disable as well as a DMA + * controller interrupt enable/disable. + * + * The driver currently enables and disables adapter interrupts at the + * bus-logic chip and assumes that Linux will take care of clearing or + * acknowledging any host-based interrupt chips. + * + * Control Functions - + * Control functions are those used to support functions such as adding + * or deleting multicast addresses, enabling or disabling packet + * reception filters, or other custom/proprietary commands. Presently, + * the driver supports the "get statistics", "set multicast list", and + * "set mac address" functions defined by Linux. A list of possible + * enhancements include: + * + * - Custom ioctl interface for executing port interface commands + * - Custom ioctl interface for adding unicast addresses to + * adapter CAM (to support bridge functions). + * - Custom ioctl interface for supporting firmware upgrades. + * + * Hardware (port interface) Support Routines - + * The driver function names that start with "dfx_hw_" represent + * low-level port interface routines that are called frequently. They + * include issuing a DMA or port control command to the adapter, + * resetting the adapter, or reading the adapter state. Since the + * driver initialization and run-time code must make calls into the + * port interface, these routines were written to be as generic and + * usable as possible. + * + * Receive Path - + * The adapter DMA engine supports a 256 entry receive descriptor block + * of which up to 255 entries can be used at any given time. The + * architecture is a standard producer, consumer, completion model in + * which the driver "produces" receive buffers to the adapter, the + * adapter "consumes" the receive buffers by DMAing incoming packet data, + * and the driver "completes" the receive buffers by servicing the + * incoming packet, then "produces" a new buffer and starts the cycle + * again. Receive buffers can be fragmented in up to 16 fragments + * (descriptor entries). For simplicity, this driver posts + * single-fragment receive buffers of 4608 bytes, then allocates a + * sk_buff, copies the data, then reposts the buffer. To reduce CPU + * utilization, a better approach would be to pass up the receive + * buffer (no extra copy) then allocate and post a replacement buffer. + * This is a performance enhancement that should be looked into at + * some point. + * + * Transmit Path - + * Like the receive path, the adapter DMA engine supports a 256 entry + * transmit descriptor block of which up to 255 entries can be used at + * any given time. Transmit buffers can be fragmented in up to 255 + * fragments (descriptor entries). This driver always posts one + * fragment per transmit packet request. + * + * The fragment contains the entire packet from FC to end of data. + * Before posting the buffer to the adapter, the driver sets a three-byte + * packet request header (PRH) which is required by the Motorola MAC chip + * used on the adapters. The PRH tells the MAC the type of token to + * receive/send, whether or not to generate and append the CRC, whether + * synchronous or asynchronous framing is used, etc. Since the PRH + * definition is not necessarily consistent across all FDDI chipsets, + * the driver, rather than the common FDDI packet handler routines, + * sets these bytes. + * + * To reduce the amount of descriptor fetches needed per transmit request, + * the driver takes advantage of the fact that there are at least three + * bytes available before the skb->data field on the outgoing transmit + * request. This is guaranteed by having fddi_setup() in net_init.c set + * dev->hard_header_len to 24 bytes. 21 bytes accounts for the largest + * header in an 802.2 SNAP frame. The other 3 bytes are the extra "pad" + * bytes which we'll use to store the PRH. + * + * There's a subtle advantage to adding these pad bytes to the + * hard_header_len, it ensures that the data portion of the packet for + * an 802.2 SNAP frame is longword aligned. Other FDDI driver + * implementations may not need the extra padding and can start copying + * or DMAing directly from the FC byte which starts at skb->data. Should + * another driver implementation need ADDITIONAL padding, the net_init.c + * module should be updated and dev->hard_header_len should be increased. + * NOTE: To maintain the alignment on the data portion of the packet, + * dev->hard_header_len should always be evenly divisible by 4 and at + * least 24 bytes in size. + * + * Modification History: + * Date Name Description + * 16-Aug-96 LVS Created. + * 20-Aug-96 LVS Updated dfx_probe so that version information + * string is only displayed if 1 or more cards are + * found. Changed dfx_rcv_queue_process to copy + * 3 NULL bytes before FC to ensure that data is + * longword aligned in receive buffer. + * 09-Sep-96 LVS Updated dfx_ctl_set_multicast_list to enable + * LLC group promiscuous mode if multicast list + * is too large. LLC individual/group promiscuous + * mode is now disabled if IFF_PROMISC flag not set. + * dfx_xmt_queue_pkt no longer checks for NULL skb + * on Alan Cox recommendation. Added node address + * override support. + * 12-Sep-96 LVS Reset current address to factory address during + * device open. Updated transmit path to post a + * single fragment which includes PRH->end of data. + */ + +/* Version information string - should be updated prior to each new release!!! */ + +static const char *version = "defxx.c:v1.04 09/16/96 Lawrence V. Stefani (stefani@lkg.dec.com)\n"; + +/* Include files */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "defxx.h" + +/* Define global routines */ + +int dfx_probe(struct device *dev); + +/* Define module-wide (static) routines */ + +static struct device *dfx_alloc_device(struct device *dev, u16 iobase); + +static void dfx_bus_init(struct device *dev); +static void dfx_bus_config_check(DFX_board_t *bp); + +static int dfx_driver_init(struct device *dev); +static int dfx_adap_init(DFX_board_t *bp); + +static int dfx_open(struct device *dev); +static int dfx_close(struct device *dev); + +static void dfx_int_pr_halt_id(DFX_board_t *bp); +static void dfx_int_type_0_process(DFX_board_t *bp); +static void dfx_int_common(DFX_board_t *bp); +static void dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +static struct enet_statistics *dfx_ctl_get_stats(struct device *dev); +static void dfx_ctl_set_multicast_list(struct device *dev); +static int dfx_ctl_set_mac_address(struct device *dev, void *addr); +static int dfx_ctl_update_cam(DFX_board_t *bp); +static int dfx_ctl_update_filters(DFX_board_t *bp); + +static int dfx_hw_dma_cmd_req(DFX_board_t *bp); +static int dfx_hw_port_ctrl_req(DFX_board_t *bp, PI_UINT32 command, PI_UINT32 data_a, PI_UINT32 data_b, PI_UINT32 *host_data); +static void dfx_hw_adap_reset(DFX_board_t *bp, PI_UINT32 type); +static int dfx_hw_adap_state_rd(DFX_board_t *bp); +static int dfx_hw_dma_uninit(DFX_board_t *bp, PI_UINT32 type); + +static void dfx_rcv_init(DFX_board_t *bp); +static void dfx_rcv_queue_process(DFX_board_t *bp); + +static int dfx_xmt_queue_pkt(struct sk_buff *skb, struct device *dev); +static void dfx_xmt_done(DFX_board_t *bp); +static void dfx_xmt_flush(DFX_board_t *bp); + +/* Define module-wide (static) variables */ + +static int num_boards = 0; /* total number of adapters configured */ +static int already_probed = 0; /* have we already entered dfx_probe? */ + + +/* + * ======================= + * = dfx_port_write_byte = + * = dfx_port_read_byte = + * = dfx_port_write_long = + * = dfx_port_read_long = + * ======================= + * + * Overview: + * Routines for reading and writing values from/to adapter + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * offset - register offset from base I/O address + * data - for dfx_port_write_byte and dfx_port_write_long, this + * is a value to write. + * for dfx_port_read_byte and dfx_port_read_byte, this + * is a pointer to store the read value. + * + * Functional Description: + * These routines perform the correct operation to read or write + * the adapter register. + * + * EISA port block base addresses are based on the slot number in which the + * controller is installed. For example, if the EISA controller is installed + * in slot 4, the port block base address is 0x4000. If the controller is + * installed in slot 2, the port block base address is 0x2000, and so on. + * This port block can be used to access PDQ, ESIC, and DEFEA on-board + * registers using the register offsets defined in DEFXX.H. + * + * PCI port block base addresses are assigned by the PCI BIOS or system + * firmware. There is one 128 byte port block which can be accessed. It + * allows for I/O mapping of both PDQ and PFI registers using the register + * offsets defined in DEFXX.H. + * + * Return Codes: + * None + * + * Assumptions: + * bp->base_addr is a valid base I/O address for this adapter. + * offset is a valid register offset for this adapter. + * + * Side Effects: + * Rather than produce macros for these functions, these routines + * are defined using "inline" to ensure that the compiler will + * generate inline code and not waste a procedure call and return. + * This provides all the benefits of macros, but with the + * advantage of strict data type checking. + */ + +static inline void dfx_port_write_byte( + DFX_board_t *bp, + int offset, + u8 data + ) + + { + u16 port = bp->base_addr + offset; + + outb(data, port); + return; + } + +static inline void dfx_port_read_byte( + DFX_board_t *bp, + int offset, + u8 *data + ) + + { + u16 port = bp->base_addr + offset; + + *data = inb(port); + return; + } + +static inline void dfx_port_write_long( + DFX_board_t *bp, + int offset, + u32 data + ) + + { + u16 port = bp->base_addr + offset; + + outl(data, port); + return; + } + +static inline void dfx_port_read_long( + DFX_board_t *bp, + int offset, + u32 *data + ) + + { + u16 port = bp->base_addr + offset; + + *data = inl(port); + return; + } + + +/* + * ============= + * = dfx_probe = + * ============= + * + * Overview: + * Probes for supported FDDI EISA and PCI controllers + * + * Returns: + * Condition code + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This routine is called by the OS for each FDDI device name (fddi0, + * fddi1,...,fddi6, fddi7) specified in drivers/net/Space.c. Since + * the DEFXX.C driver currently does not support being loaded as a + * module, dfx_probe() will initialize all devices the first time + * it is called. + * + * Let's say that dfx_probe() is getting called to initialize fddi0. + * Furthermore, let's say there are three supported controllers in the + * system. Before dfx_probe() leaves, devices fddi0, fddi1, and fddi2 + * will be initialized and a global flag will be set to indicate that + * dfx_probe() has already been called. + * + * However...the OS doesn't know that we've already initialized + * devices fddi1 and fddi2 so dfx_probe() gets called again and again + * until it reaches the end of the device list for FDDI (presently, + * fddi7). It's important that the driver "pretend" to probe for + * devices fddi1 and fddi2 and return success. Devices fddi3 + * through fddi7 will return failure since they weren't initialized. + * + * This algorithm seems to work for the time being. As other FDDI + * drivers are written for Linux, a more generic approach (perhaps + * similar to the Ethernet card approach) may need to be implemented. + * + * Return Codes: + * 0 - This device (fddi0, fddi1, etc) configured successfully + * -ENODEV - No devices present, or no Digital FDDI EISA or PCI device + * present for this device name + * + * Assumptions: + * For the time being, DEFXX.C is the only FDDI driver under Linux. + * As this assumption changes, this routine will likely be impacted. + * Also, it is assumed that no more than eight (8) FDDI controllers + * will be configured in the system (fddi0 through fddi7). This + * routine will not allocate new device structures. If more than + * eight FDDI controllers need to be configured, drivers/net/Space.c + * should be updated as well as the DFX_MAX_NUM_BOARDS constant in + * DEFXX.H. + * + * Side Effects: + * Device structures for FDDI adapters (fddi0, fddi1, etc) are + * initialized and the board resources are read and stored in + * the device structure. + */ + +int dfx_probe( + struct device *dev + ) + + { + int i; /* used in for loops */ + int version_disp; /* was version info string already displayed? */ + int port_len; /* length of port address range (in bytes) */ + u8 pci_bus; /* PCI bus number (0-255) */ + u8 pci_dev_fun; /* PCI device and function numbers (0-255) */ + u16 port; /* temporary I/O (port) address */ + u16 command; /* PCI Configuration space Command register val */ + u32 slot_id; /* EISA hardware (slot) ID read from adapter */ + DFX_board_t *bp; /* board pointer */ + + DBG_printk("In dfx_probe...\n"); + + /* + * Verify whether we're going through dfx_probe() again + * + * If so, see if we're going through for a subsequent fddi device that + * we've already initialized. If we are, return success (0). If not, + * return failure (-ENODEV). + */ + + version_disp = 0; /* default to version string not displayed */ + if (already_probed) + { + DBG_printk("Already entered dfx_probe\n"); + if (dev != NULL) + if ((strncmp(dev->name, "fddi", 4) == 0) && (dev->base_addr != 0)) + { + DBG_printk("In dfx_probe for fddi adapter (%s) we've already initialized it, so return success\n", dev->name); + return(0); + } + return(-ENODEV); + } + already_probed = 1; /* set global flag */ + + /* Scan for FDDI EISA controllers */ + + for (i=0; i < DFX_MAX_EISA_SLOTS; i++) /* only scan for up to 16 EISA slots */ + { + port = (i << 12) + PI_ESIC_K_SLOT_ID; /* port = I/O address for reading slot ID */ + slot_id = inl(port); /* read EISA HW (slot) ID */ + if ((slot_id & 0xF0FFFFFF) == DEFEA_PRODUCT_ID) + { + if (!version_disp) /* display version info if adapter is found */ + { + version_disp = 1; /* set display flag to TRUE so that */ + printk(version); /* we only display this string ONCE */ + } + + port = (i << 12); /* recalc base addr */ + + /* Verify port address range is not already being used */ + + port_len = PI_ESIC_K_CSR_IO_LEN; + if (check_region(port, port_len) == 0) + { + /* Allocate a new device structure for this adapter */ + + dev = dfx_alloc_device(dev, port); + if (dev != NULL) + { + /* Initialize board structure with bus-specific info */ + + bp = (DFX_board_t *) dev->priv; + bp->dev = dev; + bp->bus_type = DFX_BUS_TYPE_EISA; + if (dfx_driver_init(dev) == DFX_K_SUCCESS) + num_boards++; /* only increment global board count on success */ + else + dev->base_addr = 0; /* clear port address field in device structure on failure */ + } + } + else + printk("I/O range allocated to adapter (0x%X-0x%X) is already being used!\n", port, (port + port_len-1)); + } + } + + /* Scan for FDDI PCI controllers */ + + if (pcibios_present()) /* is PCI BIOS even present? */ + for (i=0; i < DFX_MAX_NUM_BOARDS; i++) /* scan for up to 8 PCI cards */ + if (pcibios_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI, i, &pci_bus, &pci_dev_fun) == 0) + { + if (!version_disp) /* display version info if adapter is found */ + { + version_disp = 1; /* set display flag to TRUE so that */ + printk(version); /* we only display this string ONCE */ + } + + /* Verify that I/O enable bit is set (PCI slot is enabled) */ + + pcibios_read_config_word(pci_bus, pci_dev_fun, PCI_COMMAND, &command); + if ((command & PCI_COMMAND_IO) == 0) + printk("I/O enable bit not set! Verify that slot is enabled\n"); + else + { + /* Turn off memory mapped space and enable mastering */ + + command |= PCI_COMMAND_MASTER; + command &= ~PCI_COMMAND_MEMORY; + pcibios_write_config_word(pci_bus, pci_dev_fun, PCI_COMMAND, command); + + /* Read I/O base address from PCI Configuration Space */ + + pcibios_read_config_word(pci_bus, pci_dev_fun, PCI_BASE_ADDRESS_1, &port); + port &= PCI_BASE_ADDRESS_IO_MASK; /* clear I/O bit (bit 0) */ + + /* Verify port address range is not already being used */ + + port_len = PFI_K_CSR_IO_LEN; + if (check_region(port, port_len) == 0) + { + /* Allocate a new device structure for this adapter */ + + dev = dfx_alloc_device(dev, port); + if (dev != NULL) + { + /* Initialize board structure with bus-specific info */ + + bp = (DFX_board_t *) dev->priv; + bp->dev = dev; + bp->bus_type = DFX_BUS_TYPE_PCI; + bp->pci_bus = pci_bus; + bp->pci_dev_fun = pci_dev_fun; + if (dfx_driver_init(dev) == DFX_K_SUCCESS) + num_boards++; /* only increment global board count on success */ + else + dev->base_addr = 0; /* clear port address field in device structure on failure */ + } + } + else + printk("I/O range allocated to adapter (0x%X-0x%X) is already being used!\n", port, (port + port_len-1)); + } + } + + /* + * If we're at this point we're going through dfx_probe() for the first + * time. Return success (0) if we've initialized 1 or more boards. + * Otherwise, return failure (-ENODEV). + */ + + if (num_boards > 0) + return(0); + else + return(-ENODEV); + } + + +/* + * ==================== + * = dfx_alloc_device = + * ==================== + * + * Overview: + * Allocate new device structure for adapter + * + * Returns: + * Pointer to device structure for this adapter or NULL if + * none are available or could not allocate memory for + * private board structure. + * + * Arguments: + * dev - pointer to device information for last device + * iobase - base I/O address of new adapter + * + * Functional Description: + * The algorithm for allocating a new device structure is + * fairly simple. Since we're presently the only FDDI driver + * under Linux, we'll find the first device structure with an + * "fddi*" device name that's free. If we run out of devices, + * we'll fail on error. This is simpler than trying to + * allocate the memory for a new device structure, determine + * the next free number (beyond 7) and link it into the chain + * of devices. A user can always modify drivers/net/Space.c + * to add new FDDI device structures if necessary. + * + * Beyond finding a free FDDI device structure, this routine + * initializes most of the fields, resource tags, and dispatch + * pointers in the device structure and calls the common + * fddi_setup() routine to perform the rest of the device + * structure initialization. + * + * Return Codes: + * None + * + * Assumptions: + * If additional FDDI drivers are integrated into Linux, + * we'll likely need to use a different approach to + * allocate a device structure. Perhaps one that is + * similar to what the Ethernet drivers use. + * + * Side Effects: + * None + */ + +struct device *dfx_alloc_device( + struct device *dev, + u16 iobase + ) + + { + struct device *tmp_dev; /* pointer to a device structure */ + + DBG_printk("In dfx_alloc_device...\n"); + + /* Find next free fddi entry */ + + for (tmp_dev = dev; tmp_dev != NULL; tmp_dev = tmp_dev->next) + if ((strncmp(tmp_dev->name, "fddi", 4) == 0) && (tmp_dev->base_addr == 0)) + break; + if (tmp_dev == NULL) + { + printk("Could not find free FDDI device structure for this adapter!\n"); + return(NULL); + } + DBG_printk("Device entry free, device name = %s\n", tmp_dev->name); + + /* Allocate space for private board structure */ + + tmp_dev->priv = (void *) kmalloc(sizeof(DFX_board_t), GFP_KERNEL); + if (tmp_dev->priv == NULL) + { + printk("Could not allocate memory for private board structure!\n"); + return(NULL); + } + memset(tmp_dev->priv, 0, sizeof(DFX_board_t)); /* clear structure */ + + /* Initialize new device structure */ + + tmp_dev->rmem_end = 0; /* shared memory isn't used */ + tmp_dev->rmem_start = 0; /* shared memory isn't used */ + tmp_dev->mem_end = 0; /* shared memory isn't used */ + tmp_dev->mem_start = 0; /* shared memory isn't used */ + tmp_dev->base_addr = iobase; /* save port (I/O) base address */ + tmp_dev->irq = 0; /* set in dfx_bus_init() */ + tmp_dev->if_port = 0; /* not applicable to FDDI adapters */ + tmp_dev->dma = 0; /* Bus Master DMA doesn't require channel */ + + tmp_dev->get_stats = &dfx_ctl_get_stats; + tmp_dev->open = &dfx_open; + tmp_dev->stop = &dfx_close; + tmp_dev->hard_start_xmit = &dfx_xmt_queue_pkt; + tmp_dev->hard_header = NULL; /* set in fddi_setup() */ + tmp_dev->rebuild_header = NULL; /* set in fddi_setup() */ + tmp_dev->set_multicast_list = &dfx_ctl_set_multicast_list; + tmp_dev->set_mac_address = &dfx_ctl_set_mac_address; + tmp_dev->do_ioctl = NULL; /* not supported for now &&& */ + tmp_dev->set_config = NULL; /* not supported for now &&& */ + tmp_dev->header_cache_bind = NULL; /* not supported */ + tmp_dev->header_cache_update = NULL; /* not supported */ + tmp_dev->change_mtu = NULL; /* set in fddi_setup() */ + + /* Initialize remaining device structure information */ + + fddi_setup(tmp_dev); + return(tmp_dev); + } + + +/* + * ================ + * = dfx_bus_init = + * ================ + * + * Overview: + * Initializes EISA and PCI controller bus-specific logic. + * + * Returns: + * None + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * Determine and save adapter IRQ in device table, + * then perform bus-specific logic initialization. + * + * Return Codes: + * None + * + * Assumptions: + * dev->base_addr has already been set with the proper + * base I/O address for this device. + * + * Side Effects: + * Interrupts are enabled at the adapter bus-specific logic. + * Note: Interrupts at the DMA engine (PDQ chip) are not + * enabled yet. + */ + +void dfx_bus_init( + struct device *dev + ) + + { + DFX_board_t *bp = (DFX_board_t *)dev->priv; + u8 val; /* used for I/O read/writes */ + + DBG_printk("In dfx_bus_init...\n"); + + /* + * Initialize base I/O address field in bp structure + * + * Note: bp->base_addr is the same as dev->base_addr. + * It's useful because often we'll need to read + * or write registers where we already have the + * bp pointer instead of the dev pointer. Having + * the base address in the bp structure will + * save a pointer dereference. + * + * IMPORTANT!! This field must be defined before + * any of the dfx_port_* inline functions are + * called. + */ + + bp->base_addr = dev->base_addr; + + /* Initialize adapter based on bus type */ + + if (bp->bus_type == DFX_BUS_TYPE_EISA) + { + /* Get the interrupt level from the ESIC chip */ + + dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val); + switch ((val & PI_CONFIG_STAT_0_M_IRQ) >> PI_CONFIG_STAT_0_V_IRQ) + { + case PI_CONFIG_STAT_0_IRQ_K_9: + dev->irq = 9; + break; + + case PI_CONFIG_STAT_0_IRQ_K_10: + dev->irq = 10; + break; + + case PI_CONFIG_STAT_0_IRQ_K_11: + dev->irq = 11; + break; + + case PI_CONFIG_STAT_0_IRQ_K_15: + dev->irq = 15; + break; + } + + /* Enable access to I/O on the board by writing 0x03 to Function Control Register */ + + dfx_port_write_byte(bp, PI_ESIC_K_FUNCTION_CNTRL, PI_ESIC_K_FUNCTION_CNTRL_IO_ENB); + + /* Set the I/O decode range of the board */ + + val = ((dev->base_addr >> 12) << PI_IO_CMP_V_SLOT); + dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_0_1, val); + dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_1_1, val); + + /* Enable access to rest of module (including PDQ and packet memory) */ + + dfx_port_write_byte(bp, PI_ESIC_K_SLOT_CNTRL, PI_SLOT_CNTRL_M_ENB); + + /* + * Map PDQ registers into I/O space. This is done by clearing a bit + * in Burst Holdoff register. + */ + + dfx_port_read_byte(bp, PI_ESIC_K_BURST_HOLDOFF, &val); + dfx_port_write_byte(bp, PI_ESIC_K_BURST_HOLDOFF, (val & ~PI_BURST_HOLDOFF_M_MEM_MAP)); + + /* Enable interrupts at EISA bus interface chip (ESIC) */ + + dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val); + dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, (val | PI_CONFIG_STAT_0_M_INT_ENB)); + } + else + { + /* Get the interrupt level from the PCI Configuration Table */ + + pcibios_read_config_byte(bp->pci_bus, bp->pci_dev_fun, PCI_INTERRUPT_LINE, &val); + dev->irq = val; /* save IRQ value in device table */ + + /* Check Latency Timer and set if less than minimal */ + + pcibios_read_config_byte(bp->pci_bus, bp->pci_dev_fun, PCI_LATENCY_TIMER, &val); + if (val < PFI_K_LAT_TIMER_MIN) /* if less than min, override with default */ + { + val = PFI_K_LAT_TIMER_DEF; + pcibios_write_config_byte(bp->pci_bus, bp->pci_dev_fun, PCI_LATENCY_TIMER, val); + } + + /* Enable interrupts at PCI bus interface chip (PFI) */ + + dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, (PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB)); + } + return; + } + + +/* + * ======================== + * = dfx_bus_config_check = + * ======================== + * + * Overview: + * Checks the configuration (burst size, full-duplex, etc.) If any parameters + * are illegal, then this routine will set new defaults. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * For Revision 1 FDDI EISA, Revision 2 or later FDDI EISA with rev E or later + * PDQ, and all FDDI PCI controllers, all values are legal. + * + * Return Codes: + * None + * + * Assumptions: + * dfx_adap_init has NOT been called yet so burst size and other items have + * not been set. + * + * Side Effects: + * None + */ + +void dfx_bus_config_check( + DFX_board_t *bp + ) + + { + int status; /* return code from adapter port control call */ + u32 slot_id; /* EISA-bus hardware id (DEC3001, DEC3002,...) */ + u32 host_data; /* LW data returned from port control call */ + + DBG_printk("In dfx_bus_config_check...\n"); + + /* Configuration check only valid for EISA adapter */ + + if (bp->bus_type == DFX_BUS_TYPE_EISA) + { + dfx_port_read_long(bp, PI_ESIC_K_SLOT_ID, &slot_id); + + /* + * First check if revision 2 EISA controller. Rev. 1 cards used + * PDQ revision B, so no workaround needed in this case. Rev. 3 + * cards used PDQ revision E, so no workaround needed in this + * case, either. Only Rev. 2 cards used either Rev. D or E + * chips, so we must verify the chip revision on Rev. 2 cards. + */ + + if (slot_id == DEFEA_PROD_ID_2) + { + /* + * Revision 2 FDDI EISA controller found, so let's check PDQ + * revision of adapter. + */ + + status = dfx_hw_port_ctrl_req(bp, + PI_PCTRL_M_SUB_CMD, + PI_SUB_CMD_K_PDQ_REV_GET, + 0, + &host_data); + if ((status != DFX_K_SUCCESS) || (host_data == 2)) + { + /* + * Either we couldn't determine the PDQ revision, or + * we determined that it is at revision D. In either case, + * we need to implement the workaround. + */ + + /* Ensure that the burst size is set to 8 longwords or less */ + + switch (bp->burst_size) + { + case PI_PDATA_B_DMA_BURST_SIZE_32: + case PI_PDATA_B_DMA_BURST_SIZE_16: + bp->burst_size = PI_PDATA_B_DMA_BURST_SIZE_8; + break; + + default: + break; + } + + /* Ensure that full-duplex mode is not enabled */ + + bp->full_duplex_enb = PI_SNMP_K_FALSE; + } + } + } + return; + } + + +/* + * =================== + * = dfx_driver_init = + * =================== + * + * Overview: + * Initializes remaining adapter board structure information + * and makes sure adapter is in a safe state prior to dfx_open(). + * + * Returns: + * Condition code + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This function allocates additional resources such as the host memory + * blocks needed by the adapter (eg. descriptor and consumer blocks). + * Remaining bus initialization steps are also completed. The adapter + * is also reset so that it is in the DMA_UNAVAILABLE state. The OS + * must call dfx_open() to open the adapter and bring it on-line. + * + * Return Codes: + * DFX_K_SUCCESS - initialization succeeded + * DFX_K_FAILURE - initialization failed - could not allocate memory + * or read adapter MAC address + * + * Assumptions: + * Memory allocated from kmalloc() call is physically contiguous, locked + * memory whose physical address equals its virtual address. + * + * Side Effects: + * Adapter is reset and should be in DMA_UNAVAILABLE state before + * returning from this routine. + */ + +int dfx_driver_init( + struct device *dev + ) + + { + DFX_board_t *bp = (DFX_board_t *)dev->priv; + int alloc_size; /* total buffer size needed */ + char *top_v, *curr_v; /* virtual addrs into memory block */ + u32 top_p, curr_p; /* physical addrs into memory block */ + u32 data; /* host data register value */ + + DBG_printk("In dfx_driver_init...\n"); + + /* Initialize bus-specific hardware registers */ + + dfx_bus_init(dev); + + /* + * Initialize default values for configurable parameters + * + * Note: All of these parameters are ones that a user may + * want to customize. It'd be nice to break these + * out into Space.c or someplace else that's more + * accessible/understandable than this file. + */ + + bp->full_duplex_enb = PI_SNMP_K_FALSE; + bp->req_ttrt = 8 * 12500; /* 8ms in 80 nanosec units */ + bp->burst_size = PI_PDATA_B_DMA_BURST_SIZE_DEF; + bp->rcv_bufs_to_post = RCV_BUFS_DEF; + + /* + * Ensure that HW configuration is OK + * + * Note: Depending on the hardware revision, we may need to modify + * some of the configurable parameters to workaround hardware + * limitations. We'll perform this configuration check AFTER + * setting the parameters to their default values. + */ + + dfx_bus_config_check(bp); + + /* Disable PDQ interrupts first */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); + + /* Place adapter in DMA_UNAVAILABLE state by resetting adapter */ + + (void) dfx_hw_dma_uninit(bp, PI_PDATA_A_RESET_M_SKIP_ST); + + /* Read the factory MAC address from the adapter then save it */ + + if (dfx_hw_port_ctrl_req(bp, + PI_PCTRL_M_MLA, + PI_PDATA_A_MLA_K_LO, + 0, + &data) != DFX_K_SUCCESS) + { + printk("%s: Could not read adapter factory MAC address!\n", dev->name); + return(DFX_K_FAILURE); + } + memcpy(&bp->factory_mac_addr[0], &data, sizeof(u32)); + + if (dfx_hw_port_ctrl_req(bp, + PI_PCTRL_M_MLA, + PI_PDATA_A_MLA_K_HI, + 0, + &data) != DFX_K_SUCCESS) + { + printk("%s: Could not read adapter factory MAC address!\n", dev->name); + return(DFX_K_FAILURE); + } + memcpy(&bp->factory_mac_addr[4], &data, sizeof(u16)); + + /* + * Set current address to factory address + * + * Note: Node address override support is handled through + * dfx_ctl_set_mac_address. + */ + + memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN); + if (bp->bus_type == DFX_BUS_TYPE_EISA) + printk("%s: DEFEA at I/O addr = 0x%lX, IRQ = %d, Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n", + dev->name, + dev->base_addr, + dev->irq, + dev->dev_addr[0], + dev->dev_addr[1], + dev->dev_addr[2], + dev->dev_addr[3], + dev->dev_addr[4], + dev->dev_addr[5]); + else + printk("%s: DEFPA at I/O addr = 0x%lX, IRQ = %d, Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n", + dev->name, + dev->base_addr, + dev->irq, + dev->dev_addr[0], + dev->dev_addr[1], + dev->dev_addr[2], + dev->dev_addr[3], + dev->dev_addr[4], + dev->dev_addr[5]); + + /* + * Get memory for descriptor block, consumer block, and other buffers + * that need to be DMA read or written to by the adapter. + */ + + alloc_size = sizeof(PI_DESCR_BLOCK) + + PI_CMD_REQ_K_SIZE_MAX + + PI_CMD_RSP_K_SIZE_MAX + + (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) + + sizeof(PI_CONSUMER_BLOCK) + + (PI_ALIGN_K_DESC_BLK - 1); + top_v = (char *) kmalloc(alloc_size, GFP_KERNEL); + if (top_v == NULL) + { + printk("%s: Could not allocate memory for host buffers and structures!\n", dev->name); + return(DFX_K_FAILURE); + } + memset(top_v, 0, alloc_size); /* zero out memory before continuing */ + top_p = virt_to_bus(top_v); /* get physical address of buffer */ + + /* + * To guarantee the 8K alignment required for the descriptor block, 8K - 1 + * plus the amount of memory needed was allocated. The physical address + * is now 8K aligned. By carving up the memory in a specific order, + * we'll guarantee the alignment requirements for all other structures. + * + * Note: If the assumptions change regarding the non-paged, non-cached, + * physically contiguous nature of the memory block or the address + * alignments, then we'll need to implement a different algorithm + * for allocating the needed memory. + */ + + curr_p = (u32) (ALIGN(top_p, PI_ALIGN_K_DESC_BLK)); + curr_v = top_v + (curr_p - top_p); + + /* Reserve space for descriptor block */ + + bp->descr_block_virt = (PI_DESCR_BLOCK *) curr_v; + bp->descr_block_phys = curr_p; + curr_v += sizeof(PI_DESCR_BLOCK); + curr_p += sizeof(PI_DESCR_BLOCK); + + /* Reserve space for command request buffer */ + + bp->cmd_req_virt = (PI_DMA_CMD_REQ *) curr_v; + bp->cmd_req_phys = curr_p; + curr_v += PI_CMD_REQ_K_SIZE_MAX; + curr_p += PI_CMD_REQ_K_SIZE_MAX; + + /* Reserve space for command response buffer */ + + bp->cmd_rsp_virt = (PI_DMA_CMD_RSP *) curr_v; + bp->cmd_rsp_phys = curr_p; + curr_v += PI_CMD_RSP_K_SIZE_MAX; + curr_p += PI_CMD_RSP_K_SIZE_MAX; + + /* Reserve space for the LLC host receive queue buffers */ + + bp->rcv_block_virt = curr_v; + bp->rcv_block_phys = curr_p; + curr_v += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX); + curr_p += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX); + + /* Reserve space for the consumer block */ + + bp->cons_block_virt = (PI_CONSUMER_BLOCK *) curr_v; + bp->cons_block_phys = curr_p; + + /* Display virtual and physical addresses if debug driver */ + + DBG_printk("%s: Descriptor block virt = %0lX, phys = %0X\n", dev->name, (long)bp->descr_block_virt, bp->descr_block_phys); + DBG_printk("%s: Command Request buffer virt = %0lX, phys = %0X\n", dev->name, (long)bp->cmd_req_virt, bp->cmd_req_phys); + DBG_printk("%s: Command Response buffer virt = %0lX, phys = %0X\n", dev->name, (long)bp->cmd_rsp_virt, bp->cmd_rsp_phys); + DBG_printk("%s: Receive buffer block virt = %0lX, phys = %0X\n", dev->name, (long)bp->rcv_block_virt, bp->rcv_block_phys); + DBG_printk("%s: Consumer block virt = %0lX, phys = %0X\n", dev->name, (long)bp->cons_block_virt, bp->cons_block_phys); + + return(DFX_K_SUCCESS); + } + + +/* + * ================= + * = dfx_adap_init = + * ================= + * + * Overview: + * Brings the adapter to the link avail/link unavailable state. + * + * Returns: + * Condition code + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Issues the low-level firmware/hardware calls necessary to bring + * the adapter up, or to properly reset and restore adapter during + * run-time. + * + * Return Codes: + * DFX_K_SUCCESS - Adapter brought up successfully + * DFX_K_FAILURE - Adapter initialization failed + * + * Assumptions: + * bp->reset_type should be set to a valid reset type value before + * calling this routine. + * + * Side Effects: + * Adapter should be in LINK_AVAILABLE or LINK_UNAVAILABLE state + * upon a successful return of this routine. + */ + +int dfx_adap_init( + DFX_board_t *bp + ) + + { + DBG_printk("In dfx_adap_init...\n"); + + /* Disable PDQ interrupts first */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); + + /* Place adapter in DMA_UNAVAILABLE state by resetting adapter */ + + if (dfx_hw_dma_uninit(bp, bp->reset_type) != DFX_K_SUCCESS) + { + printk("%s: Could not uninitialize/reset adapter!\n", bp->dev->name); + return(DFX_K_FAILURE); + } + + /* + * When the PDQ is reset, some false Type 0 interrupts may be pending, + * so we'll acknowledge all Type 0 interrupts now before continuing. + */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_0_STATUS, PI_HOST_INT_K_ACK_ALL_TYPE_0); + + /* + * Clear Type 1 and Type 2 registers before going to DMA_AVAILABLE state + * + * Note: We only need to clear host copies of these registers. The PDQ reset + * takes care of the on-board register values. + */ + + bp->cmd_req_reg.lword = 0; + bp->cmd_rsp_reg.lword = 0; + bp->rcv_xmt_reg.lword = 0; + + /* Clear consumer block before going to DMA_AVAILABLE state */ + + memset(bp->cons_block_virt, 0, sizeof(PI_CONSUMER_BLOCK)); + + /* Initialize the DMA Burst Size */ + + if (dfx_hw_port_ctrl_req(bp, + PI_PCTRL_M_SUB_CMD, + PI_SUB_CMD_K_BURST_SIZE_SET, + bp->burst_size, + NULL) != DFX_K_SUCCESS) + { + printk("%s: Could not set adapter burst size!\n", bp->dev->name); + return(DFX_K_FAILURE); + } + + /* + * Set base address of Consumer Block + * + * Assumption: 32-bit physical address of consumer block is 64 byte + * aligned. That is, bits 0-5 of the address must be zero. + */ + + if (dfx_hw_port_ctrl_req(bp, + PI_PCTRL_M_CONS_BLOCK, + bp->cons_block_phys, + 0, + NULL) != DFX_K_SUCCESS) + { + printk("%s: Could not set consumer block address!\n", bp->dev->name); + return(DFX_K_FAILURE); + } + + /* + * Set base address of Descriptor Block and bring adapter to DMA_AVAILABLE state + * + * Note: We also set the literal and data swapping requirements in this + * command. Since this driver presently runs on Intel platforms + * which are Little Endian, we'll tell the adapter to byte swap + * data only. This code will need to change when we support + * Big Endian systems (eg. PowerPC). + * + * Assumption: 32-bit physical address of descriptor block is 8Kbyte + * aligned. That is, bits 0-12 of the address must be zero. + */ + + if (dfx_hw_port_ctrl_req(bp, + PI_PCTRL_M_INIT, + (u32) (bp->descr_block_phys | PI_PDATA_A_INIT_M_BSWAP_DATA), + 0, + NULL) != DFX_K_SUCCESS) + { + printk("%s: Could not set descriptor block address!\n", bp->dev->name); + return(DFX_K_FAILURE); + } + + /* Set transmit flush timeout value */ + + bp->cmd_req_virt->cmd_type = PI_CMD_K_CHARS_SET; + bp->cmd_req_virt->char_set.item[0].item_code = PI_ITEM_K_FLUSH_TIME; + bp->cmd_req_virt->char_set.item[0].value = 3; /* 3 seconds */ + bp->cmd_req_virt->char_set.item[0].item_index = 0; + bp->cmd_req_virt->char_set.item[1].item_code = PI_ITEM_K_EOL; + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + { + printk("%s: DMA command request failed!\n", bp->dev->name); + return(DFX_K_FAILURE); + } + + /* Set the initial values for eFDXEnable and MACTReq MIB objects */ + + bp->cmd_req_virt->cmd_type = PI_CMD_K_SNMP_SET; + bp->cmd_req_virt->snmp_set.item[0].item_code = PI_ITEM_K_FDX_ENB_DIS; + bp->cmd_req_virt->snmp_set.item[0].value = bp->full_duplex_enb; + bp->cmd_req_virt->snmp_set.item[0].item_index = 0; + bp->cmd_req_virt->snmp_set.item[1].item_code = PI_ITEM_K_MAC_T_REQ; + bp->cmd_req_virt->snmp_set.item[1].value = bp->req_ttrt; + bp->cmd_req_virt->snmp_set.item[1].item_index = 0; + bp->cmd_req_virt->snmp_set.item[2].item_code = PI_ITEM_K_EOL; + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + { + printk("%s: DMA command request failed!\n", bp->dev->name); + return(DFX_K_FAILURE); + } + + /* Initialize adapter CAM */ + + if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS) + { + printk("%s: Adapter CAM update failed!\n", bp->dev->name); + return(DFX_K_FAILURE); + } + + /* Initialize adapter filters */ + + if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS) + { + printk("%s: Adapter filters update failed!\n", bp->dev->name); + return(DFX_K_FAILURE); + } + + /* Initialize receive descriptor block and produce buffers */ + + dfx_rcv_init(bp); + + /* Issue START command and bring adapter to LINK_(UN)AVAILABLE state */ + + bp->cmd_req_virt->cmd_type = PI_CMD_K_START; + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + { + printk("%s: Start command failed\n", bp->dev->name); + return(DFX_K_FAILURE); + } + + /* Initialization succeeded, reenable PDQ interrupts */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_ENABLE_DEF_INTS); + return(DFX_K_SUCCESS); + } + + +/* + * ============ + * = dfx_open = + * ============ + * + * Overview: + * Opens the adapter + * + * Returns: + * Condition code + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This function brings the adapter to an operational state. + * + * Return Codes: + * 0 - Adapter was successfully opened + * -EAGAIN - Could not register IRQ or adapter initialization failed + * + * Assumptions: + * This routine should only be called for a device that was + * initialized successfully during the dfx_probe process. + * + * Side Effects: + * Adapter should be in LINK_AVAILABLE or LINK_UNAVAILABLE state + * if the open is successful. + */ + +int dfx_open( + struct device *dev + ) + + { + DFX_board_t *bp = (DFX_board_t *)dev->priv; + + DBG_printk("In dfx_open...\n"); + + /* Register IRQ - support shared interrupts by passing device ptr */ + + if (request_irq(dev->irq, (void *)dfx_interrupt, SA_SHIRQ, dev->name, dev)) + { + printk("%s: Requested IRQ %d is busy\n", dev->name, dev->irq); + return(-EAGAIN); + } + + /* + * Set current address to factory MAC address + * + * Note: We've already done this step in dfx_driver_init. + * However, it's possible that a user has set a node + * address override, then closed and reopened the + * adapter. Unless we reset the device address field + * now, we'll continue to use the existing modified + * address. + */ + + memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN); + + /* Clear local unicast/multicast address tables and counts */ + + memset(bp->uc_table, 0, sizeof(bp->uc_table)); + memset(bp->mc_table, 0, sizeof(bp->mc_table)); + bp->uc_count = 0; + bp->mc_count = 0; + + /* Disable promiscuous filter settings */ + + bp->ind_group_prom = PI_FSTATE_K_BLOCK; + bp->group_prom = PI_FSTATE_K_BLOCK; + + /* Reset and initialize adapter */ + + bp->reset_type = PI_PDATA_A_RESET_M_SKIP_ST; /* skip self-test */ + if (dfx_adap_init(bp) != DFX_K_SUCCESS) + { + printk("%s: Adapter open failed!\n", dev->name); + return(-EAGAIN); + } + + /* Set device structure info */ + + dev->tbusy = 0; + dev->interrupt = DFX_UNMASK_INTERRUPTS; + dev->start = 1; + return(0); + } + + +/* + * ============= + * = dfx_close = + * ============= + * + * Overview: + * Closes the device/module. + * + * Returns: + * Condition code + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This routine closes the adapter and brings it to a safe state. + * The interrupt service routine is deregistered with the OS. + * The adapter can be opened again with another call to dfx_open(). + * + * Return Codes: + * Always return 0. + * + * Assumptions: + * No further requests for this adapter are made after this routine is + * called. dfx_open() can be called to reset and reinitialize the + * adapter. + * + * Side Effects: + * Adapter should be in DMA_UNAVAILABLE state upon completion of this + * routine. + */ + +int dfx_close( + struct device *dev + ) + + { + DFX_board_t *bp = (DFX_board_t *)dev->priv; + + DBG_printk("In dfx_close...\n"); + + /* Disable PDQ interrupts first */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); + + /* Place adapter in DMA_UNAVAILABLE state by resetting adapter */ + + (void) dfx_hw_dma_uninit(bp, PI_PDATA_A_RESET_M_SKIP_ST); + + /* + * Flush any pending transmit buffers + * + * Note: It's important that we flush the transmit buffers + * BEFORE we clear our copy of the Type 2 register. + * Otherwise, we'll have no idea how many buffers + * we need to free. + */ + + dfx_xmt_flush(bp); + + /* + * Clear Type 1 and Type 2 registers after adapter reset + * + * Note: Even though we're closing the adapter, it's + * possible that an interrupt will occur after + * dfx_close is called. Without some assurance to + * the contrary we want to make sure that we don't + * process receive and transmit LLC frames and update + * the Type 2 register with bad information. + */ + + bp->cmd_req_reg.lword = 0; + bp->cmd_rsp_reg.lword = 0; + bp->rcv_xmt_reg.lword = 0; + + /* Clear consumer block for the same reason given above */ + + memset(bp->cons_block_virt, 0, sizeof(PI_CONSUMER_BLOCK)); + + /* Clear device structure flags */ + + dev->start = 0; + dev->tbusy = 1; + + /* Deregister (free) IRQ */ + + free_irq(dev->irq, dev); + return(0); + } + + +/* + * ====================== + * = dfx_int_pr_halt_id = + * ====================== + * + * Overview: + * Displays halt id's in string form. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Determine current halt id and display appropriate string. + * + * Return Codes: + * None + * + * Assumptions: + * None + * + * Side Effects: + * None + */ + +void dfx_int_pr_halt_id( + DFX_board_t *bp + ) + + { + PI_UINT32 port_status; /* PDQ port status register value */ + PI_UINT32 halt_id; /* PDQ port status halt ID */ + + /* Read the latest port status */ + + dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status); + + /* Display halt state transition information */ + + halt_id = (port_status & PI_PSTATUS_M_HALT_ID) >> PI_PSTATUS_V_HALT_ID; + switch (halt_id) + { + case PI_HALT_ID_K_SELFTEST_TIMEOUT: + printk("%s: Halt ID: Selftest Timeout\n", bp->dev->name); + break; + + case PI_HALT_ID_K_PARITY_ERROR: + printk("%s: Halt ID: Host Bus Parity Error\n", bp->dev->name); + break; + + case PI_HALT_ID_K_HOST_DIR_HALT: + printk("%s: Halt ID: Host-Directed Halt\n", bp->dev->name); + break; + + case PI_HALT_ID_K_SW_FAULT: + printk("%s: Halt ID: Adapter Software Fault\n", bp->dev->name); + break; + + case PI_HALT_ID_K_HW_FAULT: + printk("%s: Halt ID: Adapter Hardware Fault\n", bp->dev->name); + break; + + case PI_HALT_ID_K_PC_TRACE: + printk("%s: Halt ID: FDDI Network PC Trace Path Test\n", bp->dev->name); + break; + + case PI_HALT_ID_K_DMA_ERROR: + printk("%s: Halt ID: Adapter DMA Error\n", bp->dev->name); + break; + + case PI_HALT_ID_K_IMAGE_CRC_ERROR: + printk("%s: Halt ID: Firmware Image CRC Error\n", bp->dev->name); + break; + + case PI_HALT_ID_K_BUS_EXCEPTION: + printk("%s: Halt ID: 68000 Bus Exception\n", bp->dev->name); + break; + + default: + printk("%s: Halt ID: Unknown (code = %X)\n", bp->dev->name, halt_id); + break; + } + return; + } + + +/* + * ========================== + * = dfx_int_type_0_process = + * ========================== + * + * Overview: + * Processes Type 0 interrupts. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Processes all enabled Type 0 interrupts. If the reason for the interrupt + * is a serious fault on the adapter, then an error message is displayed + * and the adapter is reset. + * + * One tricky potential timing window is the rapid succession of "link avail" + * "link unavail" state change interrupts. The acknowledgement of the Type 0 + * interrupt must be done before reading the state from the Port Status + * register. This is true because a state change could occur after reading + * the data, but before acknowledging the interrupt. If this state change + * does happen, it would be lost because the driver is using the old state, + * and it will never know about the new state because it subsequently + * acknowledges the state change interrupt. + * + * INCORRECT CORRECT + * read type 0 int reasons read type 0 int reasons + * read adapter state ack type 0 interrupts + * ack type 0 interrupts read adapter state + * ... process interrupt ... ... process interrupt ... + * + * Return Codes: + * None + * + * Assumptions: + * None + * + * Side Effects: + * An adapter reset may occur if the adapter has any Type 0 error interrupts + * or if the port status indicates that the adapter is halted. The driver + * is responsible for reinitializing the adapter with the current CAM + * contents and adapter filter settings. + */ + +void dfx_int_type_0_process( + DFX_board_t *bp + ) + + { + PI_UINT32 type_0_status; /* Host Interrupt Type 0 register */ + PI_UINT32 state; /* current adap state (from port status) */ + + /* + * Read host interrupt Type 0 register to determine which Type 0 + * interrupts are pending. Immediately write it back out to clear + * those interrupts. + */ + + dfx_port_read_long(bp, PI_PDQ_K_REG_TYPE_0_STATUS, &type_0_status); + dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_0_STATUS, type_0_status); + + /* Check for Type 0 error interrupts */ + + if (type_0_status & (PI_TYPE_0_STAT_M_NXM | + PI_TYPE_0_STAT_M_PM_PAR_ERR | + PI_TYPE_0_STAT_M_BUS_PAR_ERR)) + { + /* Check for Non-Existent Memory error */ + + if (type_0_status & PI_TYPE_0_STAT_M_NXM) + printk("%s: Non-Existent Memory Access Error\n", bp->dev->name); + + /* Check for Packet Memory Parity error */ + + if (type_0_status & PI_TYPE_0_STAT_M_PM_PAR_ERR) + printk("%s: Packet Memory Parity Error\n", bp->dev->name); + + /* Check for Host Bus Parity error */ + + if (type_0_status & PI_TYPE_0_STAT_M_BUS_PAR_ERR) + printk("%s: Host Bus Parity Error\n", bp->dev->name); + + /* Reset adapter and bring it back on-line */ + + bp->link_available = PI_K_FALSE; /* link is no longer available */ + bp->reset_type = 0; /* rerun on-board diagnostics */ + printk("%s: Resetting adapter...\n", bp->dev->name); + if (dfx_adap_init(bp) != DFX_K_SUCCESS) + { + printk("%s: Adapter reset failed! Disabling adapter interrupts.\n", bp->dev->name); + dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); + return; + } + printk("%s: Adapter reset successful!\n", bp->dev->name); + return; + } + + /* Check for transmit flush interrupt */ + + if (type_0_status & PI_TYPE_0_STAT_M_XMT_FLUSH) + { + /* Flush any pending xmt's and acknowledge the flush interrupt */ + + bp->link_available = PI_K_FALSE; /* link is no longer available */ + dfx_xmt_flush(bp); /* flush any outstanding packets */ + (void) dfx_hw_port_ctrl_req(bp, + PI_PCTRL_M_XMT_DATA_FLUSH_DONE, + 0, + 0, + NULL); + } + + /* Check for adapter state change */ + + if (type_0_status & PI_TYPE_0_STAT_M_STATE_CHANGE) + { + /* Get latest adapter state */ + + state = dfx_hw_adap_state_rd(bp); /* get adapter state */ + if (state == PI_STATE_K_HALTED) + { + /* + * Adapter has transitioned to HALTED state, try to reset + * adapter to bring it back on-line. If reset fails, + * leave the adapter in the broken state. + */ + + printk("%s: Controller has transitioned to HALTED state!\n", bp->dev->name); + dfx_int_pr_halt_id(bp); /* display halt id as string */ + + /* Reset adapter and bring it back on-line */ + + bp->link_available = PI_K_FALSE; /* link is no longer available */ + bp->reset_type = 0; /* rerun on-board diagnostics */ + printk("%s: Resetting adapter...\n", bp->dev->name); + if (dfx_adap_init(bp) != DFX_K_SUCCESS) + { + printk("%s: Adapter reset failed! Disabling adapter interrupts.\n", bp->dev->name); + dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); + return; + } + printk("%s: Adapter reset successful!\n", bp->dev->name); + } + else if (state == PI_STATE_K_LINK_AVAIL) + { + bp->link_available = PI_K_TRUE; /* set link available flag */ + } + } + return; + } + + +/* + * ================== + * = dfx_int_common = + * ================== + * + * Overview: + * Interrupt service routine (ISR) + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * This is the ISR which processes incoming adapter interrupts. + * + * Return Codes: + * None + * + * Assumptions: + * This routine assumes PDQ interrupts have not been disabled. + * When interrupts are disabled at the PDQ, the Port Status register + * is automatically cleared. This routine uses the Port Status + * register value to determine whether a Type 0 interrupt occurred, + * so it's important that adapter interrupts are not normally + * enabled/disabled at the PDQ. + * + * It's vital that this routine is NOT reentered for the + * same board and that the OS is not in another section of + * code (eg. dfx_xmt_queue_pkt) for the same board on a + * different thread. + * + * Side Effects: + * Pending interrupts are serviced. Depending on the type of + * interrupt, acknowledging and clearing the interrupt at the + * PDQ involves writing a register to clear the interrupt bit + * or updating completion indices. + */ + +void dfx_int_common( + DFX_board_t *bp + ) + + { + PI_UINT32 port_status; /* Port Status register */ + + /* Process xmt interrupts - frequent case, so always call this routine */ + + dfx_xmt_done(bp); /* free consumed xmt packets */ + + /* Process rcv interrupts - frequent case, so always call this routine */ + + dfx_rcv_queue_process(bp); /* service received LLC frames */ + + /* + * Transmit and receive producer and completion indices are updated on the + * adapter by writing to the Type 2 Producer register. Since the frequent + * case is that we'll be processing either LLC transmit or receive buffers, + * we'll optimize I/O writes by doing a single register write here. + */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); + + /* Read PDQ Port Status register to find out which interrupts need processing */ + + dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status); + + /* Process Type 0 interrupts (if any) - infrequent, so only call when needed */ + + if (port_status & PI_PSTATUS_M_TYPE_0_PENDING) + dfx_int_type_0_process(bp); /* process Type 0 interrupts */ + return; + } + + +/* + * ================= + * = dfx_interrupt = + * ================= + * + * Overview: + * Interrupt processing routine + * + * Returns: + * None + * + * Arguments: + * irq - interrupt vector + * dev_id - pointer to device information + * regs - pointer to registers structure + * + * Functional Description: + * This routine calls the interrupt processing routine for this adapter. It + * disables and reenables adapter interrupts, as appropriate. We can support + * shared interrupts since the incoming dev_id pointer provides our device + * structure context. + * + * Return Codes: + * None + * + * Assumptions: + * The interrupt acknowledgement at the hardware level (eg. ACKing the PIC + * on Intel-based systems) is done by the operating system outside this + * routine. + * + * System interrupts are enabled through this call. + * + * Side Effects: + * Interrupts are disabled, then reenabled at the adapter. + */ + +void dfx_interrupt( + int irq, + void *dev_id, + struct pt_regs *regs + ) + + { + struct device *dev = (struct device *) dev_id; + DFX_board_t *bp; /* private board structure pointer */ + u8 tmp; /* used for disabling/enabling ints */ + + /* Get board pointer only if device structure is valid */ + + if (dev == NULL) + { + printk("dfx_interrupt(): irq %d for unknown device!\n", irq); + return; + } + bp = (DFX_board_t *) dev->priv; + + /* See if we're already servicing an interrupt */ + + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler!\n", dev->name); + dev->interrupt = DFX_MASK_INTERRUPTS; /* ensure non reentrancy */ + + /* Service adapter interrupts */ + + if (bp->bus_type == DFX_BUS_TYPE_PCI) + { + /* Disable PDQ-PFI interrupts at PFI */ + + dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, PFI_MODE_M_DMA_ENB); + + /* Call interrupt service routine for this adapter */ + + dfx_int_common(bp); + + /* Clear PDQ interrupt status bit and reenable interrupts */ + + dfx_port_write_long(bp, PFI_K_REG_STATUS, PFI_STATUS_M_PDQ_INT); + dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, + (PFI_MODE_M_PDQ_INT_ENB + PFI_MODE_M_DMA_ENB)); + } + else + { + /* Disable interrupts at the ESIC */ + + dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &tmp); + tmp &= ~PI_CONFIG_STAT_0_M_INT_ENB; + dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, tmp); + + /* Call interrupt service routine for this adapter */ + + dfx_int_common(bp); + + /* Reenable interrupts at the ESIC */ + + dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &tmp); + tmp |= PI_CONFIG_STAT_0_M_INT_ENB; + dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, tmp); + } + + dev->interrupt = DFX_UNMASK_INTERRUPTS; + return; + } + + +/* + * ===================== + * = dfx_ctl_get_stats = + * ===================== + * + * Overview: + * Get statistics for FDDI adapter + * + * Returns: + * Pointer to FDDI statistics structure + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * Gets current MIB objects from adapter, then + * returns FDDI statistics structure as defined + * in if_fddi.h. + * + * Note: Since the FDDI statistics structure is + * still new and the device structure doesn't + * have an FDDI-specific get statistics handler, + * we'll return the FDDI statistics structure as + * a pointer to an Ethernet statistics structure. + * That way, at least the first part of the statistics + * structure can be decoded properly, and it allows + * "smart" applications to perform a second cast to + * decode the FDDI-specific statistics. + * + * We'll have to pay attention to this routine as the + * device structure becomes more mature and LAN media + * independent. + * + * Return Codes: + * None + * + * Assumptions: + * None + * + * Side Effects: + * None + */ + +struct enet_statistics *dfx_ctl_get_stats( + struct device *dev + ) + + { + DFX_board_t *bp = (DFX_board_t *)dev->priv; + + /* Fill the bp->stats structure with driver-maintained counters */ + + bp->stats.rx_packets = bp->rcv_total_frames; + bp->stats.tx_packets = bp->xmt_total_frames; + bp->stats.rx_errors = (u32)(bp->rcv_crc_errors + bp->rcv_frame_status_errors + bp->rcv_length_errors); + bp->stats.tx_errors = bp->xmt_length_errors; + bp->stats.rx_dropped = bp->rcv_discards; + bp->stats.tx_dropped = bp->xmt_discards; + bp->stats.multicast = bp->rcv_multicast_frames; + bp->stats.transmit_collision = 0; /* always zero (0) for FDDI */ + + /* Get FDDI SMT MIB objects */ + + bp->cmd_req_virt->cmd_type = PI_CMD_K_SMT_MIB_GET; + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + return((struct enet_statistics *) &bp->stats); + + /* Fill the bp->stats structure with the SMT MIB object values */ + + memcpy(bp->stats.smt_station_id, &bp->cmd_rsp_virt->smt_mib_get.smt_station_id, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_station_id)); + bp->stats.smt_op_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_op_version_id; + bp->stats.smt_hi_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_hi_version_id; + bp->stats.smt_lo_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_lo_version_id; + memcpy(bp->stats.smt_user_data, &bp->cmd_rsp_virt->smt_mib_get.smt_user_data, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_user_data)); + bp->stats.smt_mib_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_mib_version_id; + bp->stats.smt_mac_cts = bp->cmd_rsp_virt->smt_mib_get.smt_mac_ct; + bp->stats.smt_non_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_non_master_ct; + bp->stats.smt_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_master_ct; + bp->stats.smt_available_paths = bp->cmd_rsp_virt->smt_mib_get.smt_available_paths; + bp->stats.smt_config_capabilities = bp->cmd_rsp_virt->smt_mib_get.smt_config_capabilities; + bp->stats.smt_config_policy = bp->cmd_rsp_virt->smt_mib_get.smt_config_policy; + bp->stats.smt_connection_policy = bp->cmd_rsp_virt->smt_mib_get.smt_connection_policy; + bp->stats.smt_t_notify = bp->cmd_rsp_virt->smt_mib_get.smt_t_notify; + bp->stats.smt_stat_rpt_policy = bp->cmd_rsp_virt->smt_mib_get.smt_stat_rpt_policy; + bp->stats.smt_trace_max_expiration = bp->cmd_rsp_virt->smt_mib_get.smt_trace_max_expiration; + bp->stats.smt_bypass_present = bp->cmd_rsp_virt->smt_mib_get.smt_bypass_present; + bp->stats.smt_ecm_state = bp->cmd_rsp_virt->smt_mib_get.smt_ecm_state; + bp->stats.smt_cf_state = bp->cmd_rsp_virt->smt_mib_get.smt_cf_state; + bp->stats.smt_remote_disconnect_flag = bp->cmd_rsp_virt->smt_mib_get.smt_remote_disconnect_flag; + bp->stats.smt_station_status = bp->cmd_rsp_virt->smt_mib_get.smt_station_status; + bp->stats.smt_peer_wrap_flag = bp->cmd_rsp_virt->smt_mib_get.smt_peer_wrap_flag; + bp->stats.smt_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_msg_time_stamp.ls; + bp->stats.smt_transition_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_transition_time_stamp.ls; + bp->stats.mac_frame_status_functions = bp->cmd_rsp_virt->smt_mib_get.mac_frame_status_functions; + bp->stats.mac_t_max_capability = bp->cmd_rsp_virt->smt_mib_get.mac_t_max_capability; + bp->stats.mac_tvx_capability = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_capability; + bp->stats.mac_available_paths = bp->cmd_rsp_virt->smt_mib_get.mac_available_paths; + bp->stats.mac_current_path = bp->cmd_rsp_virt->smt_mib_get.mac_current_path; + memcpy(bp->stats.mac_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_upstream_nbr, FDDI_K_ALEN); + memcpy(bp->stats.mac_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_downstream_nbr, FDDI_K_ALEN); + memcpy(bp->stats.mac_old_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_upstream_nbr, FDDI_K_ALEN); + memcpy(bp->stats.mac_old_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_downstream_nbr, FDDI_K_ALEN); + bp->stats.mac_dup_address_test = bp->cmd_rsp_virt->smt_mib_get.mac_dup_address_test; + bp->stats.mac_requested_paths = bp->cmd_rsp_virt->smt_mib_get.mac_requested_paths; + bp->stats.mac_downstream_port_type = bp->cmd_rsp_virt->smt_mib_get.mac_downstream_port_type; + memcpy(bp->stats.mac_smt_address, &bp->cmd_rsp_virt->smt_mib_get.mac_smt_address, FDDI_K_ALEN); + bp->stats.mac_t_req = bp->cmd_rsp_virt->smt_mib_get.mac_t_req; + bp->stats.mac_t_neg = bp->cmd_rsp_virt->smt_mib_get.mac_t_neg; + bp->stats.mac_t_max = bp->cmd_rsp_virt->smt_mib_get.mac_t_max; + bp->stats.mac_tvx_value = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_value; + bp->stats.mac_frame_error_threshold = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_threshold; + bp->stats.mac_frame_error_ratio = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_ratio; + bp->stats.mac_rmt_state = bp->cmd_rsp_virt->smt_mib_get.mac_rmt_state; + bp->stats.mac_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_da_flag; + bp->stats.mac_una_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_unda_flag; + bp->stats.mac_frame_error_flag = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_flag; + bp->stats.mac_ma_unitdata_available = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_available; + bp->stats.mac_hardware_present = bp->cmd_rsp_virt->smt_mib_get.mac_hardware_present; + bp->stats.mac_ma_unitdata_enable = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_enable; + bp->stats.path_tvx_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_tvx_lower_bound; + bp->stats.path_t_max_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_t_max_lower_bound; + bp->stats.path_max_t_req = bp->cmd_rsp_virt->smt_mib_get.path_max_t_req; + memcpy(bp->stats.path_configuration, &bp->cmd_rsp_virt->smt_mib_get.path_configuration, sizeof(bp->cmd_rsp_virt->smt_mib_get.path_configuration)); + bp->stats.port_my_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[0]; + bp->stats.port_my_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[1]; + bp->stats.port_neighbor_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[0]; + bp->stats.port_neighbor_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[1]; + bp->stats.port_connection_policies[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[0]; + bp->stats.port_connection_policies[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[1]; + bp->stats.port_mac_indicated[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[0]; + bp->stats.port_mac_indicated[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[1]; + bp->stats.port_current_path[0] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[0]; + bp->stats.port_current_path[1] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[1]; + memcpy(&bp->stats.port_requested_paths[0*3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[0], 3); + memcpy(&bp->stats.port_requested_paths[1*3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[1], 3); + bp->stats.port_mac_placement[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[0]; + bp->stats.port_mac_placement[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[1]; + bp->stats.port_available_paths[0] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[0]; + bp->stats.port_available_paths[1] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[1]; + bp->stats.port_pmd_class[0] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[0]; + bp->stats.port_pmd_class[1] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[1]; + bp->stats.port_connection_capabilities[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[0]; + bp->stats.port_connection_capabilities[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[1]; + bp->stats.port_bs_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[0]; + bp->stats.port_bs_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[1]; + bp->stats.port_ler_estimate[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[0]; + bp->stats.port_ler_estimate[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[1]; + bp->stats.port_ler_cutoff[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[0]; + bp->stats.port_ler_cutoff[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[1]; + bp->stats.port_ler_alarm[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[0]; + bp->stats.port_ler_alarm[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[1]; + bp->stats.port_connect_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[0]; + bp->stats.port_connect_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[1]; + bp->stats.port_pcm_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[0]; + bp->stats.port_pcm_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[1]; + bp->stats.port_pc_withhold[0] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[0]; + bp->stats.port_pc_withhold[1] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[1]; + bp->stats.port_ler_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[0]; + bp->stats.port_ler_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[1]; + bp->stats.port_hardware_present[0] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[0]; + bp->stats.port_hardware_present[1] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[1]; + + /* Get FDDI counters */ + + bp->cmd_req_virt->cmd_type = PI_CMD_K_CNTRS_GET; + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + return((struct enet_statistics *) &bp->stats); + + /* Fill the bp->stats structure with the FDDI counter values */ + + bp->stats.mac_frame_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.frame_cnt.ls; + bp->stats.mac_copied_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.copied_cnt.ls; + bp->stats.mac_transmit_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.transmit_cnt.ls; + bp->stats.mac_error_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.error_cnt.ls; + bp->stats.mac_lost_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.lost_cnt.ls; + bp->stats.port_lct_fail_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[0].ls; + bp->stats.port_lct_fail_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[1].ls; + bp->stats.port_lem_reject_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[0].ls; + bp->stats.port_lem_reject_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[1].ls; + bp->stats.port_lem_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[0].ls; + bp->stats.port_lem_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[1].ls; + + return((struct enet_statistics *) &bp->stats); + } + + +/* + * ============================== + * = dfx_ctl_set_multicast_list = + * ============================== + * + * Overview: + * Enable/Disable LLC frame promiscuous mode reception + * on the adapter and/or update multicast address table. + * + * Returns: + * None + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This routine follows a fairly simple algorithm for setting the + * adapter filters and CAM: + * + * if IFF_PROMISC flag is set + * enable LLC individual/group promiscuous mode + * else + * disable LLC individual/group promiscuous mode + * if number of incoming multicast addresses > + * (CAM max size - number of unicast addresses in CAM) + * enable LLC group promiscuous mode + * set driver-maintained multicast address count to zero + * else + * disable LLC group promiscuous mode + * set driver-maintained multicast address count to incoming count + * update adapter CAM + * update adapter filters + * + * Return Codes: + * None + * + * Assumptions: + * Multicast addresses are presented in canonical (LSB) format. + * + * Side Effects: + * On-board adapter CAM and filters are updated. + */ + +void dfx_ctl_set_multicast_list( + struct device *dev + ) + + { + DFX_board_t *bp = (DFX_board_t *)dev->priv; + int i; /* used as index in for loop */ + struct dev_mc_list *dmi; /* ptr to multicast addr entry */ + + /* Enable LLC frame promiscuous mode, if necessary */ + + if (dev->flags & IFF_PROMISC) + bp->ind_group_prom = PI_FSTATE_K_PASS; /* Enable LLC ind/group prom mode */ + + /* Else, update multicast address table */ + + else + { + bp->ind_group_prom = PI_FSTATE_K_BLOCK; /* Disable LLC ind/group prom mode */ + /* + * Check whether incoming multicast address count exceeds table size + * + * Note: The adapters utilize an on-board 64 entry CAM for + * supporting perfect filtering of multicast packets + * and bridge functions when adding unicast addresses. + * There is no hash function available. To support + * additional multicast addresses, the all multicast + * filter (LLC group promiscuous mode) must be enabled. + * + * The firmware reserves two CAM entries for SMT-related + * multicast addresses, which leaves 62 entries available. + * The following code ensures that we're not being asked + * to add more than 62 addresses to the CAM. If we are, + * the driver will enable the all multicast filter. + * Should the number of multicast addresses drop below + * the high water mark, the filter will be disabled and + * perfect filtering will be used. + */ + + if (dev->mc_count > (PI_CMD_ADDR_FILTER_K_SIZE - bp->uc_count)) + { + bp->group_prom = PI_FSTATE_K_PASS; /* Enable LLC group prom mode */ + bp->mc_count = 0; /* Don't add mc addrs to CAM */ + } + else + { + bp->group_prom = PI_FSTATE_K_BLOCK; /* Disable LLC group prom mode */ + bp->mc_count = dev->mc_count; /* Add mc addrs to CAM */ + } + + /* Copy addresses to multicast address table, then update adapter CAM */ + + dmi = dev->mc_list; /* point to first multicast addr */ + for (i=0; i < bp->mc_count; i++) + { + memcpy(&bp->mc_table[i*FDDI_K_ALEN], dmi->dmi_addr, FDDI_K_ALEN); + dmi = dmi->next; /* point to next multicast addr */ + } + if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS) + { + DBG_printk("%s: Could not update multicast address table!\n", dev->name); + } + else + { + DBG_printk("%s: Multicast address table updated! Added %d addresses.\n", dev->name, bp->mc_count); + } + } + + /* Update adapter filters */ + + if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS) + { + DBG_printk("%s: Could not update adapter filters!\n", dev->name); + } + else + { + DBG_printk("%s: Adapter filters updated!\n", dev->name); + } + return; + } + + +/* + * =========================== + * = dfx_ctl_set_mac_address = + * =========================== + * + * Overview: + * Add node address override (unicast address) to adapter + * CAM and update dev_addr field in device table. + * + * Returns: + * None + * + * Arguments: + * dev - pointer to device information + * addr - pointer to sockaddr structure containing unicast address to add + * + * Functional Description: + * The adapter supports node address overrides by adding one or more + * unicast addresses to the adapter CAM. This is similar to adding + * multicast addresses. In this routine we'll update the driver and + * device structures with the new address, then update the adapter CAM + * to ensure that the adapter will copy and strip frames destined and + * sourced by that address. + * + * Return Codes: + * Always returns zero. + * + * Assumptions: + * The address pointed to by addr->sa_data is a valid unicast + * address and is presented in canonical (LSB) format. + * + * Side Effects: + * On-board adapter CAM is updated. On-board adapter filters + * may be updated. + */ + +int dfx_ctl_set_mac_address( + struct device *dev, + void *addr + ) + + { + DFX_board_t *bp = (DFX_board_t *)dev->priv; + struct sockaddr *p_sockaddr = (struct sockaddr *)addr; + + /* Copy unicast address to driver-maintained structs and update count */ + + memcpy(dev->dev_addr, p_sockaddr->sa_data, FDDI_K_ALEN); /* update device struct */ + memcpy(&bp->uc_table[0], p_sockaddr->sa_data, FDDI_K_ALEN); /* update driver struct */ + bp->uc_count = 1; + + /* + * Verify we're not exceeding the CAM size by adding unicast address + * + * Note: It's possible that before entering this routine we've + * already filled the CAM with 62 multicast addresses. + * Since we need to place the node address override into + * the CAM, we have to check to see that we're not + * exceeding the CAM size. If we are, we have to enable + * the LLC group (multicast) promiscuous mode filter as + * in dfx_ctl_set_multicast_list. + */ + + if ((bp->uc_count + bp->mc_count) > PI_CMD_ADDR_FILTER_K_SIZE) + { + bp->group_prom = PI_FSTATE_K_PASS; /* Enable LLC group prom mode */ + bp->mc_count = 0; /* Don't add mc addrs to CAM */ + + /* Update adapter filters */ + + if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS) + { + DBG_printk("%s: Could not update adapter filters!\n", dev->name); + } + else + { + DBG_printk("%s: Adapter filters updated!\n", dev->name); + } + } + + /* Update adapter CAM with new unicast address */ + + if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS) + { + DBG_printk("%s: Could not set new MAC address!\n", dev->name); + } + else + { + DBG_printk("%s: Adapter CAM updated with new MAC address\n", dev->name); + } + return(0); /* always return zero */ + } + + +/* + * ====================== + * = dfx_ctl_update_cam = + * ====================== + * + * Overview: + * Procedure to update adapter CAM (Content Addressable Memory) + * with desired unicast and multicast address entries. + * + * Returns: + * Condition code + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Updates adapter CAM with current contents of board structure + * unicast and multicast address tables. Since there are only 62 + * free entries in CAM, this routine ensures that the command + * request buffer is not overrun. + * + * Return Codes: + * DFX_K_SUCCESS - Request succeeded + * DFX_K_FAILURE - Request failed + * + * Assumptions: + * All addresses being added (unicast and multicast) are in canonical + * order. + * + * Side Effects: + * On-board adapter CAM is updated. + */ + +int dfx_ctl_update_cam( + DFX_board_t *bp + ) + + { + int i; /* used as index */ + PI_LAN_ADDR *p_addr; /* pointer to CAM entry */ + + /* + * Fill in command request information + * + * Note: Even though both the unicast and multicast address + * table entries are stored as contiguous 6 byte entries, + * the firmware address filter set command expects each + * entry to be two longwords (8 bytes total). We must be + * careful to only copy the six bytes of each unicast and + * multicast table entry into each command entry. This + * is also why we must first clear the entire command + * request buffer. + */ + + memset(bp->cmd_req_virt, 0, PI_CMD_REQ_K_SIZE_MAX); /* first clear buffer */ + bp->cmd_req_virt->cmd_type = PI_CMD_K_ADDR_FILTER_SET; + p_addr = &bp->cmd_req_virt->addr_filter_set.entry[0]; + + /* Now add unicast addresses to command request buffer, if any */ + + for (i=0; i < (int)bp->uc_count; i++) + { + if (i < PI_CMD_ADDR_FILTER_K_SIZE) + { + memcpy(p_addr, &bp->uc_table[i*FDDI_K_ALEN], FDDI_K_ALEN); + p_addr++; /* point to next command entry */ + } + } + + /* Now add multicast addresses to command request buffer, if any */ + + for (i=0; i < (int)bp->mc_count; i++) + { + if ((i + bp->uc_count) < PI_CMD_ADDR_FILTER_K_SIZE) + { + memcpy(p_addr, &bp->mc_table[i*FDDI_K_ALEN], FDDI_K_ALEN); + p_addr++; /* point to next command entry */ + } + } + + /* Issue command to update adapter CAM, then return */ + + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + return(DFX_K_FAILURE); + return(DFX_K_SUCCESS); + } + + +/* + * ========================== + * = dfx_ctl_update_filters = + * ========================== + * + * Overview: + * Procedure to update adapter filters with desired + * filter settings. + * + * Returns: + * Condition code + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Enables or disables filter using current filter settings. + * + * Return Codes: + * DFX_K_SUCCESS - Request succeeded. + * DFX_K_FAILURE - Request failed. + * + * Assumptions: + * We must always pass up packets destined to the broadcast + * address (FF-FF-FF-FF-FF-FF), so we'll always keep the + * broadcast filter enabled. + * + * Side Effects: + * On-board adapter filters are updated. + */ + +int dfx_ctl_update_filters( + DFX_board_t *bp + ) + + { + int i = 0; /* used as index */ + + /* Fill in command request information */ + + bp->cmd_req_virt->cmd_type = PI_CMD_K_FILTERS_SET; + + /* Initialize Broadcast filter - * ALWAYS ENABLED * */ + + bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_BROADCAST; + bp->cmd_req_virt->filter_set.item[i++].value = PI_FSTATE_K_PASS; + + /* Initialize LLC Individual/Group Promiscuous filter */ + + bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_IND_GROUP_PROM; + bp->cmd_req_virt->filter_set.item[i++].value = bp->ind_group_prom; + + /* Initialize LLC Group Promiscuous filter */ + + bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_GROUP_PROM; + bp->cmd_req_virt->filter_set.item[i++].value = bp->group_prom; + + /* Terminate the item code list */ + + bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_EOL; + + /* Issue command to update adapter filters, then return */ + + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + return(DFX_K_FAILURE); + return(DFX_K_SUCCESS); + } + + +/* + * ====================== + * = dfx_hw_dma_cmd_req = + * ====================== + * + * Overview: + * Sends PDQ DMA command to adapter firmware + * + * Returns: + * Condition code + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * The command request and response buffers are posted to the adapter in the manner + * described in the PDQ Port Specification: + * + * 1. Command Response Buffer is posted to adapter. + * 2. Command Request Buffer is posted to adapter. + * 3. Command Request consumer index is polled until it indicates that request + * buffer has been DMA'd to adapter. + * 4. Command Response consumer index is polled until it indicates that response + * buffer has been DMA'd from adapter. + * + * This ordering ensures that a response buffer is already available for the firmware + * to use once it's done processing the request buffer. + * + * Return Codes: + * DFX_K_SUCCESS - DMA command succeeded + * DFX_K_OUTSTATE - Adapter is NOT in proper state + * DFX_K_HW_TIMEOUT - DMA command timed out + * + * Assumptions: + * Command request buffer has already been filled with desired DMA command. + * + * Side Effects: + * None + */ + +int dfx_hw_dma_cmd_req( + DFX_board_t *bp + ) + + { + int status; /* adapter status */ + int timeout_cnt; /* used in for loops */ + + /* Make sure the adapter is in a state that we can issue the DMA command in */ + + status = dfx_hw_adap_state_rd(bp); + if ((status == PI_STATE_K_RESET) || + (status == PI_STATE_K_HALTED) || + (status == PI_STATE_K_DMA_UNAVAIL) || + (status == PI_STATE_K_UPGRADE)) + return(DFX_K_OUTSTATE); + + /* Put response buffer on the command response queue */ + + bp->descr_block_virt->cmd_rsp[bp->cmd_rsp_reg.index.prod].long_0 = (u32) (PI_RCV_DESCR_M_SOP | + ((PI_CMD_RSP_K_SIZE_MAX / PI_ALIGN_K_CMD_RSP_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); + bp->descr_block_virt->cmd_rsp[bp->cmd_rsp_reg.index.prod].long_1 = bp->cmd_rsp_phys; + + /* Bump (and wrap) the producer index and write out to register */ + + bp->cmd_rsp_reg.index.prod += 1; + bp->cmd_rsp_reg.index.prod &= PI_CMD_RSP_K_NUM_ENTRIES-1; + dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_RSP_PROD, bp->cmd_rsp_reg.lword); + + /* Put request buffer on the command request queue */ + + bp->descr_block_virt->cmd_req[bp->cmd_req_reg.index.prod].long_0 = (u32) (PI_XMT_DESCR_M_SOP | + PI_XMT_DESCR_M_EOP | (PI_CMD_REQ_K_SIZE_MAX << PI_XMT_DESCR_V_SEG_LEN)); + bp->descr_block_virt->cmd_req[bp->cmd_req_reg.index.prod].long_1 = bp->cmd_req_phys; + + /* Bump (and wrap) the producer index and write out to register */ + + bp->cmd_req_reg.index.prod += 1; + bp->cmd_req_reg.index.prod &= PI_CMD_REQ_K_NUM_ENTRIES-1; + dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_REQ_PROD, bp->cmd_req_reg.lword); + + /* + * Here we wait for the command request consumer index to be equal + * to the producer, indicating that the adapter has DMAed the request. + */ + + for (timeout_cnt = 20000; timeout_cnt > 0; timeout_cnt--) + { + if (bp->cmd_req_reg.index.prod == (u8)(bp->cons_block_virt->cmd_req)) + break; + udelay(100); /* wait for 100 microseconds */ + } + if (timeout_cnt == 0) + return(DFX_K_HW_TIMEOUT); + + /* Bump (and wrap) the completion index and write out to register */ + + bp->cmd_req_reg.index.comp += 1; + bp->cmd_req_reg.index.comp &= PI_CMD_REQ_K_NUM_ENTRIES-1; + dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_REQ_PROD, bp->cmd_req_reg.lword); + + /* + * Here we wait for the command response consumer index to be equal + * to the producer, indicating that the adapter has DMAed the response. + */ + + for (timeout_cnt = 20000; timeout_cnt > 0; timeout_cnt--) + { + if (bp->cmd_rsp_reg.index.prod == (u8)(bp->cons_block_virt->cmd_rsp)) + break; + udelay(100); /* wait for 100 microseconds */ + } + if (timeout_cnt == 0) + return(DFX_K_HW_TIMEOUT); + + /* Bump (and wrap) the completion index and write out to register */ + + bp->cmd_rsp_reg.index.comp += 1; + bp->cmd_rsp_reg.index.comp &= PI_CMD_RSP_K_NUM_ENTRIES-1; + dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_RSP_PROD, bp->cmd_rsp_reg.lword); + return(DFX_K_SUCCESS); + } + + +/* + * ======================== + * = dfx_hw_port_ctrl_req = + * ======================== + * + * Overview: + * Sends PDQ port control command to adapter firmware + * + * Returns: + * Host data register value in host_data if ptr is not NULL + * + * Arguments: + * bp - pointer to board information + * command - port control command + * data_a - port data A register value + * data_b - port data B register value + * host_data - ptr to host data register value + * + * Functional Description: + * Send generic port control command to adapter by writing + * to various PDQ port registers, then polling for completion. + * + * Return Codes: + * DFX_K_SUCCESS - port control command succeeded + * DFX_K_HW_TIMEOUT - port control command timed out + * + * Assumptions: + * None + * + * Side Effects: + * None + */ + +int dfx_hw_port_ctrl_req( + DFX_board_t *bp, + PI_UINT32 command, + PI_UINT32 data_a, + PI_UINT32 data_b, + PI_UINT32 *host_data + ) + + { + PI_UINT32 port_cmd; /* Port Control command register value */ + int timeout_cnt; /* used in for loops */ + + /* Set Command Error bit in command longword */ + + port_cmd = (PI_UINT32) (command | PI_PCTRL_M_CMD_ERROR); + + /* Issue port command to the adapter */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_A, data_a); + dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_B, data_b); + dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_CTRL, port_cmd); + + /* Now wait for command to complete */ + + if (command == PI_PCTRL_M_BLAST_FLASH) + timeout_cnt = 600000; /* set command timeout count to 60 seconds */ + else + timeout_cnt = 20000; /* set command timeout count to 2 seconds */ + + for (; timeout_cnt > 0; timeout_cnt--) + { + dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_CTRL, &port_cmd); + if (!(port_cmd & PI_PCTRL_M_CMD_ERROR)) + break; + udelay(100); /* wait for 100 microseconds */ + } + if (timeout_cnt == 0) + return(DFX_K_HW_TIMEOUT); + + /* + * If the address of host_data is non-zero, assume caller has supplied a + * non NULL pointer, and return the contents of the HOST_DATA register in + * it. + */ + + if (host_data != NULL) + dfx_port_read_long(bp, PI_PDQ_K_REG_HOST_DATA, host_data); + return(DFX_K_SUCCESS); + } + + +/* + * ===================== + * = dfx_hw_adap_reset = + * ===================== + * + * Overview: + * Resets adapter + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * type - type of reset to perform + * + * Functional Description: + * Issue soft reset to adapter by writing to PDQ Port Reset + * register. Use incoming reset type to tell adapter what + * kind of reset operation to perform. + * + * Return Codes: + * None + * + * Assumptions: + * This routine merely issues a soft reset to the adapter. + * It is expected that after this routine returns, the caller + * will appropriately poll the Port Status register for the + * adapter to enter the proper state. + * + * Side Effects: + * Internal adapter registers are cleared. + */ + +void dfx_hw_adap_reset( + DFX_board_t *bp, + PI_UINT32 type + ) + + { + /* Set Reset type and assert reset */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_A, type); /* tell adapter type of reset */ + dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, PI_RESET_M_ASSERT_RESET); + + /* Wait for at least 1 Microsecond according to the spec. We wait 20 just to be safe */ + + udelay(20); + + /* Deassert reset */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, 0); + return; + } + + +/* + * ======================== + * = dfx_hw_adap_state_rd = + * ======================== + * + * Overview: + * Returns current adapter state + * + * Returns: + * Adapter state per PDQ Port Specification + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Reads PDQ Port Status register and returns adapter state. + * + * Return Codes: + * None + * + * Assumptions: + * None + * + * Side Effects: + * None + */ + +int dfx_hw_adap_state_rd( + DFX_board_t *bp + ) + + { + PI_UINT32 port_status; /* Port Status register value */ + + dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status); + return((port_status & PI_PSTATUS_M_STATE) >> PI_PSTATUS_V_STATE); + } + + +/* + * ===================== + * = dfx_hw_dma_uninit = + * ===================== + * + * Overview: + * Brings adapter to DMA_UNAVAILABLE state + * + * Returns: + * Condition code + * + * Arguments: + * bp - pointer to board information + * type - type of reset to perform + * + * Functional Description: + * Bring adapter to DMA_UNAVAILABLE state by performing the following: + * 1. Set reset type bit in Port Data A Register then reset adapter. + * 2. Check that adapter is in DMA_UNAVAILABLE state. + * + * Return Codes: + * DFX_K_SUCCESS - adapter is in DMA_UNAVAILABLE state + * DFX_K_HW_TIMEOUT - adapter did not reset properly + * + * Assumptions: + * None + * + * Side Effects: + * Internal adapter registers are cleared. + */ + +int dfx_hw_dma_uninit( + DFX_board_t *bp, + PI_UINT32 type + ) + + { + int timeout_cnt; /* used in for loops */ + + /* Set reset type bit and reset adapter */ + + dfx_hw_adap_reset(bp, type); + + /* Now wait for adapter to enter DMA_UNAVAILABLE state */ + + for (timeout_cnt = 100000; timeout_cnt > 0; timeout_cnt--) + { + if (dfx_hw_adap_state_rd(bp) == PI_STATE_K_DMA_UNAVAIL) + break; + udelay(100); /* wait for 100 microseconds */ + } + if (timeout_cnt == 0) + return(DFX_K_HW_TIMEOUT); + return(DFX_K_SUCCESS); + } + + +/* + * ================ + * = dfx_rcv_init = + * ================ + * + * Overview: + * Produces buffers to adapter LLC Host receive descriptor block + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * This routine can be called during dfx_adap_init() or during an adapter + * reset. It initializes the descriptor block and produces all allocated + * LLC Host queue receive buffers. + * + * Return Codes: + * None + * + * Assumptions: + * The PDQ has been reset and the adapter and driver maintained Type 2 + * register indices are cleared. + * + * Side Effects: + * Receive buffers are posted to the adapter LLC queue and the adapter + * is notified. + */ + +void dfx_rcv_init( + DFX_board_t *bp + ) + + { + int i, j; /* used in for loop */ + + /* + * Since each receive buffer is a single fragment of same length, initialize + * first longword in each receive descriptor for entire LLC Host descriptor + * block. Also initialize second longword in each receive descriptor with + * physical address of receive buffer. We'll always allocate receive + * buffers in powers of 2 so that we can easily fill the 256 entry descriptor + * block and produce new receive buffers by simply updating the receive + * producer index. + * + * Assumptions: + * To support all shipping versions of PDQ, the receive buffer size + * must be mod 128 in length and the physical address must be 128 byte + * aligned. In other words, bits 0-6 of the length and address must + * be zero for the following descriptor field entries to be correct on + * all PDQ-based boards. We guaranteed both requirements during + * driver initialization when we allocated memory for the receive buffers. + */ + + for (i=0; i < (int)(bp->rcv_bufs_to_post); i++) + for (j=0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) + { + bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP | + ((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); + bp->descr_block_virt->rcv_data[i+j].long_1 = (u32) (bp->rcv_block_phys + (i * PI_RCV_DATA_K_SIZE_MAX)); + bp->p_rcv_buff_va[i+j] = (char *) (bp->rcv_block_virt + (i * PI_RCV_DATA_K_SIZE_MAX)); + } + + /* Update receive producer and Type 2 register */ + + bp->rcv_xmt_reg.index.rcv_prod = bp->rcv_bufs_to_post; + dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); + return; + } + + +/* + * ========================= + * = dfx_rcv_queue_process = + * ========================= + * + * Overview: + * Process received LLC frames. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Received LLC frames are processed until there are no more consumed frames. + * Once all frames are processed, the receive buffers are returned to the + * adapter. Note that this algorithm fixes the length of time that can be spent + * in this routine, because there are a fixed number of receive buffers to + * process and buffers are not produced until this routine exits and returns + * to the ISR. + * + * Return Codes: + * None + * + * Assumptions: + * None + * + * Side Effects: + * None + */ + +void dfx_rcv_queue_process( + DFX_board_t *bp + ) + + { + PI_TYPE_2_CONSUMER *p_type_2_cons; /* ptr to rcv/xmt consumer block register */ + char *p_buff; /* ptr to start of packet receive buffer (FMC descriptor) */ + u32 descr, pkt_len; /* FMC descriptor field and packet length */ + struct sk_buff *skb; /* pointer to a sk_buff to hold incoming packet data */ + + /* Service all consumed LLC receive frames */ + + p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data); + while (bp->rcv_xmt_reg.index.rcv_comp != p_type_2_cons->index.rcv_cons) + { + /* Process any errors */ + + p_buff = (char *) bp->p_rcv_buff_va[bp->rcv_xmt_reg.index.rcv_comp]; + memcpy(&descr, p_buff + RCV_BUFF_K_DESCR, sizeof(u32)); + + if (descr & PI_FMC_DESCR_M_RCC_FLUSH) + { + if (descr & PI_FMC_DESCR_M_RCC_CRC) + bp->rcv_crc_errors++; + else + bp->rcv_frame_status_errors++; + } + else + { + /* The frame was received without errors - verify packet length */ + + pkt_len = (u32)((descr & PI_FMC_DESCR_M_LEN) >> PI_FMC_DESCR_V_LEN); + pkt_len -= 4; /* subtract 4 byte CRC */ + if (!IN_RANGE(pkt_len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN)) + bp->rcv_length_errors++; + else + { + skb = dev_alloc_skb(pkt_len+3); /* alloc new buffer to pass up, add room for PRH */ + if (skb == NULL) + { + printk("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); + bp->rcv_discards++; + } + else + { + /* Receive buffer allocated, pass receive packet up */ + + memcpy(skb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3); + skb->data += 3; /* adjust data field so that it points to FC byte */ + skb->len = pkt_len; /* pass up packet length, NOT including CRC */ + skb->dev = bp->dev; /* pass up device pointer */ + skb->protocol = fddi_type_trans(skb, bp->dev); + netif_rx(skb); + + /* Update the rcv counters */ + + bp->rcv_total_frames++; + if (*(p_buff + RCV_BUFF_K_DA) & 0x01) + bp->rcv_multicast_frames++; + } + } + } + + /* + * Advance the producer (for recycling) and advance the completion + * (for servicing received frames). Note that it is okay to + * advance the producer without checking that it passes the + * completion index because they are both advanced at the same + * rate. + */ + + bp->rcv_xmt_reg.index.rcv_prod += 1; + bp->rcv_xmt_reg.index.rcv_comp += 1; + } + return; + } + + +/* + * ===================== + * = dfx_xmt_queue_pkt = + * ===================== + * + * Overview: + * Queues packets for transmission + * + * Returns: + * Condition code + * + * Arguments: + * skb - pointer to sk_buff to queue for transmission + * dev - pointer to device information + * + * Functional Description: + * Here we assume that an incoming skb transmit request + * is contained in a single physically contiguous buffer + * in which the virtual address of the start of packet + * (skb->data) can be converted to a physical address + * by using virt_to_bus(). + * + * Since the adapter architecture requires a three byte + * packet request header to prepend the start of packet, + * we'll write the three byte field immediately prior to + * the FC byte. This assumption is valid because we've + * ensured that dev->hard_header_len includes three pad + * bytes. By posting a single fragment to the adapter, + * we'll reduce the number of descriptor fetches and + * bus traffic needed to send the request. + * + * Also, we can't free the skb until after it's been DMA'd + * out by the adapter, so we'll queue it in the driver and + * return it in dfx_xmt_done. + * + * Return Codes: + * 0 - driver queued packet, link is unavailable, or skbuff was bad + * 1 - caller should requeue the sk_buff for later transmission + * + * Assumptions: + * First and foremost, we assume the incoming skb pointer + * is NOT NULL and is pointing to a valid sk_buff structure. + * + * The outgoing packet is complete, starting with the + * frame control byte including the last byte of data, + * but NOT including the 4 byte CRC. We'll let the + * adapter hardware generate and append the CRC. + * + * The entire packet is stored in one physically + * contiguous buffer which is not cached and whose + * 32-bit physical address can be determined. + * + * It's vital that this routine is NOT reentered for the + * same board and that the OS is not in another section of + * code (eg. dfx_int_common) for the same board on a + * different thread. + * + * Side Effects: + * None + */ + +int dfx_xmt_queue_pkt( + struct sk_buff *skb, + struct device *dev + ) + + { + DFX_board_t *bp = (DFX_board_t *) dev->priv; + u8 prod; /* local transmit producer index */ + PI_XMT_DESCR *p_xmt_descr; /* ptr to transmit descriptor block entry */ + XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ + + /* + * Verify that incoming transmit request is OK + * + * Note: The packet size check is consistent with other + * Linux device drivers, although the correct packet + * size should be verified before calling the + * transmit routine. + */ + + if (!IN_RANGE(skb->len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN)) + { + printk("%s: Invalid packet length - %lu bytes\n", dev->name, skb->len); + bp->xmt_length_errors++; /* bump error counter */ + dev_tint(dev); /* dequeue packets from xmt queue and send them */ + return(0); /* return "success" */ + } + + /* + * See if adapter link is available, if not, free buffer + * + * Note: If the link isn't available, free buffer and return 0 + * rather than tell the upper layer to requeue the packet. + * The methodology here is that by the time the link + * becomes available, the packet to be sent will be + * fairly stale. By simply dropping the packet, the + * higher layer protocols will eventually time out + * waiting for response packets which it won't receive. + */ + + if (bp->link_available == PI_K_FALSE) + { + if (dfx_hw_adap_state_rd(bp) == PI_STATE_K_LINK_AVAIL) /* is link really available? */ + bp->link_available = PI_K_TRUE; /* if so, set flag and continue */ + else + { + bp->xmt_discards++; /* bump error counter */ + dev_kfree_skb(skb, FREE_WRITE); /* free sk_buff now */ + return(0); /* return "success" */ + } + } + + /* Get the current producer and the next free xmt data descriptor */ + + prod = bp->rcv_xmt_reg.index.xmt_prod; + p_xmt_descr = &(bp->descr_block_virt->xmt_data[prod]); + + /* + * Get pointer to auxiliary queue entry to contain information for this packet. + * + * Note: The current xmt producer index will become the current xmt completion + * index when we complete this packet later on. So, we'll get the + * pointer to the next auxiliary queue entry now before we bump the + * producer index. + */ + + p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[prod++]); /* also bump producer index */ + + /* Write the three PRH bytes immediately before the FC byte */ + + *((char *)skb->data - 3) = DFX_PRH0_BYTE; /* these byte values are defined */ + *((char *)skb->data - 2) = DFX_PRH1_BYTE; /* in the Motorola FDDI MAC chip */ + *((char *)skb->data - 1) = DFX_PRH2_BYTE; /* specification */ + + /* + * Write the descriptor with buffer info and bump producer + * + * Note: Since we need to start DMA from the packet request + * header, we'll add 3 bytes to the DMA buffer length, + * and we'll determine the physical address of the + * buffer from the PRH, not skb->data. + * + * Assumptions: + * 1. Packet starts with the frame control (FC) byte + * at skb->data. + * 2. The 4-byte CRC is not appended to the buffer or + * included in the length. + * 3. Packet length (skb->len) is from FC to end of + * data, inclusive. + * 4. The packet length does not exceed the maximum + * FDDI LLC frame length of 4491 bytes. + * 5. The entire packet is contained in a physically + * contiguous, non-cached, locked memory space + * comprised of a single buffer pointed to by + * skb->data. + * 6. The physical address of the start of packet + * can be determined from the virtual address + * by using virt_to_bus() and is only 32-bits + * wide. + */ + + p_xmt_descr->long_0 = (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | ((skb->len + 3) << PI_XMT_DESCR_V_SEG_LEN)); + p_xmt_descr->long_1 = (u32) virt_to_bus(skb->data - 3); + + /* + * Verify that descriptor is actually available + * + * Note: If descriptor isn't available, return 1 which tells + * the upper layer to requeue the packet for later + * transmission. + * + * We need to ensure that the producer never reaches the + * completion, except to indicate that the queue is empty. + */ + + if (prod == bp->rcv_xmt_reg.index.xmt_comp) + return(1); /* requeue packet for later */ + + /* + * Save info for this packet for xmt done indication routine + * + * Normally, we'd save the producer index in the p_xmt_drv_descr + * structure so that we'd have it handy when we complete this + * packet later (in dfx_xmt_done). However, since the current + * transmit architecture guarantees a single fragment for the + * entire packet, we can simply bump the completion index by + * one (1) for each completed packet. + * + * Note: If this assumption changes and we're presented with + * an inconsistent number of transmit fragments for packet + * data, we'll need to modify this code to save the current + * transmit producer index. + */ + + p_xmt_drv_descr->p_skb = skb; + + /* Update Type 2 register */ + + bp->rcv_xmt_reg.index.xmt_prod = prod; + dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); + return(0); /* packet queued to adapter */ + } + + +/* + * ================ + * = dfx_xmt_done = + * ================ + * + * Overview: + * Processes all frames that have been transmitted. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * For all consumed transmit descriptors that have not + * yet been completed, we'll free the skb we were holding + * onto using dev_kfree_skb and bump the appropriate + * counters. + * + * Return Codes: + * None + * + * Assumptions: + * The Type 2 register is not updated in this routine. It is + * assumed that it will be updated in the ISR when dfx_xmt_done + * returns. + * + * Side Effects: + * None + */ + +void dfx_xmt_done( + DFX_board_t *bp + ) + + { + XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ + PI_TYPE_2_CONSUMER *p_type_2_cons; /* ptr to rcv/xmt consumer block register */ + + /* Service all consumed transmit frames */ + + p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data); + while (bp->rcv_xmt_reg.index.xmt_comp != p_type_2_cons->index.xmt_cons) + { + /* Get pointer to the transmit driver descriptor block information */ + + p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[bp->rcv_xmt_reg.index.xmt_comp]); + + /* Return skb to operating system */ + + dev_kfree_skb(p_xmt_drv_descr->p_skb, FREE_WRITE); + + /* Increment transmit counters */ + + bp->xmt_total_frames++; + + /* + * Move to start of next packet by updating completion index + * + * Here we assume that a transmit packet request is always + * serviced by posting one fragment. We can therefore + * simplify the completion code by incrementing the + * completion index by one. This code will need to be + * modified if this assumption changes. See comments + * in dfx_xmt_queue_pkt for more details. + */ + + bp->rcv_xmt_reg.index.xmt_comp += 1; + } + return; + } + + +/* + * ================= + * = dfx_xmt_flush = + * ================= + * + * Overview: + * Processes all frames whether they've been transmitted + * or not. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * For all produced transmit descriptors that have not + * yet been completed, we'll free the skb we were holding + * onto using dev_kfree_skb and bump the appropriate + * counters. Of course, it's possible that some of + * these transmit requests actually did go out, but we + * won't make that distinction here. Finally, we'll + * update the consumer index to match the producer. + * + * Return Codes: + * None + * + * Assumptions: + * This routine does NOT update the Type 2 register. It + * is assumed that this routine is being called during a + * transmit flush interrupt, or a shutdown or close routine. + * + * Side Effects: + * None + */ + +void dfx_xmt_flush( + DFX_board_t *bp + ) + + { + u32 prod_cons; /* rcv/xmt consumer block longword */ + XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ + + /* Flush all outstanding transmit frames */ + + while (bp->rcv_xmt_reg.index.xmt_comp != bp->rcv_xmt_reg.index.xmt_prod) + { + /* Get pointer to the transmit driver descriptor block information */ + + p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[bp->rcv_xmt_reg.index.xmt_comp]); + + /* Return skb to operating system */ + + dev_kfree_skb(p_xmt_drv_descr->p_skb, FREE_WRITE); + + /* Increment transmit error counter */ + + bp->xmt_discards++; + + /* + * Move to start of next packet by updating completion index + * + * Here we assume that a transmit packet request is always + * serviced by posting one fragment. We can therefore + * simplify the completion code by incrementing the + * completion index by one. This code will need to be + * modified if this assumption changes. See comments + * in dfx_xmt_queue_pkt for more details. + */ + + bp->rcv_xmt_reg.index.xmt_comp += 1; + } + + /* Update the transmit consumer index in the consumer block */ + + prod_cons = (u32)(bp->cons_block_virt->xmt_rcv_data & ~PI_CONS_M_XMT_INDEX); + prod_cons |= (u32)(bp->rcv_xmt_reg.index.xmt_prod << PI_CONS_V_XMT_INDEX); + bp->cons_block_virt->xmt_rcv_data = prod_cons; + return; + } + + +/* + * Local variables: + * kernel-compile-command: "gcc -D__KERNEL__ -I/root/linux/include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=586 -c defxx.c" + * End: + */ diff -u --recursive --new-file v2.1.10/linux/drivers/net/defxx.h linux/drivers/net/defxx.h --- v2.1.10/linux/drivers/net/defxx.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/defxx.h Mon Nov 18 11:31:31 1996 @@ -0,0 +1,1780 @@ +/* + * File Name: + * defxx.h + * + * Copyright Information: + * Copyright Digital Equipment Corporation 1996. + * + * This software may be used and distributed according to the terms of + * the GNU Public License, incorporated herein by reference. + * + * Abstract: + * Contains all definitions specified by port specification and required + * by the defxx.c driver. + * + * Maintainers: + * LVS Lawrence V. Stefani + * + * Contact: + * The author may be reached at: + * + * Inet: stefani@lkg.dec.com + * Mail: Digital Equipment Corporation + * 550 King Street + * M/S: LKG1-3/M07 + * Littleton, MA 01460 + * + * Modification History: + * Date Name Description + * 16-Aug-96 LVS Created. + * 09-Sep-96 LVS Added group_prom field. Moved read/write I/O + * macros to DEFXX.C. + * 12-Sep-96 LVS Removed packet request header pointers. + */ + +#ifndef _DEFXX_H_ +#define _DEFXX_H_ + +/* Define basic types for unsigned chars, shorts, longs */ + +typedef u8 PI_UINT8; +typedef u16 PI_UINT16; +typedef u32 PI_UINT32; + +/* Define general structures */ + +typedef struct /* 64-bit counter */ + { + PI_UINT32 ms; + PI_UINT32 ls; + } PI_CNTR; + +typedef struct /* LAN address */ + { + PI_UINT32 lwrd_0; + PI_UINT32 lwrd_1; + } PI_LAN_ADDR; + +typedef struct /* Station ID address */ + { + PI_UINT32 octet_7_4; + PI_UINT32 octet_3_0; + } PI_STATION_ID; + + +/* Define general constants */ + +#define PI_ALIGN_K_DESC_BLK 8192 /* Descriptor block boundary */ +#define PI_ALIGN_K_CONS_BLK 64 /* Consumer block boundary */ +#define PI_ALIGN_K_CMD_REQ_BUFF 128 /* Xmt Command que buffer alignment */ +#define PI_ALIGN_K_CMD_RSP_BUFF 128 /* Rcv Command que buffer alignment */ +#define PI_ALIGN_K_UNSOL_BUFF 128 /* Unsol que buffer alignment */ +#define PI_ALIGN_K_XMT_DATA_BUFF 0 /* Xmt data que buffer alignment */ +#define PI_ALIGN_K_RCV_DATA_BUFF 128 /* Rcv que buffer alignment */ + +/* Define PHY index values */ + +#define PI_PHY_K_S 0 /* Index to S phy */ +#define PI_PHY_K_A 0 /* Index to A phy */ +#define PI_PHY_K_B 1 /* Index to B phy */ +#define PI_PHY_K_MAX 2 /* Max number of phys */ + +/* Define FMC descriptor fields */ + +#define PI_FMC_DESCR_V_SOP 31 +#define PI_FMC_DESCR_V_EOP 30 +#define PI_FMC_DESCR_V_FSC 27 +#define PI_FMC_DESCR_V_FSB_ERROR 26 +#define PI_FMC_DESCR_V_FSB_ADDR_RECOG 25 +#define PI_FMC_DESCR_V_FSB_ADDR_COPIED 24 +#define PI_FMC_DESCR_V_FSB 22 +#define PI_FMC_DESCR_V_RCC_FLUSH 21 +#define PI_FMC_DESCR_V_RCC_CRC 20 +#define PI_FMC_DESCR_V_RCC_RRR 17 +#define PI_FMC_DESCR_V_RCC_DD 15 +#define PI_FMC_DESCR_V_RCC_SS 13 +#define PI_FMC_DESCR_V_RCC 13 +#define PI_FMC_DESCR_V_LEN 0 + +#define PI_FMC_DESCR_M_SOP 0x80000000 +#define PI_FMC_DESCR_M_EOP 0x40000000 +#define PI_FMC_DESCR_M_FSC 0x38000000 +#define PI_FMC_DESCR_M_FSB_ERROR 0x04000000 +#define PI_FMC_DESCR_M_FSB_ADDR_RECOG 0x02000000 +#define PI_FMC_DESCR_M_FSB_ADDR_COPIED 0x01000000 +#define PI_FMC_DESCR_M_FSB 0x07C00000 +#define PI_FMC_DESCR_M_RCC_FLUSH 0x00200000 +#define PI_FMC_DESCR_M_RCC_CRC 0x00100000 +#define PI_FMC_DESCR_M_RCC_RRR 0x000E0000 +#define PI_FMC_DESCR_M_RCC_DD 0x00018000 +#define PI_FMC_DESCR_M_RCC_SS 0x00006000 +#define PI_FMC_DESCR_M_RCC 0x003FE000 +#define PI_FMC_DESCR_M_LEN 0x00001FFF + +#define PI_FMC_DESCR_K_RCC_FMC_INT_ERR 0x01AA + +#define PI_FMC_DESCR_K_RRR_SUCCESS 0x00 +#define PI_FMC_DESCR_K_RRR_SA_MATCH 0x01 +#define PI_FMC_DESCR_K_RRR_DA_MATCH 0x02 +#define PI_FMC_DESCR_K_RRR_FMC_ABORT 0x03 +#define PI_FMC_DESCR_K_RRR_LENGTH_BAD 0x04 +#define PI_FMC_DESCR_K_RRR_FRAGMENT 0x05 +#define PI_FMC_DESCR_K_RRR_FORMAT_ERR 0x06 +#define PI_FMC_DESCR_K_RRR_MAC_RESET 0x07 + +#define PI_FMC_DESCR_K_DD_NO_MATCH 0x0 +#define PI_FMC_DESCR_K_DD_PROMISCUOUS 0x1 +#define PI_FMC_DESCR_K_DD_CAM_MATCH 0x2 +#define PI_FMC_DESCR_K_DD_LOCAL_MATCH 0x3 + +#define PI_FMC_DESCR_K_SS_NO_MATCH 0x0 +#define PI_FMC_DESCR_K_SS_BRIDGE_MATCH 0x1 +#define PI_FMC_DESCR_K_SS_NOT_POSSIBLE 0x2 +#define PI_FMC_DESCR_K_SS_LOCAL_MATCH 0x3 + +/* Define some max buffer sizes */ + +#define PI_CMD_REQ_K_SIZE_MAX 512 +#define PI_CMD_RSP_K_SIZE_MAX 512 +#define PI_UNSOL_K_SIZE_MAX 512 +#define PI_SMT_HOST_K_SIZE_MAX 4608 /* 4 1/2 K */ +#define PI_RCV_DATA_K_SIZE_MAX 4608 /* 4 1/2 K */ +#define PI_XMT_DATA_K_SIZE_MAX 4608 /* 4 1/2 K */ + +/* Define adapter states */ + +#define PI_STATE_K_RESET 0 +#define PI_STATE_K_UPGRADE 1 +#define PI_STATE_K_DMA_UNAVAIL 2 +#define PI_STATE_K_DMA_AVAIL 3 +#define PI_STATE_K_LINK_AVAIL 4 +#define PI_STATE_K_LINK_UNAVAIL 5 +#define PI_STATE_K_HALTED 6 +#define PI_STATE_K_RING_MEMBER 7 +#define PI_STATE_K_NUMBER 8 + +/* Define codes for command type */ + +#define PI_CMD_K_START 0x00 +#define PI_CMD_K_FILTERS_SET 0x01 +#define PI_CMD_K_FILTERS_GET 0x02 +#define PI_CMD_K_CHARS_SET 0x03 +#define PI_CMD_K_STATUS_CHARS_GET 0x04 +#define PI_CMD_K_CNTRS_GET 0x05 +#define PI_CMD_K_CNTRS_SET 0x06 +#define PI_CMD_K_ADDR_FILTER_SET 0x07 +#define PI_CMD_K_ADDR_FILTER_GET 0x08 +#define PI_CMD_K_ERROR_LOG_CLEAR 0x09 +#define PI_CMD_K_ERROR_LOG_GET 0x0A +#define PI_CMD_K_FDDI_MIB_GET 0x0B +#define PI_CMD_K_DEC_EXT_MIB_GET 0x0C +#define PI_CMD_K_DEVICE_SPECIFIC_GET 0x0D +#define PI_CMD_K_SNMP_SET 0x0E +#define PI_CMD_K_UNSOL_TEST 0x0F +#define PI_CMD_K_SMT_MIB_GET 0x10 +#define PI_CMD_K_SMT_MIB_SET 0x11 +#define PI_CMD_K_MAX 0x11 /* Must match last */ + +/* Define item codes for Chars_Set and Filters_Set commands */ + +#define PI_ITEM_K_EOL 0x00 /* End-of-Item list */ +#define PI_ITEM_K_T_REQ 0x01 /* DECnet T_REQ */ +#define PI_ITEM_K_TVX 0x02 /* DECnet TVX */ +#define PI_ITEM_K_RESTRICTED_TOKEN 0x03 /* DECnet Restricted Token */ +#define PI_ITEM_K_LEM_THRESHOLD 0x04 /* DECnet LEM Threshold */ +#define PI_ITEM_K_RING_PURGER 0x05 /* DECnet Ring Purger Enable */ +#define PI_ITEM_K_CNTR_INTERVAL 0x06 /* Chars_Set */ +#define PI_ITEM_K_IND_GROUP_PROM 0x07 /* Filters_Set */ +#define PI_ITEM_K_GROUP_PROM 0x08 /* Filters_Set */ +#define PI_ITEM_K_BROADCAST 0x09 /* Filters_Set */ +#define PI_ITEM_K_SMT_PROM 0x0A /* Filters_Set */ +#define PI_ITEM_K_SMT_USER 0x0B /* Filters_Set */ +#define PI_ITEM_K_RESERVED 0x0C /* Filters_Set */ +#define PI_ITEM_K_IMPLEMENTOR 0x0D /* Filters_Set */ +#define PI_ITEM_K_LOOPBACK_MODE 0x0E /* Chars_Set */ +#define PI_ITEM_K_CONFIG_POLICY 0x10 /* SMTConfigPolicy */ +#define PI_ITEM_K_CON_POLICY 0x11 /* SMTConnectionPolicy */ +#define PI_ITEM_K_T_NOTIFY 0x12 /* SMTTNotify */ +#define PI_ITEM_K_STATION_ACTION 0x13 /* SMTStationAction */ +#define PI_ITEM_K_MAC_PATHS_REQ 0x15 /* MACPathsRequested */ +#define PI_ITEM_K_MAC_ACTION 0x17 /* MACAction */ +#define PI_ITEM_K_CON_POLICIES 0x18 /* PORTConnectionPolicies */ +#define PI_ITEM_K_PORT_PATHS_REQ 0x19 /* PORTPathsRequested */ +#define PI_ITEM_K_MAC_LOOP_TIME 0x1A /* PORTMACLoopTime */ +#define PI_ITEM_K_TB_MAX 0x1B /* PORTTBMax */ +#define PI_ITEM_K_LER_CUTOFF 0x1C /* PORTLerCutoff */ +#define PI_ITEM_K_LER_ALARM 0x1D /* PORTLerAlarm */ +#define PI_ITEM_K_PORT_ACTION 0x1E /* PORTAction */ +#define PI_ITEM_K_FLUSH_TIME 0x20 /* Chars_Set */ +#define PI_ITEM_K_MAC_T_REQ 0x29 /* MACTReq */ +#define PI_ITEM_K_EMAC_RING_PURGER 0x2A /* eMACRingPurgerEnable */ +#define PI_ITEM_K_EMAC_RTOKEN_TIMEOUT 0x2B /* eMACRestrictedTokenTimeout */ +#define PI_ITEM_K_FDX_ENB_DIS 0x2C /* eFDXEnable */ +#define PI_ITEM_K_MAX 0x2C /* Must equal high item */ + +/* Values for some of the items */ + +#define PI_K_FALSE 0 /* Generic false */ +#define PI_K_TRUE 1 /* Generic true */ + +#define PI_SNMP_K_TRUE 1 /* SNMP true/false values */ +#define PI_SNMP_K_FALSE 2 + +#define PI_FSTATE_K_BLOCK 0 /* Filter State */ +#define PI_FSTATE_K_PASS 1 + +/* Define command return codes */ + +#define PI_RSP_K_SUCCESS 0x00 +#define PI_RSP_K_FAILURE 0x01 +#define PI_RSP_K_WARNING 0x02 +#define PI_RSP_K_LOOP_MODE_BAD 0x03 +#define PI_RSP_K_ITEM_CODE_BAD 0x04 +#define PI_RSP_K_TVX_BAD 0x05 +#define PI_RSP_K_TREQ_BAD 0x06 +#define PI_RSP_K_TOKEN_BAD 0x07 +#define PI_RSP_K_NO_EOL 0x0C +#define PI_RSP_K_FILTER_STATE_BAD 0x0D +#define PI_RSP_K_CMD_TYPE_BAD 0x0E +#define PI_RSP_K_ADAPTER_STATE_BAD 0x0F +#define PI_RSP_K_RING_PURGER_BAD 0x10 +#define PI_RSP_K_LEM_THRESHOLD_BAD 0x11 +#define PI_RSP_K_LOOP_NOT_SUPPORTED 0x12 +#define PI_RSP_K_FLUSH_TIME_BAD 0x13 +#define PI_RSP_K_NOT_IMPLEMENTED 0x14 +#define PI_RSP_K_CONFIG_POLICY_BAD 0x15 +#define PI_RSP_K_STATION_ACTION_BAD 0x16 +#define PI_RSP_K_MAC_ACTION_BAD 0x17 +#define PI_RSP_K_CON_POLICIES_BAD 0x18 +#define PI_RSP_K_MAC_LOOP_TIME_BAD 0x19 +#define PI_RSP_K_TB_MAX_BAD 0x1A +#define PI_RSP_K_LER_CUTOFF_BAD 0x1B +#define PI_RSP_K_LER_ALARM_BAD 0x1C +#define PI_RSP_K_MAC_PATHS_REQ_BAD 0x1D +#define PI_RSP_K_MAC_T_REQ_BAD 0x1E +#define PI_RSP_K_EMAC_RING_PURGER_BAD 0x1F +#define PI_RSP_K_EMAC_RTOKEN_TIME_BAD 0x20 +#define PI_RSP_K_NO_SUCH_ENTRY 0x21 +#define PI_RSP_K_T_NOTIFY_BAD 0x22 +#define PI_RSP_K_TR_MAX_EXP_BAD 0x23 +#define PI_RSP_K_MAC_FRM_ERR_THR_BAD 0x24 +#define PI_RSP_K_MAX_T_REQ_BAD 0x25 +#define PI_RSP_K_FDX_ENB_DIS_BAD 0x26 +#define PI_RSP_K_ITEM_INDEX_BAD 0x27 +#define PI_RSP_K_PORT_ACTION_BAD 0x28 + +/* Commonly used structures */ + +typedef struct /* Item list */ + { + PI_UINT32 item_code; + PI_UINT32 value; + } PI_ITEM_LIST; + +typedef struct /* Response header */ + { + PI_UINT32 reserved; + PI_UINT32 cmd_type; + PI_UINT32 status; + } PI_RSP_HEADER; + + +/* Start Command */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_START_REQ; + +/* Start Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_START_RSP; + +/* Filters_Set Request */ + +#define PI_CMD_FILTERS_SET_K_ITEMS_MAX 63 /* Fits in a 512 byte buffer */ + +typedef struct + { + PI_UINT32 cmd_type; + PI_ITEM_LIST item[PI_CMD_FILTERS_SET_K_ITEMS_MAX]; + } PI_CMD_FILTERS_SET_REQ; + +/* Filters_Set Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_FILTERS_SET_RSP; + +/* Filters_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_FILTERS_GET_REQ; + +/* Filters_Get Response */ + +typedef struct + { + PI_RSP_HEADER header; + PI_UINT32 ind_group_prom; + PI_UINT32 group_prom; + PI_UINT32 broadcast_all; + PI_UINT32 smt_all; + PI_UINT32 smt_user; + PI_UINT32 reserved_all; + PI_UINT32 implementor_all; + } PI_CMD_FILTERS_GET_RSP; + + +/* Chars_Set Request */ + +#define PI_CMD_CHARS_SET_K_ITEMS_MAX 42 /* Fits in a 512 byte buffer */ + +typedef struct + { + PI_UINT32 cmd_type; + struct /* Item list */ + { + PI_UINT32 item_code; + PI_UINT32 value; + PI_UINT32 item_index; + } item[PI_CMD_CHARS_SET_K_ITEMS_MAX]; + } PI_CMD_CHARS_SET_REQ; + +/* Chars_Set Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_CHARS_SET_RSP; + + +/* SNMP_Set Request */ + +#define PI_CMD_SNMP_SET_K_ITEMS_MAX 42 /* Fits in a 512 byte buffer */ + +typedef struct + { + PI_UINT32 cmd_type; + struct /* Item list */ + { + PI_UINT32 item_code; + PI_UINT32 value; + PI_UINT32 item_index; + } item[PI_CMD_SNMP_SET_K_ITEMS_MAX]; + } PI_CMD_SNMP_SET_REQ; + +/* SNMP_Set Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_SNMP_SET_RSP; + + +/* SMT_MIB_Set Request */ + +#define PI_CMD_SMT_MIB_SET_K_ITEMS_MAX 42 /* Max number of items */ + +typedef struct + { + PI_UINT32 cmd_type; + struct + { + PI_UINT32 item_code; + PI_UINT32 value; + PI_UINT32 item_index; + } item[PI_CMD_SMT_MIB_SET_K_ITEMS_MAX]; + } PI_CMD_SMT_MIB_SET_REQ; + +/* SMT_MIB_Set Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_SMT_MIB_SET_RSP; + +/* SMT_MIB_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_SMT_MIB_GET_REQ; + +/* SMT_MIB_Get Response */ + +typedef struct /* Refer to ANSI FDDI SMT Rev. 7.3 */ + { + PI_RSP_HEADER header; + + /* SMT GROUP */ + + PI_STATION_ID smt_station_id; + PI_UINT32 smt_op_version_id; + PI_UINT32 smt_hi_version_id; + PI_UINT32 smt_lo_version_id; + PI_UINT32 smt_user_data[8]; + PI_UINT32 smt_mib_version_id; + PI_UINT32 smt_mac_ct; + PI_UINT32 smt_non_master_ct; + PI_UINT32 smt_master_ct; + PI_UINT32 smt_available_paths; + PI_UINT32 smt_config_capabilities; + PI_UINT32 smt_config_policy; + PI_UINT32 smt_connection_policy; + PI_UINT32 smt_t_notify; + PI_UINT32 smt_stat_rpt_policy; + PI_UINT32 smt_trace_max_expiration; + PI_UINT32 smt_bypass_present; + PI_UINT32 smt_ecm_state; + PI_UINT32 smt_cf_state; + PI_UINT32 smt_remote_disconnect_flag; + PI_UINT32 smt_station_status; + PI_UINT32 smt_peer_wrap_flag; + PI_CNTR smt_msg_time_stamp; + PI_CNTR smt_transition_time_stamp; + + /* MAC GROUP */ + + PI_UINT32 mac_frame_status_functions; + PI_UINT32 mac_t_max_capability; + PI_UINT32 mac_tvx_capability; + PI_UINT32 mac_available_paths; + PI_UINT32 mac_current_path; + PI_LAN_ADDR mac_upstream_nbr; + PI_LAN_ADDR mac_downstream_nbr; + PI_LAN_ADDR mac_old_upstream_nbr; + PI_LAN_ADDR mac_old_downstream_nbr; + PI_UINT32 mac_dup_address_test; + PI_UINT32 mac_requested_paths; + PI_UINT32 mac_downstream_port_type; + PI_LAN_ADDR mac_smt_address; + PI_UINT32 mac_t_req; + PI_UINT32 mac_t_neg; + PI_UINT32 mac_t_max; + PI_UINT32 mac_tvx_value; + PI_UINT32 mac_frame_error_threshold; + PI_UINT32 mac_frame_error_ratio; + PI_UINT32 mac_rmt_state; + PI_UINT32 mac_da_flag; + PI_UINT32 mac_unda_flag; + PI_UINT32 mac_frame_error_flag; + PI_UINT32 mac_ma_unitdata_available; + PI_UINT32 mac_hardware_present; + PI_UINT32 mac_ma_unitdata_enable; + + /* PATH GROUP */ + + PI_UINT32 path_configuration[8]; + PI_UINT32 path_tvx_lower_bound; + PI_UINT32 path_t_max_lower_bound; + PI_UINT32 path_max_t_req; + + /* PORT GROUP */ + + PI_UINT32 port_my_type[PI_PHY_K_MAX]; + PI_UINT32 port_neighbor_type[PI_PHY_K_MAX]; + PI_UINT32 port_connection_policies[PI_PHY_K_MAX]; + PI_UINT32 port_mac_indicated[PI_PHY_K_MAX]; + PI_UINT32 port_current_path[PI_PHY_K_MAX]; + PI_UINT32 port_requested_paths[PI_PHY_K_MAX]; + PI_UINT32 port_mac_placement[PI_PHY_K_MAX]; + PI_UINT32 port_available_paths[PI_PHY_K_MAX]; + PI_UINT32 port_pmd_class[PI_PHY_K_MAX]; + PI_UINT32 port_connection_capabilities[PI_PHY_K_MAX]; + PI_UINT32 port_bs_flag[PI_PHY_K_MAX]; + PI_UINT32 port_ler_estimate[PI_PHY_K_MAX]; + PI_UINT32 port_ler_cutoff[PI_PHY_K_MAX]; + PI_UINT32 port_ler_alarm[PI_PHY_K_MAX]; + PI_UINT32 port_connect_state[PI_PHY_K_MAX]; + PI_UINT32 port_pcm_state[PI_PHY_K_MAX]; + PI_UINT32 port_pc_withhold[PI_PHY_K_MAX]; + PI_UINT32 port_ler_flag[PI_PHY_K_MAX]; + PI_UINT32 port_hardware_present[PI_PHY_K_MAX]; + + /* GROUP for things that were added later, so must be at the end. */ + + PI_CNTR path_ring_latency; + + } PI_CMD_SMT_MIB_GET_RSP; + + +/* + * Item and group code definitions for SMT 7.3 mandatory objects. These + * definitions are to be used as appropriate in SMT_MIB_SET commands and + * certain host-sent SMT frames such as PMF Get and Set requests. The + * codes have been taken from the MIB summary section of ANSI SMT 7.3. + */ + +#define PI_GRP_K_SMT_STATION_ID 0x100A +#define PI_ITEM_K_SMT_STATION_ID 0x100B +#define PI_ITEM_K_SMT_OP_VERS_ID 0x100D +#define PI_ITEM_K_SMT_HI_VERS_ID 0x100E +#define PI_ITEM_K_SMT_LO_VERS_ID 0x100F +#define PI_ITEM_K_SMT_USER_DATA 0x1011 +#define PI_ITEM_K_SMT_MIB_VERS_ID 0x1012 + +#define PI_GRP_K_SMT_STATION_CONFIG 0x1014 +#define PI_ITEM_K_SMT_MAC_CT 0x1015 +#define PI_ITEM_K_SMT_NON_MASTER_CT 0x1016 +#define PI_ITEM_K_SMT_MASTER_CT 0x1017 +#define PI_ITEM_K_SMT_AVAIL_PATHS 0x1018 +#define PI_ITEM_K_SMT_CONFIG_CAPS 0x1019 +#define PI_ITEM_K_SMT_CONFIG_POL 0x101A +#define PI_ITEM_K_SMT_CONN_POL 0x101B +#define PI_ITEM_K_SMT_T_NOTIFY 0x101D +#define PI_ITEM_K_SMT_STAT_POL 0x101E +#define PI_ITEM_K_SMT_TR_MAX_EXP 0x101F +#define PI_ITEM_K_SMT_PORT_INDEXES 0x1020 +#define PI_ITEM_K_SMT_MAC_INDEXES 0x1021 +#define PI_ITEM_K_SMT_BYPASS_PRESENT 0x1022 + +#define PI_GRP_K_SMT_STATUS 0x1028 +#define PI_ITEM_K_SMT_ECM_STATE 0x1029 +#define PI_ITEM_K_SMT_CF_STATE 0x102A +#define PI_ITEM_K_SMT_REM_DISC_FLAG 0x102C +#define PI_ITEM_K_SMT_STATION_STATUS 0x102D +#define PI_ITEM_K_SMT_PEER_WRAP_FLAG 0x102E + +#define PI_GRP_K_SMT_MIB_OPERATION 0x1032 +#define PI_ITEM_K_SMT_MSG_TIME_STAMP 0x1033 +#define PI_ITEM_K_SMT_TRN_TIME_STAMP 0x1034 + +#define PI_ITEM_K_SMT_STATION_ACT 0x103C + +#define PI_GRP_K_MAC_CAPABILITIES 0x200A +#define PI_ITEM_K_MAC_FRM_STAT_FUNC 0x200B +#define PI_ITEM_K_MAC_T_MAX_CAP 0x200D +#define PI_ITEM_K_MAC_TVX_CAP 0x200E + +#define PI_GRP_K_MAC_CONFIG 0x2014 +#define PI_ITEM_K_MAC_AVAIL_PATHS 0x2016 +#define PI_ITEM_K_MAC_CURRENT_PATH 0x2017 +#define PI_ITEM_K_MAC_UP_NBR 0x2018 +#define PI_ITEM_K_MAC_DOWN_NBR 0x2019 +#define PI_ITEM_K_MAC_OLD_UP_NBR 0x201A +#define PI_ITEM_K_MAC_OLD_DOWN_NBR 0x201B +#define PI_ITEM_K_MAC_DUP_ADDR_TEST 0x201D +#define PI_ITEM_K_MAC_REQ_PATHS 0x2020 +#define PI_ITEM_K_MAC_DOWN_PORT_TYPE 0x2021 +#define PI_ITEM_K_MAC_INDEX 0x2022 + +#define PI_GRP_K_MAC_ADDRESS 0x2028 +#define PI_ITEM_K_MAC_SMT_ADDRESS 0x2029 + +#define PI_GRP_K_MAC_OPERATION 0x2032 +#define PI_ITEM_K_MAC_TREQ 0x2033 +#define PI_ITEM_K_MAC_TNEG 0x2034 +#define PI_ITEM_K_MAC_TMAX 0x2035 +#define PI_ITEM_K_MAC_TVX_VALUE 0x2036 + +#define PI_GRP_K_MAC_COUNTERS 0x2046 +#define PI_ITEM_K_MAC_FRAME_CT 0x2047 +#define PI_ITEM_K_MAC_COPIED_CT 0x2048 +#define PI_ITEM_K_MAC_TRANSMIT_CT 0x2049 +#define PI_ITEM_K_MAC_ERROR_CT 0x2051 +#define PI_ITEM_K_MAC_LOST_CT 0x2052 + +#define PI_GRP_K_MAC_FRM_ERR_COND 0x205A +#define PI_ITEM_K_MAC_FRM_ERR_THR 0x205F +#define PI_ITEM_K_MAC_FRM_ERR_RAT 0x2060 + +#define PI_GRP_K_MAC_STATUS 0x206E +#define PI_ITEM_K_MAC_RMT_STATE 0x206F +#define PI_ITEM_K_MAC_DA_FLAG 0x2070 +#define PI_ITEM_K_MAC_UNDA_FLAG 0x2071 +#define PI_ITEM_K_MAC_FRM_ERR_FLAG 0x2072 +#define PI_ITEM_K_MAC_MA_UNIT_AVAIL 0x2074 +#define PI_ITEM_K_MAC_HW_PRESENT 0x2075 +#define PI_ITEM_K_MAC_MA_UNIT_ENAB 0x2076 + +#define PI_GRP_K_PATH_CONFIG 0x320A +#define PI_ITEM_K_PATH_INDEX 0x320B +#define PI_ITEM_K_PATH_CONFIGURATION 0x3212 +#define PI_ITEM_K_PATH_TVX_LB 0x3215 +#define PI_ITEM_K_PATH_T_MAX_LB 0x3216 +#define PI_ITEM_K_PATH_MAX_T_REQ 0x3217 + +#define PI_GRP_K_PORT_CONFIG 0x400A +#define PI_ITEM_K_PORT_MY_TYPE 0x400C +#define PI_ITEM_K_PORT_NBR_TYPE 0x400D +#define PI_ITEM_K_PORT_CONN_POLS 0x400E +#define PI_ITEM_K_PORT_MAC_INDICATED 0x400F +#define PI_ITEM_K_PORT_CURRENT_PATH 0x4010 +#define PI_ITEM_K_PORT_REQ_PATHS 0x4011 +#define PI_ITEM_K_PORT_MAC_PLACEMENT 0x4012 +#define PI_ITEM_K_PORT_AVAIL_PATHS 0x4013 +#define PI_ITEM_K_PORT_PMD_CLASS 0x4016 +#define PI_ITEM_K_PORT_CONN_CAPS 0x4017 +#define PI_ITEM_K_PORT_INDEX 0x401D + +#define PI_GRP_K_PORT_OPERATION 0x401E +#define PI_ITEM_K_PORT_BS_FLAG 0x4021 + +#define PI_GRP_K_PORT_ERR_CNTRS 0x4028 +#define PI_ITEM_K_PORT_LCT_FAIL_CT 0x402A + +#define PI_GRP_K_PORT_LER 0x4032 +#define PI_ITEM_K_PORT_LER_ESTIMATE 0x4033 +#define PI_ITEM_K_PORT_LEM_REJ_CT 0x4034 +#define PI_ITEM_K_PORT_LEM_CT 0x4035 +#define PI_ITEM_K_PORT_LER_CUTOFF 0x403A +#define PI_ITEM_K_PORT_LER_ALARM 0x403B + +#define PI_GRP_K_PORT_STATUS 0x403C +#define PI_ITEM_K_PORT_CONNECT_STATE 0x403D +#define PI_ITEM_K_PORT_PCM_STATE 0x403E +#define PI_ITEM_K_PORT_PC_WITHHOLD 0x403F +#define PI_ITEM_K_PORT_LER_FLAG 0x4040 +#define PI_ITEM_K_PORT_HW_PRESENT 0x4041 + +#define PI_ITEM_K_PORT_ACT 0x4046 + +/* Addr_Filter_Set Request */ + +#define PI_CMD_ADDR_FILTER_K_SIZE 62 + +typedef struct + { + PI_UINT32 cmd_type; + PI_LAN_ADDR entry[PI_CMD_ADDR_FILTER_K_SIZE]; + } PI_CMD_ADDR_FILTER_SET_REQ; + +/* Addr_Filter_Set Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_ADDR_FILTER_SET_RSP; + +/* Addr_Filter_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_ADDR_FILTER_GET_REQ; + +/* Addr_Filter_Get Response */ + +typedef struct + { + PI_RSP_HEADER header; + PI_LAN_ADDR entry[PI_CMD_ADDR_FILTER_K_SIZE]; + } PI_CMD_ADDR_FILTER_GET_RSP; + +/* Status_Chars_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_STATUS_CHARS_GET_REQ; + +/* Status_Chars_Get Response */ + +typedef struct + { + PI_RSP_HEADER header; + PI_STATION_ID station_id; /* Station */ + PI_UINT32 station_type; + PI_UINT32 smt_ver_id; + PI_UINT32 smt_ver_id_max; + PI_UINT32 smt_ver_id_min; + PI_UINT32 station_state; + PI_LAN_ADDR link_addr; /* Link */ + PI_UINT32 t_req; + PI_UINT32 tvx; + PI_UINT32 token_timeout; + PI_UINT32 purger_enb; + PI_UINT32 link_state; + PI_UINT32 tneg; + PI_UINT32 dup_addr_flag; + PI_LAN_ADDR una; + PI_LAN_ADDR una_old; + PI_UINT32 un_dup_addr_flag; + PI_LAN_ADDR dna; + PI_LAN_ADDR dna_old; + PI_UINT32 purger_state; + PI_UINT32 fci_mode; + PI_UINT32 error_reason; + PI_UINT32 loopback; + PI_UINT32 ring_latency; + PI_LAN_ADDR last_dir_beacon_sa; + PI_LAN_ADDR last_dir_beacon_una; + PI_UINT32 phy_type[PI_PHY_K_MAX]; /* Phy */ + PI_UINT32 pmd_type[PI_PHY_K_MAX]; + PI_UINT32 lem_threshold[PI_PHY_K_MAX]; + PI_UINT32 phy_state[PI_PHY_K_MAX]; + PI_UINT32 nbor_phy_type[PI_PHY_K_MAX]; + PI_UINT32 link_error_est[PI_PHY_K_MAX]; + PI_UINT32 broken_reason[PI_PHY_K_MAX]; + PI_UINT32 reject_reason[PI_PHY_K_MAX]; + PI_UINT32 cntr_interval; /* Miscellaneous */ + PI_UINT32 module_rev; + PI_UINT32 firmware_rev; + PI_UINT32 mop_device_type; + PI_UINT32 phy_led[PI_PHY_K_MAX]; + PI_UINT32 flush_time; + } PI_CMD_STATUS_CHARS_GET_RSP; + +/* FDDI_MIB_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_FDDI_MIB_GET_REQ; + +/* FDDI_MIB_Get Response */ + +typedef struct + { + PI_RSP_HEADER header; + + /* SMT GROUP */ + + PI_STATION_ID smt_station_id; + PI_UINT32 smt_op_version_id; + PI_UINT32 smt_hi_version_id; + PI_UINT32 smt_lo_version_id; + PI_UINT32 smt_mac_ct; + PI_UINT32 smt_non_master_ct; + PI_UINT32 smt_master_ct; + PI_UINT32 smt_paths_available; + PI_UINT32 smt_config_capabilities; + PI_UINT32 smt_config_policy; + PI_UINT32 smt_connection_policy; + PI_UINT32 smt_t_notify; + PI_UINT32 smt_status_reporting; + PI_UINT32 smt_ecm_state; + PI_UINT32 smt_cf_state; + PI_UINT32 smt_hold_state; + PI_UINT32 smt_remote_disconnect_flag; + PI_UINT32 smt_station_action; + + /* MAC GROUP */ + + PI_UINT32 mac_frame_status_capabilities; + PI_UINT32 mac_t_max_greatest_lower_bound; + PI_UINT32 mac_tvx_greatest_lower_bound; + PI_UINT32 mac_paths_available; + PI_UINT32 mac_current_path; + PI_LAN_ADDR mac_upstream_nbr; + PI_LAN_ADDR mac_old_upstream_nbr; + PI_UINT32 mac_dup_addr_test; + PI_UINT32 mac_paths_requested; + PI_UINT32 mac_downstream_port_type; + PI_LAN_ADDR mac_smt_address; + PI_UINT32 mac_t_req; + PI_UINT32 mac_t_neg; + PI_UINT32 mac_t_max; + PI_UINT32 mac_tvx_value; + PI_UINT32 mac_t_min; + PI_UINT32 mac_current_frame_status; + /* mac_frame_cts */ + /* mac_error_cts */ + /* mac_lost_cts */ + PI_UINT32 mac_frame_error_threshold; + PI_UINT32 mac_frame_error_ratio; + PI_UINT32 mac_rmt_state; + PI_UINT32 mac_da_flag; + PI_UINT32 mac_una_da_flag; + PI_UINT32 mac_frame_condition; + PI_UINT32 mac_chip_set; + PI_UINT32 mac_action; + + /* PATH GROUP => Does not need to be implemented */ + + /* PORT GROUP */ + + PI_UINT32 port_pc_type[PI_PHY_K_MAX]; + PI_UINT32 port_pc_neighbor[PI_PHY_K_MAX]; + PI_UINT32 port_connection_policies[PI_PHY_K_MAX]; + PI_UINT32 port_remote_mac_indicated[PI_PHY_K_MAX]; + PI_UINT32 port_ce_state[PI_PHY_K_MAX]; + PI_UINT32 port_paths_requested[PI_PHY_K_MAX]; + PI_UINT32 port_mac_placement[PI_PHY_K_MAX]; + PI_UINT32 port_available_paths[PI_PHY_K_MAX]; + PI_UINT32 port_mac_loop_time[PI_PHY_K_MAX]; + PI_UINT32 port_tb_max[PI_PHY_K_MAX]; + PI_UINT32 port_bs_flag[PI_PHY_K_MAX]; + /* port_lct_fail_cts[PI_PHY_K_MAX]; */ + PI_UINT32 port_ler_estimate[PI_PHY_K_MAX]; + /* port_lem_reject_cts[PI_PHY_K_MAX]; */ + /* port_lem_cts[PI_PHY_K_MAX]; */ + PI_UINT32 port_ler_cutoff[PI_PHY_K_MAX]; + PI_UINT32 port_ler_alarm[PI_PHY_K_MAX]; + PI_UINT32 port_connect_state[PI_PHY_K_MAX]; + PI_UINT32 port_pcm_state[PI_PHY_K_MAX]; + PI_UINT32 port_pc_withhold[PI_PHY_K_MAX]; + PI_UINT32 port_ler_condition[PI_PHY_K_MAX]; + PI_UINT32 port_chip_set[PI_PHY_K_MAX]; + PI_UINT32 port_action[PI_PHY_K_MAX]; + + /* ATTACHMENT GROUP */ + + PI_UINT32 attachment_class; + PI_UINT32 attachment_ob_present; + PI_UINT32 attachment_imax_expiration; + PI_UINT32 attachment_inserted_status; + PI_UINT32 attachment_insert_policy; + + /* CHIP SET GROUP => Does not need to be implemented */ + + } PI_CMD_FDDI_MIB_GET_RSP; + +/* DEC_Ext_MIB_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_DEC_EXT_MIB_GET_REQ; + +/* DEC_Ext_MIB_Get (efddi and efdx groups only) Response */ + +typedef struct + { + PI_RSP_HEADER header; + + /* SMT GROUP */ + + PI_UINT32 esmt_station_type; + + /* MAC GROUP */ + + PI_UINT32 emac_link_state; + PI_UINT32 emac_ring_purger_state; + PI_UINT32 emac_ring_purger_enable; + PI_UINT32 emac_frame_strip_mode; + PI_UINT32 emac_ring_error_reason; + PI_UINT32 emac_up_nbr_dup_addr_flag; + PI_UINT32 emac_restricted_token_timeout; + + /* PORT GROUP */ + + PI_UINT32 eport_pmd_type[PI_PHY_K_MAX]; + PI_UINT32 eport_phy_state[PI_PHY_K_MAX]; + PI_UINT32 eport_reject_reason[PI_PHY_K_MAX]; + + /* FDX (Full-Duplex) GROUP */ + + PI_UINT32 efdx_enable; /* Valid only in SMT 7.3 */ + PI_UINT32 efdx_op; /* Valid only in SMT 7.3 */ + PI_UINT32 efdx_state; /* Valid only in SMT 7.3 */ + + } PI_CMD_DEC_EXT_MIB_GET_RSP; + +typedef struct + { + PI_CNTR traces_rcvd; /* Station */ + PI_CNTR frame_cnt; /* Link */ + PI_CNTR error_cnt; + PI_CNTR lost_cnt; + PI_CNTR octets_rcvd; + PI_CNTR octets_sent; + PI_CNTR pdus_rcvd; + PI_CNTR pdus_sent; + PI_CNTR mcast_octets_rcvd; + PI_CNTR mcast_octets_sent; + PI_CNTR mcast_pdus_rcvd; + PI_CNTR mcast_pdus_sent; + PI_CNTR xmt_underruns; + PI_CNTR xmt_failures; + PI_CNTR block_check_errors; + PI_CNTR frame_status_errors; + PI_CNTR pdu_length_errors; + PI_CNTR rcv_overruns; + PI_CNTR user_buff_unavailable; + PI_CNTR inits_initiated; + PI_CNTR inits_rcvd; + PI_CNTR beacons_initiated; + PI_CNTR dup_addrs; + PI_CNTR dup_tokens; + PI_CNTR purge_errors; + PI_CNTR fci_strip_errors; + PI_CNTR traces_initiated; + PI_CNTR directed_beacons_rcvd; + PI_CNTR emac_frame_alignment_errors; + PI_CNTR ebuff_errors[PI_PHY_K_MAX]; /* Phy */ + PI_CNTR lct_rejects[PI_PHY_K_MAX]; + PI_CNTR lem_rejects[PI_PHY_K_MAX]; + PI_CNTR link_errors[PI_PHY_K_MAX]; + PI_CNTR connections[PI_PHY_K_MAX]; + PI_CNTR copied_cnt; /* Valid only if using SMT 7.3 */ + PI_CNTR transmit_cnt; /* Valid only if using SMT 7.3 */ + PI_CNTR tokens; + } PI_CNTR_BLK; + +/* Counters_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_CNTRS_GET_REQ; + +/* Counters_Get Response */ + +typedef struct + { + PI_RSP_HEADER header; + PI_CNTR time_since_reset; + PI_CNTR_BLK cntrs; + } PI_CMD_CNTRS_GET_RSP; + +/* Counters_Set Request */ + +typedef struct + { + PI_UINT32 cmd_type; + PI_CNTR_BLK cntrs; + } PI_CMD_CNTRS_SET_REQ; + +/* Counters_Set Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_CNTRS_SET_RSP; + +/* Error_Log_Clear Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_ERROR_LOG_CLEAR_REQ; + +/* Error_Log_Clear Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_ERROR_LOG_CLEAR_RSP; + +/* Error_Log_Get Request */ + +#define PI_LOG_ENTRY_K_INDEX_MIN 0 /* Minimum index for entry */ + +typedef struct + { + PI_UINT32 cmd_type; + PI_UINT32 entry_index; + } PI_CMD_ERROR_LOG_GET_REQ; + +/* Error_Log_Get Response */ + +#define PI_K_LOG_FW_SIZE 111 /* Max number of fw longwords */ +#define PI_K_LOG_DIAG_SIZE 6 /* Max number of diag longwords */ + +typedef struct + { + struct + { + PI_UINT32 fru_imp_mask; + PI_UINT32 test_id; + PI_UINT32 reserved[PI_K_LOG_DIAG_SIZE]; + } diag; + PI_UINT32 fw[PI_K_LOG_FW_SIZE]; + } PI_LOG_ENTRY; + +typedef struct + { + PI_RSP_HEADER header; + PI_UINT32 event_status; + PI_UINT32 caller_id; + PI_UINT32 timestamp_l; + PI_UINT32 timestamp_h; + PI_UINT32 write_count; + PI_LOG_ENTRY entry_info; + } PI_CMD_ERROR_LOG_GET_RSP; + +/* Define error log related constants and types. */ +/* Not all of the caller id's can occur. The only ones currently */ +/* implemented are: none, selftest, mfg, fw, console */ + +#define PI_LOG_EVENT_STATUS_K_VALID 0 /* Valid Event Status */ +#define PI_LOG_EVENT_STATUS_K_INVALID 1 /* Invalid Event Status */ +#define PI_LOG_CALLER_ID_K_NONE 0 /* No caller */ +#define PI_LOG_CALLER_ID_K_SELFTEST 1 /* Normal power-up selftest */ +#define PI_LOG_CALLER_ID_K_MFG 2 /* Mfg power-up selftest */ +#define PI_LOG_CALLER_ID_K_ONLINE 3 /* On-line diagnostics */ +#define PI_LOG_CALLER_ID_K_HW 4 /* Hardware */ +#define PI_LOG_CALLER_ID_K_FW 5 /* Firmware */ +#define PI_LOG_CALLER_ID_K_CNS_HW 6 /* CNS firmware */ +#define PI_LOG_CALLER_ID_K_CNS_FW 7 /* CNS hardware */ +#define PI_LOG_CALLER_ID_K_CONSOLE 8 /* Console Caller Id */ + +/* + * Place all DMA commands in the following request and response structures + * to simplify code. + */ + +typedef union + { + PI_UINT32 cmd_type; + PI_CMD_START_REQ start; + PI_CMD_FILTERS_SET_REQ filter_set; + PI_CMD_FILTERS_GET_REQ filter_get; + PI_CMD_CHARS_SET_REQ char_set; + PI_CMD_ADDR_FILTER_SET_REQ addr_filter_set; + PI_CMD_ADDR_FILTER_GET_REQ addr_filter_get; + PI_CMD_STATUS_CHARS_GET_REQ stat_char_get; + PI_CMD_CNTRS_GET_REQ cntrs_get; + PI_CMD_CNTRS_SET_REQ cntrs_set; + PI_CMD_ERROR_LOG_CLEAR_REQ error_log_clear; + PI_CMD_ERROR_LOG_GET_REQ error_log_read; + PI_CMD_SNMP_SET_REQ snmp_set; + PI_CMD_FDDI_MIB_GET_REQ fddi_mib_get; + PI_CMD_DEC_EXT_MIB_GET_REQ dec_mib_get; + PI_CMD_SMT_MIB_SET_REQ smt_mib_set; + PI_CMD_SMT_MIB_GET_REQ smt_mib_get; + char pad[PI_CMD_REQ_K_SIZE_MAX]; + } PI_DMA_CMD_REQ; + +typedef union + { + PI_RSP_HEADER header; + PI_CMD_START_RSP start; + PI_CMD_FILTERS_SET_RSP filter_set; + PI_CMD_FILTERS_GET_RSP filter_get; + PI_CMD_CHARS_SET_RSP char_set; + PI_CMD_ADDR_FILTER_SET_RSP addr_filter_set; + PI_CMD_ADDR_FILTER_GET_RSP addr_filter_get; + PI_CMD_STATUS_CHARS_GET_RSP stat_char_get; + PI_CMD_CNTRS_GET_RSP cntrs_get; + PI_CMD_CNTRS_SET_RSP cntrs_set; + PI_CMD_ERROR_LOG_CLEAR_RSP error_log_clear; + PI_CMD_ERROR_LOG_GET_RSP error_log_get; + PI_CMD_SNMP_SET_RSP snmp_set; + PI_CMD_FDDI_MIB_GET_RSP fddi_mib_get; + PI_CMD_DEC_EXT_MIB_GET_RSP dec_mib_get; + PI_CMD_SMT_MIB_SET_RSP smt_mib_set; + PI_CMD_SMT_MIB_GET_RSP smt_mib_get; + char pad[PI_CMD_RSP_K_SIZE_MAX]; + } PI_DMA_CMD_RSP; + +typedef union + { + PI_DMA_CMD_REQ request; + PI_DMA_CMD_RSP response; + } PI_DMA_CMD_BUFFER; + + +/* Define format of Consumer Block (resident in host memory) */ + +typedef struct + { + volatile PI_UINT32 xmt_rcv_data; + volatile PI_UINT32 reserved_1; + volatile PI_UINT32 smt_host; + volatile PI_UINT32 reserved_2; + volatile PI_UINT32 unsol; + volatile PI_UINT32 reserved_3; + volatile PI_UINT32 cmd_rsp; + volatile PI_UINT32 reserved_4; + volatile PI_UINT32 cmd_req; + volatile PI_UINT32 reserved_5; + } PI_CONSUMER_BLOCK; + +#define PI_CONS_M_RCV_INDEX 0x000000FF +#define PI_CONS_M_XMT_INDEX 0x00FF0000 +#define PI_CONS_V_RCV_INDEX 0 +#define PI_CONS_V_XMT_INDEX 16 + +/* Offsets into consumer block */ + +#define PI_CONS_BLK_K_XMT_RCV 0x00 +#define PI_CONS_BLK_K_SMT_HOST 0x08 +#define PI_CONS_BLK_K_UNSOL 0x10 +#define PI_CONS_BLK_K_CMD_RSP 0x18 +#define PI_CONS_BLK_K_CMD_REQ 0x20 + +/* Offsets into descriptor block */ + +#define PI_DESCR_BLK_K_RCV_DATA 0x0000 +#define PI_DESCR_BLK_K_XMT_DATA 0x0800 +#define PI_DESCR_BLK_K_SMT_HOST 0x1000 +#define PI_DESCR_BLK_K_UNSOL 0x1200 +#define PI_DESCR_BLK_K_CMD_RSP 0x1280 +#define PI_DESCR_BLK_K_CMD_REQ 0x1300 + +/* Define format of a rcv descr (Rcv Data, Cmd Rsp, Unsolicited, SMT Host) */ +/* Note a field has been added for later versions of the PDQ to allow for */ +/* finer granularity of the rcv buffer alignment. For backwards */ +/* compatibility, the two bits (which allow the rcv buffer to be longword */ +/* aligned) have been added at the MBZ bits. To support previous drivers, */ +/* the MBZ definition is left intact. */ + +typedef struct + { + PI_UINT32 long_0; + PI_UINT32 long_1; + } PI_RCV_DESCR; + +#define PI_RCV_DESCR_M_SOP 0x80000000 +#define PI_RCV_DESCR_M_SEG_LEN_LO 0x60000000 +#define PI_RCV_DESCR_M_MBZ 0x60000000 +#define PI_RCV_DESCR_M_SEG_LEN 0x1F800000 +#define PI_RCV_DESCR_M_SEG_LEN_HI 0x1FF00000 +#define PI_RCV_DESCR_M_SEG_CNT 0x000F0000 +#define PI_RCV_DESCR_M_BUFF_HI 0x0000FFFF + +#define PI_RCV_DESCR_V_SOP 31 +#define PI_RCV_DESCR_V_SEG_LEN_LO 29 +#define PI_RCV_DESCR_V_MBZ 29 +#define PI_RCV_DESCR_V_SEG_LEN 23 +#define PI_RCV_DESCR_V_SEG_LEN_HI 20 +#define PI_RCV_DESCR_V_SEG_CNT 16 +#define PI_RCV_DESCR_V_BUFF_HI 0 + +/* Define the format of a transmit descriptor (Xmt Data, Cmd Req) */ + +typedef struct + { + PI_UINT32 long_0; + PI_UINT32 long_1; + } PI_XMT_DESCR; + +#define PI_XMT_DESCR_M_SOP 0x80000000 +#define PI_XMT_DESCR_M_EOP 0x40000000 +#define PI_XMT_DESCR_M_MBZ 0x20000000 +#define PI_XMT_DESCR_M_SEG_LEN 0x1FFF0000 +#define PI_XMT_DESCR_M_BUFF_HI 0x0000FFFF + +#define PI_XMT_DESCR_V_SOP 31 +#define PI_XMT_DESCR_V_EOP 30 +#define PI_XMT_DESCR_V_MBZ 29 +#define PI_XMT_DESCR_V_SEG_LEN 16 +#define PI_XMT_DESCR_V_BUFF_HI 0 + +/* Define format of the Descriptor Block (resident in host memory) */ + +#define PI_RCV_DATA_K_NUM_ENTRIES 256 +#define PI_XMT_DATA_K_NUM_ENTRIES 256 +#define PI_SMT_HOST_K_NUM_ENTRIES 64 +#define PI_UNSOL_K_NUM_ENTRIES 16 +#define PI_CMD_RSP_K_NUM_ENTRIES 16 +#define PI_CMD_REQ_K_NUM_ENTRIES 16 + +typedef struct + { + PI_RCV_DESCR rcv_data[PI_RCV_DATA_K_NUM_ENTRIES]; + PI_XMT_DESCR xmt_data[PI_XMT_DATA_K_NUM_ENTRIES]; + PI_RCV_DESCR smt_host[PI_SMT_HOST_K_NUM_ENTRIES]; + PI_RCV_DESCR unsol[PI_UNSOL_K_NUM_ENTRIES]; + PI_RCV_DESCR cmd_rsp[PI_CMD_RSP_K_NUM_ENTRIES]; + PI_XMT_DESCR cmd_req[PI_CMD_REQ_K_NUM_ENTRIES]; + } PI_DESCR_BLOCK; + +/* Define Port Registers - offsets from PDQ Base address */ + +#define PI_PDQ_K_REG_PORT_RESET 0x00000000 +#define PI_PDQ_K_REG_HOST_DATA 0x00000004 +#define PI_PDQ_K_REG_PORT_CTRL 0x00000008 +#define PI_PDQ_K_REG_PORT_DATA_A 0x0000000C +#define PI_PDQ_K_REG_PORT_DATA_B 0x00000010 +#define PI_PDQ_K_REG_PORT_STATUS 0x00000014 +#define PI_PDQ_K_REG_TYPE_0_STATUS 0x00000018 +#define PI_PDQ_K_REG_HOST_INT_ENB 0x0000001C +#define PI_PDQ_K_REG_TYPE_2_PROD_NOINT 0x00000020 +#define PI_PDQ_K_REG_TYPE_2_PROD 0x00000024 +#define PI_PDQ_K_REG_CMD_RSP_PROD 0x00000028 +#define PI_PDQ_K_REG_CMD_REQ_PROD 0x0000002C +#define PI_PDQ_K_REG_SMT_HOST_PROD 0x00000030 +#define PI_PDQ_K_REG_UNSOL_PROD 0x00000034 + +/* Port Control Register - Command codes for primary commands */ + +#define PI_PCTRL_M_CMD_ERROR 0x8000 +#define PI_PCTRL_M_BLAST_FLASH 0x4000 +#define PI_PCTRL_M_HALT 0x2000 +#define PI_PCTRL_M_COPY_DATA 0x1000 +#define PI_PCTRL_M_ERROR_LOG_START 0x0800 +#define PI_PCTRL_M_ERROR_LOG_READ 0x0400 +#define PI_PCTRL_M_XMT_DATA_FLUSH_DONE 0x0200 +#define PI_PCTRL_M_INIT 0x0100 +#define PI_PCTRL_M_INIT_START 0x0080 +#define PI_PCTRL_M_CONS_BLOCK 0x0040 +#define PI_PCTRL_M_UNINIT 0x0020 +#define PI_PCTRL_M_RING_MEMBER 0x0010 +#define PI_PCTRL_M_MLA 0x0008 +#define PI_PCTRL_M_FW_REV_READ 0x0004 +#define PI_PCTRL_M_DEV_SPECIFIC 0x0002 +#define PI_PCTRL_M_SUB_CMD 0x0001 + +/* Define sub-commands accessed via the PI_PCTRL_M_SUB_CMD command */ + +#define PI_SUB_CMD_K_LINK_UNINIT 0x0001 +#define PI_SUB_CMD_K_BURST_SIZE_SET 0x0002 +#define PI_SUB_CMD_K_PDQ_REV_GET 0x0004 +#define PI_SUB_CMD_K_HW_REV_GET 0x0008 + +/* Define some Port Data B values */ + +#define PI_PDATA_B_DMA_BURST_SIZE_4 0 /* valid values for command */ +#define PI_PDATA_B_DMA_BURST_SIZE_8 1 +#define PI_PDATA_B_DMA_BURST_SIZE_16 2 +#define PI_PDATA_B_DMA_BURST_SIZE_32 3 /* not supported on PCI */ +#define PI_PDATA_B_DMA_BURST_SIZE_DEF PI_PDATA_B_DMA_BURST_SIZE_16 + +/* Port Data A Reset state */ + +#define PI_PDATA_A_RESET_M_UPGRADE 0x00000001 +#define PI_PDATA_A_RESET_M_SOFT_RESET 0x00000002 +#define PI_PDATA_A_RESET_M_SKIP_ST 0x00000004 + +/* Read adapter MLA address port control command constants */ + +#define PI_PDATA_A_MLA_K_LO 0 +#define PI_PDATA_A_MLA_K_HI 1 + +/* Byte Swap values for init command */ + +#define PI_PDATA_A_INIT_M_DESC_BLK_ADDR 0x0FFFFE000 +#define PI_PDATA_A_INIT_M_RESERVED 0x000001FFC +#define PI_PDATA_A_INIT_M_BSWAP_DATA 0x000000002 +#define PI_PDATA_A_INIT_M_BSWAP_LITERAL 0x000000001 + +#define PI_PDATA_A_INIT_V_DESC_BLK_ADDR 13 +#define PI_PDATA_A_INIT_V_RESERVED 3 +#define PI_PDATA_A_INIT_V_BSWAP_DATA 1 +#define PI_PDATA_A_INIT_V_BSWAP_LITERAL 0 + +/* Port Reset Register */ + +#define PI_RESET_M_ASSERT_RESET 1 + +/* Port Status register */ + +#define PI_PSTATUS_V_RCV_DATA_PENDING 31 +#define PI_PSTATUS_V_XMT_DATA_PENDING 30 +#define PI_PSTATUS_V_SMT_HOST_PENDING 29 +#define PI_PSTATUS_V_UNSOL_PENDING 28 +#define PI_PSTATUS_V_CMD_RSP_PENDING 27 +#define PI_PSTATUS_V_CMD_REQ_PENDING 26 +#define PI_PSTATUS_V_TYPE_0_PENDING 25 +#define PI_PSTATUS_V_RESERVED_1 16 +#define PI_PSTATUS_V_RESERVED_2 11 +#define PI_PSTATUS_V_STATE 8 +#define PI_PSTATUS_V_HALT_ID 0 + +#define PI_PSTATUS_M_RCV_DATA_PENDING 0x80000000 +#define PI_PSTATUS_M_XMT_DATA_PENDING 0x40000000 +#define PI_PSTATUS_M_SMT_HOST_PENDING 0x20000000 +#define PI_PSTATUS_M_UNSOL_PENDING 0x10000000 +#define PI_PSTATUS_M_CMD_RSP_PENDING 0x08000000 +#define PI_PSTATUS_M_CMD_REQ_PENDING 0x04000000 +#define PI_PSTATUS_M_TYPE_0_PENDING 0x02000000 +#define PI_PSTATUS_M_RESERVED_1 0x01FF0000 +#define PI_PSTATUS_M_RESERVED_2 0x0000F800 +#define PI_PSTATUS_M_STATE 0x00000700 +#define PI_PSTATUS_M_HALT_ID 0x000000FF + +/* Define Halt Id's */ +/* Do not insert into this list, only append. */ + +#define PI_HALT_ID_K_SELFTEST_TIMEOUT 0 +#define PI_HALT_ID_K_PARITY_ERROR 1 +#define PI_HALT_ID_K_HOST_DIR_HALT 2 +#define PI_HALT_ID_K_SW_FAULT 3 +#define PI_HALT_ID_K_HW_FAULT 4 +#define PI_HALT_ID_K_PC_TRACE 5 +#define PI_HALT_ID_K_DMA_ERROR 6 /* Host Data has error reg */ +#define PI_HALT_ID_K_IMAGE_CRC_ERROR 7 /* Image is bad, update it */ +#define PI_HALT_ID_K_BUS_EXCEPTION 8 /* 68K bus exception */ + +/* Host Interrupt Enable Register as seen by host */ + +#define PI_HOST_INT_M_XMT_DATA_ENB 0x80000000 /* Type 2 Enables */ +#define PI_HOST_INT_M_RCV_DATA_ENB 0x40000000 +#define PI_HOST_INT_M_SMT_HOST_ENB 0x10000000 /* Type 1 Enables */ +#define PI_HOST_INT_M_UNSOL_ENB 0x20000000 +#define PI_HOST_INT_M_CMD_RSP_ENB 0x08000000 +#define PI_HOST_INT_M_CMD_REQ_ENB 0x04000000 +#define PI_HOST_INT_M_TYPE_1_RESERVED 0x00FF0000 +#define PI_HOST_INT_M_TYPE_0_RESERVED 0x0000FF00 /* Type 0 Enables */ +#define PI_HOST_INT_M_1MS 0x00000080 +#define PI_HOST_INT_M_20MS 0x00000040 +#define PI_HOST_INT_M_CSR_CMD_DONE 0x00000020 +#define PI_HOST_INT_M_STATE_CHANGE 0x00000010 +#define PI_HOST_INT_M_XMT_FLUSH 0x00000008 +#define PI_HOST_INT_M_NXM 0x00000004 +#define PI_HOST_INT_M_PM_PAR_ERR 0x00000002 +#define PI_HOST_INT_M_BUS_PAR_ERR 0x00000001 + +#define PI_HOST_INT_V_XMT_DATA_ENB 31 /* Type 2 Enables */ +#define PI_HOST_INT_V_RCV_DATA_ENB 30 +#define PI_HOST_INT_V_SMT_HOST_ENB 29 /* Type 1 Enables */ +#define PI_HOST_INT_V_UNSOL_ENB 28 +#define PI_HOST_INT_V_CMD_RSP_ENB 27 +#define PI_HOST_INT_V_CMD_REQ_ENB 26 +#define PI_HOST_INT_V_TYPE_1_RESERVED 16 +#define PI_HOST_INT_V_TYPE_0_RESERVED 8 /* Type 0 Enables */ +#define PI_HOST_INT_V_1MS_ENB 7 +#define PI_HOST_INT_V_20MS_ENB 6 +#define PI_HOST_INT_V_CSR_CMD_DONE_ENB 5 +#define PI_HOST_INT_V_STATE_CHANGE_ENB 4 +#define PI_HOST_INT_V_XMT_FLUSH_ENB 3 +#define PI_HOST_INT_V_NXM_ENB 2 +#define PI_HOST_INT_V_PM_PAR_ERR_ENB 1 +#define PI_HOST_INT_V_BUS_PAR_ERR_ENB 0 + +#define PI_HOST_INT_K_ACK_ALL_TYPE_0 0x000000FF +#define PI_HOST_INT_K_DISABLE_ALL_INTS 0x00000000 +#define PI_HOST_INT_K_ENABLE_ALL_INTS 0xFFFFFFFF +#define PI_HOST_INT_K_ENABLE_DEF_INTS 0xC000001F + +/* Type 0 Interrupt Status Register */ + +#define PI_TYPE_0_STAT_M_1MS 0x00000080 +#define PI_TYPE_0_STAT_M_20MS 0x00000040 +#define PI_TYPE_0_STAT_M_CSR_CMD_DONE 0x00000020 +#define PI_TYPE_0_STAT_M_STATE_CHANGE 0x00000010 +#define PI_TYPE_0_STAT_M_XMT_FLUSH 0x00000008 +#define PI_TYPE_0_STAT_M_NXM 0x00000004 +#define PI_TYPE_0_STAT_M_PM_PAR_ERR 0x00000002 +#define PI_TYPE_0_STAT_M_BUS_PAR_ERR 0x00000001 + +#define PI_TYPE_0_STAT_V_1MS 7 +#define PI_TYPE_0_STAT_V_20MS 6 +#define PI_TYPE_0_STAT_V_CSR_CMD_DONE 5 +#define PI_TYPE_0_STAT_V_STATE_CHANGE 4 +#define PI_TYPE_0_STAT_V_XMT_FLUSH 3 +#define PI_TYPE_0_STAT_V_NXM 2 +#define PI_TYPE_0_STAT_V_PM_PAR_ERR 1 +#define PI_TYPE_0_STAT_V_BUS_PAR_ERR 0 + +/* Register definition structures are defined for both big and little endian systems */ + +#ifndef BIG_ENDIAN + +/* Little endian format of Type 1 Producer register */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 prod; + PI_UINT8 comp; + PI_UINT8 mbz_1; + PI_UINT8 mbz_2; + } index; + } PI_TYPE_1_PROD_REG; + +/* Little endian format of Type 2 Producer register */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 rcv_prod; + PI_UINT8 xmt_prod; + PI_UINT8 rcv_comp; + PI_UINT8 xmt_comp; + } index; + } PI_TYPE_2_PROD_REG; + +/* Little endian format of Type 1 Consumer Block longword */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 cons; + PI_UINT8 res0; + PI_UINT8 res1; + PI_UINT8 res2; + } index; + } PI_TYPE_1_CONSUMER; + +/* Little endian format of Type 2 Consumer Block longword */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 rcv_cons; + PI_UINT8 res0; + PI_UINT8 xmt_cons; + PI_UINT8 res1; + } index; + } PI_TYPE_2_CONSUMER; + +#else + +/* Big endian format of Type 1 Producer register */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 mbz_2; + PI_UINT8 mbz_1; + PI_UINT8 comp; + PI_UINT8 prod; + } index; + } PI_TYPE_1_PROD_REG; + +/* Big endian format of Type 2 Producer register */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 xmt_comp; + PI_UINT8 rcv_comp; + PI_UINT8 xmt_prod; + PI_UINT8 rcv_prod; + } index; + } PI_TYPE_2_PROD_REG; + +/* Big endian format of Type 1 Consumer Block longword */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 res2; + PI_UINT8 res1; + PI_UINT8 res0; + PI_UINT8 cons; + } index; + } PI_TYPE_1_CONSUMER; + +/* Big endian format of Type 2 Consumer Block longword */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 res1; + PI_UINT8 xmt_cons; + PI_UINT8 res0; + PI_UINT8 rcv_cons; + } index; + } PI_TYPE_2_CONSUMER; + +#endif /* #ifndef BIG_ENDIAN */ + +/* Define EISA controller register offsets */ + +#define PI_ESIC_K_BURST_HOLDOFF 0x040 +#define PI_ESIC_K_SLOT_ID 0xC80 +#define PI_ESIC_K_SLOT_CNTRL 0xC84 +#define PI_ESIC_K_MEM_ADD_CMP_0 0xC85 +#define PI_ESIC_K_MEM_ADD_CMP_1 0xC86 +#define PI_ESIC_K_MEM_ADD_CMP_2 0xC87 +#define PI_ESIC_K_MEM_ADD_HI_CMP_0 0xC88 +#define PI_ESIC_K_MEM_ADD_HI_CMP_1 0xC89 +#define PI_ESIC_K_MEM_ADD_HI_CMP_2 0xC8A +#define PI_ESIC_K_MEM_ADD_MASK_0 0xC8B +#define PI_ESIC_K_MEM_ADD_MASK_1 0xC8C +#define PI_ESIC_K_MEM_ADD_MASK_2 0xC8D +#define PI_ESIC_K_MEM_ADD_LO_CMP_0 0xC8E +#define PI_ESIC_K_MEM_ADD_LO_CMP_1 0xC8F +#define PI_ESIC_K_MEM_ADD_LO_CMP_2 0xC90 +#define PI_ESIC_K_IO_CMP_0_0 0xC91 +#define PI_ESIC_K_IO_CMP_0_1 0xC92 +#define PI_ESIC_K_IO_CMP_1_0 0xC93 +#define PI_ESIC_K_IO_CMP_1_1 0xC94 +#define PI_ESIC_K_IO_CMP_2_0 0xC95 +#define PI_ESIC_K_IO_CMP_2_1 0xC96 +#define PI_ESIC_K_IO_CMP_3_0 0xC97 +#define PI_ESIC_K_IO_CMP_3_1 0xC98 +#define PI_ESIC_K_IO_ADD_MASK_0_0 0xC99 +#define PI_ESIC_K_IO_ADD_MASK_0_1 0xC9A +#define PI_ESIC_K_IO_ADD_MASK_1_0 0xC9B +#define PI_ESIC_K_IO_ADD_MASK_1_1 0xC9C +#define PI_ESIC_K_IO_ADD_MASK_2_0 0xC9D +#define PI_ESIC_K_IO_ADD_MASK_2_1 0xC9E +#define PI_ESIC_K_IO_ADD_MASK_3_0 0xC9F +#define PI_ESIC_K_IO_ADD_MASK_3_1 0xCA0 +#define PI_ESIC_K_MOD_CONFIG_1 0xCA1 +#define PI_ESIC_K_MOD_CONFIG_2 0xCA2 +#define PI_ESIC_K_MOD_CONFIG_3 0xCA3 +#define PI_ESIC_K_MOD_CONFIG_4 0xCA4 +#define PI_ESIC_K_MOD_CONFIG_5 0xCA5 +#define PI_ESIC_K_MOD_CONFIG_6 0xCA6 +#define PI_ESIC_K_MOD_CONFIG_7 0xCA7 +#define PI_ESIC_K_DIP_SWITCH 0xCA8 +#define PI_ESIC_K_IO_CONFIG_STAT_0 0xCA9 +#define PI_ESIC_K_IO_CONFIG_STAT_1 0xCAA +#define PI_ESIC_K_DMA_CONFIG 0xCAB +#define PI_ESIC_K_INPUT_PORT 0xCAC +#define PI_ESIC_K_OUTPUT_PORT 0xCAD +#define PI_ESIC_K_FUNCTION_CNTRL 0xCAE +#define PI_ESIC_K_CSR_IO_LEN PI_ESIC_K_FUNCTION_CNTRL+1 /* always last reg + 1 */ + +/* Define the value all drivers must write to the function control register. */ + +#define PI_ESIC_K_FUNCTION_CNTRL_IO_ENB 0x03 + +/* Define the bits in the slot control register. */ + +#define PI_SLOT_CNTRL_M_RESET 0x04 /* Don't use. */ +#define PI_SLOT_CNTRL_M_ERROR 0x02 /* Not implemented. */ +#define PI_SLOT_CNTRL_M_ENB 0x01 /* Must be set. */ + +/* Define the bits in the burst holdoff register. */ + +#define PI_BURST_HOLDOFF_M_HOLDOFF 0xFC +#define PI_BURST_HOLDOFF_M_RESERVED 0x02 +#define PI_BURST_HOLDOFF_M_MEM_MAP 0x01 + +#define PI_BURST_HOLDOFF_V_HOLDOFF 2 +#define PI_BURST_HOLDOFF_V_RESERVED 1 +#define PI_BURST_HOLDOFF_V_MEM_MAP 0 + +/* + * Define the fields in the IO Compare registers. + * The driver must initialize the slot field with the slot ID shifted by the + * amount shown below. + */ + +#define PI_IO_CMP_V_SLOT 4 + +/* Define the fields in the Interrupt Channel Configuration and Status reg */ + +#define PI_CONFIG_STAT_0_M_PEND 0x80 +#define PI_CONFIG_STAT_0_M_RES_1 0x40 +#define PI_CONFIG_STAT_0_M_IREQ_OUT 0x20 +#define PI_CONFIG_STAT_0_M_IREQ_IN 0x10 +#define PI_CONFIG_STAT_0_M_INT_ENB 0x08 +#define PI_CONFIG_STAT_0_M_RES_0 0x04 +#define PI_CONFIG_STAT_0_M_IRQ 0x03 + +#define PI_CONFIG_STAT_0_V_PEND 7 +#define PI_CONFIG_STAT_0_V_RES_1 6 +#define PI_CONFIG_STAT_0_V_IREQ_OUT 5 +#define PI_CONFIG_STAT_0_V_IREQ_IN 4 +#define PI_CONFIG_STAT_0_V_INT_ENB 3 +#define PI_CONFIG_STAT_0_V_RES_0 2 +#define PI_CONFIG_STAT_0_V_IRQ 0 + +#define PI_CONFIG_STAT_0_IRQ_K_9 0 +#define PI_CONFIG_STAT_0_IRQ_K_10 1 +#define PI_CONFIG_STAT_0_IRQ_K_11 2 +#define PI_CONFIG_STAT_0_IRQ_K_15 3 + +/* Define DEC FDDIcontroller/EISA (DEFEA) EISA hardware ID's */ + +#define DEFEA_PRODUCT_ID 0x0030A310 /* DEC product 300 (no rev) */ +#define DEFEA_PROD_ID_1 0x0130A310 /* DEC product 300, rev 1 */ +#define DEFEA_PROD_ID_2 0x0230A310 /* DEC product 300, rev 2 */ +#define DEFEA_PROD_ID_3 0x0330A310 /* DEC product 300, rev 3 */ + +/**********************************************/ +/* Digital PFI Specification v1.0 Definitions */ +/**********************************************/ + +/* PCI Configuration Space Constants */ + +#define PFI_K_LAT_TIMER_DEF 0x88 /* def max master latency timer */ +#define PFI_K_LAT_TIMER_MIN 0x20 /* min max master latency timer */ +#define PFI_K_CSR_MEM_LEN 0x80 /* 128 bytes */ +#define PFI_K_CSR_IO_LEN 0x80 /* 128 bytes */ +#define PFI_K_PKT_MEM_LEN 0x10000 /* 64K bytes */ + +/* PFI Register Offsets (starting at PDQ Register Base Address) */ + +#define PFI_K_REG_RESERVED_0 0X00000038 +#define PFI_K_REG_RESERVED_1 0X0000003C +#define PFI_K_REG_MODE_CTRL 0X00000040 +#define PFI_K_REG_STATUS 0X00000044 +#define PFI_K_REG_FIFO_WRITE 0X00000048 +#define PFI_K_REG_FIFO_READ 0X0000004C + +/* PFI Mode Control Register Constants */ + +#define PFI_MODE_M_RESERVED 0XFFFFFFF0 +#define PFI_MODE_M_TGT_ABORT_ENB 0X00000008 +#define PFI_MODE_M_PDQ_INT_ENB 0X00000004 +#define PFI_MODE_M_PFI_INT_ENB 0X00000002 +#define PFI_MODE_M_DMA_ENB 0X00000001 + +#define PFI_MODE_V_RESERVED 4 +#define PFI_MODE_V_TGT_ABORT_ENB 3 +#define PFI_MODE_V_PDQ_INT_ENB 2 +#define PFI_MODE_V_PFI_INT_ENB 1 +#define PFI_MODE_V_DMA_ENB 0 + +#define PFI_MODE_K_ALL_DISABLE 0X00000000 + +/* PFI Status Register Constants */ + +#define PFI_STATUS_M_RESERVED 0XFFFFFFC0 +#define PFI_STATUS_M_PFI_ERROR 0X00000020 /* only valid in rev 1 or later PFI */ +#define PFI_STATUS_M_PDQ_INT 0X00000010 +#define PFI_STATUS_M_PDQ_DMA_ABORT 0X00000008 +#define PFI_STATUS_M_FIFO_FULL 0X00000004 +#define PFI_STATUS_M_FIFO_EMPTY 0X00000002 +#define PFI_STATUS_M_DMA_IN_PROGRESS 0X00000001 + +#define PFI_STATUS_V_RESERVED 6 +#define PFI_STATUS_V_PFI_ERROR 5 /* only valid in rev 1 or later PFI */ +#define PFI_STATUS_V_PDQ_INT 4 +#define PFI_STATUS_V_PDQ_DMA_ABORT 3 +#define PFI_STATUS_V_FIFO_FULL 2 +#define PFI_STATUS_V_FIFO_EMPTY 1 +#define PFI_STATUS_V_DMA_IN_PROGRESS 0 + +#define DFX_MAX_EISA_SLOTS 16 /* maximum number of EISA slots to scan */ +#define DFX_MAX_NUM_BOARDS 8 /* maximum number of adapters supported */ + +#define DFX_BUS_TYPE_PCI 0 /* type code for DEC FDDIcontroller/PCI */ +#define DFX_BUS_TYPE_EISA 1 /* type code for DEC FDDIcontroller/EISA */ + +#define DFX_FC_PRH2_PRH1_PRH0 0x54003820 /* Packet Request Header bytes + FC */ +#define DFX_PRH0_BYTE 0x20 /* Packet Request Header byte 0 */ +#define DFX_PRH1_BYTE 0x38 /* Packet Request Header byte 1 */ +#define DFX_PRH2_BYTE 0x00 /* Packet Request Header byte 2 */ + +/* Driver routine status (return) codes */ + +#define DFX_K_SUCCESS 0 /* routine succeeded */ +#define DFX_K_FAILURE 1 /* routine failed */ +#define DFX_K_OUTSTATE 2 /* bad state for command */ +#define DFX_K_HW_TIMEOUT 3 /* command timed out */ + +/* Define LLC host receive buffer min/max/default values */ + +#define RCV_BUFS_MIN 2 /* minimum pre-allocated receive buffers */ +#define RCV_BUFS_MAX 32 /* maximum pre-allocated receive buffers */ +#define RCV_BUFS_DEF 8 /* default pre-allocated receive buffers */ + +/* Define offsets into FDDI LLC or SMT receive frame buffers - used when indicating frames */ + +#define RCV_BUFF_K_DESCR 0 /* four byte FMC descriptor */ +#define RCV_BUFF_K_PADDING 4 /* three null bytes */ +#define RCV_BUFF_K_FC 7 /* one byte frame control */ +#define RCV_BUFF_K_DA 8 /* six byte destination address */ +#define RCV_BUFF_K_SA 14 /* six byte source address */ +#define RCV_BUFF_K_DATA 20 /* offset to start of packet data */ + +/* Define offsets into FDDI LLC transmit frame buffers - used when sending frames */ + +#define XMT_BUFF_K_FC 0 /* one byte frame control */ +#define XMT_BUFF_K_DA 1 /* six byte destination address */ +#define XMT_BUFF_K_SA 7 /* six byte source address */ +#define XMT_BUFF_K_DATA 13 /* offset to start of packet data */ + +/* + * Macro evaluates to "value" aligned to "size" bytes. Make sure that + * "size" is greater than 0 bytes. + */ + +#define ALIGN(value,size) ((value + (size - 1)) & ~(size - 1)) + +/* Macro for checking a "value" is within a specific range */ + +#define IN_RANGE(value,low,high) ((value >= low) && (value <= high)) + +/* Only execute special print call when debug driver was built */ + +#ifdef DEFXX_DEBUG +#define DBG_printk(args...) printk(## args) +#else +#define DBG_printk(args...) +#endif + +/* Define constants for masking/unmasking interrupts */ + +#define DFX_MASK_INTERRUPTS 1 +#define DFX_UNMASK_INTERRUPTS 0 + +/* Define structure for driver transmit descriptor block */ + +typedef struct + { + struct sk_buff *p_skb; /* ptr to skb */ + } XMT_DRIVER_DESCR; + +typedef struct DFX_board_tag + { + /* Keep virtual and physical pointers to locked, physically contiguous memory */ + + PI_DESCR_BLOCK *descr_block_virt; /* PDQ descriptor block virt address */ + u32 descr_block_phys; /* PDQ descriptor block phys address */ + PI_DMA_CMD_REQ *cmd_req_virt; /* Command request buffer virt address */ + u32 cmd_req_phys; /* Command request buffer phys address */ + PI_DMA_CMD_RSP *cmd_rsp_virt; /* Command response buffer virt address */ + u32 cmd_rsp_phys; /* Command response buffer phys address */ + char *rcv_block_virt; /* LLC host receive queue buf blk virt */ + u32 rcv_block_phys; /* LLC host receive queue buf blk phys */ + PI_CONSUMER_BLOCK *cons_block_virt; /* PDQ consumer block virt address */ + u32 cons_block_phys; /* PDQ consumer block phys address */ + + /* Keep local copies of Type 1 and Type 2 register data */ + + PI_TYPE_1_PROD_REG cmd_req_reg; /* Command Request register */ + PI_TYPE_1_PROD_REG cmd_rsp_reg; /* Command Response register */ + PI_TYPE_2_PROD_REG rcv_xmt_reg; /* Type 2 (RCV/XMT) register */ + + /* Storage for unicast and multicast address entries in adapter CAM */ + + u8 uc_table[1*FDDI_K_ALEN]; + u32 uc_count; /* number of unicast addresses */ + u8 mc_table[PI_CMD_ADDR_FILTER_K_SIZE*FDDI_K_ALEN]; + u32 mc_count; /* number of multicast addresses */ + + /* Current packet filter settings */ + + u32 ind_group_prom; /* LLC individual & group frame prom mode */ + u32 group_prom; /* LLC group (multicast) frame prom mode */ + + /* Link available flag needed to determine whether to drop outgoing packet requests */ + + u32 link_available; /* is link available? */ + + /* Resources to indicate reset type when resetting adapter */ + + u32 reset_type; /* skip or rerun diagnostics */ + + /* Store pointers to receive buffers for queue processing code */ + + char *p_rcv_buff_va[PI_RCV_DATA_K_NUM_ENTRIES]; + + /* Store pointers to transmit buffers for transmit completion code */ + + XMT_DRIVER_DESCR xmt_drv_descr_blk[PI_XMT_DATA_K_NUM_ENTRIES]; + + /* Store device, bus-specific, and parameter information for this adapter */ + + struct device *dev; /* pointer to device structure */ + u32 bus_type; /* bus type (0 == PCI, 1 == EISA) */ + u16 base_addr; /* base I/O address (same as dev->base_addr) */ + u8 pci_bus; /* PCI bus number */ + u8 pci_dev_fun; /* PCI device and function numbers */ + u32 full_duplex_enb; /* FDDI Full Duplex enable (1 == on, 2 == off) */ + u32 req_ttrt; /* requested TTRT value (in 80ns units) */ + u32 burst_size; /* adapter burst size (enumerated) */ + u32 rcv_bufs_to_post; /* receive buffers to post for LLC host queue */ + u8 factory_mac_addr[FDDI_K_ALEN]; /* factory (on-board) MAC address */ + + /* Common FDDI statistics structure and private counters */ + + struct fddi_statistics stats; + + u32 rcv_discards; + u32 rcv_crc_errors; + u32 rcv_frame_status_errors; + u32 rcv_length_errors; + u32 rcv_total_frames; + u32 rcv_multicast_frames; + u32 xmt_discards; + u32 xmt_length_errors; + u32 xmt_total_frames; + } DFX_board_t; + +#endif /* #ifndef _DEFXX_H_ */ diff -u --recursive --new-file v2.1.10/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c --- v2.1.10/linux/drivers/net/dgrs.c Wed Oct 16 10:48:17 1996 +++ linux/drivers/net/dgrs.c Mon Nov 18 11:31:31 1996 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.1.10/linux/drivers/net/dlci.c linux/drivers/net/dlci.c --- v2.1.10/linux/drivers/net/dlci.c Wed Oct 16 10:48:17 1996 +++ linux/drivers/net/dlci.c Mon Nov 18 11:31:31 1996 @@ -43,6 +43,8 @@ #include #include #include +#include + #include #include diff -u --recursive --new-file v2.1.10/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c --- v2.1.10/linux/drivers/net/eth16i.c Wed Oct 9 08:55:19 1996 +++ linux/drivers/net/eth16i.c Mon Nov 18 11:31:31 1996 @@ -181,8 +181,8 @@ #define BUFFER_WIDTH_8 BIT(4) /* 1 = 8bit, 0 = 16bit */ #define TBS1 BIT(3) #define TBS0 BIT(2) -#define BS1 BIT(1) /* 00=8kb, 01=16kb */ -#define BS0 BIT(0) /* 10=32kb, 11=64kb */ +#define MBS1 BIT(1) /* 00=8kb, 01=16kb */ +#define MBS0 BIT(0) /* 10=32kb, 11=64kb */ #ifndef ETH16I_TX_BUF_SIZE /* 0 = 2kb, 1 = 4kb */ #define ETH16I_TX_BUF_SIZE 2 /* 2 = 8kb, 3 = 16kb */ @@ -327,7 +327,7 @@ static int eth16i_tx(struct sk_buff *skb, struct device *dev); static void eth16i_rx(struct device *dev); static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void eth16i_multicast(struct device *dev, int num_addrs, void *addrs); +static void eth16i_multicast(struct device *dev); static void eth16i_select_regbank(unsigned char regbank, short ioaddr); static void eth16i_initialize(struct device *dev); static struct enet_statistics *eth16i_get_stats(struct device *dev); @@ -505,10 +505,10 @@ if( (node_w & 0xFF00) == 0x0800) node_byte |= BUFFER_WIDTH_8; - node_byte |= BS1; + node_byte |= MBS1; if( (node_w & 0x00FF) == 64) - node_byte |= BS0; + node_byte |= MBS0; node_byte |= DLC_EN | SRAM_CYCLE_TIME_100NS | (ETH16I_TX_BUF_SIZE << 2); @@ -1147,7 +1147,7 @@ return; } -static void eth16i_multicast(struct device *dev, int num_addrs, void *addrs) +static void eth16i_multicast(struct device *dev) { short ioaddr = dev->base_addr; diff -u --recursive --new-file v2.1.10/linux/drivers/net/hdlcdrv.c linux/drivers/net/hdlcdrv.c --- v2.1.10/linux/drivers/net/hdlcdrv.c Fri Nov 1 17:13:18 1996 +++ linux/drivers/net/hdlcdrv.c Mon Nov 18 11:31:31 1996 @@ -37,6 +37,7 @@ #include #include +#include #include #include #include diff -u --recursive --new-file v2.1.10/linux/drivers/net/loopback.c linux/drivers/net/loopback.c --- v2.1.10/linux/drivers/net/loopback.c Tue Oct 29 19:58:12 1996 +++ linux/drivers/net/loopback.c Mon Nov 18 11:31:31 1996 @@ -20,6 +20,8 @@ * Michael Griffith: Don't bother computing the checksums * on packets received on the loopback * interface. + * Alexey Kuznetsov: Potential hang under some extreme + * cases removed. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -73,9 +75,9 @@ { struct sk_buff *skb2=skb; skb=skb_clone(skb, GFP_ATOMIC); /* Clone the buffer */ - if(skb==NULL) - return 1; dev_kfree_skb(skb2, FREE_WRITE); + if(skb==NULL) + return 0; unlock=0; } else if(skb->sk) diff -u --recursive --new-file v2.1.10/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v2.1.10/linux/drivers/net/net_init.c Sat Jun 29 12:00:46 1996 +++ linux/drivers/net/net_init.c Mon Nov 18 11:31:31 1996 @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef CONFIG_NET_ALIAS #include #endif @@ -154,6 +155,19 @@ return 0; } +#ifdef CONFIG_FDDI + +static int fddi_change_mtu(struct device *dev, int new_mtu) +{ + if ((new_mtu < FDDI_K_SNAP_HLEN) || (new_mtu > FDDI_K_SNAP_DLEN)) + return(-EINVAL); + dev->mtu = new_mtu; + return(0); +} + +#endif + + void ether_setup(struct device *dev) { int i; @@ -228,6 +242,43 @@ dev->pa_mask = 0; dev->pa_alen = 4; } + +#endif + +#ifdef CONFIG_FDDI + +void fddi_setup(struct device *dev) + { + int i; + + /* + * Fill in the fields of the device structure with FDDI-generic values. + * This should be in a common file instead of per-driver. + */ + for (i=0; i < DEV_NUMBUFFS; i++) + skb_queue_head_init(&dev->buffs[i]); + + dev->change_mtu = fddi_change_mtu; + dev->hard_header = fddi_header; + dev->rebuild_header = fddi_rebuild_header; + + dev->type = ARPHRD_FDDI; + dev->hard_header_len = FDDI_K_SNAP_HLEN+3; /* Assume 802.2 SNAP hdr len + 3 pad bytes */ + dev->mtu = FDDI_K_SNAP_DLEN; /* Assume max payload of 802.2 SNAP frame */ + dev->addr_len = FDDI_K_ALEN; + dev->tx_queue_len = 100; /* Long queues on FDDI */ + + memset(dev->broadcast, 0xFF, FDDI_K_ALEN); + + /* New-style flags */ + dev->flags = IFF_BROADCAST | IFF_MULTICAST; + dev->family = AF_INET; + dev->pa_addr = 0; + dev->pa_brdaddr = 0; + dev->pa_mask = 0; + dev->pa_alen = 4; + return; + } #endif diff -u --recursive --new-file v2.1.10/linux/drivers/net/sdla.c linux/drivers/net/sdla.c --- v2.1.10/linux/drivers/net/sdla.c Wed Oct 16 10:48:19 1996 +++ linux/drivers/net/sdla.c Mon Nov 18 11:31:31 1996 @@ -51,6 +51,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.1.10/linux/drivers/net/soundmodem.c linux/drivers/net/soundmodem.c --- v2.1.10/linux/drivers/net/soundmodem.c Fri Nov 1 17:13:18 1996 +++ linux/drivers/net/soundmodem.c Mon Nov 18 11:31:31 1996 @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.1.10/linux/drivers/net/wic.c linux/drivers/net/wic.c --- v2.1.10/linux/drivers/net/wic.c Wed Oct 16 10:48:19 1996 +++ linux/drivers/net/wic.c Mon Nov 18 11:31:32 1996 @@ -49,6 +49,7 @@ #include #include #include +#include #include #define NET_DEBUG 1 diff -u --recursive --new-file v2.1.10/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c --- v2.1.10/linux/drivers/scsi/ppa.c Tue Apr 16 16:08:21 1996 +++ linux/drivers/scsi/ppa.c Mon Nov 18 11:31:32 1996 @@ -46,7 +46,7 @@ #define PPA_SPIN_TMO 5000000 /* ppa_wait loop limiter */ #define PPA_SECTOR_SIZE 512 /* for a performance hack only */ -#include +#include #include #include #include diff -u --recursive --new-file v2.1.10/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.1.10/linux/drivers/scsi/scsi.c Fri Nov 15 23:49:09 1996 +++ linux/drivers/scsi/scsi.c Mon Nov 18 11:31:32 1996 @@ -311,7 +311,7 @@ void scsi_make_blocked_list(void) { int block_count = 0, index; - unsigned int flags; + unsigned long flags; struct Scsi_Host * sh[128], * shpnt; /* @@ -1009,7 +1009,7 @@ kdev_t dev; struct request * req = NULL; int tablesize; - unsigned int flags; + unsigned long flags; struct buffer_head * bh, *bhp; struct Scsi_Host * host; Scsi_Cmnd * SCpnt = NULL; @@ -1277,7 +1277,7 @@ static void scsi_request_sense (Scsi_Cmnd * SCpnt) { - unsigned int flags; + unsigned long flags; save_flags(flags); cli(); diff -u --recursive --new-file v2.1.10/linux/include/asm-alpha/uaccess.h linux/include/asm-alpha/uaccess.h --- v2.1.10/linux/include/asm-alpha/uaccess.h Fri Nov 15 23:49:10 1996 +++ linux/include/asm-alpha/uaccess.h Fri Nov 15 22:36:52 1996 @@ -377,14 +377,14 @@ extern long __strncpy_from_user(char *__to, const char *__from, long __to_len); -#define strncpy_from_user(to,from,n) \ -({ \ - char * __sfu_to = (to); \ - const char * __sfu_from = (from); \ - long __sfu_len = (n), __sfu_ret = -EFAULT; \ - if (__access_ok(((long)__sfu_from),__sfu_len,__access_mask)) \ - __sfu_ret=__strncpy_from_user(__sfu_to,__sfu_from,__sfu_len); \ - __sfu_ret; \ +#define strncpy_from_user(to,from,n) \ +({ \ + char * __sfu_to = (to); \ + const char * __sfu_from = (from); \ + long __sfu_ret = -EFAULT; \ + if (__access_ok(((long)__sfu_from),0,__access_mask)) \ + __sfu_ret = __strncpy_from_user(__sfu_to,__sfu_from,(n)); \ + __sfu_ret; \ }) /* Returns: 0 if bad, string length+1 (memory size) of string if ok */ @@ -392,10 +392,7 @@ extern inline long strlen_user(const char *str) { - long len = __strlen_user(str); - if (!access_ok(VERIFY_READ, str, len)) - len = 0; - return len; + return access_ok(VERIFY_READ,str,0) ? __strlen_user(str) : 0; } /* diff -u --recursive --new-file v2.1.10/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h --- v2.1.10/linux/include/asm-alpha/unistd.h Wed Oct 16 10:48:29 1996 +++ linux/include/asm-alpha/unistd.h Mon Nov 18 10:25:04 1996 @@ -168,6 +168,8 @@ #define __NR_nfsctl 342 #define __NR_setresuid 343 #define __NR_getresuid 344 +#define __NR_pciconfig_read 345 +#define __NR_pciconfig_write 346 #if defined(__LIBRARY__) && defined(__GNUC__) diff -u --recursive --new-file v2.1.10/linux/include/asm-i386/socket.h linux/include/asm-i386/socket.h --- v2.1.10/linux/include/asm-i386/socket.h Sun Mar 24 12:47:39 1996 +++ linux/include/asm-i386/socket.h Mon Nov 18 11:31:32 1996 @@ -21,5 +21,10 @@ #define SO_LINGER 13 #define SO_BSDCOMPAT 14 /* To add :#define SO_REUSEPORT 15 */ +#define SO_RCVLOWAT 16 +#define SO_SNDLOWAT 17 +#define SO_RCVTIMEO 18 +#define SO_SNDTIMEO 19 + #endif /* _ASM_SOCKET_H */ diff -u --recursive --new-file v2.1.10/linux/include/asm-i386/uaccess.h linux/include/asm-i386/uaccess.h --- v2.1.10/linux/include/asm-i386/uaccess.h Fri Nov 15 23:49:10 1996 +++ linux/include/asm-i386/uaccess.h Mon Nov 18 15:11:15 1996 @@ -22,10 +22,24 @@ #define set_fs(x) (current->tss.segment = (x)) #define get_ds() (KERNEL_DS) +/* + * Address Ok: + * + * low two bits of segment + * 00 (kernel) 11 (user) + * + * high 00 1 1 + * two 01 1 1 + * bits of 10 1 1 + * address 11 1 0 + */ +#define __addr_ok(x) \ + ((((unsigned long)(x)>>30)&get_fs()) != 3) + #define __user_ok(addr,size) \ ((size <= 0xC0000000UL) && (addr <= 0xC0000000UL - size)) #define __kernel_ok \ - (get_fs() == KERNEL_DS) + (!(get_fs() & 3)) extern int __verify_write(const void *, unsigned long); @@ -412,28 +426,25 @@ * * Return 0 for error */ -extern inline long strlen_user(const char * s) + +extern inline long strlen_user(const char *s) { - long res; + unsigned long res; + __asm__ __volatile__( - "\n" - "0:\trepne ; scasb\n\t" - "notl %0\n" + "0: repne; scasb\n" + " notl %0\n" "1:\n" ".section .fixup,\"ax\"\n" - "2:\txorl %0,%0\n\t" - "jmp 1b\n" - ".section __ex_table,\"a\"\n\t" - ".align 4\n\t" - ".long 0b,2b\n" + "2: xorl %0,%0\n" + " jmp 1b\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 0b,2b\n" ".text" - :"=c" (res) - :"D" (s),"a" (0),"0" (0xffffffff) - :"di"); - if (!access_ok(VERIFY_READ, s, res)) - res = 0; - return res; + :"=c" (res), "=D" (s) + :"1" (s), "a" (0), "0" (-__addr_ok(s))); + return res & -__addr_ok(s); } - #endif /* __i386_UACCESS_H */ diff -u --recursive --new-file v2.1.10/linux/include/linux/atalk.h linux/include/linux/atalk.h --- v2.1.10/linux/include/linux/atalk.h Mon Mar 25 08:58:21 1996 +++ linux/include/linux/atalk.h Mon Nov 18 11:31:32 1996 @@ -25,7 +25,7 @@ struct sockaddr_at { - short sat_family; + sa_family_t sat_family; __u8 sat_port; struct at_addr sat_addr; char sat_zero[ 8 ]; diff -u --recursive --new-file v2.1.10/linux/include/linux/ax25.h linux/include/linux/ax25.h --- v2.1.10/linux/include/linux/ax25.h Tue Nov 12 15:56:14 1996 +++ linux/include/linux/ax25.h Mon Nov 18 11:31:32 1996 @@ -41,7 +41,7 @@ } ax25_address; struct sockaddr_ax25 { - short sax25_family; + sa_family_t sax25_family; ax25_address sax25_call; int sax25_ndigis; /* Digipeater ax25_address sets follow */ diff -u --recursive --new-file v2.1.10/linux/include/linux/fddidevice.h linux/include/linux/fddidevice.h --- v2.1.10/linux/include/linux/fddidevice.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/fddidevice.h Mon Nov 18 11:31:32 1996 @@ -0,0 +1,42 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the FDDI handlers. + * + * Version: @(#)fddidevice.h 1.0.0 08/12/96 + * + * Author: Lawrence V. Stefani, + * + * fddidevice.h is based on previous trdevice.h work by + * Ross Biro, + * Fred N. van Kempen, + * Alan Cox, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _LINUX_FDDIDEVICE_H +#define _LINUX_FDDIDEVICE_H + +#include + +#ifdef __KERNEL__ +extern int fddi_header(struct sk_buff *skb, + struct device *dev, + unsigned short type, + void *daddr, + void *saddr, + unsigned len); +extern int fddi_rebuild_header(void *buff, + struct device *dev, + unsigned long dest, + struct sk_buff *skb); +extern unsigned short fddi_type_trans(struct sk_buff *skb, + struct device *dev); +#endif + +#endif /* _LINUX_FDDIDEVICE_H */ diff -u --recursive --new-file v2.1.10/linux/include/linux/if_arp.h linux/include/linux/if_arp.h --- v2.1.10/linux/include/linux/if_arp.h Tue Nov 12 15:56:14 1996 +++ linux/include/linux/if_arp.h Mon Nov 18 15:13:20 1996 @@ -54,6 +54,7 @@ #define ARPHRD_SKIP 771 /* SKIP vif */ #define ARPHRD_LOOPBACK 772 /* Loopback device */ #define ARPHRD_LOCALTLK 773 /* Localtalk device */ +#define ARPHRD_FDDI 774 /* FDDI interfaces */ #define ARPHRD_SIT 776 /* sit0 device - IPv6-in-IPv4 */ /* ARP protocol opcodes. */ diff -u --recursive --new-file v2.1.10/linux/include/linux/if_fddi.h linux/include/linux/if_fddi.h --- v2.1.10/linux/include/linux/if_fddi.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/if_fddi.h Mon Nov 18 11:31:32 1996 @@ -0,0 +1,202 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Global definitions for the ANSI FDDI interface. + * + * Version: @(#)if_fddi.h 1.0.1 09/16/96 + * + * Author: Lawrence V. Stefani, + * + * if_fddi.h is based on previous if_ether.h and if_tr.h work by + * Fred N. van Kempen, + * Donald Becker, + * Alan Cox, + * Steve Whitehouse, + * Peter De Schrijver, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _LINUX_IF_FDDI_H +#define _LINUX_IF_FDDI_H + +/* + * Define max and min legal sizes. The frame sizes do not include + * 4 byte FCS/CRC (frame check sequence). + */ +#define FDDI_K_ALEN 6 /* Octets in one FDDI address */ +#define FDDI_K_8022_HLEN 16 /* Total octets in 802.2 header */ +#define FDDI_K_SNAP_HLEN 21 /* Total octets in 802.2 SNAP header */ +#define FDDI_K_8022_ZLEN 16 /* Min octets in 802.2 frame sans FCS */ +#define FDDI_K_SNAP_ZLEN 21 /* Min octets in 802.2 SNAP frame sans FCS */ +#define FDDI_K_8022_DLEN 4475 /* Max octets in 802.2 payload */ +#define FDDI_K_SNAP_DLEN 4470 /* Max octets in 802.2 SNAP payload */ +#define FDDI_K_LLC_ZLEN 13 /* Min octets in LLC frame sans FCS */ +#define FDDI_K_LLC_LEN 4491 /* Max octets in LLC frame sans FCS */ + +/* Define FDDI Frame Control (FC) Byte values */ +#define FDDI_FC_K_VOID 0x00 +#define FDDI_FC_K_NON_RESTRICTED_TOKEN 0x80 +#define FDDI_FC_K_RESTRICTED_TOKEN 0xC0 +#define FDDI_FC_K_SMT_MIN 0x41 +#define FDDI_FC_K_SMT_MAX 0x4F +#define FDDI_FC_K_MAC_MIN 0xC1 +#define FDDI_FC_K_MAC_MAX 0xCF +#define FDDI_FC_K_ASYNC_LLC_MIN 0x50 +#define FDDI_FC_K_ASYNC_LLC_DEF 0x54 +#define FDDI_FC_K_ASYNC_LLC_MAX 0x5F +#define FDDI_FC_K_SYNC_LLC_MIN 0xD0 +#define FDDI_FC_K_SYNC_LLC_MAX 0xD7 +#define FDDI_FC_K_IMPLEMENTOR_MIN 0x60 +#define FDDI_FC_K_IMPLEMENTOR_MAX 0x6F +#define FDDI_FC_K_RESERVED_MIN 0x70 +#define FDDI_FC_K_RESERVED_MAX 0x7F + +/* Define LLC and SNAP constants */ +#define FDDI_EXTENDED_SAP 0xAA +#define FDDI_UI_CMD 0x03 + +/* Define 802.2 Type 1 header */ +struct fddi_8022_1_hdr + { + __u8 dsap; /* destination service access point */ + __u8 ssap; /* source service access point */ + __u8 ctrl; /* control byte #1 */ + } __attribute__ ((packed)); + +/* Define 802.2 Type 2 header */ +struct fddi_8022_2_hdr + { + __u8 dsap; /* destination service access point */ + __u8 ssap; /* source service access point */ + __u8 ctrl_1; /* control byte #1 */ + __u8 ctrl_2; /* control byte #2 */ + } __attribute__ ((packed)); + +/* Define 802.2 SNAP header */ +#define FDDI_K_OUI_LEN 3 +struct fddi_snap_hdr + { + __u8 dsap; /* always 0xAA */ + __u8 ssap; /* always 0xAA */ + __u8 ctrl; /* always 0x03 */ + __u8 oui[FDDI_K_OUI_LEN]; /* organizational universal id */ + __u16 ethertype; /* packet type ID field */ + } __attribute__ ((packed)); + +/* Define FDDI LLC frame header */ +struct fddihdr + { + __u8 fc; /* frame control */ + __u8 daddr[FDDI_K_ALEN]; /* destination address */ + __u8 saddr[FDDI_K_ALEN]; /* source address */ + union + { + struct fddi_8022_1_hdr llc_8022_1; + struct fddi_8022_2_hdr llc_8022_2; + struct fddi_snap_hdr llc_snap; + } hdr; + } __attribute__ ((packed)); + +/* Define FDDI statistics structure */ +struct fddi_statistics + { + __u32 rx_packets; /* total packets received */ + __u32 tx_packets; /* total packets transmitted */ + __u32 rx_errors; /* bad packets received */ + __u32 tx_errors; /* packet transmit problems */ + __u32 rx_dropped; /* no space in linux buffers */ + __u32 tx_dropped; /* no space available in linux */ + __u32 multicast; /* multicast packets received */ + __u32 transmit_collision; /* always 0 for FDDI */ + + /* Detailed FDDI statistics. Adopted from RFC 1512 */ + + __u8 smt_station_id[8]; + __u32 smt_op_version_id; + __u32 smt_hi_version_id; + __u32 smt_lo_version_id; + __u8 smt_user_data[32]; + __u32 smt_mib_version_id; + __u32 smt_mac_cts; + __u32 smt_non_master_cts; + __u32 smt_master_cts; + __u32 smt_available_paths; + __u32 smt_config_capabilities; + __u32 smt_config_policy; + __u32 smt_connection_policy; + __u32 smt_t_notify; + __u32 smt_stat_rpt_policy; + __u32 smt_trace_max_expiration; + __u32 smt_bypass_present; + __u32 smt_ecm_state; + __u32 smt_cf_state; + __u32 smt_remote_disconnect_flag; + __u32 smt_station_status; + __u32 smt_peer_wrap_flag; + __u32 smt_time_stamp; + __u32 smt_transition_time_stamp; + __u32 mac_frame_status_functions; + __u32 mac_t_max_capability; + __u32 mac_tvx_capability; + __u32 mac_available_paths; + __u32 mac_current_path; + __u8 mac_upstream_nbr[FDDI_K_ALEN]; + __u8 mac_downstream_nbr[FDDI_K_ALEN]; + __u8 mac_old_upstream_nbr[FDDI_K_ALEN]; + __u8 mac_old_downstream_nbr[FDDI_K_ALEN]; + __u32 mac_dup_address_test; + __u32 mac_requested_paths; + __u32 mac_downstream_port_type; + __u8 mac_smt_address[FDDI_K_ALEN]; + __u32 mac_t_req; + __u32 mac_t_neg; + __u32 mac_t_max; + __u32 mac_tvx_value; + __u32 mac_frame_cts; + __u32 mac_copied_cts; + __u32 mac_transmit_cts; + __u32 mac_error_cts; + __u32 mac_lost_cts; + __u32 mac_frame_error_threshold; + __u32 mac_frame_error_ratio; + __u32 mac_rmt_state; + __u32 mac_da_flag; + __u32 mac_una_da_flag; + __u32 mac_frame_error_flag; + __u32 mac_ma_unitdata_available; + __u32 mac_hardware_present; + __u32 mac_ma_unitdata_enable; + __u32 path_tvx_lower_bound; + __u32 path_t_max_lower_bound; + __u32 path_max_t_req; + __u32 path_configuration[8]; + __u32 port_my_type[2]; + __u32 port_neighbor_type[2]; + __u32 port_connection_policies[2]; + __u32 port_mac_indicated[2]; + __u32 port_current_path[2]; + __u8 port_requested_paths[3*2]; + __u32 port_mac_placement[2]; + __u32 port_available_paths[2]; + __u32 port_pmd_class[2]; + __u32 port_connection_capabilities[2]; + __u32 port_bs_flag[2]; + __u32 port_lct_fail_cts[2]; + __u32 port_ler_estimate[2]; + __u32 port_lem_reject_cts[2]; + __u32 port_lem_cts[2]; + __u32 port_ler_cutoff[2]; + __u32 port_ler_alarm[2]; + __u32 port_connect_state[2]; + __u32 port_pcm_state[2]; + __u32 port_pc_withhold[2]; + __u32 port_ler_flag[2]; + __u32 port_hardware_present[2]; + }; + +#endif /* _LINUX_IF_FDDI_H */ diff -u --recursive --new-file v2.1.10/linux/include/linux/igmp.h linux/include/linux/igmp.h --- v2.1.10/linux/include/linux/igmp.h Sat Aug 17 20:28:10 1996 +++ linux/include/linux/igmp.h Mon Nov 18 11:31:32 1996 @@ -36,6 +36,7 @@ #define IGMP_HOST_MEMBERSHIP_REPORT 0x12 /* Ditto */ #define IGMP_DVMRP 0x13 /* DVMRP routing */ #define IGMP_PIM 0x14 /* PIM routing */ +#define IGMP_TRACE 0x15 /* CISCO trace */ #define IGMP_HOST_NEW_MEMBERSHIP_REPORT 0x16 /* New version of 0x11 */ #define IGMP_HOST_LEAVE_MESSAGE 0x17 /* An extra BSD seems to send */ @@ -90,7 +91,8 @@ unsigned long multiaddr; struct ip_mc_list *next; struct timer_list timer; - int tm_running; + short tm_running; + short reporter; int users; }; diff -u --recursive --new-file v2.1.10/linux/include/linux/in.h linux/include/linux/in.h --- v2.1.10/linux/include/linux/in.h Fri Nov 15 23:49:10 1996 +++ linux/include/linux/in.h Mon Nov 18 15:11:02 1996 @@ -57,7 +57,7 @@ /* Structure describing an Internet (IP) socket address. */ #define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */ struct sockaddr_in { - unsigned short int sin_family; /* Address family */ + sa_family_t sin_family; /* Address family */ unsigned short int sin_port; /* Port number */ struct in_addr sin_addr; /* Internet address */ diff -u --recursive --new-file v2.1.10/linux/include/linux/ipx.h linux/include/linux/ipx.h --- v2.1.10/linux/include/linux/ipx.h Mon May 13 23:39:28 1996 +++ linux/include/linux/ipx.h Mon Nov 18 11:31:32 1996 @@ -6,11 +6,11 @@ struct sockaddr_ipx { - short sipx_family; - short sipx_port; - unsigned long sipx_network; - unsigned char sipx_node[IPX_NODE_LEN]; - unsigned char sipx_type; + sa_family_t sipx_family; + __u16 sipx_port; + __u32 sipx_network; + unsigned char sipx_node[IPX_NODE_LEN]; + __u8 sipx_type; unsigned char sipx_zero; /* 16 byte fill */ }; diff -u --recursive --new-file v2.1.10/linux/include/linux/major.h linux/include/linux/major.h --- v2.1.10/linux/include/linux/major.h Tue Nov 12 15:56:14 1996 +++ linux/include/linux/major.h Sat Nov 16 13:00:34 1996 @@ -8,8 +8,8 @@ /* limits */ -#define MAX_CHRDEV 64 -#define MAX_BLKDEV 64 +#define MAX_CHRDEV 128 +#define MAX_BLKDEV 128 #define UNNAMED_MAJOR 0 #define MEM_MAJOR 1 diff -u --recursive --new-file v2.1.10/linux/include/linux/net.h linux/include/linux/net.h --- v2.1.10/linux/include/linux/net.h Mon Sep 9 16:23:58 1996 +++ linux/include/linux/net.h Mon Nov 18 11:31:32 1996 @@ -92,14 +92,14 @@ int (*dup) (struct socket *newsock, struct socket *oldsock); int (*release) (struct socket *sock, struct socket *peer); int (*bind) (struct socket *sock, struct sockaddr *umyaddr, - int sockaddr_len); + size_t sockaddr_len); int (*connect) (struct socket *sock, struct sockaddr *uservaddr, - int sockaddr_len, int flags); + size_t sockaddr_len, int flags); int (*socketpair) (struct socket *sock1, struct socket *sock2); int (*accept) (struct socket *sock, struct socket *newsock, int flags); int (*getname) (struct socket *sock, struct sockaddr *uaddr, - int *usockaddr_len, int peer); + size_t *usockaddr_len, int peer); int (*select) (struct socket *sock, int sel_type, select_table *wait); int (*ioctl) (struct socket *sock, unsigned int cmd, diff -u --recursive --new-file v2.1.10/linux/include/linux/netdevice.h linux/include/linux/netdevice.h --- v2.1.10/linux/include/linux/netdevice.h Tue Nov 12 15:56:14 1996 +++ linux/include/linux/netdevice.h Mon Nov 18 15:13:18 1996 @@ -295,6 +295,7 @@ /* These functions live elsewhere (drivers/net/net_init.c, but related) */ extern void ether_setup(struct device *dev); +extern void fddi_setup(struct device *dev); extern void tr_setup(struct device *dev); extern int ether_config(struct device *dev, struct ifmap *map); /* Support for loadable net-drivers */ diff -u --recursive --new-file v2.1.10/linux/include/linux/rose.h linux/include/linux/rose.h --- v2.1.10/linux/include/linux/rose.h Tue Nov 12 15:56:14 1996 +++ linux/include/linux/rose.h Mon Nov 18 11:31:32 1996 @@ -26,7 +26,7 @@ } rose_address; struct sockaddr_rose { - short srose_family; + sa_family_t srose_family; rose_address srose_addr; ax25_address srose_call; int srose_ndigis; diff -u --recursive --new-file v2.1.10/linux/include/linux/sched.h linux/include/linux/sched.h --- v2.1.10/linux/include/linux/sched.h Mon Sep 30 11:19:00 1996 +++ linux/include/linux/sched.h Mon Nov 18 15:11:02 1996 @@ -320,7 +320,7 @@ * On a single processor system this comes out as current_set[0] when cpp * has finished with it, which gcc will optimise away. */ -#define current (0+current_set[smp_processor_id()]) /* Current on this processor */ +#define current (current_set[smp_processor_id()]) /* Current on this processor */ extern unsigned long volatile jiffies; extern unsigned long itimer_ticks; extern unsigned long itimer_next; diff -u --recursive --new-file v2.1.10/linux/include/linux/skbuff.h linux/include/linux/skbuff.h --- v2.1.10/linux/include/linux/skbuff.h Fri Nov 15 23:49:10 1996 +++ linux/include/linux/skbuff.h Mon Nov 18 15:11:13 1996 @@ -184,6 +184,16 @@ return (list->next == (struct sk_buff *) list); } +extern __inline__ struct sk_buff *skb_unshare(struct sk_buff *skb, int pri, int dir) +{ + struct sk_buff *nskb; + if(skb->users==1) + return skb; + nskb=skb_copy(skb, pri); + kfree_skb(skb, dir); /* Free our shared copy */ + return nskb; +} + /* * Peek an sk_buff. Unlike most other operations you _MUST_ * be careful with this one. A peek leaves the buffer on the @@ -402,13 +412,14 @@ extern __inline__ unsigned char *skb_put(struct sk_buff *skb, int len) { + extern char *skb_put_errstr; unsigned char *tmp=skb->tail; skb->tail+=len; skb->len+=len; if(skb->tail>skb->end) { __label__ here; - panic("skput:over: %p:%d", &&here,len); + panic(skb_put_errstr,&&here,len); here: } return tmp; @@ -416,12 +427,13 @@ extern __inline__ unsigned char *skb_push(struct sk_buff *skb, int len) { + extern char *skb_push_errstr; skb->data-=len; skb->len+=len; if(skb->datahead) { __label__ here; - panic("skpush:under: %p:%d", &&here,len); + panic(skb_push_errstr, &&here,len); here: } return skb->data; diff -u --recursive --new-file v2.1.10/linux/include/linux/socket.h linux/include/linux/socket.h --- v2.1.10/linux/include/linux/socket.h Fri Nov 15 23:49:10 1996 +++ linux/include/linux/socket.h Mon Nov 18 11:31:32 1996 @@ -5,9 +5,15 @@ #include /* the SIOCxxx I/O controls */ #include /* iovec support */ +typedef unsigned short sa_family_t; + +/* + * 1003.1g requires sa_family_t and that sa_data is char. + */ + struct sockaddr { - unsigned short sa_family; /* address family, AF_xxx */ + sa_family_t sa_family; /* address family, AF_xxx */ char sa_data[14]; /* 14 bytes of protocol address */ }; @@ -25,11 +31,11 @@ struct msghdr { void * msg_name; /* Socket name */ - int msg_namelen; /* Length of name */ + size_t msg_namelen; /* Length of name */ struct iovec * msg_iov; /* Data blocks */ - int msg_iovlen; /* Number of blocks */ + size_t msg_iovlen; /* Number of blocks */ void * msg_control; /* Per protocol magic (eg BSD file descriptor passing) */ - int msg_controllen; /* Length of rights list */ + size_t msg_controllen; /* Length of rights list */ int msg_flags; /* 4.4 BSD item we dont use */ }; @@ -90,6 +96,7 @@ /* Supported address families. */ #define AF_UNSPEC 0 #define AF_UNIX 1 /* Unix domain sockets */ +#define AF_LOCAL 1 /* POSIX name for AF_UNIX */ #define AF_INET 2 /* Internet IP Protocol */ #define AF_AX25 3 /* Amateur Radio AX.25 */ #define AF_IPX 4 /* Novell IPX */ @@ -100,11 +107,14 @@ #define AF_X25 9 /* Reserved for X.25 project */ #define AF_INET6 10 /* IP version 6 */ #define AF_ROSE 11 /* Amateur Radio X.25 PLP */ -#define AF_MAX 13 /* For now.. */ +#define AF_DECNET 12 /* Reserved for DECnet project */ +#define AF_NETBEUI 13 /* Reserved for 802.2LLC project*/ +#define AF_MAX 32 /* For now.. */ /* Protocol families, same as address families. */ #define PF_UNSPEC AF_UNSPEC #define PF_UNIX AF_UNIX +#define PF_LOCAL AF_LOCAL #define PF_INET AF_INET #define PF_AX25 AF_AX25 #define PF_IPX AF_IPX @@ -115,18 +125,26 @@ #define PF_X25 AF_X25 #define PF_INET6 AF_INET6 #define PR_ROSE AF_ROSE +#define PF_DECNET AF_DECNET +#define PF_NETBEUI AF_NETBEUI #define PF_MAX AF_MAX /* Maximum queue length specifiable by listen. */ #define SOMAXCONN 128 -/* Flags we can use with send/ and recv. */ +/* Flags we can use with send/ and recv. + Added those for 1003.1g not all are supported yet + */ + #define MSG_OOB 1 #define MSG_PEEK 2 #define MSG_DONTROUTE 4 -/*#define MSG_CTRUNC 8 - We need to support this for BSD oddments */ +#define MSG_CTRUNC 8 /* We need to support this for BSD oddments */ #define MSG_PROXY 16 /* Supply or ask second address. */ +#define MSG_EOR 32 /* End of record */ +#define MSG_TRUNC 64 /* Data was discarded before delivery */ +#define MSG_WAITALL 128 /* Wait for a full request */ /* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */ #define SOL_IP 0 @@ -138,6 +156,7 @@ #define SOL_ATALK 258 #define SOL_NETROM 259 #define SOL_ROSE 260 +#define SOL_DECNET 261 #define SOL_TCP 6 #define SOL_UDP 17 diff -u --recursive --new-file v2.1.10/linux/include/linux/uio.h linux/include/linux/uio.h --- v2.1.10/linux/include/linux/uio.h Thu Jun 6 21:22:24 1996 +++ linux/include/linux/uio.h Mon Nov 18 11:31:32 1996 @@ -16,10 +16,14 @@ struct iovec { - void *iov_base; /* BSD uses caddr_t (same thing in effect) */ - int iov_len; + void *iov_base; /* BSD uses caddr_t (1003.1g requires void *) */ + size_t iov_len; /* Must be size_t (1003.1g) */ }; +/* + * UIO_MAXIOV shall be at least 16 1003.1g (5.4.1.1) + */ + #define UIO_MAXIOV 16 /* Maximum iovec's in one operation 16 matches BSD */ diff -u --recursive --new-file v2.1.10/linux/include/linux/un.h linux/include/linux/un.h --- v2.1.10/linux/include/linux/un.h Sun Nov 10 20:12:15 1996 +++ linux/include/linux/un.h Mon Nov 18 11:31:32 1996 @@ -4,7 +4,7 @@ #define UNIX_PATH_MAX 108 struct sockaddr_un { - unsigned short sun_family; /* AF_UNIX */ + sa_family_t sun_family; /* AF_UNIX */ char sun_path[UNIX_PATH_MAX]; /* pathname */ }; diff -u --recursive --new-file v2.1.10/linux/include/net/ax25.h linux/include/net/ax25.h --- v2.1.10/linux/include/net/ax25.h Tue Nov 12 15:56:14 1996 +++ linux/include/net/ax25.h Mon Nov 18 15:13:22 1996 @@ -128,8 +128,8 @@ #define AX25_VALUES_T1 7 /* Default T1 timeout value */ #define AX25_VALUES_T2 8 /* Default T2 timeout value */ #define AX25_VALUES_T3 9 /* Default T3 timeout value */ -#define AX25_VALUES_N2 10 /* Default N2 value */ -#define AX25_VALUES_IDLE 11 /* mode vc idle timer */ +#define AX25_VALUES_IDLE 10 /* mode vc idle timer */ +#define AX25_VALUES_N2 11 /* Default N2 value */ #define AX25_VALUES_PACLEN 12 /* AX.25 MTU */ #define AX25_VALUES_MAXQUEUE 13 /* Maximum number of buffers enqueued */ #define AX25_VALUES_DIGI 14 /* Digipeat mode */ diff -u --recursive --new-file v2.1.10/linux/include/net/br.h linux/include/net/br.h --- v2.1.10/linux/include/net/br.h Fri Apr 12 09:49:47 1996 +++ linux/include/net/br.h Mon Nov 18 11:31:32 1996 @@ -161,15 +161,29 @@ #define IS_BRIDGED 0x2e + +#define BR_MAX_PROTOCOLS 32 +#define BR_MAX_PROT_STATS BR_MAX_PROTOCOLS + +/* policy values for policy field */ +#define BR_ACCEPT 1 +#define BR_REJECT 0 + struct br_stat { unsigned int flags; Bridge_data bridge_data; Port_data port_data[No_of_ports]; + unsigned int policy; + unsigned int exempt_protocols; + unsigned short protocols[BR_MAX_PROTOCOLS]; + unsigned short prot_id[BR_MAX_PROT_STATS]; /* Protocol encountered */ + unsigned int prot_counter[BR_MAX_PROT_STATS]; /* How many packets ? */ }; /* defined flags for br_stat.flags */ #define BR_UP 0x0001 /* bridging enabled */ #define BR_DEBUG 0x0002 /* debugging enabled */ +#define BR_PROT_STATS 0x0004 /* protocol statistics enabled */ struct br_cf { unsigned int cmd; @@ -188,6 +202,11 @@ #define BRCMD_DISPLAY_FDB 8 /* arg1 = port */ #define BRCMD_ENABLE_DEBUG 9 #define BRCMD_DISABLE_DEBUG 10 +#define BRCMD_SET_POLICY 11 /* arg1 = default policy (1==bridge all) */ +#define BRCMD_EXEMPT_PROTOCOL 12 /* arg1 = protocol (see net/if_ether.h) */ +#define BRCMD_ENABLE_PROT_STATS 13 +#define BRCMD_DISABLE_PROT_STATS 14 +#define BRCMD_ZERO_PROT_STATS 15 /* prototypes of all bridging functions... */ @@ -260,6 +279,8 @@ int br_receive_frame(struct sk_buff *skb); /* 3.5 */ int br_tx_frame(struct sk_buff *skb); int br_ioctl(unsigned int cmd, void *arg); + +int br_protocol_ok(unsigned short protocol); void free_fdb(struct fdb *); struct fdb *get_fdb(void); diff -u --recursive --new-file v2.1.10/linux/include/net/inet_common.h linux/include/net/inet_common.h --- v2.1.10/linux/include/net/inet_common.h Sun Nov 10 20:12:15 1996 +++ linux/include/net/inet_common.h Mon Nov 18 11:31:32 1996 @@ -17,7 +17,7 @@ struct socket *peer); extern int inet_connect(struct socket *sock, struct sockaddr * uaddr, - int addr_len, int flags); + size_t addr_len, int flags); extern int inet_accept(struct socket *sock, struct socket *newsock, int flags); extern int inet_recvmsg(struct socket *sock, diff -u --recursive --new-file v2.1.10/linux/include/net/netlink.h linux/include/net/netlink.h --- v2.1.10/linux/include/net/netlink.h Sun Nov 10 20:12:16 1996 +++ linux/include/net/netlink.h Mon Nov 18 15:17:31 1996 @@ -2,16 +2,17 @@ #define __NET_NETLINK_H #define NET_MAJOR 36 /* Major 18 is reserved for networking */ -#define MAX_LINKS 12 /* 18,0 for route updates, 18,1 for SKIP, 18,2 debug tap 18,3 PPP reserved */ +#define MAX_LINKS 16 /* 18,0 for route updates, 18,1 for SKIP, 18,2 debug tap 18,3 PPP reserved */ /* 4-7 are psi0-psi3 8 is arpd 9 is ppp */ /* 10 is for IPSEC */ /* 11 IPv6 route updates */ + /* 12 is for firewall trapout */ #define MAX_QBYTES 32768 /* Maximum bytes in the queue */ #include -extern int netlink_attach(int unit, int (*function)(struct sk_buff *skb)); -extern int netlink_donothing(struct sk_buff *skb); +extern int netlink_attach(int unit, int (*function)(int,struct sk_buff *skb)); +extern int netlink_donothing(int, struct sk_buff *skb); extern void netlink_detach(int unit); extern int netlink_post(int unit, struct sk_buff *skb); extern int init_netlink(void); @@ -22,9 +23,9 @@ #define NETLINK_FIREWALL 3 /* Firewalling hook */ #define NETLINK_PSI 4 /* PSI devices - 4 to 7 */ #define NETLINK_ARPD 8 -#define NETLINK_NET_PPP 9 /* Non tty PPP devices */ #define NETLINK_IPSEC 10 /* IPSEC */ #define NETLINK_ROUTE6 11 /* af_inet6 route comm channel */ +#define NETLINK_ #ifdef CONFIG_RTNETLINK extern void ip_netlink_msg(unsigned long, __u32, __u32, __u32, short, short, char *); diff -u --recursive --new-file v2.1.10/linux/include/net/protocol.h linux/include/net/protocol.h --- v2.1.10/linux/include/net/protocol.h Sun Nov 10 20:12:16 1996 +++ linux/include/net/protocol.h Mon Nov 18 15:13:22 1996 @@ -41,7 +41,7 @@ int redo, struct inet_protocol *protocol); void (*err_handler)(int type, int code, unsigned char *buff, __u32 info, __u32 daddr, __u32 saddr, - struct inet_protocol *protocol); + struct inet_protocol *protocol, int len); struct inet_protocol *next; unsigned char protocol; unsigned char copy:1; diff -u --recursive --new-file v2.1.10/linux/include/net/sock.h linux/include/net/sock.h --- v2.1.10/linux/include/net/sock.h Tue Nov 12 15:56:15 1996 +++ linux/include/net/sock.h Mon Nov 18 15:13:22 1996 @@ -511,7 +511,7 @@ unsigned long timeout); int (*connect)(struct sock *sk, struct sockaddr *uaddr, - int addr_len); + size_t addr_len); struct sock * (*accept) (struct sock *sk, int flags); void (*retransmit)(struct sock *sk, int all); @@ -537,7 +537,7 @@ int len, int noblock, int flags, int *addr_len); int (*bind)(struct sock *sk, - struct sockaddr *uaddr, int addr_len); + struct sockaddr *uaddr, size_t addr_len); int (*backlog_rcv) (struct sock *sk, struct sk_buff *skb); diff -u --recursive --new-file v2.1.10/linux/include/net/tcp.h linux/include/net/tcp.h --- v2.1.10/linux/include/net/tcp.h Fri Nov 15 23:49:10 1996 +++ linux/include/net/tcp.h Mon Nov 18 15:16:59 1996 @@ -240,7 +240,8 @@ extern void tcp_v4_err(int type, int code, unsigned char *header, __u32 info, __u32 daddr, __u32 saddr, - struct inet_protocol *protocol); + struct inet_protocol *protocol, + int len); extern void tcp_shutdown (struct sock *sk, int how); @@ -315,7 +316,7 @@ struct sk_buff *skb); extern int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, - int addr_len); + size_t addr_len); extern void tcp_read_wakeup(struct sock *); diff -u --recursive --new-file v2.1.10/linux/include/net/udp.h linux/include/net/udp.h --- v2.1.10/linux/include/net/udp.h Sun Nov 10 20:12:18 1996 +++ linux/include/net/udp.h Mon Nov 18 11:31:33 1996 @@ -33,16 +33,11 @@ extern void udp_err(int type, int code, unsigned char *header, __u32 info, __u32 daddr, __u32 saddr, - struct inet_protocol *protocol); + struct inet_protocol *protocol, int len); extern void udp_send_check(struct udphdr *uh, __u32 saddr, __u32 daddr, int len, struct sock *sk); -extern int udp_recvfrom(struct sock *sk, unsigned char *to, - int len, int noblock, unsigned flags, - struct sockaddr_in *sin, int *addr_len); -extern int udp_read(struct sock *sk, unsigned char *buff, - int len, int noblock, unsigned flags); extern int udp_connect(struct sock *sk, - struct sockaddr *usin, int addr_len); + struct sockaddr *usin, size_t addr_len); extern int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len, int noblock, int flags); diff -u --recursive --new-file v2.1.10/linux/kernel/info.c linux/kernel/info.c --- v2.1.10/linux/kernel/info.c Tue Oct 29 19:58:48 1996 +++ linux/kernel/info.c Mon Nov 18 12:14:26 1996 @@ -17,12 +17,8 @@ asmlinkage int sys_sysinfo(struct sysinfo *info) { - int error; struct sysinfo val; - error = verify_area(VERIFY_WRITE, info, sizeof(struct sysinfo)); - if (error) - return error; memset((char *)&val, 0, sizeof(struct sysinfo)); val.uptime = jiffies / HZ; @@ -36,6 +32,7 @@ si_meminfo(&val); si_swapinfo(&val); - copy_to_user(info, &val, sizeof(struct sysinfo)); + if (copy_to_user(info, &val, sizeof(struct sysinfo))) + return -EFAULT; return 0; } diff -u --recursive --new-file v2.1.10/linux/kernel/itimer.c linux/kernel/itimer.c --- v2.1.10/linux/kernel/itimer.c Tue Oct 29 19:58:48 1996 +++ linux/kernel/itimer.c Sat Nov 16 13:11:17 1996 @@ -88,11 +88,7 @@ error = _getitimer(which, &get_buffer); if (error) return error; - error = verify_area(VERIFY_WRITE, value, sizeof(struct itimerval)); - if (error) - return error; - copy_to_user(value, &get_buffer, sizeof(get_buffer)); - return 0; + return copy_to_user(value, &get_buffer, sizeof(get_buffer)) ? -EFAULT : 0; } void it_real_fn(unsigned long __data) @@ -162,20 +158,17 @@ error = verify_area(VERIFY_READ, value, sizeof(*value)); if (error) return error; - copy_from_user(&set_buffer, value, sizeof(set_buffer)); + error = copy_from_user(&set_buffer, value, sizeof(set_buffer)); + if (error) + return -EFAULT; } else memset((char *) &set_buffer, 0, sizeof(set_buffer)); - if (ovalue) { - error = verify_area(VERIFY_WRITE, ovalue, sizeof(struct itimerval)); - if (error) - return error; - } - error = _setitimer(which, &set_buffer, ovalue ? &get_buffer : 0); if (error || !ovalue) return error; - copy_to_user(ovalue, &get_buffer, sizeof(get_buffer)); + if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer))) + error = -EFAULT; return error; } diff -u --recursive --new-file v2.1.10/linux/kernel/module.c linux/kernel/module.c --- v2.1.10/linux/kernel/module.c Sun Nov 10 20:12:19 1996 +++ linux/kernel/module.c Sat Nov 16 13:11:18 1996 @@ -54,7 +54,6 @@ static int freeing_modules; /* true if some modules are marked for deletion */ static struct module *find_module( const char *name); -static int get_mod_name( char *user_name, char *buf); static int free_modules( void); extern struct symbol_table symbol_table; /* in kernel/ksyms.c */ @@ -75,6 +74,21 @@ kernel_module.name = ""; } + +/* + * Copy the name of a module from user space. + */ +inline int +get_mod_name(char *user_name, char *buf) +{ + /* Should return -EBIG instead of -EFAULT when the name + is too long, but that we couldn't detect real faults then. + Maybe strncpy_from_user() should return -EBIG, when + the source string is too long. */ + return strncpy_from_user(buf, user_name, MOD_MAX_NAME); +} + + /* * Allocate space for a module. */ @@ -128,6 +142,7 @@ return (unsigned long) addr; } + /* * Initialize a module. */ @@ -157,7 +172,8 @@ return error; pr_debug("initializing module `%s', %d (0x%x) bytes\n", name, codesize, codesize); - copy_from_user(&rt, routines, sizeof rt); + if (copy_from_user(&rt, routines, sizeof rt)) + return -EFAULT; if ((mp = find_module(name)) == NULL) return -ENOENT; if (codesize & MOD_AUTOCLEAN) { @@ -170,7 +186,8 @@ } if ((codesize + sizeof (long) + PAGE_SIZE - 1) / PAGE_SIZE > mp->size) return -EINVAL; - copy_from_user((char *)mp->addr + sizeof (long), code, codesize); + if (copy_from_user((char *)mp->addr + sizeof (long), code, codesize)) + return -EFAULT; memset((char *)mp->addr + sizeof (long) + codesize, 0, mp->size * PAGE_SIZE - (codesize + sizeof (long))); pr_debug("module init entry = 0x%08lx, cleanup entry = 0x%08lx\n", @@ -190,19 +207,17 @@ int i; int legal_start; - if ((error = verify_area(VERIFY_READ, &symtab->size, sizeof(symtab->size)))) - return error; - get_user(size, &symtab->size); - + error = get_user(size, &symtab->size); + if (error) + return error; if ((newtab = (struct symbol_table*) kmalloc(size, GFP_KERNEL)) == NULL) { return -ENOMEM; } - if ((error = verify_area(VERIFY_READ, symtab, size))) { - kfree_s(newtab, size); - return error; + if (copy_from_user((char *)(newtab), symtab, size)) { + kfree_s(newtab, size); + return -EFAULT; } - copy_from_user((char *)(newtab), symtab, size); /* sanity check */ legal_start = sizeof(struct symbol_table) + @@ -344,6 +359,7 @@ struct module *mp = module_list; int i; int nmodsyms = 0; + int err; for (mp = module_list; mp; mp = mp->next) { if (mp->symtab && mp->symtab->n_symbols) { @@ -358,16 +374,15 @@ if (table != NULL) { to = table; - if ((i = verify_area(VERIFY_WRITE, to, nmodsyms * sizeof(*table)))) - return i; - /* copy all module symbols first (always LIFO order) */ for (mp = module_list; mp; mp = mp->next) { if (mp->state == MOD_RUNNING) { /* magic: write module info as a pseudo symbol */ isym.value = (unsigned long)mp; sprintf(isym.name, "#%s", mp->name); - copy_to_user(to, &isym, sizeof isym); + err = copy_to_user(to, &isym, sizeof isym); + if (err) + return -EFAULT; ++to; if (mp->symtab != NULL) { @@ -377,7 +392,9 @@ isym.value = (unsigned long)from->addr; strncpy(isym.name, from->name, sizeof isym.name); - copy_to_user(to, &isym, sizeof isym); + err = copy_to_user(to, &isym, sizeof isym); + if (err) + return -EFAULT; } } } @@ -386,27 +403,6 @@ return nmodsyms; } - - -/* - * Copy the name of a module from user space. - */ -int -get_mod_name(char *user_name, char *buf) -{ - int i; - - i = 0; - for (;;) { - get_user(buf[i], user_name + i); - if (buf[i] == '\0') - break; - if (++i >= MOD_MAX_NAME) - return -E2BIG; - } - return 0; -} - /* * Look for a module by name, ignoring modules marked for deletion. diff -u --recursive --new-file v2.1.10/linux/kernel/panic.c linux/kernel/panic.c --- v2.1.10/linux/kernel/panic.c Tue Oct 29 19:58:48 1996 +++ linux/kernel/panic.c Mon Nov 18 11:31:34 1996 @@ -58,11 +58,3 @@ for(;;); } -/* - * GCC 2.5.8 doesn't always optimize correctly; see include/asm/uaccess.h - */ - -int bad_user_access_length(void) -{ - panic("bad_user_access_length executed (not cool, dude)"); -} diff -u --recursive --new-file v2.1.10/linux/kernel/sched.c linux/kernel/sched.c --- v2.1.10/linux/kernel/sched.c Sun Nov 10 20:12:19 1996 +++ linux/kernel/sched.c Sat Nov 16 13:11:18 1996 @@ -1211,17 +1211,14 @@ static int setscheduler(pid_t pid, int policy, struct sched_param *param) { - int error; struct sched_param lp; struct task_struct *p; if (!param || pid < 0) return -EINVAL; - error = verify_area(VERIFY_READ, param, sizeof(struct sched_param)); - if (error) - return error; - copy_from_user(&lp, param, sizeof(struct sched_param)); + if (copy_from_user(&lp, param, sizeof(struct sched_param))) + return -EFAULT; p = find_process_by_pid(pid); if (!p) @@ -1286,25 +1283,18 @@ asmlinkage int sys_sched_getparam(pid_t pid, struct sched_param *param) { - int error; struct task_struct *p; struct sched_param lp; if (!param || pid < 0) return -EINVAL; - error = verify_area(VERIFY_WRITE, param, sizeof(struct sched_param)); - if (error) - return error; - p = find_process_by_pid(pid); if (!p) return -ESRCH; lp.sched_priority = p->rt_priority; - copy_to_user(param, &lp, sizeof(struct sched_param)); - - return 0; + return copy_to_user(param, &lp, sizeof(struct sched_param)) ? -EFAULT : 0; } asmlinkage int sys_sched_yield(void) @@ -1343,19 +1333,12 @@ asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval) { - int error; struct timespec t; - error = verify_area(VERIFY_WRITE, interval, sizeof(struct timespec)); - if (error) - return error; - t.tv_sec = 0; t.tv_nsec = 0; /* <-- Linus, please fill correct value in here */ return -ENOSYS; /* and then delete this line. Thanks! */ - copy_to_user(interval, &t, sizeof(struct timespec)); - - return 0; + return copy_to_user(interval, &t, sizeof(struct timespec)) ? -EFAULT : 0; } /* @@ -1387,16 +1370,9 @@ struct timespec t; unsigned long expire; - error = verify_area(VERIFY_READ, rqtp, sizeof(struct timespec)); + error = copy_from_user(&t, rqtp, sizeof(struct timespec)); if (error) - return error; - copy_from_user(&t, rqtp, sizeof(struct timespec)); - if (rmtp) { - error = verify_area(VERIFY_WRITE, rmtp, - sizeof(struct timespec)); - if (error) - return error; - } + return -EFAULT; if (t.tv_nsec >= 1000000000L || t.tv_nsec < 0 || t.tv_sec < 0) return -EINVAL; @@ -1420,7 +1396,8 @@ if (rmtp) { jiffiestotimespec(expire - jiffies - (expire > jiffies + 1), &t); - copy_to_user(rmtp, &t, sizeof(struct timespec)); + if (copy_to_user(rmtp, &t, sizeof(struct timespec))) + return -EFAULT; } return -EINTR; } diff -u --recursive --new-file v2.1.10/linux/kernel/signal.c linux/kernel/signal.c --- v2.1.10/linux/kernel/signal.c Tue Oct 29 19:58:48 1996 +++ linux/kernel/signal.c Sat Nov 16 13:11:18 1996 @@ -32,10 +32,9 @@ int error; if (set) { - error = verify_area(VERIFY_READ, set, sizeof(sigset_t)); + error = get_user(new_set, set); if (error) - return error; - get_user(new_set, set); + return error; new_set &= _BLOCKABLE; switch (how) { case SIG_BLOCK: @@ -52,10 +51,9 @@ } } if (oset) { - error = verify_area(VERIFY_WRITE, oset, sizeof(sigset_t)); + error = put_user(old_set, oset); if (error) - return error; - put_user(old_set, oset); + return error; } return 0; } @@ -80,12 +78,8 @@ asmlinkage int sys_sigpending(sigset_t *set) { - int error; /* fill in "set" with signals pending but blocked. */ - error = verify_area(VERIFY_WRITE, set, sizeof(sigset_t)); - if (!error) - put_user(current->blocked & current->signal, set); - return error; + return put_user(current->blocked & current->signal, set); } /* @@ -162,7 +156,8 @@ return err; if (signum==SIGKILL || signum==SIGSTOP) return -EINVAL; - copy_from_user(&new_sa, action, sizeof(struct sigaction)); + if (copy_from_user(&new_sa, action, sizeof(struct sigaction))) + return -EFAULT; if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) { err = verify_area(VERIFY_READ, new_sa.sa_handler, 1); if (err) @@ -170,10 +165,8 @@ } } if (oldaction) { - int err = verify_area(VERIFY_WRITE, oldaction, sizeof(*oldaction)); - if (err) - return err; - copy_to_user(oldaction, p, sizeof(struct sigaction)); + if (copy_to_user(oldaction, p, sizeof(struct sigaction))) + return -EFAULT; } if (action) { *p = new_sa; diff -u --recursive --new-file v2.1.10/linux/kernel/sys.c linux/kernel/sys.c --- v2.1.10/linux/kernel/sys.c Tue Oct 29 19:58:48 1996 +++ linux/kernel/sys.c Sat Nov 16 13:11:18 1996 @@ -578,14 +578,17 @@ asmlinkage long sys_times(struct tms * tbuf) { + int error; if (tbuf) { - int error = verify_area(VERIFY_WRITE,tbuf,sizeof *tbuf); + error = put_user(current->utime,&tbuf->tms_utime); + if (!error) + error = put_user(current->stime,&tbuf->tms_stime); + if (!error) + error = put_user(current->cutime,&tbuf->tms_cutime); + if (!error) + error = put_user(current->cstime,&tbuf->tms_cstime); if (error) - return error; - put_user(current->utime,&tbuf->tms_utime); - put_user(current->stime,&tbuf->tms_stime); - put_user(current->cutime,&tbuf->tms_cutime); - put_user(current->cstime,&tbuf->tms_cstime); + return error; } return jiffies; } @@ -706,40 +709,30 @@ break; } if (gidsetsize) { - int error; - error = verify_area(VERIFY_WRITE, grouplist, sizeof(gid_t) * gidsetsize); - if (error) - return error; if (i > gidsetsize) return -EINVAL; - - for (i = 0 ; i < NGROUPS ; i++) { - if (groups[i] == NOGROUP) - break; - put_user(groups[i], grouplist); - grouplist++; - } + if (copy_to_user(grouplist, groups, sizeof(*groups)*i)) + return -EFAULT; } return i; } asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist) { - int i; + int err; if (!suser()) return -EPERM; if (gidsetsize > NGROUPS) return -EINVAL; - i = verify_area(VERIFY_READ, grouplist, sizeof(gid_t) * gidsetsize); - if (i) - return i; - for (i = 0; i < gidsetsize; i++, grouplist++) { - get_user(current->groups[i], grouplist); - } - if (i < NGROUPS) - current->groups[i] = NOGROUP; - return 0; + err = copy_from_user(current->groups, grouplist, gidsetsize * sizeof(gid_t)); + if (err) { + gidsetsize = err/sizeof(gid_t); /* +1? */ + err = -EFAULT; + } + if (gidsetsize < NGROUPS) + current->groups[gidsetsize] = NOGROUP; + return err; } int in_group_p(gid_t grp) @@ -786,20 +779,26 @@ int error; if (!name) return -EFAULT; - error = verify_area(VERIFY_WRITE, name,sizeof *name); - if (error) - return error; - copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); - put_user(0,name->sysname+__OLD_UTS_LEN); - copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); - put_user(0,name->nodename+__OLD_UTS_LEN); - copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); - put_user(0,name->release+__OLD_UTS_LEN); - copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); - put_user(0,name->version+__OLD_UTS_LEN); - copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); - put_user(0,name->machine+__OLD_UTS_LEN); - return 0; + error = copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); + if (!error) + error = put_user(0,name->sysname+__OLD_UTS_LEN); + if (!error) + error = copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); + if (!error) + error = put_user(0,name->nodename+__OLD_UTS_LEN); + if (!error) + error = copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); + if (!error) + error = put_user(0,name->release+__OLD_UTS_LEN); + if (!error) + error = copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); + if (!error) + error = put_user(0,name->version+__OLD_UTS_LEN); + if (!error) + error = copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); + if (!error) + error = put_user(0,name->machine+__OLD_UTS_LEN); + return error ? -EFAULT : 0; } #endif @@ -812,10 +811,9 @@ return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; - error = verify_area(VERIFY_READ, name, len); + error = copy_from_user(system_utsname.nodename, name, len); if (error) - return error; - copy_from_user(system_utsname.nodename, name, len); + return -EFAULT; system_utsname.nodename[len] = 0; return 0; } @@ -826,14 +824,10 @@ if (len < 0) return -EINVAL; - i = verify_area(VERIFY_WRITE, name, len); - if (i) - return i; i = 1+strlen(system_utsname.nodename); if (i > len) i = len; - copy_to_user(name, system_utsname.nodename, i); - return 0; + return copy_to_user(name, system_utsname.nodename, i) ? -EFAULT : 0; } /* @@ -848,25 +842,19 @@ return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; - error = verify_area(VERIFY_READ, name, len); + error = copy_from_user(system_utsname.domainname, name, len); if (error) - return error; - copy_from_user(system_utsname.domainname, name, len); + return -EFAULT; system_utsname.domainname[len] = 0; return 0; } asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim) { - int error; - if (resource >= RLIM_NLIMITS) return -EINVAL; - error = verify_area(VERIFY_WRITE,rlim,sizeof *rlim); - if (error) - return error; - copy_to_user(rlim, current->rlim + resource, sizeof(*rlim)); - return 0; + return copy_to_user(rlim, current->rlim + resource, sizeof(*rlim)) + ? -EFAULT : 0 ; } asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim) @@ -876,10 +864,9 @@ if (resource >= RLIM_NLIMITS) return -EINVAL; - err = verify_area(VERIFY_READ, rlim, sizeof(*rlim)); + err = copy_from_user(&new_rlim, rlim, sizeof(*rlim)); if (err) - return err; - copy_from_user(&new_rlim, rlim, sizeof(*rlim)); + return -EFAULT; old_rlim = current->rlim + resource; if (((new_rlim.rlim_cur > old_rlim->rlim_max) || (new_rlim.rlim_max > old_rlim->rlim_max)) && @@ -903,12 +890,8 @@ */ int getrusage(struct task_struct *p, int who, struct rusage *ru) { - int error; struct rusage r; - error = verify_area(VERIFY_WRITE, ru, sizeof *ru); - if (error) - return error; memset((char *) &r, 0, sizeof(r)); switch (who) { case RUSAGE_SELF: @@ -939,8 +922,7 @@ r.ru_nswap = p->nswap + p->cnswap; break; } - copy_to_user(ru, &r, sizeof(r)); - return 0; + return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0; } asmlinkage int sys_getrusage(int who, struct rusage *ru) diff -u --recursive --new-file v2.1.10/linux/kernel/time.c linux/kernel/time.c --- v2.1.10/linux/kernel/time.c Tue Nov 12 15:56:15 1996 +++ linux/kernel/time.c Sat Nov 16 13:11:18 1996 @@ -202,15 +202,13 @@ /* Local copy of parameter */ struct timex txc; - error = verify_area(VERIFY_WRITE, txc_p, sizeof(struct timex)); - if (error) - return error; - /* Copy the user data space into the kernel copy * structure. But bear in mind that the structures * may change */ - copy_from_user(&txc, txc_p, sizeof(struct timex)); + error = copy_from_user(&txc, txc_p, sizeof(struct timex)); + if (error) + return -EFAULT; /* In order to modify anything, you gotta be super-user! */ if (txc.modes && !suser()) @@ -345,6 +343,5 @@ sti(); - copy_to_user(txc_p, &txc, sizeof(struct timex)); - return time_state; + return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : time_state; } diff -u --recursive --new-file v2.1.10/linux/mm/swapfile.c linux/mm/swapfile.c --- v2.1.10/linux/mm/swapfile.c Tue Oct 29 19:58:48 1996 +++ linux/mm/swapfile.c Fri Nov 15 22:25:19 1996 @@ -518,7 +518,8 @@ p->flags = SWP_WRITEOK; p->pages = j; nr_swap_pages += j; - printk("Adding Swap: %dk swap-space\n",j<<(PAGE_SHIFT-10)); + printk("Adding Swap: %dk swap-space (priority %d)\n", + j<<(PAGE_SHIFT-10), p->prio); /* insert swap space into swap_list: */ prev = -1; diff -u --recursive --new-file v2.1.10/linux/net/802/Makefile linux/net/802/Makefile --- v2.1.10/linux/net/802/Makefile Tue Apr 9 14:36:31 1996 +++ linux/net/802/Makefile Mon Nov 18 11:31:34 1996 @@ -14,6 +14,10 @@ O_OBJS += tr.o endif +ifdef CONFIG_FDDI +O_OBJS += fddi.o +endif + ifdef CONFIG_IPX OX_OBJS += p8022.o psnap.o p8022tr.o endif diff -u --recursive --new-file v2.1.10/linux/net/802/fddi.c linux/net/802/fddi.c --- v2.1.10/linux/net/802/fddi.c Thu Jan 1 02:00:00 1970 +++ linux/net/802/fddi.c Mon Nov 18 11:31:34 1996 @@ -0,0 +1,162 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * FDDI-type device handling. + * + * Version: @(#)fddi.c 1.0.0 08/12/96 + * + * Authors: Lawrence V. Stefani, + * + * fddi.c is based on previous eth.c and tr.c work by + * Ross Biro, + * Fred N. van Kempen, + * Mark Evans, + * Florian La Roche, + * Alan Cox, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Create the FDDI MAC header for an arbitrary protocol layer + * + * saddr=NULL means use device source address + * daddr=NULL means leave destination address (eg unresolved arp) + */ + +int fddi_header( + struct sk_buff *skb, + struct device *dev, + unsigned short type, + void *daddr, + void *saddr, + unsigned len + ) + + { + struct fddihdr *fddi = (struct fddihdr *)skb_push(skb, FDDI_K_SNAP_HLEN); + + /* Fill in frame header - assume 802.2 SNAP frames for now */ + + fddi->fc = FDDI_FC_K_ASYNC_LLC_DEF; + fddi->hdr.llc_snap.dsap = FDDI_EXTENDED_SAP; + fddi->hdr.llc_snap.ssap = FDDI_EXTENDED_SAP; + fddi->hdr.llc_snap.ctrl = FDDI_UI_CMD; + fddi->hdr.llc_snap.oui[0] = 0x00; + fddi->hdr.llc_snap.oui[1] = 0x00; + fddi->hdr.llc_snap.oui[2] = 0x00; + fddi->hdr.llc_snap.ethertype = htons(type); + + /* Set the source and destination hardware addresses */ + + if (saddr != NULL) + memcpy(fddi->saddr, saddr, dev->addr_len); + else + memcpy(fddi->saddr, dev->dev_addr, dev->addr_len); + + if (daddr != NULL) + { + memcpy(fddi->daddr, daddr, dev->addr_len); + return(FDDI_K_SNAP_HLEN); + } + return(-FDDI_K_SNAP_HLEN); + } + + +/* + * Rebuild the FDDI MAC header. This is called after an ARP + * (or in future other address resolution) has completed on + * this sk_buff. We now let ARP fill in the other fields. + */ + +int fddi_rebuild_header( + void *buff, + struct device *dev, + unsigned long dest, + struct sk_buff *skb + ) + + { + struct fddihdr *fddi = (struct fddihdr *)buff; + + /* Only ARP/IP is currently supported */ + + if (fddi->hdr.llc_snap.ethertype != htons(ETH_P_IP)) + { + printk("fddi_rebuild_header: Don't know how to resolve type %04X addresses?\n", (unsigned int)htons(fddi->hdr.llc_snap.ethertype)); + return(0); + } + + /* Try to get ARP to resolve the header and fill destination address */ + + if (arp_find(fddi->daddr, dest, dev, dev->pa_addr, skb)) + return(1); + else + return(0); + } + + +/* + * Determine the packet's protocol ID and fill in skb fields. + * This routine is called before an incoming packet is passed + * up. It's used to fill in specific skb fields and to set + * the proper pointer to the start of packet data (skb->data). + */ + +unsigned short fddi_type_trans( + struct sk_buff *skb, + struct device *dev + ) + + { + struct fddihdr *fddi = (struct fddihdr *)skb->data; + + /* + * Set mac.raw field to point to FC byte, set data field to point + * to start of packet data. Assume 802.2 SNAP frames for now. + */ + + skb->mac.raw = skb->data; /* point to frame control (FC) */ + skb_pull(skb, FDDI_K_SNAP_HLEN); /* adjust for 21 byte header */ + + /* Set packet type based on destination address and flag settings */ + + if (*fddi->daddr & 0x01) + { + if (memcmp(fddi->daddr, dev->broadcast, FDDI_K_ALEN) == 0) + skb->pkt_type = PACKET_BROADCAST; + else + skb->pkt_type = PACKET_MULTICAST; + } + + else if (dev->flags & IFF_PROMISC) + { + if (memcmp(fddi->daddr, dev->dev_addr, FDDI_K_ALEN)) + skb->pkt_type = PACKET_OTHERHOST; + } + + /* Assume 802.2 SNAP frames, for now */ + + return(fddi->hdr.llc_snap.ethertype); + } diff -u --recursive --new-file v2.1.10/linux/net/Config.in linux/net/Config.in --- v2.1.10/linux/net/Config.in Tue Nov 12 15:56:15 1996 +++ linux/net/Config.in Mon Nov 18 11:31:34 1996 @@ -3,6 +3,10 @@ # mainmenu_option next_comment comment 'Networking options' +bool 'Kernel/User network link driver' CONFIG_NETLINK +if [ "$CONFIG_NETLINK" = "y" ]; then + bool 'Routing messages' CONFIG_RTNETLINK +fi bool 'Network firewalls' CONFIG_FIREWALL bool 'Network aliasing' CONFIG_NET_ALIAS bool 'TCP/IP networking' CONFIG_INET @@ -27,9 +31,5 @@ fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE -fi -bool 'Kernel/User network link driver' CONFIG_NETLINK -if [ "$CONFIG_NETLINK" = "y" ]; then - bool 'Routing messages' CONFIG_RTNETLINK fi endmenu diff -u --recursive --new-file v2.1.10/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c --- v2.1.10/linux/net/appletalk/ddp.c Fri Nov 15 23:49:10 1996 +++ linux/net/appletalk/ddp.c Mon Nov 18 11:31:34 1996 @@ -23,6 +23,7 @@ * Tom Dyas : Module support. * Alan Cox : Hooks for PPP (based on the * localtalk hook). + * Alan Cox : Posix bits * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -735,7 +736,6 @@ struct sockaddr_at *sa; struct device *dev; struct atalk_iface *atif; - int ro=(cmd==SIOCSIFADDR); int err; int ct; int limit; @@ -1234,7 +1234,7 @@ * Set the address 'our end' of the connection. */ -static int atalk_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len) +static int atalk_bind(struct socket *sock, struct sockaddr *uaddr,size_t addr_len) { atalk_socket *sk; struct sockaddr_at *addr=(struct sockaddr_at *)uaddr; @@ -1242,7 +1242,7 @@ sk=(atalk_socket *)sock->data; if(sk->zapped==0) - return(-EIO); + return(-EINVAL); if(addr_len!=sizeof(struct sockaddr_at)) return -EINVAL; @@ -1289,7 +1289,7 @@ */ static int atalk_connect(struct socket *sock, struct sockaddr *uaddr, - int addr_len, int flags) + size_t addr_len, int flags) { atalk_socket *sk=(atalk_socket *)sock->data; struct sockaddr_at *addr; @@ -1303,9 +1303,9 @@ if(addr->sat_family!=AF_APPLETALK) return -EAFNOSUPPORT; -#if 0 /* Netatalk doesn't check this */ +#if 0 /* Netatalk doesn't check this - fix netatalk first!*/ if(addr->sat_addr.s_node==ATADDR_BCAST && !sk->broadcast) - return -EPERM; + return -EACCES; #endif if(sk->zapped) { @@ -1350,7 +1350,7 @@ */ static int atalk_getname(struct socket *sock, struct sockaddr *uaddr, - int *uaddr_len, int peer) + size_t *uaddr_len, int peer) { struct sockaddr_at sat; atalk_socket *sk; @@ -1359,7 +1359,7 @@ if(sk->zapped) { if(atalk_autobind(sk)<0) - return -EBUSY; + return -ENOBUFS; } *uaddr_len = sizeof(struct sockaddr_at); @@ -1410,6 +1410,10 @@ * Fix up the length field [Ok this is horrible but otherwise * I end up with unions of bit fields and messy bit field order * compiler/endian dependencies..] + * + * FIXME: This is a write to a shared object. Granted it + * happens to be safe BUT.. (Its safe as user space will not + * run until we put it back) */ *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); @@ -1520,10 +1524,13 @@ * Send the buffer onwards */ - skb->arp = 1; /* Resolved */ - - if(aarp_send_ddp(rt->dev, skb, &ta, NULL)==-1) - kfree_skb(skb, FREE_READ); + skb=skb_unshare(skb, GFP_ATOMIC, FREE_READ); + if(skb) + { + skb->arp = 1; /* Resolved */ + if(aarp_send_ddp(rt->dev, skb, &ta, NULL)==-1) + kfree_skb(skb, FREE_READ); + } return 0; } @@ -1642,7 +1649,6 @@ if(usat) { if(sk->zapped) - /* put the autobinding in */ { if(atalk_autobind(sk)<0) return -EBUSY; @@ -1738,7 +1744,7 @@ if (err) { kfree_skb(skb, FREE_WRITE); - return err; + return -EFAULT; } if(sk->no_check==1) @@ -1821,9 +1827,6 @@ struct sk_buff *skb; int er = 0; - if(sk->err) - return sock_error(sk); - if(addr_len) *addr_len=sizeof(*sat); @@ -1836,7 +1839,10 @@ { copied=ddp->deh_len; if(copied > size) + { copied=size; + msg->msg_flags|=MSG_TRUNC; + } er = skb_copy_datagram_iovec(skb,0,msg->msg_iov,copied); if (er) goto out; @@ -1845,7 +1851,10 @@ { copied=ddp->deh_len - sizeof(*ddp); if (copied > size) + { copied = size; + msg->msg_flags|=MSG_TRUNC; + } er = skb_copy_datagram_iovec(skb,sizeof(*ddp),msg->msg_iov,copied); if (er) goto out; @@ -1881,7 +1890,6 @@ static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) { - int err; long amount=0; atalk_socket *sk=(atalk_socket *)sock->data; @@ -1908,7 +1916,7 @@ { if(sk->stamp.tv_sec==0) return -ENOENT; - return copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval)); + return copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval)) ? -EFAULT : 0; } return -EINVAL; /* @@ -2049,7 +2057,7 @@ proc_net_register(&proc_atalk_iface); #endif - printk(KERN_INFO "Appletalk 0.17 for Linux NET3.035\n"); + printk(KERN_INFO "Appletalk 0.18 for Linux NET3.037\n"); } #ifdef MODULE diff -u --recursive --new-file v2.1.10/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c --- v2.1.10/linux/net/ax25/af_ax25.c Tue Nov 12 15:56:15 1996 +++ linux/net/ax25/af_ax25.c Mon Nov 18 11:31:34 1996 @@ -1,10 +1,10 @@ /* - * AX.25 release 033 + * AX.25 release 034 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. * - * This code REQUIRES 1.2.1 or higher/ NET3.029 + * This code REQUIRES 2.1.10 or higher/ NET3.029 * * This module: * This module is free software; you can redistribute it and/or @@ -84,6 +84,8 @@ * AX.25 033 Jonathan(G4KLX) Removed auto-router. * Hans(PE1AYX) Converted to Module. * Joerg(DL1BKE) Moved BPQ Ethernet to seperate driver. + * AX.25 034 Jonathan(G4KLX) 2.1 changes + * Alan(GW4PTS) Small POSIXisations * * To do: * Restructure the ax25_rcv code to be cleaner/faster and @@ -1359,7 +1361,7 @@ * BSD 4.4 ADDIFADDR type support. It is however small and trivially backward * compatible 8) */ -static int ax25_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len) +static int ax25_bind(struct socket *sock, struct sockaddr *uaddr,size_t addr_len) { struct sock *sk; struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr; @@ -1369,14 +1371,14 @@ sk = (struct sock *)sock->data; if (sk->zapped == 0) - return -EIO; + return -EINVAL; if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25)) return -EINVAL; call = ax25_findbyuid(current->euid); if (call == NULL && ax25_uid_policy && !suser()) - return -EPERM; + return -EACCES; if (call == NULL) sk->protinfo.ax25->source_addr = addr->fsa_ax25.sax25_call; @@ -1422,7 +1424,7 @@ } static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, - int addr_len, int flags) + size_t addr_len, int flags) { struct sock *sk = (struct sock *)sock->data; struct sockaddr_ax25 *addr = (struct sockaddr_ax25 *)uaddr; @@ -1460,7 +1462,7 @@ if (sk->protinfo.ax25->digipeat == NULL) { if ((sk->protinfo.ax25->digipeat = (ax25_digi *)kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) - return -ENOMEM; + return -ENOBUFS; } sk->protinfo.ax25->digipeat->ndigi = addr->sax25_ndigis; @@ -1490,7 +1492,7 @@ } if (sk->type == SOCK_SEQPACKET && ax25_find_cb(&sk->protinfo.ax25->source_addr, &addr->sax25_call, sk->protinfo.ax25->device) != NULL) - return -EBUSY; /* Already such a connection */ + return -EADDRINUSE; /* Already such a connection */ sk->protinfo.ax25->dest_addr = addr->sax25_call; @@ -1599,7 +1601,7 @@ } static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, - int *uaddr_len, int peer) + size_t *uaddr_len, int peer) { struct full_sockaddr_ax25 *sax = (struct full_sockaddr_ax25 *)uaddr; struct sock *sk; @@ -1677,6 +1679,10 @@ if (dp.lastrepeat + 1 < dp.ndigi) { /* Not yet digipeated completely */ if (ax25cmp(&dp.calls[dp.lastrepeat + 1], dev_addr) == 0) { struct device *dev_out = dev; + + skb=skb_unshare(skb, GFP_ATOMIC, FREE_READ); + if(skb==NULL) + return 0; /* We are the digipeater. Mark ourselves as repeated and throw the packet back out of the same device */ @@ -1959,6 +1965,12 @@ if (sk->zapped) return -EADDRNOTAVAIL; + if (sk->shutdown & SEND_SHUTDOWN) + { + send_sig(SIGPIPE, current, 0); + return -EPIPE; + } + if (sk->protinfo.ax25->device == NULL) return -ENETUNREACH; @@ -1994,6 +2006,11 @@ else dp = &dtmp; } else { + /* + * FIXME: 1003.1g - if the socket is like this because + * it has become closed (not started closed) and is VC + * we ought to SIGPIPE, EPIPE + */ if (sk->state != TCP_ESTABLISHED) return -ENOTCONN; sax.sax25_family = AF_AX25; @@ -2082,9 +2099,6 @@ int er; int dama; - if (sk->err) - return sock_error(sk); - if (addr_len != NULL) *addr_len = sizeof(*sax); @@ -2108,7 +2122,12 @@ skb->h.raw = skb->data; } - copied = (size < length) ? size : length; + copied=size; + if(copied>length) + { + copied = length; + msg->msg_flags|=MSG_TRUNC; + } skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (sax) { @@ -2421,7 +2440,7 @@ proc_net_register(&proc_ax25_calls); #endif - printk(KERN_INFO "G4KLX/GW4PTS AX.25 for Linux. Version 0.33 for Linux NET3.035 (Linux 2.0)\n"); + printk(KERN_INFO "G4KLX/GW4PTS AX.25 for Linux. Version 0.34 for Linux NET3.037 (Linux 2.1)\n"); } /* diff -u --recursive --new-file v2.1.10/linux/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c --- v2.1.10/linux/net/ax25/ax25_in.c Tue Nov 12 15:56:15 1996 +++ linux/net/ax25/ax25_in.c Mon Nov 18 11:31:34 1996 @@ -245,6 +245,7 @@ if (ax25->sk != NULL) { ax25->sk->state = TCP_CLOSE; ax25->sk->err = ECONNREFUSED; + ax25->sk->shutdown |= SEND_SHUTDOWN; if (!ax25->sk->dead) ax25->sk->state_change(ax25->sk); ax25->sk->dead = 1; @@ -289,6 +290,7 @@ if (ax25->sk != NULL) { ax25->sk->state = TCP_CLOSE; ax25->sk->err = 0; + ax25->sk->shutdown |= SEND_SHUTDOWN; if (!ax25->sk->dead) ax25->sk->state_change(ax25->sk); ax25->sk->dead = 1; @@ -304,6 +306,7 @@ if (ax25->sk != NULL) { ax25->sk->state = TCP_CLOSE; ax25->sk->err = 0; + ax25->sk->shutdown |= SEND_SHUTDOWN; if (!ax25->sk->dead) ax25->sk->state_change(ax25->sk); ax25->sk->dead = 1; @@ -319,6 +322,7 @@ if (ax25->sk != NULL) { ax25->sk->state = TCP_CLOSE; ax25->sk->err = 0; + ax25->sk->shutdown|=SEND_SHUTDOWN; if (!ax25->sk->dead) ax25->sk->state_change(ax25->sk); ax25->sk->dead = 1; @@ -400,6 +404,7 @@ if (!ax25->sk->dead) ax25->sk->state_change(ax25->sk); ax25->sk->dead = 1; + ax25->sk->shutdown|=SEND_SHUTDOWN; } break; @@ -411,6 +416,7 @@ if (ax25->sk) { ax25->sk->state = TCP_CLOSE; ax25->sk->err = ECONNRESET; + ax25->sk->shutdown |= SEND_SHUTDOWN; if (!ax25->sk->dead) ax25->sk->state_change(ax25->sk); ax25->sk->dead = 1; @@ -594,6 +600,7 @@ if (ax25->sk != NULL) { ax25->sk->state = TCP_CLOSE; ax25->sk->err = 0; + ax25->sk->shutdown |= SEND_SHUTDOWN; if (!ax25->sk->dead) ax25->sk->state_change(ax25->sk); ax25->sk->dead = 1; @@ -609,6 +616,7 @@ if (ax25->sk != NULL) { ax25->sk->state = TCP_CLOSE; ax25->sk->err = ECONNRESET; + ax25->sk->shutdown |= SEND_SHUTDOWN; if (!ax25->sk->dead) ax25->sk->state_change(ax25->sk); ax25->sk->dead = 1; diff -u --recursive --new-file v2.1.10/linux/net/ax25/ax25_timer.c linux/net/ax25/ax25_timer.c --- v2.1.10/linux/net/ax25/ax25_timer.c Tue Nov 12 15:56:15 1996 +++ linux/net/ax25/ax25_timer.c Mon Nov 18 11:31:34 1996 @@ -152,6 +152,7 @@ printk(KERN_DEBUG "AX.25 T3 Timeout\n"); ax25->sk->state = TCP_CLOSE; ax25->sk->err = ETIMEDOUT; + ax25->sk->shutdown |= SEND_SHUTDOWN; if (!ax25->sk->dead) ax25->sk->state_change(ax25->sk); ax25->sk->dead = 1; @@ -196,6 +197,7 @@ if (ax25->sk != NULL) { ax25->sk->state = TCP_CLOSE; ax25->sk->err = 0; + ax25->sk->shutdown |= SEND_SHUTDOWN; if (!ax25->sk->dead) ax25->sk->state_change(ax25->sk); ax25->sk->dead = 1; @@ -239,6 +241,7 @@ if (ax25->sk != NULL) { ax25->sk->state = TCP_CLOSE; ax25->sk->err = ETIMEDOUT; + ax25->sk->shutdown |= SEND_SHUTDOWN; if (!ax25->sk->dead) ax25->sk->state_change(ax25->sk); ax25->sk->dead = 1; @@ -269,6 +272,7 @@ if (ax25->sk != NULL) { ax25->sk->state = TCP_CLOSE; ax25->sk->err = ETIMEDOUT; + ax25->sk->shutdown |= SEND_SHUTDOWN; if (!ax25->sk->dead) ax25->sk->state_change(ax25->sk); ax25->sk->dead = 1; @@ -298,6 +302,7 @@ printk(KERN_DEBUG "AX.25 link Failure\n"); ax25->sk->state = TCP_CLOSE; ax25->sk->err = ETIMEDOUT; + ax25->sk->shutdown |= SEND_SHUTDOWN; if (!ax25->sk->dead) ax25->sk->state_change(ax25->sk); ax25->sk->dead = 1; diff -u --recursive --new-file v2.1.10/linux/net/ax25/sysctl_net_ax25.c linux/net/ax25/sysctl_net_ax25.c --- v2.1.10/linux/net/ax25/sysctl_net_ax25.c Tue Nov 12 15:56:15 1996 +++ linux/net/ax25/sysctl_net_ax25.c Sat Nov 16 14:17:53 1996 @@ -10,9 +10,9 @@ #include static int min_ax25[] = {0, 0, 0, 0, 0, 1, 1, 1 * PR_SLOWHZ, 1 * PR_SLOWHZ, - 0 * PR_SLOWHZ, 0 * PR_SLOWHZ, 1, 1, 0x00, 1}; + 0 * PR_SLOWHZ, 0 * PR_SLOWHZ, 1, 1, 1, 0x00}; static int max_ax25[] = {1, 1, 1, 1, 1, 7, 63, 30 * PR_SLOWHZ, 20 * PR_SLOWHZ, - 3600 * PR_SLOWHZ, 65535 * PR_SLOWHZ, 31, 512, 0x03, 20}; + 3600 * PR_SLOWHZ, 65535 * PR_SLOWHZ, 31, 512, 20, 0x03}; static struct ctl_table_header *ax25_table_header; diff -u --recursive --new-file v2.1.10/linux/net/bridge/br.c linux/net/bridge/br.c --- v2.1.10/linux/net/bridge/br.c Fri Nov 15 23:49:11 1996 +++ linux/net/bridge/br.c Mon Nov 18 11:31:34 1996 @@ -3,6 +3,10 @@ * * Originally by John Hayes (Network Plumbing). * Minor hacks to get it to run with 1.3.x by Alan Cox + * More hacks to be able to switch protocols on and off by Christoph Lameter + * + * Software and more Documentation for the bridge is available from ftp.debian.org + * in the bridge package or at ftp.fuller.edu/Linux/bridge * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -79,6 +83,67 @@ 0 }; +/* + * Implementation of Protocol specific bridging + * + * The protocols to be bridged or not to be bridged are stored in a hashed array. This is the old type + * of unlinked hash array where one simply takes the next cell if the one the hash function points to + * is occupied. + */ + +#define BR_PROTOCOL_HASH(x) (x % BR_MAX_PROTOCOLS) + +/* Checks if that protocol type is to be bridged */ +int br_protocol_ok(unsigned short protocol) +{ + unsigned x; + + /* See if protocol statistics are to be kept */ + if (br_stats.flags & BR_PROT_STATS) + { for(x=0;x BR_MAX_PROTOCOLS-2) return -EXFULL; + for (x=BR_PROTOCOL_HASH(p);br_stats.protocols[x]!=0;) { + if (br_stats.protocols[x]==p) return 0; /* Attempt to add the protocol a second time */ + x++; + if (x==BR_MAX_PROTOCOLS) x=0; + } + br_stats.protocols[x]=p; + br_stats.exempt_protocols++; + return 0; +} + +/* Valid Policies are 0=No Protocols bridged 1=Bridge all protocols */ +int br_set_policy(int policy) +{ + if (policy>1) return -EINVAL; + br_stats.policy=policy; + /* Policy change means initializing the exempt table */ + memset(br_stats.protocols,0,sizeof(br_stats.protocols)); + br_stats.exempt_protocols = 0; + return 0; +} + + /** Elements of Procedure (4.6) **/ /* @@ -579,7 +644,7 @@ { /* (4.8.1) */ int port_no; - printk(KERN_INFO "Ethernet Bridge 002 for NET3.035 (Linux 2.0)\n"); + printk(KERN_INFO "Ethernet Bridge 003 for NET3.037 (Linux 2.1)\n"); bridge_info.designated_root = bridge_info.bridge_id; /* (4.8.1.1) */ bridge_info.root_path_cost = Zero; bridge_info.root_port = No_port; @@ -611,6 +676,8 @@ register_netdevice_notifier(&br_dev_notifier); br_stats.flags = 0; /*BR_UP | BR_DEBUG*/; /* enable bridge */ + br_stats.policy = BR_ACCEPT; /* Enable bridge to accpet all protocols */ + br_stats.exempt_protocols = 0; /*start_hello_timer();*/ } @@ -1052,7 +1119,6 @@ int br_receive_frame(struct sk_buff *skb) /* 3.5 */ { int port; - int i; if (br_stats.flags & BR_DEBUG) printk("br_receive_frame: "); @@ -1511,6 +1577,20 @@ case BRCMD_DISABLE_DEBUG: br_stats.flags &= ~BR_DEBUG; break; + case BRCMD_SET_POLICY: + return br_set_policy(bcf.arg1); + case BRCMD_EXEMPT_PROTOCOL: + return br_add_exempt_protocol(bcf.arg1); + case BRCMD_ENABLE_PROT_STATS: + br_stats.flags |= BR_PROT_STATS; + break; + case BRCMD_DISABLE_PROT_STATS: + br_stats.flags &= ~BR_PROT_STATS; + break; + case BRCMD_ZERO_PROT_STATS: + memset(&br_stats.prot_id,0,sizeof(br_stats.prot_id)); + memset(&br_stats.prot_counter,0,sizeof(br_stats.prot_counter)); + break; default: return -EINVAL; } @@ -1536,4 +1616,4 @@ } return(0); } - + diff -u --recursive --new-file v2.1.10/linux/net/core/datagram.c linux/net/core/datagram.c --- v2.1.10/linux/net/core/datagram.c Fri Nov 15 23:49:11 1996 +++ linux/net/core/datagram.c Mon Nov 18 11:31:34 1996 @@ -19,6 +19,7 @@ * Linus Torvalds : BSD semantic fixes. * Alan Cox : Datagram iovec handling * Darryl Miles : Fixed non-blocking SOCK_STREAM. + * Alan Cox : POSIXisms * */ @@ -80,6 +81,10 @@ * * This function will lock the socket if a skb is returned, so the caller * needs to unlock the socket in that case (usually by calling skb_free_datagram) + * + * The order of the tests when we find no data waiting are specified + * quite explicitly by POSIX 1003.1g, don't change them without having + * the standard around please. */ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err) @@ -105,14 +110,14 @@ if(connection_based(sk) && sk->state!=TCP_ESTABLISHED) goto no_packet; - /* User doesn't want to wait */ - error = -EAGAIN; - if (noblock) - goto no_packet; - /* handle signals */ error = -ERESTARTSYS; if (current->signal & ~current->blocked) + goto no_packet; + + /* User doesn't want to wait */ + error = -EAGAIN; + if (noblock) goto no_packet; wait_for_packet(sk); diff -u --recursive --new-file v2.1.10/linux/net/core/dev.c linux/net/core/dev.c --- v2.1.10/linux/net/core/dev.c Fri Nov 15 23:49:11 1996 +++ linux/net/core/dev.c Mon Nov 18 11:31:35 1996 @@ -597,10 +597,11 @@ /* * If we are bridging then pass the frame up to the - * bridging code. If it is bridged then move on + * bridging code (if this protocol is to be bridged). + * If it is bridged then move on */ - if (br_stats.flags & BR_UP) + if (br_stats.flags & BR_UP && br_protocol_ok(ntohs(skb->protocol))) { /* * We pass the bridge a complete frame. This means diff -u --recursive --new-file v2.1.10/linux/net/core/iovec.c linux/net/core/iovec.c --- v2.1.10/linux/net/core/iovec.c Fri Nov 15 23:49:11 1996 +++ linux/net/core/iovec.c Mon Nov 18 10:36:06 1996 @@ -94,9 +94,8 @@ { int copy = min(iov->iov_len,len); err = copy_to_user(iov->iov_base,kdata,copy); - if (err) { - return err; - } + if (err) + return err; kdata+=copy; len-=copy; iov->iov_len-=copy; diff -u --recursive --new-file v2.1.10/linux/net/core/skbuff.c linux/net/core/skbuff.c --- v2.1.10/linux/net/core/skbuff.c Fri Nov 15 23:49:11 1996 +++ linux/net/core/skbuff.c Mon Nov 18 11:31:35 1996 @@ -68,6 +68,13 @@ extern atomic_t ip_frag_mem; +/* + * Strings we don't want inline's duplicating + */ + +char *skb_push_errstr="skpush:under: %p:%d"; +char *skb_put_errstr ="skput:over: %p:%d"; + void show_net_buffers(void) { printk(KERN_INFO "Networking buffers in use : %u\n",net_skbcount); diff -u --recursive --new-file v2.1.10/linux/net/core/sock.c linux/net/core/sock.c --- v2.1.10/linux/net/core/sock.c Fri Nov 15 23:49:11 1996 +++ linux/net/core/sock.c Mon Nov 18 11:31:35 1996 @@ -245,6 +245,8 @@ sk->bsdism = valbool; break; + /* We implementation the SO_SNDLOWAT etc to + not be settable (1003.1g 5.3) */ default: return(-ENOPROTOOPT); } @@ -317,12 +319,24 @@ ling.l_onoff=sk->linger; ling.l_linger=sk->lingertime; err = copy_to_user(optval,&ling,sizeof(ling)); + if (err) + err = -EFAULT; } return err; case SO_BSDCOMPAT: val = sk->bsdism; break; + + case SO_RCVTIMEO: + case SO_SNDTIMEO: + { + static struct timeval tm={0,0}; + return copy_to_user(optval,&tm,sizeof(tm)); + } + case SO_RCVLOWAT: + case SO_SNDLOWAT: + val=1; default: return(-ENOPROTOOPT); diff -u --recursive --new-file v2.1.10/linux/net/ipv4/Config.in linux/net/ipv4/Config.in --- v2.1.10/linux/net/ipv4/Config.in Fri Jul 19 08:24:05 1996 +++ linux/net/ipv4/Config.in Mon Nov 18 11:31:35 1996 @@ -6,6 +6,9 @@ if [ "$CONFIG_FIREWALL" = "y" ]; then bool 'IP: firewalling' CONFIG_IP_FIREWALL if [ "$CONFIG_IP_FIREWALL" = "y" ]; then + if [ "$CONFIG_NETLINK" = "y" ]; then + bool 'IP: firewall packet netlink device' CONFIG_IP_FIREWALL_NETLINK + fi bool 'IP: firewall packet logging' CONFIG_IP_FIREWALL_VERBOSE if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_IP_FORWARD" = "y" ]; then bool 'IP: masquerading (EXPERIMENTAL)' CONFIG_IP_MASQUERADE diff -u --recursive --new-file v2.1.10/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v2.1.10/linux/net/ipv4/af_inet.c Fri Nov 15 23:49:11 1996 +++ linux/net/ipv4/af_inet.c Mon Nov 18 11:31:35 1996 @@ -454,6 +454,10 @@ /* * Get a socket option on an AF_INET socket. + * + * FIX: POSIX 1003.1g is very ambiguous here. It states that + * asynchronous errors should be reported by getsockopt. We assume + * this means if you specify SO_ERROR (otherwise whats the point of it). */ int inet_getsockopt(struct socket *sock, int level, int optname, @@ -763,7 +767,7 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr, - int addr_len) + size_t addr_len) { struct sockaddr_in *addr=(struct sockaddr_in *)uaddr; struct sock *sk=(struct sock *)sock->data, *sk2; @@ -919,7 +923,7 @@ */ int inet_connect(struct socket *sock, struct sockaddr * uaddr, - int addr_len, int flags) + size_t addr_len, int flags) { struct sock *sk=(struct sock *)sock->data; int err; @@ -1086,7 +1090,7 @@ */ static int inet_getname(struct socket *sock, struct sockaddr *uaddr, - int *uaddr_len, int peer) + size_t *uaddr_len, int peer) { struct sockaddr_in *sin=(struct sockaddr_in *)uaddr; struct sock *sk; @@ -1616,7 +1620,7 @@ int i; - printk("Swansea University Computer Society TCP/IP for NET3.034\n"); + printk("Swansea University Computer Society TCP/IP for NET3.037\n"); /* * Tell SOCKET that we are alive... diff -u --recursive --new-file v2.1.10/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c --- v2.1.10/linux/net/ipv4/icmp.c Fri Nov 15 23:49:11 1996 +++ linux/net/ipv4/icmp.c Mon Nov 18 11:31:35 1996 @@ -643,9 +643,16 @@ struct inet_protocol *ipprot; unsigned char *dp; __u32 info = 0; + + if(lenihl<<2; + if(len<0) + goto flush_it; + dp= ((unsigned char *)iph)+(iph->ihl<<2); if(icmph->type==ICMP_DEST_UNREACH) @@ -778,11 +785,12 @@ if (iph->protocol == ipprot->protocol && ipprot->err_handler) { ipprot->err_handler(icmph->type, icmph->code, dp, info, - iph->daddr, iph->saddr, ipprot); + iph->daddr, iph->saddr, ipprot, len); } ipprot = nextip; } +flush_it: kfree_skb(skb, FREE_READ); } @@ -799,6 +807,9 @@ /* * Get the copied header of the packet that caused the redirect */ + + if(len<=sizeof(struct iphdr)) + goto flush_it; iph = (struct iphdr *) (icmph + 1); ip = iph->daddr; @@ -854,7 +865,7 @@ /* * Discard the original packet */ - +flush_it: kfree_skb(skb, FREE_READ); } diff -u --recursive --new-file v2.1.10/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c --- v2.1.10/linux/net/ipv4/igmp.c Tue Oct 29 19:58:49 1996 +++ linux/net/ipv4/igmp.c Mon Nov 18 11:31:35 1996 @@ -61,6 +61,9 @@ * miscalculation fixed in igmp_heard_query * and random() made to return unsigned to * prevent negative expiry times. + * Alexey Kuznetsov: Wrong group leaving behaviour, backport + * fix from pending 2.1.x patches. + * Alan Cox: Forget to enable FDDI support earlier. */ @@ -278,6 +281,7 @@ igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_NEW_MEMBERSHIP_REPORT); else igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT); + im->reporter=1; } static void igmp_init_timer(struct ip_mc_list *im) @@ -289,17 +293,24 @@ } -static void igmp_heard_report(struct device *dev, unsigned long address) +static void igmp_heard_report(struct device *dev, __u32 address, __u32 src) { struct ip_mc_list *im; - if ((address & IGMP_LOCAL_GROUP_MASK) != IGMP_LOCAL_GROUP) { - /* Timers are only set for non-local groups */ - for(im=dev->ip_mc_list;im!=NULL;im=im->next) { - if(im->multiaddr==address && im->tm_running) { - igmp_stop_timer(im); - } - } + if ((address & IGMP_LOCAL_GROUP_MASK) != IGMP_LOCAL_GROUP) + { + /* Timers are only set for non-local groups */ + for(im=dev->ip_mc_list;im!=NULL;im=im->next) + { + if(im->multiaddr==address) + { + if(im->tm_running) + igmp_stop_timer(im); + if(src!=dev->pa_addr) + im->reporter=0; + return; + } + } } } @@ -391,8 +402,8 @@ void ip_mc_filter_add(struct device *dev, unsigned long addr) { char buf[6]; - if(dev->type!=ARPHRD_ETHER) - return; /* Only do ethernet now */ + if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_FDDI) + return; /* Only do ethernet or FDDI for now */ ip_mc_map(addr,buf); dev_mc_add(dev,buf,ETH_ALEN,0); } @@ -404,8 +415,8 @@ void ip_mc_filter_del(struct device *dev, unsigned long addr) { char buf[6]; - if(dev->type!=ARPHRD_ETHER) - return; /* Only do ethernet now */ + if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_FDDI) + return; /* Only do ethernet or FDDI for now */ ip_mc_map(addr,buf); dev_mc_delete(dev,buf,ETH_ALEN,0); } @@ -473,9 +484,9 @@ if(ih->type==IGMP_HOST_MEMBERSHIP_QUERY && daddr==IGMP_ALL_HOSTS) igmp_heard_query(dev,ih->code); if(ih->type==IGMP_HOST_MEMBERSHIP_REPORT && daddr==ih->group) - igmp_heard_report(dev,ih->group); + igmp_heard_report(dev,ih->group, saddr); if(ih->type==IGMP_HOST_NEW_MEMBERSHIP_REPORT && daddr==ih->group) - igmp_heard_report(dev,ih->group); + igmp_heard_report(dev,ih->group, saddr); kfree_skb(skb, FREE_READ); return 0; } diff -u --recursive --new-file v2.1.10/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c --- v2.1.10/linux/net/ipv4/ip_forward.c Thu Oct 10 19:10:58 1996 +++ linux/net/ipv4/ip_forward.c Mon Nov 18 11:31:35 1996 @@ -16,6 +16,7 @@ * use output device for accounting. * Jos Vos : Call forward firewall after routing * (always use output device). + * Alan Cox : Unshare buffer on forward. */ #include @@ -120,6 +121,13 @@ struct sk_buff *skb_in = skb; /* So we can remember if the masquerader did some swaps */ #endif /* CONFIG_IP_MASQUERADE */ #endif /* CONFIG_FIREWALL */ + + /* + * We may be sharing the buffer with a snooper. That won't do + */ + + if((skb=skb_unshare(skb, GFP_ATOMIC,FREE_READ))==NULL) + return -1; /* * According to the RFC, we must first decrease the TTL field. If diff -u --recursive --new-file v2.1.10/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c --- v2.1.10/linux/net/ipv4/ip_fw.c Tue Oct 29 19:58:49 1996 +++ linux/net/ipv4/ip_fw.c Mon Nov 18 11:31:35 1996 @@ -37,6 +37,8 @@ * Willy Konynenberg 10/5/96. * Make separate accounting on incoming and outgoing packets possible. * Jos Vos 18/5/1996. + * Added trap out of bad frames. + * Alan Cox 17/11/1996 * * * Masquerading functionality @@ -102,6 +104,7 @@ #include #include #include +#include #include #include @@ -567,6 +570,20 @@ else answer = FW_BLOCK; +#ifdef CONFIG_IP_FIREWALL_NETLINK + if(answer == FW_REJECT || answer == FW_BLOCK) + { + struct sk_buff *skb=alloc_skb(128, GFP_ATOMIC); + if(skb) + { + int len=min(128,ntohs(ip->tot_len)); + skb_put(skb,len); + memcpy(skb->data,ip,len); + if(netlink_post(NETLINK_FIREWALL, skb)) + kfree_skb(skb, FREE_WRITE); + } + } +#endif return answer; } else /* we're doing accounting, always ok */ diff -u --recursive --new-file v2.1.10/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c --- v2.1.10/linux/net/ipv4/ip_sockglue.c Fri Nov 15 23:49:11 1996 +++ linux/net/ipv4/ip_sockglue.c Mon Nov 18 10:36:06 1996 @@ -495,8 +495,11 @@ } } err = put_user(opt->optlen, optlen); - if (!err) - err = copy_to_user(optval, opt->__data, opt->optlen); + if (!err) + { + if(copy_to_user(optval, opt->__data, opt->optlen)) + err = -EFAULT; + } return err; } return 0; @@ -520,7 +523,11 @@ len=strlen(sk->ip_mc_name); err = put_user(len, optlen); if (!err) + { err = copy_to_user((void *)optval,sk->ip_mc_name, len); + if (err) + err = -EFAULT; + } return err; #endif default: diff -u --recursive --new-file v2.1.10/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c --- v2.1.10/linux/net/ipv4/ipmr.c Fri Nov 15 23:49:11 1996 +++ linux/net/ipv4/ipmr.c Mon Nov 18 11:31:35 1996 @@ -551,14 +551,16 @@ * Control PIM assert. */ case MRT_ASSERT: + { + int v; if(optlen!=sizeof(int)) return -EINVAL; - - /* BUG BUG this is wrong IMHO -AK. */ - if((err=verify_area(VERIFY_READ, optval,sizeof(int)))<0) - return err; - mroute_do_pim= (optval)?1:0; + + if(get_user(v,(int *)optval)) + return -EFAULT; + mroute_do_pim=(v)?1:0; return 0; + } /* * Spurious command, or MRT_VERSION which you cannot * set. diff -u --recursive --new-file v2.1.10/linux/net/ipv4/packet.c linux/net/ipv4/packet.c --- v2.1.10/linux/net/ipv4/packet.c Fri Nov 15 23:49:11 1996 +++ linux/net/ipv4/packet.c Mon Nov 18 11:31:35 1996 @@ -282,7 +282,7 @@ * Bind a packet socket to a device */ -static int packet_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) +static int packet_bind(struct sock *sk, struct sockaddr *uaddr, size_t addr_len) { char name[15]; struct device *dev; @@ -410,9 +410,6 @@ struct sockaddr_pkt *saddr=(struct sockaddr_pkt *)msg->msg_name; int err; - if (sk->shutdown & RCV_SHUTDOWN) - return(0); - /* * If there is no protocol hook then the device is down. */ @@ -450,8 +447,13 @@ * user program they can ask the device for its MTU anyway. */ - copied = min(len, skb->len); - + copied = skb->len; + if(copied>len) + { + copied=len; + msg->msg_flags|=MSG_TRUNC; + } + /* We can't use skb_copy_datagram here */ err = memcpy_toiovec(msg->msg_iov, skb->data, copied); if (err) diff -u --recursive --new-file v2.1.10/linux/net/ipv4/rarp.c linux/net/ipv4/rarp.c --- v2.1.10/linux/net/ipv4/rarp.c Fri Nov 15 23:49:11 1996 +++ linux/net/ipv4/rarp.c Mon Nov 18 10:36:06 1996 @@ -436,7 +436,7 @@ * Copy the information back */ - return copy_to_user(req, &r, sizeof(r)); + return copy_to_user(req, &r, sizeof(r)) ? -EFAULT : 0; } diff -u --recursive --new-file v2.1.10/linux/net/ipv4/raw.c linux/net/ipv4/raw.c --- v2.1.10/linux/net/ipv4/raw.c Fri Nov 15 23:49:11 1996 +++ linux/net/ipv4/raw.c Mon Nov 18 11:31:36 1996 @@ -350,7 +350,12 @@ if(skb==NULL) return err; - copied = min(len, skb->len); + copied=skb->len; + if(copied>len) + { + copied=len; + msg->msg_flags|=MSG_TRUNC; + } err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); sk->stamp=skb->stamp; diff -u --recursive --new-file v2.1.10/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c --- v2.1.10/linux/net/ipv4/sysctl_net_ipv4.c Sun Nov 10 20:12:29 1996 +++ linux/net/ipv4/sysctl_net_ipv4.c Mon Nov 18 10:36:07 1996 @@ -31,7 +31,9 @@ extern int sysctl_arp_confirm_interval; extern int sysctl_arp_confirm_timeout; -extern int sysctl_tcp_vegas_cong_avoidance; +extern int sysctl_tcp_cong_avoidance; +extern int tcp_sysctl_congavoid(ctl_table *ctl, int write, struct file * filp, + void *buffer, size_t *lenp); ctl_table ipv4_table[] = { {NET_IPV4_ARP_RES_TIME, "arp_res_time", @@ -58,7 +60,7 @@ #endif {NET_IPV4_TCP_VEGAS_CONG_AVOID, "tcp_vegas_cong_avoid", - &sysctl_tcp_vegas_cong_avoidance, sizeof(int), 0644, - NULL, &proc_dointvec }, + &sysctl_tcp_cong_avoidance, sizeof(int), 0644, + NULL, &tcp_sysctl_congavoid }, {0} }; diff -u --recursive --new-file v2.1.10/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.1.10/linux/net/ipv4/tcp.c Fri Nov 15 23:49:11 1996 +++ linux/net/ipv4/tcp.c Mon Nov 18 11:31:36 1996 @@ -204,8 +204,7 @@ * * Rewrite output state machine to use a single queue. * Speed up input assembly algorithm. - * RFC1323 - PAWS and window scaling. PAWS is required for IPv6 so we - * could do with it working on IPv4 + * RFC1323 - PAWS and window scaling. * User settable/learned rtt/max window/mtu * * Change the fundamental structure to a single send queue maintained @@ -905,19 +904,20 @@ sk->mss - tcp_size > 0 && skb->end_seq < tp->snd_una + tp->snd_wnd) { + int tcopy; - copy = tcp_append_tail(sk, skb, from, + tcopy = tcp_append_tail(sk, skb, from, tcp_size, seglen); - if (copy == -1) + if (tcopy == -1) { return -EFAULT; } - from += copy; - copied += copy; - len -= copy; - seglen -= copy; + from += tcopy; + copied += tcopy; + len -= tcopy; + seglen -= tcopy; /* * FIXME: if we're nagling we @@ -1092,7 +1092,7 @@ struct msghdr *msg, int len, int flags, int *addr_len) { - int err; + int err=0; struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); /* @@ -1125,7 +1125,12 @@ char c = sk->urg_data; if (!(flags & MSG_PEEK)) sk->urg_data = URG_READ; - err = memcpy_toiovec(msg->msg_iov, &c, 1); + + if(len>0) + err = memcpy_toiovec(msg->msg_iov, &c, 1); + else + msg->msg_flags|=MSG_TRUNC; + if(msg->msg_name) { tp->af_specific->addr2sockaddr(sk, (struct sockaddr *) @@ -1133,7 +1138,10 @@ } if(addr_len) *addr_len= tp->af_specific->sockaddr_len; - + /* + * Read urgent data + */ + msg->msg_flags|=MSG_OOB; release_sock(sk); return err ? -EFAULT : 1; } @@ -1214,10 +1222,7 @@ volatile u32 *seq; /* So gcc doesn't overoptimise */ unsigned long used; int err = 0; - - /* - * This error should be checked. - */ + int target = 1; /* Read at least this may bytes */ if (sk->state == TCP_LISTEN) return -ENOTCONN; @@ -1239,6 +1244,13 @@ seq = &sk->copied_seq; if (flags & MSG_PEEK) seq = &peek_seq; + + /* + * Handle the POSIX bogosity MSG_WAITALL + */ + + if (flags & MSG_WAITALL) + target=len; add_wait_queue(sk->sleep, &wait); lock_sock(sk); @@ -1256,14 +1268,13 @@ /* * We need to check signals first, to get correct SIGURG - * handling. + * handling. FIXME: Need to check this doesnt impact 1003.1g + * and move it down to the bottom of the loop */ if (current->signal & ~current->blocked) { if (copied) break; copied = -ERESTARTSYS; - if (nonblock) - copied = -EAGAIN; break; } @@ -1300,7 +1311,7 @@ } while (skb != (struct sk_buff *)&sk->receive_queue); - if (copied) + if (copied >= target) break; if (sk->err && !(flags&MSG_PEEK)) @@ -1393,11 +1404,6 @@ * a crash when cleanup_rbuf() gets called. */ - /* - * FIXME: should break out of the loop early when an - * error occurs - */ - err = memcpy_toiovec(msg->msg_iov, ((unsigned char *)skb->h.th) + skb->h.th->doff*4 + offset, used); if (err) @@ -1427,7 +1433,8 @@ continue; /* - * Process the FIN. + * Process the FIN. We may also need to handle PSH + * here and make it break out of MSG_WAITALL */ if (skb->h.th->fin) @@ -1847,104 +1854,6 @@ { tcp_dec_slow_timer(TCP_SLT_KEEPALIVE); } -} - - -/* - * This function returns the amount that we can raise the - * usable window based on the following constraints - * - * 1. The window can never be shrunk once it is offered (RFC 793) - * 2. We limit memory per socket - */ - - -unsigned short tcp_select_window(struct sock *sk) -{ - struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; - long free_space = sock_rspace(sk); - long window; - long cur_win; - long usable; - int mss = sk->mss; - - if (sk->window_clamp) - { - free_space = min(sk->window_clamp, free_space); - mss = min(sk->window_clamp, mss); - } - - /* - * compute the actual window i.e. - * old_window - received_bytes_on_that_win - */ - - cur_win = tp->rcv_wup - (tp->rcv_nxt - tp->rcv_wnd); - window = tp->rcv_wnd; - - if ( cur_win < 0 ) - { - cur_win = 0; - printk(KERN_DEBUG "TSW: win < 0 w=%d 1=%u 2=%u\n", - tp->rcv_wnd, tp->rcv_nxt, tp->rcv_wup); - } - - /* - * RFC 1122: - * "the suggested [SWS] avoidance algoritm for the receiver is to keep - * RECV.NEXT + RCV.WIN fixed until: - * RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)" - * - * i.e. don't raise the right edge of the window until you can't raise - * it MSS bytes - */ - - /* - * It would be a good idea if it didn't break header prediction. - * and BSD made the header predition standard... - * It expects the same value in the header i.e. th->window to be - * constant - */ - - usable = free_space - cur_win; - if (usable < 0) - { - usable = 0; - } - - if ( window < usable ) - { - /* - * Window is not blocking the sender - * and we have enought free space for it - */ - - if (cur_win > (sk->mss << 1)) - goto out; - } - - - if (window >= usable) - { - /* - * We are offering too much, cut it down... - * but don't shrink the window - */ - - window = max(usable, cur_win); - } - else - { - if ((usable - window) >= mss) - { - window += mss; - } - } - - out: - tp->rcv_wnd = window; - tp->rcv_wup = tp->rcv_nxt; - return window; } /* diff -u --recursive --new-file v2.1.10/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v2.1.10/linux/net/ipv4/tcp_input.c Fri Nov 15 23:49:11 1996 +++ linux/net/ipv4/tcp_input.c Mon Nov 18 10:44:23 1996 @@ -45,12 +45,24 @@ */ #include +#include +#include #include -/* - * Policy code extracted so it's now seperate - */ + +typedef void (*tcp_sys_cong_ctl_t)(struct sock *sk, + u32 seq, u32 ack, + u32 seq_rtt); + +static void tcp_cong_avoid_vanj(struct sock *sk, u32 seq, u32 ack, + u32 seq_rtt); +static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack, + u32 seq_rtt); + +int sysctl_tcp_cong_avoidance = 0; + +static tcp_sys_cong_ctl_t tcp_sys_cong_ctl_f = &tcp_cong_avoid_vanj; /* * Called each time to estimate the delayed ack timeout. This is @@ -60,7 +72,7 @@ * The estimated value is changing to fast */ -extern __inline__ void tcp_delack_estimator(struct tcp_opt *tp) +static void tcp_delack_estimator(struct tcp_opt *tp) { int m; @@ -355,8 +367,6 @@ } -int sysctl_tcp_vegas_cong_avoidance = 1; - /* * TCP slow start and congestion avoidance in two flavors: * RFC 1122 and TCP Vegas. @@ -364,7 +374,7 @@ * This is a /proc/sys configurable option. */ -#define SHIFT_FACTOR 12 +#define SHIFT_FACTOR 16 static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack, u32 seq_rtt) @@ -380,9 +390,11 @@ * to have improved several things over the initial spec. */ - u32 Actual, Expected; - u32 snt_bytes; struct tcp_opt * tp; + unsigned int Actual, Expected; + unsigned int inv_rtt, inv_basertt; + u32 snt_bytes; + tp = &(sk->tp_pinfo.af_tcp); @@ -393,8 +405,7 @@ tp->basertt = min(seq_rtt, tp->basertt); else tp->basertt = seq_rtt; - - + /* * * Actual = throughput for this segment. @@ -403,14 +414,13 @@ */ snt_bytes = (ack - seq) << SHIFT_FACTOR; - - Actual = snt_bytes / seq_rtt; - Expected = ((tp->snd_nxt - tp->snd_una) << SHIFT_FACTOR) / tp->basertt; + inv_rtt = (1 << SHIFT_FACTOR) / seq_rtt; + + Actual = snt_bytes * inv_rtt; + + inv_basertt = (1 << SHIFT_FACTOR) / tp->basertt; + Expected = ((tp->snd_nxt - tp->snd_una) << SHIFT_FACTOR) * inv_basertt; -/* - printk(KERN_DEBUG "A:%x E:%x rtt:%x srtt:%x win: %d\n", - Actual, Expected, seq_rtt, tp->srtt, sk->cong_window); - */ /* * Slow Start */ @@ -418,23 +428,20 @@ if (sk->cong_window < sk->ssthresh && (seq == tp->snd_nxt || (((Expected - Actual) <= - ((TCP_VEGAS_GAMMA << SHIFT_FACTOR) * sk->mss / tp->basertt)) + ((TCP_VEGAS_GAMMA << SHIFT_FACTOR) * sk->mss * inv_basertt)) ) )) { - /* * "Vegas allows exponential growth only every other * RTT" */ - if (sk->cong_count || sk->cong_window <= 2) + if (!(sk->cong_count++)) { sk->cong_window++; sk->cong_count = 0; } - else - sk->cong_count++; } else { @@ -443,39 +450,32 @@ */ if (Expected - Actual <= - ((TCP_VEGAS_ALPHA << SHIFT_FACTOR) * sk->mss / tp->basertt)) + ((TCP_VEGAS_ALPHA << SHIFT_FACTOR) * sk->mss * inv_basertt)) { /* Increase Linearly */ - if (sk->cong_count >= sk->cong_window) + if (sk->cong_count++ >= sk->cong_window) { sk->cong_window++; sk->cong_count = 0; } - else - sk->cong_count++; } if (Expected - Actual >= - ((TCP_VEGAS_BETA << SHIFT_FACTOR) * sk->mss / tp->basertt)) + ((TCP_VEGAS_BETA << SHIFT_FACTOR) * sk->mss * inv_basertt)) { /* Decrease Linearly */ - if (sk->cong_count >= sk->cong_window) + if (sk->cong_count++ >= sk->cong_window) { sk->cong_window--; sk->cong_count = 0; } - else - sk->cong_count++; - - + /* Never less than 2 segments */ if (sk->cong_window < 2) sk->cong_window = 2; } - - } } @@ -520,6 +520,92 @@ #define FLAG_DATA 0x01 #define FLAG_WIN_UPDATE 0x02 #define FLAG_DATA_ACKED 0x04 + +static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack, __u32 *seq, + __u32 *seq_rtt) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + struct sk_buff *skb; + unsigned long now = jiffies; + int acked = 0; + + while((skb=skb_peek(&sk->write_queue)) && (skb != tp->send_head)) + { + +#ifdef TCP_DEBUG + /* Check for a bug. */ + + if (skb->next != (struct sk_buff*) &sk->write_queue && + after(skb->end_seq, skb->next->seq)) + printk("INET: tcp_input.c: *** " + "bug send_list out of order.\n"); +#endif + /* + * If our packet is before the ack sequence we can + * discard it as it's confirmed to have arrived the + * other end. + */ + + if (after(skb->end_seq, ack)) + break; + + if (sk->debug) + { + printk(KERN_DEBUG "removing seg %x-%x from " + "retransmit queue\n", skb->seq, skb->end_seq); + } + + acked = FLAG_DATA_ACKED; + + atomic_dec(&sk->packets_out); + + *seq = skb->seq; + *seq_rtt = now - skb->when; + + skb_unlink(skb); + skb->free = 1; + + kfree_skb(skb, FREE_WRITE); + } + + if (acked && !sk->dead) + { + tp->retrans_head = NULL; + sk->write_space(sk); + } + + return acked; +} + +static void tcp_ack_probe(struct sock *sk, __u32 ack) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + + /* + * Our probe was answered + */ + tp->probes_out = 0; + + /* + * Was it a usable window open ? + */ + + /* should always be non-null */ + if (tp->send_head != NULL && + !before (ack + tp->snd_wnd, tp->send_head->end_seq)) + { + tp->backoff = 0; + tp->pending = 0; + + tcp_clear_xmit_timer(sk, TIME_PROBE0); + + } + else + { + tcp_reset_xmit_timer(sk, TIME_PROBE0, + min(tp->rto << tp->backoff, 120*HZ)); + } +} /* * This routine deals with incoming acks, but not outgoing ones. @@ -603,85 +689,18 @@ * it needs to be for normal retransmission. */ - if (tp->pending == TIME_PROBE0) + if (tp->pending == TIME_PROBE0) { - tp->probes_out = 0; /* Our probe was answered */ - - /* - * Was it a usable window open ? - */ - - /* should always be non-null */ - if (tp->send_head != NULL && - !before (ack + tp->snd_wnd, tp->send_head->end_seq)) - { - tp->backoff = 0; - tp->pending = 0; - - tcp_clear_xmit_timer(sk, TIME_PROBE0); - - } - else - { - tcp_reset_xmit_timer(sk, TIME_PROBE0, - min(tp->rto << tp->backoff, - 120*HZ)); - } + tcp_ack_probe(sk, ack); } /* * See if we can take anything off of the retransmit queue. */ - - start_bh_atomic(); - while(((skb=skb_peek(&sk->write_queue)) != NULL) && - (skb != tp->send_head)) - { - /* Check for a bug. */ + if (tcp_clean_rtx_queue(sk, ack, &seq, &seq_rtt)) + flag |= FLAG_DATA_ACKED; - if (skb->next != (struct sk_buff*) &sk->write_queue && - after(skb->end_seq, skb->next->seq)) - printk("INET: tcp_input.c: *** " - "bug send_list out of order.\n"); - - /* - * If our packet is before the ack sequence we can - * discard it as it's confirmed to have arrived the - * other end. - */ - - if (!after(skb->end_seq, ack)) - { - if (sk->debug) - { - printk(KERN_DEBUG "removing seg %x-%x from " - "retransmit queue\n", - skb->seq, skb->end_seq); - } - - tp->retrans_head = NULL; - - flag |= FLAG_DATA_ACKED; - seq = skb->seq; - seq_rtt = jiffies - skb->when; - - skb_unlink(skb); - atomic_dec(&sk->packets_out); - skb->free = 1; - - kfree_skb(skb, FREE_WRITE); - - if (!sk->dead) - sk->write_space(sk); - } - else - { - break; - } - } - - end_bh_atomic(); /* * if we where retransmiting don't count rtt estimate @@ -709,18 +728,13 @@ if (flag & FLAG_DATA_ACKED) { tcp_rtt_estimator(tp, seq_rtt); - if (sysctl_tcp_vegas_cong_avoidance) - { - tcp_cong_avoid_vegas(sk, seq, ack, seq_rtt); - } - else - { - tcp_cong_avoid_vanj(sk, seq, ack, seq_rtt); - } + + (*tcp_sys_cong_ctl_f)(sk, seq, ack, seq_rtt); } } +#ifdef TCP_DEBUG /* Sanity check out packets_out counter */ if (skb_queue_len(&sk->write_queue) == 0 || @@ -733,7 +747,7 @@ sk->packets_out = 0; } } - +#endif if (sk->packets_out) { @@ -773,12 +787,6 @@ tcp_fast_retrans(sk, ack, (flag & (FLAG_DATA|FLAG_WIN_UPDATE))); - /* - * Maybe we can take some stuff off of the write queue, - * and put it onto the xmit queue. - */ - - return 1; uninteresting_ack: @@ -895,7 +903,7 @@ * out_of_order queue into the receive_queue */ -static __inline__ void tcp_ofo_queue(struct sock *sk) +static void tcp_ofo_queue(struct sock *sk) { struct sk_buff * skb; struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp); @@ -930,7 +938,7 @@ } } -static __inline__ void tcp_data_queue(struct sock *sk, struct sk_buff *skb) +static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) { struct sk_buff * skb1; struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp); @@ -1255,7 +1263,7 @@ } -static __inline__ void prune_queue(struct sock *sk) +static void prune_queue(struct sock *sk) { struct sk_buff * skb; @@ -1832,6 +1840,32 @@ kfree_skb(skb, FREE_READ); return 0; +} + +int tcp_sysctl_congavoid(ctl_table *ctl, int write, struct file * filp, + void *buffer, size_t *lenp) +{ + int val = sysctl_tcp_cong_avoidance; + int retv; + + retv = proc_dointvec(ctl, write, filp, buffer, lenp); + + if (write) + { + switch (sysctl_tcp_cong_avoidance) { + case 0: + tcp_sys_cong_ctl_f = &tcp_cong_avoid_vanj; + break; + case 1: + tcp_sys_cong_ctl_f = &tcp_cong_avoid_vegas; + break; + default: + retv = -EINVAL; + sysctl_tcp_cong_avoidance = val; + } + } + + return retv; } /* diff -u --recursive --new-file v2.1.10/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- v2.1.10/linux/net/ipv4/tcp_ipv4.c Tue Nov 12 15:56:16 1996 +++ linux/net/ipv4/tcp_ipv4.c Mon Nov 18 17:01:15 1996 @@ -127,7 +127,7 @@ * This will initiate an outgoing connection. */ -int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) +int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, size_t addr_len) { struct sk_buff *buff; struct sk_buff *skb1; @@ -199,7 +199,7 @@ if (buff == NULL) { release_sock(sk); - return(-ENOMEM); + return(-ENOBUFS); } buff->sk = sk; @@ -250,21 +250,6 @@ else sk->mtu = dev->mtu; -#ifdef CONFIG_SKIP - - /* - * SKIP devices set their MTU to 65535. This is so they can take packets - * unfragmented to security process then fragment. They could lie to the - * TCP layer about a suitable MTU, but its easier to let skip sort it out - * simply because the final package we want unfragmented is going to be - * - * [IPHDR][IPSP][Security data][Modified TCP data][Security data] - */ - - if(skip_pick_mtu!=NULL) /* If SKIP is loaded.. */ - sk->mtu=skip_pick_mtu(sk->mtu,dev); -#endif - if(sk->mtu < 64) sk->mtu = 64; /* Sanity limit */ @@ -370,12 +355,15 @@ */ void tcp_v4_err(int type, int code, unsigned char *header, __u32 info, - __u32 daddr, __u32 saddr, struct inet_protocol *protocol) + __u32 daddr, __u32 saddr, struct inet_protocol *protocol, int len) { struct tcphdr *th = (struct tcphdr *)header; struct tcp_opt *tp; struct sock *sk; + if(len<8) /* We use the first 8 bytes only */ + return; + th =(struct tcphdr *)header; sk = get_sock(&tcp_prot, th->source, daddr, th->dest, saddr, 0, 0); @@ -410,10 +398,7 @@ if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { struct rtable * rt; - /* - * Ugly trick to pass MTU to protocol layer. - * Really we should add argument "info" to error handler. - */ + unsigned short new_mtu = info; if ((rt = sk->ip_route_cache) != NULL) @@ -897,7 +882,7 @@ */ newsk->opt = af_req->opt; rt = ip_rt_route(newsk->opt && newsk->opt->srr ? newsk->opt->faddr : - newsk->saddr, 0); + newsk->daddr, 0); newsk->ip_route_cache = rt; @@ -918,7 +903,7 @@ newsk->mtu = 64; } - snd_mss -= sizeof(struct iphdr) - sizeof(struct tcphdr); + snd_mss -= sizeof(struct iphdr) + sizeof(struct tcphdr); if (sk->user_mss) { diff -u --recursive --new-file v2.1.10/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c --- v2.1.10/linux/net/ipv4/tcp_output.c Tue Nov 12 15:56:16 1996 +++ linux/net/ipv4/tcp_output.c Mon Nov 18 13:43:01 1996 @@ -361,7 +361,9 @@ void tcp_write_xmit(struct sock *sk) { struct sk_buff *skb; - struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; + struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; + u16 rcv_wnd; + int sent_pkts = 0; /* * The bytes will have to remain here. In time closedown will @@ -382,8 +384,14 @@ start_bh_atomic(); + rcv_wnd = htons(tcp_select_window(sk)); + while((skb = tp->send_head) && tcp_snd_test(sk, skb)) { + struct tcphdr *th; + struct sk_buff *buff; + int size; + IS_SKB(skb); /* @@ -393,21 +401,18 @@ if (!after(skb->end_seq, tp->snd_una)) { tcp_wrxmit_prob(sk, skb); + continue; } - else - { - struct tcphdr *th; - struct sk_buff *buff; - int size; - - /* - * Advance the send_head - * This one is going out. - */ - update_send_head(sk); - atomic_inc(&sk->packets_out); + /* + * Advance the send_head + * This one is going out. + */ + + update_send_head(sk); + + atomic_inc(&sk->packets_out); /* @@ -418,45 +423,147 @@ * on the write queue. */ - th = skb->h.th; - size = skb->len - (((unsigned char *) th) - skb->data); + th = skb->h.th; + size = skb->len - (((unsigned char *) th) - skb->data); - if (size - (th->doff << 2) > sk->mss) - { - if (tcp_wrxmit_frag(sk, skb, size)) - break; - } - - th->ack_seq = htonl(tp->rcv_nxt); - th->window = htons(tcp_select_window(sk)); - - tp->af_specific->send_check(sk, th, size, skb); - - if (before(skb->end_seq, tp->snd_nxt)) - printk(KERN_DEBUG "tcp_write_xmit:" - " sending already sent seq\n"); - else - tp->snd_nxt = skb->end_seq; - - clear_delayed_acks(sk); - - skb->when = jiffies; - - buff = skb_clone(skb, GFP_ATOMIC); - atomic_add(buff->truesize, &sk->wmem_alloc); - - tp->af_specific->queue_xmit(sk, skb->dev, buff, 1); - - if (!tcp_timer_is_set(sk, TIME_RETRANS)) - { - tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto); - } + if (size - (th->doff << 2) > sk->mss) + { + if (tcp_wrxmit_frag(sk, skb, size)) + break; } + + th->ack_seq = htonl(tp->rcv_nxt); + th->window = rcv_wnd; + + tp->af_specific->send_check(sk, th, size, skb); + +#ifdef TCP_DEBUG + if (before(skb->end_seq, tp->snd_nxt)) + printk(KERN_DEBUG "tcp_write_xmit:" + " sending already sent seq\n"); +#endif + + tp->snd_nxt = skb->end_seq; + + skb->when = jiffies; + clear_delayed_acks(sk); + + buff = skb_clone(skb, GFP_ATOMIC); + atomic_add(buff->truesize, &sk->wmem_alloc); + + sent_pkts = 1; + tp->af_specific->queue_xmit(sk, skb->dev, buff, 1); + + } + + if (sent_pkts && !tcp_timer_is_set(sk, TIME_RETRANS)) + { + tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto); } end_bh_atomic(); } + + +/* + * This function returns the amount that we can raise the + * usable window based on the following constraints + * + * 1. The window can never be shrunk once it is offered (RFC 793) + * 2. We limit memory per socket + */ + + +unsigned short tcp_select_window(struct sock *sk) +{ + struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; + int mss = sk->mss; + long free_space = sock_rspace(sk); + long window; + long cur_win; + long usable; + + + if (sk->window_clamp) + { + free_space = min(sk->window_clamp, free_space); + mss = min(sk->window_clamp, mss); + } + + /* + * compute the actual window i.e. + * old_window - received_bytes_on_that_win + */ + + cur_win = tp->rcv_wup - (tp->rcv_nxt - tp->rcv_wnd); + window = tp->rcv_wnd; + + if ( cur_win < 0 ) + { + cur_win = 0; + printk(KERN_DEBUG "TSW: win < 0 w=%d 1=%u 2=%u\n", + tp->rcv_wnd, tp->rcv_nxt, tp->rcv_wup); + } + + /* + * RFC 1122: + * "the suggested [SWS] avoidance algoritm for the receiver is to keep + * RECV.NEXT + RCV.WIN fixed until: + * RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)" + * + * i.e. don't raise the right edge of the window until you can't raise + * it MSS bytes + */ + + /* + * It would be a good idea if it didn't break header prediction. + * and BSD made the header predition standard... + * It expects the same value in the header i.e. th->window to be + * constant + */ + + usable = free_space - cur_win; + if (usable < 0) + { + usable = 0; + } + + if ( window < usable ) + { + /* + * Window is not blocking the sender + * and we have enought free space for it + */ + + if (cur_win > (sk->mss << 1)) + goto out; + } + + + if (window >= usable) + { + /* + * We are offering too much, cut it down... + * but don't shrink the window + */ + + window = max(usable, cur_win); + } + else + { + if ((usable - window) >= mss) + { + window += mss; + } + } + + out: + tp->rcv_wnd = window; + tp->rcv_wup = tp->rcv_nxt; + return window; +} + static int tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb) { struct tcphdr *th1, *th2; @@ -546,8 +653,10 @@ while ((skb = tp->retrans_head) != NULL) { + struct sk_buff *buff; struct tcphdr *th; - u32 tcp_size; + int tcp_size; + int size; IS_SKB(skb); @@ -582,37 +691,35 @@ tcp_retrans_try_collapse(sk, skb); } - if (tp->af_specific->rebuild_header(sk, skb) == 0) - { - struct sk_buff *buff; - int size; - - if (sk->debug) - printk("retransmit sending\n"); - - /* - * update ack and window - */ - th->ack_seq = htonl(tp->rcv_nxt); - th->window = ntohs(tcp_select_window(sk)); - - size = skb->tail - (unsigned char *) th; - tp->af_specific->send_check(sk, th, size, skb); - - skb->when = jiffies; - buff = skb_clone(skb, GFP_ATOMIC); - atomic_add(buff->truesize, &sk->wmem_alloc); - - clear_delayed_acks(sk); - - tp->af_specific->queue_xmit(sk, skb->dev, buff, 1); - } - else + if (tp->af_specific->rebuild_header(sk, skb)) { +#ifdef TCP_DEBUG printk(KERN_DEBUG "tcp_do_rebuild_header failed\n"); +#endif break; } + if (sk->debug) + printk("retransmit sending\n"); + + /* + * update ack and window + */ + + th->ack_seq = htonl(tp->rcv_nxt); + th->window = ntohs(tcp_select_window(sk)); + + size = skb->tail - (unsigned char *) th; + tp->af_specific->send_check(sk, th, size, skb); + + skb->when = jiffies; + buff = skb_clone(skb, GFP_ATOMIC); + atomic_add(buff->truesize, &sk->wmem_alloc); + + clear_delayed_acks(sk); + + tp->af_specific->queue_xmit(sk, skb->dev, buff, 1); + /* * Count retransmissions */ diff -u --recursive --new-file v2.1.10/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c --- v2.1.10/linux/net/ipv4/tcp_timer.c Tue Nov 12 15:56:16 1996 +++ linux/net/ipv4/tcp_timer.c Mon Nov 18 11:10:14 1996 @@ -185,8 +185,9 @@ sk->err=sk->err_soft; else sk->err=ETIMEDOUT; - +#ifdef TCP_DEBUG printk(KERN_DEBUG "syn timeout\n"); +#endif sk->error_report(sk); tcp_clear_xmit_timers(sk); @@ -475,17 +476,14 @@ req = tp->syn_wait_queue; - while (req && tp->syn_wait_queue) - { + do { struct open_request *conn; - + conn = req; req = req->dl_next; if (conn->sk) { - if (req == tp->syn_wait_queue) - break; continue; } @@ -496,11 +494,16 @@ if (conn->retrans >= TCP_RETR1) { +#ifdef TCP_DEBUG printk(KERN_DEBUG "syn_recv: " "too many retransmits\n"); +#endif (*conn->class->destructor)(conn); tcp_dec_slow_timer(TCP_SLT_SYNACK); kfree(conn); + + if (!tp->syn_wait_queue) + break; } else { @@ -509,14 +512,16 @@ (*conn->class->rtx_syn_ack)(sk, conn); conn->retrans++; +#ifdef TCP_DEBUG printk(KERN_DEBUG "syn_ack rtx %d\n", conn->retrans); +#endif timeo = min((TCP_TIMEOUT_INIT << conn->retrans), 120*HZ); conn->expires = now + timeo; tcp_synq_queue(tp, conn); } - } + } while (req != tp->syn_wait_queue); } sk = sk->next; diff -u --recursive --new-file v2.1.10/linux/net/ipv4/udp.c linux/net/ipv4/udp.c --- v2.1.10/linux/net/ipv4/udp.c Fri Nov 15 23:49:12 1996 +++ linux/net/ipv4/udp.c Mon Nov 18 11:31:36 1996 @@ -151,7 +151,7 @@ */ void udp_err(int type, int code, unsigned char *header, __u32 info, - __u32 daddr, __u32 saddr, struct inet_protocol *protocol) + __u32 daddr, __u32 saddr, struct inet_protocol *protocol, int len) { struct udphdr *uh; struct sock *sk; @@ -159,6 +159,9 @@ /* * Find the 8 bytes of post IP header ICMP included for us */ + + if(lenlen - sizeof(struct udphdr); - copied = min(len, truesize); + copied = truesize; + + if(lenmsg_flags|=MSG_TRUNC; + } /* * FIXME : should use udp header size info value @@ -590,10 +599,25 @@ return(copied); } -int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) +int udp_connect(struct sock *sk, struct sockaddr *uaddr, size_t addr_len) { struct sockaddr_in *usin = (struct sockaddr_in *) uaddr; struct rtable *rt; + + /* + * 1003.1g - break association. + */ + + if (usin->sin_family==AF_UNSPEC) + { + sk->saddr=INADDR_ANY; + sk->rcv_saddr=INADDR_ANY; + sk->daddr=INADDR_ANY; + sk->state = TCP_CLOSE; + udp_cache_zap(); + return 0; + } + if (addr_len < sizeof(*usin)) return(-EINVAL); diff -u --recursive --new-file v2.1.10/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c --- v2.1.10/linux/net/ipv6/addrconf.c Fri Nov 15 23:49:12 1996 +++ linux/net/ipv6/addrconf.c Mon Nov 18 10:36:07 1996 @@ -862,7 +862,7 @@ dev = sit_add_tunnel(ireq.addr.s6_addr32[3]); if (dev == NULL) - return -ENOMEM; + return -ENODEV; return 0; } diff -u --recursive --new-file v2.1.10/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c --- v2.1.10/linux/net/ipv6/af_inet6.c Fri Nov 15 23:49:12 1996 +++ linux/net/ipv6/af_inet6.c Mon Nov 18 11:31:36 1996 @@ -254,7 +254,7 @@ */ static int inet6_bind(struct socket *sock, struct sockaddr *uaddr, - int addr_len) + size_t addr_len) { struct sockaddr_in6 *addr=(struct sockaddr_in6 *)uaddr; struct sock *sk=(struct sock *)sock->data, *sk2; @@ -271,7 +271,7 @@ /* check this error. */ if (sk->state != TCP_CLOSE) - return(-EIO); + return(-EINVAL); if(addr_len < sizeof(struct sockaddr_in6)) return -EINVAL; @@ -434,7 +434,7 @@ */ static int inet6_getname(struct socket *sock, struct sockaddr *uaddr, - int *uaddr_len, int peer) + size_t *uaddr_len, int peer) { struct sockaddr_in6 *sin=(struct sockaddr_in6 *)uaddr; struct sock *sk; @@ -805,7 +805,7 @@ { int i; - printk(KERN_INFO "IPv6 v0.1\n"); + printk(KERN_INFO "IPv6 v0.1 for NET3.037\n"); sock_register(inet6_proto_ops.family, &inet6_proto_ops); diff -u --recursive --new-file v2.1.10/linux/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c --- v2.1.10/linux/net/ipv6/ndisc.c Tue Nov 12 15:56:16 1996 +++ linux/net/ipv6/ndisc.c Mon Nov 18 10:36:07 1996 @@ -15,6 +15,14 @@ */ /* + * Changes: + * + * Lars Fenneberg : fixed MTU setting on receipt + * of an RA. + * + */ + +/* * Interface: * * ndisc_lookup will be called from eth.c on dev->(re)build_header @@ -1383,7 +1391,7 @@ int mtu; struct device *dev; - mtu = htonl(*(__u32 *)opt+4); + mtu = htonl(*(__u32 *)(opt+4)); dev = rt->rt_nexthop->dev; if (mtu < 576) diff -u --recursive --new-file v2.1.10/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c --- v2.1.10/linux/net/ipv6/tcp_ipv6.c Tue Nov 12 15:56:16 1996 +++ linux/net/ipv6/tcp_ipv6.c Mon Nov 18 11:31:36 1996 @@ -85,7 +85,7 @@ } static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, - int addr_len) + size_t addr_len) { struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6; diff -u --recursive --new-file v2.1.10/linux/net/ipv6/udp.c linux/net/ipv6/udp.c --- v2.1.10/linux/net/ipv6/udp.c Fri Nov 15 23:49:12 1996 +++ linux/net/ipv6/udp.c Mon Nov 18 11:31:36 1996 @@ -192,7 +192,13 @@ return err; truesize = skb->tail - skb->h.raw - sizeof(struct udphdr); - copied = min(len, truesize); + + copied=truesize; + if(copied>len) + { + copied=len; + msg->msg_flags|=MSG_TRUNC; + } /* * FIXME : should use udp header size info value diff -u --recursive --new-file v2.1.10/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c --- v2.1.10/linux/net/ipx/af_ipx.c Fri Nov 15 23:49:12 1996 +++ linux/net/ipx/af_ipx.c Mon Nov 18 11:41:14 1996 @@ -44,6 +44,8 @@ * Revision 0.34: Module support. * Revision 0.35: Checksum support. , hooked in by * Handles WIN95 discovery packets + * Revision 0.36: Internal bump up for 2.1 + * Revision 0.37: Began adding POSIXisms. * * Protect the module by a MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT * pair. Also, now usage count is managed this way @@ -141,7 +143,7 @@ vals.ipxcfg_auto_create_interfaces = ipxcfg_auto_create_interfaces; vals.ipxcfg_auto_select_primary = ipxcfg_auto_select_primary; - return copy_to_user(arg, &vals, sizeof(vals)); + return copy_to_user(arg, &vals, sizeof(vals)) ? -EFAULT : 0; } @@ -785,8 +787,13 @@ /* We only route point-to-point packets. */ if ((skb->pkt_type != PACKET_BROADCAST) && (skb->pkt_type != PACKET_MULTICAST)) - return ipxrtr_route_skb(skb); - + { + skb=skb_unshare(skb, GFP_ATOMIC, FREE_READ); + if(skb) + return ipxrtr_route_skb(skb); + else + return 0; + } kfree_skb(skb,FREE_READ); return 0; } @@ -1785,7 +1792,7 @@ return ntohs(socketNum); } -static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len) +static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,size_t addr_len) { ipx_socket *sk; ipx_interface *intrfc; @@ -1794,7 +1801,7 @@ sk=(ipx_socket *)sock->data; if(sk->zapped==0) - return -EIO; + return -EINVAL; if(addr_len!=sizeof(struct sockaddr_ipx)) return -EINVAL; @@ -1810,7 +1817,7 @@ } if(ntohs(addr->sipx_port)protinfo.af_ipx.port=addr->sipx_port; @@ -1886,7 +1893,7 @@ } static int ipx_connect(struct socket *sock, struct sockaddr *uaddr, - int addr_len, int flags) + size_t addr_len, int flags) { ipx_socket *sk=(ipx_socket *)sock->data; struct sockaddr_ipx *addr; @@ -1942,7 +1949,7 @@ } static int ipx_getname(struct socket *sock, struct sockaddr *uaddr, - int *uaddr_len, int peer) + size_t *uaddr_len, int peer) { ipx_address *addr; struct sockaddr_ipx sipx; @@ -2149,29 +2156,33 @@ int copied = 0; int truesize; struct sk_buff *skb; - int er; - - if(sk->err) - return sock_error(sk); + int err; if (sk->zapped) - return -EIO; + return -ENOTCONN; - skb=skb_recv_datagram(sk,flags,noblock,&er); + skb=skb_recv_datagram(sk,flags,noblock,&err); if(skb==NULL) - return er; + return err; if(addr_len) *addr_len=sizeof(*sipx); ipx = (ipx_packet *)(skb->h.raw); truesize=ntohs(ipx->ipx_pktsize) - sizeof(ipx_packet); - copied = (truesize > size) ? size : truesize; + + copied = truesize; + if(copied > size) + { + copied=size; + msg->msg_flags|=MSG_TRUNC; + } + err = skb_copy_datagram_iovec(skb,sizeof(struct ipx_packet),msg->msg_iov,copied); if (err) - return err; + return err; if(sipx) { @@ -2182,7 +2193,7 @@ sipx->sipx_type = ipx->ipx_type; } skb_free_datagram(sk, skb); - return(truesize); + return(copied); } static int ipx_shutdown(struct socket *sk,int how) @@ -2199,7 +2210,6 @@ static int ipx_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) { - int err; long amount=0; ipx_socket *sk=(ipx_socket *)sock->data; @@ -2363,7 +2373,7 @@ proc_net_register(&ipx_rt_procinfo); #endif - printk(KERN_INFO "Swansea University Computer Society IPX 0.34 for NET3.035\n"); + printk(KERN_INFO "Swansea University Computer Society IPX 0.35 for NET3.037\n"); printk(KERN_INFO "IPX Portions Copyright (c) 1995 Caldera, Inc.\n"); } diff -u --recursive --new-file v2.1.10/linux/net/netlink.c linux/net/netlink.c --- v2.1.10/linux/net/netlink.c Fri Nov 15 23:49:12 1996 +++ linux/net/netlink.c Mon Nov 18 11:31:36 1996 @@ -30,7 +30,7 @@ #include #include -static int (*netlink_handler[MAX_LINKS])(struct sk_buff *skb); +static int (*netlink_handler[MAX_LINKS])(int minor, struct sk_buff *skb); static struct sk_buff_head skb_queue_rd[MAX_LINKS]; static int rdq_size[MAX_LINKS]; static struct wait_queue *read_space_wait[MAX_LINKS]; @@ -46,7 +46,7 @@ * Default write handler. */ -static int netlink_err(struct sk_buff *skb) +static int netlink_err(int minor, struct sk_buff *skb) { kfree_skb(skb, FREE_READ); return -EUNATCH; @@ -57,7 +57,7 @@ * interfaces. */ -int netlink_donothing(struct sk_buff *skb) +int netlink_donothing(int minor, struct sk_buff *skb) { kfree_skb(skb, FREE_READ); return -EINVAL; @@ -91,7 +91,7 @@ skb=alloc_skb(count, GFP_KERNEL); skb->free=1; err = copy_from_user(skb_put(skb,count),buf, count); - return err ? -EFAULT : (netlink_handler[minor])(skb); + return err ? -EFAULT : (netlink_handler[minor])(minor,skb); } /* @@ -193,7 +193,7 @@ * queueing. */ -int netlink_attach(int unit, int (*function)(struct sk_buff *skb)) +int netlink_attach(int unit, int (*function)(int minor, struct sk_buff *skb)) { if(unit>=MAX_LINKS) return -ENODEV; @@ -252,7 +252,7 @@ int init_module(void) { - printk(KERN_INFO "Network Kernel/User communications module 0.03\n"); + printk(KERN_INFO "Network Kernel/User communications module 0.04\n"); return init_netlink(); } diff -u --recursive --new-file v2.1.10/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c --- v2.1.10/linux/net/netrom/af_netrom.c Tue Nov 12 15:56:16 1996 +++ linux/net/netrom/af_netrom.c Mon Nov 18 11:31:36 1996 @@ -1,10 +1,10 @@ /* - * NET/ROM release 004 + * NET/ROM release 005 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. * - * This code REQUIRES 1.3.0 or higher/ NET3.029 + * This code REQUIRES 2.1.0 or higher/ NET3.037 * * This module: * This module is free software; you can redistribute it and/or @@ -27,6 +27,8 @@ * Alan(GW4PTS) sendmsg/recvmsg only. Fixed connect clear bug * inherited from AX.25 * NET/ROM 004 Jonathan(G4KLX) Converted to module. + * NET/ROM 005 Jonathan(G4KLX) Linux 2.1 + * Alan(GW4PTS) Started POSIXisms */ #include @@ -772,7 +774,7 @@ return 0; } -static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) +static int nr_bind(struct socket *sock, struct sockaddr *uaddr, size_t addr_len) { struct sock *sk; struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr; @@ -782,7 +784,7 @@ sk = (struct sock *)sock->data; if (sk->zapped == 0) - return -EIO; + return -EINVAL; if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25)) return -EINVAL; @@ -798,7 +800,7 @@ */ if (addr->fsa_ax25.sax25_ndigis == 1) { if (!suser()) - return -EPERM; + return -EACCES; sk->protinfo.nr->user_addr = addr->fsa_digipeater[0]; sk->protinfo.nr->source_addr = addr->fsa_ax25.sax25_call; } else { @@ -826,7 +828,7 @@ } static int nr_connect(struct socket *sock, struct sockaddr *uaddr, - int addr_len, int flags) + size_t addr_len, int flags) { struct sock *sk = (struct sock *)sock->data; struct sockaddr_ax25 *addr = (struct sockaddr_ax25 *)uaddr; @@ -977,7 +979,7 @@ } static int nr_getname(struct socket *sock, struct sockaddr *uaddr, - int *uaddr_len, int peer) + size_t *uaddr_len, int peer) { struct full_sockaddr_ax25 *sax = (struct full_sockaddr_ax25 *)uaddr; struct sock *sk; @@ -1230,9 +1232,6 @@ struct sk_buff *skb; int er; - if (sk->err) - return sock_error(sk); - if (addr_len != NULL) *addr_len = sizeof(*sax); @@ -1240,6 +1239,7 @@ * This works for seqpacket too. The receiver has ordered the queue for * us! We do one quick check first though */ + if (sk->state != TCP_ESTABLISHED) return -ENOTCONN; @@ -1252,7 +1252,12 @@ skb->h.raw = skb->data; } - copied = (size < skb->len) ? size : skb->len; + copied = skb->len; + if(copied>size) + { + copied=size; + msg->msg_flags|=MSG_TRUNC; + } skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (sax != NULL) { @@ -1462,7 +1467,7 @@ { sock_register(nr_proto_ops.family, &nr_proto_ops); register_netdevice_notifier(&nr_dev_notifier); - printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.5 for AX25.033 Linux 2.0\n"); + printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.5 for AX25.034 Linux 2.1\n"); if (!ax25_protocol_register(AX25_P_NETROM, nr_route_frame)) printk(KERN_ERR "NET/ROM unable to register protocol with AX.25\n"); diff -u --recursive --new-file v2.1.10/linux/net/netsyms.c linux/net/netsyms.c --- v2.1.10/linux/net/netsyms.c Tue Nov 12 15:56:16 1996 +++ linux/net/netsyms.c Mon Nov 18 11:31:36 1996 @@ -8,8 +8,9 @@ #include #include -#include +#include #include +#include #include #include #include diff -u --recursive --new-file v2.1.10/linux/net/rose/af_rose.c linux/net/rose/af_rose.c --- v2.1.10/linux/net/rose/af_rose.c Tue Nov 12 15:56:17 1996 +++ linux/net/rose/af_rose.c Mon Nov 18 11:31:37 1996 @@ -759,7 +759,7 @@ return 0; } -static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) +static int rose_bind(struct socket *sock, struct sockaddr *uaddr, size_t addr_len) { struct sock *sk; struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr; @@ -769,7 +769,7 @@ sk = (struct sock *)sock->data; if (sk->zapped == 0) - return -EIO; + return -EINVAL; if (addr_len != sizeof(struct sockaddr_rose)) return -EINVAL; @@ -784,7 +784,7 @@ if ((user = ax25_findbyuid(current->euid)) == NULL) { if (ax25_uid_policy && !suser()) - return -EPERM; + return -EACCES; user = source; } @@ -807,7 +807,7 @@ return 0; } -static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) +static int rose_connect(struct socket *sock, struct sockaddr *uaddr, size_t addr_len, int flags) { struct sock *sk = (struct sock *)sock->data; struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr; @@ -957,7 +957,7 @@ } static int rose_getname(struct socket *sock, struct sockaddr *uaddr, - int *uaddr_len, int peer) + size_t *uaddr_len, int peer) { struct sockaddr_rose *srose = (struct sockaddr_rose *)uaddr; struct sock *sk; @@ -1181,9 +1181,6 @@ struct sk_buff *skb; int er; - if (sk->err) - return sock_error(sk); - if (addr_len != NULL) *addr_len = sizeof(*srose); @@ -1203,7 +1200,14 @@ skb->h.raw = skb->data; } - copied = (size < skb->len) ? size : skb->len; + copied = skb->len; + + if(copied>size) + { + copied=size; + msg->msg_flags|=MSG_TRUNC; + } + skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (srose != NULL) { @@ -1404,7 +1408,7 @@ { sock_register(rose_proto_ops.family, &rose_proto_ops); register_netdevice_notifier(&rose_dev_notifier); - printk(KERN_INFO "G4KLX Rose for Linux. Version 0.1 for AX25.033 Linux 2.1\n"); + printk(KERN_INFO "G4KLX Rose for Linux. Version 0.1 for AX25.034 Linux 2.1\n"); if (!ax25_protocol_register(AX25_P_ROSE, rose_route_frame)) printk(KERN_ERR "Rose unable to register protocol with AX.25\n"); diff -u --recursive --new-file v2.1.10/linux/net/rose/rose_link.c linux/net/rose/rose_link.c --- v2.1.10/linux/net/rose/rose_link.c Tue Nov 12 15:56:17 1996 +++ linux/net/rose/rose_link.c Mon Nov 18 11:31:37 1996 @@ -272,7 +272,7 @@ #ifdef CONFIG_FIREWALL if (call_fw_firewall(PF_ROSE, skb->dev, skb->data, NULL) != FW_ACCEPT) - return 0; + return; #endif if (!ax25_link_up((ax25_address *)neigh->dev->dev_addr, &neigh->callsign, neigh->dev)) diff -u --recursive --new-file v2.1.10/linux/net/socket.c linux/net/socket.c --- v2.1.10/linux/net/socket.c Fri Nov 15 23:49:12 1996 +++ linux/net/socket.c Mon Nov 18 11:31:37 1996 @@ -159,7 +159,11 @@ if(copy_to_user(uaddr,kaddr,len)) return -EFAULT; } - return put_user(len, ulen); + /* + * "fromlen shall refer to the value before truncation.." + * 1003.1g + */ + return put_user(klen, ulen); } /* @@ -724,8 +728,12 @@ * For accept, we attempt to create a new socket, set up the link * with the client, wake up the client, then return the new * connected fd. We collect the address of the connector in kernel - * space and move it to user at the very end. This is buggy because + * space and move it to user at the very end. This is unclean because * we open the socket then return an error. + * + * 1003.1g addcs the ability to recvmsg() to query connection pending + * status to recvmsg. We need to add that support in a way thats + * clean when we restucture accept also. */ asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen) @@ -789,9 +797,16 @@ /* * Attempt to connect to a socket with the server address. The address * is in user space so we verify it is OK and move it to kernel space. + * + * For 1003.1g we need to add clean support for a bind to AF_UNSPEC to + * break bindings + * + * NOTE: 1003.1g draft 6.3 is broken with respect to AX.25/NetROM and + * other SEQPACKET protocols that take time to connect() as it doesn't + * include the -EINPROGRESS status for such sockets. */ -asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen) +asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, size_t addrlen) { struct socket *sock; struct file *file; @@ -842,7 +857,7 @@ * name to user space. */ -asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len) +asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, size_t *usockaddr_len) { struct socket *sock; char address[MAX_SOCK_ADDR]; @@ -867,7 +882,7 @@ * name to user space. */ -asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len) +asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, size_t *usockaddr_len) { struct socket *sock; char address[MAX_SOCK_ADDR]; @@ -892,7 +907,7 @@ * in user space. We check it can be read. */ -asmlinkage int sys_send(int fd, void * buff, int len, unsigned flags) +asmlinkage int sys_send(int fd, void * buff, size_t len, unsigned flags) { struct socket *sock; struct file *file; @@ -926,8 +941,8 @@ * the protocol. */ -asmlinkage int sys_sendto(int fd, void * buff, int len, unsigned flags, - struct sockaddr *addr, int addr_len) +asmlinkage int sys_sendto(int fd, void * buff, size_t len, unsigned flags, + struct sockaddr *addr, size_t addr_len) { struct socket *sock; struct file *file; @@ -971,7 +986,7 @@ * Receive a datagram from a socket. Call the protocol recvmsg method */ -asmlinkage int sys_recv(int fd, void * ubuf, int size, unsigned flags) +asmlinkage int sys_recv(int fd, void * ubuf, size_t size, unsigned flags) { struct iovec iov; struct msghdr msg; @@ -1009,8 +1024,8 @@ * sender address from kernel to user space. */ -asmlinkage int sys_recvfrom(int fd, void * ubuf, int size, unsigned flags, - struct sockaddr *addr, int *addr_len) +asmlinkage int sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags, + struct sockaddr *addr, size_t *addr_len) { struct socket *sock; struct file *file; @@ -1129,7 +1144,7 @@ if(sock->ops->sendmsg==NULL) return -EOPNOTSUPP; - if ((err = copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))) + if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr))) return -EFAULT; /* do not move before msg_sys is valid */ @@ -1192,7 +1207,7 @@ if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); - if ((err = copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))) + if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr))) return -EFAULT; if(msg_sys.msg_iovlen>UIO_MAXIOV) @@ -1238,10 +1253,10 @@ { if (!err) { - int ret; - ret = copy_to_user(usr_msg_ctl, krn_msg_ctl, + err = copy_to_user(usr_msg_ctl, krn_msg_ctl, msg_sys.msg_controllen); - err = -EFAULT; + if (err) + err = -EFAULT; } kfree(krn_msg_ctl); } @@ -1438,7 +1453,7 @@ { int i; - printk(KERN_INFO "Swansea University Computer Society NET3.035 for Linux 2.0\n"); + printk(KERN_INFO "Swansea University Computer Society NET3.037 for Linux 2.1\n"); /* * Initialize all address (protocol) families. diff -u --recursive --new-file v2.1.10/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v2.1.10/linux/net/unix/af_unix.c Fri Nov 15 23:49:12 1996 +++ linux/net/unix/af_unix.c Mon Nov 18 11:31:37 1996 @@ -28,6 +28,7 @@ * Nick Nevin : recvmsg bugfix. * Alan Cox : Started proper garbage collector * Heiko EiBfeldt : Missing verify_area check + * Alan Cox : Started POSIXisms * * Known differences from reference BSD that was tested: * @@ -43,6 +44,7 @@ * and a null first byte in the path (but not for gethost/peername - BSD bug ??) * socketpair(...SOCK_RAW..) doesn't panic the kernel. * BSD af_unix apparently has connect forgetting to block properly. + * (need to check this with the POSIX spec in detail) */ #include @@ -395,7 +397,7 @@ } -static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) +static int unix_bind(struct socket *sock, struct sockaddr *uaddr, size_t addr_len) { struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr; unix_socket *sk=sock->data; @@ -416,7 +418,7 @@ sk->protinfo.af_unix.name=kmalloc(addr_len+1, GFP_KERNEL); if(sk->protinfo.af_unix.name==NULL) - return -ENOMEM; + return -ENOBUFS; memcpy(sk->protinfo.af_unix.name, sunaddr->sun_path, addr_len+1); old_fs=get_fs(); @@ -442,14 +444,29 @@ } -static int unix_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) +static int unix_connect(struct socket *sock, struct sockaddr *uaddr, size_t addr_len, int flags) { unix_socket *sk=sock->data; struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr; unix_socket *other; struct sk_buff *skb; int err; + + /* + * 1003.1g breaking connected state with AF_UNSPEC + */ + if(sunaddr->sun_family==AF_UNSPEC) + { + if(sk->protinfo.af_unix.other) + { + sk->protinfo.af_unix.other->protinfo.af_unix.locks--; + sk->protinfo.af_unix.other=NULL; + sock->state=SS_UNCONNECTED; + } + return 0; + } + if(sk->type==SOCK_STREAM && sk->protinfo.af_unix.other) { if(sock->state==SS_CONNECTING && sk->state==TCP_ESTABLISHED) @@ -652,7 +669,7 @@ return 0; } -static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) +static int unix_getname(struct socket *sock, struct sockaddr *uaddr, size_t *uaddr_len, int peer) { unix_socket *sk=sock->data; struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr; @@ -1011,13 +1028,15 @@ static void unix_data_wait(unix_socket * sk) { - cli(); + /* + * AF_UNIX sockets get no messages during interrupts, so this + * is safe without cli/sti. + */ if (!skb_peek(&sk->receive_queue)) { sk->socket->flags |= SO_WAITDATA; interruptible_sleep_on(sk->sleep); sk->socket->flags &= ~SO_WAITDATA; } - sti(); } static int unix_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len) @@ -1033,22 +1052,23 @@ struct cmsghdr *cm=NULL; int ct=msg->msg_iovlen; int err = 0; + int target = 1; if(flags&MSG_OOB) return -EOPNOTSUPP; + if(flags&MSG_WAITALL) + target = size; + if(addr_len) *addr_len=0; - if(sk->err) - return sock_error(sk); - if(msg->msg_control) { cm=msg->msg_control; if(msg->msg_controllencmsg_type!=SCM_RIGHTS || @@ -1080,15 +1100,25 @@ if(skb==NULL) { up(&sk->protinfo.af_unix.readsem); - if(sk->shutdown & RCV_SHUTDOWN) + + if(copied >= target) return copied; - if(copied) + + /* + * POSIX checking order... + */ + + if(sk->err) + return sock_error(sk); + if(sk->shutdown & RCV_SHUTDOWN) return copied; + + if(current->signal & ~current->blocked) + return -ERESTARTSYS; if(noblock) return -EAGAIN; + unix_data_wait(sk); - if(current->signal & ~current->blocked) - return -ERESTARTSYS; down(&sk->protinfo.af_unix.readsem); continue; } @@ -1106,7 +1136,12 @@ *addr_len=sizeof(short); } - num=min(skb->len,len-done); + num=skb->len; + if(num>len-done) + { + num=len-done; + msg->msg_flags|=MSG_TRUNC; + } err = copy_to_user(sp, skb->data, num); if (err) @@ -1283,7 +1318,7 @@ void unix_proto_init(struct net_proto *pro) { - printk(KERN_INFO "NET3: Unix domain sockets 0.13 for Linux NET3.035.\n"); + printk(KERN_INFO "NET3: Unix domain sockets 0.14 for Linux NET3.037.\n"); sock_register(unix_proto_ops.family, &unix_proto_ops); #ifdef CONFIG_PROC_FS proc_net_register(&proc_net_unix);