Commit 842df073 authored by Hannes Frederic Sowa's avatar Hannes Frederic Sowa Committed by David S. Miller

ipv6: use newly introduced __ipv6_addr_needs_scope_id and ipv6_iface_scope_id

This patch requires multicast interface-scoped addresses to supply a
sin6_scope_id. Because the sin6_scope_id is now also correctly used
in case of interface-scoped multicast traffic this enables one to use
interface scoped addresses over interfaces which are not targeted by the
default multicast route (the route has to be put there manually, though).

getsockname() and getpeername() now return the correct sin6_scope_id in
case of interface-local mc addresses.

v2:
a) rebased ontop of patch 1/4 (now uses ipv6_addr_props)

v3:
a) reverted changes for ipv6_addr_props

v4:
a) unchanged

Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Acked-by: default avatarYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: default avatarHannes Frederic Sowa <hannes@stressinduktion.org>
Acked-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>dave
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b7ef213e
...@@ -323,7 +323,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -323,7 +323,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct net_device *dev = NULL; struct net_device *dev = NULL;
rcu_read_lock(); rcu_read_lock();
if (addr_type & IPV6_ADDR_LINKLOCAL) { if (__ipv6_addr_needs_scope_id(addr_type)) {
if (addr_len >= sizeof(struct sockaddr_in6) && if (addr_len >= sizeof(struct sockaddr_in6) &&
addr->sin6_scope_id) { addr->sin6_scope_id) {
/* Override any existing binding, if another one /* Override any existing binding, if another one
...@@ -471,8 +471,8 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr, ...@@ -471,8 +471,8 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
sin->sin6_port = inet->inet_sport; sin->sin6_port = inet->inet_sport;
} }
if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) sin->sin6_scope_id = ipv6_iface_scope_id(&sin->sin6_addr,
sin->sin6_scope_id = sk->sk_bound_dev_if; sk->sk_bound_dev_if);
*uaddr_len = sizeof(*sin); *uaddr_len = sizeof(*sin);
return 0; return 0;
} }
......
...@@ -124,7 +124,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -124,7 +124,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
goto out; goto out;
} }
if (addr_type&IPV6_ADDR_LINKLOCAL) { if (__ipv6_addr_needs_scope_id(addr_type)) {
if (addr_len >= sizeof(struct sockaddr_in6) && if (addr_len >= sizeof(struct sockaddr_in6) &&
usin->sin6_scope_id) { usin->sin6_scope_id) {
if (sk->sk_bound_dev_if && if (sk->sk_bound_dev_if &&
...@@ -355,18 +355,19 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) ...@@ -355,18 +355,19 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
sin->sin6_family = AF_INET6; sin->sin6_family = AF_INET6;
sin->sin6_flowinfo = 0; sin->sin6_flowinfo = 0;
sin->sin6_port = serr->port; sin->sin6_port = serr->port;
sin->sin6_scope_id = 0;
if (skb->protocol == htons(ETH_P_IPV6)) { if (skb->protocol == htons(ETH_P_IPV6)) {
const struct ipv6hdr *ip6h = container_of((struct in6_addr *)(nh + serr->addr_offset), const struct ipv6hdr *ip6h = container_of((struct in6_addr *)(nh + serr->addr_offset),
struct ipv6hdr, daddr); struct ipv6hdr, daddr);
sin->sin6_addr = ip6h->daddr; sin->sin6_addr = ip6h->daddr;
if (np->sndflow) if (np->sndflow)
sin->sin6_flowinfo = ip6_flowinfo(ip6h); sin->sin6_flowinfo = ip6_flowinfo(ip6h);
if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) sin->sin6_scope_id =
sin->sin6_scope_id = IP6CB(skb)->iif; ipv6_iface_scope_id(&sin->sin6_addr,
IP6CB(skb)->iif);
} else { } else {
ipv6_addr_set_v4mapped(*(__be32 *)(nh + serr->addr_offset), ipv6_addr_set_v4mapped(*(__be32 *)(nh + serr->addr_offset),
&sin->sin6_addr); &sin->sin6_addr);
sin->sin6_scope_id = 0;
} }
} }
...@@ -376,18 +377,19 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) ...@@ -376,18 +377,19 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) { if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) {
sin->sin6_family = AF_INET6; sin->sin6_family = AF_INET6;
sin->sin6_flowinfo = 0; sin->sin6_flowinfo = 0;
sin->sin6_scope_id = 0;
if (skb->protocol == htons(ETH_P_IPV6)) { if (skb->protocol == htons(ETH_P_IPV6)) {
sin->sin6_addr = ipv6_hdr(skb)->saddr; sin->sin6_addr = ipv6_hdr(skb)->saddr;
if (np->rxopt.all) if (np->rxopt.all)
ip6_datagram_recv_ctl(sk, msg, skb); ip6_datagram_recv_ctl(sk, msg, skb);
if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) sin->sin6_scope_id =
sin->sin6_scope_id = IP6CB(skb)->iif; ipv6_iface_scope_id(&sin->sin6_addr,
IP6CB(skb)->iif);
} else { } else {
struct inet_sock *inet = inet_sk(sk); struct inet_sock *inet = inet_sk(sk);
ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr,
&sin->sin6_addr); &sin->sin6_addr);
sin->sin6_scope_id = 0;
if (inet->cmsg_flags) if (inet->cmsg_flags)
ip_cmsg_recv(msg, skb); ip_cmsg_recv(msg, skb);
} }
......
...@@ -434,7 +434,7 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) ...@@ -434,7 +434,7 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
* Source addr check * Source addr check
*/ */
if (addr_type & IPV6_ADDR_LINKLOCAL) if (__ipv6_addr_needs_scope_id(addr_type))
iif = skb->dev->ifindex; iif = skb->dev->ifindex;
/* /*
......
...@@ -173,10 +173,8 @@ void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr) ...@@ -173,10 +173,8 @@ void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
sin6->sin6_port = inet_sk(sk)->inet_dport; sin6->sin6_port = inet_sk(sk)->inet_dport;
/* We do not store received flowlabel for TCP */ /* We do not store received flowlabel for TCP */
sin6->sin6_flowinfo = 0; sin6->sin6_flowinfo = 0;
sin6->sin6_scope_id = 0; sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
if (sk->sk_bound_dev_if && sk->sk_bound_dev_if);
ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
sin6->sin6_scope_id = sk->sk_bound_dev_if;
} }
EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr); EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr);
......
...@@ -263,7 +263,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -263,7 +263,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (addr_type != IPV6_ADDR_ANY) { if (addr_type != IPV6_ADDR_ANY) {
struct net_device *dev = NULL; struct net_device *dev = NULL;
if (addr_type & IPV6_ADDR_LINKLOCAL) { if (__ipv6_addr_needs_scope_id(addr_type)) {
if (addr_len >= sizeof(struct sockaddr_in6) && if (addr_len >= sizeof(struct sockaddr_in6) &&
addr->sin6_scope_id) { addr->sin6_scope_id) {
/* Override any existing binding, if another /* Override any existing binding, if another
...@@ -498,9 +498,8 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, ...@@ -498,9 +498,8 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,
sin6->sin6_port = 0; sin6->sin6_port = 0;
sin6->sin6_addr = ipv6_hdr(skb)->saddr; sin6->sin6_addr = ipv6_hdr(skb)->saddr;
sin6->sin6_flowinfo = 0; sin6->sin6_flowinfo = 0;
sin6->sin6_scope_id = 0; sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) IP6CB(skb)->iif);
sin6->sin6_scope_id = IP6CB(skb)->iif;
} }
sock_recv_ts_and_drops(msg, sk, skb); sock_recv_ts_and_drops(msg, sk, skb);
...@@ -802,7 +801,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -802,7 +801,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
if (addr_len >= sizeof(struct sockaddr_in6) && if (addr_len >= sizeof(struct sockaddr_in6) &&
sin6->sin6_scope_id && sin6->sin6_scope_id &&
ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) __ipv6_addr_needs_scope_id(__ipv6_addr_type(daddr)))
fl6.flowi6_oif = sin6->sin6_scope_id; fl6.flowi6_oif = sin6->sin6_scope_id;
} else { } else {
if (sk->sk_state != TCP_ESTABLISHED) if (sk->sk_state != TCP_ESTABLISHED)
......
...@@ -450,15 +450,16 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, ...@@ -450,15 +450,16 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
sin6->sin6_family = AF_INET6; sin6->sin6_family = AF_INET6;
sin6->sin6_port = udp_hdr(skb)->source; sin6->sin6_port = udp_hdr(skb)->source;
sin6->sin6_flowinfo = 0; sin6->sin6_flowinfo = 0;
sin6->sin6_scope_id = 0;
if (is_udp4) if (is_udp4) {
ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr,
&sin6->sin6_addr); &sin6->sin6_addr);
else { sin6->sin6_scope_id = 0;
} else {
sin6->sin6_addr = ipv6_hdr(skb)->saddr; sin6->sin6_addr = ipv6_hdr(skb)->saddr;
if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) sin6->sin6_scope_id =
sin6->sin6_scope_id = IP6CB(skb)->iif; ipv6_iface_scope_id(&sin6->sin6_addr,
IP6CB(skb)->iif);
} }
} }
...@@ -1118,7 +1119,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1118,7 +1119,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
if (addr_len >= sizeof(struct sockaddr_in6) && if (addr_len >= sizeof(struct sockaddr_in6) &&
sin6->sin6_scope_id && sin6->sin6_scope_id &&
ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) __ipv6_addr_needs_scope_id(__ipv6_addr_type(daddr)))
fl6.flowi6_oif = sin6->sin6_scope_id; fl6.flowi6_oif = sin6->sin6_scope_id;
} else { } else {
if (sk->sk_state != TCP_ESTABLISHED) if (sk->sk_state != TCP_ESTABLISHED)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment