diff options
author | YOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org> | 2013-01-21 01:49:17 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-01-21 13:33:18 -0500 |
commit | 1cb3fe513f62ca7c5963d551e01d75aa4f6ca72a (patch) | |
tree | 55685e7df224e4863785460d06a58470ae4f7cea /net/ipv6/ndisc.c | |
parent | b44b5f4ae96de87e458ef73fc01e7ec0dbac10c0 (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.c | 122 |
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 | ||
416 | static 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 | |||
457 | static void ndisc_send_skb(struct sk_buff *skb, | 416 | static 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 | ||