Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/netinet6/ip6_input.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/netinet6/ip6_input.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.49 retrieving revision 1.69 diff -u -p -r1.49 -r1.69 --- src/sys/netinet6/ip6_input.c 2001/12/18 03:04:03 1.49 +++ src/sys/netinet6/ip6_input.c 2003/11/12 15:25:19 1.69 @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_input.c,v 1.49 2001/12/18 03:04:03 itojun Exp $ */ +/* $NetBSD: ip6_input.c,v 1.69 2003/11/12 15:25:19 itojun Exp $ */ /* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */ /* @@ -42,11 +42,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -66,7 +62,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.49 2001/12/18 03:04:03 itojun Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.69 2003/11/12 15:25:19 itojun Exp $"); #include "opt_inet.h" #include "opt_ipsec.h" @@ -109,7 +105,6 @@ __KERNEL_RCSID(0, "$NetBSD: ip6_input.c, #include #include #include -#include #ifdef IPSEC #include @@ -123,6 +118,10 @@ __KERNEL_RCSID(0, "$NetBSD: ip6_input.c, #include "gif.h" #include "bpfilter.h" +#if NGIF > 0 +#include +#endif + #include extern struct domain inet6domain; @@ -146,6 +145,7 @@ struct ip6stat ip6stat; static void ip6_init2 __P((void *)); static int ip6_hopopts_input __P((u_int32_t *, u_int32_t *, struct mbuf **, int *)); +static struct mbuf *ip6_pullexthdr __P((struct mbuf *, size_t, int)); /* * IP6 initialization: fill in IP6 protocol switch table. @@ -156,7 +156,6 @@ ip6_init() { struct ip6protosw *pr; int i; - struct timeval tv; pr = (struct ip6protosw *)pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); if (pr == 0) @@ -171,12 +170,6 @@ ip6_init() ip6intrq.ifq_maxlen = ip6qmaxlen; nd6_init(); frag6_init(); - /* - * in many cases, random() here does NOT return random number - * as initialization during bootstrap time occur in fixed order. - */ - microtime(&tv); - ip6_flow_seq = random() ^ tv.tv_usec; ip6_init2((void *)0); @@ -195,18 +188,10 @@ static void ip6_init2(dummy) void *dummy; { - /* - * to route local address of p2p link to loopback, - * assign loopback address first. - */ - in6_ifattach(&loif[0], NULL); /* nd6_timer_init */ callout_init(&nd6_timer_ch); callout_reset(&nd6_timer_ch, hz, nd6_timer, NULL); - /* router renumbering prefix list maintenance */ - callout_init(&in6_rr_timer_ch); - callout_reset(&in6_rr_timer_ch, hz, in6_rr_timer, NULL); } /* @@ -240,6 +225,7 @@ ip6_input(m) u_int32_t rtalert = ~0; int nxt, ours = 0; struct ifnet *deliverifp = NULL; + int srcrt = 0; #ifdef IPSEC /* @@ -275,15 +261,24 @@ ip6_input(m) in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive); ip6stat.ip6s_total++; -#ifndef PULLDOWN_TEST - /* XXX is the line really necessary? */ - IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), /*nothing*/); -#endif - - if (m->m_len < sizeof(struct ip6_hdr)) { - struct ifnet *inifp; - inifp = m->m_pkthdr.rcvif; - if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == 0) { + /* + * If the IPv6 header is not aligned, slurp it up into a new + * mbuf with space for link headers, in the event we forward + * it. OTherwise, if it is aligned, make sure the entire base + * IPv6 header is in the first mbuf of the chain. + */ + if (IP6_HDR_ALIGNED_P(mtod(m, caddr_t)) == 0) { + struct ifnet *inifp = m->m_pkthdr.rcvif; + if ((m = m_copyup(m, sizeof(struct ip6_hdr), + (max_linkhdr + 3) & ~3)) == NULL) { + /* XXXJRT new stat, please */ + ip6stat.ip6s_toosmall++; + in6_ifstat_inc(inifp, ifs6_in_hdrerr); + return; + } + } else if (__predict_false(m->m_len < sizeof(struct ip6_hdr))) { + struct ifnet *inifp = m->m_pkthdr.rcvif; + if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { ip6stat.ip6s_toosmall++; in6_ifstat_inc(inifp, ifs6_in_hdrerr); return; @@ -316,12 +311,16 @@ ip6_input(m) if (1) #endif { + struct in6_addr odst; + + odst = ip6->ip6_dst; if (pfil_run_hooks(&inet6_pfil_hook, &m, m->m_pkthdr.rcvif, PFIL_IN) != 0) return; if (m == NULL) return; ip6 = mtod(m, struct ip6_hdr *); + srcrt = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst); } #endif /* PFIL_HOOKS */ @@ -339,6 +338,9 @@ ip6_input(m) */ if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src) || IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) { + /* + * XXX: "badscope" is not very suitable for a multicast source. + */ ip6stat.ip6s_badscope++; in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); goto bad; @@ -353,7 +355,7 @@ ip6_input(m) * support IPv4-less kernel compilation, we cannot support SIIT * environment at all. So, it makes more sense for us to reject any * malicious packets for non-SIIT environment, than try to do a - * partical support for SIIT environment. + * partial support for SIIT environment. */ if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { @@ -462,7 +464,7 @@ ip6_input(m) * Unicast check */ if (ip6_forward_rt.ro_rt != NULL && - (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) != 0 && + (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) != 0 && IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &((struct sockaddr_in6 *)(&ip6_forward_rt.ro_dst))->sin6_addr)) ip6stat.ip6s_forward_cachehit++; @@ -499,6 +501,7 @@ ip6_input(m) if (ip6_forward_rt.ro_rt && (ip6_forward_rt.ro_rt->rt_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST && + !(ip6_forward_rt.ro_rt->rt_flags & RTF_CLONED) && #if 0 /* * The check below is redundant since the comparison of @@ -506,7 +509,7 @@ ip6_input(m) * already done through looking up the routing table. */ IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, - &rt6_key(ip6_forward_rt.ro_rt)->sin6_addr) && + &rt6_key(ip6_forward_rt.ro_rt)->sin6_addr) && #endif ip6_forward_rt.ro_rt->rt_ifp->if_type == IFT_LOOP) { struct in6_ifaddr *ia6 = @@ -534,7 +537,7 @@ ip6_input(m) } /* - * FAITH(Firewall Aided Internet Translator) + * FAITH (Firewall Aided Internet Translator) */ #if defined(NFAITH) && 0 < NFAITH if (ip6_keepfaith) { @@ -611,7 +614,7 @@ ip6_input(m) /* * Note that if a valid jumbo payload option is * contained, ip6_hoptops_input() must set a valid - * (non-zero) payload length to the variable plen. + * (non-zero) payload length to the variable plen. */ ip6stat.ip6s_badoptions++; in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); @@ -621,17 +624,13 @@ ip6_input(m) (caddr_t)&ip6->ip6_plen - (caddr_t)ip6); return; } -#ifndef PULLDOWN_TEST - /* ip6_hopopts_input() ensures that mbuf is contiguous */ - hbh = (struct ip6_hbh *)(ip6 + 1); -#else IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), sizeof(struct ip6_hbh)); if (hbh == NULL) { ip6stat.ip6s_tooshort++; return; } -#endif + KASSERT(IP6_HDR_ALIGNED_P(hbh)); nxt = hbh->ip6h_nxt; /* @@ -684,9 +683,9 @@ ip6_input(m) return; } } else if (!ours) { - ip6_forward(m, 0); + ip6_forward(m, srcrt); return; - } + } ip6 = mtod(m, struct ip6_hdr *); @@ -749,7 +748,7 @@ ip6_input(m) goto bad; } #endif - + nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); } return; @@ -771,17 +770,8 @@ ip6_hopopts_input(plenp, rtalertp, mp, o struct mbuf *m = *mp; int off = *offp, hbhlen; struct ip6_hbh *hbh; - u_int8_t *opt; /* validation of the length of the header */ -#ifndef PULLDOWN_TEST - IP6_EXTHDR_CHECK(m, off, sizeof(*hbh), -1); - hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off); - hbhlen = (hbh->ip6h_len + 1) << 3; - - IP6_EXTHDR_CHECK(m, off, hbhlen, -1); - hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off); -#else IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), sizeof(struct ip6_hbh)); if (hbh == NULL) { @@ -795,18 +785,17 @@ ip6_hopopts_input(plenp, rtalertp, mp, o ip6stat.ip6s_tooshort++; return -1; } -#endif + KASSERT(IP6_HDR_ALIGNED_P(hbh)); off += hbhlen; hbhlen -= sizeof(struct ip6_hbh); - opt = (u_int8_t *)hbh + sizeof(struct ip6_hbh); if (ip6_process_hopopts(m, (u_int8_t *)hbh + sizeof(struct ip6_hbh), hbhlen, rtalertp, plenp) < 0) - return(-1); + return (-1); *offp = off; *mp = m; - return(0); + return (0); } /* @@ -814,6 +803,10 @@ ip6_hopopts_input(plenp, rtalertp, mp, o * This function is separate from ip6_hopopts_input() in order to * handle a case where the sending node itself process its hop-by-hop * options header. In such a case, the function is called from ip6_output(). + * + * The function assumes that hbh header is located right after the IPv6 header + * (RFC2460 p7), opthead is pointer into data content in m, and opthead to + * opthead + hbhlen is located in continuous memory region. */ int ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp) @@ -828,6 +821,7 @@ ip6_process_hopopts(m, opthead, hbhlen, u_int8_t *opt = opthead; u_int16_t rtalert_val; u_int32_t jumboplen; + const int erroff = sizeof(struct ip6_hdr) + sizeof(struct ip6_hbh); for (; hbhlen > 0; hbhlen -= optlen, opt += optlen) { switch (*opt) { @@ -848,9 +842,11 @@ ip6_process_hopopts(m, opthead, hbhlen, goto bad; } if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2) { - /* XXX: should we discard the packet? */ - log(LOG_ERR, "length of router alert opt is inconsitent(%d)", - *(opt + 1)); + /* XXX stat */ + icmp6_error(m, ICMP6_PARAM_PROB, + ICMP6_PARAMPROB_HEADER, + erroff + opt + 1 - opthead); + return (-1); } optlen = IP6OPT_RTALERT_LEN; bcopy((caddr_t)(opt + 2), (caddr_t)&rtalert_val, 2); @@ -863,10 +859,11 @@ ip6_process_hopopts(m, opthead, hbhlen, goto bad; } if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2) { - /* XXX: should we discard the packet? */ - log(LOG_ERR, "length of jumbopayload opt " - "is inconsistent(%d)\n", - *(opt + 1)); + /* XXX stat */ + icmp6_error(m, ICMP6_PARAM_PROB, + ICMP6_PARAMPROB_HEADER, + erroff + opt + 1 - opthead); + return (-1); } optlen = IP6OPT_JUMBO_LEN; @@ -878,11 +875,9 @@ ip6_process_hopopts(m, opthead, hbhlen, if (ip6->ip6_plen) { ip6stat.ip6s_badoptions++; icmp6_error(m, ICMP6_PARAM_PROB, - ICMP6_PARAMPROB_HEADER, - sizeof(struct ip6_hdr) + - sizeof(struct ip6_hbh) + - opt - opthead); - return(-1); + ICMP6_PARAMPROB_HEADER, + erroff + opt - opthead); + return (-1); } /* @@ -904,11 +899,9 @@ ip6_process_hopopts(m, opthead, hbhlen, if (*plenp != 0) { ip6stat.ip6s_badoptions++; icmp6_error(m, ICMP6_PARAM_PROB, - ICMP6_PARAMPROB_HEADER, - sizeof(struct ip6_hdr) + - sizeof(struct ip6_hbh) + - opt + 2 - opthead); - return(-1); + ICMP6_PARAMPROB_HEADER, + erroff + opt + 2 - opthead); + return (-1); } #endif @@ -918,11 +911,9 @@ ip6_process_hopopts(m, opthead, hbhlen, if (jumboplen <= IPV6_MAXPACKET) { ip6stat.ip6s_badoptions++; icmp6_error(m, ICMP6_PARAM_PROB, - ICMP6_PARAMPROB_HEADER, - sizeof(struct ip6_hdr) + - sizeof(struct ip6_hbh) + - opt + 2 - opthead); - return(-1); + ICMP6_PARAMPROB_HEADER, + erroff + opt + 2 - opthead); + return (-1); } *plenp = jumboplen; @@ -932,21 +923,20 @@ ip6_process_hopopts(m, opthead, hbhlen, ip6stat.ip6s_toosmall++; goto bad; } - if ((optlen = ip6_unknown_opt(opt, m, - sizeof(struct ip6_hdr) + - sizeof(struct ip6_hbh) + - opt - opthead)) == -1) - return(-1); + optlen = ip6_unknown_opt(opt, m, + erroff + opt - opthead); + if (optlen == -1) + return (-1); optlen += 2; break; } } - return(0); + return (0); bad: m_freem(m); - return(-1); + return (-1); } /* @@ -965,14 +955,14 @@ ip6_unknown_opt(optp, m, off) switch (IP6OPT_TYPE(*optp)) { case IP6OPT_TYPE_SKIP: /* ignore the option */ - return((int)*(optp + 1)); + return ((int)*(optp + 1)); case IP6OPT_TYPE_DISCARD: /* silently discard */ m_freem(m); - return(-1); + return (-1); case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */ ip6stat.ip6s_badoptions++; icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off); - return(-1); + return (-1); case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */ ip6stat.ip6s_badoptions++; ip6 = mtod(m, struct ip6_hdr *); @@ -982,11 +972,11 @@ ip6_unknown_opt(optp, m, off) else icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off); - return(-1); + return (-1); } m_freem(m); /* XXX: NOTREACHED */ - return(-1); + return (-1); } /* @@ -1020,15 +1010,14 @@ ip6_savecontrol(in6p, mp, ip6, m) microtime(&tv); *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), - SCM_TIMESTAMP, SOL_SOCKET); + SCM_TIMESTAMP, SOL_SOCKET); if (*mp) mp = &(*mp)->m_next; } #endif if (in6p->in6p_flags & IN6P_RECVDSTADDR) { *mp = sbcreatecontrol((caddr_t) &ip6->ip6_dst, - sizeof(struct in6_addr), IPV6_RECVDSTADDR, - IPPROTO_IPV6); + sizeof(struct in6_addr), IPV6_RECVDSTADDR, IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; } @@ -1052,15 +1041,14 @@ ip6_savecontrol(in6p, mp, ip6, m) ? m->m_pkthdr.rcvif->if_index : 0; *mp = sbcreatecontrol((caddr_t) &pi6, - sizeof(struct in6_pktinfo), IPV6_PKTINFO, - IPPROTO_IPV6); + sizeof(struct in6_pktinfo), IPV6_PKTINFO, IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; } if (in6p->in6p_flags & IN6P_HOPLIMIT) { int hlim = ip6->ip6_hlim & 0xff; - *mp = sbcreatecontrol((caddr_t) &hlim, - sizeof(int), IPV6_HOPLIMIT, IPPROTO_IPV6); + *mp = sbcreatecontrol((caddr_t) &hlim, sizeof(int), + IPV6_HOPLIMIT, IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; } @@ -1084,25 +1072,21 @@ ip6_savecontrol(in6p, mp, ip6, m) if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { struct ip6_hbh *hbh; int hbhlen; + struct mbuf *ext; -#ifndef PULLDOWN_TEST - hbh = (struct ip6_hbh *)(ip6 + 1); - hbhlen = (hbh->ip6h_len + 1) << 3; -#else - IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, - sizeof(struct ip6_hdr), sizeof(struct ip6_hbh)); - if (hbh == NULL) { + ext = ip6_pullexthdr(m, sizeof(struct ip6_hdr), + ip6->ip6_nxt); + if (ext == NULL) { ip6stat.ip6s_tooshort++; return; } + hbh = mtod(ext, struct ip6_hbh *); hbhlen = (hbh->ip6h_len + 1) << 3; - IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, - sizeof(struct ip6_hdr), hbhlen); - if (hbh == NULL) { + if (hbhlen != ext->m_len) { + m_freem(ext); ip6stat.ip6s_tooshort++; return; } -#endif /* * XXX: We copy whole the header even if a jumbo @@ -1111,16 +1095,17 @@ ip6_savecontrol(in6p, mp, ip6, m) * But it's too painful operation... */ *mp = sbcreatecontrol((caddr_t)hbh, hbhlen, - IPV6_HOPOPTS, IPPROTO_IPV6); + IPV6_HOPOPTS, IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; + m_freem(ext); } } /* IPV6_DSTOPTS and IPV6_RTHDR socket options */ if (in6p->in6p_flags & (IN6P_DSTOPTS | IN6P_RTHDR)) { struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); - int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr);; + int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr); /* * Search for destination options headers or routing @@ -1130,35 +1115,43 @@ ip6_savecontrol(in6p, mp, ip6, m) * the chain of ancillary data. */ while (1) { /* is explicit loop prevention necessary? */ - struct ip6_ext *ip6e; + struct ip6_ext *ip6e = NULL; int elen; + struct mbuf *ext = NULL; -#ifndef PULLDOWN_TEST - ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + off); - if (nxt == IPPROTO_AH) - elen = (ip6e->ip6e_len + 2) << 2; - else - elen = (ip6e->ip6e_len + 1) << 3; -#else - IP6_EXTHDR_GET(ip6e, struct ip6_ext *, m, off, - sizeof(struct ip6_ext)); - if (ip6e == NULL) { + /* + * if it is not an extension header, don't try to + * pull it from the chain. + */ + switch (nxt) { + case IPPROTO_DSTOPTS: + case IPPROTO_ROUTING: + case IPPROTO_HOPOPTS: + case IPPROTO_AH: /* is it possible? */ + break; + default: + goto loopend; + } + + ext = ip6_pullexthdr(m, off, nxt); + if (ext == NULL) { ip6stat.ip6s_tooshort++; return; } + ip6e = mtod(ext, struct ip6_ext *); if (nxt == IPPROTO_AH) elen = (ip6e->ip6e_len + 2) << 2; else elen = (ip6e->ip6e_len + 1) << 3; - IP6_EXTHDR_GET(ip6e, struct ip6_ext *, m, off, elen); - if (ip6e == NULL) { + if (elen != ext->m_len) { + m_freem(ext); ip6stat.ip6s_tooshort++; return; } -#endif + KASSERT(IP6_HDR_ALIGNED_P(ip6e)); switch (nxt) { - case IPPROTO_DSTOPTS: + case IPPROTO_DSTOPTS: if (!in6p->in6p_flags & IN6P_DSTOPTS) break; @@ -1171,8 +1164,7 @@ ip6_savecontrol(in6p, mp, ip6, m) break; *mp = sbcreatecontrol((caddr_t)ip6e, elen, - IPV6_DSTOPTS, - IPPROTO_IPV6); + IPV6_DSTOPTS, IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; break; @@ -1182,42 +1174,91 @@ ip6_savecontrol(in6p, mp, ip6, m) break; *mp = sbcreatecontrol((caddr_t)ip6e, elen, - IPV6_RTHDR, - IPPROTO_IPV6); + IPV6_RTHDR, IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; break; - case IPPROTO_UDP: - case IPPROTO_TCP: - case IPPROTO_ICMPV6: + case IPPROTO_HOPOPTS: + case IPPROTO_AH: /* is it possible? */ + break; + default: /* - * stop search if we encounter an upper - * layer protocol headers. + * other cases have been filtered in the above. + * none will visit this case. here we supply + * the code just in case (nxt overwritten or + * other cases). */ + m_freem(ext); goto loopend; - case IPPROTO_HOPOPTS: - case IPPROTO_AH: /* is it possible? */ - break; } /* proceed with the next header. */ off += elen; nxt = ip6e->ip6e_nxt; + ip6e = NULL; + m_freem(ext); + ext = NULL; } loopend: - ; + ; + } +} + +/* + * pull single extension header from mbuf chain. returns single mbuf that + * contains the result, or NULL on error. + */ +static struct mbuf * +ip6_pullexthdr(m, off, nxt) + struct mbuf *m; + size_t off; + int nxt; +{ + struct ip6_ext ip6e; + size_t elen; + struct mbuf *n; + +#ifdef DIAGNOSTIC + switch (nxt) { + case IPPROTO_DSTOPTS: + case IPPROTO_ROUTING: + case IPPROTO_HOPOPTS: + case IPPROTO_AH: /* is it possible? */ + break; + default: + printf("ip6_pullexthdr: invalid nxt=%d\n", nxt); } - if ((in6p->in6p_flags & IN6P_HOPOPTS) && privileged) { - /* to be done */ +#endif + + m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); + if (nxt == IPPROTO_AH) + elen = (ip6e.ip6e_len + 2) << 2; + else + elen = (ip6e.ip6e_len + 1) << 3; + + MGET(n, M_DONTWAIT, MT_DATA); + if (n && elen >= MLEN) { + MCLGET(n, M_DONTWAIT); + if ((n->m_flags & M_EXT) == 0) { + m_free(n); + n = NULL; + } } - if ((in6p->in6p_flags & IN6P_DSTOPTS) && privileged) { - /* to be done */ + if (!n) + return NULL; + + n->m_len = 0; + if (elen >= M_TRAILINGSPACE(n)) { + m_free(n); + return NULL; } - /* IN6P_RTHDR - to be done */ + m_copydata(m, off, elen, mtod(n, caddr_t)); + n->m_len = elen; + return n; } /* @@ -1232,7 +1273,7 @@ ip6_savecontrol(in6p, mp, ip6, m) * carefully. Moreover, it will not be used in the near future when * we develop `neater' mechanism to process extension headers. */ -char * +u_int8_t * ip6_get_prevhdr(m, off) struct mbuf *m; int off; @@ -1240,7 +1281,7 @@ ip6_get_prevhdr(m, off) struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); if (off == sizeof(struct ip6_hdr)) - return(&ip6->ip6_nxt); + return (&ip6->ip6_nxt); else { int len, nxt; struct ip6_ext *ip6e = NULL; @@ -1264,7 +1305,7 @@ ip6_get_prevhdr(m, off) nxt = ip6e->ip6e_nxt; } if (ip6e) - return(&ip6e->ip6e_nxt); + return (&ip6e->ip6e_nxt); else return NULL; } @@ -1308,7 +1349,7 @@ ip6_nexthdr(m, off, proto, nxtp) if (m->m_pkthdr.len < off + sizeof(fh)) return -1; m_copydata(m, off, sizeof(fh), (caddr_t)&fh); - if ((ntohs(fh.ip6f_offlg) & IP6F_OFF_MASK) != 0) + if ((fh.ip6f_offlg & IP6F_OFF_MASK) != 0) return -1; if (nxtp) *nxtp = fh.ip6f_nxt; @@ -1348,8 +1389,6 @@ ip6_nexthdr(m, off, proto, nxtp) default: return -1; } - - return -1; } /* @@ -1407,8 +1446,8 @@ ip6_sysctl(name, namelen, oldp, oldlenp, { int old, error; - /* All sysctl names at this level are terminal. */ - if (namelen != 1) + /* All sysctl names (except ifq.*) at this level are terminal. */ + if ((namelen != 1) && !(namelen == 2 && name[0] == IPCTL_IFQ)) return ENOTDIR; switch (name[0]) { @@ -1443,9 +1482,11 @@ ip6_sysctl(name, namelen, oldp, oldlenp, case IPV6CTL_DEFMCASTHLIM: return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_defmcasthlim); +#if NGIF > 0 case IPV6CTL_GIF_HLIM: return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_gif_hlim); +#endif case IPV6CTL_KAME_VERSION: return sysctl_rdstring(oldp, oldlenp, newp, __KAME_VERSION); case IPV6CTL_USE_DEPRECATED: @@ -1511,6 +1552,11 @@ ip6_sysctl(name, namelen, oldp, oldlenp, } return (error); #endif + case IPV6CTL_MAXFRAGS: + return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_maxfrags); + case IPV6CTL_IFQ: + return sysctl_ifq(name + 1, namelen - 1, oldp, oldlenp, + newp, newlen, &ip6intrq); default: return EOPNOTSUPP; }