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