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 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 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 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 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); 1869a747e4fSDavid du Colombier sprint(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); 2099a747e4fSDavid du Colombier sprint(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]; 2159a747e4fSDavid du Colombier sprint(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 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* 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* 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* 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* 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 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 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* 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 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 5163ff48bf5SDavid du Colombier ipremove(Chan*) 5173ff48bf5SDavid du Colombier { 5183ff48bf5SDavid du Colombier error(Eperm); 5193ff48bf5SDavid du Colombier } 5203ff48bf5SDavid du Colombier 5219a747e4fSDavid du Colombier static int 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 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 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 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); 6527dd7cddfSDavid du Colombier sprint(buf, "%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) { 6617dd7cddfSDavid du Colombier sprint(buf, "%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) { 6737dd7cddfSDavid du Colombier sprint(buf, "%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* 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 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* 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 7693ff48bf5SDavid du Colombier 77080ee5cbfSDavid du Colombier /* 7717dd7cddfSDavid du Colombier * pick a local port and set it 7727dd7cddfSDavid du Colombier */ 773e288d156SDavid du Colombier void 7747dd7cddfSDavid du Colombier setlport(Conv* c) 7757dd7cddfSDavid du Colombier { 7767dd7cddfSDavid du Colombier Proto *p; 7777dd7cddfSDavid du Colombier ushort *pp; 7787dd7cddfSDavid du Colombier int x, found; 7797dd7cddfSDavid du Colombier 7807dd7cddfSDavid du Colombier p = c->p; 7817dd7cddfSDavid du Colombier if(c->restricted) 7827dd7cddfSDavid du Colombier pp = &p->nextrport; 7837dd7cddfSDavid du Colombier else 7847dd7cddfSDavid du Colombier pp = &p->nextport; 7857dd7cddfSDavid du Colombier qlock(p); 7867dd7cddfSDavid du Colombier for(;;(*pp)++){ 7877dd7cddfSDavid du Colombier /* 7887dd7cddfSDavid du Colombier * Fsproto initialises p->nextport to 0 and the restricted 7897dd7cddfSDavid du Colombier * ports (p->nextrport) to 600. 7907dd7cddfSDavid du Colombier * Restricted ports must lie between 600 and 1024. 7917dd7cddfSDavid du Colombier * For the initial condition or if the unrestricted port number 7927dd7cddfSDavid du Colombier * has wrapped round, select a random port between 5000 and 1<<15 7937dd7cddfSDavid du Colombier * to start at. 7947dd7cddfSDavid du Colombier */ 7957dd7cddfSDavid du Colombier if(c->restricted){ 7967dd7cddfSDavid du Colombier if(*pp >= 1024) 7977dd7cddfSDavid du Colombier *pp = 600; 7987dd7cddfSDavid du Colombier } 7997dd7cddfSDavid du Colombier else while(*pp < 5000) 8007dd7cddfSDavid du Colombier *pp = nrand(1<<15); 8017dd7cddfSDavid du Colombier 8027dd7cddfSDavid du Colombier found = 0; 8037dd7cddfSDavid du Colombier for(x = 0; x < p->nc; x++){ 8047dd7cddfSDavid du Colombier if(p->conv[x] == nil) 8057dd7cddfSDavid du Colombier break; 8067dd7cddfSDavid du Colombier if(p->conv[x]->lport == *pp){ 8077dd7cddfSDavid du Colombier found = 1; 8087dd7cddfSDavid du Colombier break; 8097dd7cddfSDavid du Colombier } 8107dd7cddfSDavid du Colombier } 8117dd7cddfSDavid du Colombier if(!found) 8127dd7cddfSDavid du Colombier break; 8137dd7cddfSDavid du Colombier } 8147dd7cddfSDavid du Colombier c->lport = (*pp)++; 8157dd7cddfSDavid du Colombier qunlock(p); 8167dd7cddfSDavid du Colombier } 8177dd7cddfSDavid du Colombier 8187dd7cddfSDavid du Colombier /* 8197dd7cddfSDavid du Colombier * set a local address and port from a string of the form 82080ee5cbfSDavid du Colombier * [address!]port[!r] 8217dd7cddfSDavid du Colombier */ 822e288d156SDavid du Colombier char* 8237dd7cddfSDavid du Colombier setladdrport(Conv* c, char* str, int announcing) 8247dd7cddfSDavid du Colombier { 8257dd7cddfSDavid du Colombier char *p; 82680ee5cbfSDavid du Colombier char *rv; 82780ee5cbfSDavid du Colombier ushort lport; 8281b0a7c7eSDavid du Colombier uchar addr[IPaddrlen]; 82980ee5cbfSDavid du Colombier 83080ee5cbfSDavid du Colombier rv = nil; 8317dd7cddfSDavid du Colombier 8327dd7cddfSDavid du Colombier /* 8337dd7cddfSDavid du Colombier * ignore restricted part if it exists. it's 8347dd7cddfSDavid du Colombier * meaningless on local ports. 8357dd7cddfSDavid du Colombier */ 8367dd7cddfSDavid du Colombier p = strchr(str, '!'); 83780ee5cbfSDavid du Colombier if(p != nil){ 8387dd7cddfSDavid du Colombier *p++ = 0; 83980ee5cbfSDavid du Colombier if(strcmp(p, "r") == 0) 84080ee5cbfSDavid du Colombier p = nil; 8417dd7cddfSDavid du Colombier } 8427dd7cddfSDavid du Colombier 8437dd7cddfSDavid du Colombier c->lport = 0; 84480ee5cbfSDavid du Colombier if(p == nil){ 84580ee5cbfSDavid du Colombier if(announcing) 84680ee5cbfSDavid du Colombier ipmove(c->laddr, IPnoaddr); 84780ee5cbfSDavid du Colombier else 84880ee5cbfSDavid du Colombier setladdr(c); 84980ee5cbfSDavid du Colombier p = str; 85080ee5cbfSDavid du Colombier } else { 85180ee5cbfSDavid du Colombier if(strcmp(str, "*") == 0) 85280ee5cbfSDavid du Colombier ipmove(c->laddr, IPnoaddr); 8531b0a7c7eSDavid du Colombier else { 854*ea58ad6fSDavid du Colombier if(parseip(addr, str) == -1) 855*ea58ad6fSDavid du Colombier return Ebadip; 8561b0a7c7eSDavid du Colombier if(ipforme(c->p->f, addr)) 8571b0a7c7eSDavid du Colombier ipmove(c->laddr, addr); 85880ee5cbfSDavid du Colombier else 8591b0a7c7eSDavid du Colombier return "not a local IP address"; 8601b0a7c7eSDavid du Colombier } 8617dd7cddfSDavid du Colombier } 86280ee5cbfSDavid du Colombier 86380ee5cbfSDavid du Colombier /* one process can get all connections */ 86480ee5cbfSDavid du Colombier if(announcing && strcmp(p, "*") == 0){ 86580ee5cbfSDavid du Colombier if(!iseve()) 86680ee5cbfSDavid du Colombier error(Eperm); 86780ee5cbfSDavid du Colombier return setluniqueport(c, 0); 86880ee5cbfSDavid du Colombier } 86980ee5cbfSDavid du Colombier 87080ee5cbfSDavid du Colombier lport = atoi(p); 87180ee5cbfSDavid du Colombier if(lport <= 0) 87280ee5cbfSDavid du Colombier setlport(c); 87380ee5cbfSDavid du Colombier else 87480ee5cbfSDavid du Colombier rv = setluniqueport(c, lport); 87580ee5cbfSDavid du Colombier return rv; 8767dd7cddfSDavid du Colombier } 8777dd7cddfSDavid du Colombier 8787dd7cddfSDavid du Colombier static char* 8797dd7cddfSDavid du Colombier setraddrport(Conv* c, char* str) 8807dd7cddfSDavid du Colombier { 8817dd7cddfSDavid du Colombier char *p; 8827dd7cddfSDavid du Colombier 8837dd7cddfSDavid du Colombier p = strchr(str, '!'); 8847dd7cddfSDavid du Colombier if(p == nil) 8857dd7cddfSDavid du Colombier return "malformed address"; 8867dd7cddfSDavid du Colombier *p++ = 0; 887*ea58ad6fSDavid du Colombier if (parseip(c->raddr, str) == -1) 888*ea58ad6fSDavid du Colombier return Ebadip; 8897dd7cddfSDavid du Colombier c->rport = atoi(p); 8907dd7cddfSDavid du Colombier p = strchr(p, '!'); 8917dd7cddfSDavid du Colombier if(p){ 89280ee5cbfSDavid du Colombier if(strstr(p, "!r") != nil) 8937dd7cddfSDavid du Colombier c->restricted = 1; 8947dd7cddfSDavid du Colombier } 8957dd7cddfSDavid du Colombier return nil; 8967dd7cddfSDavid du Colombier } 8977dd7cddfSDavid du Colombier 8987dd7cddfSDavid du Colombier /* 8997dd7cddfSDavid du Colombier * called by protocol connect routine to set addresses 9007dd7cddfSDavid du Colombier */ 9017dd7cddfSDavid du Colombier char* 9027dd7cddfSDavid du Colombier Fsstdconnect(Conv *c, char *argv[], int argc) 9037dd7cddfSDavid du Colombier { 9047dd7cddfSDavid du Colombier char *p; 9057dd7cddfSDavid du Colombier 9067dd7cddfSDavid du Colombier switch(argc) { 9077dd7cddfSDavid du Colombier default: 9087dd7cddfSDavid du Colombier return "bad args to connect"; 9097dd7cddfSDavid du Colombier case 2: 9107dd7cddfSDavid du Colombier p = setraddrport(c, argv[1]); 9117dd7cddfSDavid du Colombier if(p != nil) 9127dd7cddfSDavid du Colombier return p; 9137dd7cddfSDavid du Colombier setladdr(c); 9147dd7cddfSDavid du Colombier setlport(c); 9157dd7cddfSDavid du Colombier break; 9167dd7cddfSDavid du Colombier case 3: 9177dd7cddfSDavid du Colombier p = setraddrport(c, argv[1]); 9187dd7cddfSDavid du Colombier if(p != nil) 9197dd7cddfSDavid du Colombier return p; 9203ff48bf5SDavid du Colombier p = setladdrport(c, argv[2], 0); 9213ff48bf5SDavid du Colombier if(p != nil) 9223ff48bf5SDavid du Colombier return p; 9237dd7cddfSDavid du Colombier } 9243ff48bf5SDavid du Colombier 9253ff48bf5SDavid du Colombier if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 && 9263ff48bf5SDavid du Colombier memcmp(c->laddr, v4prefix, IPv4off) == 0) 9273ff48bf5SDavid du Colombier || ipcmp(c->raddr, IPnoaddr) == 0) 9283ff48bf5SDavid du Colombier c->ipversion = V4; 9293ff48bf5SDavid du Colombier else 9303ff48bf5SDavid du Colombier c->ipversion = V6; 9313ff48bf5SDavid du Colombier 9327dd7cddfSDavid du Colombier return nil; 9337dd7cddfSDavid du Colombier } 9347dd7cddfSDavid du Colombier /* 9357dd7cddfSDavid du Colombier * initiate connection and sleep till its set up 9367dd7cddfSDavid du Colombier */ 9377dd7cddfSDavid du Colombier static int 9387dd7cddfSDavid du Colombier connected(void* a) 9397dd7cddfSDavid du Colombier { 9407dd7cddfSDavid du Colombier return ((Conv*)a)->state == Connected; 9417dd7cddfSDavid du Colombier } 9427dd7cddfSDavid du Colombier static void 9437dd7cddfSDavid du Colombier connectctlmsg(Proto *x, Conv *c, Cmdbuf *cb) 9447dd7cddfSDavid du Colombier { 9457dd7cddfSDavid du Colombier char *p; 9467dd7cddfSDavid du Colombier 94780ee5cbfSDavid du Colombier if(c->state != 0) 94880ee5cbfSDavid du Colombier error(Econinuse); 9497dd7cddfSDavid du Colombier c->state = Connecting; 9507dd7cddfSDavid du Colombier c->cerr[0] = '\0'; 9517dd7cddfSDavid du Colombier if(x->connect == nil) 9527dd7cddfSDavid du Colombier error("connect not supported"); 9537dd7cddfSDavid du Colombier p = x->connect(c, cb->f, cb->nf); 9547dd7cddfSDavid du Colombier if(p != nil) 9557dd7cddfSDavid du Colombier error(p); 95680ee5cbfSDavid du Colombier 95780ee5cbfSDavid du Colombier qunlock(c); 95880ee5cbfSDavid du Colombier if(waserror()){ 95980ee5cbfSDavid du Colombier qlock(c); 96080ee5cbfSDavid du Colombier nexterror(); 96180ee5cbfSDavid du Colombier } 9627dd7cddfSDavid du Colombier sleep(&c->cr, connected, c); 96380ee5cbfSDavid du Colombier qlock(c); 96480ee5cbfSDavid du Colombier poperror(); 96580ee5cbfSDavid du Colombier 9667dd7cddfSDavid du Colombier if(c->cerr[0] != '\0') 9677dd7cddfSDavid du Colombier error(c->cerr); 9687dd7cddfSDavid du Colombier } 9697dd7cddfSDavid du Colombier 9707dd7cddfSDavid du Colombier /* 9717dd7cddfSDavid du Colombier * called by protocol announce routine to set addresses 9727dd7cddfSDavid du Colombier */ 9737dd7cddfSDavid du Colombier char* 9747dd7cddfSDavid du Colombier Fsstdannounce(Conv* c, char* argv[], int argc) 9757dd7cddfSDavid du Colombier { 97680ee5cbfSDavid du Colombier memset(c->raddr, 0, sizeof(c->raddr)); 97780ee5cbfSDavid du Colombier c->rport = 0; 9787dd7cddfSDavid du Colombier switch(argc){ 9797dd7cddfSDavid du Colombier default: 9809acf0835SDavid du Colombier break; 9817dd7cddfSDavid du Colombier case 2: 98280ee5cbfSDavid du Colombier return setladdrport(c, argv[1], 1); 9837dd7cddfSDavid du Colombier } 9849acf0835SDavid du Colombier return "bad args to announce"; 9857dd7cddfSDavid du Colombier } 9867dd7cddfSDavid du Colombier 9877dd7cddfSDavid du Colombier /* 9887dd7cddfSDavid du Colombier * initiate announcement and sleep till its set up 9897dd7cddfSDavid du Colombier */ 9907dd7cddfSDavid du Colombier static int 9917dd7cddfSDavid du Colombier announced(void* a) 9927dd7cddfSDavid du Colombier { 9937dd7cddfSDavid du Colombier return ((Conv*)a)->state == Announced; 9947dd7cddfSDavid du Colombier } 9957dd7cddfSDavid du Colombier static void 9967dd7cddfSDavid du Colombier announcectlmsg(Proto *x, Conv *c, Cmdbuf *cb) 9977dd7cddfSDavid du Colombier { 9987dd7cddfSDavid du Colombier char *p; 9997dd7cddfSDavid du Colombier 100080ee5cbfSDavid du Colombier if(c->state != 0) 100180ee5cbfSDavid du Colombier error(Econinuse); 10027dd7cddfSDavid du Colombier c->state = Announcing; 10037dd7cddfSDavid du Colombier c->cerr[0] = '\0'; 10047dd7cddfSDavid du Colombier if(x->announce == nil) 10057dd7cddfSDavid du Colombier error("announce not supported"); 10067dd7cddfSDavid du Colombier p = x->announce(c, cb->f, cb->nf); 10077dd7cddfSDavid du Colombier if(p != nil) 10087dd7cddfSDavid du Colombier error(p); 100980ee5cbfSDavid du Colombier 101080ee5cbfSDavid du Colombier qunlock(c); 101180ee5cbfSDavid du Colombier if(waserror()){ 101280ee5cbfSDavid du Colombier qlock(c); 101380ee5cbfSDavid du Colombier nexterror(); 101480ee5cbfSDavid du Colombier } 10157dd7cddfSDavid du Colombier sleep(&c->cr, announced, c); 101680ee5cbfSDavid du Colombier qlock(c); 101780ee5cbfSDavid du Colombier poperror(); 101880ee5cbfSDavid du Colombier 10197dd7cddfSDavid du Colombier if(c->cerr[0] != '\0') 10207dd7cddfSDavid du Colombier error(c->cerr); 10217dd7cddfSDavid du Colombier } 10227dd7cddfSDavid du Colombier 10237dd7cddfSDavid du Colombier /* 102480ee5cbfSDavid du Colombier * called by protocol bind routine to set addresses 10257dd7cddfSDavid du Colombier */ 10267dd7cddfSDavid du Colombier char* 10277dd7cddfSDavid du Colombier Fsstdbind(Conv* c, char* argv[], int argc) 10287dd7cddfSDavid du Colombier { 10297dd7cddfSDavid du Colombier switch(argc){ 10307dd7cddfSDavid du Colombier default: 10319acf0835SDavid du Colombier break; 10327dd7cddfSDavid du Colombier case 2: 103380ee5cbfSDavid du Colombier return setladdrport(c, argv[1], 0); 10347dd7cddfSDavid du Colombier } 10359acf0835SDavid du Colombier return "bad args to bind"; 10367dd7cddfSDavid du Colombier } 10377dd7cddfSDavid du Colombier 10387dd7cddfSDavid du Colombier static void 10397dd7cddfSDavid du Colombier bindctlmsg(Proto *x, Conv *c, Cmdbuf *cb) 10407dd7cddfSDavid du Colombier { 10417dd7cddfSDavid du Colombier char *p; 10427dd7cddfSDavid du Colombier 10437dd7cddfSDavid du Colombier if(x->bind == nil) 10447dd7cddfSDavid du Colombier p = Fsstdbind(c, cb->f, cb->nf); 10457dd7cddfSDavid du Colombier else 10467dd7cddfSDavid du Colombier p = x->bind(c, cb->f, cb->nf); 10477dd7cddfSDavid du Colombier if(p != nil) 10487dd7cddfSDavid du Colombier error(p); 10497dd7cddfSDavid du Colombier } 10507dd7cddfSDavid du Colombier 10517dd7cddfSDavid du Colombier static void 10527dd7cddfSDavid du Colombier tosctlmsg(Conv *c, Cmdbuf *cb) 10537dd7cddfSDavid du Colombier { 10547dd7cddfSDavid du Colombier if(cb->nf < 2) 10557dd7cddfSDavid du Colombier c->tos = 0; 10567dd7cddfSDavid du Colombier else 10577dd7cddfSDavid du Colombier c->tos = atoi(cb->f[1]); 10587dd7cddfSDavid du Colombier } 10597dd7cddfSDavid du Colombier 10607dd7cddfSDavid du Colombier static void 10617dd7cddfSDavid du Colombier ttlctlmsg(Conv *c, Cmdbuf *cb) 10627dd7cddfSDavid du Colombier { 10637dd7cddfSDavid du Colombier if(cb->nf < 2) 10647dd7cddfSDavid du Colombier c->ttl = MAXTTL; 10657dd7cddfSDavid du Colombier else 10667dd7cddfSDavid du Colombier c->ttl = atoi(cb->f[1]); 10677dd7cddfSDavid du Colombier } 10687dd7cddfSDavid du Colombier 10697dd7cddfSDavid du Colombier static long 10707dd7cddfSDavid du Colombier ipwrite(Chan* ch, void *v, long n, vlong off) 10717dd7cddfSDavid du Colombier { 10727dd7cddfSDavid du Colombier Conv *c; 10737dd7cddfSDavid du Colombier Proto *x; 10747dd7cddfSDavid du Colombier char *p; 10757dd7cddfSDavid du Colombier Cmdbuf *cb; 10767dd7cddfSDavid du Colombier uchar ia[IPaddrlen], ma[IPaddrlen]; 10777dd7cddfSDavid du Colombier Fs *f; 10787dd7cddfSDavid du Colombier char *a; 10797dd7cddfSDavid du Colombier ulong offset = off; 10807dd7cddfSDavid du Colombier 10817dd7cddfSDavid du Colombier a = v; 10827dd7cddfSDavid du Colombier f = ipfs[ch->dev]; 10837dd7cddfSDavid du Colombier 10847dd7cddfSDavid du Colombier switch(TYPE(ch->qid)){ 10857dd7cddfSDavid du Colombier default: 10867dd7cddfSDavid du Colombier error(Eperm); 10877dd7cddfSDavid du Colombier case Qdata: 10887dd7cddfSDavid du Colombier x = f->p[PROTO(ch->qid)]; 10897dd7cddfSDavid du Colombier c = x->conv[CONV(ch->qid)]; 10907dd7cddfSDavid du Colombier 10917dd7cddfSDavid du Colombier if(c->wq == nil) 10927dd7cddfSDavid du Colombier error(Eperm); 10937dd7cddfSDavid du Colombier 10947dd7cddfSDavid du Colombier qwrite(c->wq, a, n); 10957dd7cddfSDavid du Colombier break; 10967dd7cddfSDavid du Colombier case Qarp: 10977dd7cddfSDavid du Colombier return arpwrite(f, a, n); 10987dd7cddfSDavid du Colombier case Qiproute: 10997dd7cddfSDavid du Colombier return routewrite(f, ch, a, n); 11007dd7cddfSDavid du Colombier case Qlog: 11019a747e4fSDavid du Colombier netlogctl(f, a, n); 11027dd7cddfSDavid du Colombier return n; 11037dd7cddfSDavid du Colombier case Qndb: 11047dd7cddfSDavid du Colombier return ndbwrite(f, a, offset, n); 11057dd7cddfSDavid du Colombier break; 11067dd7cddfSDavid du Colombier case Qctl: 11077dd7cddfSDavid du Colombier x = f->p[PROTO(ch->qid)]; 11087dd7cddfSDavid du Colombier c = x->conv[CONV(ch->qid)]; 11097dd7cddfSDavid du Colombier cb = parsecmd(a, n); 11107dd7cddfSDavid du Colombier 111180ee5cbfSDavid du Colombier qlock(c); 11127dd7cddfSDavid du Colombier if(waserror()) { 111380ee5cbfSDavid du Colombier qunlock(c); 11147dd7cddfSDavid du Colombier free(cb); 11157dd7cddfSDavid du Colombier nexterror(); 11167dd7cddfSDavid du Colombier } 11173ff48bf5SDavid du Colombier if(cb->nf < 1) 11183ff48bf5SDavid du Colombier error("short control request"); 11193ff48bf5SDavid du Colombier if(strcmp(cb->f[0], "connect") == 0) 11207dd7cddfSDavid du Colombier connectctlmsg(x, c, cb); 11213ff48bf5SDavid du Colombier else if(strcmp(cb->f[0], "announce") == 0) 11227dd7cddfSDavid du Colombier announcectlmsg(x, c, cb); 11233ff48bf5SDavid du Colombier else if(strcmp(cb->f[0], "bind") == 0) 11247dd7cddfSDavid du Colombier bindctlmsg(x, c, cb); 11253ff48bf5SDavid du Colombier else if(strcmp(cb->f[0], "ttl") == 0) 11267dd7cddfSDavid du Colombier ttlctlmsg(c, cb); 11273ff48bf5SDavid du Colombier else if(strcmp(cb->f[0], "tos") == 0) 11287dd7cddfSDavid du Colombier tosctlmsg(c, cb); 11293ff48bf5SDavid du Colombier else if(strcmp(cb->f[0], "ignoreadvice") == 0) 11303ff48bf5SDavid du Colombier c->ignoreadvice = 1; 11313ff48bf5SDavid du Colombier else if(strcmp(cb->f[0], "addmulti") == 0){ 11323ff48bf5SDavid du Colombier if(cb->nf < 2) 11333ff48bf5SDavid du Colombier error("addmulti needs interface address"); 11347dd7cddfSDavid du Colombier if(cb->nf == 2){ 11357dd7cddfSDavid du Colombier if(!ipismulticast(c->raddr)) 11367dd7cddfSDavid du Colombier error("addmulti for a non multicast address"); 1137*ea58ad6fSDavid du Colombier if (parseip(ia, cb->f[1]) == -1) 1138*ea58ad6fSDavid du Colombier error(Ebadip); 11397dd7cddfSDavid du Colombier ipifcaddmulti(c, c->raddr, ia); 11407dd7cddfSDavid du Colombier } else { 1141*ea58ad6fSDavid du Colombier if (parseip(ia, cb->f[1]) == -1 || 1142*ea58ad6fSDavid du Colombier parseip(ma, cb->f[2]) == -1) 1143*ea58ad6fSDavid du Colombier error(Ebadip); 11447dd7cddfSDavid du Colombier if(!ipismulticast(ma)) 11457dd7cddfSDavid du Colombier error("addmulti for a non multicast address"); 11467dd7cddfSDavid du Colombier ipifcaddmulti(c, ma, ia); 11477dd7cddfSDavid du Colombier } 11483ff48bf5SDavid du Colombier } else if(strcmp(cb->f[0], "remmulti") == 0){ 11497dd7cddfSDavid du Colombier if(cb->nf < 2) 11507dd7cddfSDavid du Colombier error("remmulti needs interface address"); 11517dd7cddfSDavid du Colombier if(!ipismulticast(c->raddr)) 11527dd7cddfSDavid du Colombier error("remmulti for a non multicast address"); 1153*ea58ad6fSDavid du Colombier if (parseip(ia, cb->f[1]) == -1) 1154*ea58ad6fSDavid du Colombier error(Ebadip); 11557dd7cddfSDavid du Colombier ipifcremmulti(c, c->raddr, ia); 11563ff48bf5SDavid du Colombier } else if(x->ctl != nil) { 11577dd7cddfSDavid du Colombier p = x->ctl(c, cb->f, cb->nf); 11587dd7cddfSDavid du Colombier if(p != nil) 11597dd7cddfSDavid du Colombier error(p); 11603ff48bf5SDavid du Colombier } else 11613ff48bf5SDavid du Colombier error("unknown control request"); 116280ee5cbfSDavid du Colombier qunlock(c); 11637dd7cddfSDavid du Colombier free(cb); 11647dd7cddfSDavid du Colombier poperror(); 11657dd7cddfSDavid du Colombier } 11667dd7cddfSDavid du Colombier return n; 11677dd7cddfSDavid du Colombier } 11687dd7cddfSDavid du Colombier 11697dd7cddfSDavid du Colombier static long 11707dd7cddfSDavid du Colombier ipbwrite(Chan* ch, Block* bp, ulong offset) 11717dd7cddfSDavid du Colombier { 11727dd7cddfSDavid du Colombier Conv *c; 11737dd7cddfSDavid du Colombier Proto *x; 11747dd7cddfSDavid du Colombier Fs *f; 11757dd7cddfSDavid du Colombier int n; 11767dd7cddfSDavid du Colombier 11777dd7cddfSDavid du Colombier switch(TYPE(ch->qid)){ 11787dd7cddfSDavid du Colombier case Qdata: 11797dd7cddfSDavid du Colombier f = ipfs[ch->dev]; 11807dd7cddfSDavid du Colombier x = f->p[PROTO(ch->qid)]; 11817dd7cddfSDavid du Colombier c = x->conv[CONV(ch->qid)]; 11827dd7cddfSDavid du Colombier 11837dd7cddfSDavid du Colombier if(c->wq == nil) 11847dd7cddfSDavid du Colombier error(Eperm); 11857dd7cddfSDavid du Colombier 11867dd7cddfSDavid du Colombier if(bp->next) 11877dd7cddfSDavid du Colombier bp = concatblock(bp); 11887dd7cddfSDavid du Colombier n = BLEN(bp); 11897dd7cddfSDavid du Colombier qbwrite(c->wq, bp); 11907dd7cddfSDavid du Colombier return n; 11917dd7cddfSDavid du Colombier default: 11927dd7cddfSDavid du Colombier return devbwrite(ch, bp, offset); 11937dd7cddfSDavid du Colombier } 11947dd7cddfSDavid du Colombier } 11957dd7cddfSDavid du Colombier 11967dd7cddfSDavid du Colombier Dev ipdevtab = { 11977dd7cddfSDavid du Colombier 'I', 11987dd7cddfSDavid du Colombier "ip", 11997dd7cddfSDavid du Colombier 12007dd7cddfSDavid du Colombier ipreset, 12019a747e4fSDavid du Colombier devinit, 12029a747e4fSDavid du Colombier devshutdown, 12037dd7cddfSDavid du Colombier ipattach, 12047dd7cddfSDavid du Colombier ipwalk, 12057dd7cddfSDavid du Colombier ipstat, 12067dd7cddfSDavid du Colombier ipopen, 12073ff48bf5SDavid du Colombier ipcreate, 12087dd7cddfSDavid du Colombier ipclose, 12097dd7cddfSDavid du Colombier ipread, 12107dd7cddfSDavid du Colombier ipbread, 12117dd7cddfSDavid du Colombier ipwrite, 12127dd7cddfSDavid du Colombier ipbwrite, 12133ff48bf5SDavid du Colombier ipremove, 12147dd7cddfSDavid du Colombier ipwstat, 12157dd7cddfSDavid du Colombier }; 12167dd7cddfSDavid du Colombier 12177dd7cddfSDavid du Colombier int 12187dd7cddfSDavid du Colombier Fsproto(Fs *f, Proto *p) 12197dd7cddfSDavid du Colombier { 12207dd7cddfSDavid du Colombier if(f->np >= Maxproto) 12217dd7cddfSDavid du Colombier return -1; 12227dd7cddfSDavid du Colombier 12237dd7cddfSDavid du Colombier p->f = f; 12247dd7cddfSDavid du Colombier 12257dd7cddfSDavid du Colombier if(p->ipproto > 0){ 12267dd7cddfSDavid du Colombier if(f->t2p[p->ipproto] != nil) 12277dd7cddfSDavid du Colombier return -1; 12287dd7cddfSDavid du Colombier f->t2p[p->ipproto] = p; 12297dd7cddfSDavid du Colombier } 12307dd7cddfSDavid du Colombier 12319a747e4fSDavid du Colombier p->qid.type = QTDIR; 12329a747e4fSDavid du Colombier p->qid.path = QID(f->np, 0, Qprotodir); 12337dd7cddfSDavid du Colombier p->conv = malloc(sizeof(Conv*)*(p->nc+1)); 12347dd7cddfSDavid du Colombier if(p->conv == nil) 12357dd7cddfSDavid du Colombier panic("Fsproto"); 12367dd7cddfSDavid du Colombier 12377dd7cddfSDavid du Colombier p->x = f->np; 12387dd7cddfSDavid du Colombier p->nextport = 0; 12397dd7cddfSDavid du Colombier p->nextrport = 600; 12407dd7cddfSDavid du Colombier f->p[f->np++] = p; 12417dd7cddfSDavid du Colombier 12427dd7cddfSDavid du Colombier return 0; 12437dd7cddfSDavid du Colombier } 12447dd7cddfSDavid du Colombier 12457dd7cddfSDavid du Colombier /* 12467dd7cddfSDavid du Colombier * return true if this protocol is 12477dd7cddfSDavid du Colombier * built in 12487dd7cddfSDavid du Colombier */ 12497dd7cddfSDavid du Colombier int 12507dd7cddfSDavid du Colombier Fsbuiltinproto(Fs* f, uchar proto) 12517dd7cddfSDavid du Colombier { 12527dd7cddfSDavid du Colombier return f->t2p[proto] != nil; 12537dd7cddfSDavid du Colombier } 12547dd7cddfSDavid du Colombier 12557dd7cddfSDavid du Colombier /* 12567dd7cddfSDavid du Colombier * called with protocol locked 12577dd7cddfSDavid du Colombier */ 12587dd7cddfSDavid du Colombier Conv* 12597dd7cddfSDavid du Colombier Fsprotoclone(Proto *p, char *user) 12607dd7cddfSDavid du Colombier { 12617dd7cddfSDavid du Colombier Conv *c, **pp, **ep; 12627dd7cddfSDavid du Colombier 12637dd7cddfSDavid du Colombier retry: 12647dd7cddfSDavid du Colombier c = nil; 12657dd7cddfSDavid du Colombier ep = &p->conv[p->nc]; 12667dd7cddfSDavid du Colombier for(pp = p->conv; pp < ep; pp++) { 12677dd7cddfSDavid du Colombier c = *pp; 12687dd7cddfSDavid du Colombier if(c == nil){ 12697dd7cddfSDavid du Colombier c = malloc(sizeof(Conv)); 12707dd7cddfSDavid du Colombier if(c == nil) 12717dd7cddfSDavid du Colombier error(Enomem); 12727dd7cddfSDavid du Colombier qlock(c); 12737dd7cddfSDavid du Colombier c->p = p; 12747dd7cddfSDavid du Colombier c->x = pp - p->conv; 12757dd7cddfSDavid du Colombier if(p->ptclsize != 0){ 12767dd7cddfSDavid du Colombier c->ptcl = malloc(p->ptclsize); 12777dd7cddfSDavid du Colombier if(c->ptcl == nil) { 12787dd7cddfSDavid du Colombier free(c); 12797dd7cddfSDavid du Colombier error(Enomem); 12807dd7cddfSDavid du Colombier } 12817dd7cddfSDavid du Colombier } 12827dd7cddfSDavid du Colombier *pp = c; 12837dd7cddfSDavid du Colombier p->ac++; 12843ff48bf5SDavid du Colombier c->eq = qopen(1024, Qmsg, 0, 0); 12857dd7cddfSDavid du Colombier (*p->create)(c); 12867dd7cddfSDavid du Colombier break; 12877dd7cddfSDavid du Colombier } 12887dd7cddfSDavid du Colombier if(canqlock(c)){ 12897dd7cddfSDavid du Colombier /* 12907dd7cddfSDavid du Colombier * make sure both processes and protocol 12917dd7cddfSDavid du Colombier * are done with this Conv 12927dd7cddfSDavid du Colombier */ 12937dd7cddfSDavid du Colombier if(c->inuse == 0 && (p->inuse == nil || (*p->inuse)(c) == 0)) 12947dd7cddfSDavid du Colombier break; 12957dd7cddfSDavid du Colombier 12967dd7cddfSDavid du Colombier qunlock(c); 12977dd7cddfSDavid du Colombier } 12987dd7cddfSDavid du Colombier } 12997dd7cddfSDavid du Colombier if(pp >= ep) { 13007dd7cddfSDavid du Colombier if(p->gc != nil && (*p->gc)(p)) 13017dd7cddfSDavid du Colombier goto retry; 13027dd7cddfSDavid du Colombier return nil; 13037dd7cddfSDavid du Colombier } 13047dd7cddfSDavid du Colombier 13057dd7cddfSDavid du Colombier c->inuse = 1; 13069a747e4fSDavid du Colombier kstrdup(&c->owner, user); 13077dd7cddfSDavid du Colombier c->perm = 0660; 130880ee5cbfSDavid du Colombier c->state = Idle; 13097dd7cddfSDavid du Colombier ipmove(c->laddr, IPnoaddr); 13107dd7cddfSDavid du Colombier ipmove(c->raddr, IPnoaddr); 1311a6a9e072SDavid du Colombier c->r = nil; 1312a6a9e072SDavid du Colombier c->rgen = 0; 13137dd7cddfSDavid du Colombier c->lport = 0; 13147dd7cddfSDavid du Colombier c->rport = 0; 13157dd7cddfSDavid du Colombier c->restricted = 0; 13167dd7cddfSDavid du Colombier c->ttl = MAXTTL; 13177dd7cddfSDavid du Colombier qreopen(c->rq); 13187dd7cddfSDavid du Colombier qreopen(c->wq); 13197dd7cddfSDavid du Colombier qreopen(c->eq); 13207dd7cddfSDavid du Colombier 13217dd7cddfSDavid du Colombier qunlock(c); 13227dd7cddfSDavid du Colombier return c; 13237dd7cddfSDavid du Colombier } 13247dd7cddfSDavid du Colombier 13257dd7cddfSDavid du Colombier int 13267dd7cddfSDavid du Colombier Fsconnected(Conv* c, char* msg) 13277dd7cddfSDavid du Colombier { 13287dd7cddfSDavid du Colombier if(msg != nil && *msg != '\0') 13299a747e4fSDavid du Colombier strncpy(c->cerr, msg, ERRMAX-1); 13307dd7cddfSDavid du Colombier 13317dd7cddfSDavid du Colombier switch(c->state){ 13327dd7cddfSDavid du Colombier 13337dd7cddfSDavid du Colombier case Announcing: 13347dd7cddfSDavid du Colombier c->state = Announced; 13357dd7cddfSDavid du Colombier break; 13367dd7cddfSDavid du Colombier 13377dd7cddfSDavid du Colombier case Connecting: 13387dd7cddfSDavid du Colombier c->state = Connected; 13397dd7cddfSDavid du Colombier break; 13407dd7cddfSDavid du Colombier } 13417dd7cddfSDavid du Colombier 13427dd7cddfSDavid du Colombier wakeup(&c->cr); 13437dd7cddfSDavid du Colombier return 0; 13447dd7cddfSDavid du Colombier } 13457dd7cddfSDavid du Colombier 13467dd7cddfSDavid du Colombier Proto* 13477dd7cddfSDavid du Colombier Fsrcvpcol(Fs* f, uchar proto) 13487dd7cddfSDavid du Colombier { 13497dd7cddfSDavid du Colombier if(f->ipmux) 13507dd7cddfSDavid du Colombier return f->ipmux; 13517dd7cddfSDavid du Colombier else 13527dd7cddfSDavid du Colombier return f->t2p[proto]; 13537dd7cddfSDavid du Colombier } 13547dd7cddfSDavid du Colombier 13557dd7cddfSDavid du Colombier Proto* 13567dd7cddfSDavid du Colombier Fsrcvpcolx(Fs *f, uchar proto) 13577dd7cddfSDavid du Colombier { 13587dd7cddfSDavid du Colombier return f->t2p[proto]; 13597dd7cddfSDavid du Colombier } 13607dd7cddfSDavid du Colombier 13617dd7cddfSDavid du Colombier /* 13627dd7cddfSDavid du Colombier * called with protocol locked 13637dd7cddfSDavid du Colombier */ 13647dd7cddfSDavid du Colombier Conv* 13653ff48bf5SDavid du Colombier Fsnewcall(Conv *c, uchar *raddr, ushort rport, uchar *laddr, ushort lport, uchar version) 13667dd7cddfSDavid du Colombier { 13677dd7cddfSDavid du Colombier Conv *nc; 13687dd7cddfSDavid du Colombier Conv **l; 13697dd7cddfSDavid du Colombier int i; 13707dd7cddfSDavid du Colombier 13717dd7cddfSDavid du Colombier qlock(c); 13727dd7cddfSDavid du Colombier i = 0; 13737dd7cddfSDavid du Colombier for(l = &c->incall; *l; l = &(*l)->next) 13747dd7cddfSDavid du Colombier i++; 13757dd7cddfSDavid du Colombier if(i >= Maxincall) { 13767dd7cddfSDavid du Colombier qunlock(c); 13777dd7cddfSDavid du Colombier return nil; 13787dd7cddfSDavid du Colombier } 13797dd7cddfSDavid du Colombier 13807dd7cddfSDavid du Colombier /* find a free conversation */ 13817dd7cddfSDavid du Colombier nc = Fsprotoclone(c->p, network); 13827dd7cddfSDavid du Colombier if(nc == nil) { 13837dd7cddfSDavid du Colombier qunlock(c); 13847dd7cddfSDavid du Colombier return nil; 13857dd7cddfSDavid du Colombier } 13867dd7cddfSDavid du Colombier ipmove(nc->raddr, raddr); 13877dd7cddfSDavid du Colombier nc->rport = rport; 13887dd7cddfSDavid du Colombier ipmove(nc->laddr, laddr); 13897dd7cddfSDavid du Colombier nc->lport = lport; 13907dd7cddfSDavid du Colombier nc->next = nil; 13917dd7cddfSDavid du Colombier *l = nc; 139280ee5cbfSDavid du Colombier nc->state = Connected; 13933ff48bf5SDavid du Colombier nc->ipversion = version; 13943ff48bf5SDavid du Colombier 13957dd7cddfSDavid du Colombier qunlock(c); 13967dd7cddfSDavid du Colombier 13977dd7cddfSDavid du Colombier wakeup(&c->listenr); 13987dd7cddfSDavid du Colombier 13997dd7cddfSDavid du Colombier return nc; 14007dd7cddfSDavid du Colombier } 14017dd7cddfSDavid du Colombier 14027dd7cddfSDavid du Colombier long 14037dd7cddfSDavid du Colombier ndbwrite(Fs *f, char *a, ulong off, int n) 14047dd7cddfSDavid du Colombier { 14057dd7cddfSDavid du Colombier if(off > strlen(f->ndb)) 14067dd7cddfSDavid du Colombier error(Eio); 14077dd7cddfSDavid du Colombier if(off+n >= sizeof(f->ndb)) 14087dd7cddfSDavid du Colombier error(Eio); 14097dd7cddfSDavid du Colombier memmove(f->ndb+off, a, n); 14107dd7cddfSDavid du Colombier f->ndb[off+n] = 0; 14119a747e4fSDavid du Colombier f->ndbvers++; 14129a747e4fSDavid du Colombier f->ndbmtime = seconds(); 14137dd7cddfSDavid du Colombier return n; 14147dd7cddfSDavid du Colombier } 14159a747e4fSDavid du Colombier 14169a747e4fSDavid du Colombier ulong 14179a747e4fSDavid du Colombier scalednconv(void) 14189a747e4fSDavid du Colombier { 14199a747e4fSDavid du Colombier if(cpuserver && conf.npage*BY2PG >= 128*MB) 14209a747e4fSDavid du Colombier return Nchans*4; 14219a747e4fSDavid du Colombier return Nchans; 14229a747e4fSDavid du Colombier } 1423