2 #include "../port/lib.h"
6 #include "../port/error.h"
7 #include "../port/netif.h"
9 static int netown(Netfile*, char*, int);
10 static int openfile(Netif*, int);
11 static char* matchtoken(char*, char*);
12 static char* netmulti(Netif*, Netfile*, uchar*, int);
13 static int parseaddr(uchar*, char*, int);
16 * set up a new network interface
19 netifinit(Netif *nif, char *name, int nfile, ulong limit)
21 if(strlen(name) >= sizeof nif->name)
22 panic("netifinit: name too long: %s", name);
23 strcpy(nif->name, name);
25 nif->f = xalloc(nfile*sizeof(Netfile*));
27 panic("netifinit: no memory");
28 memset(nif->f, 0, nfile*sizeof(Netfile*));
33 * generate a 3 level directory
36 netifgen(Chan *c, char*, Dirtab *vp, int, int i, Dir *dp)
39 Netif *nif = (Netif*)vp;
48 /* top level directory contains the name of the network */
54 devdir(c, q, ".", 0, eve, 0555, dp);
59 strcpy(up->genbuf, nif->name);
60 devdir(c, q, up->genbuf, 0, eve, 0555, dp);
68 /* second level contains clone plus all the conversations */
69 t = NETTYPE(c->qid.path);
70 if(t == N2ndqid || t == Ncloneqid || t == Naddrqid){
75 devdir(c, q, ".", 0, eve, DMDIR|0555, dp);
79 devdir(c, q, "clone", 0, eve, 0666, dp);
83 devdir(c, q, "addr", 0, eve, 0666, dp);
87 devdir(c, q, "stats", 0, eve, 0444, dp);
91 devdir(c, q, "ifstats", 0, eve, 0444, dp);
100 q.path = NETQID(i, N3rdqid);
101 snprint(up->genbuf, sizeof up->genbuf, "%d", i);
102 devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
109 f = nif->f[NETID(c->qid.path)];
123 strcpy(up->genbuf, nif->name);
124 devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
127 q.path = NETQID(NETID(c->qid.path), Ndataqid);
128 devdir(c, q, "data", 0, o, perm, dp);
131 q.path = NETQID(NETID(c->qid.path), Nctlqid);
132 devdir(c, q, "ctl", 0, o, perm, dp);
135 q.path = NETQID(NETID(c->qid.path), Nstatqid);
136 devdir(c, q, "stats", 0, eve, 0444, dp);
139 q.path = NETQID(NETID(c->qid.path), Ntypeqid);
140 devdir(c, q, "type", 0, eve, 0444, dp);
143 q.path = NETQID(NETID(c->qid.path), Nifstatqid);
144 devdir(c, q, "ifstats", 0, eve, 0444, dp);
153 netifwalk(Netif *nif, Chan *c, Chan *nc, char **name, int nname)
155 return devwalk(c, nc, name, nname, (Dirtab *)nif, 0, netifgen);
159 netifopen(Netif *nif, Chan *c, int omode)
165 if(c->qid.type & QTDIR){
169 switch(NETTYPE(c->qid.path)){
172 id = NETID(c->qid.path);
176 id = openfile(nif, -1);
177 c->qid.path = NETQID(id, Nctlqid);
183 switch(NETTYPE(c->qid.path)){
187 if(netown(f, up->user, omode&7) < 0)
192 c->mode = openmode(omode);
195 c->iounit = qiomaxatomic;
200 netifread(Netif *nif, Chan *c, void *a, long n, ulong offset)
206 if(c->qid.type&QTDIR)
207 return devdirread(c, a, n, (Dirtab*)nif, 0, netifgen);
209 switch(NETTYPE(c->qid.path)){
211 f = nif->f[NETID(c->qid.path)];
212 return qread(f->in, a, n);
214 return readnum(offset, a, n, NETID(c->qid.path), NUMSIZE);
216 p = smalloc(READSTR);
217 j = snprint(p, READSTR, "in: %llud\n", nif->inpackets);
218 j += snprint(p+j, READSTR-j, "link: %d\n", nif->link);
219 j += snprint(p+j, READSTR-j, "out: %llud\n", nif->outpackets);
220 j += snprint(p+j, READSTR-j, "crc errs: %d\n", nif->crcs);
221 j += snprint(p+j, READSTR-j, "overflows: %d\n", nif->overflows);
222 j += snprint(p+j, READSTR-j, "soft overflows: %d\n", nif->soverflows);
223 j += snprint(p+j, READSTR-j, "framing errs: %d\n", nif->frames);
224 j += snprint(p+j, READSTR-j, "buffer errs: %d\n", nif->buffs);
225 j += snprint(p+j, READSTR-j, "output errs: %d\n", nif->oerrs);
226 j += snprint(p+j, READSTR-j, "prom: %d\n", nif->prom);
227 j += snprint(p+j, READSTR-j, "mbps: %d\n", nif->mbps);
228 j += snprint(p+j, READSTR-j, "addr: ");
229 for(i = 0; i < nif->alen; i++)
230 j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]);
231 snprint(p+j, READSTR-j, "\n");
232 n = readstr(offset, a, n, p);
236 p = smalloc(READSTR);
238 for(i = 0; i < nif->alen; i++)
239 j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]);
240 n = readstr(offset, a, n, p);
244 f = nif->f[NETID(c->qid.path)];
245 return readnum(offset, a, n, f->type, NUMSIZE);
250 return -1; /* not reached */
254 netifbread(Netif *nif, Chan *c, long n, ulong offset)
256 if((c->qid.type & QTDIR) || NETTYPE(c->qid.path) != Ndataqid)
257 return devbread(c, n, offset);
259 return qbread(nif->f[NETID(c->qid.path)]->in, n);
263 * make sure this type isn't already in use on this device
266 typeinuse(Netif *nif, int type)
268 Netfile *f, **fp, **efp;
273 efp = &nif->f[nif->nfile];
274 for(fp = nif->f; fp < efp; fp++){
285 * the devxxx.c that calls us handles writing data, it knows best
288 netifwrite(Netif *nif, Chan *c, void *a, long n)
293 uchar binaddr[Nmaxaddr];
295 if(NETTYPE(c->qid.path) != Nctlqid)
309 f = nif->f[NETID(c->qid.path)];
310 if((p = matchtoken(buf, "connect")) != 0){
312 if(typeinuse(nif, type))
317 } else if(matchtoken(buf, "promiscuous")){
319 if(nif->prom == 0 && nif->promiscuous != nil)
320 nif->promiscuous(nif->arg, 1);
324 } else if((p = matchtoken(buf, "scanbs")) != 0){
325 /* scan for base stations */
330 if(nif->scanbs != nil)
331 nif->scanbs(nif->arg, type);
335 } else if(matchtoken(buf, "bridge")){
337 } else if(matchtoken(buf, "headersonly")){
339 } else if((p = matchtoken(buf, "addmulti")) != 0){
340 if(parseaddr(binaddr, p, nif->alen) < 0)
341 error("bad address");
342 p = netmulti(nif, f, binaddr, 1);
345 } else if((p = matchtoken(buf, "remmulti")) != 0){
346 if(parseaddr(binaddr, p, nif->alen) < 0)
347 error("bad address");
348 p = netmulti(nif, f, binaddr, 0);
359 netifwstat(Netif *nif, Chan *c, uchar *db, int n)
365 f = nif->f[NETID(c->qid.path)];
369 if(netown(f, up->user, OWRITE) < 0)
372 dir = smalloc(sizeof(Dir)+n);
373 m = convM2D(db, n, &dir[0], (char*)&dir[1]);
378 if(!emptystr(dir[0].uid)){
379 strncpy(f->owner, dir[0].uid, KNAMELEN-1);
380 f->owner[KNAMELEN-1] = 0;
382 if(dir[0].mode != ~0UL)
383 f->mode = dir[0].mode;
389 netifstat(Netif *nif, Chan *c, uchar *db, int n)
391 return devstat(c, db, n, (Dirtab *)nif, 0, netifgen);
395 netifclose(Netif *nif, Chan *c)
401 if((c->flag & COPEN) == 0)
404 t = NETTYPE(c->qid.path);
405 if(t != Ndataqid && t != Nctlqid)
408 f = nif->f[NETID(c->qid.path)];
410 if(--(f->inuse) == 0){
413 if(--(nif->prom) == 0 && nif->promiscuous != nil)
414 nif->promiscuous(nif->arg, 0);
420 if(--(nif->scan) == 0 && nif->scanbs != nil)
421 nif->scanbs(nif->arg, 0);
429 for(ap = nif->maddr; ap; ap = ap->next){
430 if(f->maddr[t/8] & (1<<(t%8)))
431 netmulti(nif, f, ap->addr, 0);
453 netown(Netfile *p, char *o, int omode)
455 static int access[] = { 0400, 0200, 0600, 0100 };
461 if(strncmp(o, p->owner, KNAMELEN) == 0) /* User */
463 else if(strncmp(o, eve, KNAMELEN) == 0) /* Bootes is group */
466 mode = p->mode<<6; /* Other */
477 strncpy(p->owner, o, KNAMELEN-1);
478 p->owner[KNAMELEN-1] = 0;
485 * Increment the reference count of a network device.
486 * If id < 0, return an unused ether device.
489 openfile(Netif *nif, int id)
491 Netfile *f, **fp, **efp;
509 efp = &nif->f[nif->nfile];
510 for(fp = nif->f; fp < efp; fp++){
513 f = malloc(sizeof(Netfile));
516 f->in = qopen(nif->limit, Qmsg, 0, 0);
532 netown(f, up->user, 0);
539 return -1; /* not reached */
543 * look for a token starting a string,
544 * return a pointer to first non-space char after it
547 matchtoken(char *p, char *token)
552 if(strncmp(p, token, n))
557 if(*p != ' ' && *p != '\t' && *p != '\n')
559 while(*p == ' ' || *p == '\t' || *p == '\n')
565 hnputv(void *p, uvlong v)
575 hnputl(void *p, uint v)
587 hnputs(void *p, ushort v)
602 return ((vlong)nhgetl(a) << 32) | nhgetl(a+4);
611 return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0);
620 return (a[0]<<8)|(a[1]<<0);
624 hash(uchar *a, int len)
629 sum = (sum << 1) + *a++;
634 activemulti(Netif *nif, uchar *addr, int alen)
638 for(hp = nif->mhash[hash(addr, alen)]; hp; hp = hp->hnext)
639 if(memcmp(addr, hp->addr, alen) == 0){
649 parseaddr(uchar *to, char *from, int alen)
656 for(i = 0; i < alen; i++){
664 to[i] = strtoul(nip, 0, 16);
672 * keep track of multicast addresses
675 netmulti(Netif *nif, Netfile *f, uchar *addr, int add)
681 if(nif->multicast == nil)
682 return "interface does not support multicast";
686 for(ap = *l; ap; ap = *l){
687 if(memcmp(addr, ap->addr, nif->alen) == 0)
695 *l = ap = smalloc(sizeof(*ap));
696 memmove(ap->addr, addr, nif->alen);
699 h = hash(addr, nif->alen);
700 ap->hnext = nif->mhash[h];
707 nif->multicast(nif->arg, addr, 1);
709 if(i < 8*sizeof(f->maddr)){
710 if((f->maddr[i/8] & (1<<(i%8))) == 0)
712 f->maddr[i/8] |= 1<<(i%8);
715 if(ap == 0 || ap->ref == 0)
720 nif->multicast(nif->arg, addr, 0);
722 if(i < 8*sizeof(f->maddr)){
723 if((f->maddr[i/8] & (1<<(i%8))) != 0)
725 f->maddr[i/8] &= ~(1<<(i%8));