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