* Called in route_output when rtm_flags contains RTF_LLDATA. */
| 676 | * Called in route_output when rtm_flags contains RTF_LLDATA. |
| 677 | */ |
| 678 | int |
| 679 | lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) |
| 680 | { |
| 681 | struct sockaddr_dl *dl = |
| 682 | (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY]; |
| 683 | struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST]; |
| 684 | struct ifnet *ifp; |
| 685 | struct lltable *llt; |
| 686 | struct llentry *lle, *lle_tmp; |
| 687 | uint8_t linkhdr[LLE_MAX_LINKHDR]; |
| 688 | size_t linkhdrsize; |
| 689 | int lladdr_off; |
| 690 | u_int laflags = 0; |
| 691 | int error; |
| 692 | |
| 693 | if (dl == NULL || dl->sdl_family != AF_LINK) |
| 694 | return (EINVAL); |
| 695 | |
| 696 | /* XXX: should be ntohs() */ |
| 697 | ifp = ifnet_byindex(dl->sdl_index); |
| 698 | if (ifp == NULL) { |
| 699 | log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n", |
| 700 | __func__, dl->sdl_index); |
| 701 | return EINVAL; |
| 702 | } |
| 703 | |
| 704 | /* XXX linked list may be too expensive */ |
| 705 | LLTABLE_LIST_RLOCK(); |
| 706 | SLIST_FOREACH(llt, &V_lltables, llt_link) { |
| 707 | if (llt->llt_af == dst->sa_family && |
| 708 | llt->llt_ifp == ifp) |
| 709 | break; |
| 710 | } |
| 711 | LLTABLE_LIST_RUNLOCK(); |
| 712 | if (llt == NULL) |
| 713 | return (ESRCH); |
| 714 | |
| 715 | error = 0; |
| 716 | |
| 717 | switch (rtm->rtm_type) { |
| 718 | case RTM_ADD: |
| 719 | /* Add static LLE */ |
| 720 | laflags = 0; |
| 721 | if (rtm->rtm_rmx.rmx_expire == 0) |
| 722 | laflags = LLE_STATIC; |
| 723 | lle = lltable_alloc_entry(llt, laflags, dst); |
| 724 | if (lle == NULL) |
| 725 | return (ENOMEM); |
| 726 | |
| 727 | linkhdrsize = sizeof(linkhdr); |
| 728 | if (lltable_calc_llheader(ifp, dst->sa_family, LLADDR(dl), |
| 729 | linkhdr, &linkhdrsize, &lladdr_off) != 0) |
| 730 | return (EINVAL); |
| 731 | lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, |
| 732 | lladdr_off); |
| 733 | if ((rtm->rtm_flags & RTF_ANNOUNCE)) |
| 734 | lle->la_flags |= LLE_PUB; |
| 735 | lle->la_expire = rtm->rtm_rmx.rmx_expire; |
no test coverage detected