# 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
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
This keeps track of your IP network traffic and produces some
VERSION = 2
PATCHLEVEL = 1
-SUBLEVEL = 10
+SUBLEVEL = 11
ARCH = i386
{
return 0;
}
+asmlinkage int sys_pciconfig_read()
+{
+ return 0;
+}
+asmlinkage int sys_pciconfig_write()
+{
+ return 0;
+}
#else /* CONFIG_PCI */
#include <asm/hwrpb.h>
#include <asm/io.h>
+#include <asm/segment.h>
#define KB 1024
}
}
+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 */
.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
/*
- * 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 <alpha/regdef.h>
99: x,##y; \
.section __ex_table,"a"; \
.gprel32 99b; \
- lda zero, $exception-99b(zero); \
+ lda v0, $exception-99b(zero); \
.text
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
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
#
# Networking options
#
+# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
# CONFIG_NET_ALIAS is not set
CONFIG_INET=y
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_AX25 is not set
-# CONFIG_NETLINK is not set
#
# SCSI support
# 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
# 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
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 <linux/symtab_end.h>
};
unsigned int cmd, unsigned long arg)
{
struct loop_device *lo;
- int dev, err;
+ int dev;
if (!inode)
return -EINVAL;
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);
}
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);
/* 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;
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) {
* 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:
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
}
}
-int cm206_media_changed(kdev_t dev)
+int cm206_media_changed(struct cdrom_device_info *i, int n)
{
if (cd != NULL) {
int r;
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);
}
/* 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;
}
/* 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();
}
/* 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 */
/* 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) {
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;
return 0;
}
-int cm206_reset(kdev_t dev)
+int cm206_reset(struct cdrom_device_info *i)
{
stop_read();
reset_cm260();
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 */
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;
}
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;
#include <linux/cdrom.h>
#include <linux/optcd.h>
+#include <asm/uaccess.h>
+
\f
/* Debug support */
| ((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 */
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);
(cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
tmp = base_addr[CyCOR3<<index] & CyREC_FIFO;
- put_fs_long(tmp,value);
+ put_user(tmp,value);
return 0;
}
static int
get_default_threshold(struct cyclades_port * info, unsigned long *value)
{
- put_fs_long(info->default_threshold,value);
+ put_user(info->default_threshold,value);
return 0;
}
(cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
tmp = base_addr[CyRTPR<<index];
- put_fs_long(tmp,value);
+ put_user(tmp,value);
return 0;
}
static int
get_default_timeout(struct cyclades_port * info, unsigned long *value)
{
- put_fs_long(info->default_timeout,value);
+ put_user(info->default_timeout,value);
return 0;
}
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
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));
#include <linux/malloc.h>
#include <linux/ioport.h>
#include <linux/delay.h>
+#include <asm/system.h>
#include <asm/io.h>
+#include <asm/uaccess.h>
/*****************************************************************************/
* 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";
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;
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);
}
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;
#include <linux/fcntl.h>
#include <linux/major.h>
+#include <asm/uaccess.h>
+
#include "riscom8.h"
#include "riscom8_reg.h"
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)
(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));
* 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";
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;
}
-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);
* 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;
static struct file_operations wdt_fops = {
- wdt_lseek,
+ wdt_llseek,
wdt_read,
wdt_write,
NULL, /* No Readdir */
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");
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;
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)
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);
(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:
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:
#if defined(__KERNEL__) || defined(__DEBUGVAR__)
#ifdef __KERNEL__
+
/* Kernel includes */
#include <linux/module.h>
#include <linux/major.h>
#include <asm/segment.h>
#include <asm/io.h>
+#include <asm/uaccess.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/malloc.h>
#include <linux/wait.h>
#include <linux/isdnif.h>
+
#endif /* __KERNEL__ */
/* some useful macros for debugging */
#include <linux/isdnif.h>
#include <asm/string.h>
#include <asm/io.h>
+#include <asm/uaccess.h>
#include "pcbit.h"
#include "edss1.h"
{
u_char cbuf[1024];
- memcpy_fromfs(cbuf, buf, len);
+ if (copy_from_user(cbuf, buf, len))
+ return -EFAULT;
for (i=0; i<len; i++)
writeb(cbuf[i], dev->sh_mem + i);
}
/* 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
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)
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;
#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, };
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:
/*
* 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;
}
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);
# 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
DEPCA_OPTS =
EWRK3_OPTS =
DE4X5_OPTS = -DDE4X5_AUTOSENSE=AUTO
+DEFXX_OPTS =
ELP_OPTS =
TULIP_OPTS =
#
# 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
#
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
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)
L_OBJS += lance.o
ifeq ($(CONFIG_LANCE32),y)
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
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.
-
-
--- /dev/null
+/*
+ * 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 <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+#include <asm/byteorder.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/fddidevice.h>
+#include <linux/skbuff.h>
+
+#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? */
+
+\f
+/*
+ * =======================
+ * = 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;
+ }
+
+\f
+/*
+ * =============
+ * = 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);
+ }
+
+\f
+/*
+ * ====================
+ * = 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);
+ }
+
+\f
+/*
+ * ================
+ * = 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;
+ }
+
+\f
+/*
+ * ========================
+ * = 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;
+ }
+
+\f
+/*
+ * ===================
+ * = 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);
+ }
+
+\f
+/*
+ * =================
+ * = 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);
+ }
+
+\f
+/*
+ * ============
+ * = 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);
+ }
+
+\f
+/*
+ * =============
+ * = 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);
+ }
+
+\f
+/*
+ * ======================
+ * = 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;
+ }
+
+\f
+/*
+ * ==========================
+ * = 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;
+ }
+
+\f
+/*
+ * ==================
+ * = 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;
+ }
+
+\f
+/*
+ * =================
+ * = 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;
+ }
+
+\f
+/*
+ * =====================
+ * = 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);
+ }
+
+\f
+/*
+ * ==============================
+ * = 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;
+ }
+
+\f
+/*
+ * ===========================
+ * = 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 */
+ }
+
+\f
+/*
+ * ======================
+ * = 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);
+ }
+
+\f
+/*
+ * ==========================
+ * = 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);
+ }
+
+\f
+/*
+ * ======================
+ * = 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);
+ }
+
+\f
+/*
+ * ========================
+ * = 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);
+ }
+
+\f
+/*
+ * =====================
+ * = 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;
+ }
+
+\f
+/*
+ * ========================
+ * = 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);
+ }
+
+\f
+/*
+ * =====================
+ * = 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);
+ }
+
+\f
+/*
+ * ================
+ * = 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;
+ }
+
+\f
+/*
+ * =========================
+ * = 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;
+ }
+
+\f
+/*
+ * =====================
+ * = 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 */
+ }
+
+\f
+/*
+ * ================
+ * = 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;
+ }
+
+\f
+/*
+ * =================
+ * = 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;
+ }
+
+\f
+/*
+ * 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:
+ */
--- /dev/null
+/*
+ * 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_ */
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/byteorder.h>
+#include <asm/uaccess.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
+#include <asm/uaccess.h>
+
#include <linux/errno.h>
#include <linux/netdevice.h>
#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 */
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);
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);
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;
#include <linux/config.h>
#include <linux/types.h>
+#include <linux/net.h>
#include <linux/in.h>
#include <linux/if.h>
#include <linux/malloc.h>
* 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
{
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)
#include <linux/etherdevice.h>
#include <linux/trdevice.h>
#include <linux/if_arp.h>
+#include <linux/fddidevice.h>
#ifdef CONFIG_NET_ALIAS
#include <linux/net_alias.h>
#endif
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;
#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
+
int ether_config(struct device *dev, struct ifmap *map)
{
if (map->mem_start != (u_long)(-1))
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
+#include <asm/uaccess.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
+#include <linux/net.h>
#include <linux/in.h>
#include <linux/string.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
+#include <asm/uaccess.h>
#include <linux/string.h>
#define NET_DEBUG 1
#define PPA_SPIN_TMO 5000000 /* ppa_wait loop limiter */
#define PPA_SECTOR_SIZE 512 /* for a performance hack only */
-#include <unistd.h>
+#include <linux/stddef.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/tqueue.h>
void scsi_make_blocked_list(void) {
int block_count = 0, index;
- unsigned int flags;
+ unsigned long flags;
struct Scsi_Host * sh[128], * shpnt;
/*
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;
static void scsi_request_sense (Scsi_Cmnd * SCpnt)
{
- unsigned int flags;
+ unsigned long flags;
save_flags(flags);
cli();
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 */
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;
}
/*
#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__)
#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 */
#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);
*
* 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 */
struct sockaddr_at
{
- short sat_family;
+ sa_family_t sat_family;
__u8 sat_port;
struct at_addr sat_addr;
char sat_zero[ 8 ];
} 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 */
--- /dev/null
+/*
+ * 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, <stefani@lkg.dec.com>
+ *
+ * fddidevice.h is based on previous trdevice.h work by
+ * Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Alan Cox, <gw4pts@gw4pts.ampr.org>
+ *
+ * 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 <linux/if_fddi.h>
+
+#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 */
#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. */
--- /dev/null
+/*
+ * 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, <stefani@lkg.dec.com>
+ *
+ * if_fddi.h is based on previous if_ether.h and if_tr.h work by
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Donald Becker, <becker@super.org>
+ * Alan Cox, <alan@cymru.net>
+ * Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
+ * Peter De Schrijver, <stud11@cc4.kuleuven.ac.be>
+ *
+ * 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 */
#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 */
unsigned long multiaddr;
struct ip_mc_list *next;
struct timer_list timer;
- int tm_running;
+ short tm_running;
+ short reporter;
int users;
};
/* 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 */
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 */
};
/* 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
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,
/* 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 */
} rose_address;
struct sockaddr_rose {
- short srose_family;
+ sa_family_t srose_family;
rose_address srose_addr;
ax25_address srose_call;
int srose_ndigis;
* 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;
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
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;
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->data<skb->head)
{
__label__ here;
- panic("skpush:under: %p:%d", &&here,len);
+ panic(skb_push_errstr, &&here,len);
here:
}
return skb->data;
#include <linux/sockios.h> /* the SIOCxxx I/O controls */
#include <linux/uio.h> /* 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 */
};
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 */
};
/* 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 */
#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
#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
#define SOL_ATALK 258
#define SOL_NETROM 259
#define SOL_ROSE 260
+#define SOL_DECNET 261
#define SOL_TCP 6
#define SOL_UDP 17
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 */
#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 */
};
#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 */
#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;
#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... */
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);
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,
#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 <John Ioannidis> */
/* 11 IPv6 route updates */
+ /* 12 is for firewall trapout */
#define MAX_QBYTES 32768 /* Maximum bytes in the queue */
#include <linux/config.h>
-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);
#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 *);
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;
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);
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);
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);
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 *);
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);
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;
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;
}
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)
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;
}
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 */
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.
*/
return (unsigned long) addr;
}
+
/*
* Initialize a module.
*/
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) {
}
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",
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) +
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) {
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) {
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;
}
}
}
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.
*/
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)");
-}
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)
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)
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;
}
/*
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;
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;
}
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:
}
}
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;
}
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);
}
/*
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)
}
}
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;
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;
}
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)
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
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;
}
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;
}
/*
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)
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)) &&
*/
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:
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)
/* 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())
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;
}
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;
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
--- /dev/null
+/*
+ * 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, <stefani@lkg.dec.com>
+ *
+ * fddi.c is based on previous eth.c and tr.c work by
+ * Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Mark Evans, <evansmp@uhura.aston.ac.uk>
+ * Florian La Roche, <rzsfl@rz.uni-sb.de>
+ * Alan Cox, <gw4pts@gw4pts.ampr.org>
+ *
+ * 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 <asm/segment.h>
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/fddidevice.h>
+#include <linux/skbuff.h>
+#include <linux/errno.h>
+#include <net/arp.h>
+#include <net/sock.h>
+
+/*
+ * 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);
+ }
#
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
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
* 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
struct sockaddr_at *sa;
struct device *dev;
struct atalk_iface *atif;
- int ro=(cmd==SIOCSIFADDR);
int err;
int ct;
int limit;
* 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;
sk=(atalk_socket *)sock->data;
if(sk->zapped==0)
- return(-EIO);
+ return(-EINVAL);
if(addr_len!=sizeof(struct sockaddr_at))
return -EINVAL;
*/
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;
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)
{
*/
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;
if(sk->zapped)
{
if(atalk_autobind(sk)<0)
- return -EBUSY;
+ return -ENOBUFS;
}
*uaddr_len = sizeof(struct sockaddr_at);
* 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));
* 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;
}
if(usat)
{
if(sk->zapped)
- /* put the autobinding in */
{
if(atalk_autobind(sk)<0)
return -EBUSY;
if (err)
{
kfree_skb(skb, FREE_WRITE);
- return err;
+ return -EFAULT;
}
if(sk->no_check==1)
struct sk_buff *skb;
int er = 0;
- if(sk->err)
- return sock_error(sk);
-
if(addr_len)
*addr_len=sizeof(*sat);
{
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;
{
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;
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;
{
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;
/*
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
/*
- * 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
* 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
* 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;
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;
}
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;
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;
}
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;
}
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;
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 */
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;
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;
int er;
int dama;
- if (sk->err)
- return sock_error(sk);
-
if (addr_len != NULL)
*addr_len = sizeof(*sax);
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) {
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");
}
/*
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;
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;
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;
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;
if (!ax25->sk->dead)
ax25->sk->state_change(ax25->sk);
ax25->sk->dead = 1;
+ ax25->sk->shutdown|=SEND_SHUTDOWN;
}
break;
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;
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;
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;
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;
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;
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;
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;
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;
#include <net/ax25.h>
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;
*
* Originally by John Hayes (Network Plumbing).
* Minor hacks to get it to run with 1.3.x by Alan Cox <Alan.Cox@linux.org>
+ * More hacks to be able to switch protocols on and off by Christoph Lameter
+ * <clameter@debian.org>
+ * 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
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_PROT_STATS &&
+ br_stats.prot_id[x]!=protocol && br_stats.prot_id[x];x++) ;
+ if (x<BR_MAX_PROT_STATS)
+ { br_stats.prot_id[x]=protocol;br_stats.prot_counter[x]++;
+ }
+ }
+
+ for (x=BR_PROTOCOL_HASH(protocol); br_stats.protocols[x]!=0;) {
+ if (br_stats.protocols[x]==protocol) return !br_stats.policy;
+ x++;
+ if (x==BR_MAX_PROTOCOLS) x=0;
+ }
+ return br_stats.policy;
+}
+
+/* Add a protocol to be handled opposite to the standard policy of the bridge */
+
+int br_add_exempt_protocol(unsigned short p)
+{
+ unsigned x;
+ if (p == 0) return -EINVAL;
+ if (br_stats.exempt_protocols > 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) **/
/*
{ /* (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;
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();*/
}
int br_receive_frame(struct sk_buff *skb) /* 3.5 */
{
int port;
- int i;
if (br_stats.flags & BR_DEBUG)
printk("br_receive_frame: ");
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;
}
}
return(0);
}
-
+
* Linus Torvalds : BSD semantic fixes.
* Alan Cox : Datagram iovec handling
* Darryl Miles : Fixed non-blocking SOCK_STREAM.
+ * Alan Cox : POSIXisms
*
*/
*
* 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)
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);
}
/*
* 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
{
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;
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);
sk->bsdism = valbool;
break;
+ /* We implementation the SO_SNDLOWAT etc to
+ not be settable (1003.1g 5.3) */
default:
return(-ENOPROTOOPT);
}
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);
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
/*
* 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,
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;
*/
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;
*/
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;
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...
struct inet_protocol *ipprot;
unsigned char *dp;
__u32 info = 0;
+
+ if(len<sizeof(struct iphdr))
+ goto flush_it;
iph = (struct iphdr *) (icmph + 1);
+ len-=iph->ihl<<2;
+ if(len<0)
+ goto flush_it;
+
dp= ((unsigned char *)iph)+(iph->ihl<<2);
if(icmph->type==ICMP_DEST_UNREACH)
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);
}
/*
* 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;
/*
* Discard the original packet
*/
-
+flush_it:
kfree_skb(skb, FREE_READ);
}
* 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.
*/
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)
}
-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;
+ }
+ }
}
}
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);
}
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);
}
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;
}
* use output device for accounting.
* Jos Vos : Call forward firewall after routing
* (always use output device).
+ * Alan Cox : Unshare buffer on forward.
*/
#include <linux/config.h>
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
* Willy Konynenberg <willy@xos.nl> 10/5/96.
* Make separate accounting on incoming and outgoing packets possible.
* Jos Vos <jos@xos.nl> 18/5/1996.
+ * Added trap out of bad frames.
+ * Alan Cox <alan@cymru.net> 17/11/1996
*
*
* Masquerading functionality
#include <net/udp.h>
#include <net/sock.h>
#include <net/icmp.h>
+#include <net/netlink.h>
#include <linux/firewall.h>
#include <linux/ip_fw.h>
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 */
}
}
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;
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:
* 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.
* 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;
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.
*/
* 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)
* Copy the information back
*/
- return copy_to_user(req, &r, sizeof(r));
+ return copy_to_user(req, &r, sizeof(r)) ? -EFAULT : 0;
}
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;
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",
#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}
};
*
* 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
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
struct msghdr *msg, int len, int flags,
int *addr_len)
{
- int err;
+ int err=0;
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
/*
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 *)
}
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;
}
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;
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);
/*
* 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;
}
}
while (skb != (struct sk_buff *)&sk->receive_queue);
- if (copied)
+ if (copied >= target)
break;
if (sk->err && !(flags&MSG_PEEK))
* 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)
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)
}
}
-
-/*
- * 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;
-}
-
/*
* Local variables:
* compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strength-reduce -pipe -m486 -DCPU=486 -c -o tcp.o tcp.c"
*/
#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/sysctl.h>
#include <net/tcp.h>
-/*
- * 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
* 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;
}
-int sysctl_tcp_vegas_cong_avoidance = 1;
-
/*
* TCP slow start and congestion avoidance in two flavors:
* RFC 1122 and TCP Vegas.
* 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)
* 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);
tp->basertt = min(seq_rtt, tp->basertt);
else
tp->basertt = seq_rtt;
-
-
+
/*
*
* Actual = throughput for this segment.
*/
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
*/
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
{
*/
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;
}
-
-
}
}
#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.
* 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
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 ||
sk->packets_out = 0;
}
}
-
+#endif
if (sk->packets_out)
{
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:
* 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);
}
}
-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);
}
-static __inline__ void prune_queue(struct sock *sk)
+static void prune_queue(struct sock *sk)
{
struct sk_buff * skb;
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;
+}
+
/*
* Local variables:
* compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strength-reduce -pipe -m486 -DCPU=486 -c -o tcp_input.o tcp_input.c"
* 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;
if (buff == NULL)
{
release_sock(sk);
- return(-ENOMEM);
+ return(-ENOBUFS);
}
buff->sk = sk;
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 */
*/
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);
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)
*/
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;
newsk->mtu = 64;
}
- snd_mss -= sizeof(struct iphdr) - sizeof(struct tcphdr);
+ snd_mss -= sizeof(struct iphdr) + sizeof(struct tcphdr);
if (sk->user_mss)
{
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
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);
/*
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);
+ /*
+ * Advance the send_head
+ * This one is going out.
+ */
+
+ update_send_head(sk);
- atomic_inc(&sk->packets_out);
+ atomic_inc(&sk->packets_out);
/*
* 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;
while ((skb = tp->retrans_head) != NULL)
{
+ struct sk_buff *buff;
struct tcphdr *th;
- u32 tcp_size;
+ int tcp_size;
+ int size;
IS_SKB(skb);
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
*/
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);
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;
}
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
{
(*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;
*/
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;
/*
* Find the 8 bytes of post IP header ICMP included for us
*/
+
+ if(len<sizeof(struct udphdr))
+ return;
uh = (struct udphdr *)header;
return er;
truesize = skb->len - sizeof(struct udphdr);
- copied = min(len, truesize);
+ copied = truesize;
+
+ if(len<truesize)
+ {
+ copied=len;
+ msg->msg_flags|=MSG_TRUNC;
+ }
/*
* FIXME : should use udp header size info value
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);
dev = sit_add_tunnel(ireq.addr.s6_addr32[3]);
if (dev == NULL)
- return -ENOMEM;
+ return -ENODEV;
return 0;
}
*/
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;
/* check this error. */
if (sk->state != TCP_CLOSE)
- return(-EIO);
+ return(-EINVAL);
if(addr_len < sizeof(struct sockaddr_in6))
return -EINVAL;
*/
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;
{
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);
* 2 of the License, or (at your option) any later version.
*/
+/*
+ * Changes:
+ *
+ * Lars Fenneberg : fixed MTU setting on receipt
+ * of an RA.
+ *
+ */
+
/*
* Interface:
*
int mtu;
struct device *dev;
- mtu = htonl(*(__u32 *)opt+4);
+ mtu = htonl(*(__u32 *)(opt+4));
dev = rt->rt_nexthop->dev;
if (mtu < 576)
}
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;
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
* Revision 0.34: Module support. <Jim Freeman>
* Revision 0.35: Checksum support. <Neil Turton>, hooked in by <Alan Cox>
* Handles WIN95 discovery packets <Volker Lendecke>
+ * 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
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;
}
/* 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;
}
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;
sk=(ipx_socket *)sock->data;
if(sk->zapped==0)
- return -EIO;
+ return -EINVAL;
if(addr_len!=sizeof(struct sockaddr_ipx))
return -EINVAL;
}
if(ntohs(addr->sipx_port)<IPX_MIN_EPHEMERAL_SOCKET && !suser())
- return -EPERM; /* protect IPX system stuff like routing/sap */
+ return -EACCES; /* protect IPX system stuff like routing/sap */
sk->protinfo.af_ipx.port=addr->sipx_port;
}
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;
}
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;
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)
{
sipx->sipx_type = ipx->ipx_type;
}
skb_free_datagram(sk, skb);
- return(truesize);
+ return(copied);
}
static int ipx_shutdown(struct socket *sk,int how)
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;
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");
}
#include <asm/uaccess.h>
#include <asm/system.h>
-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];
* 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;
* interfaces.
*/
-int netlink_donothing(struct sk_buff *skb)
+int netlink_donothing(int minor, struct sk_buff *skb)
{
kfree_skb(skb, FREE_READ);
return -EINVAL;
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);
}
/*
* 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;
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();
}
/*
- * 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
* 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 <linux/config.h>
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;
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;
*/
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 {
}
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;
}
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;
struct sk_buff *skb;
int er;
- if (sk->err)
- return sock_error(sk);
-
if (addr_len != NULL)
*addr_len = sizeof(*sax);
* 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;
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) {
{
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");
#include <linux/config.h>
#include <linux/module.h>
-#include <linux/in.h>
+#include <linux/types.h>
#include <linux/net.h>
+#include <linux/in.h>
#include <linux/netdevice.h>
#include <linux/trdevice.h>
#include <linux/ioport.h>
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;
sk = (struct sock *)sock->data;
if (sk->zapped == 0)
- return -EIO;
+ return -EINVAL;
if (addr_len != sizeof(struct sockaddr_rose))
return -EINVAL;
if ((user = ax25_findbyuid(current->euid)) == NULL) {
if (ax25_uid_policy && !suser())
- return -EPERM;
+ return -EACCES;
user = source;
}
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;
}
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;
struct sk_buff *skb;
int er;
- if (sk->err)
- return sock_error(sk);
-
if (addr_len != NULL)
*addr_len = sizeof(*srose);
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) {
{
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");
#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))
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);
}
/*
* 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)
/*
* 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;
* 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];
* 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];
* 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;
* 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;
* 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;
* 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;
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 */
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)
{
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);
}
{
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.
* 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:
*
* 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 <linux/config.h>
}
-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;
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();
}
-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)
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;
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)
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_controllen<sizeof(struct cmsghdr)
-#if 0
+#if 0
/* investigate this further -- Stevens example doesn't seem to care */
||
cm->cmsg_type!=SCM_RIGHTS ||
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;
}
*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)
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);