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.2.2.3 retrieving revision 1.16 diff -u -p -r1.2.2.3 -r1.16 --- src/sys/netinet6/ip6_input.c 1999/08/02 22:36:05 1.2.2.3 +++ src/sys/netinet6/ip6_input.c 2000/02/20 00:56:43 1.16 @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_input.c,v 1.2.2.3 1999/08/02 22:36:05 thorpej Exp $ */ +/* $NetBSD: ip6_input.c,v 1.16 2000/02/20 00:56:43 darrenr Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -64,15 +64,9 @@ * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 */ -#ifdef __FreeBSD__ -#include "opt_ip6fw.h" -#endif -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) #include "opt_inet.h" -#ifdef __NetBSD__ /*XXX*/ #include "opt_ipsec.h" -#endif -#endif +#include "opt_pfil_hooks.h" #include #include @@ -86,34 +80,35 @@ #include #include #include -#ifdef __NetBSD__ #include -#endif #include #include #include #include #include +#ifdef PFIL_HOOKS +#include +#endif #include -#include #include -#include -#if !defined(__FreeBSD__) || __FreeBSD__ < 3 -#include -#else -#include -#endif -#include -#include -#include -#include - #ifdef INET #include #include #endif /*INET*/ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef IPV6FIREWALL +#include +#endif #include @@ -124,22 +119,24 @@ #include "gif.h" #include "bpfilter.h" +#include + extern struct domain inet6domain; -extern struct ip6protosw inet6sw[]; -#ifdef __bsdi__ -extern struct ifnet loif; -#endif u_char ip6_protox[IPPROTO_MAX]; static int ip6qmaxlen = IFQ_MAXLEN; struct in6_ifaddr *in6_ifaddr; struct ifqueue ip6intrq; -#ifdef __NetBSD__ extern struct ifnet loif[NLOOP]; int ip6_forward_srcrt; /* XXX */ int ip6_sourcecheck; /* XXX */ int ip6_sourcecheck_interval; /* XXX */ + +#ifdef IPV6FIREWALL +/* firewall hooks */ +ip6_fw_chk_t *ip6_fw_chk_ptr; +ip6_fw_ctl_t *ip6_fw_ctl_ptr; #endif struct ip6stat ip6stat; @@ -148,6 +145,13 @@ static void ip6_init2 __P((void *)); static int ip6_hopopts_input __P((u_int32_t *, u_int32_t *, struct mbuf **, int *)); +#ifdef PTR +extern int ip6_protocol_tr; + +int ptr_in6 __P((struct mbuf *, struct mbuf **)); +extern void ip_forward __P((struct mbuf *, int)); +#endif + /* * IP6 initialization: fill in IP6 protocol switch table. * All protocols not implemented in kernel go to raw IP6 protocol handler. @@ -172,14 +176,15 @@ ip6_init() ip6intrq.ifq_maxlen = ip6qmaxlen; nd6_init(); frag6_init(); +#ifdef IPV6FIREWALL + ip6_fw_init(); +#endif /* * 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; - in6_iflladdr = malloc(i, M_IFADDR, M_WAITOK); - bzero(in6_iflladdr, i); ip6_init2((void *)0); } @@ -188,28 +193,23 @@ static void ip6_init2(dummy) void *dummy; { - int i; + int ret; + + /* get EUI64 from somewhere */ + ret = in6_ifattach_getifid(NULL); /* * to route local address of p2p link to loopback, * assign loopback address first. */ - for (i = 0; i < NLOOP; i++) - in6_ifattach(&loif[i], IN6_IFT_LOOP, NULL, 0); - - /* get EUI64 from somewhere, attach pseudo interfaces */ - if (in6_ifattach_getifid(NULL) == 0) - in6_ifattach_p2p(); + in6_ifattach(&loif[0], IN6_IFT_LOOP, NULL, 0); /* nd6_timer_init */ timeout(nd6_timer, (caddr_t)0, hz); + /* router renumbering prefix list maintenance */ + timeout(in6_rr_timer, (caddr_t)0, hz); } -#ifdef __FreeBSD__ -/* cheat */ -SYSINIT(netinet6init2, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, ip6_init2, NULL); -#endif - /* * IP6 input interrupt handling. Just pass the packet to ip6_input. */ @@ -229,21 +229,23 @@ ip6intr() } } -#ifdef __FreeBSD__ -NETISR_SET(NETISR_IPV6, ip6intr); -#endif - extern struct route_in6 ip6_forward_rt; void ip6_input(m) struct mbuf *m; { - register struct ip6_hdr *ip6; + struct ip6_hdr *ip6; int off = sizeof(struct ip6_hdr), nest; u_int32_t plen; u_int32_t rtalert = ~0; int nxt, ours = 0; + struct ifnet *deliverifp = NULL; +#ifdef PFIL_HOOKS + struct packet_filter_hook *pfh; + struct mbuf *m0; + int rv; +#endif /* PFIL_HOOKS */ #ifdef IPSEC /* @@ -255,6 +257,7 @@ ip6_input(m) m->m_flags &= ~M_AUTHIPDGM; } #endif + /* * mbuf statistics by kazu */ @@ -265,8 +268,9 @@ ip6_input(m) ip6stat.ip6s_mext1++; } else { if (m->m_next) { - if (m->m_flags & M_LOOP) + if (m->m_flags & M_LOOP) { ip6stat.ip6s_m2m[loif[0].if_index]++; /*XXX*/ + } else if (m->m_pkthdr.rcvif->if_index <= 31) ip6stat.ip6s_m2m[m->m_pkthdr.rcvif->if_index]++; else @@ -275,40 +279,116 @@ ip6_input(m) ip6stat.ip6s_m1++; } - IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), /*nothing*/); - + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive); ip6stat.ip6s_total++; - if (m->m_len < sizeof(struct ip6_hdr) && - (m = m_pullup(m, sizeof(struct ip6_hdr))) == 0) { - ip6stat.ip6s_toosmall++; - return; +#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) { + ip6stat.ip6s_toosmall++; + in6_ifstat_inc(inifp, ifs6_in_hdrerr); + return; + } } ip6 = mtod(m, struct ip6_hdr *); if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { ip6stat.ip6s_badvers++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); goto bad; } +#ifdef PFIL_HOOKS + /* + * Run through list of hooks for input packets. If there are any + * filters which require that additional packets in the flow are + * not fast-forwarded, they must clear the M_CANFASTFWD flag. + * Note that filters must _never_ set this flag, as another filter + * in the list may have previously cleared it. + */ + m0 = m; + pfh = pfil_hook_get(PFIL_IN, &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh); + for (; pfh; pfh = pfh->pfil_link.tqe_next) + if (pfh->pfil_func) { + rv = pfh->pfil_func(ip6, sizeof(*ip6), + m->m_pkthdr.rcvif, 0, &m0); + if (rv) + return; + m = m0; + if (m == NULL) + return; + ip6 = mtod(m, struct ip6_hdr *); + } +#endif /* PFIL_HOOKS */ + + ip6stat.ip6s_nxthist[ip6->ip6_nxt]++; +#ifdef IPV6FIREWALL + /* + * Check with the firewall... + */ + if (ip6_fw_chk_ptr) { + u_short port = 0; + /* If ipfw says divert, we have to just drop packet */ + /* use port as a dummy argument */ + if ((*ip6_fw_chk_ptr)(&ip6, NULL, &port, &m)) { + m_freem(m); + m = NULL; + } + if (!m) + return; + } +#endif + /* * Scope check */ if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src) || IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) { ip6stat.ip6s_badscope++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); + goto bad; + } + /* + * The following check is not documented in the spec. Malicious party + * may be able to use IPv4 mapped addr to confuse tcp/udp stack and + * bypass security checks (act as if it was from 127.0.0.1 by using + * IPv6 src ::ffff:127.0.0.1). Be cautious. + */ + if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || + IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { + ip6stat.ip6s_badscope++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); goto bad; } +#if 1 + /* + * We don't support it, so it is strange to get this. + */ + if (IN6_IS_ADDR_V4COMPAT(&ip6->ip6_src) || + IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) { + ip6stat.ip6s_badscope++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); + goto bad; + } +#endif if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) || IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) { if (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) { ours = 1; + deliverifp = m->m_pkthdr.rcvif; goto hbhcheck; } else { ip6stat.ip6s_badscope++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); goto bad; } } @@ -316,6 +396,7 @@ ip6_input(m) if (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) { if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) { ours = 1; + deliverifp = m->m_pkthdr.rcvif; goto hbhcheck; } } else { @@ -327,11 +408,39 @@ ip6_input(m) = htons(m->m_pkthdr.rcvif->if_index); } +#ifdef PTR + /* + * + */ + if (ip6_protocol_tr) + { + struct mbuf *m1 = NULL; + + switch (ptr_in6(m, &m1)) + { + case IPPROTO_IP: goto mcastcheck; + case IPPROTO_IPV4: ip_forward(m1, 0); break; + case IPPROTO_IPV6: ip6_forward(m1, 0); break; + case IPPROTO_MAX: /* discard this packet */ + default: + } + + if (m != m1) + m_freem(m); + + return; + } + + mcastcheck: +#endif + /* * Multicast check */ if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { struct in6_multi *in6m = 0; + + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mcast); /* * See if we belong to the destination multicast group on the * arrival interface. @@ -342,8 +451,10 @@ ip6_input(m) else if (!ip6_mrouter) { ip6stat.ip6s_notmember++; ip6stat.ip6s_cantforward++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); goto bad; } + deliverifp = m->m_pkthdr.rcvif; goto hbhcheck; } @@ -362,12 +473,7 @@ ip6_input(m) ip6_forward_rt.ro_dst.sin6_family = AF_INET6; ip6_forward_rt.ro_dst.sin6_addr = ip6->ip6_dst; -#if defined(__bsdi__) || defined(__NetBSD__) rtalloc((struct route *)&ip6_forward_rt); -#endif -#ifdef __FreeBSD__ - rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING); -#endif } #define rt6_key(r) ((struct sockaddr_in6 *)((r)->rt_nodes->rn_key)) @@ -393,12 +499,7 @@ ip6_input(m) IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &rt6_key(ip6_forward_rt.ro_rt)->sin6_addr) && #endif -#ifdef __bsdi__ - ip6_foward.rt.ro_rt->rt_ifp == &loif -#else - ip6_forward_rt.ro_rt->rt_ifp == &loif[0] -#endif - ) { + ip6_forward_rt.ro_rt->rt_ifp->if_type == IFT_LOOP) { struct in6_ifaddr *ia6 = (struct in6_ifaddr *)ip6_forward_rt.ro_rt->rt_ifa; /* packet to tentative address must not be received */ @@ -407,6 +508,7 @@ ip6_input(m) if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) { /* this interface is ready */ ours = 1; + deliverifp = ia6->ia_ifp; /* correct? */ goto hbhcheck; } else { /* this interface is not ready, fall through */ @@ -422,9 +524,34 @@ ip6_input(m) && ip6_forward_rt.ro_rt->rt_ifp->if_type == IFT_FAITH) { /* XXX do we need more sanity checks? */ ours = 1; + deliverifp = ip6_forward_rt.ro_rt->rt_ifp; /*faith*/ + goto hbhcheck; + } + } +#endif + +#if 0 + { + /* + * Last resort: check in6_ifaddr for incoming interface. + * The code is here until I update the "goto ours hack" code above + * working right. + */ + struct ifaddr *ifa; + for (ifa = m->m_pkthdr.rcvif->if_addrlist.tqh_first; + ifa; + ifa = ifa->ifa_list.tqe_next) { + if (ifa->ifa_addr == NULL) + continue; /* just for safety */ + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ip6->ip6_dst)) { + ours = 1; + deliverifp = ifa->ifa_ifp; goto hbhcheck; } } + } #endif /* @@ -433,6 +560,7 @@ ip6_input(m) */ if (!ip6_forwarding) { ip6stat.ip6s_cantforward++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); goto bad; } @@ -444,11 +572,28 @@ ip6_input(m) */ plen = (u_int32_t)ntohs(ip6->ip6_plen); if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { - if (ip6_hopopts_input(&plen, &rtalert, &m, &off)) + struct ip6_hbh *hbh; + + if (ip6_hopopts_input(&plen, &rtalert, &m, &off)) { +#if 0 /*touches NULL pointer*/ + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); +#endif return; /* m have already been freed */ + } /* adjust pointer */ ip6 = mtod(m, struct ip6_hdr *); - nxt = ((struct ip6_hbh *)(ip6 + 1))->ip6h_nxt; +#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 + nxt = hbh->ip6h_nxt; /* * accept the packet if a router alert option is included @@ -467,6 +612,7 @@ ip6_input(m) */ if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) { ip6stat.ip6s_tooshort++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); goto bad; } if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) { @@ -507,13 +653,34 @@ ip6_input(m) /* * Tell launch routine the next header */ +#ifdef IFA_STATS + if (IFA_STATS && deliverifp != NULL) { + struct in6_ifaddr *ia6; + ip6 = mtod(m, struct ip6_hdr *); + ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst); + if (ia6) + ia6->ia_ifa.ifa_data.ifad_inbytes += m->m_pkthdr.len; + } +#endif ip6stat.ip6s_delivered++; + in6_ifstat_inc(deliverifp, ifs6_in_deliver); nest = 0; while (nxt != IPPROTO_DONE) { if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) { ip6stat.ip6s_toomanyhdr++; goto bad; } + + /* + * protection against faulty packet - there should be + * more sanity checks in header chain processing. + */ + if (m->m_pkthdr.len < off) { + ip6stat.ip6s_tooshort++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); + goto bad; + } + nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); } return; @@ -538,12 +705,28 @@ 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) { + ip6stat.ip6s_tooshort++; + return -1; + } + hbhlen = (hbh->ip6h_len + 1) << 3; + IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), + hbhlen); + if (hbh == NULL) { + ip6stat.ip6s_tooshort++; + return -1; + } +#endif off += hbhlen; hbhlen -= sizeof(struct ip6_hbh); opt = (u_int8_t *)hbh + sizeof(struct ip6_hbh); @@ -589,6 +772,7 @@ ip6_process_hopopts(m, opthead, hbhlen, optlen = *(opt + 1) + 2; break; case IP6OPT_RTALERT: + /* XXX may need check for alignment */ if (hbhlen < IP6OPT_RTALERT_LEN) { ip6stat.ip6s_toosmall++; goto bad; @@ -602,6 +786,7 @@ ip6_process_hopopts(m, opthead, hbhlen, *rtalertp = ntohs(rtalert_val); break; case IP6OPT_JUMBO: + /* XXX may need check for alignment */ if (hbhlen < IP6OPT_JUMBO_LEN) { ip6stat.ip6s_toosmall++; goto bad; @@ -617,7 +802,12 @@ ip6_process_hopopts(m, opthead, hbhlen, * We can simply cast because of the alignment * requirement of the jumbo payload option. */ +#if 0 *plenp = ntohl(*(u_int32_t *)(opt + 2)); +#else + bcopy(opt + 2, plenp, sizeof(*plenp)); + *plenp = htonl(*plenp); +#endif if (*plenp <= IPV6_MAXPACKET) { /* * jumbo payload length must be larger @@ -710,7 +900,15 @@ ip6_unknown_opt(optp, m, off) } /* - * Create the "control" list for this pcb + * Create the "control" list for this pcb. + * + * The routine will be called from upper layer handlers like tcp6_input(). + * Thus the routine assumes that the caller (tcp6_input) have already + * called IP6_EXTHDR_CHECK() and all the extension headers are located in the + * very first mbuf on the mbuf chain. + * We may want to add some infinite loop prevention or sanity checks for safety. + * (This applies only when you are using KAME mbuf chain restriction, i.e. + * you are using IP6_EXTHDR_CHECK() not m_pulldown()) */ void ip6_savecontrol(in6p, mp, ip6, m) @@ -719,13 +917,14 @@ ip6_savecontrol(in6p, mp, ip6, m) register struct ip6_hdr *ip6; register struct mbuf *m; { -#ifdef __NetBSD__ struct proc *p = curproc; /* XXX */ -#endif -#ifdef __bsdi__ -# define sbcreatecontrol so_cmsg -#endif + int privileged; + + privileged = 0; + if (p && !suser(p->p_ucred, &p->p_acflag)) + privileged++; +#ifdef SO_TIMESTAMP if (in6p->in6p_socket->so_options & SO_TIMESTAMP) { struct timeval tv; @@ -735,6 +934,7 @@ ip6_savecontrol(in6p, mp, ip6, m) 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, @@ -782,8 +982,7 @@ ip6_savecontrol(in6p, mp, ip6, m) * be some hop-by-hop options which can be returned to normal user. * See RFC 2292 section 6. */ - if ((in6p->in6p_flags & IN6P_HOPOPTS) && - p && !suser(p->p_ucred, &p->p_acflag)) { + if ((in6p->in6p_flags & IN6P_HOPOPTS) && privileged) { /* * Check if a hop-by-hop options header is contatined in the * received packet, and if so, store the options as ancillary @@ -793,7 +992,27 @@ ip6_savecontrol(in6p, mp, ip6, m) */ struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { - struct ip6_hbh *hbh = (struct ip6_hbh *)(ip6 + 1); + 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) { + ip6stat.ip6s_tooshort++; + return; + } + hbhlen = (hbh->ip6h_len + 1) << 3; + IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, + sizeof(struct ip6_hdr), hbhlen); + if (hbh == NULL) { + ip6stat.ip6s_tooshort++; + return; + } +#endif /* * XXX: We copy whole the header even if a jumbo @@ -801,8 +1020,7 @@ ip6_savecontrol(in6p, mp, ip6, m) * be removed before returning in the RFC 2292. * But it's too painful operation... */ - *mp = sbcreatecontrol((caddr_t)hbh, - (hbh->ip6h_len + 1) << 3, + *mp = sbcreatecontrol((caddr_t)hbh, hbhlen, IPV6_HOPOPTS, IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; @@ -822,8 +1040,32 @@ 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 *)(mtod(m, caddr_t) + off); + 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) { + ip6stat.ip6s_tooshort++; + return; + } + 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) { + ip6stat.ip6s_tooshort++; + return; + } +#endif switch(nxt) { case IPPROTO_DSTOPTS: @@ -835,11 +1077,10 @@ ip6_savecontrol(in6p, mp, ip6, m) * the option. * See the comments on IN6_HOPOPTS. */ - if (!p || !suser(p->p_ucred, &p->p_acflag)) + if (!privileged) break; - *mp = sbcreatecontrol((caddr_t)ip6e, - (ip6e->ip6e_len + 1) << 3, + *mp = sbcreatecontrol((caddr_t)ip6e, elen, IPV6_DSTOPTS, IPPROTO_IPV6); if (*mp) @@ -850,8 +1091,7 @@ ip6_savecontrol(in6p, mp, ip6, m) if (!in6p->in6p_flags & IN6P_RTHDR) break; - *mp = sbcreatecontrol((caddr_t)ip6e, - (ip6e->ip6e_len + 1) << 3, + *mp = sbcreatecontrol((caddr_t)ip6e, elen, IPV6_RTHDR, IPPROTO_IPV6); if (*mp) @@ -874,27 +1114,19 @@ ip6_savecontrol(in6p, mp, ip6, m) } /* proceed with the next header. */ - if (nxt == IPPROTO_AH) - off += (ip6e->ip6e_len + 2) << 2; - else - off += (ip6e->ip6e_len + 1) << 3; + off += elen; nxt = ip6e->ip6e_nxt; } loopend: } - if ((in6p->in6p_flags & IN6P_HOPOPTS) - && p && !suser(p->p_ucred, &p->p_acflag)) { + if ((in6p->in6p_flags & IN6P_HOPOPTS) && privileged) { /* to be done */ } - if ((in6p->in6p_flags & IN6P_DSTOPTS) - && p && !suser(p->p_ucred, &p->p_acflag)) { + if ((in6p->in6p_flags & IN6P_DSTOPTS) && privileged) { /* to be done */ } /* IN6P_RTHDR - to be done */ -#ifdef __bsdi__ -# undef sbcreatecontrol -#endif } /* @@ -960,7 +1192,6 @@ u_char inet6ctlerrmap[PRC_NCMDS] = { ENOPROTOOPT }; -#ifdef __NetBSD__ #include #include @@ -1014,9 +1245,18 @@ ip6_sysctl(name, namelen, oldp, oldlenp, &ip6_gif_hlim); case IPV6CTL_KAME_VERSION: return sysctl_rdstring(oldp, oldlenp, newp, __KAME_VERSION); + case IPV6CTL_USE_DEPRECATED: + return sysctl_int(oldp, oldlenp, newp, newlen, + &ip6_use_deprecated); + case IPV6CTL_RR_PRUNE: + return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_rr_prune); +#ifndef INET6_BINDV6ONLY + case IPV6CTL_BINDV6ONLY: + return sysctl_int(oldp, oldlenp, newp, newlen, + &ip6_bindv6only); +#endif default: return EOPNOTSUPP; } /* NOTREACHED */ } -#endif /* __NetBSD__ */