@@ 1,5 1,11 @@
-#include <u.h>
-#include <libc.h>
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "errno.h"
+
+#include "devtab.h"
typedef struct Iproute Iproute;
typedef struct Iprtab Iprtab;
@@ 20,6 26,9 @@ uchar classmask[4][4] = {
};
#define CLASSMASK(x) classmask[(*x>>6) & 3]
+uchar netbytes[4] = { 1, 1, 2, 3 };
+#define NETBYTES(x) netbytes[(*x>>6) & 3]
+
/*
* routes
*/
@@ 31,27 40,36 @@ struct Iproute {
int inuse;
};
struct Iprtab {
-/* Lock; */
- Iproute *first;
- Iproute r[Nroutes]; /* routings */
+ Lock;
+ int n; /* number of valid routes */
+ Iproute *first; /* list of valid routes */
+ Iproute r[Nroutes]; /* all routes */
};
Iprtab iprtab;
-#define lock(x)
-#define unlock(x)
-
+/*
+ * Convert string to ip address. This is rediculously difficult because
+ * the designers of ip decided to allow any leading zero bytes in the
+ * host part to be left out.
+ */
void
-printroute(void)
+strtoip(char *s, uchar *addr)
{
- Iproute *r;
+ int i, off, first;
+ char *rptr = s;
- print("\n");
- for(r = iprtab.first; r; r = r->next)
- print("%d.%d.%d.%d %d.%d.%d.%d %d.%d.%d.%d\n",
- r->dst[0], r->dst[1], r->dst[2], r->dst[3],
- r->mask[0], r->mask[1], r->mask[2], r->mask[3],
- r->gate[0], r->gate[1], r->gate[2], r->gate[3]);
- print("\n");
+ /* convert the bytes */
+ for(i = 0; i<4 & *rptr; i++)
+ addr[i] = strtoul(rptr, &rptr, 0);
+
+ /* move host bytes to the right place */
+ first = NETBYTES(addr);
+ off = 4 - i;
+ if(off)
+ while(i != first){
+ --i;
+ addr[i+off] = addr[i];
+ }
}
/*
@@ 128,7 146,7 @@ ipaddroute(uchar *dst, uchar *mask, uchar *gate)
*/
for(i = 0; i < 4; i++)
if((dst[i]&mask[i]) != dst[i])
- return;
+ errors("bad ip route");
/*
* see if we already have a route for
@@ 147,6 165,8 @@ ipaddroute(uchar *dst, uchar *mask, uchar *gate)
return;
}
}
+ if(free == 0)
+ errors("no free ip routes");
/*
* add the new route in sorted order
@@ 165,6 185,7 @@ ipaddroute(uchar *dst, uchar *mask, uchar *gate)
iprtab.first = free;
else
e->next = free;
+ iprtab.n++;
unlock(&iprtab);
}
@@ 184,6 205,7 @@ ipremroute(uchar *dst, uchar *mask)
else
e->next = r->next;
r->inuse = 0;
+ iprtab.n--;
break;
}
e = r;
@@ 203,5 225,189 @@ ipflushroute(void)
for(r = iprtab.first; r; r = r->next)
r->inuse = 0;
iprtab.first = 0;
+ iprtab.n = 0;
unlock(&iprtab);
}
+
+/*
+ * device interface
+ */
+enum{
+ Qdir,
+ Qdata,
+};
+Dirtab iproutetab[]={
+ "iproute", Qdata, 0, 0600,
+};
+#define Niproutetab (sizeof(iproutetab)/sizeof(Dirtab))
+
+void
+iproutereset(void)
+{
+}
+
+void
+iprouteinit(void)
+{
+}
+
+Chan *
+iprouteattach(char *spec)
+{
+ return devattach('R', spec);
+}
+
+Chan *
+iprouteclone(Chan *c, Chan *nc)
+{
+ return devclone(c, nc);
+}
+
+int
+iproutewalk(Chan *c, char *name)
+{
+ return devwalk(c, name, iproutetab, (long)Niproutetab, devgen);
+}
+
+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)
+{
+ error(Eperm);
+}
+
+void
+iprouteremove(Chan *c)
+{
+ error(Eperm);
+}
+
+void
+iproutewstat(Chan *c, char *dp)
+{
+ error(Eperm);
+}
+
+void
+iprouteclose(Chan *c)
+{
+}
+
+#define IPR_ENTRYLEN 54
+#define PAD " "
+
+long
+iprouteread(Chan *c, void *a, long n)
+{
+ char buf[IPR_ENTRYLEN*2];
+ Iproute *r;
+ int part, bytes, size;
+
+ switch((int)(c->qid.path&~CHDIR)){
+ case Qdir:
+ return devdirread(c, a, n, iproutetab, Niproutetab, devgen);
+ case Qdata:
+ lock(&iprtab);
+ part = c->offset/IPR_ENTRYLEN;
+ for(r = iprtab.first; part && r; r = r->next)
+ ;
+ bytes = c->offset;
+ while(bytes < iprtab.n*IPR_ENTRYLEN && n){
+ part = bytes%IPR_ENTRYLEN;
+
+ sprint(buf,"%d.%d.%d.%d & %d.%d.%d.%d -> %d.%d.%d.%d%s",
+ r->dst[0], r->dst[1], r->dst[2], r->dst[3],
+ r->mask[0], r->mask[1], r->mask[2], r->mask[3],
+ r->gate[0], r->gate[1], r->gate[2], r->gate[3],
+ PAD);
+
+ buf[IPR_ENTRYLEN-1] = '\n';
+
+ size = IPR_ENTRYLEN - part;
+ size = MIN(n, size);
+ memmove(a, buf+part, size);
+
+ a = (void *)((int)a + size);
+ n -= size;
+ bytes += size;
+ }
+ unlock(&iprtab);
+ return bytes - c->offset;
+ break;
+ default:
+ n=0;
+ break;
+ }
+ return n;
+}
+
+long
+iproutewrite(Chan *c, char *a, long n)
+{
+ char buf[IPR_ENTRYLEN];
+ char *field[4];
+ uchar mask[4], dst[4], gate[4];
+ 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:
+ strtoip(field[1], dst);
+ strtoip(field[2], mask);
+ strtoip(field[3], gate);
+ ipaddroute(dst, mask, gate);
+ break;
+ case 3:
+ strtoip(field[1], dst);
+ strtoip(field[2], gate);
+ ipaddroute(dst, 0, gate);
+ break;
+ default:
+ error(Ebadarg);
+ }
+ } else if(strcmp(field[0], "delete") == 0){
+ switch(m){
+ case 3:
+ strtoip(field[1], dst);
+ strtoip(field[2], mask);
+ ipremroute(dst, mask);
+ break;
+ case 2:
+ strtoip(field[1], dst);
+ ipremroute(dst, 0);
+ break;
+ default:
+ error(Ebadarg);
+ }
+ }
+ break;
+ default:
+ error(Ebadusefd);
+ }
+ return n;
+}