scope6.c revision 270348
1133064Sdfr/*-
2133064Sdfr * Copyright (C) 2000 WIDE Project.
3133064Sdfr * All rights reserved.
4133064Sdfr *
5133064Sdfr * Redistribution and use in source and binary forms, with or without
6133064Sdfr * modification, are permitted provided that the following conditions
7133064Sdfr * are met:
8133064Sdfr * 1. Redistributions of source code must retain the above copyright
9133064Sdfr *    notice, this list of conditions and the following disclaimer.
10133064Sdfr * 2. Redistributions in binary form must reproduce the above copyright
11133064Sdfr *    notice, this list of conditions and the following disclaimer in the
12133064Sdfr *    documentation and/or other materials provided with the distribution.
13133064Sdfr * 3. Neither the name of the project nor the names of its contributors
14133064Sdfr *    may be used to endorse or promote products derived from this software
15133064Sdfr *    without specific prior written permission.
16133064Sdfr *
17133064Sdfr * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18133064Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19133064Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20133064Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21133064Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22133064Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23133064Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24133064Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25133064Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26133064Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27133064Sdfr * SUCH DAMAGE.
28133064Sdfr *
29133064Sdfr *	$KAME: scope6.c,v 1.10 2000/07/24 13:29:31 itojun Exp $
30133064Sdfr */
31133064Sdfr
32133064Sdfr#include <sys/cdefs.h>
33133064Sdfr__FBSDID("$FreeBSD: head/sys/netinet6/scope6.c 270348 2014-08-22 19:21:08Z markj $");
34133064Sdfr
35143921Sdavidxu#include <sys/param.h>
36133754Sdfr#include <sys/malloc.h>
37133754Sdfr#include <sys/mbuf.h>
38133754Sdfr#include <sys/socket.h>
39133754Sdfr#include <sys/sockio.h>
40143921Sdavidxu#include <sys/systm.h>
41133754Sdfr#include <sys/queue.h>
42133064Sdfr#include <sys/sysctl.h>
43133754Sdfr#include <sys/syslog.h>
44133754Sdfr
45143921Sdavidxu#include <net/if.h>
46143921Sdavidxu#include <net/if_var.h>
47143921Sdavidxu#include <net/vnet.h>
48143921Sdavidxu
49143921Sdavidxu#include <netinet/in.h>
50143921Sdavidxu
51143921Sdavidxu#include <netinet/ip6.h>
52143921Sdavidxu#include <netinet6/in6_var.h>
53143921Sdavidxu#include <netinet6/ip6_var.h>
54143921Sdavidxu#include <netinet6/scope6_var.h>
55143921Sdavidxu
56143921Sdavidxu#ifdef ENABLE_DEFAULT_SCOPE
57143921SdavidxuVNET_DEFINE(int, ip6_use_defzone) = 1;
58143921Sdavidxu#else
59143921SdavidxuVNET_DEFINE(int, ip6_use_defzone) = 0;
60143921Sdavidxu#endif
61143921SdavidxuVNET_DEFINE(int, deembed_scopeid) = 1;
62143921SdavidxuSYSCTL_DECL(_net_inet6_ip6);
63133754SdfrSYSCTL_VNET_INT(_net_inet6_ip6, OID_AUTO, deembed_scopeid, CTLFLAG_RW,
64133754Sdfr    &VNET_NAME(deembed_scopeid), 0,
65133754Sdfr    "Extract embedded zone ID and set it to sin6_scope_id in sockaddr_in6.");
66135686Scognet
67135686Scognet/*
68133754Sdfr * The scope6_lock protects the global sid default stored in
69133754Sdfr * sid_default below.
70133754Sdfr */
71133754Sdfrstatic struct mtx scope6_lock;
72133754Sdfr#define	SCOPE6_LOCK_INIT()	mtx_init(&scope6_lock, "scope6_lock", NULL, MTX_DEF)
73133754Sdfr#define	SCOPE6_LOCK()		mtx_lock(&scope6_lock)
74133754Sdfr#define	SCOPE6_UNLOCK()		mtx_unlock(&scope6_lock)
75133754Sdfr#define	SCOPE6_LOCK_ASSERT()	mtx_assert(&scope6_lock, MA_OWNED)
76133754Sdfr
77133754Sdfrstatic VNET_DEFINE(struct scope6_id, sid_default);
78133754Sdfr#define	V_sid_default			VNET(sid_default)
79133754Sdfr
80133754Sdfr#define SID(ifp) \
81133754Sdfr	(((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->scope6_id)
82133754Sdfr
83133754Sdfrstatic int	scope6_get(struct ifnet *, struct scope6_id *);
84133064Sdfrstatic int	scope6_set(struct ifnet *, struct scope6_id *);
85133064Sdfr
86143921Sdavidxuvoid
87133064Sdfrscope6_init(void)
88133064Sdfr{
89133064Sdfr
90143921Sdavidxu	bzero(&V_sid_default, sizeof(V_sid_default));
91133064Sdfr
92133064Sdfr	if (!IS_DEFAULT_VNET(curvnet))
93133064Sdfr		return;
94133064Sdfr
95133064Sdfr	SCOPE6_LOCK_INIT();
96133064Sdfr}
97133064Sdfr
98143921Sdavidxustruct scope6_id *
99133064Sdfrscope6_ifattach(struct ifnet *ifp)
100133064Sdfr{
101133064Sdfr	struct scope6_id *sid;
102133064Sdfr
103143921Sdavidxu	sid = (struct scope6_id *)malloc(sizeof(*sid), M_IFADDR, M_WAITOK);
104143921Sdavidxu	bzero(sid, sizeof(*sid));
105133754Sdfr
106133754Sdfr	/*
107142560Sdavidxu	 * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard.
108142959Sdavidxu	 * Should we rather hardcode here?
109142560Sdavidxu	 */
110133754Sdfr	sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = ifp->if_index;
111143921Sdavidxu	sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index;
112133754Sdfr#ifdef MULTI_SCOPE
113133754Sdfr	/* by default, we don't care about scope boundary for these scopes. */
114133754Sdfr	sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL] = 1;
115133754Sdfr	sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL] = 1;
116133754Sdfr#endif
117133754Sdfr
118133754Sdfr	return sid;
119133754Sdfr}
120133754Sdfr
121133754Sdfrvoid
122133754Sdfrscope6_ifdetach(struct scope6_id *sid)
123133064Sdfr{
124143921Sdavidxu
125133064Sdfr	free(sid, M_IFADDR);
126133754Sdfr}
127133754Sdfr
128133754Sdfrint
129133754Sdfrscope6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
130133754Sdfr{
131134212Sdfr	struct in6_ifreq *ifr;
132134212Sdfr
133133754Sdfr	if (ifp->if_afdata[AF_INET6] == NULL)
134133754Sdfr		return (EPFNOSUPPORT);
135133754Sdfr
136133754Sdfr	ifr = (struct in6_ifreq *)data;
137143921Sdavidxu	switch (cmd) {
138133754Sdfr	case SIOCSSCOPE6:
139133754Sdfr		return (scope6_set(ifp,
140133754Sdfr		    (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id));
141133754Sdfr	case SIOCGSCOPE6:
142133754Sdfr		return (scope6_get(ifp,
143133754Sdfr		    (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id));
144133754Sdfr	case SIOCGSCOPE6DEF:
145133754Sdfr		return (scope6_get_default(
146133754Sdfr		    (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id));
147143921Sdavidxu	default:
148133754Sdfr		return (EOPNOTSUPP);
149133754Sdfr	}
150133754Sdfr}
151133754Sdfr
152133754Sdfrstatic int
153133754Sdfrscope6_set(struct ifnet *ifp, struct scope6_id *idlist)
154143921Sdavidxu{
155133754Sdfr	int i;
156133754Sdfr	int error = 0;
157133754Sdfr	struct scope6_id *sid = NULL;
158133754Sdfr
159133754Sdfr	IF_AFDATA_WLOCK(ifp);
160133754Sdfr	sid = SID(ifp);
161133754Sdfr
162133064Sdfr	if (!sid) {	/* paranoid? */
163133064Sdfr		IF_AFDATA_WUNLOCK(ifp);
164133754Sdfr		return (EINVAL);
165133754Sdfr	}
166133754Sdfr
167133754Sdfr	/*
168133754Sdfr	 * XXX: We need more consistency checks of the relationship among
169133754Sdfr	 * scopes (e.g. an organization should be larger than a site).
170133754Sdfr	 */
171133064Sdfr
172143921Sdavidxu	/*
173133064Sdfr	 * TODO(XXX): after setting, we should reflect the changes to
174133754Sdfr	 * interface addresses, routing table entries, PCB entries...
175133754Sdfr	 */
176133754Sdfr
177133754Sdfr	for (i = 0; i < 16; i++) {
178133754Sdfr		if (idlist->s6id_list[i] &&
179133754Sdfr		    idlist->s6id_list[i] != sid->s6id_list[i]) {
180133754Sdfr			/*
181133754Sdfr			 * An interface zone ID must be the corresponding
182133754Sdfr			 * interface index by definition.
183133754Sdfr			 */
184133754Sdfr			if (i == IPV6_ADDR_SCOPE_INTFACELOCAL &&
185133754Sdfr			    idlist->s6id_list[i] != ifp->if_index) {
186133754Sdfr				IF_AFDATA_WUNLOCK(ifp);
187133754Sdfr				return (EINVAL);
188133754Sdfr			}
189133064Sdfr
190133754Sdfr			if (i == IPV6_ADDR_SCOPE_LINKLOCAL &&
191133754Sdfr			    idlist->s6id_list[i] > V_if_index) {
192133754Sdfr				/*
193133754Sdfr				 * XXX: theoretically, there should be no
194133754Sdfr				 * relationship between link IDs and interface
195143921Sdavidxu				 * IDs, but we check the consistency for
196133754Sdfr				 * safety in later use.
197133754Sdfr				 */
198133754Sdfr				IF_AFDATA_WUNLOCK(ifp);
199133754Sdfr				return (EINVAL);
200133754Sdfr			}
201133754Sdfr
202133754Sdfr			/*
203133754Sdfr			 * XXX: we must need lots of work in this case,
204133754Sdfr			 * but we simply set the new value in this initial
205133754Sdfr			 * implementation.
206133754Sdfr			 */
207133754Sdfr			sid->s6id_list[i] = idlist->s6id_list[i];
208133754Sdfr		}
209133754Sdfr	}
210133754Sdfr	IF_AFDATA_WUNLOCK(ifp);
211133754Sdfr
212133754Sdfr	return (error);
213133754Sdfr}
214133754Sdfr
215133754Sdfrstatic int
216133754Sdfrscope6_get(struct ifnet *ifp, struct scope6_id *idlist)
217133754Sdfr{
218133754Sdfr	struct scope6_id *sid;
219133754Sdfr
220133754Sdfr	/* We only need to lock the interface's afdata for SID() to work. */
221133754Sdfr	IF_AFDATA_RLOCK(ifp);
222133754Sdfr	sid = SID(ifp);
223133754Sdfr	if (sid == NULL) {	/* paranoid? */
224133754Sdfr		IF_AFDATA_RUNLOCK(ifp);
225133754Sdfr		return (EINVAL);
226133754Sdfr	}
227133754Sdfr
228133754Sdfr	*idlist = *sid;
229133754Sdfr
230133754Sdfr	IF_AFDATA_RUNLOCK(ifp);
231133754Sdfr	return (0);
232133754Sdfr}
233133754Sdfr
234133754Sdfr/*
235133754Sdfr * Get a scope of the address. Node-local, link-local, site-local or global.
236133754Sdfr */
237133754Sdfrint
238143921Sdavidxuin6_addrscope(struct in6_addr *addr)
239143921Sdavidxu{
240143921Sdavidxu	int scope;
241143921Sdavidxu
242133754Sdfr	if (addr->s6_addr[0] == 0xfe) {
243143921Sdavidxu		scope = addr->s6_addr[1] & 0xc0;
244143921Sdavidxu
245143921Sdavidxu		switch (scope) {
246143921Sdavidxu		case 0x80:
247143921Sdavidxu			return IPV6_ADDR_SCOPE_LINKLOCAL;
248133754Sdfr			break;
249133754Sdfr		case 0xc0:
250133754Sdfr			return IPV6_ADDR_SCOPE_SITELOCAL;
251143921Sdavidxu			break;
252143921Sdavidxu		default:
253143921Sdavidxu			return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */
254143921Sdavidxu			break;
255143921Sdavidxu		}
256133754Sdfr	}
257143921Sdavidxu
258143921Sdavidxu
259143921Sdavidxu	if (addr->s6_addr[0] == 0xff) {
260143921Sdavidxu		scope = addr->s6_addr[1] & 0x0f;
261133754Sdfr
262133754Sdfr		/*
263133754Sdfr		 * due to other scope such as reserved,
264133754Sdfr		 * return scope doesn't work.
265133754Sdfr		 */
266133754Sdfr		switch (scope) {
267133754Sdfr		case IPV6_ADDR_SCOPE_INTFACELOCAL:
268133754Sdfr			return IPV6_ADDR_SCOPE_INTFACELOCAL;
269133754Sdfr			break;
270133949Sdfr		case IPV6_ADDR_SCOPE_LINKLOCAL:
271133754Sdfr			return IPV6_ADDR_SCOPE_LINKLOCAL;
272133754Sdfr			break;
273133754Sdfr		case IPV6_ADDR_SCOPE_SITELOCAL:
274133754Sdfr			return IPV6_ADDR_SCOPE_SITELOCAL;
275133754Sdfr			break;
276133754Sdfr		default:
277133754Sdfr			return IPV6_ADDR_SCOPE_GLOBAL;
278133754Sdfr			break;
279133754Sdfr		}
280133754Sdfr	}
281133754Sdfr
282133754Sdfr	/*
283133754Sdfr	 * Regard loopback and unspecified addresses as global, since
284133754Sdfr	 * they have no ambiguity.
285133754Sdfr	 */
286133754Sdfr	if (bcmp(&in6addr_loopback, addr, sizeof(*addr) - 1) == 0) {
287133754Sdfr		if (addr->s6_addr[15] == 1) /* loopback */
288133754Sdfr			return IPV6_ADDR_SCOPE_LINKLOCAL;
289133754Sdfr		if (addr->s6_addr[15] == 0) /* unspecified */
290133754Sdfr			return IPV6_ADDR_SCOPE_GLOBAL; /* XXX: correct? */
291133754Sdfr	}
292133754Sdfr
293133754Sdfr	return IPV6_ADDR_SCOPE_GLOBAL;
294133754Sdfr}
295133754Sdfr
296143921Sdavidxu/*
297133754Sdfr * ifp - note that this might be NULL
298133754Sdfr */
299133754Sdfr
300133754Sdfrvoid
301133754Sdfrscope6_setdefault(struct ifnet *ifp)
302133754Sdfr{
303133754Sdfr
304133754Sdfr	/*
305133754Sdfr	 * Currently, this function just sets the default "interfaces"
306133754Sdfr	 * and "links" according to the given interface.
307133754Sdfr	 * We might eventually have to separate the notion of "link" from
308133754Sdfr	 * "interface" and provide a user interface to set the default.
309133754Sdfr	 */
310133754Sdfr	SCOPE6_LOCK();
311133754Sdfr	if (ifp) {
312133949Sdfr		V_sid_default.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] =
313133949Sdfr			ifp->if_index;
314133754Sdfr		V_sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] =
315133949Sdfr			ifp->if_index;
316133754Sdfr	} else {
317133754Sdfr		V_sid_default.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = 0;
318		V_sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0;
319	}
320	SCOPE6_UNLOCK();
321}
322
323int
324scope6_get_default(struct scope6_id *idlist)
325{
326
327	SCOPE6_LOCK();
328	*idlist = V_sid_default;
329	SCOPE6_UNLOCK();
330
331	return (0);
332}
333
334u_int32_t
335scope6_addr2default(struct in6_addr *addr)
336{
337	u_int32_t id;
338
339	/*
340	 * special case: The loopback address should be considered as
341	 * link-local, but there's no ambiguity in the syntax.
342	 */
343	if (IN6_IS_ADDR_LOOPBACK(addr))
344		return (0);
345
346	/*
347	 * XXX: 32-bit read is atomic on all our platforms, is it OK
348	 * not to lock here?
349	 */
350	SCOPE6_LOCK();
351	id = V_sid_default.s6id_list[in6_addrscope(addr)];
352	SCOPE6_UNLOCK();
353	return (id);
354}
355
356/*
357 * Validate the specified scope zone ID in the sin6_scope_id field.  If the ID
358 * is unspecified (=0), needs to be specified, and the default zone ID can be
359 * used, the default value will be used.
360 * This routine then generates the kernel-internal form: if the address scope
361 * of is interface-local or link-local, embed the interface index in the
362 * address.
363 */
364int
365sa6_embedscope(struct sockaddr_in6 *sin6, int defaultok)
366{
367	u_int32_t zoneid;
368
369	if ((zoneid = sin6->sin6_scope_id) == 0 && defaultok)
370		zoneid = scope6_addr2default(&sin6->sin6_addr);
371
372	if (zoneid != 0 &&
373	    (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
374	    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr))) {
375		/*
376		 * At this moment, we only check interface-local and
377		 * link-local scope IDs, and use interface indices as the
378		 * zone IDs assuming a one-to-one mapping between interfaces
379		 * and links.
380		 */
381		if (V_if_index < zoneid || ifnet_byindex(zoneid) == NULL)
382			return (ENXIO);
383
384		/* XXX assignment to 16bit from 32bit variable */
385		sin6->sin6_addr.s6_addr16[1] = htons(zoneid & 0xffff);
386		sin6->sin6_scope_id = 0;
387	}
388
389	return 0;
390}
391
392/*
393 * generate standard sockaddr_in6 from embedded form.
394 */
395int
396sa6_recoverscope(struct sockaddr_in6 *sin6)
397{
398	char ip6buf[INET6_ADDRSTRLEN];
399	u_int32_t zoneid;
400
401	if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
402	    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) {
403		/*
404		 * KAME assumption: link id == interface id
405		 */
406		zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]);
407		if (zoneid) {
408			/* sanity check */
409			if (V_if_index < zoneid)
410				return (ENXIO);
411#if 0
412			/* XXX: Disabled due to possible deadlock. */
413			if (!ifnet_byindex(zoneid))
414				return (ENXIO);
415#endif
416			if (sin6->sin6_scope_id != 0 &&
417			    zoneid != sin6->sin6_scope_id) {
418				log(LOG_NOTICE,
419				    "%s: embedded scope mismatch: %s%%%d. "
420				    "sin6_scope_id was overridden.", __func__,
421				    ip6_sprintf(ip6buf, &sin6->sin6_addr),
422				    sin6->sin6_scope_id);
423			}
424			sin6->sin6_addr.s6_addr16[1] = 0;
425			sin6->sin6_scope_id = zoneid;
426		}
427	}
428
429	return 0;
430}
431
432/*
433 * Determine the appropriate scope zone ID for in6 and ifp.  If ret_id is
434 * non NULL, it is set to the zone ID.  If the zone ID needs to be embedded
435 * in the in6_addr structure, in6 will be modified.
436 *
437 * ret_id - unnecessary?
438 */
439int
440in6_setscope(struct in6_addr *in6, struct ifnet *ifp, u_int32_t *ret_id)
441{
442	int scope;
443	u_int32_t zoneid = 0;
444	struct scope6_id *sid;
445
446	/*
447	 * special case: the loopback address can only belong to a loopback
448	 * interface.
449	 */
450	if (IN6_IS_ADDR_LOOPBACK(in6)) {
451		if (!(ifp->if_flags & IFF_LOOPBACK))
452			return (EINVAL);
453	} else {
454		scope = in6_addrscope(in6);
455		if (scope == IPV6_ADDR_SCOPE_INTFACELOCAL ||
456		    scope == IPV6_ADDR_SCOPE_LINKLOCAL) {
457			/*
458			 * Currently we use interface indeces as the
459			 * zone IDs for interface-local and link-local
460			 * scopes.
461			 */
462			zoneid = ifp->if_index;
463			in6->s6_addr16[1] = htons(zoneid & 0xffff); /* XXX */
464		} else if (scope != IPV6_ADDR_SCOPE_GLOBAL) {
465			IF_AFDATA_RLOCK(ifp);
466			sid = SID(ifp);
467			zoneid = sid->s6id_list[scope];
468			IF_AFDATA_RUNLOCK(ifp);
469		}
470	}
471
472	if (ret_id != NULL)
473		*ret_id = zoneid;
474
475	return (0);
476}
477
478/*
479 * Just clear the embedded scope identifier.  Return 0 if the original address
480 * is intact; return non 0 if the address is modified.
481 */
482int
483in6_clearscope(struct in6_addr *in6)
484{
485	int modified = 0;
486
487	if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) {
488		if (in6->s6_addr16[1] != 0)
489			modified = 1;
490		in6->s6_addr16[1] = 0;
491	}
492
493	return (modified);
494}
495
496/*
497 * Return the scope identifier or zero.
498 */
499uint16_t
500in6_getscope(struct in6_addr *in6)
501{
502
503	if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6))
504		return (in6->s6_addr16[1]);
505
506	return (0);
507}
508