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