From b7dc8c3959fd43bfa0dbcf65375628c86665cb94 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Fri, 4 Jan 2013 03:58:04 +0000 Subject: ndisc: Remove unused space at tail of skb for ndisc messages. (TAKE 3) Currently, the size of skb allocated for NDISC is MAX_HEADER + LL_RESERVED_SPACE(dev) + packet length + dev->needed_tailroom, but only LL_RESERVED_SPACE(dev) bytes is "reserved" for headers. As a result, the skb looks like this (after construction of the message): head data tail end +--------------------------------------------------------------+ + | | | | +--------------------------------------------------------------+ |<-hlen---->|<---ipv6 packet------>|<--tlen-->|<--MAX_HEADER-->| =LL_ = dev RESERVED_ ->needed_ SPACE(dev) tailroom As the name implies, "MAX_HEADER" is used for headers, and should be "reserved" in prior to packet construction. Or, if some space is really required at the tail of ther skb, it should be explicitly documented. We have several option after construction of NDISC message: Option 1: head data tail end +---------------------------------------------+ + | | | +---------------------------------------------+ |<-hlen---->|<---ipv6 packet------>|<--tlen-->| =LL_ = dev RESERVED_ ->needed_ SPACE(dev) tailroom Option 2: head data tail end +--------------------------------------------------+ + | | | +--------------------------------------------------+ |<--MAX_HEADER-->|<---ipv6 packet------>|<--tlen-->| = dev ->needed_ tailroom Option 3: head data tail end +--------------------------------------------------------------+ + | | | | +--------------------------------------------------------------+ |<--MAX_HEADER-->|<-hlen---->|<---ipv6 packet------>|<--tlen-->| =LL_ = dev RESERVED_ ->needed_ SPACE(dev) tailroom Our tunnel drivers try expanding headroom and the space for tunnel encapsulation was not a mandatory space -- so we are not seeing bugs here --, but just for optimization for performance critial situations. Since NDISC messages are not performance critical unlike TCP, and as we know outgoing device, LL_RESERVED_SPACE(dev) should be just enough for the device in most (if not all) cases: LL_RESERVED_SPACE(dev) <= LL_MAX_HEADER <= MAX_HEADER Note that LL_RESERVED_SPACE(dev) is also enough for NDISC over SIT (e.g., ISATAP). So, I think Option 1 is just fine here. Signed-off-by: YOSHIFUJI Hideaki Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 6574175795df..4c4ccf79d2c5 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -395,7 +395,7 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev, len += ndisc_opt_addr_space(dev); skb = sock_alloc_send_skb(sk, - (MAX_HEADER + sizeof(struct ipv6hdr) + + (sizeof(struct ipv6hdr) + len + hlen + tlen), 1, &err); if (!skb) { @@ -1439,7 +1439,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) hlen = LL_RESERVED_SPACE(dev); tlen = dev->needed_tailroom; buff = sock_alloc_send_skb(sk, - (MAX_HEADER + sizeof(struct ipv6hdr) + + (sizeof(struct ipv6hdr) + len + hlen + tlen), 1, &err); if (buff == NULL) { -- cgit v1.2.3 From 71bcdba06db91ceaaffe019b6c958b5faf06012a Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Sat, 5 Jan 2013 16:34:51 +0000 Subject: ndisc: Use struct rd_msg for redirect message. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 25 +++++++++++-------------- net/ipv6/route.c | 24 ++++++++++-------------- 2 files changed, 21 insertions(+), 28 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 4c4ccf79d2c5..5733cd27f4a3 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1355,12 +1355,11 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) struct net_device *dev = skb->dev; struct net *net = dev_net(dev); struct sock *sk = net->ipv6.ndisc_sk; - int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); + int len = sizeof(struct rd_msg); struct inet_peer *peer; struct sk_buff *buff; - struct icmp6hdr *icmph; + struct rd_msg *msg; struct in6_addr saddr_buf; - struct in6_addr *addrp; struct rt6_info *rt; struct dst_entry *dst; struct inet6_dev *idev; @@ -1455,21 +1454,19 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data); skb_put(buff, len); - icmph = icmp6_hdr(buff); + msg = (struct rd_msg *)icmp6_hdr(buff); - memset(icmph, 0, sizeof(struct icmp6hdr)); - icmph->icmp6_type = NDISC_REDIRECT; + memset(&msg->icmph, 0, sizeof(struct icmp6hdr)); + msg->icmph.icmp6_type = NDISC_REDIRECT; /* * copy target and destination addresses */ - addrp = (struct in6_addr *)(icmph + 1); - *addrp = *target; - addrp++; - *addrp = ipv6_hdr(skb)->daddr; + msg->target = *target; + msg->dest = ipv6_hdr(skb)->daddr; - opt = (u8*) (addrp + 1); + opt = msg->opt; /* * include target_address option @@ -1490,9 +1487,9 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) memcpy(opt, ipv6_hdr(skb), rd_len - 8); - icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr, - len, IPPROTO_ICMPV6, - csum_partial(icmph, len, 0)); + msg->icmph.icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr, + len, IPPROTO_ICMPV6, + csum_partial(msg, len, 0)); skb_dst_set(buff, dst); rcu_read_lock(); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index e229a3bc345d..621b68ecf16f 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1705,37 +1705,33 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu struct net *net = dev_net(skb->dev); struct netevent_redirect netevent; struct rt6_info *rt, *nrt = NULL; - const struct in6_addr *target; struct ndisc_options ndopts; - const struct in6_addr *dest; struct neighbour *old_neigh; struct inet6_dev *in6_dev; struct neighbour *neigh; - struct icmp6hdr *icmph; + struct rd_msg *msg; int optlen, on_link; u8 *lladdr; optlen = skb->tail - skb->transport_header; - optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); + optlen -= sizeof(*msg); if (optlen < 0) { net_dbg_ratelimited("rt6_do_redirect: packet too short\n"); return; } - icmph = icmp6_hdr(skb); - target = (const struct in6_addr *) (icmph + 1); - dest = target + 1; + msg = (struct rd_msg *)icmp6_hdr(skb); - if (ipv6_addr_is_multicast(dest)) { + if (ipv6_addr_is_multicast(&msg->dest)) { net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n"); return; } on_link = 0; - if (ipv6_addr_equal(dest, target)) { + if (ipv6_addr_equal(&msg->dest, &msg->target)) { on_link = 1; - } else if (ipv6_addr_type(target) != + } else if (ipv6_addr_type(&msg->target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) { net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n"); return; @@ -1752,7 +1748,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu * first-hop router for the specified ICMP Destination Address. */ - if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) { + if (!ndisc_parse_options(msg->opt, optlen, &ndopts)) { net_dbg_ratelimited("rt6_redirect: invalid ND options\n"); return; } @@ -1779,7 +1775,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu */ dst_confirm(&rt->dst); - neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1); + neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1); if (!neigh) return; @@ -1799,7 +1795,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu NEIGH_UPDATE_F_ISROUTER)) ); - nrt = ip6_rt_copy(rt, dest); + nrt = ip6_rt_copy(rt, &msg->dest); if (!nrt) goto out; @@ -1817,7 +1813,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu netevent.old_neigh = old_neigh; netevent.new = &nrt->dst; netevent.new_neigh = neigh; - netevent.daddr = dest; + netevent.daddr = &msg->dest; call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); if (rt->rt6i_flags & RTF_CACHE) { -- cgit v1.2.3 From 12fd84f4383b15b0a12cfd50b7c527cd55d6f101 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Fri, 18 Jan 2013 02:00:24 +0000 Subject: ipv6: Remove unused neigh argument for icmp6_dst_alloc() and its callers. Because of rt->n removal, we do not need neigh argument any more. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- include/net/ip6_route.h | 1 - net/ipv6/mcast.c | 4 ++-- net/ipv6/ndisc.c | 15 +++++---------- net/ipv6/route.c | 1 - 4 files changed, 7 insertions(+), 14 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 30cbb15f6279..260f83f16bcf 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -103,7 +103,6 @@ extern struct rt6_info *rt6_lookup(struct net *net, int oif, int flags); extern struct dst_entry *icmp6_dst_alloc(struct net_device *dev, - struct neighbour *neigh, struct flowi6 *fl6); extern int icmp6_dst_gc(void); diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 8237ee15eafd..587a84530a57 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1391,7 +1391,7 @@ static void mld_sendpack(struct sk_buff *skb) icmpv6_flow_init(net->ipv6.igmp_sk, &fl6, ICMPV6_MLD2_REPORT, &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, skb->dev->ifindex); - dst = icmp6_dst_alloc(skb->dev, NULL, &fl6); + dst = icmp6_dst_alloc(skb->dev, &fl6); err = 0; if (IS_ERR(dst)) { @@ -1759,7 +1759,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) icmpv6_flow_init(sk, &fl6, type, &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, skb->dev->ifindex); - dst = icmp6_dst_alloc(skb->dev, NULL, &fl6); + dst = icmp6_dst_alloc(skb->dev, &fl6); if (IS_ERR(dst)) { err = PTR_ERR(dst); goto err_out; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 5733cd27f4a3..429622d74705 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -432,7 +432,6 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev, } static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev, - struct neighbour *neigh, const struct in6_addr *daddr, const struct in6_addr *saddr, struct icmp6hdr *icmp6h) @@ -448,7 +447,7 @@ static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev, type = icmp6h->icmp6_type; icmpv6_flow_init(sk, &fl6, type, saddr, daddr, dev->ifindex); - dst = icmp6_dst_alloc(dev, neigh, &fl6); + dst = icmp6_dst_alloc(dev, &fl6); if (IS_ERR(dst)) { kfree_skb(skb); return; @@ -474,7 +473,6 @@ static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev, * Send a Neighbour Discover packet */ static void __ndisc_send(struct net_device *dev, - struct neighbour *neigh, const struct in6_addr *daddr, const struct in6_addr *saddr, struct icmp6hdr *icmp6h, const struct in6_addr *target, @@ -486,7 +484,7 @@ static void __ndisc_send(struct net_device *dev, if (!skb) return; - ndisc_send_skb(skb, dev, neigh, daddr, saddr, icmp6h); + ndisc_send_skb(skb, dev, daddr, saddr, icmp6h); } static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, @@ -521,8 +519,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, icmp6h.icmp6_solicited = solicited; icmp6h.icmp6_override = override; - __ndisc_send(dev, neigh, daddr, src_addr, - &icmp6h, solicited_addr, + __ndisc_send(dev, daddr, src_addr, &icmp6h, solicited_addr, inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); } @@ -563,8 +560,7 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, saddr = &addr_buf; } - __ndisc_send(dev, neigh, daddr, saddr, - &icmp6h, solicit, + __ndisc_send(dev, daddr, saddr, &icmp6h, solicit, !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0); } @@ -598,8 +594,7 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, } } #endif - __ndisc_send(dev, NULL, daddr, saddr, - &icmp6h, NULL, + __ndisc_send(dev, daddr, saddr, &icmp6h, NULL, send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 3a562a103312..2d94d5a7a051 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1203,7 +1203,6 @@ static struct dst_entry *icmp6_dst_gc_list; static DEFINE_SPINLOCK(icmp6_dst_lock); struct dst_entry *icmp6_dst_alloc(struct net_device *dev, - struct neighbour *neigh, struct flowi6 *fl6) { struct dst_entry *dst; -- cgit v1.2.3 From 115b0aa6b444e8dd89b7f67b77b8c472763fbc1a Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Fri, 18 Jan 2013 02:05:03 +0000 Subject: ndisc: Check NS message length before access. Check message length before accessing "target" field, as we do for other types. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 429622d74705..350f86005c13 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -671,6 +671,11 @@ static void ndisc_recv_ns(struct sk_buff *skb) bool inc; int is_router = -1; + if (skb->len < sizeof(struct nd_msg)) { + ND_PRINTK(2, warn, "NS: packet too short\n"); + return; + } + if (ipv6_addr_is_multicast(&msg->target)) { ND_PRINTK(2, warn, "NS: multicast target address\n"); return; -- cgit v1.2.3 From ca97a644d752b46e5e08526e36705c3b0dd03f5f Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Sun, 20 Jan 2013 07:39:00 +0000 Subject: ipv6: Introduce ipv6_addr_is_solict_mult() to check Solicited Node Multicast Addresses. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- include/net/addrconf.h | 8 ++++++++ net/ipv6/ndisc.c | 6 +----- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/include/net/addrconf.h b/include/net/addrconf.h index c6a44213fc74..3a3eeb407f4b 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -305,6 +305,14 @@ static inline bool ipv6_addr_is_isatap(const struct in6_addr *addr) return (addr->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE); } +static inline bool ipv6_addr_is_solict_mult(const struct in6_addr *addr) +{ + return (addr->s6_addr32[0] == htonl(0xff020000) && + addr->s6_addr32[1] == htonl(0x00000000) && + addr->s6_addr32[2] == htonl(0x00000001) && + addr->s6_addr[12] == 0xff); +} + #ifdef CONFIG_PROC_FS extern int if6_proc_init(void); extern void if6_proc_exit(void); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 350f86005c13..903191adb5ca 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -685,11 +685,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 (dad && - !(daddr->s6_addr32[0] == htonl(0xff020000) && - daddr->s6_addr32[1] == htonl(0x00000000) && - daddr->s6_addr32[2] == htonl(0x00000001) && - daddr->s6_addr [12] == 0xff )) { + if (dad && !ipv6_addr_is_solict_mult(daddr)) { ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n"); return; } -- cgit v1.2.3 From fb568637e58a8459edd551af1160f27ea53e8367 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Sun, 20 Jan 2013 07:39:18 +0000 Subject: ndisc: Make several arguments for ndisc_send_na() boolean. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 903191adb5ca..067a0d2eb557 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -490,7 +490,7 @@ static void __ndisc_send(struct net_device *dev, static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, const struct in6_addr *daddr, const struct in6_addr *solicited_addr, - int router, int solicited, int override, int inc_opt) + bool router, bool solicited, bool override, bool inc_opt) { struct in6_addr tmpaddr; struct inet6_ifaddr *ifp; @@ -776,11 +776,11 @@ static void ndisc_recv_ns(struct sk_buff *skb) } if (is_router < 0) - is_router = !!idev->cnf.forwarding; + is_router = idev->cnf.forwarding; if (dad) { ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target, - is_router, 0, (ifp != NULL), 1); + !!is_router, false, (ifp != NULL), true); goto out; } @@ -801,8 +801,8 @@ static void ndisc_recv_ns(struct sk_buff *skb) NEIGH_UPDATE_F_OVERRIDE); if (neigh || !dev->header_ops) { ndisc_send_na(dev, neigh, saddr, &msg->target, - is_router, - 1, (ifp != NULL && inc), inc); + !!is_router, + true, (ifp != NULL && inc), inc); if (neigh) neigh_release(neigh); } -- cgit v1.2.3 From 315ff09dbaebc6061948102d7ed8781d4ee46f36 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 21 Jan 2013 06:47:50 +0000 Subject: ndisc: Reduce number of arguments for ndisc_fill_addr_option(). Add pointer to struct net_device (dev) and remove data_len (= dev->addr_len) and addr_type (= dev->type). Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 067a0d2eb557..49dfc2a73ee0 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -148,10 +148,11 @@ static inline int ndisc_opt_addr_space(struct net_device *dev) return NDISC_OPT_SPACE(dev->addr_len + ndisc_addr_option_pad(dev->type)); } -static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len, - unsigned short addr_type) +static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, + struct net_device *dev) { - int pad = ndisc_addr_option_pad(addr_type); + int pad = ndisc_addr_option_pad(dev->type); + int data_len = dev->addr_len; int space = NDISC_OPT_SPACE(data_len + pad); opt[0] = type; @@ -420,8 +421,7 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev, } if (llinfo) - ndisc_fill_addr_option(opt, llinfo, dev->dev_addr, - dev->addr_len, dev->type); + ndisc_fill_addr_option(opt, llinfo, dev->dev_addr, dev); hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, len, IPPROTO_ICMPV6, @@ -1469,8 +1469,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) */ if (ha) - opt = ndisc_fill_addr_option(opt, ND_OPT_TARGET_LL_ADDR, ha, - dev->addr_len, dev->type); + opt = ndisc_fill_addr_option(opt, ND_OPT_TARGET_LL_ADDR, ha, dev); /* * build redirect option and copy skb over to the new packet. -- cgit v1.2.3 From c558e9fca876d6d0463a7c337d2291774b9c6f96 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 21 Jan 2013 06:47:56 +0000 Subject: ndisc: Move ndisc_opt_addr_space() to include/net/ndisc.h. This also makes ndisc_opt_addr_data() and ndisc_fill_addr_option() use ndisc_opt_addr_space(). Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- include/net/ndisc.h | 8 +++++++- net/ipv6/ndisc.c | 7 +------ 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/include/net/ndisc.h b/include/net/ndisc.h index ec48f42db5ed..745bf741e029 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -127,13 +127,19 @@ static int ndisc_addr_option_pad(unsigned short type) } } +static inline int ndisc_opt_addr_space(struct net_device *dev) +{ + return NDISC_OPT_SPACE(dev->addr_len + + ndisc_addr_option_pad(dev->type)); +} + static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p, struct net_device *dev) { u8 *lladdr = (u8 *)(p + 1); int lladdrlen = p->nd_opt_len << 3; int prepad = ndisc_addr_option_pad(dev->type); - if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len + prepad)) + if (lladdrlen != ndisc_opt_addr_space(dev)) return NULL; return lladdr + prepad; } diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 49dfc2a73ee0..82ccf0a43063 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -143,17 +143,12 @@ struct neigh_table nd_tbl = { .gc_thresh3 = 1024, }; -static inline int ndisc_opt_addr_space(struct net_device *dev) -{ - return NDISC_OPT_SPACE(dev->addr_len + ndisc_addr_option_pad(dev->type)); -} - static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, struct net_device *dev) { int pad = ndisc_addr_option_pad(dev->type); int data_len = dev->addr_len; - int space = NDISC_OPT_SPACE(data_len + pad); + int space = ndisc_opt_addr_space(dev); opt[0] = type; opt[1] = space>>3; -- cgit v1.2.3 From 6bce6b4e16e46cc860175b9e10a283194ef9f004 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 21 Jan 2013 06:48:03 +0000 Subject: ndisc: Use skb_linearize() instead of pskb_may_pull(skb, skb->len). Suggested by Eric Dumazet . Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 82ccf0a43063..539b2ec37d3a 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1509,7 +1509,7 @@ int ndisc_rcv(struct sk_buff *skb) { struct nd_msg *msg; - if (!pskb_may_pull(skb, skb->len)) + if (skb_linearize(skb)) return 0; msg = (struct nd_msg *)skb_transport_header(skb); -- cgit v1.2.3 From 9c86dafe94f03679b77d85915e65da1304005a7c Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 21 Jan 2013 06:48:09 +0000 Subject: ndisc: Introduce ndisc_fill_redirect_hdr_option(). Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 539b2ec37d3a..53a545f32625 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1341,6 +1341,19 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) icmpv6_notify(skb, NDISC_REDIRECT, 0, 0); } +static u8 *ndisc_fill_redirect_hdr_option(u8 *opt, struct sk_buff *orig_skb, + int rd_len) +{ + memset(opt, 0, 8); + *(opt++) = ND_OPT_REDIRECT_HDR; + *(opt++) = (rd_len >> 3); + opt += 6; + + memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8); + + return opt + rd_len - 8; +} + void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) { struct net_device *dev = skb->dev; @@ -1470,12 +1483,8 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) * build redirect option and copy skb over to the new packet. */ - memset(opt, 0, 8); - *(opt++) = ND_OPT_REDIRECT_HDR; - *(opt++) = (rd_len >> 3); - opt += 6; - - memcpy(opt, ipv6_hdr(skb), rd_len - 8); + if (rd_len) + opt = ndisc_fill_redirect_hdr_option(opt, skb, rd_len); msg->icmph.icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr, len, IPPROTO_ICMPV6, -- cgit v1.2.3 From de09334b9326632bbf1a74bfd8b01866cbbf2f61 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 21 Jan 2013 06:48:14 +0000 Subject: ndisc: Introduce ndisc_alloc_skb() helper. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 52 +++++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 25 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 53a545f32625..1776a0deee7f 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -366,6 +366,29 @@ static void pndisc_destructor(struct pneigh_entry *n) ipv6_dev_mc_dec(dev, &maddr); } +static struct sk_buff *ndisc_alloc_skb(struct net_device *dev, + int len) +{ + int hlen = LL_RESERVED_SPACE(dev); + int tlen = dev->needed_tailroom; + struct sock *sk = dev_net(dev)->ipv6.ndisc_sk; + struct sk_buff *skb; + int err; + + skb = sock_alloc_send_skb(sk, + hlen + sizeof(struct ipv6hdr) + len + tlen, + 1, &err); + if (!skb) { + ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb, err=%d\n", + __func__, err); + return NULL; + } + + skb_reserve(skb, hlen); + + return skb; +} + static struct sk_buff *ndisc_build_skb(struct net_device *dev, const struct in6_addr *daddr, const struct in6_addr *saddr, @@ -377,10 +400,7 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev, struct sock *sk = net->ipv6.ndisc_sk; struct sk_buff *skb; struct icmp6hdr *hdr; - int hlen = LL_RESERVED_SPACE(dev); - int tlen = dev->needed_tailroom; int len; - int err; u8 *opt; if (!dev->addr_len) @@ -390,17 +410,10 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev, if (llinfo) len += ndisc_opt_addr_space(dev); - skb = sock_alloc_send_skb(sk, - (sizeof(struct ipv6hdr) + - len + hlen + tlen), - 1, &err); - if (!skb) { - ND_PRINTK(0, err, "ND: %s failed to allocate an skb, err=%d\n", - __func__, err); + skb = ndisc_alloc_skb(dev, len); + if (!skb) return NULL; - } - skb_reserve(skb, hlen); ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len); skb->transport_header = skb->tail; @@ -1369,7 +1382,6 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) struct inet6_dev *idev; struct flowi6 fl6; u8 *opt; - int hlen, tlen; int rd_len; int err; u8 ha_buf[MAX_ADDR_LEN], *ha = NULL; @@ -1439,20 +1451,10 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) rd_len &= ~0x7; len += rd_len; - hlen = LL_RESERVED_SPACE(dev); - tlen = dev->needed_tailroom; - buff = sock_alloc_send_skb(sk, - (sizeof(struct ipv6hdr) + - len + hlen + tlen), - 1, &err); - if (buff == NULL) { - ND_PRINTK(0, err, - "Redirect: %s failed to allocate an skb, err=%d\n", - __func__, err); + buff = ndisc_alloc_skb(dev, len); + if (!buff) goto release; - } - skb_reserve(buff, hlen); ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr, IPPROTO_ICMPV6, len); -- cgit v1.2.3 From 2576f17dfad402e2446244238ed22dddf35c2e53 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 21 Jan 2013 06:48:19 +0000 Subject: ipv6: Unshare ip6_nd_hdr() and change return type to void. - move ip6_nd_hdr() to its users' source files. In net/ipv6/mcast.c, it will be called ip6_mc_hdr(). - make return type to void since this function never fails. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- include/net/ipv6.h | 7 ------- net/ipv6/ip6_output.c | 33 --------------------------------- net/ipv6/mcast.c | 29 +++++++++++++++++++++++++++-- net/ipv6/ndisc.c | 25 +++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 42 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 464c6f70eca1..c1878f7049c8 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -661,13 +661,6 @@ extern int ip6_xmit(struct sock *sk, struct ipv6_txoptions *opt, int tclass); -extern int ip6_nd_hdr(struct sock *sk, - struct sk_buff *skb, - struct net_device *dev, - const struct in6_addr *saddr, - const struct in6_addr *daddr, - int proto, int len); - extern int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr); extern int ip6_append_data(struct sock *sk, diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index b0895f5d5fc6..7eee94c27f8d 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -254,39 +254,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, EXPORT_SYMBOL(ip6_xmit); -/* - * To avoid extra problems ND packets are send through this - * routine. It's code duplication but I really want to avoid - * extra checks since ipv6_build_header is used by TCP (which - * is for us performance critical) - */ - -int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev, - const struct in6_addr *saddr, const struct in6_addr *daddr, - int proto, int len) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct ipv6hdr *hdr; - - skb->protocol = htons(ETH_P_IPV6); - skb->dev = dev; - - skb_reset_network_header(skb); - skb_put(skb, sizeof(struct ipv6hdr)); - hdr = ipv6_hdr(skb); - - ip6_flow_hdr(hdr, 0, 0); - - hdr->payload_len = htons(len); - hdr->nexthdr = proto; - hdr->hop_limit = np->hop_limit; - - hdr->saddr = *saddr; - hdr->daddr = *daddr; - - return 0; -} - static int ip6_call_ra_chain(struct sk_buff *skb, int sel) { struct ip6_ra_chain *ra; diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 587a84530a57..f25002aaf624 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1313,6 +1313,31 @@ mld_scount(struct ifmcaddr6 *pmc, int type, int gdeleted, int sdeleted) return scount; } +static void ip6_mc_hdr(struct sock *sk, struct sk_buff *skb, + struct net_device *dev, + const struct in6_addr *saddr, + const struct in6_addr *daddr, + int proto, int len) +{ + struct ipv6hdr *hdr; + + skb->protocol = htons(ETH_P_IPV6); + skb->dev = dev; + + skb_reset_network_header(skb); + skb_put(skb, sizeof(struct ipv6hdr)); + hdr = ipv6_hdr(skb); + + ip6_flow_hdr(hdr, 0, 0); + + hdr->payload_len = htons(len); + hdr->nexthdr = proto; + hdr->hop_limit = inet6_sk(sk)->hop_limit; + + hdr->saddr = *saddr; + hdr->daddr = *daddr; +} + static struct sk_buff *mld_newpack(struct net_device *dev, int size) { struct net *net = dev_net(dev); @@ -1348,7 +1373,7 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) } else saddr = &addr_buf; - ip6_nd_hdr(sk, skb, dev, saddr, &mld2_all_mcr, NEXTHDR_HOP, 0); + ip6_mc_hdr(sk, skb, dev, saddr, &mld2_all_mcr, NEXTHDR_HOP, 0); memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); @@ -1740,7 +1765,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) } else saddr = &addr_buf; - ip6_nd_hdr(sk, skb, dev, saddr, snd_addr, NEXTHDR_HOP, payload_len); + ip6_mc_hdr(sk, skb, dev, saddr, snd_addr, NEXTHDR_HOP, payload_len); memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 1776a0deee7f..7ce266f34cc7 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -389,6 +389,31 @@ static struct sk_buff *ndisc_alloc_skb(struct net_device *dev, return skb; } +static void ip6_nd_hdr(struct sock *sk, + struct sk_buff *skb, struct net_device *dev, + const struct in6_addr *saddr, + const struct in6_addr *daddr, + int proto, int len) +{ + struct ipv6hdr *hdr; + + skb->protocol = htons(ETH_P_IPV6); + skb->dev = dev; + + skb_reset_network_header(skb); + skb_put(skb, sizeof(struct ipv6hdr)); + hdr = ipv6_hdr(skb); + + ip6_flow_hdr(hdr, 0, 0); + + hdr->payload_len = htons(len); + hdr->nexthdr = proto; + hdr->hop_limit = inet6_sk(sk)->hop_limit; + + hdr->saddr = *saddr; + hdr->daddr = *daddr; +} + static struct sk_buff *ndisc_build_skb(struct net_device *dev, const struct in6_addr *daddr, const struct in6_addr *saddr, -- cgit v1.2.3 From c8d6c380d9463e1405d821db7071e39f63acfb28 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 21 Jan 2013 06:48:24 +0000 Subject: ndisc: Simplify arguments for ip6_nd_hdr(). Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 7ce266f34cc7..05c69964f356 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -389,11 +389,10 @@ static struct sk_buff *ndisc_alloc_skb(struct net_device *dev, return skb; } -static void ip6_nd_hdr(struct sock *sk, - struct sk_buff *skb, struct net_device *dev, +static void ip6_nd_hdr(struct sk_buff *skb, struct net_device *dev, const struct in6_addr *saddr, const struct in6_addr *daddr, - int proto, int len) + int hop_limit, int len) { struct ipv6hdr *hdr; @@ -407,8 +406,8 @@ static void ip6_nd_hdr(struct sock *sk, ip6_flow_hdr(hdr, 0, 0); hdr->payload_len = htons(len); - hdr->nexthdr = proto; - hdr->hop_limit = inet6_sk(sk)->hop_limit; + hdr->nexthdr = IPPROTO_ICMPV6; + hdr->hop_limit = hop_limit; hdr->saddr = *saddr; hdr->daddr = *daddr; @@ -439,7 +438,7 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev, if (!skb) return NULL; - ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len); + ip6_nd_hdr(skb, dev, saddr, daddr, inet6_sk(sk)->hop_limit, len); skb->transport_header = skb->tail; skb_put(skb, len); @@ -1480,8 +1479,8 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) if (!buff) goto release; - ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr, - IPPROTO_ICMPV6, len); + ip6_nd_hdr(buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr, + inet6_sk(sk)->hop_limit, len); skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data); skb_put(buff, len); -- cgit v1.2.3 From f382d03ad003815be6dc268711659d4475fb7d28 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 21 Jan 2013 06:48:29 +0000 Subject: ndisc: Set skb->dev and skb->protocol inside ndisc_alloc_skb(). Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 05c69964f356..ed3ba8eb9505 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -384,21 +384,21 @@ static struct sk_buff *ndisc_alloc_skb(struct net_device *dev, return NULL; } + skb->protocol = htons(ETH_P_IPV6); + skb->dev = dev; + skb_reserve(skb, hlen); return skb; } -static void ip6_nd_hdr(struct sk_buff *skb, struct net_device *dev, +static void ip6_nd_hdr(struct sk_buff *skb, const struct in6_addr *saddr, const struct in6_addr *daddr, int hop_limit, int len) { struct ipv6hdr *hdr; - skb->protocol = htons(ETH_P_IPV6); - skb->dev = dev; - skb_reset_network_header(skb); skb_put(skb, sizeof(struct ipv6hdr)); hdr = ipv6_hdr(skb); @@ -438,7 +438,7 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev, if (!skb) return NULL; - ip6_nd_hdr(skb, dev, saddr, daddr, inet6_sk(sk)->hop_limit, len); + ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, len); skb->transport_header = skb->tail; skb_put(skb, len); @@ -1479,7 +1479,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) if (!buff) goto release; - ip6_nd_hdr(buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr, + ip6_nd_hdr(buff, &saddr_buf, &ipv6_hdr(skb)->saddr, inet6_sk(sk)->hop_limit, len); skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data); -- cgit v1.2.3 From af9a997629488ba5f92dc3d76e1ec51fcd759c5d Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 21 Jan 2013 06:48:34 +0000 Subject: ndisc: Remove dev argument for ndisc_send_skb(). Since we have skb->dev, use it. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index ed3ba8eb9505..200b2b22b9ba 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -463,14 +463,14 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev, return skb; } -static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev, +static void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr, const struct in6_addr *saddr, struct icmp6hdr *icmp6h) { struct flowi6 fl6; struct dst_entry *dst; - struct net *net = dev_net(dev); + struct net *net = dev_net(skb->dev); struct sock *sk = net->ipv6.ndisc_sk; struct inet6_dev *idev; int err; @@ -478,8 +478,8 @@ static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev, type = icmp6h->icmp6_type; - icmpv6_flow_init(sk, &fl6, type, saddr, daddr, dev->ifindex); - dst = icmp6_dst_alloc(dev, &fl6); + icmpv6_flow_init(sk, &fl6, type, saddr, daddr, skb->dev->ifindex); + dst = icmp6_dst_alloc(skb->dev, &fl6); if (IS_ERR(dst)) { kfree_skb(skb); return; @@ -516,7 +516,7 @@ static void __ndisc_send(struct net_device *dev, if (!skb) return; - ndisc_send_skb(skb, dev, daddr, saddr, icmp6h); + ndisc_send_skb(skb, daddr, saddr, icmp6h); } static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, -- cgit v1.2.3 From 527a150fb2292a59ca0545dace8d482581253532 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 21 Jan 2013 06:48:39 +0000 Subject: ndisc: Defer building IPv6 header. Build ICMPv6 message first and make buffer management easier; we can use skb->len when filling checksum in ICMPv6 header, and then build IP header with length field. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 200b2b22b9ba..09171fdbc312 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -387,7 +387,7 @@ static struct sk_buff *ndisc_alloc_skb(struct net_device *dev, skb->protocol = htons(ETH_P_IPV6); skb->dev = dev; - skb_reserve(skb, hlen); + skb_reserve(skb, hlen + sizeof(struct ipv6hdr)); return skb; } @@ -399,8 +399,8 @@ static void ip6_nd_hdr(struct sk_buff *skb, { struct ipv6hdr *hdr; + skb_push(skb, sizeof(*hdr)); skb_reset_network_header(skb); - skb_put(skb, sizeof(struct ipv6hdr)); hdr = ipv6_hdr(skb); ip6_flow_hdr(hdr, 0, 0); @@ -438,8 +438,6 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev, if (!skb) return NULL; - ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, len); - skb->transport_header = skb->tail; skb_put(skb, len); @@ -455,10 +453,12 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev, if (llinfo) ndisc_fill_addr_option(opt, llinfo, dev->dev_addr, dev); - hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, len, + hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, csum_partial(hdr, - len, 0)); + skb->len, 0)); + + ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len); return skb; } @@ -1479,9 +1479,6 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) if (!buff) goto release; - ip6_nd_hdr(buff, &saddr_buf, &ipv6_hdr(skb)->saddr, - inet6_sk(sk)->hop_limit, len); - skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data); skb_put(buff, len); msg = (struct rd_msg *)icmp6_hdr(buff); @@ -1513,8 +1510,11 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) opt = ndisc_fill_redirect_hdr_option(opt, skb, rd_len); msg->icmph.icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr, - len, IPPROTO_ICMPV6, - csum_partial(msg, len, 0)); + buff->len, IPPROTO_ICMPV6, + csum_partial(msg, buff->len, 0)); + + ip6_nd_hdr(buff, &saddr_buf, &ipv6_hdr(skb)->saddr, + inet6_sk(sk)->hop_limit, buff->len); skb_dst_set(buff, dst); rcu_read_lock(); -- cgit v1.2.3 From 5135e633f92ab4deb3600a30cbbec6e0929fc8a4 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 21 Jan 2013 06:48:44 +0000 Subject: ndisc: Reset skb->trasport_headner inside ndisc_alloc_send_skb(). Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 09171fdbc312..62b1415bec25 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -388,6 +388,7 @@ static struct sk_buff *ndisc_alloc_skb(struct net_device *dev, skb->dev = dev; skb_reserve(skb, hlen + sizeof(struct ipv6hdr)); + skb_reset_transport_header(skb); return skb; } @@ -438,7 +439,6 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev, if (!skb) return NULL; - skb->transport_header = skb->tail; skb_put(skb, len); hdr = (struct icmp6hdr *)skb_transport_header(skb); @@ -1479,7 +1479,6 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) if (!buff) goto release; - skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data); skb_put(buff, len); msg = (struct rd_msg *)icmp6_hdr(buff); -- cgit v1.2.3 From 2ce13576144ade3e9340efce9620a6dd338aedc7 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 21 Jan 2013 06:48:49 +0000 Subject: ndisc: Calculate message body length and option length separately. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 62b1415bec25..c2b16ffeb1a8 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -426,6 +426,7 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev, struct sk_buff *skb; struct icmp6hdr *hdr; int len; + int optlen = 0; u8 *opt; if (!dev->addr_len) @@ -433,13 +434,13 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev, len = sizeof(struct icmp6hdr) + (target ? sizeof(*target) : 0); if (llinfo) - len += ndisc_opt_addr_space(dev); + optlen += ndisc_opt_addr_space(dev); - skb = ndisc_alloc_skb(dev, len); + skb = ndisc_alloc_skb(dev, len + optlen); if (!skb) return NULL; - skb_put(skb, len); + skb_put(skb, len + optlen); hdr = (struct icmp6hdr *)skb_transport_header(skb); memcpy(hdr, icmp6h, sizeof(*hdr)); @@ -1396,7 +1397,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) struct net_device *dev = skb->dev; struct net *net = dev_net(dev); struct sock *sk = net->ipv6.ndisc_sk; - int len = sizeof(struct rd_msg); + int optlen = 0; struct inet_peer *peer; struct sk_buff *buff; struct rd_msg *msg; @@ -1463,7 +1464,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) memcpy(ha_buf, neigh->ha, dev->addr_len); read_unlock_bh(&neigh->lock); ha = ha_buf; - len += ndisc_opt_addr_space(dev); + optlen += ndisc_opt_addr_space(dev); } else read_unlock_bh(&neigh->lock); @@ -1471,15 +1472,16 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) } rd_len = min_t(unsigned int, - IPV6_MIN_MTU-sizeof(struct ipv6hdr)-len, skb->len + 8); + IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen, + skb->len + 8); rd_len &= ~0x7; - len += rd_len; + optlen += rd_len; - buff = ndisc_alloc_skb(dev, len); + buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); if (!buff) goto release; - skb_put(buff, len); + skb_put(buff, sizeof(*msg) + optlen); msg = (struct rd_msg *)icmp6_hdr(buff); memset(&msg->icmph, 0, sizeof(struct icmp6hdr)); -- cgit v1.2.3 From 5f5a0115635bf678d267cbc72169a718e8724d03 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 21 Jan 2013 06:48:53 +0000 Subject: ndisc: Make ndisc_fill_xxx_option() for sk_buff. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index c2b16ffeb1a8..ed786441bc51 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -143,12 +143,12 @@ struct neigh_table nd_tbl = { .gc_thresh3 = 1024, }; -static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, - struct net_device *dev) +static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data) { - int pad = ndisc_addr_option_pad(dev->type); - int data_len = dev->addr_len; - int space = ndisc_opt_addr_space(dev); + int pad = ndisc_addr_option_pad(skb->dev->type); + int data_len = skb->dev->addr_len; + int space = ndisc_opt_addr_space(skb->dev); + u8 *opt = skb_put(skb, space); opt[0] = type; opt[1] = space>>3; @@ -162,7 +162,6 @@ static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, opt += data_len; if ((space -= data_len) > 0) memset(opt, 0, space); - return opt + space; } static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, @@ -440,7 +439,7 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev, if (!skb) return NULL; - skb_put(skb, len + optlen); + skb_put(skb, len); hdr = (struct icmp6hdr *)skb_transport_header(skb); memcpy(hdr, icmp6h, sizeof(*hdr)); @@ -452,7 +451,7 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev, } if (llinfo) - ndisc_fill_addr_option(opt, llinfo, dev->dev_addr, dev); + ndisc_fill_addr_option(skb, llinfo, dev->dev_addr); hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, @@ -1379,17 +1378,18 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) icmpv6_notify(skb, NDISC_REDIRECT, 0, 0); } -static u8 *ndisc_fill_redirect_hdr_option(u8 *opt, struct sk_buff *orig_skb, - int rd_len) +static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb, + struct sk_buff *orig_skb, + int rd_len) { + u8 *opt = skb_put(skb, rd_len); + memset(opt, 0, 8); *(opt++) = ND_OPT_REDIRECT_HDR; *(opt++) = (rd_len >> 3); opt += 6; memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8); - - return opt + rd_len - 8; } void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) @@ -1406,7 +1406,6 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) struct dst_entry *dst; struct inet6_dev *idev; struct flowi6 fl6; - u8 *opt; int rd_len; int err; u8 ha_buf[MAX_ADDR_LEN], *ha = NULL; @@ -1481,7 +1480,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) if (!buff) goto release; - skb_put(buff, sizeof(*msg) + optlen); + skb_put(buff, sizeof(*msg)); msg = (struct rd_msg *)icmp6_hdr(buff); memset(&msg->icmph, 0, sizeof(struct icmp6hdr)); @@ -1494,21 +1493,19 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) msg->target = *target; msg->dest = ipv6_hdr(skb)->daddr; - opt = msg->opt; - /* * include target_address option */ if (ha) - opt = ndisc_fill_addr_option(opt, ND_OPT_TARGET_LL_ADDR, ha, dev); + ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, ha); /* * build redirect option and copy skb over to the new packet. */ if (rd_len) - opt = ndisc_fill_redirect_hdr_option(opt, skb, rd_len); + ndisc_fill_redirect_hdr_option(buff, skb, rd_len); msg->icmph.icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr, buff->len, IPPROTO_ICMPV6, -- cgit v1.2.3 From aa4bdd4b3f43274252c1280f6464850b0f004fc8 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 21 Jan 2013 06:48:58 +0000 Subject: ndisc: Remove icmp6h argument from ndisc_send_skb(). skb_transport_header() (thus icmp6_hdr()) is available here, use it. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index ed786441bc51..f0c436b49255 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -465,8 +465,7 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev, static void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr, - const struct in6_addr *saddr, - struct icmp6hdr *icmp6h) + const struct in6_addr *saddr) { struct flowi6 fl6; struct dst_entry *dst; @@ -474,6 +473,7 @@ static void ndisc_send_skb(struct sk_buff *skb, struct sock *sk = net->ipv6.ndisc_sk; struct inet6_dev *idev; int err; + struct icmp6hdr *icmp6h = icmp6_hdr(skb); u8 type; type = icmp6h->icmp6_type; @@ -516,7 +516,7 @@ static void __ndisc_send(struct net_device *dev, if (!skb) return; - ndisc_send_skb(skb, daddr, saddr, icmp6h); + ndisc_send_skb(skb, daddr, saddr); } static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, -- cgit v1.2.3 From f4de84c64e3d801965ee4c6dadd19b76b9424bbf Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 21 Jan 2013 06:49:03 +0000 Subject: ndisc: Use ndisc_send_skb() for redirect. Reuse dst if one is attached with skb. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index f0c436b49255..437781c2af41 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -467,10 +467,8 @@ static void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr, const struct in6_addr *saddr) { - struct flowi6 fl6; - struct dst_entry *dst; + struct dst_entry *dst = skb_dst(skb); struct net *net = dev_net(skb->dev); - struct sock *sk = net->ipv6.ndisc_sk; struct inet6_dev *idev; int err; struct icmp6hdr *icmp6h = icmp6_hdr(skb); @@ -478,14 +476,19 @@ static void ndisc_send_skb(struct sk_buff *skb, type = icmp6h->icmp6_type; - icmpv6_flow_init(sk, &fl6, type, saddr, daddr, skb->dev->ifindex); - dst = icmp6_dst_alloc(skb->dev, &fl6); - if (IS_ERR(dst)) { - kfree_skb(skb); - return; - } + if (!dst) { + struct sock *sk = net->ipv6.ndisc_sk; + struct flowi6 fl6; - skb_dst_set(skb, dst); + icmpv6_flow_init(sk, &fl6, type, saddr, daddr, skb->dev->ifindex); + dst = icmp6_dst_alloc(skb->dev, &fl6); + if (IS_ERR(dst)) { + kfree_skb(skb); + return; + } + + skb_dst_set(skb, dst); + } rcu_read_lock(); idev = __in6_dev_get(dst->dev); @@ -1404,10 +1407,8 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) struct in6_addr saddr_buf; struct rt6_info *rt; struct dst_entry *dst; - struct inet6_dev *idev; struct flowi6 fl6; int rd_len; - int err; u8 ha_buf[MAX_ADDR_LEN], *ha = NULL; bool ret; @@ -1515,17 +1516,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) inet6_sk(sk)->hop_limit, buff->len); skb_dst_set(buff, dst); - rcu_read_lock(); - idev = __in6_dev_get(dst->dev); - IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); - err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev, - dst_output); - if (!err) { - ICMP6MSGOUT_INC_STATS(net, idev, NDISC_REDIRECT); - ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); - } - - rcu_read_unlock(); + ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf); return; release: -- cgit v1.2.3 From 7b3d9b06d8b6407fe25e00e627b48ec0d4a2a076 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 21 Jan 2013 06:49:08 +0000 Subject: ndisc: Fill in ICMPv6 checksum and IPv6 header in ndisc_send_skb(). Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 437781c2af41..dda4addf2919 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -420,8 +420,6 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev, const struct in6_addr *target, int llinfo) { - struct net *net = dev_net(dev); - struct sock *sk = net->ipv6.ndisc_sk; struct sk_buff *skb; struct icmp6hdr *hdr; int len; @@ -453,13 +451,6 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev, if (llinfo) ndisc_fill_addr_option(skb, llinfo, dev->dev_addr); - hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len, - IPPROTO_ICMPV6, - csum_partial(hdr, - skb->len, 0)); - - ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len); - return skb; } @@ -469,6 +460,7 @@ static void ndisc_send_skb(struct sk_buff *skb, { struct dst_entry *dst = skb_dst(skb); struct net *net = dev_net(skb->dev); + struct sock *sk = net->ipv6.ndisc_sk; struct inet6_dev *idev; int err; struct icmp6hdr *icmp6h = icmp6_hdr(skb); @@ -490,6 +482,13 @@ static void ndisc_send_skb(struct sk_buff *skb, skb_dst_set(skb, dst); } + icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len, + IPPROTO_ICMPV6, + csum_partial(icmp6h, + skb->len, 0)); + + ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len); + rcu_read_lock(); idev = __in6_dev_get(dst->dev); IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); @@ -1508,13 +1507,6 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) if (rd_len) ndisc_fill_redirect_hdr_option(buff, skb, rd_len); - msg->icmph.icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr, - buff->len, IPPROTO_ICMPV6, - csum_partial(msg, buff->len, 0)); - - ip6_nd_hdr(buff, &saddr_buf, &ipv6_hdr(skb)->saddr, - inet6_sk(sk)->hop_limit, buff->len); - skb_dst_set(buff, dst); ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf); return; -- cgit v1.2.3 From b44b5f4ae96de87e458ef73fc01e7ec0dbac10c0 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 21 Jan 2013 06:49:13 +0000 Subject: ndisc: Break down __ndisc_send(). Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index dda4addf2919..79a56a7663b7 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -503,29 +503,12 @@ static void ndisc_send_skb(struct sk_buff *skb, rcu_read_unlock(); } -/* - * Send a Neighbour Discover packet - */ -static void __ndisc_send(struct net_device *dev, - const struct in6_addr *daddr, - const struct in6_addr *saddr, - struct icmp6hdr *icmp6h, const struct in6_addr *target, - int llinfo) -{ - struct sk_buff *skb; - - skb = ndisc_build_skb(dev, daddr, saddr, icmp6h, target, llinfo); - if (!skb) - return; - - ndisc_send_skb(skb, daddr, saddr); -} - static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, const struct in6_addr *daddr, const struct in6_addr *solicited_addr, bool router, bool solicited, bool override, bool inc_opt) { + struct sk_buff *skb; struct in6_addr tmpaddr; struct inet6_ifaddr *ifp; const struct in6_addr *src_addr; @@ -553,8 +536,12 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, icmp6h.icmp6_solicited = solicited; icmp6h.icmp6_override = override; - __ndisc_send(dev, daddr, src_addr, &icmp6h, solicited_addr, - inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); + skb = ndisc_build_skb(dev, daddr, src_addr, &icmp6h, solicited_addr, + inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); + if (!skb) + return; + + ndisc_send_skb(skb, daddr, src_addr); } static void ndisc_send_unsol_na(struct net_device *dev) @@ -582,6 +569,7 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, const struct in6_addr *solicit, const struct in6_addr *daddr, const struct in6_addr *saddr) { + struct sk_buff *skb; struct in6_addr addr_buf; struct icmp6hdr icmp6h = { .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION, @@ -594,13 +582,18 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, saddr = &addr_buf; } - __ndisc_send(dev, daddr, saddr, &icmp6h, solicit, - !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0); + skb = ndisc_build_skb(dev, daddr, saddr, &icmp6h, solicit, + !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0); + if (!skb) + return; + + ndisc_send_skb(skb, daddr, saddr); } void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, const struct in6_addr *daddr) { + struct sk_buff *skb; struct icmp6hdr icmp6h = { .icmp6_type = NDISC_ROUTER_SOLICITATION, }; @@ -628,8 +621,12 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, } } #endif - __ndisc_send(dev, daddr, saddr, &icmp6h, NULL, - send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0); + skb = ndisc_build_skb(dev, daddr, saddr, &icmp6h, NULL, + send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0); + if (!skb) + return; + + ndisc_send_skb(skb, daddr, saddr); } -- cgit v1.2.3 From 1cb3fe513f62ca7c5963d551e01d75aa4f6ca72a Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 21 Jan 2013 06:49:17 +0000 Subject: ndisc: Break down ndisc_build_skb() and build message directly. Construct NS/NA/RS message directly using C99 compound literals. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 122 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 63 insertions(+), 59 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 79a56a7663b7..1c015665ce71 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -413,47 +413,6 @@ static void ip6_nd_hdr(struct sk_buff *skb, hdr->daddr = *daddr; } -static struct sk_buff *ndisc_build_skb(struct net_device *dev, - const struct in6_addr *daddr, - const struct in6_addr *saddr, - struct icmp6hdr *icmp6h, - const struct in6_addr *target, - int llinfo) -{ - struct sk_buff *skb; - struct icmp6hdr *hdr; - int len; - int optlen = 0; - u8 *opt; - - if (!dev->addr_len) - llinfo = 0; - - len = sizeof(struct icmp6hdr) + (target ? sizeof(*target) : 0); - if (llinfo) - optlen += ndisc_opt_addr_space(dev); - - skb = ndisc_alloc_skb(dev, len + optlen); - if (!skb) - return NULL; - - skb_put(skb, len); - - hdr = (struct icmp6hdr *)skb_transport_header(skb); - memcpy(hdr, icmp6h, sizeof(*hdr)); - - opt = skb_transport_header(skb) + sizeof(struct icmp6hdr); - if (target) { - *(struct in6_addr *)opt = *target; - opt += sizeof(*target); - } - - if (llinfo) - ndisc_fill_addr_option(skb, llinfo, dev->dev_addr); - - return skb; -} - static void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr, const struct in6_addr *saddr) @@ -512,9 +471,8 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, struct in6_addr tmpaddr; struct inet6_ifaddr *ifp; const struct in6_addr *src_addr; - struct icmp6hdr icmp6h = { - .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, - }; + struct nd_msg *msg; + int optlen = 0; /* for anycast or proxy, solicited_addr != src_addr */ ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1); @@ -532,15 +490,31 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, src_addr = &tmpaddr; } - icmp6h.icmp6_router = router; - icmp6h.icmp6_solicited = solicited; - icmp6h.icmp6_override = override; + if (!dev->addr_len) + inc_opt = 0; + if (inc_opt) + optlen += ndisc_opt_addr_space(dev); - skb = ndisc_build_skb(dev, daddr, src_addr, &icmp6h, solicited_addr, - inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); + skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); if (!skb) return; + msg = (struct nd_msg *)skb_put(skb, sizeof(*msg)); + *msg = (struct nd_msg) { + .icmph = { + .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, + .icmp6_router = router, + .icmp6_solicited = solicited, + .icmp6_override = override, + }, + .target = *solicited_addr, + }; + + if (inc_opt) + ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, + dev->dev_addr); + + ndisc_send_skb(skb, daddr, src_addr); } @@ -571,9 +545,9 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, { struct sk_buff *skb; struct in6_addr addr_buf; - struct icmp6hdr icmp6h = { - .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION, - }; + int inc_opt = dev->addr_len; + int optlen = 0; + struct nd_msg *msg; if (saddr == NULL) { if (ipv6_get_lladdr(dev, &addr_buf, @@ -582,11 +556,27 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, saddr = &addr_buf; } - skb = ndisc_build_skb(dev, daddr, saddr, &icmp6h, solicit, - !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0); + if (ipv6_addr_any(saddr)) + inc_opt = 0; + if (inc_opt) + optlen += ndisc_opt_addr_space(dev); + + skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); if (!skb) return; + msg = (struct nd_msg *)skb_put(skb, sizeof(*msg)); + *msg = (struct nd_msg) { + .icmph = { + .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION, + }, + .target = *solicit, + }; + + if (inc_opt) + ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR, + dev->dev_addr); + ndisc_send_skb(skb, daddr, saddr); } @@ -594,10 +584,9 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, const struct in6_addr *daddr) { struct sk_buff *skb; - struct icmp6hdr icmp6h = { - .icmp6_type = NDISC_ROUTER_SOLICITATION, - }; + struct rs_msg *msg; int send_sllao = dev->addr_len; + int optlen = 0; #ifdef CONFIG_IPV6_OPTIMISTIC_DAD /* @@ -621,11 +610,26 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, } } #endif - skb = ndisc_build_skb(dev, daddr, saddr, &icmp6h, NULL, - send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0); + if (!dev->addr_len) + send_sllao = 0; + if (send_sllao) + optlen += ndisc_opt_addr_space(dev); + + skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); if (!skb) return; + msg = (struct rs_msg *)skb_put(skb, sizeof(*msg)); + *msg = (struct rs_msg) { + .icmph = { + .icmp6_type = NDISC_ROUTER_SOLICITATION, + }, + }; + + if (send_sllao) + ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR, + dev->dev_addr); + ndisc_send_skb(skb, daddr, saddr); } -- cgit v1.2.3 From 4d5c152e8694b57094e320060be4621dee5779dd Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 21 Jan 2013 06:49:25 +0000 Subject: ndisc: Use compound literals to build redirect message. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'net/ipv6/ndisc.c') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 1c015665ce71..76ef4353d518 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1481,18 +1481,14 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) if (!buff) goto release; - skb_put(buff, sizeof(*msg)); - msg = (struct rd_msg *)icmp6_hdr(buff); - - memset(&msg->icmph, 0, sizeof(struct icmp6hdr)); - msg->icmph.icmp6_type = NDISC_REDIRECT; - - /* - * copy target and destination addresses - */ - - msg->target = *target; - msg->dest = ipv6_hdr(skb)->daddr; + msg = (struct rd_msg *)skb_put(buff, sizeof(*msg)); + *msg = (struct rd_msg) { + .icmph = { + .icmp6_type = NDISC_REDIRECT, + }, + .target = *target, + .dest = ipv6_hdr(skb)->daddr, + }; /* * include target_address option -- cgit v1.2.3