|
|
1.1 root 1: #include "u.h"
2: #include "../port/lib.h"
3: #include "mem.h"
4: #include "dat.h"
5: #include "fns.h"
6: #include "../port/error.h"
7: #include "arp.h"
8: #include "../port/ipdat.h"
9:
10: #include "devtab.h"
11:
12: #define ARP_FREE 0
13: #define ARP_OK 1
14: #define ARP_ASKED 2
15: #define ARP_TEMP 0
16: #define ARP_PERM 1
17: #define Arphashsize 32
18: #define ARPHASH(p) arphash[((p[2]^p[3])%Arphashsize)]
19:
20: typedef struct Arpcache Arpcache;
21: struct Arpcache
22: {
23: uchar status;
24: uchar type;
25: uchar eip[4];
26: uchar et[6];
27: Arpcache *hash;
28: Arpcache **hashhd;
29: Arpcache *frwd;
30: Arpcache *prev;
31: };
32:
33: Arpstats arpstats;
34: Arpcache *arplruhead, *arplrutail;
35: Arpcache *arp, **arphash;
36: Queue *Servq;
37: Lock larphash;
38:
39: void arpiput(Queue *, Block *);
40: void arpoput(Queue *, Block *);
41: void arpopn(Queue *, Stream *);
42: void arpcls(Queue *);
43: void arpenter(Arpentry*, int);
44: void arpflush(void);
45: int arpperm(char*);
46: int arpdelete(char*);
47: void arplinkhead(Arpcache*);
48: int arplookup(uchar*, uchar*);
49:
50: Qinfo arpinfo = { arpiput, arpoput, arpopn, arpcls, "arp" };
51:
52: #define ARP_ENTRYLEN 50
53: char *padstr = " ";
54:
55: enum{
56: arpdirqid,
57: arpdir2qid,
58: arpstatqid,
59: arpctlqid,
60: arpdataqid,
61: };
62:
63: Dirtab arptab[]={
64: "stats", {arpstatqid}, 0, 0444,
65: "ctl", {arpctlqid}, 0, 0664,
66: "data", {arpdataqid}, 0, 0664,
67: };
68: #define Narptab (sizeof(arptab)/sizeof(Dirtab))
69:
70: enum
71: {
72: Narp= 64, /* size of arp cache */
73: };
74:
75: /*
76: * create a 2-level directory
77: */
78: int
79: arpgen(Chan *c, void *vp, int ntab, int i, Dir *dp)
80: {
81: Qid q;
82:
83: USED(vp);
84: USED(ntab);
85:
86: q.vers = 0;
87:
88: /* top level directory contains the directory arp */
89: if(c->qid.path == CHDIR){
90: if(i)
91: return -1;
92: q.path = CHDIR | arpdir2qid;
93: devdir(c, q, "arp", 0, eve, 0555, dp);
94: return 1;
95: }
96:
97: /* next level uses table */
98: return devgen(c, arptab, Narptab, i, dp);
99: }
100:
101: void
102: arpreset(void)
103: {
104: Arpcache *ap, *ep;
105:
106: arp = xalloc(sizeof(Arpcache) * Narp);
107: arphash = (Arpcache **)xalloc(sizeof(Arpcache *) * Arphashsize);
108:
109: ep = &arp[Narp];
110: for(ap = arp; ap < ep; ap++) {
111: ap->frwd = ap+1;
112: ap->prev = ap-1;
113: ap->type = ARP_FREE;
114: ap->status = ARP_TEMP;
115: }
116:
117: arp[0].prev = 0;
118: arplruhead = arp;
119: ap = &arp[Narp-1];
120: ap->frwd = 0;
121: arplrutail = ap;
122: newqinfo(&arpinfo);
123: }
124:
125: void
126: arpinit(void)
127: {
128: }
129:
130: Chan *
131: arpattach(char *spec)
132: {
133: return devattach('a', spec);
134: }
135:
136: Chan *
137: arpclone(Chan *c, Chan *nc)
138: {
139: return devclone(c, nc);
140: }
141:
142: int
143: arpwalk(Chan *c, char *name)
144: {
145: return devwalk(c, name, 0, 0, arpgen);
146: }
147:
148: void
149: arpstat(Chan *c, char *db)
150: {
151: devstat(c, db, 0, 0, arpgen);
152: }
153:
154: Chan *
155: arpopen(Chan *c, int omode)
156: {
157: if(c->qid.path&CHDIR){
158: if(omode != OREAD)
159: error(Eperm);
160: }
161:
162: switch(STREAMTYPE(c->qid.path)) {
163: case arpdataqid:
164: break;
165: case arpstatqid:
166: if(omode != OREAD)
167: error(Ebadarg);
168: break;
169: case arpctlqid:
170: break;
171: }
172:
173: c->mode = openmode(omode);
174: c->flag |= COPEN;
175: c->offset = 0;
176: return c;
177: }
178:
179: void
180: arpcreate(Chan *c, char *name, int omode, ulong perm)
181: {
182: USED(c, name, omode, perm);
183: error(Eperm);
184: }
185:
186: void
187: arpremove(Chan *c)
188: {
189: USED(c);
190: error(Eperm);
191: }
192:
193: void
194: arpwstat(Chan *c, char *dp)
195: {
196: USED(c, dp);
197: error(Eperm);
198: }
199:
200: void
201: arpclose(Chan *c)
202: {
203: streamclose(c);
204: }
205:
206: long
207: arpread(Chan *c, void *a, long n, ulong offset)
208: {
209: char buf[100];
210: Arpcache *ap;
211: int part, bytes, size;
212: char *ststr;
213:
214: if(c->qid.path&CHDIR)
215: return devdirread(c, a, n, arptab, Narptab, arpgen);
216:
217: switch((int)(c->qid.path&~CHDIR)){
218: case arpdataqid:
219: bytes = c->offset;
220: while(bytes < Narp*ARP_ENTRYLEN && n) {
221: ap = &arp[bytes/ARP_ENTRYLEN];
222: part = bytes%ARP_ENTRYLEN;
223:
224: if(ap->status != ARP_OK)
225: ststr = "invalid";
226: else
227: ststr = (ap->type == ARP_TEMP ? "temp" : "perm");
228:
229: sprint(buf,"%d.%d.%d.%d to %.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s%s",
230: ap->eip[0], ap->eip[1], ap->eip[2], ap->eip[3],
231: ap->et[0], ap->et[1], ap->et[2], ap->et[3],
232: ap->et[4], ap->et[5],
233: ststr, padstr);
234:
235: buf[ARP_ENTRYLEN-1] = '\n';
236:
237: size = ARP_ENTRYLEN - part;
238: size = MIN(n, size);
239: memmove(a, buf+part, size);
240:
241: a = (void *)((int)a + size);
242: n -= size;
243: bytes += size;
244: }
245: return bytes - c->offset;
246: break;
247: case arpstatqid:
248: sprint(buf, "hits: %d miss: %d failed: %d\n",
249: arpstats.hit, arpstats.miss, arpstats.failed);
250:
251: return readstr(offset, a, n, buf);
252: default:
253: n=0;
254: break;
255: }
256: return n;
257: }
258:
259: long
260: arpwrite(Chan *c, char *a, long n, ulong offset)
261: {
262: int m;
263: Arpentry entry;
264: char buf[32], *field[5];
265:
266: USED(offset);
267:
268: switch(STREAMTYPE(c->qid.path)) {
269: case arpctlqid:
270: strncpy(buf, a, sizeof buf);
271: m = getfields(buf, field, 5, " ");
272:
273: if(strncmp(field[0], "flush", 5) == 0)
274: arpflush();
275: else
276: if(strcmp(field[0], "delete") == 0) {
277: if(m != 2)
278: error(Ebadarg);
279:
280: if(arpdelete(field[1]) < 0)
281: error(Enetaddr);
282: }
283: else
284: if(strcmp(field[0], "perm") == 0) {
285: if(m != 2)
286: error(Ebadarg);
287:
288: if(arpperm(field[1]) < 0)
289: error(Enetaddr);
290: }
291: else
292: error(Ebadctl);
293: break;
294:
295: case arpdataqid:
296: if(n != sizeof(Arpentry))
297: error(Emsgsize);
298: memmove(&entry, a, sizeof(Arpentry));
299: arpenter(&entry, ARP_TEMP);
300: break;
301:
302: default:
303: error(Ebadusefd);
304: }
305:
306: return n;
307: }
308:
309: void
310: arpopn(Queue *q, Stream *s)
311: {
312: USED(q, s);
313: }
314:
315: void
316: arpcls(Queue *q)
317: {
318: if(q == Servq)
319: Servq = 0;
320: }
321:
322: void
323: arpiput(Queue *q, Block *bp)
324: {
325: PUTNEXT(q, bp);
326: }
327:
328: void
329: arpoput(Queue *q, Block *bp)
330: {
331: uchar ip[4];
332: Ipaddr addr;
333: Ipdevice *p;
334: Etherhdr *eh;
335: static int dropped;
336:
337:
338: if(bp->type != M_DATA) {
339: if(Servq == 0 && streamparse("arpd", bp)) {
340: Servq = RD(q);
341: freeb(bp);
342: }
343: else
344: PUTNEXT(q, bp);
345: return;
346: }
347:
348: eh = (Etherhdr *)bp->rptr;
349: if(nhgets(eh->type) != ET_IP) {
350: PUTNEXT(q, bp);
351: return;
352: }
353:
354: /*
355: * sleaze - we hid the next hop in the ethernet destination
356: * and the interface in the first byte of the source
357: */
358: memmove(ip, eh->d, sizeof(ip));
359: p = &ipd[eh->s[0]];
360: if(p >= &ipd[Nipd] || p->q == 0)
361: p = ipd;
362:
363: /* if ip broadcast, use ether bcast address */
364: addr = nhgetl(eh->dst);
365: if(p->Myip[Myself] == 0 || addr == p->Myip[Mybcast] || addr == p->Myip[Mynet]
366: || ((addr & p->Mymask) == p->Myip[Mynet+1]
367: && (addr & ~p->Mynetmask) == ~p->Mynetmask)){
368: memset(eh->d, 0xff, sizeof(eh->d));
369: PUTNEXT(q, bp);
370: return;
371: }
372:
373: /* if a known ip addr, send downstream to the ethernet */
374: if(arplookup(ip, eh->d)) {
375: PUTNEXT(q, bp);
376: return;
377: }
378:
379: /* Push the packet up to the arp server for address resolution */
380: if(!Servq) {
381: if((dropped++ % 100) == 99)
382: print("arp: No server, packet dropped %d.%d.%d.%d\n",
383: eh->dst[0], eh->dst[1], eh->dst[2], eh->dst[3]);
384: freeb(bp);
385: return;
386: }
387: memmove(eh->d, ip, sizeof(ip));
388: PUTNEXT(Servq, bp);
389: }
390:
391: int
392: arplookup(uchar *ip, uchar *et)
393: {
394: Arpcache *ap;
395:
396: lock(&larphash);
397: for(ap = ARPHASH(ip); ap; ap = ap->hash) {
398: if(ap->status == ARP_OK && memcmp(ap->eip, ip, sizeof(ap->eip)) == 0) {
399: memmove(et, ap->et, sizeof(ap->et));
400: arplinkhead(ap);
401: arpstats.hit++;
402: unlock(&larphash);
403: return 1;
404: }
405: }
406: arpstats.miss++;
407: unlock(&larphash);
408: return 0;
409: }
410:
411: void
412: arpflush(void)
413: {
414: Arpcache *ap, *ep;
415:
416: ep = &arp[Narp];
417: for(ap = arp; ap < ep; ap++)
418: ap->status = ARP_FREE;
419: }
420:
421: void
422: arpenter(Arpentry *ape, int type)
423: {
424: Arpcache *ap, **l, *d;
425:
426:
427: /* Update an entry if we have one already */
428: l = &ARPHASH(ape->ipaddr);
429: lock(&larphash);
430: for(ap = *l; ap; ap = ap->hash) {
431: if(ap->status == ARP_OK && memcmp(ap->eip, ape->ipaddr, sizeof(ap->eip)) == 0) {
432: if(ap->type != ARP_PERM) {
433: ap->type = type;
434: memmove(ap->et, ape->etaddr, sizeof(ap->et));
435: ap->status = ARP_OK;
436: }
437: unlock(&larphash);
438: return;
439: }
440: }
441:
442: /* Find an entry to replace */
443: ap = arplrutail;
444: while(ap) {
445: if(ap->type != ARP_PERM || ap->type == ARP_FREE)
446: break;
447: ap = ap->prev;
448: }
449: if(!ap) {
450: unlock(&larphash);
451: print("arp: too many permanent entries\n");
452: return;
453: }
454:
455: if(ap->hashhd) {
456: for(d = *ap->hashhd; d; d = d->hash) {
457: if(d == ap) {
458: *(ap->hashhd) = ap->hash;
459: break;
460: }
461: ap->hashhd = &d->hash;
462: }
463: }
464:
465: ap->type = type;
466: ap->status = ARP_OK;
467: memmove(ap->eip, ape->ipaddr, sizeof(ape->ipaddr));
468: memmove(ap->et, ape->etaddr, sizeof(ape->etaddr));
469: ap->hashhd = l;
470: ap->hash = *l;
471: *l = ap;
472: arplinkhead(ap);
473: unlock(&larphash);
474: }
475:
476: int
477: arpperm(char *addr)
478: {
479: Arpcache *ap;
480: uchar ip[4];
481: Ipaddr i;
482: int rv;
483:
484: rv = -1;
485: i = ipparse(addr);
486: hnputl(ip, i);
487: lock(&larphash);
488: for(ap = arplruhead; ap; ap = ap->frwd) {
489: if(memcmp(ap->eip, ip, sizeof(ap->eip)) == 0) {
490: ap->type = ARP_PERM;
491: rv = 0;
492: break;
493: }
494: }
495: unlock(&larphash);
496: return rv;
497: }
498:
499: int
500: arpdelete(char *addr)
501: {
502: Arpcache *ap;
503: uchar ip[4];
504: Ipaddr i;
505: int rv;
506:
507: rv = -1;
508: i = ipparse(addr);
509: hnputl(ip, i);
510: lock(&larphash);
511: for(ap = arplruhead; ap; ap = ap->frwd) {
512: if(memcmp(ap->eip, ip, sizeof(ap->eip)) == 0) {
513: ap->status = ARP_FREE;
514: rv = 0;
515: break;
516: }
517: }
518: unlock(&larphash);
519: return rv;
520: }
521:
522: void
523: arplinkhead(Arpcache *ap)
524: {
525: if(ap == arplruhead)
526: return;
527:
528: if(ap->prev)
529: ap->prev->frwd = ap->frwd;
530: else
531: arplruhead = ap->frwd;
532:
533: if(ap->frwd)
534: ap->frwd->prev = ap->prev;
535: else
536: arplrutail = ap->prev;
537:
538: ap->frwd = arplruhead;
539: ap->prev = 0;
540: arplruhead->prev = ap;
541: arplruhead = ap;
542: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.