| plan 9 kernel history: overview | file list | diff list |
1992/0114/port/deviproute.c (diff list | history)
| port/deviproute.c on 1991/0331 | ||
| 1991/0331 | #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" | |
| 1992/0111 | #include "../port/error.h" | |
| 1991/0401 | #include "arp.h" #include "ipdat.h" | |
| 1991/0330 | ||
| 1991/0331 | #include "devtab.h" | |
| 1991/0401 | /* * All ip numbers and masks are stored as ulongs. * All interfaces to this code uses the standard byte * string representation. */ | |
| 1991/0330 | typedef struct Iproute Iproute; typedef struct Iprtab Iprtab; enum { Nroutes= 256, }; /* * routes */ struct Iproute { | |
| 1991/0401 | ulong dst; ulong gate; ulong mask; | |
| 1991/0330 | Iproute *next; int inuse; }; struct Iprtab { | |
| 1991/0331 | Lock; int n; /* number of valid routes */ Iproute *first; /* list of valid routes */ Iproute r[Nroutes]; /* all routes */ | |
| 1991/0330 | }; Iprtab iprtab; | |
| 1991/0331 | /* | |
| 1991/0330 | * The chosen route is the one obeys the constraint | |
| 1991/0401 | * r->mask & dst == r->dst | |
| 1991/0330 | * * If there are several matches, the one whose mask has the most | |
| 1991/0401 | * leading ones (and hence is the most specific) wins. This is * forced by storing the routes in decreasing number of ones order * and returning the first match. The default gateway has no ones * in the mask and is thus the last matched. | |
| 1991/0330 | */ void iproute(uchar *dst, uchar *gate) { Iproute *r; | |
| 1991/0401 | ulong udst; | |
| 1991/0330 | ||
| 1991/0401 | udst = nhgetl(dst); if((udst&Mymask) == (Myip&Mymask)){ memmove(gate, dst, 4); return; } | |
| 1991/0330 | /* * first check routes */ for(r = iprtab.first; r; r = r->next){ | |
| 1991/0401 | if((r->mask&udst) == r->dst){ hnputl(gate, r->gate); | |
| 1991/0330 | return; } } /* | |
| 1991/0401 | * else just return the same address | |
| 1991/0330 | */ memmove(gate, dst, 4); } /* * Add a route, create a mask if the first mask is 0. * * All routes are stored sorted by the length of leading * ones in the mask. * * NOTE: A default route has an all zeroes mask and dst. */ void | |
| 1991/0401 | ipaddroute(ulong dst, ulong mask, ulong gate) | |
| 1991/0330 | { Iproute *r, *e, *free; int i; /* * filter out impossible requests */ | |
| 1991/0401 | if((dst&mask) != dst) | |
| 1992/0114 | error(Enetaddr); | |
| 1991/0330 | /* * see if we already have a route for * the destination */ lock(&iprtab); free = 0; for(r = iprtab.r; r < &iprtab.r[Nroutes]; r++){ if(r->inuse == 0){ free = r; continue; } | |
| 1991/0401 | if(dst==r->dst && mask==r->mask){ r->gate = gate; | |
| 1991/0330 | unlock(&iprtab); return; } } | |
| 1991/0401 | if(free == 0){ unlock(&iprtab); | |
| 1992/0114 | exhausted("routes"); | |
| 1991/0401 | } | |
| 1991/0330 | /* * add the new route in sorted order */ | |
| 1991/0401 | free->dst = dst; free->mask = mask; free->gate = gate; | |
| 1991/0330 | free->inuse = 1; | |
| 1991/0401 | for(r = e = iprtab.first; r; r = r->next){ if(mask > r->mask) | |
| 1991/0330 | break; e = r; } free->next = r; if(r == iprtab.first) iprtab.first = free; else e->next = free; | |
| 1991/0331 | iprtab.n++; | |
| 1991/0330 | unlock(&iprtab); } /* * remove a route */ void | |
| 1991/0401 | ipremroute(ulong dst, ulong mask) | |
| 1991/0330 | { Iproute *r, *e; lock(&iprtab); | |
| 1991/0401 | for(r = e = iprtab.first; r; r = r->next){ if(dst==r->dst && mask==r->mask){ | |
| 1991/0330 | if(r == iprtab.first) iprtab.first = r->next; else e->next = r->next; r->inuse = 0; | |
| 1991/0331 | iprtab.n--; | |
| 1991/0330 | break; } e = r; } unlock(&iprtab); } /* * remove all routes */ void ipflushroute(void) { Iproute *r; lock(&iprtab); for(r = iprtab.first; r; r = r->next) r->inuse = 0; iprtab.first = 0; | |
| 1991/0331 | iprtab.n = 0; | |
| 1991/0330 | unlock(&iprtab); | |
| 1991/0331 | } /* * device interface */ enum{ Qdir, Qdata, }; Dirtab iproutetab[]={ | |
| 1991/1112 | "iproute", {Qdata}, 0, 0666, | |
| 1991/0331 | }; #define Niproutetab (sizeof(iproutetab)/sizeof(Dirtab)) void iproutereset(void) { } void iprouteinit(void) { } Chan * iprouteattach(char *spec) { | |
| 1991/0418 | return devattach('P', spec); | |
| 1991/0331 | } Chan * iprouteclone(Chan *c, Chan *nc) { return devclone(c, nc); } int iproutewalk(Chan *c, char *name) { return devwalk(c, name, iproutetab, (long)Niproutetab, devgen); | |
| 1991/0419 | } | |
| 1991/0331 | void iproutestat(Chan *c, char *db) { devstat(c, db, iproutetab, (long)Niproutetab, devgen); } Chan * iprouteopen(Chan *c, int omode) { if(c->qid.path == CHDIR){ if(omode != OREAD) error(Eperm); } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } void iproutecreate(Chan *c, char *name, int omode, ulong perm) { | |
| 1991/1115 | USED(c, name, omode, perm); | |
| 1991/0331 | error(Eperm); } void iprouteremove(Chan *c) { | |
| 1991/1115 | USED(c); | |
| 1991/0331 | error(Eperm); } void iproutewstat(Chan *c, char *dp) { | |
| 1991/1115 | USED(c, dp); | |
| 1991/0331 | error(Eperm); } void iprouteclose(Chan *c) { | |
| 1991/1115 | USED(c); | |
| 1991/0331 | } #define IPR_ENTRYLEN 54 #define PAD " " long | |
| 1991/0411 | iprouteread(Chan *c, void *a, long n, ulong offset) | |
| 1991/0331 | { | |
| 1991/0401 | char buf[IPR_ENTRYLEN*3]; | |
| 1991/0331 | Iproute *r; int part, bytes, size; | |
| 1991/0401 | uchar dst[4], mask[4], gate[4]; | |
| 1991/0331 | switch((int)(c->qid.path&~CHDIR)){ case Qdir: return devdirread(c, a, n, iproutetab, Niproutetab, devgen); case Qdata: lock(&iprtab); | |
| 1991/0411 | part = offset/IPR_ENTRYLEN; | |
| 1991/0331 | for(r = iprtab.first; part && r; r = r->next) | |
| 1991/0401 | part--; | |
| 1991/0411 | bytes = offset; | |
| 1991/0401 | while(r && bytes < iprtab.n*IPR_ENTRYLEN && n){ | |
| 1991/0331 | part = bytes%IPR_ENTRYLEN; | |
| 1991/0401 | hnputl(dst, r->dst); hnputl(mask, r->mask); hnputl(gate, r->gate); | |
| 1991/0331 | sprint(buf,"%d.%d.%d.%d & %d.%d.%d.%d -> %d.%d.%d.%d%s", | |
| 1991/0401 | dst[0], dst[1], dst[2], dst[3], mask[0], mask[1], mask[2], mask[3], gate[0], gate[1], gate[2], gate[3], | |
| 1991/0331 | PAD); buf[IPR_ENTRYLEN-1] = '\n'; size = IPR_ENTRYLEN - part; | |
| 1991/0401 | if(size > n) size = n; | |
| 1991/0331 | memmove(a, buf+part, size); a = (void *)((int)a + size); n -= size; bytes += size; | |
| 1991/0401 | r = r->next; | |
| 1991/0331 | } unlock(&iprtab); | |
| 1991/0411 | return bytes - offset; | |
| 1991/0331 | break; default: n=0; break; } return n; } long | |
| 1991/0411 | iproutewrite(Chan *c, char *a, long n, ulong offset) | |
| 1991/0331 | { char buf[IPR_ENTRYLEN]; char *field[4]; | |
| 1991/0401 | Ipaddr mask, dst, gate; | |
| 1991/0331 | int m; switch((int)(c->qid.path&~CHDIR)){ case Qdata: strncpy(buf, a, sizeof buf); m = getfields(buf, field, 4, ' '); if(strncmp(field[0], "flush", 5) == 0) ipflushroute(); else if(strcmp(field[0], "add") == 0){ switch(m){ case 4: | |
| 1991/0401 | dst = ipparse(field[1]); mask = ipparse(field[2]); gate = ipparse(field[3]); | |
| 1991/0331 | ipaddroute(dst, mask, gate); break; case 3: | |
| 1991/0401 | dst = ipparse(field[1]); gate = ipparse(field[2]); ipaddroute(dst, classmask[dst>>30], gate); | |
| 1991/0331 | break; default: error(Ebadarg); } } else if(strcmp(field[0], "delete") == 0){ switch(m){ case 3: | |
| 1991/0401 | dst = ipparse(field[1]); mask = ipparse(field[2]); | |
| 1991/0331 | ipremroute(dst, mask); break; case 2: | |
| 1991/0401 | dst = ipparse(field[1]); ipremroute(dst, classmask[dst>>30]); | |
| 1991/0331 | break; default: error(Ebadarg); } } break; default: error(Ebadusefd); } return n; | |
| 1991/0330 | } | |