|
@@ -434,7 +434,7 @@ static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk)
|
|
|
/* Initialize sk->sk_rcv_saddr from sctp_addr. */
|
|
|
static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
|
|
|
{
|
|
|
- if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) {
|
|
|
+ if (addr->sa.sa_family == AF_INET) {
|
|
|
sk->sk_v6_rcv_saddr.s6_addr32[0] = 0;
|
|
|
sk->sk_v6_rcv_saddr.s6_addr32[1] = 0;
|
|
|
sk->sk_v6_rcv_saddr.s6_addr32[2] = htonl(0x0000ffff);
|
|
@@ -448,7 +448,7 @@ static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
|
|
|
/* Initialize sk->sk_daddr from sctp_addr. */
|
|
|
static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
|
|
|
{
|
|
|
- if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) {
|
|
|
+ if (addr->sa.sa_family == AF_INET) {
|
|
|
sk->sk_v6_daddr.s6_addr32[0] = 0;
|
|
|
sk->sk_v6_daddr.s6_addr32[1] = 0;
|
|
|
sk->sk_v6_daddr.s6_addr32[2] = htonl(0x0000ffff);
|
|
@@ -556,8 +556,6 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
|
|
|
if (IPV6_ADDR_ANY == type)
|
|
|
return 1;
|
|
|
if (type == IPV6_ADDR_MAPPED) {
|
|
|
- if (sp && !sp->v4mapped)
|
|
|
- return 0;
|
|
|
if (sp && ipv6_only_sock(sctp_opt2sk(sp)))
|
|
|
return 0;
|
|
|
sctp_v6_map_v4(addr);
|
|
@@ -587,8 +585,6 @@ static int sctp_v6_addr_valid(union sctp_addr *addr,
|
|
|
/* Note: This routine is used in input, so v4-mapped-v6
|
|
|
* are disallowed here when there is no sctp_sock.
|
|
|
*/
|
|
|
- if (!sp || !sp->v4mapped)
|
|
|
- return 0;
|
|
|
if (sp && ipv6_only_sock(sctp_opt2sk(sp)))
|
|
|
return 0;
|
|
|
sctp_v6_map_v4(addr);
|
|
@@ -675,11 +671,23 @@ out:
|
|
|
return newsk;
|
|
|
}
|
|
|
|
|
|
-/* Map v4 address to mapped v6 address */
|
|
|
-static void sctp_v6_addr_v4map(struct sctp_sock *sp, union sctp_addr *addr)
|
|
|
+/* Format a sockaddr for return to user space. This makes sure the return is
|
|
|
+ * AF_INET or AF_INET6 depending on the SCTP_I_WANT_MAPPED_V4_ADDR option.
|
|
|
+ */
|
|
|
+static int sctp_v6_addr_to_user(struct sctp_sock *sp, union sctp_addr *addr)
|
|
|
{
|
|
|
- if (sp->v4mapped && AF_INET == addr->sa.sa_family)
|
|
|
- sctp_v4_map_v6(addr);
|
|
|
+ if (sp->v4mapped) {
|
|
|
+ if (addr->sa.sa_family == AF_INET)
|
|
|
+ sctp_v4_map_v6(addr);
|
|
|
+ } else {
|
|
|
+ if (addr->sa.sa_family == AF_INET6 &&
|
|
|
+ ipv6_addr_v4mapped(&addr->v6.sin6_addr))
|
|
|
+ sctp_v6_map_v4(addr);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (addr->sa.sa_family == AF_INET)
|
|
|
+ return sizeof(struct sockaddr_in);
|
|
|
+ return sizeof(struct sockaddr_in6);
|
|
|
}
|
|
|
|
|
|
/* Where did this skb come from? */
|
|
@@ -706,82 +714,68 @@ static void sctp_v6_ecn_capable(struct sock *sk)
|
|
|
inet6_sk(sk)->tclass |= INET_ECN_ECT_0;
|
|
|
}
|
|
|
|
|
|
-/* Initialize a PF_INET6 socket msg_name. */
|
|
|
-static void sctp_inet6_msgname(char *msgname, int *addr_len)
|
|
|
-{
|
|
|
- struct sockaddr_in6 *sin6;
|
|
|
-
|
|
|
- sin6 = (struct sockaddr_in6 *)msgname;
|
|
|
- sin6->sin6_family = AF_INET6;
|
|
|
- sin6->sin6_flowinfo = 0;
|
|
|
- sin6->sin6_scope_id = 0; /*FIXME */
|
|
|
- *addr_len = sizeof(struct sockaddr_in6);
|
|
|
-}
|
|
|
-
|
|
|
/* Initialize a PF_INET msgname from a ulpevent. */
|
|
|
static void sctp_inet6_event_msgname(struct sctp_ulpevent *event,
|
|
|
char *msgname, int *addrlen)
|
|
|
{
|
|
|
- struct sockaddr_in6 *sin6, *sin6from;
|
|
|
-
|
|
|
- if (msgname) {
|
|
|
- union sctp_addr *addr;
|
|
|
- struct sctp_association *asoc;
|
|
|
-
|
|
|
- asoc = event->asoc;
|
|
|
- sctp_inet6_msgname(msgname, addrlen);
|
|
|
- sin6 = (struct sockaddr_in6 *)msgname;
|
|
|
- sin6->sin6_port = htons(asoc->peer.port);
|
|
|
- addr = &asoc->peer.primary_addr;
|
|
|
+ union sctp_addr *addr;
|
|
|
+ struct sctp_association *asoc;
|
|
|
+ union sctp_addr *paddr;
|
|
|
|
|
|
- /* Note: If we go to a common v6 format, this code
|
|
|
- * will change.
|
|
|
- */
|
|
|
+ if (!msgname)
|
|
|
+ return;
|
|
|
|
|
|
- /* Map ipv4 address into v4-mapped-on-v6 address. */
|
|
|
- if (sctp_sk(asoc->base.sk)->v4mapped &&
|
|
|
- AF_INET == addr->sa.sa_family) {
|
|
|
- sctp_v4_map_v6((union sctp_addr *)sin6);
|
|
|
- sin6->sin6_addr.s6_addr32[3] =
|
|
|
- addr->v4.sin_addr.s_addr;
|
|
|
- return;
|
|
|
- }
|
|
|
+ addr = (union sctp_addr *)msgname;
|
|
|
+ asoc = event->asoc;
|
|
|
+ paddr = &asoc->peer.primary_addr;
|
|
|
|
|
|
- sin6from = &asoc->peer.primary_addr.v6;
|
|
|
- sin6->sin6_addr = sin6from->sin6_addr;
|
|
|
- if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
|
|
|
- sin6->sin6_scope_id = sin6from->sin6_scope_id;
|
|
|
+ if (paddr->sa.sa_family == AF_INET) {
|
|
|
+ addr->v4.sin_family = AF_INET;
|
|
|
+ addr->v4.sin_port = htons(asoc->peer.port);
|
|
|
+ addr->v4.sin_addr = paddr->v4.sin_addr;
|
|
|
+ } else {
|
|
|
+ addr->v6.sin6_family = AF_INET6;
|
|
|
+ addr->v6.sin6_flowinfo = 0;
|
|
|
+ if (ipv6_addr_type(&paddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
|
|
|
+ addr->v6.sin6_scope_id = paddr->v6.sin6_scope_id;
|
|
|
+ else
|
|
|
+ addr->v6.sin6_scope_id = 0;
|
|
|
+ addr->v6.sin6_port = htons(asoc->peer.port);
|
|
|
+ addr->v6.sin6_addr = paddr->v6.sin6_addr;
|
|
|
}
|
|
|
+
|
|
|
+ *addrlen = sctp_v6_addr_to_user(sctp_sk(asoc->base.sk), addr);
|
|
|
}
|
|
|
|
|
|
/* Initialize a msg_name from an inbound skb. */
|
|
|
static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname,
|
|
|
int *addr_len)
|
|
|
{
|
|
|
+ union sctp_addr *addr;
|
|
|
struct sctphdr *sh;
|
|
|
- struct sockaddr_in6 *sin6;
|
|
|
-
|
|
|
- if (msgname) {
|
|
|
- sctp_inet6_msgname(msgname, addr_len);
|
|
|
- sin6 = (struct sockaddr_in6 *)msgname;
|
|
|
- sh = sctp_hdr(skb);
|
|
|
- sin6->sin6_port = sh->source;
|
|
|
-
|
|
|
- /* Map ipv4 address into v4-mapped-on-v6 address. */
|
|
|
- if (sctp_sk(skb->sk)->v4mapped &&
|
|
|
- ip_hdr(skb)->version == 4) {
|
|
|
- sctp_v4_map_v6((union sctp_addr *)sin6);
|
|
|
- sin6->sin6_addr.s6_addr32[3] = ip_hdr(skb)->saddr;
|
|
|
- return;
|
|
|
- }
|
|
|
|
|
|
- /* Otherwise, just copy the v6 address. */
|
|
|
- sin6->sin6_addr = ipv6_hdr(skb)->saddr;
|
|
|
- if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
|
|
|
+ if (!msgname)
|
|
|
+ return;
|
|
|
+
|
|
|
+ addr = (union sctp_addr *)msgname;
|
|
|
+ sh = sctp_hdr(skb);
|
|
|
+
|
|
|
+ if (ip_hdr(skb)->version == 4) {
|
|
|
+ addr->v4.sin_family = AF_INET;
|
|
|
+ addr->v4.sin_port = sh->source;
|
|
|
+ addr->v4.sin_addr.s_addr = ip_hdr(skb)->saddr;
|
|
|
+ } else {
|
|
|
+ addr->v6.sin6_family = AF_INET6;
|
|
|
+ addr->v6.sin6_flowinfo = 0;
|
|
|
+ addr->v6.sin6_port = sh->source;
|
|
|
+ addr->v6.sin6_addr = ipv6_hdr(skb)->saddr;
|
|
|
+ if (ipv6_addr_type(&addr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) {
|
|
|
struct sctp_ulpevent *ev = sctp_skb2event(skb);
|
|
|
- sin6->sin6_scope_id = ev->iif;
|
|
|
+ addr->v6.sin6_scope_id = ev->iif;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ *addr_len = sctp_v6_addr_to_user(sctp_sk(skb->sk), addr);
|
|
|
}
|
|
|
|
|
|
/* Do we support this AF? */
|
|
@@ -857,9 +851,6 @@ static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr)
|
|
|
return 0;
|
|
|
}
|
|
|
rcu_read_unlock();
|
|
|
- } else if (type == IPV6_ADDR_MAPPED) {
|
|
|
- if (!opt->v4mapped)
|
|
|
- return 0;
|
|
|
}
|
|
|
|
|
|
af = opt->pf->af;
|
|
@@ -914,6 +905,23 @@ static int sctp_inet6_supported_addrs(const struct sctp_sock *opt,
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
+/* Handle SCTP_I_WANT_MAPPED_V4_ADDR for getpeername() and getsockname() */
|
|
|
+static int sctp_getname(struct socket *sock, struct sockaddr *uaddr,
|
|
|
+ int *uaddr_len, int peer)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ rc = inet6_getname(sock, uaddr, uaddr_len, peer);
|
|
|
+
|
|
|
+ if (rc != 0)
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ *uaddr_len = sctp_v6_addr_to_user(sctp_sk(sock->sk),
|
|
|
+ (union sctp_addr *)uaddr);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
static const struct proto_ops inet6_seqpacket_ops = {
|
|
|
.family = PF_INET6,
|
|
|
.owner = THIS_MODULE,
|
|
@@ -922,7 +930,7 @@ static const struct proto_ops inet6_seqpacket_ops = {
|
|
|
.connect = inet_dgram_connect,
|
|
|
.socketpair = sock_no_socketpair,
|
|
|
.accept = inet_accept,
|
|
|
- .getname = inet6_getname,
|
|
|
+ .getname = sctp_getname,
|
|
|
.poll = sctp_poll,
|
|
|
.ioctl = inet6_ioctl,
|
|
|
.listen = sctp_inet_listen,
|
|
@@ -974,8 +982,6 @@ static struct sctp_af sctp_af_inet6 = {
|
|
|
.copy_addrlist = sctp_v6_copy_addrlist,
|
|
|
.from_skb = sctp_v6_from_skb,
|
|
|
.from_sk = sctp_v6_from_sk,
|
|
|
- .to_sk_saddr = sctp_v6_to_sk_saddr,
|
|
|
- .to_sk_daddr = sctp_v6_to_sk_daddr,
|
|
|
.from_addr_param = sctp_v6_from_addr_param,
|
|
|
.to_addr_param = sctp_v6_to_addr_param,
|
|
|
.cmp_addr = sctp_v6_cmp_addr,
|
|
@@ -1005,7 +1011,9 @@ static struct sctp_pf sctp_pf_inet6 = {
|
|
|
.send_verify = sctp_inet6_send_verify,
|
|
|
.supported_addrs = sctp_inet6_supported_addrs,
|
|
|
.create_accept_sk = sctp_v6_create_accept_sk,
|
|
|
- .addr_v4map = sctp_v6_addr_v4map,
|
|
|
+ .addr_to_user = sctp_v6_addr_to_user,
|
|
|
+ .to_sk_saddr = sctp_v6_to_sk_saddr,
|
|
|
+ .to_sk_daddr = sctp_v6_to_sk_daddr,
|
|
|
.af = &sctp_af_inet6,
|
|
|
};
|
|
|
|