#include "dat.h"#include "fns.h"#include "error.h"#include "ip.h" enum{ Qtopdir = 1, /* top level directory */ Qtopbase, Qarp= Qtopbase,/* Qiproute, *//* Qipselftab, */ Qndb, Qprotodir, /* directory for a protocol */ Qprotobase, Qclone= Qprotobase, Qstats, Qconvdir, /* directory for a conversation */ Qconvbase, Qctl= Qconvbase, Qdata, Qlisten, Qlocal, Qremote, Qstatus, Logtype= 5, Masktype= (1<<Logtype)-1, Logconv= 12, Maskconv= (1<<Logconv)-1, Shiftconv= Logtype, Logproto= 8, Maskproto= (1<<Logproto)-1, Shiftproto= Logtype + Logconv, Statelen = 256, Nfs= 1, Maxproto = 4, MAXCONV = 4096};#define TYPE(x) ( ((ulong)(x).path) & Masktype )#define CONV(x) ( (((ulong)(x).path) >> Shiftconv) & Maskconv )#define PROTO(x) ( (((ulong)(x).path) >> Shiftproto) & Maskproto )#define QID(p, c, y) ( ((p)<<(Shiftproto)) | ((c)<<Shiftconv) | (y) ) enum{ Idle= 0, Announcing= 1, Announced= 2, Connecting= 3, Connected= 4, Hungup= 5,}; struct Conv{ QLock l; int x; /* conversation index */ Proto* p; uchar laddr[IPaddrlen]; /* local IP address */ uchar raddr[IPaddrlen]; /* remote IP address */ int restricted; /* remote port is restricted */ ushort lport; /* local port number */ ushort rport; /* remote port number */ char* owner; /* protections */ int perm; int inuse; /* opens of listen/data/ctl */ int state; /* udp specific */ int headers; /* data src/dst headers in udp */ char cerr[ERRMAX]; QLock listenq; void* ptcl; /* protocol specific stuff */ int sfd; QLock wlock; /* prevent data from being split by concurrent writes */}; struct Proto{ QLock l; int x; int ipproto; int stype; char* name; int maxconv; Fs* f; /* file system this proto is part of */ Conv** conv; /* array of conversations */ int pctlsize; /* size of per protocol ctl block */ int nc; /* number of conversations */ int ac; Qid qid; /* qid for protocol directory */ /* port allocation isn't done here when hosted */ void* priv;}; /* * one per IP protocol stack */struct Fs{ RWlock l; int dev; int np; Proto* p[Maxproto+1]; /* list of supported protocols */ Proto* t2p[256]; /* vector of all protocols */ char ndb[1024]; /* an ndb entry for this interface */ int ndbvers; long ndbmtime;}; static Fs *ipfs[Nfs]; /* attached fs's */static char network[] = "network";static char* ipstates[] = { "Closed", /* Idle */ "Announcing", "Announced", "Connecting", "Established", /* Connected */ "Closed", /* Hungup */}; static Conv* protoclone(Proto*, char*, int);static Conv* newconv(Proto*, Conv **);static void setladdr(Conv*);static ulong ip6w(uchar*);static void ipw6(uchar*, ulong); static intip3gen(Chan *c, int i, Dir *dp){ Qid q; Conv *cv; char *p; cv = ipfs[c->dev]->p[PROTO(c->qid)]->conv[CONV(c->qid)]; if(cv->owner == nil) kstrdup(&cv->owner, eve); mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE); switch(i) { default: return -1; case Qctl: devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp); return 1; case Qdata: devdir(c, q, "data", 0, cv->owner, cv->perm, dp); return 1; case Qlisten: devdir(c, q, "listen", 0, cv->owner, cv->perm, dp); return 1; case Qlocal: p = "local"; break; case Qremote: p = "remote"; break; case Qstatus: p = "status"; break; } devdir(c, q, p, 0, cv->owner, 0444, dp); return 1;} static intip2gen(Chan *c, int i, Dir *dp){ Qid q; switch(i) { case Qclone: mkqid(&q, QID(PROTO(c->qid), 0, Qclone), 0, QTFILE); devdir(c, q, "clone", 0, network, 0666, dp); return 1; case Qstats: mkqid(&q, QID(PROTO(c->qid), 0, Qstats), 0, QTFILE); devdir(c, q, "stats", 0, network, 0444, dp); return 1; } return -1;} static intip1gen(Chan *c, int i, Dir *dp){ Qid q; char *p; int prot; int len = 0; Fs *f; extern ulong kerndate; f = ipfs[c->dev]; prot = 0664; mkqid(&q, QID(0, 0, i), 0, QTFILE); switch(i) { default: return -1; case Qarp: p = "arp"; break; case Qndb: p = "ndb"; len = strlen(ipfs[c->dev]->ndb); break;/* case Qiproute: p = "iproute"; break; case Qipselftab: p = "ipselftab"; prot = 0444; break; case Qiprouter: p = "iprouter"; break; case Qlog: p = "log"; break;*/ } devdir(c, q, p, len, network, prot, dp); if(i == Qndb && f->ndbmtime > kerndate) dp->mtime = f->ndbmtime; return 1;} static intipgen(Chan *c, char *name, Dirtab *tab, int x, int s, Dir *dp){ Qid q; Conv *cv; Fs *f; USED(name); USED(tab); USED(x); f = ipfs[c->dev]; switch(TYPE(c->qid)) { case Qtopdir: if(s == DEVDOTDOT){ mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR); sprint(up->genbuf, "#I%lud", c->dev); devdir(c, q, up->genbuf, 0, network, 0555, dp); return 1; } if(s < f->np) {/* if(f->p[s]->connect == nil) return 0; /* protocol with no user interface */ mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR); devdir(c, q, f->p[s]->name, 0, network, 0555, dp); return 1; } s -= f->np; return ip1gen(c, s+Qtopbase, dp); case Qarp: case Qndb:/* case Qiproute: case Qiprouter: case Qipselftab: */ return ip1gen(c, TYPE(c->qid), dp); case Qprotodir: if(s == DEVDOTDOT){ mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR); sprint(up->genbuf, "#I%lud", c->dev); devdir(c, q, up->genbuf, 0, network, 0555, dp); return 1; } if(s < f->p[PROTO(c->qid)]->ac) { cv = f->p[PROTO(c->qid)]->conv[s]; sprint(up->genbuf, "%d", s); mkqid(&q, QID(PROTO(c->qid), s, Qconvdir), 0, QTDIR); devdir(c, q, up->genbuf, 0, cv->owner, 0555, dp); return 1; } s -= f->p[PROTO(c->qid)]->ac; return ip2gen(c, s+Qprotobase, dp); case Qclone: case Qstats: return ip2gen(c, TYPE(c->qid), dp); case Qconvdir: if(s == DEVDOTDOT){ s = PROTO(c->qid); mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR); devdir(c, q, f->p[s]->name, 0, network, 0555, dp); return 1; } return ip3gen(c, s+Qconvbase, dp); case Qctl: case Qdata: case Qlisten: case Qlocal: case Qremote: case Qstatus: return ip3gen(c, TYPE(c->qid), dp); } return -1;} static voidnewproto(char *name, int type, int maxconv){ Proto *p; p = smalloc(sizeof(*p)); p->name = name; p->stype = type; p->ipproto = type+1; /* temporary */ p->nc = maxconv; if(Fsproto(ipfs[0], p)) panic("can't newproto %s", name);} voidipinit(void){ ipfs[0] = malloc(sizeof(Fs)); if(ipfs[0] == nil) panic("no memory for IP stack"); newproto("udp", S_UDP, 64); newproto("tcp", S_TCP, 2048); fmtinstall('i', eipfmt); fmtinstall('I', eipfmt); fmtinstall('E', eipfmt); fmtinstall('V', eipfmt); fmtinstall('M', eipfmt);} Chan *ipattach(char *spec){ Chan *c; if(atoi(spec) != 0) error("bad specification"); c = devattach('I', spec); mkqid(&c->qid, QID(0, 0, Qtopdir), 0, QTDIR); c->dev = 0; return c;} static Walkqid*ipwalk(Chan* c, Chan *nc, char **name, int nname){ return devwalk(c, nc, name, nname, nil, 0, ipgen);} static intipstat(Chan *c, uchar *db, int n){ return devstat(c, db, n, 0, 0, ipgen);} static int m2p[] = { 4, 2, 6,}; static Chan *ipopen(Chan *c, int omode){ Conv *cv, *nc; Proto *p; ulong raddr; ushort rport; int perm, sfd; Fs *f; perm = m2p[omode&3]; f = ipfs[c->dev]; switch(TYPE(c->qid)) { default: break; case Qtopdir: case Qprotodir: case Qconvdir: case Qstatus: case Qremote: case Qlocal: case Qstats: /* case Qipselftab: */ if(omode != OREAD) error(Eperm); break; case Qndb: if(omode & (OWRITE|OTRUNC) && !iseve()) error(Eperm); if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC)){ f->ndb[0] = 0; f->ndbvers++; } break; case Qclone: p = f->p[PROTO(c->qid)]; cv = protoclone(p, up->env->user, -1); if(cv == 0) error(Enodev); mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE); break; case Qdata: case Qctl: p = f->p[PROTO(c->qid)]; qlock(&p->l); cv = p->conv[CONV(c->qid)]; qlock(&cv->l); if(waserror()){ qunlock(&cv->l); qunlock(&p->l); nexterror(); } if((perm & (cv->perm>>6)) != perm) { if(strcmp(up->env->user, cv->owner) != 0) error(Eperm); if((perm & cv->perm) != perm) error(Eperm); } cv->inuse++; if(cv->inuse == 1) { kstrdup(&cv->owner, up->env->user); cv->perm = 0660; if(cv->sfd < 0) cv->sfd = so_socket(p->stype); } poperror(); qunlock(&cv->l); qunlock(&p->l); break; case Qlisten: p = f->p[PROTO(c->qid)]; cv = p->conv[CONV(c->qid)]; if((perm & (cv->perm>>6)) != perm){ if(strcmp(up->env->user, cv->owner) != 0) error(Eperm); if((perm & cv->perm) != perm) error(Eperm); } if(cv->state != Announced) error("not announced"); qlock(&cv->listenq); if(waserror()){ qunlock(&cv->listenq); nexterror(); } sfd = so_accept(cv->sfd, &raddr, &rport); nc = protoclone(p, up->env->user, sfd); if(nc == 0) { so_close(sfd); error(Enodev); } ipw6(nc->raddr, raddr); nc->rport = rport; setladdr(nc); nc->state = Connected; mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE); poperror(); qunlock(&cv->listenq); break; } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c;} static voidcloseconv(Conv *cv){ int fd; qlock(&cv->l);Lines 1–500 of 1143. Load more
#include "dat.h" #include "fns.h" #include "error.h" #include "ip.h" enum { Qtopdir = 1, /* top level directory */ Qtopbase, Qarp= Qtopbase, /* Qiproute, */ /* Qipselftab, */ Qndb, Qprotodir, /* directory for a protocol */ Qprotobase, Qclone= Qprotobase, Qstats, Qconvdir, /* directory for a conversation */ Qconvbase, Qctl= Qconvbase, Qdata, Qlisten, Qlocal, Qremote, Qstatus, Logtype= 5, Masktype= (1<<Logtype)-1, Logconv= 12, Maskconv= (1<<Logconv)-1, Shiftconv= Logtype, Logproto= 8, Maskproto= (1<<Logproto)-1, Shiftproto= Logtype + Logconv, Statelen = 256, Nfs= 1, Maxproto = 4, MAXCONV = 4096 }; #define TYPE(x) ( ((ulong)(x).path) & Masktype ) #define CONV(x) ( (((ulong)(x).path) >> Shiftconv) & Maskconv ) #define PROTO(x) ( (((ulong)(x).path) >> Shiftproto) & Maskproto ) #define QID(p, c, y) ( ((p)<<(Shiftproto)) | ((c)<<Shiftconv) | (y) ) enum { Idle= 0, Announcing= 1, Announced= 2, Connecting= 3, Connected= 4, Hungup= 5, }; struct Conv { QLock l; int x; /* conversation index */ Proto* p; uchar laddr[IPaddrlen]; /* local IP address */ uchar raddr[IPaddrlen]; /* remote IP address */ int restricted; /* remote port is restricted */ ushort lport; /* local port number */ ushort rport; /* remote port number */ char* owner; /* protections */ int perm; int inuse; /* opens of listen/data/ctl */ int state; /* udp specific */ int headers; /* data src/dst headers in udp */ char cerr[ERRMAX]; QLock listenq; void* ptcl; /* protocol specific stuff */ int sfd; QLock wlock; /* prevent data from being split by concurrent writes */ }; struct Proto { QLock l; int x; int ipproto; int stype; char* name; int maxconv; Fs* f; /* file system this proto is part of */ Conv** conv; /* array of conversations */ int pctlsize; /* size of per protocol ctl block */ int nc; /* number of conversations */ int ac; Qid qid; /* qid for protocol directory */ /* port allocation isn't done here when hosted */ void* priv; }; /* * one per IP protocol stack */ struct Fs { RWlock l; int dev; int np; Proto* p[Maxproto+1]; /* list of supported protocols */ Proto* t2p[256]; /* vector of all protocols */ char ndb[1024]; /* an ndb entry for this interface */ int ndbvers; long ndbmtime; }; static Fs *ipfs[Nfs]; /* attached fs's */ static char network[] = "network"; static char* ipstates[] = { "Closed", /* Idle */ "Announcing", "Announced", "Connecting", "Established", /* Connected */ "Closed", /* Hungup */ }; static Conv* protoclone(Proto*, char*, int); static Conv* newconv(Proto*, Conv **); static void setladdr(Conv*); static ulong ip6w(uchar*); static void ipw6(uchar*, ulong); static int ip3gen(Chan *c, int i, Dir *dp) { Qid q; Conv *cv; char *p; cv = ipfs[c->dev]->p[PROTO(c->qid)]->conv[CONV(c->qid)]; if(cv->owner == nil) kstrdup(&cv->owner, eve); mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE); switch(i) { default: return -1; case Qctl: devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp); return 1; case Qdata: devdir(c, q, "data", 0, cv->owner, cv->perm, dp); return 1; case Qlisten: devdir(c, q, "listen", 0, cv->owner, cv->perm, dp); return 1; case Qlocal: p = "local"; break; case Qremote: p = "remote"; break; case Qstatus: p = "status"; break; } devdir(c, q, p, 0, cv->owner, 0444, dp); return 1; } static int ip2gen(Chan *c, int i, Dir *dp) { Qid q; switch(i) { case Qclone: mkqid(&q, QID(PROTO(c->qid), 0, Qclone), 0, QTFILE); devdir(c, q, "clone", 0, network, 0666, dp); return 1; case Qstats: mkqid(&q, QID(PROTO(c->qid), 0, Qstats), 0, QTFILE); devdir(c, q, "stats", 0, network, 0444, dp); return 1; } return -1; } static int ip1gen(Chan *c, int i, Dir *dp) { Qid q; char *p; int prot; int len = 0; Fs *f; extern ulong kerndate; f = ipfs[c->dev]; prot = 0664; mkqid(&q, QID(0, 0, i), 0, QTFILE); switch(i) { default: return -1; case Qarp: p = "arp"; break; case Qndb: p = "ndb"; len = strlen(ipfs[c->dev]->ndb); break; /* case Qiproute: p = "iproute"; break; case Qipselftab: p = "ipselftab"; prot = 0444; break; case Qiprouter: p = "iprouter"; break; case Qlog: p = "log"; break; */ } devdir(c, q, p, len, network, prot, dp); if(i == Qndb && f->ndbmtime > kerndate) dp->mtime = f->ndbmtime; return 1; } static int ipgen(Chan *c, char *name, Dirtab *tab, int x, int s, Dir *dp) { Qid q; Conv *cv; Fs *f; USED(name); USED(tab); USED(x); f = ipfs[c->dev]; switch(TYPE(c->qid)) { case Qtopdir: if(s == DEVDOTDOT){ mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR); sprint(up->genbuf, "#I%lud", c->dev); devdir(c, q, up->genbuf, 0, network, 0555, dp); return 1; } if(s < f->np) { /* if(f->p[s]->connect == nil) return 0; /* protocol with no user interface */ mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR); devdir(c, q, f->p[s]->name, 0, network, 0555, dp); return 1; } s -= f->np; return ip1gen(c, s+Qtopbase, dp); case Qarp: case Qndb: /* case Qiproute: case Qiprouter: case Qipselftab: */ return ip1gen(c, TYPE(c->qid), dp); case Qprotodir: if(s == DEVDOTDOT){ mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR); sprint(up->genbuf, "#I%lud", c->dev); devdir(c, q, up->genbuf, 0, network, 0555, dp); return 1; } if(s < f->p[PROTO(c->qid)]->ac) { cv = f->p[PROTO(c->qid)]->conv[s]; sprint(up->genbuf, "%d", s); mkqid(&q, QID(PROTO(c->qid), s, Qconvdir), 0, QTDIR); devdir(c, q, up->genbuf, 0, cv->owner, 0555, dp); return 1; } s -= f->p[PROTO(c->qid)]->ac; return ip2gen(c, s+Qprotobase, dp); case Qclone: case Qstats: return ip2gen(c, TYPE(c->qid), dp); case Qconvdir: if(s == DEVDOTDOT){ s = PROTO(c->qid); mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR); devdir(c, q, f->p[s]->name, 0, network, 0555, dp); return 1; } return ip3gen(c, s+Qconvbase, dp); case Qctl: case Qdata: case Qlisten: case Qlocal: case Qremote: case Qstatus: return ip3gen(c, TYPE(c->qid), dp); } return -1; } static void newproto(char *name, int type, int maxconv) { Proto *p; p = smalloc(sizeof(*p)); p->name = name; p->stype = type; p->ipproto = type+1; /* temporary */ p->nc = maxconv; if(Fsproto(ipfs[0], p)) panic("can't newproto %s", name); } void ipinit(void) { ipfs[0] = malloc(sizeof(Fs)); if(ipfs[0] == nil) panic("no memory for IP stack"); newproto("udp", S_UDP, 64); newproto("tcp", S_TCP, 2048); fmtinstall('i', eipfmt); fmtinstall('I', eipfmt); fmtinstall('E', eipfmt); fmtinstall('V', eipfmt); fmtinstall('M', eipfmt); } Chan * ipattach(char *spec) { Chan *c; if(atoi(spec) != 0) error("bad specification"); c = devattach('I', spec); mkqid(&c->qid, QID(0, 0, Qtopdir), 0, QTDIR); c->dev = 0; return c; } static Walkqid* ipwalk(Chan* c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, nil, 0, ipgen); } static int ipstat(Chan *c, uchar *db, int n) { return devstat(c, db, n, 0, 0, ipgen); } static int m2p[] = { 4, 2, 6, }; static Chan * ipopen(Chan *c, int omode) { Conv *cv, *nc; Proto *p; ulong raddr; ushort rport; int perm, sfd; Fs *f; perm = m2p[omode&3]; f = ipfs[c->dev]; switch(TYPE(c->qid)) { default: break; case Qtopdir: case Qprotodir: case Qconvdir: case Qstatus: case Qremote: case Qlocal: case Qstats: /* case Qipselftab: */ if(omode != OREAD) error(Eperm); break; case Qndb: if(omode & (OWRITE|OTRUNC) && !iseve()) error(Eperm); if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC)){ f->ndb[0] = 0; f->ndbvers++; } break; case Qclone: p = f->p[PROTO(c->qid)]; cv = protoclone(p, up->env->user, -1); if(cv == 0) error(Enodev); mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE); break; case Qdata: case Qctl: p = f->p[PROTO(c->qid)]; qlock(&p->l); cv = p->conv[CONV(c->qid)]; qlock(&cv->l); if(waserror()){ qunlock(&cv->l); qunlock(&p->l); nexterror(); } if((perm & (cv->perm>>6)) != perm) { if(strcmp(up->env->user, cv->owner) != 0) error(Eperm); if((perm & cv->perm) != perm) error(Eperm); } cv->inuse++; if(cv->inuse == 1) { kstrdup(&cv->owner, up->env->user); cv->perm = 0660; if(cv->sfd < 0) cv->sfd = so_socket(p->stype); } poperror(); qunlock(&cv->l); qunlock(&p->l); break; case Qlisten: p = f->p[PROTO(c->qid)]; cv = p->conv[CONV(c->qid)]; if((perm & (cv->perm>>6)) != perm){ if(strcmp(up->env->user, cv->owner) != 0) error(Eperm); if((perm & cv->perm) != perm) error(Eperm); } if(cv->state != Announced) error("not announced"); qlock(&cv->listenq); if(waserror()){ qunlock(&cv->listenq); nexterror(); } sfd = so_accept(cv->sfd, &raddr, &rport); nc = protoclone(p, up->env->user, sfd); if(nc == 0) { so_close(sfd); error(Enodev); } ipw6(nc->raddr, raddr); nc->rport = rport; setladdr(nc); nc->state = Connected; mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE); poperror(); qunlock(&cv->listenq); break; } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } static void closeconv(Conv *cv) { int fd; qlock(&cv->l);