#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h"#include "../ip/ip.h" enum{ Qtopdir= 1, /* top level directory */ Qtopbase, Qarp= Qtopbase, Qbootp, Qndb, Qiproute, Qipselftab, Qlog, Qprotodir, /* directory for a protocol */ Qprotobase, Qclone= Qprotobase, Qstats, Qconvdir, /* directory for a conversation */ Qconvbase, Qctl= Qconvbase, Qdata, Qerr, 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, Nfs= 16,};#define TYPE(x) ( (x).path & Masktype )#define CONV(x) ( ((x).path >> Shiftconv) & Maskconv )#define PROTO(x) ( ((x).path >> Shiftproto) & Maskproto )#define QID(p, c, y) ( ((p)<<(Shiftproto)) | ((c)<<Shiftconv) | (y) ) static char network[] = "network"; QLock fslock;Fs *ipfs[Nfs]; /* attached fs's */Queue *qlog; extern void nullmediumlink(void);extern void pktmediumlink(void); long ndbwrite(Fs *f, char *a, ulong off, int n); 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)]; switch(i) { default: return -1; case Qctl: q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qctl), 0}; devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp); return 1; case Qdata: q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qdata), 0}; devdir(c, q, "data", qlen(cv->rq), cv->owner, cv->perm, dp); return 1; case Qerr: q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qerr), 0}; devdir(c, q, "err", qlen(cv->eq), cv->owner, cv->perm, dp); return 1; case Qlisten: p = "listen"; q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qlisten), 0}; break; case Qlocal: p = "local"; q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qlocal), 0}; break; case Qremote: p = "remote"; q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qremote), 0}; break; case Qstatus: p = "status"; q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qstatus), 0}; break; } devdir(c, q, p, 0, cv->owner, 0666, dp); return 1;} static intip2gen(Chan *c, int i, Dir *dp){ Qid q; switch(i) { case Qclone: q = (Qid){QID(PROTO(c->qid), 0, Qclone), 0}; devdir(c, q, "clone", 0, network, 0666, dp); return 1; case Qstats: q = (Qid){QID(PROTO(c->qid), 0, Qstats), 0}; 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; f = ipfs[c->dev]; prot = 0666; switch(i) { default: return -1; case Qarp: p = "arp"; q = (Qid){QID(0, 0, Qarp), 0}; break; case Qbootp: p = "bootp"; q = (Qid){QID(0, 0, Qbootp), 0}; break; case Qndb: p = "ndb"; q = (Qid){QID(0, 0, Qndb), 0}; len = strlen(f->ndb); break; case Qiproute: p = "iproute"; q = (Qid){QID(0, 0, Qiproute), 0}; break; case Qipselftab: p = "ipselftab"; prot = 0444; q = (Qid){QID(0, 0, Qipselftab), 0}; break; case Qlog: p = "log"; q = (Qid){QID(0, 0, Qlog), 0}; break; } devdir(c, q, p, len, network, prot, dp); return 1;} static intipgen(Chan *c, Dirtab*, int, int s, Dir *dp){ Qid q; Conv *cv; char name[16]; Fs *f; f = ipfs[c->dev]; switch(TYPE(c->qid)) { case Qtopdir: if(s == DEVDOTDOT){ q = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0}; sprint(name, "#I%lud", c->dev); devdir(c, q, name, 0, network, 0555, dp); return 1; } if(s < f->np) { if(f->p[s]->connect == nil) return 0; /* protocol with no user interface */ q = (Qid){QID(s, 0, Qprotodir)|CHDIR, 0}; 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 Qbootp: case Qndb: case Qlog: case Qiproute: case Qipselftab: return ip1gen(c, TYPE(c->qid), dp); case Qprotodir: if(s == DEVDOTDOT){ q = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0}; sprint(name, "#I%lud", c->dev); devdir(c, q, name, 0, network, 0555, dp); return 1; } if(s < f->p[PROTO(c->qid)]->ac) { cv = f->p[PROTO(c->qid)]->conv[s]; sprint(name, "%d", s); q = (Qid){QID(PROTO(c->qid), s, Qconvdir)|CHDIR, 0}; devdir(c, q, name, 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); q = (Qid){QID(s, 0, Qprotodir)|CHDIR, 0}; devdir(c, q, f->p[s]->name, 0, network, 0555, dp); return 1; } return ip3gen(c, s+Qconvbase, dp); case Qctl: case Qdata: case Qerr: case Qlisten: case Qlocal: case Qremote: case Qstatus: return ip3gen(c, TYPE(c->qid), dp); } return -1;} static voidipreset(void){ nullmediumlink(); pktmediumlink();} static voidipinit(void){ fmtinstall('i', eipconv); fmtinstall('I', eipconv); fmtinstall('E', eipconv); fmtinstall('V', eipconv); fmtinstall('M', eipconv);} static Fs*ipgetfs(int dev){ extern void (*ipprotoinit[])(Fs*); Fs *f; int i; if(dev >= Nfs) return nil; qlock(&fslock); if(ipfs[dev] == nil){ f = smalloc(sizeof(Fs)); ip_init(f); arpinit(f); netloginit(f); for(i = 0; ipprotoinit[i]; i++) ipprotoinit[i](f); f->dev = dev; ipfs[dev] = f; } qunlock(&fslock); return ipfs[dev];} static Chan*ipattach(char* spec){ Chan *c; int dev; dev = atoi(spec); if(dev >= 16) error("bad specification"); ipgetfs(dev); c = devattach('I', spec); c->qid = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0}; c->dev = dev; return c;} static Chan*ipclone(Chan* c, Chan* nc){ return devclone(c, nc);} static intipwalk(Chan* c, char* name){ return devwalk(c, name, nil, 0, ipgen);} static voidipstat(Chan* c, char* db){ devstat(c, db, nil, 0, ipgen);} static intincoming(void* arg){ Conv *conv; conv = arg; return conv->incall != nil;} static int m2p[] = { [OREAD] 4, [OWRITE] 2, [ORDWR] 6}; static Chan*ipopen(Chan* c, int omode){ Conv *cv, *nc; Proto *p; int perm; Fs *f; omode &= 3; perm = m2p[omode]; f = ipfs[c->dev]; switch(TYPE(c->qid)) { default: break; case Qndb: if(omode & (OWRITE|OTRUNC) && !iseve()) error(Eperm); if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC)) f->ndb[0] = 0; break; case Qlog: netlogopen(f); break; case Qiproute: memmove(c->tag, "none", sizeof(c->tag)); break; case Qtopdir: case Qprotodir: case Qconvdir: case Qstatus: case Qremote: case Qlocal: case Qstats: case Qbootp: case Qipselftab: if(omode != OREAD) error(Eperm); break; case Qclone: p = f->p[PROTO(c->qid)]; qlock(p); if(waserror()){ qunlock(p); nexterror(); } cv = Fsprotoclone(p, commonuser()); qunlock(p); poperror(); if(cv == nil) { error(Enodev); break; } c->qid = (Qid){QID(p->x, cv->x, Qctl), 0}; break; case Qdata: case Qctl: case Qerr: p = f->p[PROTO(c->qid)]; qlock(p); cv = p->conv[CONV(c->qid)]; qlock(cv); if(waserror()) { qunlock(cv); qunlock(p); nexterror(); } if((perm & (cv->perm>>6)) != perm) { if(strcmp(commonuser(), cv->owner) != 0) error(Eperm); if((perm & cv->perm) != perm) error(Eperm); } cv->inuse++; if(cv->inuse == 1){ memmove(cv->owner, commonuser(), NAMELEN); cv->perm = 0660; } qunlock(cv); qunlock(p); poperror(); break; case Qlisten: cv = f->p[PROTO(c->qid)]->conv[CONV(c->qid)]; if(cv->state != Announced) error("not announced"); nc = nil; while(nc == nil) { /* give up if we got a hangup */ if(qisclosed(cv->rq)) error("listen hungup"); qlock(&cv->listenq); if(waserror()) { qunlock(&cv->listenq); nexterror(); } /* wait for a connect */ sleep(&cv->listenr, incoming, cv); qlock(cv); nc = cv->incall; if(nc != nil){ cv->incall = nc->next; c->qid = (Qid){QID(PROTO(c->qid), nc->x, Qctl), 0}; memmove(cv->owner, commonuser(), NAMELEN); } qunlock(cv); qunlock(&cv->listenq); poperror(); } break; } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c;} static voidipcreate(Chan*, char*, int, ulong){ error(Eperm);} static voidipremove(Chan*){ error(Eperm);} static voidipwstat(Chan*, char*){ error(Eperm);} voidcloseconv(Conv *cv){ Conv *nc; Ipmulti *mp; qlock(cv); if(--cv->inuse > 0) { qunlock(cv); return; } /* close all incoming calls since no listen will ever happen */ for(nc = cv->incall; nc; nc = cv->incall){ cv->incall = nc->next; closeconv(nc); } cv->incall = nil; strcpy(cv->owner, network); cv->perm = 0660; Lines 1–500 of 1302. Load more
#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "../ip/ip.h" enum { Qtopdir= 1, /* top level directory */ Qtopbase, Qarp= Qtopbase, Qbootp, Qndb, Qiproute, Qipselftab, Qlog, Qprotodir, /* directory for a protocol */ Qprotobase, Qclone= Qprotobase, Qstats, Qconvdir, /* directory for a conversation */ Qconvbase, Qctl= Qconvbase, Qdata, Qerr, 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, Nfs= 16, }; #define TYPE(x) ( (x).path & Masktype ) #define CONV(x) ( ((x).path >> Shiftconv) & Maskconv ) #define PROTO(x) ( ((x).path >> Shiftproto) & Maskproto ) #define QID(p, c, y) ( ((p)<<(Shiftproto)) | ((c)<<Shiftconv) | (y) ) static char network[] = "network"; QLock fslock; Fs *ipfs[Nfs]; /* attached fs's */ Queue *qlog; extern void nullmediumlink(void); extern void pktmediumlink(void); long ndbwrite(Fs *f, char *a, ulong off, int n); 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)]; switch(i) { default: return -1; case Qctl: q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qctl), 0}; devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp); return 1; case Qdata: q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qdata), 0}; devdir(c, q, "data", qlen(cv->rq), cv->owner, cv->perm, dp); return 1; case Qerr: q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qerr), 0}; devdir(c, q, "err", qlen(cv->eq), cv->owner, cv->perm, dp); return 1; case Qlisten: p = "listen"; q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qlisten), 0}; break; case Qlocal: p = "local"; q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qlocal), 0}; break; case Qremote: p = "remote"; q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qremote), 0}; break; case Qstatus: p = "status"; q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qstatus), 0}; break; } devdir(c, q, p, 0, cv->owner, 0666, dp); return 1; } static int ip2gen(Chan *c, int i, Dir *dp) { Qid q; switch(i) { case Qclone: q = (Qid){QID(PROTO(c->qid), 0, Qclone), 0}; devdir(c, q, "clone", 0, network, 0666, dp); return 1; case Qstats: q = (Qid){QID(PROTO(c->qid), 0, Qstats), 0}; 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; f = ipfs[c->dev]; prot = 0666; switch(i) { default: return -1; case Qarp: p = "arp"; q = (Qid){QID(0, 0, Qarp), 0}; break; case Qbootp: p = "bootp"; q = (Qid){QID(0, 0, Qbootp), 0}; break; case Qndb: p = "ndb"; q = (Qid){QID(0, 0, Qndb), 0}; len = strlen(f->ndb); break; case Qiproute: p = "iproute"; q = (Qid){QID(0, 0, Qiproute), 0}; break; case Qipselftab: p = "ipselftab"; prot = 0444; q = (Qid){QID(0, 0, Qipselftab), 0}; break; case Qlog: p = "log"; q = (Qid){QID(0, 0, Qlog), 0}; break; } devdir(c, q, p, len, network, prot, dp); return 1; } static int ipgen(Chan *c, Dirtab*, int, int s, Dir *dp) { Qid q; Conv *cv; char name[16]; Fs *f; f = ipfs[c->dev]; switch(TYPE(c->qid)) { case Qtopdir: if(s == DEVDOTDOT){ q = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0}; sprint(name, "#I%lud", c->dev); devdir(c, q, name, 0, network, 0555, dp); return 1; } if(s < f->np) { if(f->p[s]->connect == nil) return 0; /* protocol with no user interface */ q = (Qid){QID(s, 0, Qprotodir)|CHDIR, 0}; 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 Qbootp: case Qndb: case Qlog: case Qiproute: case Qipselftab: return ip1gen(c, TYPE(c->qid), dp); case Qprotodir: if(s == DEVDOTDOT){ q = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0}; sprint(name, "#I%lud", c->dev); devdir(c, q, name, 0, network, 0555, dp); return 1; } if(s < f->p[PROTO(c->qid)]->ac) { cv = f->p[PROTO(c->qid)]->conv[s]; sprint(name, "%d", s); q = (Qid){QID(PROTO(c->qid), s, Qconvdir)|CHDIR, 0}; devdir(c, q, name, 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); q = (Qid){QID(s, 0, Qprotodir)|CHDIR, 0}; devdir(c, q, f->p[s]->name, 0, network, 0555, dp); return 1; } return ip3gen(c, s+Qconvbase, dp); case Qctl: case Qdata: case Qerr: case Qlisten: case Qlocal: case Qremote: case Qstatus: return ip3gen(c, TYPE(c->qid), dp); } return -1; } static void ipreset(void) { nullmediumlink(); pktmediumlink(); } static void ipinit(void) { fmtinstall('i', eipconv); fmtinstall('I', eipconv); fmtinstall('E', eipconv); fmtinstall('V', eipconv); fmtinstall('M', eipconv); } static Fs* ipgetfs(int dev) { extern void (*ipprotoinit[])(Fs*); Fs *f; int i; if(dev >= Nfs) return nil; qlock(&fslock); if(ipfs[dev] == nil){ f = smalloc(sizeof(Fs)); ip_init(f); arpinit(f); netloginit(f); for(i = 0; ipprotoinit[i]; i++) ipprotoinit[i](f); f->dev = dev; ipfs[dev] = f; } qunlock(&fslock); return ipfs[dev]; } static Chan* ipattach(char* spec) { Chan *c; int dev; dev = atoi(spec); if(dev >= 16) error("bad specification"); ipgetfs(dev); c = devattach('I', spec); c->qid = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0}; c->dev = dev; return c; } static Chan* ipclone(Chan* c, Chan* nc) { return devclone(c, nc); } static int ipwalk(Chan* c, char* name) { return devwalk(c, name, nil, 0, ipgen); } static void ipstat(Chan* c, char* db) { devstat(c, db, nil, 0, ipgen); } static int incoming(void* arg) { Conv *conv; conv = arg; return conv->incall != nil; } static int m2p[] = { [OREAD] 4, [OWRITE] 2, [ORDWR] 6 }; static Chan* ipopen(Chan* c, int omode) { Conv *cv, *nc; Proto *p; int perm; Fs *f; omode &= 3; perm = m2p[omode]; f = ipfs[c->dev]; switch(TYPE(c->qid)) { default: break; case Qndb: if(omode & (OWRITE|OTRUNC) && !iseve()) error(Eperm); if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC)) f->ndb[0] = 0; break; case Qlog: netlogopen(f); break; case Qiproute: memmove(c->tag, "none", sizeof(c->tag)); break; case Qtopdir: case Qprotodir: case Qconvdir: case Qstatus: case Qremote: case Qlocal: case Qstats: case Qbootp: case Qipselftab: if(omode != OREAD) error(Eperm); break; case Qclone: p = f->p[PROTO(c->qid)]; qlock(p); if(waserror()){ qunlock(p); nexterror(); } cv = Fsprotoclone(p, commonuser()); qunlock(p); poperror(); if(cv == nil) { error(Enodev); break; } c->qid = (Qid){QID(p->x, cv->x, Qctl), 0}; break; case Qdata: case Qctl: case Qerr: p = f->p[PROTO(c->qid)]; qlock(p); cv = p->conv[CONV(c->qid)]; qlock(cv); if(waserror()) { qunlock(cv); qunlock(p); nexterror(); } if((perm & (cv->perm>>6)) != perm) { if(strcmp(commonuser(), cv->owner) != 0) error(Eperm); if((perm & cv->perm) != perm) error(Eperm); } cv->inuse++; if(cv->inuse == 1){ memmove(cv->owner, commonuser(), NAMELEN); cv->perm = 0660; } qunlock(cv); qunlock(p); poperror(); break; case Qlisten: cv = f->p[PROTO(c->qid)]->conv[CONV(c->qid)]; if(cv->state != Announced) error("not announced"); nc = nil; while(nc == nil) { /* give up if we got a hangup */ if(qisclosed(cv->rq)) error("listen hungup"); qlock(&cv->listenq); if(waserror()) { qunlock(&cv->listenq); nexterror(); } /* wait for a connect */ sleep(&cv->listenr, incoming, cv); qlock(cv); nc = cv->incall; if(nc != nil){ cv->incall = nc->next; c->qid = (Qid){QID(PROTO(c->qid), nc->x, Qctl), 0}; memmove(cv->owner, commonuser(), NAMELEN); } qunlock(cv); qunlock(&cv->listenq); poperror(); } break; } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } static void ipcreate(Chan*, char*, int, ulong) { error(Eperm); } static void ipremove(Chan*) { error(Eperm); } static void ipwstat(Chan*, char*) { error(Eperm); } void closeconv(Conv *cv) { Conv *nc; Ipmulti *mp; qlock(cv); if(--cv->inuse > 0) { qunlock(cv); return; } /* close all incoming calls since no listen will ever happen */ for(nc = cv->incall; nc; nc = cv->incall){ cv->incall = nc->next; closeconv(nc); } cv->incall = nil; strcpy(cv->owner, network); cv->perm = 0660;