| 480 | } |
| 481 | |
| 482 | static void |
| 483 | tcp_flush_out_le(struct tcpcb *tp, struct lro_ctrl *lc, struct lro_entry *le, int locked) |
| 484 | { |
| 485 | if (le->append_cnt > 1) { |
| 486 | struct tcphdr *th; |
| 487 | uint16_t p_len; |
| 488 | |
| 489 | p_len = htons(le->p_len); |
| 490 | switch (le->eh_type) { |
| 491 | #ifdef INET6 |
| 492 | case ETHERTYPE_IPV6: |
| 493 | { |
| 494 | struct ip6_hdr *ip6; |
| 495 | |
| 496 | ip6 = le->le_ip6; |
| 497 | ip6->ip6_plen = p_len; |
| 498 | th = (struct tcphdr *)(ip6 + 1); |
| 499 | le->m_head->m_pkthdr.csum_flags = CSUM_DATA_VALID | |
| 500 | CSUM_PSEUDO_HDR; |
| 501 | le->p_len += ETHER_HDR_LEN + sizeof(*ip6); |
| 502 | break; |
| 503 | } |
| 504 | #endif |
| 505 | #ifdef INET |
| 506 | case ETHERTYPE_IP: |
| 507 | { |
| 508 | struct ip *ip4; |
| 509 | uint32_t cl; |
| 510 | uint16_t c; |
| 511 | |
| 512 | ip4 = le->le_ip4; |
| 513 | /* Fix IP header checksum for new length. */ |
| 514 | c = ~ip4->ip_sum; |
| 515 | cl = c; |
| 516 | c = ~ip4->ip_len; |
| 517 | cl += c + p_len; |
| 518 | while (cl > 0xffff) |
| 519 | cl = (cl >> 16) + (cl & 0xffff); |
| 520 | c = cl; |
| 521 | ip4->ip_sum = ~c; |
| 522 | ip4->ip_len = p_len; |
| 523 | th = (struct tcphdr *)(ip4 + 1); |
| 524 | le->m_head->m_pkthdr.csum_flags = CSUM_DATA_VALID | |
| 525 | CSUM_PSEUDO_HDR | CSUM_IP_CHECKED | CSUM_IP_VALID; |
| 526 | le->p_len += ETHER_HDR_LEN; |
| 527 | break; |
| 528 | } |
| 529 | #endif |
| 530 | default: |
| 531 | th = NULL; /* Keep compiler happy. */ |
| 532 | } |
| 533 | le->m_head->m_pkthdr.csum_data = 0xffff; |
| 534 | le->m_head->m_pkthdr.len = le->p_len; |
| 535 | |
| 536 | /* Incorporate the latest ACK into the TCP header. */ |
| 537 | th->th_ack = le->ack_seq; |
| 538 | th->th_win = le->window; |
| 539 | /* Incorporate latest timestamp into the TCP header. */ |
no test coverage detected