| @@ -1,1533 +1,1533 @@ | | | @@ -1,1533 +1,1533 @@ |
1 | /* $NetBSD: nd6_nbr.c,v 1.166.2.4 2019/09/30 15:55:40 martin Exp $ */ | | 1 | /* $NetBSD: nd6_nbr.c,v 1.166.2.5 2020/04/23 13:31:43 martin Exp $ */ |
2 | /* $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $ */ | | 2 | /* $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $ */ |
3 | | | 3 | |
4 | /* | | 4 | /* |
5 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. | | 5 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
6 | * All rights reserved. | | 6 | * All rights reserved. |
7 | * | | 7 | * |
8 | * Redistribution and use in source and binary forms, with or without | | 8 | * Redistribution and use in source and binary forms, with or without |
9 | * modification, are permitted provided that the following conditions | | 9 | * modification, are permitted provided that the following conditions |
10 | * are met: | | 10 | * are met: |
11 | * 1. Redistributions of source code must retain the above copyright | | 11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. | | 12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright | | 13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in the | | 14 | * notice, this list of conditions and the following disclaimer in the |
15 | * documentation and/or other materials provided with the distribution. | | 15 | * documentation and/or other materials provided with the distribution. |
16 | * 3. Neither the name of the project nor the names of its contributors | | 16 | * 3. Neither the name of the project nor the names of its contributors |
17 | * may be used to endorse or promote products derived from this software | | 17 | * may be used to endorse or promote products derived from this software |
18 | * without specific prior written permission. | | 18 | * without specific prior written permission. |
19 | * | | 19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND | | 20 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE | | 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
30 | * SUCH DAMAGE. | | 30 | * SUCH DAMAGE. |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | #include <sys/cdefs.h> | | 33 | #include <sys/cdefs.h> |
34 | __KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.166.2.4 2019/09/30 15:55:40 martin Exp $"); | | 34 | __KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.166.2.5 2020/04/23 13:31:43 martin Exp $"); |
35 | | | 35 | |
36 | #ifdef _KERNEL_OPT | | 36 | #ifdef _KERNEL_OPT |
37 | #include "opt_inet.h" | | 37 | #include "opt_inet.h" |
38 | #include "opt_net_mpsafe.h" | | 38 | #include "opt_net_mpsafe.h" |
39 | #endif | | 39 | #endif |
40 | | | 40 | |
41 | #include <sys/param.h> | | 41 | #include <sys/param.h> |
42 | #include <sys/systm.h> | | 42 | #include <sys/systm.h> |
43 | #include <sys/kmem.h> | | 43 | #include <sys/kmem.h> |
44 | #include <sys/mbuf.h> | | 44 | #include <sys/mbuf.h> |
45 | #include <sys/socket.h> | | 45 | #include <sys/socket.h> |
46 | #include <sys/socketvar.h> | | 46 | #include <sys/socketvar.h> |
47 | #include <sys/sockio.h> | | 47 | #include <sys/sockio.h> |
48 | #include <sys/time.h> | | 48 | #include <sys/time.h> |
49 | #include <sys/kernel.h> | | 49 | #include <sys/kernel.h> |
50 | #include <sys/errno.h> | | 50 | #include <sys/errno.h> |
51 | #include <sys/ioctl.h> | | 51 | #include <sys/ioctl.h> |
52 | #include <sys/syslog.h> | | 52 | #include <sys/syslog.h> |
53 | #include <sys/queue.h> | | 53 | #include <sys/queue.h> |
54 | #include <sys/callout.h> | | 54 | #include <sys/callout.h> |
55 | #include <sys/cprng.h> | | 55 | #include <sys/cprng.h> |
56 | | | 56 | |
57 | #include <net/if.h> | | 57 | #include <net/if.h> |
58 | #include <net/if_types.h> | | 58 | #include <net/if_types.h> |
59 | #include <net/if_dl.h> | | 59 | #include <net/if_dl.h> |
60 | #include <net/route.h> | | 60 | #include <net/route.h> |
61 | | | 61 | |
62 | #include <netinet/in.h> | | 62 | #include <netinet/in.h> |
63 | #include <netinet/in_var.h> | | 63 | #include <netinet/in_var.h> |
64 | #include <netinet6/in6_var.h> | | 64 | #include <netinet6/in6_var.h> |
65 | #include <netinet6/in6_ifattach.h> | | 65 | #include <netinet6/in6_ifattach.h> |
66 | #include <netinet/ip6.h> | | 66 | #include <netinet/ip6.h> |
67 | #include <netinet6/ip6_var.h> | | 67 | #include <netinet6/ip6_var.h> |
68 | #include <netinet6/scope6_var.h> | | 68 | #include <netinet6/scope6_var.h> |
69 | #include <netinet6/nd6.h> | | 69 | #include <netinet6/nd6.h> |
70 | #include <netinet/icmp6.h> | | 70 | #include <netinet/icmp6.h> |
71 | #include <netinet6/icmp6_private.h> | | 71 | #include <netinet6/icmp6_private.h> |
72 | | | 72 | |
73 | #include "carp.h" | | 73 | #include "carp.h" |
74 | #if NCARP > 0 | | 74 | #if NCARP > 0 |
75 | #include <netinet/ip_carp.h> | | 75 | #include <netinet/ip_carp.h> |
76 | #endif | | 76 | #endif |
77 | | | 77 | |
78 | struct dadq; | | 78 | struct dadq; |
79 | static struct dadq *nd6_dad_find(struct ifaddr *, struct nd_opt_nonce *, bool *); | | 79 | static struct dadq *nd6_dad_find(struct ifaddr *, struct nd_opt_nonce *, bool *); |
80 | static bool nd6_dad_ownnonce(struct ifaddr *, struct nd_opt_nonce *nonce); | | 80 | static bool nd6_dad_ownnonce(struct ifaddr *, struct nd_opt_nonce *nonce); |
81 | static void nd6_dad_starttimer(struct dadq *, int); | | 81 | static void nd6_dad_starttimer(struct dadq *, int); |
82 | static void nd6_dad_destroytimer(struct dadq *); | | 82 | static void nd6_dad_destroytimer(struct dadq *); |
83 | static void nd6_dad_timer(struct dadq *); | | 83 | static void nd6_dad_timer(struct dadq *); |
84 | static void nd6_dad_ns_output(struct dadq *, struct ifaddr *); | | 84 | static void nd6_dad_ns_output(struct dadq *, struct ifaddr *); |
85 | static void nd6_dad_input(struct ifaddr *, struct nd_opt_nonce *, | | 85 | static void nd6_dad_input(struct ifaddr *, struct nd_opt_nonce *, |
86 | const struct sockaddr_dl *); | | 86 | const struct sockaddr_dl *); |
87 | static void nd6_dad_duplicated(struct ifaddr *, struct dadq *, | | 87 | static void nd6_dad_duplicated(struct ifaddr *, struct dadq *, |
88 | const struct sockaddr_dl *); | | 88 | const struct sockaddr_dl *); |
89 | | | 89 | |
90 | static int dad_maxtry = 15; /* max # of *tries* to transmit DAD packet */ | | 90 | static int dad_maxtry = 15; /* max # of *tries* to transmit DAD packet */ |
91 | | | 91 | |
92 | /* | | 92 | /* |
93 | * Input a Neighbor Solicitation Message. | | 93 | * Input a Neighbor Solicitation Message. |
94 | * | | 94 | * |
95 | * Based on RFC 2461 | | 95 | * Based on RFC 2461 |
96 | * Based on RFC 2462 (duplicate address detection) | | 96 | * Based on RFC 2462 (duplicate address detection) |
97 | */ | | 97 | */ |
98 | void | | 98 | void |
99 | nd6_ns_input(struct mbuf *m, int off, int icmp6len) | | 99 | nd6_ns_input(struct mbuf *m, int off, int icmp6len) |
100 | { | | 100 | { |
101 | struct ifnet *ifp; | | 101 | struct ifnet *ifp; |
102 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); | | 102 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); |
103 | struct nd_neighbor_solicit *nd_ns; | | 103 | struct nd_neighbor_solicit *nd_ns; |
104 | struct in6_addr saddr6 = ip6->ip6_src; | | 104 | struct in6_addr saddr6 = ip6->ip6_src; |
105 | struct in6_addr daddr6 = ip6->ip6_dst; | | 105 | struct in6_addr daddr6 = ip6->ip6_dst; |
106 | struct in6_addr taddr6; | | 106 | struct in6_addr taddr6; |
107 | struct in6_addr myaddr6; | | 107 | struct in6_addr myaddr6; |
108 | char *lladdr = NULL; | | 108 | char *lladdr = NULL; |
109 | struct ifaddr *ifa = NULL; | | 109 | struct ifaddr *ifa = NULL; |
110 | int lladdrlen = 0; | | 110 | int lladdrlen = 0; |
111 | int anycast = 0, proxy = 0, tentative = 0; | | 111 | int anycast = 0, proxy = 0, tentative = 0; |
112 | int router = ip6_forwarding; | | 112 | int router = ip6_forwarding; |
113 | int tlladdr; | | 113 | int tlladdr; |
114 | union nd_opts ndopts; | | 114 | union nd_opts ndopts; |
115 | const struct sockaddr_dl *proxydl = NULL; | | 115 | const struct sockaddr_dl *proxydl = NULL; |
116 | struct psref psref; | | 116 | struct psref psref; |
117 | struct psref psref_ia; | | 117 | struct psref psref_ia; |
118 | char ip6buf[INET6_ADDRSTRLEN], ip6buf2[INET6_ADDRSTRLEN]; | | 118 | char ip6buf[INET6_ADDRSTRLEN], ip6buf2[INET6_ADDRSTRLEN]; |
119 | | | 119 | |
120 | ifp = m_get_rcvif_psref(m, &psref); | | 120 | ifp = m_get_rcvif_psref(m, &psref); |
121 | if (ifp == NULL) | | 121 | if (ifp == NULL) |
122 | goto freeit; | | 122 | goto freeit; |
123 | | | 123 | |
124 | IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len); | | 124 | IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len); |
125 | if (nd_ns == NULL) { | | 125 | if (nd_ns == NULL) { |
126 | ICMP6_STATINC(ICMP6_STAT_TOOSHORT); | | 126 | ICMP6_STATINC(ICMP6_STAT_TOOSHORT); |
127 | m_put_rcvif_psref(ifp, &psref); | | 127 | m_put_rcvif_psref(ifp, &psref); |
128 | return; | | 128 | return; |
129 | } | | 129 | } |
130 | ip6 = mtod(m, struct ip6_hdr *); /* adjust pointer for safety */ | | 130 | ip6 = mtod(m, struct ip6_hdr *); /* adjust pointer for safety */ |
131 | taddr6 = nd_ns->nd_ns_target; | | 131 | taddr6 = nd_ns->nd_ns_target; |
132 | if (in6_setscope(&taddr6, ifp, NULL) != 0) | | 132 | if (in6_setscope(&taddr6, ifp, NULL) != 0) |
133 | goto bad; | | 133 | goto bad; |
134 | | | 134 | |
135 | if (ip6->ip6_hlim != 255) { | | 135 | if (ip6->ip6_hlim != 255) { |
136 | nd6log(LOG_ERR, "invalid hlim (%d) from %s to %s on %s\n", | | 136 | nd6log(LOG_ERR, "invalid hlim (%d) from %s to %s on %s\n", |
137 | ip6->ip6_hlim, IN6_PRINT(ip6buf, &ip6->ip6_src), | | 137 | ip6->ip6_hlim, IN6_PRINT(ip6buf, &ip6->ip6_src), |
138 | IN6_PRINT(ip6buf2, &ip6->ip6_dst), if_name(ifp)); | | 138 | IN6_PRINT(ip6buf2, &ip6->ip6_dst), if_name(ifp)); |
139 | goto bad; | | 139 | goto bad; |
140 | } | | 140 | } |
141 | | | 141 | |
142 | if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { | | 142 | if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { |
143 | /* dst has to be a solicited node multicast address. */ | | 143 | /* dst has to be a solicited node multicast address. */ |
144 | /* don't check ifindex portion */ | | 144 | /* don't check ifindex portion */ |
145 | if (daddr6.s6_addr16[0] == IPV6_ADDR_INT16_MLL && | | 145 | if (daddr6.s6_addr16[0] == IPV6_ADDR_INT16_MLL && |
146 | daddr6.s6_addr32[1] == 0 && | | 146 | daddr6.s6_addr32[1] == 0 && |
147 | daddr6.s6_addr32[2] == IPV6_ADDR_INT32_ONE && | | 147 | daddr6.s6_addr32[2] == IPV6_ADDR_INT32_ONE && |
148 | daddr6.s6_addr8[12] == 0xff) { | | 148 | daddr6.s6_addr8[12] == 0xff) { |
149 | ; /* good */ | | 149 | ; /* good */ |
150 | } else { | | 150 | } else { |
151 | nd6log(LOG_INFO, "bad DAD packet (wrong ip6 dst)\n"); | | 151 | nd6log(LOG_INFO, "bad DAD packet (wrong ip6 dst)\n"); |
152 | goto bad; | | 152 | goto bad; |
153 | } | | 153 | } |
154 | } else { | | 154 | } else { |
155 | struct sockaddr_in6 ssin6; | | 155 | struct sockaddr_in6 ssin6; |
156 | | | 156 | |
157 | /* | | 157 | /* |
158 | * Make sure the source address is from a neighbor's address. | | 158 | * Make sure the source address is from a neighbor's address. |
159 | */ | | 159 | */ |
160 | sockaddr_in6_init(&ssin6, &saddr6, 0, 0, 0); | | 160 | sockaddr_in6_init(&ssin6, &saddr6, 0, 0, 0); |
161 | if (nd6_is_addr_neighbor(&ssin6, ifp) == 0) { | | 161 | if (nd6_is_addr_neighbor(&ssin6, ifp) == 0) { |
162 | nd6log(LOG_INFO, | | 162 | nd6log(LOG_INFO, |
163 | "NS packet from non-neighbor %s on %s\n", | | 163 | "NS packet from non-neighbor %s on %s\n", |
164 | IN6_PRINT(ip6buf, &saddr6), if_name(ifp)); | | 164 | IN6_PRINT(ip6buf, &saddr6), if_name(ifp)); |
165 | goto bad; | | 165 | goto bad; |
166 | } | | 166 | } |
167 | } | | 167 | } |
168 | | | 168 | |
169 | if (IN6_IS_ADDR_MULTICAST(&taddr6)) { | | 169 | if (IN6_IS_ADDR_MULTICAST(&taddr6)) { |
170 | nd6log(LOG_INFO, "bad NS target (multicast)\n"); | | 170 | nd6log(LOG_INFO, "bad NS target (multicast)\n"); |
171 | goto bad; | | 171 | goto bad; |
172 | } | | 172 | } |
173 | | | 173 | |
174 | icmp6len -= sizeof(*nd_ns); | | 174 | icmp6len -= sizeof(*nd_ns); |
175 | nd6_option_init(nd_ns + 1, icmp6len, &ndopts); | | 175 | nd6_option_init(nd_ns + 1, icmp6len, &ndopts); |
176 | if (nd6_options(&ndopts) < 0) { | | 176 | if (nd6_options(&ndopts) < 0) { |
177 | nd6log(LOG_INFO, "invalid ND option, ignored\n"); | | 177 | nd6log(LOG_INFO, "invalid ND option, ignored\n"); |
178 | /* nd6_options have incremented stats */ | | 178 | /* nd6_options have incremented stats */ |
179 | goto freeit; | | 179 | goto freeit; |
180 | } | | 180 | } |
181 | | | 181 | |
182 | if (ndopts.nd_opts_src_lladdr) { | | 182 | if (ndopts.nd_opts_src_lladdr) { |
183 | lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); | | 183 | lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); |
184 | lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; | | 184 | lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; |
185 | } | | 185 | } |
186 | | | 186 | |
187 | if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && lladdr) { | | 187 | if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && lladdr) { |
188 | nd6log(LOG_INFO, | | 188 | nd6log(LOG_INFO, |
189 | "bad DAD packet (link-layer address option)\n"); | | 189 | "bad DAD packet (link-layer address option)\n"); |
190 | goto bad; | | 190 | goto bad; |
191 | } | | 191 | } |
192 | | | 192 | |
193 | /* | | 193 | /* |
194 | * Attaching target link-layer address to the NA? | | 194 | * Attaching target link-layer address to the NA? |
195 | * (RFC 2461 7.2.4) | | 195 | * (RFC 2461 7.2.4) |
196 | * | | 196 | * |
197 | * NS IP dst is multicast MUST add | | 197 | * NS IP dst is multicast MUST add |
198 | * Otherwise MAY be omitted | | 198 | * Otherwise MAY be omitted |
199 | * | | 199 | * |
200 | * In this implementation, we omit the target link-layer address | | 200 | * In this implementation, we omit the target link-layer address |
201 | * in the "MAY" case. | | 201 | * in the "MAY" case. |
202 | */ | | 202 | */ |
203 | #if 0 /* too much! */ | | 203 | #if 0 /* too much! */ |
204 | ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &daddr6); | | 204 | ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &daddr6); |
205 | if (ifa && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)) | | 205 | if (ifa && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)) |
206 | tlladdr = 0; | | 206 | tlladdr = 0; |
207 | else | | 207 | else |
208 | #endif | | 208 | #endif |
209 | if (!IN6_IS_ADDR_MULTICAST(&daddr6)) | | 209 | if (!IN6_IS_ADDR_MULTICAST(&daddr6)) |
210 | tlladdr = 0; | | 210 | tlladdr = 0; |
211 | else | | 211 | else |
212 | tlladdr = 1; | | 212 | tlladdr = 1; |
213 | | | 213 | |
214 | /* | | 214 | /* |
215 | * Target address (taddr6) must be either: | | 215 | * Target address (taddr6) must be either: |
216 | * (1) Valid unicast/anycast address for my receiving interface, | | 216 | * (1) Valid unicast/anycast address for my receiving interface, |
217 | * (2) Unicast address for which I'm offering proxy service, or | | 217 | * (2) Unicast address for which I'm offering proxy service, or |
218 | * (3) "tentative" address on which DAD is being performed. | | 218 | * (3) "tentative" address on which DAD is being performed. |
219 | */ | | 219 | */ |
220 | /* (1) and (3) check. */ | | 220 | /* (1) and (3) check. */ |
221 | #if NCARP > 0 | | 221 | #if NCARP > 0 |
222 | if (ifp->if_carp && ifp->if_type != IFT_CARP) { | | 222 | if (ifp->if_carp && ifp->if_type != IFT_CARP) { |
223 | int s = pserialize_read_enter(); | | 223 | int s = pserialize_read_enter(); |
224 | ifa = carp_iamatch6(ifp->if_carp, &taddr6); | | 224 | ifa = carp_iamatch6(ifp->if_carp, &taddr6); |
225 | if (ifa != NULL) | | 225 | if (ifa != NULL) |
226 | ifa_acquire(ifa, &psref_ia); | | 226 | ifa_acquire(ifa, &psref_ia); |
227 | pserialize_read_exit(s); | | 227 | pserialize_read_exit(s); |
228 | } else | | 228 | } else |
229 | ifa = NULL; | | 229 | ifa = NULL; |
230 | if (!ifa) | | 230 | if (!ifa) |
231 | ifa = (struct ifaddr *)in6ifa_ifpwithaddr_psref(ifp, &taddr6, | | 231 | ifa = (struct ifaddr *)in6ifa_ifpwithaddr_psref(ifp, &taddr6, |
232 | &psref_ia); | | 232 | &psref_ia); |
233 | #else | | 233 | #else |
234 | ifa = (struct ifaddr *)in6ifa_ifpwithaddr_psref(ifp, &taddr6, | | 234 | ifa = (struct ifaddr *)in6ifa_ifpwithaddr_psref(ifp, &taddr6, |
235 | &psref_ia); | | 235 | &psref_ia); |
236 | #endif | | 236 | #endif |
237 | | | 237 | |
238 | /* (2) check. */ | | 238 | /* (2) check. */ |
239 | if (ifa == NULL) { | | 239 | if (ifa == NULL) { |
240 | struct rtentry *rt; | | 240 | struct rtentry *rt; |
241 | struct sockaddr_in6 tsin6; | | 241 | struct sockaddr_in6 tsin6; |
242 | | | 242 | |
243 | sockaddr_in6_init(&tsin6, &taddr6, 0, 0, 0); | | 243 | sockaddr_in6_init(&tsin6, &taddr6, 0, 0, 0); |
244 | | | 244 | |
245 | rt = rtalloc1(sin6tosa(&tsin6), 0); | | 245 | rt = rtalloc1(sin6tosa(&tsin6), 0); |
246 | if (rt && (rt->rt_flags & RTF_ANNOUNCE) != 0 && | | 246 | if (rt && (rt->rt_flags & RTF_ANNOUNCE) != 0 && |
247 | rt->rt_gateway->sa_family == AF_LINK) { | | 247 | rt->rt_gateway->sa_family == AF_LINK) { |
248 | /* | | 248 | /* |
249 | * proxy NDP for single entry | | 249 | * proxy NDP for single entry |
250 | */ | | 250 | */ |
251 | ifa = (struct ifaddr *)in6ifa_ifpforlinklocal_psref(ifp, | | 251 | ifa = (struct ifaddr *)in6ifa_ifpforlinklocal_psref(ifp, |
252 | IN6_IFF_NOTREADY|IN6_IFF_ANYCAST, &psref_ia); | | 252 | IN6_IFF_NOTREADY|IN6_IFF_ANYCAST, &psref_ia); |
253 | if (ifa) { | | 253 | if (ifa) { |
254 | proxy = 1; | | 254 | proxy = 1; |
255 | proxydl = satocsdl(rt->rt_gateway); | | 255 | proxydl = satocsdl(rt->rt_gateway); |
256 | router = 0; /* XXX */ | | 256 | router = 0; /* XXX */ |
257 | } | | 257 | } |
258 | } | | 258 | } |
259 | if (rt) | | 259 | if (rt) |
260 | rt_unref(rt); | | 260 | rt_unref(rt); |
261 | } | | 261 | } |
262 | if (ifa == NULL) { | | 262 | if (ifa == NULL) { |
263 | /* | | 263 | /* |
264 | * We've got an NS packet, and we don't have that address | | 264 | * We've got an NS packet, and we don't have that address |
265 | * assigned for us. We MUST silently ignore it. | | 265 | * assigned for us. We MUST silently ignore it. |
266 | * See RFC2461 7.2.3. | | 266 | * See RFC2461 7.2.3. |
267 | */ | | 267 | */ |
268 | goto freeit; | | 268 | goto freeit; |
269 | } | | 269 | } |
270 | myaddr6 = *IFA_IN6(ifa); | | 270 | myaddr6 = *IFA_IN6(ifa); |
271 | anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST; | | 271 | anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST; |
272 | tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE; | | 272 | tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE; |
273 | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED) | | 273 | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED) |
274 | goto freeit; | | 274 | goto freeit; |
275 | | | 275 | |
276 | if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { | | 276 | if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { |
277 | nd6log(LOG_INFO, "lladdrlen mismatch for %s " | | 277 | nd6log(LOG_INFO, "lladdrlen mismatch for %s " |
278 | "(if %d, NS packet %d)\n", | | 278 | "(if %d, NS packet %d)\n", |
279 | IN6_PRINT(ip6buf, &taddr6), | | 279 | IN6_PRINT(ip6buf, &taddr6), |
280 | ifp->if_addrlen, lladdrlen - 2); | | 280 | ifp->if_addrlen, lladdrlen - 2); |
281 | goto bad; | | 281 | goto bad; |
282 | } | | 282 | } |
283 | | | 283 | |
284 | if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) { | | 284 | if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) { |
285 | nd6log(LOG_INFO, "duplicate IP6 address %s\n", | | 285 | nd6log(LOG_INFO, "duplicate IP6 address %s\n", |
286 | IN6_PRINT(ip6buf, &saddr6)); | | 286 | IN6_PRINT(ip6buf, &saddr6)); |
287 | goto freeit; | | 287 | goto freeit; |
288 | } | | 288 | } |
289 | | | 289 | |
290 | /* | | 290 | /* |
291 | * We have neighbor solicitation packet, with target address equals to | | 291 | * We have neighbor solicitation packet, with target address equals to |
292 | * one of my tentative address. | | 292 | * one of my tentative address. |
293 | * | | 293 | * |
294 | * src addr how to process? | | 294 | * src addr how to process? |
295 | * --- --- | | 295 | * --- --- |
296 | * multicast of course, invalid (rejected in ip6_input) | | 296 | * multicast of course, invalid (rejected in ip6_input) |
297 | * unicast somebody is doing address resolution -> ignore | | 297 | * unicast somebody is doing address resolution -> ignore |
298 | * unspec dup address detection | | 298 | * unspec dup address detection |
299 | * | | 299 | * |
300 | * The processing is defined in RFC 2462. | | 300 | * The processing is defined in RFC 2462. |
301 | */ | | 301 | */ |
302 | if (tentative) { | | 302 | if (tentative) { |
303 | /* | | 303 | /* |
304 | * If source address is unspecified address, it is for | | 304 | * If source address is unspecified address, it is for |
305 | * duplicate address detection. | | 305 | * duplicate address detection. |
306 | * | | 306 | * |
307 | * If not, the packet is for addess resolution; | | 307 | * If not, the packet is for addess resolution; |
308 | * silently ignore it. | | 308 | * silently ignore it. |
309 | */ | | 309 | */ |
310 | if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { | | 310 | if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { |
311 | struct sockaddr_dl sdl, *sdlp; | | 311 | struct sockaddr_dl sdl, *sdlp; |
312 | | | 312 | |
313 | if (lladdr != NULL) | | 313 | if (lladdr != NULL) |
314 | sdlp = sockaddr_dl_init(&sdl, sizeof(sdl), | | 314 | sdlp = sockaddr_dl_init(&sdl, sizeof(sdl), |
315 | ifp->if_index, ifp->if_type, | | 315 | ifp->if_index, ifp->if_type, |
316 | NULL, 0, lladdr, lladdrlen); | | 316 | NULL, 0, lladdr, lladdrlen); |
317 | else | | 317 | else |
318 | sdlp = NULL; | | 318 | sdlp = NULL; |
319 | nd6_dad_input(ifa, ndopts.nd_opts_nonce, sdlp); | | 319 | nd6_dad_input(ifa, ndopts.nd_opts_nonce, sdlp); |
320 | } | | 320 | } |
321 | goto freeit; | | 321 | goto freeit; |
322 | } | | 322 | } |
323 | | | 323 | |
324 | /* | | 324 | /* |
325 | * It looks that sender is performing DAD. | | 325 | * It looks that sender is performing DAD. |
326 | * Check that the nonce is not being used by the same address | | 326 | * Check that the nonce is not being used by the same address |
327 | * on another interface. | | 327 | * on another interface. |
328 | */ | | 328 | */ |
329 | if (IN6_IS_ADDR_UNSPECIFIED(&saddr6) && ndopts.nd_opts_nonce != NULL) { | | 329 | if (IN6_IS_ADDR_UNSPECIFIED(&saddr6) && ndopts.nd_opts_nonce != NULL) { |
330 | if (nd6_dad_ownnonce(ifa, ndopts.nd_opts_nonce)) | | 330 | if (nd6_dad_ownnonce(ifa, ndopts.nd_opts_nonce)) |
331 | goto freeit; | | 331 | goto freeit; |
332 | } | | 332 | } |
333 | | | 333 | |
334 | ifa_release(ifa, &psref_ia); | | 334 | ifa_release(ifa, &psref_ia); |
335 | ifa = NULL; | | 335 | ifa = NULL; |
336 | | | 336 | |
337 | /* | | 337 | /* |
338 | * If the source address is unspecified address, entries must not | | 338 | * If the source address is unspecified address, entries must not |
339 | * be created or updated. | | 339 | * be created or updated. |
340 | * It looks that sender is performing DAD. Output NA toward | | 340 | * It looks that sender is performing DAD. Output NA toward |
341 | * all-node multicast address, to tell the sender that I'm using | | 341 | * all-node multicast address, to tell the sender that I'm using |
342 | * the address. | | 342 | * the address. |
343 | * S bit ("solicited") must be zero. | | 343 | * S bit ("solicited") must be zero. |
344 | */ | | 344 | */ |
345 | if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { | | 345 | if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { |
346 | struct in6_addr in6_all; | | 346 | struct in6_addr in6_all; |
347 | | | 347 | |
348 | in6_all = in6addr_linklocal_allnodes; | | 348 | in6_all = in6addr_linklocal_allnodes; |
349 | if (in6_setscope(&in6_all, ifp, NULL) != 0) | | 349 | if (in6_setscope(&in6_all, ifp, NULL) != 0) |
350 | goto bad; | | 350 | goto bad; |
351 | nd6_na_output(ifp, &in6_all, &taddr6, | | 351 | nd6_na_output(ifp, &in6_all, &taddr6, |
352 | ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) | | | 352 | ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) | |
353 | (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0), | | 353 | (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0), |
354 | tlladdr, (const struct sockaddr *)proxydl); | | 354 | tlladdr, (const struct sockaddr *)proxydl); |
355 | goto freeit; | | 355 | goto freeit; |
356 | } | | 356 | } |
357 | | | 357 | |
358 | nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_NEIGHBOR_SOLICIT, 0); | | 358 | nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_NEIGHBOR_SOLICIT, 0); |
359 | | | 359 | |
360 | nd6_na_output(ifp, &saddr6, &taddr6, | | 360 | nd6_na_output(ifp, &saddr6, &taddr6, |
361 | ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) | | | 361 | ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) | |
362 | (router ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED, | | 362 | (router ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED, |
363 | tlladdr, (const struct sockaddr *)proxydl); | | 363 | tlladdr, (const struct sockaddr *)proxydl); |
364 | freeit: | | 364 | freeit: |
365 | ifa_release(ifa, &psref_ia); | | 365 | ifa_release(ifa, &psref_ia); |
366 | m_put_rcvif_psref(ifp, &psref); | | 366 | m_put_rcvif_psref(ifp, &psref); |
367 | m_freem(m); | | 367 | m_freem(m); |
368 | return; | | 368 | return; |
369 | | | 369 | |
370 | bad: | | 370 | bad: |
371 | nd6log(LOG_ERR, "src=%s\n", IN6_PRINT(ip6buf, &saddr6)); | | 371 | nd6log(LOG_ERR, "src=%s\n", IN6_PRINT(ip6buf, &saddr6)); |
372 | nd6log(LOG_ERR, "dst=%s\n", IN6_PRINT(ip6buf, &daddr6)); | | 372 | nd6log(LOG_ERR, "dst=%s\n", IN6_PRINT(ip6buf, &daddr6)); |
373 | nd6log(LOG_ERR, "tgt=%s\n", IN6_PRINT(ip6buf, &taddr6)); | | 373 | nd6log(LOG_ERR, "tgt=%s\n", IN6_PRINT(ip6buf, &taddr6)); |
374 | ICMP6_STATINC(ICMP6_STAT_BADNS); | | 374 | ICMP6_STATINC(ICMP6_STAT_BADNS); |
375 | ifa_release(ifa, &psref_ia); | | 375 | ifa_release(ifa, &psref_ia); |
376 | m_put_rcvif_psref(ifp, &psref); | | 376 | m_put_rcvif_psref(ifp, &psref); |
377 | m_freem(m); | | 377 | m_freem(m); |
378 | } | | 378 | } |
379 | | | 379 | |
380 | /* | | 380 | /* |
381 | * Output a Neighbor Solicitation Message. Caller specifies: | | 381 | * Output a Neighbor Solicitation Message. Caller specifies: |
382 | * - ICMP6 header source IP6 address | | 382 | * - ICMP6 header source IP6 address |
383 | * - ND6 header target IP6 address | | 383 | * - ND6 header target IP6 address |
384 | * - ND6 header source datalink address | | 384 | * - ND6 header source datalink address |
385 | * | | 385 | * |
386 | * Based on RFC 2461 | | 386 | * Based on RFC 2461 |
387 | * Based on RFC 2462 (duplicate address detection) | | 387 | * Based on RFC 2462 (duplicate address detection) |
388 | */ | | 388 | */ |
389 | void | | 389 | void |
390 | nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6, | | 390 | nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6, |
391 | const struct in6_addr *taddr6, | | 391 | const struct in6_addr *taddr6, |
392 | struct in6_addr *hsrc, | | 392 | struct in6_addr *hsrc, |
393 | uint8_t *nonce /* duplicate address detection */) | | 393 | uint8_t *nonce /* duplicate address detection */) |
394 | { | | 394 | { |
395 | struct mbuf *m; | | 395 | struct mbuf *m; |
396 | struct ip6_hdr *ip6; | | 396 | struct ip6_hdr *ip6; |
397 | struct nd_neighbor_solicit *nd_ns; | | 397 | struct nd_neighbor_solicit *nd_ns; |
398 | struct in6_addr *src, src_in; | | 398 | struct in6_addr *src, src_in; |
399 | struct ip6_moptions im6o; | | 399 | struct ip6_moptions im6o; |
400 | int icmp6len; | | 400 | int icmp6len; |
401 | int maxlen; | | 401 | int maxlen; |
402 | const void *mac; | | 402 | const void *mac; |
403 | struct route ro; | | 403 | struct route ro; |
404 | | | 404 | |
405 | if (IN6_IS_ADDR_MULTICAST(taddr6)) | | 405 | if (IN6_IS_ADDR_MULTICAST(taddr6)) |
406 | return; | | 406 | return; |
407 | | | 407 | |
408 | memset(&ro, 0, sizeof(ro)); | | 408 | memset(&ro, 0, sizeof(ro)); |
409 | | | 409 | |
410 | /* estimate the size of message */ | | 410 | /* estimate the size of message */ |
411 | maxlen = sizeof(*ip6) + sizeof(*nd_ns); | | 411 | maxlen = sizeof(*ip6) + sizeof(*nd_ns); |
412 | maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7; | | 412 | maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7; |
413 | KASSERTMSG(max_linkhdr + maxlen <= MCLBYTES, | | 413 | KASSERTMSG(max_linkhdr + maxlen <= MCLBYTES, |
414 | "max_linkhdr + maxlen > MCLBYTES (%d + %d > %d)", | | 414 | "max_linkhdr + maxlen > MCLBYTES (%d + %d > %d)", |
415 | max_linkhdr, maxlen, MCLBYTES); | | 415 | max_linkhdr, maxlen, MCLBYTES); |
416 | | | 416 | |
417 | MGETHDR(m, M_DONTWAIT, MT_DATA); | | 417 | MGETHDR(m, M_DONTWAIT, MT_DATA); |
418 | if (m && max_linkhdr + maxlen >= MHLEN) { | | 418 | if (m && max_linkhdr + maxlen >= MHLEN) { |
419 | MCLGET(m, M_DONTWAIT); | | 419 | MCLGET(m, M_DONTWAIT); |
420 | if ((m->m_flags & M_EXT) == 0) { | | 420 | if ((m->m_flags & M_EXT) == 0) { |
421 | m_free(m); | | 421 | m_free(m); |
422 | m = NULL; | | 422 | m = NULL; |
423 | } | | 423 | } |
424 | } | | 424 | } |
425 | if (m == NULL) | | 425 | if (m == NULL) |
426 | return; | | 426 | return; |
427 | m_reset_rcvif(m); | | 427 | m_reset_rcvif(m); |
428 | | | 428 | |
429 | if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) { | | 429 | if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) { |
430 | m->m_flags |= M_MCAST; | | 430 | m->m_flags |= M_MCAST; |
431 | im6o.im6o_multicast_if_index = if_get_index(ifp); | | 431 | im6o.im6o_multicast_if_index = if_get_index(ifp); |
432 | im6o.im6o_multicast_hlim = 255; | | 432 | im6o.im6o_multicast_hlim = 255; |
433 | im6o.im6o_multicast_loop = 0; | | 433 | im6o.im6o_multicast_loop = 0; |
434 | } | | 434 | } |
435 | | | 435 | |
436 | icmp6len = sizeof(*nd_ns); | | 436 | icmp6len = sizeof(*nd_ns); |
437 | m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len; | | 437 | m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len; |
438 | m->m_data += max_linkhdr; /* or m_align() equivalent? */ | | 438 | m->m_data += max_linkhdr; /* or m_align() equivalent? */ |
439 | | | 439 | |
440 | /* fill neighbor solicitation packet */ | | 440 | /* fill neighbor solicitation packet */ |
441 | ip6 = mtod(m, struct ip6_hdr *); | | 441 | ip6 = mtod(m, struct ip6_hdr *); |
442 | ip6->ip6_flow = 0; | | 442 | ip6->ip6_flow = 0; |
443 | ip6->ip6_vfc &= ~IPV6_VERSION_MASK; | | 443 | ip6->ip6_vfc &= ~IPV6_VERSION_MASK; |
444 | ip6->ip6_vfc |= IPV6_VERSION; | | 444 | ip6->ip6_vfc |= IPV6_VERSION; |
445 | /* ip6->ip6_plen will be set later */ | | 445 | /* ip6->ip6_plen will be set later */ |
446 | ip6->ip6_nxt = IPPROTO_ICMPV6; | | 446 | ip6->ip6_nxt = IPPROTO_ICMPV6; |
447 | ip6->ip6_hlim = 255; | | 447 | ip6->ip6_hlim = 255; |
448 | if (daddr6) | | 448 | if (daddr6) |
449 | ip6->ip6_dst = *daddr6; | | 449 | ip6->ip6_dst = *daddr6; |
450 | else { | | 450 | else { |
451 | ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL; | | 451 | ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL; |
452 | ip6->ip6_dst.s6_addr16[1] = 0; | | 452 | ip6->ip6_dst.s6_addr16[1] = 0; |
453 | ip6->ip6_dst.s6_addr32[1] = 0; | | 453 | ip6->ip6_dst.s6_addr32[1] = 0; |
454 | ip6->ip6_dst.s6_addr32[2] = IPV6_ADDR_INT32_ONE; | | 454 | ip6->ip6_dst.s6_addr32[2] = IPV6_ADDR_INT32_ONE; |
455 | ip6->ip6_dst.s6_addr32[3] = taddr6->s6_addr32[3]; | | 455 | ip6->ip6_dst.s6_addr32[3] = taddr6->s6_addr32[3]; |
456 | ip6->ip6_dst.s6_addr8[12] = 0xff; | | 456 | ip6->ip6_dst.s6_addr8[12] = 0xff; |
457 | if (in6_setscope(&ip6->ip6_dst, ifp, NULL) != 0) | | 457 | if (in6_setscope(&ip6->ip6_dst, ifp, NULL) != 0) |
458 | goto bad; | | 458 | goto bad; |
459 | } | | 459 | } |
460 | if (nonce == NULL) { | | 460 | if (nonce == NULL) { |
461 | int s; | | 461 | int s; |
462 | /* | | 462 | /* |
463 | * RFC2461 7.2.2: | | 463 | * RFC2461 7.2.2: |
464 | * "If the source address of the packet prompting the | | 464 | * "If the source address of the packet prompting the |
465 | * solicitation is the same as one of the addresses assigned | | 465 | * solicitation is the same as one of the addresses assigned |
466 | * to the outgoing interface, that address SHOULD be placed | | 466 | * to the outgoing interface, that address SHOULD be placed |
467 | * in the IP Source Address of the outgoing solicitation. | | 467 | * in the IP Source Address of the outgoing solicitation. |
468 | * Otherwise, any one of the addresses assigned to the | | 468 | * Otherwise, any one of the addresses assigned to the |
469 | * interface should be used." | | 469 | * interface should be used." |
470 | * | | 470 | * |
471 | * We use the source address for the prompting packet | | 471 | * We use the source address for the prompting packet |
472 | * (hsrc), if: | | 472 | * (hsrc), if: |
473 | * - hsrc is given from the caller (by giving "ln"), and | | 473 | * - hsrc is given from the caller (by giving "ln"), and |
474 | * - hsrc belongs to the outgoing interface. | | 474 | * - hsrc belongs to the outgoing interface. |
475 | * Otherwise, we perform the source address selection as usual. | | 475 | * Otherwise, we perform the source address selection as usual. |
476 | */ | | 476 | */ |
477 | s = pserialize_read_enter(); | | 477 | s = pserialize_read_enter(); |
478 | if (hsrc && in6ifa_ifpwithaddr(ifp, hsrc)) { | | 478 | if (hsrc && in6ifa_ifpwithaddr(ifp, hsrc)) { |
479 | pserialize_read_exit(s); | | 479 | pserialize_read_exit(s); |
480 | src = hsrc; | | 480 | src = hsrc; |
481 | } else { | | 481 | } else { |
482 | int error; | | 482 | int error; |
483 | struct sockaddr_in6 dst_sa; | | 483 | struct sockaddr_in6 dst_sa; |
484 | | | 484 | |
485 | pserialize_read_exit(s); | | 485 | pserialize_read_exit(s); |
486 | | | 486 | |
487 | sockaddr_in6_init(&dst_sa, &ip6->ip6_dst, 0, 0, 0); | | 487 | sockaddr_in6_init(&dst_sa, &ip6->ip6_dst, 0, 0, 0); |
488 | | | 488 | |
489 | error = in6_selectsrc(&dst_sa, NULL, | | 489 | error = in6_selectsrc(&dst_sa, NULL, |
490 | NULL, &ro, NULL, NULL, NULL, &src_in); | | 490 | NULL, &ro, NULL, NULL, NULL, &src_in); |
491 | if (error != 0) { | | 491 | if (error != 0) { |
492 | char ip6buf[INET6_ADDRSTRLEN]; | | 492 | char ip6buf[INET6_ADDRSTRLEN]; |
493 | nd6log(LOG_DEBUG, "source can't be " | | 493 | nd6log(LOG_DEBUG, "source can't be " |
494 | "determined: dst=%s, error=%d\n", | | 494 | "determined: dst=%s, error=%d\n", |
495 | IN6_PRINT(ip6buf, &dst_sa.sin6_addr), | | 495 | IN6_PRINT(ip6buf, &dst_sa.sin6_addr), |
496 | error); | | 496 | error); |
497 | goto bad; | | 497 | goto bad; |
498 | } | | 498 | } |
499 | src = &src_in; | | 499 | src = &src_in; |
500 | } | | 500 | } |
501 | } else { | | 501 | } else { |
502 | /* | | 502 | /* |
503 | * Source address for DAD packet must always be IPv6 | | 503 | * Source address for DAD packet must always be IPv6 |
504 | * unspecified address. (0::0) | | 504 | * unspecified address. (0::0) |
505 | * We actually don't have to 0-clear the address (we did it | | 505 | * We actually don't have to 0-clear the address (we did it |
506 | * above), but we do so here explicitly to make the intention | | 506 | * above), but we do so here explicitly to make the intention |
507 | * clearer. | | 507 | * clearer. |
508 | */ | | 508 | */ |
509 | memset(&src_in, 0, sizeof(src_in)); | | 509 | memset(&src_in, 0, sizeof(src_in)); |
510 | src = &src_in; | | 510 | src = &src_in; |
511 | } | | 511 | } |
512 | ip6->ip6_src = *src; | | 512 | ip6->ip6_src = *src; |
513 | nd_ns = (struct nd_neighbor_solicit *)(ip6 + 1); | | 513 | nd_ns = (struct nd_neighbor_solicit *)(ip6 + 1); |
514 | nd_ns->nd_ns_type = ND_NEIGHBOR_SOLICIT; | | 514 | nd_ns->nd_ns_type = ND_NEIGHBOR_SOLICIT; |
515 | nd_ns->nd_ns_code = 0; | | 515 | nd_ns->nd_ns_code = 0; |
516 | nd_ns->nd_ns_reserved = 0; | | 516 | nd_ns->nd_ns_reserved = 0; |
517 | nd_ns->nd_ns_target = *taddr6; | | 517 | nd_ns->nd_ns_target = *taddr6; |
518 | in6_clearscope(&nd_ns->nd_ns_target); /* XXX */ | | 518 | in6_clearscope(&nd_ns->nd_ns_target); /* XXX */ |
519 | | | 519 | |
520 | /* | | 520 | /* |
521 | * Add source link-layer address option. | | 521 | * Add source link-layer address option. |
522 | * | | 522 | * |
523 | * spec implementation | | 523 | * spec implementation |
524 | * --- --- | | 524 | * --- --- |
525 | * DAD packet MUST NOT do not add the option | | 525 | * DAD packet MUST NOT do not add the option |
526 | * there's no link layer address: | | 526 | * there's no link layer address: |
527 | * impossible do not add the option | | 527 | * impossible do not add the option |
528 | * there's link layer address: | | 528 | * there's link layer address: |
529 | * Multicast NS MUST add one add the option | | 529 | * Multicast NS MUST add one add the option |
530 | * Unicast NS SHOULD add one add the option | | 530 | * Unicast NS SHOULD add one add the option |
531 | */ | | 531 | */ |
532 | if (nonce == NULL && (mac = nd6_ifptomac(ifp))) { | | 532 | if (nonce == NULL && (mac = nd6_ifptomac(ifp))) { |
533 | int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen; | | 533 | int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen; |
534 | struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_ns + 1); | | 534 | struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_ns + 1); |
535 | /* 8 byte alignments... */ | | 535 | /* 8 byte alignments... */ |
536 | optlen = (optlen + 7) & ~7; | | 536 | optlen = (optlen + 7) & ~7; |
537 | | | 537 | |
538 | m->m_pkthdr.len += optlen; | | 538 | m->m_pkthdr.len += optlen; |
539 | m->m_len += optlen; | | 539 | m->m_len += optlen; |
540 | icmp6len += optlen; | | 540 | icmp6len += optlen; |
541 | memset((void *)nd_opt, 0, optlen); | | 541 | memset((void *)nd_opt, 0, optlen); |
542 | nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; | | 542 | nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; |
543 | nd_opt->nd_opt_len = optlen >> 3; | | 543 | nd_opt->nd_opt_len = optlen >> 3; |
544 | memcpy((void *)(nd_opt + 1), mac, ifp->if_addrlen); | | 544 | memcpy((void *)(nd_opt + 1), mac, ifp->if_addrlen); |
545 | } | | 545 | } |
546 | | | 546 | |
547 | /* Add a nonce option (RFC 3971) to detect looped back NS messages. | | 547 | /* Add a nonce option (RFC 3971) to detect looped back NS messages. |
548 | * This behavior is documented in RFC 7527. */ | | 548 | * This behavior is documented in RFC 7527. */ |
549 | if (nonce != NULL) { | | 549 | if (nonce != NULL) { |
550 | int optlen = sizeof(struct nd_opt_hdr) + ND_OPT_NONCE_LEN; | | 550 | int optlen = sizeof(struct nd_opt_hdr) + ND_OPT_NONCE_LEN; |
551 | struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_ns + 1); | | 551 | struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_ns + 1); |
552 | | | 552 | |
553 | /* 8-byte alignment is required. */ | | 553 | /* 8-byte alignment is required. */ |
554 | optlen = (optlen + 7) & ~7; | | 554 | optlen = (optlen + 7) & ~7; |
555 | m->m_pkthdr.len += optlen; | | 555 | m->m_pkthdr.len += optlen; |
556 | m->m_len += optlen; | | 556 | m->m_len += optlen; |
557 | icmp6len += optlen; | | 557 | icmp6len += optlen; |
558 | memset(nd_opt, 0, optlen); | | 558 | memset(nd_opt, 0, optlen); |
559 | nd_opt->nd_opt_type = ND_OPT_NONCE; | | 559 | nd_opt->nd_opt_type = ND_OPT_NONCE; |
560 | nd_opt->nd_opt_len = optlen >> 3; | | 560 | nd_opt->nd_opt_len = optlen >> 3; |
561 | memcpy(nd_opt + 1, nonce, ND_OPT_NONCE_LEN); | | 561 | memcpy(nd_opt + 1, nonce, ND_OPT_NONCE_LEN); |
562 | } | | 562 | } |
563 | | | 563 | |
564 | ip6->ip6_plen = htons((u_int16_t)icmp6len); | | 564 | ip6->ip6_plen = htons((u_int16_t)icmp6len); |
565 | nd_ns->nd_ns_cksum = 0; | | 565 | nd_ns->nd_ns_cksum = 0; |
566 | nd_ns->nd_ns_cksum = | | 566 | nd_ns->nd_ns_cksum = |
567 | in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len); | | 567 | in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len); |
568 | | | 568 | |
569 | ip6_output(m, NULL, &ro, nonce != NULL ? IPV6_UNSPECSRC : 0, | | 569 | ip6_output(m, NULL, &ro, nonce != NULL ? IPV6_UNSPECSRC : 0, |
570 | &im6o, NULL, NULL); | | 570 | &im6o, NULL, NULL); |
571 | icmp6_ifstat_inc(ifp, ifs6_out_msg); | | 571 | icmp6_ifstat_inc(ifp, ifs6_out_msg); |
572 | icmp6_ifstat_inc(ifp, ifs6_out_neighborsolicit); | | 572 | icmp6_ifstat_inc(ifp, ifs6_out_neighborsolicit); |
573 | ICMP6_STATINC(ICMP6_STAT_OUTHIST + ND_NEIGHBOR_SOLICIT); | | 573 | ICMP6_STATINC(ICMP6_STAT_OUTHIST + ND_NEIGHBOR_SOLICIT); |
574 | | | 574 | |
575 | rtcache_free(&ro); | | 575 | rtcache_free(&ro); |
576 | return; | | 576 | return; |
577 | | | 577 | |
578 | bad: | | 578 | bad: |
579 | rtcache_free(&ro); | | 579 | rtcache_free(&ro); |
580 | m_freem(m); | | 580 | m_freem(m); |
581 | return; | | 581 | return; |
582 | } | | 582 | } |
583 | | | 583 | |
584 | /* | | 584 | /* |
585 | * Neighbor advertisement input handling. | | 585 | * Neighbor advertisement input handling. |
586 | * | | 586 | * |
587 | * Based on RFC 2461 | | 587 | * Based on RFC 2461 |
588 | * Based on RFC 2462 (duplicate address detection) | | 588 | * Based on RFC 2462 (duplicate address detection) |
589 | * | | 589 | * |
590 | * the following items are not implemented yet: | | 590 | * the following items are not implemented yet: |
591 | * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD) | | 591 | * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD) |
592 | * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD) | | 592 | * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD) |
593 | */ | | 593 | */ |
594 | void | | 594 | void |
595 | nd6_na_input(struct mbuf *m, int off, int icmp6len) | | 595 | nd6_na_input(struct mbuf *m, int off, int icmp6len) |
596 | { | | 596 | { |
597 | struct ifnet *ifp; | | 597 | struct ifnet *ifp; |
598 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); | | 598 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); |
599 | struct nd_neighbor_advert *nd_na; | | 599 | struct nd_neighbor_advert *nd_na; |
600 | struct in6_addr saddr6 = ip6->ip6_src; | | 600 | struct in6_addr saddr6 = ip6->ip6_src; |
601 | struct in6_addr daddr6 = ip6->ip6_dst; | | 601 | struct in6_addr daddr6 = ip6->ip6_dst; |
602 | struct in6_addr taddr6; | | 602 | struct in6_addr taddr6; |
603 | int flags; | | 603 | int flags; |
604 | int is_router; | | 604 | int is_router; |
605 | int is_solicited; | | 605 | int is_solicited; |
606 | int is_override; | | 606 | int is_override; |
607 | int rt_cmd; | | 607 | int rt_cmd; |
608 | char *lladdr = NULL; | | 608 | char *lladdr = NULL; |
609 | int lladdrlen = 0; | | 609 | int lladdrlen = 0; |
610 | struct ifaddr *ifa; | | 610 | struct ifaddr *ifa; |
611 | struct llentry *ln = NULL; | | 611 | struct llentry *ln = NULL; |
612 | union nd_opts ndopts; | | 612 | union nd_opts ndopts; |
613 | struct sockaddr_in6 ssin6; | | 613 | struct sockaddr_in6 ssin6; |
614 | bool checklink = false; | | 614 | bool checklink = false; |
615 | struct psref psref; | | 615 | struct psref psref; |
616 | struct psref psref_ia; | | 616 | struct psref psref_ia; |
617 | char ip6buf[INET6_ADDRSTRLEN], ip6buf2[INET6_ADDRSTRLEN]; | | 617 | char ip6buf[INET6_ADDRSTRLEN], ip6buf2[INET6_ADDRSTRLEN]; |
618 | | | 618 | |
619 | ifp = m_get_rcvif_psref(m, &psref); | | 619 | ifp = m_get_rcvif_psref(m, &psref); |
620 | if (ifp == NULL) | | 620 | if (ifp == NULL) |
621 | goto freeit; | | 621 | goto freeit; |
622 | | | 622 | |
623 | if (ip6->ip6_hlim != 255) { | | 623 | if (ip6->ip6_hlim != 255) { |
624 | nd6log(LOG_ERR, | | 624 | nd6log(LOG_ERR, |
625 | "invalid hlim (%d) from %s to %s on %s\n", | | 625 | "invalid hlim (%d) from %s to %s on %s\n", |
626 | ip6->ip6_hlim, IN6_PRINT(ip6buf, &ip6->ip6_src), | | 626 | ip6->ip6_hlim, IN6_PRINT(ip6buf, &ip6->ip6_src), |
627 | IN6_PRINT(ip6buf2, &ip6->ip6_dst), if_name(ifp)); | | 627 | IN6_PRINT(ip6buf2, &ip6->ip6_dst), if_name(ifp)); |
628 | goto bad; | | 628 | goto bad; |
629 | } | | 629 | } |
630 | | | 630 | |
631 | IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m, off, icmp6len); | | 631 | IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m, off, icmp6len); |
632 | if (nd_na == NULL) { | | 632 | if (nd_na == NULL) { |
633 | m_put_rcvif_psref(ifp, &psref); | | 633 | m_put_rcvif_psref(ifp, &psref); |
634 | ICMP6_STATINC(ICMP6_STAT_TOOSHORT); | | 634 | ICMP6_STATINC(ICMP6_STAT_TOOSHORT); |
635 | return; | | 635 | return; |
636 | } | | 636 | } |
637 | | | 637 | |
638 | flags = nd_na->nd_na_flags_reserved; | | 638 | flags = nd_na->nd_na_flags_reserved; |
639 | is_router = ((flags & ND_NA_FLAG_ROUTER) != 0); | | 639 | is_router = ((flags & ND_NA_FLAG_ROUTER) != 0); |
640 | is_solicited = ((flags & ND_NA_FLAG_SOLICITED) != 0); | | 640 | is_solicited = ((flags & ND_NA_FLAG_SOLICITED) != 0); |
641 | is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0); | | 641 | is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0); |
642 | | | 642 | |
643 | taddr6 = nd_na->nd_na_target; | | 643 | taddr6 = nd_na->nd_na_target; |
644 | if (in6_setscope(&taddr6, ifp, NULL)) { | | 644 | if (in6_setscope(&taddr6, ifp, NULL)) { |
645 | goto bad; | | 645 | goto bad; |
646 | } | | 646 | } |
647 | | | 647 | |
648 | if (IN6_IS_ADDR_MULTICAST(&taddr6)) { | | 648 | if (IN6_IS_ADDR_MULTICAST(&taddr6)) { |
649 | nd6log(LOG_ERR, "invalid target address %s\n", | | 649 | nd6log(LOG_ERR, "invalid target address %s\n", |
650 | IN6_PRINT(ip6buf, &taddr6)); | | 650 | IN6_PRINT(ip6buf, &taddr6)); |
651 | goto bad; | | 651 | goto bad; |
652 | } | | 652 | } |
653 | if (is_solicited && IN6_IS_ADDR_MULTICAST(&daddr6)) { | | 653 | if (is_solicited && IN6_IS_ADDR_MULTICAST(&daddr6)) { |
654 | nd6log(LOG_ERR, "a solicited adv is multicasted\n"); | | 654 | nd6log(LOG_ERR, "a solicited adv is multicasted\n"); |
655 | goto bad; | | 655 | goto bad; |
656 | } | | 656 | } |
657 | | | 657 | |
658 | icmp6len -= sizeof(*nd_na); | | 658 | icmp6len -= sizeof(*nd_na); |
659 | nd6_option_init(nd_na + 1, icmp6len, &ndopts); | | 659 | nd6_option_init(nd_na + 1, icmp6len, &ndopts); |
660 | if (nd6_options(&ndopts) < 0) { | | 660 | if (nd6_options(&ndopts) < 0) { |
661 | nd6log(LOG_INFO, "invalid ND option, ignored\n"); | | 661 | nd6log(LOG_INFO, "invalid ND option, ignored\n"); |
662 | /* nd6_options have incremented stats */ | | 662 | /* nd6_options have incremented stats */ |
663 | goto freeit; | | 663 | goto freeit; |
664 | } | | 664 | } |
665 | | | 665 | |
666 | if (ndopts.nd_opts_tgt_lladdr != NULL) { | | 666 | if (ndopts.nd_opts_tgt_lladdr != NULL) { |
667 | struct ifnet *ifp_ll; | | 667 | struct ifnet *ifp_ll; |
668 | struct psref psref_ll; | | 668 | struct psref psref_ll; |
669 | | | 669 | |
670 | lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1); | | 670 | lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1); |
671 | lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3; | | 671 | lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3; |
672 | | | 672 | |
673 | if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { | | 673 | if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { |
674 | nd6log(LOG_INFO, "lladdrlen mismatch for %s " | | 674 | nd6log(LOG_INFO, "lladdrlen mismatch for %s " |
675 | "(if %d, NA packet %d)\n", IN6_PRINT(ip6buf, &taddr6), | | 675 | "(if %d, NA packet %d)\n", IN6_PRINT(ip6buf, &taddr6), |
676 | ifp->if_addrlen, lladdrlen - 2); | | 676 | ifp->if_addrlen, lladdrlen - 2); |
677 | goto bad; | | 677 | goto bad; |
678 | } | | 678 | } |
679 | | | 679 | |
680 | ifp_ll = if_get_bylla(lladdr, ifp->if_addrlen, &psref_ll); | | 680 | ifp_ll = if_get_bylla(lladdr, ifp->if_addrlen, &psref_ll); |
681 | if (ifp_ll != NULL) { | | 681 | if (ifp_ll != NULL) { |
682 | /* it's from me, ignore it. */ | | 682 | /* it's from me, ignore it. */ |
683 | if_put(ifp_ll, &psref_ll); | | 683 | if_put(ifp_ll, &psref_ll); |
684 | goto freeit; | | 684 | goto freeit; |
685 | } | | 685 | } |
686 | } | | 686 | } |
687 | | | 687 | |
688 | ifa = (struct ifaddr *)in6ifa_ifpwithaddr_psref(ifp, &taddr6, &psref_ia); | | 688 | ifa = (struct ifaddr *)in6ifa_ifpwithaddr_psref(ifp, &taddr6, &psref_ia); |
689 | | | 689 | |
690 | /* | | 690 | /* |
691 | * Target address matches one of my interface address. | | 691 | * Target address matches one of my interface address. |
692 | * | | 692 | * |
693 | * If my address is tentative, this means that there's somebody | | 693 | * If my address is tentative, this means that there's somebody |
694 | * already using the same address as mine. This indicates DAD failure. | | 694 | * already using the same address as mine. This indicates DAD failure. |
695 | * This is defined in RFC 2462. | | 695 | * This is defined in RFC 2462. |
696 | * | | 696 | * |
697 | * Otherwise, process as defined in RFC 2461. | | 697 | * Otherwise, process as defined in RFC 2461. |
698 | */ | | 698 | */ |
699 | if (ifa) { | | 699 | if (ifa) { |
700 | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE) { | | 700 | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE) { |
701 | struct sockaddr_dl sdl, *sdlp; | | 701 | struct sockaddr_dl sdl, *sdlp; |
702 | | | 702 | |
703 | if (lladdr != NULL) | | 703 | if (lladdr != NULL) |
704 | sdlp = sockaddr_dl_init(&sdl, sizeof(sdl), | | 704 | sdlp = sockaddr_dl_init(&sdl, sizeof(sdl), |
705 | ifp->if_index, ifp->if_type, | | 705 | ifp->if_index, ifp->if_type, |
706 | NULL, 0, lladdr, lladdrlen); | | 706 | NULL, 0, lladdr, lladdrlen); |
707 | else | | 707 | else |
708 | sdlp = NULL; | | 708 | sdlp = NULL; |
709 | nd6_dad_input(ifa, NULL, sdlp); | | 709 | nd6_dad_input(ifa, NULL, sdlp); |
710 | } else | | 710 | } else |
711 | log(LOG_ERR, | | 711 | log(LOG_ERR, |
712 | "nd6_na_input: duplicate IP6 address %s\n", | | 712 | "nd6_na_input: duplicate IP6 address %s\n", |
713 | IN6_PRINT(ip6buf, &taddr6)); | | 713 | IN6_PRINT(ip6buf, &taddr6)); |
714 | ifa_release(ifa, &psref_ia); | | 714 | ifa_release(ifa, &psref_ia); |
715 | ifa = NULL; | | 715 | ifa = NULL; |
716 | goto freeit; | | 716 | goto freeit; |
717 | } | | 717 | } |
718 | | | 718 | |
719 | /* | | 719 | /* |
720 | * Make sure the source address is from a neighbor's address. | | 720 | * Make sure the source address is from a neighbor's address. |
721 | */ | | 721 | */ |
722 | sockaddr_in6_init(&ssin6, &saddr6, 0, 0, 0); | | 722 | sockaddr_in6_init(&ssin6, &saddr6, 0, 0, 0); |
723 | if (nd6_is_addr_neighbor(&ssin6, ifp) == 0) { | | 723 | if (nd6_is_addr_neighbor(&ssin6, ifp) == 0) { |
724 | nd6log(LOG_INFO, "ND packet from non-neighbor %s on %s\n", | | 724 | nd6log(LOG_INFO, "ND packet from non-neighbor %s on %s\n", |
725 | IN6_PRINT(ip6buf, &saddr6), if_name(ifp)); | | 725 | IN6_PRINT(ip6buf, &saddr6), if_name(ifp)); |
726 | goto bad; | | 726 | goto bad; |
727 | } | | 727 | } |
728 | | | 728 | |
729 | /* | | 729 | /* |
730 | * If no neighbor cache entry is found, NA SHOULD silently be | | 730 | * If no neighbor cache entry is found, NA SHOULD silently be |
731 | * discarded. | | 731 | * discarded. |
732 | */ | | 732 | */ |
733 | ln = nd6_lookup(&taddr6, ifp, true); | | 733 | ln = nd6_lookup(&taddr6, ifp, true); |
734 | if (ln == NULL) | | 734 | if (ln == NULL) |
735 | goto freeit; | | 735 | goto freeit; |
736 | | | 736 | |
737 | rt_cmd = 0; | | 737 | rt_cmd = 0; |
738 | if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { | | 738 | if (ln->ln_state <= ND6_LLINFO_INCOMPLETE) { |
739 | /* | | 739 | /* |
740 | * If the link-layer has address, and no lladdr option came, | | 740 | * If the link-layer has address, and no lladdr option came, |
741 | * discard the packet. | | 741 | * discard the packet. |
742 | */ | | 742 | */ |
743 | if (ifp->if_addrlen && !lladdr) | | 743 | if (ifp->if_addrlen && !lladdr) |
744 | goto freeit; | | 744 | goto freeit; |
745 | | | 745 | |
746 | /* | | 746 | /* |
747 | * Record link-layer address, and update the state. | | 747 | * Record link-layer address, and update the state. |
748 | */ | | 748 | */ |
749 | memcpy(&ln->ll_addr, lladdr, ifp->if_addrlen); | | 749 | memcpy(&ln->ll_addr, lladdr, ifp->if_addrlen); |
750 | ln->la_flags |= LLE_VALID; | | 750 | ln->la_flags |= LLE_VALID; |
751 | rt_cmd = RTM_ADD; | | 751 | rt_cmd = RTM_ADD; |
752 | if (is_solicited) { | | 752 | if (is_solicited) { |
753 | ln->ln_state = ND6_LLINFO_REACHABLE; | | 753 | ln->ln_state = ND6_LLINFO_REACHABLE; |
754 | ln->ln_byhint = 0; | | 754 | ln->ln_byhint = 0; |
755 | if (!ND6_LLINFO_PERMANENT(ln)) { | | 755 | if (!ND6_LLINFO_PERMANENT(ln)) { |
756 | nd6_llinfo_settimer(ln, | | 756 | nd6_llinfo_settimer(ln, |
757 | ND_IFINFO(ln->lle_tbl->llt_ifp)->reachable * hz); | | 757 | ND_IFINFO(ln->lle_tbl->llt_ifp)->reachable * hz); |
758 | } | | 758 | } |
759 | } else { | | 759 | } else { |
760 | ln->ln_state = ND6_LLINFO_STALE; | | 760 | ln->ln_state = ND6_LLINFO_STALE; |
761 | nd6_llinfo_settimer(ln, nd6_gctimer * hz); | | 761 | nd6_llinfo_settimer(ln, nd6_gctimer * hz); |
762 | } | | 762 | } |
763 | if ((ln->ln_router = is_router) != 0) { | | 763 | if ((ln->ln_router = is_router) != 0) { |
764 | /* | | 764 | /* |
765 | * This means a router's state has changed from | | 765 | * This means a router's state has changed from |
766 | * non-reachable to probably reachable, and might | | 766 | * non-reachable to probably reachable, and might |
767 | * affect the status of associated prefixes.. | | 767 | * affect the status of associated prefixes.. |
768 | */ | | 768 | */ |
769 | checklink = true; | | 769 | checklink = true; |
770 | } | | 770 | } |
771 | } else { | | 771 | } else { |
772 | bool llchange; | | 772 | bool llchange; |
773 | | | 773 | |
774 | /* | | 774 | /* |
775 | * Check if the link-layer address has changed or not. | | 775 | * Check if the link-layer address has changed or not. |
776 | */ | | 776 | */ |
777 | if (lladdr == NULL) | | 777 | if (lladdr == NULL) |
778 | llchange = false; | | 778 | llchange = false; |
779 | else { | | 779 | else { |
780 | if (ln->la_flags & LLE_VALID) { | | 780 | if (ln->la_flags & LLE_VALID) { |
781 | if (memcmp(lladdr, &ln->ll_addr, ifp->if_addrlen)) | | 781 | if (memcmp(lladdr, &ln->ll_addr, ifp->if_addrlen)) |
782 | llchange = true; | | 782 | llchange = true; |
783 | else | | 783 | else |
784 | llchange = false; | | 784 | llchange = false; |
785 | } else | | 785 | } else |
786 | llchange = true; | | 786 | llchange = true; |
787 | } | | 787 | } |
788 | if (llchange) | | 788 | if (llchange) |
789 | rt_cmd = RTM_CHANGE; | | 789 | rt_cmd = RTM_CHANGE; |
790 | | | 790 | |
791 | /* | | 791 | /* |
792 | * This is VERY complex. Look at it with care. | | 792 | * This is VERY complex. Look at it with care. |
793 | * | | 793 | * |
794 | * override solicit lladdr llchange action | | 794 | * override solicit lladdr llchange action |
795 | * (L: record lladdr) | | 795 | * (L: record lladdr) |
796 | * | | 796 | * |
797 | * 0 0 n -- (2c) | | 797 | * 0 0 n -- (2c) |
798 | * 0 0 y n (2b) L | | 798 | * 0 0 y n (2b) L |
799 | * 0 0 y y (1) REACHABLE->STALE | | 799 | * 0 0 y y (1) REACHABLE->STALE |
800 | * 0 1 n -- (2c) *->REACHABLE | | 800 | * 0 1 n -- (2c) *->REACHABLE |
801 | * 0 1 y n (2b) L *->REACHABLE | | 801 | * 0 1 y n (2b) L *->REACHABLE |
802 | * 0 1 y y (1) REACHABLE->STALE | | 802 | * 0 1 y y (1) REACHABLE->STALE |
803 | * 1 0 n -- (2a) | | 803 | * 1 0 n -- (2a) |
804 | * 1 0 y n (2a) L | | 804 | * 1 0 y n (2a) L |
805 | * 1 0 y y (2a) L *->STALE | | 805 | * 1 0 y y (2a) L *->STALE |
806 | * 1 1 n -- (2a) *->REACHABLE | | 806 | * 1 1 n -- (2a) *->REACHABLE |
807 | * 1 1 y n (2a) L *->REACHABLE | | 807 | * 1 1 y n (2a) L *->REACHABLE |
808 | * 1 1 y y (2a) L *->REACHABLE | | 808 | * 1 1 y y (2a) L *->REACHABLE |
809 | */ | | 809 | */ |
810 | if (!is_override && lladdr != NULL && llchange) { /* (1) */ | | 810 | if (!is_override && lladdr != NULL && llchange) { /* (1) */ |
811 | /* | | 811 | /* |
812 | * If state is REACHABLE, make it STALE. | | 812 | * If state is REACHABLE, make it STALE. |
813 | * no other updates should be done. | | 813 | * no other updates should be done. |
814 | */ | | 814 | */ |
815 | if (ln->ln_state == ND6_LLINFO_REACHABLE) { | | 815 | if (ln->ln_state == ND6_LLINFO_REACHABLE) { |
816 | ln->ln_state = ND6_LLINFO_STALE; | | 816 | ln->ln_state = ND6_LLINFO_STALE; |
817 | nd6_llinfo_settimer(ln, nd6_gctimer * hz); | | 817 | nd6_llinfo_settimer(ln, nd6_gctimer * hz); |
818 | } | | 818 | } |
819 | goto freeit; | | 819 | goto freeit; |
820 | } else if (is_override /* (2a) */ | | 820 | } else if (is_override /* (2a) */ |
821 | || (!is_override && lladdr != NULL && !llchange) /* (2b) */ | | 821 | || (!is_override && lladdr != NULL && !llchange) /* (2b) */ |
822 | || lladdr == NULL) { /* (2c) */ | | 822 | || lladdr == NULL) { /* (2c) */ |
823 | /* | | 823 | /* |
824 | * Update link-local address, if any. | | 824 | * Update link-local address, if any. |
825 | */ | | 825 | */ |
826 | if (lladdr != NULL) { | | 826 | if (lladdr != NULL) { |
827 | memcpy(&ln->ll_addr, lladdr, ifp->if_addrlen); | | 827 | memcpy(&ln->ll_addr, lladdr, ifp->if_addrlen); |
828 | ln->la_flags |= LLE_VALID; | | 828 | ln->la_flags |= LLE_VALID; |
829 | } | | 829 | } |
830 | | | 830 | |
831 | /* | | 831 | /* |
832 | * If solicited, make the state REACHABLE. | | 832 | * If solicited, make the state REACHABLE. |
833 | * If not solicited and the link-layer address was | | 833 | * If not solicited and the link-layer address was |
834 | * changed, make it STALE. | | 834 | * changed, make it STALE. |
835 | */ | | 835 | */ |
836 | if (is_solicited) { | | 836 | if (is_solicited) { |
837 | ln->ln_state = ND6_LLINFO_REACHABLE; | | 837 | ln->ln_state = ND6_LLINFO_REACHABLE; |
838 | ln->ln_byhint = 0; | | 838 | ln->ln_byhint = 0; |
839 | if (!ND6_LLINFO_PERMANENT(ln)) { | | 839 | if (!ND6_LLINFO_PERMANENT(ln)) { |
840 | nd6_llinfo_settimer(ln, | | 840 | nd6_llinfo_settimer(ln, |
841 | ND_IFINFO(ifp)->reachable * hz); | | 841 | ND_IFINFO(ifp)->reachable * hz); |
842 | } | | 842 | } |
843 | } else { | | 843 | } else { |
844 | if (lladdr && llchange) { | | 844 | if (lladdr && llchange) { |
845 | ln->ln_state = ND6_LLINFO_STALE; | | 845 | ln->ln_state = ND6_LLINFO_STALE; |
846 | nd6_llinfo_settimer(ln, | | 846 | nd6_llinfo_settimer(ln, |
847 | nd6_gctimer * hz); | | 847 | nd6_gctimer * hz); |
848 | } | | 848 | } |
849 | } | | 849 | } |
850 | } | | 850 | } |
851 | | | 851 | |
852 | if (ln->ln_router && !is_router) { | | 852 | if (ln->ln_router && !is_router) { |
853 | /* | | 853 | /* |
854 | * The peer dropped the router flag. | | 854 | * The peer dropped the router flag. |
855 | * Remove the sender from the Default Router List and | | 855 | * Remove the sender from the Default Router List and |
856 | * update the Destination Cache entries. | | 856 | * update the Destination Cache entries. |
857 | */ | | 857 | */ |
858 | const struct in6_addr *in6 = &ln->r_l3addr.addr6; | | 858 | const struct in6_addr *in6 = &ln->r_l3addr.addr6; |
859 | struct nd_defrouter *dr; | | 859 | struct nd_defrouter *dr; |
860 | | | 860 | |
861 | ND6_WLOCK(); | | 861 | ND6_WLOCK(); |
862 | dr = nd6_defrouter_lookup(in6, ln->lle_tbl->llt_ifp); | | 862 | dr = nd6_defrouter_lookup(in6, ln->lle_tbl->llt_ifp); |
863 | if (dr) | | 863 | if (dr) |
864 | nd6_defrtrlist_del(dr, NULL); | | 864 | nd6_defrtrlist_del(dr, NULL); |
865 | else if (!ip6_forwarding) { | | 865 | else if (!ip6_forwarding) { |
866 | /* | | 866 | /* |
867 | * Even if the neighbor is not in the default | | 867 | * Even if the neighbor is not in the default |
868 | * router list, the neighbor may be used | | 868 | * router list, the neighbor may be used |
869 | * as a next hop for some destinations | | 869 | * as a next hop for some destinations |
870 | * (e.g. redirect case). So we must | | 870 | * (e.g. redirect case). So we must |
871 | * call nd6_rt_flush explicitly. | | 871 | * call nd6_rt_flush explicitly. |
872 | */ | | 872 | */ |
873 | nd6_rt_flush(&ip6->ip6_src, ln->lle_tbl->llt_ifp); | | 873 | nd6_rt_flush(&ip6->ip6_src, ln->lle_tbl->llt_ifp); |
874 | } | | 874 | } |
875 | ND6_UNLOCK(); | | 875 | ND6_UNLOCK(); |
876 | } | | 876 | } |
877 | ln->ln_router = is_router; | | 877 | ln->ln_router = is_router; |
878 | } | | 878 | } |
879 | /* | | 879 | /* |
880 | * XXX: does this matter? | | 880 | * XXX: does this matter? |
881 | * rt->rt_flags &= ~RTF_REJECT; | | 881 | * rt->rt_flags &= ~RTF_REJECT; |
882 | */ | | 882 | */ |
883 | ln->ln_asked = 0; | | 883 | ln->ln_asked = 0; |
884 | nd6_llinfo_release_pkts(ln, ifp); | | 884 | nd6_llinfo_release_pkts(ln, ifp); |
885 | | | 885 | |
886 | if (rt_cmd != 0) { | | 886 | if (rt_cmd != 0) { |
887 | struct sockaddr_in6 sin6; | | 887 | struct sockaddr_in6 sin6; |
888 | | | 888 | |
889 | sockaddr_in6_init(&sin6, &ln->r_l3addr.addr6, 0, 0, 0); | | 889 | sockaddr_in6_init(&sin6, &ln->r_l3addr.addr6, 0, 0, 0); |
890 | rt_clonedmsg(rt_cmd, sin6tosa(&sin6), | | 890 | rt_clonedmsg(rt_cmd, sin6tosa(&sin6), |
891 | (char *)&ln->ll_addr, ln->lle_tbl->llt_ifp); | | 891 | (char *)&ln->ll_addr, ln->lle_tbl->llt_ifp); |
892 | } | | 892 | } |
893 | | | 893 | |
894 | freeit: | | 894 | freeit: |
895 | if (ln != NULL) | | 895 | if (ln != NULL) |
896 | LLE_WUNLOCK(ln); | | 896 | LLE_WUNLOCK(ln); |
897 | | | 897 | |
898 | if (checklink) { | | 898 | if (checklink) { |
899 | ND6_WLOCK(); | | 899 | ND6_WLOCK(); |
900 | nd6_pfxlist_onlink_check(); | | 900 | nd6_pfxlist_onlink_check(); |
901 | ND6_UNLOCK(); | | 901 | ND6_UNLOCK(); |
902 | } | | 902 | } |
903 | | | 903 | |
904 | m_put_rcvif_psref(ifp, &psref); | | 904 | m_put_rcvif_psref(ifp, &psref); |
905 | m_freem(m); | | 905 | m_freem(m); |
906 | return; | | 906 | return; |
907 | | | 907 | |
908 | bad: | | 908 | bad: |
909 | if (ln != NULL) | | 909 | if (ln != NULL) |
910 | LLE_WUNLOCK(ln); | | 910 | LLE_WUNLOCK(ln); |
911 | | | 911 | |
912 | ICMP6_STATINC(ICMP6_STAT_BADNA); | | 912 | ICMP6_STATINC(ICMP6_STAT_BADNA); |
913 | m_put_rcvif_psref(ifp, &psref); | | 913 | m_put_rcvif_psref(ifp, &psref); |
914 | m_freem(m); | | 914 | m_freem(m); |
915 | } | | 915 | } |
916 | | | 916 | |
917 | /* | | 917 | /* |
918 | * Neighbor advertisement output handling. | | 918 | * Neighbor advertisement output handling. |
919 | * | | 919 | * |
920 | * Based on RFC 2461 | | 920 | * Based on RFC 2461 |
921 | * | | 921 | * |
922 | * the following items are not implemented yet: | | 922 | * the following items are not implemented yet: |
923 | * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD) | | 923 | * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD) |
924 | * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD) | | 924 | * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD) |
925 | */ | | 925 | */ |
926 | void | | 926 | void |
927 | nd6_na_output( | | 927 | nd6_na_output( |
928 | struct ifnet *ifp, | | 928 | struct ifnet *ifp, |
929 | const struct in6_addr *daddr6_0, | | 929 | const struct in6_addr *daddr6_0, |
930 | const struct in6_addr *taddr6, | | 930 | const struct in6_addr *taddr6, |
931 | u_long flags, | | 931 | u_long flags, |
932 | int tlladdr, /* 1 if include target link-layer address */ | | 932 | int tlladdr, /* 1 if include target link-layer address */ |
933 | const struct sockaddr *sdl0) /* sockaddr_dl (= proxy NA) or NULL */ | | 933 | const struct sockaddr *sdl0) /* sockaddr_dl (= proxy NA) or NULL */ |
934 | { | | 934 | { |
935 | struct mbuf *m; | | 935 | struct mbuf *m; |
936 | struct ip6_hdr *ip6; | | 936 | struct ip6_hdr *ip6; |
937 | struct nd_neighbor_advert *nd_na; | | 937 | struct nd_neighbor_advert *nd_na; |
938 | struct ip6_moptions im6o; | | 938 | struct ip6_moptions im6o; |
939 | struct sockaddr *dst; | | 939 | struct sockaddr *dst; |
940 | union { | | 940 | union { |
941 | struct sockaddr dst; | | 941 | struct sockaddr dst; |
942 | struct sockaddr_in6 dst6; | | 942 | struct sockaddr_in6 dst6; |
943 | } u; | | 943 | } u; |
944 | struct in6_addr daddr6; | | 944 | struct in6_addr daddr6; |
945 | int icmp6len, maxlen, error; | | 945 | int icmp6len, maxlen, error; |
946 | const void *mac; | | 946 | const void *mac; |
947 | struct route ro; | | 947 | struct route ro; |
948 | | | 948 | |
949 | mac = NULL; | | 949 | mac = NULL; |
950 | memset(&ro, 0, sizeof(ro)); | | 950 | memset(&ro, 0, sizeof(ro)); |
951 | | | 951 | |
952 | daddr6 = *daddr6_0; /* make a local copy for modification */ | | 952 | daddr6 = *daddr6_0; /* make a local copy for modification */ |
953 | | | 953 | |
954 | /* estimate the size of message */ | | 954 | /* estimate the size of message */ |
955 | maxlen = sizeof(*ip6) + sizeof(*nd_na); | | 955 | maxlen = sizeof(*ip6) + sizeof(*nd_na); |
956 | maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7; | | 956 | maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7; |
957 | KASSERTMSG(max_linkhdr + maxlen <= MCLBYTES, | | 957 | KASSERTMSG(max_linkhdr + maxlen <= MCLBYTES, |
958 | "max_linkhdr + maxlen > MCLBYTES (%d + %d > %d)", | | 958 | "max_linkhdr + maxlen > MCLBYTES (%d + %d > %d)", |
959 | max_linkhdr, maxlen, MCLBYTES); | | 959 | max_linkhdr, maxlen, MCLBYTES); |
960 | | | 960 | |
961 | MGETHDR(m, M_DONTWAIT, MT_DATA); | | 961 | MGETHDR(m, M_DONTWAIT, MT_DATA); |
962 | if (m && max_linkhdr + maxlen >= MHLEN) { | | 962 | if (m && max_linkhdr + maxlen >= MHLEN) { |
963 | MCLGET(m, M_DONTWAIT); | | 963 | MCLGET(m, M_DONTWAIT); |
964 | if ((m->m_flags & M_EXT) == 0) { | | 964 | if ((m->m_flags & M_EXT) == 0) { |
965 | m_free(m); | | 965 | m_free(m); |
966 | m = NULL; | | 966 | m = NULL; |
967 | } | | 967 | } |
968 | } | | 968 | } |
969 | if (m == NULL) | | 969 | if (m == NULL) |
970 | return; | | 970 | return; |
971 | m_reset_rcvif(m); | | 971 | m_reset_rcvif(m); |
972 | | | 972 | |
973 | if (IN6_IS_ADDR_MULTICAST(&daddr6)) { | | 973 | if (IN6_IS_ADDR_MULTICAST(&daddr6)) { |
974 | m->m_flags |= M_MCAST; | | 974 | m->m_flags |= M_MCAST; |
975 | im6o.im6o_multicast_if_index = if_get_index(ifp); | | 975 | im6o.im6o_multicast_if_index = if_get_index(ifp); |
976 | im6o.im6o_multicast_hlim = 255; | | 976 | im6o.im6o_multicast_hlim = 255; |
977 | im6o.im6o_multicast_loop = 0; | | 977 | im6o.im6o_multicast_loop = 0; |
978 | } | | 978 | } |
979 | | | 979 | |
980 | icmp6len = sizeof(*nd_na); | | 980 | icmp6len = sizeof(*nd_na); |
981 | m->m_pkthdr.len = m->m_len = sizeof(struct ip6_hdr) + icmp6len; | | 981 | m->m_pkthdr.len = m->m_len = sizeof(struct ip6_hdr) + icmp6len; |
982 | m->m_data += max_linkhdr; /* or m_align() equivalent? */ | | 982 | m->m_data += max_linkhdr; /* or m_align() equivalent? */ |
983 | | | 983 | |
984 | /* fill neighbor advertisement packet */ | | 984 | /* fill neighbor advertisement packet */ |
985 | ip6 = mtod(m, struct ip6_hdr *); | | 985 | ip6 = mtod(m, struct ip6_hdr *); |
986 | ip6->ip6_flow = 0; | | 986 | ip6->ip6_flow = 0; |
987 | ip6->ip6_vfc &= ~IPV6_VERSION_MASK; | | 987 | ip6->ip6_vfc &= ~IPV6_VERSION_MASK; |
988 | ip6->ip6_vfc |= IPV6_VERSION; | | 988 | ip6->ip6_vfc |= IPV6_VERSION; |
989 | ip6->ip6_nxt = IPPROTO_ICMPV6; | | 989 | ip6->ip6_nxt = IPPROTO_ICMPV6; |
990 | ip6->ip6_hlim = 255; | | 990 | ip6->ip6_hlim = 255; |
991 | if (IN6_IS_ADDR_UNSPECIFIED(&daddr6)) { | | 991 | if (IN6_IS_ADDR_UNSPECIFIED(&daddr6)) { |
992 | /* reply to DAD */ | | 992 | /* reply to DAD */ |
993 | daddr6.s6_addr16[0] = IPV6_ADDR_INT16_MLL; | | 993 | daddr6.s6_addr16[0] = IPV6_ADDR_INT16_MLL; |
994 | daddr6.s6_addr16[1] = 0; | | 994 | daddr6.s6_addr16[1] = 0; |
995 | daddr6.s6_addr32[1] = 0; | | 995 | daddr6.s6_addr32[1] = 0; |
996 | daddr6.s6_addr32[2] = 0; | | 996 | daddr6.s6_addr32[2] = 0; |
997 | daddr6.s6_addr32[3] = IPV6_ADDR_INT32_ONE; | | 997 | daddr6.s6_addr32[3] = IPV6_ADDR_INT32_ONE; |
998 | if (in6_setscope(&daddr6, ifp, NULL)) | | 998 | if (in6_setscope(&daddr6, ifp, NULL)) |
999 | goto bad; | | 999 | goto bad; |
1000 | | | 1000 | |
1001 | flags &= ~ND_NA_FLAG_SOLICITED; | | 1001 | flags &= ~ND_NA_FLAG_SOLICITED; |
1002 | } | | 1002 | } |
1003 | ip6->ip6_dst = daddr6; | | 1003 | ip6->ip6_dst = daddr6; |
1004 | sockaddr_in6_init(&u.dst6, &daddr6, 0, 0, 0); | | 1004 | sockaddr_in6_init(&u.dst6, &daddr6, 0, 0, 0); |
1005 | dst = &u.dst; | | 1005 | dst = &u.dst; |
1006 | if (rtcache_setdst(&ro, dst) != 0) | | 1006 | if (rtcache_setdst(&ro, dst) != 0) |
1007 | goto bad; | | 1007 | goto bad; |
1008 | | | 1008 | |
1009 | /* | | 1009 | /* |
1010 | * Select a source whose scope is the same as that of the dest. | | 1010 | * Select a source whose scope is the same as that of the dest. |
1011 | */ | | 1011 | */ |
1012 | error = in6_selectsrc(satosin6(dst), NULL, NULL, &ro, NULL, NULL, NULL, | | 1012 | error = in6_selectsrc(satosin6(dst), NULL, NULL, &ro, NULL, NULL, NULL, |
1013 | &ip6->ip6_src); | | 1013 | &ip6->ip6_src); |
1014 | if (error != 0) { | | 1014 | if (error != 0) { |
1015 | char ip6buf[INET6_ADDRSTRLEN]; | | 1015 | char ip6buf[INET6_ADDRSTRLEN]; |
1016 | nd6log(LOG_DEBUG, "source can't be " | | 1016 | nd6log(LOG_DEBUG, "source can't be " |
1017 | "determined: dst=%s, error=%d\n", | | 1017 | "determined: dst=%s, error=%d\n", |
1018 | IN6_PRINT(ip6buf, &satocsin6(dst)->sin6_addr), error); | | 1018 | IN6_PRINT(ip6buf, &satocsin6(dst)->sin6_addr), error); |
1019 | goto bad; | | 1019 | goto bad; |
1020 | } | | 1020 | } |
1021 | nd_na = (struct nd_neighbor_advert *)(ip6 + 1); | | 1021 | nd_na = (struct nd_neighbor_advert *)(ip6 + 1); |
1022 | nd_na->nd_na_type = ND_NEIGHBOR_ADVERT; | | 1022 | nd_na->nd_na_type = ND_NEIGHBOR_ADVERT; |
1023 | nd_na->nd_na_code = 0; | | 1023 | nd_na->nd_na_code = 0; |
1024 | nd_na->nd_na_target = *taddr6; | | 1024 | nd_na->nd_na_target = *taddr6; |
1025 | in6_clearscope(&nd_na->nd_na_target); /* XXX */ | | 1025 | in6_clearscope(&nd_na->nd_na_target); /* XXX */ |
1026 | | | 1026 | |
1027 | /* | | 1027 | /* |
1028 | * "tlladdr" indicates NS's condition for adding tlladdr or not. | | 1028 | * "tlladdr" indicates NS's condition for adding tlladdr or not. |
1029 | * see nd6_ns_input() for details. | | 1029 | * see nd6_ns_input() for details. |
1030 | * Basically, if NS packet is sent to unicast/anycast addr, | | 1030 | * Basically, if NS packet is sent to unicast/anycast addr, |
1031 | * target lladdr option SHOULD NOT be included. | | 1031 | * target lladdr option SHOULD NOT be included. |
1032 | */ | | 1032 | */ |
1033 | if (tlladdr) { | | 1033 | if (tlladdr) { |
1034 | /* | | 1034 | /* |
1035 | * sdl0 != NULL indicates proxy NA. If we do proxy, use | | 1035 | * sdl0 != NULL indicates proxy NA. If we do proxy, use |
1036 | * lladdr in sdl0. If we are not proxying (sending NA for | | 1036 | * lladdr in sdl0. If we are not proxying (sending NA for |
1037 | * my address) use lladdr configured for the interface. | | 1037 | * my address) use lladdr configured for the interface. |
1038 | */ | | 1038 | */ |
1039 | if (sdl0 == NULL) | | 1039 | if (sdl0 == NULL) |
1040 | mac = nd6_ifptomac(ifp); | | 1040 | mac = nd6_ifptomac(ifp); |
1041 | else if (sdl0->sa_family == AF_LINK) { | | 1041 | else if (sdl0->sa_family == AF_LINK) { |
1042 | const struct sockaddr_dl *sdl; | | 1042 | const struct sockaddr_dl *sdl; |
1043 | sdl = satocsdl(sdl0); | | 1043 | sdl = satocsdl(sdl0); |
1044 | if (sdl->sdl_alen == ifp->if_addrlen) | | 1044 | if (sdl->sdl_alen == ifp->if_addrlen) |
1045 | mac = CLLADDR(sdl); | | 1045 | mac = CLLADDR(sdl); |
1046 | } | | 1046 | } |
1047 | } | | 1047 | } |
1048 | if (tlladdr && mac) { | | 1048 | if (tlladdr && mac) { |
1049 | int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen; | | 1049 | int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen; |
1050 | struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_na + 1); | | 1050 | struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_na + 1); |
1051 | | | 1051 | |
1052 | /* roundup to 8 bytes alignment! */ | | 1052 | /* roundup to 8 bytes alignment! */ |
1053 | optlen = (optlen + 7) & ~7; | | 1053 | optlen = (optlen + 7) & ~7; |
1054 | | | 1054 | |
1055 | m->m_pkthdr.len += optlen; | | 1055 | m->m_pkthdr.len += optlen; |
1056 | m->m_len += optlen; | | 1056 | m->m_len += optlen; |
1057 | icmp6len += optlen; | | 1057 | icmp6len += optlen; |
1058 | memset((void *)nd_opt, 0, optlen); | | 1058 | memset((void *)nd_opt, 0, optlen); |
1059 | nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; | | 1059 | nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; |
1060 | nd_opt->nd_opt_len = optlen >> 3; | | 1060 | nd_opt->nd_opt_len = optlen >> 3; |
1061 | memcpy((void *)(nd_opt + 1), mac, ifp->if_addrlen); | | 1061 | memcpy((void *)(nd_opt + 1), mac, ifp->if_addrlen); |
1062 | } else | | 1062 | } else |
1063 | flags &= ~ND_NA_FLAG_OVERRIDE; | | 1063 | flags &= ~ND_NA_FLAG_OVERRIDE; |
1064 | | | 1064 | |
1065 | ip6->ip6_plen = htons((u_int16_t)icmp6len); | | 1065 | ip6->ip6_plen = htons((u_int16_t)icmp6len); |
1066 | nd_na->nd_na_flags_reserved = flags; | | 1066 | nd_na->nd_na_flags_reserved = flags; |
1067 | nd_na->nd_na_cksum = 0; | | 1067 | nd_na->nd_na_cksum = 0; |
1068 | nd_na->nd_na_cksum = | | 1068 | nd_na->nd_na_cksum = |
1069 | in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len); | | 1069 | in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len); |
1070 | | | 1070 | |
1071 | ip6_output(m, NULL, NULL, 0, &im6o, NULL, NULL); | | 1071 | ip6_output(m, NULL, NULL, 0, &im6o, NULL, NULL); |
1072 | | | 1072 | |
1073 | icmp6_ifstat_inc(ifp, ifs6_out_msg); | | 1073 | icmp6_ifstat_inc(ifp, ifs6_out_msg); |
1074 | icmp6_ifstat_inc(ifp, ifs6_out_neighboradvert); | | 1074 | icmp6_ifstat_inc(ifp, ifs6_out_neighboradvert); |
1075 | ICMP6_STATINC(ICMP6_STAT_OUTHIST + ND_NEIGHBOR_ADVERT); | | 1075 | ICMP6_STATINC(ICMP6_STAT_OUTHIST + ND_NEIGHBOR_ADVERT); |
1076 | | | 1076 | |
1077 | rtcache_free(&ro); | | 1077 | rtcache_free(&ro); |
1078 | return; | | 1078 | return; |
1079 | | | 1079 | |
1080 | bad: | | 1080 | bad: |
1081 | rtcache_free(&ro); | | 1081 | rtcache_free(&ro); |
1082 | m_freem(m); | | 1082 | m_freem(m); |
1083 | return; | | 1083 | return; |
1084 | } | | 1084 | } |
1085 | | | 1085 | |
1086 | const void * | | 1086 | const void * |
1087 | nd6_ifptomac(const struct ifnet *ifp) | | 1087 | nd6_ifptomac(const struct ifnet *ifp) |
1088 | { | | 1088 | { |
1089 | switch (ifp->if_type) { | | 1089 | switch (ifp->if_type) { |
1090 | case IFT_ARCNET: | | 1090 | case IFT_ARCNET: |
1091 | case IFT_ETHER: | | 1091 | case IFT_ETHER: |
1092 | case IFT_FDDI: | | 1092 | case IFT_FDDI: |
1093 | case IFT_IEEE1394: | | 1093 | case IFT_IEEE1394: |
1094 | case IFT_PROPVIRTUAL: | | 1094 | case IFT_PROPVIRTUAL: |
1095 | case IFT_CARP: | | 1095 | case IFT_CARP: |
1096 | case IFT_L2VLAN: | | 1096 | case IFT_L2VLAN: |
1097 | case IFT_IEEE80211: | | 1097 | case IFT_IEEE80211: |
1098 | return CLLADDR(ifp->if_sadl); | | 1098 | return CLLADDR(ifp->if_sadl); |
1099 | default: | | 1099 | default: |
1100 | return NULL; | | 1100 | return NULL; |
1101 | } | | 1101 | } |
1102 | } | | 1102 | } |
1103 | | | 1103 | |
1104 | TAILQ_HEAD(dadq_head, dadq); | | 1104 | TAILQ_HEAD(dadq_head, dadq); |
1105 | struct dadq { | | 1105 | struct dadq { |
1106 | TAILQ_ENTRY(dadq) dad_list; | | 1106 | TAILQ_ENTRY(dadq) dad_list; |
1107 | struct ifaddr *dad_ifa; | | 1107 | struct ifaddr *dad_ifa; |
1108 | int dad_count; /* max NS to send */ | | 1108 | int dad_count; /* max NS to send */ |
1109 | int dad_ns_tcount; /* # of trials to send NS */ | | 1109 | int dad_ns_tcount; /* # of trials to send NS */ |
1110 | int dad_ns_ocount; /* NS sent so far */ | | 1110 | int dad_ns_ocount; /* NS sent so far */ |
1111 | int dad_ns_lcount; /* looped back NS */ | | 1111 | int dad_ns_lcount; /* looped back NS */ |
1112 | struct callout dad_timer_ch; | | 1112 | struct callout dad_timer_ch; |
1113 | #define ND_OPT_NONCE_STORE 3 /* dad_count should not exceed this */ | | 1113 | #define ND_OPT_NONCE_STORE 3 /* dad_count should not exceed this */ |
1114 | /* | | 1114 | /* |
1115 | * The default ip6_dad_count is 1 as specified by RFC 4862 and | | 1115 | * The default ip6_dad_count is 1 as specified by RFC 4862 and |
1116 | * practically must users won't exceed this. | | 1116 | * practically must users won't exceed this. |
1117 | * A storage of 3 is defaulted to here, in-case the administrator wants | | 1117 | * A storage of 3 is defaulted to here, in-case the administrator wants |
1118 | * to match the equivalent behaviour in our ARP implementation. | | 1118 | * to match the equivalent behaviour in our ARP implementation. |
1119 | * This constraint could be removed by sending the on wire nonce as | | 1119 | * This constraint could be removed by sending the on wire nonce as |
1120 | * hmac(key, dad_ns_ocount), but that would increase the nonce size | | 1120 | * hmac(key, dad_ns_ocount), but that would increase the nonce size |
1121 | * sent on the wire. | | 1121 | * sent on the wire. |
1122 | */ | | 1122 | */ |
1123 | uint8_t dad_nonce[ND_OPT_NONCE_STORE][ND_OPT_NONCE_LEN]; | | 1123 | uint8_t dad_nonce[ND_OPT_NONCE_STORE][ND_OPT_NONCE_LEN]; |
1124 | }; | | 1124 | }; |
1125 | | | 1125 | |
1126 | static struct dadq_head dadq; | | 1126 | static struct dadq_head dadq; |
1127 | static kmutex_t nd6_dad_lock; | | 1127 | static kmutex_t nd6_dad_lock; |
1128 | | | 1128 | |
1129 | void | | 1129 | void |
1130 | nd6_nbr_init(void) | | 1130 | nd6_nbr_init(void) |
1131 | { | | 1131 | { |
1132 | | | 1132 | |
1133 | TAILQ_INIT(&dadq); | | 1133 | TAILQ_INIT(&dadq); |
1134 | mutex_init(&nd6_dad_lock, MUTEX_DEFAULT, IPL_NONE); | | 1134 | mutex_init(&nd6_dad_lock, MUTEX_DEFAULT, IPL_NONE); |
1135 | } | | 1135 | } |
1136 | | | 1136 | |
1137 | static struct dadq * | | 1137 | static struct dadq * |
1138 | nd6_dad_find(struct ifaddr *ifa, struct nd_opt_nonce *nonce, bool *found_nonce) | | 1138 | nd6_dad_find(struct ifaddr *ifa, struct nd_opt_nonce *nonce, bool *found_nonce) |
1139 | { | | 1139 | { |
1140 | struct in6_addr *myaddr6, *dadaddr6; | | 1140 | struct in6_addr *myaddr6, *dadaddr6; |
1141 | bool match_ifa; | | 1141 | bool match_ifa; |
1142 | struct dadq *dp; | | 1142 | struct dadq *dp; |
1143 | int i, nonce_max; | | 1143 | int i, nonce_max; |
1144 | | | 1144 | |
1145 | KASSERT(mutex_owned(&nd6_dad_lock)); | | 1145 | KASSERT(mutex_owned(&nd6_dad_lock)); |
1146 | KASSERT(ifa != NULL); | | 1146 | KASSERT(ifa != NULL); |
1147 | | | 1147 | |
1148 | myaddr6 = IFA_IN6(ifa); | | 1148 | myaddr6 = IFA_IN6(ifa); |
1149 | if (nonce != NULL && | | 1149 | if (nonce != NULL && |
1150 | nonce->nd_opt_nonce_len != (ND_OPT_NONCE_LEN + 2) / 8) | | 1150 | nonce->nd_opt_nonce_len != (ND_OPT_NONCE_LEN + 2) / 8) |
1151 | nonce = NULL; | | 1151 | nonce = NULL; |
1152 | match_ifa = nonce == NULL || found_nonce == NULL || *found_nonce == false; | | 1152 | match_ifa = nonce == NULL || found_nonce == NULL || *found_nonce == false; |
1153 | if (found_nonce != NULL) | | 1153 | if (found_nonce != NULL) |
1154 | *found_nonce = false; | | 1154 | *found_nonce = false; |
1155 | | | 1155 | |
1156 | TAILQ_FOREACH(dp, &dadq, dad_list) { | | 1156 | TAILQ_FOREACH(dp, &dadq, dad_list) { |
1157 | if (match_ifa) { | | 1157 | if (match_ifa) { |
1158 | if (dp->dad_ifa != ifa) | | 1158 | if (dp->dad_ifa != ifa) |
1159 | continue; | | 1159 | continue; |
1160 | } else { | | 1160 | } else { |
1161 | dadaddr6 = IFA_IN6(dp->dad_ifa); | | 1161 | dadaddr6 = IFA_IN6(dp->dad_ifa); |
1162 | if (!IN6_ARE_ADDR_EQUAL(myaddr6, dadaddr6)) | | 1162 | if (!IN6_ARE_ADDR_EQUAL(myaddr6, dadaddr6)) |
1163 | continue; | | 1163 | continue; |
1164 | } | | 1164 | } |
1165 | | | 1165 | |
1166 | if (nonce == NULL) | | 1166 | if (nonce == NULL) |
1167 | break; | | 1167 | break; |
1168 | | | 1168 | |
1169 | nonce_max = MIN(dp->dad_ns_ocount, ND_OPT_NONCE_STORE); | | 1169 | nonce_max = MIN(dp->dad_ns_ocount, ND_OPT_NONCE_STORE); |
1170 | for (i = 0; i < nonce_max; i++) { | | 1170 | for (i = 0; i < nonce_max; i++) { |
1171 | if (memcmp(nonce->nd_opt_nonce, | | 1171 | if (memcmp(nonce->nd_opt_nonce, |
1172 | dp->dad_nonce[i], | | 1172 | dp->dad_nonce[i], |
1173 | ND_OPT_NONCE_LEN) == 0) | | 1173 | ND_OPT_NONCE_LEN) == 0) |
1174 | break; | | 1174 | break; |
1175 | } | | 1175 | } |
1176 | if (i < nonce_max) { | | 1176 | if (i < nonce_max) { |
1177 | char ip6buf[INET6_ADDRSTRLEN]; | | 1177 | char ip6buf[INET6_ADDRSTRLEN]; |
1178 | | | 1178 | |
1179 | *found_nonce = true; | | 1179 | *found_nonce = true; |
1180 | log(LOG_DEBUG, | | 1180 | log(LOG_DEBUG, |
1181 | "%s: detected a looped back NS message for %s\n", | | 1181 | "%s: detected a looped back NS message for %s\n", |
1182 | ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???", | | 1182 | ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???", |
1183 | IN6_PRINT(ip6buf, myaddr6)); | | 1183 | IN6_PRINT(ip6buf, myaddr6)); |
1184 | dp->dad_ns_lcount++; | | 1184 | dp->dad_ns_lcount++; |
1185 | continue; | | 1185 | continue; |
1186 | } | | 1186 | } |
1187 | | | 1187 | |
1188 | break; | | 1188 | break; |
1189 | } | | 1189 | } |
1190 | return dp; | | 1190 | return dp; |
1191 | } | | 1191 | } |
1192 | | | 1192 | |
1193 | static bool | | 1193 | static bool |
1194 | nd6_dad_ownnonce(struct ifaddr *ifa, struct nd_opt_nonce *nonce) | | 1194 | nd6_dad_ownnonce(struct ifaddr *ifa, struct nd_opt_nonce *nonce) |
1195 | { | | 1195 | { |
1196 | bool found_nonce = true; | | 1196 | bool found_nonce = true; |
1197 | | | 1197 | |
1198 | mutex_enter(&nd6_dad_lock); | | 1198 | mutex_enter(&nd6_dad_lock); |
1199 | nd6_dad_find(ifa, nonce, &found_nonce); | | 1199 | nd6_dad_find(ifa, nonce, &found_nonce); |
1200 | mutex_exit(&nd6_dad_lock); | | 1200 | mutex_exit(&nd6_dad_lock); |
1201 | | | 1201 | |
1202 | return found_nonce; | | 1202 | return found_nonce; |
1203 | } | | 1203 | } |
1204 | | | 1204 | |
1205 | static void | | 1205 | static void |
1206 | nd6_dad_starttimer(struct dadq *dp, int ticks) | | 1206 | nd6_dad_starttimer(struct dadq *dp, int ticks) |
1207 | { | | 1207 | { |
1208 | | | 1208 | |
1209 | callout_reset(&dp->dad_timer_ch, ticks, | | 1209 | callout_reset(&dp->dad_timer_ch, ticks, |
1210 | (void (*)(void *))nd6_dad_timer, dp); | | 1210 | (void (*)(void *))nd6_dad_timer, dp); |
1211 | } | | 1211 | } |
1212 | | | 1212 | |
1213 | static void | | 1213 | static void |
1214 | nd6_dad_stoptimer(struct dadq *dp) | | 1214 | nd6_dad_stoptimer(struct dadq *dp) |
1215 | { | | 1215 | { |
1216 | | | 1216 | |
1217 | KASSERT(mutex_owned(&nd6_dad_lock)); | | 1217 | KASSERT(mutex_owned(&nd6_dad_lock)); |
1218 | | | 1218 | |
1219 | TAILQ_REMOVE(&dadq, dp, dad_list); | | 1219 | TAILQ_REMOVE(&dadq, dp, dad_list); |
1220 | /* Tell the timer that dp is being destroyed. */ | | 1220 | /* Tell the timer that dp is being destroyed. */ |
1221 | dp->dad_ifa = NULL; | | 1221 | dp->dad_ifa = NULL; |
1222 | callout_halt(&dp->dad_timer_ch, &nd6_dad_lock); | | 1222 | callout_halt(&dp->dad_timer_ch, &nd6_dad_lock); |
1223 | } | | 1223 | } |
1224 | | | 1224 | |
1225 | static void | | 1225 | static void |
1226 | nd6_dad_destroytimer(struct dadq *dp) | | 1226 | nd6_dad_destroytimer(struct dadq *dp) |
1227 | { | | 1227 | { |
1228 | | | 1228 | |
1229 | KASSERT(dp->dad_ifa == NULL); | | 1229 | KASSERT(dp->dad_ifa == NULL); |
1230 | callout_destroy(&dp->dad_timer_ch); | | 1230 | callout_destroy(&dp->dad_timer_ch); |
1231 | kmem_intr_free(dp, sizeof(*dp)); | | 1231 | kmem_intr_free(dp, sizeof(*dp)); |
1232 | } | | 1232 | } |
1233 | | | 1233 | |
1234 | /* | | 1234 | /* |
1235 | * Start Duplicate Address Detection (DAD) for specified interface address. | | 1235 | * Start Duplicate Address Detection (DAD) for specified interface address. |
1236 | * | | 1236 | * |
1237 | * Note that callout is used when xtick > 0 and not when xtick == 0. | | 1237 | * Note that callout is used when xtick > 0 and not when xtick == 0. |
1238 | * | | 1238 | * |
1239 | * xtick: minimum delay ticks for IFF_UP event | | 1239 | * xtick: minimum delay ticks for IFF_UP event |
1240 | */ | | 1240 | */ |
1241 | void | | 1241 | void |
1242 | nd6_dad_start(struct ifaddr *ifa, int xtick) | | 1242 | nd6_dad_start(struct ifaddr *ifa, int xtick) |
1243 | { | | 1243 | { |
1244 | struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; | | 1244 | struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; |
1245 | struct dadq *dp; | | 1245 | struct dadq *dp; |
1246 | char ip6buf[INET6_ADDRSTRLEN]; | | 1246 | char ip6buf[INET6_ADDRSTRLEN]; |
1247 | | | 1247 | |
1248 | /* | | 1248 | /* |
1249 | * If we don't need DAD, don't do it. | | 1249 | * If we don't need DAD, don't do it. |
1250 | * There are several cases: | | 1250 | * There are several cases: |
1251 | * - DAD is disabled | | 1251 | * - DAD is disabled |
1252 | * - the interface address is anycast | | 1252 | * - the interface address is anycast |
1253 | */ | | 1253 | */ |
1254 | if (!(ia->ia6_flags & IN6_IFF_TENTATIVE)) { | | 1254 | if (!(ia->ia6_flags & IN6_IFF_TENTATIVE)) { |
1255 | log(LOG_DEBUG, | | 1255 | log(LOG_DEBUG, |
1256 | "nd6_dad_start: called with non-tentative address " | | 1256 | "nd6_dad_start: called with non-tentative address " |
1257 | "%s(%s)\n", | | 1257 | "%s(%s)\n", |
1258 | IN6_PRINT(ip6buf, &ia->ia_addr.sin6_addr), | | 1258 | IN6_PRINT(ip6buf, &ia->ia_addr.sin6_addr), |
1259 | ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); | | 1259 | ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); |
1260 | return; | | 1260 | return; |
1261 | } | | 1261 | } |
1262 | if (ia->ia6_flags & IN6_IFF_ANYCAST || !ip6_dad_enabled()) { | | 1262 | if (ia->ia6_flags & IN6_IFF_ANYCAST || !ip6_dad_enabled()) { |
1263 | ia->ia6_flags &= ~IN6_IFF_TENTATIVE; | | 1263 | ia->ia6_flags &= ~IN6_IFF_TENTATIVE; |
1264 | rt_addrmsg(RTM_NEWADDR, ifa); | | 1264 | rt_addrmsg(RTM_NEWADDR, ifa); |
1265 | return; | | 1265 | return; |
1266 | } | | 1266 | } |
1267 | KASSERT(ifa->ifa_ifp != NULL); | | 1267 | KASSERT(ifa->ifa_ifp != NULL); |
1268 | if (!(ifa->ifa_ifp->if_flags & IFF_UP)) | | 1268 | if (!(ifa->ifa_ifp->if_flags & IFF_UP)) |
1269 | return; | | 1269 | return; |
1270 | | | 1270 | |
1271 | dp = kmem_intr_alloc(sizeof(*dp), KM_NOSLEEP); | | 1271 | dp = kmem_intr_alloc(sizeof(*dp), KM_NOSLEEP); |
1272 | | | 1272 | |
1273 | mutex_enter(&nd6_dad_lock); | | 1273 | mutex_enter(&nd6_dad_lock); |
1274 | if (nd6_dad_find(ifa, NULL, NULL) != NULL) { | | 1274 | if (nd6_dad_find(ifa, NULL, NULL) != NULL) { |
1275 | mutex_exit(&nd6_dad_lock); | | 1275 | mutex_exit(&nd6_dad_lock); |
1276 | /* DAD already in progress */ | | 1276 | /* DAD already in progress */ |
1277 | if (dp != NULL) | | 1277 | if (dp != NULL) |
1278 | kmem_intr_free(dp, sizeof(*dp)); | | 1278 | kmem_intr_free(dp, sizeof(*dp)); |
1279 | return; | | 1279 | return; |
1280 | } | | 1280 | } |
1281 | | | 1281 | |
1282 | if (dp == NULL) { | | 1282 | if (dp == NULL) { |
1283 | mutex_exit(&nd6_dad_lock); | | 1283 | mutex_exit(&nd6_dad_lock); |
1284 | log(LOG_ERR, "nd6_dad_start: memory allocation failed for " | | 1284 | log(LOG_ERR, "nd6_dad_start: memory allocation failed for " |
1285 | "%s(%s)\n", | | 1285 | "%s(%s)\n", |
1286 | IN6_PRINT(ip6buf, &ia->ia_addr.sin6_addr), | | 1286 | IN6_PRINT(ip6buf, &ia->ia_addr.sin6_addr), |
1287 | ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); | | 1287 | ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); |
1288 | return; | | 1288 | return; |
1289 | } | | 1289 | } |
1290 | | | 1290 | |
1291 | /* | | 1291 | /* |
1292 | * Send NS packet for DAD, ip6_dad_count times. | | 1292 | * Send NS packet for DAD, ip6_dad_count times. |
1293 | * Note that we must delay the first transmission, if this is the | | 1293 | * Note that we must delay the first transmission, if this is the |
1294 | * first packet to be sent from the interface after interface | | 1294 | * first packet to be sent from the interface after interface |
1295 | * (re)initialization. | | 1295 | * (re)initialization. |
1296 | */ | | 1296 | */ |
1297 | callout_init(&dp->dad_timer_ch, CALLOUT_MPSAFE); | | 1297 | callout_init(&dp->dad_timer_ch, CALLOUT_MPSAFE); |
1298 | dp->dad_ifa = ifa; | | 1298 | dp->dad_ifa = ifa; |
1299 | ifaref(ifa); /* just for safety */ | | 1299 | ifaref(ifa); /* just for safety */ |
1300 | dp->dad_count = ip6_dad_count; | | 1300 | dp->dad_count = ip6_dad_count; |
1301 | dp->dad_ns_ocount = dp->dad_ns_tcount = 0; | | 1301 | dp->dad_ns_ocount = dp->dad_ns_tcount = 0; |
1302 | dp->dad_ns_lcount = 0; | | 1302 | dp->dad_ns_lcount = 0; |
1303 | TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list); | | 1303 | TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list); |
1304 | | | 1304 | |
1305 | nd6log(LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp), | | 1305 | nd6log(LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp), |
1306 | IN6_PRINT(ip6buf, &ia->ia_addr.sin6_addr)); | | 1306 | IN6_PRINT(ip6buf, &ia->ia_addr.sin6_addr)); |
1307 | | | 1307 | |
1308 | if (xtick == 0) { | | 1308 | if (xtick == 0) { |
1309 | nd6_dad_ns_output(dp, ifa); | | 1309 | nd6_dad_ns_output(dp, ifa); |
1310 | nd6_dad_starttimer(dp, | | 1310 | nd6_dad_starttimer(dp, |
1311 | (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000); | | 1311 | (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000); |
1312 | } else | | 1312 | } else |
1313 | nd6_dad_starttimer(dp, xtick); | | 1313 | nd6_dad_starttimer(dp, xtick); |
1314 | mutex_exit(&nd6_dad_lock); | | 1314 | mutex_exit(&nd6_dad_lock); |
1315 | } | | 1315 | } |
1316 | | | 1316 | |
1317 | /* | | 1317 | /* |
1318 | * terminate DAD unconditionally. used for address removals. | | 1318 | * terminate DAD unconditionally. used for address removals. |
1319 | */ | | 1319 | */ |
1320 | void | | 1320 | void |
1321 | nd6_dad_stop(struct ifaddr *ifa) | | 1321 | nd6_dad_stop(struct ifaddr *ifa) |
1322 | { | | 1322 | { |
1323 | struct dadq *dp; | | 1323 | struct dadq *dp; |
1324 | | | 1324 | |
1325 | mutex_enter(&nd6_dad_lock); | | 1325 | mutex_enter(&nd6_dad_lock); |
1326 | dp = nd6_dad_find(ifa, NULL, NULL); | | 1326 | dp = nd6_dad_find(ifa, NULL, NULL); |
1327 | if (dp == NULL) { | | 1327 | if (dp == NULL) { |
1328 | mutex_exit(&nd6_dad_lock); | | 1328 | mutex_exit(&nd6_dad_lock); |
1329 | /* DAD wasn't started yet */ | | 1329 | /* DAD wasn't started yet */ |
1330 | return; | | 1330 | return; |
1331 | } | | 1331 | } |
1332 | | | 1332 | |
1333 | /* Prevent the timer from running anymore. */ | | 1333 | /* Prevent the timer from running anymore. */ |
1334 | nd6_dad_stoptimer(dp); | | 1334 | nd6_dad_stoptimer(dp); |
1335 | | | 1335 | |
1336 | mutex_exit(&nd6_dad_lock); | | 1336 | mutex_exit(&nd6_dad_lock); |
1337 | | | 1337 | |
1338 | nd6_dad_destroytimer(dp); | | 1338 | nd6_dad_destroytimer(dp); |
1339 | ifafree(ifa); | | 1339 | ifafree(ifa); |
1340 | } | | 1340 | } |
1341 | | | 1341 | |
1342 | static void | | 1342 | static void |
1343 | nd6_dad_timer(struct dadq *dp) | | 1343 | nd6_dad_timer(struct dadq *dp) |
1344 | { | | 1344 | { |
1345 | struct ifaddr *ifa; | | 1345 | struct ifaddr *ifa; |
1346 | struct in6_ifaddr *ia; | | 1346 | struct in6_ifaddr *ia; |
1347 | char ip6buf[INET6_ADDRSTRLEN]; | | 1347 | char ip6buf[INET6_ADDRSTRLEN]; |
1348 | bool need_free = false; | | 1348 | bool need_free = false; |
1349 | | | 1349 | |
1350 | KERNEL_LOCK_UNLESS_NET_MPSAFE(); | | 1350 | KERNEL_LOCK_UNLESS_NET_MPSAFE(); |
1351 | mutex_enter(&nd6_dad_lock); | | 1351 | mutex_enter(&nd6_dad_lock); |
1352 | | | 1352 | |
1353 | ifa = dp->dad_ifa; | | 1353 | ifa = dp->dad_ifa; |
1354 | if (ifa == NULL) { | | 1354 | if (ifa == NULL) { |
1355 | /* dp is being destroyed by someone. Do nothing. */ | | 1355 | /* dp is being destroyed by someone. Do nothing. */ |
1356 | goto done; | | 1356 | goto done; |
1357 | } | | 1357 | } |
1358 | | | 1358 | |
1359 | ia = (struct in6_ifaddr *)ifa; | | 1359 | ia = (struct in6_ifaddr *)ifa; |
1360 | if (ia->ia6_flags & IN6_IFF_DUPLICATED) { | | 1360 | if (ia->ia6_flags & IN6_IFF_DUPLICATED) { |
1361 | log(LOG_ERR, "nd6_dad_timer: called with duplicate address " | | 1361 | log(LOG_ERR, "nd6_dad_timer: called with duplicate address " |
1362 | "%s(%s)\n", | | 1362 | "%s(%s)\n", |
1363 | IN6_PRINT(ip6buf, &ia->ia_addr.sin6_addr), | | 1363 | IN6_PRINT(ip6buf, &ia->ia_addr.sin6_addr), |
1364 | ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); | | 1364 | ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); |
1365 | goto done; | | 1365 | goto done; |
1366 | } | | 1366 | } |
1367 | if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0) { | | 1367 | if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0) { |
1368 | log(LOG_ERR, "nd6_dad_timer: called with non-tentative address " | | 1368 | log(LOG_ERR, "nd6_dad_timer: called with non-tentative address " |
1369 | "%s(%s)\n", | | 1369 | "%s(%s)\n", |
1370 | IN6_PRINT(ip6buf, &ia->ia_addr.sin6_addr), | | 1370 | IN6_PRINT(ip6buf, &ia->ia_addr.sin6_addr), |
1371 | ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); | | 1371 | ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); |
1372 | goto done; | | 1372 | goto done; |
1373 | } | | 1373 | } |
1374 | | | 1374 | |
1375 | /* timeouted with IFF_{RUNNING,UP} check */ | | 1375 | /* timeouted with IFF_{RUNNING,UP} check */ |
1376 | if (dp->dad_ns_tcount > dad_maxtry) { | | 1376 | if (dp->dad_ns_tcount > dad_maxtry) { |
1377 | nd6log(LOG_INFO, "%s: could not run DAD, driver problem?\n", | | 1377 | nd6log(LOG_INFO, "%s: could not run DAD, driver problem?\n", |
1378 | if_name(ifa->ifa_ifp)); | | 1378 | if_name(ifa->ifa_ifp)); |
1379 | | | 1379 | |
1380 | nd6_dad_stoptimer(dp); | | 1380 | nd6_dad_stoptimer(dp); |
1381 | need_free = true; | | 1381 | need_free = true; |
1382 | goto done; | | 1382 | goto done; |
1383 | } | | 1383 | } |
1384 | | | 1384 | |
1385 | /* Need more checks? */ | | 1385 | /* Need more checks? */ |
1386 | if (dp->dad_ns_ocount < dp->dad_count) { | | 1386 | if (dp->dad_ns_ocount < dp->dad_count) { |
1387 | /* | | 1387 | /* |
1388 | * We have more NS to go. Send NS packet for DAD. | | 1388 | * We have more NS to go. Send NS packet for DAD. |
1389 | */ | | 1389 | */ |
1390 | nd6_dad_ns_output(dp, ifa); | | 1390 | nd6_dad_ns_output(dp, ifa); |
1391 | nd6_dad_starttimer(dp, | | 1391 | nd6_dad_starttimer(dp, |
1392 | (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000); | | 1392 | (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000); |
1393 | } else { | | 1393 | } else { |
1394 | /* | | 1394 | /* |
1395 | * We are done with DAD. No NA came, no NS came. | | 1395 | * We are done with DAD. No NA came, no NS came. |
1396 | * No duplicate address found. | | 1396 | * No duplicate address found. |
1397 | */ | | 1397 | */ |
1398 | ia->ia6_flags &= ~IN6_IFF_TENTATIVE; | | 1398 | ia->ia6_flags &= ~IN6_IFF_TENTATIVE; |
1399 | rt_addrmsg(RTM_NEWADDR, ifa); | | 1399 | rt_addrmsg(RTM_NEWADDR, ifa); |
1400 | | | 1400 | |
1401 | nd6log(LOG_DEBUG, | | 1401 | nd6log(LOG_DEBUG, |
1402 | "%s: DAD complete for %s - no duplicates found\n", | | 1402 | "%s: DAD complete for %s - no duplicates found\n", |
1403 | if_name(ifa->ifa_ifp), | | 1403 | if_name(ifa->ifa_ifp), |
1404 | IN6_PRINT(ip6buf, &ia->ia_addr.sin6_addr)); | | 1404 | IN6_PRINT(ip6buf, &ia->ia_addr.sin6_addr)); |
1405 | | | 1405 | |
1406 | nd6_dad_stoptimer(dp); | | 1406 | nd6_dad_stoptimer(dp); |
1407 | need_free = true; | | 1407 | need_free = true; |
1408 | } | | 1408 | } |
1409 | done: | | 1409 | done: |
1410 | mutex_exit(&nd6_dad_lock); | | 1410 | mutex_exit(&nd6_dad_lock); |
1411 | | | 1411 | |
1412 | if (need_free) { | | 1412 | if (need_free) { |
1413 | nd6_dad_destroytimer(dp); | | 1413 | nd6_dad_destroytimer(dp); |
1414 | KASSERT(ifa != NULL); | | 1414 | KASSERT(ifa != NULL); |
1415 | ifafree(ifa); | | 1415 | ifafree(ifa); |
1416 | } | | 1416 | } |
1417 | | | 1417 | |
1418 | KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); | | 1418 | KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); |
1419 | } | | 1419 | } |
1420 | | | 1420 | |
1421 | static void | | 1421 | static void |
1422 | nd6_dad_duplicated(struct ifaddr *ifa, struct dadq *dp, | | 1422 | nd6_dad_duplicated(struct ifaddr *ifa, struct dadq *dp, |
1423 | const struct sockaddr_dl *from) | | 1423 | const struct sockaddr_dl *from) |
1424 | { | | 1424 | { |
1425 | struct in6_ifaddr *ia; | | 1425 | struct in6_ifaddr *ia; |
1426 | struct ifnet *ifp; | | 1426 | struct ifnet *ifp; |
1427 | char ip6buf[INET6_ADDRSTRLEN], llabuf[LLA_ADDRSTRLEN], *llastr; | | 1427 | char ip6buf[INET6_ADDRSTRLEN], llabuf[LLA_ADDRSTRLEN], *llastr; |
1428 | | | 1428 | |
1429 | KASSERT(mutex_owned(&nd6_dad_lock)); | | 1429 | KASSERT(mutex_owned(&nd6_dad_lock)); |
1430 | KASSERT(ifa != NULL); | | 1430 | KASSERT(ifa != NULL); |
1431 | | | 1431 | |
1432 | ifp = ifa->ifa_ifp; | | 1432 | ifp = ifa->ifa_ifp; |
1433 | ia = (struct in6_ifaddr *)ifa; | | 1433 | ia = (struct in6_ifaddr *)ifa; |
1434 | | | 1434 | |
1435 | ia->ia6_flags &= ~IN6_IFF_TENTATIVE; | | 1435 | ia->ia6_flags &= ~IN6_IFF_TENTATIVE; |
1436 | ia->ia6_flags |= IN6_IFF_DUPLICATED; | | 1436 | ia->ia6_flags |= IN6_IFF_DUPLICATED; |
1437 | | | 1437 | |
1438 | if (__predict_false(from == NULL)) | | 1438 | if (__predict_false(from == NULL)) |
1439 | llastr = NULL; | | 1439 | llastr = NULL; |
1440 | else | | 1440 | else |
1441 | llastr = lla_snprintf(llabuf, sizeof(llabuf), | | 1441 | llastr = lla_snprintf(llabuf, sizeof(llabuf), |
1442 | CLLADDR(from), from->sdl_alen); | | 1442 | CLLADDR(from), from->sdl_alen); |
1443 | | | 1443 | |
1444 | log(LOG_ERR, "%s: DAD duplicate address %s from %s\n", | | 1444 | log(LOG_ERR, "%s: DAD duplicate address %s from %s\n", |
1445 | if_name(ifp), IN6_PRINT(ip6buf, &ia->ia_addr.sin6_addr), llastr); | | 1445 | if_name(ifp), IN6_PRINT(ip6buf, &ia->ia_addr.sin6_addr), llastr); |
1446 | | | 1446 | |
1447 | /* Inform the routing socket that DAD has completed */ | | 1447 | /* Inform the routing socket that DAD has completed */ |
1448 | rt_addrmsg_src(RTM_NEWADDR, ifa, (const struct sockaddr *)from); | | 1448 | rt_addrmsg_src(RTM_NEWADDR, ifa, (const struct sockaddr *)from); |
1449 | | | 1449 | |
1450 | /* | | 1450 | /* |
1451 | * If the address is a link-local address formed from an interface | | 1451 | * If the address is a link-local address formed from an interface |
1452 | * identifier based on the hardware address which is supposed to be | | 1452 | * identifier based on the hardware address which is supposed to be |
1453 | * uniquely assigned (e.g., EUI-64 for an Ethernet interface), IP | | 1453 | * uniquely assigned (e.g., EUI-64 for an Ethernet interface), IP |
1454 | * operation on the interface SHOULD be disabled. | | 1454 | * operation on the interface SHOULD be disabled. |
1455 | * [rfc2462bis-03 Section 5.4.5] | | 1455 | * [rfc2462bis-03 Section 5.4.5] |
1456 | */ | | 1456 | */ |
1457 | if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr)) { | | 1457 | if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr)) { |
1458 | struct in6_addr in6; | | 1458 | struct in6_addr in6; |
1459 | | | 1459 | |
1460 | /* | | 1460 | /* |
1461 | * To avoid over-reaction, we only apply this logic when we are | | 1461 | * To avoid over-reaction, we only apply this logic when we are |
1462 | * very sure that hardware addresses are supposed to be unique. | | 1462 | * very sure that hardware addresses are supposed to be unique. |
1463 | */ | | 1463 | */ |
1464 | switch (ifp->if_type) { | | 1464 | switch (ifp->if_type) { |
1465 | case IFT_ETHER: | | 1465 | case IFT_ETHER: |
1466 | case IFT_FDDI: | | 1466 | case IFT_FDDI: |
1467 | case IFT_ATM: | | 1467 | case IFT_ATM: |
1468 | case IFT_IEEE1394: | | 1468 | case IFT_IEEE1394: |
1469 | case IFT_IEEE80211: | | 1469 | case IFT_IEEE80211: |
1470 | in6 = ia->ia_addr.sin6_addr; | | 1470 | in6 = ia->ia_addr.sin6_addr; |
1471 | if (in6_get_hw_ifid(ifp, &in6) == 0 && | | 1471 | if (in6_get_hw_ifid(ifp, &in6) == 0 && |
1472 | IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, &in6)) { | | 1472 | IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, &in6)) { |
1473 | ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED; | | 1473 | ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED; |
1474 | log(LOG_ERR, "%s: possible hardware address " | | 1474 | log(LOG_ERR, "%s: possible hardware address " |
1475 | "duplication detected, disable IPv6\n", | | 1475 | "duplication detected, disable IPv6\n", |
1476 | if_name(ifp)); | | 1476 | if_name(ifp)); |
1477 | } | | 1477 | } |
1478 | break; | | 1478 | break; |
1479 | } | | 1479 | } |
1480 | } | | 1480 | } |
1481 | } | | 1481 | } |
1482 | | | 1482 | |
1483 | static void | | 1483 | static void |
1484 | nd6_dad_ns_output(struct dadq *dp, struct ifaddr *ifa) | | 1484 | nd6_dad_ns_output(struct dadq *dp, struct ifaddr *ifa) |
1485 | { | | 1485 | { |
1486 | struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; | | 1486 | struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; |
1487 | struct ifnet *ifp = ifa->ifa_ifp; | | 1487 | struct ifnet *ifp = ifa->ifa_ifp; |
1488 | uint8_t *nonce; | | 1488 | uint8_t *nonce; |
1489 | | | 1489 | |
1490 | dp->dad_ns_tcount++; | | 1490 | dp->dad_ns_tcount++; |
1491 | if ((ifp->if_flags & IFF_UP) == 0) { | | 1491 | if ((ifp->if_flags & IFF_UP) == 0) { |
1492 | #if 0 | | 1492 | #if 0 |
1493 | printf("%s: interface down?\n", if_name(ifp)); | | 1493 | printf("%s: interface down?\n", if_name(ifp)); |
1494 | #endif | | 1494 | #endif |
1495 | return; | | 1495 | return; |
1496 | } | | 1496 | } |
1497 | if ((ifp->if_flags & IFF_RUNNING) == 0) { | | 1497 | if ((ifp->if_flags & IFF_RUNNING) == 0) { |
1498 | #if 0 | | 1498 | #if 0 |
1499 | printf("%s: interface not running?\n", if_name(ifp)); | | 1499 | printf("%s: interface not running?\n", if_name(ifp)); |
1500 | #endif | | 1500 | #endif |
1501 | return; | | 1501 | return; |
1502 | } | | 1502 | } |
1503 | | | 1503 | |
1504 | dp->dad_ns_tcount = 0; | | 1504 | dp->dad_ns_tcount = 0; |
1505 | nonce = dp->dad_nonce[dp->dad_ns_ocount % ND_OPT_NONCE_STORE]; | | 1505 | nonce = dp->dad_nonce[dp->dad_ns_ocount % ND_OPT_NONCE_STORE]; |
1506 | cprng_fast(nonce, ND_OPT_NONCE_LEN); | | 1506 | cprng_fast(nonce, ND_OPT_NONCE_LEN); |
1507 | dp->dad_ns_ocount++; | | 1507 | dp->dad_ns_ocount++; |
1508 | | | 1508 | |
1509 | nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL, nonce); | | 1509 | nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL, nonce); |
1510 | } | | 1510 | } |
1511 | | | 1511 | |
1512 | static void | | 1512 | static void |
1513 | nd6_dad_input(struct ifaddr *ifa, struct nd_opt_nonce *nonce, | | 1513 | nd6_dad_input(struct ifaddr *ifa, struct nd_opt_nonce *nonce, |
1514 | const struct sockaddr_dl *from) | | 1514 | const struct sockaddr_dl *from) |
1515 | { | | 1515 | { |
1516 | struct dadq *dp; | | 1516 | struct dadq *dp; |
1517 | bool found_nonce = false; | | 1517 | bool found_nonce = false; |
1518 | | | 1518 | |
1519 | KASSERT(ifa != NULL); | | 1519 | KASSERT(ifa != NULL); |
1520 | | | 1520 | |
1521 | mutex_enter(&nd6_dad_lock); | | 1521 | mutex_enter(&nd6_dad_lock); |
1522 | dp = nd6_dad_find(ifa, nonce, &found_nonce); | | 1522 | dp = nd6_dad_find(ifa, nonce, &found_nonce); |
1523 | if (!found_nonce) { | | 1523 | if (!found_nonce) { |
1524 | nd6_dad_duplicated(ifa, dp, from); | | 1524 | nd6_dad_duplicated(ifa, dp, from); |
1525 | if (dp != NULL) | | 1525 | if (dp != NULL) |
1526 | nd6_dad_stoptimer(dp); | | 1526 | nd6_dad_stoptimer(dp); |
1527 | } | | 1527 | } |
1528 | mutex_exit(&nd6_dad_lock); | | 1528 | mutex_exit(&nd6_dad_lock); |
1529 | if (dp != NULL) { | | 1529 | if (dp != NULL) { |
1530 | nd6_dad_destroytimer(dp); | | 1530 | nd6_dad_destroytimer(dp); |
1531 | ifafree(ifa); | | 1531 | ifafree(ifa); |
1532 | } | | 1532 | } |
1533 | } | | 1533 | } |