diff options
Diffstat (limited to 'net/ipv6/ping.c')
-rw-r--r-- | net/ipv6/ping.c | 33 |
1 files changed, 17 insertions, 16 deletions
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c index fed40d1ec29b..0900352c924c 100644 --- a/net/ipv6/ping.c +++ b/net/ipv6/ping.c | |||
@@ -55,7 +55,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) | |||
55 | struct icmp6hdr user_icmph; | 55 | struct icmp6hdr user_icmph; |
56 | int addr_type; | 56 | int addr_type; |
57 | struct in6_addr *daddr; | 57 | struct in6_addr *daddr; |
58 | int iif = 0; | 58 | int oif = 0; |
59 | struct flowi6 fl6; | 59 | struct flowi6 fl6; |
60 | int err; | 60 | int err; |
61 | struct dst_entry *dst; | 61 | struct dst_entry *dst; |
@@ -78,25 +78,30 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) | |||
78 | if (u->sin6_family != AF_INET6) { | 78 | if (u->sin6_family != AF_INET6) { |
79 | return -EAFNOSUPPORT; | 79 | return -EAFNOSUPPORT; |
80 | } | 80 | } |
81 | if (sk->sk_bound_dev_if && | ||
82 | sk->sk_bound_dev_if != u->sin6_scope_id) { | ||
83 | return -EINVAL; | ||
84 | } | ||
85 | daddr = &(u->sin6_addr); | 81 | daddr = &(u->sin6_addr); |
86 | iif = u->sin6_scope_id; | 82 | if (__ipv6_addr_needs_scope_id(ipv6_addr_type(daddr))) |
83 | oif = u->sin6_scope_id; | ||
87 | } else { | 84 | } else { |
88 | if (sk->sk_state != TCP_ESTABLISHED) | 85 | if (sk->sk_state != TCP_ESTABLISHED) |
89 | return -EDESTADDRREQ; | 86 | return -EDESTADDRREQ; |
90 | daddr = &sk->sk_v6_daddr; | 87 | daddr = &sk->sk_v6_daddr; |
91 | } | 88 | } |
92 | 89 | ||
93 | if (!iif) | 90 | if (!oif) |
94 | iif = sk->sk_bound_dev_if; | 91 | oif = sk->sk_bound_dev_if; |
92 | |||
93 | if (!oif) | ||
94 | oif = np->sticky_pktinfo.ipi6_ifindex; | ||
95 | |||
96 | if (!oif && ipv6_addr_is_multicast(daddr)) | ||
97 | oif = np->mcast_oif; | ||
98 | else if (!oif) | ||
99 | oif = np->ucast_oif; | ||
95 | 100 | ||
96 | addr_type = ipv6_addr_type(daddr); | 101 | addr_type = ipv6_addr_type(daddr); |
97 | if (__ipv6_addr_needs_scope_id(addr_type) && !iif) | 102 | if ((__ipv6_addr_needs_scope_id(addr_type) && !oif) || |
98 | return -EINVAL; | 103 | (addr_type & IPV6_ADDR_MAPPED) || |
99 | if (addr_type & IPV6_ADDR_MAPPED) | 104 | (oif && sk->sk_bound_dev_if && oif != sk->sk_bound_dev_if)) |
100 | return -EINVAL; | 105 | return -EINVAL; |
101 | 106 | ||
102 | /* TODO: use ip6_datagram_send_ctl to get options from cmsg */ | 107 | /* TODO: use ip6_datagram_send_ctl to get options from cmsg */ |
@@ -106,16 +111,12 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) | |||
106 | fl6.flowi6_proto = IPPROTO_ICMPV6; | 111 | fl6.flowi6_proto = IPPROTO_ICMPV6; |
107 | fl6.saddr = np->saddr; | 112 | fl6.saddr = np->saddr; |
108 | fl6.daddr = *daddr; | 113 | fl6.daddr = *daddr; |
114 | fl6.flowi6_oif = oif; | ||
109 | fl6.flowi6_mark = sk->sk_mark; | 115 | fl6.flowi6_mark = sk->sk_mark; |
110 | fl6.fl6_icmp_type = user_icmph.icmp6_type; | 116 | fl6.fl6_icmp_type = user_icmph.icmp6_type; |
111 | fl6.fl6_icmp_code = user_icmph.icmp6_code; | 117 | fl6.fl6_icmp_code = user_icmph.icmp6_code; |
112 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); | 118 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); |
113 | 119 | ||
114 | if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) | ||
115 | fl6.flowi6_oif = np->mcast_oif; | ||
116 | else if (!fl6.flowi6_oif) | ||
117 | fl6.flowi6_oif = np->ucast_oif; | ||
118 | |||
119 | ipc6.tclass = np->tclass; | 120 | ipc6.tclass = np->tclass; |
120 | fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel); | 121 | fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel); |
121 | 122 | ||