scope6.c revision 238224
1139826Simp/*-
262587Sitojun * Copyright (C) 2000 WIDE Project.
362587Sitojun * All rights reserved.
4120941Sume *
562587Sitojun * Redistribution and use in source and binary forms, with or without
662587Sitojun * modification, are permitted provided that the following conditions
762587Sitojun * are met:
862587Sitojun * 1. Redistributions of source code must retain the above copyright
962587Sitojun *    notice, this list of conditions and the following disclaimer.
1062587Sitojun * 2. Redistributions in binary form must reproduce the above copyright
1162587Sitojun *    notice, this list of conditions and the following disclaimer in the
1262587Sitojun *    documentation and/or other materials provided with the distribution.
1362587Sitojun * 3. Neither the name of the project nor the names of its contributors
1462587Sitojun *    may be used to endorse or promote products derived from this software
1562587Sitojun *    without specific prior written permission.
16120941Sume *
1762587Sitojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1862587Sitojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1962587Sitojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2062587Sitojun * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2162587Sitojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2262587Sitojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2362587Sitojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2462587Sitojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2562587Sitojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2662587Sitojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2762587Sitojun * SUCH DAMAGE.
28174510Sobrien *
29174510Sobrien *	$KAME: scope6.c,v 1.10 2000/07/24 13:29:31 itojun Exp $
3062587Sitojun */
3162587Sitojun
32174510Sobrien#include <sys/cdefs.h>
33174510Sobrien__FBSDID("$FreeBSD: stable/9/sys/netinet6/scope6.c 238224 2012-07-08 09:49:01Z bz $");
34174510Sobrien
3562587Sitojun#include <sys/param.h>
3662587Sitojun#include <sys/malloc.h>
3762587Sitojun#include <sys/mbuf.h>
3862587Sitojun#include <sys/socket.h>
3962587Sitojun#include <sys/systm.h>
4078064Sume#include <sys/queue.h>
41148385Sume#include <sys/syslog.h>
4262587Sitojun
4362587Sitojun#include <net/if.h>
44185571Sbz#include <net/vnet.h>
4562587Sitojun
4662587Sitojun#include <netinet/in.h>
47185571Sbz
48183550Szec#include <netinet/ip6.h>
4962587Sitojun#include <netinet6/in6_var.h>
50195699Srwatson#include <netinet6/ip6_var.h>
5162587Sitojun#include <netinet6/scope6_var.h>
5262587Sitojun
53207369Sbz#ifdef ENABLE_DEFAULT_SCOPE
54207369SbzVNET_DEFINE(int, ip6_use_defzone) = 1;
55207369Sbz#else
56207369SbzVNET_DEFINE(int, ip6_use_defzone) = 0;
57207369Sbz#endif
58148385Sume
59121343Sume/*
60138184Sgnn * The scope6_lock protects the global sid default stored in
61138184Sgnn * sid_default below.
62121343Sume */
63121343Sumestatic struct mtx scope6_lock;
64121343Sume#define	SCOPE6_LOCK_INIT()	mtx_init(&scope6_lock, "scope6_lock", NULL, MTX_DEF)
65121343Sume#define	SCOPE6_LOCK()		mtx_lock(&scope6_lock)
66121343Sume#define	SCOPE6_UNLOCK()		mtx_unlock(&scope6_lock)
67121343Sume#define	SCOPE6_LOCK_ASSERT()	mtx_assert(&scope6_lock, MA_OWNED)
68121343Sume
69215701Sdimstatic VNET_DEFINE(struct scope6_id, sid_default);
70195727Srwatson#define	V_sid_default			VNET(sid_default)
71195699Srwatson
72121161Sume#define SID(ifp) \
73121161Sume	(((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->scope6_id)
7462587Sitojun
7562587Sitojunvoid
76171259Sdelphijscope6_init(void)
77121161Sume{
78121161Sume
79190787Szec	bzero(&V_sid_default, sizeof(V_sid_default));
80190787Szec
81190787Szec	if (!IS_DEFAULT_VNET(curvnet))
82190787Szec		return;
83190787Szec
84121343Sume	SCOPE6_LOCK_INIT();
85121161Sume}
86121161Sume
87121161Sumestruct scope6_id *
88171259Sdelphijscope6_ifattach(struct ifnet *ifp)
8962587Sitojun{
90121161Sume	struct scope6_id *sid;
9162587Sitojun
92121161Sume	sid = (struct scope6_id *)malloc(sizeof(*sid), M_IFADDR, M_WAITOK);
93121161Sume	bzero(sid, sizeof(*sid));
9462587Sitojun
9562587Sitojun	/*
9662587Sitojun	 * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard.
9762587Sitojun	 * Should we rather hardcode here?
9862587Sitojun	 */
99121315Sume	sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = ifp->if_index;
100121161Sume	sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index;
10162587Sitojun#ifdef MULTI_SCOPE
10262587Sitojun	/* by default, we don't care about scope boundary for these scopes. */
103121161Sume	sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL] = 1;
104121161Sume	sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL] = 1;
10562587Sitojun#endif
10662587Sitojun
107121161Sume	return sid;
10862587Sitojun}
10962587Sitojun
110121161Sumevoid
111171259Sdelphijscope6_ifdetach(struct scope6_id *sid)
112121161Sume{
113121161Sume
114121161Sume	free(sid, M_IFADDR);
115121161Sume}
116121161Sume
11762587Sitojunint
118171259Sdelphijscope6_set(struct ifnet *ifp, struct scope6_id *idlist)
11962587Sitojun{
120138184Sgnn	int i;
12162587Sitojun	int error = 0;
122138184Sgnn	struct scope6_id *sid = NULL;
12362587Sitojun
124138184Sgnn	IF_AFDATA_LOCK(ifp);
125138184Sgnn	sid = SID(ifp);
126138184Sgnn
127138184Sgnn	if (!sid) {	/* paranoid? */
128138184Sgnn		IF_AFDATA_UNLOCK(ifp);
129120856Sume		return (EINVAL);
130138184Sgnn	}
13162587Sitojun
13262587Sitojun	/*
13362587Sitojun	 * XXX: We need more consistency checks of the relationship among
13462587Sitojun	 * scopes (e.g. an organization should be larger than a site).
13562587Sitojun	 */
13662587Sitojun
13762587Sitojun	/*
13862587Sitojun	 * TODO(XXX): after setting, we should reflect the changes to
139120941Sume	 * interface addresses, routing table entries, PCB entries...
14062587Sitojun	 */
14162587Sitojun
142121343Sume	SCOPE6_LOCK();
14362587Sitojun	for (i = 0; i < 16; i++) {
144121161Sume		if (idlist->s6id_list[i] &&
145121161Sume		    idlist->s6id_list[i] != sid->s6id_list[i]) {
146121315Sume			/*
147121315Sume			 * An interface zone ID must be the corresponding
148121315Sume			 * interface index by definition.
149121315Sume			 */
150121315Sume			if (i == IPV6_ADDR_SCOPE_INTFACELOCAL &&
151121315Sume			    idlist->s6id_list[i] != ifp->if_index) {
152138184Sgnn				IF_AFDATA_UNLOCK(ifp);
153138184Sgnn				SCOPE6_UNLOCK();
154121315Sume				return (EINVAL);
155121315Sume			}
156121315Sume
15762587Sitojun			if (i == IPV6_ADDR_SCOPE_LINKLOCAL &&
158181803Sbz			    idlist->s6id_list[i] > V_if_index) {
15962587Sitojun				/*
16062587Sitojun				 * XXX: theoretically, there should be no
16162587Sitojun				 * relationship between link IDs and interface
16262587Sitojun				 * IDs, but we check the consistency for
16362587Sitojun				 * safety in later use.
16462587Sitojun				 */
165138184Sgnn				IF_AFDATA_UNLOCK(ifp);
166138184Sgnn				SCOPE6_UNLOCK();
167120856Sume				return (EINVAL);
16862587Sitojun			}
16962587Sitojun
17062587Sitojun			/*
17162587Sitojun			 * XXX: we must need lots of work in this case,
17262587Sitojun			 * but we simply set the new value in this initial
17362587Sitojun			 * implementation.
17462587Sitojun			 */
175121161Sume			sid->s6id_list[i] = idlist->s6id_list[i];
17662587Sitojun		}
17762587Sitojun	}
178121343Sume	SCOPE6_UNLOCK();
179138184Sgnn	IF_AFDATA_UNLOCK(ifp);
18062587Sitojun
181120856Sume	return (error);
18262587Sitojun}
18362587Sitojun
18462587Sitojunint
185171259Sdelphijscope6_get(struct ifnet *ifp, struct scope6_id *idlist)
18662587Sitojun{
187138184Sgnn	/* We only need to lock the interface's afdata for SID() to work. */
188138184Sgnn	IF_AFDATA_LOCK(ifp);
189121161Sume	struct scope6_id *sid = SID(ifp);
190121161Sume
191138184Sgnn	if (sid == NULL) {	/* paranoid? */
192138184Sgnn		IF_AFDATA_UNLOCK(ifp);
193120856Sume		return (EINVAL);
194138184Sgnn	}
19562587Sitojun
196121343Sume	SCOPE6_LOCK();
197121161Sume	*idlist = *sid;
198121343Sume	SCOPE6_UNLOCK();
19962587Sitojun
200138184Sgnn	IF_AFDATA_UNLOCK(ifp);
201120856Sume	return (0);
20262587Sitojun}
20362587Sitojun
20462587Sitojun
20562587Sitojun/*
20662587Sitojun * Get a scope of the address. Node-local, link-local, site-local or global.
20762587Sitojun */
20862587Sitojunint
209171259Sdelphijin6_addrscope(struct in6_addr *addr)
21062587Sitojun{
21162587Sitojun	int scope;
21262587Sitojun
213121315Sume	if (addr->s6_addr[0] == 0xfe) {
214121315Sume		scope = addr->s6_addr[1] & 0xc0;
21562587Sitojun
21662587Sitojun		switch (scope) {
21762587Sitojun		case 0x80:
21862587Sitojun			return IPV6_ADDR_SCOPE_LINKLOCAL;
21962587Sitojun			break;
22062587Sitojun		case 0xc0:
22162587Sitojun			return IPV6_ADDR_SCOPE_SITELOCAL;
22262587Sitojun			break;
22362587Sitojun		default:
22462587Sitojun			return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */
22562587Sitojun			break;
22662587Sitojun		}
22762587Sitojun	}
22862587Sitojun
22962587Sitojun
230121315Sume	if (addr->s6_addr[0] == 0xff) {
231121315Sume		scope = addr->s6_addr[1] & 0x0f;
23262587Sitojun
23362587Sitojun		/*
23462587Sitojun		 * due to other scope such as reserved,
23562587Sitojun		 * return scope doesn't work.
23662587Sitojun		 */
23762587Sitojun		switch (scope) {
238121315Sume		case IPV6_ADDR_SCOPE_INTFACELOCAL:
239121315Sume			return IPV6_ADDR_SCOPE_INTFACELOCAL;
24062587Sitojun			break;
24162587Sitojun		case IPV6_ADDR_SCOPE_LINKLOCAL:
24262587Sitojun			return IPV6_ADDR_SCOPE_LINKLOCAL;
24362587Sitojun			break;
24462587Sitojun		case IPV6_ADDR_SCOPE_SITELOCAL:
24562587Sitojun			return IPV6_ADDR_SCOPE_SITELOCAL;
24662587Sitojun			break;
24762587Sitojun		default:
24862587Sitojun			return IPV6_ADDR_SCOPE_GLOBAL;
24962587Sitojun			break;
25062587Sitojun		}
25162587Sitojun	}
25262587Sitojun
253121315Sume	/*
254121315Sume	 * Regard loopback and unspecified addresses as global, since
255121315Sume	 * they have no ambiguity.
256121315Sume	 */
25793128Sume	if (bcmp(&in6addr_loopback, addr, sizeof(*addr) - 1) == 0) {
258121315Sume		if (addr->s6_addr[15] == 1) /* loopback */
25962587Sitojun			return IPV6_ADDR_SCOPE_LINKLOCAL;
260121315Sume		if (addr->s6_addr[15] == 0) /* unspecified */
261121315Sume			return IPV6_ADDR_SCOPE_GLOBAL; /* XXX: correct? */
26262587Sitojun	}
26362587Sitojun
26462587Sitojun	return IPV6_ADDR_SCOPE_GLOBAL;
26562587Sitojun}
26662587Sitojun
267171259Sdelphij/*
268171259Sdelphij * ifp - note that this might be NULL
269171259Sdelphij */
270171259Sdelphij
27162587Sitojunvoid
272171259Sdelphijscope6_setdefault(struct ifnet *ifp)
27362587Sitojun{
274183550Szec
27562587Sitojun	/*
276138184Sgnn	 * Currently, this function just sets the default "interfaces"
277121161Sume	 * and "links" according to the given interface.
27862587Sitojun	 * We might eventually have to separate the notion of "link" from
27962587Sitojun	 * "interface" and provide a user interface to set the default.
28062587Sitojun	 */
281121343Sume	SCOPE6_LOCK();
28262587Sitojun	if (ifp) {
283181803Sbz		V_sid_default.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] =
28462587Sitojun			ifp->if_index;
285181803Sbz		V_sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] =
286121161Sume			ifp->if_index;
287120941Sume	} else {
288181803Sbz		V_sid_default.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = 0;
289181803Sbz		V_sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0;
29062587Sitojun	}
291121343Sume	SCOPE6_UNLOCK();
29262587Sitojun}
29362587Sitojun
29462587Sitojunint
295171259Sdelphijscope6_get_default(struct scope6_id *idlist)
29662587Sitojun{
297121343Sume
298121343Sume	SCOPE6_LOCK();
299181803Sbz	*idlist = V_sid_default;
300121343Sume	SCOPE6_UNLOCK();
30162587Sitojun
302120856Sume	return (0);
30362587Sitojun}
30462587Sitojun
30562587Sitojunu_int32_t
306171259Sdelphijscope6_addr2default(struct in6_addr *addr)
30762587Sitojun{
308121343Sume	u_int32_t id;
309121343Sume
310121161Sume	/*
311121161Sume	 * special case: The loopback address should be considered as
312121161Sume	 * link-local, but there's no ambiguity in the syntax.
313121161Sume	 */
314121161Sume	if (IN6_IS_ADDR_LOOPBACK(addr))
315121161Sume		return (0);
316121161Sume
317121343Sume	/*
318121343Sume	 * XXX: 32-bit read is atomic on all our platforms, is it OK
319121343Sume	 * not to lock here?
320121343Sume	 */
321121343Sume	SCOPE6_LOCK();
322181803Sbz	id = V_sid_default.s6id_list[in6_addrscope(addr)];
323121343Sume	SCOPE6_UNLOCK();
324121343Sume	return (id);
32562587Sitojun}
326148385Sume
327148385Sume/*
328148385Sume * Validate the specified scope zone ID in the sin6_scope_id field.  If the ID
329148385Sume * is unspecified (=0), needs to be specified, and the default zone ID can be
330148385Sume * used, the default value will be used.
331148385Sume * This routine then generates the kernel-internal form: if the address scope
332148385Sume * of is interface-local or link-local, embed the interface index in the
333148385Sume * address.
334148385Sume */
335148385Sumeint
336171259Sdelphijsa6_embedscope(struct sockaddr_in6 *sin6, int defaultok)
337148385Sume{
338148385Sume	struct ifnet *ifp;
339148385Sume	u_int32_t zoneid;
340148385Sume
341148385Sume	if ((zoneid = sin6->sin6_scope_id) == 0 && defaultok)
342148385Sume		zoneid = scope6_addr2default(&sin6->sin6_addr);
343148385Sume
344148385Sume	if (zoneid != 0 &&
345148385Sume	    (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
346148385Sume	    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr))) {
347148385Sume		/*
348148385Sume		 * At this moment, we only check interface-local and
349148385Sume		 * link-local scope IDs, and use interface indices as the
350148385Sume		 * zone IDs assuming a one-to-one mapping between interfaces
351148385Sume		 * and links.
352148385Sume		 */
353181803Sbz		if (V_if_index < zoneid)
354148385Sume			return (ENXIO);
355148385Sume		ifp = ifnet_byindex(zoneid);
356148385Sume		if (ifp == NULL) /* XXX: this can happen for some OS */
357148385Sume			return (ENXIO);
358148385Sume
359148385Sume		/* XXX assignment to 16bit from 32bit variable */
360148385Sume		sin6->sin6_addr.s6_addr16[1] = htons(zoneid & 0xffff);
361148385Sume
362148385Sume		sin6->sin6_scope_id = 0;
363148385Sume	}
364148385Sume
365148385Sume	return 0;
366148385Sume}
367148385Sume
368148385Sume/*
369148385Sume * generate standard sockaddr_in6 from embedded form.
370148385Sume */
371148385Sumeint
372171259Sdelphijsa6_recoverscope(struct sockaddr_in6 *sin6)
373148385Sume{
374165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
375148385Sume	u_int32_t zoneid;
376148385Sume
377148385Sume	if (sin6->sin6_scope_id != 0) {
378148385Sume		log(LOG_NOTICE,
379148385Sume		    "sa6_recoverscope: assumption failure (non 0 ID): %s%%%d\n",
380165118Sbz		    ip6_sprintf(ip6buf, &sin6->sin6_addr), sin6->sin6_scope_id);
381148385Sume		/* XXX: proceed anyway... */
382148385Sume	}
383148385Sume	if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
384148385Sume	    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) {
385148385Sume		/*
386148385Sume		 * KAME assumption: link id == interface id
387148385Sume		 */
388148385Sume		zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]);
389148385Sume		if (zoneid) {
390148385Sume			/* sanity check */
391181803Sbz			if (zoneid < 0 || V_if_index < zoneid)
392148385Sume				return (ENXIO);
393148385Sume			if (!ifnet_byindex(zoneid))
394148385Sume				return (ENXIO);
395148385Sume			sin6->sin6_addr.s6_addr16[1] = 0;
396148385Sume			sin6->sin6_scope_id = zoneid;
397148385Sume		}
398148385Sume	}
399148385Sume
400148385Sume	return 0;
401148385Sume}
402148385Sume
403148385Sume/*
404148385Sume * Determine the appropriate scope zone ID for in6 and ifp.  If ret_id is
405148385Sume * non NULL, it is set to the zone ID.  If the zone ID needs to be embedded
406148385Sume * in the in6_addr structure, in6 will be modified.
407171259Sdelphij *
408171259Sdelphij * ret_id - unnecessary?
409148385Sume */
410148385Sumeint
411171259Sdelphijin6_setscope(struct in6_addr *in6, struct ifnet *ifp, u_int32_t *ret_id)
412148385Sume{
413148385Sume	int scope;
414148385Sume	u_int32_t zoneid = 0;
415148396Sume	struct scope6_id *sid;
416148385Sume
417148396Sume	IF_AFDATA_LOCK(ifp);
418148396Sume
419148396Sume	sid = SID(ifp);
420148396Sume
421148385Sume#ifdef DIAGNOSTIC
422148385Sume	if (sid == NULL) { /* should not happen */
423148385Sume		panic("in6_setscope: scope array is NULL");
424148385Sume		/* NOTREACHED */
425148385Sume	}
426148385Sume#endif
427148385Sume
428148385Sume	/*
429148385Sume	 * special case: the loopback address can only belong to a loopback
430148385Sume	 * interface.
431148385Sume	 */
432148385Sume	if (IN6_IS_ADDR_LOOPBACK(in6)) {
433148399Sume		if (!(ifp->if_flags & IFF_LOOPBACK)) {
434148396Sume			IF_AFDATA_UNLOCK(ifp);
435148385Sume			return (EINVAL);
436148399Sume		} else {
437148385Sume			if (ret_id != NULL)
438148385Sume				*ret_id = 0; /* there's no ambiguity */
439148396Sume			IF_AFDATA_UNLOCK(ifp);
440148385Sume			return (0);
441148385Sume		}
442148385Sume	}
443148385Sume
444148385Sume	scope = in6_addrscope(in6);
445148385Sume
446148396Sume	SCOPE6_LOCK();
447148385Sume	switch (scope) {
448148385Sume	case IPV6_ADDR_SCOPE_INTFACELOCAL: /* should be interface index */
449148385Sume		zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL];
450148385Sume		break;
451148385Sume
452148385Sume	case IPV6_ADDR_SCOPE_LINKLOCAL:
453148385Sume		zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL];
454148385Sume		break;
455148385Sume
456148385Sume	case IPV6_ADDR_SCOPE_SITELOCAL:
457148385Sume		zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL];
458148385Sume		break;
459148385Sume
460148385Sume	case IPV6_ADDR_SCOPE_ORGLOCAL:
461148385Sume		zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL];
462148385Sume		break;
463148385Sume
464148385Sume	default:
465148385Sume		zoneid = 0;	/* XXX: treat as global. */
466148385Sume		break;
467148385Sume	}
468148396Sume	SCOPE6_UNLOCK();
469148396Sume	IF_AFDATA_UNLOCK(ifp);
470148385Sume
471148385Sume	if (ret_id != NULL)
472148385Sume		*ret_id = zoneid;
473148385Sume
474148385Sume	if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6))
475148385Sume		in6->s6_addr16[1] = htons(zoneid & 0xffff); /* XXX */
476148385Sume
477148385Sume	return (0);
478148385Sume}
479148385Sume
480148385Sume/*
481148385Sume * Just clear the embedded scope identifier.  Return 0 if the original address
482148385Sume * is intact; return non 0 if the address is modified.
483148385Sume */
484148385Sumeint
485171259Sdelphijin6_clearscope(struct in6_addr *in6)
486148385Sume{
487148385Sume	int modified = 0;
488148385Sume
489148385Sume	if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) {
490148385Sume		if (in6->s6_addr16[1] != 0)
491148385Sume			modified = 1;
492148385Sume		in6->s6_addr16[1] = 0;
493148385Sume	}
494148385Sume
495148385Sume	return (modified);
496148385Sume}
497238224Sbz
498238224Sbz/*
499238224Sbz * Return the scope identifier or zero.
500238224Sbz */
501238224Sbzuint16_t
502238224Sbzin6_getscope(struct in6_addr *in6)
503238224Sbz{
504238224Sbz
505238224Sbz	if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6))
506238224Sbz		return (in6->s6_addr16[1]);
507238224Sbz
508238224Sbz	return (0);
509238224Sbz}
510