| plan 9 kernel history: overview | file list | diff list |
2002/0325/ip/devip.c (diff list | history)
| ip/devip.c on 1997/0327 | ||
| 1997/0327 | #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, | |
| 1998/0313 | Qbootp, | |
| 2000/0116 | Qndb, | |
| 1997/0327 | Qiproute, | |
| 1998/0310 | Qipselftab, | |
| 1997/0327 | Qlog, Qprotodir, /* directory for a protocol */ Qprotobase, Qclone= Qprotobase, | |
| 1998/0306 | Qstats, | |
| 1997/0327 | Qconvdir, /* directory for a conversation */ Qconvbase, Qctl= Qconvbase, Qdata, Qerr, Qlisten, Qlocal, Qremote, Qstatus, | |
| 1998/0313 | 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, | |
| 1997/0327 | }; | |
| 2001/0527 | #define TYPE(x) ( ((ulong)(x).path) & Masktype ) #define CONV(x) ( (((ulong)(x).path) >> Shiftconv) & Maskconv ) #define PROTO(x) ( (((ulong)(x).path) >> Shiftproto) & Maskproto ) | |
| 1998/0313 | #define QID(p, c, y) ( ((p)<<(Shiftproto)) | ((c)<<Shiftconv) | (y) ) | |
| 1997/0327 | static char network[] = "network"; | |
| 1998/0313 | QLock fslock; Fs *ipfs[Nfs]; /* attached fs's */ Queue *qlog; | |
| 2001/1120 | enum { CMaddmulti, CMannounce, CMbind, CMconnect, CMremmulti, CMtos, CMttl, CMwildcard, }; Cmdtab ipctlmsg[] = { CMaddmulti, "addmulti", 0, CMannounce, "announce", 0, CMbind, "bind", 0, CMconnect, "connect", 0, CMremmulti, "remmulti", 0, CMtos, "tos", 0, CMttl, "ttl", 0, CMwildcard, "*", 0, }; | |
| 2000/0116 | extern void nullmediumlink(void); extern void pktmediumlink(void); long ndbwrite(Fs *f, char *a, ulong off, int n); | |
| 1998/0423 | ||
| 1997/0327 | static int ip3gen(Chan *c, int i, Dir *dp) { Qid q; Conv *cv; char *p; | |
| 1998/0313 | cv = ipfs[c->dev]->p[PROTO(c->qid)]->conv[CONV(c->qid)]; | |
| 2001/0527 | if(cv->owner == nil) kstrdup(&cv->owner, eve); mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE); | |
| 1997/0327 | 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: | |
| 2001/0403 | devdir(c, q, "listen", qlen(cv->eq), cv->owner, cv->perm, dp); return 1; | |
| 1997/0327 | case Qlocal: p = "local"; break; case Qremote: p = "remote"; break; case Qstatus: p = "status"; break; } | |
| 2001/0403 | devdir(c, q, p, 0, cv->owner, 0444, dp); | |
| 1997/0327 | return 1; } static int ip2gen(Chan *c, int i, Dir *dp) { Qid q; switch(i) { case Qclone: | |
| 2001/0527 | mkqid(&q, QID(PROTO(c->qid), 0, Qclone), 0, QTFILE); | |
| 1998/0306 | devdir(c, q, "clone", 0, network, 0666, dp); | |
| 1997/0327 | return 1; | |
| 1998/0306 | case Qstats: | |
| 2001/0527 | mkqid(&q, QID(PROTO(c->qid), 0, Qstats), 0, QTFILE); | |
| 1998/0306 | devdir(c, q, "stats", 0, network, 0444, dp); return 1; | |
| 1997/0327 | } return -1; } static int ip1gen(Chan *c, int i, Dir *dp) { Qid q; char *p; | |
| 1998/0310 | int prot; | |
| 2000/0126 | int len = 0; Fs *f; | |
| 1997/0327 | ||
| 2000/0126 | f = ipfs[c->dev]; | |
| 1998/0310 | prot = 0666; | |
| 2001/0527 | mkqid(&q, QID(0, 0, i), 0, QTFILE); | |
| 1997/0327 | switch(i) { default: return -1; case Qarp: p = "arp"; break; | |
| 1998/0313 | case Qbootp: p = "bootp"; break; | |
| 2000/0116 | case Qndb: p = "ndb"; | |
| 2000/0126 | len = strlen(f->ndb); | |
| 2002/0324 | q.vers = f->ndbvers; | |
| 2000/0116 | break; | |
| 1997/0327 | case Qiproute: p = "iproute"; break; | |
| 1998/0310 | case Qipselftab: p = "ipselftab"; prot = 0444; break; | |
| 1997/0327 | case Qlog: p = "log"; break; } | |
| 2000/0126 | devdir(c, q, p, len, network, prot, dp); | |
| 2002/0325 | if(i == Qndb) dp->mtime = f->ndbmtime; | |
| 1997/0327 | return 1; } static int | |
| 2001/0527 | ipgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp) | |
| 1997/0327 | { Qid q; Conv *cv; | |
| 1998/0313 | Fs *f; | |
| 1997/0327 | ||
| 1998/0313 | f = ipfs[c->dev]; | |
| 1997/0327 | switch(TYPE(c->qid)) { case Qtopdir: | |
| 1999/1230 | if(s == DEVDOTDOT){ | |
| 2001/0527 | mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR); sprint(up->genbuf, "#I%lud", c->dev); devdir(c, q, up->genbuf, 0, network, 0555, dp); | |
| 1999/1230 | return 1; } | |
| 1998/0313 | if(s < f->np) { if(f->p[s]->connect == nil) | |
| 1997/0423 | return 0; /* protocol with no user interface */ | |
| 2001/0527 | mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR); | |
| 1999/1230 | devdir(c, q, f->p[s]->name, 0, network, 0555, dp); | |
| 1997/0327 | return 1; } | |
| 1998/0313 | s -= f->np; | |
| 1997/0327 | return ip1gen(c, s+Qtopbase, dp); case Qarp: | |
| 1998/0313 | case Qbootp: | |
| 2000/0116 | case Qndb: | |
| 1997/0327 | case Qlog: case Qiproute: | |
| 1998/0310 | case Qipselftab: | |
| 1997/0327 | return ip1gen(c, TYPE(c->qid), dp); case Qprotodir: | |
| 1999/1230 | if(s == DEVDOTDOT){ | |
| 2001/0527 | mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR); sprint(up->genbuf, "#I%lud", c->dev); devdir(c, q, up->genbuf, 0, network, 0555, dp); | |
| 1999/1230 | return 1; } | |
| 1998/0313 | if(s < f->p[PROTO(c->qid)]->ac) { cv = f->p[PROTO(c->qid)]->conv[s]; | |
| 2001/0527 | 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); | |
| 1997/0327 | return 1; } | |
| 1998/0313 | s -= f->p[PROTO(c->qid)]->ac; | |
| 1997/0327 | return ip2gen(c, s+Qprotobase, dp); case Qclone: | |
| 1998/0306 | case Qstats: | |
| 1997/0327 | return ip2gen(c, TYPE(c->qid), dp); case Qconvdir: | |
| 1999/1230 | if(s == DEVDOTDOT){ s = PROTO(c->qid); | |
| 2001/0527 | mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR); | |
| 1999/1230 | devdir(c, q, f->p[s]->name, 0, network, 0555, dp); return 1; } | |
| 1997/0327 | 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) { | |
| 1998/0423 | nullmediumlink(); pktmediumlink(); | |
| 1997/0327 | ||
| 2002/0217 | fmtinstall('i', eipfmt); fmtinstall('I', eipfmt); fmtinstall('E', eipfmt); fmtinstall('V', eipfmt); fmtinstall('M', eipfmt); | |
| 1997/0327 | } | |
| 1998/0313 | 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); | |
| 1998/0924 | f->dev = dev; | |
| 1998/0313 | ipfs[dev] = f; } qunlock(&fslock); return ipfs[dev]; } | |
| 2001/0405 | IPaux* newipaux(char *owner, char *tag) { IPaux *a; int n; a = smalloc(sizeof(*a)); | |
| 2001/0527 | kstrdup(&a->owner, owner); | |
| 2001/0405 | 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) | |
| 1997/0327 | static Chan* ipattach(char* spec) { Chan *c; | |
| 1998/0313 | int dev; | |
| 1997/0327 | ||
| 1998/0313 | dev = atoi(spec); if(dev >= 16) error("bad specification"); ipgetfs(dev); | |
| 1997/0327 | c = devattach('I', spec); | |
| 2001/0527 | mkqid(&c->qid, QID(0, 0, Qtopdir), 0, QTDIR); | |
| 1998/0313 | c->dev = dev; | |
| 1997/0327 | ||
| 2001/0405 | c->aux = newipaux(commonuser(), "none"); | |
| 1997/0327 | return c; } | |
| 2001/0527 | static Walkqid* ipwalk(Chan* c, Chan *nc, char **name, int nname) | |
| 1997/0327 | { | |
| 2001/0405 | IPaux *a = c->aux; | |
| 2001/0527 | Walkqid* w; | |
| 2001/0405 | ||
| 2001/0527 | 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; | |
| 1997/0327 | } static int | |
| 2001/0527 | ipstat(Chan* c, uchar* db, int n) | |
| 1997/0327 | { | |
| 2001/0527 | return devstat(c, db, n, nil, 0, ipgen); | |
| 1997/0327 | } 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; | |
| 1998/0313 | Fs *f; | |
| 1997/0327 | ||
| 2001/0527 | omode &= 3; perm = m2p[omode]; | |
| 1997/0327 | ||
| 1998/0313 | f = ipfs[c->dev]; | |
| 1997/0327 | switch(TYPE(c->qid)) { default: break; | |
| 2000/0126 | case Qndb: | |
| 2002/0324 | if((omode & (OWRITE|OTRUNC)) && !iseve()) | |
| 2000/0126 | error(Eperm); | |
| 2002/0324 | if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC)){ | |
| 2000/0126 | f->ndb[0] = 0; | |
| 2002/0324 | f->ndbvers++; } | |
| 2000/0126 | break; | |
| 1997/0327 | case Qlog: | |
| 1998/0313 | netlogopen(f); | |
| 1997/0327 | break; | |
| 1998/0306 | case Qiproute: break; | |
| 1997/0327 | case Qtopdir: case Qprotodir: case Qconvdir: case Qstatus: case Qremote: case Qlocal: | |
| 1998/0306 | case Qstats: | |
| 1998/0313 | case Qbootp: | |
| 1998/0310 | case Qipselftab: | |
| 1997/0327 | if(omode != OREAD) error(Eperm); break; case Qclone: | |
| 1998/0313 | p = f->p[PROTO(c->qid)]; | |
| 1999/0302 | qlock(p); if(waserror()){ qunlock(p); nexterror(); } | |
| 2001/0405 | cv = Fsprotoclone(p, ATTACHER(c)); | |
| 1999/0302 | qunlock(p); poperror(); | |
| 1997/0327 | if(cv == nil) { error(Enodev); break; } | |
| 2001/0527 | mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE); | |
| 1997/0327 | break; case Qdata: case Qctl: case Qerr: | |
| 1998/0313 | p = f->p[PROTO(c->qid)]; | |
| 1998/0306 | qlock(p); | |
| 1997/0327 | cv = p->conv[CONV(c->qid)]; | |
| 1999/0302 | qlock(cv); | |
| 1997/0327 | if(waserror()) { | |
| 1999/0302 | qunlock(cv); | |
| 1998/0306 | qunlock(p); | |
| 1997/0327 | nexterror(); } if((perm & (cv->perm>>6)) != perm) { | |
| 2001/0405 | if(strcmp(ATTACHER(c), cv->owner) != 0) | |
| 1997/0327 | error(Eperm); if((perm & cv->perm) != perm) error(Eperm); } cv->inuse++; if(cv->inuse == 1){ | |
| 2001/0527 | kstrdup(&cv->owner, ATTACHER(c)); | |
| 1997/0327 | cv->perm = 0660; } | |
| 1999/0302 | qunlock(cv); | |
| 1998/0306 | qunlock(p); | |
| 1997/0327 | poperror(); break; case Qlisten: | |
| 1998/0313 | cv = f->p[PROTO(c->qid)]->conv[CONV(c->qid)]; | |
| 2001/0403 | if((perm & (cv->perm>>6)) != perm) { | |
| 2001/0405 | if(strcmp(ATTACHER(c), cv->owner) != 0) | |
| 2001/0403 | error(Eperm); if((perm & cv->perm) != perm) error(Eperm); } | |
| 1997/0327 | if(cv->state != Announced) error("not announced"); nc = nil; while(nc == nil) { | |
| 1998/1127 | /* give up if we got a hangup */ if(qisclosed(cv->rq)) error("listen hungup"); | |
| 1997/0327 | qlock(&cv->listenq); if(waserror()) { qunlock(&cv->listenq); nexterror(); } | |
| 1998/1127 | /* wait for a connect */ | |
| 1997/0327 | sleep(&cv->listenr, incoming, cv); | |
| 1999/0302 | qlock(cv); | |
| 1997/0327 | nc = cv->incall; if(nc != nil){ cv->incall = nc->next; | |
| 2001/0527 | mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE); kstrdup(&cv->owner, ATTACHER(c)); | |
| 1997/0327 | } | |
| 1999/0302 | qunlock(cv); | |
| 1997/0327 | qunlock(&cv->listenq); poperror(); } break; } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; | |
| 2001/1207 | c->iounit = qiomaxatomic; | |
| 1997/0327 | return c; } | |
| 2001/0527 | static int ipwstat(Chan *c, uchar *dp, int n) | |
| 1997/0327 | { | |
| 2001/1106 | Dir *d; | |
| 2001/0403 | Conv *cv; Fs *f; Proto *p; f = ipfs[c->dev]; switch(TYPE(c->qid)) { default: error(Eperm); break; case Qctl: case Qdata: break; } | |
| 2001/1106 | d = smalloc(n + sizeof(Dir)); if(waserror()){ free(d); nexterror(); | |
| 2001/0403 | } | |
| 2001/1106 | n = convM2D(dp, n, d, nil); if(n == 0) error(Eshortstat); p = f->p[PROTO(c->qid)]; cv = p->conv[CONV(c->qid)]; if(!iseve() && strcmp(ATTACHER(c), cv->owner) != 0) error(Eperm); if(!emptystr(d->uid)) kstrdup(&cv->owner, d->uid); if(d->mode != ~0UL) cv->perm = d->mode & 0777; poperror(); free(d); | |
| 2001/0527 | return n; | |
| 1997/0327 | } | |
| 1999/0910 | void | |
| 1997/0327 | closeconv(Conv *cv) { Conv *nc; | |
| 1998/0306 | Ipmulti *mp; | |
| 1997/0327 | ||
| 1999/0302 | qlock(cv); | |
| 1998/0306 | ||
| 1997/0327 | if(--cv->inuse > 0) { | |
| 1999/0302 | qunlock(cv); | |
| 1997/0327 | 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); } | |
| 1998/0321 | cv->incall = nil; | |
| 1997/0327 | ||
| 2001/0527 | kstrdup(&cv->owner, network); | |
| 1997/0327 | cv->perm = 0660; | |
| 1998/0306 | while((mp = cv->multi) != nil) ipifcremmulti(cv, mp->ma, mp->ia); | |
| 1997/0327 | cv->p->close(cv); | |
| 2000/1220 | cv->state = Idle; qunlock(cv); | |
| 1997/0327 | } static void ipclose(Chan* c) { | |
| 1998/0313 | Fs *f; f = ipfs[c->dev]; | |
| 1997/0327 | switch(TYPE(c->qid)) { default: break; | |
| 1998/0306 | case Qlog: | |
| 1997/0531 | if(c->flag & COPEN) | |
| 1998/0313 | netlogclose(f); | |
| 1997/0327 | break; case Qdata: case Qctl: case Qerr: if(c->flag & COPEN) | |
| 1998/0313 | closeconv(f->p[PROTO(c->qid)]->conv[CONV(c->qid)]); | |
| 1997/0327 | } | |
| 2001/0527 | free(((IPaux*)c->aux)->owner); | |
| 2001/0405 | free(c->aux); | |
| 1997/0327 | } | |
| 1998/0306 | enum { | |
| 1998/0717 | Statelen= 32*1024, | |
| 1998/0306 | }; | |
| 1997/0327 | static long | |
| 1998/0319 | ipread(Chan *ch, void *a, long n, vlong off) | |
| 1997/0327 | { Conv *c; Proto *x; | |
| 1998/0306 | char *buf, *p; | |
| 1998/0710 | long rv; | |
| 1998/0313 | Fs *f; | |
| 1998/0319 | ulong offset = off; | |
| 1997/0327 | ||
| 1998/0313 | f = ipfs[ch->dev]; | |
| 1997/0327 | 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: | |
| 1998/0313 | return arpread(f->arp, a, offset, n); case Qbootp: return bootpread(a, offset, n); | |
| 2000/0116 | case Qndb: return readstr(offset, a, n, f->ndb); | |
| 1997/0327 | case Qiproute: | |
| 1998/0313 | return routeread(f, a, offset, n); | |
| 1998/0310 | case Qipselftab: | |
| 1998/0313 | return ipselftabread(f, a, offset, n); | |
| 1997/0327 | case Qlog: | |
| 1998/0313 | return netlogread(f, a, offset, n); | |
| 1997/0327 | case Qctl: | |
| 1998/0306 | buf = smalloc(16); | |
| 1998/0825 | sprint(buf, "%lud", CONV(ch->qid)); | |
| 1998/0306 | rv = readstr(offset, p, n, buf); free(buf); return rv; | |
| 1997/0327 | case Qremote: | |
| 1998/0306 | buf = smalloc(Statelen); | |
| 1999/0316 | 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); } | |
| 1998/0306 | rv = readstr(offset, p, n, buf); free(buf); return rv; | |
| 1997/0327 | case Qlocal: | |
| 1998/0306 | buf = smalloc(Statelen); | |
| 1998/0313 | x = f->p[PROTO(ch->qid)]; | |
| 1998/0306 | 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; | |
| 1997/0327 | case Qstatus: | |
| 1998/0306 | buf = smalloc(Statelen); | |
| 1998/0313 | x = f->p[PROTO(ch->qid)]; | |
| 1997/0327 | c = x->conv[CONV(ch->qid)]; | |
| 1998/0709 | (*x->state)(c, buf, Statelen-2); | |
| 1998/0306 | rv = readstr(offset, p, n, buf); free(buf); return rv; | |
| 1997/0327 | case Qdata: | |
| 1998/0313 | c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)]; | |
| 1997/1105 | return qread(c->rq, a, n); | |
| 1997/0327 | case Qerr: | |
| 1998/0313 | c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)]; | |
| 1997/0327 | return qread(c->eq, a, n); | |
| 1998/0306 | case Qstats: | |
| 1998/0313 | x = f->p[PROTO(ch->qid)]; | |
| 1998/0306 | if(x->stats == nil) error("stats not implemented"); buf = smalloc(Statelen); | |
| 1998/0313 | (*x->stats)(x, buf, Statelen); | |
| 1998/0306 | rv = readstr(offset, p, n, buf); free(buf); return rv; | |
| 1997/0327 | } } static Block* | |
| 1999/0901 | ipbread(Chan* ch, long n, ulong offset) | |
| 1997/0327 | { | |
| 1999/0901 | Conv *c; Proto *x; Fs *f; switch(TYPE(ch->qid)){ case Qdata: f = ipfs[ch->dev]; x = f->p[PROTO(ch->qid)]; c = x->conv[CONV(ch->qid)]; return qbread(c->rq, n); default: return devbread(ch, n, offset); } | |
| 1997/0327 | } | |
| 1998/0306 | /* * set local address to be that of the ifc closest to remote address */ | |
| 1997/0327 | static void setladdr(Conv* c) { | |
| 1998/0313 | findlocalip(c->p->f, c->laddr, c->raddr); | |
| 1997/0327 | } | |
| 1998/0306 | /* | |
| 2001/0118 | * set a local port making sure the quad of raddr,rport,laddr,lport is unique */ | |
| 2001/0126 | static char* | |
| 2001/0118 | setluniqueport(Conv* c, int lport) { Proto *p; Conv *xp; int x; p = c->p; qlock(p); for(x = 0; x < p->nc; x++){ xp = p->conv[x]; if(xp == nil) break; | |
| 2001/0126 | if(xp == c) continue; | |
| 2001/0118 | if((xp->state == Connected || xp->state == Announced) && xp->lport == lport && xp->rport == c->rport && ipcmp(xp->raddr, c->raddr) == 0 && ipcmp(xp->laddr, c->laddr) == 0){ qunlock(p); | |
| 2001/0126 | return "address in use"; | |
| 2001/0118 | } } c->lport = lport; qunlock(p); | |
| 2001/0126 | return nil; | |
| 2001/0118 | } /* | |
| 1998/0306 | * pick a local port and set it */ | |
| 1997/0327 | static void setlport(Conv* c) { Proto *p; ushort *pp; int x, found; p = c->p; if(c->restricted) pp = &p->nextrport; else pp = &p->nextport; | |
| 1998/0306 | qlock(p); | |
| 1997/0327 | for(;;(*pp)++){ | |
| 1997/0508 | /* * Fsproto initialises p->nextport to 0 and the restricted * ports (p->nextrport) to 600. * Restricted ports must lie between 600 and 1024. * For the initial condition or if the unrestricted port number | |
| 1997/0811 | * has wrapped round, select a random port between 5000 and 1<<15 | |
| 1997/0508 | * to start at. */ if(c->restricted){ if(*pp >= 1024) | |
| 1997/0327 | *pp = 600; } | |
| 1997/0508 | else while(*pp < 5000) | |
| 1997/0811 | *pp = nrand(1<<15); | |
| 1997/0508 | ||
| 1997/0327 | found = 0; for(x = 0; x < p->nc; x++){ if(p->conv[x] == nil) break; if(p->conv[x]->lport == *pp){ found = 1; break; } } if(!found) break; } c->lport = (*pp)++; | |
| 1998/0306 | qunlock(p); | |
| 1997/0327 | } | |
| 1998/0306 | /* * set a local address and port from a string of the form | |
| 2001/0209 | * [address!]port[!r] | |
| 1998/0306 | */ | |
| 2001/0126 | static char* | |
| 1998/0306 | setladdrport(Conv* c, char* str, int announcing) | |
| 1997/0327 | { | |
| 1997/0423 | char *p; | |
| 2001/0126 | char *rv; | |
| 2001/0118 | ushort lport; | |
| 1997/0327 | ||
| 2001/0126 | rv = nil; | |
| 1997/1128 | /* * ignore restricted part if it exists. it's * meaningless on local ports. */ | |
| 1997/0327 | p = strchr(str, '!'); | |
| 2001/0209 | if(p != nil){ | |
| 1997/0327 | *p++ = 0; | |
| 2001/0209 | if(strcmp(p, "r") == 0) p = nil; | |
| 1997/0327 | } | |
| 1998/0306 | c->lport = 0; | |
| 2001/0301 | if(p == nil){ if(announcing) | |
| 2001/0209 | ipmove(c->laddr, IPnoaddr); | |
| 2001/0301 | else | |
| 2001/0209 | setladdr(c); | |
| 2001/0301 | p = str; } else { if(strcmp(str, "*") == 0) ipmove(c->laddr, IPnoaddr); else parseip(c->laddr, str); | |
| 2001/0209 | } | |
| 2001/0301 | /* one process can get all connections */ if(announcing && strcmp(p, "*") == 0){ if(!iseve()) error(Eperm); return setluniqueport(c, 0); } lport = atoi(p); | |
| 2001/0210 | if(lport <= 0) setlport(c); else rv = setluniqueport(c, lport); | |
| 2001/0126 | return rv; | |
| 1997/0327 | } static char* setraddrport(Conv* c, char* str) { | |
| 1997/0423 | char *p; | |
| 1997/0327 | p = strchr(str, '!'); if(p == nil) return "malformed address"; *p++ = 0; | |
| 1998/0306 | parseip(c->raddr, str); | |
| 1997/0327 | c->rport = atoi(p); p = strchr(p, '!'); if(p){ | |
| 2001/0227 | if(strstr(p, "!r") != nil) | |
| 1997/0327 | c->restricted = 1; } return nil; } | |
| 1998/0306 | /* * called by protocol connect routine to set addresses */ char* Fsstdconnect(Conv *c, char *argv[], int argc) { char *p; switch(argc) { default: return "bad args to connect"; case 2: p = setraddrport(c, argv[1]); if(p != nil) return p; setladdr(c); setlport(c); break; case 3: p = setraddrport(c, argv[1]); if(p != nil) return p; | |
| 2001/0126 | return setladdrport(c, argv[2], 0); | |
| 1998/0306 | } return nil; } /* * initiate connection and sleep till its set up */ | |
| 1997/0327 | static int connected(void* a) { return ((Conv*)a)->state == Connected; } | |
| 1998/0306 | static void connectctlmsg(Proto *x, Conv *c, Cmdbuf *cb) { char *p; | |
| 1997/0327 | ||
| 2000/1220 | if(c->state != 0) error(Econinuse); | |
| 1998/0306 | c->state = Connecting; c->cerr[0] = '\0'; if(x->connect == nil) error("connect not supported"); p = x->connect(c, cb->f, cb->nf); if(p != nil) error(p); | |
| 2000/1220 | ||
| 2000/1221 | qunlock(c); if(waserror()){ qlock(c); nexterror(); } | |
| 1998/0306 | sleep(&c->cr, connected, c); | |
| 2000/1220 | qlock(c); | |
| 2000/1221 | poperror(); | |
| 1998/0306 | if(c->cerr[0] != '\0') error(c->cerr); } /* * called by protocol announce routine to set addresses */ char* Fsstdannounce(Conv* c, char* argv[], int argc) { | |
| 2001/0118 | memset(c->raddr, 0, sizeof(c->raddr)); c->rport = 0; | |
| 1998/0306 | switch(argc){ default: return "bad args to announce"; case 2: | |
| 2001/0126 | return setladdrport(c, argv[1], 1); | |
| 1998/0306 | } return nil; } /* * initiate announcement and sleep till its set up */ | |
| 1997/0327 | static int announced(void* a) { return ((Conv*)a)->state == Announced; } | |
| 1998/0306 | static void announcectlmsg(Proto *x, Conv *c, Cmdbuf *cb) { char *p; | |
| 1997/0327 | ||
| 2000/1220 | if(c->state != 0) error(Econinuse); | |
| 1998/0306 | c->state = Announcing; c->cerr[0] = '\0'; if(x->announce == nil) error("announce not supported"); p = x->announce(c, cb->f, cb->nf); if(p != nil) error(p); | |
| 2000/1220 | ||
| 2000/1221 | qunlock(c); if(waserror()){ qlock(c); nexterror(); } | |
| 1998/0306 | sleep(&c->cr, announced, c); | |
| 2000/1220 | qlock(c); | |
| 2000/1221 | poperror(); | |
| 1998/0306 | if(c->cerr[0] != '\0') error(c->cerr); } /* | |
| 2001/0118 | * called by protocol bind routine to set addresses | |
| 1998/0306 | */ char* Fsstdbind(Conv* c, char* argv[], int argc) { switch(argc){ default: return "bad args to bind"; case 2: | |
| 2001/0126 | return setladdrport(c, argv[1], 0); | |
| 1998/0306 | } return nil; } static void bindctlmsg(Proto *x, Conv *c, Cmdbuf *cb) { char *p; if(x->bind == nil) p = Fsstdbind(c, cb->f, cb->nf); else p = x->bind(c, cb->f, cb->nf); if(p != nil) error(p); } static void | |
| 1999/0817 | tosctlmsg(Conv *c, Cmdbuf *cb) { if(cb->nf < 2) c->tos = 0; else c->tos = atoi(cb->f[1]); } static void | |
| 1998/0306 | ttlctlmsg(Conv *c, Cmdbuf *cb) { if(cb->nf < 2) c->ttl = MAXTTL; else c->ttl = atoi(cb->f[1]); } | |
| 1997/0327 | static long | |
| 2000/0116 | ipwrite(Chan* ch, void *v, long n, vlong off) | |
| 1997/0327 | { Conv *c; Proto *x; | |
| 1998/0306 | char *p; Cmdbuf *cb; | |
| 2001/1120 | Cmdtab *ct; | |
| 1998/0502 | uchar ia[IPaddrlen], ma[IPaddrlen]; | |
| 1998/0313 | Fs *f; | |
| 1999/0320 | char *a; | |
| 2000/0116 | ulong offset = off; | |
| 1997/0327 | ||
| 1999/0320 | a = v; | |
| 1998/0313 | f = ipfs[ch->dev]; | |
| 1997/0327 | switch(TYPE(ch->qid)){ default: error(Eperm); | |
| 1998/0306 | case Qdata: | |
| 1998/0313 | x = f->p[PROTO(ch->qid)]; | |
| 1998/0306 | c = x->conv[CONV(ch->qid)]; if(c->wq == nil) error(Eperm); qwrite(c->wq, a, n); | |
| 2001/0306 | x->kick(c); | |
| 1998/0306 | break; | |
| 1997/0327 | case Qarp: | |
| 1998/0630 | return arpwrite(f, a, n); | |
| 1997/0327 | case Qiproute: | |
| 1998/0313 | return routewrite(f, ch, a, n); | |
| 1997/0327 | case Qlog: | |
| 2001/1120 | netlogctl(f, a, n); | |
| 1997/0327 | return n; | |
| 2000/0116 | case Qndb: return ndbwrite(f, a, offset, n); break; | |
| 1997/0327 | case Qctl: | |
| 1998/0313 | x = f->p[PROTO(ch->qid)]; | |
| 1997/0327 | c = x->conv[CONV(ch->qid)]; | |
| 1998/0306 | cb = parsecmd(a, n); | |
| 2000/1220 | qlock(c); | |
| 1998/0306 | if(waserror()) { | |
| 2000/1220 | qunlock(c); | |
| 1998/0306 | free(cb); nexterror(); | |
| 1997/0327 | } | |
| 2001/1120 | ct = lookupcmd(cb, ipctlmsg, nelem(ipctlmsg)); switch(ct->index){ case CMconnect: | |
| 1998/0306 | connectctlmsg(x, c, cb); | |
| 2001/1120 | break; case CMannounce: | |
| 1998/0306 | announcectlmsg(x, c, cb); | |
| 2001/1120 | break; case CMbind: | |
| 1998/0306 | bindctlmsg(x, c, cb); | |
| 2001/1120 | break; case CMttl: | |
| 1998/0306 | ttlctlmsg(c, cb); | |
| 2001/1120 | break; case CMtos: | |
| 1999/0817 | tosctlmsg(c, cb); | |
| 2001/1120 | break; case CMaddmulti: if(cb->nf != 2 && cb->nf != 3) cmderror(cb, Ecmdargs); | |
| 1998/0502 | if(cb->nf == 2){ if(!ipismulticast(c->raddr)) error("addmulti for a non multicast address"); parseip(ia, cb->f[1]); ipifcaddmulti(c, c->raddr, ia); } else { parseip(ma, cb->f[2]); if(!ipismulticast(ma)) error("addmulti for a non multicast address"); parseip(ia, cb->f[1]); ipifcaddmulti(c, ma, ia); } | |
| 2001/1120 | break; case CMremmulti: | |
| 1998/0306 | if(cb->nf < 2) error("remmulti needs interface address"); if(!ipismulticast(c->raddr)) error("remmulti for a non multicast address"); parseip(ia, cb->f[1]); ipifcremmulti(c, c->raddr, ia); | |
| 2001/1120 | break; case CMwildcard: if(x->ctl == nil) cmderror(cb, "unknown control request"); | |
| 1998/0306 | p = x->ctl(c, cb->f, cb->nf); | |
| 1997/0327 | if(p != nil) error(p); | |
| 2001/1120 | } | |
| 2000/1220 | qunlock(c); | |
| 1998/0306 | free(cb); poperror(); | |
| 1997/0327 | } return n; } static long | |
| 1999/0901 | ipbwrite(Chan* ch, Block* bp, ulong offset) | |
| 1997/0327 | { | |
| 1999/0901 | Conv *c; Proto *x; Fs *f; int n; switch(TYPE(ch->qid)){ case Qdata: f = ipfs[ch->dev]; x = f->p[PROTO(ch->qid)]; c = x->conv[CONV(ch->qid)]; if(c->wq == nil) error(Eperm); if(bp->next) bp = concatblock(bp); n = BLEN(bp); qbwrite(c->wq, bp); | |
| 2001/0306 | x->kick(c); | |
| 1999/0901 | return n; default: return devbwrite(ch, bp, offset); } | |
| 1997/0327 | } Dev ipdevtab = { | |
| 1997/0408 | 'I', "ip", | |
| 1997/0327 | ipreset, | |
| 2002/0109 | devinit, devshutdown, | |
| 1997/0327 | ipattach, ipwalk, ipstat, ipopen, | |
| 2001/1204 | devcreate, | |
| 1997/0327 | ipclose, ipread, ipbread, ipwrite, ipbwrite, | |
| 2001/1204 | devremove, | |
| 1997/0327 | ipwstat, }; int | |
| 1998/0313 | Fsproto(Fs *f, Proto *p) | |
| 1997/0327 | { | |
| 1998/0313 | if(f->np >= Maxproto) | |
| 1997/0327 | return -1; | |
| 1998/0313 | p->f = f; | |
| 1997/0327 | if(p->ipproto > 0){ | |
| 1998/0313 | if(f->t2p[p->ipproto] != nil) | |
| 1997/0327 | return -1; | |
| 1998/0313 | f->t2p[p->ipproto] = p; | |
| 1997/0327 | } | |
| 2001/0527 | p->qid.type = QTDIR; p->qid.path = QID(f->np, 0, Qprotodir); | |
| 1997/0327 | p->conv = malloc(sizeof(Conv*)*(p->nc+1)); if(p->conv == nil) panic("Fsproto"); | |
| 1998/0313 | p->x = f->np; | |
| 1997/0327 | p->nextport = 0; p->nextrport = 600; | |
| 1998/0313 | f->p[f->np++] = p; | |
| 1997/0327 | return 0; } /* * return true if this protocol is * built in */ int | |
| 1998/0313 | Fsbuiltinproto(Fs* f, uchar proto) | |
| 1997/0327 | { | |
| 1998/0313 | return f->t2p[proto] != nil; | |
| 1997/0327 | } | |
| 1999/0302 | /* * called with protocol locked */ | |
| 1997/0327 | Conv* Fsprotoclone(Proto *p, char *user) { Conv *c, **pp, **ep; | |
| 2000/0424 | retry: | |
| 1997/0327 | c = nil; ep = &p->conv[p->nc]; for(pp = p->conv; pp < ep; pp++) { c = *pp; if(c == nil){ c = malloc(sizeof(Conv)); if(c == nil) error(Enomem); | |
| 1999/0302 | qlock(c); | |
| 1997/0327 | c->p = p; c->x = pp - p->conv; | |
| 1999/0711 | if(p->ptclsize != 0){ c->ptcl = malloc(p->ptclsize); if(c->ptcl == nil) { free(c); error(Enomem); } | |
| 1997/0327 | } *pp = c; p->ac++; c->eq = qopen(1024, 1, 0, 0); (*p->create)(c); break; } | |
| 1999/0302 | if(canqlock(c)){ | |
| 1998/0306 | /* * make sure both processes and protocol * are done with this Conv */ if(c->inuse == 0 && (p->inuse == nil || (*p->inuse)(c) == 0)) | |
| 1997/0327 | break; | |
| 1999/0302 | qunlock(c); | |
| 1997/0327 | } } if(pp >= ep) { | |
| 2000/0424 | if(p->gc != nil && (*p->gc)(p)) goto retry; | |
| 1997/0327 | return nil; } c->inuse = 1; | |
| 2001/0527 | kstrdup(&c->owner, user); | |
| 1997/0327 | c->perm = 0660; | |
| 2000/1220 | c->state = Idle; | |
| 1998/0306 | ipmove(c->laddr, IPnoaddr); ipmove(c->raddr, IPnoaddr); | |
| 1997/0327 | c->lport = 0; c->rport = 0; c->restricted = 0; c->ttl = MAXTTL; qreopen(c->rq); qreopen(c->wq); qreopen(c->eq); | |
| 1999/0302 | qunlock(c); | |
| 1997/0327 | return c; } int | |
| 1998/0313 | Fsconnected(Conv* c, char* msg) | |
| 1997/0327 | { if(msg != nil && *msg != '\0') | |
| 2001/0527 | strncpy(c->cerr, msg, ERRMAX-1); | |
| 1997/0327 | switch(c->state){ case Announcing: c->state = Announced; break; case Connecting: c->state = Connected; break; } wakeup(&c->cr); return 0; } Proto* | |
| 1998/0313 | Fsrcvpcol(Fs* f, uchar proto) | |
| 1997/0327 | { | |
| 1998/0327 | if(f->ipmux) | |
| 1998/0324 | return f->ipmux; else return f->t2p[proto]; | |
| 1997/0327 | } | |
| 1998/0509 | Proto* Fsrcvpcolx(Fs *f, uchar proto) { return f->t2p[proto]; } | |
| 1999/0302 | /* * called with protocol locked */ | |
| 1997/0327 | Conv* | |
| 1998/0313 | Fsnewcall(Conv *c, uchar *raddr, ushort rport, uchar *laddr, ushort lport) | |
| 1997/0327 | { Conv *nc; Conv **l; int i; | |
| 1999/0302 | qlock(c); | |
| 1997/0327 | i = 0; for(l = &c->incall; *l; l = &(*l)->next) i++; if(i >= Maxincall) { | |
| 1999/0302 | qunlock(c); | |
| 1997/0327 | return nil; } /* find a free conversation */ nc = Fsprotoclone(c->p, network); if(nc == nil) { | |
| 1999/0302 | qunlock(c); | |
| 1997/0327 | return nil; } | |
| 1998/0306 | ipmove(nc->raddr, raddr); | |
| 1997/0327 | nc->rport = rport; | |
| 1998/0306 | ipmove(nc->laddr, laddr); | |
| 1997/0327 | nc->lport = lport; nc->next = nil; *l = nc; | |
| 2000/1227 | nc->state = Connected; | |
| 1999/0302 | qunlock(c); | |
| 1997/0327 | wakeup(&c->listenr); return nc; | |
| 2000/0116 | } long ndbwrite(Fs *f, char *a, ulong off, int n) { | |
| 2000/0126 | if(off > strlen(f->ndb)) | |
| 2000/0116 | error(Eio); | |
| 2000/0126 | if(off+n >= sizeof(f->ndb)) | |
| 2000/0116 | error(Eio); | |
| 2000/0126 | memmove(f->ndb+off, a, n); f->ndb[off+n] = 0; | |
| 2002/0324 | f->ndbvers++; | |
| 2002/0325 | f->ndbmtime = seconds(); | |
| 2000/0116 | return n; | |
| 1997/0327 | } | |
| 2001/0922 | ulong scalednconv(void) { if(cpuserver && conf.npage*BY2PG >= 128*MB) return Nchans*4; return Nchans; } | |