| 413 | |
| 414 | #ifdef INET6 |
| 415 | static int |
| 416 | checksum_ipv6(priv_p priv, struct mbuf *m, int l3_offset) |
| 417 | { |
| 418 | struct ip6_hdr *ip6; |
| 419 | struct ip6_ext *ip6e = NULL; |
| 420 | int pullup_len; |
| 421 | int hlen, plen; |
| 422 | int nxt; |
| 423 | int processed = 0; |
| 424 | |
| 425 | pullup_len = l3_offset; |
| 426 | |
| 427 | PULLUP_CHECK(m, sizeof(struct ip6_hdr)); |
| 428 | ip6 = (struct ip6_hdr *) mtodo(m, l3_offset); |
| 429 | |
| 430 | if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) |
| 431 | return (EOPNOTSUPP); |
| 432 | |
| 433 | hlen = sizeof(struct ip6_hdr); |
| 434 | plen = ntohs(ip6->ip6_plen) + hlen; |
| 435 | |
| 436 | if (m->m_pkthdr.len < l3_offset + plen) |
| 437 | return (EINVAL); |
| 438 | |
| 439 | nxt = ip6->ip6_nxt; |
| 440 | |
| 441 | for (;;) { |
| 442 | switch (nxt) |
| 443 | { |
| 444 | case IPPROTO_DSTOPTS: |
| 445 | case IPPROTO_HOPOPTS: |
| 446 | case IPPROTO_ROUTING: |
| 447 | PULLUP_CHECK(m, sizeof(struct ip6_ext)); |
| 448 | ip6e = (struct ip6_ext *) mtodo(m, l3_offset + hlen); |
| 449 | nxt = ip6e->ip6e_nxt; |
| 450 | hlen += (ip6e->ip6e_len + 1) << 3; |
| 451 | pullup_len = l3_offset + hlen; |
| 452 | break; |
| 453 | |
| 454 | case IPPROTO_AH: |
| 455 | PULLUP_CHECK(m, sizeof(struct ip6_ext)); |
| 456 | ip6e = (struct ip6_ext *) mtodo(m, l3_offset + hlen); |
| 457 | nxt = ip6e->ip6e_nxt; |
| 458 | hlen += (ip6e->ip6e_len + 2) << 2; |
| 459 | pullup_len = l3_offset + hlen; |
| 460 | break; |
| 461 | |
| 462 | case IPPROTO_FRAGMENT: |
| 463 | /* We can not calculate a checksum fragmented packets */ |
| 464 | m->m_pkthdr.csum_flags &= ~(CSUM_TCP_IPV6|CSUM_UDP_IPV6); |
| 465 | return (0); |
| 466 | |
| 467 | default: |
| 468 | goto loopend; |
| 469 | } |
| 470 | |
| 471 | if (nxt == 0) |
| 472 | return (EINVAL); |
no test coverage detected