1 | /* |
---|
2 | * Copyright (c) 1982, 1986, 1988, 1993 |
---|
3 | * The Regents of the University of California. All rights reserved. |
---|
4 | * |
---|
5 | * Redistribution and use in source and binary forms, with or without |
---|
6 | * modification, are permitted provided that the following conditions |
---|
7 | * are met: |
---|
8 | * 1. Redistributions of source code must retain the above copyright |
---|
9 | * notice, this list of conditions and the following disclaimer. |
---|
10 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
11 | * notice, this list of conditions and the following disclaimer in the |
---|
12 | * documentation and/or other materials provided with the distribution. |
---|
13 | * 4. Neither the name of the University nor the names of its contributors |
---|
14 | * may be used to endorse or promote products derived from this software |
---|
15 | * without specific prior written permission. |
---|
16 | * |
---|
17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
---|
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
---|
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
27 | * SUCH DAMAGE. |
---|
28 | * |
---|
29 | * @(#)if_ether.c 8.1 (Berkeley) 6/10/93 |
---|
30 | * $FreeBSD: src/sys/netinet/if_ether.c,v 1.136 2005/03/13 11:23:22 glebius Exp $ |
---|
31 | */ |
---|
32 | |
---|
33 | /* |
---|
34 | * $Id$ |
---|
35 | */ |
---|
36 | |
---|
37 | /* |
---|
38 | * Ethernet address resolution protocol. |
---|
39 | * TODO: |
---|
40 | * add "inuse/lock" bit (or ref. count) along with valid bit |
---|
41 | */ |
---|
42 | |
---|
43 | #ifdef HAVE_CONFIG_H |
---|
44 | #include "config.h" |
---|
45 | #endif |
---|
46 | |
---|
47 | #include "opt_inet.h" |
---|
48 | |
---|
49 | #include <sys/param.h> |
---|
50 | #include <sys/kernel.h> |
---|
51 | #include <rtems/bsd/sys/queue.h> |
---|
52 | #include <sys/sysctl.h> |
---|
53 | #include <sys/systm.h> |
---|
54 | #include <sys/mbuf.h> |
---|
55 | #include <sys/malloc.h> |
---|
56 | #include <sys/socket.h> |
---|
57 | #include <sys/syslog.h> |
---|
58 | |
---|
59 | #include <net/if.h> |
---|
60 | #include <net/if_dl.h> |
---|
61 | #include <net/if_types.h> |
---|
62 | #include <net/route.h> |
---|
63 | #include <net/netisr.h> |
---|
64 | |
---|
65 | #include <netinet/in.h> |
---|
66 | #include <netinet/in_var.h> |
---|
67 | #include <netinet/if_ether.h> |
---|
68 | |
---|
69 | #define SIN(s) ((struct sockaddr_in *)s) |
---|
70 | #define SDL(s) ((struct sockaddr_dl *)s) |
---|
71 | |
---|
72 | SYSCTL_DECL(_net_link_ether); |
---|
73 | SYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW, 0, ""); |
---|
74 | |
---|
75 | /* timer values */ |
---|
76 | static int arpt_prune = (5*60*1); /* walk list every 5 minutes */ |
---|
77 | static int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */ |
---|
78 | static int arpt_down = 20; /* once declared down, don't send for 20 sec */ |
---|
79 | |
---|
80 | SYSCTL_INT(_net_link_ether_inet, OID_AUTO, prune_intvl, CTLFLAG_RW, |
---|
81 | &arpt_prune, 0, ""); |
---|
82 | SYSCTL_INT(_net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW, |
---|
83 | &arpt_keep, 0, ""); |
---|
84 | SYSCTL_INT(_net_link_ether_inet, OID_AUTO, host_down_time, CTLFLAG_RW, |
---|
85 | &arpt_down, 0, ""); |
---|
86 | |
---|
87 | #define rt_expire rt_rmx.rmx_expire |
---|
88 | |
---|
89 | struct llinfo_arp { |
---|
90 | LIST_ENTRY(llinfo_arp) la_le; |
---|
91 | struct rtentry *la_rt; |
---|
92 | struct mbuf *la_hold; /* last packet until resolved/timeout */ |
---|
93 | long la_asked; /* last time we QUERIED for this addr */ |
---|
94 | #define la_timer la_rt->rt_rmx.rmx_expire /* deletion time in seconds */ |
---|
95 | }; |
---|
96 | |
---|
97 | static LIST_HEAD(, llinfo_arp) llinfo_arp; |
---|
98 | |
---|
99 | struct ifqueue arpintrq = {0, 0, 0, 50, 0}; |
---|
100 | static int arp_inuse, arp_allocated; |
---|
101 | |
---|
102 | static int arp_maxtries = 5; |
---|
103 | static int useloopback = 1; /* use loopback interface for local traffic */ |
---|
104 | static int arp_proxyall = 0; |
---|
105 | |
---|
106 | SYSCTL_INT(_net_link_ether_inet, OID_AUTO, maxtries, CTLFLAG_RW, |
---|
107 | &arp_maxtries, 0, ""); |
---|
108 | SYSCTL_INT(_net_link_ether_inet, OID_AUTO, useloopback, CTLFLAG_RW, |
---|
109 | &useloopback, 0, ""); |
---|
110 | SYSCTL_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW, |
---|
111 | &arp_proxyall, 0, ""); |
---|
112 | |
---|
113 | static void arp_rtrequest(int, struct rtentry *, struct sockaddr *); |
---|
114 | static void arprequest(struct arpcom *, struct in_addr *, struct in_addr *, u_char *); |
---|
115 | void arpintr(void); |
---|
116 | static void arptfree(struct llinfo_arp *); |
---|
117 | static void arptimer(void *); |
---|
118 | static struct llinfo_arp |
---|
119 | *arplookup(u_long, int, int); |
---|
120 | #ifdef INET |
---|
121 | static void in_arpinput(struct mbuf *); |
---|
122 | #endif |
---|
123 | |
---|
124 | /* |
---|
125 | * Timeout routine. Age arp_tab entries periodically. |
---|
126 | */ |
---|
127 | /* ARGSUSED */ |
---|
128 | static void |
---|
129 | arptimer(void *ignored_arg) |
---|
130 | { |
---|
131 | int s = splnet(); |
---|
132 | struct llinfo_arp *la, *ola; |
---|
133 | |
---|
134 | la = llinfo_arp.lh_first; |
---|
135 | timeout(arptimer, (caddr_t)0, arpt_prune * hz); |
---|
136 | while ((ola = la) != 0) { |
---|
137 | register struct rtentry *rt = la->la_rt; |
---|
138 | la = la->la_le.le_next; |
---|
139 | if (rt->rt_expire && rt->rt_expire <= rtems_bsdnet_seconds_since_boot()) |
---|
140 | arptfree(ola); /* timer has expired, clear */ |
---|
141 | } |
---|
142 | splx(s); |
---|
143 | } |
---|
144 | |
---|
145 | /* |
---|
146 | * Parallel to llc_rtrequest. |
---|
147 | */ |
---|
148 | static void |
---|
149 | arp_rtrequest(int req, struct rtentry *rt, struct sockaddr *sa) |
---|
150 | { |
---|
151 | struct sockaddr *gate; |
---|
152 | struct llinfo_arp *la; |
---|
153 | static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK, 0, 0, 0, 0, 0, { 0 } }; |
---|
154 | static int arpinit_done; |
---|
155 | |
---|
156 | if (!arpinit_done) { |
---|
157 | arpinit_done = 1; |
---|
158 | LIST_INIT(&llinfo_arp); |
---|
159 | timeout(arptimer, (caddr_t)0, hz); |
---|
160 | } |
---|
161 | if (rt->rt_flags & RTF_GATEWAY) |
---|
162 | return; |
---|
163 | gate = rt->rt_gateway; |
---|
164 | la = (struct llinfo_arp *)rt->rt_llinfo; |
---|
165 | switch (req) { |
---|
166 | |
---|
167 | case RTM_ADD: |
---|
168 | /* |
---|
169 | * XXX: If this is a manually added route to interface |
---|
170 | * such as older version of routed or gated might provide, |
---|
171 | * restore cloning bit. |
---|
172 | */ |
---|
173 | if ((rt->rt_flags & RTF_HOST) == 0 && |
---|
174 | rt_mask(rt) != NULL && |
---|
175 | SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) |
---|
176 | rt->rt_flags |= RTF_CLONING; |
---|
177 | if (rt->rt_flags & RTF_CLONING) { |
---|
178 | /* |
---|
179 | * Case 1: This route should come from a route to iface. |
---|
180 | */ |
---|
181 | rt_setgate(rt, rt_key(rt), |
---|
182 | (struct sockaddr *)&null_sdl); |
---|
183 | gate = rt->rt_gateway; |
---|
184 | SDL(gate)->sdl_type = rt->rt_ifp->if_type; |
---|
185 | SDL(gate)->sdl_index = rt->rt_ifp->if_index; |
---|
186 | rt->rt_expire = rtems_bsdnet_seconds_since_boot(); |
---|
187 | break; |
---|
188 | } |
---|
189 | /* Announce a new entry if requested. */ |
---|
190 | if (rt->rt_flags & RTF_ANNOUNCE) |
---|
191 | arprequest((struct arpcom *)rt->rt_ifp, |
---|
192 | &SIN(rt_key(rt))->sin_addr, |
---|
193 | &SIN(rt_key(rt))->sin_addr, |
---|
194 | (u_char *)LLADDR(SDL(gate))); |
---|
195 | /*FALLTHROUGH*/ |
---|
196 | case RTM_RESOLVE: |
---|
197 | if (gate->sa_family != AF_LINK || |
---|
198 | gate->sa_len < sizeof(null_sdl)) { |
---|
199 | log(LOG_DEBUG, "arp_rtrequest: bad gateway value\n"); |
---|
200 | break; |
---|
201 | } |
---|
202 | SDL(gate)->sdl_type = rt->rt_ifp->if_type; |
---|
203 | SDL(gate)->sdl_index = rt->rt_ifp->if_index; |
---|
204 | if (la != 0) |
---|
205 | break; /* This happens on a route change */ |
---|
206 | /* |
---|
207 | * Case 2: This route may come from cloning, or a manual route |
---|
208 | * add with a LL address. |
---|
209 | */ |
---|
210 | R_Malloc(la, struct llinfo_arp *, sizeof(*la)); |
---|
211 | rt->rt_llinfo = (caddr_t)la; |
---|
212 | if (la == 0) { |
---|
213 | log(LOG_DEBUG, "arp_rtrequest: malloc failed\n"); |
---|
214 | break; |
---|
215 | } |
---|
216 | arp_inuse++; |
---|
217 | arp_allocated++; |
---|
218 | Bzero(la, sizeof(*la)); |
---|
219 | la->la_rt = rt; |
---|
220 | rt->rt_flags |= RTF_LLINFO; |
---|
221 | LIST_INSERT_HEAD(&llinfo_arp, la, la_le); |
---|
222 | |
---|
223 | /* |
---|
224 | * This keeps the multicast addresses from showing up |
---|
225 | * in `arp -a' listings as unresolved. It's not actually |
---|
226 | * functional. Then the same for broadcast. |
---|
227 | */ |
---|
228 | if (IN_MULTICAST(ntohl(SIN(rt_key(rt))->sin_addr.s_addr))) { |
---|
229 | ETHER_MAP_IP_MULTICAST(&SIN(rt_key(rt))->sin_addr, |
---|
230 | LLADDR(SDL(gate))); |
---|
231 | SDL(gate)->sdl_alen = 6; |
---|
232 | rt->rt_expire = 0; |
---|
233 | } |
---|
234 | if (in_broadcast(SIN(rt_key(rt))->sin_addr, rt->rt_ifp)) { |
---|
235 | memcpy(LLADDR(SDL(gate)), etherbroadcastaddr, 6); |
---|
236 | SDL(gate)->sdl_alen = 6; |
---|
237 | rt->rt_expire = 0; |
---|
238 | } |
---|
239 | |
---|
240 | if (SIN(rt_key(rt))->sin_addr.s_addr == |
---|
241 | (IA_SIN(rt->rt_ifa))->sin_addr.s_addr) { |
---|
242 | /* |
---|
243 | * This test used to be |
---|
244 | * if (loif.if_flags & IFF_UP) |
---|
245 | * It allowed local traffic to be forced |
---|
246 | * through the hardware by configuring the loopback down. |
---|
247 | * However, it causes problems during network configuration |
---|
248 | * for boards that can't receive packets they send. |
---|
249 | * It is now necessary to clear "useloopback" and remove |
---|
250 | * the route to force traffic out to the hardware. |
---|
251 | */ |
---|
252 | rt->rt_expire = 0; |
---|
253 | Bcopy(((struct arpcom *)rt->rt_ifp)->ac_enaddr, |
---|
254 | LLADDR(SDL(gate)), SDL(gate)->sdl_alen = 6); |
---|
255 | if (useloopback) |
---|
256 | rt->rt_ifp = loif; |
---|
257 | |
---|
258 | } |
---|
259 | break; |
---|
260 | |
---|
261 | case RTM_DELETE: |
---|
262 | if (la == 0) |
---|
263 | break; |
---|
264 | arp_inuse--; |
---|
265 | LIST_REMOVE(la, la_le); |
---|
266 | rt->rt_llinfo = 0; |
---|
267 | rt->rt_flags &= ~RTF_LLINFO; |
---|
268 | if (la->la_hold) |
---|
269 | m_freem(la->la_hold); |
---|
270 | Free((caddr_t)la); |
---|
271 | } |
---|
272 | } |
---|
273 | |
---|
274 | /* |
---|
275 | * Broadcast an ARP request. Caller specifies: |
---|
276 | * - arp header source ip address |
---|
277 | * - arp header target ip address |
---|
278 | * - arp header source ethernet address |
---|
279 | */ |
---|
280 | static void |
---|
281 | arprequest(struct arpcom *ac, struct in_addr *sip, struct in_addr *tip, u_char *enaddr) |
---|
282 | { |
---|
283 | struct mbuf *m; |
---|
284 | struct ether_header *eh; |
---|
285 | struct ether_arp *ea; |
---|
286 | struct sockaddr sa; |
---|
287 | |
---|
288 | if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) |
---|
289 | return; |
---|
290 | m->m_len = sizeof(*ea); |
---|
291 | m->m_pkthdr.len = sizeof(*ea); |
---|
292 | MH_ALIGN(m, sizeof(*ea)); |
---|
293 | ea = mtod(m, struct ether_arp *); |
---|
294 | eh = (struct ether_header *)sa.sa_data; |
---|
295 | bzero((caddr_t)ea, sizeof (*ea)); |
---|
296 | (void)memcpy(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost)); |
---|
297 | eh->ether_type = htons(ETHERTYPE_ARP); /* if_output will not swap */ |
---|
298 | ea->arp_hrd = htons(ARPHRD_ETHER); |
---|
299 | ea->arp_pro = htons(ETHERTYPE_IP); |
---|
300 | ea->arp_hln = sizeof(ea->arp_sha); /* hardware address length */ |
---|
301 | ea->arp_pln = sizeof(ea->arp_spa); /* protocol address length */ |
---|
302 | ea->arp_op = htons(ARPOP_REQUEST); |
---|
303 | (void)memcpy(ea->arp_sha, enaddr, sizeof(ea->arp_sha)); |
---|
304 | (void)memcpy(ea->arp_spa, sip, sizeof(ea->arp_spa)); |
---|
305 | (void)memcpy(ea->arp_tpa, tip, sizeof(ea->arp_tpa)); |
---|
306 | sa.sa_family = AF_UNSPEC; |
---|
307 | sa.sa_len = sizeof(sa); |
---|
308 | (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0); |
---|
309 | } |
---|
310 | |
---|
311 | /* |
---|
312 | * Resolve an IP address into an ethernet address. If success, |
---|
313 | * desten is filled in. If there is no entry in arptab, |
---|
314 | * set one up and broadcast a request for the IP address. |
---|
315 | * Hold onto this mbuf and resend it once the address |
---|
316 | * is finally resolved. A return value of 1 indicates |
---|
317 | * that desten has been filled in and the packet should be sent |
---|
318 | * normally; a 0 return indicates that the packet has been |
---|
319 | * taken over here, either now or for later transmission. |
---|
320 | */ |
---|
321 | int |
---|
322 | arpresolve( |
---|
323 | struct arpcom *ac, |
---|
324 | struct rtentry *rt, |
---|
325 | struct mbuf *m, |
---|
326 | struct sockaddr *dst, |
---|
327 | u_char *desten, |
---|
328 | struct rtentry *rt0) |
---|
329 | { |
---|
330 | struct llinfo_arp *la = 0; |
---|
331 | struct sockaddr_dl *sdl; |
---|
332 | |
---|
333 | if (m->m_flags & M_BCAST) { /* broadcast */ |
---|
334 | (void)memcpy(desten, etherbroadcastaddr, sizeof(etherbroadcastaddr)); |
---|
335 | return (1); |
---|
336 | } |
---|
337 | if (m->m_flags & M_MCAST) { /* multicast */ |
---|
338 | ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten); |
---|
339 | return(1); |
---|
340 | } |
---|
341 | if (rt) |
---|
342 | la = (struct llinfo_arp *)rt->rt_llinfo; |
---|
343 | else { |
---|
344 | la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0); |
---|
345 | if (la) |
---|
346 | rt = la->la_rt; |
---|
347 | } |
---|
348 | if (la == 0 || rt == 0) { |
---|
349 | log(LOG_DEBUG, "arpresolve: can't allocate llinfo for %s\n", |
---|
350 | inet_ntoa(SIN(dst)->sin_addr)); |
---|
351 | m_freem(m); |
---|
352 | return (0); |
---|
353 | } |
---|
354 | sdl = SDL(rt->rt_gateway); |
---|
355 | /* |
---|
356 | * Check the address family and length is valid, the address |
---|
357 | * is resolved; otherwise, try to resolve. |
---|
358 | */ |
---|
359 | if ((rt->rt_expire == 0 || rt->rt_expire > rtems_bsdnet_seconds_since_boot()) && |
---|
360 | sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) { |
---|
361 | bcopy(LLADDR(sdl), desten, sdl->sdl_alen); |
---|
362 | return 1; |
---|
363 | } |
---|
364 | /* |
---|
365 | * There is an arptab entry, but no ethernet address |
---|
366 | * response yet. Replace the held mbuf with this |
---|
367 | * latest one. |
---|
368 | */ |
---|
369 | if (la->la_hold) |
---|
370 | m_freem(la->la_hold); |
---|
371 | la->la_hold = m; |
---|
372 | if (rt->rt_expire) { |
---|
373 | rt->rt_flags &= ~RTF_REJECT; |
---|
374 | if (la->la_asked == 0 || rt->rt_expire != rtems_bsdnet_seconds_since_boot()) { |
---|
375 | rt->rt_expire = rtems_bsdnet_seconds_since_boot(); |
---|
376 | if (la->la_asked++ < arp_maxtries) |
---|
377 | arprequest(ac, |
---|
378 | &(SIN(rt->rt_ifa->ifa_addr)->sin_addr), |
---|
379 | &(SIN(dst)->sin_addr), |
---|
380 | ac->ac_enaddr); |
---|
381 | else { |
---|
382 | rt->rt_flags |= RTF_REJECT; |
---|
383 | rt->rt_expire += arpt_down; |
---|
384 | la->la_asked = 0; |
---|
385 | } |
---|
386 | |
---|
387 | } |
---|
388 | } |
---|
389 | return (0); |
---|
390 | } |
---|
391 | |
---|
392 | /* |
---|
393 | * Common length and type checks are done here, |
---|
394 | * then the protocol-specific routine is called. |
---|
395 | */ |
---|
396 | void |
---|
397 | arpintr(void) |
---|
398 | { |
---|
399 | struct mbuf *m; |
---|
400 | struct arphdr *ar; |
---|
401 | int s; |
---|
402 | |
---|
403 | while (arpintrq.ifq_head) { |
---|
404 | s = splimp(); |
---|
405 | IF_DEQUEUE(&arpintrq, m); |
---|
406 | splx(s); |
---|
407 | if (m == 0 || (m->m_flags & M_PKTHDR) == 0) |
---|
408 | panic("arpintr"); |
---|
409 | if (m->m_len >= sizeof(struct arphdr) && |
---|
410 | (ar = mtod(m, struct arphdr *)) && |
---|
411 | ntohs(ar->ar_hrd) == ARPHRD_ETHER && |
---|
412 | m->m_len >= |
---|
413 | sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln) |
---|
414 | |
---|
415 | switch (ntohs(ar->ar_pro)) { |
---|
416 | |
---|
417 | case ETHERTYPE_IP: |
---|
418 | in_arpinput(m); |
---|
419 | continue; |
---|
420 | } |
---|
421 | m_freem(m); |
---|
422 | } |
---|
423 | } |
---|
424 | |
---|
425 | NETISR_SET(NETISR_ARP, arpintr); |
---|
426 | |
---|
427 | /* |
---|
428 | * ARP for Internet protocols on 10 Mb/s Ethernet. |
---|
429 | * Algorithm is that given in RFC 826. |
---|
430 | * In addition, a sanity check is performed on the sender |
---|
431 | * protocol address, to catch impersonators. |
---|
432 | * We no longer handle negotiations for use of trailer protocol: |
---|
433 | * Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent |
---|
434 | * along with IP replies if we wanted trailers sent to us, |
---|
435 | * and also sent them in response to IP replies. |
---|
436 | * This allowed either end to announce the desire to receive |
---|
437 | * trailer packets. |
---|
438 | * We no longer reply to requests for ETHERTYPE_TRAIL protocol either, |
---|
439 | * but formerly didn't normally send requests. |
---|
440 | */ |
---|
441 | static void |
---|
442 | in_arpinput(struct mbuf *m) |
---|
443 | { |
---|
444 | struct ether_arp *ea; |
---|
445 | struct arpcom *ac = (struct arpcom *)m->m_pkthdr.rcvif; |
---|
446 | struct ether_header *eh; |
---|
447 | struct llinfo_arp *la = 0; |
---|
448 | struct rtentry *rt; |
---|
449 | struct in_ifaddr *ia; |
---|
450 | struct in_ifaddr *maybe_ia = 0; |
---|
451 | struct sockaddr_dl *sdl; |
---|
452 | struct sockaddr sa; |
---|
453 | struct in_addr isaddr, itaddr, myaddr; |
---|
454 | int op; |
---|
455 | |
---|
456 | ea = mtod(m, struct ether_arp *); |
---|
457 | op = ntohs(ea->arp_op); |
---|
458 | (void)memcpy(&isaddr, ea->arp_spa, sizeof (isaddr)); |
---|
459 | (void)memcpy(&itaddr, ea->arp_tpa, sizeof (itaddr)); |
---|
460 | for (ia = in_ifaddr; ia; ia = ia->ia_next) |
---|
461 | if (ia->ia_ifp == &ac->ac_if) { |
---|
462 | maybe_ia = ia; |
---|
463 | if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) || |
---|
464 | (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr)) |
---|
465 | break; |
---|
466 | } |
---|
467 | if (maybe_ia == 0) { |
---|
468 | m_freem(m); |
---|
469 | return; |
---|
470 | } |
---|
471 | myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr; |
---|
472 | if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr, |
---|
473 | sizeof (ea->arp_sha))) { |
---|
474 | m_freem(m); /* it's from me, ignore it. */ |
---|
475 | return; |
---|
476 | } |
---|
477 | if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr, |
---|
478 | sizeof (ea->arp_sha))) { |
---|
479 | log(LOG_ERR, |
---|
480 | "arp: ether address is broadcast for IP address %s!\n", |
---|
481 | inet_ntoa(isaddr)); |
---|
482 | m_freem(m); |
---|
483 | return; |
---|
484 | } |
---|
485 | if (isaddr.s_addr == myaddr.s_addr) { |
---|
486 | log(LOG_ERR, |
---|
487 | "arp: %6D is using my IP address %s!\n", |
---|
488 | ea->arp_sha, ":", inet_ntoa(isaddr)); |
---|
489 | itaddr = myaddr; |
---|
490 | goto reply; |
---|
491 | } |
---|
492 | la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0); |
---|
493 | if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) { |
---|
494 | if (sdl->sdl_alen && |
---|
495 | bcmp((caddr_t)ea->arp_sha, LLADDR(sdl), sdl->sdl_alen)) |
---|
496 | log(LOG_INFO, "arp: %s moved from %6D to %6D\n", |
---|
497 | inet_ntoa(isaddr), (u_char *)LLADDR(sdl), ":", |
---|
498 | ea->arp_sha, ":"); |
---|
499 | (void)memcpy(LLADDR(sdl), ea->arp_sha, sizeof(ea->arp_sha)); |
---|
500 | sdl->sdl_alen = sizeof(ea->arp_sha); |
---|
501 | if (rt->rt_expire) |
---|
502 | rt->rt_expire = rtems_bsdnet_seconds_since_boot() + arpt_keep; |
---|
503 | rt->rt_flags &= ~RTF_REJECT; |
---|
504 | la->la_asked = 0; |
---|
505 | if (la->la_hold) { |
---|
506 | (*ac->ac_if.if_output)(&ac->ac_if, la->la_hold, |
---|
507 | rt_key(rt), rt); |
---|
508 | la->la_hold = 0; |
---|
509 | } |
---|
510 | } |
---|
511 | reply: |
---|
512 | if (op != ARPOP_REQUEST) { |
---|
513 | m_freem(m); |
---|
514 | return; |
---|
515 | } |
---|
516 | if (itaddr.s_addr == myaddr.s_addr) { |
---|
517 | /* I am the target */ |
---|
518 | (void)memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha)); |
---|
519 | (void)memcpy(ea->arp_sha, ac->ac_enaddr, sizeof(ea->arp_sha)); |
---|
520 | } else { |
---|
521 | la = arplookup(itaddr.s_addr, 0, SIN_PROXY); |
---|
522 | if (la == NULL) { |
---|
523 | struct sockaddr_in sin; |
---|
524 | |
---|
525 | if (!arp_proxyall) { |
---|
526 | m_freem(m); |
---|
527 | return; |
---|
528 | } |
---|
529 | |
---|
530 | bzero(&sin, sizeof sin); |
---|
531 | sin.sin_family = AF_INET; |
---|
532 | sin.sin_len = sizeof sin; |
---|
533 | sin.sin_addr = itaddr; |
---|
534 | |
---|
535 | rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL); |
---|
536 | if (!rt) { |
---|
537 | m_freem(m); |
---|
538 | return; |
---|
539 | } |
---|
540 | /* |
---|
541 | * Don't send proxies for nodes on the same interface |
---|
542 | * as this one came out of, or we'll get into a fight |
---|
543 | * over who claims what Ether address. |
---|
544 | */ |
---|
545 | if (rt->rt_ifp == &ac->ac_if) { |
---|
546 | rtfree(rt); |
---|
547 | m_freem(m); |
---|
548 | return; |
---|
549 | } |
---|
550 | (void)memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha)); |
---|
551 | (void)memcpy(ea->arp_sha, ac->ac_enaddr, sizeof(ea->arp_sha)); |
---|
552 | rtfree(rt); |
---|
553 | #ifdef DEBUG_PROXY |
---|
554 | printf("arp: proxying for %s\n", |
---|
555 | inet_ntoa(itaddr)); |
---|
556 | #endif |
---|
557 | } else { |
---|
558 | rt = la->la_rt; |
---|
559 | (void)memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha)); |
---|
560 | sdl = SDL(rt->rt_gateway); |
---|
561 | (void)memcpy(ea->arp_sha, LLADDR(sdl), sizeof(ea->arp_sha)); |
---|
562 | } |
---|
563 | } |
---|
564 | |
---|
565 | (void)memcpy(ea->arp_tpa, ea->arp_spa, sizeof(ea->arp_spa)); |
---|
566 | (void)memcpy(ea->arp_spa, &itaddr, sizeof(ea->arp_spa)); |
---|
567 | ea->arp_op = htons(ARPOP_REPLY); |
---|
568 | ea->arp_pro = htons(ETHERTYPE_IP); /* let's be sure! */ |
---|
569 | eh = (struct ether_header *)sa.sa_data; |
---|
570 | (void)memcpy(eh->ether_dhost, ea->arp_tha, sizeof(eh->ether_dhost)); |
---|
571 | eh->ether_type = htons(ETHERTYPE_ARP); |
---|
572 | sa.sa_family = AF_UNSPEC; |
---|
573 | sa.sa_len = sizeof(sa); |
---|
574 | (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0); |
---|
575 | return; |
---|
576 | } |
---|
577 | |
---|
578 | /* |
---|
579 | * Free an arp entry. |
---|
580 | */ |
---|
581 | static void |
---|
582 | arptfree(struct llinfo_arp *la) |
---|
583 | { |
---|
584 | struct rtentry *rt = la->la_rt; |
---|
585 | struct sockaddr_dl *sdl; |
---|
586 | if (rt == 0) |
---|
587 | panic("arptfree"); |
---|
588 | if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) && |
---|
589 | sdl->sdl_family == AF_LINK) { |
---|
590 | sdl->sdl_alen = 0; |
---|
591 | la->la_asked = 0; |
---|
592 | rt->rt_flags &= ~RTF_REJECT; |
---|
593 | return; |
---|
594 | } |
---|
595 | rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt), |
---|
596 | 0, (struct rtentry **)0); |
---|
597 | } |
---|
598 | /* |
---|
599 | * Lookup or enter a new address in arptab. |
---|
600 | */ |
---|
601 | static struct llinfo_arp * |
---|
602 | arplookup(u_long addr, int create, int proxy) |
---|
603 | { |
---|
604 | struct rtentry *rt; |
---|
605 | static struct sockaddr_inarp sin = {sizeof(sin), AF_INET, 0, { 0 }, { 0 }, 0, 0 }; |
---|
606 | const char *why = 0; |
---|
607 | |
---|
608 | sin.sin_len = sizeof(sin); |
---|
609 | sin.sin_family = AF_INET; |
---|
610 | sin.sin_addr.s_addr = addr; |
---|
611 | sin.sin_other = proxy ? SIN_PROXY : 0; |
---|
612 | rt = rtalloc1((struct sockaddr *)&sin, create, 0UL); |
---|
613 | if (rt == 0) |
---|
614 | return (0); |
---|
615 | rt->rt_refcnt--; |
---|
616 | |
---|
617 | if (rt->rt_flags & RTF_GATEWAY) |
---|
618 | why = "host is not on local network"; |
---|
619 | else if ((rt->rt_flags & RTF_LLINFO) == 0) |
---|
620 | why = "could not allocate llinfo"; |
---|
621 | else if (rt->rt_gateway->sa_family != AF_LINK) |
---|
622 | why = "gateway route is not ours"; |
---|
623 | |
---|
624 | if (why && create) { |
---|
625 | log(LOG_DEBUG, "arplookup %s failed: %s\n", |
---|
626 | inet_ntoa(sin.sin_addr), why); |
---|
627 | return 0; |
---|
628 | } else if (why) { |
---|
629 | return 0; |
---|
630 | } |
---|
631 | return ((struct llinfo_arp *)rt->rt_llinfo); |
---|
632 | } |
---|
633 | |
---|
634 | void |
---|
635 | arp_ifinit(struct arpcom *ac, struct ifaddr *ifa) |
---|
636 | { |
---|
637 | if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) |
---|
638 | arprequest(ac, &(IA_SIN(ifa)->sin_addr), |
---|
639 | &(IA_SIN(ifa)->sin_addr), ac->ac_enaddr); |
---|
640 | ifa->ifa_rtrequest = arp_rtrequest; |
---|
641 | ifa->ifa_flags |= RTF_CLONING; |
---|
642 | } |
---|