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