Annotation of src/sys/netinet6/ip6_input.c, Revision 1.3
1.3 ! thorpej 1: /* $NetBSD$ */
! 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"
72: #endif
73:
74: #include <sys/param.h>
75: #include <sys/systm.h>
76: #include <sys/malloc.h>
77: #include <sys/mbuf.h>
78: #include <sys/domain.h>
79: #include <sys/protosw.h>
80: #include <sys/socket.h>
81: #include <sys/socketvar.h>
82: #include <sys/errno.h>
83: #include <sys/time.h>
84: #include <sys/kernel.h>
85: #include <sys/syslog.h>
86: #ifdef __NetBSD__
87: #include <sys/proc.h>
88: #endif
89:
90: #include <net/if.h>
91: #include <net/if_types.h>
92: #include <net/if_dl.h>
93: #include <net/route.h>
94: #include <net/netisr.h>
95:
96: #include <netinet/in.h>
97: #include <netinet6/in6_var.h>
98: #include <netinet/in_systm.h>
99: #include <netinet6/ip6.h>
100: #if !defined(__FreeBSD__) || __FreeBSD__ < 3
101: #include <netinet6/in6_pcb.h>
102: #else
103: #include <netinet/in_pcb.h>
104: #endif
105: #include <netinet6/ip6_var.h>
106: #include <netinet6/icmp6.h>
107: #include <netinet6/in6_ifattach.h>
108: #include <netinet6/nd6.h>
109:
110: #ifdef INET
111: #include <netinet/ip.h>
112: #include <netinet/ip_icmp.h>
113: #endif /*INET*/
114:
115: #include <netinet6/ip6protosw.h>
116:
117: /* we need it for NLOOP. */
118: #include "loop.h"
119: #include "faith.h"
120:
121: #include "gif.h"
122: #include "bpfilter.h"
123:
124: extern struct domain inet6domain;
125: extern struct ip6protosw inet6sw[];
126: #ifdef __bsdi__
127: extern struct ifnet loif;
128: #endif
129:
130: u_char ip6_protox[IPPROTO_MAX];
131: static int ip6qmaxlen = IFQ_MAXLEN;
132: struct in6_ifaddr *in6_ifaddr;
133: struct ifqueue ip6intrq;
134:
135: #ifdef __NetBSD__
136: extern struct ifnet loif[NLOOP];
137: int ip6_forward_srcrt; /* XXX */
138: int ip6_sourcecheck; /* XXX */
139: int ip6_sourcecheck_interval; /* XXX */
140: #endif
141:
142: struct ip6stat ip6stat;
143:
144: static void ip6_init2 __P((void *));
145:
146: static int ip6_hopopts_input __P((u_int32_t *, long *, struct mbuf **, int *));
147:
148: /*
149: * IP6 initialization: fill in IP6 protocol switch table.
150: * All protocols not implemented in kernel go to raw IP6 protocol handler.
151: */
152: void
153: ip6_init()
154: {
155: register struct ip6protosw *pr;
156: register int i;
157: struct timeval tv;
158:
159: pr = (struct ip6protosw *)pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW);
160: if (pr == 0)
161: panic("ip6_init");
162: for (i = 0; i < IPPROTO_MAX; i++)
163: ip6_protox[i] = pr - inet6sw;
164: for (pr = (struct ip6protosw *)inet6domain.dom_protosw;
165: pr < (struct ip6protosw *)inet6domain.dom_protoswNPROTOSW; pr++)
166: if (pr->pr_domain->dom_family == PF_INET6 &&
167: pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
168: ip6_protox[pr->pr_protocol] = pr - inet6sw;
169: ip6intrq.ifq_maxlen = ip6qmaxlen;
170: nd6_init();
171: frag6_init();
172: /*
173: * in many cases, random() here does NOT return random number
174: * as initialization during bootstrap time occur in fixed order.
175: */
176: microtime(&tv);
177: ip6_flow_seq = random() ^ tv.tv_usec;
178: in6_iflladdr = malloc(i, M_IFADDR, M_WAITOK);
179: bzero(in6_iflladdr, i);
180:
181: ip6_init2((void *)0);
182: }
183:
184: static void
185: ip6_init2(dummy)
186: void *dummy;
187: {
188: int i;
189:
190: /*
191: * to route local address of p2p link to loopback,
192: * assign loopback address first.
193: */
194: for (i = 0; i < NLOOP; i++)
195: in6_ifattach(&loif[i], IN6_IFT_LOOP, NULL, 0);
196:
197: /* get EUI64 from somewhere, attach pseudo interfaces */
198: if (in6_ifattach_getifid(NULL) == 0)
199: in6_ifattach_p2p();
200:
201: /* nd6_timer_init */
202: timeout(nd6_timer, (caddr_t)0, hz);
203: }
204:
205: #ifdef __FreeBSD__
206: /* cheat */
207: SYSINIT(netinet6init2, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, ip6_init2, NULL);
208: #endif
209:
210: /*
211: * IP6 input interrupt handling. Just pass the packet to ip6_input.
212: */
213: void
214: ip6intr()
215: {
216: int s;
217: struct mbuf *m;
218:
219: for (;;) {
220: s = splimp();
221: IF_DEQUEUE(&ip6intrq, m);
222: splx(s);
223: if (m == 0)
224: return;
225: ip6_input(m);
226: }
227: }
228:
229: #ifdef __FreeBSD__
230: NETISR_SET(NETISR_IPV6, ip6intr);
231: #endif
232:
233: extern struct route_in6 ip6_forward_rt;
234:
235: void
236: ip6_input(m)
237: struct mbuf *m;
238: {
239: register struct ip6_hdr *ip6;
240: int off = sizeof(struct ip6_hdr), nest;
241: u_int32_t plen;
242: long rtalert = -1;
243: int nxt, ours = 0;
244:
245: #ifdef IPSEC
246: /*
247: * should the inner packet be considered authentic?
248: * see comment in ah4_input().
249: */
250: if (m) {
251: m->m_flags &= ~M_AUTHIPHDR;
252: m->m_flags &= ~M_AUTHIPDGM;
253: }
254: #endif
255: /*
256: * mbuf statistics by kazu
257: */
258: if (m->m_flags & M_EXT) {
259: if (m->m_next)
260: ip6stat.ip6s_mext2m++;
261: else
262: ip6stat.ip6s_mext1++;
263: } else {
264: if (m->m_next) {
265: if (m->m_flags & M_LOOP)
266: ip6stat.ip6s_m2m[loif[0].if_index]++; /*XXX*/
267: else if (m->m_pkthdr.rcvif->if_index <= 31)
268: ip6stat.ip6s_m2m[m->m_pkthdr.rcvif->if_index]++;
269: else
270: ip6stat.ip6s_m2m[0]++;
271: } else
272: ip6stat.ip6s_m1++;
273: }
274:
275: IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), /*nothing*/);
276:
277: ip6stat.ip6s_total++;
278:
279: if (m->m_len < sizeof(struct ip6_hdr) &&
280: (m = m_pullup(m, sizeof(struct ip6_hdr))) == 0) {
281: ip6stat.ip6s_toosmall++;
282: return;
283: }
284:
285: ip6 = mtod(m, struct ip6_hdr *);
286:
287: if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
288: ip6stat.ip6s_badvers++;
289: goto bad;
290: }
291:
292: ip6stat.ip6s_nxthist[ip6->ip6_nxt]++;
293:
294: /*
295: * Scope check
296: */
297: if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src) ||
298: IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) {
299: ip6stat.ip6s_badscope++;
300: goto bad;
301: }
302: if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) ||
303: IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) {
304: if (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) {
305: ours = 1;
306: goto hbhcheck;
307: } else {
308: ip6stat.ip6s_badscope++;
309: goto bad;
310: }
311: }
312:
313: if (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) {
314: if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) {
315: ours = 1;
316: goto hbhcheck;
317: }
318: } else {
319: if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
320: ip6->ip6_src.s6_addr16[1]
321: = htons(m->m_pkthdr.rcvif->if_index);
322: if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
323: ip6->ip6_dst.s6_addr16[1]
324: = htons(m->m_pkthdr.rcvif->if_index);
325: }
326:
327: /*
328: * Multicast check
329: */
330: if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
331: struct in6_multi *in6m = 0;
332: /*
333: * See if we belong to the destination multicast group on the
334: * arrival interface.
335: */
336: IN6_LOOKUP_MULTI(ip6->ip6_dst, m->m_pkthdr.rcvif, in6m);
337: if (in6m)
338: ours = 1;
339: else if (!ip6_mrouter) {
340: ip6stat.ip6s_notmember++;
341: ip6stat.ip6s_cantforward++;
342: goto bad;
343: }
344: goto hbhcheck;
345: }
346:
347: /*
348: * Unicast check
349: */
350: if (ip6_forward_rt.ro_rt == 0 ||
351: !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
352: &ip6_forward_rt.ro_dst.sin6_addr)) {
353: if (ip6_forward_rt.ro_rt) {
354: RTFREE(ip6_forward_rt.ro_rt);
355: ip6_forward_rt.ro_rt = 0;
356: }
357: bzero(&ip6_forward_rt.ro_dst, sizeof(struct sockaddr_in6));
358: ip6_forward_rt.ro_dst.sin6_len = sizeof(struct sockaddr_in6);
359: ip6_forward_rt.ro_dst.sin6_family = AF_INET6;
360: ip6_forward_rt.ro_dst.sin6_addr = ip6->ip6_dst;
361:
362: #if defined(__bsdi__) || defined(__NetBSD__)
363: rtalloc((struct route *)&ip6_forward_rt);
364: #endif
365: #ifdef __FreeBSD__
366: rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING);
367: #endif
368: }
369:
370: #define rt6_key(r) ((struct sockaddr_in6 *)((r)->rt_nodes->rn_key))
371:
372: /*
373: * Accept the packet if the forwarding interface to the destination
374: * according to the routing table is the loopback interface,
375: * unless the associated route has a gateway.
376: * Note that this approach causes to accept a packet if there is a
377: * route to the loopback interface for the destination of the packet.
378: * But we think it's even useful in some situations, e.g. when using
379: * a special daemon which wants to intercept the packet.
380: */
381: if (ip6_forward_rt.ro_rt &&
382: (ip6_forward_rt.ro_rt->rt_flags &
383: (RTF_HOST|RTF_GATEWAY)) == RTF_HOST &&
384: #if 0
385: /*
386: * The check below is redundant since the comparison of
387: * the destination and the key of the rtentry has
388: * already done through looking up the routing table.
389: */
390: IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
391: &rt6_key(ip6_forward_rt.ro_rt)->sin6_addr) &&
392: #endif
393: #ifdef __bsdi__
394: ip6_foward.rt.ro_rt->rt_ifp == &loif
395: #else
396: ip6_forward_rt.ro_rt->rt_ifp == &loif[0]
397: #endif
398: ) {
399: struct in6_ifaddr *ia6 =
400: (struct in6_ifaddr *)ip6_forward_rt.ro_rt->rt_ifa;
401: /* packet to tentative address must not be received */
402: if (ia6->ia6_flags & IN6_IFF_ANYCAST)
403: m->m_flags |= M_ANYCAST6;
404: if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) {
405: /* this interface is ready */
406: ours = 1;
407: goto hbhcheck;
408: } else {
409: /* this interface is not ready, fall through */
410: }
411: }
412:
413: /*
414: * FAITH(Firewall Aided Internet Translator)
415: */
416: #if defined(NFAITH) && 0 < NFAITH
417: if (ip6_keepfaith) {
418: if (ip6_forward_rt.ro_rt && ip6_forward_rt.ro_rt->rt_ifp
419: && ip6_forward_rt.ro_rt->rt_ifp->if_type == IFT_FAITH) {
420: /* XXX do we need more sanity checks? */
421: ours = 1;
422: goto hbhcheck;
423: }
424: }
425: #endif
426:
427: /*
428: * Now there is no reason to process the packet if it's not our own
429: * and we're not a router.
430: */
431: if (!ip6_forwarding) {
432: ip6stat.ip6s_cantforward++;
433: goto bad;
434: }
435:
436: hbhcheck:
437: /*
438: * Process Hop-by-Hop options header if it's contained.
439: * m may be modified in ip6_hopopts_input().
440: * If a JumboPayload option is included, plen will also be modified.
441: */
442: plen = (u_int32_t)ntohs(ip6->ip6_plen);
443: if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {
444: if (ip6_hopopts_input(&plen, &rtalert, &m, &off))
445: return; /* m have already been freed */
446: /* adjust pointer */
447: ip6 = mtod(m, struct ip6_hdr *);
448: nxt = ((struct ip6_hbh *)(ip6 + 1))->ip6h_nxt;
449:
450: /*
451: * accept the packet if a router alert option is included
452: * and we act as an IPv6 router.
453: */
454: if (rtalert >= 0 && ip6_forwarding)
455: ours = 1;
456: } else
457: nxt = ip6->ip6_nxt;
458:
459: /*
460: * Check that the amount of data in the buffers
461: * is as at least much as the IPv6 header would have us expect.
462: * Trim mbufs if longer than we expect.
463: * Drop packet if shorter than we expect.
464: */
465: if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) {
466: ip6stat.ip6s_tooshort++;
467: goto bad;
468: }
469: if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) {
470: if (m->m_len == m->m_pkthdr.len) {
471: m->m_len = sizeof(struct ip6_hdr) + plen;
472: m->m_pkthdr.len = sizeof(struct ip6_hdr) + plen;
473: } else
474: m_adj(m, sizeof(struct ip6_hdr) + plen - m->m_pkthdr.len);
475: }
476:
477: /*
478: * Forward if desirable.
479: */
480: if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
481: /*
482: * If we are acting as a multicast router, all
483: * incoming multicast packets are passed to the
484: * kernel-level multicast forwarding function.
485: * The packet is returned (relatively) intact; if
486: * ip6_mforward() returns a non-zero value, the packet
487: * must be discarded, else it may be accepted below.
488: */
489: if (ip6_mrouter && ip6_mforward(ip6, m->m_pkthdr.rcvif, m)) {
490: ip6stat.ip6s_cantforward++;
491: m_freem(m);
492: return;
493: }
494: if (!ours) {
495: m_freem(m);
496: return;
497: }
498: }
499: else if (!ours) {
500: ip6_forward(m, 0);
501: return;
502: }
503:
504: /*
505: * Tell launch routine the next header
506: */
507: ip6stat.ip6s_delivered++;
508: nest = 0;
509: while (nxt != IPPROTO_DONE) {
510: if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) {
511: ip6stat.ip6s_toomanyhdr++;
512: goto bad;
513: }
514: nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt);
515: }
516: return;
517: bad:
518: m_freem(m);
519: }
520:
521: /*
522: * Hop-by-Hop options header processing. If a valid jumbo payload option is
523: * included, the real payload length will be stored in plenp.
524: */
525: static int
526: ip6_hopopts_input(plenp, rtalertp, mp, offp)
527: u_int32_t *plenp;
528: long *rtalertp; /* XXX: should be stored more smart way */
529: struct mbuf **mp;
530: int *offp;
531: {
532: register struct mbuf *m = *mp;
533: int off = *offp, hbhlen;
534: struct ip6_hbh *hbh;
535: u_int8_t *opt;
536:
537: /* validation of the length of the header */
538: IP6_EXTHDR_CHECK(m, off, sizeof(*hbh), -1);
539: hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off);
540: hbhlen = (hbh->ip6h_len + 1) << 3;
541:
542: IP6_EXTHDR_CHECK(m, off, hbhlen, -1);
543: hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off);
544: off += hbhlen;
545: hbhlen -= sizeof(struct ip6_hbh);
546: opt = (u_int8_t *)hbh + sizeof(struct ip6_hbh);
547:
548: if (ip6_process_hopopts(m, (u_int8_t *)hbh + sizeof(struct ip6_hbh),
549: hbhlen, rtalertp, plenp) < 0)
550: return(-1);
551:
552: *offp = off;
553: *mp = m;
554: return(0);
555: }
556:
557: /*
558: * Search header for all Hop-by-hop options and process each option.
559: * This function is separate from ip6_hopopts_input() in order to
560: * handle a case where the sending node itself process its hop-by-hop
561: * options header. In such a case, the function is called from ip6_output().
562: */
563: int
564: ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp)
565: struct mbuf *m;
566: u_int8_t *opthead;
567: int hbhlen;
568: long *rtalertp;
569: u_int32_t *plenp;
570: {
571: struct ip6_hdr *ip6;
572: int optlen = 0;
573: u_int8_t *opt = opthead;
574: u_int16_t rtalert_val;
575:
576: for (; hbhlen > 0; hbhlen -= optlen, opt += optlen) {
577: switch(*opt) {
578: case IP6OPT_PAD1:
579: optlen = 1;
580: break;
581: case IP6OPT_PADN:
582: if (hbhlen < IP6OPT_MINLEN) {
583: ip6stat.ip6s_toosmall++;
584: goto bad;
585: }
586: optlen = *(opt + 1) + 2;
587: break;
588: case IP6OPT_RTALERT:
589: if (hbhlen < IP6OPT_RTALERT_LEN) {
590: ip6stat.ip6s_toosmall++;
591: goto bad;
592: }
593: if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2)
594: /* XXX: should we discard the packet? */
595: log(LOG_ERR, "length of router alert opt is inconsitent(%d)",
596: *(opt + 1));
597: optlen = IP6OPT_RTALERT_LEN;
598: bcopy((caddr_t)(opt + 2), (caddr_t)&rtalert_val, 2);
599: *rtalertp = ntohs(rtalert_val);
600: break;
601: case IP6OPT_JUMBO:
602: if (hbhlen < IP6OPT_JUMBO_LEN) {
603: ip6stat.ip6s_toosmall++;
604: goto bad;
605: }
606: if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2)
607: /* XXX: should we discard the packet? */
608: log(LOG_ERR, "length of jumbopayload opt "
609: "is inconsistent(%d)",
610: *(opt + 1));
611: optlen = IP6OPT_JUMBO_LEN;
612:
613: /*
614: * We can simply cast because of the alignment
615: * requirement of the jumbo payload option.
616: */
617: *plenp = ntohl(*(u_int32_t *)(opt + 2));
618: if (*plenp <= IPV6_MAXPACKET) {
619: /*
620: * jumbo payload length must be larger
621: * than 65535
622: */
623: ip6stat.ip6s_badoptions++;
624: icmp6_error(m, ICMP6_PARAM_PROB,
625: ICMP6_PARAMPROB_HEADER,
626: sizeof(struct ip6_hdr) +
627: sizeof(struct ip6_hbh) +
628: opt + 2 - opthead);
629: return(-1);
630: }
631:
632: ip6 = mtod(m, struct ip6_hdr *);
633: if (ip6->ip6_plen) {
634: /*
635: * IPv6 packets that have non 0 payload length
636: * must not contain a jumbo paylod option.
637: */
638: ip6stat.ip6s_badoptions++;
639: icmp6_error(m, ICMP6_PARAM_PROB,
640: ICMP6_PARAMPROB_HEADER,
641: sizeof(struct ip6_hdr) +
642: sizeof(struct ip6_hbh) +
643: opt - opthead);
644: return(-1);
645: }
646: break;
647: default: /* unknown option */
648: if (hbhlen < IP6OPT_MINLEN) {
649: ip6stat.ip6s_toosmall++;
650: goto bad;
651: }
652: if ((optlen = ip6_unknown_opt(opt, m,
653: sizeof(struct ip6_hdr) +
654: sizeof(struct ip6_hbh) +
655: opt - opthead)) == -1)
656: return(-1);
657: optlen += 2;
658: break;
659: }
660: }
661:
662: return(0);
663:
664: bad:
665: m_freem(m);
666: return(-1);
667: }
668:
669: /*
670: * Unknown option processing.
671: * The third argument `off' is the offset from the IPv6 header to the option,
672: * which is necessary if the IPv6 header the and option header and IPv6 header
673: * is not continuous in order to return an ICMPv6 error.
674: */
675: int
676: ip6_unknown_opt(optp, m, off)
677: u_int8_t *optp;
678: struct mbuf *m;
679: int off;
680: {
681: struct ip6_hdr *ip6;
682:
683: switch(IP6OPT_TYPE(*optp)) {
684: case IP6OPT_TYPE_SKIP: /* ignore the option */
685: return((int)*(optp + 1));
686: case IP6OPT_TYPE_DISCARD: /* silently discard */
687: m_freem(m);
688: return(-1);
689: case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */
690: ip6stat.ip6s_badoptions++;
691: icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off);
692: return(-1);
693: case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */
694: ip6stat.ip6s_badoptions++;
695: ip6 = mtod(m, struct ip6_hdr *);
696: if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
697: (m->m_flags & (M_BCAST|M_MCAST)))
698: m_freem(m);
699: else
700: icmp6_error(m, ICMP6_PARAM_PROB,
701: ICMP6_PARAMPROB_OPTION, off);
702: return(-1);
703: }
704:
705: m_freem(m); /* XXX: NOTREACHED */
706: return(-1);
707: }
708:
709: /*
710: * Create the "control" list for this pcb
711: */
712: void
713: ip6_savecontrol(in6p, mp, ip6, m)
714: register struct in6pcb *in6p;
715: register struct mbuf **mp;
716: register struct ip6_hdr *ip6;
717: register struct mbuf *m;
718: {
719: #ifdef __NetBSD__
720: struct proc *p = curproc; /* XXX */
721: #endif
722: #ifdef __bsdi__
723: # define sbcreatecontrol so_cmsg
724: #endif
725:
726: if (in6p->in6p_socket->so_options & SO_TIMESTAMP) {
727: struct timeval tv;
728:
729: microtime(&tv);
730: *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv),
731: SCM_TIMESTAMP, SOL_SOCKET);
732: if (*mp)
733: mp = &(*mp)->m_next;
734: }
735: if (in6p->in6p_flags & IN6P_RECVDSTADDR) {
736: *mp = sbcreatecontrol((caddr_t) &ip6->ip6_dst,
737: sizeof(struct in6_addr), IPV6_RECVDSTADDR,
738: IPPROTO_IPV6);
739: if (*mp)
740: mp = &(*mp)->m_next;
741: }
742:
743: #ifdef noyet
744: /* options were tossed above */
745: if (in6p->in6p_flags & IN6P_RECVOPTS)
746: /* broken */
747: /* ip6_srcroute doesn't do what we want here, need to fix */
748: if (in6p->in6p_flags & IPV6P_RECVRETOPTS)
749: /* broken */
750: #endif
751:
752: /* RFC 2292 sec. 5 */
753: if (in6p->in6p_flags & IN6P_PKTINFO) {
754: struct in6_pktinfo pi6;
755: bcopy(&ip6->ip6_dst, &pi6.ipi6_addr, sizeof(struct in6_addr));
756: if (IN6_IS_SCOPE_LINKLOCAL(&pi6.ipi6_addr))
757: pi6.ipi6_addr.s6_addr16[1] = 0;
758: pi6.ipi6_ifindex = (m && m->m_pkthdr.rcvif)
759: ? m->m_pkthdr.rcvif->if_index
760: : 0;
761: *mp = sbcreatecontrol((caddr_t) &pi6,
762: sizeof(struct in6_pktinfo), IPV6_PKTINFO,
763: IPPROTO_IPV6);
764: if (*mp)
765: mp = &(*mp)->m_next;
766: }
767: if (in6p->in6p_flags & IN6P_HOPLIMIT) {
768: int hlim = ip6->ip6_hlim & 0xff;
769: *mp = sbcreatecontrol((caddr_t) &hlim,
770: sizeof(int), IPV6_HOPLIMIT, IPPROTO_IPV6);
771: if (*mp)
772: mp = &(*mp)->m_next;
773: }
774: /* IN6P_NEXTHOP - for outgoing packet only */
775:
776: /*
777: * IPV6_HOPOPTS socket option. We require super-user privilege
778: * for the option, but it might be too strict, since there might
779: * be some hop-by-hop options which can be returned to normal user.
780: * See RFC 2292 section 6.
781: */
782: if ((in6p->in6p_flags & IN6P_HOPOPTS) &&
783: p && !suser(p->p_ucred, &p->p_acflag)) {
784: /*
785: * Check if a hop-by-hop options header is contatined in the
786: * received packet, and if so, store the options as ancillary
787: * data. Note that a hop-by-hop options header must be
788: * just after the IPv6 header, which fact is assured through
789: * the IPv6 input processing.
790: */
791: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
792: if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {
793: struct ip6_hbh *hbh = (struct ip6_hbh *)(ip6 + 1);
794:
795: /*
796: * XXX: We copy whole the header even if a jumbo
797: * payload option is included, which option is to
798: * be removed before returning in the RFC 2292.
799: * But it's too painful operation...
800: */
801: *mp = sbcreatecontrol((caddr_t)hbh,
802: (hbh->ip6h_len + 1) << 3,
803: IPV6_HOPOPTS, IPPROTO_IPV6);
804: if (*mp)
805: mp = &(*mp)->m_next;
806: }
807: }
808:
809: /* IPV6_DSTOPTS and IPV6_RTHDR socket options */
810: if (in6p->in6p_flags & (IN6P_DSTOPTS | IN6P_RTHDR)) {
811: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
812: int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr);;
813:
814: /*
815: * Search for destination options headers or routing
816: * header(s) through the header chain, and stores each
817: * header as ancillary data.
818: * Note that the order of the headers remains in
819: * the chain of ancillary data.
820: */
821: while(1) { /* is explicit loop prevention necessary? */
822: struct ip6_ext *ip6e =
823: (struct ip6_ext *)(mtod(m, caddr_t) + off);
824:
825: switch(nxt) {
826: case IPPROTO_DSTOPTS:
827: if (!in6p->in6p_flags & IN6P_DSTOPTS)
828: break;
829:
830: /*
831: * We also require super-user privilege for
832: * the option.
833: * See the comments on IN6_HOPOPTS.
834: */
835: if (!p || !suser(p->p_ucred, &p->p_acflag))
836: break;
837:
838: *mp = sbcreatecontrol((caddr_t)ip6e,
839: (ip6e->ip6e_len + 1) << 3,
840: IPV6_DSTOPTS,
841: IPPROTO_IPV6);
842: if (*mp)
843: mp = &(*mp)->m_next;
844: break;
845:
846: case IPPROTO_ROUTING:
847: if (!in6p->in6p_flags & IN6P_RTHDR)
848: break;
849:
850: *mp = sbcreatecontrol((caddr_t)ip6e,
851: (ip6e->ip6e_len + 1) << 3,
852: IPV6_RTHDR,
853: IPPROTO_IPV6);
854: if (*mp)
855: mp = &(*mp)->m_next;
856: break;
857:
858: case IPPROTO_UDP:
859: case IPPROTO_TCP:
860: case IPPROTO_ICMPV6:
861: default:
862: /*
863: * stop search if we encounter an upper
864: * layer protocol headers.
865: */
866: goto loopend;
867:
868: case IPPROTO_HOPOPTS:
869: case IPPROTO_AH: /* is it possible? */
870: break;
871: }
872:
873: /* proceed with the next header. */
874: if (nxt == IPPROTO_AH)
875: off += (ip6e->ip6e_len + 2) << 2;
876: else
877: off += (ip6e->ip6e_len + 1) << 3;
878: nxt = ip6e->ip6e_nxt;
879: }
880: loopend:
881: }
882: if ((in6p->in6p_flags & IN6P_HOPOPTS)
883: && p && !suser(p->p_ucred, &p->p_acflag)) {
884: /* to be done */
885: }
886: if ((in6p->in6p_flags & IN6P_DSTOPTS)
887: && p && !suser(p->p_ucred, &p->p_acflag)) {
888: /* to be done */
889: }
890: /* IN6P_RTHDR - to be done */
891:
892: #ifdef __bsdi__
893: # undef sbcreatecontrol
894: #endif
895: }
896:
897: /*
898: * Get pointer to the previous header followed by the header
899: * currently processed.
900: * XXX: This function supposes that
901: * M includes all headers,
902: * the next header field and the header length field of each header
903: * are valid, and
904: * the sum of each header length equals to OFF.
905: * Because of these assumptions, this function must be called very
906: * carefully. Moreover, it will not be used in the near future when
907: * we develop `neater' mechanism to process extension headers.
908: */
909: char *
910: ip6_get_prevhdr(m, off)
911: struct mbuf *m;
912: int off;
913: {
914: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
915:
916: if (off == sizeof(struct ip6_hdr))
917: return(&ip6->ip6_nxt);
918: else {
919: int len, nxt;
920: struct ip6_ext *ip6e = NULL;
921:
922: nxt = ip6->ip6_nxt;
923: len = sizeof(struct ip6_hdr);
924: while (len < off) {
925: ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + len);
926:
927: switch(nxt) {
928: case IPPROTO_FRAGMENT:
929: len += sizeof(struct ip6_frag);
930: break;
931: case IPPROTO_AH:
932: len += (ip6e->ip6e_len + 2) << 2;
933: break;
934: default:
935: len += (ip6e->ip6e_len + 1) << 3;
936: break;
937: }
938: nxt = ip6e->ip6e_nxt;
939: }
940: if (ip6e)
941: return(&ip6e->ip6e_nxt);
942: else
943: return NULL;
944: }
945: }
946:
947: /*
948: * System control for IP6
949: */
950:
951: u_char inet6ctlerrmap[PRC_NCMDS] = {
952: 0, 0, 0, 0,
953: 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH,
954: EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
955: EMSGSIZE, EHOSTUNREACH, 0, 0,
956: 0, 0, 0, 0,
957: ENOPROTOOPT
958: };
959:
960: #ifdef __NetBSD__
961: #include <vm/vm.h>
962: #include <sys/sysctl.h>
963:
964: int
965: ip6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
966: int *name;
967: u_int namelen;
968: void *oldp;
969: size_t *oldlenp;
970: void *newp;
971: size_t newlen;
972: {
973: /* All sysctl names at this level are terminal. */
974: if (namelen != 1)
975: return ENOTDIR;
976:
977: switch (name[0]) {
978:
979: case IPV6CTL_FORWARDING:
980: return sysctl_int(oldp, oldlenp, newp, newlen,
981: &ip6_forwarding);
982: case IPV6CTL_SENDREDIRECTS:
983: return sysctl_int(oldp, oldlenp, newp, newlen,
984: &ip6_sendredirects);
985: case IPV6CTL_DEFHLIM:
986: return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_defhlim);
987: case IPV6CTL_MAXFRAGPACKETS:
988: return sysctl_int(oldp, oldlenp, newp, newlen,
989: &ip6_maxfragpackets);
990: case IPV6CTL_ACCEPT_RTADV:
991: return sysctl_int(oldp, oldlenp, newp, newlen,
992: &ip6_accept_rtadv);
993: case IPV6CTL_KEEPFAITH:
994: return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_keepfaith);
995: case IPV6CTL_LOG_INTERVAL:
996: return sysctl_int(oldp, oldlenp, newp, newlen,
997: &ip6_log_interval);
998: case IPV6CTL_HDRNESTLIMIT:
999: return sysctl_int(oldp, oldlenp, newp, newlen,
1000: &ip6_hdrnestlimit);
1001: case IPV6CTL_DAD_COUNT:
1002: return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_dad_count);
1003: case IPV6CTL_AUTO_FLOWLABEL:
1004: return sysctl_int(oldp, oldlenp, newp, newlen,
1005: &ip6_auto_flowlabel);
1006: case IPV6CTL_DEFMCASTHLIM:
1007: return sysctl_int(oldp, oldlenp, newp, newlen,
1008: &ip6_defmcasthlim);
1009: case IPV6CTL_GIF_HLIM:
1010: return sysctl_int(oldp, oldlenp, newp, newlen,
1011: &ip6_gif_hlim);
1012: case IPV6CTL_KAME_VERSION:
1013: return sysctl_rdstring(oldp, oldlenp, newp, __KAME_VERSION);
1014: default:
1015: return EOPNOTSUPP;
1016: }
1017: /* NOTREACHED */
1018: }
1019: #endif /* __NetBSD__ */
CVSweb <webmaster@jp.NetBSD.org>