1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
2 | |
---|
3 | /*- |
---|
4 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
---|
5 | * All rights reserved. |
---|
6 | * |
---|
7 | * Redistribution and use in source and binary forms, with or without |
---|
8 | * modification, are permitted provided that the following conditions |
---|
9 | * are met: |
---|
10 | * 1. Redistributions of source code must retain the above copyright |
---|
11 | * notice, this list of conditions and the following disclaimer. |
---|
12 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
13 | * notice, this list of conditions and the following disclaimer in the |
---|
14 | * documentation and/or other materials provided with the distribution. |
---|
15 | * 3. Neither the name of the project nor the names of its contributors |
---|
16 | * may be used to endorse or promote products derived from this software |
---|
17 | * without specific prior written permission. |
---|
18 | * |
---|
19 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
---|
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
---|
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
29 | * SUCH DAMAGE. |
---|
30 | * |
---|
31 | * $KAME: ip6_input.c,v 1.259 2002/01/21 04:58:09 jinmei Exp $ |
---|
32 | */ |
---|
33 | |
---|
34 | /*- |
---|
35 | * Copyright (c) 1982, 1986, 1988, 1993 |
---|
36 | * The Regents of the University of California. All rights reserved. |
---|
37 | * |
---|
38 | * Redistribution and use in source and binary forms, with or without |
---|
39 | * modification, are permitted provided that the following conditions |
---|
40 | * are met: |
---|
41 | * 1. Redistributions of source code must retain the above copyright |
---|
42 | * notice, this list of conditions and the following disclaimer. |
---|
43 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
44 | * notice, this list of conditions and the following disclaimer in the |
---|
45 | * documentation and/or other materials provided with the distribution. |
---|
46 | * 4. Neither the name of the University nor the names of its contributors |
---|
47 | * may be used to endorse or promote products derived from this software |
---|
48 | * without specific prior written permission. |
---|
49 | * |
---|
50 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
---|
51 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
52 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
53 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
---|
54 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
55 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
56 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
57 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
58 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
59 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
60 | * SUCH DAMAGE. |
---|
61 | * |
---|
62 | * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 |
---|
63 | */ |
---|
64 | |
---|
65 | #include <sys/cdefs.h> |
---|
66 | __FBSDID("$FreeBSD$"); |
---|
67 | |
---|
68 | #include <rtems/bsd/local/opt_inet.h> |
---|
69 | #include <rtems/bsd/local/opt_inet6.h> |
---|
70 | #include <rtems/bsd/local/opt_ipfw.h> |
---|
71 | #include <rtems/bsd/local/opt_ipsec.h> |
---|
72 | #include <rtems/bsd/local/opt_route.h> |
---|
73 | |
---|
74 | #include <rtems/bsd/sys/param.h> |
---|
75 | #include <sys/systm.h> |
---|
76 | #include <sys/malloc.h> |
---|
77 | #include <sys/mbuf.h> |
---|
78 | #include <sys/proc.h> |
---|
79 | #include <sys/domain.h> |
---|
80 | #include <sys/protosw.h> |
---|
81 | #include <sys/socket.h> |
---|
82 | #include <sys/socketvar.h> |
---|
83 | #include <rtems/bsd/sys/errno.h> |
---|
84 | #include <sys/time.h> |
---|
85 | #include <sys/kernel.h> |
---|
86 | #include <sys/syslog.h> |
---|
87 | |
---|
88 | #include <net/if.h> |
---|
89 | #include <net/if_types.h> |
---|
90 | #include <net/if_dl.h> |
---|
91 | #include <net/route.h> |
---|
92 | #include <net/netisr.h> |
---|
93 | #include <net/pfil.h> |
---|
94 | #include <net/vnet.h> |
---|
95 | |
---|
96 | #include <netinet/in.h> |
---|
97 | #include <netinet/ip_var.h> |
---|
98 | #include <netinet/in_systm.h> |
---|
99 | #include <net/if_llatbl.h> |
---|
100 | #ifdef INET |
---|
101 | #include <netinet/ip.h> |
---|
102 | #include <netinet/ip_icmp.h> |
---|
103 | #endif /* INET */ |
---|
104 | #include <netinet/ip6.h> |
---|
105 | #include <netinet6/in6_var.h> |
---|
106 | #include <netinet6/ip6_var.h> |
---|
107 | #include <netinet/in_pcb.h> |
---|
108 | #include <netinet/icmp6.h> |
---|
109 | #include <netinet6/scope6_var.h> |
---|
110 | #include <netinet6/in6_ifattach.h> |
---|
111 | #include <netinet6/nd6.h> |
---|
112 | |
---|
113 | #ifdef IPSEC |
---|
114 | #include <netipsec/ipsec.h> |
---|
115 | #include <netinet6/ip6_ipsec.h> |
---|
116 | #include <netipsec/ipsec6.h> |
---|
117 | #endif /* IPSEC */ |
---|
118 | |
---|
119 | #include <netinet6/ip6protosw.h> |
---|
120 | |
---|
121 | #ifdef FLOWTABLE |
---|
122 | #include <net/flowtable.h> |
---|
123 | VNET_DECLARE(int, ip6_output_flowtable_size); |
---|
124 | #define V_ip6_output_flowtable_size VNET(ip6_output_flowtable_size) |
---|
125 | #endif |
---|
126 | |
---|
127 | extern struct domain inet6domain; |
---|
128 | |
---|
129 | u_char ip6_protox[IPPROTO_MAX]; |
---|
130 | VNET_DEFINE(struct in6_ifaddrhead, in6_ifaddrhead); |
---|
131 | |
---|
132 | static struct netisr_handler ip6_nh = { |
---|
133 | .nh_name = "ip6", |
---|
134 | .nh_handler = ip6_input, |
---|
135 | .nh_proto = NETISR_IPV6, |
---|
136 | .nh_policy = NETISR_POLICY_FLOW, |
---|
137 | }; |
---|
138 | |
---|
139 | VNET_DECLARE(struct callout, in6_tmpaddrtimer_ch); |
---|
140 | #define V_in6_tmpaddrtimer_ch VNET(in6_tmpaddrtimer_ch) |
---|
141 | |
---|
142 | VNET_DEFINE(struct pfil_head, inet6_pfil_hook); |
---|
143 | |
---|
144 | VNET_DEFINE(struct ip6stat, ip6stat); |
---|
145 | |
---|
146 | struct rwlock in6_ifaddr_lock; |
---|
147 | RW_SYSINIT(in6_ifaddr_lock, &in6_ifaddr_lock, "in6_ifaddr_lock"); |
---|
148 | |
---|
149 | static void ip6_init2(void *); |
---|
150 | static struct ip6aux *ip6_setdstifaddr(struct mbuf *, struct in6_ifaddr *); |
---|
151 | static struct ip6aux *ip6_addaux(struct mbuf *); |
---|
152 | static struct ip6aux *ip6_findaux(struct mbuf *m); |
---|
153 | static void ip6_delaux (struct mbuf *); |
---|
154 | static int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *); |
---|
155 | #ifdef PULLDOWN_TEST |
---|
156 | static struct mbuf *ip6_pullexthdr(struct mbuf *, size_t, int); |
---|
157 | #endif |
---|
158 | |
---|
159 | /* |
---|
160 | * IP6 initialization: fill in IP6 protocol switch table. |
---|
161 | * All protocols not implemented in kernel go to raw IP6 protocol handler. |
---|
162 | */ |
---|
163 | void |
---|
164 | ip6_init(void) |
---|
165 | { |
---|
166 | struct ip6protosw *pr; |
---|
167 | int i; |
---|
168 | |
---|
169 | TUNABLE_INT_FETCH("net.inet6.ip6.auto_linklocal", |
---|
170 | &V_ip6_auto_linklocal); |
---|
171 | TUNABLE_INT_FETCH("net.inet6.ip6.accept_rtadv", &V_ip6_accept_rtadv); |
---|
172 | TUNABLE_INT_FETCH("net.inet6.ip6.no_radr", &V_ip6_no_radr); |
---|
173 | |
---|
174 | TAILQ_INIT(&V_in6_ifaddrhead); |
---|
175 | |
---|
176 | /* Initialize packet filter hooks. */ |
---|
177 | V_inet6_pfil_hook.ph_type = PFIL_TYPE_AF; |
---|
178 | V_inet6_pfil_hook.ph_af = AF_INET6; |
---|
179 | if ((i = pfil_head_register(&V_inet6_pfil_hook)) != 0) |
---|
180 | printf("%s: WARNING: unable to register pfil hook, " |
---|
181 | "error %d\n", __func__, i); |
---|
182 | |
---|
183 | scope6_init(); |
---|
184 | addrsel_policy_init(); |
---|
185 | nd6_init(); |
---|
186 | frag6_init(); |
---|
187 | |
---|
188 | #ifdef FLOWTABLE |
---|
189 | if (TUNABLE_INT_FETCH("net.inet6.ip6.output_flowtable_size", |
---|
190 | &V_ip6_output_flowtable_size)) { |
---|
191 | if (V_ip6_output_flowtable_size < 256) |
---|
192 | V_ip6_output_flowtable_size = 256; |
---|
193 | if (!powerof2(V_ip6_output_flowtable_size)) { |
---|
194 | printf("flowtable must be power of 2 size\n"); |
---|
195 | V_ip6_output_flowtable_size = 2048; |
---|
196 | } |
---|
197 | } else { |
---|
198 | /* |
---|
199 | * round up to the next power of 2 |
---|
200 | */ |
---|
201 | V_ip6_output_flowtable_size = 1 << fls((1024 + maxusers * 64)-1); |
---|
202 | } |
---|
203 | V_ip6_ft = flowtable_alloc("ipv6", V_ip6_output_flowtable_size, FL_IPV6|FL_PCPU); |
---|
204 | #endif |
---|
205 | |
---|
206 | V_ip6_desync_factor = arc4random() % MAX_TEMP_DESYNC_FACTOR; |
---|
207 | |
---|
208 | /* Skip global initialization stuff for non-default instances. */ |
---|
209 | if (!IS_DEFAULT_VNET(curvnet)) |
---|
210 | return; |
---|
211 | |
---|
212 | #ifdef DIAGNOSTIC |
---|
213 | if (sizeof(struct protosw) != sizeof(struct ip6protosw)) |
---|
214 | panic("sizeof(protosw) != sizeof(ip6protosw)"); |
---|
215 | #endif |
---|
216 | pr = (struct ip6protosw *)pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); |
---|
217 | if (pr == NULL) |
---|
218 | panic("ip6_init"); |
---|
219 | |
---|
220 | /* Initialize the entire ip6_protox[] array to IPPROTO_RAW. */ |
---|
221 | for (i = 0; i < IPPROTO_MAX; i++) |
---|
222 | ip6_protox[i] = pr - inet6sw; |
---|
223 | /* |
---|
224 | * Cycle through IP protocols and put them into the appropriate place |
---|
225 | * in ip6_protox[]. |
---|
226 | */ |
---|
227 | for (pr = (struct ip6protosw *)inet6domain.dom_protosw; |
---|
228 | pr < (struct ip6protosw *)inet6domain.dom_protoswNPROTOSW; pr++) |
---|
229 | if (pr->pr_domain->dom_family == PF_INET6 && |
---|
230 | pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) { |
---|
231 | /* Be careful to only index valid IP protocols. */ |
---|
232 | if (pr->pr_protocol < IPPROTO_MAX) |
---|
233 | ip6_protox[pr->pr_protocol] = pr - inet6sw; |
---|
234 | } |
---|
235 | |
---|
236 | netisr_register(&ip6_nh); |
---|
237 | } |
---|
238 | |
---|
239 | /* |
---|
240 | * The protocol to be inserted into ip6_protox[] must be already registered |
---|
241 | * in inet6sw[], either statically or through pf_proto_register(). |
---|
242 | */ |
---|
243 | int |
---|
244 | ip6proto_register(short ip6proto) |
---|
245 | { |
---|
246 | struct ip6protosw *pr; |
---|
247 | |
---|
248 | /* Sanity checks. */ |
---|
249 | if (ip6proto <= 0 || ip6proto >= IPPROTO_MAX) |
---|
250 | return (EPROTONOSUPPORT); |
---|
251 | |
---|
252 | /* |
---|
253 | * The protocol slot must not be occupied by another protocol |
---|
254 | * already. An index pointing to IPPROTO_RAW is unused. |
---|
255 | */ |
---|
256 | pr = (struct ip6protosw *)pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); |
---|
257 | if (pr == NULL) |
---|
258 | return (EPFNOSUPPORT); |
---|
259 | if (ip6_protox[ip6proto] != pr - inet6sw) /* IPPROTO_RAW */ |
---|
260 | return (EEXIST); |
---|
261 | |
---|
262 | /* |
---|
263 | * Find the protocol position in inet6sw[] and set the index. |
---|
264 | */ |
---|
265 | for (pr = (struct ip6protosw *)inet6domain.dom_protosw; |
---|
266 | pr < (struct ip6protosw *)inet6domain.dom_protoswNPROTOSW; pr++) { |
---|
267 | if (pr->pr_domain->dom_family == PF_INET6 && |
---|
268 | pr->pr_protocol && pr->pr_protocol == ip6proto) { |
---|
269 | ip6_protox[pr->pr_protocol] = pr - inet6sw; |
---|
270 | return (0); |
---|
271 | } |
---|
272 | } |
---|
273 | return (EPROTONOSUPPORT); |
---|
274 | } |
---|
275 | |
---|
276 | int |
---|
277 | ip6proto_unregister(short ip6proto) |
---|
278 | { |
---|
279 | struct ip6protosw *pr; |
---|
280 | |
---|
281 | /* Sanity checks. */ |
---|
282 | if (ip6proto <= 0 || ip6proto >= IPPROTO_MAX) |
---|
283 | return (EPROTONOSUPPORT); |
---|
284 | |
---|
285 | /* Check if the protocol was indeed registered. */ |
---|
286 | pr = (struct ip6protosw *)pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); |
---|
287 | if (pr == NULL) |
---|
288 | return (EPFNOSUPPORT); |
---|
289 | if (ip6_protox[ip6proto] == pr - inet6sw) /* IPPROTO_RAW */ |
---|
290 | return (ENOENT); |
---|
291 | |
---|
292 | /* Reset the protocol slot to IPPROTO_RAW. */ |
---|
293 | ip6_protox[ip6proto] = pr - inet6sw; |
---|
294 | return (0); |
---|
295 | } |
---|
296 | |
---|
297 | #ifdef VIMAGE |
---|
298 | void |
---|
299 | ip6_destroy() |
---|
300 | { |
---|
301 | |
---|
302 | nd6_destroy(); |
---|
303 | callout_drain(&V_in6_tmpaddrtimer_ch); |
---|
304 | } |
---|
305 | #endif |
---|
306 | |
---|
307 | static int |
---|
308 | ip6_init2_vnet(const void *unused __unused) |
---|
309 | { |
---|
310 | |
---|
311 | /* nd6_timer_init */ |
---|
312 | callout_init(&V_nd6_timer_ch, 0); |
---|
313 | callout_reset(&V_nd6_timer_ch, hz, nd6_timer, curvnet); |
---|
314 | |
---|
315 | /* timer for regeneranation of temporary addresses randomize ID */ |
---|
316 | callout_init(&V_in6_tmpaddrtimer_ch, 0); |
---|
317 | callout_reset(&V_in6_tmpaddrtimer_ch, |
---|
318 | (V_ip6_temp_preferred_lifetime - V_ip6_desync_factor - |
---|
319 | V_ip6_temp_regen_advance) * hz, |
---|
320 | in6_tmpaddrtimer, curvnet); |
---|
321 | |
---|
322 | return (0); |
---|
323 | } |
---|
324 | |
---|
325 | static void |
---|
326 | ip6_init2(void *dummy) |
---|
327 | { |
---|
328 | |
---|
329 | ip6_init2_vnet(NULL); |
---|
330 | } |
---|
331 | |
---|
332 | /* cheat */ |
---|
333 | /* This must be after route_init(), which is now SI_ORDER_THIRD */ |
---|
334 | SYSINIT(netinet6init2, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ip6_init2, NULL); |
---|
335 | |
---|
336 | static int |
---|
337 | ip6_input_hbh(struct mbuf *m, uint32_t *plen, uint32_t *rtalert, int *off, |
---|
338 | int *nxt, int *ours) |
---|
339 | { |
---|
340 | struct ip6_hdr *ip6; |
---|
341 | struct ip6_hbh *hbh; |
---|
342 | |
---|
343 | if (ip6_hopopts_input(plen, rtalert, &m, off)) { |
---|
344 | #if 0 /*touches NULL pointer*/ |
---|
345 | in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); |
---|
346 | #endif |
---|
347 | goto out; /* m have already been freed */ |
---|
348 | } |
---|
349 | |
---|
350 | /* adjust pointer */ |
---|
351 | ip6 = mtod(m, struct ip6_hdr *); |
---|
352 | |
---|
353 | /* |
---|
354 | * if the payload length field is 0 and the next header field |
---|
355 | * indicates Hop-by-Hop Options header, then a Jumbo Payload |
---|
356 | * option MUST be included. |
---|
357 | */ |
---|
358 | if (ip6->ip6_plen == 0 && *plen == 0) { |
---|
359 | /* |
---|
360 | * Note that if a valid jumbo payload option is |
---|
361 | * contained, ip6_hopopts_input() must set a valid |
---|
362 | * (non-zero) payload length to the variable plen. |
---|
363 | */ |
---|
364 | IP6STAT_INC(ip6s_badoptions); |
---|
365 | in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); |
---|
366 | in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); |
---|
367 | icmp6_error(m, ICMP6_PARAM_PROB, |
---|
368 | ICMP6_PARAMPROB_HEADER, |
---|
369 | (caddr_t)&ip6->ip6_plen - (caddr_t)ip6); |
---|
370 | goto out; |
---|
371 | } |
---|
372 | #ifndef PULLDOWN_TEST |
---|
373 | /* ip6_hopopts_input() ensures that mbuf is contiguous */ |
---|
374 | hbh = (struct ip6_hbh *)(ip6 + 1); |
---|
375 | #else |
---|
376 | IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), |
---|
377 | sizeof(struct ip6_hbh)); |
---|
378 | if (hbh == NULL) { |
---|
379 | IP6STAT_INC(ip6s_tooshort); |
---|
380 | goto out; |
---|
381 | } |
---|
382 | #endif |
---|
383 | *nxt = hbh->ip6h_nxt; |
---|
384 | |
---|
385 | /* |
---|
386 | * If we are acting as a router and the packet contains a |
---|
387 | * router alert option, see if we know the option value. |
---|
388 | * Currently, we only support the option value for MLD, in which |
---|
389 | * case we should pass the packet to the multicast routing |
---|
390 | * daemon. |
---|
391 | */ |
---|
392 | if (*rtalert != ~0) { |
---|
393 | switch (*rtalert) { |
---|
394 | case IP6OPT_RTALERT_MLD: |
---|
395 | if (V_ip6_forwarding) |
---|
396 | *ours = 1; |
---|
397 | break; |
---|
398 | default: |
---|
399 | /* |
---|
400 | * RFC2711 requires unrecognized values must be |
---|
401 | * silently ignored. |
---|
402 | */ |
---|
403 | break; |
---|
404 | } |
---|
405 | } |
---|
406 | |
---|
407 | return (0); |
---|
408 | |
---|
409 | out: |
---|
410 | return (1); |
---|
411 | } |
---|
412 | |
---|
413 | void |
---|
414 | ip6_input(struct mbuf *m) |
---|
415 | { |
---|
416 | struct ip6_hdr *ip6; |
---|
417 | int off = sizeof(struct ip6_hdr), nest; |
---|
418 | u_int32_t plen; |
---|
419 | u_int32_t rtalert = ~0; |
---|
420 | int nxt, ours = 0; |
---|
421 | struct ifnet *deliverifp = NULL, *ifp = NULL; |
---|
422 | struct in6_addr odst; |
---|
423 | struct route_in6 rin6; |
---|
424 | int srcrt = 0; |
---|
425 | struct llentry *lle = NULL; |
---|
426 | struct sockaddr_in6 dst6, *dst; |
---|
427 | |
---|
428 | bzero(&rin6, sizeof(struct route_in6)); |
---|
429 | #ifdef IPSEC |
---|
430 | /* |
---|
431 | * should the inner packet be considered authentic? |
---|
432 | * see comment in ah4_input(). |
---|
433 | * NB: m cannot be NULL when passed to the input routine |
---|
434 | */ |
---|
435 | |
---|
436 | m->m_flags &= ~M_AUTHIPHDR; |
---|
437 | m->m_flags &= ~M_AUTHIPDGM; |
---|
438 | |
---|
439 | #endif /* IPSEC */ |
---|
440 | |
---|
441 | /* |
---|
442 | * make sure we don't have onion peering information into m_tag. |
---|
443 | */ |
---|
444 | ip6_delaux(m); |
---|
445 | |
---|
446 | if (m->m_flags & M_FASTFWD_OURS) { |
---|
447 | /* |
---|
448 | * Firewall changed destination to local. |
---|
449 | */ |
---|
450 | m->m_flags &= ~M_FASTFWD_OURS; |
---|
451 | ours = 1; |
---|
452 | deliverifp = m->m_pkthdr.rcvif; |
---|
453 | ip6 = mtod(m, struct ip6_hdr *); |
---|
454 | goto hbhcheck; |
---|
455 | } |
---|
456 | |
---|
457 | /* |
---|
458 | * mbuf statistics |
---|
459 | */ |
---|
460 | if (m->m_flags & M_EXT) { |
---|
461 | if (m->m_next) |
---|
462 | IP6STAT_INC(ip6s_mext2m); |
---|
463 | else |
---|
464 | IP6STAT_INC(ip6s_mext1); |
---|
465 | } else { |
---|
466 | if (m->m_next) { |
---|
467 | if (m->m_flags & M_LOOP) { |
---|
468 | IP6STAT_INC(ip6s_m2m[V_loif->if_index]); |
---|
469 | } else if (m->m_pkthdr.rcvif->if_index < IP6S_M2MMAX) |
---|
470 | IP6STAT_INC( |
---|
471 | ip6s_m2m[m->m_pkthdr.rcvif->if_index]); |
---|
472 | else |
---|
473 | IP6STAT_INC(ip6s_m2m[0]); |
---|
474 | } else |
---|
475 | IP6STAT_INC(ip6s_m1); |
---|
476 | } |
---|
477 | |
---|
478 | /* drop the packet if IPv6 operation is disabled on the IF */ |
---|
479 | if ((ND_IFINFO(m->m_pkthdr.rcvif)->flags & ND6_IFF_IFDISABLED)) { |
---|
480 | m_freem(m); |
---|
481 | return; |
---|
482 | } |
---|
483 | |
---|
484 | in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive); |
---|
485 | IP6STAT_INC(ip6s_total); |
---|
486 | |
---|
487 | #ifndef PULLDOWN_TEST |
---|
488 | /* |
---|
489 | * L2 bridge code and some other code can return mbuf chain |
---|
490 | * that does not conform to KAME requirement. too bad. |
---|
491 | * XXX: fails to join if interface MTU > MCLBYTES. jumbogram? |
---|
492 | */ |
---|
493 | if (m && m->m_next != NULL && m->m_pkthdr.len < MCLBYTES) { |
---|
494 | struct mbuf *n; |
---|
495 | |
---|
496 | MGETHDR(n, M_DONTWAIT, MT_HEADER); |
---|
497 | if (n) |
---|
498 | M_MOVE_PKTHDR(n, m); |
---|
499 | if (n && n->m_pkthdr.len > MHLEN) { |
---|
500 | MCLGET(n, M_DONTWAIT); |
---|
501 | if ((n->m_flags & M_EXT) == 0) { |
---|
502 | m_freem(n); |
---|
503 | n = NULL; |
---|
504 | } |
---|
505 | } |
---|
506 | if (n == NULL) { |
---|
507 | m_freem(m); |
---|
508 | return; /* ENOBUFS */ |
---|
509 | } |
---|
510 | |
---|
511 | m_copydata(m, 0, n->m_pkthdr.len, mtod(n, caddr_t)); |
---|
512 | n->m_len = n->m_pkthdr.len; |
---|
513 | m_freem(m); |
---|
514 | m = n; |
---|
515 | } |
---|
516 | IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), /* nothing */); |
---|
517 | #endif |
---|
518 | |
---|
519 | if (m->m_len < sizeof(struct ip6_hdr)) { |
---|
520 | struct ifnet *inifp; |
---|
521 | inifp = m->m_pkthdr.rcvif; |
---|
522 | if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { |
---|
523 | IP6STAT_INC(ip6s_toosmall); |
---|
524 | in6_ifstat_inc(inifp, ifs6_in_hdrerr); |
---|
525 | return; |
---|
526 | } |
---|
527 | } |
---|
528 | |
---|
529 | ip6 = mtod(m, struct ip6_hdr *); |
---|
530 | |
---|
531 | if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { |
---|
532 | IP6STAT_INC(ip6s_badvers); |
---|
533 | in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); |
---|
534 | goto bad; |
---|
535 | } |
---|
536 | |
---|
537 | IP6STAT_INC(ip6s_nxthist[ip6->ip6_nxt]); |
---|
538 | |
---|
539 | /* |
---|
540 | * Check against address spoofing/corruption. |
---|
541 | */ |
---|
542 | if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src) || |
---|
543 | IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) { |
---|
544 | /* |
---|
545 | * XXX: "badscope" is not very suitable for a multicast source. |
---|
546 | */ |
---|
547 | IP6STAT_INC(ip6s_badscope); |
---|
548 | in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); |
---|
549 | goto bad; |
---|
550 | } |
---|
551 | if (IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) && |
---|
552 | !(m->m_flags & M_LOOP)) { |
---|
553 | /* |
---|
554 | * In this case, the packet should come from the loopback |
---|
555 | * interface. However, we cannot just check the if_flags, |
---|
556 | * because ip6_mloopback() passes the "actual" interface |
---|
557 | * as the outgoing/incoming interface. |
---|
558 | */ |
---|
559 | IP6STAT_INC(ip6s_badscope); |
---|
560 | in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); |
---|
561 | goto bad; |
---|
562 | } |
---|
563 | if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && |
---|
564 | IPV6_ADDR_MC_SCOPE(&ip6->ip6_dst) == 0) { |
---|
565 | /* |
---|
566 | * RFC4291 2.7: |
---|
567 | * Nodes must not originate a packet to a multicast address |
---|
568 | * whose scop field contains the reserved value 0; if such |
---|
569 | * a packet is received, it must be silently dropped. |
---|
570 | */ |
---|
571 | IP6STAT_INC(ip6s_badscope); |
---|
572 | in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); |
---|
573 | goto bad; |
---|
574 | } |
---|
575 | #ifdef ALTQ |
---|
576 | if (altq_input != NULL && (*altq_input)(m, AF_INET6) == 0) { |
---|
577 | /* packet is dropped by traffic conditioner */ |
---|
578 | return; |
---|
579 | } |
---|
580 | #endif |
---|
581 | /* |
---|
582 | * The following check is not documented in specs. A malicious |
---|
583 | * party may be able to use IPv4 mapped addr to confuse tcp/udp stack |
---|
584 | * and bypass security checks (act as if it was from 127.0.0.1 by using |
---|
585 | * IPv6 src ::ffff:127.0.0.1). Be cautious. |
---|
586 | * |
---|
587 | * This check chokes if we are in an SIIT cloud. As none of BSDs |
---|
588 | * support IPv4-less kernel compilation, we cannot support SIIT |
---|
589 | * environment at all. So, it makes more sense for us to reject any |
---|
590 | * malicious packets for non-SIIT environment, than try to do a |
---|
591 | * partial support for SIIT environment. |
---|
592 | */ |
---|
593 | if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || |
---|
594 | IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { |
---|
595 | IP6STAT_INC(ip6s_badscope); |
---|
596 | in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); |
---|
597 | goto bad; |
---|
598 | } |
---|
599 | #if 0 |
---|
600 | /* |
---|
601 | * Reject packets with IPv4 compatible addresses (auto tunnel). |
---|
602 | * |
---|
603 | * The code forbids auto tunnel relay case in RFC1933 (the check is |
---|
604 | * stronger than RFC1933). We may want to re-enable it if mech-xx |
---|
605 | * is revised to forbid relaying case. |
---|
606 | */ |
---|
607 | if (IN6_IS_ADDR_V4COMPAT(&ip6->ip6_src) || |
---|
608 | IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) { |
---|
609 | IP6STAT_INC(ip6s_badscope); |
---|
610 | in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); |
---|
611 | goto bad; |
---|
612 | } |
---|
613 | #endif |
---|
614 | #ifdef IPSEC |
---|
615 | /* |
---|
616 | * Bypass packet filtering for packets previously handled by IPsec. |
---|
617 | */ |
---|
618 | if (ip6_ipsec_filtertunnel(m)) |
---|
619 | goto passin; |
---|
620 | #endif /* IPSEC */ |
---|
621 | |
---|
622 | /* |
---|
623 | * Run through list of hooks for input packets. |
---|
624 | * |
---|
625 | * NB: Beware of the destination address changing |
---|
626 | * (e.g. by NAT rewriting). When this happens, |
---|
627 | * tell ip6_forward to do the right thing. |
---|
628 | */ |
---|
629 | odst = ip6->ip6_dst; |
---|
630 | |
---|
631 | /* Jump over all PFIL processing if hooks are not active. */ |
---|
632 | if (!PFIL_HOOKED(&V_inet6_pfil_hook)) |
---|
633 | goto passin; |
---|
634 | |
---|
635 | if (pfil_run_hooks(&V_inet6_pfil_hook, &m, |
---|
636 | m->m_pkthdr.rcvif, PFIL_IN, NULL)) |
---|
637 | return; |
---|
638 | if (m == NULL) /* consumed by filter */ |
---|
639 | return; |
---|
640 | ip6 = mtod(m, struct ip6_hdr *); |
---|
641 | srcrt = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst); |
---|
642 | |
---|
643 | if (m->m_flags & M_FASTFWD_OURS) { |
---|
644 | m->m_flags &= ~M_FASTFWD_OURS; |
---|
645 | ours = 1; |
---|
646 | deliverifp = m->m_pkthdr.rcvif; |
---|
647 | goto hbhcheck; |
---|
648 | } |
---|
649 | if ((m->m_flags & M_IP6_NEXTHOP) && |
---|
650 | m_tag_find(m, PACKET_TAG_IPFORWARD, NULL) != NULL) { |
---|
651 | /* |
---|
652 | * Directly ship the packet on. This allows forwarding |
---|
653 | * packets originally destined to us to some other directly |
---|
654 | * connected host. |
---|
655 | */ |
---|
656 | ip6_forward(m, 1); |
---|
657 | goto out; |
---|
658 | } |
---|
659 | |
---|
660 | passin: |
---|
661 | /* |
---|
662 | * Disambiguate address scope zones (if there is ambiguity). |
---|
663 | * We first make sure that the original source or destination address |
---|
664 | * is not in our internal form for scoped addresses. Such addresses |
---|
665 | * are not necessarily invalid spec-wise, but we cannot accept them due |
---|
666 | * to the usage conflict. |
---|
667 | * in6_setscope() then also checks and rejects the cases where src or |
---|
668 | * dst are the loopback address and the receiving interface |
---|
669 | * is not loopback. |
---|
670 | */ |
---|
671 | if (in6_clearscope(&ip6->ip6_src) || in6_clearscope(&ip6->ip6_dst)) { |
---|
672 | IP6STAT_INC(ip6s_badscope); /* XXX */ |
---|
673 | goto bad; |
---|
674 | } |
---|
675 | if (in6_setscope(&ip6->ip6_src, m->m_pkthdr.rcvif, NULL) || |
---|
676 | in6_setscope(&ip6->ip6_dst, m->m_pkthdr.rcvif, NULL)) { |
---|
677 | IP6STAT_INC(ip6s_badscope); |
---|
678 | goto bad; |
---|
679 | } |
---|
680 | |
---|
681 | /* |
---|
682 | * Multicast check. Assume packet is for us to avoid |
---|
683 | * prematurely taking locks. |
---|
684 | */ |
---|
685 | if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { |
---|
686 | ours = 1; |
---|
687 | in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mcast); |
---|
688 | deliverifp = m->m_pkthdr.rcvif; |
---|
689 | goto hbhcheck; |
---|
690 | } |
---|
691 | |
---|
692 | /* |
---|
693 | * Unicast check |
---|
694 | */ |
---|
695 | |
---|
696 | bzero(&dst6, sizeof(dst6)); |
---|
697 | dst6.sin6_family = AF_INET6; |
---|
698 | dst6.sin6_len = sizeof(struct sockaddr_in6); |
---|
699 | dst6.sin6_addr = ip6->ip6_dst; |
---|
700 | ifp = m->m_pkthdr.rcvif; |
---|
701 | IF_AFDATA_RLOCK(ifp); |
---|
702 | lle = lla_lookup(LLTABLE6(ifp), 0, |
---|
703 | (struct sockaddr *)&dst6); |
---|
704 | IF_AFDATA_RUNLOCK(ifp); |
---|
705 | if ((lle != NULL) && (lle->la_flags & LLE_IFADDR)) { |
---|
706 | struct ifaddr *ifa; |
---|
707 | struct in6_ifaddr *ia6; |
---|
708 | int bad; |
---|
709 | |
---|
710 | bad = 1; |
---|
711 | #define sa_equal(a1, a2) \ |
---|
712 | (bcmp((a1), (a2), ((a1))->sin6_len) == 0) |
---|
713 | IF_ADDR_RLOCK(ifp); |
---|
714 | TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { |
---|
715 | if (ifa->ifa_addr->sa_family != dst6.sin6_family) |
---|
716 | continue; |
---|
717 | if (sa_equal(&dst6, ifa->ifa_addr)) |
---|
718 | break; |
---|
719 | } |
---|
720 | KASSERT(ifa != NULL, ("%s: ifa not found for lle %p", |
---|
721 | __func__, lle)); |
---|
722 | #undef sa_equal |
---|
723 | |
---|
724 | ia6 = (struct in6_ifaddr *)ifa; |
---|
725 | if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) { |
---|
726 | /* Count the packet in the ip address stats */ |
---|
727 | ia6->ia_ifa.if_ipackets++; |
---|
728 | ia6->ia_ifa.if_ibytes += m->m_pkthdr.len; |
---|
729 | |
---|
730 | /* |
---|
731 | * record address information into m_tag. |
---|
732 | */ |
---|
733 | (void)ip6_setdstifaddr(m, ia6); |
---|
734 | |
---|
735 | bad = 0; |
---|
736 | } else { |
---|
737 | char ip6bufs[INET6_ADDRSTRLEN]; |
---|
738 | char ip6bufd[INET6_ADDRSTRLEN]; |
---|
739 | /* address is not ready, so discard the packet. */ |
---|
740 | nd6log((LOG_INFO, |
---|
741 | "ip6_input: packet to an unready address %s->%s\n", |
---|
742 | ip6_sprintf(ip6bufs, &ip6->ip6_src), |
---|
743 | ip6_sprintf(ip6bufd, &ip6->ip6_dst))); |
---|
744 | } |
---|
745 | IF_ADDR_RUNLOCK(ifp); |
---|
746 | LLE_RUNLOCK(lle); |
---|
747 | if (bad) |
---|
748 | goto bad; |
---|
749 | else { |
---|
750 | ours = 1; |
---|
751 | deliverifp = ifp; |
---|
752 | goto hbhcheck; |
---|
753 | } |
---|
754 | } |
---|
755 | if (lle != NULL) |
---|
756 | LLE_RUNLOCK(lle); |
---|
757 | |
---|
758 | dst = &rin6.ro_dst; |
---|
759 | dst->sin6_len = sizeof(struct sockaddr_in6); |
---|
760 | dst->sin6_family = AF_INET6; |
---|
761 | dst->sin6_addr = ip6->ip6_dst; |
---|
762 | rin6.ro_rt = in6_rtalloc1((struct sockaddr *)dst, 0, 0, M_GETFIB(m)); |
---|
763 | if (rin6.ro_rt) |
---|
764 | RT_UNLOCK(rin6.ro_rt); |
---|
765 | |
---|
766 | #define rt6_key(r) ((struct sockaddr_in6 *)((r)->rt_nodes->rn_key)) |
---|
767 | |
---|
768 | /* |
---|
769 | * Accept the packet if the forwarding interface to the destination |
---|
770 | * according to the routing table is the loopback interface, |
---|
771 | * unless the associated route has a gateway. |
---|
772 | * Note that this approach causes to accept a packet if there is a |
---|
773 | * route to the loopback interface for the destination of the packet. |
---|
774 | * But we think it's even useful in some situations, e.g. when using |
---|
775 | * a special daemon which wants to intercept the packet. |
---|
776 | * |
---|
777 | * XXX: some OSes automatically make a cloned route for the destination |
---|
778 | * of an outgoing packet. If the outgoing interface of the packet |
---|
779 | * is a loopback one, the kernel would consider the packet to be |
---|
780 | * accepted, even if we have no such address assinged on the interface. |
---|
781 | * We check the cloned flag of the route entry to reject such cases, |
---|
782 | * assuming that route entries for our own addresses are not made by |
---|
783 | * cloning (it should be true because in6_addloop explicitly installs |
---|
784 | * the host route). However, we might have to do an explicit check |
---|
785 | * while it would be less efficient. Or, should we rather install a |
---|
786 | * reject route for such a case? |
---|
787 | */ |
---|
788 | if (rin6.ro_rt && |
---|
789 | (rin6.ro_rt->rt_flags & |
---|
790 | (RTF_HOST|RTF_GATEWAY)) == RTF_HOST && |
---|
791 | #ifdef RTF_WASCLONED |
---|
792 | !(rin6.ro_rt->rt_flags & RTF_WASCLONED) && |
---|
793 | #endif |
---|
794 | #ifdef RTF_CLONED |
---|
795 | !(rin6.ro_rt->rt_flags & RTF_CLONED) && |
---|
796 | #endif |
---|
797 | #if 0 |
---|
798 | /* |
---|
799 | * The check below is redundant since the comparison of |
---|
800 | * the destination and the key of the rtentry has |
---|
801 | * already done through looking up the routing table. |
---|
802 | */ |
---|
803 | IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, |
---|
804 | &rt6_key(rin6.ro_rt)->sin6_addr) |
---|
805 | #endif |
---|
806 | rin6.ro_rt->rt_ifp->if_type == IFT_LOOP) { |
---|
807 | int free_ia6 = 0; |
---|
808 | struct in6_ifaddr *ia6; |
---|
809 | |
---|
810 | /* |
---|
811 | * found the loopback route to the interface address |
---|
812 | */ |
---|
813 | if (rin6.ro_rt->rt_gateway->sa_family == AF_LINK) { |
---|
814 | struct sockaddr_in6 dest6; |
---|
815 | |
---|
816 | bzero(&dest6, sizeof(dest6)); |
---|
817 | dest6.sin6_family = AF_INET6; |
---|
818 | dest6.sin6_len = sizeof(dest6); |
---|
819 | dest6.sin6_addr = ip6->ip6_dst; |
---|
820 | ia6 = (struct in6_ifaddr *) |
---|
821 | ifa_ifwithaddr((struct sockaddr *)&dest6); |
---|
822 | if (ia6 == NULL) |
---|
823 | goto bad; |
---|
824 | free_ia6 = 1; |
---|
825 | } |
---|
826 | else |
---|
827 | ia6 = (struct in6_ifaddr *)rin6.ro_rt->rt_ifa; |
---|
828 | |
---|
829 | /* |
---|
830 | * record address information into m_tag. |
---|
831 | */ |
---|
832 | (void)ip6_setdstifaddr(m, ia6); |
---|
833 | |
---|
834 | /* |
---|
835 | * packets to a tentative, duplicated, or somehow invalid |
---|
836 | * address must not be accepted. |
---|
837 | */ |
---|
838 | if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) { |
---|
839 | /* this address is ready */ |
---|
840 | ours = 1; |
---|
841 | deliverifp = ia6->ia_ifp; /* correct? */ |
---|
842 | /* Count the packet in the ip address stats */ |
---|
843 | ia6->ia_ifa.if_ipackets++; |
---|
844 | ia6->ia_ifa.if_ibytes += m->m_pkthdr.len; |
---|
845 | if (ia6 != NULL && free_ia6 != 0) |
---|
846 | ifa_free(&ia6->ia_ifa); |
---|
847 | goto hbhcheck; |
---|
848 | } else { |
---|
849 | char ip6bufs[INET6_ADDRSTRLEN]; |
---|
850 | char ip6bufd[INET6_ADDRSTRLEN]; |
---|
851 | /* address is not ready, so discard the packet. */ |
---|
852 | nd6log((LOG_INFO, |
---|
853 | "ip6_input: packet to an unready address %s->%s\n", |
---|
854 | ip6_sprintf(ip6bufs, &ip6->ip6_src), |
---|
855 | ip6_sprintf(ip6bufd, &ip6->ip6_dst))); |
---|
856 | |
---|
857 | if (ia6 != NULL && free_ia6 != 0) |
---|
858 | ifa_free(&ia6->ia_ifa); |
---|
859 | goto bad; |
---|
860 | } |
---|
861 | } |
---|
862 | |
---|
863 | /* |
---|
864 | * FAITH (Firewall Aided Internet Translator) |
---|
865 | */ |
---|
866 | if (V_ip6_keepfaith) { |
---|
867 | if (rin6.ro_rt && rin6.ro_rt->rt_ifp && |
---|
868 | rin6.ro_rt->rt_ifp->if_type == IFT_FAITH) { |
---|
869 | /* XXX do we need more sanity checks? */ |
---|
870 | ours = 1; |
---|
871 | deliverifp = rin6.ro_rt->rt_ifp; /* faith */ |
---|
872 | goto hbhcheck; |
---|
873 | } |
---|
874 | } |
---|
875 | |
---|
876 | /* |
---|
877 | * Now there is no reason to process the packet if it's not our own |
---|
878 | * and we're not a router. |
---|
879 | */ |
---|
880 | if (!V_ip6_forwarding) { |
---|
881 | IP6STAT_INC(ip6s_cantforward); |
---|
882 | in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); |
---|
883 | goto bad; |
---|
884 | } |
---|
885 | |
---|
886 | hbhcheck: |
---|
887 | /* |
---|
888 | * record address information into m_tag, if we don't have one yet. |
---|
889 | * note that we are unable to record it, if the address is not listed |
---|
890 | * as our interface address (e.g. multicast addresses, addresses |
---|
891 | * within FAITH prefixes and such). |
---|
892 | */ |
---|
893 | if (deliverifp) { |
---|
894 | struct in6_ifaddr *ia6; |
---|
895 | |
---|
896 | if ((ia6 = ip6_getdstifaddr(m)) != NULL) { |
---|
897 | ifa_free(&ia6->ia_ifa); |
---|
898 | } else { |
---|
899 | ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst); |
---|
900 | if (ia6) { |
---|
901 | if (!ip6_setdstifaddr(m, ia6)) { |
---|
902 | /* |
---|
903 | * XXX maybe we should drop the packet here, |
---|
904 | * as we could not provide enough information |
---|
905 | * to the upper layers. |
---|
906 | */ |
---|
907 | } |
---|
908 | ifa_free(&ia6->ia_ifa); |
---|
909 | } |
---|
910 | } |
---|
911 | } |
---|
912 | |
---|
913 | /* |
---|
914 | * Process Hop-by-Hop options header if it's contained. |
---|
915 | * m may be modified in ip6_hopopts_input(). |
---|
916 | * If a JumboPayload option is included, plen will also be modified. |
---|
917 | */ |
---|
918 | plen = (u_int32_t)ntohs(ip6->ip6_plen); |
---|
919 | if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { |
---|
920 | int error; |
---|
921 | |
---|
922 | error = ip6_input_hbh(m, &plen, &rtalert, &off, &nxt, &ours); |
---|
923 | if (error != 0) |
---|
924 | goto out; |
---|
925 | } else |
---|
926 | nxt = ip6->ip6_nxt; |
---|
927 | |
---|
928 | /* |
---|
929 | * Check that the amount of data in the buffers |
---|
930 | * is as at least much as the IPv6 header would have us expect. |
---|
931 | * Trim mbufs if longer than we expect. |
---|
932 | * Drop packet if shorter than we expect. |
---|
933 | */ |
---|
934 | if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) { |
---|
935 | IP6STAT_INC(ip6s_tooshort); |
---|
936 | in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); |
---|
937 | goto bad; |
---|
938 | } |
---|
939 | if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) { |
---|
940 | if (m->m_len == m->m_pkthdr.len) { |
---|
941 | m->m_len = sizeof(struct ip6_hdr) + plen; |
---|
942 | m->m_pkthdr.len = sizeof(struct ip6_hdr) + plen; |
---|
943 | } else |
---|
944 | m_adj(m, sizeof(struct ip6_hdr) + plen - m->m_pkthdr.len); |
---|
945 | } |
---|
946 | |
---|
947 | /* |
---|
948 | * Forward if desirable. |
---|
949 | */ |
---|
950 | if (V_ip6_mrouter && |
---|
951 | IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { |
---|
952 | /* |
---|
953 | * If we are acting as a multicast router, all |
---|
954 | * incoming multicast packets are passed to the |
---|
955 | * kernel-level multicast forwarding function. |
---|
956 | * The packet is returned (relatively) intact; if |
---|
957 | * ip6_mforward() returns a non-zero value, the packet |
---|
958 | * must be discarded, else it may be accepted below. |
---|
959 | * |
---|
960 | * XXX TODO: Check hlim and multicast scope here to avoid |
---|
961 | * unnecessarily calling into ip6_mforward(). |
---|
962 | */ |
---|
963 | if (ip6_mforward && |
---|
964 | ip6_mforward(ip6, m->m_pkthdr.rcvif, m)) { |
---|
965 | IP6STAT_INC(ip6s_cantforward); |
---|
966 | in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); |
---|
967 | goto bad; |
---|
968 | } |
---|
969 | } else if (!ours) { |
---|
970 | ip6_forward(m, srcrt); |
---|
971 | goto out; |
---|
972 | } |
---|
973 | |
---|
974 | ip6 = mtod(m, struct ip6_hdr *); |
---|
975 | |
---|
976 | /* |
---|
977 | * Malicious party may be able to use IPv4 mapped addr to confuse |
---|
978 | * tcp/udp stack and bypass security checks (act as if it was from |
---|
979 | * 127.0.0.1 by using IPv6 src ::ffff:127.0.0.1). Be cautious. |
---|
980 | * |
---|
981 | * For SIIT end node behavior, you may want to disable the check. |
---|
982 | * However, you will become vulnerable to attacks using IPv4 mapped |
---|
983 | * source. |
---|
984 | */ |
---|
985 | if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || |
---|
986 | IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { |
---|
987 | IP6STAT_INC(ip6s_badscope); |
---|
988 | in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); |
---|
989 | goto bad; |
---|
990 | } |
---|
991 | |
---|
992 | /* |
---|
993 | * Tell launch routine the next header |
---|
994 | */ |
---|
995 | IP6STAT_INC(ip6s_delivered); |
---|
996 | in6_ifstat_inc(deliverifp, ifs6_in_deliver); |
---|
997 | nest = 0; |
---|
998 | |
---|
999 | while (nxt != IPPROTO_DONE) { |
---|
1000 | if (V_ip6_hdrnestlimit && (++nest > V_ip6_hdrnestlimit)) { |
---|
1001 | IP6STAT_INC(ip6s_toomanyhdr); |
---|
1002 | goto bad; |
---|
1003 | } |
---|
1004 | |
---|
1005 | /* |
---|
1006 | * protection against faulty packet - there should be |
---|
1007 | * more sanity checks in header chain processing. |
---|
1008 | */ |
---|
1009 | if (m->m_pkthdr.len < off) { |
---|
1010 | IP6STAT_INC(ip6s_tooshort); |
---|
1011 | in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); |
---|
1012 | goto bad; |
---|
1013 | } |
---|
1014 | |
---|
1015 | #ifdef IPSEC |
---|
1016 | /* |
---|
1017 | * enforce IPsec policy checking if we are seeing last header. |
---|
1018 | * note that we do not visit this with protocols with pcb layer |
---|
1019 | * code - like udp/tcp/raw ip. |
---|
1020 | */ |
---|
1021 | if (ip6_ipsec_input(m, nxt)) |
---|
1022 | goto bad; |
---|
1023 | #endif /* IPSEC */ |
---|
1024 | |
---|
1025 | /* |
---|
1026 | * Use mbuf flags to propagate Router Alert option to |
---|
1027 | * ICMPv6 layer, as hop-by-hop options have been stripped. |
---|
1028 | */ |
---|
1029 | if (nxt == IPPROTO_ICMPV6 && rtalert != ~0) |
---|
1030 | m->m_flags |= M_RTALERT_MLD; |
---|
1031 | |
---|
1032 | nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); |
---|
1033 | } |
---|
1034 | goto out; |
---|
1035 | bad: |
---|
1036 | m_freem(m); |
---|
1037 | out: |
---|
1038 | if (rin6.ro_rt) |
---|
1039 | RTFREE(rin6.ro_rt); |
---|
1040 | } |
---|
1041 | |
---|
1042 | /* |
---|
1043 | * set/grab in6_ifaddr correspond to IPv6 destination address. |
---|
1044 | * XXX backward compatibility wrapper |
---|
1045 | * |
---|
1046 | * XXXRW: We should bump the refcount on ia6 before sticking it in the m_tag, |
---|
1047 | * and then bump it when the tag is copied, and release it when the tag is |
---|
1048 | * freed. Unfortunately, m_tags don't support deep copies (yet), so instead |
---|
1049 | * we just bump the ia refcount when we receive it. This should be fixed. |
---|
1050 | */ |
---|
1051 | static struct ip6aux * |
---|
1052 | ip6_setdstifaddr(struct mbuf *m, struct in6_ifaddr *ia6) |
---|
1053 | { |
---|
1054 | struct ip6aux *ip6a; |
---|
1055 | |
---|
1056 | ip6a = ip6_addaux(m); |
---|
1057 | if (ip6a) |
---|
1058 | ip6a->ip6a_dstia6 = ia6; |
---|
1059 | return ip6a; /* NULL if failed to set */ |
---|
1060 | } |
---|
1061 | |
---|
1062 | struct in6_ifaddr * |
---|
1063 | ip6_getdstifaddr(struct mbuf *m) |
---|
1064 | { |
---|
1065 | struct ip6aux *ip6a; |
---|
1066 | struct in6_ifaddr *ia; |
---|
1067 | |
---|
1068 | ip6a = ip6_findaux(m); |
---|
1069 | if (ip6a) { |
---|
1070 | ia = ip6a->ip6a_dstia6; |
---|
1071 | ifa_ref(&ia->ia_ifa); |
---|
1072 | return ia; |
---|
1073 | } else |
---|
1074 | return NULL; |
---|
1075 | } |
---|
1076 | |
---|
1077 | /* |
---|
1078 | * Hop-by-Hop options header processing. If a valid jumbo payload option is |
---|
1079 | * included, the real payload length will be stored in plenp. |
---|
1080 | * |
---|
1081 | * rtalertp - XXX: should be stored more smart way |
---|
1082 | */ |
---|
1083 | static int |
---|
1084 | ip6_hopopts_input(u_int32_t *plenp, u_int32_t *rtalertp, |
---|
1085 | struct mbuf **mp, int *offp) |
---|
1086 | { |
---|
1087 | struct mbuf *m = *mp; |
---|
1088 | int off = *offp, hbhlen; |
---|
1089 | struct ip6_hbh *hbh; |
---|
1090 | |
---|
1091 | /* validation of the length of the header */ |
---|
1092 | #ifndef PULLDOWN_TEST |
---|
1093 | IP6_EXTHDR_CHECK(m, off, sizeof(*hbh), -1); |
---|
1094 | hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off); |
---|
1095 | hbhlen = (hbh->ip6h_len + 1) << 3; |
---|
1096 | |
---|
1097 | IP6_EXTHDR_CHECK(m, off, hbhlen, -1); |
---|
1098 | hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off); |
---|
1099 | #else |
---|
1100 | IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, |
---|
1101 | sizeof(struct ip6_hdr), sizeof(struct ip6_hbh)); |
---|
1102 | if (hbh == NULL) { |
---|
1103 | IP6STAT_INC(ip6s_tooshort); |
---|
1104 | return -1; |
---|
1105 | } |
---|
1106 | hbhlen = (hbh->ip6h_len + 1) << 3; |
---|
1107 | IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), |
---|
1108 | hbhlen); |
---|
1109 | if (hbh == NULL) { |
---|
1110 | IP6STAT_INC(ip6s_tooshort); |
---|
1111 | return -1; |
---|
1112 | } |
---|
1113 | #endif |
---|
1114 | off += hbhlen; |
---|
1115 | hbhlen -= sizeof(struct ip6_hbh); |
---|
1116 | if (ip6_process_hopopts(m, (u_int8_t *)hbh + sizeof(struct ip6_hbh), |
---|
1117 | hbhlen, rtalertp, plenp) < 0) |
---|
1118 | return (-1); |
---|
1119 | |
---|
1120 | *offp = off; |
---|
1121 | *mp = m; |
---|
1122 | return (0); |
---|
1123 | } |
---|
1124 | |
---|
1125 | /* |
---|
1126 | * Search header for all Hop-by-hop options and process each option. |
---|
1127 | * This function is separate from ip6_hopopts_input() in order to |
---|
1128 | * handle a case where the sending node itself process its hop-by-hop |
---|
1129 | * options header. In such a case, the function is called from ip6_output(). |
---|
1130 | * |
---|
1131 | * The function assumes that hbh header is located right after the IPv6 header |
---|
1132 | * (RFC2460 p7), opthead is pointer into data content in m, and opthead to |
---|
1133 | * opthead + hbhlen is located in contiguous memory region. |
---|
1134 | */ |
---|
1135 | int |
---|
1136 | ip6_process_hopopts(struct mbuf *m, u_int8_t *opthead, int hbhlen, |
---|
1137 | u_int32_t *rtalertp, u_int32_t *plenp) |
---|
1138 | { |
---|
1139 | struct ip6_hdr *ip6; |
---|
1140 | int optlen = 0; |
---|
1141 | u_int8_t *opt = opthead; |
---|
1142 | u_int16_t rtalert_val; |
---|
1143 | u_int32_t jumboplen; |
---|
1144 | const int erroff = sizeof(struct ip6_hdr) + sizeof(struct ip6_hbh); |
---|
1145 | |
---|
1146 | for (; hbhlen > 0; hbhlen -= optlen, opt += optlen) { |
---|
1147 | switch (*opt) { |
---|
1148 | case IP6OPT_PAD1: |
---|
1149 | optlen = 1; |
---|
1150 | break; |
---|
1151 | case IP6OPT_PADN: |
---|
1152 | if (hbhlen < IP6OPT_MINLEN) { |
---|
1153 | IP6STAT_INC(ip6s_toosmall); |
---|
1154 | goto bad; |
---|
1155 | } |
---|
1156 | optlen = *(opt + 1) + 2; |
---|
1157 | break; |
---|
1158 | case IP6OPT_ROUTER_ALERT: |
---|
1159 | /* XXX may need check for alignment */ |
---|
1160 | if (hbhlen < IP6OPT_RTALERT_LEN) { |
---|
1161 | IP6STAT_INC(ip6s_toosmall); |
---|
1162 | goto bad; |
---|
1163 | } |
---|
1164 | if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2) { |
---|
1165 | /* XXX stat */ |
---|
1166 | icmp6_error(m, ICMP6_PARAM_PROB, |
---|
1167 | ICMP6_PARAMPROB_HEADER, |
---|
1168 | erroff + opt + 1 - opthead); |
---|
1169 | return (-1); |
---|
1170 | } |
---|
1171 | optlen = IP6OPT_RTALERT_LEN; |
---|
1172 | bcopy((caddr_t)(opt + 2), (caddr_t)&rtalert_val, 2); |
---|
1173 | *rtalertp = ntohs(rtalert_val); |
---|
1174 | break; |
---|
1175 | case IP6OPT_JUMBO: |
---|
1176 | /* XXX may need check for alignment */ |
---|
1177 | if (hbhlen < IP6OPT_JUMBO_LEN) { |
---|
1178 | IP6STAT_INC(ip6s_toosmall); |
---|
1179 | goto bad; |
---|
1180 | } |
---|
1181 | if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2) { |
---|
1182 | /* XXX stat */ |
---|
1183 | icmp6_error(m, ICMP6_PARAM_PROB, |
---|
1184 | ICMP6_PARAMPROB_HEADER, |
---|
1185 | erroff + opt + 1 - opthead); |
---|
1186 | return (-1); |
---|
1187 | } |
---|
1188 | optlen = IP6OPT_JUMBO_LEN; |
---|
1189 | |
---|
1190 | /* |
---|
1191 | * IPv6 packets that have non 0 payload length |
---|
1192 | * must not contain a jumbo payload option. |
---|
1193 | */ |
---|
1194 | ip6 = mtod(m, struct ip6_hdr *); |
---|
1195 | if (ip6->ip6_plen) { |
---|
1196 | IP6STAT_INC(ip6s_badoptions); |
---|
1197 | icmp6_error(m, ICMP6_PARAM_PROB, |
---|
1198 | ICMP6_PARAMPROB_HEADER, |
---|
1199 | erroff + opt - opthead); |
---|
1200 | return (-1); |
---|
1201 | } |
---|
1202 | |
---|
1203 | /* |
---|
1204 | * We may see jumbolen in unaligned location, so |
---|
1205 | * we'd need to perform bcopy(). |
---|
1206 | */ |
---|
1207 | bcopy(opt + 2, &jumboplen, sizeof(jumboplen)); |
---|
1208 | jumboplen = (u_int32_t)htonl(jumboplen); |
---|
1209 | |
---|
1210 | #if 1 |
---|
1211 | /* |
---|
1212 | * if there are multiple jumbo payload options, |
---|
1213 | * *plenp will be non-zero and the packet will be |
---|
1214 | * rejected. |
---|
1215 | * the behavior may need some debate in ipngwg - |
---|
1216 | * multiple options does not make sense, however, |
---|
1217 | * there's no explicit mention in specification. |
---|
1218 | */ |
---|
1219 | if (*plenp != 0) { |
---|
1220 | IP6STAT_INC(ip6s_badoptions); |
---|
1221 | icmp6_error(m, ICMP6_PARAM_PROB, |
---|
1222 | ICMP6_PARAMPROB_HEADER, |
---|
1223 | erroff + opt + 2 - opthead); |
---|
1224 | return (-1); |
---|
1225 | } |
---|
1226 | #endif |
---|
1227 | |
---|
1228 | /* |
---|
1229 | * jumbo payload length must be larger than 65535. |
---|
1230 | */ |
---|
1231 | if (jumboplen <= IPV6_MAXPACKET) { |
---|
1232 | IP6STAT_INC(ip6s_badoptions); |
---|
1233 | icmp6_error(m, ICMP6_PARAM_PROB, |
---|
1234 | ICMP6_PARAMPROB_HEADER, |
---|
1235 | erroff + opt + 2 - opthead); |
---|
1236 | return (-1); |
---|
1237 | } |
---|
1238 | *plenp = jumboplen; |
---|
1239 | |
---|
1240 | break; |
---|
1241 | default: /* unknown option */ |
---|
1242 | if (hbhlen < IP6OPT_MINLEN) { |
---|
1243 | IP6STAT_INC(ip6s_toosmall); |
---|
1244 | goto bad; |
---|
1245 | } |
---|
1246 | optlen = ip6_unknown_opt(opt, m, |
---|
1247 | erroff + opt - opthead); |
---|
1248 | if (optlen == -1) |
---|
1249 | return (-1); |
---|
1250 | optlen += 2; |
---|
1251 | break; |
---|
1252 | } |
---|
1253 | } |
---|
1254 | |
---|
1255 | return (0); |
---|
1256 | |
---|
1257 | bad: |
---|
1258 | m_freem(m); |
---|
1259 | return (-1); |
---|
1260 | } |
---|
1261 | |
---|
1262 | /* |
---|
1263 | * Unknown option processing. |
---|
1264 | * The third argument `off' is the offset from the IPv6 header to the option, |
---|
1265 | * which is necessary if the IPv6 header the and option header and IPv6 header |
---|
1266 | * is not contiguous in order to return an ICMPv6 error. |
---|
1267 | */ |
---|
1268 | int |
---|
1269 | ip6_unknown_opt(u_int8_t *optp, struct mbuf *m, int off) |
---|
1270 | { |
---|
1271 | struct ip6_hdr *ip6; |
---|
1272 | |
---|
1273 | switch (IP6OPT_TYPE(*optp)) { |
---|
1274 | case IP6OPT_TYPE_SKIP: /* ignore the option */ |
---|
1275 | return ((int)*(optp + 1)); |
---|
1276 | case IP6OPT_TYPE_DISCARD: /* silently discard */ |
---|
1277 | m_freem(m); |
---|
1278 | return (-1); |
---|
1279 | case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */ |
---|
1280 | IP6STAT_INC(ip6s_badoptions); |
---|
1281 | icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off); |
---|
1282 | return (-1); |
---|
1283 | case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */ |
---|
1284 | IP6STAT_INC(ip6s_badoptions); |
---|
1285 | ip6 = mtod(m, struct ip6_hdr *); |
---|
1286 | if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || |
---|
1287 | (m->m_flags & (M_BCAST|M_MCAST))) |
---|
1288 | m_freem(m); |
---|
1289 | else |
---|
1290 | icmp6_error(m, ICMP6_PARAM_PROB, |
---|
1291 | ICMP6_PARAMPROB_OPTION, off); |
---|
1292 | return (-1); |
---|
1293 | } |
---|
1294 | |
---|
1295 | m_freem(m); /* XXX: NOTREACHED */ |
---|
1296 | return (-1); |
---|
1297 | } |
---|
1298 | |
---|
1299 | /* |
---|
1300 | * Create the "control" list for this pcb. |
---|
1301 | * These functions will not modify mbuf chain at all. |
---|
1302 | * |
---|
1303 | * With KAME mbuf chain restriction: |
---|
1304 | * The routine will be called from upper layer handlers like tcp6_input(). |
---|
1305 | * Thus the routine assumes that the caller (tcp6_input) have already |
---|
1306 | * called IP6_EXTHDR_CHECK() and all the extension headers are located in the |
---|
1307 | * very first mbuf on the mbuf chain. |
---|
1308 | * |
---|
1309 | * ip6_savecontrol_v4 will handle those options that are possible to be |
---|
1310 | * set on a v4-mapped socket. |
---|
1311 | * ip6_savecontrol will directly call ip6_savecontrol_v4 to handle those |
---|
1312 | * options and handle the v6-only ones itself. |
---|
1313 | */ |
---|
1314 | struct mbuf ** |
---|
1315 | ip6_savecontrol_v4(struct inpcb *inp, struct mbuf *m, struct mbuf **mp, |
---|
1316 | int *v4only) |
---|
1317 | { |
---|
1318 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); |
---|
1319 | |
---|
1320 | #ifdef SO_TIMESTAMP |
---|
1321 | if ((inp->inp_socket->so_options & SO_TIMESTAMP) != 0) { |
---|
1322 | struct timeval tv; |
---|
1323 | |
---|
1324 | microtime(&tv); |
---|
1325 | *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), |
---|
1326 | SCM_TIMESTAMP, SOL_SOCKET); |
---|
1327 | if (*mp) |
---|
1328 | mp = &(*mp)->m_next; |
---|
1329 | } |
---|
1330 | #endif |
---|
1331 | |
---|
1332 | #define IS2292(inp, x, y) (((inp)->inp_flags & IN6P_RFC2292) ? (x) : (y)) |
---|
1333 | /* RFC 2292 sec. 5 */ |
---|
1334 | if ((inp->inp_flags & IN6P_PKTINFO) != 0) { |
---|
1335 | struct in6_pktinfo pi6; |
---|
1336 | |
---|
1337 | if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { |
---|
1338 | #ifdef INET |
---|
1339 | struct ip *ip; |
---|
1340 | |
---|
1341 | ip = mtod(m, struct ip *); |
---|
1342 | pi6.ipi6_addr.s6_addr32[0] = 0; |
---|
1343 | pi6.ipi6_addr.s6_addr32[1] = 0; |
---|
1344 | pi6.ipi6_addr.s6_addr32[2] = IPV6_ADDR_INT32_SMP; |
---|
1345 | pi6.ipi6_addr.s6_addr32[3] = ip->ip_dst.s_addr; |
---|
1346 | #else |
---|
1347 | /* We won't hit this code */ |
---|
1348 | bzero(&pi6.ipi6_addr, sizeof(struct in6_addr)); |
---|
1349 | #endif |
---|
1350 | } else { |
---|
1351 | bcopy(&ip6->ip6_dst, &pi6.ipi6_addr, sizeof(struct in6_addr)); |
---|
1352 | in6_clearscope(&pi6.ipi6_addr); /* XXX */ |
---|
1353 | } |
---|
1354 | pi6.ipi6_ifindex = |
---|
1355 | (m && m->m_pkthdr.rcvif) ? m->m_pkthdr.rcvif->if_index : 0; |
---|
1356 | |
---|
1357 | *mp = sbcreatecontrol((caddr_t) &pi6, |
---|
1358 | sizeof(struct in6_pktinfo), |
---|
1359 | IS2292(inp, IPV6_2292PKTINFO, IPV6_PKTINFO), IPPROTO_IPV6); |
---|
1360 | if (*mp) |
---|
1361 | mp = &(*mp)->m_next; |
---|
1362 | } |
---|
1363 | |
---|
1364 | if ((inp->inp_flags & IN6P_HOPLIMIT) != 0) { |
---|
1365 | int hlim; |
---|
1366 | |
---|
1367 | if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { |
---|
1368 | #ifdef INET |
---|
1369 | struct ip *ip; |
---|
1370 | |
---|
1371 | ip = mtod(m, struct ip *); |
---|
1372 | hlim = ip->ip_ttl; |
---|
1373 | #else |
---|
1374 | /* We won't hit this code */ |
---|
1375 | hlim = 0; |
---|
1376 | #endif |
---|
1377 | } else { |
---|
1378 | hlim = ip6->ip6_hlim & 0xff; |
---|
1379 | } |
---|
1380 | *mp = sbcreatecontrol((caddr_t) &hlim, sizeof(int), |
---|
1381 | IS2292(inp, IPV6_2292HOPLIMIT, IPV6_HOPLIMIT), |
---|
1382 | IPPROTO_IPV6); |
---|
1383 | if (*mp) |
---|
1384 | mp = &(*mp)->m_next; |
---|
1385 | } |
---|
1386 | |
---|
1387 | if ((inp->inp_flags & IN6P_TCLASS) != 0) { |
---|
1388 | int tclass; |
---|
1389 | |
---|
1390 | if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { |
---|
1391 | #ifdef INET |
---|
1392 | struct ip *ip; |
---|
1393 | |
---|
1394 | ip = mtod(m, struct ip *); |
---|
1395 | tclass = ip->ip_tos; |
---|
1396 | #else |
---|
1397 | /* We won't hit this code */ |
---|
1398 | tclass = 0; |
---|
1399 | #endif |
---|
1400 | } else { |
---|
1401 | u_int32_t flowinfo; |
---|
1402 | |
---|
1403 | flowinfo = (u_int32_t)ntohl(ip6->ip6_flow & IPV6_FLOWINFO_MASK); |
---|
1404 | flowinfo >>= 20; |
---|
1405 | tclass = flowinfo & 0xff; |
---|
1406 | } |
---|
1407 | *mp = sbcreatecontrol((caddr_t) &tclass, sizeof(int), |
---|
1408 | IPV6_TCLASS, IPPROTO_IPV6); |
---|
1409 | if (*mp) |
---|
1410 | mp = &(*mp)->m_next; |
---|
1411 | } |
---|
1412 | |
---|
1413 | if (v4only != NULL) { |
---|
1414 | if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { |
---|
1415 | *v4only = 1; |
---|
1416 | } else { |
---|
1417 | *v4only = 0; |
---|
1418 | } |
---|
1419 | } |
---|
1420 | |
---|
1421 | return (mp); |
---|
1422 | } |
---|
1423 | |
---|
1424 | void |
---|
1425 | ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp) |
---|
1426 | { |
---|
1427 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); |
---|
1428 | int v4only = 0; |
---|
1429 | |
---|
1430 | mp = ip6_savecontrol_v4(in6p, m, mp, &v4only); |
---|
1431 | if (v4only) |
---|
1432 | return; |
---|
1433 | |
---|
1434 | /* |
---|
1435 | * IPV6_HOPOPTS socket option. Recall that we required super-user |
---|
1436 | * privilege for the option (see ip6_ctloutput), but it might be too |
---|
1437 | * strict, since there might be some hop-by-hop options which can be |
---|
1438 | * returned to normal user. |
---|
1439 | * See also RFC 2292 section 6 (or RFC 3542 section 8). |
---|
1440 | */ |
---|
1441 | if ((in6p->inp_flags & IN6P_HOPOPTS) != 0) { |
---|
1442 | /* |
---|
1443 | * Check if a hop-by-hop options header is contatined in the |
---|
1444 | * received packet, and if so, store the options as ancillary |
---|
1445 | * data. Note that a hop-by-hop options header must be |
---|
1446 | * just after the IPv6 header, which is assured through the |
---|
1447 | * IPv6 input processing. |
---|
1448 | */ |
---|
1449 | if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { |
---|
1450 | struct ip6_hbh *hbh; |
---|
1451 | int hbhlen = 0; |
---|
1452 | #ifdef PULLDOWN_TEST |
---|
1453 | struct mbuf *ext; |
---|
1454 | #endif |
---|
1455 | |
---|
1456 | #ifndef PULLDOWN_TEST |
---|
1457 | hbh = (struct ip6_hbh *)(ip6 + 1); |
---|
1458 | hbhlen = (hbh->ip6h_len + 1) << 3; |
---|
1459 | #else |
---|
1460 | ext = ip6_pullexthdr(m, sizeof(struct ip6_hdr), |
---|
1461 | ip6->ip6_nxt); |
---|
1462 | if (ext == NULL) { |
---|
1463 | IP6STAT_INC(ip6s_tooshort); |
---|
1464 | return; |
---|
1465 | } |
---|
1466 | hbh = mtod(ext, struct ip6_hbh *); |
---|
1467 | hbhlen = (hbh->ip6h_len + 1) << 3; |
---|
1468 | if (hbhlen != ext->m_len) { |
---|
1469 | m_freem(ext); |
---|
1470 | IP6STAT_INC(ip6s_tooshort); |
---|
1471 | return; |
---|
1472 | } |
---|
1473 | #endif |
---|
1474 | |
---|
1475 | /* |
---|
1476 | * XXX: We copy the whole header even if a |
---|
1477 | * jumbo payload option is included, the option which |
---|
1478 | * is to be removed before returning according to |
---|
1479 | * RFC2292. |
---|
1480 | * Note: this constraint is removed in RFC3542 |
---|
1481 | */ |
---|
1482 | *mp = sbcreatecontrol((caddr_t)hbh, hbhlen, |
---|
1483 | IS2292(in6p, IPV6_2292HOPOPTS, IPV6_HOPOPTS), |
---|
1484 | IPPROTO_IPV6); |
---|
1485 | if (*mp) |
---|
1486 | mp = &(*mp)->m_next; |
---|
1487 | #ifdef PULLDOWN_TEST |
---|
1488 | m_freem(ext); |
---|
1489 | #endif |
---|
1490 | } |
---|
1491 | } |
---|
1492 | |
---|
1493 | if ((in6p->inp_flags & (IN6P_RTHDR | IN6P_DSTOPTS)) != 0) { |
---|
1494 | int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr); |
---|
1495 | |
---|
1496 | /* |
---|
1497 | * Search for destination options headers or routing |
---|
1498 | * header(s) through the header chain, and stores each |
---|
1499 | * header as ancillary data. |
---|
1500 | * Note that the order of the headers remains in |
---|
1501 | * the chain of ancillary data. |
---|
1502 | */ |
---|
1503 | while (1) { /* is explicit loop prevention necessary? */ |
---|
1504 | struct ip6_ext *ip6e = NULL; |
---|
1505 | int elen; |
---|
1506 | #ifdef PULLDOWN_TEST |
---|
1507 | struct mbuf *ext = NULL; |
---|
1508 | #endif |
---|
1509 | |
---|
1510 | /* |
---|
1511 | * if it is not an extension header, don't try to |
---|
1512 | * pull it from the chain. |
---|
1513 | */ |
---|
1514 | switch (nxt) { |
---|
1515 | case IPPROTO_DSTOPTS: |
---|
1516 | case IPPROTO_ROUTING: |
---|
1517 | case IPPROTO_HOPOPTS: |
---|
1518 | case IPPROTO_AH: /* is it possible? */ |
---|
1519 | break; |
---|
1520 | default: |
---|
1521 | goto loopend; |
---|
1522 | } |
---|
1523 | |
---|
1524 | #ifndef PULLDOWN_TEST |
---|
1525 | if (off + sizeof(*ip6e) > m->m_len) |
---|
1526 | goto loopend; |
---|
1527 | ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + off); |
---|
1528 | if (nxt == IPPROTO_AH) |
---|
1529 | elen = (ip6e->ip6e_len + 2) << 2; |
---|
1530 | else |
---|
1531 | elen = (ip6e->ip6e_len + 1) << 3; |
---|
1532 | if (off + elen > m->m_len) |
---|
1533 | goto loopend; |
---|
1534 | #else |
---|
1535 | ext = ip6_pullexthdr(m, off, nxt); |
---|
1536 | if (ext == NULL) { |
---|
1537 | IP6STAT_INC(ip6s_tooshort); |
---|
1538 | return; |
---|
1539 | } |
---|
1540 | ip6e = mtod(ext, struct ip6_ext *); |
---|
1541 | if (nxt == IPPROTO_AH) |
---|
1542 | elen = (ip6e->ip6e_len + 2) << 2; |
---|
1543 | else |
---|
1544 | elen = (ip6e->ip6e_len + 1) << 3; |
---|
1545 | if (elen != ext->m_len) { |
---|
1546 | m_freem(ext); |
---|
1547 | IP6STAT_INC(ip6s_tooshort); |
---|
1548 | return; |
---|
1549 | } |
---|
1550 | #endif |
---|
1551 | |
---|
1552 | switch (nxt) { |
---|
1553 | case IPPROTO_DSTOPTS: |
---|
1554 | if (!(in6p->inp_flags & IN6P_DSTOPTS)) |
---|
1555 | break; |
---|
1556 | |
---|
1557 | *mp = sbcreatecontrol((caddr_t)ip6e, elen, |
---|
1558 | IS2292(in6p, |
---|
1559 | IPV6_2292DSTOPTS, IPV6_DSTOPTS), |
---|
1560 | IPPROTO_IPV6); |
---|
1561 | if (*mp) |
---|
1562 | mp = &(*mp)->m_next; |
---|
1563 | break; |
---|
1564 | case IPPROTO_ROUTING: |
---|
1565 | if (!(in6p->inp_flags & IN6P_RTHDR)) |
---|
1566 | break; |
---|
1567 | |
---|
1568 | *mp = sbcreatecontrol((caddr_t)ip6e, elen, |
---|
1569 | IS2292(in6p, IPV6_2292RTHDR, IPV6_RTHDR), |
---|
1570 | IPPROTO_IPV6); |
---|
1571 | if (*mp) |
---|
1572 | mp = &(*mp)->m_next; |
---|
1573 | break; |
---|
1574 | case IPPROTO_HOPOPTS: |
---|
1575 | case IPPROTO_AH: /* is it possible? */ |
---|
1576 | break; |
---|
1577 | |
---|
1578 | default: |
---|
1579 | /* |
---|
1580 | * other cases have been filtered in the above. |
---|
1581 | * none will visit this case. here we supply |
---|
1582 | * the code just in case (nxt overwritten or |
---|
1583 | * other cases). |
---|
1584 | */ |
---|
1585 | #ifdef PULLDOWN_TEST |
---|
1586 | m_freem(ext); |
---|
1587 | #endif |
---|
1588 | goto loopend; |
---|
1589 | |
---|
1590 | } |
---|
1591 | |
---|
1592 | /* proceed with the next header. */ |
---|
1593 | off += elen; |
---|
1594 | nxt = ip6e->ip6e_nxt; |
---|
1595 | ip6e = NULL; |
---|
1596 | #ifdef PULLDOWN_TEST |
---|
1597 | m_freem(ext); |
---|
1598 | ext = NULL; |
---|
1599 | #endif |
---|
1600 | } |
---|
1601 | loopend: |
---|
1602 | ; |
---|
1603 | } |
---|
1604 | } |
---|
1605 | #undef IS2292 |
---|
1606 | |
---|
1607 | void |
---|
1608 | ip6_notify_pmtu(struct inpcb *inp, struct sockaddr_in6 *dst, u_int32_t mtu) |
---|
1609 | { |
---|
1610 | struct socket *so; |
---|
1611 | struct mbuf *m_mtu; |
---|
1612 | struct ip6_mtuinfo mtuctl; |
---|
1613 | |
---|
1614 | KASSERT(inp != NULL, ("%s: inp == NULL", __func__)); |
---|
1615 | /* |
---|
1616 | * Notify the error by sending IPV6_PATHMTU ancillary data if |
---|
1617 | * application wanted to know the MTU value. |
---|
1618 | * NOTE: we notify disconnected sockets, because some udp |
---|
1619 | * applications keep sending sockets disconnected. |
---|
1620 | * NOTE: our implementation doesn't notify connected sockets that has |
---|
1621 | * foreign address that is different than given destination addresses |
---|
1622 | * (this is permitted by RFC 3542). |
---|
1623 | */ |
---|
1624 | if ((inp->inp_flags & IN6P_MTU) == 0 || ( |
---|
1625 | !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) && |
---|
1626 | !IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, &dst->sin6_addr))) |
---|
1627 | return; |
---|
1628 | |
---|
1629 | mtuctl.ip6m_mtu = mtu; |
---|
1630 | mtuctl.ip6m_addr = *dst; |
---|
1631 | if (sa6_recoverscope(&mtuctl.ip6m_addr)) |
---|
1632 | return; |
---|
1633 | |
---|
1634 | if ((m_mtu = sbcreatecontrol((caddr_t)&mtuctl, sizeof(mtuctl), |
---|
1635 | IPV6_PATHMTU, IPPROTO_IPV6)) == NULL) |
---|
1636 | return; |
---|
1637 | |
---|
1638 | so = inp->inp_socket; |
---|
1639 | if (sbappendaddr(&so->so_rcv, (struct sockaddr *)dst, NULL, m_mtu) |
---|
1640 | == 0) { |
---|
1641 | m_freem(m_mtu); |
---|
1642 | /* XXX: should count statistics */ |
---|
1643 | } else |
---|
1644 | sorwakeup(so); |
---|
1645 | } |
---|
1646 | |
---|
1647 | #ifdef PULLDOWN_TEST |
---|
1648 | /* |
---|
1649 | * pull single extension header from mbuf chain. returns single mbuf that |
---|
1650 | * contains the result, or NULL on error. |
---|
1651 | */ |
---|
1652 | static struct mbuf * |
---|
1653 | ip6_pullexthdr(struct mbuf *m, size_t off, int nxt) |
---|
1654 | { |
---|
1655 | struct ip6_ext ip6e; |
---|
1656 | size_t elen; |
---|
1657 | struct mbuf *n; |
---|
1658 | |
---|
1659 | #ifdef DIAGNOSTIC |
---|
1660 | switch (nxt) { |
---|
1661 | case IPPROTO_DSTOPTS: |
---|
1662 | case IPPROTO_ROUTING: |
---|
1663 | case IPPROTO_HOPOPTS: |
---|
1664 | case IPPROTO_AH: /* is it possible? */ |
---|
1665 | break; |
---|
1666 | default: |
---|
1667 | printf("ip6_pullexthdr: invalid nxt=%d\n", nxt); |
---|
1668 | } |
---|
1669 | #endif |
---|
1670 | |
---|
1671 | m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); |
---|
1672 | if (nxt == IPPROTO_AH) |
---|
1673 | elen = (ip6e.ip6e_len + 2) << 2; |
---|
1674 | else |
---|
1675 | elen = (ip6e.ip6e_len + 1) << 3; |
---|
1676 | |
---|
1677 | MGET(n, M_DONTWAIT, MT_DATA); |
---|
1678 | if (n && elen >= MLEN) { |
---|
1679 | MCLGET(n, M_DONTWAIT); |
---|
1680 | if ((n->m_flags & M_EXT) == 0) { |
---|
1681 | m_free(n); |
---|
1682 | n = NULL; |
---|
1683 | } |
---|
1684 | } |
---|
1685 | if (!n) |
---|
1686 | return NULL; |
---|
1687 | |
---|
1688 | n->m_len = 0; |
---|
1689 | if (elen >= M_TRAILINGSPACE(n)) { |
---|
1690 | m_free(n); |
---|
1691 | return NULL; |
---|
1692 | } |
---|
1693 | |
---|
1694 | m_copydata(m, off, elen, mtod(n, caddr_t)); |
---|
1695 | n->m_len = elen; |
---|
1696 | return n; |
---|
1697 | } |
---|
1698 | #endif |
---|
1699 | |
---|
1700 | /* |
---|
1701 | * Get pointer to the previous header followed by the header |
---|
1702 | * currently processed. |
---|
1703 | * XXX: This function supposes that |
---|
1704 | * M includes all headers, |
---|
1705 | * the next header field and the header length field of each header |
---|
1706 | * are valid, and |
---|
1707 | * the sum of each header length equals to OFF. |
---|
1708 | * Because of these assumptions, this function must be called very |
---|
1709 | * carefully. Moreover, it will not be used in the near future when |
---|
1710 | * we develop `neater' mechanism to process extension headers. |
---|
1711 | */ |
---|
1712 | char * |
---|
1713 | ip6_get_prevhdr(struct mbuf *m, int off) |
---|
1714 | { |
---|
1715 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); |
---|
1716 | |
---|
1717 | if (off == sizeof(struct ip6_hdr)) |
---|
1718 | return (&ip6->ip6_nxt); |
---|
1719 | else { |
---|
1720 | int len, nxt; |
---|
1721 | struct ip6_ext *ip6e = NULL; |
---|
1722 | |
---|
1723 | nxt = ip6->ip6_nxt; |
---|
1724 | len = sizeof(struct ip6_hdr); |
---|
1725 | while (len < off) { |
---|
1726 | ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + len); |
---|
1727 | |
---|
1728 | switch (nxt) { |
---|
1729 | case IPPROTO_FRAGMENT: |
---|
1730 | len += sizeof(struct ip6_frag); |
---|
1731 | break; |
---|
1732 | case IPPROTO_AH: |
---|
1733 | len += (ip6e->ip6e_len + 2) << 2; |
---|
1734 | break; |
---|
1735 | default: |
---|
1736 | len += (ip6e->ip6e_len + 1) << 3; |
---|
1737 | break; |
---|
1738 | } |
---|
1739 | nxt = ip6e->ip6e_nxt; |
---|
1740 | } |
---|
1741 | if (ip6e) |
---|
1742 | return (&ip6e->ip6e_nxt); |
---|
1743 | else |
---|
1744 | return NULL; |
---|
1745 | } |
---|
1746 | } |
---|
1747 | |
---|
1748 | /* |
---|
1749 | * get next header offset. m will be retained. |
---|
1750 | */ |
---|
1751 | int |
---|
1752 | ip6_nexthdr(struct mbuf *m, int off, int proto, int *nxtp) |
---|
1753 | { |
---|
1754 | struct ip6_hdr ip6; |
---|
1755 | struct ip6_ext ip6e; |
---|
1756 | struct ip6_frag fh; |
---|
1757 | |
---|
1758 | /* just in case */ |
---|
1759 | if (m == NULL) |
---|
1760 | panic("ip6_nexthdr: m == NULL"); |
---|
1761 | if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.len < off) |
---|
1762 | return -1; |
---|
1763 | |
---|
1764 | switch (proto) { |
---|
1765 | case IPPROTO_IPV6: |
---|
1766 | if (m->m_pkthdr.len < off + sizeof(ip6)) |
---|
1767 | return -1; |
---|
1768 | m_copydata(m, off, sizeof(ip6), (caddr_t)&ip6); |
---|
1769 | if (nxtp) |
---|
1770 | *nxtp = ip6.ip6_nxt; |
---|
1771 | off += sizeof(ip6); |
---|
1772 | return off; |
---|
1773 | |
---|
1774 | case IPPROTO_FRAGMENT: |
---|
1775 | /* |
---|
1776 | * terminate parsing if it is not the first fragment, |
---|
1777 | * it does not make sense to parse through it. |
---|
1778 | */ |
---|
1779 | if (m->m_pkthdr.len < off + sizeof(fh)) |
---|
1780 | return -1; |
---|
1781 | m_copydata(m, off, sizeof(fh), (caddr_t)&fh); |
---|
1782 | /* IP6F_OFF_MASK = 0xfff8(BigEndian), 0xf8ff(LittleEndian) */ |
---|
1783 | if (fh.ip6f_offlg & IP6F_OFF_MASK) |
---|
1784 | return -1; |
---|
1785 | if (nxtp) |
---|
1786 | *nxtp = fh.ip6f_nxt; |
---|
1787 | off += sizeof(struct ip6_frag); |
---|
1788 | return off; |
---|
1789 | |
---|
1790 | case IPPROTO_AH: |
---|
1791 | if (m->m_pkthdr.len < off + sizeof(ip6e)) |
---|
1792 | return -1; |
---|
1793 | m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); |
---|
1794 | if (nxtp) |
---|
1795 | *nxtp = ip6e.ip6e_nxt; |
---|
1796 | off += (ip6e.ip6e_len + 2) << 2; |
---|
1797 | return off; |
---|
1798 | |
---|
1799 | case IPPROTO_HOPOPTS: |
---|
1800 | case IPPROTO_ROUTING: |
---|
1801 | case IPPROTO_DSTOPTS: |
---|
1802 | if (m->m_pkthdr.len < off + sizeof(ip6e)) |
---|
1803 | return -1; |
---|
1804 | m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); |
---|
1805 | if (nxtp) |
---|
1806 | *nxtp = ip6e.ip6e_nxt; |
---|
1807 | off += (ip6e.ip6e_len + 1) << 3; |
---|
1808 | return off; |
---|
1809 | |
---|
1810 | case IPPROTO_NONE: |
---|
1811 | case IPPROTO_ESP: |
---|
1812 | case IPPROTO_IPCOMP: |
---|
1813 | /* give up */ |
---|
1814 | return -1; |
---|
1815 | |
---|
1816 | default: |
---|
1817 | return -1; |
---|
1818 | } |
---|
1819 | |
---|
1820 | return -1; |
---|
1821 | } |
---|
1822 | |
---|
1823 | /* |
---|
1824 | * get offset for the last header in the chain. m will be kept untainted. |
---|
1825 | */ |
---|
1826 | int |
---|
1827 | ip6_lasthdr(struct mbuf *m, int off, int proto, int *nxtp) |
---|
1828 | { |
---|
1829 | int newoff; |
---|
1830 | int nxt; |
---|
1831 | |
---|
1832 | if (!nxtp) { |
---|
1833 | nxt = -1; |
---|
1834 | nxtp = &nxt; |
---|
1835 | } |
---|
1836 | while (1) { |
---|
1837 | newoff = ip6_nexthdr(m, off, proto, nxtp); |
---|
1838 | if (newoff < 0) |
---|
1839 | return off; |
---|
1840 | else if (newoff < off) |
---|
1841 | return -1; /* invalid */ |
---|
1842 | else if (newoff == off) |
---|
1843 | return newoff; |
---|
1844 | |
---|
1845 | off = newoff; |
---|
1846 | proto = *nxtp; |
---|
1847 | } |
---|
1848 | } |
---|
1849 | |
---|
1850 | static struct ip6aux * |
---|
1851 | ip6_addaux(struct mbuf *m) |
---|
1852 | { |
---|
1853 | struct m_tag *mtag; |
---|
1854 | |
---|
1855 | mtag = m_tag_find(m, PACKET_TAG_IPV6_INPUT, NULL); |
---|
1856 | if (!mtag) { |
---|
1857 | mtag = m_tag_get(PACKET_TAG_IPV6_INPUT, sizeof(struct ip6aux), |
---|
1858 | M_NOWAIT); |
---|
1859 | if (mtag) { |
---|
1860 | m_tag_prepend(m, mtag); |
---|
1861 | bzero(mtag + 1, sizeof(struct ip6aux)); |
---|
1862 | } |
---|
1863 | } |
---|
1864 | return mtag ? (struct ip6aux *)(mtag + 1) : NULL; |
---|
1865 | } |
---|
1866 | |
---|
1867 | static struct ip6aux * |
---|
1868 | ip6_findaux(struct mbuf *m) |
---|
1869 | { |
---|
1870 | struct m_tag *mtag; |
---|
1871 | |
---|
1872 | mtag = m_tag_find(m, PACKET_TAG_IPV6_INPUT, NULL); |
---|
1873 | return mtag ? (struct ip6aux *)(mtag + 1) : NULL; |
---|
1874 | } |
---|
1875 | |
---|
1876 | static void |
---|
1877 | ip6_delaux(struct mbuf *m) |
---|
1878 | { |
---|
1879 | struct m_tag *mtag; |
---|
1880 | |
---|
1881 | mtag = m_tag_find(m, PACKET_TAG_IPV6_INPUT, NULL); |
---|
1882 | if (mtag) |
---|
1883 | m_tag_delete(m, mtag); |
---|
1884 | } |
---|
1885 | |
---|
1886 | /* |
---|
1887 | * System control for IP6 |
---|
1888 | */ |
---|
1889 | |
---|
1890 | u_char inet6ctlerrmap[PRC_NCMDS] = { |
---|
1891 | 0, 0, 0, 0, |
---|
1892 | 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, |
---|
1893 | EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, |
---|
1894 | EMSGSIZE, EHOSTUNREACH, 0, 0, |
---|
1895 | 0, 0, 0, 0, |
---|
1896 | ENOPROTOOPT |
---|
1897 | }; |
---|