+static void tcp_enqueue_data(struct pipe *b, struct pkt *p)
+{
+ struct pkt *q, *prev, *new;
+ u32 last_seq;
+
+ DBG("DATA:");
+ if (tcp_seq_lt(b->last_acked_seq, p->seq) && p->seq - b->last_acked_seq >= 0x40000)
+ {
+ DBG(" OUT OF WINDOW (last-ack=%u)\n", b->last_acked_seq);
+ pkt_free(p);
+ return;
+ }
+ prev = (struct pkt *) &b->queue.head;
+ last_seq = b->last_acked_seq;
+ while (p)
+ {
+ if (tcp_seq_lt(p->seq, last_seq))
+ {
+ if (tcp_seq_le(p->seq + pkt_len(p), last_seq))
+ {
+ DBG(" have\n");
+ pkt_free(p);
+ return;
+ }
+ pkt_pop(p, p->seq + pkt_len(p) - last_seq);
+ p->seq = last_seq;
+ DBG(" clip");
+ }
+ q = list_next(&b->queue, &prev->n);
+ if (q && tcp_seq_le(q->seq, p->seq))
+ {
+ /* next packet starts before us => skip it */
+ prev = q;
+ last_seq = q->seq + pkt_len(q);
+ }
+ else
+ {
+ new = NULL;
+ if (q && tcp_seq_lt(q->seq, p->seq + pkt_len(p)))
+ {
+ /* overlap with next packet => split */
+ DBG(" split");
+ uns keeplen = q->seq - p->seq;
+ uns newlen = pkt_len(p) - keeplen;
+ new = pkt_new(0, newlen);
+ memcpy(pkt_append(new, newlen), pkt_unappend(p, newlen), newlen);
+ new->seq = p->seq + keeplen;
+ }
+ DBG(" insert");
+ list_insert(&p->n, &prev->n);
+ prev = p;
+ last_seq = p->seq + pkt_len(p);
+ p = new;
+ }
+ }
+ DBG("\n");
+}
+