| 286 | } |
| 287 | |
| 288 | static uint16_t |
| 289 | tcp_lro_rx_csum_fixup(struct lro_entry *le, void *l3hdr, struct tcphdr *th, |
| 290 | uint16_t tcp_data_len, uint16_t csum) |
| 291 | { |
| 292 | uint32_t c; |
| 293 | uint16_t cs; |
| 294 | |
| 295 | c = csum; |
| 296 | |
| 297 | /* Remove length from checksum. */ |
| 298 | switch (le->eh_type) { |
| 299 | #ifdef INET6 |
| 300 | case ETHERTYPE_IPV6: |
| 301 | { |
| 302 | struct ip6_hdr *ip6; |
| 303 | |
| 304 | ip6 = (struct ip6_hdr *)l3hdr; |
| 305 | if (le->append_cnt == 0) |
| 306 | cs = ip6->ip6_plen; |
| 307 | else { |
| 308 | uint32_t cx; |
| 309 | |
| 310 | cx = ntohs(ip6->ip6_plen); |
| 311 | cs = in6_cksum_pseudo(ip6, cx, ip6->ip6_nxt, 0); |
| 312 | } |
| 313 | break; |
| 314 | } |
| 315 | #endif |
| 316 | #ifdef INET |
| 317 | case ETHERTYPE_IP: |
| 318 | { |
| 319 | struct ip *ip4; |
| 320 | |
| 321 | ip4 = (struct ip *)l3hdr; |
| 322 | if (le->append_cnt == 0) |
| 323 | cs = ip4->ip_len; |
| 324 | else { |
| 325 | cs = in_addword(ntohs(ip4->ip_len) - sizeof(*ip4), |
| 326 | IPPROTO_TCP); |
| 327 | cs = in_pseudo(ip4->ip_src.s_addr, ip4->ip_dst.s_addr, |
| 328 | htons(cs)); |
| 329 | } |
| 330 | break; |
| 331 | } |
| 332 | #endif |
| 333 | default: |
| 334 | cs = 0; /* Keep compiler happy. */ |
| 335 | } |
| 336 | |
| 337 | cs = ~cs; |
| 338 | c += cs; |
| 339 | |
| 340 | /* Remove TCP header csum. */ |
| 341 | cs = ~tcp_lro_csum_th(th); |
| 342 | c += cs; |
| 343 | while (c > 0xffff) |
| 344 | c = (c >> 16) + (c & 0xffff); |
| 345 |
no test coverage detected