* Set up IP options in pcb for insertion in output packets. Store in mbuf * with pointer in pcbopt, adding pseudo-option with destination address if * source routed. */
| 598 | * source routed. |
| 599 | */ |
| 600 | int |
| 601 | ip_pcbopts(struct inpcb *inp, int optname, struct mbuf *m) |
| 602 | { |
| 603 | int cnt, optlen; |
| 604 | u_char *cp; |
| 605 | struct mbuf **pcbopt; |
| 606 | u_char opt; |
| 607 | |
| 608 | INP_WLOCK_ASSERT(inp); |
| 609 | |
| 610 | pcbopt = &inp->inp_options; |
| 611 | |
| 612 | /* turn off any old options */ |
| 613 | if (*pcbopt) |
| 614 | (void)m_free(*pcbopt); |
| 615 | *pcbopt = NULL; |
| 616 | if (m == NULL || m->m_len == 0) { |
| 617 | /* |
| 618 | * Only turning off any previous options. |
| 619 | */ |
| 620 | if (m != NULL) |
| 621 | (void)m_free(m); |
| 622 | return (0); |
| 623 | } |
| 624 | |
| 625 | if (m->m_len % sizeof(int32_t)) |
| 626 | goto bad; |
| 627 | /* |
| 628 | * IP first-hop destination address will be stored before actual |
| 629 | * options; move other options back and clear it when none present. |
| 630 | */ |
| 631 | if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN]) |
| 632 | goto bad; |
| 633 | cnt = m->m_len; |
| 634 | m->m_len += sizeof(struct in_addr); |
| 635 | cp = mtod(m, u_char *) + sizeof(struct in_addr); |
| 636 | bcopy(mtod(m, void *), cp, (unsigned)cnt); |
| 637 | bzero(mtod(m, void *), sizeof(struct in_addr)); |
| 638 | |
| 639 | for (; cnt > 0; cnt -= optlen, cp += optlen) { |
| 640 | opt = cp[IPOPT_OPTVAL]; |
| 641 | if (opt == IPOPT_EOL) |
| 642 | break; |
| 643 | if (opt == IPOPT_NOP) |
| 644 | optlen = 1; |
| 645 | else { |
| 646 | if (cnt < IPOPT_OLEN + sizeof(*cp)) |
| 647 | goto bad; |
| 648 | optlen = cp[IPOPT_OLEN]; |
| 649 | if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) |
| 650 | goto bad; |
| 651 | } |
| 652 | switch (opt) { |
| 653 | default: |
| 654 | break; |
| 655 | |
| 656 | case IPOPT_LSRR: |
| 657 | case IPOPT_SSRR: |
no test coverage detected