From 315ff09dbaebc6061948102d7ed8781d4ee46f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Mon, 21 Jan 2013 06:47:50 +0000 Subject: [PATCH 01/19] 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(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 067a0d2eb5570..49dfc2a73ee04 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. From c558e9fca876d6d0463a7c337d2291774b9c6f96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Mon, 21 Jan 2013 06:47:56 +0000 Subject: [PATCH 02/19] 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(-) diff --git a/include/net/ndisc.h b/include/net/ndisc.h index ec48f42db5ed1..745bf741e029c 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 49dfc2a73ee04..82ccf0a43063f 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; From 6bce6b4e16e46cc860175b9e10a283194ef9f004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Mon, 21 Jan 2013 06:48:03 +0000 Subject: [PATCH 03/19] 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(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 82ccf0a43063f..539b2ec37d3a4 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); From 9c86dafe94f03679b77d85915e65da1304005a7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Mon, 21 Jan 2013 06:48:09 +0000 Subject: [PATCH 04/19] 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(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 539b2ec37d3a4..53a545f326254 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, From de09334b9326632bbf1a74bfd8b01866cbbf2f61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Mon, 21 Jan 2013 06:48:14 +0000 Subject: [PATCH 05/19] 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(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 53a545f326254..1776a0deee7f3 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); From 2576f17dfad402e2446244238ed22dddf35c2e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Mon, 21 Jan 2013 06:48:19 +0000 Subject: [PATCH 06/19] 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(-) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 464c6f70eca16..c1878f7049c8f 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 b0895f5d5fc6b..7eee94c27f8d6 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 587a84530a574..f25002aaf624d 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 1776a0deee7f3..7ce266f34cc7c 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, From c8d6c380d9463e1405d821db7071e39f63acfb28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Mon, 21 Jan 2013 06:48:24 +0000 Subject: [PATCH 07/19] 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(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 7ce266f34cc7c..05c69964f356c 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); From f382d03ad003815be6dc268711659d4475fb7d28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Mon, 21 Jan 2013 06:48:29 +0000 Subject: [PATCH 08/19] 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(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 05c69964f356c..ed3ba8eb9505f 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); From af9a997629488ba5f92dc3d76e1ec51fcd759c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Mon, 21 Jan 2013 06:48:34 +0000 Subject: [PATCH 09/19] 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(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index ed3ba8eb9505f..200b2b22b9ba2 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, From 527a150fb2292a59ca0545dace8d482581253532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Mon, 21 Jan 2013 06:48:39 +0000 Subject: [PATCH 10/19] 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(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 200b2b22b9ba2..09171fdbc3124 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(); From 5135e633f92ab4deb3600a30cbbec6e0929fc8a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Mon, 21 Jan 2013 06:48:44 +0000 Subject: [PATCH 11/19] 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(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 09171fdbc3124..62b1415bec25b 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); From 2ce13576144ade3e9340efce9620a6dd338aedc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Mon, 21 Jan 2013 06:48:49 +0000 Subject: [PATCH 12/19] 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(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 62b1415bec25b..c2b16ffeb1a8a 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)); From 5f5a0115635bf678d267cbc72169a718e8724d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Mon, 21 Jan 2013 06:48:53 +0000 Subject: [PATCH 13/19] 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(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index c2b16ffeb1a8a..ed786441bc51d 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, From aa4bdd4b3f43274252c1280f6464850b0f004fc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Mon, 21 Jan 2013 06:48:58 +0000 Subject: [PATCH 14/19] 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(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index ed786441bc51d..f0c436b492551 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, From f4de84c64e3d801965ee4c6dadd19b76b9424bbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Mon, 21 Jan 2013 06:49:03 +0000 Subject: [PATCH 15/19] 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(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index f0c436b492551..437781c2af416 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: From 7b3d9b06d8b6407fe25e00e627b48ec0d4a2a076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Mon, 21 Jan 2013 06:49:08 +0000 Subject: [PATCH 16/19] 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(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 437781c2af416..dda4addf29193 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; From b44b5f4ae96de87e458ef73fc01e7ec0dbac10c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Mon, 21 Jan 2013 06:49:13 +0000 Subject: [PATCH 17/19] 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(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index dda4addf29193..79a56a7663b7e 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); } From 1cb3fe513f62ca7c5963d551e01d75aa4f6ca72a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Mon, 21 Jan 2013 06:49:17 +0000 Subject: [PATCH 18/19] 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(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 79a56a7663b7e..1c015665ce71c 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); } From 4d5c152e8694b57094e320060be4621dee5779dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki=20/=20=E5=90=89=E8=97=A4=E8=8B=B1?= =?UTF-8?q?=E6=98=8E?= Date: Mon, 21 Jan 2013 06:49:25 +0000 Subject: [PATCH 19/19] 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(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 1c015665ce71c..76ef4353d5187 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