FreeBSD/Linux Kernel Cross Reference
sys/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 sprint(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 }
Cache object: f4638837519c51411255ff3e7c711206
|