// SPDX-License-Identifier: GPL-2.0-or-later /* SCTP kernel implementation * (C) Copyright IBM Corp. 2002, 2004 * Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2002-2003 Intel Corp. * * This file is part of the SCTP kernel implementation * * SCTP over IPv6. * * Please send any bug reports or fixes you make to the * email address(es): * lksctp developers <linux-sctp@vger.kernel.org> * * Written or modified by: * Le Yanqun <yanqun.le@nokia.com> * Hui Huang <hui.huang@nokia.com> * La Monte H.P. Yarroll <piggy@acm.org> * Sridhar Samudrala <sri@us.ibm.com> * Jon Grimm <jgrimm@us.ibm.com> * Ardelle Fan <ardelle.fan@intel.com> * * Based on: * linux/net/ipv6/tcp_ipv6.c
*/
/* Event handler for inet6 address addition/deletion events. * The sctp_local_addr_list needs to be protocted by a spin lock since * multiple notifiers (say IPv4 and IPv6) may be running at the same * time and thus corrupt the list. * The reader side is protected with RCU.
*/ staticint sctp_inet6addr_event(struct notifier_block *this, unsignedlong ev, void *ptr)
{ struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr; struct sctp_sockaddr_entry *addr = NULL; struct sctp_sockaddr_entry *temp; struct net *net = dev_net(ifa->idev->dev); int found = 0;
bp = &asoc->base.bind_addr;
scope = sctp_scope(daddr); /* ip6_dst_lookup has filled in the fl6->saddr for us. Check * to see if we can use it.
*/ if (!IS_ERR(dst)) { /* Walk through the bind address list and look for a bind * address that matches the source address of the returned dst.
*/
sctp_v6_to_addr(&dst_saddr, &fl6->saddr, htons(bp->port));
rcu_read_lock();
list_for_each_entry_rcu(laddr, &bp->address_list, list) { if (!laddr->valid || laddr->state == SCTP_ADDR_DEL ||
(laddr->state != SCTP_ADDR_SRC &&
!asoc->src_out_of_asoc_ok)) continue;
/* Do not compare against v4 addrs */ if ((laddr->a.sa.sa_family == AF_INET6) &&
(sctp_v6_cmp_addr(&dst_saddr, &laddr->a))) {
rcu_read_unlock();
t->dst = dst;
memcpy(fl, &_fl, sizeof(_fl)); goto out;
}
}
rcu_read_unlock(); /* None of the bound addresses match the source address of the * dst. So release it.
*/
dst_release(dst);
dst = NULL;
}
/* Walk through the bind address list and try to get the * best source address for a given destination.
*/
rcu_read_lock();
list_for_each_entry_rcu(laddr, &bp->address_list, list) { struct dst_entry *bdst;
__u8 bmatchlen;
/* Returns the number of consecutive initial bits that match in the 2 ipv6 * addresses.
*/ staticinlineint sctp_v6_addr_match_len(union sctp_addr *s1, union sctp_addr *s2)
{ return ipv6_addr_diff(&s1->v6.sin6_addr, &s2->v6.sin6_addr);
}
/* Fills in the source address(saddr) based on the destination address(daddr) * and asoc's bind address list.
*/ staticvoid sctp_v6_get_saddr(struct sctp_sock *sk, struct sctp_transport *t, struct flowi *fl)
{ struct flowi6 *fl6 = &fl->u.ip6; union sctp_addr *saddr = &t->saddr;
/* Copy over any ip options */ staticvoid sctp_v6_copy_ip_options(struct sock *sk, struct sock *newsk)
{ struct ipv6_pinfo *newnp, *np = inet6_sk(sk); struct ipv6_txoptions *opt;
newnp = inet6_sk(newsk);
rcu_read_lock();
opt = rcu_dereference(np->opt); if (opt) {
opt = ipv6_dup_options(newsk, opt); if (!opt)
pr_err("%s: Failed to copy ip options\n", __func__);
}
RCU_INIT_POINTER(newnp->opt, opt);
rcu_read_unlock();
}
/* Account for the IP options */ staticint sctp_v6_ip_options_len(struct sock *sk)
{ struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_txoptions *opt; int len = 0;
rcu_read_lock();
opt = rcu_dereference(np->opt); if (opt)
len = opt->opt_flen + opt->opt_nflen;
rcu_read_unlock(); return len;
}
/* Initialize a sockaddr_storage from in incoming skb. */ staticvoid sctp_v6_from_skb(union sctp_addr *addr, struct sk_buff *skb, int is_saddr)
{ /* Always called on head skb, so this is safe */ struct sctphdr *sh = sctp_hdr(skb); struct sockaddr_in6 *sa = &addr->v6;
/* Initialize a sctp_addr from an address parameter. */ staticbool sctp_v6_from_addr_param(union sctp_addr *addr, union sctp_addr_param *param,
__be16 port, int iif)
{ if (ntohs(param->v6.param_hdr.length) < sizeof(struct sctp_ipv6addr_param)) returnfalse;
/* Initialize an address parameter from a sctp_addr and return the length * of the address parameter.
*/ staticint sctp_v6_to_addr_param(constunion sctp_addr *addr, union sctp_addr_param *param)
{ int length = sizeof(struct sctp_ipv6addr_param);
if (!ipv6_addr_equal(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr)) return 0;
/* If this is a linklocal address, compare the scope_id. */ if ((ipv6_addr_type(&addr1->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) &&
addr1->v6.sin6_scope_id && addr2->v6.sin6_scope_id &&
addr1->v6.sin6_scope_id != addr2->v6.sin6_scope_id) return 0;
return 1;
}
/* Compare addresses exactly. * v4-mapped-v6 is also in consideration.
*/ staticint sctp_v6_cmp_addr(constunion sctp_addr *addr1, constunion sctp_addr *addr2)
{ return __sctp_v6_cmp_addr(addr1, addr2) &&
addr1->v6.sin6_port == addr2->v6.sin6_port;
}
/* Is this a wildcard address? */ staticint sctp_v6_is_any(constunion sctp_addr *addr)
{ return ipv6_addr_any(&addr->v6.sin6_addr);
}
/* Should this be available for binding? */ staticint sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
{ conststruct in6_addr *in6 = (conststruct in6_addr *)&addr->v6.sin6_addr; struct sock *sk = &sp->inet.sk; struct net *net = sock_net(sk); struct net_device *dev = NULL; int type, res, bound_dev_if;
type = ipv6_addr_type(in6); if (IPV6_ADDR_ANY == type) return 1; if (type == IPV6_ADDR_MAPPED) { if (sp && ipv6_only_sock(sctp_opt2sk(sp))) return 0;
sctp_v6_map_v4(addr); return sctp_get_af_specific(AF_INET)->available(addr, sp);
} if (!(type & IPV6_ADDR_UNICAST)) return 0;
rcu_read_lock();
bound_dev_if = READ_ONCE(sk->sk_bound_dev_if); if (bound_dev_if) {
res = 0;
dev = dev_get_by_index_rcu(net, bound_dev_if); if (!dev) goto out;
}
res = ipv6_can_nonlocal_bind(net, &sp->inet) ||
ipv6_chk_addr(net, in6, dev, 0);
out:
rcu_read_unlock(); return res;
}
/* This function checks if the address is a valid address to be used for * SCTP. * * Output: * Return 0 - If the address is a non-unicast or an illegal address. * Return 1 - If the address is a unicast.
*/ staticint sctp_v6_addr_valid(union sctp_addr *addr, struct sctp_sock *sp, conststruct sk_buff *skb)
{ int ret = ipv6_addr_type(&addr->v6.sin6_addr);
/* Support v4-mapped-v6 address. */ if (ret == IPV6_ADDR_MAPPED) { /* Note: This routine is used in input, so v4-mapped-v6 * are disallowed here when there is no sctp_sock.
*/ if (sp && ipv6_only_sock(sctp_opt2sk(sp))) return 0;
sctp_v6_map_v4(addr); return sctp_get_af_specific(AF_INET)->addr_valid(addr, sp, skb);
}
/* Is this a non-unicast address */ if (!(ret & IPV6_ADDR_UNICAST)) return 0;
return 1;
}
/* What is the scope of 'addr'? */ staticenum sctp_scope sctp_v6_scope(union sctp_addr *addr)
{ enum sctp_scope retval; int v6scope;
/* The IPv6 scope is really a set of bit fields. * See IFA_* in <net/if_inet6.h>. Map to a generic SCTP scope.
*/
v6scope = ipv6_addr_scope(&addr->v6.sin6_addr); switch (v6scope) { case IFA_HOST:
retval = SCTP_SCOPE_LOOPBACK; break; case IFA_LINK:
retval = SCTP_SCOPE_LINK; break; case IFA_SITE:
retval = SCTP_SCOPE_PRIVATE; break; default:
retval = SCTP_SCOPE_GLOBAL; break;
}
return retval;
}
/* Create and initialize a new sk for the socket to be returned by accept(). */ staticstruct sock *sctp_v6_create_accept_sk(struct sock *sk, struct sctp_association *asoc, bool kern)
{ struct sock *newsk; struct ipv6_pinfo *newnp, *np = inet6_sk(sk); struct sctp6_sock *newsctp6sk;
/* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname() * and getpeername().
*/
sctp_v6_to_sk_daddr(&asoc->peer.primary_addr, newsk);
newsk->sk_v6_rcv_saddr = sk->sk_v6_rcv_saddr;
if (newsk->sk_prot->init(newsk)) {
sk_common_release(newsk);
newsk = NULL;
}
out: return newsk;
}
/* 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.
*/ staticint sctp_v6_addr_to_user(struct sctp_sock *sp, union sctp_addr *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);
}
/* Initialize a PF_INET msgname from a ulpevent. */ staticvoid sctp_inet6_event_msgname(struct sctp_ulpevent *event, char *msgname, int *addrlen)
{ union sctp_addr *addr; struct sctp_association *asoc; union sctp_addr *paddr;
/* Initialize a msg_name from an inbound skb. */ staticvoid sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname, int *addr_len)
{ union sctp_addr *addr; struct sctphdr *sh;
if (!msgname) return;
addr = (union sctp_addr *)msgname;
sh = sctp_hdr(skb);
/* Do we support this AF? */ staticint sctp_inet6_af_supported(sa_family_t family, struct sctp_sock *sp)
{ switch (family) { case AF_INET6: return 1; /* v4-mapped-v6 addresses */ case AF_INET: if (!ipv6_only_sock(sctp_opt2sk(sp))) return 1;
fallthrough; default: return 0;
}
}
/* Address matching with wildcards allowed. This extra level * of indirection lets us choose whether a PF_INET6 should * disallow any v4 addresses if we so choose.
*/ staticint sctp_inet6_cmp_addr(constunion sctp_addr *addr1, constunion sctp_addr *addr2, struct sctp_sock *opt)
{ struct sock *sk = sctp_opt2sk(opt); struct sctp_af *af1, *af2;
/* Verify that the provided sockaddr looks bindable. Common verification, * has already been taken care of.
*/ staticint sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr)
{ struct sctp_af *af;
/* ASSERT: address family has already been verified. */ if (addr->sa.sa_family != AF_INET6)
af = sctp_get_af_specific(addr->sa.sa_family); else { int type = ipv6_addr_type(&addr->v6.sin6_addr); struct net_device *dev;
if (type & IPV6_ADDR_LINKLOCAL) { struct net *net; if (!addr->v6.sin6_scope_id) return 0;
net = sock_net(&opt->inet.sk);
rcu_read_lock();
dev = dev_get_by_index_rcu(net, addr->v6.sin6_scope_id); if (!dev || !(ipv6_can_nonlocal_bind(net, &opt->inet) ||
ipv6_chk_addr(net, &addr->v6.sin6_addr,
dev, 0))) {
rcu_read_unlock(); return 0;
}
rcu_read_unlock();
}
af = opt->pf->af;
} return af->available(addr, opt);
}
/* Verify that the provided sockaddr looks sendable. Common verification, * has already been taken care of.
*/ staticint sctp_inet6_send_verify(struct sctp_sock *opt, union sctp_addr *addr)
{ struct sctp_af *af = NULL;
/* ASSERT: address family has already been verified. */ if (addr->sa.sa_family != AF_INET6)
af = sctp_get_af_specific(addr->sa.sa_family); else { int type = ipv6_addr_type(&addr->v6.sin6_addr); struct net_device *dev;
if (type & IPV6_ADDR_LINKLOCAL) { if (!addr->v6.sin6_scope_id) return 0;
rcu_read_lock();
dev = dev_get_by_index_rcu(sock_net(&opt->inet.sk),
addr->v6.sin6_scope_id);
rcu_read_unlock(); if (!dev) return 0;
}
af = opt->pf->af;
}
return af != NULL;
}
/* Fill in Supported Address Type information for INIT and INIT-ACK * chunks. Note: In the future, we may want to look at sock options * to determine whether a PF_INET6 socket really wants to have IPV4 * addresses. * Returns number of addresses supported.
*/ staticint sctp_inet6_supported_addrs(conststruct sctp_sock *opt,
__be16 *types)
{
types[0] = SCTP_PARAM_IPV6_ADDRESS; if (!opt || !ipv6_only_sock(sctp_opt2sk(opt))) {
types[1] = SCTP_PARAM_IPV4_ADDRESS; return 2;
} return 1;
}
/* Handle SCTP_I_WANT_MAPPED_V4_ADDR for getpeername() and getsockname() */ staticint sctp_getname(struct socket *sock, struct sockaddr *uaddr, int peer)
{ int rc;
/* Initialize IPv6 support and register with socket layer. */ void sctp_v6_pf_init(void)
{ /* Register the SCTP specific PF_INET6 functions. */
sctp_register_pf(&sctp_pf_inet6, PF_INET6);
/* Register the SCTP specific AF_INET6 functions. */
sctp_register_af(&sctp_af_inet6);
}