* Resolve an IP address into an ethernet address - heavy version. * Used internally by arpresolve(). * We have already checked that we can't use an existing lle without * modification so we have to acquire an LLE_EXCLUSIVE lle lock. * * On success, desten and pflags are filled in and the function returns 0; * If the packet must be held pending resolution, we return EWOULDBLOCK * On other er
| 470 | * Note that m_freem() handles NULL. |
| 471 | */ |
| 472 | static int |
| 473 | arpresolve_full(struct ifnet *ifp, int is_gw, int flags, struct mbuf *m, |
| 474 | const struct sockaddr *dst, u_char *desten, uint32_t *pflags, |
| 475 | struct llentry **plle) |
| 476 | { |
| 477 | struct llentry *la = NULL, *la_tmp; |
| 478 | struct mbuf *curr = NULL; |
| 479 | struct mbuf *next = NULL; |
| 480 | int error, renew; |
| 481 | char *lladdr; |
| 482 | int ll_len; |
| 483 | |
| 484 | NET_EPOCH_ASSERT(); |
| 485 | |
| 486 | if (pflags != NULL) |
| 487 | *pflags = 0; |
| 488 | if (plle != NULL) |
| 489 | *plle = NULL; |
| 490 | |
| 491 | if ((flags & LLE_CREATE) == 0) |
| 492 | la = lla_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst); |
| 493 | if (la == NULL && (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) { |
| 494 | la = lltable_alloc_entry(LLTABLE(ifp), 0, dst); |
| 495 | if (la == NULL) { |
| 496 | char addrbuf[INET_ADDRSTRLEN]; |
| 497 | |
| 498 | log(LOG_DEBUG, |
| 499 | "arpresolve: can't allocate llinfo for %s on %s\n", |
| 500 | inet_ntoa_r(SIN(dst)->sin_addr, addrbuf), |
| 501 | if_name(ifp)); |
| 502 | m_freem(m); |
| 503 | return (EINVAL); |
| 504 | } |
| 505 | |
| 506 | IF_AFDATA_WLOCK(ifp); |
| 507 | LLE_WLOCK(la); |
| 508 | la_tmp = lla_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst); |
| 509 | /* Prefer ANY existing lle over newly-created one */ |
| 510 | if (la_tmp == NULL) |
| 511 | lltable_link_entry(LLTABLE(ifp), la); |
| 512 | IF_AFDATA_WUNLOCK(ifp); |
| 513 | if (la_tmp != NULL) { |
| 514 | lltable_free_entry(LLTABLE(ifp), la); |
| 515 | la = la_tmp; |
| 516 | } |
| 517 | } |
| 518 | if (la == NULL) { |
| 519 | m_freem(m); |
| 520 | return (EINVAL); |
| 521 | } |
| 522 | |
| 523 | if ((la->la_flags & LLE_VALID) && |
| 524 | ((la->la_flags & LLE_STATIC) || la->la_expire > time_uptime)) { |
| 525 | if (flags & LLE_ADDRONLY) { |
| 526 | lladdr = la->ll_addr; |
| 527 | ll_len = ifp->if_addrlen; |
| 528 | } else { |
| 529 | lladdr = la->r_linkdata; |
no test coverage detected