diff -urN src/sys/netinet.old/ip_input.c src/sys/netinet/ip_input.c --- src/sys/netinet.old/ip_input.c Sat May 7 18:39:34 2005 +++ src/sys/netinet/ip_input.c Sun May 8 16:45:40 2005 @@ -797,7 +797,7 @@ struct mbuf *p, *q, *nq, *t; struct ipq *fp = NULL; struct ipqhead *head; - int i, hlen, next; + int i, hlen; u_int8_t ecn, ecn0; u_short hash; @@ -917,6 +917,11 @@ fp->ipq_src = ip->ip_src; fp->ipq_dst = ip->ip_dst; fp->ipq_frags = m; + if ((m->m_flags & M_FRAG) == 0) + fp->ipq_len = ip->ip_len + ip->ip_off; + else + fp->ipq_len = 0; + fp->ipq_curlen = ip->ip_len; m->m_nextpkt = NULL; goto done; } else { @@ -926,6 +931,19 @@ #endif } + /* Final fragment */ + if ((m->m_flags & M_FRAG) == 0) { + /* We have already received a final fragment. Drop packet. */ + if (fp->ipq_len != 0) { + ipstat.ips_fragdropped += fp->ipq_nfrags + 1; + m_freem(m); + ip_freef(head, fp); + goto done; + } + fp->ipq_len = ip->ip_len + ip->ip_off; + } + fp->ipq_curlen += ip->ip_len; + #define GETIP(m) ((struct ip*)((m)->m_pkthdr.header)) /* @@ -969,6 +987,7 @@ m->m_pkthdr.csum_flags = 0; ip->ip_off += i; ip->ip_len -= i; + fp->ipq_curlen -= i; } m->m_nextpkt = p->m_nextpkt; p->m_nextpkt = m; @@ -989,12 +1008,14 @@ GETIP(q)->ip_off += i; m_adj(q, i); q->m_pkthdr.csum_flags = 0; + fp->ipq_curlen -= i; break; } nq = q->m_nextpkt; m->m_nextpkt = nq; ipstat.ips_fragdropped++; fp->ipq_nfrags--; + fp->ipq_curlen -= GETIP(q)->ip_len; m_freem(q); } @@ -1008,19 +1029,7 @@ * only n will ever be stored. (n = maxfragsperpacket.) * */ - next = 0; - for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) { - if (GETIP(q)->ip_off != next) { - if (fp->ipq_nfrags > maxfragsperpacket) { - ipstat.ips_fragdropped += fp->ipq_nfrags; - ip_freef(head, fp); - } - goto done; - } - next += GETIP(q)->ip_len; - } - /* Make sure the last packet didn't have the IP_MF flag */ - if (p->m_flags & M_FRAG) { + if (fp->ipq_len != fp->ipq_curlen) { if (fp->ipq_nfrags > maxfragsperpacket) { ipstat.ips_fragdropped += fp->ipq_nfrags; ip_freef(head, fp); @@ -1033,7 +1042,7 @@ */ q = fp->ipq_frags; ip = GETIP(q); - if (next + (ip->ip_hl << 2) > IP_MAXPACKET) { + if (fp->ipq_len + (ip->ip_hl << 2) > IP_MAXPACKET) { ipstat.ips_toolong++; ipstat.ips_fragdropped += fp->ipq_nfrags; ip_freef(head, fp); @@ -1066,7 +1075,7 @@ * packet; dequeue and discard fragment reassembly header. * Make header visible. */ - ip->ip_len = (ip->ip_hl << 2) + next; + ip->ip_len = (ip->ip_hl << 2) + fp->ipq_len; ip->ip_src = fp->ipq_src; ip->ip_dst = fp->ipq_dst; TAILQ_REMOVE(head, fp, ipq_list); @@ -1083,8 +1092,10 @@ dropfrag: ipstat.ips_fragdropped++; - if (fp != NULL) + if (fp != NULL) { fp->ipq_nfrags--; + fp->ipq_curlen -= GETIP(m)->ip_len; + } m_freem(m); done: IPQ_UNLOCK(); diff -urN src/sys/netinet.old/ip_var.h src/sys/netinet/ip_var.h --- src/sys/netinet.old/ip_var.h Sat May 7 18:39:34 2005 +++ src/sys/netinet/ip_var.h Sat May 7 20:00:18 2005 @@ -61,6 +61,8 @@ struct mbuf *ipq_frags; /* to ip headers of fragments */ struct in_addr ipq_src,ipq_dst; u_char ipq_nfrags; /* # frags in this packet */ + u_short ipq_len; /* length of final packet */ + u_short ipq_curlen; /* how much we've gotten so far */ struct label *ipq_label; /* MAC label */ }; #endif /* _KERNEL */