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