|
|
1.8 ! itojun 1: /* $NetBSD: ip6_input.c,v 1.7 1999/08/07 12:33:04 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:
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;
1.5 itojun 243: u_int32_t rtalert = ~0;
1.2 itojun 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: */
1.5 itojun 455: if (rtalert != ~0 && ip6_forwarding)
1.2 itojun 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: }
1.8 ! itojun 515:
! 516: /*
! 517: * protection against faulty packet - there should be
! 518: * more sanity checks in header chain processing.
! 519: */
! 520: if (m->m_pkthdr.len < off) {
! 521: ip6stat.ip6s_tooshort++;
! 522: goto bad;
! 523: }
! 524:
1.2 itojun 525: nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt);
526: }
527: return;
528: bad:
529: m_freem(m);
530: }
531:
532: /*
533: * Hop-by-Hop options header processing. If a valid jumbo payload option is
534: * included, the real payload length will be stored in plenp.
535: */
536: static int
537: ip6_hopopts_input(plenp, rtalertp, mp, offp)
538: u_int32_t *plenp;
1.5 itojun 539: u_int32_t *rtalertp; /* XXX: should be stored more smart way */
1.2 itojun 540: struct mbuf **mp;
541: int *offp;
542: {
543: register struct mbuf *m = *mp;
544: int off = *offp, hbhlen;
545: struct ip6_hbh *hbh;
546: u_int8_t *opt;
547:
548: /* validation of the length of the header */
549: IP6_EXTHDR_CHECK(m, off, sizeof(*hbh), -1);
550: hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off);
551: hbhlen = (hbh->ip6h_len + 1) << 3;
552:
553: IP6_EXTHDR_CHECK(m, off, hbhlen, -1);
554: hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off);
555: off += hbhlen;
556: hbhlen -= sizeof(struct ip6_hbh);
557: opt = (u_int8_t *)hbh + sizeof(struct ip6_hbh);
558:
559: if (ip6_process_hopopts(m, (u_int8_t *)hbh + sizeof(struct ip6_hbh),
560: hbhlen, rtalertp, plenp) < 0)
561: return(-1);
562:
563: *offp = off;
564: *mp = m;
565: return(0);
566: }
567:
568: /*
569: * Search header for all Hop-by-hop options and process each option.
570: * This function is separate from ip6_hopopts_input() in order to
571: * handle a case where the sending node itself process its hop-by-hop
572: * options header. In such a case, the function is called from ip6_output().
573: */
574: int
575: ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp)
576: struct mbuf *m;
577: u_int8_t *opthead;
578: int hbhlen;
1.5 itojun 579: u_int32_t *rtalertp;
1.2 itojun 580: u_int32_t *plenp;
581: {
582: struct ip6_hdr *ip6;
583: int optlen = 0;
584: u_int8_t *opt = opthead;
585: u_int16_t rtalert_val;
586:
587: for (; hbhlen > 0; hbhlen -= optlen, opt += optlen) {
588: switch(*opt) {
589: case IP6OPT_PAD1:
590: optlen = 1;
591: break;
592: case IP6OPT_PADN:
593: if (hbhlen < IP6OPT_MINLEN) {
594: ip6stat.ip6s_toosmall++;
595: goto bad;
596: }
597: optlen = *(opt + 1) + 2;
598: break;
599: case IP6OPT_RTALERT:
1.8 ! itojun 600: /* XXX may need check for alignment */
1.2 itojun 601: if (hbhlen < IP6OPT_RTALERT_LEN) {
602: ip6stat.ip6s_toosmall++;
603: goto bad;
604: }
605: if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2)
606: /* XXX: should we discard the packet? */
607: log(LOG_ERR, "length of router alert opt is inconsitent(%d)",
608: *(opt + 1));
609: optlen = IP6OPT_RTALERT_LEN;
610: bcopy((caddr_t)(opt + 2), (caddr_t)&rtalert_val, 2);
611: *rtalertp = ntohs(rtalert_val);
612: break;
613: case IP6OPT_JUMBO:
1.8 ! itojun 614: /* XXX may need check for alignment */
1.2 itojun 615: if (hbhlen < IP6OPT_JUMBO_LEN) {
616: ip6stat.ip6s_toosmall++;
617: goto bad;
618: }
619: if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2)
620: /* XXX: should we discard the packet? */
621: log(LOG_ERR, "length of jumbopayload opt "
622: "is inconsistent(%d)",
623: *(opt + 1));
624: optlen = IP6OPT_JUMBO_LEN;
625:
626: /*
627: * We can simply cast because of the alignment
628: * requirement of the jumbo payload option.
629: */
1.8 ! itojun 630: #if 0
1.2 itojun 631: *plenp = ntohl(*(u_int32_t *)(opt + 2));
1.8 ! itojun 632: #else
! 633: bcopy(opt + 2, plenp, sizeof(*plenp));
! 634: *plenp = htonl(*plenp);
! 635: #endif
1.2 itojun 636: if (*plenp <= IPV6_MAXPACKET) {
637: /*
638: * jumbo payload length must be larger
639: * than 65535
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 + 2 - opthead);
647: return(-1);
648: }
649:
650: ip6 = mtod(m, struct ip6_hdr *);
651: if (ip6->ip6_plen) {
652: /*
653: * IPv6 packets that have non 0 payload length
654: * must not contain a jumbo paylod option.
655: */
656: ip6stat.ip6s_badoptions++;
657: icmp6_error(m, ICMP6_PARAM_PROB,
658: ICMP6_PARAMPROB_HEADER,
659: sizeof(struct ip6_hdr) +
660: sizeof(struct ip6_hbh) +
661: opt - opthead);
662: return(-1);
663: }
664: break;
665: default: /* unknown option */
666: if (hbhlen < IP6OPT_MINLEN) {
667: ip6stat.ip6s_toosmall++;
668: goto bad;
669: }
670: if ((optlen = ip6_unknown_opt(opt, m,
671: sizeof(struct ip6_hdr) +
672: sizeof(struct ip6_hbh) +
673: opt - opthead)) == -1)
674: return(-1);
675: optlen += 2;
676: break;
677: }
678: }
679:
680: return(0);
681:
682: bad:
683: m_freem(m);
684: return(-1);
685: }
686:
687: /*
688: * Unknown option processing.
689: * The third argument `off' is the offset from the IPv6 header to the option,
690: * which is necessary if the IPv6 header the and option header and IPv6 header
691: * is not continuous in order to return an ICMPv6 error.
692: */
693: int
694: ip6_unknown_opt(optp, m, off)
695: u_int8_t *optp;
696: struct mbuf *m;
697: int off;
698: {
699: struct ip6_hdr *ip6;
700:
701: switch(IP6OPT_TYPE(*optp)) {
702: case IP6OPT_TYPE_SKIP: /* ignore the option */
703: return((int)*(optp + 1));
704: case IP6OPT_TYPE_DISCARD: /* silently discard */
705: m_freem(m);
706: return(-1);
707: case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */
708: ip6stat.ip6s_badoptions++;
709: icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off);
710: return(-1);
711: case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */
712: ip6stat.ip6s_badoptions++;
713: ip6 = mtod(m, struct ip6_hdr *);
714: if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
715: (m->m_flags & (M_BCAST|M_MCAST)))
716: m_freem(m);
717: else
718: icmp6_error(m, ICMP6_PARAM_PROB,
719: ICMP6_PARAMPROB_OPTION, off);
720: return(-1);
721: }
722:
723: m_freem(m); /* XXX: NOTREACHED */
724: return(-1);
725: }
726:
727: /*
728: * Create the "control" list for this pcb
729: */
730: void
731: ip6_savecontrol(in6p, mp, ip6, m)
732: register struct in6pcb *in6p;
733: register struct mbuf **mp;
734: register struct ip6_hdr *ip6;
735: register struct mbuf *m;
736: {
737: #ifdef __NetBSD__
738: struct proc *p = curproc; /* XXX */
739: #endif
740: #ifdef __bsdi__
741: # define sbcreatecontrol so_cmsg
742: #endif
743:
744: if (in6p->in6p_socket->so_options & SO_TIMESTAMP) {
745: struct timeval tv;
746:
747: microtime(&tv);
748: *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv),
749: SCM_TIMESTAMP, SOL_SOCKET);
750: if (*mp)
751: mp = &(*mp)->m_next;
752: }
753: if (in6p->in6p_flags & IN6P_RECVDSTADDR) {
754: *mp = sbcreatecontrol((caddr_t) &ip6->ip6_dst,
755: sizeof(struct in6_addr), IPV6_RECVDSTADDR,
756: IPPROTO_IPV6);
757: if (*mp)
758: mp = &(*mp)->m_next;
759: }
760:
761: #ifdef noyet
762: /* options were tossed above */
763: if (in6p->in6p_flags & IN6P_RECVOPTS)
764: /* broken */
765: /* ip6_srcroute doesn't do what we want here, need to fix */
766: if (in6p->in6p_flags & IPV6P_RECVRETOPTS)
767: /* broken */
768: #endif
769:
770: /* RFC 2292 sec. 5 */
771: if (in6p->in6p_flags & IN6P_PKTINFO) {
772: struct in6_pktinfo pi6;
773: bcopy(&ip6->ip6_dst, &pi6.ipi6_addr, sizeof(struct in6_addr));
774: if (IN6_IS_SCOPE_LINKLOCAL(&pi6.ipi6_addr))
775: pi6.ipi6_addr.s6_addr16[1] = 0;
776: pi6.ipi6_ifindex = (m && m->m_pkthdr.rcvif)
777: ? m->m_pkthdr.rcvif->if_index
778: : 0;
779: *mp = sbcreatecontrol((caddr_t) &pi6,
780: sizeof(struct in6_pktinfo), IPV6_PKTINFO,
781: IPPROTO_IPV6);
782: if (*mp)
783: mp = &(*mp)->m_next;
784: }
785: if (in6p->in6p_flags & IN6P_HOPLIMIT) {
786: int hlim = ip6->ip6_hlim & 0xff;
787: *mp = sbcreatecontrol((caddr_t) &hlim,
788: sizeof(int), IPV6_HOPLIMIT, IPPROTO_IPV6);
789: if (*mp)
790: mp = &(*mp)->m_next;
791: }
792: /* IN6P_NEXTHOP - for outgoing packet only */
793:
794: /*
795: * IPV6_HOPOPTS socket option. We require super-user privilege
796: * for the option, but it might be too strict, since there might
797: * be some hop-by-hop options which can be returned to normal user.
798: * See RFC 2292 section 6.
799: */
800: if ((in6p->in6p_flags & IN6P_HOPOPTS) &&
801: p && !suser(p->p_ucred, &p->p_acflag)) {
802: /*
803: * Check if a hop-by-hop options header is contatined in the
804: * received packet, and if so, store the options as ancillary
805: * data. Note that a hop-by-hop options header must be
806: * just after the IPv6 header, which fact is assured through
807: * the IPv6 input processing.
808: */
809: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
810: if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {
811: struct ip6_hbh *hbh = (struct ip6_hbh *)(ip6 + 1);
812:
813: /*
814: * XXX: We copy whole the header even if a jumbo
815: * payload option is included, which option is to
816: * be removed before returning in the RFC 2292.
817: * But it's too painful operation...
818: */
819: *mp = sbcreatecontrol((caddr_t)hbh,
820: (hbh->ip6h_len + 1) << 3,
821: IPV6_HOPOPTS, IPPROTO_IPV6);
822: if (*mp)
823: mp = &(*mp)->m_next;
824: }
825: }
826:
827: /* IPV6_DSTOPTS and IPV6_RTHDR socket options */
828: if (in6p->in6p_flags & (IN6P_DSTOPTS | IN6P_RTHDR)) {
829: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
830: int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr);;
831:
832: /*
833: * Search for destination options headers or routing
834: * header(s) through the header chain, and stores each
835: * header as ancillary data.
836: * Note that the order of the headers remains in
837: * the chain of ancillary data.
838: */
839: while(1) { /* is explicit loop prevention necessary? */
840: struct ip6_ext *ip6e =
841: (struct ip6_ext *)(mtod(m, caddr_t) + off);
842:
843: switch(nxt) {
844: case IPPROTO_DSTOPTS:
845: if (!in6p->in6p_flags & IN6P_DSTOPTS)
846: break;
847:
848: /*
849: * We also require super-user privilege for
850: * the option.
851: * See the comments on IN6_HOPOPTS.
852: */
853: if (!p || !suser(p->p_ucred, &p->p_acflag))
854: break;
855:
856: *mp = sbcreatecontrol((caddr_t)ip6e,
857: (ip6e->ip6e_len + 1) << 3,
858: IPV6_DSTOPTS,
859: IPPROTO_IPV6);
860: if (*mp)
861: mp = &(*mp)->m_next;
862: break;
863:
864: case IPPROTO_ROUTING:
865: if (!in6p->in6p_flags & IN6P_RTHDR)
866: break;
867:
868: *mp = sbcreatecontrol((caddr_t)ip6e,
869: (ip6e->ip6e_len + 1) << 3,
870: IPV6_RTHDR,
871: IPPROTO_IPV6);
872: if (*mp)
873: mp = &(*mp)->m_next;
874: break;
875:
876: case IPPROTO_UDP:
877: case IPPROTO_TCP:
878: case IPPROTO_ICMPV6:
879: default:
880: /*
881: * stop search if we encounter an upper
882: * layer protocol headers.
883: */
884: goto loopend;
885:
886: case IPPROTO_HOPOPTS:
887: case IPPROTO_AH: /* is it possible? */
888: break;
889: }
890:
891: /* proceed with the next header. */
892: if (nxt == IPPROTO_AH)
893: off += (ip6e->ip6e_len + 2) << 2;
894: else
895: off += (ip6e->ip6e_len + 1) << 3;
896: nxt = ip6e->ip6e_nxt;
897: }
898: loopend:
899: }
900: if ((in6p->in6p_flags & IN6P_HOPOPTS)
901: && p && !suser(p->p_ucred, &p->p_acflag)) {
902: /* to be done */
903: }
904: if ((in6p->in6p_flags & IN6P_DSTOPTS)
905: && p && !suser(p->p_ucred, &p->p_acflag)) {
906: /* to be done */
907: }
908: /* IN6P_RTHDR - to be done */
909:
910: #ifdef __bsdi__
911: # undef sbcreatecontrol
912: #endif
913: }
914:
915: /*
916: * Get pointer to the previous header followed by the header
917: * currently processed.
918: * XXX: This function supposes that
919: * M includes all headers,
920: * the next header field and the header length field of each header
921: * are valid, and
922: * the sum of each header length equals to OFF.
923: * Because of these assumptions, this function must be called very
924: * carefully. Moreover, it will not be used in the near future when
925: * we develop `neater' mechanism to process extension headers.
926: */
927: char *
928: ip6_get_prevhdr(m, off)
929: struct mbuf *m;
930: int off;
931: {
932: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
933:
934: if (off == sizeof(struct ip6_hdr))
935: return(&ip6->ip6_nxt);
936: else {
937: int len, nxt;
938: struct ip6_ext *ip6e = NULL;
939:
940: nxt = ip6->ip6_nxt;
941: len = sizeof(struct ip6_hdr);
942: while (len < off) {
943: ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + len);
944:
945: switch(nxt) {
946: case IPPROTO_FRAGMENT:
947: len += sizeof(struct ip6_frag);
948: break;
949: case IPPROTO_AH:
950: len += (ip6e->ip6e_len + 2) << 2;
951: break;
952: default:
953: len += (ip6e->ip6e_len + 1) << 3;
954: break;
955: }
956: nxt = ip6e->ip6e_nxt;
957: }
958: if (ip6e)
959: return(&ip6e->ip6e_nxt);
960: else
961: return NULL;
962: }
963: }
964:
965: /*
966: * System control for IP6
967: */
968:
969: u_char inet6ctlerrmap[PRC_NCMDS] = {
970: 0, 0, 0, 0,
971: 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH,
972: EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
973: EMSGSIZE, EHOSTUNREACH, 0, 0,
974: 0, 0, 0, 0,
975: ENOPROTOOPT
976: };
977:
978: #ifdef __NetBSD__
979: #include <vm/vm.h>
980: #include <sys/sysctl.h>
981:
982: int
983: ip6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
984: int *name;
985: u_int namelen;
986: void *oldp;
987: size_t *oldlenp;
988: void *newp;
989: size_t newlen;
990: {
991: /* All sysctl names at this level are terminal. */
992: if (namelen != 1)
993: return ENOTDIR;
994:
995: switch (name[0]) {
996:
997: case IPV6CTL_FORWARDING:
998: return sysctl_int(oldp, oldlenp, newp, newlen,
999: &ip6_forwarding);
1000: case IPV6CTL_SENDREDIRECTS:
1001: return sysctl_int(oldp, oldlenp, newp, newlen,
1002: &ip6_sendredirects);
1003: case IPV6CTL_DEFHLIM:
1004: return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_defhlim);
1005: case IPV6CTL_MAXFRAGPACKETS:
1006: return sysctl_int(oldp, oldlenp, newp, newlen,
1007: &ip6_maxfragpackets);
1008: case IPV6CTL_ACCEPT_RTADV:
1009: return sysctl_int(oldp, oldlenp, newp, newlen,
1010: &ip6_accept_rtadv);
1011: case IPV6CTL_KEEPFAITH:
1012: return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_keepfaith);
1013: case IPV6CTL_LOG_INTERVAL:
1014: return sysctl_int(oldp, oldlenp, newp, newlen,
1015: &ip6_log_interval);
1016: case IPV6CTL_HDRNESTLIMIT:
1017: return sysctl_int(oldp, oldlenp, newp, newlen,
1018: &ip6_hdrnestlimit);
1019: case IPV6CTL_DAD_COUNT:
1020: return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_dad_count);
1021: case IPV6CTL_AUTO_FLOWLABEL:
1022: return sysctl_int(oldp, oldlenp, newp, newlen,
1023: &ip6_auto_flowlabel);
1024: case IPV6CTL_DEFMCASTHLIM:
1025: return sysctl_int(oldp, oldlenp, newp, newlen,
1026: &ip6_defmcasthlim);
1027: case IPV6CTL_GIF_HLIM:
1028: return sysctl_int(oldp, oldlenp, newp, newlen,
1029: &ip6_gif_hlim);
1030: case IPV6CTL_KAME_VERSION:
1031: return sysctl_rdstring(oldp, oldlenp, newp, __KAME_VERSION);
1032: default:
1033: return EOPNOTSUPP;
1034: }
1035: /* NOTREACHED */
1036: }
1037: #endif /* __NetBSD__ */