📄 devip.c
字号:
#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, Qsnoop, Logtype= 5, Masktype= (1<<Logtype)-1, Logconv= 12, Maskconv= (1<<Logconv)-1, Shiftconv= Logtype, Logproto= 8, Maskproto= (1<<Logproto)-1, Shiftproto= Logtype + Logconv, Nfs= 128,};#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) )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)]; 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", qlen(cv->rq), cv->owner, cv->perm, dp); return 1; case Qerr: devdir(c, q, "err", qlen(cv->eq), 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 Qsnoop: if(strcmp(cv->p->name, "ipifc") != 0) return -1; devdir(c, q, "snoop", qlen(cv->sq), cv->owner, 0400, dp); return 1; 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 = 0666; mkqid(&q, QID(0, 0, i), 0, QTFILE); switch(i) { default: return -1; case Qarp: p = "arp"; prot = 0664; break; case Qbootp: p = "bootp"; break; case Qndb: p = "ndb"; len = strlen(f->ndb); q.vers = f->ndbvers; break; case Qiproute: p = "iproute"; prot = 0664; break; case Qipselftab: p = "ipselftab"; prot = 0444; 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*, Dirtab*, int, int s, Dir *dp){ Qid q; Conv *cv; Fs *f; 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 Qbootp: case Qndb: case Qlog: case Qiproute: 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 Qerr: case Qlisten: case Qlocal: case Qremote: case Qstatus: case Qsnoop: return ip3gen(c, TYPE(c->qid), dp); } return -1;}static voidipreset(void){ nullmediumlink(); pktmediumlink(); fmtinstall('i', eipfmt); fmtinstall('I', eipfmt); fmtinstall('E', eipfmt); fmtinstall('V', eipfmt); fmtinstall('M', eipfmt);}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];}IPaux*newipaux(char *owner, char *tag){ IPaux *a; int n; a = smalloc(sizeof(*a)); kstrdup(&a->owner, owner); memset(a->tag, ' ', sizeof(a->tag)); n = strlen(tag); if(n > sizeof(a->tag)) n = sizeof(a->tag); memmove(a->tag, tag, n); return a;}#define ATTACHER(c) (((IPaux*)((c)->aux))->owner)static Chan*ipattach(char* spec){ Chan *c; int dev; dev = atoi(spec); if(dev >= Nfs) error("bad specification"); ipgetfs(dev); c = devattach('I', spec); mkqid(&c->qid, QID(0, 0, Qtopdir), 0, QTDIR); c->dev = dev; c->aux = newipaux(commonuser(), "none"); return c;}static Walkqid*ipwalk(Chan* c, Chan *nc, char **name, int nname){ IPaux *a = c->aux; Walkqid* w; w = devwalk(c, nc, name, nname, nil, 0, ipgen); if(w != nil && w->clone != nil) w->clone->aux = newipaux(a->owner, a->tag); return w;}static intipstat(Chan* c, uchar* db, int n){ return devstat(c, db, n, 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; perm = m2p[omode&3]; 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: case Qarp: if(omode != OREAD && !iseve()) error(Eperm); 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 Qsnoop: if(omode != OREAD) error(Eperm); p = f->p[PROTO(c->qid)]; cv = p->conv[CONV(c->qid)]; if(strcmp(ATTACHER(c), cv->owner) != 0 && !iseve()) error(Eperm); incref(&cv->snoopers); break; case Qclone: p = f->p[PROTO(c->qid)]; qlock(p); if(waserror()){ qunlock(p); nexterror(); } cv = Fsprotoclone(p, ATTACHER(c)); qunlock(p); poperror(); if(cv == nil) { error(Enodev); break; } mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE); 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(ATTACHER(c), cv->owner) != 0) error(Eperm); if((perm & cv->perm) != perm) error(Eperm); } cv->inuse++; if(cv->inuse == 1){ kstrdup(&cv->owner, ATTACHER(c)); cv->perm = 0660; } qunlock(cv); qunlock(p); poperror(); break; case Qlisten: cv = f->p[PROTO(c->qid)]->conv[CONV(c->qid)]; if((perm & (cv->perm>>6)) != perm) { if(strcmp(ATTACHER(c), cv->owner) != 0) error(Eperm); if((perm & cv->perm) != perm) error(Eperm); } if(cv->state != Announced) error("not announced"); if(waserror()){ closeconv(cv); nexterror(); } qlock(cv); cv->inuse++; qunlock(cv); 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; mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE); kstrdup(&cv->owner, ATTACHER(c)); } qunlock(cv); qunlock(&cv->listenq); poperror(); } closeconv(cv); 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 intipwstat(Chan *c, uchar *dp, int n){ Dir d; Conv *cv; Fs *f; Proto *p; f = ipfs[c->dev]; switch(TYPE(c->qid)) { default: error(Eperm); break; case Qctl: case Qdata: break; } n = convM2D(dp, n, &d, nil); if(n > 0){ p = f->p[PROTO(c->qid)]; cv = p->conv[CONV(c->qid)]; if(!iseve() && strcmp(ATTACHER(c), cv->owner) != 0) error(Eperm); if(d.uid[0]) kstrdup(&cv->owner, d.uid); cv->perm = d.mode & 0777; } return n;}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; kstrdup(&cv->owner, network); cv->perm = 0660; while((mp = cv->multi) != nil) ipifcremmulti(cv, mp->ma, mp->ia); cv->r = nil; cv->rgen = 0; cv->p->close(cv); cv->state = Idle; qunlock(cv);}static voidipclose(Chan* c){ Fs *f; f = ipfs[c->dev]; switch(TYPE(c->qid)) { default: break; case Qlog: if(c->flag & COPEN) netlogclose(f); break; case Qdata: case Qctl: case Qerr: if(c->flag & COPEN) closeconv(f->p[PROTO(c->qid)]->conv[CONV(c->qid)]); break; case Qsnoop: if(c->flag & COPEN) decref(&f->p[PROTO(c->qid)]->conv[CONV(c->qid)]->snoopers); break; } free(((IPaux*)c->aux)->owner); free(c->aux);}enum{ Statelen= 32*1024,};static longipread(Chan *ch, void *a, long n, vlong off){ Conv *c; Proto *x; char *buf, *p; long rv; Fs *f; ulong offset = off; f = ipfs[ch->dev]; p = a; switch(TYPE(ch->qid)) { default: error(Eperm); case Qtopdir: case Qprotodir: case Qconvdir: return devdirread(ch, a, n, 0, 0, ipgen); case Qarp: return arpread(f->arp, a, offset, n); case Qbootp: return bootpread(a, offset, n); case Qndb: return readstr(offset, a, n, f->ndb); case Qiproute: return routeread(f, a, offset, n); case Qipselftab: return ipselftabread(f, a, offset, n); case Qlog: return netlogread(f, a, offset, n); case Qctl: buf = smalloc(16); sprint(buf, "%lud", CONV(ch->qid)); rv = readstr(offset, p, n, buf); free(buf); return rv; case Qremote: buf = smalloc(Statelen); 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; case Qlocal: buf = smalloc(Statelen); x = f->p[PROTO(ch->qid)]; c = x->conv[CONV(ch->qid)]; if(x->local == nil) { sprint(buf, "%I!%d\n", c->laddr, c->lport); } else { (*x->local)(c, buf, Statelen-2); } rv = readstr(offset, p, n, buf); free(buf); return rv; case Qstatus: buf = smalloc(Statelen); x = f->p[PROTO(ch->qid)]; c = x->conv[CONV(ch->qid)]; (*x->state)(c, buf, Statelen-2); rv = readstr(offset, p, n, buf); free(buf); return rv; case Qdata: c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)]; return qread(c->rq, a, n); case Qerr: c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)]; return qread(c->eq, a, n); case Qsnoop: c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)]; return qread(c->sq, a, n); case Qstats: x = f->p[PROTO(ch->qid)]; if(x->stats == nil) error("stats not implemented"); buf = smalloc(Statelen); (*x->stats)(x, buf, Statelen); rv = readstr(offset, p, n, buf); free(buf); return rv; }}static Block*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -