fix carrier drop handling in ttread & try improving LCASE mode
[unix-history] / usr / src / sys / netinet / if_ether.c
CommitLineData
36e09a72 1/* if_ether.c 6.9 85/04/24 */
2b0e2bab
SL
2
3/*
4 * Ethernet address resolution protocol.
5 */
6
20666ad3
JB
7#include "param.h"
8#include "systm.h"
9#include "mbuf.h"
10#include "socket.h"
11#include "time.h"
12#include "kernel.h"
13#include "errno.h"
14#include "ioctl.h"
2b0e2bab
SL
15
16#include "../net/if.h"
20666ad3
JB
17#include "in.h"
18#include "in_systm.h"
19#include "ip.h"
20#include "if_ether.h"
2b0e2bab 21
2b0e2bab
SL
22#define ARPTAB_BSIZ 5 /* bucket size */
23#define ARPTAB_NB 19 /* number of buckets */
24#define ARPTAB_SIZE (ARPTAB_BSIZ * ARPTAB_NB)
25struct arptab arptab[ARPTAB_SIZE];
07847ffa 26int arptab_size = ARPTAB_SIZE; /* for arp command */
2b0e2bab
SL
27
28#define ARPTAB_HASH(a) \
29 ((short)((((a) >> 16) ^ (a)) & 0x7fff) % ARPTAB_NB)
30
31#define ARPTAB_LOOK(at,addr) { \
32 register n; \
33 at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \
34 for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \
35 if (at->at_iaddr.s_addr == addr) \
36 break; \
37 if (n >= ARPTAB_BSIZ) \
38 at = 0; }
39
2b0e2bab
SL
40int arpt_age; /* aging timer */
41
42/* timer values */
43#define ARPT_AGE (60*1) /* aging timer, 1 min. */
44#define ARPT_KILLC 20 /* kill completed entry in 20 mins. */
45#define ARPT_KILLI 3 /* kill incomplete entry in 3 minutes */
46
9350cacc 47u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
2b0e2bab
SL
48extern struct ifnet loif;
49
1a259c14
SL
50/*
51 * Local addresses in the range oldmap to infinity are
52 * mapped according to the old mapping scheme. That is,
53 * mapping of Internet to Ethernet addresses is performed
54 * by taking the high three bytes of the network interface's
55 * address and the low three bytes of the local address part.
56 * This only allows boards from the same manufacturer to
57 * communicate unless the on-board address is overridden
58 * (not possible in many manufacture's hardware).
59 *
60 * NB: setting oldmap to zero completely disables ARP
61 * (i.e. identical to setting IFF_NOARP with an ioctl).
62 */
63int oldmap = 1024;
2b0e2bab 64
2b0e2bab
SL
65/*
66 * Timeout routine. Age arp_tab entries once a minute.
67 */
68arptimer()
69{
2b0e2bab
SL
70 register struct arptab *at;
71 register i;
72
755d8841 73 timeout(arptimer, (caddr_t)0, hz);
2b0e2bab
SL
74 if (++arpt_age > ARPT_AGE) {
75 arpt_age = 0;
76 at = &arptab[0];
77 for (i = 0; i < ARPTAB_SIZE; i++, at++) {
07847ffa 78 if (at->at_flags == 0 || (at->at_flags & ATF_PERM))
2b0e2bab
SL
79 continue;
80 if (++at->at_timer < ((at->at_flags&ATF_COM) ?
81 ARPT_KILLC : ARPT_KILLI))
82 continue;
83 /* timer has expired, clear entry */
84 arptfree(at);
85 }
86 }
87}
88
89/*
90 * Broadcast an ARP packet, asking who has addr on interface ac.
91 */
92arpwhohas(ac, addr)
93 register struct arpcom *ac;
94 struct in_addr *addr;
95{
96 register struct mbuf *m;
97 register struct ether_header *eh;
98 register struct ether_arp *ea;
99 struct sockaddr sa;
100
101 if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL)
07847ffa 102 return (1);
b5bc9bc1 103 m->m_len = sizeof *ea;
2b0e2bab
SL
104 m->m_off = MMAXOFF - m->m_len;
105 ea = mtod(m, struct ether_arp *);
106 eh = (struct ether_header *)sa.sa_data;
755d8841 107 bzero((caddr_t)ea, sizeof (*ea));
9350cacc
MK
108 bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
109 sizeof(eh->ether_dhost));
935a6d59 110 eh->ether_type = ETHERTYPE_ARP; /* if_output will swap */
2b0e2bab 111 ea->arp_hrd = htons(ARPHRD_ETHER);
935a6d59 112 ea->arp_pro = htons(ETHERTYPE_IP);
9350cacc
MK
113 ea->arp_hln = sizeof(ea->arp_sha); /* hardware address length */
114 ea->arp_pln = sizeof(ea->arp_spa); /* protocol address length */
2b0e2bab 115 ea->arp_op = htons(ARPOP_REQUEST);
9350cacc
MK
116 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
117 sizeof(ea->arp_sha));
118 bcopy((caddr_t)&ac->ac_ipaddr, (caddr_t)ea->arp_spa,
119 sizeof(ea->arp_spa));
120 bcopy((caddr_t)addr, (caddr_t)ea->arp_tpa, sizeof(ea->arp_tpa));
2b0e2bab 121 sa.sa_family = AF_UNSPEC;
07847ffa 122 return ((*ac->ac_if.if_output)(&ac->ac_if, m, &sa));
2b0e2bab
SL
123}
124
125/*
126 * Resolve an IP address into an ethernet address. If success,
127 * desten is filled in and 1 is returned. If there is no entry
128 * in arptab, set one up and broadcast a request
129 * for the IP address; return 0. Hold onto this mbuf and
130 * resend it once the address is finally resolved.
131 *
132 * We do some (conservative) locking here at splimp, since
133 * arptab is also altered from input interrupt service (ecintr/ilintr
935a6d59 134 * calls arpinput when ETHERTYPE_ARP packets come in).
2b0e2bab
SL
135 */
136arpresolve(ac, m, destip, desten)
137 register struct arpcom *ac;
138 struct mbuf *m;
139 register struct in_addr *destip;
9350cacc 140 register u_char *desten;
2b0e2bab
SL
141{
142 register struct arptab *at;
1a259c14 143 register struct ifnet *ifp;
07847ffa 144 register int i;
2b0e2bab
SL
145 struct sockaddr_in sin;
146 int s, lna;
147
935a6d59 148 if (in_broadcast(*destip)) { /* broadcast address */
9350cacc
MK
149 bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten,
150 sizeof(etherbroadcastaddr));
2b0e2bab
SL
151 return (1);
152 }
935a6d59 153 lna = in_lnaof(*destip);
1a259c14
SL
154 ifp = &ac->ac_if;
155 /* if for us, then use software loopback driver */
935a6d59 156 if (destip->s_addr == ac->ac_ipaddr.s_addr &&
07847ffa 157 (loif.if_flags & IFF_UP)) {
2b0e2bab
SL
158 sin.sin_family = AF_INET;
159 sin.sin_addr = *destip;
b746b290
SL
160 (void) looutput(&loif, m, (struct sockaddr *)&sin);
161 /*
162 * We really don't want to indicate failure,
163 * but the packet has already been sent and freed.
164 */
165 return (0);
2b0e2bab 166 }
2b0e2bab
SL
167 s = splimp();
168 ARPTAB_LOOK(at, destip->s_addr);
169 if (at == 0) { /* not found */
07847ffa 170 if ((ifp->if_flags & IFF_NOARP) || lna >= oldmap) {
9350cacc
MK
171 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3);
172 desten[3] = (lna >> 16) & 0x7f;
173 desten[4] = (lna >> 8) & 0xff;
174 desten[5] = lna & 0xff;
07847ffa
MK
175 splx(s);
176 return (1);
177 } else {
178 at = arptnew(destip);
179 at->at_hold = m;
180 arpwhohas(ac, destip);
181 splx(s);
182 return (0);
183 }
2b0e2bab
SL
184 }
185 at->at_timer = 0; /* restart the timer */
186 if (at->at_flags & ATF_COM) { /* entry IS complete */
9350cacc
MK
187 bcopy((caddr_t)at->at_enaddr, (caddr_t)desten,
188 sizeof(at->at_enaddr));
2b0e2bab
SL
189 splx(s);
190 return (1);
191 }
192 /*
193 * There is an arptab entry, but no ethernet address
194 * response yet. Replace the held mbuf with this
195 * latest one.
196 */
197 if (at->at_hold)
198 m_freem(at->at_hold);
199 at->at_hold = m;
200 arpwhohas(ac, destip); /* ask again */
201 splx(s);
202 return (0);
203}
204
2b0e2bab 205/*
935a6d59
MK
206 * Called from 10 Mb/s Ethernet interrupt handlers
207 * when ether packet type ETHERTYPE_ARP
07847ffa 208 * is received. Algorithm is that given in RFC 826.
2b0e2bab
SL
209 * In addition, a sanity check is performed on the sender
210 * protocol address, to catch impersonators.
211 */
212arpinput(ac, m)
213 register struct arpcom *ac;
214 struct mbuf *m;
215{
216 register struct ether_arp *ea;
217 struct ether_header *eh;
218 register struct arptab *at = 0; /* same as "merge" flag */
219 struct sockaddr_in sin;
220 struct sockaddr sa;
2b0e2bab
SL
221 struct in_addr isaddr,itaddr,myaddr;
222
223 if (m->m_len < sizeof *ea)
224 goto out;
07847ffa
MK
225 if (ac->ac_if.if_flags & IFF_NOARP)
226 goto out;
935a6d59 227 myaddr = ac->ac_ipaddr;
2b0e2bab 228 ea = mtod(m, struct ether_arp *);
935a6d59 229 if (ntohs(ea->arp_pro) != ETHERTYPE_IP)
2b0e2bab 230 goto out;
9350cacc
MK
231 isaddr.s_addr = ((struct in_addr *)ea->arp_spa)->s_addr;
232 itaddr.s_addr = ((struct in_addr *)ea->arp_tpa)->s_addr;
233 if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
234 sizeof (ea->arp_sha)))
2b0e2bab
SL
235 goto out; /* it's from me, ignore it. */
236 if (isaddr.s_addr == myaddr.s_addr) {
237 printf("duplicate IP address!! sent from ethernet address: ");
9350cacc
MK
238 printf("%x %x %x %x %x %x\n", ea->arp_sha[0], ea->arp_sha[1],
239 ea->arp_sha[2], ea->arp_sha[3],
240 ea->arp_sha[4], ea->arp_sha[5]);
07847ffa 241 itaddr = myaddr;
9350cacc
MK
242 if (ntohs(ea->arp_op) == ARPOP_REQUEST) {
243 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
244 sizeof(ea->arp_sha));
2b0e2bab 245 goto reply;
9350cacc 246 }
2b0e2bab
SL
247 goto out;
248 }
249 ARPTAB_LOOK(at, isaddr.s_addr);
36e09a72 250 if (at && (at->at_flags & ATF_COM) == 0) {
9350cacc
MK
251 bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
252 sizeof(ea->arp_sha));
2b0e2bab
SL
253 at->at_flags |= ATF_COM;
254 if (at->at_hold) {
2b0e2bab
SL
255 sin.sin_family = AF_INET;
256 sin.sin_addr = isaddr;
257 (*ac->ac_if.if_output)(&ac->ac_if,
36e09a72
MK
258 at->at_hold, (struct sockaddr *)&sin);
259 at->at_hold = 0;
2b0e2bab 260 }
36e09a72
MK
261 }
262 if (at == 0 && itaddr.s_addr == myaddr.s_addr) {
07847ffa 263 /* ensure we have a table entry */
2b0e2bab 264 at = arptnew(&isaddr);
9350cacc
MK
265 bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
266 sizeof(ea->arp_sha));
2b0e2bab
SL
267 at->at_flags |= ATF_COM;
268 }
269 if (ntohs(ea->arp_op) != ARPOP_REQUEST)
270 goto out;
07847ffa
MK
271 ARPTAB_LOOK(at, itaddr.s_addr);
272 if (at == NULL) {
273 if (itaddr.s_addr != myaddr.s_addr)
274 goto out; /* if I am not the target */
275 at = arptnew(&myaddr);
9350cacc
MK
276 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)at->at_enaddr,
277 sizeof(at->at_enaddr));
07847ffa
MK
278 at->at_flags |= ATF_COM;
279 }
280 if (itaddr.s_addr != myaddr.s_addr && (at->at_flags & ATF_PUBL) == 0)
281 goto out;
282
2b0e2bab 283reply:
9350cacc
MK
284 bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
285 sizeof(ea->arp_sha));
286 bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa,
287 sizeof(ea->arp_spa));
36e09a72
MK
288 if (at) /* done above if at == 0 */
289 bcopy((caddr_t)at->at_enaddr, (caddr_t)ea->arp_sha,
290 sizeof(ea->arp_sha));
9350cacc
MK
291 bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa,
292 sizeof(ea->arp_spa));
2b0e2bab
SL
293 ea->arp_op = htons(ARPOP_REPLY);
294 eh = (struct ether_header *)sa.sa_data;
9350cacc
MK
295 bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
296 sizeof(eh->ether_dhost));
935a6d59 297 eh->ether_type = ETHERTYPE_ARP;
2b0e2bab
SL
298 sa.sa_family = AF_UNSPEC;
299 (*ac->ac_if.if_output)(&ac->ac_if, m, &sa);
300 return;
301out:
302 m_freem(m);
303 return;
304}
305
306/*
307 * Free an arptab entry.
308 */
309arptfree(at)
310 register struct arptab *at;
311{
312 int s = splimp();
313
314 if (at->at_hold)
315 m_freem(at->at_hold);
316 at->at_hold = 0;
317 at->at_timer = at->at_flags = 0;
318 at->at_iaddr.s_addr = 0;
319 splx(s);
320}
321
322/*
323 * Enter a new address in arptab, pushing out the oldest entry
324 * from the bucket if there is no room.
07847ffa
MK
325 * This always succeeds since no bucket can be completely filled
326 * with permanent entries (except from arpioctl when testing whether
9350cacc 327 * another permanent entry will fit).
2b0e2bab
SL
328 */
329struct arptab *
330arptnew(addr)
331 struct in_addr *addr;
332{
333 register n;
334 int oldest = 0;
07847ffa
MK
335 register struct arptab *at, *ato = NULL;
336 static int first = 1;
2b0e2bab 337
07847ffa
MK
338 if (first) {
339 first = 0;
340 timeout(arptimer, (caddr_t)0, hz);
341 }
342 at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ];
9350cacc 343 for (n = 0; n < ARPTAB_BSIZ; n++,at++) {
2b0e2bab
SL
344 if (at->at_flags == 0)
345 goto out; /* found an empty entry */
07847ffa
MK
346 if (at->at_flags & ATF_PERM)
347 continue;
2b0e2bab
SL
348 if (at->at_timer > oldest) {
349 oldest = at->at_timer;
350 ato = at;
351 }
352 }
07847ffa 353 if (ato == NULL)
9350cacc 354 return (NULL);
2b0e2bab
SL
355 at = ato;
356 arptfree(at);
357out:
358 at->at_iaddr = *addr;
359 at->at_flags = ATF_INUSE;
360 return (at);
361}
07847ffa
MK
362
363arpioctl(cmd, data)
364 int cmd;
365 caddr_t data;
366{
367 register struct arpreq *ar = (struct arpreq *)data;
368 register struct arptab *at;
369 register struct sockaddr_in *sin;
370 int s;
371
372 if (ar->arp_pa.sa_family != AF_INET ||
373 ar->arp_ha.sa_family != AF_UNSPEC)
374 return (EAFNOSUPPORT);
375 sin = (struct sockaddr_in *)&ar->arp_pa;
376 s = splimp();
377 ARPTAB_LOOK(at, sin->sin_addr.s_addr);
378 if (at == NULL) { /* not found */
379 if (cmd != SIOCSARP) {
380 splx(s);
381 return (ENXIO);
382 }
935a6d59 383 if (ifa_ifwithnet(&ar->arp_pa) == NULL) {
07847ffa
MK
384 splx(s);
385 return (ENETUNREACH);
386 }
387 }
388 switch (cmd) {
389
390 case SIOCSARP: /* set entry */
391 if (at == NULL) {
392 at = arptnew(&sin->sin_addr);
393 if (ar->arp_flags & ATF_PERM) {
394 /* never make all entries in a bucket permanent */
395 register struct arptab *tat;
396
397 /* try to re-allocate */
398 tat = arptnew(&sin->sin_addr);
399 if (tat == NULL) {
400 arptfree(at);
401 splx(s);
402 return (EADDRNOTAVAIL);
403 }
404 arptfree(tat);
405 }
406 }
9350cacc
MK
407 bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->at_enaddr,
408 sizeof(at->at_enaddr));
07847ffa
MK
409 at->at_flags = ATF_COM | ATF_INUSE |
410 (ar->arp_flags & (ATF_PERM|ATF_PUBL));
411 at->at_timer = 0;
412 break;
413
414 case SIOCDARP: /* delete entry */
415 arptfree(at);
416 break;
417
418 case SIOCGARP: /* get entry */
9350cacc
MK
419 bcopy((caddr_t)at->at_enaddr, (caddr_t)ar->arp_ha.sa_data,
420 sizeof(at->at_enaddr));
07847ffa
MK
421 ar->arp_flags = at->at_flags;
422 break;
423 }
424 splx(s);
425 return (0);
426}