162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* SCTP kernel implementation
362306a36Sopenharmony_ci * (C) Copyright IBM Corp. 2001, 2003
462306a36Sopenharmony_ci * Copyright (c) Cisco 1999,2000
562306a36Sopenharmony_ci * Copyright (c) Motorola 1999,2000,2001
662306a36Sopenharmony_ci * Copyright (c) La Monte H.P. Yarroll 2001
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * This file is part of the SCTP kernel implementation.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * A collection class to handle the storage of transport addresses.
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Please send any bug reports or fixes you make to the
1362306a36Sopenharmony_ci * email address(es):
1462306a36Sopenharmony_ci *    lksctp developers <linux-sctp@vger.kernel.org>
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * Written or modified by:
1762306a36Sopenharmony_ci *    La Monte H.P. Yarroll <piggy@acm.org>
1862306a36Sopenharmony_ci *    Karl Knutson          <karl@athena.chicago.il.us>
1962306a36Sopenharmony_ci *    Jon Grimm             <jgrimm@us.ibm.com>
2062306a36Sopenharmony_ci *    Daisy Chang           <daisyc@us.ibm.com>
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <linux/types.h>
2462306a36Sopenharmony_ci#include <linux/slab.h>
2562306a36Sopenharmony_ci#include <linux/in.h>
2662306a36Sopenharmony_ci#include <net/sock.h>
2762306a36Sopenharmony_ci#include <net/ipv6.h>
2862306a36Sopenharmony_ci#include <net/if_inet6.h>
2962306a36Sopenharmony_ci#include <net/sctp/sctp.h>
3062306a36Sopenharmony_ci#include <net/sctp/sm.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/* Forward declarations for internal helpers. */
3362306a36Sopenharmony_cistatic int sctp_copy_one_addr(struct net *net, struct sctp_bind_addr *dest,
3462306a36Sopenharmony_ci			      union sctp_addr *addr, enum sctp_scope scope,
3562306a36Sopenharmony_ci			      gfp_t gfp, int flags);
3662306a36Sopenharmony_cistatic void sctp_bind_addr_clean(struct sctp_bind_addr *);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/* First Level Abstractions. */
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/* Copy 'src' to 'dest' taking 'scope' into account.  Omit addresses
4162306a36Sopenharmony_ci * in 'src' which have a broader scope than 'scope'.
4262306a36Sopenharmony_ci */
4362306a36Sopenharmony_ciint sctp_bind_addr_copy(struct net *net, struct sctp_bind_addr *dest,
4462306a36Sopenharmony_ci			const struct sctp_bind_addr *src,
4562306a36Sopenharmony_ci			enum sctp_scope scope, gfp_t gfp,
4662306a36Sopenharmony_ci			int flags)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	struct sctp_sockaddr_entry *addr;
4962306a36Sopenharmony_ci	int error = 0;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	/* All addresses share the same port.  */
5262306a36Sopenharmony_ci	dest->port = src->port;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	/* Extract the addresses which are relevant for this scope.  */
5562306a36Sopenharmony_ci	list_for_each_entry(addr, &src->address_list, list) {
5662306a36Sopenharmony_ci		error = sctp_copy_one_addr(net, dest, &addr->a, scope,
5762306a36Sopenharmony_ci					   gfp, flags);
5862306a36Sopenharmony_ci		if (error < 0)
5962306a36Sopenharmony_ci			goto out;
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	/* If there are no addresses matching the scope and
6362306a36Sopenharmony_ci	 * this is global scope, try to get a link scope address, with
6462306a36Sopenharmony_ci	 * the assumption that we must be sitting behind a NAT.
6562306a36Sopenharmony_ci	 */
6662306a36Sopenharmony_ci	if (list_empty(&dest->address_list) && (SCTP_SCOPE_GLOBAL == scope)) {
6762306a36Sopenharmony_ci		list_for_each_entry(addr, &src->address_list, list) {
6862306a36Sopenharmony_ci			error = sctp_copy_one_addr(net, dest, &addr->a,
6962306a36Sopenharmony_ci						   SCTP_SCOPE_LINK, gfp,
7062306a36Sopenharmony_ci						   flags);
7162306a36Sopenharmony_ci			if (error < 0)
7262306a36Sopenharmony_ci				goto out;
7362306a36Sopenharmony_ci		}
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	/* If somehow no addresses were found that can be used with this
7762306a36Sopenharmony_ci	 * scope, it's an error.
7862306a36Sopenharmony_ci	 */
7962306a36Sopenharmony_ci	if (list_empty(&dest->address_list))
8062306a36Sopenharmony_ci		error = -ENETUNREACH;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ciout:
8362306a36Sopenharmony_ci	if (error)
8462306a36Sopenharmony_ci		sctp_bind_addr_clean(dest);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	return error;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/* Exactly duplicate the address lists.  This is necessary when doing
9062306a36Sopenharmony_ci * peer-offs and accepts.  We don't want to put all the current system
9162306a36Sopenharmony_ci * addresses into the endpoint.  That's useless.  But we do want duplicat
9262306a36Sopenharmony_ci * the list of bound addresses that the older endpoint used.
9362306a36Sopenharmony_ci */
9462306a36Sopenharmony_ciint sctp_bind_addr_dup(struct sctp_bind_addr *dest,
9562306a36Sopenharmony_ci			const struct sctp_bind_addr *src,
9662306a36Sopenharmony_ci			gfp_t gfp)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	struct sctp_sockaddr_entry *addr;
9962306a36Sopenharmony_ci	int error = 0;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	/* All addresses share the same port.  */
10262306a36Sopenharmony_ci	dest->port = src->port;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	list_for_each_entry(addr, &src->address_list, list) {
10562306a36Sopenharmony_ci		error = sctp_add_bind_addr(dest, &addr->a, sizeof(addr->a),
10662306a36Sopenharmony_ci					   1, gfp);
10762306a36Sopenharmony_ci		if (error < 0)
10862306a36Sopenharmony_ci			break;
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	return error;
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci/* Initialize the SCTP_bind_addr structure for either an endpoint or
11562306a36Sopenharmony_ci * an association.
11662306a36Sopenharmony_ci */
11762306a36Sopenharmony_civoid sctp_bind_addr_init(struct sctp_bind_addr *bp, __u16 port)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	INIT_LIST_HEAD(&bp->address_list);
12062306a36Sopenharmony_ci	bp->port = port;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/* Dispose of the address list. */
12462306a36Sopenharmony_cistatic void sctp_bind_addr_clean(struct sctp_bind_addr *bp)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	struct sctp_sockaddr_entry *addr, *temp;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	/* Empty the bind address list. */
12962306a36Sopenharmony_ci	list_for_each_entry_safe(addr, temp, &bp->address_list, list) {
13062306a36Sopenharmony_ci		list_del_rcu(&addr->list);
13162306a36Sopenharmony_ci		kfree_rcu(addr, rcu);
13262306a36Sopenharmony_ci		SCTP_DBG_OBJCNT_DEC(addr);
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci/* Dispose of an SCTP_bind_addr structure  */
13762306a36Sopenharmony_civoid sctp_bind_addr_free(struct sctp_bind_addr *bp)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	/* Empty the bind address list. */
14062306a36Sopenharmony_ci	sctp_bind_addr_clean(bp);
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci/* Add an address to the bind address list in the SCTP_bind_addr structure. */
14462306a36Sopenharmony_ciint sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new,
14562306a36Sopenharmony_ci		       int new_size, __u8 addr_state, gfp_t gfp)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	struct sctp_sockaddr_entry *addr;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	/* Add the address to the bind address list.  */
15062306a36Sopenharmony_ci	addr = kzalloc(sizeof(*addr), gfp);
15162306a36Sopenharmony_ci	if (!addr)
15262306a36Sopenharmony_ci		return -ENOMEM;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	memcpy(&addr->a, new, min_t(size_t, sizeof(*new), new_size));
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	/* Fix up the port if it has not yet been set.
15762306a36Sopenharmony_ci	 * Both v4 and v6 have the port at the same offset.
15862306a36Sopenharmony_ci	 */
15962306a36Sopenharmony_ci	if (!addr->a.v4.sin_port)
16062306a36Sopenharmony_ci		addr->a.v4.sin_port = htons(bp->port);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	addr->state = addr_state;
16362306a36Sopenharmony_ci	addr->valid = 1;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	INIT_LIST_HEAD(&addr->list);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/* We always hold a socket lock when calling this function,
16862306a36Sopenharmony_ci	 * and that acts as a writer synchronizing lock.
16962306a36Sopenharmony_ci	 */
17062306a36Sopenharmony_ci	list_add_tail_rcu(&addr->list, &bp->address_list);
17162306a36Sopenharmony_ci	SCTP_DBG_OBJCNT_INC(addr);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return 0;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci/* Delete an address from the bind address list in the SCTP_bind_addr
17762306a36Sopenharmony_ci * structure.
17862306a36Sopenharmony_ci */
17962306a36Sopenharmony_ciint sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct sctp_sockaddr_entry *addr, *temp;
18262306a36Sopenharmony_ci	int found = 0;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/* We hold the socket lock when calling this function,
18562306a36Sopenharmony_ci	 * and that acts as a writer synchronizing lock.
18662306a36Sopenharmony_ci	 */
18762306a36Sopenharmony_ci	list_for_each_entry_safe(addr, temp, &bp->address_list, list) {
18862306a36Sopenharmony_ci		if (sctp_cmp_addr_exact(&addr->a, del_addr)) {
18962306a36Sopenharmony_ci			/* Found the exact match. */
19062306a36Sopenharmony_ci			found = 1;
19162306a36Sopenharmony_ci			addr->valid = 0;
19262306a36Sopenharmony_ci			list_del_rcu(&addr->list);
19362306a36Sopenharmony_ci			break;
19462306a36Sopenharmony_ci		}
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (found) {
19862306a36Sopenharmony_ci		kfree_rcu(addr, rcu);
19962306a36Sopenharmony_ci		SCTP_DBG_OBJCNT_DEC(addr);
20062306a36Sopenharmony_ci		return 0;
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	return -EINVAL;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci/* Create a network byte-order representation of all the addresses
20762306a36Sopenharmony_ci * formated as SCTP parameters.
20862306a36Sopenharmony_ci *
20962306a36Sopenharmony_ci * The second argument is the return value for the length.
21062306a36Sopenharmony_ci */
21162306a36Sopenharmony_ciunion sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
21262306a36Sopenharmony_ci					 int *addrs_len,
21362306a36Sopenharmony_ci					 gfp_t gfp)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	union sctp_params addrparms;
21662306a36Sopenharmony_ci	union sctp_params retval;
21762306a36Sopenharmony_ci	int addrparms_len;
21862306a36Sopenharmony_ci	union sctp_addr_param rawaddr;
21962306a36Sopenharmony_ci	int len;
22062306a36Sopenharmony_ci	struct sctp_sockaddr_entry *addr;
22162306a36Sopenharmony_ci	struct list_head *pos;
22262306a36Sopenharmony_ci	struct sctp_af *af;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	addrparms_len = 0;
22562306a36Sopenharmony_ci	len = 0;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	/* Allocate enough memory at once. */
22862306a36Sopenharmony_ci	list_for_each(pos, &bp->address_list) {
22962306a36Sopenharmony_ci		len += sizeof(union sctp_addr_param);
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	/* Don't even bother embedding an address if there
23362306a36Sopenharmony_ci	 * is only one.
23462306a36Sopenharmony_ci	 */
23562306a36Sopenharmony_ci	if (len == sizeof(union sctp_addr_param)) {
23662306a36Sopenharmony_ci		retval.v = NULL;
23762306a36Sopenharmony_ci		goto end_raw;
23862306a36Sopenharmony_ci	}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	retval.v = kmalloc(len, gfp);
24162306a36Sopenharmony_ci	if (!retval.v)
24262306a36Sopenharmony_ci		goto end_raw;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	addrparms = retval;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	list_for_each_entry(addr, &bp->address_list, list) {
24762306a36Sopenharmony_ci		af = sctp_get_af_specific(addr->a.v4.sin_family);
24862306a36Sopenharmony_ci		len = af->to_addr_param(&addr->a, &rawaddr);
24962306a36Sopenharmony_ci		memcpy(addrparms.v, &rawaddr, len);
25062306a36Sopenharmony_ci		addrparms.v += len;
25162306a36Sopenharmony_ci		addrparms_len += len;
25262306a36Sopenharmony_ci	}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ciend_raw:
25562306a36Sopenharmony_ci	*addrs_len = addrparms_len;
25662306a36Sopenharmony_ci	return retval;
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci/*
26062306a36Sopenharmony_ci * Create an address list out of the raw address list format (IPv4 and IPv6
26162306a36Sopenharmony_ci * address parameters).
26262306a36Sopenharmony_ci */
26362306a36Sopenharmony_ciint sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list,
26462306a36Sopenharmony_ci			   int addrs_len, __u16 port, gfp_t gfp)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	union sctp_addr_param *rawaddr;
26762306a36Sopenharmony_ci	struct sctp_paramhdr *param;
26862306a36Sopenharmony_ci	union sctp_addr addr;
26962306a36Sopenharmony_ci	int retval = 0;
27062306a36Sopenharmony_ci	int len;
27162306a36Sopenharmony_ci	struct sctp_af *af;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	/* Convert the raw address to standard address format */
27462306a36Sopenharmony_ci	while (addrs_len) {
27562306a36Sopenharmony_ci		param = (struct sctp_paramhdr *)raw_addr_list;
27662306a36Sopenharmony_ci		rawaddr = (union sctp_addr_param *)raw_addr_list;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci		af = sctp_get_af_specific(param_type2af(param->type));
27962306a36Sopenharmony_ci		if (unlikely(!af) ||
28062306a36Sopenharmony_ci		    !af->from_addr_param(&addr, rawaddr, htons(port), 0)) {
28162306a36Sopenharmony_ci			retval = -EINVAL;
28262306a36Sopenharmony_ci			goto out_err;
28362306a36Sopenharmony_ci		}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci		if (sctp_bind_addr_state(bp, &addr) != -1)
28662306a36Sopenharmony_ci			goto next;
28762306a36Sopenharmony_ci		retval = sctp_add_bind_addr(bp, &addr, sizeof(addr),
28862306a36Sopenharmony_ci					    SCTP_ADDR_SRC, gfp);
28962306a36Sopenharmony_ci		if (retval)
29062306a36Sopenharmony_ci			/* Can't finish building the list, clean up. */
29162306a36Sopenharmony_ci			goto out_err;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cinext:
29462306a36Sopenharmony_ci		len = ntohs(param->length);
29562306a36Sopenharmony_ci		addrs_len -= len;
29662306a36Sopenharmony_ci		raw_addr_list += len;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	return retval;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ciout_err:
30262306a36Sopenharmony_ci	if (retval)
30362306a36Sopenharmony_ci		sctp_bind_addr_clean(bp);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	return retval;
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci/********************************************************************
30962306a36Sopenharmony_ci * 2nd Level Abstractions
31062306a36Sopenharmony_ci ********************************************************************/
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci/* Does this contain a specified address?  Allow wildcarding. */
31362306a36Sopenharmony_ciint sctp_bind_addr_match(struct sctp_bind_addr *bp,
31462306a36Sopenharmony_ci			 const union sctp_addr *addr,
31562306a36Sopenharmony_ci			 struct sctp_sock *opt)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	struct sctp_sockaddr_entry *laddr;
31862306a36Sopenharmony_ci	int match = 0;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	rcu_read_lock();
32162306a36Sopenharmony_ci	list_for_each_entry_rcu(laddr, &bp->address_list, list) {
32262306a36Sopenharmony_ci		if (!laddr->valid)
32362306a36Sopenharmony_ci			continue;
32462306a36Sopenharmony_ci		if (opt->pf->cmp_addr(&laddr->a, addr, opt)) {
32562306a36Sopenharmony_ci			match = 1;
32662306a36Sopenharmony_ci			break;
32762306a36Sopenharmony_ci		}
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci	rcu_read_unlock();
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	return match;
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ciint sctp_bind_addrs_check(struct sctp_sock *sp,
33562306a36Sopenharmony_ci			  struct sctp_sock *sp2, int cnt2)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	struct sctp_bind_addr *bp2 = &sp2->ep->base.bind_addr;
33862306a36Sopenharmony_ci	struct sctp_bind_addr *bp = &sp->ep->base.bind_addr;
33962306a36Sopenharmony_ci	struct sctp_sockaddr_entry *laddr, *laddr2;
34062306a36Sopenharmony_ci	bool exist = false;
34162306a36Sopenharmony_ci	int cnt = 0;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	rcu_read_lock();
34462306a36Sopenharmony_ci	list_for_each_entry_rcu(laddr, &bp->address_list, list) {
34562306a36Sopenharmony_ci		list_for_each_entry_rcu(laddr2, &bp2->address_list, list) {
34662306a36Sopenharmony_ci			if (sp->pf->af->cmp_addr(&laddr->a, &laddr2->a) &&
34762306a36Sopenharmony_ci			    laddr->valid && laddr2->valid) {
34862306a36Sopenharmony_ci				exist = true;
34962306a36Sopenharmony_ci				goto next;
35062306a36Sopenharmony_ci			}
35162306a36Sopenharmony_ci		}
35262306a36Sopenharmony_ci		cnt = 0;
35362306a36Sopenharmony_ci		break;
35462306a36Sopenharmony_cinext:
35562306a36Sopenharmony_ci		cnt++;
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci	rcu_read_unlock();
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	return (cnt == cnt2) ? 0 : (exist ? -EEXIST : 1);
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci/* Does the address 'addr' conflict with any addresses in
36362306a36Sopenharmony_ci * the bp.
36462306a36Sopenharmony_ci */
36562306a36Sopenharmony_ciint sctp_bind_addr_conflict(struct sctp_bind_addr *bp,
36662306a36Sopenharmony_ci			    const union sctp_addr *addr,
36762306a36Sopenharmony_ci			    struct sctp_sock *bp_sp,
36862306a36Sopenharmony_ci			    struct sctp_sock *addr_sp)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	struct sctp_sockaddr_entry *laddr;
37162306a36Sopenharmony_ci	int conflict = 0;
37262306a36Sopenharmony_ci	struct sctp_sock *sp;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	/* Pick the IPv6 socket as the basis of comparison
37562306a36Sopenharmony_ci	 * since it's usually a superset of the IPv4.
37662306a36Sopenharmony_ci	 * If there is no IPv6 socket, then default to bind_addr.
37762306a36Sopenharmony_ci	 */
37862306a36Sopenharmony_ci	if (sctp_opt2sk(bp_sp)->sk_family == AF_INET6)
37962306a36Sopenharmony_ci		sp = bp_sp;
38062306a36Sopenharmony_ci	else if (sctp_opt2sk(addr_sp)->sk_family == AF_INET6)
38162306a36Sopenharmony_ci		sp = addr_sp;
38262306a36Sopenharmony_ci	else
38362306a36Sopenharmony_ci		sp = bp_sp;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	rcu_read_lock();
38662306a36Sopenharmony_ci	list_for_each_entry_rcu(laddr, &bp->address_list, list) {
38762306a36Sopenharmony_ci		if (!laddr->valid)
38862306a36Sopenharmony_ci			continue;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci		conflict = sp->pf->cmp_addr(&laddr->a, addr, sp);
39162306a36Sopenharmony_ci		if (conflict)
39262306a36Sopenharmony_ci			break;
39362306a36Sopenharmony_ci	}
39462306a36Sopenharmony_ci	rcu_read_unlock();
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	return conflict;
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci/* Get the state of the entry in the bind_addr_list */
40062306a36Sopenharmony_ciint sctp_bind_addr_state(const struct sctp_bind_addr *bp,
40162306a36Sopenharmony_ci			 const union sctp_addr *addr)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	struct sctp_sockaddr_entry *laddr;
40462306a36Sopenharmony_ci	struct sctp_af *af;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	af = sctp_get_af_specific(addr->sa.sa_family);
40762306a36Sopenharmony_ci	if (unlikely(!af))
40862306a36Sopenharmony_ci		return -1;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	list_for_each_entry_rcu(laddr, &bp->address_list, list) {
41162306a36Sopenharmony_ci		if (!laddr->valid)
41262306a36Sopenharmony_ci			continue;
41362306a36Sopenharmony_ci		if (af->cmp_addr(&laddr->a, addr))
41462306a36Sopenharmony_ci			return laddr->state;
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	return -1;
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci/* Find the first address in the bind address list that is not present in
42162306a36Sopenharmony_ci * the addrs packed array.
42262306a36Sopenharmony_ci */
42362306a36Sopenharmony_ciunion sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr	*bp,
42462306a36Sopenharmony_ci					const union sctp_addr	*addrs,
42562306a36Sopenharmony_ci					int			addrcnt,
42662306a36Sopenharmony_ci					struct sctp_sock	*opt)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	struct sctp_sockaddr_entry	*laddr;
42962306a36Sopenharmony_ci	union sctp_addr			*addr;
43062306a36Sopenharmony_ci	void 				*addr_buf;
43162306a36Sopenharmony_ci	struct sctp_af			*af;
43262306a36Sopenharmony_ci	int				i;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	/* This is only called sctp_send_asconf_del_ip() and we hold
43562306a36Sopenharmony_ci	 * the socket lock in that code patch, so that address list
43662306a36Sopenharmony_ci	 * can't change.
43762306a36Sopenharmony_ci	 */
43862306a36Sopenharmony_ci	list_for_each_entry(laddr, &bp->address_list, list) {
43962306a36Sopenharmony_ci		addr_buf = (union sctp_addr *)addrs;
44062306a36Sopenharmony_ci		for (i = 0; i < addrcnt; i++) {
44162306a36Sopenharmony_ci			addr = addr_buf;
44262306a36Sopenharmony_ci			af = sctp_get_af_specific(addr->v4.sin_family);
44362306a36Sopenharmony_ci			if (!af)
44462306a36Sopenharmony_ci				break;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci			if (opt->pf->cmp_addr(&laddr->a, addr, opt))
44762306a36Sopenharmony_ci				break;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci			addr_buf += af->sockaddr_len;
45062306a36Sopenharmony_ci		}
45162306a36Sopenharmony_ci		if (i == addrcnt)
45262306a36Sopenharmony_ci			return &laddr->a;
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	return NULL;
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci/* Copy out addresses from the global local address list. */
45962306a36Sopenharmony_cistatic int sctp_copy_one_addr(struct net *net, struct sctp_bind_addr *dest,
46062306a36Sopenharmony_ci			      union sctp_addr *addr, enum sctp_scope scope,
46162306a36Sopenharmony_ci			      gfp_t gfp, int flags)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	int error = 0;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	if (sctp_is_any(NULL, addr)) {
46662306a36Sopenharmony_ci		error = sctp_copy_local_addr_list(net, dest, scope, gfp, flags);
46762306a36Sopenharmony_ci	} else if (sctp_in_scope(net, addr, scope)) {
46862306a36Sopenharmony_ci		/* Now that the address is in scope, check to see if
46962306a36Sopenharmony_ci		 * the address type is supported by local sock as
47062306a36Sopenharmony_ci		 * well as the remote peer.
47162306a36Sopenharmony_ci		 */
47262306a36Sopenharmony_ci		if ((((AF_INET == addr->sa.sa_family) &&
47362306a36Sopenharmony_ci		      (flags & SCTP_ADDR4_ALLOWED) &&
47462306a36Sopenharmony_ci		      (flags & SCTP_ADDR4_PEERSUPP))) ||
47562306a36Sopenharmony_ci		    (((AF_INET6 == addr->sa.sa_family) &&
47662306a36Sopenharmony_ci		      (flags & SCTP_ADDR6_ALLOWED) &&
47762306a36Sopenharmony_ci		      (flags & SCTP_ADDR6_PEERSUPP))))
47862306a36Sopenharmony_ci			error = sctp_add_bind_addr(dest, addr, sizeof(*addr),
47962306a36Sopenharmony_ci						   SCTP_ADDR_SRC, gfp);
48062306a36Sopenharmony_ci	}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	return error;
48362306a36Sopenharmony_ci}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci/* Is this a wildcard address?  */
48662306a36Sopenharmony_ciint sctp_is_any(struct sock *sk, const union sctp_addr *addr)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	unsigned short fam = 0;
48962306a36Sopenharmony_ci	struct sctp_af *af;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	/* Try to get the right address family */
49262306a36Sopenharmony_ci	if (addr->sa.sa_family != AF_UNSPEC)
49362306a36Sopenharmony_ci		fam = addr->sa.sa_family;
49462306a36Sopenharmony_ci	else if (sk)
49562306a36Sopenharmony_ci		fam = sk->sk_family;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	af = sctp_get_af_specific(fam);
49862306a36Sopenharmony_ci	if (!af)
49962306a36Sopenharmony_ci		return 0;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	return af->is_any(addr);
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci/* Is 'addr' valid for 'scope'?  */
50562306a36Sopenharmony_ciint sctp_in_scope(struct net *net, const union sctp_addr *addr,
50662306a36Sopenharmony_ci		  enum sctp_scope scope)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	enum sctp_scope addr_scope = sctp_scope(addr);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	/* The unusable SCTP addresses will not be considered with
51162306a36Sopenharmony_ci	 * any defined scopes.
51262306a36Sopenharmony_ci	 */
51362306a36Sopenharmony_ci	if (SCTP_SCOPE_UNUSABLE == addr_scope)
51462306a36Sopenharmony_ci		return 0;
51562306a36Sopenharmony_ci	/*
51662306a36Sopenharmony_ci	 * For INIT and INIT-ACK address list, let L be the level of
51762306a36Sopenharmony_ci	 * requested destination address, sender and receiver
51862306a36Sopenharmony_ci	 * SHOULD include all of its addresses with level greater
51962306a36Sopenharmony_ci	 * than or equal to L.
52062306a36Sopenharmony_ci	 *
52162306a36Sopenharmony_ci	 * Address scoping can be selectively controlled via sysctl
52262306a36Sopenharmony_ci	 * option
52362306a36Sopenharmony_ci	 */
52462306a36Sopenharmony_ci	switch (net->sctp.scope_policy) {
52562306a36Sopenharmony_ci	case SCTP_SCOPE_POLICY_DISABLE:
52662306a36Sopenharmony_ci		return 1;
52762306a36Sopenharmony_ci	case SCTP_SCOPE_POLICY_ENABLE:
52862306a36Sopenharmony_ci		if (addr_scope <= scope)
52962306a36Sopenharmony_ci			return 1;
53062306a36Sopenharmony_ci		break;
53162306a36Sopenharmony_ci	case SCTP_SCOPE_POLICY_PRIVATE:
53262306a36Sopenharmony_ci		if (addr_scope <= scope || SCTP_SCOPE_PRIVATE == addr_scope)
53362306a36Sopenharmony_ci			return 1;
53462306a36Sopenharmony_ci		break;
53562306a36Sopenharmony_ci	case SCTP_SCOPE_POLICY_LINK:
53662306a36Sopenharmony_ci		if (addr_scope <= scope || SCTP_SCOPE_LINK == addr_scope)
53762306a36Sopenharmony_ci			return 1;
53862306a36Sopenharmony_ci		break;
53962306a36Sopenharmony_ci	default:
54062306a36Sopenharmony_ci		break;
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	return 0;
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ciint sctp_is_ep_boundall(struct sock *sk)
54762306a36Sopenharmony_ci{
54862306a36Sopenharmony_ci	struct sctp_bind_addr *bp;
54962306a36Sopenharmony_ci	struct sctp_sockaddr_entry *addr;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	bp = &sctp_sk(sk)->ep->base.bind_addr;
55262306a36Sopenharmony_ci	if (sctp_list_single_entry(&bp->address_list)) {
55362306a36Sopenharmony_ci		addr = list_entry(bp->address_list.next,
55462306a36Sopenharmony_ci				  struct sctp_sockaddr_entry, list);
55562306a36Sopenharmony_ci		if (sctp_is_any(sk, &addr->a))
55662306a36Sopenharmony_ci			return 1;
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci	return 0;
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci/********************************************************************
56262306a36Sopenharmony_ci * 3rd Level Abstractions
56362306a36Sopenharmony_ci ********************************************************************/
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci/* What is the scope of 'addr'?  */
56662306a36Sopenharmony_cienum sctp_scope sctp_scope(const union sctp_addr *addr)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	struct sctp_af *af;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	af = sctp_get_af_specific(addr->sa.sa_family);
57162306a36Sopenharmony_ci	if (!af)
57262306a36Sopenharmony_ci		return SCTP_SCOPE_UNUSABLE;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	return af->scope((union sctp_addr *)addr);
57562306a36Sopenharmony_ci}
576