o Move all parts of the IP reassembly process into the function ip_reass() to

make it fully self-contained.
o ip_reass() now returns a new mbuf with the reassembled packet and ip->ip_len
  including the IP header.
o Computation of the delayed checksum is moved into divert_packet().

Reviewed by:	silby
This commit is contained in:
andre 2004-08-03 12:31:38 +00:00
parent 8d14ac3ae0
commit fd96163246
2 changed files with 131 additions and 116 deletions

View File

@ -168,6 +168,14 @@ divert_packet(struct mbuf *m, int incoming)
return;
ip = mtod(m, struct ip *);
/* Delayed checksums are currently not compatible with divert. */
if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
ip->ip_len = ntohs(ip->ip_len);
in_delayed_cksum(m);
m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
ip->ip_len = htons(ip->ip_len);
}
/*
* Record receive interface address, if any.
* But only for incoming packets.

View File

@ -240,7 +240,7 @@ static int ip_dooptions(struct mbuf *m, int,
static void ip_forward(struct mbuf *m, int srcrt,
struct sockaddr_in *next_hop);
static void ip_freef(struct ipqhead *, struct ipq *);
static struct mbuf *ip_reass(struct mbuf *, struct ipqhead *, struct ipq *);
static struct mbuf *ip_reass(struct mbuf *);
/*
* IP initialization: fill in IP protocol switch table.
@ -296,7 +296,6 @@ void
ip_input(struct mbuf *m)
{
struct ip *ip = NULL;
struct ipq *fp;
struct in_ifaddr *ia = NULL;
struct ifaddr *ifa;
int i, checkif, hlen = 0;
@ -726,103 +725,19 @@ ip_input(struct mbuf *m)
}
/*
* If offset or IP_MF are set, must reassemble.
* Otherwise, nothing need be done.
* (We could look in the reassembly queue to see
* if the packet was previously fragmented,
* but it's not worth the time; just let them time out.)
* Attempt reassembly; if it succeeds, proceed.
* ip_reass() will return a different mbuf.
*/
if (ip->ip_off & (IP_MF | IP_OFFMASK)) {
/* If maxnipq is 0, never accept fragments. */
if (maxnipq == 0) {
ipstat.ips_fragments++;
ipstat.ips_fragdropped++;
goto bad;
}
sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
IPQ_LOCK();
/*
* Look for queue of fragments
* of this datagram.
*/
TAILQ_FOREACH(fp, &ipq[sum], ipq_list)
if (ip->ip_id == fp->ipq_id &&
ip->ip_src.s_addr == fp->ipq_src.s_addr &&
ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
#ifdef MAC
mac_fragment_match(m, fp) &&
#endif
ip->ip_p == fp->ipq_p)
goto found;
fp = NULL;
/*
* Enforce upper bound on number of fragmented packets
* for which we attempt reassembly;
* If maxnipq is -1, accept all fragments without limitation.
*/
if ((nipq > maxnipq) && (maxnipq > 0)) {
/*
* drop something from the tail of the current queue
* before proceeding further
*/
struct ipq *q = TAILQ_LAST(&ipq[sum], ipqhead);
if (q == NULL) { /* gak */
for (i = 0; i < IPREASS_NHASH; i++) {
struct ipq *r = TAILQ_LAST(&ipq[i], ipqhead);
if (r) {
ipstat.ips_fragtimeout += r->ipq_nfrags;
ip_freef(&ipq[i], r);
break;
}
}
} else {
ipstat.ips_fragtimeout += q->ipq_nfrags;
ip_freef(&ipq[sum], q);
}
}
found:
/*
* Adjust ip_len to not reflect header,
* convert offset of this to bytes.
*/
ip->ip_len -= hlen;
if (ip->ip_off & IP_MF) {
/*
* Make sure that fragments have a data length
* that's a non-zero multiple of 8 bytes.
*/
if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) {
IPQ_UNLOCK();
ipstat.ips_toosmall++; /* XXX */
goto bad;
}
m->m_flags |= M_FRAG;
} else
m->m_flags &= ~M_FRAG;
ip->ip_off <<= 3;
/*
* Attempt reassembly; if it succeeds, proceed.
* ip_reass() will return a different mbuf.
*/
ipstat.ips_fragments++;
m->m_pkthdr.header = ip;
m = ip_reass(m, &ipq[sum], fp);
IPQ_UNLOCK();
if (m == 0)
m = ip_reass(m);
if (m == NULL)
return;
ipstat.ips_reassembled++;
ip = mtod(m, struct ip *);
/* Get the header length of the reassembled packet */
hlen = ip->ip_hl << 2;
#ifdef IPDIVERT
/* Restore original checksum before diverting packet */
if (divert_find_info(m) != 0) {
ip->ip_len += hlen;
ip->ip_len = htons(ip->ip_len);
ip->ip_off = htons(ip->ip_off);
ip->ip_sum = 0;
@ -832,11 +747,15 @@ ip_input(struct mbuf *m)
ip->ip_sum = in_cksum(m, hlen);
ip->ip_off = ntohs(ip->ip_off);
ip->ip_len = ntohs(ip->ip_len);
ip->ip_len -= hlen;
}
#endif
} else
ip->ip_len -= hlen;
}
/*
* Further protocols expect the packet length to be w/o the
* IP header.
*/
ip->ip_len -= hlen;
#ifdef IPDIVERT
/*
@ -951,27 +870,112 @@ DPRINTF(("ip_input: no SP, packet discarded\n"));/*XXX*/
/*
* Take incoming datagram fragment and try to reassemble it into
* whole datagram. If a chain for reassembly of this datagram already
* exists, then it is given as fp; otherwise have to make a chain.
*
* When IPDIVERT enabled, keep additional state with each packet that
* tells us if we need to divert or tee the packet we're building.
* In particular, *divinfo includes the port and TEE flag,
* *divert_rule is the number of the matching rule.
* whole datagram. If the argument is the first fragment or one
* in between the function will return NULL and store the mbuf
* in the fragment chain. If the argument is the last fragment
* the packet will be reassembled and the pointer to the new
* mbuf returned for further processing. Only m_tags attached
* to the first packet/fragment are preserved.
* The IP header is *NOT* adjusted out of iplen.
*/
static struct mbuf *
ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp)
struct mbuf *
ip_reass(struct mbuf *m)
{
struct ip *ip = mtod(m, struct ip *);
register struct mbuf *p, *q, *nq;
struct mbuf *t;
int hlen = ip->ip_hl << 2;
int i, next;
struct ip *ip;
struct mbuf *p, *q, *nq, *t;
struct ipq *fp = NULL;
struct ipqhead *head;
int i, hlen, next;
u_int8_t ecn, ecn0;
u_short hash;
IPQ_LOCK_ASSERT();
/* If maxnipq is 0, never accept fragments. */
if (maxnipq == 0) {
ipstat.ips_fragments++;
ipstat.ips_fragdropped++;
goto dropfrag;
}
ip = mtod(m, struct ip *);
hlen = ip->ip_hl << 2;
hash = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
head = &ipq[hash];
IPQ_LOCK();
/*
* Look for queue of fragments
* of this datagram.
*/
TAILQ_FOREACH(fp, head, ipq_list)
if (ip->ip_id == fp->ipq_id &&
ip->ip_src.s_addr == fp->ipq_src.s_addr &&
ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
#ifdef MAC
mac_fragment_match(m, fp) &&
#endif
ip->ip_p == fp->ipq_p)
goto found;
fp = NULL;
/*
* Enforce upper bound on number of fragmented packets
* for which we attempt reassembly;
* If maxnipq is -1, accept all fragments without limitation.
*/
if ((nipq > maxnipq) && (maxnipq > 0)) {
/*
* drop something from the tail of the current queue
* before proceeding further
*/
struct ipq *q = TAILQ_LAST(head, ipqhead);
if (q == NULL) { /* gak */
for (i = 0; i < IPREASS_NHASH; i++) {
struct ipq *r = TAILQ_LAST(&ipq[i], ipqhead);
if (r) {
ipstat.ips_fragtimeout += r->ipq_nfrags;
ip_freef(&ipq[i], r);
break;
}
}
} else {
ipstat.ips_fragtimeout += q->ipq_nfrags;
ip_freef(head, q);
}
}
found:
/*
* Adjust ip_len to not reflect header,
* convert offset of this to bytes.
*/
ip->ip_len -= hlen;
if (ip->ip_off & IP_MF) {
/*
* Make sure that fragments have a data length
* that's a non-zero multiple of 8 bytes.
*/
if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) {
IPQ_UNLOCK();
ipstat.ips_toosmall++; /* XXX */
goto dropfrag;
}
m->m_flags |= M_FRAG;
} else
m->m_flags &= ~M_FRAG;
ip->ip_off <<= 3;
/*
* Attempt reassembly; if it succeeds, proceed.
* ip_reass() will return a different mbuf.
*/
ipstat.ips_fragments++;
m->m_pkthdr.header = ip;
/* Previous ip_reass() started here. */
/*
* Presence of header sizes in mbufs
* would confuse code below.
@ -1114,7 +1118,7 @@ ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp)
ipstat.ips_fragdropped += fp->ipq_nfrags;
ip_freef(head, fp);
}
return (0);
goto done;
}
next += GETIP(q)->ip_len;
}
@ -1124,7 +1128,7 @@ ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp)
ipstat.ips_fragdropped += fp->ipq_nfrags;
ip_freef(head, fp);
}
return (0);
goto done;
}
/*
@ -1136,7 +1140,7 @@ ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp)
ipstat.ips_toolong++;
ipstat.ips_fragdropped += fp->ipq_nfrags;
ip_freef(head, fp);
return (0);
goto done;
}
/*
@ -1161,12 +1165,11 @@ ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp)
#endif
/*
* Create header for new ip packet by
* modifying header of first packet;
* dequeue and discard fragment reassembly header.
* Create header for new ip packet by modifying header of first
* packet; dequeue and discard fragment reassembly header.
* Make header visible.
*/
ip->ip_len = next;
ip->ip_len = (ip->ip_hl << 2) + next;
ip->ip_src = fp->ipq_src;
ip->ip_dst = fp->ipq_dst;
TAILQ_REMOVE(head, fp, ipq_list);
@ -1177,6 +1180,8 @@ ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp)
/* some debugging cruft by sklower, below, will go away soon */
if (m->m_flags & M_PKTHDR) /* XXX this should be done elsewhere */
m_fixhdr(m);
ipstat.ips_reassembled++;
IPQ_UNLOCK();
return (m);
dropfrag:
@ -1184,7 +1189,9 @@ ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp)
if (fp != NULL)
fp->ipq_nfrags--;
m_freem(m);
return (0);
done:
IPQ_UNLOCK();
return (NULL);
#undef GETIP
}