Annotation of src/sys/netinet6/ip6_input.c, Revision 1.17
1.17 ! itojun 1: /* $NetBSD: ip6_input.c,v 1.16 2000/02/20 00:56:43 darrenr Exp $ */
! 2: /* $KAME: ip6_input.c,v 1.72 2000/03/21 09:23:19 itojun Exp $ */
1.3 thorpej 3:
1.2 itojun 4: /*
5: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6: * All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
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
18: * without specific prior written permission.
19: *
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
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
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
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
30: * SUCH DAMAGE.
31: */
32:
33: /*
34: * Copyright (c) 1982, 1986, 1988, 1993
35: * The Regents of the University of California. All rights reserved.
36: *
37: * Redistribution and use in source and binary forms, with or without
38: * modification, are permitted provided that the following conditions
39: * are met:
40: * 1. Redistributions of source code must retain the above copyright
41: * notice, this list of conditions and the following disclaimer.
42: * 2. Redistributions in binary form must reproduce the above copyright
43: * notice, this list of conditions and the following disclaimer in the
44: * documentation and/or other materials provided with the distribution.
45: * 3. All advertising materials mentioning features or use of this software
46: * must display the following acknowledgement:
47: * This product includes software developed by the University of
48: * California, Berkeley and its contributors.
49: * 4. Neither the name of the University nor the names of its contributors
50: * may be used to endorse or promote products derived from this software
51: * without specific prior written permission.
52: *
53: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63: * SUCH DAMAGE.
64: *
65: * @(#)ip_input.c 8.2 (Berkeley) 1/4/94
66: */
67:
68: #include "opt_inet.h"
1.4 thorpej 69: #include "opt_ipsec.h"
1.15 darrenr 70: #include "opt_pfil_hooks.h"
1.2 itojun 71:
72: #include <sys/param.h>
73: #include <sys/systm.h>
74: #include <sys/malloc.h>
75: #include <sys/mbuf.h>
76: #include <sys/domain.h>
77: #include <sys/protosw.h>
78: #include <sys/socket.h>
79: #include <sys/socketvar.h>
80: #include <sys/errno.h>
81: #include <sys/time.h>
82: #include <sys/kernel.h>
83: #include <sys/syslog.h>
84: #include <sys/proc.h>
85:
86: #include <net/if.h>
87: #include <net/if_types.h>
88: #include <net/if_dl.h>
89: #include <net/route.h>
90: #include <net/netisr.h>
1.15 darrenr 91: #ifdef PFIL_HOOKS
92: #include <net/pfil.h>
93: #endif
1.2 itojun 94:
95: #include <netinet/in.h>
1.9 itojun 96: #include <netinet/in_systm.h>
97: #ifdef INET
98: #include <netinet/ip.h>
99: #include <netinet/ip_icmp.h>
100: #endif /*INET*/
1.14 itojun 101: #include <netinet/ip6.h>
1.2 itojun 102: #include <netinet6/in6_var.h>
1.11 itojun 103: #include <netinet6/ip6_var.h>
1.2 itojun 104: #include <netinet6/in6_pcb.h>
1.14 itojun 105: #include <netinet/icmp6.h>
1.2 itojun 106: #include <netinet6/in6_ifattach.h>
107: #include <netinet6/nd6.h>
1.9 itojun 108: #include <netinet6/in6_prefix.h>
1.2 itojun 109:
1.9 itojun 110: #ifdef IPV6FIREWALL
111: #include <netinet6/ip6_fw.h>
112: #endif
1.2 itojun 113:
114: #include <netinet6/ip6protosw.h>
115:
116: /* we need it for NLOOP. */
117: #include "loop.h"
118: #include "faith.h"
119:
120: #include "gif.h"
121: #include "bpfilter.h"
122:
1.9 itojun 123: #include <net/net_osdep.h>
124:
1.2 itojun 125: extern struct domain inet6domain;
126:
127: u_char ip6_protox[IPPROTO_MAX];
128: static int ip6qmaxlen = IFQ_MAXLEN;
129: struct in6_ifaddr *in6_ifaddr;
130: struct ifqueue ip6intrq;
131:
132: extern struct ifnet loif[NLOOP];
133: int ip6_forward_srcrt; /* XXX */
134: int ip6_sourcecheck; /* XXX */
135: int ip6_sourcecheck_interval; /* XXX */
1.9 itojun 136:
137: #ifdef IPV6FIREWALL
138: /* firewall hooks */
139: ip6_fw_chk_t *ip6_fw_chk_ptr;
140: ip6_fw_ctl_t *ip6_fw_ctl_ptr;
1.2 itojun 141: #endif
142:
143: struct ip6stat ip6stat;
144:
145: static void ip6_init2 __P((void *));
146:
1.5 itojun 147: static int ip6_hopopts_input __P((u_int32_t *, u_int32_t *, struct mbuf **, int *));
1.2 itojun 148:
1.12 itojun 149: #ifdef PTR
1.9 itojun 150: extern int ip6_protocol_tr;
151:
152: int ptr_in6 __P((struct mbuf *, struct mbuf **));
153: extern void ip_forward __P((struct mbuf *, int));
154: #endif
155:
1.2 itojun 156: /*
157: * IP6 initialization: fill in IP6 protocol switch table.
158: * All protocols not implemented in kernel go to raw IP6 protocol handler.
159: */
160: void
161: ip6_init()
162: {
163: register struct ip6protosw *pr;
164: register int i;
165: struct timeval tv;
166:
167: pr = (struct ip6protosw *)pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW);
168: if (pr == 0)
169: panic("ip6_init");
170: for (i = 0; i < IPPROTO_MAX; i++)
171: ip6_protox[i] = pr - inet6sw;
172: for (pr = (struct ip6protosw *)inet6domain.dom_protosw;
173: pr < (struct ip6protosw *)inet6domain.dom_protoswNPROTOSW; pr++)
174: if (pr->pr_domain->dom_family == PF_INET6 &&
175: pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
176: ip6_protox[pr->pr_protocol] = pr - inet6sw;
177: ip6intrq.ifq_maxlen = ip6qmaxlen;
178: nd6_init();
179: frag6_init();
1.9 itojun 180: #ifdef IPV6FIREWALL
181: ip6_fw_init();
182: #endif
1.2 itojun 183: /*
184: * in many cases, random() here does NOT return random number
185: * as initialization during bootstrap time occur in fixed order.
186: */
187: microtime(&tv);
188: ip6_flow_seq = random() ^ tv.tv_usec;
189:
190: ip6_init2((void *)0);
191: }
192:
193: static void
194: ip6_init2(dummy)
195: void *dummy;
196: {
1.9 itojun 197: int ret;
198:
199: /* get EUI64 from somewhere */
200: ret = in6_ifattach_getifid(NULL);
1.2 itojun 201:
202: /*
203: * to route local address of p2p link to loopback,
204: * assign loopback address first.
205: */
1.9 itojun 206: in6_ifattach(&loif[0], IN6_IFT_LOOP, NULL, 0);
1.2 itojun 207:
208: /* nd6_timer_init */
209: timeout(nd6_timer, (caddr_t)0, hz);
1.9 itojun 210: /* router renumbering prefix list maintenance */
211: timeout(in6_rr_timer, (caddr_t)0, hz);
1.2 itojun 212: }
213:
214: /*
215: * IP6 input interrupt handling. Just pass the packet to ip6_input.
216: */
217: void
218: ip6intr()
219: {
220: int s;
221: struct mbuf *m;
222:
223: for (;;) {
224: s = splimp();
225: IF_DEQUEUE(&ip6intrq, m);
226: splx(s);
227: if (m == 0)
228: return;
229: ip6_input(m);
230: }
231: }
232:
233: extern struct route_in6 ip6_forward_rt;
234:
235: void
236: ip6_input(m)
237: struct mbuf *m;
238: {
1.9 itojun 239: struct ip6_hdr *ip6;
1.2 itojun 240: int off = sizeof(struct ip6_hdr), nest;
241: u_int32_t plen;
1.5 itojun 242: u_int32_t rtalert = ~0;
1.2 itojun 243: int nxt, ours = 0;
1.9 itojun 244: struct ifnet *deliverifp = NULL;
1.15 darrenr 245: #ifdef PFIL_HOOKS
246: struct packet_filter_hook *pfh;
247: struct mbuf *m0;
248: int rv;
249: #endif /* PFIL_HOOKS */
1.2 itojun 250:
251: #ifdef IPSEC
252: /*
253: * should the inner packet be considered authentic?
254: * see comment in ah4_input().
255: */
256: if (m) {
257: m->m_flags &= ~M_AUTHIPHDR;
258: m->m_flags &= ~M_AUTHIPDGM;
259: }
260: #endif
1.9 itojun 261:
1.2 itojun 262: /*
263: * mbuf statistics by kazu
264: */
265: if (m->m_flags & M_EXT) {
266: if (m->m_next)
267: ip6stat.ip6s_mext2m++;
268: else
269: ip6stat.ip6s_mext1++;
270: } else {
271: if (m->m_next) {
1.9 itojun 272: if (m->m_flags & M_LOOP) {
1.2 itojun 273: ip6stat.ip6s_m2m[loif[0].if_index]++; /*XXX*/
1.9 itojun 274: }
1.2 itojun 275: else if (m->m_pkthdr.rcvif->if_index <= 31)
276: ip6stat.ip6s_m2m[m->m_pkthdr.rcvif->if_index]++;
277: else
278: ip6stat.ip6s_m2m[0]++;
279: } else
280: ip6stat.ip6s_m1++;
281: }
282:
1.9 itojun 283: in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive);
284: ip6stat.ip6s_total++;
285:
286: #ifndef PULLDOWN_TEST
287: /* XXX is the line really necessary? */
1.2 itojun 288: IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), /*nothing*/);
1.9 itojun 289: #endif
1.2 itojun 290:
1.9 itojun 291: if (m->m_len < sizeof(struct ip6_hdr)) {
292: struct ifnet *inifp;
293: inifp = m->m_pkthdr.rcvif;
294: if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == 0) {
295: ip6stat.ip6s_toosmall++;
296: in6_ifstat_inc(inifp, ifs6_in_hdrerr);
297: return;
298: }
1.2 itojun 299: }
300:
301: ip6 = mtod(m, struct ip6_hdr *);
302:
303: if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
304: ip6stat.ip6s_badvers++;
1.9 itojun 305: in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr);
1.2 itojun 306: goto bad;
307: }
1.15 darrenr 308:
309: #ifdef PFIL_HOOKS
310: /*
311: * Run through list of hooks for input packets. If there are any
312: * filters which require that additional packets in the flow are
313: * not fast-forwarded, they must clear the M_CANFASTFWD flag.
314: * Note that filters must _never_ set this flag, as another filter
315: * in the list may have previously cleared it.
316: */
317: m0 = m;
1.16 darrenr 318: pfh = pfil_hook_get(PFIL_IN, &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);
1.15 darrenr 319: for (; pfh; pfh = pfh->pfil_link.tqe_next)
320: if (pfh->pfil_func) {
321: rv = pfh->pfil_func(ip6, sizeof(*ip6),
322: m->m_pkthdr.rcvif, 0, &m0);
323: if (rv)
324: return;
325: m = m0;
326: if (m == NULL)
327: return;
328: ip6 = mtod(m, struct ip6_hdr *);
329: }
330: #endif /* PFIL_HOOKS */
331:
1.2 itojun 332:
333: ip6stat.ip6s_nxthist[ip6->ip6_nxt]++;
334:
1.9 itojun 335: #ifdef IPV6FIREWALL
336: /*
337: * Check with the firewall...
338: */
339: if (ip6_fw_chk_ptr) {
340: u_short port = 0;
341: /* If ipfw says divert, we have to just drop packet */
342: /* use port as a dummy argument */
343: if ((*ip6_fw_chk_ptr)(&ip6, NULL, &port, &m)) {
344: m_freem(m);
345: m = NULL;
346: }
347: if (!m)
348: return;
349: }
350: #endif
351:
1.2 itojun 352: /*
353: * Scope check
354: */
355: if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src) ||
356: IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) {
357: ip6stat.ip6s_badscope++;
1.9 itojun 358: in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
1.2 itojun 359: goto bad;
360: }
1.13 itojun 361: /*
362: * The following check is not documented in the spec. Malicious party
363: * may be able to use IPv4 mapped addr to confuse tcp/udp stack and
364: * bypass security checks (act as if it was from 127.0.0.1 by using
365: * IPv6 src ::ffff:127.0.0.1). Be cautious.
366: */
367: if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
368: IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
369: ip6stat.ip6s_badscope++;
370: in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
371: goto bad;
372: }
1.17 ! itojun 373: #if 0
1.13 itojun 374: /*
1.17 ! itojun 375: * Reject packets with IPv4 compatible addresses (auto tunnel).
! 376: *
! 377: * The code forbids auto tunnel relay case in RFC1933 (the check is
! 378: * stronger than RFC1933). We may want to re-enable it if mech-xx
! 379: * is revised to forbid relaying case.
1.13 itojun 380: */
381: if (IN6_IS_ADDR_V4COMPAT(&ip6->ip6_src) ||
382: IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) {
383: ip6stat.ip6s_badscope++;
384: in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
385: goto bad;
386: }
387: #endif
1.2 itojun 388: if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) ||
389: IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) {
390: if (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) {
391: ours = 1;
1.9 itojun 392: deliverifp = m->m_pkthdr.rcvif;
1.2 itojun 393: goto hbhcheck;
394: } else {
395: ip6stat.ip6s_badscope++;
1.9 itojun 396: in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
1.2 itojun 397: goto bad;
398: }
399: }
400:
401: if (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) {
402: if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) {
403: ours = 1;
1.9 itojun 404: deliverifp = m->m_pkthdr.rcvif;
1.2 itojun 405: goto hbhcheck;
406: }
407: } else {
408: if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
409: ip6->ip6_src.s6_addr16[1]
410: = htons(m->m_pkthdr.rcvif->if_index);
411: if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
412: ip6->ip6_dst.s6_addr16[1]
413: = htons(m->m_pkthdr.rcvif->if_index);
414: }
415:
1.12 itojun 416: #ifdef PTR
1.9 itojun 417: /*
418: *
419: */
420: if (ip6_protocol_tr)
421: {
422: struct mbuf *m1 = NULL;
423:
424: switch (ptr_in6(m, &m1))
425: {
426: case IPPROTO_IP: goto mcastcheck;
427: case IPPROTO_IPV4: ip_forward(m1, 0); break;
428: case IPPROTO_IPV6: ip6_forward(m1, 0); break;
429: case IPPROTO_MAX: /* discard this packet */
430: default:
431: }
432:
433: if (m != m1)
434: m_freem(m);
435:
436: return;
437: }
438:
439: mcastcheck:
440: #endif
441:
1.2 itojun 442: /*
443: * Multicast check
444: */
445: if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
446: struct in6_multi *in6m = 0;
1.9 itojun 447:
448: in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mcast);
1.2 itojun 449: /*
450: * See if we belong to the destination multicast group on the
451: * arrival interface.
452: */
453: IN6_LOOKUP_MULTI(ip6->ip6_dst, m->m_pkthdr.rcvif, in6m);
454: if (in6m)
455: ours = 1;
456: else if (!ip6_mrouter) {
457: ip6stat.ip6s_notmember++;
458: ip6stat.ip6s_cantforward++;
1.9 itojun 459: in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);
1.2 itojun 460: goto bad;
461: }
1.9 itojun 462: deliverifp = m->m_pkthdr.rcvif;
1.2 itojun 463: goto hbhcheck;
464: }
465:
466: /*
467: * Unicast check
468: */
469: if (ip6_forward_rt.ro_rt == 0 ||
470: !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
471: &ip6_forward_rt.ro_dst.sin6_addr)) {
472: if (ip6_forward_rt.ro_rt) {
473: RTFREE(ip6_forward_rt.ro_rt);
474: ip6_forward_rt.ro_rt = 0;
475: }
476: bzero(&ip6_forward_rt.ro_dst, sizeof(struct sockaddr_in6));
477: ip6_forward_rt.ro_dst.sin6_len = sizeof(struct sockaddr_in6);
478: ip6_forward_rt.ro_dst.sin6_family = AF_INET6;
479: ip6_forward_rt.ro_dst.sin6_addr = ip6->ip6_dst;
480:
1.9 itojun 481: rtalloc((struct route *)&ip6_forward_rt);
1.2 itojun 482: }
483:
484: #define rt6_key(r) ((struct sockaddr_in6 *)((r)->rt_nodes->rn_key))
485:
486: /*
487: * Accept the packet if the forwarding interface to the destination
488: * according to the routing table is the loopback interface,
489: * unless the associated route has a gateway.
490: * Note that this approach causes to accept a packet if there is a
491: * route to the loopback interface for the destination of the packet.
492: * But we think it's even useful in some situations, e.g. when using
493: * a special daemon which wants to intercept the packet.
494: */
495: if (ip6_forward_rt.ro_rt &&
496: (ip6_forward_rt.ro_rt->rt_flags &
497: (RTF_HOST|RTF_GATEWAY)) == RTF_HOST &&
498: #if 0
499: /*
500: * The check below is redundant since the comparison of
501: * the destination and the key of the rtentry has
502: * already done through looking up the routing table.
503: */
504: IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
505: &rt6_key(ip6_forward_rt.ro_rt)->sin6_addr) &&
506: #endif
1.9 itojun 507: ip6_forward_rt.ro_rt->rt_ifp->if_type == IFT_LOOP) {
1.2 itojun 508: struct in6_ifaddr *ia6 =
509: (struct in6_ifaddr *)ip6_forward_rt.ro_rt->rt_ifa;
510: /* packet to tentative address must not be received */
511: if (ia6->ia6_flags & IN6_IFF_ANYCAST)
512: m->m_flags |= M_ANYCAST6;
513: if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) {
514: /* this interface is ready */
515: ours = 1;
1.9 itojun 516: deliverifp = ia6->ia_ifp; /* correct? */
1.2 itojun 517: goto hbhcheck;
518: } else {
519: /* this interface is not ready, fall through */
520: }
521: }
522:
523: /*
524: * FAITH(Firewall Aided Internet Translator)
525: */
526: #if defined(NFAITH) && 0 < NFAITH
527: if (ip6_keepfaith) {
528: if (ip6_forward_rt.ro_rt && ip6_forward_rt.ro_rt->rt_ifp
529: && ip6_forward_rt.ro_rt->rt_ifp->if_type == IFT_FAITH) {
530: /* XXX do we need more sanity checks? */
531: ours = 1;
1.9 itojun 532: deliverifp = ip6_forward_rt.ro_rt->rt_ifp; /*faith*/
533: goto hbhcheck;
534: }
535: }
536: #endif
537:
538: #if 0
539: {
540: /*
541: * Last resort: check in6_ifaddr for incoming interface.
542: * The code is here until I update the "goto ours hack" code above
543: * working right.
544: */
545: struct ifaddr *ifa;
546: for (ifa = m->m_pkthdr.rcvif->if_addrlist.tqh_first;
547: ifa;
548: ifa = ifa->ifa_list.tqe_next) {
549: if (ifa->ifa_addr == NULL)
550: continue; /* just for safety */
551: if (ifa->ifa_addr->sa_family != AF_INET6)
552: continue;
553: if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ip6->ip6_dst)) {
554: ours = 1;
555: deliverifp = ifa->ifa_ifp;
1.2 itojun 556: goto hbhcheck;
557: }
558: }
1.9 itojun 559: }
1.2 itojun 560: #endif
561:
562: /*
563: * Now there is no reason to process the packet if it's not our own
564: * and we're not a router.
565: */
566: if (!ip6_forwarding) {
567: ip6stat.ip6s_cantforward++;
1.9 itojun 568: in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);
1.2 itojun 569: goto bad;
570: }
571:
572: hbhcheck:
573: /*
574: * Process Hop-by-Hop options header if it's contained.
575: * m may be modified in ip6_hopopts_input().
576: * If a JumboPayload option is included, plen will also be modified.
577: */
578: plen = (u_int32_t)ntohs(ip6->ip6_plen);
579: if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {
1.9 itojun 580: struct ip6_hbh *hbh;
581:
582: if (ip6_hopopts_input(&plen, &rtalert, &m, &off)) {
583: #if 0 /*touches NULL pointer*/
584: in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);
585: #endif
1.2 itojun 586: return; /* m have already been freed */
1.9 itojun 587: }
1.2 itojun 588: /* adjust pointer */
589: ip6 = mtod(m, struct ip6_hdr *);
1.9 itojun 590: #ifndef PULLDOWN_TEST
591: /* ip6_hopopts_input() ensures that mbuf is contiguous */
592: hbh = (struct ip6_hbh *)(ip6 + 1);
593: #else
594: IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),
595: sizeof(struct ip6_hbh));
596: if (hbh == NULL) {
597: ip6stat.ip6s_tooshort++;
598: return;
599: }
600: #endif
601: nxt = hbh->ip6h_nxt;
1.2 itojun 602:
603: /*
604: * accept the packet if a router alert option is included
605: * and we act as an IPv6 router.
606: */
1.5 itojun 607: if (rtalert != ~0 && ip6_forwarding)
1.2 itojun 608: ours = 1;
609: } else
610: nxt = ip6->ip6_nxt;
611:
612: /*
613: * Check that the amount of data in the buffers
614: * is as at least much as the IPv6 header would have us expect.
615: * Trim mbufs if longer than we expect.
616: * Drop packet if shorter than we expect.
617: */
618: if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) {
619: ip6stat.ip6s_tooshort++;
1.9 itojun 620: in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated);
1.2 itojun 621: goto bad;
622: }
623: if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) {
624: if (m->m_len == m->m_pkthdr.len) {
625: m->m_len = sizeof(struct ip6_hdr) + plen;
626: m->m_pkthdr.len = sizeof(struct ip6_hdr) + plen;
627: } else
628: m_adj(m, sizeof(struct ip6_hdr) + plen - m->m_pkthdr.len);
629: }
630:
631: /*
632: * Forward if desirable.
633: */
634: if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
635: /*
636: * If we are acting as a multicast router, all
637: * incoming multicast packets are passed to the
638: * kernel-level multicast forwarding function.
639: * The packet is returned (relatively) intact; if
640: * ip6_mforward() returns a non-zero value, the packet
641: * must be discarded, else it may be accepted below.
642: */
643: if (ip6_mrouter && ip6_mforward(ip6, m->m_pkthdr.rcvif, m)) {
644: ip6stat.ip6s_cantforward++;
645: m_freem(m);
646: return;
647: }
648: if (!ours) {
649: m_freem(m);
650: return;
651: }
652: }
653: else if (!ours) {
654: ip6_forward(m, 0);
655: return;
656: }
657:
658: /*
659: * Tell launch routine the next header
660: */
1.12 itojun 661: #ifdef IFA_STATS
1.9 itojun 662: if (IFA_STATS && deliverifp != NULL) {
663: struct in6_ifaddr *ia6;
664: ip6 = mtod(m, struct ip6_hdr *);
665: ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst);
666: if (ia6)
667: ia6->ia_ifa.ifa_data.ifad_inbytes += m->m_pkthdr.len;
668: }
669: #endif
1.2 itojun 670: ip6stat.ip6s_delivered++;
1.9 itojun 671: in6_ifstat_inc(deliverifp, ifs6_in_deliver);
1.2 itojun 672: nest = 0;
673: while (nxt != IPPROTO_DONE) {
674: if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) {
675: ip6stat.ip6s_toomanyhdr++;
676: goto bad;
677: }
1.8 itojun 678:
679: /*
680: * protection against faulty packet - there should be
681: * more sanity checks in header chain processing.
682: */
683: if (m->m_pkthdr.len < off) {
684: ip6stat.ip6s_tooshort++;
1.9 itojun 685: in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated);
1.8 itojun 686: goto bad;
687: }
688:
1.2 itojun 689: nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt);
690: }
691: return;
692: bad:
693: m_freem(m);
694: }
695:
696: /*
697: * Hop-by-Hop options header processing. If a valid jumbo payload option is
698: * included, the real payload length will be stored in plenp.
699: */
700: static int
701: ip6_hopopts_input(plenp, rtalertp, mp, offp)
702: u_int32_t *plenp;
1.5 itojun 703: u_int32_t *rtalertp; /* XXX: should be stored more smart way */
1.2 itojun 704: struct mbuf **mp;
705: int *offp;
706: {
707: register struct mbuf *m = *mp;
708: int off = *offp, hbhlen;
709: struct ip6_hbh *hbh;
710: u_int8_t *opt;
711:
712: /* validation of the length of the header */
1.9 itojun 713: #ifndef PULLDOWN_TEST
1.2 itojun 714: IP6_EXTHDR_CHECK(m, off, sizeof(*hbh), -1);
715: hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off);
716: hbhlen = (hbh->ip6h_len + 1) << 3;
717:
718: IP6_EXTHDR_CHECK(m, off, hbhlen, -1);
719: hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off);
1.9 itojun 720: #else
721: IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m,
722: sizeof(struct ip6_hdr), sizeof(struct ip6_hbh));
723: if (hbh == NULL) {
724: ip6stat.ip6s_tooshort++;
725: return -1;
726: }
727: hbhlen = (hbh->ip6h_len + 1) << 3;
728: IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),
729: hbhlen);
730: if (hbh == NULL) {
731: ip6stat.ip6s_tooshort++;
732: return -1;
733: }
734: #endif
1.2 itojun 735: off += hbhlen;
736: hbhlen -= sizeof(struct ip6_hbh);
737: opt = (u_int8_t *)hbh + sizeof(struct ip6_hbh);
738:
739: if (ip6_process_hopopts(m, (u_int8_t *)hbh + sizeof(struct ip6_hbh),
740: hbhlen, rtalertp, plenp) < 0)
741: return(-1);
742:
743: *offp = off;
744: *mp = m;
745: return(0);
746: }
747:
748: /*
749: * Search header for all Hop-by-hop options and process each option.
750: * This function is separate from ip6_hopopts_input() in order to
751: * handle a case where the sending node itself process its hop-by-hop
752: * options header. In such a case, the function is called from ip6_output().
753: */
754: int
755: ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp)
756: struct mbuf *m;
757: u_int8_t *opthead;
758: int hbhlen;
1.5 itojun 759: u_int32_t *rtalertp;
1.2 itojun 760: u_int32_t *plenp;
761: {
762: struct ip6_hdr *ip6;
763: int optlen = 0;
764: u_int8_t *opt = opthead;
765: u_int16_t rtalert_val;
766:
767: for (; hbhlen > 0; hbhlen -= optlen, opt += optlen) {
768: switch(*opt) {
769: case IP6OPT_PAD1:
770: optlen = 1;
771: break;
772: case IP6OPT_PADN:
773: if (hbhlen < IP6OPT_MINLEN) {
774: ip6stat.ip6s_toosmall++;
775: goto bad;
776: }
777: optlen = *(opt + 1) + 2;
778: break;
779: case IP6OPT_RTALERT:
1.8 itojun 780: /* XXX may need check for alignment */
1.2 itojun 781: if (hbhlen < IP6OPT_RTALERT_LEN) {
782: ip6stat.ip6s_toosmall++;
783: goto bad;
784: }
785: if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2)
786: /* XXX: should we discard the packet? */
787: log(LOG_ERR, "length of router alert opt is inconsitent(%d)",
788: *(opt + 1));
789: optlen = IP6OPT_RTALERT_LEN;
790: bcopy((caddr_t)(opt + 2), (caddr_t)&rtalert_val, 2);
791: *rtalertp = ntohs(rtalert_val);
792: break;
793: case IP6OPT_JUMBO:
1.8 itojun 794: /* XXX may need check for alignment */
1.2 itojun 795: if (hbhlen < IP6OPT_JUMBO_LEN) {
796: ip6stat.ip6s_toosmall++;
797: goto bad;
798: }
799: if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2)
800: /* XXX: should we discard the packet? */
801: log(LOG_ERR, "length of jumbopayload opt "
802: "is inconsistent(%d)",
803: *(opt + 1));
804: optlen = IP6OPT_JUMBO_LEN;
805:
806: /*
807: * We can simply cast because of the alignment
808: * requirement of the jumbo payload option.
809: */
1.8 itojun 810: #if 0
1.2 itojun 811: *plenp = ntohl(*(u_int32_t *)(opt + 2));
1.8 itojun 812: #else
813: bcopy(opt + 2, plenp, sizeof(*plenp));
814: *plenp = htonl(*plenp);
815: #endif
1.2 itojun 816: if (*plenp <= IPV6_MAXPACKET) {
817: /*
818: * jumbo payload length must be larger
819: * than 65535
820: */
821: ip6stat.ip6s_badoptions++;
822: icmp6_error(m, ICMP6_PARAM_PROB,
823: ICMP6_PARAMPROB_HEADER,
824: sizeof(struct ip6_hdr) +
825: sizeof(struct ip6_hbh) +
826: opt + 2 - opthead);
827: return(-1);
828: }
829:
830: ip6 = mtod(m, struct ip6_hdr *);
831: if (ip6->ip6_plen) {
832: /*
833: * IPv6 packets that have non 0 payload length
834: * must not contain a jumbo paylod option.
835: */
836: ip6stat.ip6s_badoptions++;
837: icmp6_error(m, ICMP6_PARAM_PROB,
838: ICMP6_PARAMPROB_HEADER,
839: sizeof(struct ip6_hdr) +
840: sizeof(struct ip6_hbh) +
841: opt - opthead);
842: return(-1);
843: }
844: break;
845: default: /* unknown option */
846: if (hbhlen < IP6OPT_MINLEN) {
847: ip6stat.ip6s_toosmall++;
848: goto bad;
849: }
850: if ((optlen = ip6_unknown_opt(opt, m,
851: sizeof(struct ip6_hdr) +
852: sizeof(struct ip6_hbh) +
853: opt - opthead)) == -1)
854: return(-1);
855: optlen += 2;
856: break;
857: }
858: }
859:
860: return(0);
861:
862: bad:
863: m_freem(m);
864: return(-1);
865: }
866:
867: /*
868: * Unknown option processing.
869: * The third argument `off' is the offset from the IPv6 header to the option,
870: * which is necessary if the IPv6 header the and option header and IPv6 header
871: * is not continuous in order to return an ICMPv6 error.
872: */
873: int
874: ip6_unknown_opt(optp, m, off)
875: u_int8_t *optp;
876: struct mbuf *m;
877: int off;
878: {
879: struct ip6_hdr *ip6;
880:
881: switch(IP6OPT_TYPE(*optp)) {
882: case IP6OPT_TYPE_SKIP: /* ignore the option */
883: return((int)*(optp + 1));
884: case IP6OPT_TYPE_DISCARD: /* silently discard */
885: m_freem(m);
886: return(-1);
887: case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */
888: ip6stat.ip6s_badoptions++;
889: icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off);
890: return(-1);
891: case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */
892: ip6stat.ip6s_badoptions++;
893: ip6 = mtod(m, struct ip6_hdr *);
894: if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
895: (m->m_flags & (M_BCAST|M_MCAST)))
896: m_freem(m);
897: else
898: icmp6_error(m, ICMP6_PARAM_PROB,
899: ICMP6_PARAMPROB_OPTION, off);
900: return(-1);
901: }
902:
903: m_freem(m); /* XXX: NOTREACHED */
904: return(-1);
905: }
906:
907: /*
1.9 itojun 908: * Create the "control" list for this pcb.
909: *
910: * The routine will be called from upper layer handlers like tcp6_input().
911: * Thus the routine assumes that the caller (tcp6_input) have already
912: * called IP6_EXTHDR_CHECK() and all the extension headers are located in the
913: * very first mbuf on the mbuf chain.
914: * We may want to add some infinite loop prevention or sanity checks for safety.
915: * (This applies only when you are using KAME mbuf chain restriction, i.e.
916: * you are using IP6_EXTHDR_CHECK() not m_pulldown())
1.2 itojun 917: */
918: void
919: ip6_savecontrol(in6p, mp, ip6, m)
920: register struct in6pcb *in6p;
921: register struct mbuf **mp;
922: register struct ip6_hdr *ip6;
923: register struct mbuf *m;
924: {
925: struct proc *p = curproc; /* XXX */
1.9 itojun 926: int privileged;
1.2 itojun 927:
1.9 itojun 928: privileged = 0;
929: if (p && !suser(p->p_ucred, &p->p_acflag))
930: privileged++;
931:
932: #ifdef SO_TIMESTAMP
1.2 itojun 933: if (in6p->in6p_socket->so_options & SO_TIMESTAMP) {
934: struct timeval tv;
935:
936: microtime(&tv);
937: *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv),
938: SCM_TIMESTAMP, SOL_SOCKET);
939: if (*mp)
940: mp = &(*mp)->m_next;
941: }
1.9 itojun 942: #endif
1.2 itojun 943: if (in6p->in6p_flags & IN6P_RECVDSTADDR) {
944: *mp = sbcreatecontrol((caddr_t) &ip6->ip6_dst,
945: sizeof(struct in6_addr), IPV6_RECVDSTADDR,
946: IPPROTO_IPV6);
947: if (*mp)
948: mp = &(*mp)->m_next;
949: }
950:
951: #ifdef noyet
952: /* options were tossed above */
953: if (in6p->in6p_flags & IN6P_RECVOPTS)
954: /* broken */
955: /* ip6_srcroute doesn't do what we want here, need to fix */
956: if (in6p->in6p_flags & IPV6P_RECVRETOPTS)
957: /* broken */
958: #endif
959:
960: /* RFC 2292 sec. 5 */
961: if (in6p->in6p_flags & IN6P_PKTINFO) {
962: struct in6_pktinfo pi6;
963: bcopy(&ip6->ip6_dst, &pi6.ipi6_addr, sizeof(struct in6_addr));
964: if (IN6_IS_SCOPE_LINKLOCAL(&pi6.ipi6_addr))
965: pi6.ipi6_addr.s6_addr16[1] = 0;
966: pi6.ipi6_ifindex = (m && m->m_pkthdr.rcvif)
967: ? m->m_pkthdr.rcvif->if_index
968: : 0;
969: *mp = sbcreatecontrol((caddr_t) &pi6,
970: sizeof(struct in6_pktinfo), IPV6_PKTINFO,
971: IPPROTO_IPV6);
972: if (*mp)
973: mp = &(*mp)->m_next;
974: }
975: if (in6p->in6p_flags & IN6P_HOPLIMIT) {
976: int hlim = ip6->ip6_hlim & 0xff;
977: *mp = sbcreatecontrol((caddr_t) &hlim,
978: sizeof(int), IPV6_HOPLIMIT, IPPROTO_IPV6);
979: if (*mp)
980: mp = &(*mp)->m_next;
981: }
982: /* IN6P_NEXTHOP - for outgoing packet only */
983:
984: /*
985: * IPV6_HOPOPTS socket option. We require super-user privilege
986: * for the option, but it might be too strict, since there might
987: * be some hop-by-hop options which can be returned to normal user.
988: * See RFC 2292 section 6.
989: */
1.9 itojun 990: if ((in6p->in6p_flags & IN6P_HOPOPTS) && privileged) {
1.2 itojun 991: /*
992: * Check if a hop-by-hop options header is contatined in the
993: * received packet, and if so, store the options as ancillary
994: * data. Note that a hop-by-hop options header must be
995: * just after the IPv6 header, which fact is assured through
996: * the IPv6 input processing.
997: */
998: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
999: if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {
1.9 itojun 1000: struct ip6_hbh *hbh;
1001: int hbhlen;
1002:
1003: #ifndef PULLDOWN_TEST
1004: hbh = (struct ip6_hbh *)(ip6 + 1);
1005: hbhlen = (hbh->ip6h_len + 1) << 3;
1006: #else
1007: IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m,
1008: sizeof(struct ip6_hdr), sizeof(struct ip6_hbh));
1009: if (hbh == NULL) {
1010: ip6stat.ip6s_tooshort++;
1011: return;
1012: }
1013: hbhlen = (hbh->ip6h_len + 1) << 3;
1014: IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m,
1015: sizeof(struct ip6_hdr), hbhlen);
1016: if (hbh == NULL) {
1017: ip6stat.ip6s_tooshort++;
1018: return;
1019: }
1020: #endif
1.2 itojun 1021:
1022: /*
1023: * XXX: We copy whole the header even if a jumbo
1024: * payload option is included, which option is to
1025: * be removed before returning in the RFC 2292.
1026: * But it's too painful operation...
1027: */
1.9 itojun 1028: *mp = sbcreatecontrol((caddr_t)hbh, hbhlen,
1.2 itojun 1029: IPV6_HOPOPTS, IPPROTO_IPV6);
1030: if (*mp)
1031: mp = &(*mp)->m_next;
1032: }
1033: }
1034:
1035: /* IPV6_DSTOPTS and IPV6_RTHDR socket options */
1036: if (in6p->in6p_flags & (IN6P_DSTOPTS | IN6P_RTHDR)) {
1037: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1038: int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr);;
1039:
1040: /*
1041: * Search for destination options headers or routing
1042: * header(s) through the header chain, and stores each
1043: * header as ancillary data.
1044: * Note that the order of the headers remains in
1045: * the chain of ancillary data.
1046: */
1047: while(1) { /* is explicit loop prevention necessary? */
1.9 itojun 1048: struct ip6_ext *ip6e;
1049: int elen;
1050:
1051: #ifndef PULLDOWN_TEST
1052: ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + off);
1053: if (nxt == IPPROTO_AH)
1054: elen = (ip6e->ip6e_len + 2) << 2;
1055: else
1056: elen = (ip6e->ip6e_len + 1) << 3;
1057: #else
1058: IP6_EXTHDR_GET(ip6e, struct ip6_ext *, m, off,
1059: sizeof(struct ip6_ext));
1060: if (ip6e == NULL) {
1061: ip6stat.ip6s_tooshort++;
1062: return;
1063: }
1064: if (nxt == IPPROTO_AH)
1065: elen = (ip6e->ip6e_len + 2) << 2;
1066: else
1067: elen = (ip6e->ip6e_len + 1) << 3;
1068: IP6_EXTHDR_GET(ip6e, struct ip6_ext *, m, off, elen);
1069: if (ip6e == NULL) {
1070: ip6stat.ip6s_tooshort++;
1071: return;
1072: }
1073: #endif
1.2 itojun 1074:
1075: switch(nxt) {
1076: case IPPROTO_DSTOPTS:
1077: if (!in6p->in6p_flags & IN6P_DSTOPTS)
1078: break;
1079:
1080: /*
1081: * We also require super-user privilege for
1082: * the option.
1083: * See the comments on IN6_HOPOPTS.
1084: */
1.9 itojun 1085: if (!privileged)
1.2 itojun 1086: break;
1087:
1.9 itojun 1088: *mp = sbcreatecontrol((caddr_t)ip6e, elen,
1.2 itojun 1089: IPV6_DSTOPTS,
1090: IPPROTO_IPV6);
1091: if (*mp)
1092: mp = &(*mp)->m_next;
1093: break;
1094:
1095: case IPPROTO_ROUTING:
1096: if (!in6p->in6p_flags & IN6P_RTHDR)
1097: break;
1098:
1.9 itojun 1099: *mp = sbcreatecontrol((caddr_t)ip6e, elen,
1.2 itojun 1100: IPV6_RTHDR,
1101: IPPROTO_IPV6);
1102: if (*mp)
1103: mp = &(*mp)->m_next;
1104: break;
1105:
1106: case IPPROTO_UDP:
1107: case IPPROTO_TCP:
1108: case IPPROTO_ICMPV6:
1109: default:
1110: /*
1111: * stop search if we encounter an upper
1112: * layer protocol headers.
1113: */
1114: goto loopend;
1115:
1116: case IPPROTO_HOPOPTS:
1117: case IPPROTO_AH: /* is it possible? */
1118: break;
1119: }
1120:
1121: /* proceed with the next header. */
1.9 itojun 1122: off += elen;
1.2 itojun 1123: nxt = ip6e->ip6e_nxt;
1124: }
1125: loopend:
1126: }
1.9 itojun 1127: if ((in6p->in6p_flags & IN6P_HOPOPTS) && privileged) {
1.2 itojun 1128: /* to be done */
1129: }
1.9 itojun 1130: if ((in6p->in6p_flags & IN6P_DSTOPTS) && privileged) {
1.2 itojun 1131: /* to be done */
1132: }
1133: /* IN6P_RTHDR - to be done */
1134:
1135: }
1136:
1137: /*
1138: * Get pointer to the previous header followed by the header
1139: * currently processed.
1140: * XXX: This function supposes that
1141: * M includes all headers,
1142: * the next header field and the header length field of each header
1143: * are valid, and
1144: * the sum of each header length equals to OFF.
1145: * Because of these assumptions, this function must be called very
1146: * carefully. Moreover, it will not be used in the near future when
1147: * we develop `neater' mechanism to process extension headers.
1148: */
1149: char *
1150: ip6_get_prevhdr(m, off)
1151: struct mbuf *m;
1152: int off;
1153: {
1154: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1155:
1156: if (off == sizeof(struct ip6_hdr))
1157: return(&ip6->ip6_nxt);
1158: else {
1159: int len, nxt;
1160: struct ip6_ext *ip6e = NULL;
1161:
1162: nxt = ip6->ip6_nxt;
1163: len = sizeof(struct ip6_hdr);
1164: while (len < off) {
1165: ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + len);
1166:
1167: switch(nxt) {
1168: case IPPROTO_FRAGMENT:
1169: len += sizeof(struct ip6_frag);
1170: break;
1171: case IPPROTO_AH:
1172: len += (ip6e->ip6e_len + 2) << 2;
1173: break;
1174: default:
1175: len += (ip6e->ip6e_len + 1) << 3;
1176: break;
1177: }
1178: nxt = ip6e->ip6e_nxt;
1179: }
1180: if (ip6e)
1181: return(&ip6e->ip6e_nxt);
1182: else
1183: return NULL;
1184: }
1185: }
1186:
1187: /*
1188: * System control for IP6
1189: */
1190:
1191: u_char inet6ctlerrmap[PRC_NCMDS] = {
1192: 0, 0, 0, 0,
1193: 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH,
1194: EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
1195: EMSGSIZE, EHOSTUNREACH, 0, 0,
1196: 0, 0, 0, 0,
1197: ENOPROTOOPT
1198: };
1199:
1200: #include <vm/vm.h>
1201: #include <sys/sysctl.h>
1202:
1203: int
1204: ip6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
1205: int *name;
1206: u_int namelen;
1207: void *oldp;
1208: size_t *oldlenp;
1209: void *newp;
1210: size_t newlen;
1211: {
1212: /* All sysctl names at this level are terminal. */
1213: if (namelen != 1)
1214: return ENOTDIR;
1215:
1216: switch (name[0]) {
1217:
1218: case IPV6CTL_FORWARDING:
1219: return sysctl_int(oldp, oldlenp, newp, newlen,
1220: &ip6_forwarding);
1221: case IPV6CTL_SENDREDIRECTS:
1222: return sysctl_int(oldp, oldlenp, newp, newlen,
1223: &ip6_sendredirects);
1224: case IPV6CTL_DEFHLIM:
1225: return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_defhlim);
1226: case IPV6CTL_MAXFRAGPACKETS:
1227: return sysctl_int(oldp, oldlenp, newp, newlen,
1228: &ip6_maxfragpackets);
1229: case IPV6CTL_ACCEPT_RTADV:
1230: return sysctl_int(oldp, oldlenp, newp, newlen,
1231: &ip6_accept_rtadv);
1232: case IPV6CTL_KEEPFAITH:
1233: return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_keepfaith);
1234: case IPV6CTL_LOG_INTERVAL:
1235: return sysctl_int(oldp, oldlenp, newp, newlen,
1236: &ip6_log_interval);
1237: case IPV6CTL_HDRNESTLIMIT:
1238: return sysctl_int(oldp, oldlenp, newp, newlen,
1239: &ip6_hdrnestlimit);
1240: case IPV6CTL_DAD_COUNT:
1241: return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_dad_count);
1242: case IPV6CTL_AUTO_FLOWLABEL:
1243: return sysctl_int(oldp, oldlenp, newp, newlen,
1244: &ip6_auto_flowlabel);
1245: case IPV6CTL_DEFMCASTHLIM:
1246: return sysctl_int(oldp, oldlenp, newp, newlen,
1247: &ip6_defmcasthlim);
1248: case IPV6CTL_GIF_HLIM:
1249: return sysctl_int(oldp, oldlenp, newp, newlen,
1250: &ip6_gif_hlim);
1251: case IPV6CTL_KAME_VERSION:
1252: return sysctl_rdstring(oldp, oldlenp, newp, __KAME_VERSION);
1.9 itojun 1253: case IPV6CTL_USE_DEPRECATED:
1254: return sysctl_int(oldp, oldlenp, newp, newlen,
1255: &ip6_use_deprecated);
1.10 itojun 1256: case IPV6CTL_RR_PRUNE:
1257: return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_rr_prune);
1.12 itojun 1258: #ifndef INET6_BINDV6ONLY
1.11 itojun 1259: case IPV6CTL_BINDV6ONLY:
1260: return sysctl_int(oldp, oldlenp, newp, newlen,
1261: &ip6_bindv6only);
1262: #endif
1.2 itojun 1263: default:
1264: return EOPNOTSUPP;
1265: }
1266: /* NOTREACHED */
1267: }
CVSweb <webmaster@jp.NetBSD.org>