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 strncpy(nif->name, name, KNAMELEN-1);
22 nif->name[KNAMELEN-1] = 0;
24 nif->f = xalloc(nfile*sizeof(Netfile*));
26 panic("netifinit: no memory");
27 memset(nif->f, 0, nfile*sizeof(Netfile*));
32 * generate a 3 level directory
35 netifgen(Chan *c, char*, Dirtab *vp, int, int i, Dir *dp)
38 Netif *nif = (Netif*)vp;
47 /* top level directory contains the name of the network */
53 devdir(c, q, ".", 0, eve, 0555, dp);
58 strcpy(up->genbuf, nif->name);
59 devdir(c, q, up->genbuf, 0, eve, 0555, dp);
67 /* second level contains clone plus all the conversations */
68 t = NETTYPE(c->qid.path);
69 if(t == N2ndqid || t == Ncloneqid || t == Naddrqid){
74 devdir(c, q, ".", 0, eve, DMDIR|0555, dp);
78 devdir(c, q, "clone", 0, eve, 0666, dp);
82 devdir(c, q, "addr", 0, eve, 0666, dp);
86 devdir(c, q, "stats", 0, eve, 0444, dp);
90 devdir(c, q, "ifstats", 0, eve, 0444, dp);
99 q.path = NETQID(i, N3rdqid);
100 snprint(up->genbuf, sizeof up->genbuf, "%d", i);
101 devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
108 f = nif->f[NETID(c->qid.path)];
122 strcpy(up->genbuf, nif->name);
123 devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
126 q.path = NETQID(NETID(c->qid.path), Ndataqid);
127 devdir(c, q, "data", 0, o, perm, dp);
130 q.path = NETQID(NETID(c->qid.path), Nctlqid);
131 devdir(c, q, "ctl", 0, o, perm, dp);
134 q.path = NETQID(NETID(c->qid.path), Nstatqid);
135 devdir(c, q, "stats", 0, eve, 0444, dp);
138 q.path = NETQID(NETID(c->qid.path), Ntypeqid);
139 devdir(c, q, "type", 0, eve, 0444, dp);
142 q.path = NETQID(NETID(c->qid.path), Nifstatqid);
143 devdir(c, q, "ifstats", 0, eve, 0444, dp);
152 netifwalk(Netif *nif, Chan *c, Chan *nc, char **name, int nname)
154 return devwalk(c, nc, name, nname, (Dirtab *)nif, 0, netifgen);
158 netifopen(Netif *nif, Chan *c, int omode)
164 if(c->qid.type & QTDIR){
168 switch(NETTYPE(c->qid.path)){
171 id = NETID(c->qid.path);
175 id = openfile(nif, -1);
176 c->qid.path = NETQID(id, Nctlqid);
182 switch(NETTYPE(c->qid.path)){
186 if(netown(f, up->user, omode&7) < 0)
191 c->mode = openmode(omode);
194 c->iounit = qiomaxatomic;
199 netifread(Netif *nif, Chan *c, void *a, long n, ulong offset)
205 if(c->qid.type&QTDIR)
206 return devdirread(c, a, n, (Dirtab*)nif, 0, netifgen);
208 switch(NETTYPE(c->qid.path)){
210 f = nif->f[NETID(c->qid.path)];
211 return qread(f->in, a, n);
213 return readnum(offset, a, n, NETID(c->qid.path), NUMSIZE);
216 j = snprint(p, READSTR, "in: %llud\n", nif->inpackets);
217 j += snprint(p+j, READSTR-j, "link: %d\n", nif->link);
218 j += snprint(p+j, READSTR-j, "out: %llud\n", nif->outpackets);
219 j += snprint(p+j, READSTR-j, "crc errs: %d\n", nif->crcs);
220 j += snprint(p+j, READSTR-j, "overflows: %d\n", nif->overflows);
221 j += snprint(p+j, READSTR-j, "soft overflows: %d\n", nif->soverflows);
222 j += snprint(p+j, READSTR-j, "framing errs: %d\n", nif->frames);
223 j += snprint(p+j, READSTR-j, "buffer errs: %d\n", nif->buffs);
224 j += snprint(p+j, READSTR-j, "output errs: %d\n", nif->oerrs);
225 j += snprint(p+j, READSTR-j, "prom: %d\n", nif->prom);
226 j += snprint(p+j, READSTR-j, "mbps: %d\n", nif->mbps);
227 j += snprint(p+j, READSTR-j, "addr: ");
228 for(i = 0; i < nif->alen; i++)
229 j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]);
230 snprint(p+j, READSTR-j, "\n");
231 n = readstr(offset, a, n, p);
237 for(i = 0; i < nif->alen; i++)
238 j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]);
239 n = readstr(offset, a, n, p);
243 f = nif->f[NETID(c->qid.path)];
244 return readnum(offset, a, n, f->type, NUMSIZE);
249 return -1; /* not reached */
253 netifbread(Netif *nif, Chan *c, long n, ulong offset)
255 if((c->qid.type & QTDIR) || NETTYPE(c->qid.path) != Ndataqid)
256 return devbread(c, n, offset);
258 return qbread(nif->f[NETID(c->qid.path)]->in, n);
262 * make sure this type isn't already in use on this device
265 typeinuse(Netif *nif, int type)
267 Netfile *f, **fp, **efp;
272 efp = &nif->f[nif->nfile];
273 for(fp = nif->f; fp < efp; fp++){
284 * the devxxx.c that calls us handles writing data, it knows best
287 netifwrite(Netif *nif, Chan *c, void *a, long n)
292 uchar binaddr[Nmaxaddr];
294 if(NETTYPE(c->qid.path) != Nctlqid)
308 f = nif->f[NETID(c->qid.path)];
309 if((p = matchtoken(buf, "connect")) != 0){
311 if(typeinuse(nif, type))
316 } else if(matchtoken(buf, "promiscuous")){
318 if(nif->prom == 0 && nif->promiscuous != nil)
319 nif->promiscuous(nif->arg, 1);
323 } else if((p = matchtoken(buf, "scanbs")) != 0){
324 /* scan for base stations */
329 if(nif->scanbs != nil)
330 nif->scanbs(nif->arg, type);
334 } else if(matchtoken(buf, "bridge")){
336 } else if(matchtoken(buf, "headersonly")){
338 } else if((p = matchtoken(buf, "addmulti")) != 0){
339 if(parseaddr(binaddr, p, nif->alen) < 0)
340 error("bad address");
341 p = netmulti(nif, f, binaddr, 1);
344 } else if((p = matchtoken(buf, "remmulti")) != 0){
345 if(parseaddr(binaddr, p, nif->alen) < 0)
346 error("bad address");
347 p = netmulti(nif, f, binaddr, 0);
358 netifwstat(Netif *nif, Chan *c, uchar *db, int n)
364 f = nif->f[NETID(c->qid.path)];
368 if(netown(f, up->user, OWRITE) < 0)
371 dir = smalloc(sizeof(Dir)+n);
372 m = convM2D(db, n, &dir[0], (char*)&dir[1]);
377 if(!emptystr(dir[0].uid))
378 strncpy(f->owner, dir[0].uid, KNAMELEN);
379 if(dir[0].mode != ~0UL)
380 f->mode = dir[0].mode;
386 netifstat(Netif *nif, Chan *c, uchar *db, int n)
388 return devstat(c, db, n, (Dirtab *)nif, 0, netifgen);
392 netifclose(Netif *nif, Chan *c)
398 if((c->flag & COPEN) == 0)
401 t = NETTYPE(c->qid.path);
402 if(t != Ndataqid && t != Nctlqid)
405 f = nif->f[NETID(c->qid.path)];
407 if(--(f->inuse) == 0){
410 if(--(nif->prom) == 0 && nif->promiscuous != nil)
411 nif->promiscuous(nif->arg, 0);
417 if(--(nif->scan) == 0 && nif->scanbs != nil)
418 nif->scanbs(nif->arg, 0);
426 for(ap = nif->maddr; ap; ap = ap->next){
427 if(f->maddr[t/8] & (1<<(t%8)))
428 netmulti(nif, f, ap->addr, 0);
450 netown(Netfile *p, char *o, int omode)
452 static int access[] = { 0400, 0200, 0600, 0100 };
458 if(strncmp(o, p->owner, KNAMELEN) == 0) /* User */
460 else if(strncmp(o, eve, KNAMELEN) == 0) /* Bootes is group */
463 mode = p->mode<<6; /* Other */
474 strncpy(p->owner, o, KNAMELEN);
481 * Increment the reference count of a network device.
482 * If id < 0, return an unused ether device.
485 openfile(Netif *nif, int id)
487 Netfile *f, **fp, **efp;
505 efp = &nif->f[nif->nfile];
506 for(fp = nif->f; fp < efp; fp++){
509 f = malloc(sizeof(Netfile));
512 f->in = qopen(nif->limit, Qmsg, 0, 0);
528 netown(f, up->user, 0);
535 return -1; /* not reached */
539 * look for a token starting a string,
540 * return a pointer to first non-space char after it
543 matchtoken(char *p, char *token)
548 if(strncmp(p, token, n))
553 if(*p != ' ' && *p != '\t' && *p != '\n')
555 while(*p == ' ' || *p == '\t' || *p == '\n')
561 hnputv(void *p, uvlong v)
571 hnputl(void *p, uint v)
583 hnputs(void *p, ushort v)
598 return ((vlong)nhgetl(a) << 32) | nhgetl(a+4);
607 return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0);
616 return (a[0]<<8)|(a[1]<<0);
620 hash(uchar *a, int len)
625 sum = (sum << 1) + *a++;
630 activemulti(Netif *nif, uchar *addr, int alen)
634 for(hp = nif->mhash[hash(addr, alen)]; hp; hp = hp->hnext)
635 if(memcmp(addr, hp->addr, alen) == 0){
645 parseaddr(uchar *to, char *from, int alen)
652 for(i = 0; i < alen; i++){
660 to[i] = strtoul(nip, 0, 16);
668 * keep track of multicast addresses
671 netmulti(Netif *nif, Netfile *f, uchar *addr, int add)
677 if(nif->multicast == nil)
678 return "interface does not support multicast";
682 for(ap = *l; ap; ap = *l){
683 if(memcmp(addr, ap->addr, nif->alen) == 0)
691 *l = ap = smalloc(sizeof(*ap));
692 memmove(ap->addr, addr, nif->alen);
695 h = hash(addr, nif->alen);
696 ap->hnext = nif->mhash[h];
703 nif->multicast(nif->arg, addr, 1);
705 if(i < 8*sizeof(f->maddr)){
706 if((f->maddr[i/8] & (1<<(i%8))) == 0)
708 f->maddr[i/8] |= 1<<(i%8);
711 if(ap == 0 || ap->ref == 0)
716 nif->multicast(nif->arg, addr, 0);
718 if(i < 8*sizeof(f->maddr)){
719 if((f->maddr[i/8] & (1<<(i%8))) != 0)
721 f->maddr[i/8] &= ~(1<<(i%8));