|
|
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: /*
21: * Internet to ethernet address resolution table.
22: */
23: struct arptab {
24: struct in_addr at_iaddr; /* internet address */
25: u_char at_enaddr[6]; /* ethernet address */
26: struct mbuf *at_hold; /* last packet until resolved/timeout */
27: u_char at_timer; /* minutes since last reference */
28: u_char at_flags; /* flags */
29: };
30: /* at_flags field values */
31: #define ATF_INUSE 1 /* entry in use */
32: #define ATF_COM 2 /* completed entry (enaddr valid) */
33:
34: #define ARPTAB_BSIZ 5 /* bucket size */
35: #define ARPTAB_NB 19 /* number of buckets */
36: #define ARPTAB_SIZE (ARPTAB_BSIZ * ARPTAB_NB)
37: struct arptab arptab[ARPTAB_SIZE];
38:
39: #define ARPTAB_HASH(a) \
40: ((short)((((a) >> 16) ^ (a)) & 0x7fff) % ARPTAB_NB)
41:
42: #define ARPTAB_LOOK(at,addr) { \
43: register n; \
44: at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \
45: for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \
46: if (at->at_iaddr.s_addr == addr) \
47: break; \
48: if (n >= ARPTAB_BSIZ) \
49: at = 0; }
50:
51: struct arpcom *arpcom; /* chain of active ether interfaces */
52: int arpt_age; /* aging timer */
53:
54: /* timer values */
55: #define ARPT_AGE (60*1) /* aging timer, 1 min. */
56: #define ARPT_KILLC 20 /* kill completed entry in 20 mins. */
57: #define ARPT_KILLI 3 /* kill incomplete entry in 3 minutes */
58:
59: u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
60: extern struct ifnet loif;
61:
62: /*
63: * Local addresses in the range oldmap to infinity are
64: * mapped according to the old mapping scheme. That is,
65: * mapping of Internet to Ethernet addresses is performed
66: * by taking the high three bytes of the network interface's
67: * address and the low three bytes of the local address part.
68: * This only allows boards from the same manufacturer to
69: * communicate unless the on-board address is overridden
70: * (not possible in many manufacture's hardware).
71: *
72: * NB: setting oldmap to zero completely disables ARP
73: * (i.e. identical to setting IFF_NOARP with an ioctl).
74: */
75: int oldmap = 1024;
76:
77: /*
78: * Attach an ethernet interface to the list "arpcom" where
79: * arptimer() can find it. If first time
80: * initialization, start arptimer().
81: */
82: arpattach(ac)
83: register struct arpcom *ac;
84: {
85: register struct arpcom *acp;
86:
87: for (acp = arpcom; acp != (struct arpcom *)0; acp = acp->ac_ac)
88: if (acp == ac) /* if already on list */
89: return;
90: ac->ac_ac = arpcom;
91: arpcom = ac;
92: if (arpcom->ac_ac == 0) /* very first time */
93: arptimer();
94: }
95:
96: /*
97: * Timeout routine. Age arp_tab entries once a minute.
98: */
99: arptimer()
100: {
101: register struct arptab *at;
102: register i;
103:
104: timeout(arptimer, (caddr_t)0, hz);
105: #ifdef notdef
106: if (++arpt_sanity > ARPT_SANITY) {
107: register struct arpcom *ac;
108:
109: /*
110: * Randomize sanity timer based on my host address.
111: * Ask who has my own address; if someone else replies,
112: * then they are impersonating me.
113: */
114: arpt_sanity = arpcom->ac_enaddr[5] & 0x3f;
115: for (ac = arpcom; ac != (struct arpcom *)-1; ac = ac->ac_ac)
116: arpwhohas(ac, &((struct sockaddr_in *)
117: &ac->ac_if.if_addr)->sin_addr);
118: }
119: #endif
120: if (++arpt_age > ARPT_AGE) {
121: arpt_age = 0;
122: at = &arptab[0];
123: for (i = 0; i < ARPTAB_SIZE; i++, at++) {
124: if (at->at_flags == 0)
125: continue;
126: if (++at->at_timer < ((at->at_flags&ATF_COM) ?
127: ARPT_KILLC : ARPT_KILLI))
128: continue;
129: /* timer has expired, clear entry */
130: arptfree(at);
131: }
132: }
133: }
134:
135: /*
136: * Broadcast an ARP packet, asking who has addr on interface ac.
137: */
138: arpwhohas(ac, addr)
139: register struct arpcom *ac;
140: struct in_addr *addr;
141: {
142: register struct mbuf *m;
143: register struct ether_header *eh;
144: register struct ether_arp *ea;
145: struct sockaddr sa;
146:
147: if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL)
148: return;
149: m->m_len = sizeof *ea + sizeof *eh;
150: m->m_off = MMAXOFF - m->m_len;
151: ea = mtod(m, struct ether_arp *);
152: eh = (struct ether_header *)sa.sa_data;
153: bzero((caddr_t)ea, sizeof (*ea));
154: bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
155: sizeof (etherbroadcastaddr));
156: eh->ether_type = ETHERPUP_ARPTYPE; /* if_output will swap */
157: ea->arp_hrd = htons(ARPHRD_ETHER);
158: ea->arp_pro = htons(ETHERPUP_IPTYPE);
159: ea->arp_hln = sizeof ea->arp_sha; /* hardware address length */
160: ea->arp_pln = sizeof ea->arp_spa; /* protocol address length */
161: ea->arp_op = htons(ARPOP_REQUEST);
162: bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
163: sizeof (ea->arp_sha));
164: bcopy((caddr_t)&((struct sockaddr_in *)&ac->ac_if.if_addr)->sin_addr,
165: (caddr_t)ea->arp_spa, sizeof (ea->arp_spa));
166: bcopy((caddr_t)addr, (caddr_t)ea->arp_tpa, sizeof (ea->arp_tpa));
167: sa.sa_family = AF_UNSPEC;
168: (void) (*ac->ac_if.if_output)(&ac->ac_if, m, &sa);
169: }
170:
171: /*
172: * Resolve an IP address into an ethernet address. If success,
173: * desten is filled in and 1 is returned. If there is no entry
174: * in arptab, set one up and broadcast a request
175: * for the IP address; return 0. Hold onto this mbuf and
176: * resend it once the address is finally resolved.
177: *
178: * We do some (conservative) locking here at splimp, since
179: * arptab is also altered from input interrupt service (ecintr/ilintr
180: * calls arpinput when ETHERPUP_ARPTYPE packets come in).
181: */
182: arpresolve(ac, m, destip, desten)
183: register struct arpcom *ac;
184: struct mbuf *m;
185: register struct in_addr *destip;
186: register u_char *desten;
187: {
188: register struct arptab *at;
189: register struct ifnet *ifp;
190: struct sockaddr_in sin;
191: int s, lna;
192:
193: lna = in_lnaof(*destip);
194: if (lna == INADDR_ANY) { /* broadcast address */
195: bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten,
196: sizeof (etherbroadcastaddr));
197: return (1);
198: }
199: ifp = &ac->ac_if;
200: /* if for us, then use software loopback driver */
201: if (destip->s_addr ==
202: ((struct sockaddr_in *)&ifp->if_addr)-> sin_addr.s_addr) {
203: sin.sin_family = AF_INET;
204: sin.sin_addr = *destip;
205: return (looutput(&loif, m, (struct sockaddr *)&sin));
206: }
207: if ((ifp->if_flags & IFF_NOARP) || lna >= oldmap) {
208: bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3);
209: desten[3] = (lna >> 16) & 0x7f;
210: desten[4] = (lna >> 8) & 0xff;
211: desten[5] = lna & 0xff;
212: return (1);
213: }
214: s = splimp();
215: ARPTAB_LOOK(at, destip->s_addr);
216: if (at == 0) { /* not found */
217: at = arptnew(destip);
218: at->at_hold = m;
219: arpwhohas(ac, destip);
220: splx(s);
221: return (0);
222: }
223: at->at_timer = 0; /* restart the timer */
224: if (at->at_flags & ATF_COM) { /* entry IS complete */
225: bcopy((caddr_t)at->at_enaddr, (caddr_t)desten, 6);
226: splx(s);
227: return (1);
228: }
229: /*
230: * There is an arptab entry, but no ethernet address
231: * response yet. Replace the held mbuf with this
232: * latest one.
233: */
234: if (at->at_hold)
235: m_freem(at->at_hold);
236: at->at_hold = m;
237: arpwhohas(ac, destip); /* ask again */
238: splx(s);
239: return (0);
240: }
241:
242: /*
243: * Find my own IP address. It will either be waiting for us in
244: * monitor RAM, or can be obtained via broadcast to the file/boot
245: * server (not necessarily using the ARP packet format).
246: *
247: * Unimplemented at present, return 0 and assume that the host
248: * will set his own IP address via the SIOCSIFADDR ioctl.
249: */
250: /*ARGSUSED*/
251: struct in_addr
252: arpmyaddr(ac)
253: register struct arpcom *ac;
254: {
255: static struct in_addr addr;
256:
257: #ifdef lint
258: ac = ac;
259: #endif
260: addr.s_addr = 0;
261: return (addr);
262: }
263:
264: /*
265: * Called from ecintr/ilintr when ether packet type ETHERPUP_ARP
266: * is received. Algorithm is exactly that given in RFC 826.
267: * In addition, a sanity check is performed on the sender
268: * protocol address, to catch impersonators.
269: */
270: arpinput(ac, m)
271: register struct arpcom *ac;
272: struct mbuf *m;
273: {
274: register struct ether_arp *ea;
275: struct ether_header *eh;
276: register struct arptab *at = 0; /* same as "merge" flag */
277: struct sockaddr_in sin;
278: struct sockaddr sa;
279: struct mbuf *mhold;
280: struct in_addr isaddr,itaddr,myaddr;
281:
282: if (m->m_len < sizeof *ea)
283: goto out;
284: myaddr = ((struct sockaddr_in *)&ac->ac_if.if_addr)->sin_addr;
285: ea = mtod(m, struct ether_arp *);
286: if (ntohs(ea->arp_pro) != ETHERPUP_IPTYPE)
287: goto out;
288: isaddr.s_addr = ((struct in_addr *)ea->arp_spa)->s_addr;
289: itaddr.s_addr = ((struct in_addr *)ea->arp_tpa)->s_addr;
290: if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
291: sizeof (ac->ac_enaddr)))
292: goto out; /* it's from me, ignore it. */
293: if (isaddr.s_addr == myaddr.s_addr) {
294: printf("duplicate IP address!! sent from ethernet address: ");
295: printf("%x %x %x %x %x %x\n", ea->arp_sha[0], ea->arp_sha[1],
296: ea->arp_sha[2], ea->arp_sha[3],
297: ea->arp_sha[4], ea->arp_sha[5]);
298: if (ntohs(ea->arp_op) == ARPOP_REQUEST)
299: goto reply;
300: goto out;
301: }
302: ARPTAB_LOOK(at, isaddr.s_addr);
303: if (at) {
304: bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
305: sizeof (ea->arp_sha));
306: at->at_flags |= ATF_COM;
307: if (at->at_hold) {
308: mhold = at->at_hold;
309: at->at_hold = 0;
310: sin.sin_family = AF_INET;
311: sin.sin_addr = isaddr;
312: (*ac->ac_if.if_output)(&ac->ac_if,
313: mhold, (struct sockaddr *)&sin);
314: }
315: }
316: if (itaddr.s_addr != myaddr.s_addr)
317: goto out; /* if I am not the target */
318: if (at == 0) { /* ensure we have a table entry */
319: at = arptnew(&isaddr);
320: bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
321: sizeof (ea->arp_sha));
322: at->at_flags |= ATF_COM;
323: }
324: if (ntohs(ea->arp_op) != ARPOP_REQUEST)
325: goto out;
326: reply:
327: bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
328: sizeof (ea->arp_sha));
329: bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa,
330: sizeof (ea->arp_spa));
331: bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
332: sizeof (ea->arp_sha));
333: bcopy((caddr_t)&myaddr, (caddr_t)ea->arp_spa,
334: sizeof (ea->arp_spa));
335: ea->arp_op = htons(ARPOP_REPLY);
336: eh = (struct ether_header *)sa.sa_data;
337: bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
338: sizeof (eh->ether_dhost));
339: eh->ether_type = ETHERPUP_ARPTYPE;
340: sa.sa_family = AF_UNSPEC;
341: (*ac->ac_if.if_output)(&ac->ac_if, m, &sa);
342: return;
343: out:
344: m_freem(m);
345: return;
346: }
347:
348: /*
349: * Free an arptab entry.
350: */
351: arptfree(at)
352: register struct arptab *at;
353: {
354: int s = splimp();
355:
356: if (at->at_hold)
357: m_freem(at->at_hold);
358: at->at_hold = 0;
359: at->at_timer = at->at_flags = 0;
360: at->at_iaddr.s_addr = 0;
361: splx(s);
362: }
363:
364: /*
365: * Enter a new address in arptab, pushing out the oldest entry
366: * from the bucket if there is no room.
367: */
368: struct arptab *
369: arptnew(addr)
370: struct in_addr *addr;
371: {
372: register n;
373: int oldest = 0;
374: register struct arptab *at, *ato;
375:
376: ato = at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ];
377: for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) {
378: if (at->at_flags == 0)
379: goto out; /* found an empty entry */
380: if (at->at_timer > oldest) {
381: oldest = at->at_timer;
382: ato = at;
383: }
384: }
385: at = ato;
386: arptfree(at);
387: out:
388: at->at_iaddr = *addr;
389: at->at_flags = ATF_INUSE;
390: return (at);
391: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.