aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ndisc.c
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org>2013-01-21 01:49:17 -0500
committerDavid S. Miller <davem@davemloft.net>2013-01-21 13:33:18 -0500
commit1cb3fe513f62ca7c5963d551e01d75aa4f6ca72a (patch)
tree55685e7df224e4863785460d06a58470ae4f7cea /net/ipv6/ndisc.c
parentb44b5f4ae96de87e458ef73fc01e7ec0dbac10c0 (diff)
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 <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/ndisc.c')
-rw-r--r--net/ipv6/ndisc.c122
1 files changed, 63 insertions, 59 deletions
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,
413 hdr->daddr = *daddr; 413 hdr->daddr = *daddr;
414} 414}
415 415
416static struct sk_buff *ndisc_build_skb(struct net_device *dev,
417 const struct in6_addr *daddr,
418 const struct in6_addr *saddr,
419 struct icmp6hdr *icmp6h,
420 const struct in6_addr *target,
421 int llinfo)
422{
423 struct sk_buff *skb;
424 struct icmp6hdr *hdr;
425 int len;
426 int optlen = 0;
427 u8 *opt;
428
429 if (!dev->addr_len)
430 llinfo = 0;
431
432 len = sizeof(struct icmp6hdr) + (target ? sizeof(*target) : 0);
433 if (llinfo)
434 optlen += ndisc_opt_addr_space(dev);
435
436 skb = ndisc_alloc_skb(dev, len + optlen);
437 if (!skb)
438 return NULL;
439
440 skb_put(skb, len);
441
442 hdr = (struct icmp6hdr *)skb_transport_header(skb);
443 memcpy(hdr, icmp6h, sizeof(*hdr));
444
445 opt = skb_transport_header(skb) + sizeof(struct icmp6hdr);
446 if (target) {
447 *(struct in6_addr *)opt = *target;
448 opt += sizeof(*target);
449 }
450
451 if (llinfo)
452 ndisc_fill_addr_option(skb, llinfo, dev->dev_addr);
453
454 return skb;
455}
456
457static void ndisc_send_skb(struct sk_buff *skb, 416static void ndisc_send_skb(struct sk_buff *skb,
458 const struct in6_addr *daddr, 417 const struct in6_addr *daddr,
459 const struct in6_addr *saddr) 418 const struct in6_addr *saddr)
@@ -512,9 +471,8 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
512 struct in6_addr tmpaddr; 471 struct in6_addr tmpaddr;
513 struct inet6_ifaddr *ifp; 472 struct inet6_ifaddr *ifp;
514 const struct in6_addr *src_addr; 473 const struct in6_addr *src_addr;
515 struct icmp6hdr icmp6h = { 474 struct nd_msg *msg;
516 .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, 475 int optlen = 0;
517 };
518 476
519 /* for anycast or proxy, solicited_addr != src_addr */ 477 /* for anycast or proxy, solicited_addr != src_addr */
520 ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1); 478 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,
532 src_addr = &tmpaddr; 490 src_addr = &tmpaddr;
533 } 491 }
534 492
535 icmp6h.icmp6_router = router; 493 if (!dev->addr_len)
536 icmp6h.icmp6_solicited = solicited; 494 inc_opt = 0;
537 icmp6h.icmp6_override = override; 495 if (inc_opt)
496 optlen += ndisc_opt_addr_space(dev);
538 497
539 skb = ndisc_build_skb(dev, daddr, src_addr, &icmp6h, solicited_addr, 498 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
540 inc_opt ? ND_OPT_TARGET_LL_ADDR : 0);
541 if (!skb) 499 if (!skb)
542 return; 500 return;
543 501
502 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
503 *msg = (struct nd_msg) {
504 .icmph = {
505 .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
506 .icmp6_router = router,
507 .icmp6_solicited = solicited,
508 .icmp6_override = override,
509 },
510 .target = *solicited_addr,
511 };
512
513 if (inc_opt)
514 ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
515 dev->dev_addr);
516
517
544 ndisc_send_skb(skb, daddr, src_addr); 518 ndisc_send_skb(skb, daddr, src_addr);
545} 519}
546 520
@@ -571,9 +545,9 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
571{ 545{
572 struct sk_buff *skb; 546 struct sk_buff *skb;
573 struct in6_addr addr_buf; 547 struct in6_addr addr_buf;
574 struct icmp6hdr icmp6h = { 548 int inc_opt = dev->addr_len;
575 .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION, 549 int optlen = 0;
576 }; 550 struct nd_msg *msg;
577 551
578 if (saddr == NULL) { 552 if (saddr == NULL) {
579 if (ipv6_get_lladdr(dev, &addr_buf, 553 if (ipv6_get_lladdr(dev, &addr_buf,
@@ -582,11 +556,27 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
582 saddr = &addr_buf; 556 saddr = &addr_buf;
583 } 557 }
584 558
585 skb = ndisc_build_skb(dev, daddr, saddr, &icmp6h, solicit, 559 if (ipv6_addr_any(saddr))
586 !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0); 560 inc_opt = 0;
561 if (inc_opt)
562 optlen += ndisc_opt_addr_space(dev);
563
564 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
587 if (!skb) 565 if (!skb)
588 return; 566 return;
589 567
568 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
569 *msg = (struct nd_msg) {
570 .icmph = {
571 .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
572 },
573 .target = *solicit,
574 };
575
576 if (inc_opt)
577 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
578 dev->dev_addr);
579
590 ndisc_send_skb(skb, daddr, saddr); 580 ndisc_send_skb(skb, daddr, saddr);
591} 581}
592 582
@@ -594,10 +584,9 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
594 const struct in6_addr *daddr) 584 const struct in6_addr *daddr)
595{ 585{
596 struct sk_buff *skb; 586 struct sk_buff *skb;
597 struct icmp6hdr icmp6h = { 587 struct rs_msg *msg;
598 .icmp6_type = NDISC_ROUTER_SOLICITATION,
599 };
600 int send_sllao = dev->addr_len; 588 int send_sllao = dev->addr_len;
589 int optlen = 0;
601 590
602#ifdef CONFIG_IPV6_OPTIMISTIC_DAD 591#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
603 /* 592 /*
@@ -621,11 +610,26 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
621 } 610 }
622 } 611 }
623#endif 612#endif
624 skb = ndisc_build_skb(dev, daddr, saddr, &icmp6h, NULL, 613 if (!dev->addr_len)
625 send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0); 614 send_sllao = 0;
615 if (send_sllao)
616 optlen += ndisc_opt_addr_space(dev);
617
618 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
626 if (!skb) 619 if (!skb)
627 return; 620 return;
628 621
622 msg = (struct rs_msg *)skb_put(skb, sizeof(*msg));
623 *msg = (struct rs_msg) {
624 .icmph = {
625 .icmp6_type = NDISC_ROUTER_SOLICITATION,
626 },
627 };
628
629 if (send_sllao)
630 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
631 dev->dev_addr);
632
629 ndisc_send_skb(skb, daddr, saddr); 633 ndisc_send_skb(skb, daddr, saddr);
630} 634}
631 635