📄 dev.c
字号:
/* * NET3 Protocol independent device support routines. * * 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. * * Derived from the non IP parts of dev.c 1.0.19 * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Mark Evans, <evansmp@uhura.aston.ac.uk> * * Additional Authors: * Florian la Roche <rzsfl@rz.uni-sb.de> * Alan Cox <gw4pts@gw4pts.ampr.org> * David Hinds <dhinds@allegro.stanford.edu> * * Changes: * Alan Cox : device private ioctl copies fields back. * Alan Cox : Transmit queue code does relevant stunts to * keep the queue safe. * Alan Cox : Fixed double lock. * Alan Cox : Fixed promisc NULL pointer trap * ???????? : Support the full private ioctl range * Alan Cox : Moved ioctl permission check into drivers * Tim Kordas : SIOCADDMULTI/SIOCDELMULTI * Alan Cox : 100 backlog just doesn't cut it when * you start doing multicast video 8) * Alan Cox : Rewrote net_bh and list manager. * Alan Cox : Fix ETH_P_ALL echoback lengths. * Alan Cox : Took out transmit every packet pass * Saved a few bytes in the ioctl handler * Alan Cox : Network driver sets packet type before calling netif_rx. Saves * a function call a packet. * Alan Cox : Hashed net_bh() * Richard Kooijman: Timestamp fixes. * Alan Cox : Wrong field in SIOCGIFDSTADDR * Alan Cox : Device lock protection. * Alan Cox : Fixed nasty side effect of device close changes. * Rudi Cilibrasi : Pass the right thing to set_mac_address() * Dave Miller : 32bit quantity for the device lock to make it work out * on a Sparc. * Bjorn Ekwall : Added KERNELD hack. * Alan Cox : Cleaned up the backlog initialise. * Craig Metz : SIOCGIFCONF fix if space for under * 1 device. * Thomas Bogendoerfer : Return ENODEV for dev_open, if there * is no device open function. * Lawrence V. Stefani : Changed set MTU ioctl to not assume * min MTU of 68 bytes for devices * that have change MTU functions. * */#include <asm/segment.h>#include <asm/system.h>#include <asm/bitops.h>#include <linux/config.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/sockios.h>#include <linux/in.h>#include <linux/errno.h>#include <linux/interrupt.h>#include <linux/if_ether.h>#include <linux/inet.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/notifier.h>#include <net/ip.h>#include <net/route.h>#include <linux/skbuff.h>#include <net/sock.h>#include <net/arp.h>#include <net/slhc.h>#include <linux/proc_fs.h>#include <linux/stat.h>#include <net/br.h>#ifdef CONFIG_NET_ALIAS#include <linux/net_alias.h>#endif#ifdef CONFIG_KERNELD#include <linux/kerneld.h>#endif#ifdef CONFIG_NET_RADIO#include <linux/wireless.h>#endif /* CONFIG_NET_RADIO */#ifndef MACH/* * The list of packet types we will receive (as opposed to discard) * and the routines to invoke. */struct packet_type *ptype_base[16];struct packet_type *ptype_all = NULL; /* Taps *//* * Device list lock */ int dev_lockct=0; /* * Our notifier list */ struct notifier_block *netdev_chain=NULL;/* * Device drivers call our routines to queue packets here. We empty the * queue in the bottom half handler. */static struct sk_buff_head backlog;/* * We don't overdo the queue or we will thrash memory badly. */ static int backlog_size = 0;/* * Return the lesser of the two values. */ static __inline__ unsigned long min(unsigned long a, unsigned long b){ return (a < b)? a : b;}/****************************************************************************************** Protocol management and registration routines*******************************************************************************************//* * For efficiency */static int dev_nit=0;/* * Add a protocol ID to the list. Now that the input handler is * smarter we can dispense with all the messy stuff that used to be * here. */ void dev_add_pack(struct packet_type *pt){ int hash; if(pt->type==htons(ETH_P_ALL)) { dev_nit++; pt->next=ptype_all; ptype_all=pt; } else { hash=ntohs(pt->type)&15; pt->next = ptype_base[hash]; ptype_base[hash] = pt; }}/* * Remove a protocol ID from the list. */ void dev_remove_pack(struct packet_type *pt){ struct packet_type **pt1; if(pt->type==htons(ETH_P_ALL)) { dev_nit--; pt1=&ptype_all; } else pt1=&ptype_base[ntohs(pt->type)&15]; for(; (*pt1)!=NULL; pt1=&((*pt1)->next)) { if(pt==(*pt1)) { *pt1=pt->next; return; } } printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt);}/***************************************************************************************** Device Interface Subroutines******************************************************************************************//* * Find an interface by name. */ struct device *dev_get(const char *name){ struct device *dev; for (dev = dev_base; dev != NULL; dev = dev->next) { if (strcmp(dev->name, name) == 0) return(dev); } return NULL;} /* * Find and possibly load an interface. */ #ifdef CONFIG_KERNELDextern __inline__ void dev_load(const char *name){ if(!dev_get(name) && suser()) {#ifdef CONFIG_NET_ALIAS const char *sptr; for (sptr=name ; *sptr ; sptr++) if(*sptr==':') break; if (!(*sptr && *(sptr+1)))#endif request_module(name); }}#endif /* * Prepare an interface for use. */ int dev_open(struct device *dev){ int ret = -ENODEV; /* * Call device private open method */ if (dev->open) ret = dev->open(dev); /* * If it went open OK then set the flags */ if (ret == 0) { dev->flags |= (IFF_UP | IFF_RUNNING); /* * Initialise multicasting status */ dev_mc_upload(dev); notifier_call_chain(&netdev_chain, NETDEV_UP, dev); } return(ret);}/* * Completely shutdown an interface. */ int dev_close(struct device *dev){ int ct=0; /* * Call the device specific close. This cannot fail. * Only if device is UP */ if ((dev->flags & IFF_UP) && dev->stop) dev->stop(dev); /* * Device is now down. */ dev->flags&=~(IFF_UP|IFF_RUNNING); /* * Tell people we are going down */ notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); /* * Flush the multicast chain */ dev_mc_discard(dev); /* * Purge any queued packets when we down the link */ while(ct<DEV_NUMBUFFS) { struct sk_buff *skb; while((skb=skb_dequeue(&dev->buffs[ct]))!=NULL) if(skb->free) kfree_skb(skb,FREE_WRITE); ct++; } return(0);}/* * Device change register/unregister. These are not inline or static * as we export them to the world. */int register_netdevice_notifier(struct notifier_block *nb){ return notifier_chain_register(&netdev_chain, nb);}int unregister_netdevice_notifier(struct notifier_block *nb){ return notifier_chain_unregister(&netdev_chain,nb);}/* * Send (or queue for sending) a packet. * * IMPORTANT: When this is called to resend frames. The caller MUST * already have locked the sk_buff. Apart from that we do the * rest of the magic. */static void do_dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri){ unsigned long flags; struct sk_buff_head *list; int retransmission = 0; /* used to say if the packet should go */ /* 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 * start on a failure. */ if (pri < 0) { pri = -pri-1; retransmission = 1; }#ifdef CONFIG_NET_DEBUG if (pri >= DEV_NUMBUFFS) { printk(KERN_WARNING "bad priority in 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_dev_tx(dev);#endif /* * If we are bridging and this is directly generated output * pass the frame via the bridge. */#ifdef CONFIG_BRIDGE if(skb->pkt_bridged!=IS_BRIDGED && br_stats.flags & BR_UP) { if(br_tx_frame(skb)) return; }#endif 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; skb->stamp=xtime; 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; /* FIXME?: Wrong when the hard_header_len * is an upper bound. Is this even * used anywhere? */ skb2->h.raw = skb2->data + dev->hard_header_len; /* On soft header devices we * yank the header before mac.raw * back off. This is set by * dev->hard_header(). */ if (dev->flags&IFF_SOFTHEADERS) skb_pull(skb2,skb2->mac.raw-skb2->data); skb2->mac.raw = skb2->data; ptype->func(skb2, skb->dev, ptype); } } } 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); } } if (dev->hard_start_xmit(skb, dev) == 0) { /* * Packet is now solely the responsibility of the driver */ return; } /* * Transmission failed, put skb back into a list. Once on the list it's safe and * 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){ start_bh_atomic(); do_dev_queue_xmit(skb, dev, pri); end_bh_atomic();}/* * 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. */void netif_rx(struct sk_buff *skb){ static int dropping = 0; /* * Any received buffers are un-owned and should be discarded * when freed. These will be updated later as the frames get * owners. */ skb->sk = NULL; skb->free = 1; if(skb->stamp.tv_sec==0) skb->stamp = xtime; /* * Check that we aren't overdoing things. */ if (!backlog_size) dropping = 0; else if (backlog_size > 300) dropping = 1; if (dropping) { kfree_skb(skb, FREE_READ); return; } /* * Add it to the "backlog" queue. */#if CONFIG_SKB_CHECK IS_SKB(skb);#endif skb_queue_tail(&backlog,skb); backlog_size++; /* * If any packet arrived, mark it for processing after the * hardware interrupt returns. */ mark_bh(NET_BH);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -