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.245.2.2 retrieving revision 1.268.2.1 diff -u -p -r1.245.2.2 -r1.268.2.1 --- src/sys/netinet/ip_input.c 2007/04/10 13:26:49 1.245.2.2 +++ src/sys/netinet/ip_input.c 2008/05/16 02:25:41 1.268.2.1 @@ -1,4 +1,4 @@ -/* $NetBSD: ip_input.c,v 1.245.2.2 2007/04/10 13:26:49 ad Exp $ */ +/* $NetBSD: ip_input.c,v 1.268.2.1 2008/05/16 02:25:41 yamt Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -45,13 +45,6 @@ * 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 NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -98,7 +91,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.245.2.2 2007/04/10 13:26:49 ad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.268.2.1 2008/05/16 02:25:41 yamt Exp $"); #include "opt_inet.h" #include "opt_gateway.h" @@ -135,6 +128,7 @@ __KERNEL_RCSID(0, "$NetBSD: ip_input.c,v #include #include #include +#include #include /* just for gif_ttl */ #include @@ -148,6 +142,7 @@ __KERNEL_RCSID(0, "$NetBSD: ip_input.c,v #ifdef IPSEC #include +#include #include #endif #ifdef FAST_IPSEC @@ -230,9 +225,10 @@ u_long in_multihash; /* size of hash int in_multientries; /* total number of addrs */ struct in_multihashhead *in_multihashtbl; struct ifqueue ipintrq; -struct ipstat ipstat; uint16_t ip_id; +percpu_t *ipstat_percpu; + #ifdef PFIL_HOOKS struct pfil_head inet_pfil_hook; #endif @@ -417,16 +413,17 @@ ip_init(void) for (i = 0; i < IPREASS_NHASH; i++) LIST_INIT(&ipq[i]); + ip_initid(); ip_id = time_second & 0xfffff; ipintrq.ifq_maxlen = ipqmaxlen; ip_nmbclusters_changed(); TAILQ_INIT(&in_ifaddrhead); - in_ifaddrhashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, M_IFADDR, - M_WAITOK, &in_ifaddrhash); - in_multihashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, M_IPMADDR, - M_WAITOK, &in_multihash); + 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); @@ -446,6 +443,8 @@ ip_init(void) MOWNER_ATTACH(&ip_tx_mowner); MOWNER_ATTACH(&ip_rx_mowner); #endif /* MBUFTRACE */ + + ipstat_percpu = percpu_alloc(sizeof(uint64_t) * IP_NSTATS); } struct sockaddr_in ipaddr = { @@ -463,15 +462,18 @@ ipintr(void) int s; struct mbuf *m; + mutex_enter(softnet_lock); + KERNEL_LOCK(1, NULL); while (!IF_IS_EMPTY(&ipintrq)) { s = splnet(); IF_DEQUEUE(&ipintrq, m); splx(s); - if (m == 0) - return; - MCLAIM(m, &ip_rx_mowner); + if (m == NULL) + break; ip_input(m); } + KERNEL_UNLOCK_ONE(NULL); + mutex_exit(softnet_lock); } /* @@ -511,7 +513,7 @@ ip_input(struct mbuf *m) */ if (TAILQ_FIRST(&in_ifaddrhead) == 0) goto bad; - ipstat.ips_total++; + 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 @@ -522,28 +524,28 @@ ip_input(struct mbuf *m) if ((m = m_copyup(m, sizeof(struct ip), (max_linkhdr + 3) & ~3)) == NULL) { /* XXXJRT new stat, please */ - ipstat.ips_toosmall++; + IP_STATINC(IP_STAT_TOOSMALL); return; } } else if (__predict_false(m->m_len < sizeof (struct ip))) { if ((m = m_pullup(m, sizeof (struct ip))) == NULL) { - ipstat.ips_toosmall++; + IP_STATINC(IP_STAT_TOOSMALL); return; } } ip = mtod(m, struct ip *); if (ip->ip_v != IPVERSION) { - ipstat.ips_badvers++; + IP_STATINC(IP_STAT_BADVERS); goto bad; } hlen = ip->ip_hl << 2; if (hlen < sizeof(struct ip)) { /* minimum header length */ - ipstat.ips_badhlen++; + IP_STATINC(IP_STAT_BADHLEN); goto bad; } if (hlen > m->m_len) { if ((m = m_pullup(m, hlen)) == 0) { - ipstat.ips_badhlen++; + IP_STATINC(IP_STAT_BADHLEN); return; } ip = mtod(m, struct ip *); @@ -554,7 +556,7 @@ ip_input(struct mbuf *m) * not allowed. */ if (IN_MULTICAST(ip->ip_src.s_addr)) { - ipstat.ips_badaddr++; + IP_STATINC(IP_STAT_BADADDR); goto bad; } @@ -562,7 +564,7 @@ ip_input(struct mbuf *m) 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) { - ipstat.ips_badaddr++; + IP_STATINC(IP_STAT_BADADDR); goto bad; } } @@ -600,7 +602,7 @@ ip_input(struct mbuf *m) * Check for additional length bogosity */ if (len < hlen) { - ipstat.ips_badlen++; + IP_STATINC(IP_STAT_BADLEN); goto bad; } @@ -611,7 +613,7 @@ ip_input(struct mbuf *m) * Drop packet if shorter than we expect. */ if (m->m_pkthdr.len < len) { - ipstat.ips_tooshort++; + IP_STATINC(IP_STAT_TOOSHORT); goto bad; } if (m->m_pkthdr.len > len) { @@ -780,7 +782,7 @@ ip_input(struct mbuf *m) * ip_output().) */ if (ip_mforward(m, m->m_pkthdr.rcvif) != 0) { - ipstat.ips_cantforward++; + IP_STATINC(IP_STAT_CANTFORWARD); m_freem(m); return; } @@ -792,7 +794,7 @@ ip_input(struct mbuf *m) */ if (ip->ip_p == IPPROTO_IGMP) goto ours; - ipstat.ips_forward++; + IP_STATINC(IP_STAT_CANTFORWARD); } #endif /* @@ -801,7 +803,7 @@ ip_input(struct mbuf *m) */ IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); if (inm == NULL) { - ipstat.ips_cantforward++; + IP_STATINC(IP_STAT_CANTFORWARD); m_freem(m); return; } @@ -815,7 +817,7 @@ ip_input(struct mbuf *m) * Not for us; forward if possible and desirable. */ if (ipforwarding == 0) { - ipstat.ips_cantforward++; + IP_STATINC(IP_STAT_CANTFORWARD); m_freem(m); } else { /* @@ -826,12 +828,12 @@ ip_input(struct mbuf *m) */ if (downmatch) { icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); - ipstat.ips_cantforward++; + IP_STATINC(IP_STAT_CANTFORWARD); return; } #ifdef IPSEC if (ipsec4_in_reject(m, NULL)) { - ipsecstat.in_polvio++; + IPSEC_STATINC(IPSEC_STAT_IN_POLVIO); goto bad; } #endif @@ -859,7 +861,7 @@ ip_input(struct mbuf *m) KEY_FREESP(&sp); splx(s); if (error) { - ipstat.ips_cantforward++; + IP_STATINC(IP_STAT_CANTFORWARD); goto bad; } @@ -897,22 +899,39 @@ ours: * but it's not worth the time; just let them time out.) */ if (ip->ip_off & ~htons(IP_DF|IP_RF)) { - + uint16_t off; + /* + * Prevent TCP blind data attacks by not allowing non-initial + * fragments to start at less than 68 bytes (minimal fragment + * size) and making sure the first fragment is at least 68 + * bytes. + */ + off = (ntohs(ip->ip_off) & IP_OFFMASK) << 3; + if ((off > 0 ? off + hlen : len) < IP_MINFRAGSIZE - 1) { + IP_STATINC(IP_STAT_BADFRAGS); + goto bad; + } /* * Look for queue of fragments * of this datagram. */ IPQ_LOCK(); hash = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); - /* XXX LIST_FOREACH(fp, &ipq[hash], ipq_q) */ - for (fp = LIST_FIRST(&ipq[hash]); fp != NULL; - fp = LIST_NEXT(fp, ipq_q)) { + LIST_FOREACH(fp, &ipq[hash], ipq_q) { if (ip->ip_id == fp->ipq_id && in_hosteq(ip->ip_src, fp->ipq_src) && in_hosteq(ip->ip_dst, fp->ipq_dst) && - ip->ip_p == fp->ipq_p) + ip->ip_p == fp->ipq_p) { + /* + * Make sure the TOS is matches previous + * fragments. + */ + if (ip->ip_tos != fp->ipq_tos) { + IP_STATINC(IP_STAT_BADFRAGS); + goto bad; + } goto found; - + } } fp = 0; found: @@ -931,7 +950,7 @@ found: */ if (ntohs(ip->ip_len) == 0 || (ntohs(ip->ip_len) & 0x7) != 0) { - ipstat.ips_badfrags++; + IP_STATINC(IP_STAT_BADFRAGS); IPQ_UNLOCK(); goto bad; } @@ -944,12 +963,12 @@ found: * attempt reassembly; if it succeeds, proceed. */ if (mff || ip->ip_off != htons(0)) { - ipstat.ips_fragments++; + IP_STATINC(IP_STAT_FRAGMENTS); s = splvm(); ipqe = pool_get(&ipqent_pool, PR_NOWAIT); splx(s); if (ipqe == NULL) { - ipstat.ips_rcvmemdrop++; + IP_STATINC(IP_STAT_RCVMEMDROP); IPQ_UNLOCK(); goto bad; } @@ -961,7 +980,7 @@ found: IPQ_UNLOCK(); return; } - ipstat.ips_reassembled++; + IP_STATINC(IP_STAT_REASSEMBLED); ip = mtod(m, struct ip *); hlen = ip->ip_hl << 2; ip->ip_len = htons(ntohs(ip->ip_len) + hlen); @@ -979,7 +998,7 @@ found: */ if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0 && ipsec4_in_reject(m, NULL)) { - ipsecstat.in_polvio++; + IPSEC_STATINC(IPSEC_STAT_IN_POLVIO); goto bad; } #endif @@ -1015,7 +1034,6 @@ found: /* XXX error stat??? */ error = EINVAL; DPRINTF(("ip_input: no SP, packet discarded\n"));/*XXX*/ - goto bad; } splx(s); if (error) @@ -1030,7 +1048,7 @@ DPRINTF(("ip_input: no SP, packet discar if (ia && ip) ia->ia_ifa.ifa_data.ifad_inbytes += ntohs(ip->ip_len); #endif - ipstat.ips_delivered++; + IP_STATINC(IP_STAT_DELIVERED); { int off = hlen, nh = ip->ip_p; @@ -1042,7 +1060,7 @@ bad: return; badcsum: - ipstat.ips_badsum++; + IP_STATINC(IP_STAT_BADSUM); m_freem(m); } @@ -1109,6 +1127,7 @@ ip_reass(struct ipqent *ipqe, struct ipq fp->ipq_ttl = IPFRAGTTL; fp->ipq_p = ipqe->ipqe_ip->ip_p; fp->ipq_id = ipqe->ipqe_ip->ip_id; + fp->ipq_tos = ipqe->ipqe_ip->ip_tos; TAILQ_INIT(&fp->ipq_fragq); fp->ipq_src = ipqe->ipqe_ip->ip_src; fp->ipq_dst = ipqe->ipqe_ip->ip_dst; @@ -1199,7 +1218,7 @@ insert: q = TAILQ_FIRST(&fp->ipq_fragq); ip = q->ipqe_ip; if ((next + (ip->ip_hl << 2)) > IP_MAXPACKET) { - ipstat.ips_toolong++; + IP_STATINC(IP_STAT_TOOLONG); ip_freef(fp); return (0); } @@ -1249,7 +1268,7 @@ dropfrag: if (fp != 0) fp->ipq_nfrags--; ip_nfrags--; - ipstat.ips_fragdropped++; + IP_STATINC(IP_STAT_FRAGDROPPED); m_freem(m); s = splvm(); pool_put(&ipqent_pool, ipqe); @@ -1316,7 +1335,7 @@ ip_reass_ttl_decr(u_int ticks) 0 : fp->ipq_ttl - ticks); nfp = LIST_NEXT(fp, ipq_q); if (fp->ipq_ttl == 0) { - ipstat.ips_fragtimeout++; + IP_STATINC(IP_STAT_FRAGTIMEOUT); ip_freef(fp); } else { nfrags += fp->ipq_nfrags; @@ -1367,7 +1386,9 @@ ip_slowtimo(void) static u_int dropscanidx = 0; u_int i; u_int median_ttl; - int s = splsoftnet(); + + mutex_enter(softnet_lock); + KERNEL_LOCK(1, NULL); IPQ_LOCK(); @@ -1409,30 +1430,35 @@ ip_slowtimo(void) dropscanidx = i; } IPQ_UNLOCK(); - splx(s); + + KERNEL_UNLOCK_ONE(NULL); + mutex_exit(softnet_lock); } /* - * Drain off all datagram fragments. + * Drain off all datagram fragments. Don't acquire softnet_lock as + * can be called from hardware interrupt context. */ void ip_drain(void) { + KERNEL_LOCK(1, NULL); + /* * We may be called from a device's interrupt context. If * the ipq is already busy, just bail out now. */ - if (ipq_lock_try() == 0) - return; - - /* - * Drop half the total fragments now. If more mbufs are needed, - * we will be called again soon. - */ - ip_reass_drophalf(); + if (ipq_lock_try() != 0) { + /* + * Drop half the total fragments now. If more mbufs are + * needed, we will be called again soon. + */ + ip_reass_drophalf(); + IPQ_UNLOCK(); + } - IPQ_UNLOCK(); + KERNEL_UNLOCK_ONE(NULL); } /* @@ -1663,7 +1689,7 @@ ip_dooptions(struct mbuf *m) return (0); bad: icmp_error(m, type, code, 0, 0); - ipstat.ips_badoptions++; + IP_STATINC(IP_STAT_BADOPTIONS); return (1); } @@ -1674,23 +1700,18 @@ bad: struct in_ifaddr * ip_rtaddr(struct in_addr dst) { - if (!in_hosteq(dst, satocsin(rtcache_getdst(&ipforward_rt))->sin_addr)) - rtcache_free(&ipforward_rt); - else - rtcache_check(&ipforward_rt); - - if (ipforward_rt.ro_rt == NULL) { - struct sockaddr_in *sin = satosin(&ipforward_rt.ro_dst); - - sin->sin_family = AF_INET; - sin->sin_len = sizeof(*sin); - sin->sin_addr = dst; - - rtcache_init(&ipforward_rt); - if (ipforward_rt.ro_rt == NULL) - return NULL; - } - return ifatoia(ipforward_rt.ro_rt->rt_ifa); + struct rtentry *rt; + union { + struct sockaddr dst; + struct sockaddr_in dst4; + } u; + + sockaddr_in_init(&u.dst4, &dst, 0); + + if ((rt = rtcache_lookup(&ipforward_rt, &u.dst)) == NULL) + return NULL; + + return ifatoia(rt->rt_ifa); } /* @@ -1784,39 +1805,16 @@ ip_srcroute(void) return (m); } -/* - * Strip out IP options, at higher - * level protocol in the kernel. - * Second argument is buffer to which options - * will be moved, and return value is their length. - * XXX should be deleted; last arg currently ignored. - */ -void -ip_stripoptions(struct mbuf *m, struct mbuf *mopt) -{ - int i; - struct ip *ip = mtod(m, struct ip *); - void *opts; - int olen; - - olen = (ip->ip_hl << 2) - sizeof (struct ip); - opts = (void *)(ip + 1); - i = m->m_len - (sizeof (struct ip) + olen); - memmove(opts, (char *)opts + olen, (unsigned)i); - m->m_len -= olen; - if (m->m_flags & M_PKTHDR) - m->m_pkthdr.len -= olen; - ip->ip_len = htons(ntohs(ip->ip_len) - olen); - ip->ip_hl = sizeof (struct ip) >> 2; -} - const int inetctlerrmap[PRC_NCMDS] = { - 0, 0, 0, 0, - 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, - EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, - EMSGSIZE, EHOSTUNREACH, 0, 0, - 0, 0, 0, 0, - ENOPROTOOPT + [PRC_MSGSIZE] = EMSGSIZE, + [PRC_HOSTDEAD] = EHOSTDOWN, + [PRC_HOSTUNREACH] = EHOSTUNREACH, + [PRC_UNREACH_NET] = EHOSTUNREACH, + [PRC_UNREACH_HOST] = EHOSTUNREACH, + [PRC_UNREACH_PROTOCOL] = ECONNREFUSED, + [PRC_UNREACH_PORT] = ECONNREFUSED, + [PRC_UNREACH_SRCFAIL] = EHOSTUNREACH, + [PRC_PARAMPROB] = ENOPROTOOPT, }; /* @@ -1841,6 +1839,10 @@ ip_forward(struct mbuf *m, int srcrt) int error, type = 0, code = 0, destmtu = 0; struct mbuf *mcopy; n_long dest; + union { + struct sockaddr dst; + struct sockaddr_in dst4; + } u; /* * We are now in the output path. @@ -1860,7 +1862,7 @@ ip_forward(struct mbuf *m, int srcrt) } #endif if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) { - ipstat.ips_cantforward++; + IP_STATINC(IP_STAT_CANTFORWARD); m_freem(m); return; } @@ -1869,25 +1871,11 @@ ip_forward(struct mbuf *m, int srcrt) return; } - if (!in_hosteq(ip->ip_dst, - satocsin(rtcache_getdst(&ipforward_rt))->sin_addr)) - rtcache_free(&ipforward_rt); - else - rtcache_check(&ipforward_rt); - if (ipforward_rt.ro_rt == NULL) { - struct sockaddr_in *sin = satosin(&ipforward_rt.ro_dst); - - sin->sin_family = AF_INET; - sin->sin_len = sizeof(*sin); - sin->sin_addr = ip->ip_dst; - - rtcache_init(&ipforward_rt); - if (ipforward_rt.ro_rt == NULL) { - icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, dest, 0); - 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); + return; } - rt = ipforward_rt.ro_rt; /* * Save at most 68 bytes of the packet in case @@ -1910,7 +1898,7 @@ ip_forward(struct mbuf *m, int srcrt) */ if (rt->rt_ifp == m->m_pkthdr.rcvif && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && - !in_nullhost(satosin(rt_key(rt))->sin_addr) && + !in_nullhost(satocsin(rt_getkey(rt))->sin_addr) && ipsendredirects && !srcrt) { if (rt->rt_ifa && (ip->ip_src.s_addr & ifatoia(rt->rt_ifa)->ia_subnetmask) == @@ -1938,12 +1926,15 @@ ip_forward(struct mbuf *m, int srcrt) (struct ip_moptions *)NULL, (struct socket *)NULL); if (error) - ipstat.ips_cantforward++; + IP_STATINC(IP_STAT_CANTFORWARD); else { - ipstat.ips_forward++; - if (type) - ipstat.ips_redirectsent++; - 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) { #ifdef GATEWAY if (mcopy->m_flags & M_CANFASTFWD) @@ -1975,17 +1966,17 @@ ip_forward(struct mbuf *m, int srcrt) case EMSGSIZE: type = ICMP_UNREACH; code = ICMP_UNREACH_NEEDFRAG; -#if !defined(IPSEC) && !defined(FAST_IPSEC) - if (ipforward_rt.ro_rt != NULL) - destmtu = ipforward_rt.ro_rt->rt_ifp->if_mtu; -#else - /* - * 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!!! - */ - if (ipforward_rt.ro_rt != NULL) { + + if ((rt = rtcache_validate(&ipforward_rt)) != NULL) { + +#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; @@ -1994,10 +1985,11 @@ ip_forward(struct mbuf *m, int srcrt) sp = ipsec4_getpolicybyaddr(mcopy, IPSEC_DIR_OUTBOUND, IP_FORWARDING, &ipsecerror); +#endif - if (sp == NULL) - destmtu = ipforward_rt.ro_rt->rt_ifp->if_mtu; - else { + destmtu = rt->rt_ifp->if_mtu; +#if defined(IPSEC) || defined(FAST_IPSEC) + if (sp != NULL) { /* count IPsec header size */ ipsechdr = ipsec4_hdrsiz(mcopy, IPSEC_DIR_OUTBOUND, NULL); @@ -2011,11 +2003,11 @@ ip_forward(struct mbuf *m, int srcrt) && sp->req->sav != NULL && sp->req->sav->sah != NULL) { ro = &sp->req->sav->sah->sa_route; - if (ro->ro_rt && ro->ro_rt->rt_ifp) { + if (rt && rt->rt_ifp) { destmtu = - ro->ro_rt->rt_rmx.rmx_mtu ? - ro->ro_rt->rt_rmx.rmx_mtu : - ro->ro_rt->rt_ifp->if_mtu; + rt->rt_rmx.rmx_mtu ? + rt->rt_rmx.rmx_mtu : + rt->rt_ifp->if_mtu; destmtu -= ipsechdr; } } @@ -2026,9 +2018,9 @@ ip_forward(struct mbuf *m, int srcrt) KEY_FREESP(&sp); #endif } +#endif /*defined(IPSEC) || defined(FAST_IPSEC)*/ } -#endif /*IPSEC*/ - ipstat.ips_cantfrag++; + IP_STATINC(IP_STAT_CANTFRAG); break; case ENOBUFS: @@ -2096,13 +2088,12 @@ ip_savecontrol(struct inpcb *inp, struct if (inp->inp_flags & INP_RECVIF) { struct sockaddr_dl sdl; - sdl.sdl_len = offsetof(struct sockaddr_dl, sdl_data[0]); - sdl.sdl_family = AF_LINK; - sdl.sdl_index = m->m_pkthdr.rcvif ? - m->m_pkthdr.rcvif->if_index : 0; - sdl.sdl_nlen = sdl.sdl_alen = sdl.sdl_slen = 0; - *mp = sbcreatecontrol((void *) &sdl, sdl.sdl_len, - IP_RECVIF, IPPROTO_IP); + sockaddr_dl_init(&sdl, sizeof(sdl), + (m->m_pkthdr.rcvif != NULL) + ? m->m_pkthdr.rcvif->if_index + : 0, + 0, NULL, 0, NULL, 0); + *mp = sbcreatecontrol(&sdl, sdl.sdl_len, IP_RECVIF, IPPROTO_IP); if (*mp) mp = &(*mp)->m_next; } @@ -2172,7 +2163,7 @@ sysctl_net_inet_ip_maxflows(SYSCTLFN_ARG return (s); s = splsoftnet(); - ipflow_reap(0); + ipflow_prune(); splx(s); return (0); @@ -2208,6 +2199,12 @@ sysctl_net_inet_ip_hashsize(SYSCTLFN_ARG } #endif /* GATEWAY */ +static int +sysctl_net_inet_ip_stats(SYSCTLFN_ARGS) +{ + + return (NETSTAT_SYSCTL(ipstat_percpu, IP_NSTATS)); +} SYSCTL_SETUP(sysctl_net_inet_ip_setup, "sysctl net.inet.ip subtree setup") { @@ -2412,7 +2409,15 @@ SYSCTL_SETUP(sysctl_net_inet_ip_setup, " CTLFLAG_PERMANENT, CTLTYPE_STRUCT, "stats", SYSCTL_DESCR("IP statistics"), - NULL, 0, &ipstat, sizeof(ipstat), + sysctl_net_inet_ip_stats, 0, NULL, 0, CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS, CTL_EOL); } + +void +ip_statinc(u_int stat) +{ + + KASSERT(stat < IP_NSTATS); + IP_STATINC(stat); +}