xref: /netbsd-src/sys/netinet6/scope6.c (revision 3ec4b526b7f3eae31f23b06da24dd588c4712d54)
1*3ec4b526Smaxv /*	$NetBSD: scope6.c,v 1.23 2020/06/16 17:12:18 maxv Exp $	*/
278678b13Srpaulo /*	$KAME$	*/
378678b13Srpaulo 
4c4a55989Smaxv /*
578678b13Srpaulo  * Copyright (C) 2000 WIDE Project.
678678b13Srpaulo  * All rights reserved.
778678b13Srpaulo  *
878678b13Srpaulo  * Redistribution and use in source and binary forms, with or without
978678b13Srpaulo  * modification, are permitted provided that the following conditions
1078678b13Srpaulo  * are met:
1178678b13Srpaulo  * 1. Redistributions of source code must retain the above copyright
1278678b13Srpaulo  *    notice, this list of conditions and the following disclaimer.
1378678b13Srpaulo  * 2. Redistributions in binary form must reproduce the above copyright
1478678b13Srpaulo  *    notice, this list of conditions and the following disclaimer in the
1578678b13Srpaulo  *    documentation and/or other materials provided with the distribution.
1678678b13Srpaulo  * 3. Neither the name of the project nor the names of its contributors
1778678b13Srpaulo  *    may be used to endorse or promote products derived from this software
1878678b13Srpaulo  *    without specific prior written permission.
1978678b13Srpaulo  *
2078678b13Srpaulo  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2178678b13Srpaulo  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2278678b13Srpaulo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2378678b13Srpaulo  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2478678b13Srpaulo  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2578678b13Srpaulo  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2678678b13Srpaulo  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2778678b13Srpaulo  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2878678b13Srpaulo  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2978678b13Srpaulo  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3078678b13Srpaulo  * SUCH DAMAGE.
3178678b13Srpaulo  */
3278678b13Srpaulo 
33456279dfSlukem #include <sys/cdefs.h>
34*3ec4b526Smaxv __KERNEL_RCSID(0, "$NetBSD: scope6.c,v 1.23 2020/06/16 17:12:18 maxv Exp $");
35456279dfSlukem 
3678678b13Srpaulo #include <sys/param.h>
3778678b13Srpaulo #include <sys/malloc.h>
3878678b13Srpaulo #include <sys/mbuf.h>
3978678b13Srpaulo #include <sys/socket.h>
4078678b13Srpaulo #include <sys/systm.h>
4178678b13Srpaulo #include <sys/queue.h>
4278678b13Srpaulo #include <sys/syslog.h>
4378678b13Srpaulo 
4478678b13Srpaulo #include <net/if.h>
4578678b13Srpaulo 
4678678b13Srpaulo #include <netinet/in.h>
4778678b13Srpaulo 
4878678b13Srpaulo #include <netinet6/in6_var.h>
4978678b13Srpaulo #include <netinet6/scope6_var.h>
5078678b13Srpaulo 
5178678b13Srpaulo #ifdef ENABLE_DEFAULT_SCOPE
5278678b13Srpaulo int ip6_use_defzone = 1;
5378678b13Srpaulo #else
5478678b13Srpaulo int ip6_use_defzone = 0;
5578678b13Srpaulo #endif
5678678b13Srpaulo 
5778678b13Srpaulo static struct scope6_id sid_default;
5878678b13Srpaulo #define SID(ifp) \
59fa02ef2cSchristos     ((ifp)->if_afdata[AF_INET6] == NULL ? NULL : \
60fa02ef2cSchristos 	((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->scope6_id)
6178678b13Srpaulo 
6278678b13Srpaulo void
scope6_init(void)63dc56dbbdScegger scope6_init(void)
6478678b13Srpaulo {
6578678b13Srpaulo 
660131d257Srpaulo 	memset(&sid_default, 0, sizeof(sid_default));
6778678b13Srpaulo }
6878678b13Srpaulo 
6978678b13Srpaulo struct scope6_id *
scope6_ifattach(struct ifnet * ifp)7078678b13Srpaulo scope6_ifattach(struct ifnet *ifp)
7178678b13Srpaulo {
7278678b13Srpaulo 	struct scope6_id *sid;
7378678b13Srpaulo 
74c4a55989Smaxv 	sid = malloc(sizeof(*sid), M_IFADDR, M_WAITOK | M_ZERO);
7578678b13Srpaulo 
7678678b13Srpaulo 	/*
7778678b13Srpaulo 	 * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard.
7878678b13Srpaulo 	 * Should we rather hardcode here?
7978678b13Srpaulo 	 */
8078678b13Srpaulo 	sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = ifp->if_index;
8178678b13Srpaulo 	sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index;
8278678b13Srpaulo #ifdef MULTI_SCOPE
8378678b13Srpaulo 	/* by default, we don't care about scope boundary for these scopes. */
8478678b13Srpaulo 	sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL] = 1;
8578678b13Srpaulo 	sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL] = 1;
8678678b13Srpaulo #endif
8778678b13Srpaulo 
8878678b13Srpaulo 	return sid;
8978678b13Srpaulo }
9078678b13Srpaulo 
9178678b13Srpaulo void
scope6_ifdetach(struct scope6_id * sid)9278678b13Srpaulo scope6_ifdetach(struct scope6_id *sid)
9378678b13Srpaulo {
9478678b13Srpaulo 
9578678b13Srpaulo 	free(sid, M_IFADDR);
9678678b13Srpaulo }
9778678b13Srpaulo 
9878678b13Srpaulo /*
9978678b13Srpaulo  * Get a scope of the address. Interface-local, link-local, site-local
10078678b13Srpaulo  * or global.
10178678b13Srpaulo  */
10278678b13Srpaulo int
in6_addrscope(const struct in6_addr * addr)103d072fd0fSdyoung in6_addrscope(const struct in6_addr *addr)
10478678b13Srpaulo {
10578678b13Srpaulo 	int scope;
10678678b13Srpaulo 
10778678b13Srpaulo 	if (addr->s6_addr[0] == 0xfe) {
10878678b13Srpaulo 		scope = addr->s6_addr[1] & 0xc0;
10978678b13Srpaulo 
11078678b13Srpaulo 		switch (scope) {
11178678b13Srpaulo 		case 0x80:
11278678b13Srpaulo 			return IPV6_ADDR_SCOPE_LINKLOCAL;
11378678b13Srpaulo 		case 0xc0:
11478678b13Srpaulo 			return IPV6_ADDR_SCOPE_SITELOCAL;
11578678b13Srpaulo 		default:
11678678b13Srpaulo 			return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */
11778678b13Srpaulo 		}
11878678b13Srpaulo 	}
11978678b13Srpaulo 
12078678b13Srpaulo 	if (addr->s6_addr[0] == 0xff) {
12178678b13Srpaulo 		scope = addr->s6_addr[1] & 0x0f;
12278678b13Srpaulo 
12378678b13Srpaulo 		/*
12478678b13Srpaulo 		 * due to other scope such as reserved,
12578678b13Srpaulo 		 * return scope doesn't work.
12678678b13Srpaulo 		 */
12778678b13Srpaulo 		switch (scope) {
12878678b13Srpaulo 		case IPV6_ADDR_SCOPE_INTFACELOCAL:
12978678b13Srpaulo 			return IPV6_ADDR_SCOPE_INTFACELOCAL;
13078678b13Srpaulo 		case IPV6_ADDR_SCOPE_LINKLOCAL:
13178678b13Srpaulo 			return IPV6_ADDR_SCOPE_LINKLOCAL;
13278678b13Srpaulo 		case IPV6_ADDR_SCOPE_SITELOCAL:
13378678b13Srpaulo 			return IPV6_ADDR_SCOPE_SITELOCAL;
13478678b13Srpaulo 		default:
13578678b13Srpaulo 			return IPV6_ADDR_SCOPE_GLOBAL;
13678678b13Srpaulo 		}
13778678b13Srpaulo 	}
13878678b13Srpaulo 
139d072fd0fSdyoung 	if (memcmp(&in6addr_loopback, addr, sizeof(*addr) - 1) == 0) {
14078678b13Srpaulo 		if (addr->s6_addr[15] == 1) /* loopback */
14178678b13Srpaulo 			return IPV6_ADDR_SCOPE_LINKLOCAL;
14278678b13Srpaulo 		if (addr->s6_addr[15] == 0) {
14378678b13Srpaulo 			/*
14478678b13Srpaulo 			 * Regard the unspecified addresses as global,
14578678b13Srpaulo 			 * since it has no ambiguity.
14678678b13Srpaulo 			 * XXX: not sure if it's correct...
14778678b13Srpaulo 			 */
14878678b13Srpaulo 			return IPV6_ADDR_SCOPE_GLOBAL;
14978678b13Srpaulo 		}
15078678b13Srpaulo 	}
15178678b13Srpaulo 
15278678b13Srpaulo 	return IPV6_ADDR_SCOPE_GLOBAL;
15378678b13Srpaulo }
15478678b13Srpaulo 
15578678b13Srpaulo uint32_t
scope6_addr2default(const struct in6_addr * addr)156d072fd0fSdyoung scope6_addr2default(const struct in6_addr *addr)
15778678b13Srpaulo {
15878678b13Srpaulo 	uint32_t id;
15978678b13Srpaulo 
16078678b13Srpaulo 	/*
16178678b13Srpaulo 	 * special case: The loopback address should be considered as
16278678b13Srpaulo 	 * link-local, but there's no ambiguity in the syntax.
16378678b13Srpaulo 	 */
16478678b13Srpaulo 	if (IN6_IS_ADDR_LOOPBACK(addr))
165c4a55989Smaxv 		return 0;
16678678b13Srpaulo 
16778678b13Srpaulo 	/*
16878678b13Srpaulo 	 * XXX: 32-bit read is atomic on all our platforms, is it OK
16978678b13Srpaulo 	 * not to lock here?
17078678b13Srpaulo 	 */
17178678b13Srpaulo 	id = sid_default.s6id_list[in6_addrscope(addr)];
17278678b13Srpaulo 
173c4a55989Smaxv 	return id;
17478678b13Srpaulo }
17578678b13Srpaulo 
17678678b13Srpaulo /*
17778678b13Srpaulo  * Validate the specified scope zone ID in the sin6_scope_id field.  If the ID
17878678b13Srpaulo  * is unspecified (=0), needs to be specified, and the default zone ID can be
17978678b13Srpaulo  * used, the default value will be used.
18078678b13Srpaulo  * This routine then generates the kernel-internal form: if the address scope
18178678b13Srpaulo  * of is interface-local or link-local, embed the interface index in the
18278678b13Srpaulo  * address.
18378678b13Srpaulo  */
18478678b13Srpaulo int
sa6_embedscope(struct sockaddr_in6 * sin6,int defaultok)18578678b13Srpaulo sa6_embedscope(struct sockaddr_in6 *sin6, int defaultok)
18678678b13Srpaulo {
18778678b13Srpaulo 	struct ifnet *ifp;
18878678b13Srpaulo 	uint32_t zoneid;
18978678b13Srpaulo 
19078678b13Srpaulo 	if ((zoneid = sin6->sin6_scope_id) == 0 && defaultok)
19178678b13Srpaulo 		zoneid = scope6_addr2default(&sin6->sin6_addr);
19278678b13Srpaulo 
19378678b13Srpaulo 	if (zoneid != 0 &&
19478678b13Srpaulo 	    (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
19578678b13Srpaulo 	    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr))) {
196c7e18ccbSozaki-r 		int s;
19778678b13Srpaulo 		/*
19878678b13Srpaulo 		 * At this moment, we only check interface-local and
19978678b13Srpaulo 		 * link-local scope IDs, and use interface indices as the
20078678b13Srpaulo 		 * zone IDs assuming a one-to-one mapping between interfaces
20178678b13Srpaulo 		 * and links.
20278678b13Srpaulo 		 */
203c7e18ccbSozaki-r 		s = pserialize_read_enter();
204bc9504c9Srmind 		ifp = if_byindex(zoneid);
205c7e18ccbSozaki-r 		if (ifp == NULL) {
206c7e18ccbSozaki-r 			pserialize_read_exit(s);
207c4a55989Smaxv 			return ENXIO;
208c7e18ccbSozaki-r 		}
209c7e18ccbSozaki-r 		pserialize_read_exit(s);
21078678b13Srpaulo 
21178678b13Srpaulo 		/* XXX assignment to 16bit from 32bit variable */
21278678b13Srpaulo 		sin6->sin6_addr.s6_addr16[1] = htons(zoneid & 0xffff);
21378678b13Srpaulo 
21478678b13Srpaulo 		sin6->sin6_scope_id = 0;
21578678b13Srpaulo 	}
21678678b13Srpaulo 
21778678b13Srpaulo 	return 0;
21878678b13Srpaulo }
21978678b13Srpaulo 
220c5d5f769Sdyoung struct sockaddr *
sockaddr_in6_externalize(struct sockaddr * dst,socklen_t socklen,const struct sockaddr * src)221c5d5f769Sdyoung sockaddr_in6_externalize(struct sockaddr *dst, socklen_t socklen,
222c5d5f769Sdyoung     const struct sockaddr *src)
223c5d5f769Sdyoung {
224c5d5f769Sdyoung 	struct sockaddr_in6 *sin6;
225c5d5f769Sdyoung 
226c5d5f769Sdyoung 	sin6 = satosin6(sockaddr_copy(dst, socklen, src));
227c5d5f769Sdyoung 
228c5d5f769Sdyoung 	if (sin6 == NULL || sa6_recoverscope(sin6) != 0)
229c5d5f769Sdyoung 		return NULL;
230c5d5f769Sdyoung 
231c5d5f769Sdyoung 	return dst;
232c5d5f769Sdyoung }
233c5d5f769Sdyoung 
23478678b13Srpaulo /*
23578678b13Srpaulo  * generate standard sockaddr_in6 from embedded form.
23678678b13Srpaulo  */
23778678b13Srpaulo int
sa6_recoverscope(struct sockaddr_in6 * sin6)23878678b13Srpaulo sa6_recoverscope(struct sockaddr_in6 *sin6)
23978678b13Srpaulo {
24078678b13Srpaulo 	uint32_t zoneid;
24128f4c24cSryo 	char ip6buf[INET6_ADDRSTRLEN];
24278678b13Srpaulo 
24378678b13Srpaulo 	if (sin6->sin6_scope_id != 0) {
24478678b13Srpaulo 		log(LOG_NOTICE,
245da66cce8Schristos 		    "%s: assumption failure (non 0 ID): %s%%%d\n", __func__,
24635561f6bSchristos 		    IN6_PRINT(ip6buf, &sin6->sin6_addr), sin6->sin6_scope_id);
24778678b13Srpaulo 		/* XXX: proceed anyway... */
24878678b13Srpaulo 	}
24978678b13Srpaulo 	if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
25078678b13Srpaulo 	    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) {
25178678b13Srpaulo 		/*
25278678b13Srpaulo 		 * KAME assumption: link id == interface id
25378678b13Srpaulo 		 */
25478678b13Srpaulo 		zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]);
25578678b13Srpaulo 		if (zoneid) {
256c7e18ccbSozaki-r 			int s = pserialize_read_enter();
257c7e18ccbSozaki-r 			if (!if_byindex(zoneid)) {
258c7e18ccbSozaki-r 				pserialize_read_exit(s);
259c4a55989Smaxv 				return ENXIO;
260c7e18ccbSozaki-r 			}
261c7e18ccbSozaki-r 			pserialize_read_exit(s);
26278678b13Srpaulo 			sin6->sin6_addr.s6_addr16[1] = 0;
26378678b13Srpaulo 			sin6->sin6_scope_id = zoneid;
26478678b13Srpaulo 		}
26578678b13Srpaulo 	}
26678678b13Srpaulo 
26778678b13Srpaulo 	return 0;
26878678b13Srpaulo }
26978678b13Srpaulo 
270d072fd0fSdyoung int
in6_setzoneid(struct in6_addr * in6,uint32_t zoneid)271d072fd0fSdyoung in6_setzoneid(struct in6_addr *in6, uint32_t zoneid)
272d072fd0fSdyoung {
273d072fd0fSdyoung 	if (IN6_IS_SCOPE_EMBEDDABLE(in6))
274d072fd0fSdyoung 		in6->s6_addr16[1] = htons(zoneid & 0xffff); /* XXX */
275d072fd0fSdyoung 
276d072fd0fSdyoung 	return 0;
277d072fd0fSdyoung }
278d072fd0fSdyoung 
27978678b13Srpaulo /*
28078678b13Srpaulo  * Determine the appropriate scope zone ID for in6 and ifp.  If ret_id is
28178678b13Srpaulo  * non NULL, it is set to the zone ID.  If the zone ID needs to be embedded
28278678b13Srpaulo  * in the in6_addr structure, in6 will be modified.
28378678b13Srpaulo  */
28478678b13Srpaulo int
in6_setscope(struct in6_addr * in6,const struct ifnet * ifp,uint32_t * ret_id)285d072fd0fSdyoung in6_setscope(struct in6_addr *in6, const struct ifnet *ifp, uint32_t *ret_id)
28678678b13Srpaulo {
28778678b13Srpaulo 	int scope;
28878678b13Srpaulo 	uint32_t zoneid = 0;
289d072fd0fSdyoung 	const struct scope6_id *sid = SID(ifp);
29078678b13Srpaulo 
291da66cce8Schristos 	if (sid == NULL) {
292da66cce8Schristos 		log(LOG_NOTICE, "%s: no scope id for %s\n", __func__,
293da66cce8Schristos 		    if_name(ifp));
294fa02ef2cSchristos 		return EINVAL;
295da66cce8Schristos 	}
29678678b13Srpaulo 
29778678b13Srpaulo 	/*
29878678b13Srpaulo 	 * special case: the loopback address can only belong to a loopback
29978678b13Srpaulo 	 * interface.
30078678b13Srpaulo 	 */
30178678b13Srpaulo 	if (IN6_IS_ADDR_LOOPBACK(in6)) {
302da66cce8Schristos 		if (!(ifp->if_flags & IFF_LOOPBACK)) {
303da66cce8Schristos 			char ip6buf[INET6_ADDRSTRLEN];
304da66cce8Schristos 			log(LOG_NOTICE, "%s: can't set scope for not loopback "
305da66cce8Schristos 			    "interface %s and loopback address %s\n",
306da66cce8Schristos 			    __func__, if_name(ifp), IN6_PRINT(ip6buf, in6));
307da66cce8Schristos 			return EINVAL;
308da66cce8Schristos 		} else {
30978678b13Srpaulo 			if (ret_id != NULL)
31078678b13Srpaulo 				*ret_id = 0; /* there's no ambiguity */
311da66cce8Schristos 			return 0;
31278678b13Srpaulo 		}
31378678b13Srpaulo 	}
31478678b13Srpaulo 
31578678b13Srpaulo 	scope = in6_addrscope(in6);
31678678b13Srpaulo 
31778678b13Srpaulo 	switch (scope) {
31878678b13Srpaulo 	case IPV6_ADDR_SCOPE_INTFACELOCAL: /* should be interface index */
31978678b13Srpaulo 		zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL];
32078678b13Srpaulo 		break;
32178678b13Srpaulo 
32278678b13Srpaulo 	case IPV6_ADDR_SCOPE_LINKLOCAL:
32378678b13Srpaulo 		zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL];
32478678b13Srpaulo 		break;
32578678b13Srpaulo 
32678678b13Srpaulo 	case IPV6_ADDR_SCOPE_SITELOCAL:
32778678b13Srpaulo 		zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL];
32878678b13Srpaulo 		break;
32978678b13Srpaulo 
33078678b13Srpaulo 	case IPV6_ADDR_SCOPE_ORGLOCAL:
33178678b13Srpaulo 		zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL];
33278678b13Srpaulo 		break;
33378678b13Srpaulo 
33478678b13Srpaulo 	default:
33578678b13Srpaulo 		zoneid = 0;	/* XXX: treat as global. */
33678678b13Srpaulo 		break;
33778678b13Srpaulo 	}
33878678b13Srpaulo 
33978678b13Srpaulo 	if (ret_id != NULL)
34078678b13Srpaulo 		*ret_id = zoneid;
34178678b13Srpaulo 
342d072fd0fSdyoung 	return in6_setzoneid(in6, zoneid);
34378678b13Srpaulo }
34478678b13Srpaulo 
345d1456cccSchristos const char *
in6_getscopename(const struct in6_addr * addr)346d1456cccSchristos in6_getscopename(const struct in6_addr *addr)
347d1456cccSchristos {
348d1456cccSchristos 	switch (in6_addrscope(addr)) {
349c4a55989Smaxv 	case IPV6_ADDR_SCOPE_INTFACELOCAL:
350c4a55989Smaxv 		return "interface";
351d1456cccSchristos #if IPV6_ADDR_SCOPE_INTFACELOCAL != IPV6_ADDR_SCOPE_NODELOCAL
352c4a55989Smaxv 	case IPV6_ADDR_SCOPE_NODELOCAL:
353c4a55989Smaxv 		return "node";
354d1456cccSchristos #endif
355c4a55989Smaxv 	case IPV6_ADDR_SCOPE_LINKLOCAL:
356c4a55989Smaxv 		return "link";
357c4a55989Smaxv 	case IPV6_ADDR_SCOPE_SITELOCAL:
358c4a55989Smaxv 		return "site";
359c4a55989Smaxv 	case IPV6_ADDR_SCOPE_ORGLOCAL:
360c4a55989Smaxv 		return "organization";
361c4a55989Smaxv 	case IPV6_ADDR_SCOPE_GLOBAL:
362c4a55989Smaxv 		return "global";
363c4a55989Smaxv 	default:
364c4a55989Smaxv 		return "unknown";
365d1456cccSchristos 	}
366d1456cccSchristos }
367d1456cccSchristos 
36878678b13Srpaulo /*
36978678b13Srpaulo  * Just clear the embedded scope identifier.  Return 0 if the original address
37078678b13Srpaulo  * is intact; return non 0 if the address is modified.
37178678b13Srpaulo  */
37278678b13Srpaulo int
in6_clearscope(struct in6_addr * in6)37378678b13Srpaulo in6_clearscope(struct in6_addr *in6)
37478678b13Srpaulo {
37578678b13Srpaulo 	int modified = 0;
37678678b13Srpaulo 
37778678b13Srpaulo 	if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) {
37878678b13Srpaulo 		if (in6->s6_addr16[1] != 0)
37978678b13Srpaulo 			modified = 1;
38078678b13Srpaulo 		in6->s6_addr16[1] = 0;
38178678b13Srpaulo 	}
38278678b13Srpaulo 
383c4a55989Smaxv 	return modified;
38478678b13Srpaulo }
385