- fp = (struct ipq *)((int)m + MHEAD);
- fp->iqx.ip_next = fp->iqx.ip_prev = (struct ip *)fp;
- bcopy(ip, &fp->iqh, min(MLEN-28, hlen));
- fp->iqh.ip_ttl = MAXTTL;
- fp->iq_next = NULL;
- fp->iq_prev = netcb.n_ip_tail;
- if (netcb.n_ip_head != NULL)
- netcb.n_ip_tail->iq_next = fp;
- else
- netcb.n_ip_head = fp;
- netcb.n_ip_tail = fp;
- }
-
- /***********************************************************
- * *
- * merge fragment into reass.q *
- * algorithm: match start and end bytes of new *
- * fragment with fragments on the queue. if no *
- * overlaps are found, add new frag. to the queue. *
- * otherwise, adjust start and end of new frag. so no *
- * overlap and add remainder to queue. if any *
- * fragments are completely covered by the new one, or *
- * if the new one is completely duplicated, free the *
- * fragments. *
- * *
- ***********************************************************/
-
- q = fp->iqx.ip_next; /* -> top of reass. chain */
- ip->ip_end = ip->ip_off + ip->ip_len - 1;
-
- /* skip frags which new doesn't overlap at end */
-
- while ((q != (struct ip *)fp) && (ip->ip_off > q->ip_end))
- q = q->ip_next;
-
- if (q == (struct ip *)fp) /* frag at end of chain */
- ip_enq(ip, fp->iqx.ip_prev);
-
- else {
- if (ip->ip_end < q->ip_off) /* frag doesn't overlap any on chain */
- ip_enq(ip, q->ip_prev);
-
- /* new overlaps beginning of next frag only */
-
- else if (ip->ip_end < q->ip_end) {
- if ((i = ip->ip_end - q->ip_off + 1) < ip->ip_len) {
- ip->ip_len -= i;
- ip->ip_end -= i;
- m_adj(mp, -i);
- ip_enq(ip, q->ip_prev);
- } else
- m_freem(mp);
-
- /* new overlaps end of previous frag */
-
- } else {
-
- savq = q;
- if (ip->ip_off <= q->ip_off) { /* complete cover */
- savq = q->ip_prev;
- ip_deq(q);
- m_freem(dtom(q));
-
- } else { /* overlap */
- if ((i = q->ip_end - ip->ip_off + 1) < ip->ip_len) {
- ip->ip_off += i;
- ip->ip_len -= i;
- m_adj(mp, i);
- } else
- ip->ip_len = 0;
- }
-
- /* new overlaps at beginning of successor frags */
-
- q = savq->ip_next;
- while ((q != (struct ip *)fp) && (ip->ip_len != 0) &&
- (q->ip_off < ip->ip_end))
-
- /* complete cover */
-
- if (q->ip_end <= ip->ip_end) {
- p = q->ip_next;
- ip_deq(q);
- m_freem(dtom(q));
- q = p;
-
- } else { /* overlap */
-
- if ((i = ip->ip_end - q->ip_off + 1) < ip->ip_len) {
- ip->ip_len -= i;
- ip->ip_end -= i;
- m_adj(mp, -i);
- } else
- ip->ip_len = 0;
- break;
- }
-
- /* enqueue whatever is left of new before successors */
-
- if (ip->ip_len != 0)
- ip_enq(ip, savq);
- else
- m_freem(mp);
- }
+ /*
+ * Find a segment which begins after this one does.
+ */
+ for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next)
+ if (q->ip_off > ip->ip_off)
+ break;
+
+ /*
+ * If there is a preceding segment, it may provide some of
+ * our data already. If so, drop the data from the incoming
+ * segment. If it provides all of our data, drop us.
+ */
+ if (q->ipf_prev != (struct ipasfrag *)fp) {
+ i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off;
+ if (i > 0) {
+ if (i >= ip->ip_len)
+ goto dropfrag;
+ m_adj(dtom(ip), i);
+ ip->ip_off += i;
+ ip->ip_len -= i;