From 8a8e855385b609d2d3c936693917785f9266aa6b Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 5 Feb 2004 21:29:54 -0800 Subject: [NETLINK]: Fix illegal lvalue with gcc-3.5 --- net/netlink/af_netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; -- cgit v1.2.3 From 11591177061035b54333d03f2f39405fd28855f3 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 5 Feb 2004 21:30:24 -0800 Subject: [AF_PACKET]: Fix illegal lvalue with gcc-3.5 --- net/packet/af_packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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)); -- cgit v1.2.3 From 33be943504778ad51cd2caca8b5497cdf75f30ac Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 5 Feb 2004 21:30:50 -0800 Subject: [PPPOE]: Fix illegal lvalue with gcc-3.5 --- drivers/net/pppoe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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)); -- cgit v1.2.3 From cc1b2ba84162afbb7b11d230a1062bfba12adc24 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 5 Feb 2004 21:35:14 -0800 Subject: [NET]: Move dev_base and dev_base_lock into net/core/dev.c --- drivers/net/Space.c | 25 ------------------------- net/core/dev.c | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 25 deletions(-) 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/net/core/dev.c b/net/core/dev.c index 55fbdfa556c1..e298f2b7f9c9 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -160,6 +160,31 @@ static void sample_queue(unsigned long dummy); 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; +rwlock_t dev_base_lock = RW_LOCK_UNLOCKED; + +EXPORT_SYMBOL(dev_base); +EXPORT_SYMBOL(dev_base_lock); + /* * Our notifier list */ -- cgit v1.2.3 From fa13a7b8fd68f4c00fc8c6905261b50a4733d8c3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 5 Feb 2004 21:39:01 -0800 Subject: [NET]: Hash netdevices by name for faster lookup. --- include/linux/netdevice.h | 2 ++ net/core/dev.c | 55 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 84b6fd41e2d2..11723ab7e2c5 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -375,6 +375,8 @@ struct net_device atomic_t refcnt; /* delayed register/unregister */ struct list_head todo_list; + /* device name hash chain */ + struct hlist_node name_hlist; /* register/unregister state machine */ enum { NETREG_UNINITIALIZED=0, diff --git a/net/core/dev.c b/net/core/dev.c index e298f2b7f9c9..d5ba80179da6 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -180,11 +180,21 @@ static struct timer_list samp_timer = TIMER_INITIALIZER(sample_queue, 0, 0); * 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<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; } -- cgit v1.2.3 From 353131f37e48c775ed37e18eafd7a570d0feac15 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 5 Feb 2004 23:09:25 -0800 Subject: [NET]: Simply net_ratelimit(). Reimplement net_ratelimit() in terms of the new printk_ratelimit(). As net_ratelimit() already has it own sysctls we generalise printk_ratelimit() a bit so that networking does not lose its existing sysctls and so that it can use different time constants from the more generic printk_ratelimit(). --- include/linux/kernel.h | 1 + kernel/printk.c | 29 ++++++++++++++++++----------- net/core/utils.c | 30 ++---------------------------- 3 files changed, 21 insertions(+), 39 deletions(-) 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/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/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); -- cgit v1.2.3 From b1e63f72029af02a4f1b66e08652ec249c338552 Mon Sep 17 00:00:00 2001 From: Hideaki Yoshifuji Date: Thu, 5 Feb 2004 23:26:19 -0800 Subject: [IPV6]: Clean-up NS (including DAD) vs tentative address. --- net/ipv6/ndisc.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 79b1dbf6692c..d0b59590b252 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -764,23 +764,24 @@ 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); - } - } else + if (addr_type != IPV6_ADDR_ANY) { in6_ifa_put(ifp); + return; + } + 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 */ + in6_ifa_put(ifp); + return; + } + } + addrconf_dad_failure(ifp); return; } -- cgit v1.2.3 From 13ef52adea98ef92fa0d4b8dbc055ffd28452265 Mon Sep 17 00:00:00 2001 From: Hideaki Yoshifuji Date: Thu, 5 Feb 2004 23:27:38 -0800 Subject: [IPV6]: Unify 3 similar code paths in ndisc_recv_ns(). --- net/ipv6/ndisc.c | 171 +++++++++++++++++++------------------------------------ 1 file changed, 60 insertions(+), 111 deletions(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index d0b59590b252..dd2cb637da34 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 inc; if (ipv6_addr_is_multicast(&msg->target)) { if (net_ratelimit()) @@ -757,6 +759,8 @@ static void ndisc_recv_ns(struct sk_buff *skb) } } + 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 @@ -784,127 +788,72 @@ static void ndisc_recv_ns(struct sk_buff *skb) addrconf_dad_failure(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); - 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 (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, (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; } -- cgit v1.2.3 From f002d840a6614b33e02cfc3becce0a3dcf3a2481 Mon Sep 17 00:00:00 2001 From: Hideaki Yoshifuji Date: Thu, 5 Feb 2004 23:29:07 -0800 Subject: [IPV6]: Use cheaper ipv6_addr_any() where appropriate. --- net/ipv6/ndisc.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index dd2cb637da34..5c2c1f6aafd5 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -709,7 +709,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) 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)) { @@ -722,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) && @@ -752,7 +752,7 @@ 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; @@ -768,10 +768,8 @@ 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) { - in6_ifa_put(ifp); - return; - } + 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 && @@ -781,8 +779,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) sadr[12] == dev->dev_addr[4] && sadr[13] == dev->dev_addr[5]) { /* looped-back to us */ - in6_ifa_put(ifp); - return; + goto out; } } addrconf_dad_failure(ifp); @@ -820,7 +817,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) goto out; } - if (addr_type == IPV6_ADDR_ANY) { + if (dad) { struct in6_addr maddr; ipv6_addr_all_nodes(&maddr); -- cgit v1.2.3 From 6d7c32165fa2483419d6d4a0e82a7dd0830613e8 Mon Sep 17 00:00:00 2001 From: Shmulik Hen Date: Fri, 6 Feb 2004 00:00:41 -0800 Subject: [IPV4]: Split arp_send into arp_create and arp_xmit, export them. --- include/net/arp.h | 8 +++++++ net/ipv4/arp.c | 66 +++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 57 insertions(+), 17 deletions(-) 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 #include +#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/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 @@ -487,26 +491,18 @@ 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 */ @@ -514,7 +510,7 @@ void arp_send(int type, int ptype, u32 dest_ip, 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); -- cgit v1.2.3 From cdea4568af5eecf3446de415c55a9751822d757d Mon Sep 17 00:00:00 2001 From: Shmulik Hen Date: Fri, 6 Feb 2004 00:20:43 -0800 Subject: [VLAN]: Export VLAN tag get/set functionality. Enable intermediate network drivers like bonding to get or set a VLAN tag in an skb without a need to know about how tagging is done according to a network adapter's capabilities. --- include/linux/if_vlan.h | 146 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) 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 */ -- cgit v1.2.3 From 7c7057e21775909ed34322d0bb3a233e743dbbaa Mon Sep 17 00:00:00 2001 From: Shmulik Hen Date: Fri, 6 Feb 2004 00:21:32 -0800 Subject: [VLAN]: Use VLAN tag set functionality in 8021q module. Make the regular/HW accelerated xmit functions in the 8021q module use the new set VLAN tag functionality to reduce code duplication. --- net/8021q/vlan_dev.c | 63 +++++++++++++++++++--------------------------------- 1 file changed, 23 insertions(+), 40 deletions(-) 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; -- cgit v1.2.3 From 7a98480512254fa9e9f029aaeca21be1aeb5fc28 Mon Sep 17 00:00:00 2001 From: "Petri T. Koistinen" Date: Fri, 6 Feb 2004 00:24:31 -0800 Subject: [NET]: Bunch of Kconfig and doc URL updates. --- Documentation/Changes | 2 +- Documentation/networking/ethertap.txt | 2 +- net/Kconfig | 10 +++++----- net/decnet/Kconfig | 5 +++-- net/ipv4/Kconfig | 2 +- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Documentation/Changes b/Documentation/Changes index e0288627d64a..fe1bf8b9445f 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -407,7 +407,7 @@ o Ip-route2 --------- -o +o 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/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: - . + . More detailed documentation is available in . @@ -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 and - . + . Information about X.25 for Linux is contained in the files and . @@ -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 - ). + ). 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 - ). + ). 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 . + from the package iproute2+tc at . That package also contains some documentation; for more, check out . 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 ). The "Network packet filtering" option - will be required for the forthcoming routing daemon to work. + from ). The "Network packet + filtering" option will be required for the forthcoming routing daemon + to work. See 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 and . You will need supporting software from - . + . If unsure, say N. -- cgit v1.2.3