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