|
|
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.