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.268.2.3 retrieving revision 1.287 diff -u -p -r1.268.2.3 -r1.287 --- src/sys/netinet/ip_input.c 2009/07/18 14:53:25 1.268.2.3 +++ src/sys/netinet/ip_input.c 2010/07/09 18:42:46 1.287 @@ -1,4 +1,4 @@ -/* $NetBSD: ip_input.c,v 1.268.2.3 2009/07/18 14:53:25 yamt Exp $ */ +/* $NetBSD: ip_input.c,v 1.287 2010/07/09 18:42:46 rmind Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -91,7 +91,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.268.2.3 2009/07/18 14:53:25 yamt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.287 2010/07/09 18:42:46 rmind Exp $"); #include "opt_inet.h" #include "opt_compat_netbsd.h" @@ -231,6 +231,7 @@ u_long in_multihash; /* size of hash int in_multientries; /* total number of addrs */ struct in_multihashhead *in_multihashtbl; struct ifqueue ipintrq; + uint16_t ip_id; percpu_t *ipstat_percpu; @@ -383,6 +384,8 @@ 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 **); + /* * Compute IP limits derived from the value of nmbclusters. */ @@ -403,6 +406,8 @@ ip_init(void) const struct protosw *pr; int i; + sysctl_net_inet_ip_setup(NULL); + pool_init(&inmulti_pool, sizeof(struct in_multi), 0, 0, 0, "inmltpl", NULL, IPL_SOFTNET); pool_init(&ipqent_pool, sizeof(struct ipqent), 0, 0, 0, "ipqepl", @@ -470,18 +475,35 @@ ipintr(void) { int s; struct mbuf *m; + struct ifqueue lcl_intrq; + + memset(&lcl_intrq, 0, sizeof(lcl_intrq)); + ipintrq.ifq_maxlen = ipqmaxlen; mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); - while (!IF_IS_EMPTY(&ipintrq)) { + if (!IF_IS_EMPTY(&ipintrq)) { s = splnet(); - IF_DEQUEUE(&ipintrq, m); + + /* 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; ip_input(m); } - KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); } @@ -908,7 +930,7 @@ 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; + u_int off; /* * Prevent TCP blind data attacks by not allowing non-initial * fragments to start at less than 68 bytes (minimal fragment @@ -920,31 +942,6 @@ ours: 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); - 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) { - /* - * Make sure the TOS is matches previous - * fragments. - */ - if (ip->ip_tos != fp->ipq_tos) { - IP_STATINC(IP_STAT_BADFRAGS); - IPQ_UNLOCK(); - goto bad; - } - goto found; - } - } - fp = 0; -found: /* * Adjust ip_len to not reflect header, @@ -954,20 +951,44 @@ found: ip->ip_len = htons(ntohs(ip->ip_len) - hlen); mff = (ip->ip_off & htons(IP_MF)) != 0; if (mff) { - /* - * Make sure that fragments have a data length + /* + * Make sure that fragments have a data length * that's a non-zero multiple of 8 bytes. - */ + */ if (ntohs(ip->ip_len) == 0 || (ntohs(ip->ip_len) & 0x7) != 0) { IP_STATINC(IP_STAT_BADFRAGS); - IPQ_UNLOCK(); goto bad; } } ip->ip_off = htons((ntohs(ip->ip_off) & IP_OFFMASK) << 3); /* + * Look for queue of fragments of this datagram. + */ + IPQ_LOCK(); + hash = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); + LIST_FOREACH(fp, &ipq[hash], ipq_q) { + if (ip->ip_id != fp->ipq_id) + continue; + if (!in_hosteq(ip->ip_src, fp->ipq_src)) + continue; + if (!in_hosteq(ip->ip_dst, fp->ipq_dst)) + continue; + if (ip->ip_p != fp->ipq_p) + continue; + /* + * Make sure the TOS is matches previous fragments. + */ + if (ip->ip_tos != fp->ipq_tos) { + IP_STATINC(IP_STAT_BADFRAGS); + IPQ_UNLOCK(); + goto bad; + } + break; + } + + /* * If datagram marked as having more fragments * or if this is not the first fragment, * attempt reassembly; if it succeeds, proceed. @@ -986,7 +1007,7 @@ found: ipqe->ipqe_m = m; ipqe->ipqe_ip = ip; m = ip_reass(ipqe, fp, &ipq[hash]); - if (m == 0) { + if (m == NULL) { IPQ_UNLOCK(); return; } @@ -994,9 +1015,9 @@ found: ip = mtod(m, struct ip *); hlen = ip->ip_hl << 2; ip->ip_len = htons(ntohs(ip->ip_len) + hlen); - } else - if (fp) - ip_freef(fp); + } else if (fp) { + ip_freef(fp); + } IPQ_UNLOCK(); } @@ -2057,9 +2078,9 @@ ip_savecontrol(struct inpcb *inp, struct struct mbuf *m) { - if (inp->inp_socket->so_options & SO_TIMESTAMP + if (inp->inp_socket->so_options & SO_TIMESTAMP #ifdef SO_OTIMESTAMP - || inp->inp_socket->so_options & SO_OTIMESTAMP + || inp->inp_socket->so_options & SO_OTIMESTAMP #endif ) { struct timeval tv; @@ -2207,7 +2228,7 @@ sysctl_net_inet_ip_maxflows(SYSCTLFN_ARG static int sysctl_net_inet_ip_hashsize(SYSCTLFN_ARGS) -{ +{ int error, tmp; struct sysctlnode node; @@ -2235,7 +2256,7 @@ sysctl_net_inet_ip_hashsize(SYSCTLFN_ARG * EINVAL if not a power of 2 */ error = EINVAL; - } + } return error; } @@ -2248,7 +2269,8 @@ 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") +static void +sysctl_net_inet_ip_setup(struct sysctllog **clog) { extern int subnetsarelocal, hostzeroisbroadcast;