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.37.2.7 retrieving revision 1.61 diff -u -p -r1.37.2.7 -r1.61 --- src/sys/netinet6/ip6_input.c 2001/11/14 19:18:09 1.37.2.7 +++ src/sys/netinet6/ip6_input.c 2003/05/14 06:47:41 1.61 @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_input.c,v 1.37.2.7 2001/11/14 19:18:09 nathanw Exp $ */ +/* $NetBSD: ip6_input.c,v 1.61 2003/05/14 06:47:41 itojun Exp $ */ /* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */ /* @@ -66,7 +66,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.37.2.7 2001/11/14 19:18:09 nathanw Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.61 2003/05/14 06:47:41 itojun Exp $"); #include "opt_inet.h" #include "opt_ipsec.h" @@ -84,7 +84,6 @@ __KERNEL_RCSID(0, "$NetBSD: ip6_input.c, #include #include #include -#include #include #include @@ -110,7 +109,6 @@ __KERNEL_RCSID(0, "$NetBSD: ip6_input.c, #include #include #include -#include #ifdef IPSEC #include @@ -124,6 +122,10 @@ __KERNEL_RCSID(0, "$NetBSD: ip6_input.c, #include "gif.h" #include "bpfilter.h" +#if NGIF > 0 +#include +#endif + #include extern struct domain inet6domain; @@ -157,7 +159,6 @@ ip6_init() { struct ip6protosw *pr; int i; - struct timeval tv; pr = (struct ip6protosw *)pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); if (pr == 0) @@ -172,12 +173,7 @@ 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_flow_seq = arc4random(); ip6_init2((void *)0); @@ -196,18 +192,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); } /* @@ -247,10 +235,8 @@ ip6_input(m) * should the inner packet be considered authentic? * see comment in ah4_input(). */ - if (m) { - m->m_flags &= ~M_AUTHIPHDR; - m->m_flags &= ~M_AUTHIPDGM; - } + m->m_flags &= ~M_AUTHIPHDR; + m->m_flags &= ~M_AUTHIPDGM; #endif /* @@ -278,15 +264,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; @@ -342,6 +337,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; @@ -356,7 +354,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)) { @@ -465,7 +463,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++; @@ -502,6 +500,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 @@ -509,7 +508,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 = @@ -537,7 +536,7 @@ ip6_input(m) } /* - * FAITH(Firewall Aided Internet Translator) + * FAITH (Firewall Aided Internet Translator) */ #if defined(NFAITH) && 0 < NFAITH if (ip6_keepfaith) { @@ -606,7 +605,7 @@ ip6_input(m) ip6 = mtod(m, struct ip6_hdr *); /* - * if the payload length field is 0 and the next header field + * if the payload length field is 0 and the next header field * indicates Hop-by-Hop Options header, then a Jumbo Payload * option MUST be included. */ @@ -614,7 +613,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); @@ -624,17 +623,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; /* @@ -689,7 +684,7 @@ ip6_input(m) } else if (!ours) { ip6_forward(m, 0); return; - } + } ip6 = mtod(m, struct ip6_hdr *); @@ -752,7 +747,7 @@ ip6_input(m) goto bad; } #endif - + nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); } return; @@ -777,14 +772,6 @@ ip6_hopopts_input(plenp, rtalertp, mp, o 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) { @@ -798,18 +785,18 @@ 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); } /* @@ -817,6 +804,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) @@ -831,6 +822,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) { @@ -851,9 +843,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); @@ -866,10 +860,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; @@ -881,11 +876,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); } /* @@ -907,11 +900,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 @@ -921,11 +912,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; @@ -935,21 +924,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); } /* @@ -968,14 +956,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 *); @@ -985,11 +973,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); } /* @@ -1010,7 +998,7 @@ ip6_savecontrol(in6p, mp, ip6, m) struct ip6_hdr *ip6; struct mbuf *m; { - struct proc *p = (curproc ? curproc->l_proc : 0); /* XXX */ + struct proc *p = curproc; /* XXX */ int privileged; privileged = 0; @@ -1088,10 +1076,6 @@ ip6_savecontrol(in6p, mp, ip6, m) struct ip6_hbh *hbh; int hbhlen; -#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) { @@ -1105,7 +1089,6 @@ ip6_savecontrol(in6p, mp, ip6, m) ip6stat.ip6s_tooshort++; return; } -#endif /* * XXX: We copy whole the header even if a jumbo @@ -1123,7 +1106,7 @@ ip6_savecontrol(in6p, mp, ip6, m) /* 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 @@ -1136,13 +1119,6 @@ ip6_savecontrol(in6p, mp, ip6, m) struct ip6_ext *ip6e; int elen; -#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) { @@ -1158,7 +1134,7 @@ ip6_savecontrol(in6p, mp, ip6, m) ip6stat.ip6s_tooshort++; return; } -#endif + KASSERT(IP6_HDR_ALIGNED_P(ip6e)); switch (nxt) { case IPPROTO_DSTOPTS: @@ -1235,7 +1211,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; @@ -1243,7 +1219,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; @@ -1267,7 +1243,7 @@ ip6_get_prevhdr(m, off) nxt = ip6e->ip6e_nxt; } if (ip6e) - return(&ip6e->ip6e_nxt); + return (&ip6e->ip6e_nxt); else return NULL; } @@ -1351,8 +1327,6 @@ ip6_nexthdr(m, off, proto, nxtp) default: return -1; } - - return -1; } /* @@ -1446,9 +1420,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: @@ -1514,6 +1490,8 @@ ip6_sysctl(name, namelen, oldp, oldlenp, } return (error); #endif + case IPV6CTL_MAXFRAGS: + return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_maxfrags); default: return EOPNOTSUPP; }