M boot/boot.c => boot/boot.c +5 -1
@@ 117,10 117,14 @@ boot(int argc, char *argv[])
*/
if(bind("/", "/", MREPL) < 0)
fatal("bind /");
- if(mount(fd, "/", MAFTER|MCREATE, "") < 0)
+ if(mount(fd, "/root", MREPL|MCREATE, "") < 0)
fatal("mount /");
+ if(bind(rootdir, "/", MAFTER|MCREATE) < 0)
+ fatal("bind /");
close(fd);
+ setenv("rootdir", rootdir);
+
/*
* if a local file server exists and it's not
* running, start it and mount it onto /n/kfs
M boot/boot.h => boot/boot.h +1 -0
@@ 9,6 9,7 @@ struct Method
};
extern char* bootdisk;
+extern char* rootdir;
extern int (*cfs)(int);
extern int cpuflag;
extern char cputype[];
M ip/devip.c => ip/devip.c +9 -2
@@ 565,8 565,13 @@ ipread(Chan *ch, void *a, long n, vlong off)
return rv;
case Qremote:
buf = smalloc(Statelen);
- c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
- sprint(buf, "%I!%d\n", c->raddr, c->rport);
+ x = f->p[PROTO(ch->qid)];
+ c = x->conv[CONV(ch->qid)];
+ if(x->remote == nil) {
+ sprint(buf, "%I!%d\n", c->raddr, c->rport);
+ } else {
+ (*x->remote)(c, buf, Statelen-2);
+ }
rv = readstr(offset, p, n, buf);
free(buf);
return rv;
@@ 905,6 910,8 @@ ipwrite(Chan* ch, char* a, long n, vlong)
free(cb);
nexterror();
}
+ if(cb->nf < 1)
+ error("short control request");
if(strcmp(cb->f[0], "connect") == 0)
connectctlmsg(x, c, cb);
else if(strcmp(cb->f[0], "announce") == 0)
A ip/esp.c => ip/esp.c +645 -0
@@ 0,0 1,645 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+#include "ip.h"
+
+#include "libcrypt.h"
+
+typedef struct Esphdr Esphdr;
+typedef struct Esptail Esptail;
+typedef struct Userhdr Userhdr;
+typedef struct Esppriv Esppriv;
+typedef struct Espcb Espcb;
+typedef struct Algorithm Algorithm;
+
+#define DPRINT if(0)print
+
+enum
+{
+ IP_ESPPROTO = 50,
+ EsphdrSize = 28, // includes IP header
+ IphdrSize = 20, // options have been striped
+ EsptailSize = 2, // does not include pad or auth data
+ UserhdrSize = 4, // user visable header size - if enabled
+};
+
+struct Esphdr
+{
+ /* ip header */
+ uchar vihl; /* Version and header length */
+ uchar tos; /* Type of service */
+ uchar length[2]; /* packet length */
+ uchar id[2]; /* Identification */
+ uchar frag[2]; /* Fragment information */
+ uchar Unused;
+ uchar espproto; /* Protocol */
+ uchar espplen[2]; /* Header plus data length */
+ uchar espsrc[4]; /* Ip source */
+ uchar espdst[4]; /* Ip destination */
+
+ /* esp header */
+ uchar espspi[4]; /* Security parameter index */
+ uchar espseq[4]; /* Sequence number */
+};
+
+struct Esptail
+{
+ uchar pad;
+ uchar nexthdr;
+};
+
+/* header as seen by the user */
+struct Userhdr
+{
+ uchar nexthdr; // next protocol
+ uchar unused[3];
+};
+
+struct Esppriv
+{
+ ulong in;
+ ulong inerrors;
+};
+
+/*
+ * protocol specific part of Conv
+ */
+struct Espcb
+{
+ int incoming;
+ int header; // user user level header
+ ulong spi;
+ ulong seq; // last seq sent
+ ulong window; // for replay attacks
+ char *espalg;
+ void *espstate; // other state for esp
+ int espivlen; // in bytes
+ int espblklen;
+ int (*cipher)(Espcb*, uchar *buf, int len);
+ char *ahalg;
+ void *ahstate; // other state for esp
+ int ahlen; // auth data length in bytes
+ int ahblklen;
+ int (*auth)(Espcb*, uchar *buf, int len, uchar *hash);
+};
+
+struct Algorithm
+{
+ char *name;
+ int keylen; // in bits
+ void (*init)(Espcb*, char* name, uchar *key, int keylen);
+};
+
+static Conv* convlookup(Proto *esp, ulong spi);
+static char *setalg(Espcb *ecb, char **f, int n, Algorithm *alg);
+static void nullespinit(Espcb*, char*, uchar *key, int keylen);
+static void nullahinit(Espcb*, char*, uchar *key, int keylen);
+static void desespinit(Espcb *ecb, char *name, uchar *k, int n);
+
+static Algorithm espalg[] =
+{
+ "null", 0, nullespinit,
+ "des_56_cbc", 64, desespinit,
+ nil, 0, nil,
+};
+
+static Algorithm ahalg[] =
+{
+ "null", 0, nullahinit,
+ nil, 0, nil,
+};
+
+static char*
+espconnect(Conv *c, char **argv, int argc)
+{
+ char *p, *pp;
+ char *e = nil;
+ ulong spi;
+ Espcb *ecb = (Espcb*)c->ptcl;
+
+ qlock(c);
+ switch(argc) {
+ default:
+ e = "bad args to connect";
+ break;
+ case 2:
+ p = strchr(argv[1], '!');
+ if(p == nil){
+ e = "malformed address";
+ break;
+ }
+ *p++ = 0;
+ parseip(c->raddr, argv[1]);
+ findlocalip(c->p->f, c->laddr, c->raddr);
+ ecb->incoming = 0;
+ ecb->seq = 0;
+ if(strcmp(p, "*") == 0) {
+ qlock(c->p);
+ for(;;) {
+ spi = nrand(1<<16) + 256;
+ if(convlookup(c->p, spi) == nil)
+ break;
+ }
+ qunlock(c->p);
+ ecb->spi = spi;
+ ecb->incoming = 1;
+ qhangup(c->wq, nil);
+ } else {
+ spi = strtoul(p, &pp, 10);
+ if(pp == p) {
+ e = "malformed address";
+ break;
+ }
+ ecb->spi = spi;
+ qhangup(c->rq, nil);
+ }
+ nullespinit(ecb, "null", nil, 0);
+ nullahinit(ecb, "null", nil, 0);
+ }
+ qunlock(c);
+ Fsconnected(c, e);
+
+ return e;
+}
+
+
+static int
+espstate(Conv *c, char *state, int n)
+{
+ return snprint(state, n, "%s", c->inuse?"Open\n":"Closed\n");
+}
+
+static void
+espcreate(Conv *c)
+{
+ c->rq = qopen(64*1024, 1, 0, 0);
+ c->wq = qopen(64*1024, 0, 0, 0);
+}
+
+static void
+espclose(Conv *c)
+{
+ Espcb *ecb;
+
+ qclose(c->rq);
+ qclose(c->wq);
+ qclose(c->eq);
+ ipmove(c->laddr, IPnoaddr);
+ ipmove(c->raddr, IPnoaddr);
+
+ ecb = (Espcb*)c->ptcl;
+ free(ecb->espstate);
+ free(ecb->ahstate);
+ memset(ecb, 0, sizeof(Espcb));
+
+ qunlock(c);
+}
+
+void
+espkick(Conv *c, int)
+{
+ Esphdr *eh;
+ Esptail *et;
+ Userhdr *uh;
+ Espcb *ecb;
+ Block *bp;
+ int nexthdr;
+ int payload;
+ int pad;
+ int align;
+ uchar *auth;
+
+ bp = qget(c->wq);
+ if(bp == nil)
+ return;
+
+ qlock(c);
+ ecb = c->ptcl;
+
+ if(ecb->header) {
+ /* make sure the message has a User header */
+ bp = pullupblock(bp, UserhdrSize);
+ if(bp == nil) {
+ qunlock(c);
+ return;
+ }
+ uh = (Userhdr*)bp->rp;
+ nexthdr = uh->nexthdr;
+ bp->rp += UserhdrSize;
+ } else {
+ nexthdr = 0; // what should this be?
+ }
+
+ payload = BLEN(bp) + ecb->espivlen;
+
+ /* Make space to fit ip header */
+ bp = padblock(bp, EsphdrSize + ecb->espivlen);
+
+ align = 4;
+ if(ecb->espblklen > align)
+ align = ecb->espblklen;
+ if(align % ecb->ahblklen != 0)
+ panic("espkick: ahblklen is important after all");
+ pad = (align-1) - (payload + EsptailSize-1)%align;
+
+ /*
+ * Make space for tail
+ * this is done by calling padblock with a negative size
+ * Padblock does not change bp->wp!
+ */
+ bp = padblock(bp, -(pad+EsptailSize+ecb->ahlen));
+ bp->wp += pad+EsptailSize+ecb->ahlen;
+
+ eh = (Esphdr *)(bp->rp);
+ et = (Esptail*)(bp->rp + EsphdrSize + payload + pad);
+
+ // fill in tail
+ et->pad = pad;
+ et->nexthdr = nexthdr;
+
+ ecb->cipher(ecb, bp->rp+EsphdrSize, payload+pad+EsptailSize);
+ auth = bp->rp + EsphdrSize + payload + pad + EsptailSize;
+ ecb->auth(ecb, bp->rp+IphdrSize, (EsphdrSize-IphdrSize)+payload+pad+EsptailSize, auth);
+
+ // fill in head
+ hnputl(eh->espspi, ecb->spi);
+ hnputl(eh->espseq, ++ecb->seq);
+ v6tov4(eh->espsrc, c->laddr);
+ v6tov4(eh->espdst, c->raddr);
+ eh->espproto = IP_ESPPROTO;
+ eh->frag[0] = 0;
+ eh->frag[1] = 0;
+
+ qunlock(c);
+//print("esp: pass down: %uld\n", BLEN(bp));
+ ipoput(c->p->f, bp, 0, c->ttl);
+}
+
+void
+espiput(Proto *esp, uchar*, Block *bp)
+{
+ Esphdr *eh;
+ Esptail *et;
+ Userhdr *uh;
+ Conv *c;
+ Espcb *ecb;
+ uchar raddr[IPaddrlen], laddr[IPaddrlen];
+ Fs *f;
+ uchar *auth;
+ ulong spi;
+ int payload, nexthdr;
+
+ f = esp->f;
+
+ bp = pullupblock(bp, EsphdrSize+EsptailSize);
+ if(bp == nil) {
+ netlog(f, Logesp, "esp: short packet\n");
+ return;
+ }
+
+ eh = (Esphdr*)(bp->rp);
+ spi = nhgetl(eh->espspi);
+ v4tov6(raddr, eh->espsrc);
+ v4tov6(laddr, eh->espdst);
+
+ qlock(esp);
+ /* Look for a conversation structure for this port */
+ c = convlookup(esp, spi);
+ if(c == nil) {
+ qunlock(esp);
+ netlog(f, Logesp, "esp: no conv %I -> %I!%d\n", raddr,
+ laddr, spi);
+ icmpnoconv(f, bp);
+ freeblist(bp);
+ return;
+ }
+
+ qlock(c);
+ qunlock(esp);
+
+ ecb = c->ptcl;
+ // too hard to do decryption/authentication on block lists
+ if(bp->next)
+ bp = concatblock(bp);
+
+ if(BLEN(bp) < EsphdrSize + ecb->espivlen + EsptailSize + ecb->ahlen) {
+ qunlock(esp);
+ netlog(f, Logesp, "esp: short block %I -> %I!%d\n", raddr,
+ laddr, spi);
+ freeb(bp);
+ return;
+ }
+
+ eh = (Esphdr*)(bp->rp);
+ auth = bp->wp - ecb->ahlen;
+ if(!ecb->auth(ecb, eh->espspi, auth-eh->espspi, auth)) {
+ qunlock(esp);
+ netlog(f, Logesp, "esp: bad auth %I -> %I!%d\n", raddr,
+ laddr, spi);
+ freeb(bp);
+ return;
+ }
+
+ payload = BLEN(bp)-EsphdrSize-ecb->ahlen;
+ if(payload<=0 || payload%4 != 0 || payload%ecb->espblklen!=0) {
+ qunlock(esp);
+ netlog(f, Logesp, "esp: bad length %I -> %I!%d payload=%d BLEN=%d\n", raddr,
+ laddr, spi, payload, BLEN(bp));
+ freeb(bp);
+ return;
+ }
+ ecb->cipher(ecb, bp->rp+EsphdrSize, payload);
+
+ payload -= EsptailSize;
+ et = (Esptail*)(bp->rp + EsphdrSize + payload);
+ payload -= et->pad + ecb->espivlen;
+ nexthdr = et->nexthdr;
+ if(payload <= 0) {
+ qunlock(esp);
+ netlog(f, Logesp, "esp: short packet after decrypt %I -> %I!%d\n", raddr,
+ laddr, spi);
+ freeb(bp);
+ return;
+ }
+
+ // trim packet
+ bp->rp += EsphdrSize + ecb->espivlen;
+ bp->wp = bp->rp + payload;
+ if(ecb->header) {
+ // assume UserhdrSize < EsphdrSize
+ bp->rp -= UserhdrSize;
+ uh = (Userhdr*)bp->rp;
+ memset(uh, 0, UserhdrSize);
+ uh->nexthdr = nexthdr;
+ }
+
+ if(qfull(c->rq)){
+ netlog(f, Logesp, "esp: qfull %I -> %I.%uld\n", raddr,
+ laddr, spi);
+ freeblist(bp);
+ }else {
+//print("esp: pass up: %uld\n", BLEN(bp));
+ qpass(c->rq, bp);
+ }
+
+ qunlock(c);
+}
+
+char*
+espctl(Conv *c, char **f, int n)
+{
+ Espcb *ecb = c->ptcl;
+ char *e = nil;
+
+ qlock(c);
+ if(strcmp(f[0], "esp") == 0)
+ e = setalg(ecb, f, n, espalg);
+ else if(strcmp(f[0], "ah") == 0)
+ e = setalg(ecb, f, n, ahalg);
+ else if(strcmp(f[0], "header") == 0)
+ ecb->header = 1;
+ else if(strcmp(f[0], "noheader") == 0)
+ ecb->header = 0;
+ else
+ e = "unknown control request";
+ qunlock(c);
+ return e;
+}
+
+void
+espadvise(Proto *esp, Block *bp, char *msg)
+{
+ Esphdr *h;
+ Conv *c;
+ ulong spi;
+
+ h = (Esphdr*)(bp->rp);
+
+ spi = nhgets(h->espspi);
+ qlock(esp);
+ c = convlookup(esp, spi);
+ if(c != nil) {
+ qhangup(c->rq, msg);
+ qhangup(c->wq, msg);
+ }
+ qunlock(esp);
+ freeblist(bp);
+}
+
+int
+espstats(Proto *esp, char *buf, int len)
+{
+ Esppriv *upriv;
+
+ upriv = esp->priv;
+ return snprint(buf, len, "%lud %lud\n",
+ upriv->in,
+ upriv->inerrors);
+}
+
+static int
+esplocal(Conv *c, char *buf, int len)
+{
+ Espcb *ecb = c->ptcl;
+ int n;
+
+ qlock(c);
+ if(ecb->incoming)
+ n = snprint(buf, len, "%I!%uld\n", c->laddr, ecb->spi);
+ else
+ n = snprint(buf, len, "%I\n", c->laddr);
+ qunlock(c);
+ return n;
+}
+
+static int
+espremote(Conv *c, char *buf, int len)
+{
+ Espcb *ecb = c->ptcl;
+ int n;
+
+ qlock(c);
+ if(ecb->incoming)
+ n = snprint(buf, len, "%I\n", c->raddr);
+ else
+ n = snprint(buf, len, "%I!%uld\n", c->raddr, ecb->spi);
+ qunlock(c);
+ return n;
+}
+
+// should have esp locked
+static Conv*
+convlookup(Proto *esp, ulong spi)
+{
+ Conv *c, **p;
+ Espcb *ecb;
+
+ for(p=esp->conv; *p; p++){
+ c = *p;
+ ecb = c->ptcl;
+ if(ecb->incoming && ecb->spi == spi)
+ return c;
+ }
+}
+
+static char *
+setalg(Espcb *ecb, char **f, int n, Algorithm *alg)
+{
+ uchar *key;
+ int i, nbyte, nchar;
+ int c;
+
+ if(n < 2)
+ return "bad format";
+ for(; alg->name; alg++)
+ if(strcmp(f[1], alg->name) == 0)
+ break;
+ if(alg->name == nil)
+ return "unknown algorithm";
+
+ if(n != 3)
+ return "bad format";
+ nbyte = (alg->keylen + 7) >> 3;
+ nchar = strlen(f[2]);
+ for(i=0; i<nchar; i++) {
+ c = f[2][i];
+ if(c >= '0' && c <= '9')
+ f[2][i] -= '0';
+ else if(c >= 'a' && c <= 'f')
+ f[2][i] -= 'a'-10;
+ else if(c >= 'A' && c <= 'F')
+ f[2][i] -= 'A'-10;
+ else
+ return "bad character in key";
+ }
+ key = smalloc(nbyte);
+ for(i=0; i<nchar && i*2<nbyte; i++) {
+ c = f[2][nchar-i-1];
+ if(i&1)
+ c <<= 4;
+ key[i>>1] |= c;
+ }
+
+ alg->init(ecb, alg->name, key, alg->keylen);
+ free(key);
+ return nil;
+}
+
+static int
+nullcipher(Espcb*, uchar*, int)
+{
+ return 1;
+}
+
+static void
+nullespinit(Espcb *ecb, char *name, uchar*, int)
+{
+ ecb->espalg = name;
+ ecb->espblklen = 1;
+ ecb->espivlen = 0;
+ ecb->cipher = nullcipher;
+}
+
+static int
+nullauth(Espcb*, uchar*, int, uchar*)
+{
+ return 1;
+}
+
+static void
+nullahinit(Espcb *ecb, char *name, uchar*, int)
+{
+ ecb->ahalg = name;
+ ecb->ahblklen = 1;
+ ecb->ahlen = 0;
+ ecb->auth = nullauth;
+}
+
+static int
+descipher(Espcb *ecb, uchar *p, int n)
+{
+ uchar tmp[8];
+ uchar *pp, *tp, *ip, *eip, *ep;
+ DESstate *ds = ecb->espstate;
+
+ ep = p + n;
+ if(ecb->incoming) {
+ memmove(ds->ivec, p, 8);
+ p += 8;
+ while(p < ep){
+ memmove(tmp, p, 8);
+ block_cipher(ds->expanded, p, 1);
+ tp = tmp;
+ ip = ds->ivec;
+ for(eip = ip+8; ip < eip; ){
+ *p++ ^= *ip;
+ *ip++ = *tp++;
+ }
+ }
+ } else {
+ memmove(p, ds->ivec, 8);
+ for(p += 8; p < ep; p += 8){
+ pp = p;
+ ip = ds->ivec;
+ for(eip = ip+8; ip < eip; )
+ *pp++ ^= *ip++;
+ block_cipher(ds->expanded, p, 0);
+ memmove(ds->ivec, p, 8);
+ }
+ }
+ return 1;
+}
+
+static void
+desespinit(Espcb *ecb, char *name, uchar *k, int n)
+{
+ uchar key[8];
+ uchar ivec[8];
+ int i;
+
+ // bits to bytes
+ n = (n+7)>>3;
+ if(n > 8)
+ n = 8;
+ memset(key, 0, sizeof(key));
+ memmove(key, k, n);
+ for(i=0; i<8; i++)
+ ivec[i] = nrand(256);
+ ecb->espalg = name;
+ ecb->espblklen = 8;
+ ecb->espivlen = 8;
+ ecb->cipher = descipher;
+ ecb->espstate = smalloc(sizeof(DESstate));
+ setupDESstate(ecb->espstate, key, ivec);
+}
+
+void
+espinit(Fs *fs)
+{
+ Proto *esp;
+
+ esp = smalloc(sizeof(Proto));
+ esp->priv = smalloc(sizeof(Esppriv));
+ esp->name = "esp";
+ esp->kick = espkick;
+ esp->connect = espconnect;
+ esp->announce = nil;
+ esp->ctl = espctl;
+ esp->state = espstate;
+ esp->create = espcreate;
+ esp->close = espclose;
+ esp->rcv = espiput;
+ esp->advise = espadvise;
+ esp->stats = espstats;
+ esp->local = esplocal;
+ esp->remote = espremote;
+ esp->ipproto = IP_ESPPROTO;
+ esp->nc = Nchans;
+ esp->ptclsize = sizeof(Espcb);
+
+ Fsproto(fs, esp);
+}
M ip/ip.h => ip/ip.h +4 -13
@@ 11,7 11,7 @@ typedef struct Ipmulti Ipmulti;
typedef struct Ipmux Ipmux;
typedef struct IProuter IProuter;
typedef struct Ipifc Ipifc;
-typedef struct Log Log;
+typedef struct Netlog Netlog;
typedef struct Ifclog Ifclog;
typedef struct Medium Medium;
typedef struct Proto Proto;
@@ 212,6 212,7 @@ struct Proto
void (*advise)(Proto*, Block*, char*);
int (*stats)(Proto*, char*, int);
int (*local)(Conv*, char*, int);
+ int (*remote)(Conv*, char*, int);
int (*inuse)(Conv*);
Fs *f; /* file system this proto is part of */
@@ 258,7 259,7 @@ struct Fs
Route *v6root[1<<Lroot]; /* v6 routing forest */
Route *queue; /* used as temp when reinjecting routes */
- Log *alog;
+ Netlog *alog;
Ifclog *ilog;
};
@@ 295,7 296,7 @@ enum
Logipmsg= 1<<14,
Logrudp= 1<<15,
Logrudpmsg= 1<<16,
-
+ Logesp= 1<<17,
};
void netloginit(Fs*);
@@ 415,14 416,6 @@ extern void arpenter(Fs*, int version, uchar *ip, uchar *mac, int len, int noref
* ipaux.c
*/
-typedef struct Cmdbuf Cmdbuf;
-struct Cmdbuf
-{
- char buf[64];
- char *f[16];
- int nf;
-};
-
extern int myetheraddr(uchar*, char*);
extern ulong parseip(uchar*, char*);
extern ulong parseipmask(uchar*, char*);
@@ 433,7 426,6 @@ extern uchar* defmask(uchar*);
extern int isv4(uchar*);
extern void v4tov6(uchar *v6, uchar *v4);
extern int v6tov4(uchar *v4, uchar *v6);
-extern Cmdbuf* parsecmd(char *a, int n);
extern int eipconv(va_list *arg, Fconv *f);
#define ipcmp(x, y) memcmp(x, y, IPaddrlen)
@@ 498,7 490,6 @@ extern void (*ipextprotoiput)(Block*);
extern void ipiput(Fs*, uchar*, Block*);
extern void ipoput(Fs*, Block*, int, int);
extern int ipstats(Fs*, char*, int);
-extern uchar* logctl(uchar*);
extern ushort ptclbsum(uchar*, int);
extern ushort ptclcsum(Block*, int, int);
extern void ip_init(Fs*);
M ip/ipaux.c => ip/ipaux.c +0 -20
@@ 361,26 361,6 @@ defmask(uchar *ip)
}
/*
- * parse a command written to a device
- */
-Cmdbuf*
-parsecmd(char *p, int n)
-{
- Cmdbuf *cb;
-
- cb = smalloc(sizeof(*cb));
-
- if(n > sizeof(cb->buf)-1)
- n = sizeof(cb->buf)-1;
- memmove(cb->buf, p, n);
- if(n > 0 && cb->buf[n-1] == '\n')
- n--;
- cb->buf[n] = '\0';
- cb->nf = parsefields(cb->buf, cb->f, nelem(cb->f), " ");
- return cb;
-}
-
-/*
* parse a hex mac address
*/
int
M ip/netlog.c => ip/netlog.c +7 -6
@@ 13,7 13,7 @@ enum {
/*
* action log
*/
-struct Log {
+struct Netlog {
Lock;
int opens;
char* buf;
@@ 29,12 29,12 @@ struct Log {
Rendez;
};
-typedef struct Logflag {
+typedef struct Netlogflag {
char* name;
int mask;
-} Logflag;
+} Netlogflag;
-static Logflag flags[] =
+static Netlogflag flags[] =
{
{ "ppp", Logppp, },
{ "ip", Logip, },
@@ 49,6 49,7 @@ static Logflag flags[] =
{ "tcpmsg", Logtcp|Logtcpmsg, },
{ "udpmsg", Logudp|Logudpmsg, },
{ "ipmsg", Logip|Logipmsg, },
+ { "esp", Logesp, },
{ nil, 0, },
};
@@ 57,7 58,7 @@ static char Ebadnetctl[] = "unknown netlog ctl message";
void
netloginit(Fs *f)
{
- f->alog = smalloc(sizeof(Log));
+ f->alog = smalloc(sizeof(Netlog));
}
void
@@ 158,7 159,7 @@ char*
netlogctl(Fs *f, char* s, int len)
{
int i, n, set;
- Logflag *fp;
+ Netlogflag *fp;
char *fields[10], *p, buf[256];
if(len == 0)
M pc/devether.c => pc/devether.c +12 -4
@@ 134,7 134,7 @@ etheriq(Ether* ether, Block* bp, int freebp)
{
Etherpkt *pkt;
ushort type;
- int len;
+ int len, multi, forme;
Netfile **ep, *f, **fp, *fx;
Block *xbp;
@@ 146,8 146,9 @@ etheriq(Ether* ether, Block* bp, int freebp)
fx = 0;
ep = ðer->f[Ntypes];
+ multi = pkt->d[0] & 1;
/* check for valid multcast addresses */
- if((pkt->d[0] & 1) && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){
+ if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){
if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
if(freebp){
freeb(bp);
@@ 157,6 158,9 @@ etheriq(Ether* ether, Block* bp, int freebp)
}
}
+ // is it for me?
+ forme = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
+
/*
* Multiplex the packet to all the connections which want it.
* If the packet is not to be used subsequently (freebp != 0),
@@ 164,7 168,7 @@ etheriq(Ether* ether, Block* bp, int freebp)
* saving a copy of the data (usual case hopefully).
*/
for(fp = ether->f; fp < ep; fp++){
- if((f = *fp) && (f->type == type || f->type < 0)){
+ if((f = *fp) && (f->type == type || f->type < 0) && (forme || multi || f->prom)){
if(f->type > -2){
if(freebp && fx == 0)
fx = f;
@@ 197,7 201,7 @@ etheriq(Ether* ether, Block* bp, int freebp)
static int
etheroq(Ether* ether, Block* bp)
{
- int len, loopback, s;
+ int len, loopback, s, mine;
Etherpkt *pkt;
ether->outpackets++;
@@ 208,10 212,14 @@ etheroq(Ether* ether, Block* bp)
* in promiscuous mode.
* If it's a loopback packet indicate to etheriq that the data isn't
* needed and return, etheriq will pass-on or free the block.
+ * To enable bridging to work, only packets that were originated
+ * by this interface are feedback
*/
pkt = (Etherpkt*)bp->rp;
len = BLEN(bp);
loopback = (memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0);
+ mine = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
+ if(mine)
if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
s = splhi();
etheriq(ether, bp, loopback);
A port/devbridge.c => port/devbridge.c +907 -0
@@ 0,0 1,907 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/netif.h"
+#include "../port/error.h"
+
+typedef struct Bridge Bridge;
+typedef struct Port Port;
+typedef struct Centry Centry;
+
+enum
+{
+ Qtopdir= 1, /* top level directory */
+
+ Qbridgedir, /* bridge* directory */
+ Qbctl,
+ Qstats,
+ Qcache,
+ Qlog,
+
+ Qportdir, /* directory for a protocol */
+ Qpctl,
+ Qlocal,
+ Qstatus,
+
+ MaxQ,
+
+ Maxbridge= 4,
+ Maxport= 16, // power of 2
+ CacheHash= 257, // prime
+ CacheLook= 5, // how many cache entries to examine
+ CacheSize= (CacheHash+CacheLook-1),
+ CacheTimeout= 5*60, // timeout for cache entry in seconds
+
+ Addrlen= 16, // must be long enough of IP addr and ether addr
+};
+
+Dirtab bridgedirtab[]={
+ "ctl", {Qbctl}, 0, 0666,
+ "stats", {Qstats}, 0, 0444,
+ "cache", {Qcache}, 0, 0444,
+ "log", {Qlog}, 0, 0666,
+};
+
+Dirtab portdirtab[]={
+ "ctl", {Qpctl}, 0, 0666,
+ "local", {Qlocal}, 0, 0444,
+ "status", {Qstatus}, 0, 0444,
+};
+
+enum {
+ Logcache= (1<<0),
+ Logmcast= (1<<1),
+};
+
+// types of interfaces
+enum
+{
+ Tether,
+ Ttunnel,
+};
+
+static Logflag logflags[] =
+{
+ { "cache", Logcache, },
+ { "multicast", Logmcast, },
+ { nil, 0, },
+};
+
+static Dirtab *dirtab[MaxQ];
+
+#define TYPE(x) ((x).path & 0xff)
+#define PORT(x) (((x).path >> 8)&(Maxport-1))
+#define QID(x, y) (((x)<<8) | (y))
+
+struct Centry
+{
+ uchar d[Eaddrlen];
+ int port;
+ long expire; // entry expires this number of seconds after bootime
+ long src;
+ long dst;
+};
+
+struct Bridge
+{
+ QLock;
+ int nport;
+ Port *port[Maxport];
+ Centry cache[CacheSize];
+ int hit;
+ int miss;
+
+ Log;
+};
+
+struct Port
+{
+ int id;
+ Bridge *bridge;
+ int ref;
+ int closed;
+
+ Chan *data[2]; // channel to data
+
+ int mcast; // send multi cast packets
+ Proc *readp; // read proc
+
+ // the following uniquely identifies the port
+ int type;
+ uchar addr[Addrlen];
+
+ // owner hash - avoids bind/unbind races
+ ulong ownhash;
+
+ // various stats
+ int in; // number of packets read
+ int inmulti; // multicast or broadcast
+ int inunknown; // unknown address
+ int out; // number of packets read
+ int outmulti; // multicast or broadcast
+ int outunknown; // unknown address
+ int nentry; // number of cache entries for this port
+};
+
+static Bridge bridgetab[Maxbridge];
+
+static int m2p[] = {
+ [OREAD] 4,
+ [OWRITE] 2,
+ [ORDWR] 6
+};
+
+static int bridgegen(Chan *c, Dirtab*, int, int s, Dir *dp);
+static void portbind(Bridge *b, int argc, char *argv[]);
+static void portunbind(Bridge *b, int argc, char *argv[]);
+static void etherread(void *a);
+static char *cachedump(Bridge *b);
+static void portfree(Port *port);
+static void cacheflushport(Bridge *b, int port);
+
+extern ulong parseip(uchar*, char*);
+
+static void
+bridgeinit(void)
+{
+ int i;
+ Dirtab *dt;
+ // setup dirtab with non directory entries
+ for(i=0; i<nelem(bridgedirtab); i++) {
+ dt = bridgedirtab + i;
+ dirtab[TYPE(dt->qid)] = dt;
+ }
+ for(i=0; i<nelem(portdirtab); i++) {
+ dt = portdirtab + i;
+ dirtab[TYPE(dt->qid)] = dt;
+ }
+}
+
+static Chan*
+bridgeattach(char* spec)
+{
+ Chan *c;
+ int dev;
+
+ dev = atoi(spec);
+ if(dev<0 || dev >= Maxbridge)
+ error("bad specification");
+
+ c = devattach('B', spec);
+ c->qid = (Qid){QID(0, Qtopdir)|CHDIR, 0};
+ c->dev = dev;
+
+ return c;
+}
+
+static int
+bridgewalk(Chan *c, char *name)
+{
+ Path *op;
+
+ if(strcmp(name, "..") == 0){
+ switch(TYPE(c->qid)){
+ case Qtopdir:
+ case Qbridgedir:
+ c->qid = (Qid){CHDIR|Qtopdir, 0};
+ break;
+ case Qportdir:
+ c->qid = (Qid){CHDIR|Qbridgedir, 0};
+ break;
+ default:
+ panic("bridgewalk %lux", c->qid.path);
+ }
+ op = c->path;
+ c->path = ptenter(&syspt, op, name);
+ decref(op);
+ return 1;
+ }
+
+ return devwalk(c, name, 0, 0, bridgegen);
+}
+
+static void
+bridgestat(Chan* c, char* db)
+{
+ devstat(c, db, nil, 0, bridgegen);
+}
+
+static Chan*
+bridgeopen(Chan* c, int omode)
+{
+ int perm;
+ Bridge *b;
+
+ omode &= 3;
+ perm = m2p[omode];
+ USED(perm);
+
+ b = bridgetab + c->dev;
+ USED(b);
+
+ switch(TYPE(c->qid)) {
+ default:
+ break;
+ case Qtopdir:
+ case Qbridgedir:
+ case Qportdir:
+ case Qstatus:
+ case Qlocal:
+ case Qstats:
+ if(omode != OREAD)
+ error(Eperm);
+ break;
+ case Qlog:
+ logopen(b);
+ break;
+ case Qcache:
+ if(omode != OREAD)
+ error(Eperm);
+ c->aux = cachedump(b);
+ break;
+ }
+ c->mode = openmode(omode);
+ c->flag |= COPEN;
+ c->offset = 0;
+ return c;
+}
+
+static void
+bridgeclose(Chan* c)
+{
+ Bridge *b = bridgetab + c->dev;
+
+ switch(TYPE(c->qid)) {
+ case Qcache:
+ if(c->flag & COPEN)
+ free(c->aux);
+ break;
+ case Qlog:
+ if(c->flag & COPEN)
+ logclose(b);
+ break;
+ }
+}
+
+static long
+bridgeread(Chan *c, void *a, long n, vlong off)
+{
+ char buf[256];
+ Bridge *b = bridgetab + c->dev;
+ Port *port;
+ int i;
+
+ USED(off);
+ switch(TYPE(c->qid)) {
+ default:
+ error(Eperm);
+ case Qtopdir:
+ case Qbridgedir:
+ case Qportdir:
+ return devdirread(c, a, n, 0, 0, bridgegen);
+ case Qlog:
+ return logread(b, a, off, n);
+ case Qstatus:
+ qlock(b);
+ port = b->port[PORT(c->qid)];
+ if(port == 0)
+ strcpy(buf, "unbound\n");
+ else {
+ i = 0;
+ switch(port->type) {
+ default: panic("bridgeread: unknown port type: %d", port->type);
+ case Tether:
+ i += snprint(buf+i, sizeof(buf)-i, "ether %E: ", port->addr);
+ break;
+ case Ttunnel:
+ i += snprint(buf+i, sizeof(buf)-i, "tunnel %I: ", port->addr);
+ break;
+ }
+ i += snprint(buf+i, sizeof(buf)-i, "in=%d/%d/%d out=%d/%d/%d\n",
+ port->in, port->inmulti, port->inunknown,
+ port->out, port->outmulti, port->outunknown);
+ USED(i);
+ }
+ n = readstr(off, a, n, buf);
+ qunlock(b);
+ return n;
+ case Qcache:
+ n = readstr(off, a, n, c->aux);
+ return n;
+ }
+}
+
+static long
+bridgewrite(Chan *c, void *a, long n, vlong off)
+{
+ Bridge *b = bridgetab + c->dev;
+ Cmdbuf *cb;
+ char *arg0;
+ char *p;
+
+ USED(off);
+
+ switch(TYPE(c->qid)) {
+ default:
+ error(Eperm);
+ case Qbctl:
+ cb = parsecmd(a, n);
+ qlock(b);
+ if(waserror()) {
+ qunlock(b);
+ free(cb);
+ nexterror();
+ }
+ if(cb->nf == 0)
+ error("short write");
+ arg0 = cb->f[0];
+ if(strcmp(arg0, "bind") == 0)
+ portbind(b, cb->nf-1, cb->f+1);
+ else if(strcmp(arg0, "unbind") == 0)
+ portunbind(b, cb->nf-1, cb->f+1);
+ else if(strcmp(arg0, "cacheflush") == 0) {
+ log(b, Logcache, "cache flush\n");
+ memset(b->cache, 0, CacheSize*sizeof(Centry));
+ } else
+ error("unknown control request");
+ poperror();
+ qunlock(b);
+ free(cb);
+ return n;
+ case Qlog:
+ cb = parsecmd(a, n);
+ p = logctl(b, cb->nf, cb->f, logflags);
+ free(cb);
+ if(p != nil)
+ error(p);
+ return n;
+ }
+}
+
+static int
+bridgegen(Chan *c, Dirtab*, int, int s, Dir *dp)
+{
+ Bridge *b = bridgetab + c->dev;
+ int type = TYPE(c->qid);
+ char buf[32];
+ Dirtab *dt;
+ Qid qid;
+
+ switch(type) {
+ default:
+ // non directory entries end up here
+ if(c->qid.path & CHDIR)
+ panic("bridgegen: unexpected directory");
+ if(s != 0)
+ return -1;
+ dt = dirtab[TYPE(c->qid)];
+ if(dt == nil)
+ panic("bridgegen: unknown type: %d", TYPE(c->qid));
+ devdir(c, c->qid, dt->name, dt->length, eve, dt->perm, dp);
+ return 1;
+ case Qtopdir:
+ if(s != 0)
+ return -1;
+ sprint(buf, "bridge%ld", c->dev);
+ devdir(c, (Qid){QID(0,Qbridgedir)|CHDIR,0}, buf, 0, eve, 0555, dp);
+ return 1;
+ case Qbridgedir:
+ if(s<nelem(bridgedirtab)) {
+ dt = bridgedirtab+s;
+ devdir(c, dt->qid, dt->name, dt->length, eve, dt->perm, dp);
+ return 1;
+ }
+ s -= nelem(bridgedirtab);
+ if(s >= b->nport)
+ return -1;
+ qid = (Qid){QID(s,Qportdir)|CHDIR, 0};
+ snprint(buf, sizeof(buf), "%d", s);
+ devdir(c, qid, buf, 0, eve, 0555, dp);
+ return 1;
+ case Qportdir:
+ if(s>=nelem(portdirtab))
+ return -1;
+ dt = portdirtab+s;
+ qid = (Qid){QID(PORT(c->qid),TYPE(dt->qid)),0};
+ devdir(c, qid, dt->name, dt->length, eve, dt->perm, dp);
+ return 1;
+ }
+}
+
+// also in netif.c
+static int
+parseaddr(uchar *to, char *from, int alen)
+{
+ char nip[4];
+ char *p;
+ int i;
+
+ p = from;
+ for(i = 0; i < alen; i++){
+ if(*p == 0)
+ return -1;
+ nip[0] = *p++;
+ if(*p == 0)
+ return -1;
+ nip[1] = *p++;
+ nip[2] = 0;
+ to[i] = strtoul(nip, 0, 16);
+ if(*p == ':')
+ p++;
+ }
+ return 0;
+}
+
+// assumes b is locked
+static void
+portbind(Bridge *b, int argc, char *argv[])
+{
+ Port *port;
+ char path[8*NAMELEN];
+ char buf[100];
+ char *dev, *dev2=nil, *p;
+ Chan *ctl;
+ int type=0, i, n;
+ char *usage = "usage: bind ether|tunnel addr ownhash dev [dev2]";
+ uchar addr[Addrlen];
+ ulong ownhash;
+
+ memset(addr, 0, Addrlen);
+ if(argc < 4)
+ error(usage);
+ if(strcmp(argv[0], "ether") == 0) {
+ if(argc != 4)
+ error(usage);
+ type = Tether;
+ parseaddr(addr, argv[1], Eaddrlen);
+ } else if(strcmp(argv[0], "tunnel") == 0) {
+ if(argc != 5)
+ error(usage);
+ type = Ttunnel;
+ parseip(addr, argv[1]);
+ dev2 = argv[4];
+ } else
+ error(usage);
+ ownhash = atoi(argv[2]);
+ dev = argv[3];
+ for(i=0; i<b->nport; i++) {
+ port = b->port[i];
+ if(port != nil)
+ if(port->type == type)
+ if(memcmp(port->addr, addr, Addrlen) == 0)
+ error("port in use");
+ }
+ for(i=0; i<Maxport; i++)
+ if(b->port[i] == nil)
+ break;
+ if(i == Maxport)
+ error("no more ports");
+ port = smalloc(sizeof(Port));
+ port->ref = 1;
+ port->id = i;
+ port->ownhash = ownhash;
+
+ if(waserror()) {
+ portfree(port);
+ nexterror();
+ }
+
+ port->type = type;
+ memmove(port->addr, addr, Addrlen);
+ switch(port->type) {
+ default: panic("portbind: unknown port type: %d", type);
+ case Tether:
+ snprint(path, sizeof(path), "%s/clone", dev);
+ ctl = namec(path, Aopen, ORDWR, 0);
+ if(waserror()) {
+ cclose(ctl);
+ nexterror();
+ }
+ // check addr?
+
+ // get directory name
+ n = devtab[ctl->type]->read(ctl, buf, sizeof(buf), 0);
+ buf[n] = 0;
+ for(p = buf; *p == ' '; p++)
+ ;
+ snprint(path, sizeof(path), "%s/%lud/data", dev, strtoul(p, 0, 0));
+
+ // setup connection to be promiscuous
+ snprint(buf, sizeof(buf), "connect -1");
+ devtab[ctl->type]->write(ctl, buf, strlen(buf), 0);
+ snprint(buf, sizeof(buf), "promiscuous");
+ devtab[ctl->type]->write(ctl, buf, strlen(buf), 0);
+
+ // open data port
+ port->data[0] = namec(path, Aopen, ORDWR, 0);
+ // dup it
+ incref(port->data[0]);
+ port->data[1] = port->data[0];
+
+ poperror();
+ cclose(ctl);
+
+ break;
+ case Ttunnel:
+ port->data[0] = namec(dev, Aopen, OREAD, 0);
+ port->data[1] = namec(dev2, Aopen, OWRITE, 0);
+ break;
+ }
+
+ poperror();
+
+ // commited to binding port
+ b->port[port->id] = port;
+ port->bridge = b;
+ if(b->nport <= port->id)
+ b->nport = port->id+1;
+
+ // assumes kproc always succeeds
+ port->ref++;
+ kproc("etherread", etherread, port); // poperror must be next
+}
+
+// assumes b is locked
+static void
+portunbind(Bridge *b, int argc, char *argv[])
+{
+ Port *port=nil;
+ int type=0, i;
+ char *usage = "usage: unbind ether|tunnel addr [ownhash]";
+ uchar addr[Addrlen];
+ ulong ownhash;
+
+ memset(addr, 0, Addrlen);
+ if(argc < 2 || argc > 3)
+ error(usage);
+ if(strcmp(argv[0], "ether") == 0) {
+ type = Tether;
+ parseaddr(addr, argv[1], Eaddrlen);
+ } else if(strcmp(argv[0], "tunnel") == 0) {
+ type = Ttunnel;
+ parseip(addr, argv[1]);
+ } else
+ error(usage);
+ if(argc == 3)
+ ownhash = atoi(argv[2]);
+ else
+ ownhash = 0;
+ for(i=0; i<b->nport; i++) {
+ port = b->port[i];
+ if(port != nil)
+ if(port->type == type)
+ if(memcmp(port->addr, addr, Addrlen) == 0)
+ break;
+ }
+ if(i == b->nport)
+ error("port not found");
+ if(ownhash != 0 && port->ownhash != 0 && ownhash != port->ownhash)
+ error("bad owner hash");
+
+ port->closed = 1;
+ b->port[i] = nil; // port is now unbound
+ cacheflushport(b, i);
+
+ // try and stop reader
+ if(port->readp)
+ postnote(port->readp, 1, "unbind", 0);
+ portfree(port);
+}
+
+// assumes b is locked
+static Centry *
+cachelookup(Bridge *b, uchar d[Eaddrlen])
+{
+ int i;
+ uint h;
+ Centry *p;
+ long sec;
+
+ // dont cache multicast or broadcast
+ if(d[0] & 1)
+ return 0;
+
+ h = 0;
+ for(i=0; i<Eaddrlen; i++) {
+ h *= 7;
+ h += d[i];
+ }
+ h %= CacheHash;
+ p = b->cache + h;
+ sec = TK2SEC(m->ticks);
+ for(i=0; i<CacheLook; i++,p++) {
+ if(memcmp(d, p->d, Eaddrlen) == 0) {
+ p->dst++;
+ if(sec >= p->expire) {
+ log(b, Logcache, "expired cache entry: %E %d\n",
+ d, p->port);
+ return nil;
+ }
+ p->expire = sec + CacheTimeout;
+ return p;
+ }
+ }
+ log(b, Logcache, "cache miss: %E\n", d);
+ return nil;
+}
+
+// assumes b is locked
+static void
+cacheupdate(Bridge *b, uchar d[Eaddrlen], int port)
+{
+ int i;
+ uint h;
+ Centry *p, *pp;
+ long sec;
+
+ // dont cache multicast or broadcast
+ if(d[0] & 1) {
+ log(b, Logcache, "bad source address: %E\n", d);
+ return;
+ }
+
+ h = 0;
+ for(i=0; i<Eaddrlen; i++) {
+ h *= 7;
+ h += d[i];
+ }
+ h %= CacheHash;
+ p = b->cache + h;
+ pp = p;
+ sec = p->expire;
+
+ // look for oldest entry
+ for(i=0; i<CacheLook; i++,p++) {
+ if(memcmp(p->d, d, Eaddrlen) == 0) {
+ p->expire = TK2SEC(m->ticks) + CacheTimeout;
+ if(p->port != port) {
+ log(b, Logcache, "NIC changed port %d->%d: %E\n",
+ p->port, port, d);
+ p->port = port;
+ }
+ p->src++;
+ return;
+ }
+ if(p->expire < sec) {
+ sec = p->expire;
+ pp = p;
+ }
+ }
+ if(pp->expire != 0)
+ log(b, Logcache, "bumping from cache: %E %d\n", pp->d, pp->port);
+ pp->expire = TK2SEC(m->ticks) + CacheTimeout;
+ memmove(pp->d, d, Eaddrlen);
+ pp->port = port;
+ pp->src = 1;
+ pp->dst = 0;
+ log(b, Logcache, "adding to cache: %E %d\n", pp->d, pp->port);
+}
+
+// assumes b is locked
+static void
+cacheflushport(Bridge *b, int port)
+{
+ Centry *ce;
+ int i;
+
+ ce = b->cache;
+ for(i=0; i<CacheSize; i++,ce++) {
+ if(ce->port != port)
+ continue;
+ memset(ce, 0, sizeof(Centry));
+ }
+}
+
+static char *
+cachedump(Bridge *b)
+{
+ int i, n;
+ long sec, off;
+ char *buf, *p, *ep;
+ Centry *ce;
+ char c;
+
+ qlock(b);
+ if(waserror()) {
+ qunlock(b);
+ nexterror();
+ }
+ sec = TK2SEC(m->ticks);
+ n = 0;
+ for(i=0; i<CacheSize; i++)
+ if(b->cache[i].expire != 0)
+ n++;
+
+ n *= 51; // change if print format is changed
+ n += 10; // some slop at the end
+ buf = malloc(n);
+ p = buf;
+ ep = buf + n;
+ ce = b->cache;
+ off = seconds() - sec;
+ for(i=0; i<CacheSize; i++,ce++) {
+ if(ce->expire == 0)
+ continue;
+ c = (sec < ce->expire)?'v':'e';
+ p += snprint(p, ep-p, "%E %2d %10ld %10ld %10ld %c\n", ce->d,
+ ce->port, ce->src, ce->dst, ce->expire+off, c);
+ }
+ *p = 0;
+ poperror();
+ qunlock(b);
+
+ return buf;
+}
+
+
+
+// assumes b is locked
+static void
+ethermultiwrite(Bridge *b, Block *bp, Port *port)
+{
+ Chan *c;
+ Block *bp2;
+ Etherpkt *ep;
+ int i, mcast, bcast;
+ static uchar bcastaddr[Eaddrlen] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ if(waserror()) {
+ if(bp)
+ freeb(bp);
+ nexterror();
+ }
+
+ ep = (Etherpkt*)bp->rp;
+ mcast = ep->d[0] & 1;
+ if(mcast)
+ bcast = memcmp(ep->d, bcastaddr, Eaddrlen) == 0;
+ else
+ bcast = 0;
+
+ c = nil;
+ for(i=0; i<b->nport; i++) {
+ if(i == port->id || b->port[i] == nil)
+ continue;
+ if(mcast && !bcast && !b->port[i]->mcast)
+ continue;
+ b->port[i]->out++;
+ if(mcast)
+ b->port[i]->outmulti++;
+ else
+ b->port[i]->outunknown++;
+
+ // delay one so that the last write does not copy
+ if(c != nil) {
+ // can not use write since it changes scr addr
+ bp2 = copyblock(bp, blocklen(bp));
+ devtab[c->type]->bwrite(c, bp2, 0);
+ }
+ c = b->port[i]->data[1];
+ }
+
+ // last write free block
+ if(c) {
+ bp2 = bp; bp = nil; USED(bp);
+ devtab[c->type]->bwrite(c, bp2, 0);
+ } else
+ freeb(bp);
+
+ poperror();
+}
+
+/*
+ * process to read from the ethernet
+ */
+static void
+etherread(void *a)
+{
+ Port *port = a, *oport;
+ Bridge *b = port->bridge;
+ Block *bp, *bp2;
+ Etherpkt *ep;
+ Centry *ce;
+
+
+ qlock(b);
+ port->readp = up; /* hide identity under a rock for unbind */
+
+ while(!port->closed){
+ // release lock to read - error means it is time to quit
+ qunlock(b);
+ if(waserror()) {
+ qlock(b);
+ break;
+ }
+//print("devbridge: etherread: reading\n");
+ bp = devtab[port->data[0]->type]->bread(port->data[0], ETHERMAXTU, 0);
+//print("devbridge: etherread: blocklen = %d\n", blocklen(bp));
+ poperror();
+ qlock(b);
+
+ if(port->closed)
+ break;
+ if(waserror()) {
+ if(bp)
+ freeb(bp);
+print("devbridge: etherread: %r\n");
+ continue;
+ }
+ if(blocklen(bp) < ETHERMINTU)
+ error("short packet");
+ port->in++;
+ ep = (Etherpkt*)bp->rp;
+ cacheupdate(b, ep->s, port->id);
+
+ if(ep->d[0] & 1) {
+ log(b, Logmcast, "mulitcast: port=%d src=%E dst=%E type=%#.4ux\n",
+ port->id, ep->s, ep->d, (ep->type[0]<<8)|ep->type[1] );
+ port->inmulti++;
+ bp2 = bp; bp = nil;
+ ethermultiwrite(b, bp2, port);
+ } else {
+ ce = cachelookup(b, ep->d);
+ if(ce == nil) {
+ b->miss++;
+ port->inunknown++;
+ bp2 = bp; bp = nil;
+ ethermultiwrite(b, bp2, port);
+ } else if (ce->port != port->id) {
+ b->hit++;
+ bp2 = bp; bp = nil;
+ oport = b->port[ce->port];
+ oport->out++;
+ devtab[oport->data[1]->type]->bwrite(oport->data[1], bp2, 0);
+ }
+ }
+
+ poperror();
+ if(bp)
+ freeb(bp);
+ }
+print("etherread: trying to exit\n");
+ port->readp = nil;
+ portfree(port);
+ qunlock(b);
+ pexit("hangup", 1);
+}
+
+// hold b lock
+static void
+portfree(Port *port)
+{
+ port->ref--;
+ if(port->ref < 0)
+ panic("portfree: bad ref");
+ if(port->ref > 0)
+ return;
+
+ if(port->data[0])
+ cclose(port->data[0]);
+ if(port->data[1])
+ cclose(port->data[1]);
+ memset(port, 0, sizeof(Port));
+ free(port);
+}
+
+Dev bridgedevtab = {
+ 'B',
+ "bridge",
+
+ devreset,
+ bridgeinit,
+ bridgeattach,
+ devclone,
+ bridgewalk,
+ bridgestat,
+ bridgeopen,
+ devcreate,
+ bridgeclose,
+ bridgeread,
+ devbread,
+ bridgewrite,
+ devbwrite,
+ devremove,
+ devwstat,
+};
M port/devroot.c => port/devroot.c +4 -0
@@ 14,6 14,9 @@ enum{
Qnet,
Qnetalt,
Qrecover,
+ Qroot, /* boot root */
+
+ // add new entries above this
Qboot, /* readable files */
Nfiles=13, /* max root files */
@@ 30,6 33,7 @@ Dirtab rootdir[Nfiles]={
"net", {Qnet|CHDIR}, 0, 0777,
"net.alt", {Qnetalt|CHDIR}, 0, 0777,
"recover", {Qrecover}, 0, 0777,
+ "root", {Qroot|CHDIR}, 0, 0777,
};
static uchar *rootdata[Nfiles];
A port/log.c => port/log.c +175 -0
@@ 0,0 1,175 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+static char Ebadlogctl[] = "unknown log ctl message";
+
+enum {
+ Nlog = 4*1024,
+};
+
+void
+logopen(Log *alog)
+{
+ lock(alog);
+ if(waserror()){
+ unlock(alog);
+ nexterror();
+ }
+ if(alog->opens == 0){
+ if(alog->buf == nil)
+ alog->buf = malloc(Nlog);
+ alog->rptr = alog->buf;
+ alog->end = alog->buf + Nlog;
+ }
+ alog->opens++;
+ unlock(alog);
+ poperror();
+}
+
+void
+logclose(Log *alog)
+{
+ lock(alog);
+ if(waserror()){
+ unlock(alog);
+ nexterror();
+ }
+ alog->opens--;
+ if(alog->opens == 0){
+ free(alog->buf);
+ alog->buf = nil;
+ }
+ unlock(alog);
+ poperror();
+}
+
+static int
+logready(void *a)
+{
+ Log *alog = a;
+
+ return alog->len;
+}
+
+long
+logread(Log *alog, void *a, ulong, long n)
+{
+ int i, d;
+ char *p, *rptr;
+
+ qlock(&alog->readq);
+ if(waserror()){
+ qunlock(&alog->readq);
+ nexterror();
+ }
+
+ for(;;){
+ lock(alog);
+ if(alog->len){
+ if(n > alog->len)
+ n = alog->len;
+ d = 0;
+ rptr = alog->rptr;
+ alog->rptr += n;
+ if(alog->rptr >= alog->end){
+ d = alog->rptr - alog->end;
+ alog->rptr = alog->buf + d;
+ }
+ alog->len -= n;
+ unlock(alog);
+
+ i = n;
+ p = a;
+ if(d){
+ memmove(p, rptr, d);
+ i -= d;
+ p += d;
+ rptr = alog->buf;
+ }
+ memmove(p, rptr, i);
+ break;
+ }
+ else
+ unlock(alog);
+
+ sleep(&alog->readr, logready, alog);
+ }
+
+ qunlock(&alog->readq);
+ poperror();
+
+ return n;
+}
+
+char*
+logctl(Log *alog, int argc, char *argv[], Logflag *flags)
+{
+ int i, n, set;
+ Logflag *fp;
+
+ if(argc < 2)
+ return Ebadlogctl;
+
+ if(strcmp("set", argv[0]) == 0)
+ set = 1;
+ else if(strcmp("clear", argv[0]) == 0)
+ set = 0;
+ else
+ return Ebadlogctl;
+
+ for(i = 1; i < argc; i++){
+ for(fp = flags; fp->name; fp++)
+ if(strcmp(fp->name, argv[i]) == 0)
+ break;
+ if(fp->name == nil)
+ continue;
+ if(set)
+ alog->logmask |= fp->mask;
+ else
+ alog->logmask &= ~fp->mask;
+ }
+
+ return nil;
+}
+
+void
+log(Log *alog, int mask, char *fmt, ...)
+{
+ char buf[128], *t, *fp;
+ int i, n;
+ va_list arg;
+
+ if(!(alog->logmask & mask))
+ return;
+
+ va_start(arg, fmt);
+ n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf;
+ va_end(arg);
+
+ if(alog->opens == 0)
+ return;
+
+ lock(alog);
+ i = alog->len + n - Nlog;
+ if(i > 0){
+ alog->len -= i;
+ alog->rptr += i;
+ if(alog->rptr >= alog->end)
+ alog->rptr = alog->buf + (alog->rptr - alog->end);
+ }
+ t = alog->rptr + alog->len;
+ fp = buf;
+ alog->len += n;
+ while(n-- > 0){
+ if(t >= alog->end)
+ t = alog->buf + (t - alog->end);
+ *t++ = *fp++;
+ }
+ unlock(alog);
+
+ wakeup(&alog->readr);
+}
M port/netif.c => port/netif.c +24 -7
@@ 59,17 59,26 @@ netifgen(Chan *c, void *vp, int, int i, Dir *dp)
/* second level contains clone plus all the conversations */
t = NETTYPE(c->qid.path);
if(t == N2ndqid || t == Ncloneqid){
- if(i == 0){
+ switch(i) {
+ case 0:
q.path = Ncloneqid;
devdir(c, q, "clone", 0, eve, 0666, dp);
- }else if(i <= nif->nfile){
- if(nif->f[i-1] == 0)
+ break;
+ case 1:
+ q.path = Naddrqid;
+ devdir(c, q, "addr", 0, eve, 0666, dp);
+ break;
+ default:
+ i -= 2;
+ if(i >= nif->nfile)
+ return -1;
+ if(nif->f[i] == 0)
return 0;
- q.path = CHDIR|NETQID(i-1, N3rdqid);
- sprint(buf, "%d", i-1);
+ q.path = CHDIR|NETQID(i, N3rdqid);
+ sprint(buf, "%d", i);
devdir(c, q, buf, 0, eve, 0555, dp);
- }else
- return -1;
+ break;
+ }
return 1;
}
@@ 192,6 201,14 @@ netifread(Netif *nif, Chan *c, void *a, long n, ulong offset)
n = readstr(offset, a, n, p);
free(p);
return n;
+ case Naddrqid:
+ p = malloc(READSTR);
+ j = 0;
+ for(i = 0; i < nif->alen; i++)
+ j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]);
+ n = readstr(offset, a, n, p);
+ free(p);
+ return n;
case Ntypeqid:
f = nif->f[NETID(c->qid.path)];
return readnum(offset, a, n, f->type, NUMSIZE);
M port/netif.h => port/netif.h +1 -0
@@ 9,6 9,7 @@ enum
Nmhash= 31,
Ncloneqid= 1,
+ Naddrqid,
N2ndqid,
N3rdqid,
Ndataqid,
A port/parse.c => port/parse.c +44 -0
@@ 0,0 1,44 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+int
+parsefields(char *lp, char **fields, int n, char *sep)
+{
+ int i;
+
+ for(i=0; lp && *lp && i<n; i++){
+ while(*lp && strchr(sep, *lp) != 0)
+ *lp++=0;
+ if(*lp == 0)
+ break;
+ fields[i]=lp;
+ while(*lp && strchr(sep, *lp) == 0)
+ lp++;
+ }
+ return i;
+}
+
+/*
+ * parse a command written to a device
+ */
+Cmdbuf*
+parsecmd(char *p, int n)
+{
+ Cmdbuf *cb;
+
+ cb = smalloc(sizeof(*cb));
+
+ if(n > sizeof(cb->buf)-1)
+ n = sizeof(cb->buf)-1;
+ memmove(cb->buf, p, n);
+ if(n > 0 && cb->buf[n-1] == '\n')
+ n--;
+ cb->buf[n] = '\0';
+ cb->nf = parsefields(cb->buf, cb->f, nelem(cb->f), " ");
+ return cb;
+}
+
M port/portdat.h => port/portdat.h +33 -0
@@ 1,6 1,7 @@
typedef struct Alarms Alarms;
typedef struct Block Block;
typedef struct Chan Chan;
+typedef struct Cmdbuf Cmdbuf;
typedef struct Crypt Crypt;
typedef struct Dev Dev;
typedef struct Dirtab Dirtab;
@@ 9,6 10,8 @@ typedef struct Evalue Evalue;
typedef struct Fgrp Fgrp;
typedef struct Image Image;
typedef struct List List;
+typedef struct Log Log;
+typedef struct Logflag Logflag;
typedef struct Mntcache Mntcache;
typedef struct Mount Mount;
typedef struct Mntrpc Mntrpc;
@@ 39,6 42,7 @@ typedef struct Target Target;
typedef struct Waitq Waitq;
typedef int Devgen(Chan*, Dirtab*, int, int, Dir*);
+
#include <auth.h>
#include <fcall.h>
@@ 716,6 720,35 @@ enum
LRESPROF = 3,
};
+/*
+ * action log
+ */
+struct Log {
+ Lock;
+ int opens;
+ char* buf;
+ char *end;
+ char *rptr;
+ int len;
+
+ int logmask; /* mask of things to debug */
+
+ QLock readq;
+ Rendez readr;
+};
+
+struct Logflag {
+ char* name;
+ int mask;
+};
+
+struct Cmdbuf
+{
+ char buf[64];
+ char *f[16];
+ int nf;
+};
+
extern int nsyscall;
#pragma varargck argpos print 1
M port/portfns.h => port/portfns.h +6 -0
@@ 142,6 142,11 @@ void ksetenv(char*, char*);
long latin1(uchar*, int);
void lock(Lock*);
void lockinit(void);
+void logopen(Log*);
+void logclose(Log*);
+char* logctl(Log*, int, char**, Logflag*);
+long logread(Log*, void*, ulong, long);
+void log(Log*, int, char*, ...);
Page* lookpage(Image*, ulong);
void machinit(void);
void* mallocz(ulong, int);
@@ 179,6 184,7 @@ void pagersummary(void);
void panic(char*, ...);
int parseether(uchar*, char*);
int parsefields(char*, char**, int, char*);
+Cmdbuf* parsecmd(char *a, int n);
void pexit(char*, int);
void pgrpcpy(Pgrp*, Pgrp*);
void pgrpnote(ulong, char*, long, int);