diff options
| author | David S. Miller <davem@kernel.bkbits.net> | 2004-02-06 00:57:55 -0800 |
|---|---|---|
| committer | David S. Miller <davem@kernel.bkbits.net> | 2004-02-06 00:57:55 -0800 |
| commit | 39c09b95dabcbdbb7c2e35ad5a9fbf6aaac202a9 (patch) | |
| tree | 128ce6c648fbd3269d0889a7f532c5526f34b646 | |
| parent | d925eab60387b18a46b036d8812c0b2166a70332 (diff) | |
| parent | 7a98480512254fa9e9f029aaeca21be1aeb5fc28 (diff) | |
Merge davem@nuts.davemloft.net:/disk1/BK/net-2.6
into kernel.bkbits.net:/home/davem/net-2.6
| -rw-r--r-- | Documentation/Changes | 2 | ||||
| -rw-r--r-- | Documentation/networking/ethertap.txt | 2 | ||||
| -rw-r--r-- | drivers/net/Space.c | 25 | ||||
| -rw-r--r-- | drivers/net/pppoe.c | 2 | ||||
| -rw-r--r-- | include/linux/if_vlan.h | 146 | ||||
| -rw-r--r-- | include/linux/kernel.h | 1 | ||||
| -rw-r--r-- | include/linux/netdevice.h | 4 | ||||
| -rw-r--r-- | include/linux/string.h | 3 | ||||
| -rw-r--r-- | include/net/arp.h | 8 | ||||
| -rw-r--r-- | kernel/printk.c | 29 | ||||
| -rw-r--r-- | lib/string.c | 16 | ||||
| -rw-r--r-- | net/8021q/vlan_dev.c | 63 | ||||
| -rw-r--r-- | net/Kconfig | 10 | ||||
| -rw-r--r-- | net/core/dev.c | 167 | ||||
| -rw-r--r-- | net/core/utils.c | 30 | ||||
| -rw-r--r-- | net/decnet/Kconfig | 5 | ||||
| -rw-r--r-- | net/ipv4/Kconfig | 2 | ||||
| -rw-r--r-- | net/ipv4/arp.c | 66 | ||||
| -rw-r--r-- | net/ipv6/ndisc.c | 207 | ||||
| -rw-r--r-- | net/netlink/af_netlink.c | 2 | ||||
| -rw-r--r-- | net/packet/af_packet.c | 2 |
21 files changed, 491 insertions, 301 deletions
diff --git a/Documentation/Changes b/Documentation/Changes index e0288627d64a..fe1bf8b9445f 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -407,7 +407,7 @@ o <http://www.iptables.org/downloads.html> Ip-route2 --------- -o <ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.2.4-now-ss991023.tar.gz> +o <ftp://ftp.tux.org/pub/net/ip-routing/iproute2-2.2.4-now-ss991023.tar.gz> OProfile -------- diff --git a/Documentation/networking/ethertap.txt b/Documentation/networking/ethertap.txt index 7f3b52955a0b..337f650d7678 100644 --- a/Documentation/networking/ethertap.txt +++ b/Documentation/networking/ethertap.txt @@ -47,7 +47,7 @@ This allows the kernel to exchange data with userspace applications. There are two ways of doing this, the new way works with netlink sockets and I have no experience with that yet. ANK uses it in his excellent iproute2 package, see for example rtmon.c. iproute2 can be found on -ftp://ftp.inr.ac.ru/ip-routing/iproute2* +ftp://ftp.tux.org/pub/net/ip-routing/iproute2* The new way is described, partly in netlink(7), available on http://www.europe.redhat.com/documentation/man-pages/man7/netlink.7.php3 diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 51ed68f486b8..4da8f077de9a 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -430,28 +430,3 @@ static int __init net_olddevs_init(void) } device_initcall(net_olddevs_init); - -/* - * The @dev_base list is protected by @dev_base_lock and the rtln - * semaphore. - * - * Pure readers hold dev_base_lock for reading. - * - * Writers must hold the rtnl semaphore while they loop through the - * dev_base list, and hold dev_base_lock for writing when they do the - * actual updates. This allows pure readers to access the list even - * while a writer is preparing to update it. - * - * To put it another way, dev_base_lock is held for writing only to - * protect against pure readers; the rtnl semaphore provides the - * protection against other writers. - * - * See, for example usages, register_netdevice() and - * unregister_netdevice(), which must be called with the rtnl - * semaphore held. - */ -struct net_device *dev_base; -rwlock_t dev_base_lock = RW_LOCK_UNLOCKED; - -EXPORT_SYMBOL(dev_base); -EXPORT_SYMBOL(dev_base_lock); diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 011eaf26e9f6..733c72960d3c 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -517,7 +517,7 @@ static int pppoe_create(struct socket *sock) sk->sk_protocol = PX_PROTO_OE; sk->sk_destruct = pppoe_sk_free; - po = pppox_sk(sk) = kmalloc(sizeof(*po), GFP_KERNEL); + po = sk->sk_protinfo = kmalloc(sizeof(*po), GFP_KERNEL); if (!po) goto frees; memset(po, 0, sizeof(*po)); diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 6cb10ed07188..104df1877778 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -200,6 +200,152 @@ static inline int vlan_hwaccel_receive_skb(struct sk_buff *skb, { return __vlan_hwaccel_rx(skb, grp, vlan_tag, 1); } + +/** + * __vlan_put_tag - regular VLAN tag inserting + * @skb: skbuff to tag + * @tag: VLAN tag to insert + * + * Inserts the VLAN tag into @skb as part of the payload + * Returns a VLAN tagged skb. If a new skb is created, @skb is freed. + * + * Following the skb_unshare() example, in case of error, the calling function + * doesn't have to worry about freeing the original skb. + */ +static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, unsigned short tag) +{ + struct vlan_ethhdr *veth; + + if (skb_headroom(skb) < VLAN_HLEN) { + struct sk_buff *sk_tmp = skb; + skb = skb_realloc_headroom(sk_tmp, VLAN_HLEN); + kfree_skb(sk_tmp); + if (!skb) { + printk(KERN_ERR "vlan: failed to realloc headroom\n"); + return NULL; + } + } else { + skb = skb_unshare(skb, GFP_ATOMIC); + if (!skb) { + printk(KERN_ERR "vlan: failed to unshare skbuff\n"); + return NULL; + } + } + + veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN); + + /* Move the mac addresses to the beginning of the new header. */ + memmove(skb->data, skb->data + VLAN_HLEN, 2 * VLAN_ETH_ALEN); + + /* first, the ethernet type */ + veth->h_vlan_proto = __constant_htons(ETH_P_8021Q); + + /* now, the tag */ + veth->h_vlan_TCI = htons(tag); + + skb->protocol = __constant_htons(ETH_P_8021Q); + skb->mac.raw -= VLAN_HLEN; + skb->nh.raw -= VLAN_HLEN; + + return skb; +} + +/** + * __vlan_hwaccel_put_tag - hardware accelerated VLAN inserting + * @skb: skbuff to tag + * @tag: VLAN tag to insert + * + * Puts the VLAN tag in @skb->cb[] and lets the device do the rest + */ +static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, unsigned short tag) +{ + struct vlan_skb_tx_cookie *cookie; + + cookie = VLAN_TX_SKB_CB(skb); + cookie->magic = VLAN_TX_COOKIE_MAGIC; + cookie->vlan_tag = tag; + + return skb; +} + +#define HAVE_VLAN_PUT_TAG + +/** + * vlan_put_tag - inserts VLAN tag according to device features + * @skb: skbuff to tag + * @tag: VLAN tag to insert + * + * Assumes skb->dev is the target that will xmit this frame. + * Returns a VLAN tagged skb. + */ +static inline struct sk_buff *vlan_put_tag(struct sk_buff *skb, unsigned short tag) +{ + if (skb->dev->features & NETIF_F_HW_VLAN_TX) { + return __vlan_hwaccel_put_tag(skb, tag); + } else { + return __vlan_put_tag(skb, tag); + } +} + +/** + * __vlan_get_tag - get the VLAN ID that is part of the payload + * @skb: skbuff to query + * @tag: buffer to store vlaue + * + * Returns error if the skb is not of VLAN type + */ +static inline int __vlan_get_tag(struct sk_buff *skb, unsigned short *tag) +{ + struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb->data; + + if (veth->h_vlan_proto != __constant_htons(ETH_P_8021Q)) { + return -EINVAL; + } + + *tag = ntohs(veth->h_vlan_TCI); + + return 0; +} + +/** + * __vlan_hwaccel_get_tag - get the VLAN ID that is in @skb->cb[] + * @skb: skbuff to query + * @tag: buffer to store vlaue + * + * Returns error if @skb->cb[] is not set correctly + */ +static inline int __vlan_hwaccel_get_tag(struct sk_buff *skb, unsigned short *tag) +{ + struct vlan_skb_tx_cookie *cookie; + + cookie = VLAN_TX_SKB_CB(skb); + if (cookie->magic == VLAN_TX_COOKIE_MAGIC) { + *tag = cookie->vlan_tag; + return 0; + } else { + *tag = 0; + return -EINVAL; + } +} + +#define HAVE_VLAN_GET_TAG + +/** + * vlan_get_tag - get the VLAN ID from the skb + * @skb: skbuff to query + * @tag: buffer to store vlaue + * + * Returns error if the skb is not VLAN tagged + */ +static inline int vlan_get_tag(struct sk_buff *skb, unsigned short *tag) +{ + if (skb->dev->features & NETIF_F_HW_VLAN_TX) { + return __vlan_hwaccel_get_tag(skb, tag); + } else { + return __vlan_get_tag(skb, tag); + } +} + #endif /* __KERNEL__ */ /* VLAN IOCTLs are found in sockios.h */ diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 6365a4159514..228182715b1d 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -90,6 +90,7 @@ asmlinkage int printk(const char * fmt, ...) unsigned long int_sqrt(unsigned long); extern int printk_ratelimit(void); +extern int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst); static inline void console_silent(void) { diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 84b6fd41e2d2..1a77c3caf115 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -375,6 +375,10 @@ struct net_device atomic_t refcnt; /* delayed register/unregister */ struct list_head todo_list; + /* device name hash chain */ + struct hlist_node name_hlist; + /* device index hash chain */ + struct hlist_node index_hlist; /* register/unregister state machine */ enum { NETREG_UNINITIALIZED=0, diff --git a/include/linux/string.h b/include/linux/string.h index f37b7a6813d3..6ad4e5c32f22 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -52,6 +52,9 @@ extern int strnicmp(const char *, const char *, __kernel_size_t); #ifndef __HAVE_ARCH_STRCHR extern char * strchr(const char *,int); #endif +#ifndef __HAVE_ARCH_STRNCHR +extern char * strnchr(const char *, size_t, int); +#endif #ifndef __HAVE_ARCH_STRRCHR extern char * strrchr(const char *,int); #endif diff --git a/include/net/arp.h b/include/net/arp.h index f65d245f42cc..61fd735c7017 100644 --- a/include/net/arp.h +++ b/include/net/arp.h @@ -5,6 +5,8 @@ #include <linux/if_arp.h> #include <net/neighbour.h> +#define HAVE_ARP_CREATE + extern struct neigh_table arp_tbl; extern void arp_init(void); @@ -19,6 +21,12 @@ extern int arp_bind_neighbour(struct dst_entry *dst); extern int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir); extern void arp_ifdown(struct net_device *dev); +extern struct sk_buff *arp_create(int type, int ptype, u32 dest_ip, + struct net_device *dev, u32 src_ip, + unsigned char *dest_hw, unsigned char *src_hw, + unsigned char *target_hw); +extern void arp_xmit(struct sk_buff *skb); + extern struct neigh_ops arp_broken_ops; #endif /* _ARP_H */ diff --git a/kernel/printk.c b/kernel/printk.c index 90be371e4842..8f2905cfa0a6 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -784,12 +784,6 @@ void tty_write_message(struct tty_struct *tty, char *msg) return; } -/* minimum time in jiffies between messages */ -int printk_ratelimit_jiffies = 5*HZ; - -/* number of messages we send before ratelimiting */ -int printk_ratelimit_burst = 10; - /* * printk rate limiting, lifted from the networking subsystem. * @@ -797,7 +791,7 @@ int printk_ratelimit_burst = 10; * every printk_ratelimit_jiffies to make a denial-of-service * attack impossible. */ -int printk_ratelimit(void) +int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst) { static spinlock_t ratelimit_lock = SPIN_LOCK_UNLOCKED; static unsigned long toks = 10*5*HZ; @@ -809,12 +803,12 @@ int printk_ratelimit(void) spin_lock_irqsave(&ratelimit_lock, flags); toks += now - last_msg; last_msg = now; - if (toks > (printk_ratelimit_burst * printk_ratelimit_jiffies)) - toks = printk_ratelimit_burst * printk_ratelimit_jiffies; - if (toks >= printk_ratelimit_jiffies) { + if (toks > (ratelimit_burst * ratelimit_jiffies)) + toks = ratelimit_burst * ratelimit_jiffies; + if (toks >= ratelimit_jiffies) { int lost = missed; missed = 0; - toks -= printk_ratelimit_jiffies; + toks -= ratelimit_jiffies; spin_unlock_irqrestore(&ratelimit_lock, flags); if (lost) printk(KERN_WARNING "printk: %d messages suppressed.\n", lost); @@ -824,4 +818,17 @@ int printk_ratelimit(void) spin_unlock_irqrestore(&ratelimit_lock, flags); return 0; } +EXPORT_SYMBOL(__printk_ratelimit); + +/* minimum time in jiffies between messages */ +int printk_ratelimit_jiffies = 5*HZ; + +/* number of messages we send before ratelimiting */ +int printk_ratelimit_burst = 10; + +int printk_ratelimit(void) +{ + return __printk_ratelimit(printk_ratelimit_jiffies, + printk_ratelimit_burst); +} EXPORT_SYMBOL(printk_ratelimit); diff --git a/lib/string.c b/lib/string.c index e660de079a57..d2f23f2c1e69 100644 --- a/lib/string.c +++ b/lib/string.c @@ -273,6 +273,22 @@ char * strrchr(const char * s, int c) } #endif +#ifndef __HAVE_ARCH_STRNCHR +/** + * strnchr - Find a character in a length limited string + * @s: The string to be searched + * @count: The number of characters to be searched + * @c: The character to search for + */ +char *strnchr(const char *s, size_t count, int c) +{ + for (; count-- && *s != '\0'; ++s) + if (*s == (char) c) + return (char *) s; + return NULL; +} +#endif + #ifndef __HAVE_ARCH_STRLEN /** * strlen - Find the length of a string diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 47131d2b27a3..b91d251f3fed 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -445,6 +445,7 @@ int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) */ if (veth->h_vlan_proto != __constant_htons(ETH_P_8021Q)) { + int orig_headroom = skb_headroom(skb); unsigned short veth_TCI; /* This is not a VLAN frame...but we can fix that! */ @@ -454,33 +455,7 @@ int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(VLAN_DBG "%s: proto to encap: 0x%hx (hbo)\n", __FUNCTION__, htons(veth->h_vlan_proto)); #endif - - if (skb_headroom(skb) < VLAN_HLEN) { - struct sk_buff *sk_tmp = skb; - skb = skb_realloc_headroom(sk_tmp, VLAN_HLEN); - kfree_skb(sk_tmp); - if (skb == NULL) { - stats->tx_dropped++; - return 0; - } - VLAN_DEV_INFO(dev)->cnt_inc_headroom_on_tx++; - } else { - if (!(skb = skb_unshare(skb, GFP_ATOMIC))) { - printk(KERN_ERR "vlan: failed to unshare skbuff\n"); - stats->tx_dropped++; - return 0; - } - } - veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN); - - /* Move the mac addresses to the beginning of the new header. */ - memmove(skb->data, skb->data + VLAN_HLEN, 12); - - /* first, the ethernet type */ - /* put_unaligned(__constant_htons(ETH_P_8021Q), &veth->h_vlan_proto); */ - veth->h_vlan_proto = __constant_htons(ETH_P_8021Q); - - /* Now, construct the second two bytes. This field looks something + /* Construct the second two bytes. This field looks something * like: * usr_priority: 3 bits (high bits) * CFI 1 bit @@ -489,10 +464,16 @@ int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) veth_TCI = VLAN_DEV_INFO(dev)->vlan_id; veth_TCI |= vlan_dev_get_egress_qos_mask(dev, skb); - veth->h_vlan_TCI = htons(veth_TCI); - } + skb = __vlan_put_tag(skb, veth_TCI); + if (!skb) { + stats->tx_dropped++; + return 0; + } - skb->dev = VLAN_DEV_INFO(dev)->real_dev; + if (orig_headroom < VLAN_HLEN) { + VLAN_DEV_INFO(dev)->cnt_inc_headroom_on_tx++; + } + } #ifdef VLAN_DEBUG printk(VLAN_DBG "%s: about to send skb: %p to dev: %s\n", @@ -506,10 +487,7 @@ int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) stats->tx_packets++; /* for statics only */ stats->tx_bytes += skb->len; - skb->protocol = __constant_htons(ETH_P_8021Q); - skb->mac.raw -= VLAN_HLEN; - skb->nh.raw -= VLAN_HLEN; - + skb->dev = VLAN_DEV_INFO(dev)->real_dev; dev_queue_xmit(skb); return 0; @@ -518,17 +496,22 @@ int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_device_stats *stats = vlan_dev_get_stats(dev); - struct vlan_skb_tx_cookie *cookie; + unsigned short veth_TCI; + + /* Construct the second two bytes. This field looks something + * like: + * usr_priority: 3 bits (high bits) + * CFI 1 bit + * VLAN ID 12 bits (low bits) + */ + veth_TCI = VLAN_DEV_INFO(dev)->vlan_id; + veth_TCI |= vlan_dev_get_egress_qos_mask(dev, skb); + skb = __vlan_hwaccel_put_tag(skb, veth_TCI); stats->tx_packets++; stats->tx_bytes += skb->len; skb->dev = VLAN_DEV_INFO(dev)->real_dev; - cookie = VLAN_TX_SKB_CB(skb); - cookie->magic = VLAN_TX_COOKIE_MAGIC; - cookie->vlan_tag = (VLAN_DEV_INFO(dev)->vlan_id | - vlan_dev_get_egress_qos_mask(dev, skb)); - dev_queue_xmit(skb); return 0; diff --git a/net/Kconfig b/net/Kconfig index 3dcc4c31eb0a..d20ba708570c 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -145,7 +145,7 @@ config DECNET To find some tools to use with the kernel layer support, please look at Patrick Caulfield's web site: - <http://linux.dreamtime.org/decnet/>. + <http://linux-decnet.sourceforge.net/>. More detailed documentation is available in <file:Documentation/networking/decnet.txt>. @@ -436,7 +436,7 @@ config X25 (say Y to "LAPB Data Link Driver" below if you want that). You can read more about X.25 at <http://www.sangoma.com/x25.htm> and - <http://www.cisco.com/univercd/data/doc/software/11_0/rpcg/cx25.htm>. + <http://www.cisco.com/univercd/cc/td/doc/product/software/ios11/cbook/cx25.htm>. Information about X.25 for Linux is contained in the files <file:Documentation/networking/x25.txt> and <file:Documentation/networking/x25-iface.txt>. @@ -571,7 +571,7 @@ config NET_FASTROUTE At the moment, few devices support fast switching (tulip is one of them, a modified 8390 driver can be found at - <ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz>). + <ftp://ftp.tux.org/pub/net/ip-routing/fastroute/fastroute-8390.tar.gz>). If unsure, say N. @@ -583,7 +583,7 @@ config NET_HW_FLOWCONTROL during periods of extreme congestion. At the moment only a couple of device drivers support it (really only one -- tulip, a modified 8390 driver can be found at - <ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz>). + <ftp://ftp.tux.org/pub/net/ip-routing/fastroute/fastroute-8390.tar.gz>). Really, this option is applicable to any machine attached to a fast enough network, and even a 10 Mb NIC is able to kill a not very slow @@ -614,7 +614,7 @@ config NET_SCHED This code is considered to be experimental. To administer these schedulers, you'll need the user-level utilities - from the package iproute2+tc at <ftp://ftp.inr.ac.ru/ip-routing/>. + from the package iproute2+tc at <ftp://ftp.tux.org/pub/net/ip-routing/>. That package also contains some documentation; for more, check out <http://snafu.freedom.org/linux2.2/iproute-notes.html>. diff --git a/net/core/dev.c b/net/core/dev.c index 55fbdfa556c1..d1dfcef63c5a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -161,6 +161,47 @@ static struct timer_list samp_timer = TIMER_INITIALIZER(sample_queue, 0, 0); #endif /* + * The @dev_base list is protected by @dev_base_lock and the rtln + * semaphore. + * + * Pure readers hold dev_base_lock for reading. + * + * Writers must hold the rtnl semaphore while they loop through the + * dev_base list, and hold dev_base_lock for writing when they do the + * actual updates. This allows pure readers to access the list even + * while a writer is preparing to update it. + * + * To put it another way, dev_base_lock is held for writing only to + * protect against pure readers; the rtnl semaphore provides the + * protection against other writers. + * + * See, for example usages, register_netdevice() and + * unregister_netdevice(), which must be called with the rtnl + * semaphore held. + */ +struct net_device *dev_base; +struct net_device **dev_tail = &dev_base; +rwlock_t dev_base_lock = RW_LOCK_UNLOCKED; + +EXPORT_SYMBOL(dev_base); +EXPORT_SYMBOL(dev_base_lock); + +#define NETDEV_HASHBITS 8 +static struct hlist_head dev_name_head[1<<NETDEV_HASHBITS]; +static struct hlist_head dev_index_head[1<<NETDEV_HASHBITS]; + +static inline struct hlist_head *dev_name_hash(const char *name) +{ + unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ)); + return &dev_name_head[hash & ((1<<NETDEV_HASHBITS)-1)]; +} + +static inline struct hlist_head *dev_index_hash(int ifindex) +{ + return &dev_index_head[ifindex & ((1<<NETDEV_HASHBITS)-1)]; +} + +/* * Our notifier list */ @@ -443,12 +484,15 @@ __setup("netdev=", netdev_boot_setup); struct net_device *__dev_get_by_name(const char *name) { - struct net_device *dev; + struct hlist_node *p; - for (dev = dev_base; dev; dev = dev->next) + hlist_for_each(p, dev_name_hash(name)) { + struct net_device *dev + = hlist_entry(p, struct net_device, name_hlist); if (!strncmp(dev->name, name, IFNAMSIZ)) - break; - return dev; + return dev; + } + return NULL; } /** @@ -516,12 +560,15 @@ int __dev_get(const char *name) struct net_device *__dev_get_by_index(int ifindex) { - struct net_device *dev; + struct hlist_node *p; - for (dev = dev_base; dev; dev = dev->next) + hlist_for_each(p, dev_index_hash(ifindex)) { + struct net_device *dev + = hlist_entry(p, struct net_device, index_hlist); if (dev->ifindex == ifindex) - break; - return dev; + return dev; + } + return NULL; } @@ -673,30 +720,55 @@ int dev_valid_name(const char *name) int dev_alloc_name(struct net_device *dev, const char *name) { - int i; - char buf[32]; - char *p; + int i = 0; + char buf[IFNAMSIZ]; + const char *p; + const int max_netdevices = 8*PAGE_SIZE; + long *inuse; + struct net_device *d; - /* - * Verify the string as this thing may have come from - * the user. There must be either one "%d" and no other "%" - * characters, or no "%" characters at all. - */ - p = strchr(name, '%'); - if (p && (p[1] != 'd' || strchr(p + 2, '%'))) - return -EINVAL; + p = strnchr(name, IFNAMSIZ-1, '%'); + if (p) { + /* + * Verify the string as this thing may have come from + * the user. There must be either one "%d" and no other "%" + * characters. + */ + if (p[1] != 'd' || strchr(p + 2, '%')) + return -EINVAL; - /* - * If you need over 100 please also fix the algorithm... - */ - for (i = 0; i < 100; i++) { - snprintf(buf, sizeof(buf), name, i); - if (!__dev_get_by_name(buf)) { - strcpy(dev->name, buf); - return i; + /* Use one page as a bit array of possible slots */ + inuse = (long *) get_zeroed_page(GFP_ATOMIC); + if (!inuse) + return -ENOMEM; + + for (d = dev_base; d; d = d->next) { + if (!sscanf(d->name, name, &i)) + continue; + if (i < 0 || i >= max_netdevices) + continue; + + /* avoid cases where sscanf is not exact inverse of printf */ + snprintf(buf, sizeof(buf), name, i); + if (!strncmp(buf, d->name, IFNAMSIZ)) + set_bit(i, inuse); } + + i = find_first_zero_bit(inuse, max_netdevices); + free_page((unsigned long) inuse); } - return -ENFILE; /* Over 100 of the things .. bail out! */ + + snprintf(buf, sizeof(buf), name, i); + if (!__dev_get_by_name(buf)) { + strlcpy(dev->name, buf, IFNAMSIZ); + return i; + } + + /* It is possible to run out of possible slots + * when the name is long and there isn't enough space left + * for the digits, or if all bits are used. + */ + return -ENFILE; } @@ -729,6 +801,9 @@ int dev_change_name(struct net_device *dev, char *newname) else strlcpy(dev->name, newname, IFNAMSIZ); + hlist_del(&dev->name_hlist); + hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name)); + class_device_rename(&dev->class_dev, dev->name); notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); return 0; @@ -2717,7 +2792,8 @@ static inline void net_set_todo(struct net_device *dev) int register_netdevice(struct net_device *dev) { - struct net_device *d, **dp; + struct hlist_head *head; + struct hlist_node *p; int ret; BUG_ON(dev_boot_phase); @@ -2758,13 +2834,17 @@ int register_netdevice(struct net_device *dev) if (dev->iflink == -1) dev->iflink = dev->ifindex; - /* Check for existence, and append to tail of chain */ - ret = -EEXIST; - for (dp = &dev_base; (d = *dp) != NULL; dp = &d->next) { - if (d == dev || !strcmp(d->name, dev->name)) - goto out_err; - } - + /* Check for existence of name */ + head = dev_name_hash(dev->name); + hlist_for_each(p, head) { + struct net_device *d + = hlist_entry(p, struct net_device, name_hlist); + if (!strncmp(d->name, dev->name, IFNAMSIZ)) { + ret = -EEXIST; + goto out_err; + } + } + /* Fix illegal SG+CSUM combinations. */ if ((dev->features & NETIF_F_SG) && !(dev->features & (NETIF_F_IP_CSUM | @@ -2793,7 +2873,10 @@ int register_netdevice(struct net_device *dev) dev->next = NULL; dev_init_scheduler(dev); write_lock_bh(&dev_base_lock); - *dp = dev; + *dev_tail = dev; + dev_tail = &dev->next; + 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); @@ -3015,6 +3098,10 @@ int unregister_netdevice(struct net_device *dev) for (dp = &dev_base; (d = *dp) != NULL; dp = &d->next) { if (d == dev) { write_lock_bh(&dev_base_lock); + hlist_del(&dev->name_hlist); + hlist_del(&dev->index_hlist); + if (dev_tail == &dev->next) + dev_tail = dp; *dp = d->next; write_unlock_bh(&dev_base_lock); break; @@ -3091,6 +3178,12 @@ static int __init net_dev_init(void) for (i = 0; i < 16; i++) INIT_LIST_HEAD(&ptype_base[i]); + for (i = 0; i < ARRAY_SIZE(dev_name_head); i++) + INIT_HLIST_HEAD(&dev_name_head[i]); + + for (i = 0; i < ARRAY_SIZE(dev_index_head); i++) + INIT_HLIST_HEAD(&dev_index_head[i]); + /* * Initialise the packet receive queues. */ diff --git a/net/core/utils.c b/net/core/utils.c index 995f2b5168c2..8058d9c5e236 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -41,37 +41,11 @@ int net_msg_cost = 5*HZ; int net_msg_burst = 10; /* - * This enforces a rate limit: not more than one kernel message - * every 5secs to make a denial-of-service attack impossible. - * - * All warning printk()s should be guarded by this function. + * All net warning printk()s should be guarded by this function. */ int net_ratelimit(void) { - static spinlock_t ratelimit_lock = SPIN_LOCK_UNLOCKED; - static unsigned long toks = 10*5*HZ; - static unsigned long last_msg; - static int missed; - unsigned long flags; - unsigned long now = jiffies; - - spin_lock_irqsave(&ratelimit_lock, flags); - toks += now - last_msg; - last_msg = now; - if (toks > net_msg_burst) - toks = net_msg_burst; - if (toks >= net_msg_cost) { - int lost = missed; - missed = 0; - toks -= net_msg_cost; - spin_unlock_irqrestore(&ratelimit_lock, flags); - if (lost) - printk(KERN_WARNING "NET: %d messages suppressed.\n", lost); - return 1; - } - missed++; - spin_unlock_irqrestore(&ratelimit_lock, flags); - return 0; + return __printk_ratelimit(net_msg_cost, net_msg_burst); } EXPORT_SYMBOL(net_random); diff --git a/net/decnet/Kconfig b/net/decnet/Kconfig index 74f1f2db6618..74d6aaceeaed 100644 --- a/net/decnet/Kconfig +++ b/net/decnet/Kconfig @@ -22,8 +22,9 @@ config DECNET_ROUTER network link driver", "Routing messages" and "Network packet filtering". The first two are required to allow configuration via rtnetlink (you will need Alexey Kuznetsov's iproute2 package - from <ftp://ftp.inr.ac.ru/>). The "Network packet filtering" option - will be required for the forthcoming routing daemon to work. + from <ftp://ftp.tux.org/pub/net/ip-routing/>). The "Network packet + filtering" option will be required for the forthcoming routing daemon + to work. See <file:Documentation/networking/decnet.txt> for more information. diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 6ee8011d0bc3..0791bd025704 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -71,7 +71,7 @@ config IP_MULTIPLE_TABLES documentation at <http://www.compendium.com.ar/policy-routing.txt> and <ftp://post.tepkom.ru/pub/vol2/Linux/docs/advanced-routing.tex>. You will need supporting software from - <ftp://ftp.inr.ac.ru/ip-routing/>. + <ftp://ftp.tux.org/pub/net/ip-routing/>. If unsure, say N. diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 5c03f63502bc..0de93f953ef9 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -67,6 +67,10 @@ * now it is in net/core/neighbour.c. * Krzysztof Halasa: Added Frame Relay ARP support. * Arnaldo C. Melo : convert /proc/net/arp to seq_file + * Shmulik Hen: Split arp_send to arp_create and + * arp_xmit so intermediate drivers like + * bonding can change the skb before + * sending (e.g. insert 8021q tag). */ #include <linux/module.h> @@ -487,34 +491,26 @@ static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt) */ /* - * Create and send an arp packet. If (dest_hw == NULL), we create a broadcast + * Create an arp packet. If (dest_hw == NULL), we create a broadcast * message. */ - -void arp_send(int type, int ptype, u32 dest_ip, - struct net_device *dev, u32 src_ip, - unsigned char *dest_hw, unsigned char *src_hw, - unsigned char *target_hw) +struct sk_buff *arp_create(int type, int ptype, u32 dest_ip, + struct net_device *dev, u32 src_ip, + unsigned char *dest_hw, unsigned char *src_hw, + unsigned char *target_hw) { struct sk_buff *skb; struct arphdr *arp; unsigned char *arp_ptr; /* - * No arp on this interface. - */ - - if (dev->flags&IFF_NOARP) - return; - - /* * Allocate a buffer */ skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4) + LL_RESERVED_SPACE(dev), GFP_ATOMIC); if (skb == NULL) - return; + return NULL; skb_reserve(skb, LL_RESERVED_SPACE(dev)); skb->nh.raw = skb->data; @@ -594,12 +590,46 @@ void arp_send(int type, int ptype, u32 dest_ip, arp_ptr+=dev->addr_len; memcpy(arp_ptr, &dest_ip, 4); - /* Send it off, maybe filter it using firewalling first. */ - NF_HOOK(NF_ARP, NF_ARP_OUT, skb, NULL, dev, dev_queue_xmit); - return; + return skb; out: kfree_skb(skb); + return NULL; +} + +/* + * Send an arp packet. + */ +void arp_xmit(struct sk_buff *skb) +{ + /* Send it off, maybe filter it using firewalling first. */ + NF_HOOK(NF_ARP, NF_ARP_OUT, skb, NULL, skb->dev, dev_queue_xmit); +} + +/* + * Create and send an arp packet. + */ +void arp_send(int type, int ptype, u32 dest_ip, + struct net_device *dev, u32 src_ip, + unsigned char *dest_hw, unsigned char *src_hw, + unsigned char *target_hw) +{ + struct sk_buff *skb; + + /* + * No arp on this interface. + */ + + if (dev->flags&IFF_NOARP) + return; + + skb = arp_create(type, ptype, dest_ip, dev, src_ip, + dest_hw, src_hw, target_hw); + if (skb == NULL) { + return; + } + + arp_xmit(skb); } static void parp_redo(struct sk_buff *skb) @@ -1437,6 +1467,8 @@ static int __init arp_proc_init(void) EXPORT_SYMBOL(arp_broken_ops); EXPORT_SYMBOL(arp_find); EXPORT_SYMBOL(arp_rcv); +EXPORT_SYMBOL(arp_create); +EXPORT_SYMBOL(arp_xmit); EXPORT_SYMBOL(arp_send); EXPORT_SYMBOL(arp_tbl); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 79b1dbf6692c..5c2c1f6aafd5 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -707,8 +707,10 @@ static void ndisc_recv_ns(struct sk_buff *skb) struct ndisc_options ndopts; struct net_device *dev = skb->dev; struct inet6_ifaddr *ifp; + struct inet6_dev *idev = NULL; struct neighbour *neigh; - int addr_type = ipv6_addr_type(saddr); + int dad = ipv6_addr_any(saddr); + int inc; if (ipv6_addr_is_multicast(&msg->target)) { if (net_ratelimit()) @@ -720,7 +722,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) * RFC2461 7.1.1: * DAD has to be destined for solicited node multicast address. */ - if (addr_type == IPV6_ADDR_ANY && + if (dad && !(daddr->s6_addr32[0] == htonl(0xff020000) && daddr->s6_addr32[1] == htonl(0x00000000) && daddr->s6_addr32[2] == htonl(0x00000001) && @@ -750,13 +752,15 @@ static void ndisc_recv_ns(struct sk_buff *skb) * there MUST NOT be source link-layer address option * in the message. */ - if (addr_type == IPV6_ADDR_ANY) { + if (dad) { if (net_ratelimit()) printk(KERN_WARNING "ICMP6 NS: bad DAD packet (link-layer address option)\n"); return; } } + inc = ipv6_addr_is_multicast(daddr); + if ((ifp = ipv6_get_ifaddr(&msg->target, dev, 1)) != NULL) { if (ifp->flags & IFA_F_TENTATIVE) { /* Address is tentative. If the source @@ -764,146 +768,89 @@ static void ndisc_recv_ns(struct sk_buff *skb) does DAD, otherwise we ignore solicitations until DAD timer expires. */ - if (addr_type == IPV6_ADDR_ANY) { - if (dev->type == ARPHRD_IEEE802_TR) { - unsigned char *sadr = skb->mac.raw ; - if (((sadr[8] &0x7f) != (dev->dev_addr[0] & 0x7f)) || - (sadr[9] != dev->dev_addr[1]) || - (sadr[10] != dev->dev_addr[2]) || - (sadr[11] != dev->dev_addr[3]) || - (sadr[12] != dev->dev_addr[4]) || - (sadr[13] != dev->dev_addr[5])) - { - addrconf_dad_failure(ifp) ; - } - } else { - addrconf_dad_failure(ifp); + if (!dad) + goto out; + if (dev->type == ARPHRD_IEEE802_TR) { + unsigned char *sadr = skb->mac.raw; + if (((sadr[8] ^ dev->dev_addr[0]) & 0x7f) == 0 && + sadr[9] == dev->dev_addr[1] && + sadr[10] == dev->dev_addr[2] && + sadr[11] == dev->dev_addr[3] && + sadr[12] == dev->dev_addr[4] && + sadr[13] == dev->dev_addr[5]) { + /* looped-back to us */ + goto out; } - } else - in6_ifa_put(ifp); - return; - } - - if (addr_type == IPV6_ADDR_ANY) { - struct in6_addr maddr; - - ipv6_addr_all_nodes(&maddr); - ndisc_send_na(dev, NULL, &maddr, &ifp->addr, - ifp->idev->cnf.forwarding, 0, - 1, 1); - in6_ifa_put(ifp); + } + addrconf_dad_failure(ifp); return; } - if (addr_type & IPV6_ADDR_UNICAST) { - if (ipv6_addr_is_multicast(daddr)) - nd_tbl.stats.rcv_probes_mcast++; - else - nd_tbl.stats.rcv_probes_ucast++; - - /* - * update / create cache entry - * for the source address - */ - - neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev); - - if (neigh || !dev->hard_header) { - ndisc_send_na(dev, neigh, saddr, &ifp->addr, - ifp->idev->cnf.forwarding, 1, - 1, 1); - if (neigh) - neigh_release(neigh); - } - } - in6_ifa_put(ifp); - } else if (ipv6_chk_acast_addr(dev, &msg->target)) { - struct inet6_dev *idev = in6_dev_get(dev); - - /* anycast */ - + idev = ifp->idev; + } else { + idev = in6_dev_get(dev); if (!idev) { /* XXX: count this drop? */ return; } - - if (addr_type == IPV6_ADDR_ANY) { - struct in6_addr maddr; - - ipv6_addr_all_nodes(&maddr); - ndisc_send_na(dev, NULL, &maddr, &msg->target, - idev->cnf.forwarding, 0, 0, 1); - in6_dev_put(idev); - return; - } - - if (addr_type & IPV6_ADDR_UNICAST) { - int inc = ipv6_addr_is_multicast(daddr); - if (inc) - nd_tbl.stats.rcv_probes_mcast++; - else - nd_tbl.stats.rcv_probes_ucast++; - - /* - * update / create cache entry - * for the source address - */ - neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, skb->dev); - - if (neigh || !dev->hard_header) { - ndisc_send_na(dev, neigh, saddr, - &msg->target, - idev->cnf.forwarding, 1, 0, inc); - if (neigh) - neigh_release(neigh); - } - } - in6_dev_put(idev); - } else { - struct inet6_dev *in6_dev = in6_dev_get(dev); - - if (in6_dev && in6_dev->cnf.forwarding && - (addr_type & IPV6_ADDR_UNICAST || - addr_type == IPV6_ADDR_ANY) && - pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) { - int inc = ipv6_addr_is_multicast(daddr); - - if (skb->stamp.tv_sec == 0 || - skb->pkt_type == PACKET_HOST || - inc == 0 || - in6_dev->nd_parms->proxy_delay == 0) { - if (inc) - nd_tbl.stats.rcv_probes_mcast++; - else - nd_tbl.stats.rcv_probes_ucast++; - - if (addr_type & IPV6_ADDR_UNICAST) { - neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev); - - if (neigh) { - ndisc_send_na(dev, neigh, saddr, &msg->target, - 0, 1, 0, 1); - neigh_release(neigh); - } - } else { - /* proxy should also protect against DAD */ - struct in6_addr maddr; - ipv6_addr_all_nodes(&maddr); - ndisc_send_na(dev, NULL, &maddr, &msg->target, - 0, 0, 0, 1); - } - } else { + if (ipv6_chk_acast_addr(dev, &msg->target) || + (idev->cnf.forwarding && + pneigh_lookup(&nd_tbl, &msg->target, dev, 0))) { + if (skb->stamp.tv_sec != 0 && + skb->pkt_type != PACKET_HOST && + inc != 0 && + idev->nd_parms->proxy_delay != 0) { + /* + * for anycast or proxy, + * sender should delay its response + * by a random time between 0 and + * MAX_ANYCAST_DELAY_TIME seconds. + * (RFC2461) -- yoshfuji + */ struct sk_buff *n = skb_clone(skb, GFP_ATOMIC); if (n) - pneigh_enqueue(&nd_tbl, in6_dev->nd_parms, n); - in6_dev_put(in6_dev); - return; + pneigh_enqueue(&nd_tbl, idev->nd_parms, n); + goto out; } - } - if (in6_dev) - in6_dev_put(in6_dev); + } else + goto out; } + + if (dad) { + struct in6_addr maddr; + + ipv6_addr_all_nodes(&maddr); + ndisc_send_na(dev, NULL, &maddr, &msg->target, + idev->cnf.forwarding, 0, (ifp != NULL), 1); + goto out; + } + + if (inc) + nd_tbl.stats.rcv_probes_mcast++; + else + nd_tbl.stats.rcv_probes_ucast++; + + /* + * update / create cache entry + * for the source address + */ + neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev); + + if (neigh || !dev->hard_header) { + ndisc_send_na(dev, neigh, saddr, &msg->target, + idev->cnf.forwarding, + 1, (ifp != NULL && inc), inc); + if (neigh) + neigh_release(neigh); + } + +out: + if (ifp) + in6_ifa_put(ifp); + else + in6_dev_put(idev); + return; } diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index b0e410d1a88c..38c27b9bb70a 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -230,7 +230,7 @@ static int netlink_create(struct socket *sock, int protocol) sock_init_data(sock,sk); sk_set_owner(sk, THIS_MODULE); - nlk = nlk_sk(sk) = kmalloc(sizeof(*nlk), GFP_KERNEL); + nlk = sk->sk_protinfo = kmalloc(sizeof(*nlk), GFP_KERNEL); if (!nlk) { sk_free(sk); return -ENOMEM; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 3b01f540b652..7b4a14aac955 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -961,7 +961,7 @@ static int packet_create(struct socket *sock, int protocol) sock_init_data(sock,sk); sk_set_owner(sk, THIS_MODULE); - po = pkt_sk(sk) = kmalloc(sizeof(*po), GFP_KERNEL); + po = sk->sk_protinfo = kmalloc(sizeof(*po), GFP_KERNEL); if (!po) goto out_free; memset(po, 0, sizeof(*po)); |
