| 676 | } |
| 677 | |
| 678 | static void |
| 679 | tcp_lro_condense(struct tcpcb *tp, struct lro_ctrl *lc, struct lro_entry *le, int locked) |
| 680 | { |
| 681 | /* |
| 682 | * Walk through the mbuf chain we |
| 683 | * have on tap and compress/condense |
| 684 | * as required. |
| 685 | */ |
| 686 | uint32_t *ts_ptr; |
| 687 | struct mbuf *m; |
| 688 | struct tcphdr *th; |
| 689 | uint16_t tcp_data_len, csum_upd; |
| 690 | int l; |
| 691 | |
| 692 | /* |
| 693 | * First we must check the lead (m_head) |
| 694 | * we must make sure that it is *not* |
| 695 | * something that should be sent up |
| 696 | * right away (sack etc). |
| 697 | */ |
| 698 | again: |
| 699 | |
| 700 | m = le->m_head->m_nextpkt; |
| 701 | if (m == NULL) { |
| 702 | /* Just the one left */ |
| 703 | return; |
| 704 | } |
| 705 | th = tcp_lro_get_th(le, le->m_head); |
| 706 | KASSERT(th != NULL, |
| 707 | ("le:%p m:%p th comes back NULL?", le, le->m_head)); |
| 708 | l = (th->th_off << 2); |
| 709 | l -= sizeof(*th); |
| 710 | ts_ptr = (uint32_t *)(th + 1); |
| 711 | if (l != 0 && (__predict_false(l != TCPOLEN_TSTAMP_APPA) || |
| 712 | (*ts_ptr != ntohl(TCPOPT_NOP<<24|TCPOPT_NOP<<16| |
| 713 | TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP)))) { |
| 714 | /* |
| 715 | * Its not the timestamp. We can't |
| 716 | * use this guy as the head. |
| 717 | */ |
| 718 | le->m_head->m_nextpkt = m->m_nextpkt; |
| 719 | tcp_push_and_replace(tp, lc, le, m, locked); |
| 720 | goto again; |
| 721 | } |
| 722 | if ((th->th_flags & ~(TH_ACK | TH_PUSH)) != 0) { |
| 723 | /* |
| 724 | * Make sure that previously seen segements/ACKs are delivered |
| 725 | * before this segment, e.g. FIN. |
| 726 | */ |
| 727 | le->m_head->m_nextpkt = m->m_nextpkt; |
| 728 | tcp_push_and_replace(tp, lc, le, m, locked); |
| 729 | goto again; |
| 730 | } |
| 731 | while((m = le->m_head->m_nextpkt) != NULL) { |
| 732 | /* |
| 733 | * condense m into le, first |
| 734 | * pull m out of the list. |
| 735 | */ |
no test coverage detected