diff options
Diffstat (limited to 'net/core/dev.c')
-rw-r--r-- | net/core/dev.c | 686 |
1 files changed, 443 insertions, 243 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index f6bc01f9d..c02d4052e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -78,26 +78,52 @@ #include <linux/proc_fs.h> #include <linux/stat.h> #include <net/br.h> -#ifdef CONFIG_NET_ALIAS #include <linux/net_alias.h> -#endif +#include <linux/init.h> #ifdef CONFIG_KERNELD #include <linux/kerneld.h> #endif +#ifdef CONFIG_NET_RADIO +#include <linux/wireless.h> +#endif /* CONFIG_NET_RADIO */ +#ifdef CONFIG_PLIP +extern int plip_init(void); +#endif + +/* + * The list of devices, that are able to output. + */ + +static struct device *dev_up_base; /* * The list of packet types we will receive (as opposed to discard) * and the routines to invoke. + * + * Why 16. Because with 16 the only overlap we get on a hash of the + * low nibble of the protocol value is RARP/SNAP/X.25. + * + * 0800 IP + * 0001 802.3 + * 0002 AX.25 + * 0004 802.2 + * 8035 RARP + * 0005 SNAP + * 0805 X.25 + * 0806 ARP + * 8137 IPX + * 0009 Localtalk + * 86DD IPv6 */ -struct packet_type *ptype_base[16]; +struct packet_type *ptype_base[16]; /* 16 way hashed list */ struct packet_type *ptype_all = NULL; /* Taps */ /* * Device list lock */ -int dev_lockct=0; +atomic_t dev_lockct = ATOMIC_INIT(0); /* * Our notifier list @@ -202,14 +228,79 @@ struct device *dev_get(const char *name) } return NULL; } - + +struct device * dev_get_by_index(int ifindex) +{ + struct device *dev; + + for (dev = dev_base; dev != NULL; dev = dev->next) + { + if (dev->ifindex == ifindex) + return(dev); + } + return NULL; +} + +struct device *dev_getbyhwaddr(unsigned short type, char *ha) +{ + struct device *dev; + + for (dev = dev_base; dev != NULL; dev = dev->next) + { + if (dev->type == type && + !(dev->flags&(IFF_LOOPBACK|IFF_NOARP)) && + memcmp(dev->dev_addr, ha, dev->addr_len) == 0) + return(dev); + } + return(NULL); +} + +/* + * Passed a format string - eg "lt%d" it will try and find a suitable + * id. Not efficient for many devices, not called a lot.. + */ + +int dev_alloc_name(struct device *dev, const char *name) +{ + int i; + /* + * If you need over 100 please also fix the algorithm... + */ + for(i=0;i<100;i++) + { + sprintf(dev->name,name,i); + if(dev_get(dev->name)==NULL) + return i; + } + return -ENFILE; /* Over 100 of the things .. bail out! */ +} + +struct device *dev_alloc(const char *name, int *err) +{ + struct device *dev=kmalloc(sizeof(struct device)+16, GFP_KERNEL); + if(dev==NULL) + { + *err=-ENOBUFS; + return NULL; + } + dev->name=(char *)(dev+1); /* Name string space */ + *err=dev_alloc_name(dev,name); + if(*err<0) + { + kfree(dev); + return NULL; + } + return dev; +} + + /* * Find and possibly load an interface. */ #ifdef CONFIG_KERNELD -extern __inline__ void dev_load(const char *name) +void dev_load(const char *name) { if(!dev_get(name)) { #ifdef CONFIG_NET_ALIAS @@ -230,11 +321,12 @@ extern __inline__ void dev_load(const char *name) int dev_open(struct device *dev) { - int ret = -ENODEV; + int ret = 0; /* * Call device private open method */ + if (dev->open) ret = dev->open(dev); @@ -250,6 +342,18 @@ int dev_open(struct device *dev) */ dev_mc_upload(dev); notifier_call_chain(&netdev_chain, NETDEV_UP, dev); + + /* + * Passive non transmitting devices (including + * aliases) need not be on this chain. + */ + if (!net_alias_is(dev) && dev->tx_queue_len) + { + cli(); + dev->next_up = dev_up_base; + dev_up_base = dev; + sti(); + } } return(ret); } @@ -262,6 +366,7 @@ int dev_open(struct device *dev) int dev_close(struct device *dev) { int ct=0; + struct device **devp; /* * Call the device specific close. This cannot fail. @@ -280,6 +385,7 @@ int dev_close(struct device *dev) /* * Tell people we are going down */ + notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); /* * Flush the multicast chain @@ -293,10 +399,24 @@ int dev_close(struct device *dev) { struct sk_buff *skb; while((skb=skb_dequeue(&dev->buffs[ct]))!=NULL) - if(skb->free) - kfree_skb(skb,FREE_WRITE); + kfree_skb(skb,FREE_WRITE); ct++; } + + /* + * The device is no longer up. Drop it from the list. + */ + + devp = &dev_up_base; + while (*devp) + { + if (*devp == dev) + { + *devp = dev->next_up; + break; + } + devp = &(*devp)->next_up; + } return(0); } @@ -317,6 +437,34 @@ int unregister_netdevice_notifier(struct notifier_block *nb) } /* + * Support routine. Sends outgoing frames to any network + * taps currently in use. + */ + +static void queue_xmit_nit(struct sk_buff *skb, struct device *dev) +{ + struct packet_type *ptype; + get_fast_time(&skb->stamp); + + for (ptype = ptype_all; ptype!=NULL; ptype = ptype->next) + { + /* Never send packets back to the socket + * they originated from - MvS (miquels@drinkel.ow.org) + */ + if ((ptype->dev == dev || !ptype->dev) && + ((struct sock *)ptype->data != skb->sk)) + { + struct sk_buff *skb2; + if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) + break; + skb2->mac.raw = skb2->data; + skb2->nh.raw = skb2->h.raw = skb2->data + dev->hard_header_len; + ptype->func(skb2, skb->dev, ptype); + } + } +} + +/* * Send (or queue for sending) a packet. * * IMPORTANT: When this is called to resend frames. The caller MUST @@ -332,13 +480,6 @@ static void do_dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) /* at the front or the back of the */ /* queue - front is a retransmit try */ - if(pri>=0 && !skb_device_locked(skb)) - skb_device_lock(skb); /* Shove a lock on the frame */ -#if CONFIG_SKB_CHECK - IS_SKB(skb); -#endif - skb->dev = dev; - /* * Negative priority is used to flag a frame that is being pulled from the * queue front as a retransmit attempt. It therefore goes back on the queue @@ -354,34 +495,12 @@ static void do_dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) #ifdef CONFIG_NET_DEBUG if (pri >= DEV_NUMBUFFS) { - printk(KERN_WARNING "bad priority in dev_queue_xmit.\n"); + printk(KERN_WARNING "bad priority in do_dev_queue_xmit.\n"); pri = 1; } #endif /* - * If the address has not been resolved. Call the device header rebuilder. - * This can cover all protocols and technically not just ARP either. - */ - - if (!skb->arp && dev->rebuild_header(skb->data, dev, skb->raddr, skb)) { - return; - } - - /* - * - * If dev is an alias, switch to its main device. - * "arp" resolution has been made with alias device, so - * arp entries refer to alias, not main. - * - */ - -#ifdef CONFIG_NET_ALIAS - if (net_alias_is(dev)) - skb->dev = dev = net_alias_main_dev(dev); -#endif - - /* * If we are bridging and this is directly generated output * pass the frame via the bridge. */ @@ -397,46 +516,34 @@ static void do_dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) list = dev->buffs + pri; save_flags(flags); - /* if this isn't a retransmission, use the first packet instead... */ - if (!retransmission) { - if (skb_queue_len(list)) { - /* avoid overrunning the device queue.. */ - if (skb_queue_len(list) > dev->tx_queue_len) { - dev_kfree_skb(skb, FREE_WRITE); - return; - } - } - /* copy outgoing packets to any sniffer packet handlers */ - if (dev_nit) { - struct packet_type *ptype; - - get_fast_time(&skb->stamp); + /* + * If this isn't a retransmission, use the first packet instead. + * Note: We don't do strict priority ordering here. We will in + * fact kick the queue that is our priority. The dev_tint reload + * does strict priority queueing. In effect what we are doing here + * is to add some random jitter to the queues and to do so by + * saving clocks. Doing a perfect priority queue isn't a good idea + * as you get some fascinating timing interactions. + */ - for (ptype = ptype_all; ptype!=NULL; ptype = ptype->next) - { - /* Never send packets back to the socket - * they originated from - MvS (miquels@drinkel.ow.org) - */ - if ((ptype->dev == dev || !ptype->dev) && - ((struct sock *)ptype->data != skb->sk)) - { - struct sk_buff *skb2; - if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) - break; - skb2->h.raw = skb2->data + dev->hard_header_len; - skb2->mac.raw = skb2->data; - ptype->func(skb2, skb->dev, ptype); - } - } + if (!retransmission) + { + /* avoid overrunning the device queue.. */ + if (skb_queue_len(list) > dev->tx_queue_len) + { + dev_kfree_skb(skb, FREE_WRITE); + return; } + /* copy outgoing packets to any sniffer packet handlers */ + if (dev_nit) + queue_xmit_nit(skb,dev); + if (skb_queue_len(list)) { cli(); - skb_device_unlock(skb); /* Buffer is on the device queue and can be freed safely */ __skb_queue_tail(list, skb); skb = __skb_dequeue(list); - skb_device_lock(skb); /* New buffer needs locking down */ restore_flags(flags); } } @@ -452,22 +559,82 @@ static void do_dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) * no longer device locked (it can be freed safely from the device queue) */ cli(); - skb_device_unlock(skb); __skb_queue_head(list,skb); restore_flags(flags); } -void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) +/* + * Entry point for transmitting frames. + */ + +int dev_queue_xmit(struct sk_buff *skb) { + struct device *dev = skb->dev; + start_bh_atomic(); - do_dev_queue_xmit(skb, dev, pri); + + /* + * If the address has not been resolved. Call the device header rebuilder. + * This can cover all protocols and technically not just ARP either. + */ + + if (!skb->arp) + { + /* + * FIXME: we should make the printk for no rebuild + * header a default rebuild_header routine and drop + * this call. Similarly we should make hard_header + * have a default NULL operation not check conditions. + */ + if (dev->rebuild_header) + { + if (dev->rebuild_header(skb)) + { + end_bh_atomic(); + return 0; + } + } + else + printk(KERN_DEBUG "%s: !skb->arp & !rebuild_header!\n", dev->name); + } + + /* + * + * If dev is an alias, switch to its main device. + * "arp" resolution has been made with alias device, so + * arp entries refer to alias, not main. + * + */ + + if (net_alias_is(dev)) + skb->dev = dev = net_alias_main_dev(dev); + + do_dev_queue_xmit(skb, dev, skb->priority); end_bh_atomic(); + return 0; } /* + * Fast path for loopback frames. + */ + +void dev_loopback_xmit(struct sk_buff *skb) +{ + struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC); + if (newskb==NULL) + return; + + skb_pull(newskb, newskb->nh.raw - newskb->data); + newskb->ip_summed = CHECKSUM_UNNECESSARY; + if (newskb->dst==NULL) + printk(KERN_DEBUG "BUG: packet without dst looped back 1\n"); + netif_rx(newskb); +} + + +/* * Receive a packet from a device driver and queue it for the upper - * (protocol) levels. It always succeeds. This is the recommended - * interface to use. + * (protocol) levels. It always succeeds. */ void netif_rx(struct sk_buff *skb) @@ -481,7 +648,6 @@ void netif_rx(struct sk_buff *skb) */ skb->sk = NULL; - skb->free = 1; if(skb->stamp.tv_sec==0) get_fast_time(&skb->stamp); @@ -503,9 +669,7 @@ void netif_rx(struct sk_buff *skb) /* * Add it to the "backlog" queue. */ -#if CONFIG_SKB_CHECK - IS_SKB(skb); -#endif + skb_queue_tail(&backlog,skb); backlog_size++; @@ -526,9 +690,10 @@ static void dev_transmit(void) { struct device *dev; - for (dev = dev_base; dev != NULL; dev = dev->next) + for (dev = dev_up_base; dev != NULL; dev = dev->next_up) { - if (dev->flags != 0 && !dev->tbusy) { + if (dev->flags != 0 && !dev->tbusy) + { /* * Kick the device */ @@ -557,6 +722,7 @@ void net_bh(void) struct packet_type *ptype; struct packet_type *pt_prev; unsigned short type; + int nit = 301; /* * Can we send anything now? We want to clear the @@ -581,7 +747,8 @@ void net_bh(void) * disabling interrupts. */ - while (!skb_queue_empty(&backlog)) { + while (!skb_queue_empty(&backlog)) + { struct sk_buff * skb = backlog.next; /* @@ -591,8 +758,18 @@ void net_bh(void) __skb_unlink(skb, &backlog); backlog_size--; sti(); - + /* + * We do not want to spin in net_bh infinitely. --ANK + */ + if (--nit <= 0) + { + if (nit == 0) + printk(KERN_WARNING "net_bh: too many loops, dropping...\n"); + kfree_skb(skb, FREE_WRITE); + continue; + } + #ifdef CONFIG_BRIDGE /* @@ -629,10 +806,11 @@ void net_bh(void) * Bump the pointer to the next structure. * * On entry to the protocol layer. skb->data and - * skb->h.raw point to the MAC and encapsulated data + * skb->nh.raw point to the MAC and encapsulated data */ - skb->h.raw = skb->data; + /* XXX until we figure out every place to modify.. */ + skb->h.raw = skb->nh.raw = skb->data; /* * Fetch the packet protocol ID. @@ -715,9 +893,7 @@ void net_bh(void) * One last output flush. */ -#ifdef XMIT_AFTER dev_transmit(); -#endif } @@ -736,9 +912,11 @@ void dev_tint(struct device *dev) * aliases do not transmit (for now :) ) */ -#ifdef CONFIG_NET_ALIAS - if (net_alias_is(dev)) return; -#endif + if (net_alias_is(dev)) { + printk(KERN_DEBUG "net alias %s transmits\n", dev->name); + return; + } + head = dev->buffs; save_flags(flags); cli(); @@ -757,7 +935,6 @@ void dev_tint(struct device *dev) /* * Stop anyone freeing the buffer while we retransmit it */ - skb_device_lock(skb); restore_flags(flags); /* * Feed them to the output stage and if it fails @@ -778,7 +955,7 @@ void dev_tint(struct device *dev) /* * Perform a SIOCGIFCONF call. This structure will change - * size shortly, and there is nothing I can do about it. + * size eventually, and there is nothing I can do about it. * Thus we will need a 'compatibility mode'. */ @@ -812,8 +989,6 @@ static int dev_ifconf(char *arg) for (dev = dev_base; dev != NULL; dev = dev->next) { - if(!(dev->flags & IFF_UP)) /* Downed devices don't count */ - continue; /* * Have we run out of space here ? */ @@ -864,17 +1039,19 @@ static int dev_ifconf(char *arg) #ifdef CONFIG_PROC_FS static int sprintf_stats(char *buffer, struct device *dev) { - struct enet_statistics *stats = (dev->get_stats ? dev->get_stats(dev): NULL); + struct net_device_stats *stats = (dev->get_stats ? dev->get_stats(dev): NULL); int size; if (stats) - size = sprintf(buffer, "%6s:%7d %4d %4d %4d %4d %8d %4d %4d %4d %5d %4d\n", + size = sprintf(buffer, "%6s:%8lu %7lu %4lu %4lu %4lu %4lu %8lu %8lu %4lu %4lu %4lu %5lu %4lu\n", dev->name, + stats->rx_bytes, stats->rx_packets, stats->rx_errors, stats->rx_dropped + stats->rx_missed_errors, stats->rx_fifo_errors, stats->rx_length_errors + stats->rx_over_errors + stats->rx_crc_errors + stats->rx_frame_errors, + stats->tx_bytes, stats->tx_packets, stats->tx_errors, stats->tx_dropped, stats->tx_fifo_errors, stats->collisions, stats->tx_carrier_errors + stats->tx_aborted_errors @@ -901,7 +1078,7 @@ int dev_get_info(char *buffer, char **start, off_t offset, int length, int dummy size = sprintf(buffer, "Inter-| Receive | Transmit\n" - " face |packets errs drop fifo frame|packets errs drop fifo colls carrier\n"); + " face |bytes packets errs drop fifo frame|bytes packets errs drop fifo colls carrier\n"); pos+=size; len+=size; @@ -931,19 +1108,87 @@ int dev_get_info(char *buffer, char **start, off_t offset, int length, int dummy #endif /* CONFIG_PROC_FS */ +#ifdef CONFIG_NET_RADIO +#ifdef CONFIG_PROC_FS + /* - * This checks bitmasks for the ioctl calls for devices. + * Print one entry of /proc/net/wireless + * This is a clone of /proc/net/dev (just above) */ - -static inline int bad_mask(unsigned long mask, unsigned long addr) +static int sprintf_wireless_stats(char *buffer, struct device *dev) { - if (addr & (mask = ~mask)) - return 1; - mask = ntohl(mask); - if (mask & (mask+1)) - return 1; - return 0; + /* Get stats from the driver */ + struct iw_statistics *stats = (dev->get_wireless_stats ? + dev->get_wireless_stats(dev) : + (struct iw_statistics *) NULL); + int size; + + if(stats != (struct iw_statistics *) NULL) + size = sprintf(buffer, + "%6s: %02x %3d%c %3d%c %3d%c %5d %5d %5d\n", + dev->name, + stats->status, + stats->qual.qual, + stats->qual.updated & 1 ? '.' : ' ', + stats->qual.level, + stats->qual.updated & 2 ? '.' : ' ', + stats->qual.noise, + stats->qual.updated & 3 ? '.' : ' ', + stats->discard.nwid, + stats->discard.code, + stats->discard.misc); + else + size = 0; + + return size; +} + +/* + * Print info for /proc/net/wireless (print all entries) + * This is a clone of /proc/net/dev (just above) + */ +int dev_get_wireless_info(char * buffer, char **start, off_t offset, + int length, int dummy) +{ + int len = 0; + off_t begin = 0; + off_t pos = 0; + int size; + + struct device * dev; + + size = sprintf(buffer, + "Inter-|sta| Quality | Discarded packets\n" + " face |tus|link level noise| nwid crypt misc\n"); + + pos+=size; + len+=size; + + for(dev = dev_base; dev != NULL; dev = dev->next) + { + size = sprintf_wireless_stats(buffer+len, dev); + len+=size; + pos=begin+len; + + if(pos < offset) + { + len=0; + begin=pos; + } + if(pos > offset + length) + break; + } + + *start = buffer + (offset - begin); /* Start of wanted data */ + len -= (offset - begin); /* Start slop */ + if(len > length) + len = length; /* Ending slop */ + + return len; } +#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_NET_RADIO */ + /* * Perform the SIOCxIFxxx calls. @@ -1004,6 +1249,7 @@ static int dev_ifsioc(void *arg, unsigned int getset) */ dev_lock_wait(); + dev_lock_list(); /* * Set the flags on our device. @@ -1044,134 +1290,21 @@ static int dev_ifsioc(void *arg, unsigned int getset) */ dev_mc_upload(dev); - } - break; - - case SIOCGIFADDR: /* Get interface address (and family) */ - if(ifr.ifr_addr.sa_family==AF_UNSPEC) - { - memcpy(ifr.ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN); - ifr.ifr_hwaddr.sa_family=dev->type; - goto rarok; - } - else - { - (*(struct sockaddr_in *) - &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr; - (*(struct sockaddr_in *) - &ifr.ifr_addr).sin_family = dev->family; - (*(struct sockaddr_in *) - &ifr.ifr_addr).sin_port = 0; - } - goto rarok; - - case SIOCSIFADDR: /* Set interface address (and family) */ - - /* - * BSDism. SIOCSIFADDR family=AF_UNSPEC sets the - * physical address. We can cope with this now. - */ - - if(ifr.ifr_addr.sa_family==AF_UNSPEC) - { - if(dev->set_mac_address==NULL) - return -EOPNOTSUPP; - ret=dev->set_mac_address(dev,&ifr.ifr_addr); - } - else - { - u32 new_pa_addr = (*(struct sockaddr_in *) - &ifr.ifr_addr).sin_addr.s_addr; - u16 new_family = ifr.ifr_addr.sa_family; - - if (new_family == dev->family && - new_pa_addr == dev->pa_addr) { - ret =0; - break; + if ((dev->flags&IFF_UP) && ((old_flags^dev->flags)&~(IFF_UP|IFF_RUNNING|IFF_PROMISC))) + { + printk(KERN_DEBUG "SIFFL %s(%s)\n", dev->name, current->comm); + notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev); } - if (dev->flags & IFF_UP) - notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); - - /* - * if dev is an alias, must rehash to update - * address change - */ - -#ifdef CONFIG_NET_ALIAS - if (net_alias_is(dev)) - net_alias_dev_rehash(dev ,&ifr.ifr_addr); -#endif - dev->pa_addr = new_pa_addr; - dev->family = new_family; - -#ifdef CONFIG_INET - /* This is naughty. When net-032e comes out It wants moving into the net032 - code not the kernel. Till then it can sit here (SIGH) */ - if (!dev->pa_mask) - dev->pa_mask = ip_get_mask(dev->pa_addr); -#endif - if (!dev->pa_brdaddr) - dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask; - if (dev->flags & IFF_UP) - notifier_call_chain(&netdev_chain, NETDEV_UP, dev); - ret = 0; - } - break; - - case SIOCGIFBRDADDR: /* Get the broadcast address */ - (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_addr.s_addr = dev->pa_brdaddr; - (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_family = dev->family; - (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_port = 0; - goto rarok; - - case SIOCSIFBRDADDR: /* Set the broadcast address */ - dev->pa_brdaddr = (*(struct sockaddr_in *) - &ifr.ifr_broadaddr).sin_addr.s_addr; - ret = 0; - break; - - case SIOCGIFDSTADDR: /* Get the destination address (for point-to-point links) */ - (*(struct sockaddr_in *) - &ifr.ifr_dstaddr).sin_addr.s_addr = dev->pa_dstaddr; - (*(struct sockaddr_in *) - &ifr.ifr_dstaddr).sin_family = dev->family; - (*(struct sockaddr_in *) - &ifr.ifr_dstaddr).sin_port = 0; - goto rarok; - - case SIOCSIFDSTADDR: /* Set the destination address (for point-to-point links) */ - dev->pa_dstaddr = (*(struct sockaddr_in *) - &ifr.ifr_dstaddr).sin_addr.s_addr; - ret = 0; - break; - - case SIOCGIFNETMASK: /* Get the netmask for the interface */ - (*(struct sockaddr_in *) - &ifr.ifr_netmask).sin_addr.s_addr = dev->pa_mask; - (*(struct sockaddr_in *) - &ifr.ifr_netmask).sin_family = dev->family; - (*(struct sockaddr_in *) - &ifr.ifr_netmask).sin_port = 0; - goto rarok; - - case SIOCSIFNETMASK: /* Set the netmask for the interface */ - { - unsigned long mask = (*(struct sockaddr_in *) - &ifr.ifr_netmask).sin_addr.s_addr; - ret = -EINVAL; - /* - * The mask we set must be legal. - */ - if (bad_mask(mask,0)) - break; - dev->pa_mask = mask; - ret = 0; + if ((dev->flags^old_flags)&IFF_PROMISC) { + if (dev->flags&IFF_PROMISC) + printk(KERN_INFO "%s enters promiscuous mode.\n", dev->name); + else + printk(KERN_INFO "%s leave promiscuous mode.\n", dev->name); + } + dev_unlock_list(); } break; - + case SIOCGIFMETRIC: /* Get the metric on the interface (currently unused) */ ifr.ifr_metric = dev->metric; @@ -1188,6 +1321,11 @@ static int dev_ifsioc(void *arg, unsigned int getset) case SIOCSIFMTU: /* Set the MTU of a device */ + if (ifr.ifr_mtu == dev->mtu) { + ret = 0; + break; + } + /* * MTU must be positive. */ @@ -1202,6 +1340,10 @@ static int dev_ifsioc(void *arg, unsigned int getset) dev->mtu = ifr.ifr_mtu; ret = 0; } + if (!ret && dev->flags&IFF_UP) { + printk(KERN_DEBUG "SIFMTU %s(%s)\n", dev->name, current->comm); + notifier_call_chain(&netdev_chain, NETDEV_CHANGEMTU, dev); + } break; case SIOCGIFMEM: /* Get the per device memory space. We can add this but currently @@ -1224,6 +1366,8 @@ static int dev_ifsioc(void *arg, unsigned int getset) if(ifr.ifr_hwaddr.sa_family!=dev->type) return -EINVAL; ret=dev->set_mac_address(dev,&ifr.ifr_hwaddr); + if (!ret) + notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); break; case SIOCGIFMAP: @@ -1255,6 +1399,12 @@ static int dev_ifsioc(void *arg, unsigned int getset) return -EINVAL; dev_mc_delete(dev,ifr.ifr_hwaddr.sa_data,dev->addr_len, 1); return 0; + + case SIOGIFINDEX: + ifr.ifr_ifindex = dev->ifindex; + goto rarok; + + /* * Unknown or private ioctl */ @@ -1273,7 +1423,27 @@ static int dev_ifsioc(void *arg, unsigned int getset) } break; } - + +#ifdef CONFIG_NET_RADIO + if((getset >= SIOCIWFIRST) && (getset <= SIOCIWLAST)) + { + if(dev->do_ioctl==NULL) + return -EOPNOTSUPP; + /* Perform the ioctl */ + ret=dev->do_ioctl(dev, &ifr, getset); + /* If return args... */ + if(IW_IS_GET(getset)) + { + if (copy_to_user(arg, &ifr, + sizeof(struct ifreq))) + { + ret = -EFAULT; + } + } + break; + } +#endif /* CONFIG_NET_RADIO */ + ret = -EINVAL; } return(ret); @@ -1306,10 +1476,6 @@ int dev_ioctl(unsigned int cmd, void *arg) */ case SIOCGIFFLAGS: - case SIOCGIFADDR: - case SIOCGIFDSTADDR: - case SIOCGIFBRDADDR: - case SIOCGIFNETMASK: case SIOCGIFMETRIC: case SIOCGIFMTU: case SIOCGIFMEM: @@ -1317,6 +1483,7 @@ int dev_ioctl(unsigned int cmd, void *arg) case SIOCSIFHWADDR: case SIOCGIFSLAVE: case SIOCGIFMAP: + case SIOGIFINDEX: return dev_ifsioc(arg, cmd); /* @@ -1324,10 +1491,6 @@ int dev_ioctl(unsigned int cmd, void *arg) */ case SIOCSIFFLAGS: - case SIOCSIFADDR: - case SIOCSIFDSTADDR: - case SIOCSIFBRDADDR: - case SIOCSIFNETMASK: case SIOCSIFMETRIC: case SIOCSIFMTU: case SIOCSIFMEM: @@ -1351,10 +1514,23 @@ int dev_ioctl(unsigned int cmd, void *arg) (cmd <= (SIOCDEVPRIVATE + 15))) { return dev_ifsioc(arg, cmd); } +#ifdef CONFIG_NET_RADIO + if((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) + { + if((IW_IS_SET(cmd)) && (!suser())) + return -EPERM; + return dev_ifsioc(arg, cmd); + } +#endif /* CONFIG_NET_RADIO */ return -EINVAL; } } +int dev_new_index() +{ + static int ifindex; + return ++ifindex; +} /* * Initialize the DEV module. At boot time this walks the device list and @@ -1363,7 +1539,6 @@ int dev_ioctl(unsigned int cmd, void *arg) * */ extern int lance_init(void); -extern int ni65_init(void); extern int pi_init(void); extern int bpq_init(void); extern int scc_init(void); @@ -1372,6 +1547,7 @@ extern void dlci_setup(void); extern int pt_init(void); extern int sm_init(void); extern int baycom_init(void); +extern int lapbeth_init(void); #ifdef CONFIG_PROC_FS static struct proc_dir_entry proc_net_dev = { @@ -1382,7 +1558,18 @@ static struct proc_dir_entry proc_net_dev = { }; #endif -int net_dev_init(void) +#ifdef CONFIG_NET_RADIO +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry proc_net_wireless = { + PROC_NET_WIRELESS, 8, "wireless", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_net_inode_operations, + dev_get_wireless_info +}; +#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_NET_RADIO */ + +__initfunc(int net_dev_init(void)) { struct device *dev, **dp; @@ -1432,6 +1619,12 @@ int net_dev_init(void) #if defined(CONFIG_SOUNDMODEM) sm_init(); #endif +#if defined(CONFIG_LAPBETHER) + lapbeth_init(); +#endif +#if defined(CONFIG_PLIP) + plip_init(); +#endif /* * SLHC if present needs attaching so other people see it * even if not opened. @@ -1467,6 +1660,7 @@ int net_dev_init(void) else { dp = &dev->next; + dev->ifindex = dev_new_index(); } } @@ -1474,6 +1668,12 @@ int net_dev_init(void) proc_net_register(&proc_net_dev); #endif +#ifdef CONFIG_NET_RADIO +#ifdef CONFIG_PROC_FS + proc_net_register(&proc_net_wireless); +#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_NET_RADIO */ + /* * Initialise net_alias engine * |