summaryrefslogtreecommitdiffstats
path: root/net/core/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/dev.c')
-rw-r--r--net/core/dev.c686
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
*