- if (fp == NULL) { /* first fragment of datagram in */
-
- /* set up reass.q header: enq it, set up as head of frag
- chain, set a timer value, and move in ip header */
-
- if ((m = m_get(1)) == NULL) { /* allocate an mbuf */
- m_freem(mp);
- return;
- }
-
- 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;
- }
+ /*
+ * Look for queue of fragments
+ * of this datagram.
+ */
+ for (fp = ipq.next; fp != &ipq; fp = fp->next)
+ 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 &&
+ ip->ip_p == fp->ipq_p)
+ goto found;
+ fp = 0;
+found:
+
+ /*
+ * Adjust ip_len to not reflect header,
+ * set ip_mff if more fragments are expected,
+ * convert offset of this to bytes.
+ */
+ ip->ip_len -= hlen;
+ ((struct ipasfrag *)ip)->ipf_mff = 0;
+ if (ip->ip_off & IP_MF)
+ ((struct ipasfrag *)ip)->ipf_mff = 1;
+ ip->ip_off <<= 3;
+
+ /*
+ * If datagram marked as having more fragments
+ * or if this is not the first fragment,
+ * attempt reassembly; if it succeeds, proceed.
+ */
+ if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) {
+ ip = ip_reass((struct ipasfrag *)ip, fp);
+ if (ip == 0)
+ return;
+ hlen = ip->ip_hl << 2;
+ m = dtom(ip);
+ } else
+ if (fp)
+ (void) ip_freef(fp);
+ (*protosw[ip_protox[ip->ip_p]].pr_input)(m);
+}