X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fcore%2Fdev.c;fp=net%2Fcore%2Fdev.c;h=18accefb79cb03600122e4d042f4e3798b71fada;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=39253c957ba2161d41b3f83c31d9b9b01817301a;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/net/core/dev.c b/net/core/dev.c index 39253c957..18accefb7 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -76,11 +76,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -110,20 +110,12 @@ #include #include #include -#include +#ifdef CONFIG_NET_RADIO +#include /* Note : will define WIRELESS_EXT */ #include -#include -#include -#include -#include -#include +#endif /* CONFIG_NET_RADIO */ #include - -#ifdef CONFIG_XEN -#include -#include -#include -#endif +#include /* * The list of packet types we will receive (as opposed to discard) @@ -136,7 +128,7 @@ * sure which should go first, but I bet it won't make much * difference if we are running VLANs. The good news is that * this protocol won't be in the list unless compiled in, so - * the average user (w/out VLANs) will not be adversely affected. + * the average user (w/out VLANs) will not be adversly affected. * --BLG * * 0800 IP @@ -157,14 +149,8 @@ static DEFINE_SPINLOCK(ptype_lock); static struct list_head ptype_base[16]; /* 16 way hashed list */ static struct list_head ptype_all; /* Taps */ -#ifdef CONFIG_NET_DMA -static struct dma_client *net_dma_client; -static unsigned int net_dma_count; -static spinlock_t net_dma_event_lock; -#endif - /* - * The @dev_base list is protected by @dev_base_lock and the rtnl + * The @dev_base list is protected by @dev_base_lock and the rtln * semaphore. * * Pure readers hold dev_base_lock for reading. @@ -208,7 +194,7 @@ static inline struct hlist_head *dev_index_hash(int ifindex) * Our notifier list */ -static RAW_NOTIFIER_HEAD(netdev_chain); +static struct notifier_block *netdev_chain; /* * Device drivers call our routines to queue packets here. We empty the @@ -237,7 +223,7 @@ extern void netdev_unregister_sysfs(struct net_device *); * For efficiency */ -static int netdev_nit; +int netdev_nit; /* * Add a protocol ID to the list. Now that the input handler is @@ -640,22 +626,14 @@ struct net_device * dev_get_by_flags(unsigned short if_flags, unsigned short mas * @name: name string * * Network device names need to be valid file names to - * to allow sysfs to work. We also disallow any kind of - * whitespace. + * to allow sysfs to work */ int dev_valid_name(const char *name) { - if (*name == '\0') - return 0; - if (!strcmp(name, ".") || !strcmp(name, "..")) - return 0; - - while (*name) { - if (*name == '/' || isspace(*name)) - return 0; - name++; - } - return 1; + return !(*name == '\0' + || !strcmp(name, ".") + || !strcmp(name, "..") + || strchr(name, '/')); } /** @@ -664,12 +642,10 @@ int dev_valid_name(const char *name) * @name: name format string * * Passed a format string - eg "lt%d" it will try and find a suitable - * id. It scans list of devices to build up a free map, then chooses - * the first empty slot. The caller must hold the dev_base or rtnl lock - * while allocating the name and adding the device in order to avoid - * duplicates. - * Limited to bits_per_byte * page size devices (ie 32K on most platforms). - * Returns the number of the unit assigned or a negative errno code. + * id. Not efficient for many devices, not called a lot. The caller + * must hold the dev_base or rtnl lock while allocating the name and + * adding the device in order to avoid duplicates. Returns the number + * of the unit assigned or a negative errno code. */ int dev_alloc_name(struct net_device *dev, const char *name) @@ -761,22 +737,21 @@ int dev_change_name(struct net_device *dev, char *newname) if (!err) { hlist_del(&dev->name_hlist); hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name)); - raw_notifier_call_chain(&netdev_chain, - NETDEV_CHANGENAME, dev); + notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); } return err; } /** - * netdev_features_change - device changes features + * netdev_features_change - device changes fatures * @dev: device to cause notification * * Called to indicate a device has changed features. */ void netdev_features_change(struct net_device *dev) { - raw_notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev); + notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev); } EXPORT_SYMBOL(netdev_features_change); @@ -791,8 +766,7 @@ EXPORT_SYMBOL(netdev_features_change); void netdev_state_change(struct net_device *dev) { if (dev->flags & IFF_UP) { - raw_notifier_call_chain(&netdev_chain, - NETDEV_CHANGE, dev); + notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev); rtmsg_ifinfo(RTM_NEWLINK, dev, 0); } } @@ -889,7 +863,7 @@ int dev_open(struct net_device *dev) /* * ... and announce new interface. */ - raw_notifier_call_chain(&netdev_chain, NETDEV_UP, dev); + notifier_call_chain(&netdev_chain, NETDEV_UP, dev); } return ret; } @@ -912,7 +886,7 @@ int dev_close(struct net_device *dev) * Tell people we are going down, so that they can * prepare to death, when device is still operating. */ - raw_notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev); + notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev); dev_deactivate(dev); @@ -949,7 +923,7 @@ int dev_close(struct net_device *dev) /* * Tell people we are down */ - raw_notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); + notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); return 0; } @@ -980,7 +954,7 @@ int register_netdevice_notifier(struct notifier_block *nb) int err; rtnl_lock(); - err = raw_notifier_chain_register(&netdev_chain, nb); + err = notifier_chain_register(&netdev_chain, nb); if (!err) { for (dev = dev_base; dev; dev = dev->next) { nb->notifier_call(nb, NETDEV_REGISTER, dev); @@ -1005,12 +979,7 @@ int register_netdevice_notifier(struct notifier_block *nb) int unregister_netdevice_notifier(struct notifier_block *nb) { - int err; - - rtnl_lock(); - err = raw_notifier_chain_unregister(&netdev_chain, nb); - rtnl_unlock(); - return err; + return notifier_chain_unregister(&netdev_chain, nb); } /** @@ -1019,12 +988,12 @@ int unregister_netdevice_notifier(struct notifier_block *nb) * @v: pointer passed unmodified to notifier function * * Call all network notifier blocks. Parameters and return value - * are as for raw_notifier_call_chain(). + * are as for notifier_call_chain(). */ int call_netdevice_notifiers(unsigned long val, void *v) { - return raw_notifier_call_chain(&netdev_chain, val, v); + return notifier_call_chain(&netdev_chain, val, v); } /* When > 0 there are consumers of rx skb time stamps */ @@ -1064,7 +1033,7 @@ static inline void net_timestamp(struct sk_buff *skb) * taps currently in use. */ -static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) +void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) { struct packet_type *ptype; @@ -1105,70 +1074,6 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) rcu_read_unlock(); } - -void __netif_schedule(struct net_device *dev) -{ - if (!test_and_set_bit(__LINK_STATE_SCHED, &dev->state)) { - unsigned long flags; - struct softnet_data *sd; - - local_irq_save(flags); - sd = &__get_cpu_var(softnet_data); - dev->next_sched = sd->output_queue; - sd->output_queue = dev; - raise_softirq_irqoff(NET_TX_SOFTIRQ); - local_irq_restore(flags); - } -} -EXPORT_SYMBOL(__netif_schedule); - -void __netif_rx_schedule(struct net_device *dev) -{ - unsigned long flags; - - local_irq_save(flags); - dev_hold(dev); - list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list); - if (dev->quota < 0) - dev->quota += dev->weight; - else - dev->quota = dev->weight; - __raise_softirq_irqoff(NET_RX_SOFTIRQ); - local_irq_restore(flags); -} -EXPORT_SYMBOL(__netif_rx_schedule); - -void dev_kfree_skb_any(struct sk_buff *skb) -{ - if (in_irq() || irqs_disabled()) - dev_kfree_skb_irq(skb); - else - dev_kfree_skb(skb); -} -EXPORT_SYMBOL(dev_kfree_skb_any); - - -/* Hot-plugging. */ -void netif_device_detach(struct net_device *dev) -{ - if (test_and_clear_bit(__LINK_STATE_PRESENT, &dev->state) && - netif_running(dev)) { - netif_stop_queue(dev); - } -} -EXPORT_SYMBOL(netif_device_detach); - -void netif_device_attach(struct net_device *dev) -{ - if (!test_and_set_bit(__LINK_STATE_PRESENT, &dev->state) && - netif_running(dev)) { - netif_wake_queue(dev); - __netdev_watchdog_up(dev); - } -} -EXPORT_SYMBOL(netif_device_attach); - - /* * Invalidate hardware checksum when packet is to be mangled, and * complete checksum manually on outgoing path. @@ -1178,12 +1083,9 @@ int skb_checksum_help(struct sk_buff *skb, int inward) unsigned int csum; int ret = 0, offset = skb->h.raw - skb->data; - if (inward) - goto out_set_summed; - - if (unlikely(skb_shinfo(skb)->gso_size)) { - /* Let GSO fix up the checksum. */ - goto out_set_summed; + if (inward) { + skb->ip_summed = CHECKSUM_NONE; + goto out; } if (skb_cloned(skb)) { @@ -1200,65 +1102,11 @@ int skb_checksum_help(struct sk_buff *skb, int inward) BUG_ON(skb->csum + 2 > offset); *(u16*)(skb->h.raw + skb->csum) = csum_fold(csum); - -out_set_summed: skb->ip_summed = CHECKSUM_NONE; out: return ret; } -/** - * skb_gso_segment - Perform segmentation on skb. - * @skb: buffer to segment - * @features: features for the output path (see dev->features) - * - * This function segments the given skb and returns a list of segments. - * - * It may return NULL if the skb requires no segmentation. This is - * only possible when GSO is used for verifying header integrity. - */ -struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features) -{ - struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); - struct packet_type *ptype; - int type = skb->protocol; - int err; - - BUG_ON(skb_shinfo(skb)->frag_list); - - skb->mac.raw = skb->data; - skb->mac_len = skb->nh.raw - skb->data; - __skb_pull(skb, skb->mac_len); - - if (unlikely(skb->ip_summed != CHECKSUM_HW)) { - if (skb_header_cloned(skb) && - (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) - return ERR_PTR(err); - } - - rcu_read_lock(); - list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) { - if (ptype->type == type && !ptype->dev && ptype->gso_segment) { - if (unlikely(skb->ip_summed != CHECKSUM_HW)) { - err = ptype->gso_send_check(skb); - segs = ERR_PTR(err); - if (err || skb_gso_ok(skb, features)) - break; - __skb_push(skb, skb->data - skb->nh.raw); - } - segs = ptype->gso_segment(skb, features); - break; - } - } - rcu_read_unlock(); - - __skb_push(skb, skb->data - skb->mac.raw); - - return segs; -} - -EXPORT_SYMBOL(skb_gso_segment); - /* Take action when hardware reception checksum errors are detected. */ #ifdef CONFIG_BUG void netdev_rx_csum_fault(struct net_device *dev) @@ -1272,6 +1120,7 @@ void netdev_rx_csum_fault(struct net_device *dev) EXPORT_SYMBOL(netdev_rx_csum_fault); #endif +#ifdef CONFIG_HIGHMEM /* Actually, we should eliminate this check as soon as we know, that: * 1. IOMMU is present and allows to map all the memory. * 2. No high memory really exists on this machine. @@ -1279,7 +1128,6 @@ EXPORT_SYMBOL(netdev_rx_csum_fault); static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb) { -#ifdef CONFIG_HIGHMEM int i; if (dev->features & NETIF_F_HIGHDMA) @@ -1289,152 +1137,85 @@ static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb) if (PageHighMem(skb_shinfo(skb)->frags[i].page)) return 1; -#endif return 0; } +#else +#define illegal_highdma(dev, skb) (0) +#endif -struct dev_gso_cb { - void (*destructor)(struct sk_buff *skb); -}; - -#define DEV_GSO_CB(skb) ((struct dev_gso_cb *)(skb)->cb) - -static void dev_gso_skb_destructor(struct sk_buff *skb) +/* Keep head the same: replace data */ +int __skb_linearize(struct sk_buff *skb, gfp_t gfp_mask) { - struct dev_gso_cb *cb; - - do { - struct sk_buff *nskb = skb->next; + unsigned int size; + u8 *data; + long offset; + struct skb_shared_info *ninfo; + int headerlen = skb->data - skb->head; + int expand = (skb->tail + skb->data_len) - skb->end; - skb->next = nskb->next; - nskb->next = NULL; - kfree_skb(nskb); - } while (skb->next); + if (skb_shared(skb)) + BUG(); - cb = DEV_GSO_CB(skb); - if (cb->destructor) - cb->destructor(skb); -} + if (expand <= 0) + expand = 0; -/** - * dev_gso_segment - Perform emulated hardware segmentation on skb. - * @skb: buffer to segment - * - * This function segments the given skb and stores the list of segments - * in skb->next. - */ -static int dev_gso_segment(struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - struct sk_buff *segs; - int features = dev->features & ~(illegal_highdma(dev, skb) ? - NETIF_F_SG : 0); - - segs = skb_gso_segment(skb, features); - - /* Verifying header integrity only. */ - if (!segs) - return 0; + size = skb->end - skb->head + expand; + size = SKB_DATA_ALIGN(size); + data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask); + if (!data) + return -ENOMEM; - if (unlikely(IS_ERR(segs))) - return PTR_ERR(segs); + /* Copy entire thing */ + if (skb_copy_bits(skb, -headerlen, data, headerlen + skb->len)) + BUG(); - skb->next = segs; - DEV_GSO_CB(skb)->destructor = skb->destructor; - skb->destructor = dev_gso_skb_destructor; + /* Set up shinfo */ + ninfo = (struct skb_shared_info*)(data + size); + atomic_set(&ninfo->dataref, 1); + ninfo->tso_size = skb_shinfo(skb)->tso_size; + ninfo->tso_segs = skb_shinfo(skb)->tso_segs; + ninfo->ufo_size = skb_shinfo(skb)->ufo_size; + ninfo->nr_frags = 0; + ninfo->frag_list = NULL; - return 0; -} + /* Offset between the two in bytes */ + offset = data - skb->head; -int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - if (likely(!skb->next)) { - if (netdev_nit) - dev_queue_xmit_nit(skb, dev); + /* Free old data. */ + skb_release_data(skb); - if (netif_needs_gso(dev, skb)) { - if (unlikely(dev_gso_segment(skb))) - goto out_kfree_skb; - if (skb->next) - goto gso; - } + skb->head = data; + skb->end = data + size; - return dev->hard_start_xmit(skb, dev); - } + /* Set up new pointers */ + skb->h.raw += offset; + skb->nh.raw += offset; + skb->mac.raw += offset; + skb->tail += offset; + skb->data += offset; -gso: - do { - struct sk_buff *nskb = skb->next; - int rc; - - skb->next = nskb->next; - nskb->next = NULL; - rc = dev->hard_start_xmit(nskb, dev); - if (unlikely(rc)) { - nskb->next = skb->next; - skb->next = nskb; - return rc; - } - if (unlikely(netif_queue_stopped(dev) && skb->next)) - return NETDEV_TX_BUSY; - } while (skb->next); - - skb->destructor = DEV_GSO_CB(skb)->destructor; + /* We are no longer a clone, even if we were. */ + skb->cloned = 0; -out_kfree_skb: - kfree_skb(skb); + skb->tail += skb->data_len; + skb->data_len = 0; return 0; } #define HARD_TX_LOCK(dev, cpu) { \ if ((dev->features & NETIF_F_LLTX) == 0) { \ - netif_tx_lock(dev); \ + spin_lock(&dev->xmit_lock); \ + dev->xmit_lock_owner = cpu; \ } \ } #define HARD_TX_UNLOCK(dev) { \ if ((dev->features & NETIF_F_LLTX) == 0) { \ - netif_tx_unlock(dev); \ + dev->xmit_lock_owner = -1; \ + spin_unlock(&dev->xmit_lock); \ } \ } -#ifdef CONFIG_XEN -inline int skb_checksum_setup(struct sk_buff *skb) -{ - if (skb->proto_csum_blank) { - if (skb->protocol != htons(ETH_P_IP)) - goto out; - skb->h.raw = (unsigned char *)skb->nh.iph + 4*skb->nh.iph->ihl; - if (skb->h.raw >= skb->tail) - goto out; - switch (skb->nh.iph->protocol) { - case IPPROTO_TCP: - skb->csum = offsetof(struct tcphdr, check); - break; - case IPPROTO_UDP: - skb->csum = offsetof(struct udphdr, check); - break; - default: - if (net_ratelimit()) - printk(KERN_ERR "Attempting to checksum a non-" - "TCP/UDP packet, dropping a protocol" - " %d packet", skb->nh.iph->protocol); - goto out; - } - if ((skb->h.raw + skb->csum + 2) > skb->tail) - goto out; - skb->ip_summed = CHECKSUM_HW; - skb->proto_csum_blank = 0; - } - return 0; -out: - return -EPROTO; -} -#else -inline int skb_checksum_setup(struct sk_buff *skb) { return 0; } -#endif - - /** * dev_queue_xmit - transmit a buffer * @skb: buffer to transmit @@ -1467,19 +1248,9 @@ int dev_queue_xmit(struct sk_buff *skb) struct Qdisc *q; int rc = -ENOMEM; - /* If a checksum-deferred packet is forwarded to a device that needs a - * checksum, correct the pointers and force checksumming. - */ - if (skb_checksum_setup(skb)) - goto out_kfree_skb; - - /* GSO will handle the following emulations directly. */ - if (netif_needs_gso(dev, skb)) - goto gso; - if (skb_shinfo(skb)->frag_list && !(dev->features & NETIF_F_FRAGLIST) && - __skb_linearize(skb)) + __skb_linearize(skb, GFP_ATOMIC)) goto out_kfree_skb; /* Fragmented skb is linearized if device does not support SG, @@ -1488,26 +1259,25 @@ int dev_queue_xmit(struct sk_buff *skb) */ if (skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) && - __skb_linearize(skb)) + __skb_linearize(skb, GFP_ATOMIC)) goto out_kfree_skb; /* If packet is not checksummed and device does not support * checksumming for this protocol, complete checksumming here. */ if (skb->ip_summed == CHECKSUM_HW && - (!(dev->features & NETIF_F_GEN_CSUM) && + (!(dev->features & (NETIF_F_HW_CSUM | NETIF_F_NO_CSUM)) && (!(dev->features & NETIF_F_IP_CSUM) || skb->protocol != htons(ETH_P_IP)))) if (skb_checksum_help(skb, 0)) goto out_kfree_skb; -gso: spin_lock_prefetch(&dev->queue_lock); /* Disable soft irqs for various locks below. Also * stops preemption for RCU. */ - rcu_read_lock_bh(); + local_bh_disable(); /* Updates of qdisc are serialized by queue_lock. * The struct Qdisc which is pointed to by qdisc is now a @@ -1543,8 +1313,8 @@ gso: /* The device has no queue. Common case for software devices: loopback, all the sorts of tunnels... - Really, it is unlikely that netif_tx_lock protection is necessary - here. (f.e. loopback and IP tunnels are clean ignoring statistics + Really, it is unlikely that xmit_lock protection is necessary here. + (f.e. loopback and IP tunnels are clean ignoring statistics counters.) However, it is possible, that they rely on protection made by us here. @@ -1560,8 +1330,11 @@ gso: HARD_TX_LOCK(dev, cpu); if (!netif_queue_stopped(dev)) { + if (netdev_nit) + dev_queue_xmit_nit(skb, dev); + rc = 0; - if (!dev_hard_start_xmit(skb, dev)) { + if (!dev->hard_start_xmit(skb, dev)) { HARD_TX_UNLOCK(dev); goto out; } @@ -1580,13 +1353,13 @@ gso: } rc = -ENETDOWN; - rcu_read_unlock_bh(); + local_bh_enable(); out_kfree_skb: kfree_skb(skb); return rc; out: - rcu_read_unlock_bh(); + local_bh_enable(); return rc; } @@ -1679,13 +1452,8 @@ static inline struct net_device *skb_bond(struct sk_buff *skb) { struct net_device *dev = skb->dev; - if (dev->master) { - if (skb_bond_should_drop(skb)) { - kfree_skb(skb); - return NULL; - } + if (dev->master) skb->dev = dev->master; - } return dev; } @@ -1790,7 +1558,7 @@ static int ing_filter(struct sk_buff *skb) if (dev->qdisc_ingress) { __u32 ttl = (__u32) G_TC_RTTL(skb->tc_verd); if (MAX_RED_LOOP < ttl++) { - printk(KERN_WARNING "Redir loop detected Dropping packet (%s->%s)\n", + printk("Redir loop detected Dropping packet (%s->%s)\n", skb->input_dev->name, skb->dev->name); return TC_ACT_SHOT; } @@ -1829,9 +1597,6 @@ int netif_receive_skb(struct sk_buff *skb) orig_dev = skb_bond(skb); - if (!orig_dev) - return NET_RX_DROP; - __get_cpu_var(netdev_rx_stat).total++; skb->h.raw = skb->nh.raw = skb->data; @@ -1848,19 +1613,6 @@ int netif_receive_skb(struct sk_buff *skb) } #endif -#ifdef CONFIG_XEN - switch (skb->ip_summed) { - case CHECKSUM_UNNECESSARY: - skb->proto_data_valid = 1; - break; - case CHECKSUM_HW: - /* XXX Implement me. */ - default: - skb->proto_data_valid = 0; - break; - } -#endif - list_for_each_entry_rcu(ptype, &ptype_all, list) { if (!ptype->dev || ptype->dev == skb->dev) { if (pt_prev) @@ -1989,7 +1741,8 @@ static void net_rx_action(struct softirq_action *h) if (dev->quota <= 0 || dev->poll(dev, &budget)) { netpoll_poll_unlock(have); local_irq_disable(); - list_move_tail(&dev->poll_list, &queue->poll_list); + list_del(&dev->poll_list); + list_add_tail(&dev->poll_list, &queue->poll_list); if (dev->quota < 0) dev->quota += dev->weight; else @@ -2001,19 +1754,6 @@ static void net_rx_action(struct softirq_action *h) } } out: -#ifdef CONFIG_NET_DMA - /* - * There may not be any more sk_buffs coming right now, so push - * any pending DMA copies to hardware - */ - if (net_dma_client) { - struct dma_chan *chan; - rcu_read_lock(); - list_for_each_entry_rcu(chan, &net_dma_client->channels, client_node) - dma_async_memcpy_issue_pending(chan); - rcu_read_unlock(); - } -#endif local_irq_enable(); return; @@ -2299,7 +2039,7 @@ static struct file_operations softnet_seq_fops = { .release = seq_release, }; -#ifdef CONFIG_WIRELESS_EXT +#ifdef WIRELESS_EXT extern int wireless_proc_init(void); #else #define wireless_proc_init() 0 @@ -2373,7 +2113,7 @@ int netdev_set_master(struct net_device *slave, struct net_device *master) * @dev: device * @inc: modifier * - * Add or remove promiscuity from a device. While the count in the device + * Add or remove promsicuity from a device. While the count in the device * remains above zero the interface remains promiscuous. Once it hits zero * the device reverts back to normal filtering operation. A negative inc * value is used to drop promiscuity on the device. @@ -2391,12 +2131,6 @@ void dev_set_promiscuity(struct net_device *dev, int inc) printk(KERN_INFO "device %s %s promiscuous mode\n", dev->name, (dev->flags & IFF_PROMISC) ? "entered" : "left"); - audit_log(current->audit_context, GFP_ATOMIC, - AUDIT_ANOM_PROMISCUOUS, - "dev=%s prom=%d old_prom=%d auid=%u", - dev->name, (dev->flags & IFF_PROMISC), - (old_flags & IFF_PROMISC), - audit_get_loginuid(current->audit_context)); } } @@ -2429,20 +2163,12 @@ unsigned dev_get_flags(const struct net_device *dev) flags = (dev->flags & ~(IFF_PROMISC | IFF_ALLMULTI | - IFF_RUNNING | - IFF_LOWER_UP | - IFF_DORMANT)) | + IFF_RUNNING)) | (dev->gflags & (IFF_PROMISC | IFF_ALLMULTI)); - if (netif_running(dev)) { - if (netif_oper_up(dev)) - flags |= IFF_RUNNING; - if (netif_carrier_ok(dev)) - flags |= IFF_LOWER_UP; - if (netif_dormant(dev)) - flags |= IFF_DORMANT; - } + if (netif_running(dev) && netif_carrier_ok(dev)) + flags |= IFF_RUNNING; return flags; } @@ -2485,8 +2211,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags) if (dev->flags & IFF_UP && ((old_flags ^ dev->flags) &~ (IFF_UP | IFF_PROMISC | IFF_ALLMULTI | IFF_VOLATILE))) - raw_notifier_call_chain(&netdev_chain, - NETDEV_CHANGE, dev); + notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev); if ((flags ^ dev->gflags) & IFF_PROMISC) { int inc = (flags & IFF_PROMISC) ? +1 : -1; @@ -2530,8 +2255,8 @@ int dev_set_mtu(struct net_device *dev, int new_mtu) else dev->mtu = new_mtu; if (!err && dev->flags & IFF_UP) - raw_notifier_call_chain(&netdev_chain, - NETDEV_CHANGEMTU, dev); + notifier_call_chain(&netdev_chain, + NETDEV_CHANGEMTU, dev); return err; } @@ -2547,8 +2272,7 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa) return -ENODEV; err = dev->set_mac_address(dev, sa); if (!err) - raw_notifier_call_chain(&netdev_chain, - NETDEV_CHANGEADDR, dev); + notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); return err; } @@ -2604,7 +2328,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) return -EINVAL; memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); - raw_notifier_call_chain(&netdev_chain, + notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); return 0; @@ -2723,9 +2447,9 @@ int dev_ioctl(unsigned int cmd, void __user *arg) */ if (cmd == SIOCGIFCONF) { - rtnl_lock(); + rtnl_shlock(); ret = dev_ifconf((char __user *) arg); - rtnl_unlock(); + rtnl_shunlock(); return ret; } if (cmd == SIOCGIFNAME) @@ -2869,14 +2593,13 @@ int dev_ioctl(unsigned int cmd, void __user *arg) ret = -EFAULT; return ret; } -#ifdef CONFIG_WIRELESS_EXT +#ifdef WIRELESS_EXT /* Take care of Wireless Extensions */ if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { /* If command is `set a parameter', or * `get the encoding parameters', check if * the user has the right to do it */ - if (IW_IS_SET(cmd) || cmd == SIOCGIWENCODE - || cmd == SIOCGIWENCODEEXT) { + if (IW_IS_SET(cmd) || cmd == SIOCGIWENCODE) { if (!capable(CAP_NET_ADMIN)) return -EPERM; } @@ -2891,7 +2614,7 @@ int dev_ioctl(unsigned int cmd, void __user *arg) ret = -EFAULT; return ret; } -#endif /* CONFIG_WIRELESS_EXT */ +#endif /* WIRELESS_EXT */ return -EINVAL; } } @@ -2954,13 +2677,11 @@ int register_netdevice(struct net_device *dev) BUG_ON(dev_boot_phase); ASSERT_RTNL(); - might_sleep(); - /* When net_device's are persistent, this will be fatal. */ BUG_ON(dev->reg_state != NETREG_UNINITIALIZED); spin_lock_init(&dev->queue_lock); - spin_lock_init(&dev->_xmit_lock); + spin_lock_init(&dev->xmit_lock); dev->xmit_lock_owner = -1; #ifdef CONFIG_NET_CLS_ACT spin_lock_init(&dev->ingress_lock); @@ -3004,8 +2725,10 @@ int register_netdevice(struct net_device *dev) /* Fix illegal SG+CSUM combinations. */ if ((dev->features & NETIF_F_SG) && - !(dev->features & NETIF_F_ALL_CSUM)) { - printk(KERN_NOTICE "%s: Dropping NETIF_F_SG since no checksum feature.\n", + !(dev->features & (NETIF_F_IP_CSUM | + NETIF_F_NO_CSUM | + NETIF_F_HW_CSUM))) { + printk("%s: Dropping NETIF_F_SG since no checksum feature.\n", dev->name); dev->features &= ~NETIF_F_SG; } @@ -3013,7 +2736,7 @@ int register_netdevice(struct net_device *dev) /* TSO requires that SG is present as well. */ if ((dev->features & NETIF_F_TSO) && !(dev->features & NETIF_F_SG)) { - printk(KERN_NOTICE "%s: Dropping NETIF_F_TSO since no SG feature.\n", + printk("%s: Dropping NETIF_F_TSO since no SG feature.\n", dev->name); dev->features &= ~NETIF_F_TSO; } @@ -3040,11 +2763,6 @@ int register_netdevice(struct net_device *dev) if (!dev->rebuild_header) dev->rebuild_header = default_rebuild_header; - ret = netdev_register_sysfs(dev); - if (ret) - goto out_err; - dev->reg_state = NETREG_REGISTERED; - /* * Default initial state at registry is that the * device is present. @@ -3060,11 +2778,14 @@ int register_netdevice(struct net_device *dev) hlist_add_head(&dev->name_hlist, head); hlist_add_head(&dev->index_hlist, dev_index_hash(dev->ifindex)); dev_hold(dev); + dev->reg_state = NETREG_REGISTERING; write_unlock_bh(&dev_base_lock); /* Notify protocols, that a new device appeared. */ - raw_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); + notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); + /* Finish registration after unlock */ + net_set_todo(dev); ret = 0; out: @@ -3137,10 +2858,10 @@ static void netdev_wait_allrefs(struct net_device *dev) rebroadcast_time = warning_time = jiffies; while (atomic_read(&dev->refcnt) != 0) { if (time_after(jiffies, rebroadcast_time + 1 * HZ)) { - rtnl_lock(); + rtnl_shlock(); /* Rebroadcast unregister notification */ - raw_notifier_call_chain(&netdev_chain, + notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); if (test_bit(__LINK_STATE_LINKWATCH_PENDING, @@ -3154,7 +2875,7 @@ static void netdev_wait_allrefs(struct net_device *dev) linkwatch_run_queue(); } - __rtnl_unlock(); + rtnl_shunlock(); rebroadcast_time = jiffies; } @@ -3187,18 +2908,20 @@ static void netdev_wait_allrefs(struct net_device *dev) * * We are invoked by rtnl_unlock() after it drops the semaphore. * This allows us to deal with problems: - * 1) We can delete sysfs objects which invoke hotplug + * 1) We can create/delete sysfs objects which invoke hotplug * without deadlocking with linkwatch via keventd. * 2) Since we run with the RTNL semaphore not held, we can sleep * safely in order to wait for the netdev refcnt to drop to zero. */ -static DEFINE_MUTEX(net_todo_run_mutex); +static DECLARE_MUTEX(net_todo_run_mutex); void netdev_run_todo(void) { - struct list_head list; + struct list_head list = LIST_HEAD_INIT(list); + int err; + /* Need to guard against multiple cpu's getting out of order. */ - mutex_lock(&net_todo_run_mutex); + down(&net_todo_run_mutex); /* Not safe to do outside the semaphore. We must not return * until all unregister events invoked by the local processor @@ -3210,41 +2933,52 @@ void netdev_run_todo(void) /* Snapshot list, allow later requests */ spin_lock(&net_todo_list_lock); - list_replace_init(&net_todo_list, &list); + list_splice_init(&net_todo_list, &list); spin_unlock(&net_todo_list_lock); - + while (!list_empty(&list)) { struct net_device *dev = list_entry(list.next, struct net_device, todo_list); list_del(&dev->todo_list); - if (unlikely(dev->reg_state != NETREG_UNREGISTERING)) { - printk(KERN_ERR "network todo '%s' but state %d\n", - dev->name, dev->reg_state); - dump_stack(); - continue; - } + switch(dev->reg_state) { + case NETREG_REGISTERING: + dev->reg_state = NETREG_REGISTERED; + err = netdev_register_sysfs(dev); + if (err) + printk(KERN_ERR "%s: failed sysfs registration (%d)\n", + dev->name, err); + break; - netdev_unregister_sysfs(dev); - dev->reg_state = NETREG_UNREGISTERED; + case NETREG_UNREGISTERING: + netdev_unregister_sysfs(dev); + dev->reg_state = NETREG_UNREGISTERED; - netdev_wait_allrefs(dev); + netdev_wait_allrefs(dev); - /* paranoia */ - BUG_ON(atomic_read(&dev->refcnt)); - BUG_TRAP(!dev->ip_ptr); - BUG_TRAP(!dev->ip6_ptr); - BUG_TRAP(!dev->dn_ptr); + /* paranoia */ + BUG_ON(atomic_read(&dev->refcnt)); + BUG_TRAP(!dev->ip_ptr); + BUG_TRAP(!dev->ip6_ptr); + BUG_TRAP(!dev->dn_ptr); - /* It must be the very last action, - * after this 'dev' may point to freed up memory. - */ - if (dev->destructor) - dev->destructor(dev); + + /* It must be the very last action, + * after this 'dev' may point to freed up memory. + */ + if (dev->destructor) + dev->destructor(dev); + break; + + default: + printk(KERN_ERR "network todo '%s' but state %d\n", + dev->name, dev->reg_state); + break; + } } out: - mutex_unlock(&net_todo_run_mutex); + up(&net_todo_run_mutex); } /** @@ -3267,11 +3001,12 @@ struct net_device *alloc_netdev(int sizeof_priv, const char *name, alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST; alloc_size += sizeof_priv + NETDEV_ALIGN_CONST; - p = kzalloc(alloc_size, GFP_KERNEL); + p = kmalloc(alloc_size, GFP_KERNEL); if (!p) { printk(KERN_ERR "alloc_dev: Unable to allocate device.\n"); return NULL; } + memset(p, 0, alloc_size); dev = (struct net_device *) (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); @@ -3297,7 +3032,7 @@ EXPORT_SYMBOL(alloc_netdev); void free_netdev(struct net_device *dev) { #ifdef CONFIG_SYSFS - /* Compatibility with error handling in drivers */ + /* Compatiablity with error handling in drivers */ if (dev->reg_state == NETREG_UNINITIALIZED) { kfree((char *)dev - dev->padded); return; @@ -3382,7 +3117,7 @@ int unregister_netdevice(struct net_device *dev) /* Notify protocols, that we are about to destroy this device. They should clean all the things. */ - raw_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); + notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); /* * Flush the multicast chain @@ -3473,83 +3208,6 @@ static int dev_cpu_callback(struct notifier_block *nfb, } #endif /* CONFIG_HOTPLUG_CPU */ -#ifdef CONFIG_NET_DMA -/** - * net_dma_rebalance - - * This is called when the number of channels allocated to the net_dma_client - * changes. The net_dma_client tries to have one DMA channel per CPU. - */ -static void net_dma_rebalance(void) -{ - unsigned int cpu, i, n; - struct dma_chan *chan; - - if (net_dma_count == 0) { - for_each_online_cpu(cpu) - rcu_assign_pointer(per_cpu(softnet_data, cpu).net_dma, NULL); - return; - } - - i = 0; - cpu = first_cpu(cpu_online_map); - - rcu_read_lock(); - list_for_each_entry(chan, &net_dma_client->channels, client_node) { - n = ((num_online_cpus() / net_dma_count) - + (i < (num_online_cpus() % net_dma_count) ? 1 : 0)); - - while(n) { - per_cpu(softnet_data, cpu).net_dma = chan; - cpu = next_cpu(cpu, cpu_online_map); - n--; - } - i++; - } - rcu_read_unlock(); -} - -/** - * netdev_dma_event - event callback for the net_dma_client - * @client: should always be net_dma_client - * @chan: DMA channel for the event - * @event: event type - */ -static void netdev_dma_event(struct dma_client *client, struct dma_chan *chan, - enum dma_event event) -{ - spin_lock(&net_dma_event_lock); - switch (event) { - case DMA_RESOURCE_ADDED: - net_dma_count++; - net_dma_rebalance(); - break; - case DMA_RESOURCE_REMOVED: - net_dma_count--; - net_dma_rebalance(); - break; - default: - break; - } - spin_unlock(&net_dma_event_lock); -} - -/** - * netdev_dma_regiser - register the networking subsystem as a DMA client - */ -static int __init netdev_dma_register(void) -{ - spin_lock_init(&net_dma_event_lock); - net_dma_client = dma_async_client_register(netdev_dma_event); - if (net_dma_client == NULL) - return -ENOMEM; - - dma_async_client_chan_request(net_dma_client, num_online_cpus()); - return 0; -} - -#else -static int __init netdev_dma_register(void) { return -ENODEV; } -#endif /* CONFIG_NET_DMA */ /* * Initialize the DEV module. At boot time this walks the device list and @@ -3590,7 +3248,7 @@ static int __init net_dev_init(void) * Initialise the packet receive queues. */ - for_each_possible_cpu(i) { + for_each_cpu(i) { struct softnet_data *queue; queue = &per_cpu(softnet_data, i); @@ -3603,8 +3261,6 @@ static int __init net_dev_init(void) atomic_set(&queue->backlog_dev.refcnt, 1); } - netdev_dma_register(); - dev_boot_phase = 0; open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL); @@ -3623,6 +3279,7 @@ subsys_initcall(net_dev_init); EXPORT_SYMBOL(__dev_get_by_index); EXPORT_SYMBOL(__dev_get_by_name); EXPORT_SYMBOL(__dev_remove_pack); +EXPORT_SYMBOL(__skb_linearize); EXPORT_SYMBOL(dev_valid_name); EXPORT_SYMBOL(dev_add_pack); EXPORT_SYMBOL(dev_alloc_name); @@ -3654,7 +3311,6 @@ EXPORT_SYMBOL(unregister_netdevice_notifier); EXPORT_SYMBOL(net_enable_timestamp); EXPORT_SYMBOL(net_disable_timestamp); EXPORT_SYMBOL(dev_get_flags); -EXPORT_SYMBOL(skb_checksum_setup); #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) EXPORT_SYMBOL(br_handle_frame_hook);