|
|
1.1 root 1: /* if_ether.c 6.2 83/08/28 */
2:
3: /*
4: * Ethernet address resolution protocol.
5: */
6:
7: #include "../h/param.h"
8: #include "../h/systm.h"
9: #include "../h/mbuf.h"
10: #include "../h/socket.h"
11: #include "../h/time.h"
12: #include "../h/kernel.h"
13: #include "../h/errno.h"
14:
15: #include "../net/if.h"
16: #include "../netinet/in.h"
17: #include "../netinet/if_ether.h"
18:
19: /*
20: * changes:
21: *
22: * . always return 0 after calling looutput().
23: *
24: * . forces messages going to net if flag gotoether is set.
25: * (set this flag through "adb" for debugging purposes).
26: *
27: * . add symbolic return code to arpresolve(). See comments in
28: * arpresolve().
29: */
30:
31: /*
32: * Internet to ethernet address resolution table.
33: */
34: struct arptab {
35: struct in_addr at_iaddr; /* internet address */
36: u_char at_enaddr[6]; /* ethernet address */
37: struct mbuf *at_hold; /* last packet until resolved/timeout */
38: u_char at_timer; /* minutes since last reference */
39: u_char at_flags; /* flags */
40: };
41: /* at_flags field values */
42: #define ATF_INUSE 1 /* entry in use */
43: #define ATF_COM 2 /* completed entry (enaddr valid) */
44:
45: #define ARPTAB_BSIZ 5 /* bucket size */
46: #define ARPTAB_NB 19 /* number of buckets */
47: #define ARPTAB_SIZE (ARPTAB_BSIZ * ARPTAB_NB)
48: struct arptab arptab[ARPTAB_SIZE];
49:
50: #define ARPTAB_HASH(a) \
51: ((short)((((a) >> 16) ^ (a)) & 0x7fff) % ARPTAB_NB)
52:
53: #define ARPTAB_LOOK(at,addr) { \
54: register n; \
55: at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \
56: for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \
57: if (at->at_iaddr.s_addr == addr) \
58: break; \
59: if (n >= ARPTAB_BSIZ) \
60: at = 0; }
61:
62: struct arpcom *arpcom; /* chain of active ether interfaces */
63: int arpt_age; /* aging timer */
64: int gotoether; /* force traffic to Ethernet; no software
65: loopback */
66:
67: /* timer values */
68: #define ARPT_AGE (60*1) /* aging timer, 1 min. */
69: #define ARPT_KILLC 20 /* kill completed entry in 20 mins. */
70: #define ARPT_KILLI 3 /* kill incomplete entry in 3 minutes */
71:
72: u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
73: extern struct ifnet loif;
74:
75: /*------------- debug tools ---------------*/
76: #ifdef ARPPRINTFS
77: int arpprintfs;
78: # define ARPTRACE(X) {if (arpprintfs) X }
79: #else ARPPRINTFS
80: # define ARPTRACE(X)
81: #endif ARPPRINTFS
82:
83: /*
84: * Local addresses in the range oldmap to infinity are
85: * mapped according to the old mapping scheme. That is,
86: * mapping of Internet to Ethernet addresses is performed
87: * by taking the high three bytes of the network interface's
88: * address and the low three bytes of the local address part.
89: * This only allows boards from the same manufacturer to
90: * communicate unless the on-board address is overridden
91: * (not possible in many manufacture's hardware).
92: *
93: * NB: setting oldmap to zero completely disables ARP
94: * (i.e. identical to setting IFF_NOARP with an ioctl).
95: */
96: int oldmap = 0xffffff;
97:
98: /*
99: * Attach an ethernet interface to the list "arpcom" where
100: * arptimer() can find it. If first time
101: * initialization, start arptimer().
102: */
103: arpattach(ac)
104: register struct arpcom *ac;
105: {
106: register struct arpcom *acp;
107:
108: for (acp = arpcom; acp != (struct arpcom *)0; acp = acp->ac_ac)
109: if (acp == ac) /* if already on list */
110: return;
111: ac->ac_ac = arpcom;
112: arpcom = ac;
113: if (arpcom->ac_ac == 0) /* very first time */
114: arptimer();
115: }
116:
117: /*
118: * Timeout routine. Age arp_tab entries once a minute.
119: */
120: arptimer()
121: {
122: register struct arptab *at;
123: register i;
124:
125: timeout(arptimer, (caddr_t)0, hz);
126: #ifdef notdef
127: if (++arpt_sanity > ARPT_SANITY) {
128: register struct arpcom *ac;
129:
130: /*
131: * Randomize sanity timer based on my host address.
132: * Ask who has my own address; if someone else replies,
133: * then they are impersonating me.
134: */
135: arpt_sanity = arpcom->ac_enaddr[5] & 0x3f;
136: for (ac = arpcom; ac != (struct arpcom *)-1; ac = ac->ac_ac)
137: arpwhohas(ac, &((struct sockaddr_in *)
138: &ac->ac_if.if_addr)->sin_addr);
139: }
140: #endif
141: if (++arpt_age > ARPT_AGE) {
142: arpt_age = 0;
143: at = &arptab[0];
144: for (i = 0; i < ARPTAB_SIZE; i++, at++) {
145: if (at->at_flags == 0)
146: continue;
147: if (++at->at_timer < ((at->at_flags&ATF_COM) ?
148: ARPT_KILLC : ARPT_KILLI))
149: continue;
150: /* timer has expired, clear entry */
151: arptfree(at);
152: }
153: }
154: }
155:
156: /*
157: * Broadcast an ARP packet, asking who has addr on interface ac.
158: */
159: arpwhohas(ac, addr)
160: register struct arpcom *ac;
161: struct in_addr *addr;
162: {
163: register struct mbuf *m;
164: register struct ether_header *eh;
165: register struct ether_arp *ea;
166: struct sockaddr sa;
167:
168: m = m_get(M_DONTWAIT, MT_DATA);
169: MBUFNULL(5,m); /* for debugging */
170: if (m == NULL)
171: return;
172: m->m_len = sizeof *ea + SIZEOF_ETHEADER;
173: m->m_off = MMAXOFF - m->m_len;
174: ea = mtod(m, struct ether_arp *);
175: eh = (struct ether_header *)sa.sa_data;
176: bzero((caddr_t)ea, sizeof (*ea));
177: bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
178: sizeof (etherbroadcastaddr));
179: eh->ether_type = ETHERPUP_ARPTYPE; /* if_output will swap */
180: ea->arp_hrd = htons(ARPHRD_ETHER);
181: ea->arp_pro = htons(ETHERPUP_IPTYPE);
182: ea->arp_hln = sizeof ea->arp_sha; /* hardware address length */
183: ea->arp_pln = sizeof ea->arp_spa; /* protocol address length */
184: ea->arp_op = htons(ARPOP_REQUEST);
185: bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
186: sizeof (ea->arp_sha));
187: bcopy((caddr_t)&((struct sockaddr_in *)&ac->ac_if.if_addr)->sin_addr,
188: (caddr_t)ea->arp_spa, sizeof (ea->arp_spa));
189: bcopy((caddr_t)addr, (caddr_t)ea->arp_tpa, sizeof (ea->arp_tpa));
190: sa.sa_family = AF_UNSPEC;
191: ARPTRACE(printf("arpwhohas:broadcast through %s%d for addr %lx\n",
192: ac->ac_if.if_name, ac->ac_if.if_unit, addr->s_addr);)
193: (void) (*ac->ac_if.if_output)(&ac->ac_if, m, &sa);
194: }
195:
196: /*
197: *
198: * Resolve an IP address into an ethernet address. If success,
199: * desten is filled in and 1 is returned. If there is no entry
200: * in arptab, set one up and broadcast a request
201: * for the IP address; return 0. Hold onto this mbuf and
202: * resend it once the address is finally resolved.
203: *
204: * We do some (conservative) locking here at splimp, since
205: * arptab is also altered from input interrupt service (ecintr/ilintr
206: * calls arpinput when ETHERPUP_ARPTYPE packets come in).
207: *
208: * Returns:
209: *
210: * ARPRESOLVE_WILLSEND
211: * arpresolve() cannot resolve the address. It will send the
212: * packet when it the address is resolved. However, if the
213: * destination is same as origination, arpresolve() does not
214: * resolve address, it routes the packet to software loopback.
215: *
216: * ARPRESOLVE_OK
217: * arpresolve() successfully resolves the address. The calling
218: * routine is responsible for sending out the packet. Address
219: * is not a wild-card (not broadcast).
220: *
221: * ARPRESOLVE_BROADCAST
222: * arpresovle() successfully resolves the address which is
223: * a wildcard. If the controller is NOT capable of listening to
224: * its own broadcast, the device driver is responsible for
225: * routing a copy of the packet to the software loopback.
226: *
227: */
228: arpresolve(ac, m, destip, desten)
229: register struct arpcom *ac;
230: struct mbuf *m;
231: register struct in_addr *destip;
232: register u_char *desten;
233: {
234: register struct arptab *at;
235: register struct ifnet *ifp;
236: struct sockaddr_in sin;
237: int s, lna;
238:
239: lna = in_lnaof(*destip);
240: if (lna == INADDR_ANY) { /* broadcast address */
241: bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten,
242: sizeof (etherbroadcastaddr));
243: return (ARPRESOLVE_BROADCAST);
244: }
245: ifp = &ac->ac_if;
246: /* if for us, then use software loopback driver */
247: if ((destip->s_addr ==
248: ((struct sockaddr_in *)&ifp->if_addr)-> sin_addr.s_addr) &&
249: (gotoether==0)) {
250: sin.sin_family = AF_INET;
251: sin.sin_addr = *destip;
252: looutput(&loif, m, (struct sockaddr *)&sin);
253: return(ARPRESOLVE_WILLSEND);
254: }
255: if ((ifp->if_flags & IFF_NOARP) || lna >= oldmap) {
256: bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3);
257: desten[3] = (lna >> 16) & 0x7f;
258: desten[4] = (lna >> 8) & 0xff;
259: desten[5] = lna & 0xff;
260: return (ARPRESOLVE_OK);
261: }
262: s = splimp();
263: ARPTAB_LOOK(at, destip->s_addr);
264: if (at == 0) { /* not found */
265: at = arptnew(destip);
266: ARPTRACE(printf("arpresolve(%s%d) (m=%lx), arptab empty\n",
267: ac->ac_if.if_name, ac->ac_if.if_unit, m);)
268:
269: ARPTRACE(if (at->at_hold)
270: printf("arpresolve: LOOSE mbuf %lx\n",m);)
271: at->at_hold = m;
272: arpwhohas(ac, destip);
273: splx(s);
274: return (ARPRESOLVE_WILLSEND);
275: }
276: at->at_timer = 0; /* restart the timer */
277: if (at->at_flags & ATF_COM) { /* entry IS complete */
278: bcopy((caddr_t)at->at_enaddr, (caddr_t)desten, 6);
279: splx(s);
280: return (ARPRESOLVE_OK);
281: }
282: /*
283: * There is an arptab entry, but no ethernet address
284: * response yet. Replace the held mbuf with this
285: * latest one.
286: */
287: ARPTRACE(printf("arpresolve(%s%d) (m=%lx), arptab not completed\n",
288: ac->ac_if.if_name, ac->ac_if.if_unit, m);)
289: if (at->at_hold)
290: m_freem(at->at_hold);
291: at->at_hold = m;
292: arpwhohas(ac, destip); /* ask again */
293: splx(s);
294: return (ARPRESOLVE_WILLSEND);
295: }
296:
297: /*
298: * Find my own IP address. It will either be waiting for us in
299: * monitor RAM, or can be obtained via broadcast to the file/boot
300: * server (not necessarily using the ARP packet format).
301: *
302: * Unimplemented at present, return 0 and assume that the host
303: * will set his own IP address via the SIOCSIFADDR ioctl.
304: */
305: /*ARGSUSED*/
306: struct in_addr
307: arpmyaddr(ac)
308: register struct arpcom *ac;
309: {
310: static struct in_addr addr;
311:
312: #ifdef lint
313: ac = ac;
314: #endif
315: addr.s_addr = 0;
316: return (addr);
317: }
318:
319: /*
320: * Called from ecintr/ilintr when ether packet type ETHERPUP_ARP
321: * is received. Algorithm is exactly that given in RFC 826.
322: * In addition, a sanity check is performed on the sender
323: * protocol address, to catch impersonators.
324: */
325: arpinput(ac, m)
326: register struct arpcom *ac;
327: struct mbuf *m;
328: {
329: register struct ether_arp *ea;
330: struct ether_header *eh;
331: register struct arptab *at = 0; /* same as "merge" flag */
332: struct sockaddr_in sin;
333: struct sockaddr sa;
334: struct mbuf *mhold;
335: struct in_addr isaddr,itaddr,myaddr;
336:
337: ARPTRACE(printf("arpinput through %s%d (m=%lx)\n",
338: ac->ac_if.if_name, ac->ac_if.if_unit, m);)
339:
340: if (m->m_len < sizeof *ea)
341: goto out;
342:
343: myaddr = ((struct sockaddr_in *)&ac->ac_if.if_addr)->sin_addr;
344: ea = mtod(m, struct ether_arp *);
345: if (ntohs(ea->arp_pro) != ETHERPUP_IPTYPE)
346: goto out;
347: bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr.s_addr,
348: sizeof (ea->arp_spa));
349: /* isaddr.s_addr = ((struct in_addr *)ea->arp_spa)->s_addr;*/
350: bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr.s_addr,
351: sizeof (ea->arp_spa));
352: /* itaddr.s_addr = ((struct in_addr *)ea->arp_tpa)->s_addr;*/
353: if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
354: sizeof (ac->ac_enaddr)))
355: goto out; /* it's from me, ignore it. */
356:
357: ARPTRACE(printf("\tarpinput (%s%d) sender: %lx, %x.%x.%x.%x.%x.%x, target: %lx, %x.%x.%x.%x.%x.%x\n",
358: ac->ac_if.if_name, ac->ac_if.if_unit,
359: isaddr.s_addr,
360: ea->arp_sha[0] & 0xff, ea->arp_sha[1] & 0xff,
361: ea->arp_sha[2] & 0xff, ea->arp_sha[3] & 0xff,
362: ea->arp_sha[4] & 0xff, ea->arp_sha[5] & 0xff,
363: itaddr.s_addr,
364: ea->arp_tha[0] & 0xff, ea->arp_tha[1] & 0xff,
365: ea->arp_tha[2] & 0xff, ea->arp_tha[3] & 0xff,
366: ea->arp_tha[4] & 0xff, ea->arp_tha[5] & 0xff);)
367:
368: if (isaddr.s_addr == myaddr.s_addr) {
369: printf("duplicate IP address!! sent from ethernet address: ");
370: printf("%x %x %x %x %x %x\n", ea->arp_sha[0], ea->arp_sha[1],
371: ea->arp_sha[2], ea->arp_sha[3],
372: ea->arp_sha[4], ea->arp_sha[5]);
373: if (ntohs(ea->arp_op) == ARPOP_REQUEST)
374: goto reply;
375: goto out;
376: }
377: ARPTAB_LOOK(at, isaddr.s_addr);
378: if (at) {
379: bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
380: sizeof (ea->arp_sha));
381: ARPTRACE(printf("\tarpinput(%s%d). Update sender addr\n",
382: ac->ac_if.if_name, ac->ac_if.if_unit);)
383:
384: at->at_flags |= ATF_COM;
385: if (at->at_hold) {
386: mhold = at->at_hold;
387: at->at_hold = 0;
388: sin.sin_family = AF_INET;
389: sin.sin_addr = isaddr;
390: (*ac->ac_if.if_output)(&ac->ac_if,
391: mhold, (struct sockaddr *)&sin);
392: }
393: }
394: if (itaddr.s_addr != myaddr.s_addr) {
395: ARPTRACE(printf("\tarpinput(%s%d) Iam not the target\n",
396: ac->ac_if.if_name, ac->ac_if.if_unit);)
397: goto out; /* if I am not the target */
398: }
399: if (at == 0) { /* ensure we have a table entry */
400: ARPTRACE(printf("\tarpinput(%s%d). New entry for sender addr\n",
401: ac->ac_if.if_name, ac->ac_if.if_unit);)
402: at = arptnew(&isaddr);
403: bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
404: sizeof (ea->arp_sha));
405: at->at_flags |= ATF_COM;
406: }
407: if (ntohs(ea->arp_op) != ARPOP_REQUEST)
408: goto out;
409: reply:
410: bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
411: sizeof (ea->arp_sha));
412: bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa,
413: sizeof (ea->arp_spa));
414: bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
415: sizeof (ea->arp_sha));
416: bcopy((caddr_t)&myaddr, (caddr_t)ea->arp_spa,
417: sizeof (ea->arp_spa));
418: ea->arp_op = htons(ARPOP_REPLY);
419: eh = (struct ether_header *)sa.sa_data;
420: bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
421: sizeof (eh->ether_dhost));
422: eh->ether_type = ETHERPUP_ARPTYPE;
423: sa.sa_family = AF_UNSPEC;
424:
425: ARPTRACE(bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr.s_addr,
426: sizeof (ea->arp_tpa));)
427: ARPTRACE(printf("\tarpinput(%s%d). Send reply to %lx\n",
428: ac->ac_if.if_name, ac->ac_if.if_unit,itaddr.s_addr);)
429:
430: (*ac->ac_if.if_output)(&ac->ac_if, m, &sa);
431: return;
432: out:
433: m_freem(m);
434: return;
435: }
436:
437: /*
438: * Free an arptab entry.
439: */
440: arptfree(at)
441: register struct arptab *at;
442: {
443: int s = splimp();
444:
445: if (at->at_hold)
446: m_freem(at->at_hold);
447: at->at_hold = 0;
448: at->at_timer = at->at_flags = 0;
449: at->at_iaddr.s_addr = 0;
450: splx(s);
451: }
452:
453: /*
454: * Enter a new address in arptab, pushing out the oldest entry
455: * from the bucket if there is no room.
456: */
457: struct arptab *
458: arptnew(addr)
459: struct in_addr *addr;
460: {
461: register n;
462: int oldest = 0;
463: register struct arptab *at, *ato;
464:
465: ato = at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ];
466: for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) {
467: if (at->at_flags == 0)
468: goto out; /* found an empty entry */
469: if (at->at_timer > oldest) {
470: oldest = at->at_timer;
471: ato = at;
472: }
473: }
474: at = ato;
475: arptfree(at);
476: out:
477: at->at_iaddr = *addr;
478: at->at_flags = ATF_INUSE;
479: return (at);
480: }
481:
482: arpremove(addr)
483: struct sockaddr *addr;
484: {
485: register struct arptab *at;
486: struct in_addr *idst;
487: register long x;
488:
489: idst = &((struct sockaddr_in *)addr)->sin_addr;
490: x = splimp();
491: ARPTAB_LOOK(at, idst->s_addr);
492: if (at) arptfree(at);
493: splx(x);
494: }
495:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.