17dd7cddfSDavid du Colombier #include "u.h"
27dd7cddfSDavid du Colombier #include "../port/lib.h"
37dd7cddfSDavid du Colombier #include "mem.h"
47dd7cddfSDavid du Colombier #include "dat.h"
57dd7cddfSDavid du Colombier #include "fns.h"
67dd7cddfSDavid du Colombier #include "../port/error.h"
77dd7cddfSDavid du Colombier #include "../ip/ip.h"
87dd7cddfSDavid du Colombier
97dd7cddfSDavid du Colombier enum
107dd7cddfSDavid du Colombier {
117dd7cddfSDavid du Colombier Qtopdir= 1, /* top level directory */
127dd7cddfSDavid du Colombier Qtopbase,
137dd7cddfSDavid du Colombier Qarp= Qtopbase,
147dd7cddfSDavid du Colombier Qbootp,
157dd7cddfSDavid du Colombier Qndb,
167dd7cddfSDavid du Colombier Qiproute,
177dd7cddfSDavid du Colombier Qipselftab,
187dd7cddfSDavid du Colombier Qlog,
197dd7cddfSDavid du Colombier
207dd7cddfSDavid du Colombier Qprotodir, /* directory for a protocol */
217dd7cddfSDavid du Colombier Qprotobase,
227dd7cddfSDavid du Colombier Qclone= Qprotobase,
237dd7cddfSDavid du Colombier Qstats,
247dd7cddfSDavid du Colombier
257dd7cddfSDavid du Colombier Qconvdir, /* directory for a conversation */
267dd7cddfSDavid du Colombier Qconvbase,
277dd7cddfSDavid du Colombier Qctl= Qconvbase,
287dd7cddfSDavid du Colombier Qdata,
297dd7cddfSDavid du Colombier Qerr,
307dd7cddfSDavid du Colombier Qlisten,
317dd7cddfSDavid du Colombier Qlocal,
327dd7cddfSDavid du Colombier Qremote,
337dd7cddfSDavid du Colombier Qstatus,
34ef9eff0bSDavid du Colombier Qsnoop,
357dd7cddfSDavid du Colombier
367dd7cddfSDavid du Colombier Logtype= 5,
377dd7cddfSDavid du Colombier Masktype= (1<<Logtype)-1,
387dd7cddfSDavid du Colombier Logconv= 12,
397dd7cddfSDavid du Colombier Maskconv= (1<<Logconv)-1,
407dd7cddfSDavid du Colombier Shiftconv= Logtype,
417dd7cddfSDavid du Colombier Logproto= 8,
427dd7cddfSDavid du Colombier Maskproto= (1<<Logproto)-1,
437dd7cddfSDavid du Colombier Shiftproto= Logtype + Logconv,
447dd7cddfSDavid du Colombier
458c1c8807SDavid du Colombier Nfs= 128,
467dd7cddfSDavid du Colombier };
479a747e4fSDavid du Colombier #define TYPE(x) ( ((ulong)(x).path) & Masktype )
489a747e4fSDavid du Colombier #define CONV(x) ( (((ulong)(x).path) >> Shiftconv) & Maskconv )
499a747e4fSDavid du Colombier #define PROTO(x) ( (((ulong)(x).path) >> Shiftproto) & Maskproto )
507dd7cddfSDavid du Colombier #define QID(p, c, y) ( ((p)<<(Shiftproto)) | ((c)<<Shiftconv) | (y) )
517dd7cddfSDavid du Colombier
527dd7cddfSDavid du Colombier static char network[] = "network";
537dd7cddfSDavid du Colombier
547dd7cddfSDavid du Colombier QLock fslock;
557dd7cddfSDavid du Colombier Fs *ipfs[Nfs]; /* attached fs's */
567dd7cddfSDavid du Colombier Queue *qlog;
577dd7cddfSDavid du Colombier
587dd7cddfSDavid du Colombier extern void nullmediumlink(void);
597dd7cddfSDavid du Colombier extern void pktmediumlink(void);
607dd7cddfSDavid du Colombier long ndbwrite(Fs *f, char *a, ulong off, int n);
617dd7cddfSDavid du Colombier
627dd7cddfSDavid du Colombier static int
ip3gen(Chan * c,int i,Dir * dp)637dd7cddfSDavid du Colombier ip3gen(Chan *c, int i, Dir *dp)
647dd7cddfSDavid du Colombier {
657dd7cddfSDavid du Colombier Qid q;
667dd7cddfSDavid du Colombier Conv *cv;
677dd7cddfSDavid du Colombier char *p;
687dd7cddfSDavid du Colombier
697dd7cddfSDavid du Colombier cv = ipfs[c->dev]->p[PROTO(c->qid)]->conv[CONV(c->qid)];
709a747e4fSDavid du Colombier if(cv->owner == nil)
719a747e4fSDavid du Colombier kstrdup(&cv->owner, eve);
729a747e4fSDavid du Colombier mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE);
739a747e4fSDavid du Colombier
747dd7cddfSDavid du Colombier switch(i) {
757dd7cddfSDavid du Colombier default:
767dd7cddfSDavid du Colombier return -1;
777dd7cddfSDavid du Colombier case Qctl:
787dd7cddfSDavid du Colombier devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp);
797dd7cddfSDavid du Colombier return 1;
807dd7cddfSDavid du Colombier case Qdata:
8136d3592fSDavid du Colombier devdir(c, q, "data", qlen(cv->rq), cv->owner, cv->perm, dp);
827dd7cddfSDavid du Colombier return 1;
837dd7cddfSDavid du Colombier case Qerr:
8436d3592fSDavid du Colombier devdir(c, q, "err", qlen(cv->eq), cv->owner, cv->perm, dp);
857dd7cddfSDavid du Colombier return 1;
867dd7cddfSDavid du Colombier case Qlisten:
87ef9eff0bSDavid du Colombier devdir(c, q, "listen", 0, cv->owner, cv->perm, dp);
889a747e4fSDavid du Colombier return 1;
897dd7cddfSDavid du Colombier case Qlocal:
907dd7cddfSDavid du Colombier p = "local";
917dd7cddfSDavid du Colombier break;
927dd7cddfSDavid du Colombier case Qremote:
937dd7cddfSDavid du Colombier p = "remote";
947dd7cddfSDavid du Colombier break;
95ef9eff0bSDavid du Colombier case Qsnoop:
96ef9eff0bSDavid du Colombier if(strcmp(cv->p->name, "ipifc") != 0)
97ef9eff0bSDavid du Colombier return -1;
9836d3592fSDavid du Colombier devdir(c, q, "snoop", qlen(cv->sq), cv->owner, 0400, dp);
99ef9eff0bSDavid du Colombier return 1;
1007dd7cddfSDavid du Colombier case Qstatus:
1017dd7cddfSDavid du Colombier p = "status";
1027dd7cddfSDavid du Colombier break;
1037dd7cddfSDavid du Colombier }
1049a747e4fSDavid du Colombier devdir(c, q, p, 0, cv->owner, 0444, dp);
1057dd7cddfSDavid du Colombier return 1;
1067dd7cddfSDavid du Colombier }
1077dd7cddfSDavid du Colombier
1087dd7cddfSDavid du Colombier static int
ip2gen(Chan * c,int i,Dir * dp)1097dd7cddfSDavid du Colombier ip2gen(Chan *c, int i, Dir *dp)
1107dd7cddfSDavid du Colombier {
1117dd7cddfSDavid du Colombier Qid q;
1127dd7cddfSDavid du Colombier
1137dd7cddfSDavid du Colombier switch(i) {
1147dd7cddfSDavid du Colombier case Qclone:
1159a747e4fSDavid du Colombier mkqid(&q, QID(PROTO(c->qid), 0, Qclone), 0, QTFILE);
1167dd7cddfSDavid du Colombier devdir(c, q, "clone", 0, network, 0666, dp);
1177dd7cddfSDavid du Colombier return 1;
1187dd7cddfSDavid du Colombier case Qstats:
1199a747e4fSDavid du Colombier mkqid(&q, QID(PROTO(c->qid), 0, Qstats), 0, QTFILE);
1207dd7cddfSDavid du Colombier devdir(c, q, "stats", 0, network, 0444, dp);
1217dd7cddfSDavid du Colombier return 1;
1227dd7cddfSDavid du Colombier }
1237dd7cddfSDavid du Colombier return -1;
1247dd7cddfSDavid du Colombier }
1257dd7cddfSDavid du Colombier
1267dd7cddfSDavid du Colombier static int
ip1gen(Chan * c,int i,Dir * dp)1277dd7cddfSDavid du Colombier ip1gen(Chan *c, int i, Dir *dp)
1287dd7cddfSDavid du Colombier {
1297dd7cddfSDavid du Colombier Qid q;
1307dd7cddfSDavid du Colombier char *p;
1317dd7cddfSDavid du Colombier int prot;
1327dd7cddfSDavid du Colombier int len = 0;
1337dd7cddfSDavid du Colombier Fs *f;
1343ff48bf5SDavid du Colombier extern ulong kerndate;
1357dd7cddfSDavid du Colombier
1367dd7cddfSDavid du Colombier f = ipfs[c->dev];
1377dd7cddfSDavid du Colombier
1387dd7cddfSDavid du Colombier prot = 0666;
1399a747e4fSDavid du Colombier mkqid(&q, QID(0, 0, i), 0, QTFILE);
1407dd7cddfSDavid du Colombier switch(i) {
1417dd7cddfSDavid du Colombier default:
1427dd7cddfSDavid du Colombier return -1;
1437dd7cddfSDavid du Colombier case Qarp:
1447dd7cddfSDavid du Colombier p = "arp";
14537c8dc8dSDavid du Colombier prot = 0664;
1467dd7cddfSDavid du Colombier break;
1477dd7cddfSDavid du Colombier case Qbootp:
1487dd7cddfSDavid du Colombier p = "bootp";
1497dd7cddfSDavid du Colombier break;
1507dd7cddfSDavid du Colombier case Qndb:
1517dd7cddfSDavid du Colombier p = "ndb";
1527dd7cddfSDavid du Colombier len = strlen(f->ndb);
1539a747e4fSDavid du Colombier q.vers = f->ndbvers;
1547dd7cddfSDavid du Colombier break;
1557dd7cddfSDavid du Colombier case Qiproute:
1567dd7cddfSDavid du Colombier p = "iproute";
15737c8dc8dSDavid du Colombier prot = 0664;
1587dd7cddfSDavid du Colombier break;
1597dd7cddfSDavid du Colombier case Qipselftab:
1607dd7cddfSDavid du Colombier p = "ipselftab";
1617dd7cddfSDavid du Colombier prot = 0444;
1627dd7cddfSDavid du Colombier break;
1637dd7cddfSDavid du Colombier case Qlog:
1647dd7cddfSDavid du Colombier p = "log";
1657dd7cddfSDavid du Colombier break;
1667dd7cddfSDavid du Colombier }
1677dd7cddfSDavid du Colombier devdir(c, q, p, len, network, prot, dp);
1683ff48bf5SDavid du Colombier if(i == Qndb && f->ndbmtime > kerndate)
1699a747e4fSDavid du Colombier dp->mtime = f->ndbmtime;
1707dd7cddfSDavid du Colombier return 1;
1717dd7cddfSDavid du Colombier }
1727dd7cddfSDavid du Colombier
1737dd7cddfSDavid du Colombier static int
ipgen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)1749a747e4fSDavid du Colombier ipgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
1757dd7cddfSDavid du Colombier {
1767dd7cddfSDavid du Colombier Qid q;
1777dd7cddfSDavid du Colombier Conv *cv;
1787dd7cddfSDavid du Colombier Fs *f;
1797dd7cddfSDavid du Colombier
1807dd7cddfSDavid du Colombier f = ipfs[c->dev];
1817dd7cddfSDavid du Colombier
1827dd7cddfSDavid du Colombier switch(TYPE(c->qid)) {
1837dd7cddfSDavid du Colombier case Qtopdir:
1847dd7cddfSDavid du Colombier if(s == DEVDOTDOT){
1859a747e4fSDavid du Colombier mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);
186*57d98441SDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "#I%lud", c->dev);
1879a747e4fSDavid du Colombier devdir(c, q, up->genbuf, 0, network, 0555, dp);
1887dd7cddfSDavid du Colombier return 1;
1897dd7cddfSDavid du Colombier }
1907dd7cddfSDavid du Colombier if(s < f->np) {
1917dd7cddfSDavid du Colombier if(f->p[s]->connect == nil)
1927dd7cddfSDavid du Colombier return 0; /* protocol with no user interface */
1939a747e4fSDavid du Colombier mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);
1947dd7cddfSDavid du Colombier devdir(c, q, f->p[s]->name, 0, network, 0555, dp);
1957dd7cddfSDavid du Colombier return 1;
1967dd7cddfSDavid du Colombier }
1977dd7cddfSDavid du Colombier s -= f->np;
1987dd7cddfSDavid du Colombier return ip1gen(c, s+Qtopbase, dp);
1997dd7cddfSDavid du Colombier case Qarp:
2007dd7cddfSDavid du Colombier case Qbootp:
2017dd7cddfSDavid du Colombier case Qndb:
2027dd7cddfSDavid du Colombier case Qlog:
2037dd7cddfSDavid du Colombier case Qiproute:
2047dd7cddfSDavid du Colombier case Qipselftab:
2057dd7cddfSDavid du Colombier return ip1gen(c, TYPE(c->qid), dp);
2067dd7cddfSDavid du Colombier case Qprotodir:
2077dd7cddfSDavid du Colombier if(s == DEVDOTDOT){
2089a747e4fSDavid du Colombier mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);
209*57d98441SDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "#I%lud", c->dev);
2109a747e4fSDavid du Colombier devdir(c, q, up->genbuf, 0, network, 0555, dp);
2117dd7cddfSDavid du Colombier return 1;
2127dd7cddfSDavid du Colombier }
2137dd7cddfSDavid du Colombier if(s < f->p[PROTO(c->qid)]->ac) {
2147dd7cddfSDavid du Colombier cv = f->p[PROTO(c->qid)]->conv[s];
215*57d98441SDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "%d", s);
2169a747e4fSDavid du Colombier mkqid(&q, QID(PROTO(c->qid), s, Qconvdir), 0, QTDIR);
2179a747e4fSDavid du Colombier devdir(c, q, up->genbuf, 0, cv->owner, 0555, dp);
2187dd7cddfSDavid du Colombier return 1;
2197dd7cddfSDavid du Colombier }
2207dd7cddfSDavid du Colombier s -= f->p[PROTO(c->qid)]->ac;
2217dd7cddfSDavid du Colombier return ip2gen(c, s+Qprotobase, dp);
2227dd7cddfSDavid du Colombier case Qclone:
2237dd7cddfSDavid du Colombier case Qstats:
2247dd7cddfSDavid du Colombier return ip2gen(c, TYPE(c->qid), dp);
2257dd7cddfSDavid du Colombier case Qconvdir:
2267dd7cddfSDavid du Colombier if(s == DEVDOTDOT){
2277dd7cddfSDavid du Colombier s = PROTO(c->qid);
2289a747e4fSDavid du Colombier mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);
2297dd7cddfSDavid du Colombier devdir(c, q, f->p[s]->name, 0, network, 0555, dp);
2307dd7cddfSDavid du Colombier return 1;
2317dd7cddfSDavid du Colombier }
2327dd7cddfSDavid du Colombier return ip3gen(c, s+Qconvbase, dp);
2337dd7cddfSDavid du Colombier case Qctl:
2347dd7cddfSDavid du Colombier case Qdata:
2357dd7cddfSDavid du Colombier case Qerr:
2367dd7cddfSDavid du Colombier case Qlisten:
2377dd7cddfSDavid du Colombier case Qlocal:
2387dd7cddfSDavid du Colombier case Qremote:
2397dd7cddfSDavid du Colombier case Qstatus:
240ef9eff0bSDavid du Colombier case Qsnoop:
2417dd7cddfSDavid du Colombier return ip3gen(c, TYPE(c->qid), dp);
2427dd7cddfSDavid du Colombier }
2437dd7cddfSDavid du Colombier return -1;
2447dd7cddfSDavid du Colombier }
2457dd7cddfSDavid du Colombier
2467dd7cddfSDavid du Colombier static void
ipreset(void)2477dd7cddfSDavid du Colombier ipreset(void)
2487dd7cddfSDavid du Colombier {
2497dd7cddfSDavid du Colombier nullmediumlink();
2507dd7cddfSDavid du Colombier pktmediumlink();
2517dd7cddfSDavid du Colombier
2529a747e4fSDavid du Colombier fmtinstall('i', eipfmt);
2539a747e4fSDavid du Colombier fmtinstall('I', eipfmt);
2549a747e4fSDavid du Colombier fmtinstall('E', eipfmt);
2559a747e4fSDavid du Colombier fmtinstall('V', eipfmt);
2569a747e4fSDavid du Colombier fmtinstall('M', eipfmt);
2577dd7cddfSDavid du Colombier }
2587dd7cddfSDavid du Colombier
2597dd7cddfSDavid du Colombier static Fs*
ipgetfs(int dev)2607dd7cddfSDavid du Colombier ipgetfs(int dev)
2617dd7cddfSDavid du Colombier {
2627dd7cddfSDavid du Colombier extern void (*ipprotoinit[])(Fs*);
2637dd7cddfSDavid du Colombier Fs *f;
2647dd7cddfSDavid du Colombier int i;
2657dd7cddfSDavid du Colombier
2667dd7cddfSDavid du Colombier if(dev >= Nfs)
2677dd7cddfSDavid du Colombier return nil;
2687dd7cddfSDavid du Colombier
2697dd7cddfSDavid du Colombier qlock(&fslock);
2707dd7cddfSDavid du Colombier if(ipfs[dev] == nil){
2717dd7cddfSDavid du Colombier f = smalloc(sizeof(Fs));
2727dd7cddfSDavid du Colombier ip_init(f);
2737dd7cddfSDavid du Colombier arpinit(f);
2747dd7cddfSDavid du Colombier netloginit(f);
2757dd7cddfSDavid du Colombier for(i = 0; ipprotoinit[i]; i++)
2767dd7cddfSDavid du Colombier ipprotoinit[i](f);
2777dd7cddfSDavid du Colombier f->dev = dev;
2787dd7cddfSDavid du Colombier ipfs[dev] = f;
2797dd7cddfSDavid du Colombier }
2807dd7cddfSDavid du Colombier qunlock(&fslock);
2817dd7cddfSDavid du Colombier
2827dd7cddfSDavid du Colombier return ipfs[dev];
2837dd7cddfSDavid du Colombier }
2847dd7cddfSDavid du Colombier
2859a747e4fSDavid du Colombier IPaux*
newipaux(char * owner,char * tag)2869a747e4fSDavid du Colombier newipaux(char *owner, char *tag)
2879a747e4fSDavid du Colombier {
2889a747e4fSDavid du Colombier IPaux *a;
2899a747e4fSDavid du Colombier int n;
2909a747e4fSDavid du Colombier
2919a747e4fSDavid du Colombier a = smalloc(sizeof(*a));
2929a747e4fSDavid du Colombier kstrdup(&a->owner, owner);
2939a747e4fSDavid du Colombier memset(a->tag, ' ', sizeof(a->tag));
2949a747e4fSDavid du Colombier n = strlen(tag);
2959a747e4fSDavid du Colombier if(n > sizeof(a->tag))
2969a747e4fSDavid du Colombier n = sizeof(a->tag);
2979a747e4fSDavid du Colombier memmove(a->tag, tag, n);
2989a747e4fSDavid du Colombier return a;
2999a747e4fSDavid du Colombier }
3009a747e4fSDavid du Colombier
3019a747e4fSDavid du Colombier #define ATTACHER(c) (((IPaux*)((c)->aux))->owner)
3029a747e4fSDavid du Colombier
3037dd7cddfSDavid du Colombier static Chan*
ipattach(char * spec)3047dd7cddfSDavid du Colombier ipattach(char* spec)
3057dd7cddfSDavid du Colombier {
3067dd7cddfSDavid du Colombier Chan *c;
3077dd7cddfSDavid du Colombier int dev;
3087dd7cddfSDavid du Colombier
3097dd7cddfSDavid du Colombier dev = atoi(spec);
3108c1c8807SDavid du Colombier if(dev >= Nfs)
3117dd7cddfSDavid du Colombier error("bad specification");
3127dd7cddfSDavid du Colombier
3137dd7cddfSDavid du Colombier ipgetfs(dev);
3147dd7cddfSDavid du Colombier c = devattach('I', spec);
3159a747e4fSDavid du Colombier mkqid(&c->qid, QID(0, 0, Qtopdir), 0, QTDIR);
3167dd7cddfSDavid du Colombier c->dev = dev;
3177dd7cddfSDavid du Colombier
3189a747e4fSDavid du Colombier c->aux = newipaux(commonuser(), "none");
3199a747e4fSDavid du Colombier
3207dd7cddfSDavid du Colombier return c;
3217dd7cddfSDavid du Colombier }
3227dd7cddfSDavid du Colombier
3239a747e4fSDavid du Colombier static Walkqid*
ipwalk(Chan * c,Chan * nc,char ** name,int nname)3249a747e4fSDavid du Colombier ipwalk(Chan* c, Chan *nc, char **name, int nname)
3257dd7cddfSDavid du Colombier {
3269a747e4fSDavid du Colombier IPaux *a = c->aux;
3279a747e4fSDavid du Colombier Walkqid* w;
3289a747e4fSDavid du Colombier
3299a747e4fSDavid du Colombier w = devwalk(c, nc, name, nname, nil, 0, ipgen);
3309a747e4fSDavid du Colombier if(w != nil && w->clone != nil)
3319a747e4fSDavid du Colombier w->clone->aux = newipaux(a->owner, a->tag);
3329a747e4fSDavid du Colombier return w;
3337dd7cddfSDavid du Colombier }
3347dd7cddfSDavid du Colombier
3353ff48bf5SDavid du Colombier
3367dd7cddfSDavid du Colombier static int
ipstat(Chan * c,uchar * db,int n)3379a747e4fSDavid du Colombier ipstat(Chan* c, uchar* db, int n)
3387dd7cddfSDavid du Colombier {
3399a747e4fSDavid du Colombier return devstat(c, db, n, nil, 0, ipgen);
3407dd7cddfSDavid du Colombier }
3417dd7cddfSDavid du Colombier
3427dd7cddfSDavid du Colombier static int
incoming(void * arg)3437dd7cddfSDavid du Colombier incoming(void* arg)
3447dd7cddfSDavid du Colombier {
3457dd7cddfSDavid du Colombier Conv *conv;
3467dd7cddfSDavid du Colombier
3477dd7cddfSDavid du Colombier conv = arg;
3487dd7cddfSDavid du Colombier return conv->incall != nil;
3497dd7cddfSDavid du Colombier }
3507dd7cddfSDavid du Colombier
3517dd7cddfSDavid du Colombier static int m2p[] = {
3527dd7cddfSDavid du Colombier [OREAD] 4,
3537dd7cddfSDavid du Colombier [OWRITE] 2,
3547dd7cddfSDavid du Colombier [ORDWR] 6
3557dd7cddfSDavid du Colombier };
3567dd7cddfSDavid du Colombier
3577dd7cddfSDavid du Colombier static Chan*
ipopen(Chan * c,int omode)3587dd7cddfSDavid du Colombier ipopen(Chan* c, int omode)
3597dd7cddfSDavid du Colombier {
3607dd7cddfSDavid du Colombier Conv *cv, *nc;
3617dd7cddfSDavid du Colombier Proto *p;
3627dd7cddfSDavid du Colombier int perm;
3637dd7cddfSDavid du Colombier Fs *f;
3647dd7cddfSDavid du Colombier
3651b0a7c7eSDavid du Colombier perm = m2p[omode&3];
3667dd7cddfSDavid du Colombier
3677dd7cddfSDavid du Colombier f = ipfs[c->dev];
3687dd7cddfSDavid du Colombier
3697dd7cddfSDavid du Colombier switch(TYPE(c->qid)) {
3707dd7cddfSDavid du Colombier default:
3717dd7cddfSDavid du Colombier break;
3727dd7cddfSDavid du Colombier case Qndb:
3733ff48bf5SDavid du Colombier if(omode & (OWRITE|OTRUNC) && !iseve())
3747dd7cddfSDavid du Colombier error(Eperm);
3753ff48bf5SDavid du Colombier if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC))
3767dd7cddfSDavid du Colombier f->ndb[0] = 0;
3777dd7cddfSDavid du Colombier break;
3787dd7cddfSDavid du Colombier case Qlog:
3797dd7cddfSDavid du Colombier netlogopen(f);
3807dd7cddfSDavid du Colombier break;
3817dd7cddfSDavid du Colombier case Qiproute:
38237c8dc8dSDavid du Colombier case Qarp:
38337c8dc8dSDavid du Colombier if(omode != OREAD && !iseve())
38437c8dc8dSDavid du Colombier error(Eperm);
3857dd7cddfSDavid du Colombier break;
3867dd7cddfSDavid du Colombier case Qtopdir:
3877dd7cddfSDavid du Colombier case Qprotodir:
3887dd7cddfSDavid du Colombier case Qconvdir:
3897dd7cddfSDavid du Colombier case Qstatus:
3907dd7cddfSDavid du Colombier case Qremote:
3917dd7cddfSDavid du Colombier case Qlocal:
3927dd7cddfSDavid du Colombier case Qstats:
3937dd7cddfSDavid du Colombier case Qbootp:
3947dd7cddfSDavid du Colombier case Qipselftab:
3957dd7cddfSDavid du Colombier if(omode != OREAD)
3967dd7cddfSDavid du Colombier error(Eperm);
3977dd7cddfSDavid du Colombier break;
398ef9eff0bSDavid du Colombier case Qsnoop:
399ef9eff0bSDavid du Colombier if(omode != OREAD)
400ef9eff0bSDavid du Colombier error(Eperm);
401ef9eff0bSDavid du Colombier p = f->p[PROTO(c->qid)];
402ef9eff0bSDavid du Colombier cv = p->conv[CONV(c->qid)];
403ef9eff0bSDavid du Colombier if(strcmp(ATTACHER(c), cv->owner) != 0 && !iseve())
404ef9eff0bSDavid du Colombier error(Eperm);
405ef9eff0bSDavid du Colombier incref(&cv->snoopers);
406ef9eff0bSDavid du Colombier break;
4077dd7cddfSDavid du Colombier case Qclone:
4087dd7cddfSDavid du Colombier p = f->p[PROTO(c->qid)];
4097dd7cddfSDavid du Colombier qlock(p);
4107dd7cddfSDavid du Colombier if(waserror()){
4117dd7cddfSDavid du Colombier qunlock(p);
4127dd7cddfSDavid du Colombier nexterror();
4137dd7cddfSDavid du Colombier }
4149a747e4fSDavid du Colombier cv = Fsprotoclone(p, ATTACHER(c));
4157dd7cddfSDavid du Colombier qunlock(p);
4167dd7cddfSDavid du Colombier poperror();
4177dd7cddfSDavid du Colombier if(cv == nil) {
4187dd7cddfSDavid du Colombier error(Enodev);
4197dd7cddfSDavid du Colombier break;
4207dd7cddfSDavid du Colombier }
4219a747e4fSDavid du Colombier mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE);
4227dd7cddfSDavid du Colombier break;
4237dd7cddfSDavid du Colombier case Qdata:
4247dd7cddfSDavid du Colombier case Qctl:
4257dd7cddfSDavid du Colombier case Qerr:
4267dd7cddfSDavid du Colombier p = f->p[PROTO(c->qid)];
4277dd7cddfSDavid du Colombier qlock(p);
4287dd7cddfSDavid du Colombier cv = p->conv[CONV(c->qid)];
4297dd7cddfSDavid du Colombier qlock(cv);
4307dd7cddfSDavid du Colombier if(waserror()) {
4317dd7cddfSDavid du Colombier qunlock(cv);
4327dd7cddfSDavid du Colombier qunlock(p);
4337dd7cddfSDavid du Colombier nexterror();
4347dd7cddfSDavid du Colombier }
4357dd7cddfSDavid du Colombier if((perm & (cv->perm>>6)) != perm) {
4369a747e4fSDavid du Colombier if(strcmp(ATTACHER(c), cv->owner) != 0)
4377dd7cddfSDavid du Colombier error(Eperm);
4387dd7cddfSDavid du Colombier if((perm & cv->perm) != perm)
4397dd7cddfSDavid du Colombier error(Eperm);
4407dd7cddfSDavid du Colombier
4417dd7cddfSDavid du Colombier }
4427dd7cddfSDavid du Colombier cv->inuse++;
4437dd7cddfSDavid du Colombier if(cv->inuse == 1){
4449a747e4fSDavid du Colombier kstrdup(&cv->owner, ATTACHER(c));
4457dd7cddfSDavid du Colombier cv->perm = 0660;
4467dd7cddfSDavid du Colombier }
4477dd7cddfSDavid du Colombier qunlock(cv);
4487dd7cddfSDavid du Colombier qunlock(p);
4497dd7cddfSDavid du Colombier poperror();
4507dd7cddfSDavid du Colombier break;
4517dd7cddfSDavid du Colombier case Qlisten:
4527dd7cddfSDavid du Colombier cv = f->p[PROTO(c->qid)]->conv[CONV(c->qid)];
4539a747e4fSDavid du Colombier if((perm & (cv->perm>>6)) != perm) {
4549a747e4fSDavid du Colombier if(strcmp(ATTACHER(c), cv->owner) != 0)
4559a747e4fSDavid du Colombier error(Eperm);
4569a747e4fSDavid du Colombier if((perm & cv->perm) != perm)
4579a747e4fSDavid du Colombier error(Eperm);
4589a747e4fSDavid du Colombier
4599a747e4fSDavid du Colombier }
4609a747e4fSDavid du Colombier
4617dd7cddfSDavid du Colombier if(cv->state != Announced)
4627dd7cddfSDavid du Colombier error("not announced");
4637dd7cddfSDavid du Colombier
46451711cb6SDavid du Colombier if(waserror()){
46551711cb6SDavid du Colombier closeconv(cv);
46651711cb6SDavid du Colombier nexterror();
46751711cb6SDavid du Colombier }
46851711cb6SDavid du Colombier qlock(cv);
46951711cb6SDavid du Colombier cv->inuse++;
47051711cb6SDavid du Colombier qunlock(cv);
47151711cb6SDavid du Colombier
4727dd7cddfSDavid du Colombier nc = nil;
4737dd7cddfSDavid du Colombier while(nc == nil) {
4747dd7cddfSDavid du Colombier /* give up if we got a hangup */
4757dd7cddfSDavid du Colombier if(qisclosed(cv->rq))
4767dd7cddfSDavid du Colombier error("listen hungup");
4777dd7cddfSDavid du Colombier
4787dd7cddfSDavid du Colombier qlock(&cv->listenq);
4797dd7cddfSDavid du Colombier if(waserror()) {
4807dd7cddfSDavid du Colombier qunlock(&cv->listenq);
4817dd7cddfSDavid du Colombier nexterror();
4827dd7cddfSDavid du Colombier }
4837dd7cddfSDavid du Colombier
4847dd7cddfSDavid du Colombier /* wait for a connect */
4857dd7cddfSDavid du Colombier sleep(&cv->listenr, incoming, cv);
4867dd7cddfSDavid du Colombier
4877dd7cddfSDavid du Colombier qlock(cv);
4887dd7cddfSDavid du Colombier nc = cv->incall;
4897dd7cddfSDavid du Colombier if(nc != nil){
4907dd7cddfSDavid du Colombier cv->incall = nc->next;
4919a747e4fSDavid du Colombier mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE);
4929a747e4fSDavid du Colombier kstrdup(&cv->owner, ATTACHER(c));
4937dd7cddfSDavid du Colombier }
4947dd7cddfSDavid du Colombier qunlock(cv);
4957dd7cddfSDavid du Colombier
4967dd7cddfSDavid du Colombier qunlock(&cv->listenq);
4977dd7cddfSDavid du Colombier poperror();
4987dd7cddfSDavid du Colombier }
49951711cb6SDavid du Colombier closeconv(cv);
50051711cb6SDavid du Colombier poperror();
5017dd7cddfSDavid du Colombier break;
5027dd7cddfSDavid du Colombier }
5037dd7cddfSDavid du Colombier c->mode = openmode(omode);
5047dd7cddfSDavid du Colombier c->flag |= COPEN;
5057dd7cddfSDavid du Colombier c->offset = 0;
5067dd7cddfSDavid du Colombier return c;
5077dd7cddfSDavid du Colombier }
5087dd7cddfSDavid du Colombier
5093ff48bf5SDavid du Colombier static void
ipcreate(Chan *,char *,int,ulong)5103ff48bf5SDavid du Colombier ipcreate(Chan*, char*, int, ulong)
5113ff48bf5SDavid du Colombier {
5123ff48bf5SDavid du Colombier error(Eperm);
5133ff48bf5SDavid du Colombier }
5143ff48bf5SDavid du Colombier
5153ff48bf5SDavid du Colombier static void
ipremove(Chan *)5163ff48bf5SDavid du Colombier ipremove(Chan*)
5173ff48bf5SDavid du Colombier {
5183ff48bf5SDavid du Colombier error(Eperm);
5193ff48bf5SDavid du Colombier }
5203ff48bf5SDavid du Colombier
5219a747e4fSDavid du Colombier static int
ipwstat(Chan * c,uchar * dp,int n)5229a747e4fSDavid du Colombier ipwstat(Chan *c, uchar *dp, int n)
5237dd7cddfSDavid du Colombier {
5243ff48bf5SDavid du Colombier Dir d;
5259a747e4fSDavid du Colombier Conv *cv;
5269a747e4fSDavid du Colombier Fs *f;
5279a747e4fSDavid du Colombier Proto *p;
5289a747e4fSDavid du Colombier
5299a747e4fSDavid du Colombier f = ipfs[c->dev];
5309a747e4fSDavid du Colombier switch(TYPE(c->qid)) {
5319a747e4fSDavid du Colombier default:
5327dd7cddfSDavid du Colombier error(Eperm);
5339a747e4fSDavid du Colombier break;
5349a747e4fSDavid du Colombier case Qctl:
5359a747e4fSDavid du Colombier case Qdata:
5369a747e4fSDavid du Colombier break;
5377dd7cddfSDavid du Colombier }
5387dd7cddfSDavid du Colombier
5393ff48bf5SDavid du Colombier n = convM2D(dp, n, &d, nil);
5403ff48bf5SDavid du Colombier if(n > 0){
5419a747e4fSDavid du Colombier p = f->p[PROTO(c->qid)];
5429a747e4fSDavid du Colombier cv = p->conv[CONV(c->qid)];
5439a747e4fSDavid du Colombier if(!iseve() && strcmp(ATTACHER(c), cv->owner) != 0)
5447dd7cddfSDavid du Colombier error(Eperm);
5453ff48bf5SDavid du Colombier if(d.uid[0])
5463ff48bf5SDavid du Colombier kstrdup(&cv->owner, d.uid);
5473ff48bf5SDavid du Colombier cv->perm = d.mode & 0777;
5483ff48bf5SDavid du Colombier }
5499a747e4fSDavid du Colombier return n;
5507dd7cddfSDavid du Colombier }
5517dd7cddfSDavid du Colombier
5527dd7cddfSDavid du Colombier void
closeconv(Conv * cv)5537dd7cddfSDavid du Colombier closeconv(Conv *cv)
5547dd7cddfSDavid du Colombier {
5557dd7cddfSDavid du Colombier Conv *nc;
5567dd7cddfSDavid du Colombier Ipmulti *mp;
5577dd7cddfSDavid du Colombier
5587dd7cddfSDavid du Colombier qlock(cv);
5597dd7cddfSDavid du Colombier
5607dd7cddfSDavid du Colombier if(--cv->inuse > 0) {
5617dd7cddfSDavid du Colombier qunlock(cv);
5627dd7cddfSDavid du Colombier return;
5637dd7cddfSDavid du Colombier }
5647dd7cddfSDavid du Colombier
5657dd7cddfSDavid du Colombier /* close all incoming calls since no listen will ever happen */
5667dd7cddfSDavid du Colombier for(nc = cv->incall; nc; nc = cv->incall){
5677dd7cddfSDavid du Colombier cv->incall = nc->next;
5687dd7cddfSDavid du Colombier closeconv(nc);
5697dd7cddfSDavid du Colombier }
5707dd7cddfSDavid du Colombier cv->incall = nil;
5717dd7cddfSDavid du Colombier
5729a747e4fSDavid du Colombier kstrdup(&cv->owner, network);
5737dd7cddfSDavid du Colombier cv->perm = 0660;
5747dd7cddfSDavid du Colombier
5757dd7cddfSDavid du Colombier while((mp = cv->multi) != nil)
5767dd7cddfSDavid du Colombier ipifcremmulti(cv, mp->ma, mp->ia);
5777dd7cddfSDavid du Colombier
578a6a9e072SDavid du Colombier cv->r = nil;
579a6a9e072SDavid du Colombier cv->rgen = 0;
5807dd7cddfSDavid du Colombier cv->p->close(cv);
58180ee5cbfSDavid du Colombier cv->state = Idle;
58280ee5cbfSDavid du Colombier qunlock(cv);
5837dd7cddfSDavid du Colombier }
5847dd7cddfSDavid du Colombier
5857dd7cddfSDavid du Colombier static void
ipclose(Chan * c)5867dd7cddfSDavid du Colombier ipclose(Chan* c)
5877dd7cddfSDavid du Colombier {
5887dd7cddfSDavid du Colombier Fs *f;
5897dd7cddfSDavid du Colombier
5907dd7cddfSDavid du Colombier f = ipfs[c->dev];
5917dd7cddfSDavid du Colombier switch(TYPE(c->qid)) {
5927dd7cddfSDavid du Colombier default:
5937dd7cddfSDavid du Colombier break;
5947dd7cddfSDavid du Colombier case Qlog:
5957dd7cddfSDavid du Colombier if(c->flag & COPEN)
5967dd7cddfSDavid du Colombier netlogclose(f);
5977dd7cddfSDavid du Colombier break;
5987dd7cddfSDavid du Colombier case Qdata:
5997dd7cddfSDavid du Colombier case Qctl:
6007dd7cddfSDavid du Colombier case Qerr:
6017dd7cddfSDavid du Colombier if(c->flag & COPEN)
6027dd7cddfSDavid du Colombier closeconv(f->p[PROTO(c->qid)]->conv[CONV(c->qid)]);
603ef9eff0bSDavid du Colombier break;
604ef9eff0bSDavid du Colombier case Qsnoop:
605ef9eff0bSDavid du Colombier if(c->flag & COPEN)
606ef9eff0bSDavid du Colombier decref(&f->p[PROTO(c->qid)]->conv[CONV(c->qid)]->snoopers);
607ef9eff0bSDavid du Colombier break;
6087dd7cddfSDavid du Colombier }
6099a747e4fSDavid du Colombier free(((IPaux*)c->aux)->owner);
6109a747e4fSDavid du Colombier free(c->aux);
6117dd7cddfSDavid du Colombier }
6127dd7cddfSDavid du Colombier
6137dd7cddfSDavid du Colombier enum
6147dd7cddfSDavid du Colombier {
6157dd7cddfSDavid du Colombier Statelen= 32*1024,
6167dd7cddfSDavid du Colombier };
6177dd7cddfSDavid du Colombier
6187dd7cddfSDavid du Colombier static long
ipread(Chan * ch,void * a,long n,vlong off)6197dd7cddfSDavid du Colombier ipread(Chan *ch, void *a, long n, vlong off)
6207dd7cddfSDavid du Colombier {
6217dd7cddfSDavid du Colombier Conv *c;
6227dd7cddfSDavid du Colombier Proto *x;
6237dd7cddfSDavid du Colombier char *buf, *p;
6247dd7cddfSDavid du Colombier long rv;
6257dd7cddfSDavid du Colombier Fs *f;
6267dd7cddfSDavid du Colombier ulong offset = off;
6277dd7cddfSDavid du Colombier
6287dd7cddfSDavid du Colombier f = ipfs[ch->dev];
6297dd7cddfSDavid du Colombier
6307dd7cddfSDavid du Colombier p = a;
6317dd7cddfSDavid du Colombier switch(TYPE(ch->qid)) {
6327dd7cddfSDavid du Colombier default:
6337dd7cddfSDavid du Colombier error(Eperm);
6347dd7cddfSDavid du Colombier case Qtopdir:
6357dd7cddfSDavid du Colombier case Qprotodir:
6367dd7cddfSDavid du Colombier case Qconvdir:
6377dd7cddfSDavid du Colombier return devdirread(ch, a, n, 0, 0, ipgen);
6387dd7cddfSDavid du Colombier case Qarp:
6397dd7cddfSDavid du Colombier return arpread(f->arp, a, offset, n);
6407dd7cddfSDavid du Colombier case Qbootp:
6417dd7cddfSDavid du Colombier return bootpread(a, offset, n);
6427dd7cddfSDavid du Colombier case Qndb:
6437dd7cddfSDavid du Colombier return readstr(offset, a, n, f->ndb);
6447dd7cddfSDavid du Colombier case Qiproute:
6457dd7cddfSDavid du Colombier return routeread(f, a, offset, n);
6467dd7cddfSDavid du Colombier case Qipselftab:
6477dd7cddfSDavid du Colombier return ipselftabread(f, a, offset, n);
6487dd7cddfSDavid du Colombier case Qlog:
6497dd7cddfSDavid du Colombier return netlogread(f, a, offset, n);
6507dd7cddfSDavid du Colombier case Qctl:
6517dd7cddfSDavid du Colombier buf = smalloc(16);
652*57d98441SDavid du Colombier snprint(buf, 16, "%lud", CONV(ch->qid));
6537dd7cddfSDavid du Colombier rv = readstr(offset, p, n, buf);
6547dd7cddfSDavid du Colombier free(buf);
6557dd7cddfSDavid du Colombier return rv;
6567dd7cddfSDavid du Colombier case Qremote:
6577dd7cddfSDavid du Colombier buf = smalloc(Statelen);
6587dd7cddfSDavid du Colombier x = f->p[PROTO(ch->qid)];
6597dd7cddfSDavid du Colombier c = x->conv[CONV(ch->qid)];
6607dd7cddfSDavid du Colombier if(x->remote == nil) {
661*57d98441SDavid du Colombier snprint(buf, Statelen, "%I!%d\n", c->raddr, c->rport);
6627dd7cddfSDavid du Colombier } else {
6637dd7cddfSDavid du Colombier (*x->remote)(c, buf, Statelen-2);
6647dd7cddfSDavid du Colombier }
6657dd7cddfSDavid du Colombier rv = readstr(offset, p, n, buf);
6667dd7cddfSDavid du Colombier free(buf);
6677dd7cddfSDavid du Colombier return rv;
6687dd7cddfSDavid du Colombier case Qlocal:
6697dd7cddfSDavid du Colombier buf = smalloc(Statelen);
6707dd7cddfSDavid du Colombier x = f->p[PROTO(ch->qid)];
6717dd7cddfSDavid du Colombier c = x->conv[CONV(ch->qid)];
6727dd7cddfSDavid du Colombier if(x->local == nil) {
673*57d98441SDavid du Colombier snprint(buf, Statelen, "%I!%d\n", c->laddr, c->lport);
6747dd7cddfSDavid du Colombier } else {
6757dd7cddfSDavid du Colombier (*x->local)(c, buf, Statelen-2);
6767dd7cddfSDavid du Colombier }
6777dd7cddfSDavid du Colombier rv = readstr(offset, p, n, buf);
6787dd7cddfSDavid du Colombier free(buf);
6797dd7cddfSDavid du Colombier return rv;
6807dd7cddfSDavid du Colombier case Qstatus:
6817dd7cddfSDavid du Colombier buf = smalloc(Statelen);
6827dd7cddfSDavid du Colombier x = f->p[PROTO(ch->qid)];
6837dd7cddfSDavid du Colombier c = x->conv[CONV(ch->qid)];
6847dd7cddfSDavid du Colombier (*x->state)(c, buf, Statelen-2);
6857dd7cddfSDavid du Colombier rv = readstr(offset, p, n, buf);
6867dd7cddfSDavid du Colombier free(buf);
6877dd7cddfSDavid du Colombier return rv;
6887dd7cddfSDavid du Colombier case Qdata:
6897dd7cddfSDavid du Colombier c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
6907dd7cddfSDavid du Colombier return qread(c->rq, a, n);
6917dd7cddfSDavid du Colombier case Qerr:
6927dd7cddfSDavid du Colombier c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
6937dd7cddfSDavid du Colombier return qread(c->eq, a, n);
694ef9eff0bSDavid du Colombier case Qsnoop:
695ef9eff0bSDavid du Colombier c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
696ef9eff0bSDavid du Colombier return qread(c->sq, a, n);
6977dd7cddfSDavid du Colombier case Qstats:
6987dd7cddfSDavid du Colombier x = f->p[PROTO(ch->qid)];
6997dd7cddfSDavid du Colombier if(x->stats == nil)
7007dd7cddfSDavid du Colombier error("stats not implemented");
7017dd7cddfSDavid du Colombier buf = smalloc(Statelen);
7027dd7cddfSDavid du Colombier (*x->stats)(x, buf, Statelen);
7037dd7cddfSDavid du Colombier rv = readstr(offset, p, n, buf);
7047dd7cddfSDavid du Colombier free(buf);
7057dd7cddfSDavid du Colombier return rv;
7067dd7cddfSDavid du Colombier }
7077dd7cddfSDavid du Colombier }
7087dd7cddfSDavid du Colombier
7097dd7cddfSDavid du Colombier static Block*
ipbread(Chan * ch,long n,ulong offset)7107dd7cddfSDavid du Colombier ipbread(Chan* ch, long n, ulong offset)
7117dd7cddfSDavid du Colombier {
7127dd7cddfSDavid du Colombier Conv *c;
7137dd7cddfSDavid du Colombier Proto *x;
7147dd7cddfSDavid du Colombier Fs *f;
7157dd7cddfSDavid du Colombier
7167dd7cddfSDavid du Colombier switch(TYPE(ch->qid)){
7177dd7cddfSDavid du Colombier case Qdata:
7187dd7cddfSDavid du Colombier f = ipfs[ch->dev];
7197dd7cddfSDavid du Colombier x = f->p[PROTO(ch->qid)];
7207dd7cddfSDavid du Colombier c = x->conv[CONV(ch->qid)];
7217dd7cddfSDavid du Colombier return qbread(c->rq, n);
7227dd7cddfSDavid du Colombier default:
7237dd7cddfSDavid du Colombier return devbread(ch, n, offset);
7247dd7cddfSDavid du Colombier }
7257dd7cddfSDavid du Colombier }
7267dd7cddfSDavid du Colombier
7277dd7cddfSDavid du Colombier /*
7287dd7cddfSDavid du Colombier * set local address to be that of the ifc closest to remote address
7297dd7cddfSDavid du Colombier */
7307dd7cddfSDavid du Colombier static void
setladdr(Conv * c)7317dd7cddfSDavid du Colombier setladdr(Conv* c)
7327dd7cddfSDavid du Colombier {
7337dd7cddfSDavid du Colombier findlocalip(c->p->f, c->laddr, c->raddr);
7347dd7cddfSDavid du Colombier }
7357dd7cddfSDavid du Colombier
7367dd7cddfSDavid du Colombier /*
73780ee5cbfSDavid du Colombier * set a local port making sure the quad of raddr,rport,laddr,lport is unique
73880ee5cbfSDavid du Colombier */
739e288d156SDavid du Colombier char*
setluniqueport(Conv * c,int lport)74080ee5cbfSDavid du Colombier setluniqueport(Conv* c, int lport)
74180ee5cbfSDavid du Colombier {
74280ee5cbfSDavid du Colombier Proto *p;
74380ee5cbfSDavid du Colombier Conv *xp;
74480ee5cbfSDavid du Colombier int x;
74580ee5cbfSDavid du Colombier
74680ee5cbfSDavid du Colombier p = c->p;
74780ee5cbfSDavid du Colombier
74880ee5cbfSDavid du Colombier qlock(p);
74980ee5cbfSDavid du Colombier for(x = 0; x < p->nc; x++){
75080ee5cbfSDavid du Colombier xp = p->conv[x];
75180ee5cbfSDavid du Colombier if(xp == nil)
75280ee5cbfSDavid du Colombier break;
75380ee5cbfSDavid du Colombier if(xp == c)
75480ee5cbfSDavid du Colombier continue;
75580ee5cbfSDavid du Colombier if((xp->state == Connected || xp->state == Announced)
75680ee5cbfSDavid du Colombier && xp->lport == lport
75780ee5cbfSDavid du Colombier && xp->rport == c->rport
75880ee5cbfSDavid du Colombier && ipcmp(xp->raddr, c->raddr) == 0
75980ee5cbfSDavid du Colombier && ipcmp(xp->laddr, c->laddr) == 0){
76080ee5cbfSDavid du Colombier qunlock(p);
76180ee5cbfSDavid du Colombier return "address in use";
76280ee5cbfSDavid du Colombier }
76380ee5cbfSDavid du Colombier }
76480ee5cbfSDavid du Colombier c->lport = lport;
76580ee5cbfSDavid du Colombier qunlock(p);
76680ee5cbfSDavid du Colombier return nil;
76780ee5cbfSDavid du Colombier }
76880ee5cbfSDavid du Colombier
7692b5cb72cSDavid du Colombier /*
7702b5cb72cSDavid du Colombier * is lport in use by anyone?
7712b5cb72cSDavid du Colombier */
7722b5cb72cSDavid du Colombier static int
lportinuse(Proto * p,ushort lport)7732b5cb72cSDavid du Colombier lportinuse(Proto *p, ushort lport)
7742b5cb72cSDavid du Colombier {
7752b5cb72cSDavid du Colombier int x;
7762b5cb72cSDavid du Colombier
7772b5cb72cSDavid du Colombier for(x = 0; x < p->nc && p->conv[x]; x++)
7782b5cb72cSDavid du Colombier if(p->conv[x]->lport == lport)
7792b5cb72cSDavid du Colombier return 1;
7802b5cb72cSDavid du Colombier return 0;
7812b5cb72cSDavid du Colombier }
7823ff48bf5SDavid du Colombier
78380ee5cbfSDavid du Colombier /*
7847dd7cddfSDavid du Colombier * pick a local port and set it
7857dd7cddfSDavid du Colombier */
7862b5cb72cSDavid du Colombier char *
setlport(Conv * c)7877dd7cddfSDavid du Colombier setlport(Conv* c)
7887dd7cddfSDavid du Colombier {
7897dd7cddfSDavid du Colombier Proto *p;
7902b5cb72cSDavid du Colombier int i, port;
7917dd7cddfSDavid du Colombier
7927dd7cddfSDavid du Colombier p = c->p;
7937dd7cddfSDavid du Colombier qlock(p);
7947dd7cddfSDavid du Colombier if(c->restricted){
7952b5cb72cSDavid du Colombier /* Restricted ports cycle between 600 and 1024. */
7962b5cb72cSDavid du Colombier for(i=0; i<1024-600; i++){
7972b5cb72cSDavid du Colombier if(p->nextrport >= 1024 || p->nextrport < 600)
7982b5cb72cSDavid du Colombier p->nextrport = 600;
7992b5cb72cSDavid du Colombier port = p->nextrport++;
8002b5cb72cSDavid du Colombier if(!lportinuse(p, port))
8012b5cb72cSDavid du Colombier goto chosen;
8027dd7cddfSDavid du Colombier }
8032b5cb72cSDavid du Colombier }else{
8042b5cb72cSDavid du Colombier /*
8052b5cb72cSDavid du Colombier * Unrestricted ports are chosen randomly
8062b5cb72cSDavid du Colombier * between 2^15 and 2^16. There are at most
8072b5cb72cSDavid du Colombier * 4*Nchan = 4096 ports in use at any given time,
8082b5cb72cSDavid du Colombier * so even in the worst case, a random probe has a
8092b5cb72cSDavid du Colombier * 1 - 4096/2^15 = 87% chance of success.
8102b5cb72cSDavid du Colombier * If 64 successive probes fail, there is a bug somewhere
8112b5cb72cSDavid du Colombier * (or a once in 10^58 event has happened, but that's
8122b5cb72cSDavid du Colombier * less likely than a venti collision).
8132b5cb72cSDavid du Colombier */
8142b5cb72cSDavid du Colombier for(i=0; i<64; i++){
8152b5cb72cSDavid du Colombier port = (1<<15) + nrand(1<<15);
8162b5cb72cSDavid du Colombier if(!lportinuse(p, port))
8172b5cb72cSDavid du Colombier goto chosen;
8187dd7cddfSDavid du Colombier }
8197dd7cddfSDavid du Colombier }
8207dd7cddfSDavid du Colombier qunlock(p);
821c6569576SDavid du Colombier /*
822c6569576SDavid du Colombier * debugging: let's see if we ever get this.
823c6569576SDavid du Colombier * if we do (and we're a cpu server), we might as well restart
824c6569576SDavid du Colombier * since we're now unable to service new connections.
825c6569576SDavid du Colombier */
826c6569576SDavid du Colombier panic("setlport: out of ports");
8272b5cb72cSDavid du Colombier return "no ports available";
8282b5cb72cSDavid du Colombier
8292b5cb72cSDavid du Colombier chosen:
8302b5cb72cSDavid du Colombier c->lport = port;
8312b5cb72cSDavid du Colombier qunlock(p);
8322b5cb72cSDavid du Colombier return nil;
8337dd7cddfSDavid du Colombier }
8347dd7cddfSDavid du Colombier
8357dd7cddfSDavid du Colombier /*
8367dd7cddfSDavid du Colombier * set a local address and port from a string of the form
83780ee5cbfSDavid du Colombier * [address!]port[!r]
8387dd7cddfSDavid du Colombier */
839e288d156SDavid du Colombier char*
setladdrport(Conv * c,char * str,int announcing)8407dd7cddfSDavid du Colombier setladdrport(Conv* c, char* str, int announcing)
8417dd7cddfSDavid du Colombier {
8427dd7cddfSDavid du Colombier char *p;
84380ee5cbfSDavid du Colombier char *rv;
84480ee5cbfSDavid du Colombier ushort lport;
8451b0a7c7eSDavid du Colombier uchar addr[IPaddrlen];
84680ee5cbfSDavid du Colombier
8477dd7cddfSDavid du Colombier /*
8487dd7cddfSDavid du Colombier * ignore restricted part if it exists. it's
8497dd7cddfSDavid du Colombier * meaningless on local ports.
8507dd7cddfSDavid du Colombier */
8517dd7cddfSDavid du Colombier p = strchr(str, '!');
85280ee5cbfSDavid du Colombier if(p != nil){
8537dd7cddfSDavid du Colombier *p++ = 0;
85480ee5cbfSDavid du Colombier if(strcmp(p, "r") == 0)
85580ee5cbfSDavid du Colombier p = nil;
8567dd7cddfSDavid du Colombier }
8577dd7cddfSDavid du Colombier
8587dd7cddfSDavid du Colombier c->lport = 0;
85980ee5cbfSDavid du Colombier if(p == nil){
86080ee5cbfSDavid du Colombier if(announcing)
86180ee5cbfSDavid du Colombier ipmove(c->laddr, IPnoaddr);
86280ee5cbfSDavid du Colombier else
86380ee5cbfSDavid du Colombier setladdr(c);
86480ee5cbfSDavid du Colombier p = str;
86580ee5cbfSDavid du Colombier } else {
86680ee5cbfSDavid du Colombier if(strcmp(str, "*") == 0)
86780ee5cbfSDavid du Colombier ipmove(c->laddr, IPnoaddr);
8681b0a7c7eSDavid du Colombier else {
869ea58ad6fSDavid du Colombier if(parseip(addr, str) == -1)
870ea58ad6fSDavid du Colombier return Ebadip;
8711b0a7c7eSDavid du Colombier if(ipforme(c->p->f, addr))
8721b0a7c7eSDavid du Colombier ipmove(c->laddr, addr);
87380ee5cbfSDavid du Colombier else
8741b0a7c7eSDavid du Colombier return "not a local IP address";
8751b0a7c7eSDavid du Colombier }
8767dd7cddfSDavid du Colombier }
87780ee5cbfSDavid du Colombier
87880ee5cbfSDavid du Colombier /* one process can get all connections */
87980ee5cbfSDavid du Colombier if(announcing && strcmp(p, "*") == 0){
88080ee5cbfSDavid du Colombier if(!iseve())
88180ee5cbfSDavid du Colombier error(Eperm);
88280ee5cbfSDavid du Colombier return setluniqueport(c, 0);
88380ee5cbfSDavid du Colombier }
88480ee5cbfSDavid du Colombier
88580ee5cbfSDavid du Colombier lport = atoi(p);
88680ee5cbfSDavid du Colombier if(lport <= 0)
8872b5cb72cSDavid du Colombier rv = setlport(c);
88880ee5cbfSDavid du Colombier else
88980ee5cbfSDavid du Colombier rv = setluniqueport(c, lport);
89080ee5cbfSDavid du Colombier return rv;
8917dd7cddfSDavid du Colombier }
8927dd7cddfSDavid du Colombier
8937dd7cddfSDavid du Colombier static char*
setraddrport(Conv * c,char * str)8947dd7cddfSDavid du Colombier setraddrport(Conv* c, char* str)
8957dd7cddfSDavid du Colombier {
8967dd7cddfSDavid du Colombier char *p;
8977dd7cddfSDavid du Colombier
8987dd7cddfSDavid du Colombier p = strchr(str, '!');
8997dd7cddfSDavid du Colombier if(p == nil)
9007dd7cddfSDavid du Colombier return "malformed address";
9017dd7cddfSDavid du Colombier *p++ = 0;
902ea58ad6fSDavid du Colombier if (parseip(c->raddr, str) == -1)
903ea58ad6fSDavid du Colombier return Ebadip;
9047dd7cddfSDavid du Colombier c->rport = atoi(p);
9057dd7cddfSDavid du Colombier p = strchr(p, '!');
9067dd7cddfSDavid du Colombier if(p){
90780ee5cbfSDavid du Colombier if(strstr(p, "!r") != nil)
9087dd7cddfSDavid du Colombier c->restricted = 1;
9097dd7cddfSDavid du Colombier }
9107dd7cddfSDavid du Colombier return nil;
9117dd7cddfSDavid du Colombier }
9127dd7cddfSDavid du Colombier
9137dd7cddfSDavid du Colombier /*
9147dd7cddfSDavid du Colombier * called by protocol connect routine to set addresses
9157dd7cddfSDavid du Colombier */
9167dd7cddfSDavid du Colombier char*
Fsstdconnect(Conv * c,char * argv[],int argc)9177dd7cddfSDavid du Colombier Fsstdconnect(Conv *c, char *argv[], int argc)
9187dd7cddfSDavid du Colombier {
9197dd7cddfSDavid du Colombier char *p;
9207dd7cddfSDavid du Colombier
9217dd7cddfSDavid du Colombier switch(argc) {
9227dd7cddfSDavid du Colombier default:
9237dd7cddfSDavid du Colombier return "bad args to connect";
9247dd7cddfSDavid du Colombier case 2:
9257dd7cddfSDavid du Colombier p = setraddrport(c, argv[1]);
9267dd7cddfSDavid du Colombier if(p != nil)
9277dd7cddfSDavid du Colombier return p;
9287dd7cddfSDavid du Colombier setladdr(c);
9292b5cb72cSDavid du Colombier p = setlport(c);
9302b5cb72cSDavid du Colombier if (p != nil)
9312b5cb72cSDavid du Colombier return p;
9327dd7cddfSDavid du Colombier break;
9337dd7cddfSDavid du Colombier case 3:
9347dd7cddfSDavid du Colombier p = setraddrport(c, argv[1]);
9357dd7cddfSDavid du Colombier if(p != nil)
9367dd7cddfSDavid du Colombier return p;
9373ff48bf5SDavid du Colombier p = setladdrport(c, argv[2], 0);
9383ff48bf5SDavid du Colombier if(p != nil)
9393ff48bf5SDavid du Colombier return p;
9407dd7cddfSDavid du Colombier }
9413ff48bf5SDavid du Colombier
9423ff48bf5SDavid du Colombier if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
9433ff48bf5SDavid du Colombier memcmp(c->laddr, v4prefix, IPv4off) == 0)
9443ff48bf5SDavid du Colombier || ipcmp(c->raddr, IPnoaddr) == 0)
9453ff48bf5SDavid du Colombier c->ipversion = V4;
9463ff48bf5SDavid du Colombier else
9473ff48bf5SDavid du Colombier c->ipversion = V6;
9483ff48bf5SDavid du Colombier
9497dd7cddfSDavid du Colombier return nil;
9507dd7cddfSDavid du Colombier }
9517dd7cddfSDavid du Colombier /*
9527dd7cddfSDavid du Colombier * initiate connection and sleep till its set up
9537dd7cddfSDavid du Colombier */
9547dd7cddfSDavid du Colombier static int
connected(void * a)9557dd7cddfSDavid du Colombier connected(void* a)
9567dd7cddfSDavid du Colombier {
9577dd7cddfSDavid du Colombier return ((Conv*)a)->state == Connected;
9587dd7cddfSDavid du Colombier }
9597dd7cddfSDavid du Colombier static void
connectctlmsg(Proto * x,Conv * c,Cmdbuf * cb)9607dd7cddfSDavid du Colombier connectctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
9617dd7cddfSDavid du Colombier {
9627dd7cddfSDavid du Colombier char *p;
9637dd7cddfSDavid du Colombier
96480ee5cbfSDavid du Colombier if(c->state != 0)
96580ee5cbfSDavid du Colombier error(Econinuse);
9667dd7cddfSDavid du Colombier c->state = Connecting;
9677dd7cddfSDavid du Colombier c->cerr[0] = '\0';
9687dd7cddfSDavid du Colombier if(x->connect == nil)
9697dd7cddfSDavid du Colombier error("connect not supported");
9707dd7cddfSDavid du Colombier p = x->connect(c, cb->f, cb->nf);
9717dd7cddfSDavid du Colombier if(p != nil)
9727dd7cddfSDavid du Colombier error(p);
97380ee5cbfSDavid du Colombier
97480ee5cbfSDavid du Colombier qunlock(c);
97580ee5cbfSDavid du Colombier if(waserror()){
97680ee5cbfSDavid du Colombier qlock(c);
97780ee5cbfSDavid du Colombier nexterror();
97880ee5cbfSDavid du Colombier }
9797dd7cddfSDavid du Colombier sleep(&c->cr, connected, c);
98080ee5cbfSDavid du Colombier qlock(c);
98180ee5cbfSDavid du Colombier poperror();
98280ee5cbfSDavid du Colombier
9837dd7cddfSDavid du Colombier if(c->cerr[0] != '\0')
9847dd7cddfSDavid du Colombier error(c->cerr);
9857dd7cddfSDavid du Colombier }
9867dd7cddfSDavid du Colombier
9877dd7cddfSDavid du Colombier /*
9887dd7cddfSDavid du Colombier * called by protocol announce routine to set addresses
9897dd7cddfSDavid du Colombier */
9907dd7cddfSDavid du Colombier char*
Fsstdannounce(Conv * c,char * argv[],int argc)9917dd7cddfSDavid du Colombier Fsstdannounce(Conv* c, char* argv[], int argc)
9927dd7cddfSDavid du Colombier {
99380ee5cbfSDavid du Colombier memset(c->raddr, 0, sizeof(c->raddr));
99480ee5cbfSDavid du Colombier c->rport = 0;
9957dd7cddfSDavid du Colombier switch(argc){
9967dd7cddfSDavid du Colombier default:
9979acf0835SDavid du Colombier break;
9987dd7cddfSDavid du Colombier case 2:
99980ee5cbfSDavid du Colombier return setladdrport(c, argv[1], 1);
10007dd7cddfSDavid du Colombier }
10019acf0835SDavid du Colombier return "bad args to announce";
10027dd7cddfSDavid du Colombier }
10037dd7cddfSDavid du Colombier
10047dd7cddfSDavid du Colombier /*
10057dd7cddfSDavid du Colombier * initiate announcement and sleep till its set up
10067dd7cddfSDavid du Colombier */
10077dd7cddfSDavid du Colombier static int
announced(void * a)10087dd7cddfSDavid du Colombier announced(void* a)
10097dd7cddfSDavid du Colombier {
10107dd7cddfSDavid du Colombier return ((Conv*)a)->state == Announced;
10117dd7cddfSDavid du Colombier }
10127dd7cddfSDavid du Colombier static void
announcectlmsg(Proto * x,Conv * c,Cmdbuf * cb)10137dd7cddfSDavid du Colombier announcectlmsg(Proto *x, Conv *c, Cmdbuf *cb)
10147dd7cddfSDavid du Colombier {
10157dd7cddfSDavid du Colombier char *p;
10167dd7cddfSDavid du Colombier
101780ee5cbfSDavid du Colombier if(c->state != 0)
101880ee5cbfSDavid du Colombier error(Econinuse);
10197dd7cddfSDavid du Colombier c->state = Announcing;
10207dd7cddfSDavid du Colombier c->cerr[0] = '\0';
10217dd7cddfSDavid du Colombier if(x->announce == nil)
10227dd7cddfSDavid du Colombier error("announce not supported");
10237dd7cddfSDavid du Colombier p = x->announce(c, cb->f, cb->nf);
10247dd7cddfSDavid du Colombier if(p != nil)
10257dd7cddfSDavid du Colombier error(p);
102680ee5cbfSDavid du Colombier
102780ee5cbfSDavid du Colombier qunlock(c);
102880ee5cbfSDavid du Colombier if(waserror()){
102980ee5cbfSDavid du Colombier qlock(c);
103080ee5cbfSDavid du Colombier nexterror();
103180ee5cbfSDavid du Colombier }
10327dd7cddfSDavid du Colombier sleep(&c->cr, announced, c);
103380ee5cbfSDavid du Colombier qlock(c);
103480ee5cbfSDavid du Colombier poperror();
103580ee5cbfSDavid du Colombier
10367dd7cddfSDavid du Colombier if(c->cerr[0] != '\0')
10377dd7cddfSDavid du Colombier error(c->cerr);
10387dd7cddfSDavid du Colombier }
10397dd7cddfSDavid du Colombier
10407dd7cddfSDavid du Colombier /*
104180ee5cbfSDavid du Colombier * called by protocol bind routine to set addresses
10427dd7cddfSDavid du Colombier */
10437dd7cddfSDavid du Colombier char*
Fsstdbind(Conv * c,char * argv[],int argc)10447dd7cddfSDavid du Colombier Fsstdbind(Conv* c, char* argv[], int argc)
10457dd7cddfSDavid du Colombier {
10467dd7cddfSDavid du Colombier switch(argc){
10477dd7cddfSDavid du Colombier default:
10489acf0835SDavid du Colombier break;
10497dd7cddfSDavid du Colombier case 2:
105080ee5cbfSDavid du Colombier return setladdrport(c, argv[1], 0);
10517dd7cddfSDavid du Colombier }
10529acf0835SDavid du Colombier return "bad args to bind";
10537dd7cddfSDavid du Colombier }
10547dd7cddfSDavid du Colombier
10557dd7cddfSDavid du Colombier static void
bindctlmsg(Proto * x,Conv * c,Cmdbuf * cb)10567dd7cddfSDavid du Colombier bindctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
10577dd7cddfSDavid du Colombier {
10587dd7cddfSDavid du Colombier char *p;
10597dd7cddfSDavid du Colombier
10607dd7cddfSDavid du Colombier if(x->bind == nil)
10617dd7cddfSDavid du Colombier p = Fsstdbind(c, cb->f, cb->nf);
10627dd7cddfSDavid du Colombier else
10637dd7cddfSDavid du Colombier p = x->bind(c, cb->f, cb->nf);
10647dd7cddfSDavid du Colombier if(p != nil)
10657dd7cddfSDavid du Colombier error(p);
10667dd7cddfSDavid du Colombier }
10677dd7cddfSDavid du Colombier
10687dd7cddfSDavid du Colombier static void
tosctlmsg(Conv * c,Cmdbuf * cb)10697dd7cddfSDavid du Colombier tosctlmsg(Conv *c, Cmdbuf *cb)
10707dd7cddfSDavid du Colombier {
10717dd7cddfSDavid du Colombier if(cb->nf < 2)
10727dd7cddfSDavid du Colombier c->tos = 0;
10737dd7cddfSDavid du Colombier else
10747dd7cddfSDavid du Colombier c->tos = atoi(cb->f[1]);
10757dd7cddfSDavid du Colombier }
10767dd7cddfSDavid du Colombier
10777dd7cddfSDavid du Colombier static void
ttlctlmsg(Conv * c,Cmdbuf * cb)10787dd7cddfSDavid du Colombier ttlctlmsg(Conv *c, Cmdbuf *cb)
10797dd7cddfSDavid du Colombier {
10807dd7cddfSDavid du Colombier if(cb->nf < 2)
10817dd7cddfSDavid du Colombier c->ttl = MAXTTL;
10827dd7cddfSDavid du Colombier else
10837dd7cddfSDavid du Colombier c->ttl = atoi(cb->f[1]);
10847dd7cddfSDavid du Colombier }
10857dd7cddfSDavid du Colombier
10867dd7cddfSDavid du Colombier static long
ipwrite(Chan * ch,void * v,long n,vlong off)10877dd7cddfSDavid du Colombier ipwrite(Chan* ch, void *v, long n, vlong off)
10887dd7cddfSDavid du Colombier {
10897dd7cddfSDavid du Colombier Conv *c;
10907dd7cddfSDavid du Colombier Proto *x;
10917dd7cddfSDavid du Colombier char *p;
10927dd7cddfSDavid du Colombier Cmdbuf *cb;
10937dd7cddfSDavid du Colombier uchar ia[IPaddrlen], ma[IPaddrlen];
10947dd7cddfSDavid du Colombier Fs *f;
10957dd7cddfSDavid du Colombier char *a;
10967dd7cddfSDavid du Colombier ulong offset = off;
10977dd7cddfSDavid du Colombier
10987dd7cddfSDavid du Colombier a = v;
10997dd7cddfSDavid du Colombier f = ipfs[ch->dev];
11007dd7cddfSDavid du Colombier
11017dd7cddfSDavid du Colombier switch(TYPE(ch->qid)){
11027dd7cddfSDavid du Colombier default:
11037dd7cddfSDavid du Colombier error(Eperm);
11047dd7cddfSDavid du Colombier case Qdata:
11057dd7cddfSDavid du Colombier x = f->p[PROTO(ch->qid)];
11067dd7cddfSDavid du Colombier c = x->conv[CONV(ch->qid)];
11077dd7cddfSDavid du Colombier
11087dd7cddfSDavid du Colombier if(c->wq == nil)
11097dd7cddfSDavid du Colombier error(Eperm);
11107dd7cddfSDavid du Colombier
11117dd7cddfSDavid du Colombier qwrite(c->wq, a, n);
11127dd7cddfSDavid du Colombier break;
11137dd7cddfSDavid du Colombier case Qarp:
11147dd7cddfSDavid du Colombier return arpwrite(f, a, n);
11157dd7cddfSDavid du Colombier case Qiproute:
11167dd7cddfSDavid du Colombier return routewrite(f, ch, a, n);
11177dd7cddfSDavid du Colombier case Qlog:
11189a747e4fSDavid du Colombier netlogctl(f, a, n);
11197dd7cddfSDavid du Colombier return n;
11207dd7cddfSDavid du Colombier case Qndb:
11217dd7cddfSDavid du Colombier return ndbwrite(f, a, offset, n);
11227dd7cddfSDavid du Colombier break;
11237dd7cddfSDavid du Colombier case Qctl:
11247dd7cddfSDavid du Colombier x = f->p[PROTO(ch->qid)];
11257dd7cddfSDavid du Colombier c = x->conv[CONV(ch->qid)];
11267dd7cddfSDavid du Colombier cb = parsecmd(a, n);
11277dd7cddfSDavid du Colombier
112880ee5cbfSDavid du Colombier qlock(c);
11297dd7cddfSDavid du Colombier if(waserror()) {
113080ee5cbfSDavid du Colombier qunlock(c);
11317dd7cddfSDavid du Colombier free(cb);
11327dd7cddfSDavid du Colombier nexterror();
11337dd7cddfSDavid du Colombier }
11343ff48bf5SDavid du Colombier if(cb->nf < 1)
11353ff48bf5SDavid du Colombier error("short control request");
11363ff48bf5SDavid du Colombier if(strcmp(cb->f[0], "connect") == 0)
11377dd7cddfSDavid du Colombier connectctlmsg(x, c, cb);
11383ff48bf5SDavid du Colombier else if(strcmp(cb->f[0], "announce") == 0)
11397dd7cddfSDavid du Colombier announcectlmsg(x, c, cb);
11403ff48bf5SDavid du Colombier else if(strcmp(cb->f[0], "bind") == 0)
11417dd7cddfSDavid du Colombier bindctlmsg(x, c, cb);
11423ff48bf5SDavid du Colombier else if(strcmp(cb->f[0], "ttl") == 0)
11437dd7cddfSDavid du Colombier ttlctlmsg(c, cb);
11443ff48bf5SDavid du Colombier else if(strcmp(cb->f[0], "tos") == 0)
11457dd7cddfSDavid du Colombier tosctlmsg(c, cb);
11463ff48bf5SDavid du Colombier else if(strcmp(cb->f[0], "ignoreadvice") == 0)
11473ff48bf5SDavid du Colombier c->ignoreadvice = 1;
11483ff48bf5SDavid du Colombier else if(strcmp(cb->f[0], "addmulti") == 0){
11493ff48bf5SDavid du Colombier if(cb->nf < 2)
11503ff48bf5SDavid du Colombier error("addmulti needs interface address");
11517dd7cddfSDavid du Colombier if(cb->nf == 2){
11527dd7cddfSDavid du Colombier if(!ipismulticast(c->raddr))
11537dd7cddfSDavid du Colombier error("addmulti for a non multicast address");
1154ea58ad6fSDavid du Colombier if (parseip(ia, cb->f[1]) == -1)
1155ea58ad6fSDavid du Colombier error(Ebadip);
11567dd7cddfSDavid du Colombier ipifcaddmulti(c, c->raddr, ia);
11577dd7cddfSDavid du Colombier } else {
1158ea58ad6fSDavid du Colombier if (parseip(ia, cb->f[1]) == -1 ||
1159ea58ad6fSDavid du Colombier parseip(ma, cb->f[2]) == -1)
1160ea58ad6fSDavid du Colombier error(Ebadip);
11617dd7cddfSDavid du Colombier if(!ipismulticast(ma))
11627dd7cddfSDavid du Colombier error("addmulti for a non multicast address");
11637dd7cddfSDavid du Colombier ipifcaddmulti(c, ma, ia);
11647dd7cddfSDavid du Colombier }
11653ff48bf5SDavid du Colombier } else if(strcmp(cb->f[0], "remmulti") == 0){
11667dd7cddfSDavid du Colombier if(cb->nf < 2)
11677dd7cddfSDavid du Colombier error("remmulti needs interface address");
11687dd7cddfSDavid du Colombier if(!ipismulticast(c->raddr))
11697dd7cddfSDavid du Colombier error("remmulti for a non multicast address");
1170ea58ad6fSDavid du Colombier if (parseip(ia, cb->f[1]) == -1)
1171ea58ad6fSDavid du Colombier error(Ebadip);
11727dd7cddfSDavid du Colombier ipifcremmulti(c, c->raddr, ia);
11732b5cb72cSDavid du Colombier } else if(strcmp(cb->f[0], "maxfragsize") == 0){
11742b5cb72cSDavid du Colombier if(cb->nf < 2)
11752b5cb72cSDavid du Colombier error("maxfragsize needs size");
11762b5cb72cSDavid du Colombier
11772b5cb72cSDavid du Colombier c->maxfragsize = (int)strtol(cb->f[1], nil, 0);
11782b5cb72cSDavid du Colombier
11793ff48bf5SDavid du Colombier } else if(x->ctl != nil) {
11807dd7cddfSDavid du Colombier p = x->ctl(c, cb->f, cb->nf);
11817dd7cddfSDavid du Colombier if(p != nil)
11827dd7cddfSDavid du Colombier error(p);
11833ff48bf5SDavid du Colombier } else
11843ff48bf5SDavid du Colombier error("unknown control request");
118580ee5cbfSDavid du Colombier qunlock(c);
11867dd7cddfSDavid du Colombier free(cb);
11877dd7cddfSDavid du Colombier poperror();
11887dd7cddfSDavid du Colombier }
11897dd7cddfSDavid du Colombier return n;
11907dd7cddfSDavid du Colombier }
11917dd7cddfSDavid du Colombier
11927dd7cddfSDavid du Colombier static long
ipbwrite(Chan * ch,Block * bp,ulong offset)11937dd7cddfSDavid du Colombier ipbwrite(Chan* ch, Block* bp, ulong offset)
11947dd7cddfSDavid du Colombier {
11957dd7cddfSDavid du Colombier Conv *c;
11967dd7cddfSDavid du Colombier Proto *x;
11977dd7cddfSDavid du Colombier Fs *f;
11987dd7cddfSDavid du Colombier int n;
11997dd7cddfSDavid du Colombier
12007dd7cddfSDavid du Colombier switch(TYPE(ch->qid)){
12017dd7cddfSDavid du Colombier case Qdata:
12027dd7cddfSDavid du Colombier f = ipfs[ch->dev];
12037dd7cddfSDavid du Colombier x = f->p[PROTO(ch->qid)];
12047dd7cddfSDavid du Colombier c = x->conv[CONV(ch->qid)];
12057dd7cddfSDavid du Colombier
12067dd7cddfSDavid du Colombier if(c->wq == nil)
12077dd7cddfSDavid du Colombier error(Eperm);
12087dd7cddfSDavid du Colombier
12097dd7cddfSDavid du Colombier if(bp->next)
12107dd7cddfSDavid du Colombier bp = concatblock(bp);
12117dd7cddfSDavid du Colombier n = BLEN(bp);
12127dd7cddfSDavid du Colombier qbwrite(c->wq, bp);
12137dd7cddfSDavid du Colombier return n;
12147dd7cddfSDavid du Colombier default:
12157dd7cddfSDavid du Colombier return devbwrite(ch, bp, offset);
12167dd7cddfSDavid du Colombier }
12177dd7cddfSDavid du Colombier }
12187dd7cddfSDavid du Colombier
12197dd7cddfSDavid du Colombier Dev ipdevtab = {
12207dd7cddfSDavid du Colombier 'I',
12217dd7cddfSDavid du Colombier "ip",
12227dd7cddfSDavid du Colombier
12237dd7cddfSDavid du Colombier ipreset,
12249a747e4fSDavid du Colombier devinit,
12259a747e4fSDavid du Colombier devshutdown,
12267dd7cddfSDavid du Colombier ipattach,
12277dd7cddfSDavid du Colombier ipwalk,
12287dd7cddfSDavid du Colombier ipstat,
12297dd7cddfSDavid du Colombier ipopen,
12303ff48bf5SDavid du Colombier ipcreate,
12317dd7cddfSDavid du Colombier ipclose,
12327dd7cddfSDavid du Colombier ipread,
12337dd7cddfSDavid du Colombier ipbread,
12347dd7cddfSDavid du Colombier ipwrite,
12357dd7cddfSDavid du Colombier ipbwrite,
12363ff48bf5SDavid du Colombier ipremove,
12377dd7cddfSDavid du Colombier ipwstat,
12387dd7cddfSDavid du Colombier };
12397dd7cddfSDavid du Colombier
12407dd7cddfSDavid du Colombier int
Fsproto(Fs * f,Proto * p)12417dd7cddfSDavid du Colombier Fsproto(Fs *f, Proto *p)
12427dd7cddfSDavid du Colombier {
12437dd7cddfSDavid du Colombier if(f->np >= Maxproto)
12447dd7cddfSDavid du Colombier return -1;
12457dd7cddfSDavid du Colombier
12467dd7cddfSDavid du Colombier p->f = f;
12477dd7cddfSDavid du Colombier
12487dd7cddfSDavid du Colombier if(p->ipproto > 0){
12497dd7cddfSDavid du Colombier if(f->t2p[p->ipproto] != nil)
12507dd7cddfSDavid du Colombier return -1;
12517dd7cddfSDavid du Colombier f->t2p[p->ipproto] = p;
12527dd7cddfSDavid du Colombier }
12537dd7cddfSDavid du Colombier
12549a747e4fSDavid du Colombier p->qid.type = QTDIR;
12559a747e4fSDavid du Colombier p->qid.path = QID(f->np, 0, Qprotodir);
12567dd7cddfSDavid du Colombier p->conv = malloc(sizeof(Conv*)*(p->nc+1));
12577dd7cddfSDavid du Colombier if(p->conv == nil)
12587dd7cddfSDavid du Colombier panic("Fsproto");
12597dd7cddfSDavid du Colombier
12607dd7cddfSDavid du Colombier p->x = f->np;
12617dd7cddfSDavid du Colombier p->nextrport = 600;
12627dd7cddfSDavid du Colombier f->p[f->np++] = p;
12637dd7cddfSDavid du Colombier
12647dd7cddfSDavid du Colombier return 0;
12657dd7cddfSDavid du Colombier }
12667dd7cddfSDavid du Colombier
12677dd7cddfSDavid du Colombier /*
12687dd7cddfSDavid du Colombier * return true if this protocol is
12697dd7cddfSDavid du Colombier * built in
12707dd7cddfSDavid du Colombier */
12717dd7cddfSDavid du Colombier int
Fsbuiltinproto(Fs * f,uchar proto)12727dd7cddfSDavid du Colombier Fsbuiltinproto(Fs* f, uchar proto)
12737dd7cddfSDavid du Colombier {
12747dd7cddfSDavid du Colombier return f->t2p[proto] != nil;
12757dd7cddfSDavid du Colombier }
12767dd7cddfSDavid du Colombier
12777dd7cddfSDavid du Colombier /*
12787dd7cddfSDavid du Colombier * called with protocol locked
12797dd7cddfSDavid du Colombier */
12807dd7cddfSDavid du Colombier Conv*
Fsprotoclone(Proto * p,char * user)12817dd7cddfSDavid du Colombier Fsprotoclone(Proto *p, char *user)
12827dd7cddfSDavid du Colombier {
12837dd7cddfSDavid du Colombier Conv *c, **pp, **ep;
12847dd7cddfSDavid du Colombier
12857dd7cddfSDavid du Colombier retry:
12867dd7cddfSDavid du Colombier c = nil;
12877dd7cddfSDavid du Colombier ep = &p->conv[p->nc];
12887dd7cddfSDavid du Colombier for(pp = p->conv; pp < ep; pp++) {
12897dd7cddfSDavid du Colombier c = *pp;
12907dd7cddfSDavid du Colombier if(c == nil){
12917dd7cddfSDavid du Colombier c = malloc(sizeof(Conv));
12927dd7cddfSDavid du Colombier if(c == nil)
12937dd7cddfSDavid du Colombier error(Enomem);
12947dd7cddfSDavid du Colombier qlock(c);
12957dd7cddfSDavid du Colombier c->p = p;
12967dd7cddfSDavid du Colombier c->x = pp - p->conv;
12977dd7cddfSDavid du Colombier if(p->ptclsize != 0){
12987dd7cddfSDavid du Colombier c->ptcl = malloc(p->ptclsize);
12997dd7cddfSDavid du Colombier if(c->ptcl == nil) {
13007dd7cddfSDavid du Colombier free(c);
13017dd7cddfSDavid du Colombier error(Enomem);
13027dd7cddfSDavid du Colombier }
13037dd7cddfSDavid du Colombier }
13047dd7cddfSDavid du Colombier *pp = c;
13057dd7cddfSDavid du Colombier p->ac++;
13063ff48bf5SDavid du Colombier c->eq = qopen(1024, Qmsg, 0, 0);
13077dd7cddfSDavid du Colombier (*p->create)(c);
13087dd7cddfSDavid du Colombier break;
13097dd7cddfSDavid du Colombier }
13107dd7cddfSDavid du Colombier if(canqlock(c)){
13117dd7cddfSDavid du Colombier /*
13127dd7cddfSDavid du Colombier * make sure both processes and protocol
13137dd7cddfSDavid du Colombier * are done with this Conv
13147dd7cddfSDavid du Colombier */
13157dd7cddfSDavid du Colombier if(c->inuse == 0 && (p->inuse == nil || (*p->inuse)(c) == 0))
13167dd7cddfSDavid du Colombier break;
13177dd7cddfSDavid du Colombier
13187dd7cddfSDavid du Colombier qunlock(c);
13197dd7cddfSDavid du Colombier }
13207dd7cddfSDavid du Colombier }
13217dd7cddfSDavid du Colombier if(pp >= ep) {
1322c6569576SDavid du Colombier if(p->gc)
1323c6569576SDavid du Colombier print("Fsprotoclone: garbage collecting Convs\n");
13247dd7cddfSDavid du Colombier if(p->gc != nil && (*p->gc)(p))
13257dd7cddfSDavid du Colombier goto retry;
1326c6569576SDavid du Colombier /* debugging: do we ever get here? */
1327ac10c8dbSDavid du Colombier if (cpuserver)
1328c6569576SDavid du Colombier panic("Fsprotoclone: all conversations in use");
13297dd7cddfSDavid du Colombier return nil;
13307dd7cddfSDavid du Colombier }
13317dd7cddfSDavid du Colombier
13327dd7cddfSDavid du Colombier c->inuse = 1;
13339a747e4fSDavid du Colombier kstrdup(&c->owner, user);
13347dd7cddfSDavid du Colombier c->perm = 0660;
133580ee5cbfSDavid du Colombier c->state = Idle;
13367dd7cddfSDavid du Colombier ipmove(c->laddr, IPnoaddr);
13377dd7cddfSDavid du Colombier ipmove(c->raddr, IPnoaddr);
1338a6a9e072SDavid du Colombier c->r = nil;
1339a6a9e072SDavid du Colombier c->rgen = 0;
13407dd7cddfSDavid du Colombier c->lport = 0;
13417dd7cddfSDavid du Colombier c->rport = 0;
13427dd7cddfSDavid du Colombier c->restricted = 0;
13432b5cb72cSDavid du Colombier c->maxfragsize = 0;
13447dd7cddfSDavid du Colombier c->ttl = MAXTTL;
13457dd7cddfSDavid du Colombier qreopen(c->rq);
13467dd7cddfSDavid du Colombier qreopen(c->wq);
13477dd7cddfSDavid du Colombier qreopen(c->eq);
13487dd7cddfSDavid du Colombier
13497dd7cddfSDavid du Colombier qunlock(c);
13507dd7cddfSDavid du Colombier return c;
13517dd7cddfSDavid du Colombier }
13527dd7cddfSDavid du Colombier
13537dd7cddfSDavid du Colombier int
Fsconnected(Conv * c,char * msg)13547dd7cddfSDavid du Colombier Fsconnected(Conv* c, char* msg)
13557dd7cddfSDavid du Colombier {
13567dd7cddfSDavid du Colombier if(msg != nil && *msg != '\0')
13579a747e4fSDavid du Colombier strncpy(c->cerr, msg, ERRMAX-1);
13587dd7cddfSDavid du Colombier
13597dd7cddfSDavid du Colombier switch(c->state){
13607dd7cddfSDavid du Colombier
13617dd7cddfSDavid du Colombier case Announcing:
13627dd7cddfSDavid du Colombier c->state = Announced;
13637dd7cddfSDavid du Colombier break;
13647dd7cddfSDavid du Colombier
13657dd7cddfSDavid du Colombier case Connecting:
13667dd7cddfSDavid du Colombier c->state = Connected;
13677dd7cddfSDavid du Colombier break;
13687dd7cddfSDavid du Colombier }
13697dd7cddfSDavid du Colombier
13707dd7cddfSDavid du Colombier wakeup(&c->cr);
13717dd7cddfSDavid du Colombier return 0;
13727dd7cddfSDavid du Colombier }
13737dd7cddfSDavid du Colombier
13747dd7cddfSDavid du Colombier Proto*
Fsrcvpcol(Fs * f,uchar proto)13757dd7cddfSDavid du Colombier Fsrcvpcol(Fs* f, uchar proto)
13767dd7cddfSDavid du Colombier {
13777dd7cddfSDavid du Colombier if(f->ipmux)
13787dd7cddfSDavid du Colombier return f->ipmux;
13797dd7cddfSDavid du Colombier else
13807dd7cddfSDavid du Colombier return f->t2p[proto];
13817dd7cddfSDavid du Colombier }
13827dd7cddfSDavid du Colombier
13837dd7cddfSDavid du Colombier Proto*
Fsrcvpcolx(Fs * f,uchar proto)13847dd7cddfSDavid du Colombier Fsrcvpcolx(Fs *f, uchar proto)
13857dd7cddfSDavid du Colombier {
13867dd7cddfSDavid du Colombier return f->t2p[proto];
13877dd7cddfSDavid du Colombier }
13887dd7cddfSDavid du Colombier
13897dd7cddfSDavid du Colombier /*
13907dd7cddfSDavid du Colombier * called with protocol locked
13917dd7cddfSDavid du Colombier */
13927dd7cddfSDavid du Colombier Conv*
Fsnewcall(Conv * c,uchar * raddr,ushort rport,uchar * laddr,ushort lport,uchar version)13933ff48bf5SDavid du Colombier Fsnewcall(Conv *c, uchar *raddr, ushort rport, uchar *laddr, ushort lport, uchar version)
13947dd7cddfSDavid du Colombier {
13957dd7cddfSDavid du Colombier Conv *nc;
13967dd7cddfSDavid du Colombier Conv **l;
13977dd7cddfSDavid du Colombier int i;
13987dd7cddfSDavid du Colombier
13997dd7cddfSDavid du Colombier qlock(c);
14007dd7cddfSDavid du Colombier i = 0;
14017dd7cddfSDavid du Colombier for(l = &c->incall; *l; l = &(*l)->next)
14027dd7cddfSDavid du Colombier i++;
14037dd7cddfSDavid du Colombier if(i >= Maxincall) {
1404c6569576SDavid du Colombier static int beenhere;
1405c6569576SDavid du Colombier
14067dd7cddfSDavid du Colombier qunlock(c);
1407c6569576SDavid du Colombier if (!beenhere) {
1408c6569576SDavid du Colombier beenhere = 1;
1409c6569576SDavid du Colombier print("Fsnewcall: incall queue full (%d) on port %d\n",
1410c6569576SDavid du Colombier i, c->lport);
1411c6569576SDavid du Colombier }
14127dd7cddfSDavid du Colombier return nil;
14137dd7cddfSDavid du Colombier }
14147dd7cddfSDavid du Colombier
14157dd7cddfSDavid du Colombier /* find a free conversation */
14167dd7cddfSDavid du Colombier nc = Fsprotoclone(c->p, network);
14177dd7cddfSDavid du Colombier if(nc == nil) {
14187dd7cddfSDavid du Colombier qunlock(c);
14197dd7cddfSDavid du Colombier return nil;
14207dd7cddfSDavid du Colombier }
14217dd7cddfSDavid du Colombier ipmove(nc->raddr, raddr);
14227dd7cddfSDavid du Colombier nc->rport = rport;
14237dd7cddfSDavid du Colombier ipmove(nc->laddr, laddr);
14247dd7cddfSDavid du Colombier nc->lport = lport;
14257dd7cddfSDavid du Colombier nc->next = nil;
14267dd7cddfSDavid du Colombier *l = nc;
142780ee5cbfSDavid du Colombier nc->state = Connected;
14283ff48bf5SDavid du Colombier nc->ipversion = version;
14293ff48bf5SDavid du Colombier
14307dd7cddfSDavid du Colombier qunlock(c);
14317dd7cddfSDavid du Colombier
14327dd7cddfSDavid du Colombier wakeup(&c->listenr);
14337dd7cddfSDavid du Colombier
14347dd7cddfSDavid du Colombier return nc;
14357dd7cddfSDavid du Colombier }
14367dd7cddfSDavid du Colombier
14377dd7cddfSDavid du Colombier long
ndbwrite(Fs * f,char * a,ulong off,int n)14387dd7cddfSDavid du Colombier ndbwrite(Fs *f, char *a, ulong off, int n)
14397dd7cddfSDavid du Colombier {
14407dd7cddfSDavid du Colombier if(off > strlen(f->ndb))
14417dd7cddfSDavid du Colombier error(Eio);
14427dd7cddfSDavid du Colombier if(off+n >= sizeof(f->ndb))
14437dd7cddfSDavid du Colombier error(Eio);
14447dd7cddfSDavid du Colombier memmove(f->ndb+off, a, n);
14457dd7cddfSDavid du Colombier f->ndb[off+n] = 0;
14469a747e4fSDavid du Colombier f->ndbvers++;
14479a747e4fSDavid du Colombier f->ndbmtime = seconds();
14487dd7cddfSDavid du Colombier return n;
14497dd7cddfSDavid du Colombier }
14509a747e4fSDavid du Colombier
14519a747e4fSDavid du Colombier ulong
scalednconv(void)14529a747e4fSDavid du Colombier scalednconv(void)
14539a747e4fSDavid du Colombier {
14549a747e4fSDavid du Colombier if(cpuserver && conf.npage*BY2PG >= 128*MB)
14559a747e4fSDavid du Colombier return Nchans*4;
14569a747e4fSDavid du Colombier return Nchans;
14579a747e4fSDavid du Colombier }
1458