/** * Insert segment into the list (segments covered with new one will be deleted) * * Called from tcp_receive() */ static void tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next) { struct tcp_seg *old_seg; if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { /* received segment overlaps all following segments */ tcp_segs_free(next); next = NULL; } else { /* delete some following segments oos queue may have segments with FIN flag */ while (next && TCP_SEQ_GEQ((seqno + cseg->len), (next->tcphdr->seqno + next->len))) { /* cseg with FIN already processed */ if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { TCPH_FLAGS_SET(cseg->tcphdr, TCPH_FLAGS(cseg->tcphdr) | TCP_FIN); } old_seg = next; next = next->next; tcp_seg_free(old_seg); } if (next && TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) { /* We need to trim the incoming segment. */ cseg->len = (u16_t)(next->tcphdr->seqno - seqno); pbuf_realloc(cseg->p, cseg->len); } } cseg->next = next; }
/** * Update the state that tracks the available window space to advertise. * * Returns how much extra window would be advertised if we sent an * update now. */ u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb) { u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd; if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + LWIP_MIN((TCP_WND / 2), pcb->mss))) { /* we can advertise more window */ pcb->rcv_ann_wnd = pcb->rcv_wnd; return new_right_edge - pcb->rcv_ann_right_edge; } else { if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) { /* Can happen due to other end sending out of advertised window, * but within actual available (but not yet advertised) window */ pcb->rcv_ann_wnd = 0; } else { /* keep the right edge of window constant */ pcb->rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt; } return 0; } }