Commit | Line | Data |
---|---|---|
8ae0e4b4 | 1 | /* |
9d91b170 | 2 | * Copyright (c) 1982, 1986, 1988 Regents of the University of California. |
2b6b6284 | 3 | * All rights reserved. |
8ae0e4b4 | 4 | * |
dbf0c423 | 5 | * %sccs.include.redist.c% |
2b6b6284 | 6 | * |
ab877e7b | 7 | * @(#)if_ether.c 7.25 (Berkeley) %G% |
8ae0e4b4 | 8 | */ |
2b0e2bab SL |
9 | |
10 | /* | |
11 | * Ethernet address resolution protocol. | |
878ad3fa | 12 | * TODO: |
878ad3fa | 13 | * add "inuse/lock" bit (or ref. count) along with valid bit |
2b0e2bab SL |
14 | */ |
15 | ||
20666ad3 JB |
16 | #include "param.h" |
17 | #include "systm.h" | |
9d91b170 | 18 | #include "malloc.h" |
20666ad3 JB |
19 | #include "mbuf.h" |
20 | #include "socket.h" | |
21 | #include "time.h" | |
22 | #include "kernel.h" | |
23 | #include "errno.h" | |
24 | #include "ioctl.h" | |
8a0ea807 | 25 | #include "syslog.h" |
2b0e2bab SL |
26 | |
27 | #include "../net/if.h" | |
1302f739 KS |
28 | #include "../net/if_dl.h" |
29 | #include "../net/route.h" | |
30 | ||
20666ad3 JB |
31 | #include "in.h" |
32 | #include "in_systm.h" | |
b4dc7708 | 33 | #include "in_var.h" |
20666ad3 JB |
34 | #include "ip.h" |
35 | #include "if_ether.h" | |
2b0e2bab | 36 | |
1302f739 KS |
37 | #define SIN(s) ((struct sockaddr_in *)s) |
38 | #define SDL(s) ((struct sockaddr_dl *)s) | |
39 | #define SRP(s) ((struct sockaddr_inarp *)s) | |
2b0e2bab | 40 | |
8a0ea807 MK |
41 | /* |
42 | * ARP trailer negotiation. Trailer protocol is not IP specific, | |
43 | * but ARP request/response use IP addresses. | |
44 | */ | |
45 | #define ETHERTYPE_IPTRAILERS ETHERTYPE_TRAIL | |
46 | ||
2b0e2bab SL |
47 | |
48 | /* timer values */ | |
1302f739 KS |
49 | int arpt_prune = (5*60*1); /* walk list every 5 minutes */ |
50 | int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */ | |
51 | int arpt_down = 20; /* once declared down, don't send for 20 secs */ | |
d6fa15c2 | 52 | #define rt_expire rt_rmx.rmx_expire |
2b0e2bab | 53 | |
d6fa15c2 KS |
54 | static void arprequest __P((struct arpcom *, u_long *, u_long *, u_char *)); |
55 | static void arptfree __P((struct llinfo_arp *)); | |
56 | static struct llinfo_arp *arplookup __P((u_long, int, int)); | |
57 | static void arpcatchme __P(()); | |
58 | ||
59 | extern struct ifnet loif; | |
60 | extern struct timeval time; | |
61 | struct llinfo_arp llinfo_arp = {&llinfo_arp, &llinfo_arp}; | |
62 | struct ifqueue arpintrq = {0, 0, 0, 50}; | |
1302f739 KS |
63 | int arp_inuse, arp_allocated, arp_intimer; |
64 | int arp_maxtries = 5; | |
65 | int useloopback = 1; /* use loopback interface for local traffic */ | |
66 | int arpinit_done = 0; | |
2b0e2bab | 67 | |
2b0e2bab | 68 | /* |
1302f739 | 69 | * Timeout routine. Age arp_tab entries periodically. |
2b0e2bab | 70 | */ |
d6fa15c2 | 71 | void |
2b0e2bab SL |
72 | arptimer() |
73 | { | |
1302f739 KS |
74 | int s = splnet(); |
75 | register struct llinfo_arp *la = llinfo_arp.la_next; | |
76 | ||
77 | timeout(arptimer, (caddr_t)0, arpt_prune * hz); | |
78 | while (la != &llinfo_arp) { | |
79 | register struct rtentry *rt = la->la_rt; | |
80 | la = la->la_next; | |
81 | if (rt->rt_expire && rt->rt_expire <= time.tv_sec) | |
82 | arptfree(la->la_prev); /* timer has expired, clear */ | |
83 | } | |
84 | splx(s); | |
85 | } | |
86 | ||
87 | /* | |
d6fa15c2 | 88 | * Parallel to llc_rtrequest. |
1302f739 | 89 | */ |
d6fa15c2 | 90 | void |
1302f739 KS |
91 | arp_rtrequest(req, rt, sa) |
92 | int req; | |
93 | register struct rtentry *rt; | |
94 | struct sockaddr *sa; | |
95 | { | |
96 | register struct sockaddr *gate = rt->rt_gateway; | |
97 | register struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo; | |
98 | static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; | |
99 | ||
100 | if (!arpinit_done) { | |
101 | arpinit_done = 1; | |
102 | timeout(arptimer, (caddr_t)0, hz); | |
103 | } | |
104 | if (rt->rt_flags & RTF_GATEWAY) | |
105 | return; | |
106 | switch (req) { | |
d6fa15c2 | 107 | |
1302f739 | 108 | case RTM_ADD: |
d6fa15c2 KS |
109 | /* |
110 | * XXX: If this is a manually added route to interface | |
111 | * such as older version of routed or gated might provide, | |
112 | * restore cloning bit. | |
113 | */ | |
28c5de95 KS |
114 | if ((rt->rt_flags & RTF_HOST) == 0 && |
115 | SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) | |
d6fa15c2 | 116 | rt->rt_flags |= RTF_CLONING; |
1302f739 KS |
117 | if (rt->rt_flags & RTF_CLONING) { |
118 | /* | |
119 | * Case 1: This route should come from a route to iface. | |
120 | */ | |
121 | rt_setgate(rt, rt_key(rt), &null_sdl); | |
122 | gate = rt->rt_gateway; | |
123 | SDL(gate)->sdl_type = rt->rt_ifp->if_type; | |
124 | SDL(gate)->sdl_index = rt->rt_ifp->if_index; | |
125 | rt->rt_expire = time.tv_sec; | |
126 | break; | |
127 | } | |
d6fa15c2 KS |
128 | /* Announce a new entry if requested. */ |
129 | if (rt->rt_flags & RTF_ANNOUNCE) | |
130 | arprequest((struct arpcom *)rt->rt_ifp, | |
131 | &SIN(rt_key(rt))->sin_addr.s_addr, | |
132 | &SIN(rt_key(rt))->sin_addr.s_addr, | |
133 | (u_char *)LLADDR(SDL(gate))); | |
134 | /*FALLTHROUGH*/ | |
135 | case RTM_RESOLVE: | |
1302f739 KS |
136 | if (gate->sa_family != AF_LINK || |
137 | gate->sa_len < sizeof(null_sdl)) { | |
138 | log(LOG_DEBUG, "arp_rtrequest: bad gateway value"); | |
139 | break; | |
140 | } | |
141 | SDL(gate)->sdl_type = rt->rt_ifp->if_type; | |
142 | SDL(gate)->sdl_index = rt->rt_ifp->if_index; | |
143 | if (la != 0) | |
144 | break; /* This happens on a route change */ | |
145 | /* | |
146 | * Case 2: This route may come from cloning, or a manual route | |
147 | * add with a LL address. | |
148 | */ | |
149 | R_Malloc(la, struct llinfo_arp *, sizeof(*la)); | |
150 | rt->rt_llinfo = (caddr_t)la; | |
151 | if (la == 0) { | |
152 | log(LOG_DEBUG, "arp_rtrequest: malloc failed\n"); | |
153 | break; | |
154 | } | |
155 | arp_inuse++, arp_allocated++; | |
156 | Bzero(la, sizeof(*la)); | |
157 | la->la_rt = rt; | |
158 | rt->rt_flags |= RTF_LLINFO; | |
159 | insque(la, &llinfo_arp); | |
160 | if (SIN(rt_key(rt))->sin_addr.s_addr == | |
161 | (IA_SIN(rt->rt_ifa))->sin_addr.s_addr) { | |
162 | /* | |
163 | * This test used to be | |
164 | * if (loif.if_flags & IFF_UP) | |
165 | * It allowed local traffic to be forced | |
166 | * through the hardware by configuring the loopback down. | |
167 | * However, it causes problems during network configuration | |
168 | * for boards that can't receive packets they send. | |
169 | * It is now necessary to clear "useloopback" and remove | |
170 | * the route to force traffic out to the hardware. | |
171 | */ | |
172 | rt->rt_expire = 0; | |
173 | Bcopy(((struct arpcom *)rt->rt_ifp)->ac_enaddr, | |
174 | LLADDR(SDL(gate)), SDL(gate)->sdl_alen = 6); | |
175 | if (useloopback) | |
176 | rt->rt_ifp = &loif; | |
d6fa15c2 | 177 | |
1302f739 KS |
178 | } |
179 | break; | |
180 | ||
181 | case RTM_DELETE: | |
182 | if (la == 0) | |
183 | break; | |
184 | arp_inuse--; | |
185 | remque(la); | |
186 | rt->rt_llinfo = 0; | |
187 | rt->rt_flags &= ~RTF_LLINFO; | |
188 | if (la->la_hold) | |
189 | m_freem(la->la_hold); | |
190 | Free((caddr_t)la); | |
2b0e2bab SL |
191 | } |
192 | } | |
193 | ||
194 | /* | |
195 | * Broadcast an ARP packet, asking who has addr on interface ac. | |
196 | */ | |
2cf7dc27 | 197 | void |
2b0e2bab SL |
198 | arpwhohas(ac, addr) |
199 | register struct arpcom *ac; | |
d6fa15c2 KS |
200 | register struct in_addr *addr; |
201 | { | |
202 | arprequest(ac, &ac->ac_ipaddr.s_addr, &addr->s_addr, ac->ac_enaddr); | |
203 | } | |
204 | ||
205 | /* | |
206 | * Broadcast an ARP request. Caller specifies: | |
207 | * - arp header source ip address | |
208 | * - arp header target ip address | |
209 | * - arp header source ethernet address | |
210 | */ | |
211 | static void | |
212 | arprequest(ac, sip, tip, enaddr) | |
213 | register struct arpcom *ac; | |
214 | register u_long *sip, *tip; | |
215 | register u_char *enaddr; | |
2b0e2bab SL |
216 | { |
217 | register struct mbuf *m; | |
218 | register struct ether_header *eh; | |
219 | register struct ether_arp *ea; | |
220 | struct sockaddr sa; | |
221 | ||
9d91b170 | 222 | if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) |
8011f5df | 223 | return; |
9d91b170 MK |
224 | m->m_len = sizeof(*ea); |
225 | m->m_pkthdr.len = sizeof(*ea); | |
226 | MH_ALIGN(m, sizeof(*ea)); | |
2b0e2bab SL |
227 | ea = mtod(m, struct ether_arp *); |
228 | eh = (struct ether_header *)sa.sa_data; | |
755d8841 | 229 | bzero((caddr_t)ea, sizeof (*ea)); |
9350cacc MK |
230 | bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, |
231 | sizeof(eh->ether_dhost)); | |
935a6d59 | 232 | eh->ether_type = ETHERTYPE_ARP; /* if_output will swap */ |
2b0e2bab | 233 | ea->arp_hrd = htons(ARPHRD_ETHER); |
935a6d59 | 234 | ea->arp_pro = htons(ETHERTYPE_IP); |
9350cacc MK |
235 | ea->arp_hln = sizeof(ea->arp_sha); /* hardware address length */ |
236 | ea->arp_pln = sizeof(ea->arp_spa); /* protocol address length */ | |
2b0e2bab | 237 | ea->arp_op = htons(ARPOP_REQUEST); |
d6fa15c2 KS |
238 | bcopy((caddr_t)enaddr, (caddr_t)ea->arp_sha, sizeof(ea->arp_sha)); |
239 | bcopy((caddr_t)sip, (caddr_t)ea->arp_spa, sizeof(ea->arp_spa)); | |
240 | bcopy((caddr_t)tip, (caddr_t)ea->arp_tpa, sizeof(ea->arp_tpa)); | |
2b0e2bab | 241 | sa.sa_family = AF_UNSPEC; |
0d246a40 | 242 | sa.sa_len = sizeof(sa); |
24b9cbfc | 243 | (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0); |
2b0e2bab SL |
244 | } |
245 | ||
878ad3fa MK |
246 | int useloopback = 1; /* use loopback interface for local traffic */ |
247 | ||
2b0e2bab | 248 | /* |
d6fa15c2 | 249 | * Resolve an IP address into an ethernet address. If success, |
8a0ea807 MK |
250 | * desten is filled in. If there is no entry in arptab, |
251 | * set one up and broadcast a request for the IP address. | |
252 | * Hold onto this mbuf and resend it once the address | |
253 | * is finally resolved. A return value of 1 indicates | |
254 | * that desten has been filled in and the packet should be sent | |
255 | * normally; a 0 return indicates that the packet has been | |
256 | * taken over here, either now or for later transmission. | |
2b0e2bab | 257 | */ |
d6fa15c2 KS |
258 | int |
259 | arpresolve(ac, rt, m, dst, desten) | |
2b0e2bab | 260 | register struct arpcom *ac; |
1302f739 | 261 | register struct rtentry *rt; |
2b0e2bab | 262 | struct mbuf *m; |
1302f739 | 263 | register struct sockaddr *dst; |
9350cacc | 264 | register u_char *desten; |
2b0e2bab | 265 | { |
1302f739 | 266 | register struct llinfo_arp *la; |
1302f739 | 267 | struct sockaddr_dl *sdl; |
2b0e2bab | 268 | |
9d91b170 | 269 | if (m->m_flags & M_BCAST) { /* broadcast */ |
9350cacc MK |
270 | bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten, |
271 | sizeof(etherbroadcastaddr)); | |
2b0e2bab SL |
272 | return (1); |
273 | } | |
d6fa15c2 KS |
274 | #ifdef MULTICAST |
275 | if (m->m_flags & M_MCAST) { /* multicast */ | |
276 | ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten); | |
277 | return(1); | |
278 | } | |
279 | #endif | |
1302f739 KS |
280 | if (rt) |
281 | la = (struct llinfo_arp *)rt->rt_llinfo; | |
282 | else { | |
d6fa15c2 | 283 | if (la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0)) |
1302f739 | 284 | rt = la->la_rt; |
2b0e2bab | 285 | } |
1302f739 KS |
286 | if (la == 0 || rt == 0) { |
287 | log(LOG_DEBUG, "arpresolve: can't allocate llinfo"); | |
288 | m_freem(m); | |
289 | return (0); | |
2b0e2bab | 290 | } |
1302f739 KS |
291 | sdl = SDL(rt->rt_gateway); |
292 | /* | |
293 | * Check the address family and length is valid, the address | |
294 | * is resolved; otherwise, try to resolve. | |
295 | */ | |
296 | if ((rt->rt_expire == 0 || rt->rt_expire > time.tv_sec) && | |
297 | sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) { | |
298 | bcopy(LLADDR(sdl), desten, sdl->sdl_alen); | |
1302f739 | 299 | return 1; |
2b0e2bab SL |
300 | } |
301 | /* | |
302 | * There is an arptab entry, but no ethernet address | |
303 | * response yet. Replace the held mbuf with this | |
304 | * latest one. | |
305 | */ | |
1302f739 KS |
306 | if (la->la_hold) |
307 | m_freem(la->la_hold); | |
308 | la->la_hold = m; | |
309 | if (rt->rt_expire) { | |
310 | rt->rt_flags &= ~RTF_REJECT; | |
311 | if (la->la_asked == 0 || rt->rt_expire != time.tv_sec) { | |
312 | rt->rt_expire = time.tv_sec; | |
313 | if (la->la_asked++ < arp_maxtries) | |
314 | arpwhohas(ac, &(SIN(dst)->sin_addr)); | |
315 | else { | |
316 | rt->rt_flags |= RTF_REJECT; | |
317 | rt->rt_expire += arpt_down; | |
318 | la->la_asked = 0; | |
319 | } | |
320 | ||
321 | } | |
322 | } | |
2b0e2bab SL |
323 | return (0); |
324 | } | |
325 | ||
2b0e2bab | 326 | /* |
1302f739 | 327 | * Common length and type checks are done here, |
8a0ea807 MK |
328 | * then the protocol-specific routine is called. |
329 | */ | |
d6fa15c2 | 330 | void |
1302f739 | 331 | arpintr() |
8a0ea807 | 332 | { |
1302f739 | 333 | register struct mbuf *m; |
8a0ea807 | 334 | register struct arphdr *ar; |
1302f739 | 335 | int s; |
8a0ea807 | 336 | |
1302f739 KS |
337 | while (arpintrq.ifq_head) { |
338 | s = splimp(); | |
339 | IF_DEQUEUE(&arpintrq, m); | |
340 | splx(s); | |
341 | if (m == 0 || (m->m_flags & M_PKTHDR) == 0) | |
342 | panic("arpintr"); | |
343 | if (m->m_len >= sizeof(struct arphdr) && | |
344 | (ar = mtod(m, struct arphdr *)) && | |
345 | ntohs(ar->ar_hrd) == ARPHRD_ETHER && | |
346 | m->m_len >= | |
347 | sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln) | |
348 | ||
349 | switch (ntohs(ar->ar_pro)) { | |
350 | ||
351 | case ETHERTYPE_IP: | |
352 | case ETHERTYPE_IPTRAILERS: | |
353 | in_arpinput(m); | |
354 | continue; | |
355 | } | |
356 | m_freem(m); | |
8a0ea807 | 357 | } |
8a0ea807 MK |
358 | } |
359 | ||
360 | /* | |
361 | * ARP for Internet protocols on 10 Mb/s Ethernet. | |
362 | * Algorithm is that given in RFC 826. | |
2b0e2bab SL |
363 | * In addition, a sanity check is performed on the sender |
364 | * protocol address, to catch impersonators. | |
d6fa15c2 KS |
365 | * We no longer handle negotiations for use of trailer protocol: |
366 | * Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent | |
367 | * along with IP replies if we wanted trailers sent to us, | |
368 | * and also sent them in response to IP replies. | |
369 | * This allowed either end to announce the desire to receive | |
8a0ea807 | 370 | * trailer packets. |
d6fa15c2 KS |
371 | * We no longer reply to requests for ETHERTYPE_TRAIL protocol either, |
372 | * but formerly didn't normally send requests. | |
2b0e2bab | 373 | */ |
0cf7ef94 | 374 | void |
1302f739 | 375 | in_arpinput(m) |
2b0e2bab SL |
376 | struct mbuf *m; |
377 | { | |
378 | register struct ether_arp *ea; | |
1302f739 | 379 | register struct arpcom *ac = (struct arpcom *)m->m_pkthdr.rcvif; |
2b0e2bab | 380 | struct ether_header *eh; |
91e0f45a | 381 | register struct llinfo_arp *la = 0; |
1302f739 KS |
382 | register struct rtentry *rt; |
383 | struct in_ifaddr *ia, *maybe_ia = 0; | |
1302f739 | 384 | struct sockaddr_dl *sdl; |
2b0e2bab | 385 | struct sockaddr sa; |
8a0ea807 | 386 | struct in_addr isaddr, itaddr, myaddr; |
d6fa15c2 | 387 | int op; |
2b0e2bab | 388 | |
2b0e2bab | 389 | ea = mtod(m, struct ether_arp *); |
8a0ea807 | 390 | op = ntohs(ea->arp_op); |
878ad3fa MK |
391 | bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof (isaddr)); |
392 | bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr, sizeof (itaddr)); | |
b4dc7708 KS |
393 | for (ia = in_ifaddr; ia; ia = ia->ia_next) |
394 | if (ia->ia_ifp == &ac->ac_if) { | |
395 | maybe_ia = ia; | |
396 | if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) || | |
397 | (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr)) | |
398 | break; | |
399 | } | |
400 | if (maybe_ia == 0) | |
401 | goto out; | |
402 | myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr; | |
9350cacc | 403 | if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr, |
9d91b170 | 404 | sizeof (ea->arp_sha))) |
2b0e2bab | 405 | goto out; /* it's from me, ignore it. */ |
8a0ea807 MK |
406 | if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr, |
407 | sizeof (ea->arp_sha))) { | |
408 | log(LOG_ERR, | |
409 | "arp: ether address is broadcast for IP address %x!\n", | |
410 | ntohl(isaddr.s_addr)); | |
411 | goto out; | |
412 | } | |
2b0e2bab | 413 | if (isaddr.s_addr == myaddr.s_addr) { |
0d246a40 MK |
414 | log(LOG_ERR, |
415 | "duplicate IP address %x!! sent from ethernet address: %s\n", | |
416 | ntohl(isaddr.s_addr), ether_sprintf(ea->arp_sha)); | |
07847ffa | 417 | itaddr = myaddr; |
d6fa15c2 | 418 | goto reply; |
2b0e2bab | 419 | } |
878ad3fa | 420 | s = splimp(); |
1302f739 KS |
421 | la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0); |
422 | if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) { | |
423 | if (sdl->sdl_alen && | |
424 | bcmp((caddr_t)ea->arp_sha, LLADDR(sdl), sdl->sdl_alen)) | |
425 | log(LOG_INFO, "arp info overwritten for %x by %s\n", | |
426 | isaddr.s_addr, ether_sprintf(ea->arp_sha)); | |
1302f739 KS |
427 | bcopy((caddr_t)ea->arp_sha, LLADDR(sdl), |
428 | sdl->sdl_alen = sizeof(ea->arp_sha)); | |
429 | if (rt->rt_expire) | |
430 | rt->rt_expire = time.tv_sec + arpt_keep; | |
431 | rt->rt_flags &= ~RTF_REJECT; | |
432 | la->la_asked = 0; | |
433 | if (la->la_hold) { | |
434 | (*ac->ac_if.if_output)(&ac->ac_if, la->la_hold, | |
435 | rt_key(rt), rt); | |
436 | la->la_hold = 0; | |
9c76eb65 | 437 | } |
2b0e2bab | 438 | } |
2b0e2bab | 439 | reply: |
d6fa15c2 KS |
440 | if (op != ARPOP_REQUEST) { |
441 | out: | |
442 | m_freem(m); | |
443 | return; | |
8a0ea807 MK |
444 | } |
445 | if (itaddr.s_addr == myaddr.s_addr) { | |
446 | /* I am the target */ | |
447 | bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha, | |
448 | sizeof(ea->arp_sha)); | |
449 | bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha, | |
450 | sizeof(ea->arp_sha)); | |
451 | } else { | |
1302f739 KS |
452 | la = arplookup(itaddr.s_addr, 0, SIN_PROXY); |
453 | if (la == NULL) | |
8a0ea807 | 454 | goto out; |
623f39dc | 455 | rt = la->la_rt; |
8a0ea807 MK |
456 | bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha, |
457 | sizeof(ea->arp_sha)); | |
623f39dc | 458 | sdl = SDL(rt->rt_gateway); |
1302f739 | 459 | bcopy(LLADDR(sdl), (caddr_t)ea->arp_sha, sizeof(ea->arp_sha)); |
8a0ea807 MK |
460 | } |
461 | ||
d6fa15c2 KS |
462 | bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa, sizeof(ea->arp_spa)); |
463 | bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa, sizeof(ea->arp_spa)); | |
464 | ea->arp_op = htons(ARPOP_REPLY); | |
465 | ea->arp_pro = htons(ETHERTYPE_IP); /* let's be sure! */ | |
2b0e2bab | 466 | eh = (struct ether_header *)sa.sa_data; |
9350cacc MK |
467 | bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost, |
468 | sizeof(eh->ether_dhost)); | |
935a6d59 | 469 | eh->ether_type = ETHERTYPE_ARP; |
2b0e2bab | 470 | sa.sa_family = AF_UNSPEC; |
0d246a40 | 471 | sa.sa_len = sizeof(sa); |
24b9cbfc | 472 | (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0); |
2b0e2bab SL |
473 | return; |
474 | } | |
475 | ||
476 | /* | |
1302f739 | 477 | * Free an arp entry. |
2b0e2bab | 478 | */ |
d6fa15c2 | 479 | static void |
1302f739 KS |
480 | arptfree(la) |
481 | register struct llinfo_arp *la; | |
2b0e2bab | 482 | { |
1302f739 KS |
483 | register struct rtentry *rt = la->la_rt; |
484 | register struct sockaddr_dl *sdl; | |
485 | if (rt == 0) | |
486 | panic("arptfree"); | |
487 | if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) && | |
488 | sdl->sdl_family == AF_LINK) { | |
489 | sdl->sdl_alen = 0; | |
490 | la->la_asked = 0; | |
491 | rt->rt_flags &= ~RTF_REJECT; | |
492 | return; | |
493 | } | |
494 | rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt), | |
495 | 0, (struct rtentry **)0); | |
2b0e2bab | 496 | } |
2b0e2bab | 497 | /* |
1302f739 | 498 | * Lookup or enter a new address in arptab. |
2b0e2bab | 499 | */ |
d6fa15c2 | 500 | static struct llinfo_arp * |
1302f739 KS |
501 | arplookup(addr, create, proxy) |
502 | u_long addr; | |
64f72726 | 503 | int create, proxy; |
2b0e2bab | 504 | { |
1302f739 KS |
505 | register struct rtentry *rt; |
506 | static struct sockaddr_inarp sin = {sizeof(sin), AF_INET }; | |
507 | ||
508 | sin.sin_addr.s_addr = addr; | |
509 | sin.sin_other = proxy ? SIN_PROXY : 0; | |
510 | rt = rtalloc1((struct sockaddr *)&sin, create); | |
511 | if (rt == 0) | |
512 | return (0); | |
513 | rt->rt_refcnt--; | |
d6fa15c2 KS |
514 | if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 || |
515 | rt->rt_gateway->sa_family != AF_LINK) { | |
516 | if (create) | |
1302f739 KS |
517 | log(LOG_DEBUG, "arptnew failed on %x\n", ntohl(addr)); |
518 | return (0); | |
07847ffa | 519 | } |
1302f739 | 520 | return ((struct llinfo_arp *)rt->rt_llinfo); |
2b0e2bab | 521 | } |
07847ffa | 522 | |
d6fa15c2 | 523 | int |
07847ffa MK |
524 | arpioctl(cmd, data) |
525 | int cmd; | |
526 | caddr_t data; | |
527 | { | |
1302f739 | 528 | return (EOPNOTSUPP); |
07847ffa | 529 | } |