]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/netif.c
bind devshr to /shr
[plan9front.git] / sys / src / 9 / port / netif.c
1 #include        "u.h"
2 #include        "../port/lib.h"
3 #include        "mem.h"
4 #include        "dat.h"
5 #include        "fns.h"
6 #include        "../port/error.h"
7 #include        "../port/netif.h"
8
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);
14
15 /*
16  *  set up a new network interface
17  */
18 void
19 netifinit(Netif *nif, char *name, int nfile, ulong limit)
20 {
21         strncpy(nif->name, name, KNAMELEN-1);
22         nif->name[KNAMELEN-1] = 0;
23         nif->nfile = nfile;
24         nif->f = xalloc(nfile*sizeof(Netfile*));
25         if (nif->f == nil)
26                 panic("netifinit: no memory");
27         memset(nif->f, 0, nfile*sizeof(Netfile*));
28         nif->limit = limit;
29 }
30
31 /*
32  *  generate a 3 level directory
33  */
34 static int
35 netifgen(Chan *c, char*, Dirtab *vp, int, int i, Dir *dp)
36 {
37         Qid q;
38         Netif *nif = (Netif*)vp;
39         Netfile *f;
40         int t;
41         int perm;
42         char *o;
43
44         q.type = QTFILE;
45         q.vers = 0;
46
47         /* top level directory contains the name of the network */
48         if(c->qid.path == 0){
49                 switch(i){
50                 case DEVDOTDOT:
51                         q.path = 0;
52                         q.type = QTDIR;
53                         devdir(c, q, ".", 0, eve, 0555, dp);
54                         break;
55                 case 0:
56                         q.path = N2ndqid;
57                         q.type = QTDIR;
58                         strcpy(up->genbuf, nif->name);
59                         devdir(c, q, up->genbuf, 0, eve, 0555, dp);
60                         break;
61                 default:
62                         return -1;
63                 }
64                 return 1;
65         }
66
67         /* second level contains clone plus all the conversations */
68         t = NETTYPE(c->qid.path);
69         if(t == N2ndqid || t == Ncloneqid || t == Naddrqid){
70                 switch(i) {
71                 case DEVDOTDOT:
72                         q.type = QTDIR;
73                         q.path = 0;
74                         devdir(c, q, ".", 0, eve, DMDIR|0555, dp);
75                         break;
76                 case 0:
77                         q.path = Ncloneqid;
78                         devdir(c, q, "clone", 0, eve, 0666, dp);
79                         break;
80                 case 1:
81                         q.path = Naddrqid;
82                         devdir(c, q, "addr", 0, eve, 0666, dp);
83                         break;
84                 case 2:
85                         q.path = Nstatqid;
86                         devdir(c, q, "stats", 0, eve, 0444, dp);
87                         break;
88                 case 3:
89                         q.path = Nifstatqid;
90                         devdir(c, q, "ifstats", 0, eve, 0444, dp);
91                         break;
92                 default:
93                         i -= 4;
94                         if(i >= nif->nfile)
95                                 return -1;
96                         if(nif->f[i] == 0)
97                                 return 0;
98                         q.type = QTDIR;
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);
102                         break;
103                 }
104                 return 1;
105         }
106
107         /* third level */
108         f = nif->f[NETID(c->qid.path)];
109         if(f == 0)
110                 return 0;
111         if(*f->owner){
112                 o = f->owner;
113                 perm = f->mode;
114         } else {
115                 o = eve;
116                 perm = 0666;
117         }
118         switch(i){
119         case DEVDOTDOT:
120                 q.type = QTDIR;
121                 q.path = N2ndqid;
122                 strcpy(up->genbuf, nif->name);
123                 devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
124                 break;
125         case 0:
126                 q.path = NETQID(NETID(c->qid.path), Ndataqid);
127                 devdir(c, q, "data", 0, o, perm, dp);
128                 break;
129         case 1:
130                 q.path = NETQID(NETID(c->qid.path), Nctlqid);
131                 devdir(c, q, "ctl", 0, o, perm, dp);
132                 break;
133         case 2:
134                 q.path = NETQID(NETID(c->qid.path), Nstatqid);
135                 devdir(c, q, "stats", 0, eve, 0444, dp);
136                 break;
137         case 3:
138                 q.path = NETQID(NETID(c->qid.path), Ntypeqid);
139                 devdir(c, q, "type", 0, eve, 0444, dp);
140                 break;
141         case 4:
142                 q.path = NETQID(NETID(c->qid.path), Nifstatqid);
143                 devdir(c, q, "ifstats", 0, eve, 0444, dp);
144                 break;
145         default:
146                 return -1;
147         }
148         return 1;
149 }
150
151 Walkqid*
152 netifwalk(Netif *nif, Chan *c, Chan *nc, char **name, int nname)
153 {
154         return devwalk(c, nc, name, nname, (Dirtab *)nif, 0, netifgen);
155 }
156
157 Chan*
158 netifopen(Netif *nif, Chan *c, int omode)
159 {
160         int id;
161         Netfile *f;
162
163         id = 0;
164         if(c->qid.type & QTDIR){
165                 if(omode != OREAD)
166                         error(Eperm);
167         } else {
168                 switch(NETTYPE(c->qid.path)){
169                 case Ndataqid:
170                 case Nctlqid:
171                         id = NETID(c->qid.path);
172                         openfile(nif, id);
173                         break;
174                 case Ncloneqid:
175                         id = openfile(nif, -1);
176                         c->qid.path = NETQID(id, Nctlqid);
177                         break;
178                 default:
179                         if(omode != OREAD)
180                                 error(Ebadarg);
181                 }
182                 switch(NETTYPE(c->qid.path)){
183                 case Ndataqid:
184                 case Nctlqid:
185                         f = nif->f[id];
186                         if(netown(f, up->user, omode&7) < 0)
187                                 error(Eperm);
188                         break;
189                 }
190         }
191         c->mode = openmode(omode);
192         c->flag |= COPEN;
193         c->offset = 0;
194         c->iounit = qiomaxatomic;
195         return c;
196 }
197
198 long
199 netifread(Netif *nif, Chan *c, void *a, long n, ulong offset)
200 {
201         int i, j;
202         Netfile *f;
203         char *p;
204
205         if(c->qid.type&QTDIR)
206                 return devdirread(c, a, n, (Dirtab*)nif, 0, netifgen);
207
208         switch(NETTYPE(c->qid.path)){
209         case Ndataqid:
210                 f = nif->f[NETID(c->qid.path)];
211                 return qread(f->in, a, n);
212         case Nctlqid:
213                 return readnum(offset, a, n, NETID(c->qid.path), NUMSIZE);
214         case Nstatqid:
215                 p = malloc(READSTR);
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);
232                 free(p);
233                 return n;
234         case Naddrqid:
235                 p = malloc(READSTR);
236                 j = 0;
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);
240                 free(p);
241                 return n;
242         case Ntypeqid:
243                 f = nif->f[NETID(c->qid.path)];
244                 return readnum(offset, a, n, f->type, NUMSIZE);
245         case Nifstatqid:
246                 return 0;
247         }
248         error(Ebadarg);
249         return -1;      /* not reached */
250 }
251
252 Block*
253 netifbread(Netif *nif, Chan *c, long n, ulong offset)
254 {
255         if((c->qid.type & QTDIR) || NETTYPE(c->qid.path) != Ndataqid)
256                 return devbread(c, n, offset);
257
258         return qbread(nif->f[NETID(c->qid.path)]->in, n);
259 }
260
261 /*
262  *  make sure this type isn't already in use on this device
263  */
264 static int
265 typeinuse(Netif *nif, int type)
266 {
267         Netfile *f, **fp, **efp;
268
269         if(type <= 0)
270                 return 0;
271
272         efp = &nif->f[nif->nfile];
273         for(fp = nif->f; fp < efp; fp++){
274                 f = *fp;
275                 if(f == 0)
276                         continue;
277                 if(f->type == type)
278                         return 1;
279         }
280         return 0;
281 }
282
283 /*
284  *  the devxxx.c that calls us handles writing data, it knows best
285  */
286 long
287 netifwrite(Netif *nif, Chan *c, void *a, long n)
288 {
289         Netfile *f;
290         int type;
291         char *p, buf[64];
292         uchar binaddr[Nmaxaddr];
293
294         if(NETTYPE(c->qid.path) != Nctlqid)
295                 error(Eperm);
296
297         if(n >= sizeof(buf))
298                 n = sizeof(buf)-1;
299         memmove(buf, a, n);
300         buf[n] = 0;
301
302         if(waserror()){
303                 qunlock(nif);
304                 nexterror();
305         }
306
307         qlock(nif);
308         f = nif->f[NETID(c->qid.path)];
309         if((p = matchtoken(buf, "connect")) != 0){
310                 type = atoi(p);
311                 if(typeinuse(nif, type))
312                         error(Einuse);
313                 f->type = type;
314                 if(f->type < 0)
315                         nif->all++;
316         } else if(matchtoken(buf, "promiscuous")){
317                 if(f->prom == 0){
318                         if(nif->prom == 0 && nif->promiscuous != nil)
319                                 nif->promiscuous(nif->arg, 1);
320                         f->prom = 1;
321                         nif->prom++;
322                 }
323         } else if((p = matchtoken(buf, "scanbs")) != 0){
324                 /* scan for base stations */
325                 if(f->scan == 0){
326                         type = atoi(p);
327                         if(type < 5)
328                                 type = 5;
329                         if(nif->scanbs != nil)
330                                 nif->scanbs(nif->arg, type);
331                         f->scan = type;
332                         nif->scan++;
333                 }
334         } else if(matchtoken(buf, "bridge")){
335                 f->bridge = 1;
336         } else if(matchtoken(buf, "headersonly")){
337                 f->headersonly = 1;
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);
342                 if(p)
343                         error(p);
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);
348                 if(p)
349                         error(p);
350         } else
351                 n = -1;
352         qunlock(nif);
353         poperror();
354         return n;
355 }
356
357 int
358 netifwstat(Netif *nif, Chan *c, uchar *db, int n)
359 {
360         Dir *dir;
361         Netfile *f;
362         int m;
363
364         f = nif->f[NETID(c->qid.path)];
365         if(f == 0)
366                 error(Enonexist);
367
368         if(netown(f, up->user, OWRITE) < 0)
369                 error(Eperm);
370
371         dir = smalloc(sizeof(Dir)+n);
372         m = convM2D(db, n, &dir[0], (char*)&dir[1]);
373         if(m == 0){
374                 free(dir);
375                 error(Eshortstat);
376         }
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;
381         free(dir);
382         return m;
383 }
384
385 int
386 netifstat(Netif *nif, Chan *c, uchar *db, int n)
387 {
388         return devstat(c, db, n, (Dirtab *)nif, 0, netifgen);
389 }
390
391 void
392 netifclose(Netif *nif, Chan *c)
393 {
394         Netfile *f;
395         int t;
396         Netaddr *ap;
397
398         if((c->flag & COPEN) == 0)
399                 return;
400
401         t = NETTYPE(c->qid.path);
402         if(t != Ndataqid && t != Nctlqid)
403                 return;
404
405         f = nif->f[NETID(c->qid.path)];
406         qlock(f);
407         if(--(f->inuse) == 0){
408                 if(f->prom){
409                         qlock(nif);
410                         if(--(nif->prom) == 0 && nif->promiscuous != nil)
411                                 nif->promiscuous(nif->arg, 0);
412                         qunlock(nif);
413                         f->prom = 0;
414                 }
415                 if(f->scan){
416                         qlock(nif);
417                         if(--(nif->scan) == 0 && nif->scanbs != nil)
418                                 nif->scanbs(nif->arg, 0);
419                         qunlock(nif);
420                         f->prom = 0;
421                         f->scan = 0;
422                 }
423                 if(f->nmaddr){
424                         qlock(nif);
425                         t = 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);
429                         }
430                         qunlock(nif);
431                         f->nmaddr = 0;
432                 }
433                 if(f->type < 0){
434                         qlock(nif);
435                         --(nif->all);
436                         qunlock(nif);
437                 }
438                 f->owner[0] = 0;
439                 f->type = 0;
440                 f->bridge = 0;
441                 f->headersonly = 0;
442                 qclose(f->in);
443         }
444         qunlock(f);
445 }
446
447 Lock netlock;
448
449 static int
450 netown(Netfile *p, char *o, int omode)
451 {
452         static int access[] = { 0400, 0200, 0600, 0100 };
453         int mode;
454         int t;
455
456         lock(&netlock);
457         if(*p->owner){
458                 if(strncmp(o, p->owner, KNAMELEN) == 0) /* User */
459                         mode = p->mode;
460                 else if(strncmp(o, eve, KNAMELEN) == 0) /* Bootes is group */
461                         mode = p->mode<<3;
462                 else
463                         mode = p->mode<<6;              /* Other */
464
465                 t = access[omode&3];
466                 if((t & mode) == t){
467                         unlock(&netlock);
468                         return 0;
469                 } else {
470                         unlock(&netlock);
471                         return -1;
472                 }
473         }
474         strncpy(p->owner, o, KNAMELEN);
475         p->mode = 0660;
476         unlock(&netlock);
477         return 0;
478 }
479
480 /*
481  *  Increment the reference count of a network device.
482  *  If id < 0, return an unused ether device.
483  */
484 static int
485 openfile(Netif *nif, int id)
486 {
487         Netfile *f, **fp, **efp;
488
489         if(id >= 0){
490                 f = nif->f[id];
491                 if(f == 0)
492                         error(Enodev);
493                 qlock(f);
494                 qreopen(f->in);
495                 f->inuse++;
496                 qunlock(f);
497                 return id;
498         }
499
500         qlock(nif);
501         if(waserror()){
502                 qunlock(nif);
503                 nexterror();
504         }
505         efp = &nif->f[nif->nfile];
506         for(fp = nif->f; fp < efp; fp++){
507                 f = *fp;
508                 if(f == 0){
509                         f = malloc(sizeof(Netfile));
510                         if(f == 0)
511                                 exhausted("memory");
512                         f->in = qopen(nif->limit, Qmsg, 0, 0);
513                         if(f->in == nil){
514                                 free(f);
515                                 exhausted("memory");
516                         }
517                         *fp = f;
518                         qlock(f);
519                 } else {
520                         qlock(f);
521                         if(f->inuse){
522                                 qunlock(f);
523                                 continue;
524                         }
525                 }
526                 f->inuse = 1;
527                 qreopen(f->in);
528                 netown(f, up->user, 0);
529                 qunlock(f);
530                 qunlock(nif);
531                 poperror();
532                 return fp - nif->f;
533         }
534         error(Enodev);
535         return -1;      /* not reached */
536 }
537
538 /*
539  *  look for a token starting a string,
540  *  return a pointer to first non-space char after it
541  */
542 static char*
543 matchtoken(char *p, char *token)
544 {
545         int n;
546
547         n = strlen(token);
548         if(strncmp(p, token, n))
549                 return 0;
550         p += n;
551         if(*p == 0)
552                 return p;
553         if(*p != ' ' && *p != '\t' && *p != '\n')
554                 return 0;
555         while(*p == ' ' || *p == '\t' || *p == '\n')
556                 p++;
557         return p;
558 }
559
560 void
561 hnputv(void *p, uvlong v)
562 {
563         uchar *a;
564
565         a = p;
566         hnputl(a, v>>32);
567         hnputl(a+4, v);
568 }
569
570 void
571 hnputl(void *p, uint v)
572 {
573         uchar *a;
574
575         a = p;
576         a[0] = v>>24;
577         a[1] = v>>16;
578         a[2] = v>>8;
579         a[3] = v;
580 }
581
582 void
583 hnputs(void *p, ushort v)
584 {
585         uchar *a;
586
587         a = p;
588         a[0] = v>>8;
589         a[1] = v;
590 }
591
592 uvlong
593 nhgetv(void *p)
594 {
595         uchar *a;
596
597         a = p;
598         return ((vlong)nhgetl(a) << 32) | nhgetl(a+4);
599 }
600
601 uint
602 nhgetl(void *p)
603 {
604         uchar *a;
605
606         a = p;
607         return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0);
608 }
609
610 ushort
611 nhgets(void *p)
612 {
613         uchar *a;
614
615         a = p;
616         return (a[0]<<8)|(a[1]<<0);
617 }
618
619 static ulong
620 hash(uchar *a, int len)
621 {
622         ulong sum = 0;
623
624         while(len-- > 0)
625                 sum = (sum << 1) + *a++;
626         return sum%Nmhash;
627 }
628
629 int
630 activemulti(Netif *nif, uchar *addr, int alen)
631 {
632         Netaddr *hp;
633
634         for(hp = nif->mhash[hash(addr, alen)]; hp; hp = hp->hnext)
635                 if(memcmp(addr, hp->addr, alen) == 0){
636                         if(hp->ref)
637                                 return 1;
638                         else
639                                 break;
640                 }
641         return 0;
642 }
643
644 static int
645 parseaddr(uchar *to, char *from, int alen)
646 {
647         char nip[4];
648         char *p;
649         int i;
650
651         p = from;
652         for(i = 0; i < alen; i++){
653                 if(*p == 0)
654                         return -1;
655                 nip[0] = *p++;
656                 if(*p == 0)
657                         return -1;
658                 nip[1] = *p++;
659                 nip[2] = 0;
660                 to[i] = strtoul(nip, 0, 16);
661                 if(*p == ':')
662                         p++;
663         }
664         return 0;
665 }
666
667 /*
668  *  keep track of multicast addresses
669  */
670 static char*
671 netmulti(Netif *nif, Netfile *f, uchar *addr, int add)
672 {
673         Netaddr **l, *ap;
674         int i;
675         ulong h;
676
677         if(nif->multicast == nil)
678                 return "interface does not support multicast";
679
680         l = &nif->maddr;
681         i = 0;
682         for(ap = *l; ap; ap = *l){
683                 if(memcmp(addr, ap->addr, nif->alen) == 0)
684                         break;
685                 i++;
686                 l = &ap->next;
687         }
688
689         if(add){
690                 if(ap == 0){
691                         *l = ap = smalloc(sizeof(*ap));
692                         memmove(ap->addr, addr, nif->alen);
693                         ap->next = 0;
694                         ap->ref = 1;
695                         h = hash(addr, nif->alen);
696                         ap->hnext = nif->mhash[h];
697                         nif->mhash[h] = ap;
698                 } else {
699                         ap->ref++;
700                 }
701                 if(ap->ref == 1){
702                         nif->nmaddr++;
703                         nif->multicast(nif->arg, addr, 1);
704                 }
705                 if(i < 8*sizeof(f->maddr)){
706                         if((f->maddr[i/8] & (1<<(i%8))) == 0)
707                                 f->nmaddr++;
708                         f->maddr[i/8] |= 1<<(i%8);
709                 }
710         } else {
711                 if(ap == 0 || ap->ref == 0)
712                         return 0;
713                 ap->ref--;
714                 if(ap->ref == 0){
715                         nif->nmaddr--;
716                         nif->multicast(nif->arg, addr, 0);
717                 }
718                 if(i < 8*sizeof(f->maddr)){
719                         if((f->maddr[i/8] & (1<<(i%8))) != 0)
720                                 f->nmaddr--;
721                         f->maddr[i/8] &= ~(1<<(i%8));
722                 }
723         }
724         return 0;
725 }