19ef1f84bSDavid du Colombier #include "u.h"
29ef1f84bSDavid du Colombier #include "../port/lib.h"
39ef1f84bSDavid du Colombier #include "mem.h"
49ef1f84bSDavid du Colombier #include "dat.h"
59ef1f84bSDavid du Colombier #include "fns.h"
69ef1f84bSDavid du Colombier #include "../port/error.h"
79ef1f84bSDavid du Colombier
89ef1f84bSDavid du Colombier #include "../port/netif.h"
99ef1f84bSDavid du Colombier
109ef1f84bSDavid du Colombier static int netown(Netfile*, char*, int);
119ef1f84bSDavid du Colombier static int openfile(Netif*, int);
129ef1f84bSDavid du Colombier static char* matchtoken(char*, char*);
139ef1f84bSDavid du Colombier static char* netmulti(Netif*, Netfile*, uchar*, int);
149ef1f84bSDavid du Colombier static int parseaddr(uchar*, char*, int);
159ef1f84bSDavid du Colombier
169ef1f84bSDavid du Colombier /*
179ef1f84bSDavid du Colombier * set up a new network interface
189ef1f84bSDavid du Colombier */
199ef1f84bSDavid du Colombier void
netifinit(Netif * nif,char * name,int nfile,ulong limit)209ef1f84bSDavid du Colombier netifinit(Netif *nif, char *name, int nfile, ulong limit)
219ef1f84bSDavid du Colombier {
229ef1f84bSDavid du Colombier strncpy(nif->name, name, KNAMELEN-1);
239ef1f84bSDavid du Colombier nif->name[KNAMELEN-1] = 0;
249ef1f84bSDavid du Colombier nif->nfile = nfile;
259ef1f84bSDavid du Colombier nif->f = malloc(nfile*sizeof(Netfile*));
269ef1f84bSDavid du Colombier if(nif->f == nil)
279ef1f84bSDavid du Colombier panic("netifinit: no memory");
289ef1f84bSDavid du Colombier memset(nif->f, 0, nfile*sizeof(Netfile*));
299ef1f84bSDavid du Colombier nif->limit = limit;
309ef1f84bSDavid du Colombier }
319ef1f84bSDavid du Colombier
329ef1f84bSDavid du Colombier /*
339ef1f84bSDavid du Colombier * generate a 3 level directory
349ef1f84bSDavid du Colombier */
359ef1f84bSDavid du Colombier static int
netifgen(Chan * c,char *,Dirtab * vp,int,int i,Dir * dp)369ef1f84bSDavid du Colombier netifgen(Chan *c, char*, Dirtab *vp, int, int i, Dir *dp)
379ef1f84bSDavid du Colombier {
389ef1f84bSDavid du Colombier Qid q;
399ef1f84bSDavid du Colombier Netif *nif = (Netif*)vp;
409ef1f84bSDavid du Colombier Netfile *f;
419ef1f84bSDavid du Colombier int t;
429ef1f84bSDavid du Colombier int perm;
439ef1f84bSDavid du Colombier char *o;
449ef1f84bSDavid du Colombier
459ef1f84bSDavid du Colombier q.type = QTFILE;
469ef1f84bSDavid du Colombier q.vers = 0;
479ef1f84bSDavid du Colombier
489ef1f84bSDavid du Colombier /* top level directory contains the name of the network */
499ef1f84bSDavid du Colombier if(c->qid.path == 0){
509ef1f84bSDavid du Colombier switch(i){
519ef1f84bSDavid du Colombier case DEVDOTDOT:
529ef1f84bSDavid du Colombier q.path = 0;
539ef1f84bSDavid du Colombier q.type = QTDIR;
549ef1f84bSDavid du Colombier devdir(c, q, ".", 0, eve, 0555, dp);
559ef1f84bSDavid du Colombier break;
569ef1f84bSDavid du Colombier case 0:
579ef1f84bSDavid du Colombier q.path = N2ndqid;
589ef1f84bSDavid du Colombier q.type = QTDIR;
599ef1f84bSDavid du Colombier strcpy(up->genbuf, nif->name);
609ef1f84bSDavid du Colombier devdir(c, q, up->genbuf, 0, eve, 0555, dp);
619ef1f84bSDavid du Colombier break;
629ef1f84bSDavid du Colombier default:
639ef1f84bSDavid du Colombier return -1;
649ef1f84bSDavid du Colombier }
659ef1f84bSDavid du Colombier return 1;
669ef1f84bSDavid du Colombier }
679ef1f84bSDavid du Colombier
689ef1f84bSDavid du Colombier /* second level contains clone plus all the conversations */
699ef1f84bSDavid du Colombier t = NETTYPE(c->qid.path);
709ef1f84bSDavid du Colombier if(t == N2ndqid || t == Ncloneqid || t == Naddrqid){
719ef1f84bSDavid du Colombier switch(i) {
729ef1f84bSDavid du Colombier case DEVDOTDOT:
739ef1f84bSDavid du Colombier q.type = QTDIR;
749ef1f84bSDavid du Colombier q.path = 0;
759ef1f84bSDavid du Colombier devdir(c, q, ".", 0, eve, DMDIR|0555, dp);
769ef1f84bSDavid du Colombier break;
779ef1f84bSDavid du Colombier case 0:
789ef1f84bSDavid du Colombier q.path = Ncloneqid;
799ef1f84bSDavid du Colombier devdir(c, q, "clone", 0, eve, 0666, dp);
809ef1f84bSDavid du Colombier break;
819ef1f84bSDavid du Colombier case 1:
829ef1f84bSDavid du Colombier q.path = Naddrqid;
839ef1f84bSDavid du Colombier devdir(c, q, "addr", 0, eve, 0666, dp);
849ef1f84bSDavid du Colombier break;
859ef1f84bSDavid du Colombier case 2:
869ef1f84bSDavid du Colombier q.path = Nstatqid;
879ef1f84bSDavid du Colombier devdir(c, q, "stats", 0, eve, 0444, dp);
889ef1f84bSDavid du Colombier break;
899ef1f84bSDavid du Colombier case 3:
909ef1f84bSDavid du Colombier q.path = Nifstatqid;
919ef1f84bSDavid du Colombier devdir(c, q, "ifstats", 0, eve, 0444, dp);
929ef1f84bSDavid du Colombier break;
939ef1f84bSDavid du Colombier default:
949ef1f84bSDavid du Colombier i -= 4;
959ef1f84bSDavid du Colombier if(i >= nif->nfile)
969ef1f84bSDavid du Colombier return -1;
979ef1f84bSDavid du Colombier if(nif->f[i] == 0)
989ef1f84bSDavid du Colombier return 0;
999ef1f84bSDavid du Colombier q.type = QTDIR;
1009ef1f84bSDavid du Colombier q.path = NETQID(i, N3rdqid);
101*406c76faSDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "%d", i);
1029ef1f84bSDavid du Colombier devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
1039ef1f84bSDavid du Colombier break;
1049ef1f84bSDavid du Colombier }
1059ef1f84bSDavid du Colombier return 1;
1069ef1f84bSDavid du Colombier }
1079ef1f84bSDavid du Colombier
1089ef1f84bSDavid du Colombier /* third level */
1099ef1f84bSDavid du Colombier f = nif->f[NETID(c->qid.path)];
1109ef1f84bSDavid du Colombier if(f == 0)
1119ef1f84bSDavid du Colombier return 0;
1129ef1f84bSDavid du Colombier if(*f->owner){
1139ef1f84bSDavid du Colombier o = f->owner;
1149ef1f84bSDavid du Colombier perm = f->mode;
1159ef1f84bSDavid du Colombier } else {
1169ef1f84bSDavid du Colombier o = eve;
1179ef1f84bSDavid du Colombier perm = 0666;
1189ef1f84bSDavid du Colombier }
1199ef1f84bSDavid du Colombier switch(i){
1209ef1f84bSDavid du Colombier case DEVDOTDOT:
1219ef1f84bSDavid du Colombier q.type = QTDIR;
1229ef1f84bSDavid du Colombier q.path = N2ndqid;
1239ef1f84bSDavid du Colombier strcpy(up->genbuf, nif->name);
1249ef1f84bSDavid du Colombier devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
1259ef1f84bSDavid du Colombier break;
1269ef1f84bSDavid du Colombier case 0:
1279ef1f84bSDavid du Colombier q.path = NETQID(NETID(c->qid.path), Ndataqid);
1289ef1f84bSDavid du Colombier devdir(c, q, "data", 0, o, perm, dp);
1299ef1f84bSDavid du Colombier break;
1309ef1f84bSDavid du Colombier case 1:
1319ef1f84bSDavid du Colombier q.path = NETQID(NETID(c->qid.path), Nctlqid);
1329ef1f84bSDavid du Colombier devdir(c, q, "ctl", 0, o, perm, dp);
1339ef1f84bSDavid du Colombier break;
1349ef1f84bSDavid du Colombier case 2:
1359ef1f84bSDavid du Colombier q.path = NETQID(NETID(c->qid.path), Nstatqid);
1369ef1f84bSDavid du Colombier devdir(c, q, "stats", 0, eve, 0444, dp);
1379ef1f84bSDavid du Colombier break;
1389ef1f84bSDavid du Colombier case 3:
1399ef1f84bSDavid du Colombier q.path = NETQID(NETID(c->qid.path), Ntypeqid);
1409ef1f84bSDavid du Colombier devdir(c, q, "type", 0, eve, 0444, dp);
1419ef1f84bSDavid du Colombier break;
1429ef1f84bSDavid du Colombier case 4:
1439ef1f84bSDavid du Colombier q.path = NETQID(NETID(c->qid.path), Nifstatqid);
1449ef1f84bSDavid du Colombier devdir(c, q, "ifstats", 0, eve, 0444, dp);
1459ef1f84bSDavid du Colombier break;
1469ef1f84bSDavid du Colombier default:
1479ef1f84bSDavid du Colombier return -1;
1489ef1f84bSDavid du Colombier }
1499ef1f84bSDavid du Colombier return 1;
1509ef1f84bSDavid du Colombier }
1519ef1f84bSDavid du Colombier
1529ef1f84bSDavid du Colombier Walkqid*
netifwalk(Netif * nif,Chan * c,Chan * nc,char ** name,int nname)1539ef1f84bSDavid du Colombier netifwalk(Netif *nif, Chan *c, Chan *nc, char **name, int nname)
1549ef1f84bSDavid du Colombier {
1559ef1f84bSDavid du Colombier return devwalk(c, nc, name, nname, (Dirtab *)nif, 0, netifgen);
1569ef1f84bSDavid du Colombier }
1579ef1f84bSDavid du Colombier
1589ef1f84bSDavid du Colombier Chan*
netifopen(Netif * nif,Chan * c,int omode)1599ef1f84bSDavid du Colombier netifopen(Netif *nif, Chan *c, int omode)
1609ef1f84bSDavid du Colombier {
1619ef1f84bSDavid du Colombier int id;
1629ef1f84bSDavid du Colombier Netfile *f;
1639ef1f84bSDavid du Colombier
1649ef1f84bSDavid du Colombier id = 0;
1659ef1f84bSDavid du Colombier if(c->qid.type & QTDIR){
1669ef1f84bSDavid du Colombier if(omode != OREAD)
1679ef1f84bSDavid du Colombier error(Eperm);
1689ef1f84bSDavid du Colombier } else {
1699ef1f84bSDavid du Colombier switch(NETTYPE(c->qid.path)){
1709ef1f84bSDavid du Colombier case Ndataqid:
1719ef1f84bSDavid du Colombier case Nctlqid:
1729ef1f84bSDavid du Colombier id = NETID(c->qid.path);
1739ef1f84bSDavid du Colombier openfile(nif, id);
1749ef1f84bSDavid du Colombier break;
1759ef1f84bSDavid du Colombier case Ncloneqid:
1769ef1f84bSDavid du Colombier id = openfile(nif, -1);
1779ef1f84bSDavid du Colombier c->qid.path = NETQID(id, Nctlqid);
1789ef1f84bSDavid du Colombier break;
1799ef1f84bSDavid du Colombier default:
1809ef1f84bSDavid du Colombier if(omode != OREAD)
1819ef1f84bSDavid du Colombier error(Ebadarg);
1829ef1f84bSDavid du Colombier }
1839ef1f84bSDavid du Colombier switch(NETTYPE(c->qid.path)){
1849ef1f84bSDavid du Colombier case Ndataqid:
1859ef1f84bSDavid du Colombier case Nctlqid:
1869ef1f84bSDavid du Colombier f = nif->f[id];
1879ef1f84bSDavid du Colombier if(netown(f, up->user, omode&7) < 0)
1889ef1f84bSDavid du Colombier error(Eperm);
1899ef1f84bSDavid du Colombier break;
1909ef1f84bSDavid du Colombier }
1919ef1f84bSDavid du Colombier }
1929ef1f84bSDavid du Colombier c->mode = openmode(omode);
1939ef1f84bSDavid du Colombier c->flag |= COPEN;
1949ef1f84bSDavid du Colombier c->offset = 0;
1959ef1f84bSDavid du Colombier c->iounit = qiomaxatomic;
1969ef1f84bSDavid du Colombier return c;
1979ef1f84bSDavid du Colombier }
1989ef1f84bSDavid du Colombier
1999ef1f84bSDavid du Colombier long
netifread(Netif * nif,Chan * c,void * a,long n,vlong off)2009ef1f84bSDavid du Colombier netifread(Netif *nif, Chan *c, void *a, long n, vlong off)
2019ef1f84bSDavid du Colombier {
2029ef1f84bSDavid du Colombier int i, j;
2039ef1f84bSDavid du Colombier Netfile *f;
2049ef1f84bSDavid du Colombier char *p;
2059ef1f84bSDavid du Colombier long offset;
2069ef1f84bSDavid du Colombier
2079ef1f84bSDavid du Colombier if(c->qid.type & QTDIR)
2089ef1f84bSDavid du Colombier return devdirread(c, a, n, (Dirtab*)nif, 0, netifgen);
2099ef1f84bSDavid du Colombier
2109ef1f84bSDavid du Colombier offset = off;
2119ef1f84bSDavid du Colombier switch(NETTYPE(c->qid.path)){
2129ef1f84bSDavid du Colombier case Ndataqid:
2139ef1f84bSDavid du Colombier f = nif->f[NETID(c->qid.path)];
2149ef1f84bSDavid du Colombier return qread(f->iq, a, n);
2159ef1f84bSDavid du Colombier case Nctlqid:
2169ef1f84bSDavid du Colombier return readnum(offset, a, n, NETID(c->qid.path), NUMSIZE);
2179ef1f84bSDavid du Colombier case Nstatqid:
2189ef1f84bSDavid du Colombier p = malloc(READSTR);
219*406c76faSDavid du Colombier if(p == nil)
220*406c76faSDavid du Colombier error(Enomem);
221*406c76faSDavid du Colombier j = snprint(p, READSTR, "in: %llud\n", nif->inpackets);
2229ef1f84bSDavid du Colombier j += snprint(p+j, READSTR-j, "link: %d\n", nif->link);
223*406c76faSDavid du Colombier j += snprint(p+j, READSTR-j, "out: %llud\n", nif->outpackets);
2249ef1f84bSDavid du Colombier j += snprint(p+j, READSTR-j, "crc errs: %d\n", nif->crcs);
2259ef1f84bSDavid du Colombier j += snprint(p+j, READSTR-j, "overflows: %d\n", nif->overflows);
2269ef1f84bSDavid du Colombier j += snprint(p+j, READSTR-j, "soft overflows: %d\n", nif->soverflows);
2279ef1f84bSDavid du Colombier j += snprint(p+j, READSTR-j, "framing errs: %d\n", nif->frames);
2289ef1f84bSDavid du Colombier j += snprint(p+j, READSTR-j, "buffer errs: %d\n", nif->buffs);
2299ef1f84bSDavid du Colombier j += snprint(p+j, READSTR-j, "output errs: %d\n", nif->oerrs);
2309ef1f84bSDavid du Colombier j += snprint(p+j, READSTR-j, "prom: %d\n", nif->prom);
2319ef1f84bSDavid du Colombier j += snprint(p+j, READSTR-j, "mbps: %d\n", nif->mbps);
2329ef1f84bSDavid du Colombier j += snprint(p+j, READSTR-j, "addr: ");
2339ef1f84bSDavid du Colombier for(i = 0; i < nif->alen; i++)
2349ef1f84bSDavid du Colombier j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]);
2359ef1f84bSDavid du Colombier snprint(p+j, READSTR-j, "\n");
2369ef1f84bSDavid du Colombier n = readstr(offset, a, n, p);
2379ef1f84bSDavid du Colombier free(p);
2389ef1f84bSDavid du Colombier return n;
2399ef1f84bSDavid du Colombier case Naddrqid:
2409ef1f84bSDavid du Colombier p = malloc(READSTR);
241*406c76faSDavid du Colombier if(p == nil)
242*406c76faSDavid du Colombier error(Enomem);
2439ef1f84bSDavid du Colombier j = 0;
2449ef1f84bSDavid du Colombier for(i = 0; i < nif->alen; i++)
2459ef1f84bSDavid du Colombier j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]);
2469ef1f84bSDavid du Colombier n = readstr(offset, a, n, p);
2479ef1f84bSDavid du Colombier free(p);
2489ef1f84bSDavid du Colombier return n;
2499ef1f84bSDavid du Colombier case Ntypeqid:
2509ef1f84bSDavid du Colombier f = nif->f[NETID(c->qid.path)];
2519ef1f84bSDavid du Colombier return readnum(offset, a, n, f->type, NUMSIZE);
2529ef1f84bSDavid du Colombier case Nifstatqid:
2539ef1f84bSDavid du Colombier return 0;
2549ef1f84bSDavid du Colombier }
2559ef1f84bSDavid du Colombier error(Ebadarg);
2569ef1f84bSDavid du Colombier return -1; /* not reached */
2579ef1f84bSDavid du Colombier }
2589ef1f84bSDavid du Colombier
2599ef1f84bSDavid du Colombier Block*
netifbread(Netif * nif,Chan * c,long n,vlong offset)2609ef1f84bSDavid du Colombier netifbread(Netif *nif, Chan *c, long n, vlong offset)
2619ef1f84bSDavid du Colombier {
2629ef1f84bSDavid du Colombier if((c->qid.type & QTDIR) || NETTYPE(c->qid.path) != Ndataqid)
2639ef1f84bSDavid du Colombier return devbread(c, n, offset);
2649ef1f84bSDavid du Colombier
2659ef1f84bSDavid du Colombier return qbread(nif->f[NETID(c->qid.path)]->iq, n);
2669ef1f84bSDavid du Colombier }
2679ef1f84bSDavid du Colombier
2689ef1f84bSDavid du Colombier /*
2699ef1f84bSDavid du Colombier * make sure this type isn't already in use on this device
2709ef1f84bSDavid du Colombier */
2719ef1f84bSDavid du Colombier static int
typeinuse(Netif * nif,int type)2729ef1f84bSDavid du Colombier typeinuse(Netif *nif, int type)
2739ef1f84bSDavid du Colombier {
2749ef1f84bSDavid du Colombier Netfile *f, **fp, **efp;
2759ef1f84bSDavid du Colombier
2769ef1f84bSDavid du Colombier if(type <= 0)
2779ef1f84bSDavid du Colombier return 0;
2789ef1f84bSDavid du Colombier
2799ef1f84bSDavid du Colombier efp = &nif->f[nif->nfile];
2809ef1f84bSDavid du Colombier for(fp = nif->f; fp < efp; fp++){
2819ef1f84bSDavid du Colombier f = *fp;
2829ef1f84bSDavid du Colombier if(f == 0)
2839ef1f84bSDavid du Colombier continue;
2849ef1f84bSDavid du Colombier if(f->type == type)
2859ef1f84bSDavid du Colombier return 1;
2869ef1f84bSDavid du Colombier }
2879ef1f84bSDavid du Colombier return 0;
2889ef1f84bSDavid du Colombier }
2899ef1f84bSDavid du Colombier
2909ef1f84bSDavid du Colombier /*
2919ef1f84bSDavid du Colombier * the devxxx.c that calls us handles writing data, it knows best
2929ef1f84bSDavid du Colombier */
2939ef1f84bSDavid du Colombier long
netifwrite(Netif * nif,Chan * c,void * a,long n)2949ef1f84bSDavid du Colombier netifwrite(Netif *nif, Chan *c, void *a, long n)
2959ef1f84bSDavid du Colombier {
2969ef1f84bSDavid du Colombier Netfile *f;
2979ef1f84bSDavid du Colombier int type;
2989ef1f84bSDavid du Colombier char *p, buf[64];
2999ef1f84bSDavid du Colombier uchar binaddr[Nmaxaddr];
3009ef1f84bSDavid du Colombier
3019ef1f84bSDavid du Colombier if(NETTYPE(c->qid.path) != Nctlqid)
3029ef1f84bSDavid du Colombier error(Eperm);
3039ef1f84bSDavid du Colombier
3049ef1f84bSDavid du Colombier if(n >= sizeof(buf))
3059ef1f84bSDavid du Colombier n = sizeof(buf)-1;
3069ef1f84bSDavid du Colombier memmove(buf, a, n);
3079ef1f84bSDavid du Colombier buf[n] = 0;
3089ef1f84bSDavid du Colombier
3099ef1f84bSDavid du Colombier if(waserror()){
3109ef1f84bSDavid du Colombier qunlock(nif);
3119ef1f84bSDavid du Colombier nexterror();
3129ef1f84bSDavid du Colombier }
3139ef1f84bSDavid du Colombier
3149ef1f84bSDavid du Colombier qlock(nif);
3159ef1f84bSDavid du Colombier f = nif->f[NETID(c->qid.path)];
3169ef1f84bSDavid du Colombier if((p = matchtoken(buf, "connect")) != 0){
3179ef1f84bSDavid du Colombier type = atoi(p);
3189ef1f84bSDavid du Colombier if(typeinuse(nif, type))
3199ef1f84bSDavid du Colombier error(Einuse);
3209ef1f84bSDavid du Colombier f->type = type;
3219ef1f84bSDavid du Colombier if(f->type < 0)
3229ef1f84bSDavid du Colombier nif->all++;
3239ef1f84bSDavid du Colombier } else if(matchtoken(buf, "promiscuous")){
3249ef1f84bSDavid du Colombier if(f->prom == 0){
3259ef1f84bSDavid du Colombier if(nif->prom == 0 && nif->promiscuous != nil)
3269ef1f84bSDavid du Colombier nif->promiscuous(nif->arg, 1);
3279ef1f84bSDavid du Colombier f->prom = 1;
3289ef1f84bSDavid du Colombier nif->prom++;
3299ef1f84bSDavid du Colombier }
3309ef1f84bSDavid du Colombier } else if((p = matchtoken(buf, "scanbs")) != 0){
3319ef1f84bSDavid du Colombier /* scan for base stations */
3329ef1f84bSDavid du Colombier if(f->scan == 0){
3339ef1f84bSDavid du Colombier type = atoi(p);
3349ef1f84bSDavid du Colombier if(type < 5)
3359ef1f84bSDavid du Colombier type = 5;
3369ef1f84bSDavid du Colombier if(nif->scanbs != nil)
3379ef1f84bSDavid du Colombier nif->scanbs(nif->arg, type);
3389ef1f84bSDavid du Colombier f->scan = type;
3399ef1f84bSDavid du Colombier nif->scan++;
3409ef1f84bSDavid du Colombier }
3419ef1f84bSDavid du Colombier } else if(matchtoken(buf, "bridge")){
3429ef1f84bSDavid du Colombier f->bridge = 1;
3439ef1f84bSDavid du Colombier } else if(matchtoken(buf, "headersonly")){
3449ef1f84bSDavid du Colombier f->headersonly = 1;
3459ef1f84bSDavid du Colombier } else if((p = matchtoken(buf, "addmulti")) != 0){
3469ef1f84bSDavid du Colombier if(parseaddr(binaddr, p, nif->alen) < 0)
3479ef1f84bSDavid du Colombier error("bad address");
3489ef1f84bSDavid du Colombier p = netmulti(nif, f, binaddr, 1);
3499ef1f84bSDavid du Colombier if(p)
3509ef1f84bSDavid du Colombier error(p);
3519ef1f84bSDavid du Colombier } else if((p = matchtoken(buf, "remmulti")) != 0){
3529ef1f84bSDavid du Colombier if(parseaddr(binaddr, p, nif->alen) < 0)
3539ef1f84bSDavid du Colombier error("bad address");
3549ef1f84bSDavid du Colombier p = netmulti(nif, f, binaddr, 0);
3559ef1f84bSDavid du Colombier if(p)
3569ef1f84bSDavid du Colombier error(p);
3579ef1f84bSDavid du Colombier } else
3589ef1f84bSDavid du Colombier n = -1;
3599ef1f84bSDavid du Colombier qunlock(nif);
3609ef1f84bSDavid du Colombier poperror();
3619ef1f84bSDavid du Colombier return n;
3629ef1f84bSDavid du Colombier }
3639ef1f84bSDavid du Colombier
3649ef1f84bSDavid du Colombier long
netifwstat(Netif * nif,Chan * c,uchar * db,long n)3659ef1f84bSDavid du Colombier netifwstat(Netif *nif, Chan *c, uchar *db, long n)
3669ef1f84bSDavid du Colombier {
3679ef1f84bSDavid du Colombier Dir *dir;
3689ef1f84bSDavid du Colombier Netfile *f;
3699ef1f84bSDavid du Colombier int l;
3709ef1f84bSDavid du Colombier
3719ef1f84bSDavid du Colombier f = nif->f[NETID(c->qid.path)];
3729ef1f84bSDavid du Colombier if(f == 0)
3739ef1f84bSDavid du Colombier error(Enonexist);
3749ef1f84bSDavid du Colombier
3759ef1f84bSDavid du Colombier if(netown(f, up->user, OWRITE) < 0)
3769ef1f84bSDavid du Colombier error(Eperm);
3779ef1f84bSDavid du Colombier
3789ef1f84bSDavid du Colombier dir = smalloc(sizeof(Dir)+n);
3799ef1f84bSDavid du Colombier l = convM2D(db, n, &dir[0], (char*)&dir[1]);
3809ef1f84bSDavid du Colombier if(l == 0){
3819ef1f84bSDavid du Colombier free(dir);
3829ef1f84bSDavid du Colombier error(Eshortstat);
3839ef1f84bSDavid du Colombier }
3849ef1f84bSDavid du Colombier if(!emptystr(dir[0].uid))
3859ef1f84bSDavid du Colombier strncpy(f->owner, dir[0].uid, KNAMELEN);
3869ef1f84bSDavid du Colombier if(dir[0].mode != ~0UL)
3879ef1f84bSDavid du Colombier f->mode = dir[0].mode;
3889ef1f84bSDavid du Colombier free(dir);
3899ef1f84bSDavid du Colombier return l;
3909ef1f84bSDavid du Colombier }
3919ef1f84bSDavid du Colombier
3929ef1f84bSDavid du Colombier long
netifstat(Netif * nif,Chan * c,uchar * db,long n)3939ef1f84bSDavid du Colombier netifstat(Netif *nif, Chan *c, uchar *db, long n)
3949ef1f84bSDavid du Colombier {
3959ef1f84bSDavid du Colombier return devstat(c, db, n, (Dirtab *)nif, 0, netifgen);
3969ef1f84bSDavid du Colombier }
3979ef1f84bSDavid du Colombier
3989ef1f84bSDavid du Colombier void
netifclose(Netif * nif,Chan * c)3999ef1f84bSDavid du Colombier netifclose(Netif *nif, Chan *c)
4009ef1f84bSDavid du Colombier {
4019ef1f84bSDavid du Colombier Netfile *f;
4029ef1f84bSDavid du Colombier int t;
4039ef1f84bSDavid du Colombier Netaddr *ap;
4049ef1f84bSDavid du Colombier
4059ef1f84bSDavid du Colombier if((c->flag & COPEN) == 0)
4069ef1f84bSDavid du Colombier return;
4079ef1f84bSDavid du Colombier
4089ef1f84bSDavid du Colombier t = NETTYPE(c->qid.path);
4099ef1f84bSDavid du Colombier if(t != Ndataqid && t != Nctlqid)
4109ef1f84bSDavid du Colombier return;
4119ef1f84bSDavid du Colombier
4129ef1f84bSDavid du Colombier f = nif->f[NETID(c->qid.path)];
4139ef1f84bSDavid du Colombier qlock(f);
4149ef1f84bSDavid du Colombier if(--(f->inuse) == 0){
4159ef1f84bSDavid du Colombier if(f->prom){
4169ef1f84bSDavid du Colombier qlock(nif);
4179ef1f84bSDavid du Colombier if(--(nif->prom) == 0 && nif->promiscuous != nil)
4189ef1f84bSDavid du Colombier nif->promiscuous(nif->arg, 0);
4199ef1f84bSDavid du Colombier qunlock(nif);
4209ef1f84bSDavid du Colombier f->prom = 0;
4219ef1f84bSDavid du Colombier }
4229ef1f84bSDavid du Colombier if(f->scan){
4239ef1f84bSDavid du Colombier qlock(nif);
4249ef1f84bSDavid du Colombier if(--(nif->scan) == 0 && nif->scanbs != nil)
4259ef1f84bSDavid du Colombier nif->scanbs(nif->arg, 0);
4269ef1f84bSDavid du Colombier qunlock(nif);
4279ef1f84bSDavid du Colombier f->prom = 0;
4289ef1f84bSDavid du Colombier f->scan = 0;
4299ef1f84bSDavid du Colombier }
4309ef1f84bSDavid du Colombier if(f->nmaddr){
4319ef1f84bSDavid du Colombier qlock(nif);
4329ef1f84bSDavid du Colombier t = 0;
4339ef1f84bSDavid du Colombier for(ap = nif->maddr; ap; ap = ap->next){
4349ef1f84bSDavid du Colombier if(f->maddr[t/8] & (1<<(t%8)))
4359ef1f84bSDavid du Colombier netmulti(nif, f, ap->addr, 0);
4369ef1f84bSDavid du Colombier }
4379ef1f84bSDavid du Colombier qunlock(nif);
4389ef1f84bSDavid du Colombier f->nmaddr = 0;
4399ef1f84bSDavid du Colombier }
4409ef1f84bSDavid du Colombier if(f->type < 0){
4419ef1f84bSDavid du Colombier qlock(nif);
4429ef1f84bSDavid du Colombier --(nif->all);
4439ef1f84bSDavid du Colombier qunlock(nif);
4449ef1f84bSDavid du Colombier }
4459ef1f84bSDavid du Colombier f->owner[0] = 0;
4469ef1f84bSDavid du Colombier f->type = 0;
4479ef1f84bSDavid du Colombier f->bridge = 0;
4489ef1f84bSDavid du Colombier f->headersonly = 0;
4499ef1f84bSDavid du Colombier qclose(f->iq);
4509ef1f84bSDavid du Colombier }
4519ef1f84bSDavid du Colombier qunlock(f);
4529ef1f84bSDavid du Colombier }
4539ef1f84bSDavid du Colombier
4549ef1f84bSDavid du Colombier Lock netlock;
4559ef1f84bSDavid du Colombier
4569ef1f84bSDavid du Colombier static int
netown(Netfile * p,char * o,int omode)4579ef1f84bSDavid du Colombier netown(Netfile *p, char *o, int omode)
4589ef1f84bSDavid du Colombier {
4599ef1f84bSDavid du Colombier static int access[] = { 0400, 0200, 0600, 0100 };
4609ef1f84bSDavid du Colombier int mode;
4619ef1f84bSDavid du Colombier int t;
4629ef1f84bSDavid du Colombier
4639ef1f84bSDavid du Colombier lock(&netlock);
4649ef1f84bSDavid du Colombier if(*p->owner){
4659ef1f84bSDavid du Colombier if(strncmp(o, p->owner, KNAMELEN) == 0) /* User */
4669ef1f84bSDavid du Colombier mode = p->mode;
4679ef1f84bSDavid du Colombier else if(strncmp(o, eve, KNAMELEN) == 0) /* Bootes is group */
4689ef1f84bSDavid du Colombier mode = p->mode<<3;
4699ef1f84bSDavid du Colombier else
4709ef1f84bSDavid du Colombier mode = p->mode<<6; /* Other */
4719ef1f84bSDavid du Colombier
4729ef1f84bSDavid du Colombier t = access[omode&3];
4739ef1f84bSDavid du Colombier if((t & mode) == t){
4749ef1f84bSDavid du Colombier unlock(&netlock);
4759ef1f84bSDavid du Colombier return 0;
4769ef1f84bSDavid du Colombier } else {
4779ef1f84bSDavid du Colombier unlock(&netlock);
4789ef1f84bSDavid du Colombier return -1;
4799ef1f84bSDavid du Colombier }
4809ef1f84bSDavid du Colombier }
4819ef1f84bSDavid du Colombier strncpy(p->owner, o, KNAMELEN);
4829ef1f84bSDavid du Colombier p->mode = 0660;
4839ef1f84bSDavid du Colombier unlock(&netlock);
4849ef1f84bSDavid du Colombier return 0;
4859ef1f84bSDavid du Colombier }
4869ef1f84bSDavid du Colombier
4879ef1f84bSDavid du Colombier /*
4889ef1f84bSDavid du Colombier * Increment the reference count of a network device.
4899ef1f84bSDavid du Colombier * If id < 0, return an unused ether device.
4909ef1f84bSDavid du Colombier */
4919ef1f84bSDavid du Colombier static int
openfile(Netif * nif,int id)4929ef1f84bSDavid du Colombier openfile(Netif *nif, int id)
4939ef1f84bSDavid du Colombier {
4949ef1f84bSDavid du Colombier Netfile *f, **fp, **efp;
4959ef1f84bSDavid du Colombier
4969ef1f84bSDavid du Colombier if(id >= 0){
4979ef1f84bSDavid du Colombier f = nif->f[id];
4989ef1f84bSDavid du Colombier if(f == 0)
4999ef1f84bSDavid du Colombier error(Enodev);
5009ef1f84bSDavid du Colombier qlock(f);
5019ef1f84bSDavid du Colombier qreopen(f->iq);
5029ef1f84bSDavid du Colombier f->inuse++;
5039ef1f84bSDavid du Colombier qunlock(f);
5049ef1f84bSDavid du Colombier return id;
5059ef1f84bSDavid du Colombier }
5069ef1f84bSDavid du Colombier
5079ef1f84bSDavid du Colombier qlock(nif);
5089ef1f84bSDavid du Colombier if(waserror()){
5099ef1f84bSDavid du Colombier qunlock(nif);
5109ef1f84bSDavid du Colombier nexterror();
5119ef1f84bSDavid du Colombier }
5129ef1f84bSDavid du Colombier efp = &nif->f[nif->nfile];
5139ef1f84bSDavid du Colombier for(fp = nif->f; fp < efp; fp++){
5149ef1f84bSDavid du Colombier f = *fp;
5159ef1f84bSDavid du Colombier if(f == 0){
5169ef1f84bSDavid du Colombier f = malloc(sizeof(Netfile));
5179ef1f84bSDavid du Colombier if(f == 0)
5189ef1f84bSDavid du Colombier exhausted("memory");
5199ef1f84bSDavid du Colombier f->iq = qopen(nif->limit, Qmsg, 0, 0);
5209ef1f84bSDavid du Colombier if(f->iq == nil){
5219ef1f84bSDavid du Colombier free(f);
5229ef1f84bSDavid du Colombier exhausted("memory");
5239ef1f84bSDavid du Colombier }
5249ef1f84bSDavid du Colombier *fp = f;
5259ef1f84bSDavid du Colombier qlock(f);
5269ef1f84bSDavid du Colombier } else {
5279ef1f84bSDavid du Colombier qlock(f);
5289ef1f84bSDavid du Colombier if(f->inuse){
5299ef1f84bSDavid du Colombier qunlock(f);
5309ef1f84bSDavid du Colombier continue;
5319ef1f84bSDavid du Colombier }
5329ef1f84bSDavid du Colombier }
5339ef1f84bSDavid du Colombier f->inuse = 1;
5349ef1f84bSDavid du Colombier qreopen(f->iq);
5359ef1f84bSDavid du Colombier netown(f, up->user, 0);
5369ef1f84bSDavid du Colombier qunlock(f);
5379ef1f84bSDavid du Colombier qunlock(nif);
5389ef1f84bSDavid du Colombier poperror();
5399ef1f84bSDavid du Colombier return fp - nif->f;
5409ef1f84bSDavid du Colombier }
5419ef1f84bSDavid du Colombier error(Enodev);
5429ef1f84bSDavid du Colombier return -1; /* not reached */
5439ef1f84bSDavid du Colombier }
5449ef1f84bSDavid du Colombier
5459ef1f84bSDavid du Colombier /*
5469ef1f84bSDavid du Colombier * look for a token starting a string,
5479ef1f84bSDavid du Colombier * return a pointer to first non-space char after it
5489ef1f84bSDavid du Colombier */
5499ef1f84bSDavid du Colombier static char*
matchtoken(char * p,char * token)5509ef1f84bSDavid du Colombier matchtoken(char *p, char *token)
5519ef1f84bSDavid du Colombier {
5529ef1f84bSDavid du Colombier int n;
5539ef1f84bSDavid du Colombier
5549ef1f84bSDavid du Colombier n = strlen(token);
5559ef1f84bSDavid du Colombier if(strncmp(p, token, n))
5569ef1f84bSDavid du Colombier return 0;
5579ef1f84bSDavid du Colombier p += n;
5589ef1f84bSDavid du Colombier if(*p == 0)
5599ef1f84bSDavid du Colombier return p;
5609ef1f84bSDavid du Colombier if(*p != ' ' && *p != '\t' && *p != '\n')
5619ef1f84bSDavid du Colombier return 0;
5629ef1f84bSDavid du Colombier while(*p == ' ' || *p == '\t' || *p == '\n')
5639ef1f84bSDavid du Colombier p++;
5649ef1f84bSDavid du Colombier return p;
5659ef1f84bSDavid du Colombier }
5669ef1f84bSDavid du Colombier
5679ef1f84bSDavid du Colombier void
hnputv(void * p,uvlong v)5689ef1f84bSDavid du Colombier hnputv(void *p, uvlong v)
5699ef1f84bSDavid du Colombier {
5709ef1f84bSDavid du Colombier uchar *a;
5719ef1f84bSDavid du Colombier
5729ef1f84bSDavid du Colombier a = p;
5739ef1f84bSDavid du Colombier hnputl(a, v>>32);
5749ef1f84bSDavid du Colombier hnputl(a+4, v);
5759ef1f84bSDavid du Colombier }
5769ef1f84bSDavid du Colombier
5779ef1f84bSDavid du Colombier void
hnputl(void * p,uint v)5789ef1f84bSDavid du Colombier hnputl(void *p, uint v)
5799ef1f84bSDavid du Colombier {
5809ef1f84bSDavid du Colombier uchar *a;
5819ef1f84bSDavid du Colombier
5829ef1f84bSDavid du Colombier a = p;
5839ef1f84bSDavid du Colombier a[0] = v>>24;
5849ef1f84bSDavid du Colombier a[1] = v>>16;
5859ef1f84bSDavid du Colombier a[2] = v>>8;
5869ef1f84bSDavid du Colombier a[3] = v;
5879ef1f84bSDavid du Colombier }
5889ef1f84bSDavid du Colombier
5899ef1f84bSDavid du Colombier void
hnputs(void * p,ushort v)5909ef1f84bSDavid du Colombier hnputs(void *p, ushort v)
5919ef1f84bSDavid du Colombier {
5929ef1f84bSDavid du Colombier uchar *a;
5939ef1f84bSDavid du Colombier
5949ef1f84bSDavid du Colombier a = p;
5959ef1f84bSDavid du Colombier a[0] = v>>8;
5969ef1f84bSDavid du Colombier a[1] = v;
5979ef1f84bSDavid du Colombier }
5989ef1f84bSDavid du Colombier
5999ef1f84bSDavid du Colombier uvlong
nhgetv(void * p)6009ef1f84bSDavid du Colombier nhgetv(void *p)
6019ef1f84bSDavid du Colombier {
6029ef1f84bSDavid du Colombier uchar *a;
6039ef1f84bSDavid du Colombier
6049ef1f84bSDavid du Colombier a = p;
6059ef1f84bSDavid du Colombier return ((vlong)nhgetl(a) << 32) | nhgetl(a+4);
6069ef1f84bSDavid du Colombier }
6079ef1f84bSDavid du Colombier
6089ef1f84bSDavid du Colombier uint
nhgetl(void * p)6099ef1f84bSDavid du Colombier nhgetl(void *p)
6109ef1f84bSDavid du Colombier {
6119ef1f84bSDavid du Colombier uchar *a;
6129ef1f84bSDavid du Colombier
6139ef1f84bSDavid du Colombier a = p;
6149ef1f84bSDavid du Colombier return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0);
6159ef1f84bSDavid du Colombier }
6169ef1f84bSDavid du Colombier
6179ef1f84bSDavid du Colombier ushort
nhgets(void * p)6189ef1f84bSDavid du Colombier nhgets(void *p)
6199ef1f84bSDavid du Colombier {
6209ef1f84bSDavid du Colombier uchar *a;
6219ef1f84bSDavid du Colombier
6229ef1f84bSDavid du Colombier a = p;
6239ef1f84bSDavid du Colombier return (a[0]<<8)|(a[1]<<0);
6249ef1f84bSDavid du Colombier }
6259ef1f84bSDavid du Colombier
6269ef1f84bSDavid du Colombier static ulong
hash(uchar * a,int len)6279ef1f84bSDavid du Colombier hash(uchar *a, int len)
6289ef1f84bSDavid du Colombier {
6299ef1f84bSDavid du Colombier ulong sum = 0;
6309ef1f84bSDavid du Colombier
6319ef1f84bSDavid du Colombier while(len-- > 0)
6329ef1f84bSDavid du Colombier sum = (sum << 1) + *a++;
6339ef1f84bSDavid du Colombier return sum%Nmhash;
6349ef1f84bSDavid du Colombier }
6359ef1f84bSDavid du Colombier
6369ef1f84bSDavid du Colombier int
activemulti(Netif * nif,uchar * addr,int alen)6379ef1f84bSDavid du Colombier activemulti(Netif *nif, uchar *addr, int alen)
6389ef1f84bSDavid du Colombier {
6399ef1f84bSDavid du Colombier Netaddr *hp;
6409ef1f84bSDavid du Colombier
6419ef1f84bSDavid du Colombier for(hp = nif->mhash[hash(addr, alen)]; hp; hp = hp->hnext)
6429ef1f84bSDavid du Colombier if(memcmp(addr, hp->addr, alen) == 0){
6439ef1f84bSDavid du Colombier if(hp->ref)
6449ef1f84bSDavid du Colombier return 1;
6459ef1f84bSDavid du Colombier else
6469ef1f84bSDavid du Colombier break;
6479ef1f84bSDavid du Colombier }
6489ef1f84bSDavid du Colombier return 0;
6499ef1f84bSDavid du Colombier }
6509ef1f84bSDavid du Colombier
6519ef1f84bSDavid du Colombier static int
parseaddr(uchar * to,char * from,int alen)6529ef1f84bSDavid du Colombier parseaddr(uchar *to, char *from, int alen)
6539ef1f84bSDavid du Colombier {
6549ef1f84bSDavid du Colombier char nip[4];
6559ef1f84bSDavid du Colombier char *p;
6569ef1f84bSDavid du Colombier int i;
6579ef1f84bSDavid du Colombier
6589ef1f84bSDavid du Colombier p = from;
6599ef1f84bSDavid du Colombier for(i = 0; i < alen; i++){
6609ef1f84bSDavid du Colombier if(*p == 0)
6619ef1f84bSDavid du Colombier return -1;
6629ef1f84bSDavid du Colombier nip[0] = *p++;
6639ef1f84bSDavid du Colombier if(*p == 0)
6649ef1f84bSDavid du Colombier return -1;
6659ef1f84bSDavid du Colombier nip[1] = *p++;
6669ef1f84bSDavid du Colombier nip[2] = 0;
6679ef1f84bSDavid du Colombier to[i] = strtoul(nip, 0, 16);
6689ef1f84bSDavid du Colombier if(*p == ':')
6699ef1f84bSDavid du Colombier p++;
6709ef1f84bSDavid du Colombier }
6719ef1f84bSDavid du Colombier return 0;
6729ef1f84bSDavid du Colombier }
6739ef1f84bSDavid du Colombier
6749ef1f84bSDavid du Colombier /*
6759ef1f84bSDavid du Colombier * keep track of multicast addresses
6769ef1f84bSDavid du Colombier */
6779ef1f84bSDavid du Colombier static char*
netmulti(Netif * nif,Netfile * f,uchar * addr,int add)6789ef1f84bSDavid du Colombier netmulti(Netif *nif, Netfile *f, uchar *addr, int add)
6799ef1f84bSDavid du Colombier {
6809ef1f84bSDavid du Colombier Netaddr **l, *ap;
6819ef1f84bSDavid du Colombier int i;
6829ef1f84bSDavid du Colombier ulong h;
6839ef1f84bSDavid du Colombier
6849ef1f84bSDavid du Colombier if(nif->multicast == nil)
6859ef1f84bSDavid du Colombier return "interface does not support multicast";
6869ef1f84bSDavid du Colombier
6879ef1f84bSDavid du Colombier l = &nif->maddr;
6889ef1f84bSDavid du Colombier i = 0;
6899ef1f84bSDavid du Colombier for(ap = *l; ap; ap = *l){
6909ef1f84bSDavid du Colombier if(memcmp(addr, ap->addr, nif->alen) == 0)
6919ef1f84bSDavid du Colombier break;
6929ef1f84bSDavid du Colombier i++;
6939ef1f84bSDavid du Colombier l = &ap->next;
6949ef1f84bSDavid du Colombier }
6959ef1f84bSDavid du Colombier
6969ef1f84bSDavid du Colombier if(add){
6979ef1f84bSDavid du Colombier if(ap == 0){
6989ef1f84bSDavid du Colombier *l = ap = smalloc(sizeof(*ap));
6999ef1f84bSDavid du Colombier memmove(ap->addr, addr, nif->alen);
7009ef1f84bSDavid du Colombier ap->next = 0;
7019ef1f84bSDavid du Colombier ap->ref = 1;
7029ef1f84bSDavid du Colombier h = hash(addr, nif->alen);
7039ef1f84bSDavid du Colombier ap->hnext = nif->mhash[h];
7049ef1f84bSDavid du Colombier nif->mhash[h] = ap;
7059ef1f84bSDavid du Colombier } else {
7069ef1f84bSDavid du Colombier ap->ref++;
7079ef1f84bSDavid du Colombier }
7089ef1f84bSDavid du Colombier if(ap->ref == 1){
7099ef1f84bSDavid du Colombier nif->nmaddr++;
7109ef1f84bSDavid du Colombier nif->multicast(nif->arg, addr, 1);
7119ef1f84bSDavid du Colombier }
7129ef1f84bSDavid du Colombier if(i < 8*sizeof(f->maddr)){
7139ef1f84bSDavid du Colombier if((f->maddr[i/8] & (1<<(i%8))) == 0)
7149ef1f84bSDavid du Colombier f->nmaddr++;
7159ef1f84bSDavid du Colombier f->maddr[i/8] |= 1<<(i%8);
7169ef1f84bSDavid du Colombier }
7179ef1f84bSDavid du Colombier } else {
7189ef1f84bSDavid du Colombier if(ap == 0 || ap->ref == 0)
7199ef1f84bSDavid du Colombier return 0;
7209ef1f84bSDavid du Colombier ap->ref--;
7219ef1f84bSDavid du Colombier if(ap->ref == 0){
7229ef1f84bSDavid du Colombier nif->nmaddr--;
7239ef1f84bSDavid du Colombier nif->multicast(nif->arg, addr, 0);
7249ef1f84bSDavid du Colombier }
7259ef1f84bSDavid du Colombier if(i < 8*sizeof(f->maddr)){
7269ef1f84bSDavid du Colombier if((f->maddr[i/8] & (1<<(i%8))) != 0)
7279ef1f84bSDavid du Colombier f->nmaddr--;
7289ef1f84bSDavid du Colombier f->maddr[i/8] &= ~(1<<(i%8));
7299ef1f84bSDavid du Colombier }
7309ef1f84bSDavid du Colombier }
7319ef1f84bSDavid du Colombier return 0;
7329ef1f84bSDavid du Colombier }
733