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/netinet/ip_input.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/netinet/ip_input.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.284.4.2 retrieving revision 1.333 diff -u -p -r1.284.4.2 -r1.333 --- src/sys/netinet/ip_input.c 2011/03/05 20:55:57 1.284.4.2 +++ src/sys/netinet/ip_input.c 2016/07/04 08:10:50 1.333 @@ -1,4 +1,4 @@ -/* $NetBSD: ip_input.c,v 1.284.4.2 2011/03/05 20:55:57 rmind Exp $ */ +/* $NetBSD: ip_input.c,v 1.333 2016/07/04 08:10:50 ozaki-r Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -91,19 +91,23 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.284.4.2 2011/03/05 20:55:57 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.333 2016/07/04 08:10:50 ozaki-r Exp $"); +#ifdef _KERNEL_OPT #include "opt_inet.h" #include "opt_compat_netbsd.h" #include "opt_gateway.h" -#include "opt_pfil_hooks.h" #include "opt_ipsec.h" #include "opt_mrouting.h" #include "opt_mbuftrace.h" #include "opt_inet_csum.h" +#endif + +#include "arp.h" #include #include +#include #include #include #include @@ -119,6 +123,7 @@ __KERNEL_RCSID(0, "$NetBSD: ip_input.c,v #include #include #include +#include #include #include @@ -139,16 +144,11 @@ __KERNEL_RCSID(0, "$NetBSD: ip_input.c,v #ifdef MROUTING #include #endif +#include #ifdef IPSEC -#include -#include -#include -#endif -#ifdef FAST_IPSEC #include -#include -#endif /* FAST_IPSEC*/ +#endif #ifndef IPFORWARDING #ifdef GATEWAY @@ -216,31 +216,18 @@ int ip_do_randomid = 0; * to the loopback interface instead of the interface where the * packets for those addresses are received. */ -int ip_checkinterface = 0; - +static int ip_checkinterface __read_mostly = 0; struct rttimer_queue *ip_mtudisc_timeout_q = NULL; -int ipqmaxlen = IFQ_MAXLEN; -u_long in_ifaddrhash; /* size of hash table - 1 */ -int in_ifaddrentries; /* total number of addrs */ -struct in_ifaddrhead in_ifaddrhead; -struct in_ifaddrhashhead *in_ifaddrhashtbl; -u_long in_multihash; /* size of hash table - 1 */ -int in_multientries; /* total number of addrs */ -struct in_multihashhead *in_multihashtbl; -struct ifqueue ipintrq; +pktqueue_t * ip_pktq __read_mostly; +pfil_head_t * inet_pfil_hook __read_mostly; +ipid_state_t * ip_ids __read_mostly; +percpu_t * ipstat_percpu __read_mostly; -ipid_state_t * ip_ids; -uint16_t ip_id; +static struct route ipforward_rt __cacheline_aligned; -percpu_t *ipstat_percpu; - -#ifdef PFIL_HOOKS -struct pfil_head inet_pfil_hook; -#endif - -struct pool inmulti_pool; +uint16_t ip_id; #ifdef INET_CSUM_COUNTERS #include @@ -271,7 +258,9 @@ EVCNT_ATTACH_STATIC(ip_swcsum); * maintenance when the remote end is on a network that is not known * to us. */ -int ip_nhops = 0; + +static int ip_nhops = 0; + static struct ip_srcrt { struct in_addr dst; /* final destination */ char nop; /* one NOP to align */ @@ -279,6 +268,13 @@ static struct ip_srcrt { struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; } ip_srcrt; +static int ip_drainwanted; + +struct sockaddr_in ipaddr = { + .sin_len = sizeof(ipaddr), + .sin_family = AF_INET, +}; + static void save_rte(u_char *, struct in_addr); #ifdef MBUFTRACE @@ -286,7 +282,21 @@ struct mowner ip_rx_mowner = MOWNER_INIT struct mowner ip_tx_mowner = MOWNER_INIT("internet", "tx"); #endif -static void sysctl_net_inet_ip_setup(struct sysctllog **); +static void ipintr(void *); +static void ip_input(struct mbuf *); +static void ip_forward(struct mbuf *, int, struct ifnet *); +static bool ip_dooptions(struct mbuf *); +static struct in_ifaddr *ip_rtaddr(struct in_addr); +static void sysctl_net_inet_ip_setup(struct sysctllog **); + +static struct in_ifaddr *ip_match_our_address(struct ifnet *, struct ip *, + int *); +static struct in_ifaddr *ip_match_our_address_broadcast(struct ifnet *, + struct ip *); + +/* XXX: Not yet enabled. */ +#define SOFTNET_LOCK() KASSERT(mutex_owned(softnet_lock)) +#define SOFTNET_UNLOCK() KASSERT(mutex_owned(softnet_lock)) /* * IP initialization: fill in IP protocol switch table. @@ -296,18 +306,19 @@ void ip_init(void) { const struct protosw *pr; - int i; + in_init(); sysctl_net_inet_ip_setup(NULL); - pool_init(&inmulti_pool, sizeof(struct in_multi), 0, 0, 0, "inmltpl", - NULL, IPL_SOFTNET); - pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); - if (pr == 0) - panic("ip_init"); - for (i = 0; i < IPPROTO_MAX; i++) + KASSERT(pr != NULL); + + ip_pktq = pktq_create(IFQ_MAXLEN, ipintr, NULL); + KASSERT(ip_pktq != NULL); + + for (u_int i = 0; i < IPPROTO_MAX; i++) { ip_protox[i] = pr - inetsw; + } for (pr = inetdomain.dom_protosw; pr < inetdomain.dom_protoswNPROTOSW; pr++) if (pr->pr_domain->dom_family == PF_INET && @@ -317,29 +328,16 @@ ip_init(void) ip_reass_init(); ip_ids = ip_id_init(); - ip_id = time_second & 0xfffff; - - ipintrq.ifq_maxlen = ipqmaxlen; + ip_id = time_uptime & 0xfffff; - TAILQ_INIT(&in_ifaddrhead); - in_ifaddrhashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, true, - &in_ifaddrhash); - in_multihashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, true, - &in_multihash); ip_mtudisc_timeout_q = rt_timer_queue_create(ip_mtudisc_timeout); #ifdef GATEWAY - ipflow_init(ip_hashsize); + ipflow_init(); #endif -#ifdef PFIL_HOOKS /* Register our Packet Filter hook. */ - inet_pfil_hook.ph_type = PFIL_TYPE_AF; - inet_pfil_hook.ph_af = AF_INET; - i = pfil_head_register(&inet_pfil_hook); - if (i != 0) - printf("ip_init: WARNING: unable to register pfil hook, " - "error %d\n", i); -#endif /* PFIL_HOOKS */ + inet_pfil_hook = pfil_head_create(PFIL_TYPE_AF, (void *)AF_INET); + KASSERT(inet_pfil_hook != NULL); #ifdef MBUFTRACE MOWNER_ATTACH(&ip_tx_mowner); @@ -349,83 +347,133 @@ ip_init(void) ipstat_percpu = percpu_alloc(sizeof(uint64_t) * IP_NSTATS); } -struct sockaddr_in ipaddr = { - .sin_len = sizeof(ipaddr), - .sin_family = AF_INET, -}; -struct route ipforward_rt; +static struct in_ifaddr * +ip_match_our_address(struct ifnet *ifp, struct ip *ip, int *downmatch) +{ + struct in_ifaddr *ia = NULL; + int checkif; + + /* + * Enable a consistency check between the destination address + * and the arrival interface for a unicast packet (the RFC 1122 + * strong ES model) if IP forwarding is disabled and the packet + * is not locally generated. + * + * XXX - Checking also should be disabled if the destination + * address is ipnat'ed to a different interface. + * + * XXX - Checking is incompatible with IP aliases added + * to the loopback interface instead of the interface where + * the packets are received. + * + * XXX - We need to add a per ifaddr flag for this so that + * we get finer grain control. + */ + checkif = ip_checkinterface && (ipforwarding == 0) && + (ifp->if_flags & IFF_LOOPBACK) == 0; + + LIST_FOREACH(ia, &IN_IFADDR_HASH(ip->ip_dst.s_addr), ia_hash) { + if (in_hosteq(ia->ia_addr.sin_addr, ip->ip_dst)) { + if (ia->ia4_flags & IN_IFF_NOTREADY) + continue; + if (checkif && ia->ia_ifp != ifp) + continue; + if ((ia->ia_ifp->if_flags & IFF_UP) != 0) + break; + else + downmatch++; + } + } + + return ia; +} + +static struct in_ifaddr * +ip_match_our_address_broadcast(struct ifnet *ifp, struct ip *ip) +{ + struct in_ifaddr *ia = NULL; + struct ifaddr *ifa; + + IFADDR_FOREACH(ifa, ifp) { + if (ifa->ifa_addr->sa_family != AF_INET) + continue; + ia = ifatoia(ifa); + if (ia->ia4_flags & IN_IFF_NOTREADY) + continue; + if (in_hosteq(ip->ip_dst, ia->ia_broadaddr.sin_addr) || + in_hosteq(ip->ip_dst, ia->ia_netbroadcast) || + /* + * Look for all-0's host part (old broadcast addr), + * either for subnet or net. + */ + ip->ip_dst.s_addr == ia->ia_subnet || + ip->ip_dst.s_addr == ia->ia_net) + goto matched; + /* + * An interface with IP address zero accepts + * all packets that arrive on that interface. + */ + if (in_nullhost(ia->ia_addr.sin_addr)) + goto matched; + } + ia = NULL; + +matched: + return ia; +} /* - * IP software interrupt routine + * IP software interrupt routine. */ -void -ipintr(void) +static void +ipintr(void *arg __unused) { - int s; struct mbuf *m; - struct ifqueue lcl_intrq; - memset(&lcl_intrq, 0, sizeof(lcl_intrq)); - ipintrq.ifq_maxlen = ipqmaxlen; + KASSERT(cpu_softintr_p()); mutex_enter(softnet_lock); - KERNEL_LOCK(1, NULL); - if (!IF_IS_EMPTY(&ipintrq)) { - s = splnet(); - - /* Take existing queue onto stack */ - lcl_intrq = ipintrq; - - /* Zero out global queue, preserving maxlen and drops */ - ipintrq.ifq_head = NULL; - ipintrq.ifq_tail = NULL; - ipintrq.ifq_len = 0; - ipintrq.ifq_maxlen = lcl_intrq.ifq_maxlen; - ipintrq.ifq_drops = lcl_intrq.ifq_drops; - - splx(s); - } - KERNEL_UNLOCK_ONE(NULL); - while (!IF_IS_EMPTY(&lcl_intrq)) { - IF_DEQUEUE(&lcl_intrq, m); - if (m == NULL) - break; + while ((m = pktq_dequeue(ip_pktq)) != NULL) { ip_input(m); } mutex_exit(softnet_lock); } /* - * Ip input routine. Checksum and byte swap header. If fragmented + * IP input routine. Checksum and byte swap header. If fragmented * try to reassemble. Process options. Pass to next level. */ -void +static void ip_input(struct mbuf *m) { struct ip *ip = NULL; struct in_ifaddr *ia; - struct ifaddr *ifa; int hlen = 0, len; int downmatch; - int checkif; int srcrt = 0; -#ifdef FAST_IPSEC - struct m_tag *mtag; - struct tdb_ident *tdbi; - struct secpolicy *sp; - int error, s; -#endif /* FAST_IPSEC */ + ifnet_t *ifp; + struct psref psref; + + KASSERTMSG(cpu_softintr_p(), "ip_input: not in the software " + "interrupt handler; synchronization assumptions violated"); MCLAIM(m, &ip_rx_mowner); KASSERT((m->m_flags & M_PKTHDR) != 0); + ifp = m_get_rcvif_psref(m, &psref); + if (__predict_false(ifp == NULL)) + goto out; + /* * If no IP addresses have been set yet but the interfaces * are receiving, can't do anything with incoming packets yet. + * Note: we pre-check without locks held. */ - if (TAILQ_FIRST(&in_ifaddrhead) == 0) - goto bad; + if (!TAILQ_FIRST(&in_ifaddrhead)) { + goto out; + } IP_STATINC(IP_STAT_TOTAL); + /* * If the IP header is not aligned, slurp it up into a new * mbuf with space for link headers, in the event we forward @@ -437,28 +485,28 @@ ip_input(struct mbuf *m) (max_linkhdr + 3) & ~3)) == NULL) { /* XXXJRT new stat, please */ IP_STATINC(IP_STAT_TOOSMALL); - return; + goto out; } } else if (__predict_false(m->m_len < sizeof (struct ip))) { if ((m = m_pullup(m, sizeof (struct ip))) == NULL) { IP_STATINC(IP_STAT_TOOSMALL); - return; + goto out; } } ip = mtod(m, struct ip *); if (ip->ip_v != IPVERSION) { IP_STATINC(IP_STAT_BADVERS); - goto bad; + goto out; } hlen = ip->ip_hl << 2; if (hlen < sizeof(struct ip)) { /* minimum header length */ IP_STATINC(IP_STAT_BADHLEN); - goto bad; + goto out; } if (hlen > m->m_len) { - if ((m = m_pullup(m, hlen)) == 0) { + if ((m = m_pullup(m, hlen)) == NULL) { IP_STATINC(IP_STAT_BADHLEN); - return; + goto out; } ip = mtod(m, struct ip *); } @@ -469,24 +517,25 @@ ip_input(struct mbuf *m) */ if (IN_MULTICAST(ip->ip_src.s_addr)) { IP_STATINC(IP_STAT_BADADDR); - goto bad; + goto out; } /* 127/8 must not appear on wire - RFC1122 */ if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) { - if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { + if ((ifp->if_flags & IFF_LOOPBACK) == 0) { IP_STATINC(IP_STAT_BADADDR); - goto bad; + goto out; } } switch (m->m_pkthdr.csum_flags & - ((m->m_pkthdr.rcvif->if_csum_flags_rx & M_CSUM_IPv4) | + ((ifp->if_csum_flags_rx & M_CSUM_IPv4) | M_CSUM_IPv4_BAD)) { case M_CSUM_IPv4|M_CSUM_IPv4_BAD: INET_CSUM_COUNTER_INCR(&ip_hwcsum_bad); - goto badcsum; + IP_STATINC(IP_STAT_BADSUM); + goto out; case M_CSUM_IPv4: /* Checksum was okay. */ @@ -498,11 +547,13 @@ ip_input(struct mbuf *m) * Must compute it ourselves. Maybe skip checksum on * loopback interfaces. */ - if (__predict_true(!(m->m_pkthdr.rcvif->if_flags & - IFF_LOOPBACK) || ip_do_loopback_cksum)) { + if (__predict_true(!(ifp->if_flags & IFF_LOOPBACK) || + ip_do_loopback_cksum)) { INET_CSUM_COUNTER_INCR(&ip_swcsum); - if (in_cksum(m, hlen) != 0) - goto badcsum; + if (in_cksum(m, hlen) != 0) { + IP_STATINC(IP_STAT_BADSUM); + goto out; + } } break; } @@ -515,7 +566,7 @@ ip_input(struct mbuf *m) */ if (len < hlen) { IP_STATINC(IP_STAT_BADLEN); - goto bad; + goto out; } /* @@ -526,7 +577,7 @@ ip_input(struct mbuf *m) */ if (m->m_pkthdr.len < len) { IP_STATINC(IP_STAT_TOOSHORT); - goto bad; + goto out; } if (m->m_pkthdr.len > len) { if (m->m_len == m->m_pkthdr.len) { @@ -536,18 +587,12 @@ ip_input(struct mbuf *m) m_adj(m, len - m->m_pkthdr.len); } -#if defined(IPSEC) - /* ipflow (IP fast forwarding) is not compatible with IPsec. */ - m->m_flags &= ~M_CANFASTFWD; -#else /* * Assume that we can create a fast-forward IP flow entry * based on this packet. */ m->m_flags |= M_CANFASTFWD; -#endif -#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 @@ -555,28 +600,24 @@ ip_input(struct mbuf *m) * Note that filters must _never_ set this flag, as another filter * in the list may have previously cleared it. */ - /* - * let ipfilter look at packet on the wire, - * not the decapsulated packet. - */ -#ifdef IPSEC - if (!ipsec_getnhist(m)) -#elif defined(FAST_IPSEC) - if (!ipsec_indone(m)) +#if defined(IPSEC) + if (!ipsec_used || !ipsec_indone(m)) #else if (1) #endif { - struct in_addr odst; + struct in_addr odst = ip->ip_dst; + bool freed; - odst = ip->ip_dst; - if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif, - PFIL_IN) != 0) - return; - if (m == NULL) - return; + SOFTNET_LOCK(); + freed = pfil_run_hooks(inet_pfil_hook, &m, ifp, PFIL_IN) != 0; + SOFTNET_UNLOCK(); + if (freed || m == NULL) { + goto out; + } ip = mtod(m, struct ip *); hlen = ip->ip_hl << 2; + /* * XXX The setting of "srcrt" here is to prevent ip_forward() * from generating ICMP redirects for packets that have @@ -593,13 +634,17 @@ ip_input(struct mbuf *m) */ srcrt = (odst.s_addr != ip->ip_dst.s_addr); } -#endif /* PFIL_HOOKS */ #ifdef ALTQ /* XXX Temporary until ALTQ is changed to use a pfil hook */ - if (altq_input != NULL && (*altq_input)(m, AF_INET) == 0) { - /* packet dropped by traffic conditioner */ - return; + if (altq_input) { + SOFTNET_LOCK(); + if ((*altq_input)(m, AF_INET) == 0) { + /* Packet dropped by traffic conditioner. */ + SOFTNET_UNLOCK(); + goto out; + } + SOFTNET_UNLOCK(); } #endif @@ -611,72 +656,27 @@ ip_input(struct mbuf *m) */ ip_nhops = 0; /* for source routed packets */ if (hlen > sizeof (struct ip) && ip_dooptions(m)) - return; - - /* - * Enable a consistency check between the destination address - * and the arrival interface for a unicast packet (the RFC 1122 - * strong ES model) if IP forwarding is disabled and the packet - * is not locally generated. - * - * XXX - Checking also should be disabled if the destination - * address is ipnat'ed to a different interface. - * - * XXX - Checking is incompatible with IP aliases added - * to the loopback interface instead of the interface where - * the packets are received. - * - * XXX - We need to add a per ifaddr flag for this so that - * we get finer grain control. - */ - checkif = ip_checkinterface && (ipforwarding == 0) && - (m->m_pkthdr.rcvif != NULL) && - ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0); + goto out; /* * Check our list of addresses, to see if the packet is for us. * * Traditional 4.4BSD did not consult IFF_UP at all. * The behavior here is to treat addresses on !IFF_UP interface - * as not mine. + * or IN_IFF_NOTREADY addresses as not mine. */ downmatch = 0; - LIST_FOREACH(ia, &IN_IFADDR_HASH(ip->ip_dst.s_addr), ia_hash) { - if (in_hosteq(ia->ia_addr.sin_addr, ip->ip_dst)) { - if (checkif && ia->ia_ifp != m->m_pkthdr.rcvif) - continue; - if ((ia->ia_ifp->if_flags & IFF_UP) != 0) - break; - else - downmatch++; - } - } + ia = ip_match_our_address(ifp, ip, &downmatch); if (ia != NULL) goto ours; - if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST) { - IFADDR_FOREACH(ifa, m->m_pkthdr.rcvif) { - if (ifa->ifa_addr->sa_family != AF_INET) - continue; - ia = ifatoia(ifa); - if (in_hosteq(ip->ip_dst, ia->ia_broadaddr.sin_addr) || - in_hosteq(ip->ip_dst, ia->ia_netbroadcast) || - /* - * Look for all-0's host part (old broadcast addr), - * either for subnet or net. - */ - ip->ip_dst.s_addr == ia->ia_subnet || - ip->ip_dst.s_addr == ia->ia_net) - goto ours; - /* - * An interface with IP address zero accepts - * all packets that arrive on that interface. - */ - if (in_nullhost(ia->ia_addr.sin_addr)) - goto ours; - } + + if (ifp->if_flags & IFF_BROADCAST) { + ia = ip_match_our_address_broadcast(ifp, ip); + if (ia != NULL) + goto ours; } + if (IN_MULTICAST(ip->ip_dst.s_addr)) { - struct in_multi *inm; #ifdef MROUTING extern struct socket *ip_mrouter; @@ -693,19 +693,22 @@ ip_input(struct mbuf *m) * as expected when ip_mforward() is called from * ip_output().) */ - if (ip_mforward(m, m->m_pkthdr.rcvif) != 0) { + SOFTNET_LOCK(); + if (ip_mforward(m, ifp) != 0) { + SOFTNET_UNLOCK(); IP_STATINC(IP_STAT_CANTFORWARD); - m_freem(m); - return; + goto out; } + SOFTNET_UNLOCK(); /* * The process-level routing demon needs to receive * all multicast IGMP packets, whether or not this * host belongs to their destination groups. */ - if (ip->ip_p == IPPROTO_IGMP) + if (ip->ip_p == IPPROTO_IGMP) { goto ours; + } IP_STATINC(IP_STAT_CANTFORWARD); } #endif @@ -713,11 +716,9 @@ ip_input(struct mbuf *m) * See if we belong to the destination multicast group on the * arrival interface. */ - IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); - if (inm == NULL) { + if (!in_multi_group(ip->ip_dst, ifp, 0)) { IP_STATINC(IP_STAT_CANTFORWARD); - m_freem(m); - return; + goto out; } goto ours; } @@ -729,6 +730,7 @@ ip_input(struct mbuf *m) * Not for us; forward if possible and desirable. */ if (ipforwarding == 0) { + m_put_rcvif_psref(ifp, &psref); IP_STATINC(IP_STAT_CANTFORWARD); m_freem(m); } else { @@ -739,70 +741,32 @@ ip_input(struct mbuf *m) * forwarding loop till TTL goes to 0. */ if (downmatch) { + m_put_rcvif_psref(ifp, &psref); icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); IP_STATINC(IP_STAT_CANTFORWARD); return; } #ifdef IPSEC - if (ipsec4_in_reject(m, NULL)) { - IPSEC_STATINC(IPSEC_STAT_IN_POLVIO); - goto bad; - } -#endif -#ifdef FAST_IPSEC - mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); - s = splsoftnet(); - if (mtag != NULL) { - tdbi = (struct tdb_ident *)(mtag + 1); - sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND); - } else { - sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, - IP_FORWARDING, &error); - } - if (sp == NULL) { /* NB: can happen if error */ - splx(s); - /*XXX error stat???*/ - DPRINTF(("ip_input: no SP for forwarding\n")); /*XXX*/ - goto bad; - } - - /* - * Check security policy against packet attributes. - */ - error = ipsec_in_reject(sp, m); - KEY_FREESP(&sp); - splx(s); - if (error) { - IP_STATINC(IP_STAT_CANTFORWARD); - goto bad; - } - - /* - * Peek at the outbound SP for this packet to determine if - * it's a Fast Forward candidate. - */ - mtag = m_tag_find(m, PACKET_TAG_IPSEC_PENDING_TDB, NULL); - if (mtag != NULL) - m->m_flags &= ~M_CANFASTFWD; - else { - s = splsoftnet(); - sp = ipsec4_checkpolicy(m, IPSEC_DIR_OUTBOUND, - (IP_FORWARDING | - (ip_directedbcast ? IP_ALLOWBROADCAST : 0)), - &error, NULL); - if (sp != NULL) { - m->m_flags &= ~M_CANFASTFWD; - KEY_FREESP(&sp); + /* Perform IPsec, if any. */ + if (ipsec_used) { + SOFTNET_LOCK(); + if (ipsec4_input(m, IP_FORWARDING | + (ip_directedbcast ? IP_ALLOWBROADCAST : 0)) != 0) { + SOFTNET_UNLOCK(); + goto out; } - splx(s); + SOFTNET_UNLOCK(); } -#endif /* FAST_IPSEC */ - - ip_forward(m, srcrt); +#endif + ip_forward(m, srcrt, ifp); + m_put_rcvif_psref(ifp, &psref); } return; ours: + m_put_rcvif_psref(ifp, &psref); + ifp = NULL; + /* * If offset or IP_MF are set, must reassemble. */ @@ -812,11 +776,11 @@ ours: */ if (ip_reass_packet(&m, ip) != 0) { /* Failed; invalid fragment(s) or packet. */ - goto bad; + goto out; } if (m == NULL) { /* More fragments should come; silently return. */ - return; + goto out; } /* * Reassembly is done, we have the final packet. @@ -826,56 +790,22 @@ ours: hlen = ip->ip_hl << 2; } -#if defined(IPSEC) - /* - * enforce IPsec policy checking if we are seeing last header. - * note that we do not visit this with protocols with pcb layer - * code - like udp/tcp/raw ip. - */ - if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0 && - ipsec4_in_reject(m, NULL)) { - IPSEC_STATINC(IPSEC_STAT_IN_POLVIO); - goto bad; - } -#endif -#ifdef FAST_IPSEC +#ifdef IPSEC /* - * enforce IPsec policy checking if we are seeing last header. - * note that we do not visit this with protocols with pcb layer - * code - like udp/tcp/raw ip. - */ - if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0) { - /* - * Check if the packet has already had IPsec processing - * done. If so, then just pass it along. This tag gets - * set during AH, ESP, etc. input handling, before the - * packet is returned to the ip input queue for delivery. - */ - mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); - s = splsoftnet(); - if (mtag != NULL) { - tdbi = (struct tdb_ident *)(mtag + 1); - sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND); - } else { - sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, - IP_FORWARDING, &error); + * Enforce IPsec policy checking if we are seeing last header. + * Note that we do not visit this with protocols with PCB layer + * code - like UDP/TCP/raw IP. + */ + if (ipsec_used && + (inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0) { + SOFTNET_LOCK(); + if (ipsec4_input(m, 0) != 0) { + SOFTNET_UNLOCK(); + goto out; } - if (sp != NULL) { - /* - * Check security policy against packet attributes. - */ - error = ipsec_in_reject(sp, m); - KEY_FREESP(&sp); - } else { - /* XXX error stat??? */ - error = EINVAL; -DPRINTF(("ip_input: no SP, packet discarded\n"));/*XXX*/ - } - splx(s); - if (error) - goto bad; + SOFTNET_UNLOCK(); } -#endif /* FAST_IPSEC */ +#endif /* * Switch out to protocol's input routine. @@ -885,19 +815,18 @@ DPRINTF(("ip_input: no SP, packet discar ia->ia_ifa.ifa_data.ifad_inbytes += ntohs(ip->ip_len); #endif IP_STATINC(IP_STAT_DELIVERED); - { - int off = hlen, nh = ip->ip_p; + const int off = hlen, nh = ip->ip_p; + + SOFTNET_LOCK(); (*inetsw[ip_protox[nh]].pr_input)(m, off, nh); - return; - } -bad: - m_freem(m); + SOFTNET_UNLOCK(); return; -badcsum: - IP_STATINC(IP_STAT_BADSUM); - m_freem(m); +out: + m_put_rcvif_psref(ifp, &psref); + if (m != NULL) + m_freem(m); } /* @@ -929,13 +858,13 @@ ip_drain(void) } /* - * Do option processing on a datagram, - * possibly discarding it if bad options are encountered, - * or forwarding it if source-routed. - * Returns 1 if packet has been forwarded/freed, - * 0 if the packet should be processed further. + * ip_dooptions: perform option processing on a datagram, possibly discarding + * it if bad options are encountered, or forwarding it if source-routed. + * + * => Returns true if packet has been forwarded/freed. + * => Returns false if the packet should be processed further. */ -int +static bool ip_dooptions(struct mbuf *m) { struct ip *ip = mtod(m, struct ip *); @@ -1099,7 +1028,10 @@ ip_dooptions(struct mbuf *m) case IPOPT_TS_TSONLY: break; - case IPOPT_TS_TSANDADDR: + case IPOPT_TS_TSANDADDR: { + struct ifnet *rcvif; + int s; + if (ipt->ipt_ptr - 1 + sizeof(n_time) + sizeof(struct in_addr) > ipt->ipt_len) { code = (u_char *)&ipt->ipt_ptr - @@ -1107,14 +1039,17 @@ ip_dooptions(struct mbuf *m) goto bad; } ipaddr.sin_addr = dst; + rcvif = m_get_rcvif(m, &s); ia = ifatoia(ifaof_ifpforaddr(sintosa(&ipaddr), - m->m_pkthdr.rcvif)); + rcvif)); + m_put_rcvif(rcvif, &s); if (ia == 0) continue; bcopy(&ia->ia_addr.sin_addr, cp0, sizeof(struct in_addr)); ipt->ipt_ptr += sizeof(struct in_addr); break; + } case IPOPT_TS_PRESPEC: if (ipt->ipt_ptr - 1 + sizeof(n_time) + @@ -1145,26 +1080,37 @@ ip_dooptions(struct mbuf *m) } } if (forward) { + struct ifnet *rcvif; + struct psref psref; + if (ip_forwsrcrt == 0) { type = ICMP_UNREACH; code = ICMP_UNREACH_SRCFAIL; goto bad; } - ip_forward(m, 1); - return (1); + + rcvif = m_get_rcvif_psref(m, &psref); + if (__predict_false(rcvif == NULL)) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_HOST; + goto bad; + } + ip_forward(m, 1, rcvif); + m_put_rcvif_psref(rcvif, &psref); + return true; } - return (0); + return false; bad: icmp_error(m, type, code, 0, 0); IP_STATINC(IP_STAT_BADOPTIONS); - return (1); + return true; } /* - * Given address of next destination (final or next hop), + * ip_rtaddr: given address of next destination (final or next hop), * return internet address info of interface to be used to get there. */ -struct in_ifaddr * +static struct in_ifaddr * ip_rtaddr(struct in_addr dst) { struct rtentry *rt; @@ -1175,26 +1121,25 @@ ip_rtaddr(struct in_addr dst) sockaddr_in_init(&u.dst4, &dst, 0); - if ((rt = rtcache_lookup(&ipforward_rt, &u.dst)) == NULL) + SOFTNET_LOCK(); + rt = rtcache_lookup(&ipforward_rt, &u.dst); + SOFTNET_UNLOCK(); + if (rt == NULL) return NULL; return ifatoia(rt->rt_ifa); } /* - * Save incoming source route for use in replies, - * to be picked up later by ip_srcroute if the receiver is interested. + * save_rte: save incoming source route for use in replies, to be picked + * up later by ip_srcroute if the receiver is interested. */ -void +static void save_rte(u_char *option, struct in_addr dst) { unsigned olen; olen = option[IPOPT_OLEN]; -#ifdef DIAGNOSTIC - if (ipprintfs) - printf("save_rte: olen %d\n", olen); -#endif /* 0 */ if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) return; memcpy((void *)ip_srcrt.srcopt, (void *)option, olen); @@ -1225,20 +1170,12 @@ ip_srcroute(void) /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) + OPTSIZ; -#ifdef DIAGNOSTIC - if (ipprintfs) - printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len); -#endif /* * First save first hop for return route */ p = &ip_srcrt.route[ip_nhops - 1]; *(mtod(m, struct in_addr *)) = *p--; -#ifdef DIAGNOSTIC - if (ipprintfs) - printf(" hops %x", ntohl(mtod(m, struct in_addr *)->s_addr)); -#endif /* * Copy option fields and padding (nop) to mbuf. @@ -1255,20 +1192,12 @@ ip_srcroute(void) * reversing the path (pointers are now aligned). */ while (p >= ip_srcrt.route) { -#ifdef DIAGNOSTIC - if (ipprintfs) - printf(" %x", ntohl(q->s_addr)); -#endif *q++ = *p--; } /* * Last hop goes to final destination. */ *q = ip_srcrt.dst; -#ifdef DIAGNOSTIC - if (ipprintfs) - printf(" %x\n", ntohl(q->s_addr)); -#endif return (m); } @@ -1284,6 +1213,21 @@ const int inetctlerrmap[PRC_NCMDS] = { [PRC_PARAMPROB] = ENOPROTOOPT, }; +void +ip_fasttimo(void) +{ + if (ip_drainwanted) { + ip_drain(); + ip_drainwanted = 0; + } +} + +void +ip_drainstub(void) +{ + ip_drainwanted = 1; +} + /* * Forward a packet. If some error occurs return the sender * an icmp packet. Note we can't always generate a meaningful @@ -1298,8 +1242,8 @@ const int inetctlerrmap[PRC_NCMDS] = { * The srcrt parameter indicates whether the packet is being forwarded * via a source route. */ -void -ip_forward(struct mbuf *m, int srcrt) +static void +ip_forward(struct mbuf *m, int srcrt, struct ifnet *rcvif) { struct ip *ip = mtod(m, struct ip *); struct rtentry *rt; @@ -1310,6 +1254,10 @@ ip_forward(struct mbuf *m, int srcrt) struct sockaddr dst; struct sockaddr_in dst4; } u; + uint64_t *ips; + + KASSERTMSG(cpu_softintr_p(), "ip_forward: not in the software " + "interrupt handler; synchronization assumptions violated"); /* * We are now in the output path. @@ -1322,25 +1270,25 @@ ip_forward(struct mbuf *m, int srcrt) m->m_pkthdr.csum_flags = 0; dest = 0; -#ifdef DIAGNOSTIC - if (ipprintfs) { - printf("forward: src %s ", inet_ntoa(ip->ip_src)); - printf("dst %s ttl %x\n", inet_ntoa(ip->ip_dst), ip->ip_ttl); - } -#endif if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) { IP_STATINC(IP_STAT_CANTFORWARD); m_freem(m); return; } + + SOFTNET_LOCK(); + if (ip->ip_ttl <= IPTTLDEC) { icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest, 0); + SOFTNET_UNLOCK(); return; } sockaddr_in_init(&u.dst4, &ip->ip_dst, 0); + if ((rt = rtcache_lookup(&ipforward_rt, &u.dst)) == NULL) { icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, dest, 0); + SOFTNET_UNLOCK(); return; } @@ -1363,7 +1311,7 @@ ip_forward(struct mbuf *m, int srcrt) * Also, don't send redirect if forwarding using a default route * or a route modified by a redirect. */ - if (rt->rt_ifp == m->m_pkthdr.rcvif && + if (rt->rt_ifp == rcvif && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && !in_nullhost(satocsin(rt_getkey(rt))->sin_addr) && ipsendredirects && !srcrt) { @@ -1380,40 +1328,45 @@ ip_forward(struct mbuf *m, int srcrt) */ type = ICMP_REDIRECT; code = ICMP_REDIRECT_HOST; -#ifdef DIAGNOSTIC - if (ipprintfs) - printf("redirect (%d) to %x\n", code, - (u_int32_t)dest); -#endif } } error = ip_output(m, NULL, &ipforward_rt, (IP_FORWARDING | (ip_directedbcast ? IP_ALLOWBROADCAST : 0)), - (struct ip_moptions *)NULL, (struct socket *)NULL); + NULL, NULL); - if (error) + if (error) { IP_STATINC(IP_STAT_CANTFORWARD); - else { - uint64_t *ips = IP_STAT_GETREF(); - ips[IP_STAT_FORWARD]++; - if (type) { - ips[IP_STAT_REDIRECTSENT]++; - IP_STAT_PUTREF(); - } else { - IP_STAT_PUTREF(); - if (mcopy) { + goto error; + } + + ips = IP_STAT_GETREF(); + ips[IP_STAT_FORWARD]++; + + if (type) { + ips[IP_STAT_REDIRECTSENT]++; + IP_STAT_PUTREF(); + goto redirect; + } + + IP_STAT_PUTREF(); + if (mcopy) { #ifdef GATEWAY - if (mcopy->m_flags & M_CANFASTFWD) - ipflow_create(&ipforward_rt, mcopy); + if (mcopy->m_flags & M_CANFASTFWD) + ipflow_create(&ipforward_rt, mcopy); #endif - m_freem(mcopy); - } - return; - } + m_freem(mcopy); } - if (mcopy == NULL) + + SOFTNET_UNLOCK(); + return; + +redirect: +error: + if (mcopy == NULL) { + SOFTNET_UNLOCK(); return; + } switch (error) { @@ -1436,95 +1389,52 @@ ip_forward(struct mbuf *m, int srcrt) if ((rt = rtcache_validate(&ipforward_rt)) != NULL) destmtu = rt->rt_ifp->if_mtu; - -#if defined(IPSEC) || defined(FAST_IPSEC) - { - /* - * If the packet is routed over IPsec tunnel, tell the - * originator the tunnel MTU. - * tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz - * XXX quickhack!!! - */ - - struct secpolicy *sp; - int ipsecerror; - size_t ipsechdr; - struct route *ro; - - sp = ipsec4_getpolicybyaddr(mcopy, - IPSEC_DIR_OUTBOUND, IP_FORWARDING, - &ipsecerror); - - if (sp != NULL) { - /* count IPsec header size */ - ipsechdr = ipsec4_hdrsiz(mcopy, - IPSEC_DIR_OUTBOUND, NULL); - - /* - * find the correct route for outer IPv4 - * header, compute tunnel MTU. - */ - - if (sp->req != NULL - && sp->req->sav != NULL - && sp->req->sav->sah != NULL) { - ro = &sp->req->sav->sah->sa_route; - rt = rtcache_validate(ro); - if (rt && rt->rt_ifp) { - destmtu = - rt->rt_rmx.rmx_mtu ? - rt->rt_rmx.rmx_mtu : - rt->rt_ifp->if_mtu; - destmtu -= ipsechdr; - } - } - -#ifdef IPSEC - key_freesp(sp); -#else - KEY_FREESP(&sp); +#ifdef IPSEC + if (ipsec_used) + (void)ipsec4_forward(mcopy, &destmtu); #endif - } - } -#endif /*defined(IPSEC) || defined(FAST_IPSEC)*/ IP_STATINC(IP_STAT_CANTFRAG); break; case ENOBUFS: -#if 1 /* - * a router should not generate ICMP_SOURCEQUENCH as - * required in RFC1812 Requirements for IP Version 4 Routers. - * source quench could be a big problem under DoS attacks, - * or if the underlying interface is rate-limited. + * Do not generate ICMP_SOURCEQUENCH as required in RFC 1812, + * Requirements for IP Version 4 Routers. Source quench can + * big problem under DoS attacks or if the underlying + * interface is rate-limited. */ if (mcopy) m_freem(mcopy); + SOFTNET_UNLOCK(); return; -#else - type = ICMP_SOURCEQUENCH; - code = 0; - break; -#endif } icmp_error(mcopy, type, code, dest, destmtu); + SOFTNET_UNLOCK(); } void ip_savecontrol(struct inpcb *inp, struct mbuf **mp, struct ip *ip, struct mbuf *m) { + struct socket *so = inp->inp_socket; + ifnet_t *ifp; + int inpflags = inp->inp_flags; + struct psref psref; + + ifp = m_get_rcvif_psref(m, &psref); + if (__predict_false(ifp == NULL)) + return; /* XXX should report error? */ - if (inp->inp_socket->so_options & SO_TIMESTAMP + if (so->so_options & SO_TIMESTAMP #ifdef SO_OTIMESTAMP - || inp->inp_socket->so_options & SO_OTIMESTAMP + || so->so_options & SO_OTIMESTAMP #endif ) { struct timeval tv; microtime(&tv); #ifdef SO_OTIMESTAMP - if (inp->inp_socket->so_options & SO_OTIMESTAMP) { + if (so->so_options & SO_OTIMESTAMP) { struct timeval50 tv50; timeval_to_timeval50(&tv, &tv50); *mp = sbcreatecontrol((void *) &tv50, sizeof(tv50), @@ -1536,52 +1446,46 @@ ip_savecontrol(struct inpcb *inp, struct if (*mp) mp = &(*mp)->m_next; } - if (inp->inp_flags & INP_RECVDSTADDR) { + if (inpflags & INP_RECVDSTADDR) { *mp = sbcreatecontrol((void *) &ip->ip_dst, sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP); if (*mp) mp = &(*mp)->m_next; } -#ifdef notyet - /* - * XXX - * Moving these out of udp_input() made them even more broken - * than they already were. - * - fenner@parc.xerox.com - */ - /* options were tossed already */ - if (inp->inp_flags & INP_RECVOPTS) { - *mp = sbcreatecontrol((void *) opts_deleted_above, - sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP); + if (inpflags & INP_RECVPKTINFO) { + struct in_pktinfo ipi; + ipi.ipi_addr = ip->ip_src; + ipi.ipi_ifindex = ifp->if_index; + *mp = sbcreatecontrol((void *) &ipi, + sizeof(ipi), IP_RECVPKTINFO, IPPROTO_IP); if (*mp) mp = &(*mp)->m_next; } - /* ip_srcroute doesn't do what we want here, need to fix */ - if (inp->inp_flags & INP_RECVRETOPTS) { - *mp = sbcreatecontrol((void *) ip_srcroute(), - sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP); + if (inpflags & INP_PKTINFO) { + struct in_pktinfo ipi; + ipi.ipi_addr = ip->ip_dst; + ipi.ipi_ifindex = ifp->if_index; + *mp = sbcreatecontrol((void *) &ipi, + sizeof(ipi), IP_PKTINFO, IPPROTO_IP); if (*mp) mp = &(*mp)->m_next; } -#endif - if (inp->inp_flags & INP_RECVIF) { + if (inpflags & INP_RECVIF) { struct sockaddr_dl sdl; - sockaddr_dl_init(&sdl, sizeof(sdl), - (m->m_pkthdr.rcvif != NULL) - ? m->m_pkthdr.rcvif->if_index - : 0, - 0, NULL, 0, NULL, 0); + sockaddr_dl_init(&sdl, sizeof(sdl), ifp ? + ifp->if_index : 0, 0, NULL, 0, NULL, 0); *mp = sbcreatecontrol(&sdl, sdl.sdl_len, IP_RECVIF, IPPROTO_IP); if (*mp) mp = &(*mp)->m_next; } - if (inp->inp_flags & INP_RECVTTL) { + if (inpflags & INP_RECVTTL) { *mp = sbcreatecontrol((void *) &ip->ip_ttl, sizeof(uint8_t), IP_RECVTTL, IPPROTO_IP); if (*mp) mp = &(*mp)->m_next; } + m_put_rcvif_psref(ifp, &psref); } /* @@ -1639,66 +1543,6 @@ sysctl_net_inet_ip_pmtudto(SYSCTLFN_ARGS return (0); } -#ifdef GATEWAY -/* - * sysctl helper routine for net.inet.ip.maxflows. - */ -static int -sysctl_net_inet_ip_maxflows(SYSCTLFN_ARGS) -{ - int error; - - error = sysctl_lookup(SYSCTLFN_CALL(rnode)); - if (error || newp == NULL) - return (error); - - mutex_enter(softnet_lock); - KERNEL_LOCK(1, NULL); - - ipflow_prune(); - - KERNEL_UNLOCK_ONE(NULL); - mutex_exit(softnet_lock); - - return (0); -} - -static int -sysctl_net_inet_ip_hashsize(SYSCTLFN_ARGS) -{ - int error, tmp; - struct sysctlnode node; - - node = *rnode; - tmp = ip_hashsize; - node.sysctl_data = &tmp; - error = sysctl_lookup(SYSCTLFN_CALL(&node)); - if (error || newp == NULL) - return (error); - - if ((tmp & (tmp - 1)) == 0 && tmp != 0) { - /* - * Can only fail due to malloc() - */ - mutex_enter(softnet_lock); - KERNEL_LOCK(1, NULL); - - error = ipflow_invalidate_all(tmp); - - KERNEL_UNLOCK_ONE(NULL); - mutex_exit(softnet_lock); - - } else { - /* - * EINVAL if not a power of 2 - */ - error = EINVAL; - } - - return error; -} -#endif /* GATEWAY */ - static int sysctl_net_inet_ip_stats(SYSCTLFN_ARGS) { @@ -1709,13 +1553,6 @@ sysctl_net_inet_ip_stats(SYSCTLFN_ARGS) static void sysctl_net_inet_ip_setup(struct sysctllog **clog) { - extern int subnetsarelocal, hostzeroisbroadcast; - - sysctl_createv(clog, 0, NULL, NULL, - CTLFLAG_PERMANENT, - CTLTYPE_NODE, "net", NULL, - NULL, 0, NULL, 0, - CTL_NET, CTL_EOL); sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT, CTLTYPE_NODE, "inet", @@ -1781,14 +1618,7 @@ sysctl_net_inet_ip_setup(struct sysctllo NULL, 0, &ip_allowsrcrt, 0, CTL_NET, PF_INET, IPPROTO_IP, IPCTL_ALLOWSRCRT, CTL_EOL); - sysctl_createv(clog, 0, NULL, NULL, - CTLFLAG_PERMANENT|CTLFLAG_READWRITE, - CTLTYPE_INT, "subnetsarelocal", - SYSCTL_DESCR("Whether logical subnets are considered " - "local"), - NULL, 0, &subnetsarelocal, 0, - CTL_NET, PF_INET, IPPROTO_IP, - IPCTL_SUBNETSARELOCAL, CTL_EOL); + sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "mtudisc", @@ -1814,41 +1644,9 @@ sysctl_net_inet_ip_setup(struct sysctllo CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "mtudisctimeout", SYSCTL_DESCR("Lifetime of a Path MTU Discovered route"), - sysctl_net_inet_ip_pmtudto, 0, &ip_mtudisc_timeout, 0, + sysctl_net_inet_ip_pmtudto, 0, (void *)&ip_mtudisc_timeout, 0, CTL_NET, PF_INET, IPPROTO_IP, IPCTL_MTUDISCTIMEOUT, CTL_EOL); -#ifdef GATEWAY - sysctl_createv(clog, 0, NULL, NULL, - CTLFLAG_PERMANENT|CTLFLAG_READWRITE, - CTLTYPE_INT, "maxflows", - SYSCTL_DESCR("Number of flows for fast forwarding"), - sysctl_net_inet_ip_maxflows, 0, &ip_maxflows, 0, - CTL_NET, PF_INET, IPPROTO_IP, - IPCTL_MAXFLOWS, CTL_EOL); - sysctl_createv(clog, 0, NULL, NULL, - CTLFLAG_PERMANENT|CTLFLAG_READWRITE, - CTLTYPE_INT, "hashsize", - SYSCTL_DESCR("Size of hash table for fast forwarding (IPv4)"), - sysctl_net_inet_ip_hashsize, 0, &ip_hashsize, 0, - CTL_NET, PF_INET, IPPROTO_IP, - CTL_CREATE, CTL_EOL); -#endif /* GATEWAY */ - sysctl_createv(clog, 0, NULL, NULL, - CTLFLAG_PERMANENT|CTLFLAG_READWRITE, - CTLTYPE_INT, "hostzerobroadcast", - SYSCTL_DESCR("All zeroes address is broadcast address"), - NULL, 0, &hostzeroisbroadcast, 0, - CTL_NET, PF_INET, IPPROTO_IP, - IPCTL_HOSTZEROBROADCAST, CTL_EOL); -#if NGIF > 0 - sysctl_createv(clog, 0, NULL, NULL, - CTLFLAG_PERMANENT|CTLFLAG_READWRITE, - CTLTYPE_INT, "gifttl", - SYSCTL_DESCR("Default TTL for a gif tunnel datagram"), - NULL, 0, &ip_gif_ttl, 0, - CTL_NET, PF_INET, IPPROTO_IP, - IPCTL_GIF_TTL, CTL_EOL); -#endif /* NGIF */ #ifndef IPNOPRIVPORTS sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT|CTLFLAG_READWRITE, @@ -1905,6 +1703,43 @@ sysctl_net_inet_ip_setup(struct sysctllo sysctl_net_inet_ip_stats, 0, NULL, 0, CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS, CTL_EOL); +#if NARP + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "dad_count", + SYSCTL_DESCR("Number of Duplicate Address Detection " + "probes to send"), + NULL, 0, &ip_dad_count, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_DAD_COUNT, CTL_EOL); +#endif + + /* anonportalgo RFC6056 subtree */ + const struct sysctlnode *portalgo_node; + sysctl_createv(clog, 0, NULL, &portalgo_node, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "anonportalgo", + SYSCTL_DESCR("Anonymous Port Algorithm Selection (RFC 6056)"), + NULL, 0, NULL, 0, + CTL_NET, PF_INET, IPPROTO_IP, CTL_CREATE, CTL_EOL); + sysctl_createv(clog, 0, &portalgo_node, NULL, + CTLFLAG_PERMANENT, + CTLTYPE_STRING, "available", + SYSCTL_DESCR("available algorithms"), + sysctl_portalgo_available, 0, NULL, PORTALGO_MAXLEN, + CTL_CREATE, CTL_EOL); + sysctl_createv(clog, 0, &portalgo_node, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_STRING, "selected", + SYSCTL_DESCR("selected algorithm"), + sysctl_portalgo_selected4, 0, NULL, PORTALGO_MAXLEN, + CTL_CREATE, CTL_EOL); + sysctl_createv(clog, 0, &portalgo_node, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_STRUCT, "reserve", + SYSCTL_DESCR("bitmap of reserved ports"), + sysctl_portalgo_reserve4, 0, NULL, 0, + CTL_CREATE, CTL_EOL); } void