aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ndisc.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ndisc.c')
-rw-r--r--net/ipv6/ndisc.c362
1 files changed, 181 insertions, 181 deletions
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 6574175795df..76ef4353d518 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -143,16 +143,12 @@ struct neigh_table nd_tbl = {
143 .gc_thresh3 = 1024, 143 .gc_thresh3 = 1024,
144}; 144};
145 145
146static inline int ndisc_opt_addr_space(struct net_device *dev) 146static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data)
147{ 147{
148 return NDISC_OPT_SPACE(dev->addr_len + ndisc_addr_option_pad(dev->type)); 148 int pad = ndisc_addr_option_pad(skb->dev->type);
149} 149 int data_len = skb->dev->addr_len;
150 150 int space = ndisc_opt_addr_space(skb->dev);
151static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len, 151 u8 *opt = skb_put(skb, space);
152 unsigned short addr_type)
153{
154 int pad = ndisc_addr_option_pad(addr_type);
155 int space = NDISC_OPT_SPACE(data_len + pad);
156 152
157 opt[0] = type; 153 opt[0] = type;
158 opt[1] = space>>3; 154 opt[1] = space>>3;
@@ -166,7 +162,6 @@ static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len,
166 opt += data_len; 162 opt += data_len;
167 if ((space -= data_len) > 0) 163 if ((space -= data_len) > 0)
168 memset(opt, 0, space); 164 memset(opt, 0, space);
169 return opt + space;
170} 165}
171 166
172static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, 167static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
@@ -370,91 +365,88 @@ static void pndisc_destructor(struct pneigh_entry *n)
370 ipv6_dev_mc_dec(dev, &maddr); 365 ipv6_dev_mc_dec(dev, &maddr);
371} 366}
372 367
373static struct sk_buff *ndisc_build_skb(struct net_device *dev, 368static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
374 const struct in6_addr *daddr, 369 int len)
375 const struct in6_addr *saddr,
376 struct icmp6hdr *icmp6h,
377 const struct in6_addr *target,
378 int llinfo)
379{ 370{
380 struct net *net = dev_net(dev);
381 struct sock *sk = net->ipv6.ndisc_sk;
382 struct sk_buff *skb;
383 struct icmp6hdr *hdr;
384 int hlen = LL_RESERVED_SPACE(dev); 371 int hlen = LL_RESERVED_SPACE(dev);
385 int tlen = dev->needed_tailroom; 372 int tlen = dev->needed_tailroom;
386 int len; 373 struct sock *sk = dev_net(dev)->ipv6.ndisc_sk;
374 struct sk_buff *skb;
387 int err; 375 int err;
388 u8 *opt;
389
390 if (!dev->addr_len)
391 llinfo = 0;
392
393 len = sizeof(struct icmp6hdr) + (target ? sizeof(*target) : 0);
394 if (llinfo)
395 len += ndisc_opt_addr_space(dev);
396 376
397 skb = sock_alloc_send_skb(sk, 377 skb = sock_alloc_send_skb(sk,
398 (MAX_HEADER + sizeof(struct ipv6hdr) + 378 hlen + sizeof(struct ipv6hdr) + len + tlen,
399 len + hlen + tlen),
400 1, &err); 379 1, &err);
401 if (!skb) { 380 if (!skb) {
402 ND_PRINTK(0, err, "ND: %s failed to allocate an skb, err=%d\n", 381 ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb, err=%d\n",
403 __func__, err); 382 __func__, err);
404 return NULL; 383 return NULL;
405 } 384 }
406 385
407 skb_reserve(skb, hlen); 386 skb->protocol = htons(ETH_P_IPV6);
408 ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len); 387 skb->dev = dev;
409 388
410 skb->transport_header = skb->tail; 389 skb_reserve(skb, hlen + sizeof(struct ipv6hdr));
411 skb_put(skb, len); 390 skb_reset_transport_header(skb);
412 391
413 hdr = (struct icmp6hdr *)skb_transport_header(skb); 392 return skb;
414 memcpy(hdr, icmp6h, sizeof(*hdr)); 393}
415 394
416 opt = skb_transport_header(skb) + sizeof(struct icmp6hdr); 395static void ip6_nd_hdr(struct sk_buff *skb,
417 if (target) { 396 const struct in6_addr *saddr,
418 *(struct in6_addr *)opt = *target; 397 const struct in6_addr *daddr,
419 opt += sizeof(*target); 398 int hop_limit, int len)
420 } 399{
400 struct ipv6hdr *hdr;
421 401
422 if (llinfo) 402 skb_push(skb, sizeof(*hdr));
423 ndisc_fill_addr_option(opt, llinfo, dev->dev_addr, 403 skb_reset_network_header(skb);
424 dev->addr_len, dev->type); 404 hdr = ipv6_hdr(skb);
425 405
426 hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, len, 406 ip6_flow_hdr(hdr, 0, 0);
427 IPPROTO_ICMPV6,
428 csum_partial(hdr,
429 len, 0));
430 407
431 return skb; 408 hdr->payload_len = htons(len);
409 hdr->nexthdr = IPPROTO_ICMPV6;
410 hdr->hop_limit = hop_limit;
411
412 hdr->saddr = *saddr;
413 hdr->daddr = *daddr;
432} 414}
433 415
434static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev, 416static void ndisc_send_skb(struct sk_buff *skb,
435 struct neighbour *neigh,
436 const struct in6_addr *daddr, 417 const struct in6_addr *daddr,
437 const struct in6_addr *saddr, 418 const struct in6_addr *saddr)
438 struct icmp6hdr *icmp6h)
439{ 419{
440 struct flowi6 fl6; 420 struct dst_entry *dst = skb_dst(skb);
441 struct dst_entry *dst; 421 struct net *net = dev_net(skb->dev);
442 struct net *net = dev_net(dev);
443 struct sock *sk = net->ipv6.ndisc_sk; 422 struct sock *sk = net->ipv6.ndisc_sk;
444 struct inet6_dev *idev; 423 struct inet6_dev *idev;
445 int err; 424 int err;
425 struct icmp6hdr *icmp6h = icmp6_hdr(skb);
446 u8 type; 426 u8 type;
447 427
448 type = icmp6h->icmp6_type; 428 type = icmp6h->icmp6_type;
449 429
450 icmpv6_flow_init(sk, &fl6, type, saddr, daddr, dev->ifindex); 430 if (!dst) {
451 dst = icmp6_dst_alloc(dev, neigh, &fl6); 431 struct sock *sk = net->ipv6.ndisc_sk;
452 if (IS_ERR(dst)) { 432 struct flowi6 fl6;
453 kfree_skb(skb); 433
454 return; 434 icmpv6_flow_init(sk, &fl6, type, saddr, daddr, skb->dev->ifindex);
435 dst = icmp6_dst_alloc(skb->dev, &fl6);
436 if (IS_ERR(dst)) {
437 kfree_skb(skb);
438 return;
439 }
440
441 skb_dst_set(skb, dst);
455 } 442 }
456 443
457 skb_dst_set(skb, dst); 444 icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len,
445 IPPROTO_ICMPV6,
446 csum_partial(icmp6h,
447 skb->len, 0));
448
449 ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len);
458 450
459 rcu_read_lock(); 451 rcu_read_lock();
460 idev = __in6_dev_get(dst->dev); 452 idev = __in6_dev_get(dst->dev);
@@ -470,36 +462,17 @@ static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev,
470 rcu_read_unlock(); 462 rcu_read_unlock();
471} 463}
472 464
473/*
474 * Send a Neighbour Discover packet
475 */
476static void __ndisc_send(struct net_device *dev,
477 struct neighbour *neigh,
478 const struct in6_addr *daddr,
479 const struct in6_addr *saddr,
480 struct icmp6hdr *icmp6h, const struct in6_addr *target,
481 int llinfo)
482{
483 struct sk_buff *skb;
484
485 skb = ndisc_build_skb(dev, daddr, saddr, icmp6h, target, llinfo);
486 if (!skb)
487 return;
488
489 ndisc_send_skb(skb, dev, neigh, daddr, saddr, icmp6h);
490}
491
492static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, 465static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
493 const struct in6_addr *daddr, 466 const struct in6_addr *daddr,
494 const struct in6_addr *solicited_addr, 467 const struct in6_addr *solicited_addr,
495 int router, int solicited, int override, int inc_opt) 468 bool router, bool solicited, bool override, bool inc_opt)
496{ 469{
470 struct sk_buff *skb;
497 struct in6_addr tmpaddr; 471 struct in6_addr tmpaddr;
498 struct inet6_ifaddr *ifp; 472 struct inet6_ifaddr *ifp;
499 const struct in6_addr *src_addr; 473 const struct in6_addr *src_addr;
500 struct icmp6hdr icmp6h = { 474 struct nd_msg *msg;
501 .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, 475 int optlen = 0;
502 };
503 476
504 /* for anycast or proxy, solicited_addr != src_addr */ 477 /* for anycast or proxy, solicited_addr != src_addr */
505 ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1); 478 ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);
@@ -517,13 +490,32 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
517 src_addr = &tmpaddr; 490 src_addr = &tmpaddr;
518 } 491 }
519 492
520 icmp6h.icmp6_router = router; 493 if (!dev->addr_len)
521 icmp6h.icmp6_solicited = solicited; 494 inc_opt = 0;
522 icmp6h.icmp6_override = override; 495 if (inc_opt)
496 optlen += ndisc_opt_addr_space(dev);
497
498 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
499 if (!skb)
500 return;
523 501
524 __ndisc_send(dev, neigh, daddr, src_addr, 502 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
525 &icmp6h, solicited_addr, 503 *msg = (struct nd_msg) {
526 inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); 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
518 ndisc_send_skb(skb, daddr, src_addr);
527} 519}
528 520
529static void ndisc_send_unsol_na(struct net_device *dev) 521static void ndisc_send_unsol_na(struct net_device *dev)
@@ -551,10 +543,11 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
551 const struct in6_addr *solicit, 543 const struct in6_addr *solicit,
552 const struct in6_addr *daddr, const struct in6_addr *saddr) 544 const struct in6_addr *daddr, const struct in6_addr *saddr)
553{ 545{
546 struct sk_buff *skb;
554 struct in6_addr addr_buf; 547 struct in6_addr addr_buf;
555 struct icmp6hdr icmp6h = { 548 int inc_opt = dev->addr_len;
556 .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION, 549 int optlen = 0;
557 }; 550 struct nd_msg *msg;
558 551
559 if (saddr == NULL) { 552 if (saddr == NULL) {
560 if (ipv6_get_lladdr(dev, &addr_buf, 553 if (ipv6_get_lladdr(dev, &addr_buf,
@@ -563,18 +556,37 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
563 saddr = &addr_buf; 556 saddr = &addr_buf;
564 } 557 }
565 558
566 __ndisc_send(dev, neigh, daddr, saddr, 559 if (ipv6_addr_any(saddr))
567 &icmp6h, solicit, 560 inc_opt = 0;
568 !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0); 561 if (inc_opt)
562 optlen += ndisc_opt_addr_space(dev);
563
564 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
565 if (!skb)
566 return;
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
580 ndisc_send_skb(skb, daddr, saddr);
569} 581}
570 582
571void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, 583void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
572 const struct in6_addr *daddr) 584 const struct in6_addr *daddr)
573{ 585{
574 struct icmp6hdr icmp6h = { 586 struct sk_buff *skb;
575 .icmp6_type = NDISC_ROUTER_SOLICITATION, 587 struct rs_msg *msg;
576 };
577 int send_sllao = dev->addr_len; 588 int send_sllao = dev->addr_len;
589 int optlen = 0;
578 590
579#ifdef CONFIG_IPV6_OPTIMISTIC_DAD 591#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
580 /* 592 /*
@@ -598,9 +610,27 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
598 } 610 }
599 } 611 }
600#endif 612#endif
601 __ndisc_send(dev, NULL, daddr, saddr, 613 if (!dev->addr_len)
602 &icmp6h, NULL, 614 send_sllao = 0;
603 send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0); 615 if (send_sllao)
616 optlen += ndisc_opt_addr_space(dev);
617
618 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
619 if (!skb)
620 return;
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
633 ndisc_send_skb(skb, daddr, saddr);
604} 634}
605 635
606 636
@@ -676,6 +706,11 @@ static void ndisc_recv_ns(struct sk_buff *skb)
676 bool inc; 706 bool inc;
677 int is_router = -1; 707 int is_router = -1;
678 708
709 if (skb->len < sizeof(struct nd_msg)) {
710 ND_PRINTK(2, warn, "NS: packet too short\n");
711 return;
712 }
713
679 if (ipv6_addr_is_multicast(&msg->target)) { 714 if (ipv6_addr_is_multicast(&msg->target)) {
680 ND_PRINTK(2, warn, "NS: multicast target address\n"); 715 ND_PRINTK(2, warn, "NS: multicast target address\n");
681 return; 716 return;
@@ -685,11 +720,7 @@ static void ndisc_recv_ns(struct sk_buff *skb)
685 * RFC2461 7.1.1: 720 * RFC2461 7.1.1:
686 * DAD has to be destined for solicited node multicast address. 721 * DAD has to be destined for solicited node multicast address.
687 */ 722 */
688 if (dad && 723 if (dad && !ipv6_addr_is_solict_mult(daddr)) {
689 !(daddr->s6_addr32[0] == htonl(0xff020000) &&
690 daddr->s6_addr32[1] == htonl(0x00000000) &&
691 daddr->s6_addr32[2] == htonl(0x00000001) &&
692 daddr->s6_addr [12] == 0xff )) {
693 ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n"); 724 ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n");
694 return; 725 return;
695 } 726 }
@@ -780,11 +811,11 @@ static void ndisc_recv_ns(struct sk_buff *skb)
780 } 811 }
781 812
782 if (is_router < 0) 813 if (is_router < 0)
783 is_router = !!idev->cnf.forwarding; 814 is_router = idev->cnf.forwarding;
784 815
785 if (dad) { 816 if (dad) {
786 ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target, 817 ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target,
787 is_router, 0, (ifp != NULL), 1); 818 !!is_router, false, (ifp != NULL), true);
788 goto out; 819 goto out;
789 } 820 }
790 821
@@ -805,8 +836,8 @@ static void ndisc_recv_ns(struct sk_buff *skb)
805 NEIGH_UPDATE_F_OVERRIDE); 836 NEIGH_UPDATE_F_OVERRIDE);
806 if (neigh || !dev->header_ops) { 837 if (neigh || !dev->header_ops) {
807 ndisc_send_na(dev, neigh, saddr, &msg->target, 838 ndisc_send_na(dev, neigh, saddr, &msg->target,
808 is_router, 839 !!is_router,
809 1, (ifp != NULL && inc), inc); 840 true, (ifp != NULL && inc), inc);
810 if (neigh) 841 if (neigh)
811 neigh_release(neigh); 842 neigh_release(neigh);
812 } 843 }
@@ -1350,25 +1381,34 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
1350 icmpv6_notify(skb, NDISC_REDIRECT, 0, 0); 1381 icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
1351} 1382}
1352 1383
1384static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb,
1385 struct sk_buff *orig_skb,
1386 int rd_len)
1387{
1388 u8 *opt = skb_put(skb, rd_len);
1389
1390 memset(opt, 0, 8);
1391 *(opt++) = ND_OPT_REDIRECT_HDR;
1392 *(opt++) = (rd_len >> 3);
1393 opt += 6;
1394
1395 memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8);
1396}
1397
1353void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) 1398void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
1354{ 1399{
1355 struct net_device *dev = skb->dev; 1400 struct net_device *dev = skb->dev;
1356 struct net *net = dev_net(dev); 1401 struct net *net = dev_net(dev);
1357 struct sock *sk = net->ipv6.ndisc_sk; 1402 struct sock *sk = net->ipv6.ndisc_sk;
1358 int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); 1403 int optlen = 0;
1359 struct inet_peer *peer; 1404 struct inet_peer *peer;
1360 struct sk_buff *buff; 1405 struct sk_buff *buff;
1361 struct icmp6hdr *icmph; 1406 struct rd_msg *msg;
1362 struct in6_addr saddr_buf; 1407 struct in6_addr saddr_buf;
1363 struct in6_addr *addrp;
1364 struct rt6_info *rt; 1408 struct rt6_info *rt;
1365 struct dst_entry *dst; 1409 struct dst_entry *dst;
1366 struct inet6_dev *idev;
1367 struct flowi6 fl6; 1410 struct flowi6 fl6;
1368 u8 *opt;
1369 int hlen, tlen;
1370 int rd_len; 1411 int rd_len;
1371 int err;
1372 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL; 1412 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
1373 bool ret; 1413 bool ret;
1374 1414
@@ -1424,7 +1464,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
1424 memcpy(ha_buf, neigh->ha, dev->addr_len); 1464 memcpy(ha_buf, neigh->ha, dev->addr_len);
1425 read_unlock_bh(&neigh->lock); 1465 read_unlock_bh(&neigh->lock);
1426 ha = ha_buf; 1466 ha = ha_buf;
1427 len += ndisc_opt_addr_space(dev); 1467 optlen += ndisc_opt_addr_space(dev);
1428 } else 1468 } else
1429 read_unlock_bh(&neigh->lock); 1469 read_unlock_bh(&neigh->lock);
1430 1470
@@ -1432,80 +1472,40 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
1432 } 1472 }
1433 1473
1434 rd_len = min_t(unsigned int, 1474 rd_len = min_t(unsigned int,
1435 IPV6_MIN_MTU-sizeof(struct ipv6hdr)-len, skb->len + 8); 1475 IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen,
1476 skb->len + 8);
1436 rd_len &= ~0x7; 1477 rd_len &= ~0x7;
1437 len += rd_len; 1478 optlen += rd_len;
1438
1439 hlen = LL_RESERVED_SPACE(dev);
1440 tlen = dev->needed_tailroom;
1441 buff = sock_alloc_send_skb(sk,
1442 (MAX_HEADER + sizeof(struct ipv6hdr) +
1443 len + hlen + tlen),
1444 1, &err);
1445 if (buff == NULL) {
1446 ND_PRINTK(0, err,
1447 "Redirect: %s failed to allocate an skb, err=%d\n",
1448 __func__, err);
1449 goto release;
1450 }
1451
1452 skb_reserve(buff, hlen);
1453 ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr,
1454 IPPROTO_ICMPV6, len);
1455
1456 skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data);
1457 skb_put(buff, len);
1458 icmph = icmp6_hdr(buff);
1459
1460 memset(icmph, 0, sizeof(struct icmp6hdr));
1461 icmph->icmp6_type = NDISC_REDIRECT;
1462 1479
1463 /* 1480 buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
1464 * copy target and destination addresses 1481 if (!buff)
1465 */ 1482 goto release;
1466
1467 addrp = (struct in6_addr *)(icmph + 1);
1468 *addrp = *target;
1469 addrp++;
1470 *addrp = ipv6_hdr(skb)->daddr;
1471 1483
1472 opt = (u8*) (addrp + 1); 1484 msg = (struct rd_msg *)skb_put(buff, sizeof(*msg));
1485 *msg = (struct rd_msg) {
1486 .icmph = {
1487 .icmp6_type = NDISC_REDIRECT,
1488 },
1489 .target = *target,
1490 .dest = ipv6_hdr(skb)->daddr,
1491 };
1473 1492
1474 /* 1493 /*
1475 * include target_address option 1494 * include target_address option
1476 */ 1495 */
1477 1496
1478 if (ha) 1497 if (ha)
1479 opt = ndisc_fill_addr_option(opt, ND_OPT_TARGET_LL_ADDR, ha, 1498 ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, ha);
1480 dev->addr_len, dev->type);
1481 1499
1482 /* 1500 /*
1483 * build redirect option and copy skb over to the new packet. 1501 * build redirect option and copy skb over to the new packet.
1484 */ 1502 */
1485 1503
1486 memset(opt, 0, 8); 1504 if (rd_len)
1487 *(opt++) = ND_OPT_REDIRECT_HDR; 1505 ndisc_fill_redirect_hdr_option(buff, skb, rd_len);
1488 *(opt++) = (rd_len >> 3);
1489 opt += 6;
1490
1491 memcpy(opt, ipv6_hdr(skb), rd_len - 8);
1492
1493 icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr,
1494 len, IPPROTO_ICMPV6,
1495 csum_partial(icmph, len, 0));
1496 1506
1497 skb_dst_set(buff, dst); 1507 skb_dst_set(buff, dst);
1498 rcu_read_lock(); 1508 ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf);
1499 idev = __in6_dev_get(dst->dev);
1500 IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
1501 err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev,
1502 dst_output);
1503 if (!err) {
1504 ICMP6MSGOUT_INC_STATS(net, idev, NDISC_REDIRECT);
1505 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
1506 }
1507
1508 rcu_read_unlock();
1509 return; 1509 return;
1510 1510
1511release: 1511release:
@@ -1522,7 +1522,7 @@ int ndisc_rcv(struct sk_buff *skb)
1522{ 1522{
1523 struct nd_msg *msg; 1523 struct nd_msg *msg;
1524 1524
1525 if (!pskb_may_pull(skb, skb->len)) 1525 if (skb_linearize(skb))
1526 return 0; 1526 return 0;
1527 1527
1528 msg = (struct nd_msg *)skb_transport_header(skb); 1528 msg = (struct nd_msg *)skb_transport_header(skb);