aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/datagram.c42
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)) {