Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/if_ether.c
Show First 20 Lines • Show All 413 Lines • ▼ Show 20 Lines | |||||
* modification so we have to acquire LLE_EXCLUSIVE lle lock. | * modification so we have to acquire LLE_EXCLUSIVE lle lock. | ||||
* | * | ||||
* On success, desten and flags are filled in and the function returns 0; | * On success, desten and flags are filled in and the function returns 0; | ||||
* If the packet must be held pending resolution, we return EWOULDBLOCK | * If the packet must be held pending resolution, we return EWOULDBLOCK | ||||
* On other errors, we return the corresponding error code. | * On other errors, we return the corresponding error code. | ||||
* Note that m_freem() handles NULL. | * Note that m_freem() handles NULL. | ||||
*/ | */ | ||||
static int | static int | ||||
arpresolve_full(struct ifnet *ifp, int is_gw, int flags, struct mbuf *m, | arpresolve_full(struct ifnet *ifp, int flags, struct mbuf *m, | ||||
const struct sockaddr *dst, u_char *desten, uint32_t *pflags) | const struct in_addr *dst, u_char *desten, uint32_t *pflags) | ||||
{ | { | ||||
struct llentry *la = NULL, *la_tmp; | struct llentry *la = NULL, *la_tmp; | ||||
struct mbuf *curr = NULL; | struct mbuf *curr = NULL; | ||||
struct mbuf *next = NULL; | struct mbuf *next = NULL; | ||||
int error, renew; | int error, renew; | ||||
char *lladdr; | char *lladdr; | ||||
int ll_len; | int ll_len; | ||||
if (pflags != NULL) | if (pflags != NULL) | ||||
*pflags = 0; | *pflags = 0; | ||||
if ((flags & LLE_CREATE) == 0) { | if ((flags & LLE_CREATE) == 0) { | ||||
IF_AFDATA_RLOCK(ifp); | IF_AFDATA_RLOCK(ifp); | ||||
la = lla_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst); | la = arp_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst); | ||||
IF_AFDATA_RUNLOCK(ifp); | IF_AFDATA_RUNLOCK(ifp); | ||||
} | } | ||||
if (la == NULL && (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) { | if (la == NULL && (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) { | ||||
la = lltable_alloc_entry(LLTABLE(ifp), 0, dst); | la = arp_alloc(LLTABLE(ifp), 0, dst); | ||||
if (la == NULL) { | if (la == NULL) { | ||||
log(LOG_DEBUG, | log(LOG_DEBUG, | ||||
"arpresolve: can't allocate llinfo for %s on %s\n", | "arpresolve: can't allocate llinfo for %s on %s\n", | ||||
inet_ntoa(SIN(dst)->sin_addr), if_name(ifp)); | inet_ntoa(SIN(dst)->sin_addr), if_name(ifp)); | ||||
m_freem(m); | m_freem(m); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
IF_AFDATA_WLOCK(ifp); | IF_AFDATA_WLOCK(ifp); | ||||
LLE_WLOCK(la); | LLE_WLOCK(la); | ||||
la_tmp = lla_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst); | la_tmp = arp_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst); | ||||
/* Prefer ANY existing lle over newly-created one */ | /* Prefer ANY existing lle over newly-created one */ | ||||
if (la_tmp == NULL) | if (la_tmp == NULL) | ||||
lltable_link_entry(LLTABLE(ifp), la); | lltable_link_entry(LLTABLE(ifp), la); | ||||
IF_AFDATA_WUNLOCK(ifp); | IF_AFDATA_WUNLOCK(ifp); | ||||
if (la_tmp != NULL) { | if (la_tmp != NULL) { | ||||
lltable_free_entry(LLTABLE(ifp), la); | lltable_free_entry(LLTABLE(ifp), la); | ||||
la = la_tmp; | la = la_tmp; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | arpresolve_full(struct ifnet *ifp, int flags, struct mbuf *m, | ||||
* Return EWOULDBLOCK if we have tried less than arp_maxtries. It | * Return EWOULDBLOCK if we have tried less than arp_maxtries. It | ||||
* will be masked by ether_output(). Return EHOSTDOWN/EHOSTUNREACH | * will be masked by ether_output(). Return EHOSTDOWN/EHOSTUNREACH | ||||
* if we have already sent arp_maxtries ARP requests. Retransmit the | * if we have already sent arp_maxtries ARP requests. Retransmit the | ||||
* ARP request, but not faster than one request per second. | * ARP request, but not faster than one request per second. | ||||
*/ | */ | ||||
if (la->la_asked < V_arp_maxtries) | if (la->la_asked < V_arp_maxtries) | ||||
error = EWOULDBLOCK; /* First request. */ | error = EWOULDBLOCK; /* First request. */ | ||||
else | else | ||||
error = is_gw != 0 ? EHOSTUNREACH : EHOSTDOWN; | error = EHOSTDOWN; | ||||
if (renew) { | if (renew) { | ||||
int canceled; | int canceled; | ||||
LLE_ADDREF(la); | LLE_ADDREF(la); | ||||
la->la_expire = time_uptime; | la->la_expire = time_uptime; | ||||
canceled = callout_reset(&la->lle_timer, hz * V_arpt_down, | canceled = callout_reset(&la->lle_timer, hz * V_arpt_down, | ||||
arptimer, la); | arptimer, la); | ||||
if (canceled) | if (canceled) | ||||
LLE_REMREF(la); | LLE_REMREF(la); | ||||
la->la_asked++; | la->la_asked++; | ||||
LLE_WUNLOCK(la); | LLE_WUNLOCK(la); | ||||
arprequest(ifp, NULL, &SIN(dst)->sin_addr, NULL); | arprequest(ifp, NULL, dst, NULL); | ||||
return (error); | return (error); | ||||
} | } | ||||
LLE_WUNLOCK(la); | LLE_WUNLOCK(la); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Resolve an IP address into an ethernet address. | * Resolve an IP address into an ethernet address. | ||||
*/ | */ | ||||
int | int | ||||
arpresolve_addr(struct ifnet *ifp, int flags, const struct sockaddr *dst, | arpresolve_addr(struct ifnet *ifp, int flags, const struct sockaddr *dst, | ||||
char *desten, uint32_t *pflags) | char *desten, uint32_t *pflags) | ||||
{ | { | ||||
const struct sockaddr_in *dst4; | |||||
int error; | int error; | ||||
flags |= LLE_ADDRONLY; | flags |= LLE_ADDRONLY; | ||||
error = arpresolve_full(ifp, 0, flags, NULL, dst, desten, pflags); | dst4 = (const struct sockaddr_in *)dst; | ||||
error = arpresolve_full(ifp, flags, NULL, &dst4->sin_addr, desten, | |||||
pflags); | |||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Lookups link header based on an IP address. | * Lookups link header based on an IP address. | ||||
* On input: | * On input: | ||||
* ifp is the interface we use | * ifp is the interface we use | ||||
* is_gw != 0 if @dst represents gateway to some destination | * is_gw != 0 if @dst represents gateway to some destination | ||||
* m is the mbuf. May be NULL if we don't have a packet. | * m is the mbuf. May be NULL if we don't have a packet. | ||||
* dst is the next hop, | * dst is the next hop, | ||||
* desten is the storage to put LL header. | * desten is the storage to put LL header. | ||||
* flags returns subset of lle flags: LLE_VALID | LLE_IFADDR | * flags returns subset of lle flags: LLE_VALID | LLE_IFADDR | ||||
* | * | ||||
* On success, full/partial link header and flags are filled in and | * On success, full/partial link header and flags are filled in and | ||||
* the function returns 0. | * the function returns 0. | ||||
* If the packet must be held pending resolution, we return EWOULDBLOCK | * If the packet must be held pending resolution, we return EWOULDBLOCK | ||||
* On other errors, we return the corresponding error code. | * On other errors, we return the corresponding error code. | ||||
* Note that m_freem() handles NULL. | * Note that m_freem() handles NULL. | ||||
*/ | */ | ||||
int | int | ||||
arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m, | arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m, | ||||
const struct sockaddr *dst, u_char *desten, uint32_t *pflags) | const struct sockaddr *dst, u_char *desten, uint32_t *pflags) | ||||
{ | { | ||||
struct llentry *la = 0; | const struct sockaddr_in *dst4; | ||||
int error; | |||||
if (pflags != NULL) | if (pflags != NULL) | ||||
*pflags = 0; | *pflags = 0; | ||||
if (m != NULL) { | if (m != NULL) { | ||||
if (m->m_flags & M_BCAST) { | if (m->m_flags & M_BCAST) { | ||||
/* broadcast */ | /* broadcast */ | ||||
(void)memcpy(desten, | (void)memcpy(desten, | ||||
ifp->if_broadcastaddr, ifp->if_addrlen); | ifp->if_broadcastaddr, ifp->if_addrlen); | ||||
return (0); | return (0); | ||||
} | } | ||||
if (m->m_flags & M_MCAST) { | if (m->m_flags & M_MCAST) { | ||||
/* multicast */ | /* multicast */ | ||||
ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten); | ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten); | ||||
return (0); | return (0); | ||||
} | } | ||||
} | } | ||||
dst4 = (const struct sockaddr_in *)dst; | |||||
error = in_resolve_lla(ifp, m, &dst4->sin_addr, desten, pflags); | |||||
if (error == EHOSTDOWN && is_gw != 0) | |||||
error = EHOSTUNREACH; | |||||
return (error); | |||||
} | |||||
/* | |||||
* Lookups link header based on an IP address. | |||||
* On input: | |||||
* ifp is the interface we use | |||||
* m is the mbuf. May be NULL if we don't have a packet. | |||||
* dst is the next hop, | |||||
* desten is the storage to put LL header. | |||||
* flags returns subset of lle flags: LLE_VALID | LLE_IFADDR | |||||
* | |||||
* On success, full/partial link header and flags are filled in and | |||||
* the function returns 0. | |||||
* If the packet must be held pending resolution, we return EWOULDBLOCK | |||||
* On other errors, we return the corresponding error code. | |||||
* Note that m_freem() handles NULL. | |||||
*/ | |||||
int | |||||
in_resolve_lla(struct ifnet *ifp, struct mbuf *m, const struct in_addr *dst, | |||||
u_char *desten, uint32_t *pflags) | |||||
{ | |||||
struct llentry *la = 0; | |||||
IF_AFDATA_RLOCK(ifp); | IF_AFDATA_RLOCK(ifp); | ||||
la = lla_lookup(LLTABLE(ifp), LLE_UNLOCKED, dst); | la = arp_lookup(LLTABLE(ifp), LLE_UNLOCKED, dst); | ||||
if (la != NULL && (la->r_flags & RLLE_VALID) != 0) { | if (la != NULL && (la->r_flags & RLLE_VALID) != 0) { | ||||
/* Entry found, let's copy lle info */ | /* Entry found, let's copy lle info */ | ||||
bcopy(la->r_linkdata, desten, la->r_hdrlen); | bcopy(la->r_linkdata, desten, la->r_hdrlen); | ||||
if (pflags != NULL) | if (pflags != NULL) | ||||
*pflags = LLE_VALID | (la->r_flags & RLLE_IFADDR); | *pflags = LLE_VALID | (la->r_flags & RLLE_IFADDR); | ||||
/* Check if we have feedback request from arptimer() */ | /* Check if we have feedback request from arptimer() */ | ||||
if (la->r_skip_req != 0) { | if (la->r_skip_req != 0) { | ||||
LLE_REQ_LOCK(la); | LLE_REQ_LOCK(la); | ||||
la->r_skip_req = 0; /* Notify that entry was used */ | la->r_skip_req = 0; /* Notify that entry was used */ | ||||
LLE_REQ_UNLOCK(la); | LLE_REQ_UNLOCK(la); | ||||
} | } | ||||
IF_AFDATA_RUNLOCK(ifp); | IF_AFDATA_RUNLOCK(ifp); | ||||
return (0); | return (0); | ||||
} | } | ||||
IF_AFDATA_RUNLOCK(ifp); | IF_AFDATA_RUNLOCK(ifp); | ||||
return (arpresolve_full(ifp, is_gw, la == NULL ? LLE_CREATE : 0, m, dst, | return (arpresolve_full(ifp, la == NULL ? LLE_CREATE : 0, m, dst, | ||||
desten, pflags)); | desten, pflags)); | ||||
} | } | ||||
/* | /* | ||||
* Common length and type checks are done here, | * Common length and type checks are done here, | ||||
* then the protocol-specific routine is called. | * then the protocol-specific routine is called. | ||||
*/ | */ | ||||
static void | static void | ||||
▲ Show 20 Lines • Show All 125 Lines • ▼ Show 20 Lines | in_arpinput(struct mbuf *m) | ||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
struct in_ifaddr *ia; | struct in_ifaddr *ia; | ||||
struct sockaddr sa; | struct sockaddr sa; | ||||
struct in_addr isaddr, itaddr, myaddr; | struct in_addr isaddr, itaddr, myaddr; | ||||
u_int8_t *enaddr = NULL; | u_int8_t *enaddr = NULL; | ||||
int op; | int op; | ||||
int bridged = 0, is_bridge = 0; | int bridged = 0, is_bridge = 0; | ||||
int carped; | int carped; | ||||
struct sockaddr_in sin; | |||||
struct sockaddr *dst; | |||||
struct nhop4_basic nh4; | struct nhop4_basic nh4; | ||||
uint8_t linkhdr[LLE_MAX_LINKHDR]; | uint8_t linkhdr[LLE_MAX_LINKHDR]; | ||||
struct route ro; | struct route ro; | ||||
size_t linkhdrsize; | size_t linkhdrsize; | ||||
int lladdr_off; | int lladdr_off; | ||||
int error; | int error; | ||||
sin.sin_len = sizeof(struct sockaddr_in); | |||||
sin.sin_family = AF_INET; | |||||
sin.sin_addr.s_addr = 0; | |||||
if (ifp->if_bridge) | if (ifp->if_bridge) | ||||
bridged = 1; | bridged = 1; | ||||
if (ifp->if_type == IFT_BRIDGE) | if (ifp->if_type == IFT_BRIDGE) | ||||
is_bridge = 1; | is_bridge = 1; | ||||
/* | /* | ||||
* We already have checked that mbuf contains enough contiguous data | * We already have checked that mbuf contains enough contiguous data | ||||
* to hold entire arp message according to the arp header. | * to hold entire arp message according to the arp header. | ||||
▲ Show 20 Lines • Show All 133 Lines • ▼ Show 20 Lines | ARP_LOG(LOG_ERR, "%*D is using my IP address %s on %s!\n", | ||||
inet_ntoa(isaddr), ifp->if_xname); | inet_ntoa(isaddr), ifp->if_xname); | ||||
itaddr = myaddr; | itaddr = myaddr; | ||||
ARPSTAT_INC(dupips); | ARPSTAT_INC(dupips); | ||||
goto reply; | goto reply; | ||||
} | } | ||||
if (ifp->if_flags & IFF_STATICARP) | if (ifp->if_flags & IFF_STATICARP) | ||||
goto reply; | goto reply; | ||||
bzero(&sin, sizeof(sin)); | |||||
sin.sin_len = sizeof(struct sockaddr_in); | |||||
sin.sin_family = AF_INET; | |||||
sin.sin_addr = isaddr; | |||||
dst = (struct sockaddr *)&sin; | |||||
IF_AFDATA_RLOCK(ifp); | IF_AFDATA_RLOCK(ifp); | ||||
la = lla_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst); | la = arp_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, &isaddr); | ||||
IF_AFDATA_RUNLOCK(ifp); | IF_AFDATA_RUNLOCK(ifp); | ||||
if (la != NULL) | if (la != NULL) | ||||
arp_check_update_lle(ah, isaddr, ifp, bridged, la); | arp_check_update_lle(ah, isaddr, ifp, bridged, la); | ||||
else if (itaddr.s_addr == myaddr.s_addr) { | else if (itaddr.s_addr == myaddr.s_addr) { | ||||
/* | /* | ||||
* Request/reply to our address, but no lle exists yet. | * Request/reply to our address, but no lle exists yet. | ||||
* Calculate full link prepend to use in lle. | * Calculate full link prepend to use in lle. | ||||
*/ | */ | ||||
linkhdrsize = sizeof(linkhdr); | linkhdrsize = sizeof(linkhdr); | ||||
if (lltable_calc_llheader(ifp, AF_INET, ar_sha(ah), linkhdr, | if (lltable_calc_llheader(ifp, AF_INET, ar_sha(ah), linkhdr, | ||||
&linkhdrsize, &lladdr_off) != 0) | &linkhdrsize, &lladdr_off) != 0) | ||||
goto reply; | goto reply; | ||||
/* Allocate new entry */ | /* Allocate new entry */ | ||||
la = lltable_alloc_entry(LLTABLE(ifp), 0, dst); | la = arp_alloc(LLTABLE(ifp), 0, &isaddr); | ||||
if (la == NULL) { | if (la == NULL) { | ||||
/* | /* | ||||
* lle creation may fail if source address belongs | * lle creation may fail if source address belongs | ||||
* to non-directly connected subnet. However, we | * to non-directly connected subnet. However, we | ||||
* will try to answer the request instead of dropping | * will try to answer the request instead of dropping | ||||
* frame. | * frame. | ||||
*/ | */ | ||||
goto reply; | goto reply; | ||||
} | } | ||||
lltable_set_entry_addr(ifp, la, linkhdr, linkhdrsize, | lltable_set_entry_addr(ifp, la, linkhdr, linkhdrsize, | ||||
lladdr_off); | lladdr_off); | ||||
IF_AFDATA_WLOCK(ifp); | IF_AFDATA_WLOCK(ifp); | ||||
LLE_WLOCK(la); | LLE_WLOCK(la); | ||||
la_tmp = lla_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst); | la_tmp = arp_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, &isaddr); | ||||
/* | /* | ||||
* Check if lle still does not exists. | * Check if lle still does not exists. | ||||
* If it does, that means that we either | * If it does, that means that we either | ||||
* 1) have configured it explicitly, via | * 1) have configured it explicitly, via | ||||
* 1a) 'arp -s' static entry or | * 1a) 'arp -s' static entry or | ||||
* 1b) interface address static record | * 1b) interface address static record | ||||
* or | * or | ||||
Show All 30 Lines | reply: | ||||
if (itaddr.s_addr == myaddr.s_addr) { | if (itaddr.s_addr == myaddr.s_addr) { | ||||
/* Shortcut.. the receiving interface is the target. */ | /* Shortcut.. the receiving interface is the target. */ | ||||
(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); | (void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); | ||||
(void)memcpy(ar_sha(ah), enaddr, ah->ar_hln); | (void)memcpy(ar_sha(ah), enaddr, ah->ar_hln); | ||||
} else { | } else { | ||||
struct llentry *lle = NULL; | struct llentry *lle = NULL; | ||||
sin.sin_addr = itaddr; | |||||
IF_AFDATA_RLOCK(ifp); | IF_AFDATA_RLOCK(ifp); | ||||
lle = lla_lookup(LLTABLE(ifp), 0, (struct sockaddr *)&sin); | lle = arp_lookup(LLTABLE(ifp), 0, &itaddr); | ||||
IF_AFDATA_RUNLOCK(ifp); | IF_AFDATA_RUNLOCK(ifp); | ||||
if ((lle != NULL) && (lle->la_flags & LLE_PUB)) { | if ((lle != NULL) && (lle->la_flags & LLE_PUB)) { | ||||
(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); | (void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); | ||||
(void)memcpy(ar_sha(ah), lle->ll_addr, ah->ar_hln); | (void)memcpy(ar_sha(ah), lle->ll_addr, ah->ar_hln); | ||||
LLE_RUNLOCK(lle); | LLE_RUNLOCK(lle); | ||||
} else { | } else { | ||||
▲ Show 20 Lines • Show All 217 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Add pernament link-layer record for given interface address. | * Add pernament link-layer record for given interface address. | ||||
*/ | */ | ||||
static __noinline void | static __noinline void | ||||
arp_add_ifa_lle(struct ifnet *ifp, const struct sockaddr *dst) | arp_add_ifa_lle(struct ifnet *ifp, const struct sockaddr *dst) | ||||
{ | { | ||||
struct llentry *lle, *lle_tmp; | struct llentry *lle, *lle_tmp; | ||||
struct in_addr in; | |||||
/* | /* | ||||
* Interface address LLE record is considered static | * Interface address LLE record is considered static | ||||
* because kernel code relies on LLE_STATIC flag to check | * because kernel code relies on LLE_STATIC flag to check | ||||
* if these entries can be rewriten by arp updates. | * if these entries can be rewriten by arp updates. | ||||
*/ | */ | ||||
lle = lltable_alloc_entry(LLTABLE(ifp), LLE_IFADDR | LLE_STATIC, dst); | in = ((const struct sockaddr_in *)dst)->sin_addr; | ||||
lle = arp_alloc(LLTABLE(ifp), LLE_IFADDR | LLE_STATIC, &in); | |||||
if (lle == NULL) { | if (lle == NULL) { | ||||
log(LOG_INFO, "arp_ifinit: cannot create arp " | log(LOG_INFO, "arp_ifinit: cannot create arp " | ||||
"entry for interface address\n"); | "entry for interface address\n"); | ||||
return; | return; | ||||
} | } | ||||
IF_AFDATA_WLOCK(ifp); | IF_AFDATA_WLOCK(ifp); | ||||
LLE_WLOCK(lle); | LLE_WLOCK(lle); | ||||
/* Unlink any entry if exists */ | /* Unlink any entry if exists */ | ||||
lle_tmp = lla_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst); | lle_tmp = arp_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, &in); | ||||
if (lle_tmp != NULL) | if (lle_tmp != NULL) | ||||
lltable_unlink_entry(LLTABLE(ifp), lle_tmp); | lltable_unlink_entry(LLTABLE(ifp), lle_tmp); | ||||
lltable_link_entry(LLTABLE(ifp), lle); | lltable_link_entry(LLTABLE(ifp), lle); | ||||
IF_AFDATA_WUNLOCK(ifp); | IF_AFDATA_WUNLOCK(ifp); | ||||
if (lle_tmp != NULL) | if (lle_tmp != NULL) | ||||
EVENTHANDLER_INVOKE(lle_event, lle_tmp, LLENTRY_EXPIRED); | EVENTHANDLER_INVOKE(lle_event, lle_tmp, LLENTRY_EXPIRED); | ||||
▲ Show 20 Lines • Show All 72 Lines • Show Last 20 Lines |