diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv6/datagram.c | 42 |
1 files changed, 22 insertions, 20 deletions
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 94fa6ae77cfe..53e3883f7666 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -509,7 +509,6 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, | |||
509 | 509 | ||
510 | for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { | 510 | for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { |
511 | int addr_type; | 511 | int addr_type; |
512 | struct net_device *dev = NULL; | ||
513 | 512 | ||
514 | if (!CMSG_OK(msg, cmsg)) { | 513 | if (!CMSG_OK(msg, cmsg)) { |
515 | err = -EINVAL; | 514 | err = -EINVAL; |
@@ -522,6 +521,9 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, | |||
522 | switch (cmsg->cmsg_type) { | 521 | switch (cmsg->cmsg_type) { |
523 | case IPV6_PKTINFO: | 522 | case IPV6_PKTINFO: |
524 | case IPV6_2292PKTINFO: | 523 | case IPV6_2292PKTINFO: |
524 | { | ||
525 | struct net_device *dev = NULL; | ||
526 | |||
525 | if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct in6_pktinfo))) { | 527 | if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct in6_pktinfo))) { |
526 | err = -EINVAL; | 528 | err = -EINVAL; |
527 | goto exit_f; | 529 | goto exit_f; |
@@ -535,32 +537,32 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, | |||
535 | fl->oif = src_info->ipi6_ifindex; | 537 | fl->oif = src_info->ipi6_ifindex; |
536 | } | 538 | } |
537 | 539 | ||
538 | addr_type = ipv6_addr_type(&src_info->ipi6_addr); | 540 | addr_type = __ipv6_addr_type(&src_info->ipi6_addr); |
539 | 541 | ||
540 | if (addr_type == IPV6_ADDR_ANY) | 542 | if (fl->oif) { |
541 | break; | 543 | dev = dev_get_by_index(&init_net, fl->oif); |
544 | if (!dev) | ||
545 | return -ENODEV; | ||
546 | } else if (addr_type & IPV6_ADDR_LINKLOCAL) | ||
547 | return -EINVAL; | ||
542 | 548 | ||
543 | if (addr_type & IPV6_ADDR_LINKLOCAL) { | 549 | if (addr_type != IPV6_ADDR_ANY) { |
544 | if (!src_info->ipi6_ifindex) | 550 | int strict = __ipv6_addr_src_scope(addr_type) <= IPV6_ADDR_SCOPE_LINKLOCAL; |
545 | return -EINVAL; | 551 | if (!ipv6_chk_addr(&init_net, &src_info->ipi6_addr, |
546 | else { | 552 | strict ? dev : NULL, 0)) |
547 | dev = dev_get_by_index(&init_net, src_info->ipi6_ifindex); | 553 | err = -EINVAL; |
548 | if (!dev) | 554 | else |
549 | return -ENODEV; | 555 | ipv6_addr_copy(&fl->fl6_src, &src_info->ipi6_addr); |
550 | } | ||
551 | } | ||
552 | if (!ipv6_chk_addr(&init_net, &src_info->ipi6_addr, | ||
553 | dev, 0)) { | ||
554 | if (dev) | ||
555 | dev_put(dev); | ||
556 | err = -EINVAL; | ||
557 | goto exit_f; | ||
558 | } | 556 | } |
557 | |||
559 | if (dev) | 558 | if (dev) |
560 | dev_put(dev); | 559 | dev_put(dev); |
561 | 560 | ||
562 | ipv6_addr_copy(&fl->fl6_src, &src_info->ipi6_addr); | 561 | if (err) |
562 | goto exit_f; | ||
563 | |||
563 | break; | 564 | break; |
565 | } | ||
564 | 566 | ||
565 | case IPV6_FLOWINFO: | 567 | case IPV6_FLOWINFO: |
566 | if (cmsg->cmsg_len < CMSG_LEN(4)) { | 568 | if (cmsg->cmsg_len < CMSG_LEN(4)) { |