patch-2.1.15 linux/net/core/dev.c
Next file: linux/net/core/dev_mcast.c
Previous file: linux/net/core/datagram.c
Back to the patch index
Back to the overall index
- Lines: 698
- Date:
Thu Dec 12 16:54:23 1996
- Orig file:
v2.1.14/linux/net/core/dev.c
- Orig date:
Tue Nov 19 15:53:59 1996
diff -u --recursive --new-file v2.1.14/linux/net/core/dev.c linux/net/core/dev.c
@@ -84,6 +84,14 @@
#ifdef CONFIG_KERNELD
#include <linux/kerneld.h>
#endif
+#ifdef CONFIG_NET_RADIO
+#include <linux/wireless.h>
+#endif /* CONFIG_NET_RADIO */
+
+/*
+ * 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)
@@ -97,7 +105,7 @@
* Device list lock
*/
-int dev_lockct=0;
+atomic_t dev_lockct=0;
/*
* Our notifier list
@@ -209,7 +217,7 @@
#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,7 +238,7 @@
int dev_open(struct device *dev)
{
- int ret = -ENODEV;
+ int ret = 0;
/*
* Call device private open method
@@ -245,11 +253,23 @@
if (ret == 0)
{
dev->flags |= (IFF_UP | IFF_RUNNING);
+ dev->hash = dev_hash_name(dev->name);
/*
* Initialise multicasting status
*/
dev_mc_upload(dev);
notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
+#ifdef CONFIG_NET_ALIAS
+ if (!net_alias_is(dev) || dev->tx_queue_len)
+#else
+ if (dev->tx_queue_len)
+#endif
+ {
+ cli();
+ dev->next_up = dev_up_base;
+ dev_up_base = dev;
+ sti();
+ }
}
return(ret);
}
@@ -262,6 +282,7 @@
int dev_close(struct device *dev)
{
int ct=0;
+ struct device **devp;
/*
* Call the device specific close. This cannot fail.
@@ -293,10 +314,20 @@
{
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++;
}
+
+ devp = &dev_up_base;
+ while (*devp)
+ {
+ if (*devp == dev)
+ {
+ *devp = dev->next_up;
+ break;
+ }
+ devp = &(*devp)->next_up;
+ }
return(0);
}
@@ -332,12 +363,9 @@
/* 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
@@ -354,34 +382,12 @@
#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.
*/
@@ -424,8 +430,9 @@
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;
+ skb2->nh.raw =
+ skb2->h.raw = skb2->data + dev->hard_header_len;
ptype->func(skb2, skb->dev, ptype);
}
}
@@ -433,10 +440,8 @@
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,18 +457,68 @@
* 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)
+int dev_queue_xmit(struct sk_buff *skb)
{
+ struct device *dev = skb->dev;
+
start_bh_atomic();
- do_dev_queue_xmit(skb, dev, pri);
+
+
+#if CONFIG_SKB_CHECK
+ IS_SKB(skb);
+#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) {
+ if (dev->rebuild_header) {
+ if (dev->rebuild_header(skb)) {
+ end_bh_atomic();
+ return 0;
+ }
+ } else
+ printk("%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.
+ *
+ */
+
+#ifdef CONFIG_NET_ALIAS
+ if (net_alias_is(dev))
+ skb->dev = dev = net_alias_main_dev(dev);
+#endif
+
+ do_dev_queue_xmit(skb, dev, skb->priority);
end_bh_atomic();
+ return 0;
}
+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("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
@@ -481,7 +536,6 @@
*/
skb->sk = NULL;
- skb->free = 1;
if(skb->stamp.tv_sec==0)
get_fast_time(&skb->stamp);
@@ -526,7 +580,7 @@
{
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) {
/*
@@ -557,6 +611,7 @@
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
@@ -591,6 +646,18 @@
__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 +696,11 @@
* 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.
@@ -737,7 +805,10 @@
*/
#ifdef CONFIG_NET_ALIAS
- if (net_alias_is(dev)) return;
+ if (net_alias_is(dev)) {
+ printk("net alias %s transmits\n", dev->name);
+ return;
+ }
#endif
head = dev->buffs;
save_flags(flags);
@@ -757,7 +828,6 @@
/*
* 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
@@ -931,19 +1001,87 @@
#endif /* CONFIG_PROC_FS */
+#ifdef CONFIG_NET_RADIO
+#ifdef CONFIG_PROC_FS
+
+/*
+ * Print one entry of /proc/net/wireless
+ * This is a clone of /proc/net/dev (just above)
+ */
+static int sprintf_wireless_stats(char *buffer, struct device *dev)
+{
+ /* 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.crypt,
+ stats->discard.misc);
+ else
+ size = 0;
+
+ return size;
+}
+
/*
- * This checks bitmasks for the ioctl calls for devices.
+ * Print info for /proc/net/wireless (print all entries)
+ * This is a clone of /proc/net/dev (just above)
*/
-
-static inline int bad_mask(unsigned long mask, unsigned long addr)
+int dev_get_wireless_info(char * buffer, char **start, off_t offset,
+ int length, int dummy)
{
- if (addr & (mask = ~mask))
- return 1;
- mask = ntohl(mask);
- if (mask & (mask+1))
- return 1;
- return 0;
+ 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 +1142,7 @@
*/
dev_lock_wait();
+ dev_lock_list();
/*
* Set the flags on our device.
@@ -1044,134 +1183,21 @@
*/
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 +1214,11 @@
case SIOCSIFMTU: /* Set the MTU of a device */
+ if (ifr.ifr_mtu == dev->mtu) {
+ ret = 0;
+ break;
+ }
+
/*
* MTU must be positive.
*/
@@ -1202,6 +1233,10 @@
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_CHANGE, dev);
+ }
break;
case SIOCGIFMEM: /* Get the per device memory space. We can add this but currently
@@ -1273,7 +1308,27 @@
}
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 +1361,6 @@
*/
case SIOCGIFFLAGS:
- case SIOCGIFADDR:
- case SIOCGIFDSTADDR:
- case SIOCGIFBRDADDR:
- case SIOCGIFNETMASK:
case SIOCGIFMETRIC:
case SIOCGIFMTU:
case SIOCGIFMEM:
@@ -1324,10 +1375,6 @@
*/
case SIOCSIFFLAGS:
- case SIOCSIFADDR:
- case SIOCSIFDSTADDR:
- case SIOCSIFBRDADDR:
- case SIOCSIFNETMASK:
case SIOCSIFMETRIC:
case SIOCSIFMTU:
case SIOCSIFMEM:
@@ -1351,6 +1398,14 @@
(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;
}
}
@@ -1363,7 +1418,6 @@
*
*/
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);
@@ -1382,6 +1436,17 @@
};
#endif
+#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 */
+
int net_dev_init(void)
{
struct device *dev, **dp;
@@ -1473,6 +1538,12 @@
#ifdef CONFIG_PROC_FS
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
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov