1*1fddfc45Sflorian /* $OpenBSD: in6.c,v 1.267 2024/06/07 09:48:19 florian Exp $ */
22c239e58Sitojun /* $KAME: in6.c,v 1.372 2004/06/14 08:14:21 itojun Exp $ */
3f4f4d166Sitojun
4d3b325d0Sderaadt /*
5287546eaSitojun * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6287546eaSitojun * All rights reserved.
7287546eaSitojun *
8287546eaSitojun * Redistribution and use in source and binary forms, with or without
9287546eaSitojun * modification, are permitted provided that the following conditions
10287546eaSitojun * are met:
11287546eaSitojun * 1. Redistributions of source code must retain the above copyright
12287546eaSitojun * notice, this list of conditions and the following disclaimer.
13287546eaSitojun * 2. Redistributions in binary form must reproduce the above copyright
14287546eaSitojun * notice, this list of conditions and the following disclaimer in the
15287546eaSitojun * documentation and/or other materials provided with the distribution.
16287546eaSitojun * 3. Neither the name of the project nor the names of its contributors
17287546eaSitojun * may be used to endorse or promote products derived from this software
18287546eaSitojun * without specific prior written permission.
19287546eaSitojun *
20287546eaSitojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21287546eaSitojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22287546eaSitojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23287546eaSitojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24287546eaSitojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25287546eaSitojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26287546eaSitojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27287546eaSitojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28287546eaSitojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29287546eaSitojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30287546eaSitojun * SUCH DAMAGE.
31d3b325d0Sderaadt */
32d3b325d0Sderaadt
33287546eaSitojun /*
34287546eaSitojun * Copyright (c) 1982, 1986, 1991, 1993
35287546eaSitojun * The Regents of the University of California. All rights reserved.
36287546eaSitojun *
37287546eaSitojun * Redistribution and use in source and binary forms, with or without
38287546eaSitojun * modification, are permitted provided that the following conditions
39287546eaSitojun * are met:
40287546eaSitojun * 1. Redistributions of source code must retain the above copyright
41287546eaSitojun * notice, this list of conditions and the following disclaimer.
42287546eaSitojun * 2. Redistributions in binary form must reproduce the above copyright
43287546eaSitojun * notice, this list of conditions and the following disclaimer in the
44287546eaSitojun * documentation and/or other materials provided with the distribution.
4529295d1cSmillert * 3. Neither the name of the University nor the names of its contributors
46287546eaSitojun * may be used to endorse or promote products derived from this software
47287546eaSitojun * without specific prior written permission.
48287546eaSitojun *
49287546eaSitojun * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50287546eaSitojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51287546eaSitojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52287546eaSitojun * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53287546eaSitojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54287546eaSitojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55287546eaSitojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56287546eaSitojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57287546eaSitojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58287546eaSitojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59287546eaSitojun * SUCH DAMAGE.
60287546eaSitojun *
61287546eaSitojun * @(#)in.c 8.2 (Berkeley) 11/15/93
62287546eaSitojun */
63287546eaSitojun
64276c252dSbluhm #include "carp.h"
65276c252dSbluhm
66d3b325d0Sderaadt #include <sys/param.h>
67d3b325d0Sderaadt #include <sys/ioctl.h>
68d3b325d0Sderaadt #include <sys/errno.h>
69d3b325d0Sderaadt #include <sys/malloc.h>
70d3b325d0Sderaadt #include <sys/socket.h>
71d3b325d0Sderaadt #include <sys/socketvar.h>
72287546eaSitojun #include <sys/sockio.h>
73377da2e0Sderaadt #include <sys/mbuf.h>
74d3b325d0Sderaadt #include <sys/systm.h>
75287546eaSitojun #include <sys/time.h>
76287546eaSitojun #include <sys/kernel.h>
77287546eaSitojun #include <sys/syslog.h>
78d3b325d0Sderaadt
79d3b325d0Sderaadt #include <net/if.h>
80cfc71c8bSclaudio #include <net/if_dl.h>
81d3b325d0Sderaadt #include <net/if_types.h>
82d3b325d0Sderaadt #include <net/route.h>
83d3b325d0Sderaadt
84d3b325d0Sderaadt #include <netinet/in.h>
85287546eaSitojun #include <netinet/if_ether.h>
86d3b325d0Sderaadt
87dc572864Sbluhm #include <netinet6/in6_var.h>
887832ad60Sitojun #include <netinet/ip6.h>
89287546eaSitojun #include <netinet6/ip6_var.h>
90cab0f1b1Sitojun #include <netinet6/nd6.h>
91287546eaSitojun #include <netinet6/mld6_var.h>
92d9c6379eSclaudio #ifdef MROUTING
93287546eaSitojun #include <netinet6/ip6_mroute.h>
94d9c6379eSclaudio #endif
95287546eaSitojun #include <netinet6/in6_ifattach.h>
96a7e28db1Sbluhm #if NCARP > 0
97a7e28db1Sbluhm #include <netinet/ip_carp.h>
98a7e28db1Sbluhm #endif
99d3b325d0Sderaadt
100d3b325d0Sderaadt /*
101ecd7743bSitojun * Definitions of some constant IP6 addresses.
102d3b325d0Sderaadt */
103d3b325d0Sderaadt const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
104d3b325d0Sderaadt const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
105d4070096Sitojun const struct in6_addr in6addr_intfacelocal_allnodes =
106d4070096Sitojun IN6ADDR_INTFACELOCAL_ALLNODES_INIT;
107287546eaSitojun const struct in6_addr in6addr_linklocal_allnodes =
108287546eaSitojun IN6ADDR_LINKLOCAL_ALLNODES_INIT;
10970af887bSflorian const struct in6_addr in6addr_linklocal_allrouters =
11070af887bSflorian IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
111287546eaSitojun
112287546eaSitojun const struct in6_addr in6mask0 = IN6MASK0;
113287546eaSitojun const struct in6_addr in6mask32 = IN6MASK32;
114287546eaSitojun const struct in6_addr in6mask64 = IN6MASK64;
115287546eaSitojun const struct in6_addr in6mask96 = IN6MASK96;
116287546eaSitojun const struct in6_addr in6mask128 = IN6MASK128;
117287546eaSitojun
11853224561Sguenther int in6_ioctl(u_long, caddr_t, struct ifnet *, int);
119fdc18db1Stb int in6_ioctl_change_ifaddr(u_long, caddr_t, struct ifnet *);
12089076952Stb int in6_ioctl_get(u_long, caddr_t, struct ifnet *);
121aeb66976Stb int in6_check_embed_scope(struct sockaddr_in6 *, unsigned int);
122aeb66976Stb int in6_clear_scope_id(struct sockaddr_in6 *, unsigned int);
123525dbc5aSjsing int in6_ifinit(struct ifnet *, struct in6_ifaddr *, int);
124525dbc5aSjsing void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *);
125287546eaSitojun
126525dbc5aSjsing const struct sockaddr_in6 sa6_any = {
127525dbc5aSjsing sizeof(sa6_any), AF_INET6, 0, 0, IN6ADDR_ANY_INIT, 0
128525dbc5aSjsing };
12930a4dc1cSitojun
130287546eaSitojun int
in6_mask2len(struct in6_addr * mask,u_char * lim0)131ee37ea65Smcbride in6_mask2len(struct in6_addr *mask, u_char *lim0)
132287546eaSitojun {
133d8a7e3a7Sitojun int x = 0, y;
134d8a7e3a7Sitojun u_char *lim = lim0, *p;
135287546eaSitojun
136d8a7e3a7Sitojun /* ignore the scope_id part */
137d8a7e3a7Sitojun if (lim0 == NULL || lim0 - (u_char *)mask > sizeof(*mask))
138d8a7e3a7Sitojun lim = (u_char *)mask + sizeof(*mask);
139d8a7e3a7Sitojun for (p = (u_char *)mask; p < lim; x++, p++) {
140d8a7e3a7Sitojun if (*p != 0xff)
141287546eaSitojun break;
142287546eaSitojun }
143287546eaSitojun y = 0;
144d8a7e3a7Sitojun if (p < lim) {
145287546eaSitojun for (y = 0; y < 8; y++) {
146d8a7e3a7Sitojun if ((*p & (0x80 >> y)) == 0)
147287546eaSitojun break;
148287546eaSitojun }
149287546eaSitojun }
150d8a7e3a7Sitojun
151d8a7e3a7Sitojun /*
152d8a7e3a7Sitojun * when the limit pointer is given, do a stricter check on the
153d8a7e3a7Sitojun * remaining bits.
154d8a7e3a7Sitojun */
155d8a7e3a7Sitojun if (p < lim) {
156d8a7e3a7Sitojun if (y != 0 && (*p & (0x00ff >> y)) != 0)
157d8a7e3a7Sitojun return (-1);
158d8a7e3a7Sitojun for (p = p + 1; p < lim; p++)
159d8a7e3a7Sitojun if (*p != 0)
160d8a7e3a7Sitojun return (-1);
161d8a7e3a7Sitojun }
162d8a7e3a7Sitojun
163287546eaSitojun return x * 8 + y;
164287546eaSitojun }
165d3b325d0Sderaadt
166d3b325d0Sderaadt int
in6_nam2sin6(const struct mbuf * nam,struct sockaddr_in6 ** sin6)167b2a698eaSbluhm in6_nam2sin6(const struct mbuf *nam, struct sockaddr_in6 **sin6)
168b2a698eaSbluhm {
169b2a698eaSbluhm struct sockaddr *sa = mtod(nam, struct sockaddr *);
170b2a698eaSbluhm
171b2a698eaSbluhm if (nam->m_len < offsetof(struct sockaddr, sa_data))
172b2a698eaSbluhm return EINVAL;
173b2a698eaSbluhm if (sa->sa_family != AF_INET6)
174b2a698eaSbluhm return EAFNOSUPPORT;
175b2a698eaSbluhm if (sa->sa_len != nam->m_len)
176b2a698eaSbluhm return EINVAL;
177b2a698eaSbluhm if (sa->sa_len != sizeof(struct sockaddr_in6))
178b2a698eaSbluhm return EINVAL;
179b2a698eaSbluhm *sin6 = satosin6(sa);
180b2a698eaSbluhm
181b2a698eaSbluhm return 0;
182b2a698eaSbluhm }
183b2a698eaSbluhm
184b2a698eaSbluhm int
in6_sa2sin6(struct sockaddr * sa,struct sockaddr_in6 ** sin6)1855c135f85Sbluhm in6_sa2sin6(struct sockaddr *sa, struct sockaddr_in6 **sin6)
1865c135f85Sbluhm {
1875c135f85Sbluhm if (sa->sa_family != AF_INET6)
1885c135f85Sbluhm return EAFNOSUPPORT;
1895c135f85Sbluhm if (sa->sa_len != sizeof(struct sockaddr_in6))
1905c135f85Sbluhm return EINVAL;
1915c135f85Sbluhm *sin6 = satosin6(sa);
1925c135f85Sbluhm
1935c135f85Sbluhm return 0;
1945c135f85Sbluhm }
1955c135f85Sbluhm
1965c135f85Sbluhm int
in6_control(struct socket * so,u_long cmd,caddr_t data,struct ifnet * ifp)19781bfb674Smpi in6_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp)
198d3b325d0Sderaadt {
199d732431aSmpi int privileged;
200287546eaSitojun
201287546eaSitojun privileged = 0;
202287546eaSitojun if ((so->so_state & SS_PRIV) != 0)
203287546eaSitojun privileged++;
204d3b325d0Sderaadt
205287546eaSitojun switch (cmd) {
20629477734Sflorian #ifdef MROUTING
207287546eaSitojun case SIOCGETSGCNT_IN6:
208287546eaSitojun case SIOCGETMIFCNT_IN6:
209a9069a72Skn return mrt6_ioctl(so, cmd, data);
2106c1326fdSmpi #endif /* MROUTING */
21129477734Sflorian default:
212a9069a72Skn return in6_ioctl(cmd, data, ifp, privileged);
21329477734Sflorian }
214d732431aSmpi }
215d732431aSmpi
216d732431aSmpi int
in6_ioctl(u_long cmd,caddr_t data,struct ifnet * ifp,int privileged)217d732431aSmpi in6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, int privileged)
218d732431aSmpi {
219d8a7e3a7Sitojun if (ifp == NULL)
220145df85aSmpi return (ENXIO);
221145df85aSmpi
222287546eaSitojun switch (cmd) {
223287546eaSitojun case SIOCGIFINFO_IN6:
224287546eaSitojun case SIOCGNBRINFO_IN6:
225287546eaSitojun return (nd6_ioctl(cmd, data, ifp));
22689076952Stb case SIOCGIFDSTADDR_IN6:
22789076952Stb case SIOCGIFNETMASK_IN6:
22889076952Stb case SIOCGIFAFLAG_IN6:
22989076952Stb case SIOCGIFALIFETIME_IN6:
23089076952Stb return (in6_ioctl_get(cmd, data, ifp));
23189076952Stb case SIOCAIFADDR_IN6:
23289076952Stb case SIOCDIFADDR_IN6:
233fdc18db1Stb if (!privileged)
234fdc18db1Stb return (EPERM);
235fdc18db1Stb return (in6_ioctl_change_ifaddr(cmd, data, ifp));
23689076952Stb case SIOCSIFADDR:
23789076952Stb case SIOCSIFDSTADDR:
23889076952Stb case SIOCSIFBRDADDR:
23989076952Stb case SIOCSIFNETMASK:
24089076952Stb /*
24189076952Stb * Do not pass those ioctl to driver handler since they are not
24289076952Stb * properly set up. Instead just error out.
24389076952Stb */
24489076952Stb return (EINVAL);
24589076952Stb default:
24689076952Stb return (EOPNOTSUPP);
247d3b325d0Sderaadt }
248fdc18db1Stb }
249fdc18db1Stb
250fdc18db1Stb int
in6_ioctl_change_ifaddr(u_long cmd,caddr_t data,struct ifnet * ifp)251fdc18db1Stb in6_ioctl_change_ifaddr(u_long cmd, caddr_t data, struct ifnet *ifp)
252fdc18db1Stb {
253fdc18db1Stb struct in6_ifaddr *ia6 = NULL;
254fdc18db1Stb struct in6_aliasreq *ifra = (struct in6_aliasreq *)data;
2555c135f85Sbluhm struct sockaddr *sa;
2565c135f85Sbluhm struct sockaddr_in6 *sa6 = NULL;
257fdc18db1Stb int error = 0, newifaddr = 0, plen;
258d3b325d0Sderaadt
259287546eaSitojun /*
260287546eaSitojun * Find address for this interface, if it exists.
261f04bc9a1Sitojun *
262f04bc9a1Sitojun * In netinet code, we have checked ifra_addr in SIOCSIF*ADDR operation
263f04bc9a1Sitojun * only, and used the first interface address as the target of other
264f04bc9a1Sitojun * operations (without checking ifra_addr). This was because netinet
265f04bc9a1Sitojun * code/API assumed at most 1 interface address per interface.
266f04bc9a1Sitojun * Since IPv6 allows a node to assign multiple addresses
267f04bc9a1Sitojun * on a single interface, we almost always look and check the
268f04bc9a1Sitojun * presence of ifra_addr, and reject invalid ones here.
269f04bc9a1Sitojun * It also decreases duplicated code among SIOC*_IN6 operations.
2705c135f85Sbluhm *
2715c135f85Sbluhm * We always require users to specify a valid IPv6 address for
2725c135f85Sbluhm * the corresponding operation.
273287546eaSitojun */
274fdc18db1Stb switch (cmd) {
275fdc18db1Stb case SIOCAIFADDR_IN6:
2765c135f85Sbluhm sa = sin6tosa(&ifra->ifra_addr);
277fdc18db1Stb break;
278fdc18db1Stb case SIOCDIFADDR_IN6:
2795c135f85Sbluhm sa = sin6tosa(&((struct in6_ifreq *)data)->ifr_addr);
280fdc18db1Stb break;
281fdc18db1Stb default:
2825c135f85Sbluhm panic("%s: invalid ioctl %lu", __func__, cmd);
2835c135f85Sbluhm }
2845c135f85Sbluhm if (sa->sa_family == AF_INET6) {
2855c135f85Sbluhm error = in6_sa2sin6(sa, &sa6);
2865c135f85Sbluhm if (error)
2875c135f85Sbluhm return (error);
288fdc18db1Stb }
289dd66399bStb
2903cf38294Skn KERNEL_LOCK();
291dd66399bStb NET_LOCK();
292dd66399bStb
2935c135f85Sbluhm if (sa6 != NULL) {
294aeb66976Stb error = in6_check_embed_scope(sa6, ifp->if_index);
295aeb66976Stb if (error)
296dd66399bStb goto err;
297aeb66976Stb error = in6_clear_scope_id(sa6, ifp->if_index);
298aeb66976Stb if (error)
299dd66399bStb goto err;
300b9e83c60Sbluhm ia6 = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr);
301fdc18db1Stb }
302287546eaSitojun
303287546eaSitojun switch (cmd) {
304287546eaSitojun case SIOCDIFADDR_IN6:
305f4f4d166Sitojun /*
30630a4dc1cSitojun * for IPv4, we look for existing in_ifaddr here to allow
307f04bc9a1Sitojun * "ifconfig if0 delete" to remove the first IPv4 address on
308f04bc9a1Sitojun * the interface. For IPv6, as the spec allows multiple
309f04bc9a1Sitojun * interface address from the day one, we consider "remove the
310f04bc9a1Sitojun * first one" semantics to be not preferable.
311f4f4d166Sitojun */
312dd66399bStb if (ia6 == NULL) {
313dd66399bStb error = EADDRNOTAVAIL;
314fdc18db1Stb break;
315dd66399bStb }
316fdc18db1Stb in6_purgeaddr(&ia6->ia_ifa);
317f22742abSdlg if_addrhooks_run(ifp);
318fdc18db1Stb break;
319fdc18db1Stb
320287546eaSitojun case SIOCAIFADDR_IN6:
321efa3c3ddSanton if (ifra->ifra_addr.sin6_family != AF_INET6 ||
322efa3c3ddSanton ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6)) {
323efa3c3ddSanton error = EAFNOSUPPORT;
324efa3c3ddSanton break;
325efa3c3ddSanton }
326efa3c3ddSanton
32789076952Stb /* reject read-only flags */
32889076952Stb if ((ifra->ifra_flags & IN6_IFF_DUPLICATED) != 0 ||
32989076952Stb (ifra->ifra_flags & IN6_IFF_DETACHED) != 0 ||
33089076952Stb (ifra->ifra_flags & IN6_IFF_DEPRECATED) != 0) {
33189076952Stb error = EINVAL;
33289076952Stb break;
33389076952Stb }
33489076952Stb
33589076952Stb if (ia6 == NULL)
33689076952Stb newifaddr = 1;
33789076952Stb
33889076952Stb /*
33989076952Stb * Make the address tentative before joining multicast
34089076952Stb * addresses, so that corresponding MLD responses would
34189076952Stb * not have a tentative source address.
34289076952Stb */
34389076952Stb if (newifaddr && in6if_do_dad(ifp))
34489076952Stb ifra->ifra_flags |= IN6_IFF_TENTATIVE;
34589076952Stb
34689076952Stb /*
34789076952Stb * first, make or update the interface address structure,
34889076952Stb * and link it to the list. try to enable inet6 if there
34989076952Stb * is no link-local yet.
35089076952Stb */
35189076952Stb error = in6_ifattach(ifp);
3525c135f85Sbluhm if (error)
35389076952Stb break;
35489076952Stb error = in6_update_ifa(ifp, ifra, ia6);
3555c135f85Sbluhm if (error)
35689076952Stb break;
35789076952Stb
3585c135f85Sbluhm ia6 = NULL;
3595c135f85Sbluhm if (sa6 != NULL)
3605c135f85Sbluhm ia6 = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr);
36189076952Stb if (ia6 == NULL) {
36289076952Stb /*
36389076952Stb * this can happen when the user specify the 0 valid
36489076952Stb * lifetime.
36589076952Stb */
36689076952Stb break;
36789076952Stb }
36889076952Stb
36989076952Stb /* Perform DAD, if needed. */
37089076952Stb if (ia6->ia6_flags & IN6_IFF_TENTATIVE)
37189076952Stb nd6_dad_start(&ia6->ia_ifa);
37289076952Stb
37389076952Stb if (!newifaddr) {
374f22742abSdlg if_addrhooks_run(ifp);
37589076952Stb break;
37689076952Stb }
37789076952Stb
37889076952Stb plen = in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL);
37989076952Stb if ((ifp->if_flags & IFF_LOOPBACK) || plen == 128) {
380f22742abSdlg if_addrhooks_run(ifp);
38189076952Stb break; /* No need to install a connected route. */
38289076952Stb }
38389076952Stb
38462cb75b3Sdlg error = rt_ifa_add(&ia6->ia_ifa,
38562cb75b3Sdlg RTF_CLONING | RTF_CONNECTED | RTF_MPATH,
3868f960e22Sdlg ia6->ia_ifa.ifa_addr, ifp->if_rdomain);
38789076952Stb if (error) {
38889076952Stb in6_purgeaddr(&ia6->ia_ifa);
38989076952Stb break;
39089076952Stb }
391f22742abSdlg if_addrhooks_run(ifp);
39289076952Stb break;
39389076952Stb }
39489076952Stb
39589076952Stb err:
39689076952Stb NET_UNLOCK();
3973cf38294Skn KERNEL_UNLOCK();
39889076952Stb return (error);
39989076952Stb }
40089076952Stb
40189076952Stb int
in6_ioctl_get(u_long cmd,caddr_t data,struct ifnet * ifp)40289076952Stb in6_ioctl_get(u_long cmd, caddr_t data, struct ifnet *ifp)
40389076952Stb {
40489076952Stb struct in6_ifreq *ifr = (struct in6_ifreq *)data;
40589076952Stb struct in6_ifaddr *ia6 = NULL;
4065c135f85Sbluhm struct sockaddr *sa;
4075c135f85Sbluhm struct sockaddr_in6 *sa6 = NULL;
40889076952Stb int error = 0;
40989076952Stb
4105c135f85Sbluhm sa = sin6tosa(&ifr->ifr_addr);
4115c135f85Sbluhm if (sa->sa_family == AF_INET6) {
412bf722da6Sbluhm sa->sa_len = sizeof(struct sockaddr_in6);
4135c135f85Sbluhm error = in6_sa2sin6(sa, &sa6);
4145c135f85Sbluhm if (error)
4155c135f85Sbluhm return (error);
4165c135f85Sbluhm }
41789076952Stb
4186a1c2aefSbluhm NET_LOCK_SHARED();
41989076952Stb
4205c135f85Sbluhm if (sa6 != NULL) {
421aeb66976Stb error = in6_check_embed_scope(sa6, ifp->if_index);
422aeb66976Stb if (error)
42389076952Stb goto err;
424aeb66976Stb error = in6_clear_scope_id(sa6, ifp->if_index);
425aeb66976Stb if (error)
42689076952Stb goto err;
42789076952Stb ia6 = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr);
42889076952Stb }
42989076952Stb
430287546eaSitojun /* must think again about its semantics */
431dd66399bStb if (ia6 == NULL) {
432dd66399bStb error = EADDRNOTAVAIL;
433dd66399bStb goto err;
434dd66399bStb }
435287546eaSitojun
436287546eaSitojun switch (cmd) {
437287546eaSitojun case SIOCGIFDSTADDR_IN6:
438dd66399bStb if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
439dd66399bStb error = EINVAL;
440dd66399bStb break;
441dd66399bStb }
442d8a7e3a7Sitojun /*
443d8a7e3a7Sitojun * XXX: should we check if ifa_dstaddr is NULL and return
444d8a7e3a7Sitojun * an error?
445d8a7e3a7Sitojun */
446b9e83c60Sbluhm ifr->ifr_dstaddr = ia6->ia_dstaddr;
447287546eaSitojun break;
448287546eaSitojun
449287546eaSitojun case SIOCGIFNETMASK_IN6:
450b9e83c60Sbluhm ifr->ifr_addr = ia6->ia_prefixmask;
451287546eaSitojun break;
452287546eaSitojun
453287546eaSitojun case SIOCGIFAFLAG_IN6:
454b9e83c60Sbluhm ifr->ifr_ifru.ifru_flags6 = ia6->ia6_flags;
455287546eaSitojun break;
456287546eaSitojun
457287546eaSitojun case SIOCGIFALIFETIME_IN6:
458b9e83c60Sbluhm ifr->ifr_ifru.ifru_lifetime = ia6->ia6_lifetime;
459b9e83c60Sbluhm if (ia6->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
46056b4879eSmpi time_t expire, maxexpire;
461d8a7e3a7Sitojun struct in6_addrlifetime *retlt =
462d8a7e3a7Sitojun &ifr->ifr_ifru.ifru_lifetime;
463d8a7e3a7Sitojun
464d8a7e3a7Sitojun /*
465d8a7e3a7Sitojun * XXX: adjust expiration time assuming time_t is
466d8a7e3a7Sitojun * signed.
467d8a7e3a7Sitojun */
46891a535ffSguenther maxexpire =
46991a535ffSguenther (time_t)~(1ULL << ((sizeof(maxexpire) * 8) - 1));
470b9e83c60Sbluhm if (ia6->ia6_lifetime.ia6t_vltime <
471b9e83c60Sbluhm maxexpire - ia6->ia6_updatetime) {
47256b4879eSmpi expire = ia6->ia6_updatetime +
473b9e83c60Sbluhm ia6->ia6_lifetime.ia6t_vltime;
47456b4879eSmpi if (expire != 0) {
4753209772dScheloha expire -= getuptime();
4763209772dScheloha expire += gettime();
47756b4879eSmpi }
47856b4879eSmpi retlt->ia6t_expire = expire;
479d8a7e3a7Sitojun } else
480d8a7e3a7Sitojun retlt->ia6t_expire = maxexpire;
481d8a7e3a7Sitojun }
482b9e83c60Sbluhm if (ia6->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
483c5364f84Sflorian time_t expire, maxexpire;
484d8a7e3a7Sitojun struct in6_addrlifetime *retlt =
485d8a7e3a7Sitojun &ifr->ifr_ifru.ifru_lifetime;
486d8a7e3a7Sitojun
487d8a7e3a7Sitojun /*
488d8a7e3a7Sitojun * XXX: adjust expiration time assuming time_t is
489d8a7e3a7Sitojun * signed.
490d8a7e3a7Sitojun */
49191a535ffSguenther maxexpire =
49291a535ffSguenther (time_t)~(1ULL << ((sizeof(maxexpire) * 8) - 1));
493b9e83c60Sbluhm if (ia6->ia6_lifetime.ia6t_pltime <
494b9e83c60Sbluhm maxexpire - ia6->ia6_updatetime) {
495c5364f84Sflorian expire = ia6->ia6_updatetime +
496b9e83c60Sbluhm ia6->ia6_lifetime.ia6t_pltime;
497c5364f84Sflorian if (expire != 0) {
4983209772dScheloha expire -= getuptime();
4993209772dScheloha expire += gettime();
500c5364f84Sflorian }
501c5364f84Sflorian retlt->ia6t_preferred = expire;
502d8a7e3a7Sitojun } else
503d8a7e3a7Sitojun retlt->ia6t_preferred = maxexpire;
504d8a7e3a7Sitojun }
505287546eaSitojun break;
506287546eaSitojun
507d8a7e3a7Sitojun default:
5085c135f85Sbluhm panic("%s: invalid ioctl %lu", __func__, cmd);
509d8a7e3a7Sitojun }
510d8a7e3a7Sitojun
511dd66399bStb err:
5126a1c2aefSbluhm NET_UNLOCK_SHARED();
513dd66399bStb return (error);
514d8a7e3a7Sitojun }
515d8a7e3a7Sitojun
516aeb66976Stb int
in6_check_embed_scope(struct sockaddr_in6 * sa6,unsigned int ifidx)517aeb66976Stb in6_check_embed_scope(struct sockaddr_in6 *sa6, unsigned int ifidx)
518aeb66976Stb {
519aeb66976Stb if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
520aeb66976Stb if (sa6->sin6_addr.s6_addr16[1] == 0) {
521aeb66976Stb /* link ID is not embedded by the user */
522aeb66976Stb sa6->sin6_addr.s6_addr16[1] = htons(ifidx);
523aeb66976Stb } else if (sa6->sin6_addr.s6_addr16[1] != htons(ifidx))
524aeb66976Stb return EINVAL; /* link ID contradicts */
525aeb66976Stb }
526aeb66976Stb return 0;
527aeb66976Stb }
528aeb66976Stb
529aeb66976Stb int
in6_clear_scope_id(struct sockaddr_in6 * sa6,unsigned int ifidx)530aeb66976Stb in6_clear_scope_id(struct sockaddr_in6 *sa6, unsigned int ifidx)
531aeb66976Stb {
532aeb66976Stb if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
533aeb66976Stb if (sa6->sin6_scope_id) {
534aeb66976Stb if (sa6->sin6_scope_id != (u_int32_t)ifidx)
535aeb66976Stb return EINVAL;
536aeb66976Stb sa6->sin6_scope_id = 0; /* XXX: good way? */
537aeb66976Stb }
538aeb66976Stb }
539aeb66976Stb return 0;
540aeb66976Stb }
541aeb66976Stb
542d8a7e3a7Sitojun /*
543d8a7e3a7Sitojun * Update parameters of an IPv6 interface address.
544d8a7e3a7Sitojun * If necessary, a new entry is created and linked into address chains.
545d8a7e3a7Sitojun * This function is separated from in6_control().
546d8a7e3a7Sitojun */
547d8a7e3a7Sitojun int
in6_update_ifa(struct ifnet * ifp,struct in6_aliasreq * ifra,struct in6_ifaddr * ia6)548ee37ea65Smcbride in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
549b9e83c60Sbluhm struct in6_ifaddr *ia6)
550d8a7e3a7Sitojun {
551d8a7e3a7Sitojun int error = 0, hostIsNew = 0, plen = -1;
552*1fddfc45Sflorian struct sockaddr_in6 dst6, gw6;
553d8a7e3a7Sitojun struct in6_addrlifetime *lt;
554d8a7e3a7Sitojun struct in6_multi_mship *imm;
555d8a7e3a7Sitojun struct rtentry *rt;
556bbcf0337Smpi char addr[INET6_ADDRSTRLEN];
557d8a7e3a7Sitojun
55866736630Smpi NET_ASSERT_LOCKED();
559c81f9a03Smcbride
560d8a7e3a7Sitojun /* Validate parameters */
561d8a7e3a7Sitojun if (ifp == NULL || ifra == NULL) /* this maybe redundant */
562d8a7e3a7Sitojun return (EINVAL);
563d8a7e3a7Sitojun
564f4f4d166Sitojun /*
5657186e918Sflorian * The destination address for a p2p link or the address of the
5667186e918Sflorian * announcing router for an autoconf address must have a family of
5677186e918Sflorian * AF_UNSPEC or AF_INET6.
568f4f4d166Sitojun */
5697186e918Sflorian if ((ifp->if_flags & IFF_POINTOPOINT) ||
5707186e918Sflorian (ifp->if_flags & IFF_LOOPBACK) ||
5717186e918Sflorian (ifra->ifra_flags & IN6_IFF_AUTOCONF)) {
5727186e918Sflorian if (ifra->ifra_dstaddr.sin6_family != AF_INET6 &&
573f4f4d166Sitojun ifra->ifra_dstaddr.sin6_family != AF_UNSPEC)
574f4f4d166Sitojun return (EAFNOSUPPORT);
575727c267dShenning
5767186e918Sflorian } else if (ifra->ifra_dstaddr.sin6_family != AF_UNSPEC)
5777186e918Sflorian return (EINVAL);
5787186e918Sflorian
579f4f4d166Sitojun /*
580d8a7e3a7Sitojun * validate ifra_prefixmask. don't check sin6_family, netmask
581d8a7e3a7Sitojun * does not carry fields other than sin6_len.
582f4f4d166Sitojun */
583d8a7e3a7Sitojun if (ifra->ifra_prefixmask.sin6_len > sizeof(struct sockaddr_in6))
584d8a7e3a7Sitojun return (EINVAL);
585d8a7e3a7Sitojun /*
586d8a7e3a7Sitojun * Because the IPv6 address architecture is classless, we require
587d8a7e3a7Sitojun * users to specify a (non 0) prefix length (mask) for a new address.
588d8a7e3a7Sitojun * We also require the prefix (when specified) mask is valid, and thus
589d8a7e3a7Sitojun * reject a non-consecutive mask.
590d8a7e3a7Sitojun */
591b9e83c60Sbluhm if (ia6 == NULL && ifra->ifra_prefixmask.sin6_len == 0)
592d8a7e3a7Sitojun return (EINVAL);
593d8a7e3a7Sitojun if (ifra->ifra_prefixmask.sin6_len != 0) {
594d8a7e3a7Sitojun plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,
595d8a7e3a7Sitojun (u_char *)&ifra->ifra_prefixmask +
596d8a7e3a7Sitojun ifra->ifra_prefixmask.sin6_len);
597d8a7e3a7Sitojun if (plen <= 0)
598d8a7e3a7Sitojun return (EINVAL);
599d8a7e3a7Sitojun } else {
600d8a7e3a7Sitojun /*
601b9e83c60Sbluhm * In this case, ia6 must not be NULL. We just use its prefix
602d8a7e3a7Sitojun * length.
603d8a7e3a7Sitojun */
604b9e83c60Sbluhm plen = in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL);
605d3b325d0Sderaadt }
6067186e918Sflorian
607*1fddfc45Sflorian if (ifra->ifra_flags & IN6_IFF_AUTOCONF) {
608*1fddfc45Sflorian gw6 = ifra->ifra_dstaddr;
609*1fddfc45Sflorian memset(&dst6, 0, sizeof(dst6));
610*1fddfc45Sflorian } else {
611d8a7e3a7Sitojun dst6 = ifra->ifra_dstaddr;
612*1fddfc45Sflorian memset(&gw6, 0, sizeof(gw6));
613*1fddfc45Sflorian }
6147186e918Sflorian if (dst6.sin6_family == AF_INET6) {
615aeb66976Stb error = in6_check_embed_scope(&dst6, ifp->if_index);
616aeb66976Stb if (error)
617aeb66976Stb return error;
6187186e918Sflorian
6197186e918Sflorian if (((ifp->if_flags & IFF_POINTOPOINT) ||
6207186e918Sflorian (ifp->if_flags & IFF_LOOPBACK)) && plen != 128)
621d8a7e3a7Sitojun return (EINVAL);
622248db9a2Sitojun }
623*1fddfc45Sflorian if (gw6.sin6_family == AF_INET6) {
624*1fddfc45Sflorian error = in6_check_embed_scope(&gw6, ifp->if_index);
625*1fddfc45Sflorian if (error)
626*1fddfc45Sflorian return error;
627*1fddfc45Sflorian }
628d8a7e3a7Sitojun /* lifetime consistency check */
629d8a7e3a7Sitojun lt = &ifra->ifra_lifetime;
630d8a7e3a7Sitojun if (lt->ia6t_pltime > lt->ia6t_vltime)
631d8a7e3a7Sitojun return (EINVAL);
632d8a7e3a7Sitojun if (lt->ia6t_vltime == 0) {
633287546eaSitojun /*
634d8a7e3a7Sitojun * the following log might be noisy, but this is a typical
635d8a7e3a7Sitojun * configuration mistake or a tool's bug.
636287546eaSitojun */
637d61e4f47Sbluhm nd6log((LOG_INFO, "%s: valid lifetime is 0 for %s\n", __func__,
638bbcf0337Smpi inet_ntop(AF_INET6, &ifra->ifra_addr.sin6_addr,
639bbcf0337Smpi addr, sizeof(addr))));
640d8a7e3a7Sitojun
641b9e83c60Sbluhm if (ia6 == NULL)
642d8a7e3a7Sitojun return (0); /* there's nothing to do */
643287546eaSitojun }
644287546eaSitojun
645d8a7e3a7Sitojun /*
646d8a7e3a7Sitojun * If this is a new address, allocate a new ifaddr and link it
647d8a7e3a7Sitojun * into chains.
648d8a7e3a7Sitojun */
649b9e83c60Sbluhm if (ia6 == NULL) {
650d8a7e3a7Sitojun hostIsNew = 1;
651b9e83c60Sbluhm ia6 = malloc(sizeof(*ia6), M_IFADDR, M_WAITOK | M_ZERO);
65218a44669Sbluhm refcnt_init_trace(&ia6->ia_ifa.ifa_refcnt,
65318a44669Sbluhm DT_REFCNT_IDX_IFADDR);
654b9e83c60Sbluhm LIST_INIT(&ia6->ia6_memberships);
655d8a7e3a7Sitojun /* Initialize the address and masks, and put time stamp */
656b9e83c60Sbluhm ia6->ia_ifa.ifa_addr = sin6tosa(&ia6->ia_addr);
657b9e83c60Sbluhm ia6->ia_addr.sin6_family = AF_INET6;
658b9e83c60Sbluhm ia6->ia_addr.sin6_len = sizeof(ia6->ia_addr);
6593209772dScheloha ia6->ia6_updatetime = getuptime();
6607186e918Sflorian if ((ifp->if_flags & IFF_POINTOPOINT) ||
6617186e918Sflorian (ifp->if_flags & IFF_LOOPBACK)) {
662d8a7e3a7Sitojun /*
663d8a7e3a7Sitojun * XXX: some functions expect that ifa_dstaddr is not
664d8a7e3a7Sitojun * NULL for p2p interfaces.
665d8a7e3a7Sitojun */
666b9e83c60Sbluhm ia6->ia_ifa.ifa_dstaddr = sin6tosa(&ia6->ia_dstaddr);
667d8a7e3a7Sitojun } else {
668b9e83c60Sbluhm ia6->ia_ifa.ifa_dstaddr = NULL;
669d8a7e3a7Sitojun }
670b9e83c60Sbluhm ia6->ia_ifa.ifa_netmask = sin6tosa(&ia6->ia_prefixmask);
671287546eaSitojun
672b9e83c60Sbluhm ia6->ia_ifp = ifp;
673b9e83c60Sbluhm ia6->ia_addr = ifra->ifra_addr;
674b9e83c60Sbluhm ifa_add(ifp, &ia6->ia_ifa);
675d8a7e3a7Sitojun }
676d8a7e3a7Sitojun
677d8a7e3a7Sitojun /* set prefix mask */
678d8a7e3a7Sitojun if (ifra->ifra_prefixmask.sin6_len) {
679d8a7e3a7Sitojun /*
680d8a7e3a7Sitojun * We prohibit changing the prefix length of an existing
681d8a7e3a7Sitojun * address, because
682d8a7e3a7Sitojun * + such an operation should be rare in IPv6, and
683d8a7e3a7Sitojun * + the operation would confuse prefix management.
684d8a7e3a7Sitojun */
685b9e83c60Sbluhm if (ia6->ia_prefixmask.sin6_len &&
686b9e83c60Sbluhm in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL) != plen) {
687d8a7e3a7Sitojun error = EINVAL;
688d8a7e3a7Sitojun goto unlink;
689d8a7e3a7Sitojun }
690b9e83c60Sbluhm ia6->ia_prefixmask = ifra->ifra_prefixmask;
691d8a7e3a7Sitojun }
692d8a7e3a7Sitojun
693d8a7e3a7Sitojun /*
694d8a7e3a7Sitojun * If a new destination address is specified, scrub the old one and
6957186e918Sflorian * install the new destination.
696d8a7e3a7Sitojun */
6977186e918Sflorian if (((ifp->if_flags & IFF_POINTOPOINT) ||
6987186e918Sflorian (ifp->if_flags & IFF_LOOPBACK)) && dst6.sin6_family == AF_INET6 &&
699b9e83c60Sbluhm !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, &ia6->ia_dstaddr.sin6_addr)) {
700daed62aeSmpi struct ifaddr *ifa = &ia6->ia_ifa;
701d8a7e3a7Sitojun
702b9e83c60Sbluhm if ((ia6->ia_flags & IFA_ROUTE) != 0 &&
7038f960e22Sdlg rt_ifa_del(ifa, RTF_HOST, ifa->ifa_dstaddr,
7048f960e22Sdlg ifp->if_rdomain) != 0) {
705d61e4f47Sbluhm nd6log((LOG_ERR, "%s: failed to remove a route "
706d61e4f47Sbluhm "to the old destination: %s\n", __func__,
707b9e83c60Sbluhm inet_ntop(AF_INET6, &ia6->ia_addr.sin6_addr,
708bbcf0337Smpi addr, sizeof(addr))));
709d8a7e3a7Sitojun /* proceed anyway... */
710d8a7e3a7Sitojun } else
711b9e83c60Sbluhm ia6->ia_flags &= ~IFA_ROUTE;
712b9e83c60Sbluhm ia6->ia_dstaddr = dst6;
713d8a7e3a7Sitojun }
714d8a7e3a7Sitojun
7157186e918Sflorian if ((ifra->ifra_flags & IN6_IFF_AUTOCONF) &&
716*1fddfc45Sflorian gw6.sin6_family == AF_INET6 &&
7177186e918Sflorian !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, &ia6->ia_gwaddr.sin6_addr)) {
7187186e918Sflorian /* Set or update announcing router */
719*1fddfc45Sflorian ia6->ia_gwaddr = gw6;
7207186e918Sflorian }
7217186e918Sflorian
722d8a7e3a7Sitojun /*
723d8a7e3a7Sitojun * Set lifetimes. We do not refer to ia6t_expire and ia6t_preferred
724d8a7e3a7Sitojun * to see if the address is deprecated or invalidated, but initialize
725d8a7e3a7Sitojun * these members for applications.
726d8a7e3a7Sitojun */
7273209772dScheloha ia6->ia6_updatetime = getuptime();
728b9e83c60Sbluhm ia6->ia6_lifetime = ifra->ifra_lifetime;
729b9e83c60Sbluhm if (ia6->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
730b9e83c60Sbluhm ia6->ia6_lifetime.ia6t_expire =
7313209772dScheloha getuptime() + ia6->ia6_lifetime.ia6t_vltime;
732287546eaSitojun } else
733b9e83c60Sbluhm ia6->ia6_lifetime.ia6t_expire = 0;
734b9e83c60Sbluhm if (ia6->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
735b9e83c60Sbluhm ia6->ia6_lifetime.ia6t_preferred =
7363209772dScheloha getuptime() + ia6->ia6_lifetime.ia6t_pltime;
737287546eaSitojun } else
738b9e83c60Sbluhm ia6->ia6_lifetime.ia6t_preferred = 0;
739287546eaSitojun
740d8a7e3a7Sitojun /* reset the interface and routing table appropriately. */
741b9e83c60Sbluhm if ((error = in6_ifinit(ifp, ia6, hostIsNew)) != 0)
742d8a7e3a7Sitojun goto unlink;
743d8a7e3a7Sitojun
744d505a6a7Sflorian /* re-run DAD */
745d505a6a7Sflorian if (ia6->ia6_flags & (IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED))
746d505a6a7Sflorian ifra->ifra_flags |= IN6_IFF_TENTATIVE;
747287546eaSitojun /*
7487d37e67aSitojun * configure address flags.
7497d37e67aSitojun */
750b9e83c60Sbluhm ia6->ia6_flags = ifra->ifra_flags;
751d8a7e3a7Sitojun
752c6bbd2a8Sflorian nd6_expire_timer_update(ia6);
753c6bbd2a8Sflorian
754d8a7e3a7Sitojun /*
755c61d7628Sitojun * We are done if we have simply modified an existing address.
756c61d7628Sitojun */
7576859a790Sflorian if (!hostIsNew) {
7586859a790Sflorian /* DAD sends RTM_CHGADDRATTR when done. */
7596859a790Sflorian if (!(ia6->ia6_flags & IN6_IFF_TENTATIVE))
7606859a790Sflorian rtm_addr(RTM_CHGADDRATTR, &ia6->ia_ifa);
761c61d7628Sitojun return (error);
7626859a790Sflorian }
763c61d7628Sitojun
764c61d7628Sitojun /*
765d8a7e3a7Sitojun * Beyond this point, we should call in6_purgeaddr upon an error,
766d8a7e3a7Sitojun * not just go to unlink.
767d8a7e3a7Sitojun */
768d8a7e3a7Sitojun
769c61d7628Sitojun /* join necessary multiast groups */
770d8a7e3a7Sitojun if ((ifp->if_flags & IFF_MULTICAST) != 0) {
771d8a7e3a7Sitojun struct sockaddr_in6 mltaddr, mltmask;
772287546eaSitojun
773d8a7e3a7Sitojun /* join solicited multicast addr for new host id */
774d8a7e3a7Sitojun struct sockaddr_in6 llsol;
775287546eaSitojun
776d8a7e3a7Sitojun bzero(&llsol, sizeof(llsol));
777d8a7e3a7Sitojun llsol.sin6_family = AF_INET6;
778d8a7e3a7Sitojun llsol.sin6_len = sizeof(llsol);
779d8a7e3a7Sitojun llsol.sin6_addr.s6_addr16[0] = htons(0xff02);
780d8a7e3a7Sitojun llsol.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
781d8a7e3a7Sitojun llsol.sin6_addr.s6_addr32[1] = 0;
782d8a7e3a7Sitojun llsol.sin6_addr.s6_addr32[2] = htonl(1);
783d8a7e3a7Sitojun llsol.sin6_addr.s6_addr32[3] =
784d8a7e3a7Sitojun ifra->ifra_addr.sin6_addr.s6_addr32[3];
785d8a7e3a7Sitojun llsol.sin6_addr.s6_addr8[12] = 0xff;
786c61d7628Sitojun imm = in6_joingroup(ifp, &llsol.sin6_addr, &error);
7873236de58Smpi if (!imm)
788d8a7e3a7Sitojun goto cleanup;
789b9e83c60Sbluhm LIST_INSERT_HEAD(&ia6->ia6_memberships, imm, i6mm_chain);
790d8a7e3a7Sitojun
791d8a7e3a7Sitojun bzero(&mltmask, sizeof(mltmask));
792d8a7e3a7Sitojun mltmask.sin6_len = sizeof(struct sockaddr_in6);
793d8a7e3a7Sitojun mltmask.sin6_family = AF_INET6;
794d8a7e3a7Sitojun mltmask.sin6_addr = in6mask32;
795d8a7e3a7Sitojun
796d8a7e3a7Sitojun /*
797d8a7e3a7Sitojun * join link-local all-nodes address
798d8a7e3a7Sitojun */
799d8a7e3a7Sitojun bzero(&mltaddr, sizeof(mltaddr));
800d8a7e3a7Sitojun mltaddr.sin6_len = sizeof(struct sockaddr_in6);
801d8a7e3a7Sitojun mltaddr.sin6_family = AF_INET6;
802d8a7e3a7Sitojun mltaddr.sin6_addr = in6addr_linklocal_allnodes;
803d8a7e3a7Sitojun mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
804d4070096Sitojun mltaddr.sin6_scope_id = 0;
805d8a7e3a7Sitojun
806d8a7e3a7Sitojun /*
807d8a7e3a7Sitojun * XXX: do we really need this automatic routes?
808d8a7e3a7Sitojun * We should probably reconsider this stuff. Most applications
809d8a7e3a7Sitojun * actually do not need the routes, since they usually specify
810d8a7e3a7Sitojun * the outgoing interface.
811d8a7e3a7Sitojun */
8125148b194Smpi rt = rtalloc(sin6tosa(&mltaddr), 0, ifp->if_rdomain);
813d8a7e3a7Sitojun if (rt) {
81466f69fe1Smpi /* 32bit came from "mltmask" */
815d8a7e3a7Sitojun if (memcmp(&mltaddr.sin6_addr,
816c3c56496Sbluhm &satosin6(rt_key(rt))->sin6_addr,
817d8a7e3a7Sitojun 32 / 8)) {
81827ae666cSmpi rtfree(rt);
819d8a7e3a7Sitojun rt = NULL;
820d8a7e3a7Sitojun }
821d8a7e3a7Sitojun }
822d8a7e3a7Sitojun if (!rt) {
823d8a7e3a7Sitojun struct rt_addrinfo info;
824d8a7e3a7Sitojun
825d8a7e3a7Sitojun bzero(&info, sizeof(info));
82666f69fe1Smpi info.rti_ifa = &ia6->ia_ifa;
827c3c56496Sbluhm info.rti_info[RTAX_DST] = sin6tosa(&mltaddr);
8283ccf3a0fSmpi info.rti_info[RTAX_GATEWAY] = sin6tosa(&ia6->ia_addr);
829c3c56496Sbluhm info.rti_info[RTAX_NETMASK] = sin6tosa(&mltmask);
830b9e83c60Sbluhm info.rti_info[RTAX_IFA] = sin6tosa(&ia6->ia_addr);
831b71b7f0aSmpi info.rti_flags = RTF_MULTICAST;
8327ffb277fSbluhm error = rtrequest(RTM_ADD, &info, RTP_CONNECTED, NULL,
833ba79ddd5Ssperreault ifp->if_rdomain);
834d8a7e3a7Sitojun if (error)
835d8a7e3a7Sitojun goto cleanup;
836d8a7e3a7Sitojun } else {
83727ae666cSmpi rtfree(rt);
838d8a7e3a7Sitojun }
839d8a7e3a7Sitojun imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error);
8403236de58Smpi if (!imm)
841d8a7e3a7Sitojun goto cleanup;
842b9e83c60Sbluhm LIST_INSERT_HEAD(&ia6->ia6_memberships, imm, i6mm_chain);
843d8a7e3a7Sitojun
844d8a7e3a7Sitojun /*
845d4070096Sitojun * join interface-local all-nodes address.
846d8a7e3a7Sitojun * (ff01::1%ifN, and ff01::%ifN/32)
847d8a7e3a7Sitojun */
8489c794535Sbluhm bzero(&mltaddr, sizeof(mltaddr));
849d4070096Sitojun mltaddr.sin6_len = sizeof(struct sockaddr_in6);
850d4070096Sitojun mltaddr.sin6_family = AF_INET6;
851d4070096Sitojun mltaddr.sin6_addr = in6addr_intfacelocal_allnodes;
852d4070096Sitojun mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
853d4070096Sitojun mltaddr.sin6_scope_id = 0;
854d8a7e3a7Sitojun
855d8a7e3a7Sitojun /* XXX: again, do we really need the route? */
8565148b194Smpi rt = rtalloc(sin6tosa(&mltaddr), 0, ifp->if_rdomain);
857d8a7e3a7Sitojun if (rt) {
858d8a7e3a7Sitojun /* 32bit came from "mltmask" */
859d8a7e3a7Sitojun if (memcmp(&mltaddr.sin6_addr,
860c3c56496Sbluhm &satosin6(rt_key(rt))->sin6_addr,
861d8a7e3a7Sitojun 32 / 8)) {
86227ae666cSmpi rtfree(rt);
863d8a7e3a7Sitojun rt = NULL;
864d8a7e3a7Sitojun }
865d8a7e3a7Sitojun }
866d8a7e3a7Sitojun if (!rt) {
867d8a7e3a7Sitojun struct rt_addrinfo info;
868d8a7e3a7Sitojun
869d8a7e3a7Sitojun bzero(&info, sizeof(info));
87066f69fe1Smpi info.rti_ifa = &ia6->ia_ifa;
871c3c56496Sbluhm info.rti_info[RTAX_DST] = sin6tosa(&mltaddr);
8723ccf3a0fSmpi info.rti_info[RTAX_GATEWAY] = sin6tosa(&ia6->ia_addr);
873c3c56496Sbluhm info.rti_info[RTAX_NETMASK] = sin6tosa(&mltmask);
874b9e83c60Sbluhm info.rti_info[RTAX_IFA] = sin6tosa(&ia6->ia_addr);
875b71b7f0aSmpi info.rti_flags = RTF_MULTICAST;
8767ffb277fSbluhm error = rtrequest(RTM_ADD, &info, RTP_CONNECTED, NULL,
8770ffd01d4Sbluhm ifp->if_rdomain);
878d8a7e3a7Sitojun if (error)
879d8a7e3a7Sitojun goto cleanup;
880d8a7e3a7Sitojun } else {
88127ae666cSmpi rtfree(rt);
882d8a7e3a7Sitojun }
883c61d7628Sitojun imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error);
8843236de58Smpi if (!imm)
885d8a7e3a7Sitojun goto cleanup;
886b9e83c60Sbluhm LIST_INSERT_HEAD(&ia6->ia6_memberships, imm, i6mm_chain);
887d8a7e3a7Sitojun }
888d8a7e3a7Sitojun
889287546eaSitojun return (error);
890287546eaSitojun
891d8a7e3a7Sitojun unlink:
892d8a7e3a7Sitojun /*
893d8a7e3a7Sitojun * XXX: if a change of an existing address failed, keep the entry
894d8a7e3a7Sitojun * anyway.
895d8a7e3a7Sitojun */
896d8a7e3a7Sitojun if (hostIsNew)
897b9e83c60Sbluhm in6_unlink_ifa(ia6, ifp);
898d8a7e3a7Sitojun return (error);
89922770369Sitojun
900d8a7e3a7Sitojun cleanup:
901b9e83c60Sbluhm in6_purgeaddr(&ia6->ia_ifa);
902d8a7e3a7Sitojun return error;
90322770369Sitojun }
90422770369Sitojun
90522770369Sitojun void
in6_purgeaddr(struct ifaddr * ifa)906ee37ea65Smcbride in6_purgeaddr(struct ifaddr *ifa)
90722770369Sitojun {
908d8a7e3a7Sitojun struct ifnet *ifp = ifa->ifa_ifp;
9099ea9b1e7Smpi struct in6_ifaddr *ia6 = ifatoia6(ifa);
910d8a7e3a7Sitojun struct in6_multi_mship *imm;
91122770369Sitojun
912b0d0a571Sitojun /* stop DAD processing */
913b0d0a571Sitojun nd6_dad_stop(ifa);
914b0d0a571Sitojun
915287546eaSitojun /*
916d8a7e3a7Sitojun * delete route to the destination of the address being purged.
917d8a7e3a7Sitojun * The interface must be p2p or loopback in this case.
918287546eaSitojun */
9196c41171aSmpi if ((ifp->if_flags & IFF_POINTOPOINT) && (ia6->ia_flags & IFA_ROUTE) &&
9206c41171aSmpi ia6->ia_dstaddr.sin6_len != 0) {
921d8a7e3a7Sitojun int e;
922287546eaSitojun
9238f960e22Sdlg e = rt_ifa_del(ifa, RTF_HOST, ifa->ifa_dstaddr,
9248f960e22Sdlg ifp->if_rdomain);
9258f960e22Sdlg if (e != 0) {
926bbcf0337Smpi char addr[INET6_ADDRSTRLEN];
927d8a7e3a7Sitojun log(LOG_ERR, "in6_purgeaddr: failed to remove "
928d8a7e3a7Sitojun "a route to the p2p destination: %s on %s, "
929d8a7e3a7Sitojun "errno=%d\n",
930b9e83c60Sbluhm inet_ntop(AF_INET6, &ia6->ia_addr.sin6_addr,
931bbcf0337Smpi addr, sizeof(addr)),
932bbcf0337Smpi ifp->if_xname, e);
933d8a7e3a7Sitojun /* proceed anyway... */
934d8a7e3a7Sitojun } else
935b9e83c60Sbluhm ia6->ia_flags &= ~IFA_ROUTE;
936287546eaSitojun }
937287546eaSitojun
9389ea9b1e7Smpi /* Remove ownaddr's loopback rtentry, if it exists. */
939dfa661caSmpi rt_ifa_dellocal(&(ia6->ia_ifa));
940d8a7e3a7Sitojun
941d8a7e3a7Sitojun /*
942d8a7e3a7Sitojun * leave from multicast groups we have joined for the interface
943d8a7e3a7Sitojun */
944b9e83c60Sbluhm while (!LIST_EMPTY(&ia6->ia6_memberships)) {
945b9e83c60Sbluhm imm = LIST_FIRST(&ia6->ia6_memberships);
946d8a7e3a7Sitojun LIST_REMOVE(imm, i6mm_chain);
947d8a7e3a7Sitojun in6_leavegroup(imm);
948d8a7e3a7Sitojun }
949d8a7e3a7Sitojun
950b9e83c60Sbluhm in6_unlink_ifa(ia6, ifp);
951d8a7e3a7Sitojun }
952d8a7e3a7Sitojun
953525dbc5aSjsing void
in6_unlink_ifa(struct in6_ifaddr * ia6,struct ifnet * ifp)954b9e83c60Sbluhm in6_unlink_ifa(struct in6_ifaddr *ia6, struct ifnet *ifp)
955d8a7e3a7Sitojun {
956ef6620bcSmpi struct ifaddr *ifa = &ia6->ia_ifa;
95790e1bc04Smpi int plen;
958ef6620bcSmpi
95966736630Smpi NET_ASSERT_LOCKED();
960d8a7e3a7Sitojun
961203dbc93Sbluhm /* Release the reference to the base prefix. */
96290e1bc04Smpi plen = in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL);
96390e1bc04Smpi if ((ifp->if_flags & IFF_LOOPBACK) == 0 && plen != 128) {
96467f077d8Smpi rt_ifa_del(ifa, RTF_CLONING | RTF_CONNECTED,
9658f960e22Sdlg ifa->ifa_addr, ifp->if_rdomain);
96667f077d8Smpi }
967d8a7e3a7Sitojun
96803edf7baSmpi rt_ifa_purge(ifa);
96903edf7baSmpi ifa_del(ifp, ifa);
97003edf7baSmpi
97103edf7baSmpi ia6->ia_ifp = NULL;
972f42926caSkn ifafree(ifa);
973d8a7e3a7Sitojun }
974d8a7e3a7Sitojun
975287546eaSitojun /*
976df8d9afdSjsg * Initialize an interface's inet6 address
977287546eaSitojun * and routing table entry.
978287546eaSitojun */
979525dbc5aSjsing int
in6_ifinit(struct ifnet * ifp,struct in6_ifaddr * ia6,int newhost)980b9e83c60Sbluhm in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia6, int newhost)
981d3b325d0Sderaadt {
982d8a7e3a7Sitojun int error = 0, plen, ifacount = 0;
983d8a7e3a7Sitojun struct ifaddr *ifa;
984d3b325d0Sderaadt
98566736630Smpi NET_ASSERT_LOCKED();
986fafd72b5Smpi
987d3b325d0Sderaadt /*
988d3b325d0Sderaadt * Give the interface a chance to initialize
989f33d0285Smcbride * if this is its first address (or it is a CARP interface)
990d3b325d0Sderaadt * and to validate the address if necessary.
991d3b325d0Sderaadt */
9921573508eSmiod TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
993d8a7e3a7Sitojun if (ifa->ifa_addr->sa_family != AF_INET6)
994d8a7e3a7Sitojun continue;
995d8a7e3a7Sitojun ifacount++;
996d8a7e3a7Sitojun }
997d8a7e3a7Sitojun
9987da1c795Smpi if ((ifacount <= 1 || ifp->if_type == IFT_CARP ||
999ddeaef8bSmpi (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))) &&
1000b9e83c60Sbluhm (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia6))) {
1001287546eaSitojun return (error);
1002d3b325d0Sderaadt }
1003d8a7e3a7Sitojun
1004b9e83c60Sbluhm ia6->ia_ifa.ifa_metric = ifp->if_metric;
1005d8a7e3a7Sitojun
1006d8a7e3a7Sitojun /* we could do in(6)_socktrim here, but just omit it at this moment. */
1007d8a7e3a7Sitojun
1008d8a7e3a7Sitojun /*
1009d8a7e3a7Sitojun * Special case:
1010d8a7e3a7Sitojun * If the destination address is specified for a point-to-point
1011d8a7e3a7Sitojun * interface, install a route to the destination as an interface
1012d8a7e3a7Sitojun * direct route.
1013d8a7e3a7Sitojun */
1014b9e83c60Sbluhm plen = in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL); /* XXX */
10156c41171aSmpi if ((ifp->if_flags & IFF_POINTOPOINT) && plen == 128 &&
10166c41171aSmpi ia6->ia_dstaddr.sin6_family == AF_INET6) {
1017daed62aeSmpi ifa = &ia6->ia_ifa;
101862cb75b3Sdlg error = rt_ifa_add(ifa, RTF_HOST | RTF_MPATH,
10198f960e22Sdlg ifa->ifa_dstaddr, ifp->if_rdomain);
1020daed62aeSmpi if (error != 0)
1021d8a7e3a7Sitojun return (error);
1022b9e83c60Sbluhm ia6->ia_flags |= IFA_ROUTE;
1023d8a7e3a7Sitojun }
1024d3b325d0Sderaadt
1025dcb17c31Smpi if (newhost)
1026f68cfd0eSmpi error = rt_ifa_addlocal(&(ia6->ia_ifa));
1027287546eaSitojun
1028287546eaSitojun return (error);
1029287546eaSitojun }
1030287546eaSitojun
1031287546eaSitojun /*
1032287546eaSitojun * Add an address to the list of IP6 multicast addresses for a
1033287546eaSitojun * given interface.
1034287546eaSitojun */
1035287546eaSitojun struct in6_multi *
in6_addmulti(struct in6_addr * maddr6,struct ifnet * ifp,int * errorp)1036ee37ea65Smcbride in6_addmulti(struct in6_addr *maddr6, struct ifnet *ifp, int *errorp)
1037287546eaSitojun {
1038287546eaSitojun struct in6_ifreq ifr;
1039287546eaSitojun struct in6_multi *in6m;
1040f9fc830cSmpi
104166736630Smpi NET_ASSERT_LOCKED();
1042287546eaSitojun
1043287546eaSitojun *errorp = 0;
1044287546eaSitojun /*
1045287546eaSitojun * See if address already in list.
1046287546eaSitojun */
1047287546eaSitojun IN6_LOOKUP_MULTI(*maddr6, ifp, in6m);
1048287546eaSitojun if (in6m != NULL) {
1049287546eaSitojun /*
1050678831beSjsg * Found it; just increment the reference count.
1051287546eaSitojun */
1052a409c69cSkn refcnt_take(&in6m->in6m_refcnt);
1053287546eaSitojun } else {
1054287546eaSitojun /*
1055287546eaSitojun * New address; allocate a new multicast record
1056287546eaSitojun * and link it into the interface's multicast list.
1057287546eaSitojun */
10589c794535Sbluhm in6m = malloc(sizeof(*in6m), M_IPMADDR, M_NOWAIT | M_ZERO);
1059287546eaSitojun if (in6m == NULL) {
1060287546eaSitojun *errorp = ENOBUFS;
1061287546eaSitojun return (NULL);
1062287546eaSitojun }
10632bea58a8Smpi
10642bea58a8Smpi in6m->in6m_sin.sin6_len = sizeof(struct sockaddr_in6);
10652bea58a8Smpi in6m->in6m_sin.sin6_family = AF_INET6;
10662bea58a8Smpi in6m->in6m_sin.sin6_addr = *maddr6;
1067a409c69cSkn refcnt_init_trace(&in6m->in6m_refcnt, DT_REFCNT_IDX_IFMADDR);
106833082e9fSmpi in6m->in6m_ifidx = ifp->if_index;
10692bea58a8Smpi in6m->in6m_ifma.ifma_addr = sin6tosa(&in6m->in6m_sin);
1070d3b325d0Sderaadt
1071d3b325d0Sderaadt /*
1072d3b325d0Sderaadt * Ask the network driver to update its multicast reception
1073d3b325d0Sderaadt * filter appropriately for the new address.
1074d3b325d0Sderaadt */
10752bea58a8Smpi memcpy(&ifr.ifr_addr, &in6m->in6m_sin, sizeof(in6m->in6m_sin));
1076bfb4dd3fSmvs KERNEL_LOCK();
10772bea58a8Smpi *errorp = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
1078bfb4dd3fSmvs KERNEL_UNLOCK();
1079287546eaSitojun if (*errorp) {
1080c90e561bStedu free(in6m, M_IPMADDR, sizeof(*in6m));
1081287546eaSitojun return (NULL);
1082d3b325d0Sderaadt }
10832bea58a8Smpi
10842bea58a8Smpi TAILQ_INSERT_HEAD(&ifp->if_maddrlist, &in6m->in6m_ifma,
10852bea58a8Smpi ifma_list);
10862bea58a8Smpi
1087287546eaSitojun /*
1088287546eaSitojun * Let MLD6 know that we have joined a new IP6 multicast
1089287546eaSitojun * group.
1090287546eaSitojun */
1091287546eaSitojun mld6_start_listening(in6m);
1092d3b325d0Sderaadt }
10932bea58a8Smpi
1094287546eaSitojun return (in6m);
1095d3b325d0Sderaadt }
1096d3b325d0Sderaadt
1097d3b325d0Sderaadt /*
1098287546eaSitojun * Delete a multicast address record.
1099d3b325d0Sderaadt */
1100287546eaSitojun void
in6_delmulti(struct in6_multi * in6m)1101ee37ea65Smcbride in6_delmulti(struct in6_multi *in6m)
1102287546eaSitojun {
1103287546eaSitojun struct in6_ifreq ifr;
11042bea58a8Smpi struct ifnet *ifp;
1105f9fc830cSmpi
110666736630Smpi NET_ASSERT_LOCKED();
1107d3b325d0Sderaadt
1108a409c69cSkn if (refcnt_rele(&in6m->in6m_refcnt) != 0) {
1109287546eaSitojun /*
1110287546eaSitojun * No remaining claims to this record; let MLD6 know
1111287546eaSitojun * that we are leaving the multicast group.
1112287546eaSitojun */
1113287546eaSitojun mld6_stop_listening(in6m);
111433082e9fSmpi ifp = if_get(in6m->in6m_ifidx);
1115287546eaSitojun
1116287546eaSitojun /*
1117287546eaSitojun * Notify the network driver to update its multicast
1118287546eaSitojun * reception filter.
1119287546eaSitojun */
112033082e9fSmpi if (ifp != NULL) {
1121287546eaSitojun bzero(&ifr.ifr_addr, sizeof(struct sockaddr_in6));
1122287546eaSitojun ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
1123287546eaSitojun ifr.ifr_addr.sin6_family = AF_INET6;
1124287546eaSitojun ifr.ifr_addr.sin6_addr = in6m->in6m_addr;
11254b9a5ba9Svisa KERNEL_LOCK();
112633082e9fSmpi (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
11274b9a5ba9Svisa KERNEL_UNLOCK();
11282bea58a8Smpi
112933082e9fSmpi TAILQ_REMOVE(&ifp->if_maddrlist, &in6m->in6m_ifma,
113033082e9fSmpi ifma_list);
113133082e9fSmpi }
113202ca5288Sclaudio if_put(ifp);
11332bea58a8Smpi
1134c90e561bStedu free(in6m, M_IPMADDR, sizeof(*in6m));
1135d3b325d0Sderaadt }
1136d3b325d0Sderaadt }
1137287546eaSitojun
113834dbf6d6Smpi /*
113934dbf6d6Smpi * Return 1 if the multicast group represented by ``maddr6'' has been
114034dbf6d6Smpi * joined by interface ``ifp'', 0 otherwise.
114134dbf6d6Smpi */
114234dbf6d6Smpi int
in6_hasmulti(struct in6_addr * maddr6,struct ifnet * ifp)114334dbf6d6Smpi in6_hasmulti(struct in6_addr *maddr6, struct ifnet *ifp)
114434dbf6d6Smpi {
114534dbf6d6Smpi struct in6_multi *in6m;
114634dbf6d6Smpi int joined;
114734dbf6d6Smpi
114834dbf6d6Smpi IN6_LOOKUP_MULTI(*maddr6, ifp, in6m);
114934dbf6d6Smpi joined = (in6m != NULL);
115034dbf6d6Smpi
115134dbf6d6Smpi return (joined);
115234dbf6d6Smpi }
115334dbf6d6Smpi
11547b2ccaf7Sitojun struct in6_multi_mship *
in6_joingroup(struct ifnet * ifp,struct in6_addr * addr,int * errorp)1155ee37ea65Smcbride in6_joingroup(struct ifnet *ifp, struct in6_addr *addr, int *errorp)
11567b2ccaf7Sitojun {
11577b2ccaf7Sitojun struct in6_multi_mship *imm;
11587b2ccaf7Sitojun
11597b2ccaf7Sitojun imm = malloc(sizeof(*imm), M_IPMADDR, M_NOWAIT);
11607b2ccaf7Sitojun if (!imm) {
11617b2ccaf7Sitojun *errorp = ENOBUFS;
11627b2ccaf7Sitojun return NULL;
11637b2ccaf7Sitojun }
11647b2ccaf7Sitojun imm->i6mm_maddr = in6_addmulti(addr, ifp, errorp);
11657b2ccaf7Sitojun if (!imm->i6mm_maddr) {
1166678831beSjsg /* *errorp is already set */
1167c90e561bStedu free(imm, M_IPMADDR, sizeof(*imm));
11687b2ccaf7Sitojun return NULL;
11697b2ccaf7Sitojun }
11707b2ccaf7Sitojun return imm;
11717b2ccaf7Sitojun }
11727b2ccaf7Sitojun
1173743125a4Sflorian void
in6_leavegroup(struct in6_multi_mship * imm)1174525dbc5aSjsing in6_leavegroup(struct in6_multi_mship *imm)
11757b2ccaf7Sitojun {
11767b2ccaf7Sitojun
11777b2ccaf7Sitojun if (imm->i6mm_maddr)
11787b2ccaf7Sitojun in6_delmulti(imm->i6mm_maddr);
1179c90e561bStedu free(imm, M_IPMADDR, sizeof(*imm));
11807b2ccaf7Sitojun }
11817b2ccaf7Sitojun
1182287546eaSitojun /*
1183287546eaSitojun * Find an IPv6 interface link-local address specific to an interface.
1184287546eaSitojun */
1185287546eaSitojun struct in6_ifaddr *
in6ifa_ifpforlinklocal(struct ifnet * ifp,int ignoreflags)1186ee37ea65Smcbride in6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags)
1187287546eaSitojun {
11889063e41fSitojun struct ifaddr *ifa;
1189287546eaSitojun
11901573508eSmiod TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
1191287546eaSitojun if (ifa->ifa_addr->sa_family != AF_INET6)
1192287546eaSitojun continue;
1193f4f4d166Sitojun if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) {
1194de654afdSbluhm if ((ifatoia6(ifa)->ia6_flags & ignoreflags) != 0)
1195f4f4d166Sitojun continue;
1196287546eaSitojun break;
1197287546eaSitojun }
1198f4f4d166Sitojun }
1199287546eaSitojun
12006143cd01Sbluhm return (ifatoia6(ifa));
1201287546eaSitojun }
1202287546eaSitojun
1203287546eaSitojun
1204287546eaSitojun /*
1205287546eaSitojun * find the internet address corresponding to a given interface and address.
1206287546eaSitojun */
1207287546eaSitojun struct in6_ifaddr *
in6ifa_ifpwithaddr(struct ifnet * ifp,struct in6_addr * addr)1208ee37ea65Smcbride in6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr)
1209287546eaSitojun {
12109063e41fSitojun struct ifaddr *ifa;
1211287546eaSitojun
12121573508eSmiod TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
1213287546eaSitojun if (ifa->ifa_addr->sa_family != AF_INET6)
1214287546eaSitojun continue;
1215287546eaSitojun if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa)))
1216287546eaSitojun break;
1217287546eaSitojun }
1218287546eaSitojun
12196143cd01Sbluhm return (ifatoia6(ifa));
1220287546eaSitojun }
1221287546eaSitojun
1222287546eaSitojun /*
1223287546eaSitojun * Get a scope of the address. Node-local, link-local, site-local or global.
1224287546eaSitojun */
1225287546eaSitojun int
in6_addrscope(struct in6_addr * addr)1226ee37ea65Smcbride in6_addrscope(struct in6_addr *addr)
1227287546eaSitojun {
1228287546eaSitojun int scope;
1229287546eaSitojun
1230287546eaSitojun if (addr->s6_addr8[0] == 0xfe) {
1231287546eaSitojun scope = addr->s6_addr8[1] & 0xc0;
1232287546eaSitojun
1233287546eaSitojun switch (scope) {
1234287546eaSitojun case 0x80:
12355453c090Sderaadt return __IPV6_ADDR_SCOPE_LINKLOCAL;
1236287546eaSitojun break;
1237287546eaSitojun case 0xc0:
12385453c090Sderaadt return __IPV6_ADDR_SCOPE_SITELOCAL;
1239287546eaSitojun break;
1240287546eaSitojun default:
12415453c090Sderaadt return __IPV6_ADDR_SCOPE_GLOBAL; /* just in case */
1242287546eaSitojun break;
1243287546eaSitojun }
1244287546eaSitojun }
1245287546eaSitojun
1246287546eaSitojun
1247287546eaSitojun if (addr->s6_addr8[0] == 0xff) {
1248287546eaSitojun scope = addr->s6_addr8[1] & 0x0f;
1249287546eaSitojun
1250287546eaSitojun /*
1251287546eaSitojun * due to other scope such as reserved,
1252287546eaSitojun * return scope doesn't work.
1253287546eaSitojun */
1254287546eaSitojun switch (scope) {
12555453c090Sderaadt case __IPV6_ADDR_SCOPE_INTFACELOCAL:
12565453c090Sderaadt return __IPV6_ADDR_SCOPE_INTFACELOCAL;
1257287546eaSitojun break;
12585453c090Sderaadt case __IPV6_ADDR_SCOPE_LINKLOCAL:
12595453c090Sderaadt return __IPV6_ADDR_SCOPE_LINKLOCAL;
1260287546eaSitojun break;
12615453c090Sderaadt case __IPV6_ADDR_SCOPE_SITELOCAL:
12625453c090Sderaadt return __IPV6_ADDR_SCOPE_SITELOCAL;
1263287546eaSitojun break;
1264287546eaSitojun default:
12655453c090Sderaadt return __IPV6_ADDR_SCOPE_GLOBAL;
1266287546eaSitojun break;
1267287546eaSitojun }
1268287546eaSitojun }
1269287546eaSitojun
12709b6307b6Sitojun if (bcmp(&in6addr_loopback, addr, sizeof(*addr) - 1) == 0) {
1271287546eaSitojun if (addr->s6_addr8[15] == 1) /* loopback */
12725453c090Sderaadt return __IPV6_ADDR_SCOPE_INTFACELOCAL;
1273287546eaSitojun if (addr->s6_addr8[15] == 0) /* unspecified */
12745453c090Sderaadt return __IPV6_ADDR_SCOPE_LINKLOCAL;
1275287546eaSitojun }
1276287546eaSitojun
12775453c090Sderaadt return __IPV6_ADDR_SCOPE_GLOBAL;
1278287546eaSitojun }
1279287546eaSitojun
1280f4f4d166Sitojun int
in6_addr2scopeid(unsigned int ifidx,struct in6_addr * addr)12811a3ab866Smpi in6_addr2scopeid(unsigned int ifidx, struct in6_addr *addr)
1282f4f4d166Sitojun {
1283f4f4d166Sitojun int scope = in6_addrscope(addr);
1284f4f4d166Sitojun
1285f4f4d166Sitojun switch(scope) {
12865453c090Sderaadt case __IPV6_ADDR_SCOPE_INTFACELOCAL:
12875453c090Sderaadt case __IPV6_ADDR_SCOPE_LINKLOCAL:
1288f4f4d166Sitojun /* XXX: we do not distinguish between a link and an I/F. */
12891a3ab866Smpi return (ifidx);
1290f4f4d166Sitojun
12915453c090Sderaadt case __IPV6_ADDR_SCOPE_SITELOCAL:
1292f4f4d166Sitojun return (0); /* XXX: invalid. */
1293f4f4d166Sitojun
1294f4f4d166Sitojun default:
1295f4f4d166Sitojun return (0); /* XXX: treat as global. */
1296f4f4d166Sitojun }
1297f4f4d166Sitojun }
1298f4f4d166Sitojun
1299287546eaSitojun /*
1300287546eaSitojun * return length of part which dst and src are equal
1301287546eaSitojun * hard coding...
1302287546eaSitojun */
1303287546eaSitojun int
in6_matchlen(struct in6_addr * src,struct in6_addr * dst)1304ee37ea65Smcbride in6_matchlen(struct in6_addr *src, struct in6_addr *dst)
1305287546eaSitojun {
1306287546eaSitojun int match = 0;
1307287546eaSitojun u_char *s = (u_char *)src, *d = (u_char *)dst;
1308287546eaSitojun u_char *lim = s + 16, r;
1309287546eaSitojun
1310287546eaSitojun while (s < lim)
1311287546eaSitojun if ((r = (*d++ ^ *s++)) != 0) {
1312287546eaSitojun while (r < 128) {
1313287546eaSitojun match++;
1314287546eaSitojun r <<= 1;
1315287546eaSitojun }
1316287546eaSitojun break;
1317287546eaSitojun } else
1318287546eaSitojun match += 8;
1319287546eaSitojun return match;
1320287546eaSitojun }
1321287546eaSitojun
1322287546eaSitojun void
in6_prefixlen2mask(struct in6_addr * maskp,int len)1323ee37ea65Smcbride in6_prefixlen2mask(struct in6_addr *maskp, int len)
1324287546eaSitojun {
1325287546eaSitojun u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
1326287546eaSitojun int bytelen, bitlen, i;
1327287546eaSitojun
1328287546eaSitojun /* sanity check */
1329fc94afa0Stedu if (0 > len || len > 128) {
1330287546eaSitojun log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n",
1331287546eaSitojun len);
1332287546eaSitojun return;
1333287546eaSitojun }
1334287546eaSitojun
1335287546eaSitojun bzero(maskp, sizeof(*maskp));
1336287546eaSitojun bytelen = len / 8;
1337287546eaSitojun bitlen = len % 8;
1338287546eaSitojun for (i = 0; i < bytelen; i++)
1339287546eaSitojun maskp->s6_addr[i] = 0xff;
1340fc94afa0Stedu /* len == 128 is ok because bitlen == 0 then */
1341287546eaSitojun if (bitlen)
1342287546eaSitojun maskp->s6_addr[bytelen] = maskarray[bitlen - 1];
1343287546eaSitojun }
1344287546eaSitojun
1345287546eaSitojun /*
1346287546eaSitojun * return the best address out of the same scope
1347287546eaSitojun */
1348287546eaSitojun struct in6_ifaddr *
in6_ifawithscope(struct ifnet * oifp,struct in6_addr * dst,u_int rdomain,struct rtentry * rt)13497186e918Sflorian in6_ifawithscope(struct ifnet *oifp, struct in6_addr *dst, u_int rdomain,
13507186e918Sflorian struct rtentry *rt)
1351287546eaSitojun {
1352d374aaacSitojun int dst_scope = in6_addrscope(dst), src_scope, best_scope = 0;
1353f4f4d166Sitojun int blen = -1;
1354287546eaSitojun struct ifaddr *ifa;
1355f4f4d166Sitojun struct ifnet *ifp;
1356b9e83c60Sbluhm struct in6_ifaddr *ia6_best = NULL;
13577186e918Sflorian struct in6_addr *gw6 = NULL;
13587186e918Sflorian
13597186e918Sflorian if (rt) {
13607186e918Sflorian if (rt->rt_gateway != NULL &&
13617186e918Sflorian rt->rt_gateway->sa_family == AF_INET6)
13627186e918Sflorian gw6 = &(satosin6(rt->rt_gateway)->sin6_addr);
13637186e918Sflorian }
1364287546eaSitojun
1365f4f4d166Sitojun if (oifp == NULL) {
1366d61e4f47Sbluhm printf("%s: output interface is not specified\n", __func__);
1367f4f4d166Sitojun return (NULL);
1368f4f4d166Sitojun }
1369287546eaSitojun
137010319ffdSflorian /* We search for all addresses on all interfaces from the beginning. */
1371ccb45f8eSkn TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
1372ba79ddd5Ssperreault if (ifp->if_rdomain != rdomain)
1373ba79ddd5Ssperreault continue;
1374a7e28db1Sbluhm #if NCARP > 0
1375a7e28db1Sbluhm /*
1376a7e28db1Sbluhm * Never use a carp address of an interface which is not
1377a7e28db1Sbluhm * the master.
1378a7e28db1Sbluhm */
1379442f4bb4Smpi if (ifp->if_type == IFT_CARP && !carp_iamatch(ifp))
1380a7e28db1Sbluhm continue;
1381a7e28db1Sbluhm #endif
1382ba79ddd5Ssperreault
1383f4f4d166Sitojun /*
1384f4f4d166Sitojun * We can never take an address that breaks the scope zone
1385f4f4d166Sitojun * of the destination.
1386f4f4d166Sitojun */
13871a3ab866Smpi if (in6_addr2scopeid(ifp->if_index, dst) !=
13881a3ab866Smpi in6_addr2scopeid(oifp->if_index, dst))
1389f4f4d166Sitojun continue;
1390f4f4d166Sitojun
13911573508eSmiod TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
139210319ffdSflorian int tlen = -1;
1393f4f4d166Sitojun
1394287546eaSitojun if (ifa->ifa_addr->sa_family != AF_INET6)
1395287546eaSitojun continue;
1396f4f4d166Sitojun
1397f4f4d166Sitojun src_scope = in6_addrscope(IFA_IN6(ifa));
1398f4f4d166Sitojun
1399f4f4d166Sitojun /*
1400f4f4d166Sitojun * Don't use an address before completing DAD
1401f4f4d166Sitojun * nor a duplicated address.
1402f4f4d166Sitojun */
1403b2ea68e0Smpi if (ifatoia6(ifa)->ia6_flags &
1404b2ea68e0Smpi (IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED))
1405287546eaSitojun continue;
1406f4f4d166Sitojun
140710319ffdSflorian /*
140810319ffdSflorian * RFC 6724 allows anycast addresses as source address
140910319ffdSflorian * because the restriction was removed in RFC 4291.
141010319ffdSflorian * However RFC 4443 states that ICMPv6 responses
141110319ffdSflorian * MUST use a unicast source address.
141210319ffdSflorian *
141310319ffdSflorian * XXX Skip anycast addresses for now since
141410319ffdSflorian * icmp6_reflect() uses this function for source
141510319ffdSflorian * address selection.
141610319ffdSflorian */
1417de654afdSbluhm if (ifatoia6(ifa)->ia6_flags & IN6_IFF_ANYCAST)
1418f4f4d166Sitojun continue;
1419f4f4d166Sitojun
1420de654afdSbluhm if (ifatoia6(ifa)->ia6_flags & IN6_IFF_DETACHED)
1421f4f4d166Sitojun continue;
1422f4f4d166Sitojun
1423f4f4d166Sitojun /*
1424f4f4d166Sitojun * If this is the first address we find,
1425f4f4d166Sitojun * keep it anyway.
1426f4f4d166Sitojun */
1427b9e83c60Sbluhm if (ia6_best == NULL)
1428f4f4d166Sitojun goto replace;
1429f4f4d166Sitojun
1430f4f4d166Sitojun /*
1431b9e83c60Sbluhm * ia6_best is never NULL beyond this line except
1432f4f4d166Sitojun * within the block labeled "replace".
1433f4f4d166Sitojun */
1434f4f4d166Sitojun
1435f4f4d166Sitojun /*
143610319ffdSflorian * Rule 2: Prefer appropriate scope.
143710319ffdSflorian * Find the address with the smallest scope that is
143810319ffdSflorian * bigger (or equal) to the scope of the destination
143910319ffdSflorian * address.
144010319ffdSflorian * Accept an address with smaller scope than the
144110319ffdSflorian * destination if non exists with bigger scope.
1442f4f4d166Sitojun */
144310319ffdSflorian if (best_scope < src_scope) {
144410319ffdSflorian if (best_scope < dst_scope)
1445f4f4d166Sitojun goto replace;
144610319ffdSflorian else
1447f4f4d166Sitojun continue;
144810319ffdSflorian } else if (src_scope < best_scope) {
144910319ffdSflorian if (src_scope < dst_scope)
145010319ffdSflorian continue;
145110319ffdSflorian else
145210319ffdSflorian goto replace;
145310319ffdSflorian }
1454f4f4d166Sitojun
145510319ffdSflorian /* Rule 3: Avoid deprecated addresses. */
1456de654afdSbluhm if (ifatoia6(ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
1457287546eaSitojun /*
1458f4f4d166Sitojun * Ignore any deprecated addresses if
1459f4f4d166Sitojun * specified by configuration.
1460287546eaSitojun */
1461f4f4d166Sitojun if (!ip6_use_deprecated)
1462f4f4d166Sitojun continue;
1463f4f4d166Sitojun
1464f4f4d166Sitojun /*
1465f4f4d166Sitojun * If we have already found a non-deprecated
1466f4f4d166Sitojun * candidate, just ignore deprecated addresses.
1467f4f4d166Sitojun */
1468b9e83c60Sbluhm if ((ia6_best->ia6_flags & IN6_IFF_DEPRECATED)
1469f4f4d166Sitojun == 0)
1470f4f4d166Sitojun continue;
147110319ffdSflorian } else if ((ia6_best->ia6_flags & IN6_IFF_DEPRECATED))
1472f4f4d166Sitojun goto replace;
1473f4f4d166Sitojun
147410319ffdSflorian /*
147510319ffdSflorian * Rule 4: Prefer home addresses.
147610319ffdSflorian * We do not support home addresses.
147710319ffdSflorian */
147810319ffdSflorian
147910319ffdSflorian /* Rule 5: Prefer outgoing interface */
1480cfef168aSbluhm if (ia6_best->ia_ifp == oifp && ifp != oifp)
1481cfef168aSbluhm continue;
1482cfef168aSbluhm if (ia6_best->ia_ifp != oifp && ifp == oifp)
1483cfef168aSbluhm goto replace;
1484cfef168aSbluhm
1485f4f4d166Sitojun /*
148610319ffdSflorian * Rule 5.5: Prefer addresses in a prefix advertised
148710319ffdSflorian * by the next-hop.
1488f4f4d166Sitojun */
14897186e918Sflorian if (gw6) {
14907186e918Sflorian struct in6_addr *in6_bestgw, *in6_newgw;
14917186e918Sflorian
14927186e918Sflorian in6_bestgw = &ia6_best->ia_gwaddr.sin6_addr;
14937186e918Sflorian in6_newgw = &ifatoia6(ifa)->ia_gwaddr.sin6_addr;
14947186e918Sflorian if (!IN6_ARE_ADDR_EQUAL(in6_bestgw, gw6) &&
14957186e918Sflorian IN6_ARE_ADDR_EQUAL(in6_newgw, gw6))
14967186e918Sflorian goto replace;
14977186e918Sflorian }
1498f4f4d166Sitojun
1499f4f4d166Sitojun /*
150010319ffdSflorian * Rule 6: Prefer matching label.
150110319ffdSflorian * We do not implement policy tables.
1502f4f4d166Sitojun */
1503988e29a9Sstsp
150410319ffdSflorian /* Rule 7: Prefer temporary addresses. */
150510319ffdSflorian if ((ia6_best->ia6_flags & IN6_IFF_TEMPORARY) &&
150610319ffdSflorian !(ifatoia6(ifa)->ia6_flags & IN6_IFF_TEMPORARY))
150710319ffdSflorian continue;
150810319ffdSflorian if (!(ia6_best->ia6_flags & IN6_IFF_TEMPORARY) &&
150910319ffdSflorian (ifatoia6(ifa)->ia6_flags & IN6_IFF_TEMPORARY))
1510988e29a9Sstsp goto replace;
151110319ffdSflorian
151210319ffdSflorian /* Rule 8: Use longest matching prefix. */
1513287546eaSitojun tlen = in6_matchlen(IFA_IN6(ifa), dst);
151410319ffdSflorian if (tlen > blen) {
1515d35187fbSstsp #if NCARP > 0
1516d35187fbSstsp /*
1517d35187fbSstsp * Don't let carp interfaces win a tie against
1518d35187fbSstsp * the output interface based on matchlen.
1519d35187fbSstsp * We should only use a carp address if no
1520d35187fbSstsp * other interface has a usable address.
1521d35187fbSstsp * Otherwise, when communicating from a carp
1522fae51641Sbenno * master to a carp backup, the backup system
1523fae51641Sbenno * won't respond since the carp address is also
1524fae51641Sbenno * configured as a local address on the backup.
1525d35187fbSstsp * Note that carp interfaces in backup state
1526d35187fbSstsp * were already skipped above.
1527d35187fbSstsp */
1528d35187fbSstsp if (ifp->if_type == IFT_CARP &&
1529d35187fbSstsp oifp->if_type != IFT_CARP)
1530d35187fbSstsp continue;
1531d35187fbSstsp #endif
1532f4f4d166Sitojun goto replace;
15337bd1e8e8Sflorian } else if (tlen < blen)
15347bd1e8e8Sflorian continue;
15357bd1e8e8Sflorian
15367bd1e8e8Sflorian /*
15377bd1e8e8Sflorian * If the eight rules fail to choose a single address,
15387bd1e8e8Sflorian * the tiebreaker is implementation-specific.
15397bd1e8e8Sflorian */
15407bd1e8e8Sflorian
15417bd1e8e8Sflorian /* Prefer address with highest pltime. */
15427bd1e8e8Sflorian if (ia6_best->ia6_updatetime +
15437bd1e8e8Sflorian ia6_best->ia6_lifetime.ia6t_pltime <
15447bd1e8e8Sflorian ifatoia6(ifa)->ia6_updatetime +
15457bd1e8e8Sflorian ifatoia6(ifa)->ia6_lifetime.ia6t_pltime)
15467bd1e8e8Sflorian goto replace;
15477bd1e8e8Sflorian else if (ia6_best->ia6_updatetime +
15487bd1e8e8Sflorian ia6_best->ia6_lifetime.ia6t_pltime >
15497bd1e8e8Sflorian ifatoia6(ifa)->ia6_updatetime +
15507bd1e8e8Sflorian ifatoia6(ifa)->ia6_lifetime.ia6t_pltime)
15517bd1e8e8Sflorian continue;
15527bd1e8e8Sflorian
15537bd1e8e8Sflorian /* Prefer address with highest vltime. */
15547bd1e8e8Sflorian if (ia6_best->ia6_updatetime +
15557bd1e8e8Sflorian ia6_best->ia6_lifetime.ia6t_vltime <
15567bd1e8e8Sflorian ifatoia6(ifa)->ia6_updatetime +
15577bd1e8e8Sflorian ifatoia6(ifa)->ia6_lifetime.ia6t_vltime)
15587bd1e8e8Sflorian goto replace;
15597bd1e8e8Sflorian else if (ia6_best->ia6_updatetime +
15607bd1e8e8Sflorian ia6_best->ia6_lifetime.ia6t_vltime >
15617bd1e8e8Sflorian ifatoia6(ifa)->ia6_updatetime +
15627bd1e8e8Sflorian ifatoia6(ifa)->ia6_lifetime.ia6t_vltime)
15637bd1e8e8Sflorian continue;
15647bd1e8e8Sflorian
1565f4f4d166Sitojun continue;
1566f4f4d166Sitojun replace:
1567b9e83c60Sbluhm ia6_best = ifatoia6(ifa);
1568f4f4d166Sitojun blen = tlen >= 0 ? tlen :
1569f4f4d166Sitojun in6_matchlen(IFA_IN6(ifa), dst);
1570d61e4f47Sbluhm best_scope =
1571d61e4f47Sbluhm in6_addrscope(&ia6_best->ia_addr.sin6_addr);
1572287546eaSitojun }
1573287546eaSitojun }
1574287546eaSitojun
1575f4f4d166Sitojun /* count statistics for future improvements */
1576b9e83c60Sbluhm if (ia6_best == NULL)
157731e14cacSjca ip6stat_inc(ip6s_sources_none);
1578f4f4d166Sitojun else {
1579b9e83c60Sbluhm if (oifp == ia6_best->ia_ifp)
158031e14cacSjca ip6stat_inc(ip6s_sources_sameif + best_scope);
1581f4f4d166Sitojun else
158231e14cacSjca ip6stat_inc(ip6s_sources_otherif + best_scope);
1583287546eaSitojun
1584f4f4d166Sitojun if (best_scope == dst_scope)
158531e14cacSjca ip6stat_inc(ip6s_sources_samescope + best_scope);
1586f4f4d166Sitojun else
158731e14cacSjca ip6stat_inc(ip6s_sources_otherscope + best_scope);
1588f4f4d166Sitojun
1589b9e83c60Sbluhm if ((ia6_best->ia6_flags & IN6_IFF_DEPRECATED) != 0)
159031e14cacSjca ip6stat_inc(ip6s_sources_deprecated + best_scope);
1591f4f4d166Sitojun }
1592f4f4d166Sitojun
1593b9e83c60Sbluhm return (ia6_best);
1594287546eaSitojun }
1595287546eaSitojun
1596ce832999Sitojun int
in6if_do_dad(struct ifnet * ifp)1597ee37ea65Smcbride in6if_do_dad(struct ifnet *ifp)
1598ce832999Sitojun {
1599ce832999Sitojun if ((ifp->if_flags & IFF_LOOPBACK) != 0)
1600ce832999Sitojun return (0);
1601ce832999Sitojun
1602ce832999Sitojun switch (ifp->if_type) {
1603a7e28db1Sbluhm #if NCARP > 0
1604a7e28db1Sbluhm case IFT_CARP:
1605a7e28db1Sbluhm /*
1606a7e28db1Sbluhm * XXX: DAD does not work currently on carp(4)
1607a7e28db1Sbluhm * so disable it for now.
1608a7e28db1Sbluhm */
1609a7e28db1Sbluhm return (0);
1610a7e28db1Sbluhm #endif
1611ce832999Sitojun default:
1612ce832999Sitojun /*
1613ce832999Sitojun * Our DAD routine requires the interface up and running.
1614ce832999Sitojun * However, some interfaces can be up before the RUNNING
1615678831beSjsg * status. Additionally, users may try to assign addresses
1616ce832999Sitojun * before the interface becomes up (or running).
1617ce832999Sitojun * We simply skip DAD in such a case as a work around.
1618ce832999Sitojun * XXX: we should rather mark "tentative" on such addresses,
1619ce832999Sitojun * and do DAD after the interface becomes ready.
1620ce832999Sitojun */
1621ce832999Sitojun if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) !=
1622ce832999Sitojun (IFF_UP|IFF_RUNNING))
1623ce832999Sitojun return (0);
1624ce832999Sitojun
1625ce832999Sitojun return (1);
1626ce832999Sitojun }
1627ce832999Sitojun }
1628