|
Lines 27-33
Link Here
|
| 27 |
* SUCH DAMAGE. |
27 |
* SUCH DAMAGE. |
| 28 |
* |
28 |
* |
| 29 |
* @(#)if_ether.c 8.1 (Berkeley) 6/10/93 |
29 |
* @(#)if_ether.c 8.1 (Berkeley) 6/10/93 |
| 30 |
* $FreeBSD: src/sys/netinet/if_ether.c,v 1.127 2004/04/25 15:00:17 luigi Exp $ |
30 |
* $FreeBSD$ |
| 31 |
*/ |
31 |
*/ |
| 32 |
|
32 |
|
| 33 |
/* |
33 |
/* |
|
Lines 101-107
Link Here
|
| 101 |
static LIST_HEAD(, llinfo_arp) llinfo_arp; |
101 |
static LIST_HEAD(, llinfo_arp) llinfo_arp; |
| 102 |
|
102 |
|
| 103 |
static struct ifqueue arpintrq; |
103 |
static struct ifqueue arpintrq; |
| 104 |
static int arp_allocated; |
|
|
| 105 |
|
104 |
|
| 106 |
static int arp_maxtries = 5; |
105 |
static int arp_maxtries = 5; |
| 107 |
static int useloopback = 1; /* use loopback interface for local traffic */ |
106 |
static int useloopback = 1; /* use loopback interface for local traffic */ |
|
Lines 116-133
Link Here
|
| 116 |
&arp_proxyall, 0, ""); |
115 |
&arp_proxyall, 0, ""); |
| 117 |
|
116 |
|
| 118 |
static void arp_init(void); |
117 |
static void arp_init(void); |
| 119 |
static void arp_rtrequest(int, struct rtentry *, struct rt_addrinfo *); |
|
|
| 120 |
static void arprequest(struct ifnet *, |
118 |
static void arprequest(struct ifnet *, |
| 121 |
struct in_addr *, struct in_addr *, u_char *); |
119 |
struct in_addr *, struct in_addr *, u_char *); |
| 122 |
static void arpintr(struct mbuf *); |
120 |
static void arpintr(struct mbuf *); |
| 123 |
static void arptfree(struct llinfo_arp *); |
121 |
static void arptfree(struct llinfo_arp *); |
| 124 |
static void arptimer(void *); |
122 |
static void arptimer(void *); |
| 125 |
static struct llinfo_arp |
123 |
struct llentry *arplookup(struct ifnet *ifp, uint32_t addr, uint32_t flags); |
| 126 |
*arplookup(u_long, int, int); |
|
|
| 127 |
#ifdef INET |
124 |
#ifdef INET |
| 128 |
static void in_arpinput(struct mbuf *); |
125 |
static void in_arpinput(struct mbuf *); |
| 129 |
#endif |
126 |
#endif |
| 130 |
|
127 |
|
|
|
128 |
/*** |
| 129 |
*** |
| 130 |
*** Start of new arp support routines which should go to a separate file. |
| 131 |
*** |
| 132 |
***/ |
| 133 |
#define DEB(x) |
| 134 |
#define DDB(x) x |
| 135 |
|
| 136 |
struct llentry { |
| 137 |
struct llentry *lle_next; |
| 138 |
struct mbuf *la_hold; |
| 139 |
uint16_t flags; /* see values in if_ether.h */ |
| 140 |
uint8_t la_preempt; |
| 141 |
uint8_t la_asked; |
| 142 |
time_t expire; |
| 143 |
struct in_addr l3_addr; |
| 144 |
union { |
| 145 |
uint64_t mac_aligned; |
| 146 |
uint16_t mac16[3]; |
| 147 |
} ll_addr; |
| 148 |
}; |
| 149 |
|
| 150 |
MALLOC_DEFINE(M_ARP, "arp", "arp entries"); /* XXX will move to UMA */ |
| 151 |
|
| 152 |
int arp_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info); |
| 153 |
int sysctl_dumparp(int af, struct sysctl_req *wr); |
| 154 |
void arp_ifscrub(struct ifnet *ifp, uint32_t addr); |
| 155 |
|
| 156 |
/* |
| 157 |
* called by in_ifscrub to remove entry from the table when |
| 158 |
* the interface goes away |
| 159 |
*/ |
| 160 |
void |
| 161 |
arp_ifscrub(struct ifnet *ifp, uint32_t addr) |
| 162 |
{ |
| 163 |
arplookup(ifp, addr, LLE_DELETE | LLE_IFADDR); |
| 164 |
} |
| 165 |
|
| 166 |
/* |
| 167 |
* Find an interface address matching the ifp-addr pair. |
| 168 |
* This may replicate some of the functions of ifa_ifwithnet() |
| 169 |
*/ |
| 170 |
static struct ifaddr * |
| 171 |
find_ifa(struct ifnet *ifp, uint32_t addr) |
| 172 |
{ |
| 173 |
struct ifaddr *ifa; |
| 174 |
|
| 175 |
if (ifp == NULL) |
| 176 |
return NULL; |
| 177 |
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { |
| 178 |
if (ifa->ifa_addr->sa_family != AF_INET) |
| 179 |
continue; |
| 180 |
if (ifp->if_flags & IFF_POINTOPOINT) |
| 181 |
break; |
| 182 |
if (((addr ^ SIN(ifa->ifa_addr)->sin_addr.s_addr) & |
| 183 |
SIN(ifa->ifa_netmask)->sin_addr.s_addr ) == 0) |
| 184 |
break; /* found! */ |
| 185 |
} |
| 186 |
return ifa; |
| 187 |
} |
| 188 |
|
| 189 |
static void |
| 190 |
llentry_free(struct llentry **e) |
| 191 |
{ |
| 192 |
struct llentry *x; |
| 193 |
|
| 194 |
if (e == 0) |
| 195 |
panic("llentry_free: null ptr"); |
| 196 |
x = *e; |
| 197 |
*e = x->lle_next; |
| 198 |
if (x->la_hold) |
| 199 |
m_freem(x->la_hold); |
| 200 |
free(x, M_ARP); |
| 201 |
} |
| 202 |
|
| 203 |
/* |
| 204 |
* Add a new table at the head of the list for interface ifp |
| 205 |
*/ |
| 206 |
struct lltable * |
| 207 |
lltable_new(struct ifnet *ifp, int af) |
| 208 |
{ |
| 209 |
struct lltable *t; |
| 210 |
|
| 211 |
t = malloc(sizeof (struct lltable), M_ARP, M_DONTWAIT | M_ZERO); |
| 212 |
if (t != NULL) { |
| 213 |
t->llt_next = ifp->lltables; |
| 214 |
t->llt_af = af; |
| 215 |
ifp->lltables = t; |
| 216 |
} |
| 217 |
return t; |
| 218 |
} |
| 219 |
|
| 220 |
struct lltable ** |
| 221 |
lltable_free(struct lltable **t) |
| 222 |
{ |
| 223 |
struct lltable *x; |
| 224 |
|
| 225 |
if (t == NULL) |
| 226 |
panic("lltable_free: null ptr"); |
| 227 |
x = *t; |
| 228 |
*t = x->llt_next; |
| 229 |
free(x, M_ARP); |
| 230 |
return t; |
| 231 |
} |
| 232 |
|
| 233 |
static void |
| 234 |
newarptimer(__unused void *ignored_arg) |
| 235 |
{ |
| 236 |
struct lltable *t; |
| 237 |
struct llentry **e; |
| 238 |
struct ifnet *ifp; |
| 239 |
|
| 240 |
IFNET_RLOCK(); |
| 241 |
printf("arptimer!\n"); |
| 242 |
TAILQ_FOREACH(ifp, &ifnet, if_link) { |
| 243 |
for (t = ifp->lltables; t ; t = t->llt_next) { |
| 244 |
if (t->llt_af != AF_INET) |
| 245 |
continue; |
| 246 |
for (e = (struct llentry **)&t->lle_head; *e; ) { |
| 247 |
int kill; |
| 248 |
|
| 249 |
if ((*e)->flags & LLE_DELETED) |
| 250 |
kill = 1; |
| 251 |
else if ((*e)->flags & LLE_STATIC) |
| 252 |
kill = 0; |
| 253 |
else |
| 254 |
kill = time_second >= (*e)->expire; |
| 255 |
if (kill) |
| 256 |
llentry_free(e); |
| 257 |
else |
| 258 |
e = &((*e)->lle_next); |
| 259 |
} |
| 260 |
} |
| 261 |
} |
| 262 |
IFNET_RUNLOCK(); |
| 263 |
callout_reset(&arp_callout, arpt_prune * hz, newarptimer, NULL); |
| 264 |
} |
| 265 |
|
| 266 |
static int |
| 267 |
inet_dumparp(struct ifnet *ifp, void *head, struct sysctl_req *wr) |
| 268 |
{ |
| 269 |
struct llentry *e; |
| 270 |
int error = 0; |
| 271 |
|
| 272 |
for (e = head; e; e = e->lle_next) { |
| 273 |
struct { |
| 274 |
struct rt_msghdr rtm; |
| 275 |
struct sockaddr_inarp sin2; |
| 276 |
struct sockaddr_dl sdl; |
| 277 |
//struct sockaddr_inarp addr2; |
| 278 |
} d; |
| 279 |
|
| 280 |
DEB(printf("ifp %p index %d flags 0x%x ip %x %s\n", |
| 281 |
ifp, ifp->if_index, |
| 282 |
e->flags, |
| 283 |
ntohl(e->l3_addr.s_addr), |
| 284 |
(e->flags & LLA_VALID) ? "valid" : "incomplete");) |
| 285 |
if (e->flags & LLE_DELETED) /* skip deleted entries */ |
| 286 |
continue; |
| 287 |
/* |
| 288 |
* produce a msg made of: |
| 289 |
* struct rt_msghdr; |
| 290 |
* struct sockaddr_inarp; |
| 291 |
* struct sockaddr_dl; |
| 292 |
*/ |
| 293 |
bzero(&d, sizeof (d)); |
| 294 |
d.rtm.rtm_msglen = sizeof(d); |
| 295 |
d.sin2.sin_family = AF_INET; |
| 296 |
d.sin2.sin_len = sizeof(d.sin2); |
| 297 |
d.sin2.sin_addr.s_addr = e->l3_addr.s_addr; |
| 298 |
|
| 299 |
if (e->flags & LLA_VALID) { /* valid MAC */ |
| 300 |
d.sdl.sdl_family = AF_LINK; |
| 301 |
d.sdl.sdl_len = sizeof(d.sdl); |
| 302 |
d.sdl.sdl_alen = ifp->if_addrlen; |
| 303 |
d.sdl.sdl_index = ifp->if_index; |
| 304 |
d.sdl.sdl_type = ifp->if_type; |
| 305 |
bcopy(&e->ll_addr, LLADDR(&d.sdl), ifp->if_addrlen); |
| 306 |
} |
| 307 |
d.rtm.rtm_rmx.rmx_expire = |
| 308 |
e->flags & LLE_STATIC ? 0 : e->expire; |
| 309 |
d.rtm.rtm_flags = RTF_LLINFO; |
| 310 |
if (e->flags & LLE_STATIC) |
| 311 |
d.rtm.rtm_flags |= RTF_STATIC; |
| 312 |
d.rtm.rtm_index = ifp->if_index; |
| 313 |
error = SYSCTL_OUT(wr, &d, sizeof(d)); |
| 314 |
if (error) |
| 315 |
break; |
| 316 |
} |
| 317 |
return error; |
| 318 |
} |
| 319 |
|
| 320 |
/* |
| 321 |
* glue to dump arp tables |
| 322 |
*/ |
| 323 |
int |
| 324 |
sysctl_dumparp(int af, struct sysctl_req *wr) |
| 325 |
{ |
| 326 |
struct lltable *t; |
| 327 |
struct ifnet *ifp; |
| 328 |
int error = 0; |
| 329 |
|
| 330 |
IFNET_RLOCK(); |
| 331 |
TAILQ_FOREACH(ifp, &ifnet, if_link) { |
| 332 |
for (t = ifp->lltables; t ; t = t->llt_next) { |
| 333 |
if (af != 0 && t->llt_af != af) |
| 334 |
continue; |
| 335 |
switch (af) { |
| 336 |
case AF_INET: |
| 337 |
error = inet_dumparp(ifp, t->lle_head, wr); |
| 338 |
break; |
| 339 |
/* other handlers, if any */ |
| 340 |
} |
| 341 |
if (error) |
| 342 |
goto done; |
| 343 |
} |
| 344 |
} |
| 345 |
done: |
| 346 |
IFNET_RUNLOCK(); |
| 347 |
return (error); |
| 348 |
} |
| 349 |
|
| 350 |
/* |
| 351 |
* Called in route_output when adding/deleting a route to an interface. |
| 352 |
*/ |
| 353 |
int |
| 354 |
arp_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) |
| 355 |
{ |
| 356 |
struct sockaddr_dl *dl = |
| 357 |
(struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY]; |
| 358 |
struct sockaddr_in *dst = |
| 359 |
(struct sockaddr_in *)info->rti_info[RTAX_DST]; |
| 360 |
struct ifnet *ifp; |
| 361 |
struct llentry *la; |
| 362 |
u_int flags; |
| 363 |
|
| 364 |
printf("arp_rt_output type %d af: gw %d dst %d:%x if_index %d\n", |
| 365 |
rtm->rtm_type, |
| 366 |
dl ? dl->sdl_family : 0, |
| 367 |
dst ? dst->sin_family : 0, |
| 368 |
dst && dst->sin_family == AF_INET ? |
| 369 |
ntohl(dst->sin_addr.s_addr) : 0, |
| 370 |
dl ? dl->sdl_index : 0); |
| 371 |
if (dl == NULL || dl->sdl_family != AF_LINK) { |
| 372 |
/* XXX should also check (dl->sdl_index < if_indexlim) */ |
| 373 |
printf("invalid gateway/index\n"); |
| 374 |
return EINVAL; |
| 375 |
} |
| 376 |
ifp = ifnet_byindex(dl->sdl_index); |
| 377 |
if (ifp == NULL) { |
| 378 |
printf("invalid ifp\n"); |
| 379 |
return EINVAL; |
| 380 |
} |
| 381 |
|
| 382 |
switch (rtm->rtm_type) { |
| 383 |
case RTM_ADD: |
| 384 |
flags = LLE_CREATE; |
| 385 |
break; |
| 386 |
|
| 387 |
case RTM_CHANGE: |
| 388 |
default: |
| 389 |
return EINVAL; /* XXX not implemented yet */ |
| 390 |
|
| 391 |
case RTM_DELETE: |
| 392 |
flags = LLE_DELETE; |
| 393 |
break; |
| 394 |
} |
| 395 |
la = arplookup(ifp, dst->sin_addr.s_addr, flags); |
| 396 |
if (la == NULL) { |
| 397 |
bcopy(LLADDR(dl), &la->ll_addr, ifp->if_addrlen); |
| 398 |
la->flags |= LLA_VALID; |
| 399 |
if (rtm->rtm_flags & RTF_STATIC) |
| 400 |
la->flags |= LLE_STATIC; |
| 401 |
else |
| 402 |
la->expire = time_second + arpt_keep; |
| 403 |
} |
| 404 |
return 0; |
| 405 |
} |
| 406 |
|
| 407 |
|
| 408 |
|
| 409 |
/*** |
| 410 |
*** |
| 411 |
*** End of new arp support routines which should go to a separate file. |
| 412 |
*** |
| 413 |
***/ |
| 414 |
|
| 131 |
/* |
415 |
/* |
| 132 |
* Timeout routine. Age arp_tab entries periodically. |
416 |
* Timeout routine. Age arp_tab entries periodically. |
| 133 |
*/ |
417 |
*/ |
|
Lines 152-157
Link Here
|
| 152 |
callout_reset(&arp_callout, arpt_prune * hz, arptimer, NULL); |
436 |
callout_reset(&arp_callout, arpt_prune * hz, arptimer, NULL); |
| 153 |
} |
437 |
} |
| 154 |
|
438 |
|
|
|
439 |
#if 0 /* this is unused */ |
| 440 |
static int arp_allocated; |
| 441 |
|
| 155 |
/* |
442 |
/* |
| 156 |
* Parallel to llc_rtrequest. |
443 |
* Parallel to llc_rtrequest. |
| 157 |
*/ |
444 |
*/ |
|
Lines 284-289
Link Here
|
| 284 |
Free((caddr_t)la); |
571 |
Free((caddr_t)la); |
| 285 |
} |
572 |
} |
| 286 |
} |
573 |
} |
|
|
574 |
#endif /* arp_rtrequest unused */ |
| 287 |
|
575 |
|
| 288 |
/* |
576 |
/* |
| 289 |
* Broadcast an ARP request. Caller specifies: |
577 |
* Broadcast an ARP request. Caller specifies: |
|
Lines 301-306
Link Here
|
| 301 |
struct arphdr *ah; |
589 |
struct arphdr *ah; |
| 302 |
struct sockaddr sa; |
590 |
struct sockaddr sa; |
| 303 |
|
591 |
|
|
|
592 |
if (sip == NULL) { |
| 593 |
/* |
| 594 |
* The caller did not supply a source address, try to find |
| 595 |
* a compatible one among those assigned to this interface. |
| 596 |
*/ |
| 597 |
struct ifaddr *ifa; |
| 598 |
|
| 599 |
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { |
| 600 |
if (!ifa->ifa_addr || |
| 601 |
ifa->ifa_addr->sa_family != AF_INET) |
| 602 |
continue; |
| 603 |
sip = &SIN(ifa->ifa_addr)->sin_addr; |
| 604 |
if (0 == ((sip->s_addr ^ tip->s_addr) & |
| 605 |
SIN(ifa->ifa_netmask)->sin_addr.s_addr) ) |
| 606 |
break; /* found it. */ |
| 607 |
} |
| 608 |
} |
| 609 |
if (sip == NULL) { |
| 610 |
printf(" cannot find matching address, no arprequest\n"); |
| 611 |
return; |
| 612 |
} |
| 613 |
|
| 304 |
if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) |
614 |
if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) |
| 305 |
return; |
615 |
return; |
| 306 |
m->m_len = sizeof(*ah) + 2*sizeof(struct in_addr) + |
616 |
m->m_len = sizeof(*ah) + 2*sizeof(struct in_addr) + |
|
Lines 344-359
Link Here
|
| 344 |
arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, |
654 |
arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, |
| 345 |
struct sockaddr *dst, u_char *desten) |
655 |
struct sockaddr *dst, u_char *desten) |
| 346 |
{ |
656 |
{ |
| 347 |
struct llinfo_arp *la = 0; |
657 |
struct llentry *la = 0; |
| 348 |
struct sockaddr_dl *sdl; |
658 |
struct sockaddr_dl *sdl; |
| 349 |
int error; |
|
|
| 350 |
struct rtentry *rt; |
659 |
struct rtentry *rt; |
| 351 |
|
660 |
u_int flags = (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) ? |
| 352 |
error = rt_check(&rt, &rt0, dst); |
661 |
0 : LLE_CREATE; |
| 353 |
if (error) { |
|
|
| 354 |
m_freem(m); |
| 355 |
return error; |
| 356 |
} |
| 357 |
|
662 |
|
| 358 |
if (m->m_flags & M_BCAST) { /* broadcast */ |
663 |
if (m->m_flags & M_BCAST) { /* broadcast */ |
| 359 |
(void)memcpy(desten, ifp->if_broadcastaddr, ifp->if_addrlen); |
664 |
(void)memcpy(desten, ifp->if_broadcastaddr, ifp->if_addrlen); |
|
Lines 363-413
Link Here
|
| 363 |
ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten); |
668 |
ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten); |
| 364 |
return (0); |
669 |
return (0); |
| 365 |
} |
670 |
} |
| 366 |
if (rt) |
671 |
la = arplookup(ifp, SIN(dst)->sin_addr.s_addr, flags); |
| 367 |
la = (struct llinfo_arp *)rt->rt_llinfo; |
672 |
if (la == NULL) { |
| 368 |
if (la == 0) { |
673 |
if (flags & LLE_CREATE) |
| 369 |
la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0); |
674 |
log(LOG_DEBUG, |
| 370 |
if (la) |
675 |
"arpresolve: can't allocate llinfo for %s\n", |
| 371 |
rt = la->la_rt; |
676 |
inet_ntoa(SIN(dst)->sin_addr)); |
| 372 |
} |
|
|
| 373 |
if (la == 0 || rt == 0) { |
| 374 |
log(LOG_DEBUG, "arpresolve: can't allocate llinfo for %s%s%s\n", |
| 375 |
inet_ntoa(SIN(dst)->sin_addr), la ? "la" : "", |
| 376 |
rt ? "rt" : ""); |
| 377 |
m_freem(m); |
677 |
m_freem(m); |
| 378 |
return (EINVAL); /* XXX */ |
678 |
return (EINVAL); /* XXX */ |
| 379 |
} |
679 |
} |
| 380 |
sdl = SDL(rt->rt_gateway); |
680 |
sdl = SDL(rt->rt_gateway); |
| 381 |
/* |
681 |
/* |
| 382 |
* Check the address family and length is valid, the address |
682 |
* If the entry is valid and not expired, use it. |
| 383 |
* is resolved; otherwise, try to resolve. |
|
|
| 384 |
*/ |
683 |
*/ |
| 385 |
if ((rt->rt_expire == 0 || rt->rt_expire > time_second) && |
684 |
if (la->flags & LLA_VALID && |
| 386 |
sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) { |
685 |
(la->flags & LLE_STATIC || la->expire > time_second)) { |
|
|
686 |
bcopy(&la->ll_addr, desten, ifp->if_addrlen); |
| 387 |
/* |
687 |
/* |
| 388 |
* If entry has an expiry time and it is approaching, |
688 |
* If entry has an expiry time and it is approaching, |
| 389 |
* see if we need to send an ARP request within this |
689 |
* see if we need to send an ARP request within this |
| 390 |
* arpt_down interval. |
690 |
* arpt_down interval. |
| 391 |
*/ |
691 |
*/ |
| 392 |
if ((rt->rt_expire != 0) && |
692 |
if (!(la->flags & LLE_STATIC) && |
| 393 |
(time_second + la->la_preempt > rt->rt_expire)) { |
693 |
time_second + la->la_preempt > la->expire) { |
| 394 |
arprequest(ifp, |
694 |
arprequest(ifp, NULL, |
| 395 |
&SIN(rt->rt_ifa->ifa_addr)->sin_addr, |
695 |
&SIN(dst)->sin_addr, IF_LLADDR(ifp)); |
| 396 |
&SIN(dst)->sin_addr, |
|
|
| 397 |
IF_LLADDR(ifp)); |
| 398 |
la->la_preempt--; |
696 |
la->la_preempt--; |
| 399 |
} |
697 |
} |
| 400 |
|
698 |
|
| 401 |
bcopy(LLADDR(sdl), desten, sdl->sdl_alen); |
|
|
| 402 |
return (0); |
699 |
return (0); |
| 403 |
} |
700 |
} |
| 404 |
/* |
701 |
if (la->flags & LLE_STATIC) { /* should not happen! */ |
| 405 |
* If ARP is disabled or static on this interface, stop. |
702 |
log(LOG_DEBUG, "arpresolve: ouch, empty static llinfo for %s\n", |
| 406 |
* XXX |
703 |
inet_ntoa(SIN(dst)->sin_addr)); |
| 407 |
* Probably should not allocate empty llinfo struct if we are |
|
|
| 408 |
* not going to be sending out an arp request. |
| 409 |
*/ |
| 410 |
if (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) { |
| 411 |
m_freem(m); |
704 |
m_freem(m); |
| 412 |
return (EINVAL); |
705 |
return (EINVAL); |
| 413 |
} |
706 |
} |
|
Lines 419-444
Link Here
|
| 419 |
if (la->la_hold) |
712 |
if (la->la_hold) |
| 420 |
m_freem(la->la_hold); |
713 |
m_freem(la->la_hold); |
| 421 |
la->la_hold = m; |
714 |
la->la_hold = m; |
| 422 |
if (rt->rt_expire) { |
715 |
/* |
| 423 |
RT_LOCK(rt); |
716 |
* Now implement the logic to issue requests -- we can send up |
| 424 |
rt->rt_flags &= ~RTF_REJECT; |
717 |
* to arp_maxtries with a 1-sec spacing, followed by a pause |
| 425 |
if (la->la_asked == 0 || rt->rt_expire != time_second) { |
718 |
* of arpt_down seconds if no replies are coming back. |
| 426 |
rt->rt_expire = time_second; |
719 |
* Take the chance to enforce limits on arp_maxtries and arpt_down |
| 427 |
if (la->la_asked++ < arp_maxtries) { |
720 |
*/ |
| 428 |
arprequest(ifp, |
721 |
if (la->expire <= time_second) { /* ok, expired */ |
| 429 |
&SIN(rt->rt_ifa->ifa_addr)->sin_addr, |
722 |
if (arp_maxtries > 100) /* enforce a sane limit */ |
| 430 |
&SIN(dst)->sin_addr, |
723 |
arp_maxtries = 100; |
| 431 |
IF_LLADDR(ifp)); |
724 |
else if (arp_maxtries < 3) |
| 432 |
} else { |
725 |
arp_maxtries = 3; |
| 433 |
rt->rt_flags |= RTF_REJECT; |
726 |
if (la->la_asked++ < arp_maxtries) |
| 434 |
rt->rt_expire += arpt_down; |
727 |
la->expire = time_second + 1; |
| 435 |
la->la_asked = 0; |
728 |
else { |
| 436 |
la->la_preempt = arp_maxtries; |
729 |
la->la_asked = 0; |
| 437 |
} |
730 |
la->expire = time_second + arpt_down; |
| 438 |
|
731 |
la->la_preempt = arp_maxtries; |
| 439 |
} |
732 |
} |
| 440 |
RT_UNLOCK(rt); |
733 |
arprequest(ifp, NULL, &SIN(dst)->sin_addr, IF_LLADDR(ifp)); |
| 441 |
} |
734 |
} |
| 442 |
return (EWOULDBLOCK); |
735 |
return (EWOULDBLOCK); |
| 443 |
} |
736 |
} |
| 444 |
|
737 |
|
|
Lines 518-533
Link Here
|
| 518 |
{ |
811 |
{ |
| 519 |
struct arphdr *ah; |
812 |
struct arphdr *ah; |
| 520 |
struct ifnet *ifp = m->m_pkthdr.rcvif; |
813 |
struct ifnet *ifp = m->m_pkthdr.rcvif; |
| 521 |
struct iso88025_header *th = (struct iso88025_header *)0; |
814 |
struct llentry *la = 0; |
| 522 |
struct iso88025_sockaddr_dl_data *trld; |
|
|
| 523 |
struct llinfo_arp *la = 0; |
| 524 |
struct rtentry *rt; |
| 525 |
struct ifaddr *ifa; |
815 |
struct ifaddr *ifa; |
| 526 |
struct in_ifaddr *ia; |
816 |
struct in_ifaddr *ia; |
| 527 |
struct sockaddr_dl *sdl; |
|
|
| 528 |
struct sockaddr sa; |
817 |
struct sockaddr sa; |
| 529 |
struct in_addr isaddr, itaddr, myaddr; |
818 |
struct in_addr isaddr, itaddr, myaddr; |
| 530 |
int op, rif_len; |
819 |
int op; |
| 531 |
int req_len; |
820 |
int req_len; |
| 532 |
|
821 |
|
| 533 |
req_len = arphdr_len2(ifp->if_addrlen, sizeof(struct in_addr)); |
822 |
req_len = arphdr_len2(ifp->if_addrlen, sizeof(struct in_addr)); |
|
Lines 540-545
Link Here
|
| 540 |
op = ntohs(ah->ar_op); |
829 |
op = ntohs(ah->ar_op); |
| 541 |
(void)memcpy(&isaddr, ar_spa(ah), sizeof (isaddr)); |
830 |
(void)memcpy(&isaddr, ar_spa(ah), sizeof (isaddr)); |
| 542 |
(void)memcpy(&itaddr, ar_tpa(ah), sizeof (itaddr)); |
831 |
(void)memcpy(&itaddr, ar_tpa(ah), sizeof (itaddr)); |
|
|
832 |
/* |
| 833 |
* sanity check for the address length. |
| 834 |
* XXX this does not work for protocols with variable address |
| 835 |
* length. -is |
| 836 |
*/ |
| 837 |
if (ifp->if_addrlen != ah->ar_hln) { |
| 838 |
log(LOG_WARNING, |
| 839 |
"arp from %*D: addr len: new %d, i/f %d (ignored)", |
| 840 |
ifp->if_addrlen, (u_char *) ar_sha(ah), ":", |
| 841 |
ah->ar_hln, ifp->if_addrlen); |
| 842 |
goto drop; |
| 843 |
} |
| 844 |
|
| 543 |
#ifdef BRIDGE |
845 |
#ifdef BRIDGE |
| 544 |
#define BRIDGE_TEST (do_bridge) |
846 |
#define BRIDGE_TEST (do_bridge) |
| 545 |
#else |
847 |
#else |
|
Lines 592-653
Link Here
|
| 592 |
} |
894 |
} |
| 593 |
if (ifp->if_flags & IFF_STATICARP) |
895 |
if (ifp->if_flags & IFF_STATICARP) |
| 594 |
goto reply; |
896 |
goto reply; |
| 595 |
la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0); |
897 |
/* Look up the source. If I am the target, create an entry for it. */ |
| 596 |
if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) { |
898 |
la = arplookup(ifp, isaddr.s_addr, |
| 597 |
/* the following is not an error when doing bridging */ |
899 |
(itaddr.s_addr == myaddr.s_addr) ? LLE_CREATE : 0); |
| 598 |
if (!BRIDGE_TEST && rt->rt_ifp != ifp) { |
900 |
if (la != NULL) { |
| 599 |
if (log_arp_wrong_iface) |
901 |
/* We have a valid entry. Check and store the MAC. */ |
| 600 |
log(LOG_ERR, "arp: %s is on %s but got reply from %*D on %s\n", |
902 |
if (la->flags & LLA_VALID && |
| 601 |
inet_ntoa(isaddr), |
903 |
bcmp(ar_sha(ah), &la->ll_addr, ifp->if_addrlen)) { |
| 602 |
rt->rt_ifp->if_xname, |
904 |
if (la->flags & LLE_STATIC) { |
| 603 |
ifp->if_addrlen, (u_char *)ar_sha(ah), ":", |
|
|
| 604 |
ifp->if_xname); |
| 605 |
goto reply; |
| 606 |
} |
| 607 |
if (sdl->sdl_alen && |
| 608 |
bcmp(ar_sha(ah), LLADDR(sdl), sdl->sdl_alen)) { |
| 609 |
if (rt->rt_expire) { |
| 610 |
if (log_arp_movements) |
| 611 |
log(LOG_INFO, "arp: %s moved from %*D to %*D on %s\n", |
| 612 |
inet_ntoa(isaddr), |
| 613 |
ifp->if_addrlen, (u_char *)LLADDR(sdl), ":", |
| 614 |
ifp->if_addrlen, (u_char *)ar_sha(ah), ":", |
| 615 |
ifp->if_xname); |
| 616 |
} else { |
| 617 |
log(LOG_ERR, |
905 |
log(LOG_ERR, |
| 618 |
"arp: %*D attempts to modify permanent entry for %s on %s\n", |
906 |
"arp: %*D attempts to modify permanent entry for %s on %s\n", |
| 619 |
ifp->if_addrlen, (u_char *)ar_sha(ah), ":", |
907 |
ifp->if_addrlen, (u_char *)ar_sha(ah), ":", |
| 620 |
inet_ntoa(isaddr), ifp->if_xname); |
908 |
inet_ntoa(isaddr), ifp->if_xname); |
| 621 |
goto reply; |
909 |
goto reply; |
| 622 |
} |
910 |
} |
|
|
911 |
if (log_arp_movements) |
| 912 |
log(LOG_INFO, "arp: %s moved from %*D to %*D on %s\n", |
| 913 |
inet_ntoa(isaddr), |
| 914 |
ifp->if_addrlen, (u_char *)&la->ll_addr, ":", |
| 915 |
ifp->if_addrlen, (u_char *)ar_sha(ah), ":", |
| 916 |
ifp->if_xname); |
| 623 |
} |
917 |
} |
| 624 |
/* |
918 |
bcopy(ar_sha(ah), &la->ll_addr, ifp->if_addrlen); |
| 625 |
* sanity check for the address length. |
919 |
la->flags |= LLA_VALID; |
| 626 |
* XXX this does not work for protocols with variable address |
920 |
#if 0 /* XXX this needs to be fixed */ |
| 627 |
* length. -is |
|
|
| 628 |
*/ |
| 629 |
if (sdl->sdl_alen && |
| 630 |
sdl->sdl_alen != ah->ar_hln) { |
| 631 |
log(LOG_WARNING, |
| 632 |
"arp from %*D: new addr len %d, was %d", |
| 633 |
ifp->if_addrlen, (u_char *) ar_sha(ah), ":", |
| 634 |
ah->ar_hln, sdl->sdl_alen); |
| 635 |
} |
| 636 |
if (ifp->if_addrlen != ah->ar_hln) { |
| 637 |
log(LOG_WARNING, |
| 638 |
"arp from %*D: addr len: new %d, i/f %d (ignored)", |
| 639 |
ifp->if_addrlen, (u_char *) ar_sha(ah), ":", |
| 640 |
ah->ar_hln, ifp->if_addrlen); |
| 641 |
goto reply; |
| 642 |
} |
| 643 |
(void)memcpy(LLADDR(sdl), ar_sha(ah), |
| 644 |
sdl->sdl_alen = ah->ar_hln); |
| 645 |
/* |
921 |
/* |
| 646 |
* If we receive an arp from a token-ring station over |
922 |
* If we receive an arp from a token-ring station over |
| 647 |
* a token-ring nic then try to save the source |
923 |
* a token-ring nic then try to save the source |
| 648 |
* routing info. |
924 |
* routing info. |
| 649 |
*/ |
925 |
*/ |
| 650 |
if (ifp->if_type == IFT_ISO88025) { |
926 |
if (ifp->if_type == IFT_ISO88025) { |
|
|
927 |
struct iso88025_header *th; |
| 928 |
struct iso88025_sockaddr_dl_data *trld; |
| 929 |
struct sockaddr_dl *sdl; |
| 930 |
int rif_len; |
| 931 |
|
| 651 |
th = (struct iso88025_header *)m->m_pkthdr.header; |
932 |
th = (struct iso88025_header *)m->m_pkthdr.header; |
| 652 |
trld = SDL_ISO88025(sdl); |
933 |
trld = SDL_ISO88025(sdl); |
| 653 |
rif_len = TR_RCF_RIFLEN(th->rcf); |
934 |
rif_len = TR_RCF_RIFLEN(th->rcf); |
|
Lines 673-687
Link Here
|
| 673 |
m->m_pkthdr.len += 8; |
954 |
m->m_pkthdr.len += 8; |
| 674 |
th->rcf = trld->trld_rcf; |
955 |
th->rcf = trld->trld_rcf; |
| 675 |
} |
956 |
} |
| 676 |
RT_LOCK(rt); |
957 |
#endif |
| 677 |
if (rt->rt_expire) |
958 |
if (!(la->flags & LLE_STATIC)) |
| 678 |
rt->rt_expire = time_second + arpt_keep; |
959 |
la->expire = time_second + arpt_keep; |
| 679 |
rt->rt_flags &= ~RTF_REJECT; |
|
|
| 680 |
RT_UNLOCK(rt); |
| 681 |
la->la_asked = 0; |
960 |
la->la_asked = 0; |
| 682 |
la->la_preempt = arp_maxtries; |
961 |
la->la_preempt = arp_maxtries; |
| 683 |
if (la->la_hold) { |
962 |
if (la->la_hold) { |
| 684 |
(*ifp->if_output)(ifp, la->la_hold, rt_key(rt), rt); |
963 |
struct sockaddr_in sin; |
|
|
964 |
|
| 965 |
bzero(&sin, sizeof(sin)); |
| 966 |
sin.sin_len = sizeof(struct sockaddr_in); |
| 967 |
sin.sin_family = AF_INET; |
| 968 |
sin.sin_addr.s_addr = la->l3_addr.s_addr; |
| 969 |
ifp->if_output(ifp, la->la_hold, |
| 970 |
(struct sockaddr *)&sin, NULL); |
| 685 |
la->la_hold = 0; |
971 |
la->la_hold = 0; |
| 686 |
} |
972 |
} |
| 687 |
} |
973 |
} |
|
Lines 693-701
Link Here
|
| 693 |
(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); |
979 |
(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); |
| 694 |
(void)memcpy(ar_sha(ah), IF_LLADDR(ifp), ah->ar_hln); |
980 |
(void)memcpy(ar_sha(ah), IF_LLADDR(ifp), ah->ar_hln); |
| 695 |
} else { |
981 |
} else { |
| 696 |
la = arplookup(itaddr.s_addr, 0, SIN_PROXY); |
982 |
la = arplookup(ifp, itaddr.s_addr, LLE_PROXY); |
| 697 |
if (la == NULL) { |
983 |
if (la == NULL) { |
| 698 |
struct sockaddr_in sin; |
984 |
struct sockaddr_in sin; |
|
|
985 |
struct rtentry *rt; |
| 699 |
|
986 |
|
| 700 |
if (!arp_proxyall) |
987 |
if (!arp_proxyall) |
| 701 |
goto drop; |
988 |
goto drop; |
|
Lines 747-756
Link Here
|
| 747 |
inet_ntoa(itaddr)); |
1034 |
inet_ntoa(itaddr)); |
| 748 |
#endif |
1035 |
#endif |
| 749 |
} else { |
1036 |
} else { |
| 750 |
rt = la->la_rt; |
|
|
| 751 |
(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); |
1037 |
(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); |
| 752 |
sdl = SDL(rt->rt_gateway); |
1038 |
(void)memcpy(ar_sha(ah), &la->ll_addr, ah->ar_hln); |
| 753 |
(void)memcpy(ar_sha(ah), LLADDR(sdl), ah->ar_hln); |
|
|
| 754 |
} |
1039 |
} |
| 755 |
} |
1040 |
} |
| 756 |
|
1041 |
|
|
Lines 798-863
Link Here
|
| 798 |
/* |
1083 |
/* |
| 799 |
* Lookup or enter a new address in arptab. |
1084 |
* Lookup or enter a new address in arptab. |
| 800 |
*/ |
1085 |
*/ |
| 801 |
static struct llinfo_arp * |
1086 |
struct llentry * |
| 802 |
arplookup(addr, create, proxy) |
1087 |
arplookup(struct ifnet *ifp, uint32_t l3addr, u_int flags) |
| 803 |
u_long addr; |
|
|
| 804 |
int create, proxy; |
| 805 |
{ |
1088 |
{ |
| 806 |
struct rtentry *rt; |
1089 |
struct llentry *e; |
| 807 |
struct sockaddr_inarp sin; |
1090 |
struct lltable *t; |
| 808 |
const char *why = 0; |
1091 |
// uint proxy = flags & LLE_PROXY; |
| 809 |
|
1092 |
|
| 810 |
bzero(&sin, sizeof(sin)); |
1093 |
if (ifp == NULL) |
| 811 |
sin.sin_len = sizeof(sin); |
1094 |
return NULL; |
| 812 |
sin.sin_family = AF_INET; |
1095 |
/* LOCK_IFNET */ |
| 813 |
sin.sin_addr.s_addr = addr; |
1096 |
for (t = ifp->lltables; t && t->llt_af != AF_INET; t = t->llt_next) |
| 814 |
if (proxy) |
1097 |
; |
| 815 |
sin.sin_other = SIN_PROXY; |
1098 |
if (t == NULL && flags & LLE_CREATE) |
| 816 |
rt = rtalloc1((struct sockaddr *)&sin, create, 0UL); |
1099 |
t = lltable_new(ifp, AF_INET); |
| 817 |
if (rt == 0) |
1100 |
if (t == NULL) { |
| 818 |
return (0); |
1101 |
/* UNLOCK_ALL_TABLES */ |
| 819 |
|
1102 |
return NULL; /* failed! */ |
| 820 |
if (rt->rt_flags & RTF_GATEWAY) |
1103 |
} |
| 821 |
why = "host is not on local network"; |
1104 |
/* LOCK_TABLE(t) */ |
| 822 |
else if ((rt->rt_flags & RTF_LLINFO) == 0) |
1105 |
/* UNLOCK_ALL_TABLES */ |
| 823 |
why = "could not allocate llinfo"; |
1106 |
for (e = (struct llentry *)t->lle_head; e ; e = e->lle_next) { |
| 824 |
else if (rt->rt_gateway->sa_family != AF_LINK) |
1107 |
if (e->flags & LLE_DELETED) |
| 825 |
why = "gateway route is not ours"; |
1108 |
continue; |
| 826 |
|
1109 |
if (l3addr == e->l3_addr.s_addr) |
| 827 |
if (why) { |
1110 |
break; |
| 828 |
#define ISDYNCLONE(_rt) \ |
1111 |
} |
| 829 |
(((_rt)->rt_flags & (RTF_STATIC | RTF_WASCLONED)) == RTF_WASCLONED) |
1112 |
if (e == NULL) { /* entry not found */ |
| 830 |
if (create) |
1113 |
if (!(flags & LLE_CREATE)) |
| 831 |
log(LOG_DEBUG, "arplookup %s failed: %s\n", |
1114 |
goto done; |
| 832 |
inet_ntoa(sin.sin_addr), why); |
1115 |
if (find_ifa(ifp, l3addr) == NULL) { |
| 833 |
/* |
1116 |
printf("host is not on local network\n"); |
| 834 |
* If there are no references to this Layer 2 route, |
1117 |
goto done; |
| 835 |
* and it is a cloned route, and not static, and |
1118 |
} |
| 836 |
* arplookup() is creating the route, then purge |
1119 |
e = malloc(sizeof (struct llentry), M_ARP, M_DONTWAIT | M_ZERO); |
| 837 |
* it from the routing table as it is probably bogus. |
1120 |
if (e == NULL) { |
| 838 |
*/ |
1121 |
printf("arp malloc failed\n"); |
| 839 |
if (rt->rt_refcnt == 1 && ISDYNCLONE(rt)) |
1122 |
goto done; |
| 840 |
rtexpunge(rt); |
1123 |
} |
| 841 |
RTFREE_LOCKED(rt); |
1124 |
e->expire = time_second; /* mark expired */ |
| 842 |
return (0); |
1125 |
e->l3_addr.s_addr = l3addr; |
| 843 |
#undef ISDYNCLONE |
1126 |
e->lle_next = t->lle_head; |
| 844 |
} else { |
1127 |
t->lle_head = e; |
| 845 |
RT_REMREF(rt); |
1128 |
} |
| 846 |
RT_UNLOCK(rt); |
1129 |
if (flags & LLE_DELETE && |
| 847 |
return ((struct llinfo_arp *)rt->rt_llinfo); |
1130 |
(e->flags & LLE_IFADDR) == (flags & LLE_IFADDR)) |
| 848 |
} |
1131 |
e->flags = LLE_DELETED; |
|
|
1132 |
done: |
| 1133 |
/* UNLOCK(t) */ |
| 1134 |
return e; |
| 849 |
} |
1135 |
} |
| 850 |
|
1136 |
|
|
|
1137 |
|
| 851 |
void |
1138 |
void |
| 852 |
arp_ifinit(ifp, ifa) |
1139 |
arp_ifinit(ifp, ifa) |
| 853 |
struct ifnet *ifp; |
1140 |
struct ifnet *ifp; |
| 854 |
struct ifaddr *ifa; |
1141 |
struct ifaddr *ifa; |
| 855 |
{ |
1142 |
{ |
|
|
1143 |
struct llentry *la; |
| 1144 |
|
| 1145 |
printf("arp_ifinit ifp %p addr 0x%x\n", |
| 1146 |
ifp, ntohl(IA_SIN(ifa)->sin_addr.s_addr)); |
| 1147 |
|
| 856 |
if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) |
1148 |
if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) |
| 857 |
arprequest(ifp, &IA_SIN(ifa)->sin_addr, |
1149 |
arprequest(ifp, &IA_SIN(ifa)->sin_addr, |
| 858 |
&IA_SIN(ifa)->sin_addr, IF_LLADDR(ifp)); |
1150 |
&IA_SIN(ifa)->sin_addr, IF_LLADDR(ifp)); |
| 859 |
ifa->ifa_rtrequest = arp_rtrequest; |
1151 |
la = arplookup(ifp, IA_SIN(ifa)->sin_addr.s_addr, LLE_CREATE); |
| 860 |
ifa->ifa_flags |= RTF_CLONING; |
1152 |
if (la) { /* store our address */ |
|
|
1153 |
bcopy(IF_LLADDR(ifp), &la->ll_addr, ifp->if_addrlen); |
| 1154 |
la->flags |= LLA_VALID | LLE_STATIC | LLE_IFADDR; |
| 1155 |
} |
| 1156 |
ifa->ifa_rtrequest = NULL; |
| 861 |
} |
1157 |
} |
| 862 |
|
1158 |
|
| 863 |
static void |
1159 |
static void |
|
Lines 866-874
Link Here
|
| 866 |
|
1162 |
|
| 867 |
arpintrq.ifq_maxlen = 50; |
1163 |
arpintrq.ifq_maxlen = 50; |
| 868 |
mtx_init(&arpintrq.ifq_mtx, "arp_inq", NULL, MTX_DEF); |
1164 |
mtx_init(&arpintrq.ifq_mtx, "arp_inq", NULL, MTX_DEF); |
| 869 |
LIST_INIT(&llinfo_arp); |
|
|
| 870 |
callout_init(&arp_callout, CALLOUT_MPSAFE); |
1165 |
callout_init(&arp_callout, CALLOUT_MPSAFE); |
| 871 |
netisr_register(NETISR_ARP, arpintr, &arpintrq, NETISR_MPSAFE); |
1166 |
netisr_register(NETISR_ARP, arpintr, &arpintrq, NETISR_MPSAFE); |
| 872 |
callout_reset(&arp_callout, hz, arptimer, NULL); |
1167 |
callout_reset(&arp_callout, hz, newarptimer, NULL); |
| 873 |
} |
1168 |
} |
| 874 |
SYSINIT(arp, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, arp_init, 0); |
1169 |
SYSINIT(arp, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, arp_init, 0); |