xref: /plan9-contrib/sys/src/9/port/netif.c (revision 75184bd408f1c14b5ab3ed7d519e0377b9761a74)
17dd7cddfSDavid du Colombier #include	"u.h"
27dd7cddfSDavid du Colombier #include	"../port/lib.h"
37dd7cddfSDavid du Colombier #include	"mem.h"
47dd7cddfSDavid du Colombier #include	"dat.h"
57dd7cddfSDavid du Colombier #include	"fns.h"
67dd7cddfSDavid du Colombier #include	"../port/error.h"
77dd7cddfSDavid du Colombier #include	"../port/netif.h"
87dd7cddfSDavid du Colombier 
97dd7cddfSDavid du Colombier static int netown(Netfile*, char*, int);
107dd7cddfSDavid du Colombier static int openfile(Netif*, int);
117dd7cddfSDavid du Colombier static char* matchtoken(char*, char*);
127dd7cddfSDavid du Colombier static char* netmulti(Netif*, Netfile*, uchar*, int);
137dd7cddfSDavid du Colombier static int parseaddr(uchar*, char*, int);
147dd7cddfSDavid du Colombier 
157dd7cddfSDavid du Colombier /*
167dd7cddfSDavid du Colombier  *  set up a new network interface
177dd7cddfSDavid du Colombier  */
187dd7cddfSDavid du Colombier void
netifinit(Netif * nif,char * name,int nfile,ulong limit)197dd7cddfSDavid du Colombier netifinit(Netif *nif, char *name, int nfile, ulong limit)
207dd7cddfSDavid du Colombier {
219a747e4fSDavid du Colombier 	strncpy(nif->name, name, KNAMELEN-1);
229a747e4fSDavid du Colombier 	nif->name[KNAMELEN-1] = 0;
237dd7cddfSDavid du Colombier 	nif->nfile = nfile;
247dd7cddfSDavid du Colombier 	nif->f = xalloc(nfile*sizeof(Netfile*));
259c63691cSDavid du Colombier 	if (nif->f == nil)
269c63691cSDavid du Colombier 		panic("netifinit: no memory");
277dd7cddfSDavid du Colombier 	memset(nif->f, 0, nfile*sizeof(Netfile*));
287dd7cddfSDavid du Colombier 	nif->limit = limit;
297dd7cddfSDavid du Colombier }
307dd7cddfSDavid du Colombier 
317dd7cddfSDavid du Colombier /*
327dd7cddfSDavid du Colombier  *  generate a 3 level directory
337dd7cddfSDavid du Colombier  */
347dd7cddfSDavid du Colombier static int
netifgen(Chan * c,char *,Dirtab * vp,int,int i,Dir * dp)359a747e4fSDavid du Colombier netifgen(Chan *c, char*, Dirtab *vp, int, int i, Dir *dp)
367dd7cddfSDavid du Colombier {
377dd7cddfSDavid du Colombier 	Qid q;
387dd7cddfSDavid du Colombier 	Netif *nif = (Netif*)vp;
397dd7cddfSDavid du Colombier 	Netfile *f;
407dd7cddfSDavid du Colombier 	int t;
417dd7cddfSDavid du Colombier 	int perm;
427dd7cddfSDavid du Colombier 	char *o;
437dd7cddfSDavid du Colombier 
449a747e4fSDavid du Colombier 	q.type = QTFILE;
457dd7cddfSDavid du Colombier 	q.vers = 0;
467dd7cddfSDavid du Colombier 
477dd7cddfSDavid du Colombier 	/* top level directory contains the name of the network */
489a747e4fSDavid du Colombier 	if(c->qid.path == 0){
497dd7cddfSDavid du Colombier 		switch(i){
507dd7cddfSDavid du Colombier 		case DEVDOTDOT:
519a747e4fSDavid du Colombier 			q.path = 0;
529a747e4fSDavid du Colombier 			q.type = QTDIR;
539a747e4fSDavid du Colombier 			devdir(c, q, ".", 0, eve, 0555, dp);
547dd7cddfSDavid du Colombier 			break;
557dd7cddfSDavid du Colombier 		case 0:
569a747e4fSDavid du Colombier 			q.path = N2ndqid;
579a747e4fSDavid du Colombier 			q.type = QTDIR;
589a747e4fSDavid du Colombier 			strcpy(up->genbuf, nif->name);
599a747e4fSDavid du Colombier 			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
607dd7cddfSDavid du Colombier 			break;
617dd7cddfSDavid du Colombier 		default:
627dd7cddfSDavid du Colombier 			return -1;
637dd7cddfSDavid du Colombier 		}
647dd7cddfSDavid du Colombier 		return 1;
657dd7cddfSDavid du Colombier 	}
667dd7cddfSDavid du Colombier 
677dd7cddfSDavid du Colombier 	/* second level contains clone plus all the conversations */
687dd7cddfSDavid du Colombier 	t = NETTYPE(c->qid.path);
69*75184bd4SDavid du Colombier 	if(t == N2ndqid || t == Ncloneqid || t == Naddrqid || t == Nstatqid || t == Nifstatqid){
707dd7cddfSDavid du Colombier 		switch(i) {
717dd7cddfSDavid du Colombier 		case DEVDOTDOT:
729a747e4fSDavid du Colombier 			q.type = QTDIR;
739a747e4fSDavid du Colombier 			q.path = 0;
749a747e4fSDavid du Colombier 			devdir(c, q, ".", 0, eve, DMDIR|0555, dp);
757dd7cddfSDavid du Colombier 			break;
767dd7cddfSDavid du Colombier 		case 0:
777dd7cddfSDavid du Colombier 			q.path = Ncloneqid;
787dd7cddfSDavid du Colombier 			devdir(c, q, "clone", 0, eve, 0666, dp);
797dd7cddfSDavid du Colombier 			break;
807dd7cddfSDavid du Colombier 		case 1:
817dd7cddfSDavid du Colombier 			q.path = Naddrqid;
827dd7cddfSDavid du Colombier 			devdir(c, q, "addr", 0, eve, 0666, dp);
837dd7cddfSDavid du Colombier 			break;
843432ceaeSDavid du Colombier 		case 2:
853432ceaeSDavid du Colombier 			q.path = Nstatqid;
863432ceaeSDavid du Colombier 			devdir(c, q, "stats", 0, eve, 0444, dp);
873432ceaeSDavid du Colombier 			break;
883432ceaeSDavid du Colombier 		case 3:
893432ceaeSDavid du Colombier 			q.path = Nifstatqid;
903432ceaeSDavid du Colombier 			devdir(c, q, "ifstats", 0, eve, 0444, dp);
913432ceaeSDavid du Colombier 			break;
927dd7cddfSDavid du Colombier 		default:
933432ceaeSDavid du Colombier 			i -= 4;
947dd7cddfSDavid du Colombier 			if(i >= nif->nfile)
957dd7cddfSDavid du Colombier 				return -1;
967dd7cddfSDavid du Colombier 			if(nif->f[i] == 0)
977dd7cddfSDavid du Colombier 				return 0;
989a747e4fSDavid du Colombier 			q.type = QTDIR;
999a747e4fSDavid du Colombier 			q.path = NETQID(i, N3rdqid);
10057d98441SDavid du Colombier 			snprint(up->genbuf, sizeof up->genbuf, "%d", i);
1019a747e4fSDavid du Colombier 			devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
1027dd7cddfSDavid du Colombier 			break;
1037dd7cddfSDavid du Colombier 		}
1047dd7cddfSDavid du Colombier 		return 1;
1057dd7cddfSDavid du Colombier 	}
1067dd7cddfSDavid du Colombier 
1077dd7cddfSDavid du Colombier 	/* third level */
1087dd7cddfSDavid du Colombier 	f = nif->f[NETID(c->qid.path)];
1097dd7cddfSDavid du Colombier 	if(f == 0)
1107dd7cddfSDavid du Colombier 		return 0;
1117dd7cddfSDavid du Colombier 	if(*f->owner){
1127dd7cddfSDavid du Colombier 		o = f->owner;
1137dd7cddfSDavid du Colombier 		perm = f->mode;
1147dd7cddfSDavid du Colombier 	} else {
1157dd7cddfSDavid du Colombier 		o = eve;
1167dd7cddfSDavid du Colombier 		perm = 0666;
1177dd7cddfSDavid du Colombier 	}
1187dd7cddfSDavid du Colombier 	switch(i){
1197dd7cddfSDavid du Colombier 	case DEVDOTDOT:
1209a747e4fSDavid du Colombier 		q.type = QTDIR;
1219a747e4fSDavid du Colombier 		q.path = N2ndqid;
1229a747e4fSDavid du Colombier 		strcpy(up->genbuf, nif->name);
1239a747e4fSDavid du Colombier 		devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
1247dd7cddfSDavid du Colombier 		break;
1257dd7cddfSDavid du Colombier 	case 0:
1267dd7cddfSDavid du Colombier 		q.path = NETQID(NETID(c->qid.path), Ndataqid);
1277dd7cddfSDavid du Colombier 		devdir(c, q, "data", 0, o, perm, dp);
1287dd7cddfSDavid du Colombier 		break;
1297dd7cddfSDavid du Colombier 	case 1:
1307dd7cddfSDavid du Colombier 		q.path = NETQID(NETID(c->qid.path), Nctlqid);
1317dd7cddfSDavid du Colombier 		devdir(c, q, "ctl", 0, o, perm, dp);
1327dd7cddfSDavid du Colombier 		break;
1337dd7cddfSDavid du Colombier 	case 2:
1347dd7cddfSDavid du Colombier 		q.path = NETQID(NETID(c->qid.path), Nstatqid);
1357dd7cddfSDavid du Colombier 		devdir(c, q, "stats", 0, eve, 0444, dp);
1367dd7cddfSDavid du Colombier 		break;
1377dd7cddfSDavid du Colombier 	case 3:
1387dd7cddfSDavid du Colombier 		q.path = NETQID(NETID(c->qid.path), Ntypeqid);
1397dd7cddfSDavid du Colombier 		devdir(c, q, "type", 0, eve, 0444, dp);
1407dd7cddfSDavid du Colombier 		break;
1417dd7cddfSDavid du Colombier 	case 4:
1427dd7cddfSDavid du Colombier 		q.path = NETQID(NETID(c->qid.path), Nifstatqid);
1437dd7cddfSDavid du Colombier 		devdir(c, q, "ifstats", 0, eve, 0444, dp);
1447dd7cddfSDavid du Colombier 		break;
1457dd7cddfSDavid du Colombier 	default:
1467dd7cddfSDavid du Colombier 		return -1;
1477dd7cddfSDavid du Colombier 	}
1487dd7cddfSDavid du Colombier 	return 1;
1497dd7cddfSDavid du Colombier }
1507dd7cddfSDavid du Colombier 
1519a747e4fSDavid du Colombier Walkqid*
netifwalk(Netif * nif,Chan * c,Chan * nc,char ** name,int nname)1529a747e4fSDavid du Colombier netifwalk(Netif *nif, Chan *c, Chan *nc, char **name, int nname)
1537dd7cddfSDavid du Colombier {
1549a747e4fSDavid du Colombier 	return devwalk(c, nc, name, nname, (Dirtab *)nif, 0, netifgen);
1557dd7cddfSDavid du Colombier }
1567dd7cddfSDavid du Colombier 
1577dd7cddfSDavid du Colombier Chan*
netifopen(Netif * nif,Chan * c,int omode)1587dd7cddfSDavid du Colombier netifopen(Netif *nif, Chan *c, int omode)
1597dd7cddfSDavid du Colombier {
1607dd7cddfSDavid du Colombier 	int id;
1617dd7cddfSDavid du Colombier 	Netfile *f;
1627dd7cddfSDavid du Colombier 
1637dd7cddfSDavid du Colombier 	id = 0;
1649a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR){
1657dd7cddfSDavid du Colombier 		if(omode != OREAD)
1667dd7cddfSDavid du Colombier 			error(Eperm);
1677dd7cddfSDavid du Colombier 	} else {
1687dd7cddfSDavid du Colombier 		switch(NETTYPE(c->qid.path)){
1697dd7cddfSDavid du Colombier 		case Ndataqid:
1707dd7cddfSDavid du Colombier 		case Nctlqid:
1717dd7cddfSDavid du Colombier 			id = NETID(c->qid.path);
1727dd7cddfSDavid du Colombier 			openfile(nif, id);
1737dd7cddfSDavid du Colombier 			break;
1747dd7cddfSDavid du Colombier 		case Ncloneqid:
1757dd7cddfSDavid du Colombier 			id = openfile(nif, -1);
1767dd7cddfSDavid du Colombier 			c->qid.path = NETQID(id, Nctlqid);
1777dd7cddfSDavid du Colombier 			break;
1787dd7cddfSDavid du Colombier 		default:
1797dd7cddfSDavid du Colombier 			if(omode != OREAD)
1807dd7cddfSDavid du Colombier 				error(Ebadarg);
1817dd7cddfSDavid du Colombier 		}
1827dd7cddfSDavid du Colombier 		switch(NETTYPE(c->qid.path)){
1837dd7cddfSDavid du Colombier 		case Ndataqid:
1847dd7cddfSDavid du Colombier 		case Nctlqid:
1857dd7cddfSDavid du Colombier 			f = nif->f[id];
1867dd7cddfSDavid du Colombier 			if(netown(f, up->user, omode&7) < 0)
1877dd7cddfSDavid du Colombier 				error(Eperm);
1887dd7cddfSDavid du Colombier 			break;
1897dd7cddfSDavid du Colombier 		}
1907dd7cddfSDavid du Colombier 	}
1917dd7cddfSDavid du Colombier 	c->mode = openmode(omode);
1927dd7cddfSDavid du Colombier 	c->flag |= COPEN;
1937dd7cddfSDavid du Colombier 	c->offset = 0;
1949a747e4fSDavid du Colombier 	c->iounit = qiomaxatomic;
1957dd7cddfSDavid du Colombier 	return c;
1967dd7cddfSDavid du Colombier }
1977dd7cddfSDavid du Colombier 
1987dd7cddfSDavid du Colombier long
netifread(Netif * nif,Chan * c,void * a,long n,ulong offset)1997dd7cddfSDavid du Colombier netifread(Netif *nif, Chan *c, void *a, long n, ulong offset)
2007dd7cddfSDavid du Colombier {
2017dd7cddfSDavid du Colombier 	int i, j;
2027dd7cddfSDavid du Colombier 	Netfile *f;
2037dd7cddfSDavid du Colombier 	char *p;
2047dd7cddfSDavid du Colombier 
2059a747e4fSDavid du Colombier 	if(c->qid.type&QTDIR)
2067dd7cddfSDavid du Colombier 		return devdirread(c, a, n, (Dirtab*)nif, 0, netifgen);
2077dd7cddfSDavid du Colombier 
2087dd7cddfSDavid du Colombier 	switch(NETTYPE(c->qid.path)){
2097dd7cddfSDavid du Colombier 	case Ndataqid:
2107dd7cddfSDavid du Colombier 		f = nif->f[NETID(c->qid.path)];
2117dd7cddfSDavid du Colombier 		return qread(f->in, a, n);
2127dd7cddfSDavid du Colombier 	case Nctlqid:
2137dd7cddfSDavid du Colombier 		return readnum(offset, a, n, NETID(c->qid.path), NUMSIZE);
2147dd7cddfSDavid du Colombier 	case Nstatqid:
2157dd7cddfSDavid du Colombier 		p = malloc(READSTR);
216aa72973aSDavid du Colombier 		if(p == nil)
217aa72973aSDavid du Colombier 			error(Enomem);
21808cb4641SDavid du Colombier 		j = snprint(p, READSTR, "in: %llud\n", nif->inpackets);
2193432ceaeSDavid du Colombier 		j += snprint(p+j, READSTR-j, "link: %d\n", nif->link);
22008cb4641SDavid du Colombier 		j += snprint(p+j, READSTR-j, "out: %llud\n", nif->outpackets);
2217dd7cddfSDavid du Colombier 		j += snprint(p+j, READSTR-j, "crc errs: %d\n", nif->crcs);
2227dd7cddfSDavid du Colombier 		j += snprint(p+j, READSTR-j, "overflows: %d\n", nif->overflows);
2237dd7cddfSDavid du Colombier 		j += snprint(p+j, READSTR-j, "soft overflows: %d\n", nif->soverflows);
2247dd7cddfSDavid du Colombier 		j += snprint(p+j, READSTR-j, "framing errs: %d\n", nif->frames);
2257dd7cddfSDavid du Colombier 		j += snprint(p+j, READSTR-j, "buffer errs: %d\n", nif->buffs);
2267dd7cddfSDavid du Colombier 		j += snprint(p+j, READSTR-j, "output errs: %d\n", nif->oerrs);
2277dd7cddfSDavid du Colombier 		j += snprint(p+j, READSTR-j, "prom: %d\n", nif->prom);
2283f695129SDavid du Colombier 		j += snprint(p+j, READSTR-j, "mbps: %d\n", nif->mbps);
2297dd7cddfSDavid du Colombier 		j += snprint(p+j, READSTR-j, "addr: ");
2307dd7cddfSDavid du Colombier 		for(i = 0; i < nif->alen; i++)
2317dd7cddfSDavid du Colombier 			j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]);
2327dd7cddfSDavid du Colombier 		snprint(p+j, READSTR-j, "\n");
2337dd7cddfSDavid du Colombier 		n = readstr(offset, a, n, p);
2347dd7cddfSDavid du Colombier 		free(p);
2357dd7cddfSDavid du Colombier 		return n;
2367dd7cddfSDavid du Colombier 	case Naddrqid:
2377dd7cddfSDavid du Colombier 		p = malloc(READSTR);
238aa72973aSDavid du Colombier 		if(p == nil)
239aa72973aSDavid du Colombier 			error(Enomem);
2407dd7cddfSDavid du Colombier 		j = 0;
2417dd7cddfSDavid du Colombier 		for(i = 0; i < nif->alen; i++)
2427dd7cddfSDavid du Colombier 			j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]);
2437dd7cddfSDavid du Colombier 		n = readstr(offset, a, n, p);
2447dd7cddfSDavid du Colombier 		free(p);
2457dd7cddfSDavid du Colombier 		return n;
2467dd7cddfSDavid du Colombier 	case Ntypeqid:
2477dd7cddfSDavid du Colombier 		f = nif->f[NETID(c->qid.path)];
2487dd7cddfSDavid du Colombier 		return readnum(offset, a, n, f->type, NUMSIZE);
2497dd7cddfSDavid du Colombier 	case Nifstatqid:
2507dd7cddfSDavid du Colombier 		return 0;
2517dd7cddfSDavid du Colombier 	}
2527dd7cddfSDavid du Colombier 	error(Ebadarg);
2537dd7cddfSDavid du Colombier 	return -1;	/* not reached */
2547dd7cddfSDavid du Colombier }
2557dd7cddfSDavid du Colombier 
2567dd7cddfSDavid du Colombier Block*
netifbread(Netif * nif,Chan * c,long n,ulong offset)2577dd7cddfSDavid du Colombier netifbread(Netif *nif, Chan *c, long n, ulong offset)
2587dd7cddfSDavid du Colombier {
2599a747e4fSDavid du Colombier 	if((c->qid.type & QTDIR) || NETTYPE(c->qid.path) != Ndataqid)
2607dd7cddfSDavid du Colombier 		return devbread(c, n, offset);
2617dd7cddfSDavid du Colombier 
2627dd7cddfSDavid du Colombier 	return qbread(nif->f[NETID(c->qid.path)]->in, n);
2637dd7cddfSDavid du Colombier }
2647dd7cddfSDavid du Colombier 
2657dd7cddfSDavid du Colombier /*
2667dd7cddfSDavid du Colombier  *  make sure this type isn't already in use on this device
2677dd7cddfSDavid du Colombier  */
2687dd7cddfSDavid du Colombier static int
typeinuse(Netif * nif,int type)2697dd7cddfSDavid du Colombier typeinuse(Netif *nif, int type)
2707dd7cddfSDavid du Colombier {
2717dd7cddfSDavid du Colombier 	Netfile *f, **fp, **efp;
2727dd7cddfSDavid du Colombier 
2737dd7cddfSDavid du Colombier 	if(type <= 0)
2747dd7cddfSDavid du Colombier 		return 0;
2757dd7cddfSDavid du Colombier 
2767dd7cddfSDavid du Colombier 	efp = &nif->f[nif->nfile];
2777dd7cddfSDavid du Colombier 	for(fp = nif->f; fp < efp; fp++){
2787dd7cddfSDavid du Colombier 		f = *fp;
2797dd7cddfSDavid du Colombier 		if(f == 0)
2807dd7cddfSDavid du Colombier 			continue;
2817dd7cddfSDavid du Colombier 		if(f->type == type)
2827dd7cddfSDavid du Colombier 			return 1;
2837dd7cddfSDavid du Colombier 	}
2847dd7cddfSDavid du Colombier 	return 0;
2857dd7cddfSDavid du Colombier }
2867dd7cddfSDavid du Colombier 
2877dd7cddfSDavid du Colombier /*
2887dd7cddfSDavid du Colombier  *  the devxxx.c that calls us handles writing data, it knows best
2897dd7cddfSDavid du Colombier  */
2907dd7cddfSDavid du Colombier long
netifwrite(Netif * nif,Chan * c,void * a,long n)2917dd7cddfSDavid du Colombier netifwrite(Netif *nif, Chan *c, void *a, long n)
2927dd7cddfSDavid du Colombier {
2937dd7cddfSDavid du Colombier 	Netfile *f;
2947dd7cddfSDavid du Colombier 	int type;
2957dd7cddfSDavid du Colombier 	char *p, buf[64];
2967dd7cddfSDavid du Colombier 	uchar binaddr[Nmaxaddr];
2977dd7cddfSDavid du Colombier 
2987dd7cddfSDavid du Colombier 	if(NETTYPE(c->qid.path) != Nctlqid)
2997dd7cddfSDavid du Colombier 		error(Eperm);
3007dd7cddfSDavid du Colombier 
3017dd7cddfSDavid du Colombier 	if(n >= sizeof(buf))
3027dd7cddfSDavid du Colombier 		n = sizeof(buf)-1;
3037dd7cddfSDavid du Colombier 	memmove(buf, a, n);
3047dd7cddfSDavid du Colombier 	buf[n] = 0;
3057dd7cddfSDavid du Colombier 
3067dd7cddfSDavid du Colombier 	if(waserror()){
3077dd7cddfSDavid du Colombier 		qunlock(nif);
3087dd7cddfSDavid du Colombier 		nexterror();
3097dd7cddfSDavid du Colombier 	}
3107dd7cddfSDavid du Colombier 
3117dd7cddfSDavid du Colombier 	qlock(nif);
3127dd7cddfSDavid du Colombier 	f = nif->f[NETID(c->qid.path)];
3137dd7cddfSDavid du Colombier 	if((p = matchtoken(buf, "connect")) != 0){
3147dd7cddfSDavid du Colombier 		type = atoi(p);
3157dd7cddfSDavid du Colombier 		if(typeinuse(nif, type))
3167dd7cddfSDavid du Colombier 			error(Einuse);
3177dd7cddfSDavid du Colombier 		f->type = type;
3187dd7cddfSDavid du Colombier 		if(f->type < 0)
3197dd7cddfSDavid du Colombier 			nif->all++;
3207dd7cddfSDavid du Colombier 	} else if(matchtoken(buf, "promiscuous")){
3217dd7cddfSDavid du Colombier 		if(f->prom == 0){
3227dd7cddfSDavid du Colombier 			if(nif->prom == 0 && nif->promiscuous != nil)
3237dd7cddfSDavid du Colombier 				nif->promiscuous(nif->arg, 1);
3247dd7cddfSDavid du Colombier 			f->prom = 1;
3257dd7cddfSDavid du Colombier 			nif->prom++;
3267dd7cddfSDavid du Colombier 		}
32715763c87SDavid du Colombier 	} else if((p = matchtoken(buf, "scanbs")) != 0){
32815763c87SDavid du Colombier 		/* scan for base stations */
32915763c87SDavid du Colombier 		if(f->scan == 0){
33015763c87SDavid du Colombier 			type = atoi(p);
33115763c87SDavid du Colombier 			if(type < 5)
33215763c87SDavid du Colombier 				type = 5;
33315763c87SDavid du Colombier 			if(nif->scanbs != nil)
33415763c87SDavid du Colombier 				nif->scanbs(nif->arg, type);
33515763c87SDavid du Colombier 			f->scan = type;
33615763c87SDavid du Colombier 			nif->scan++;
33715763c87SDavid du Colombier 		}
3387dd7cddfSDavid du Colombier 	} else if(matchtoken(buf, "bridge")){
3397dd7cddfSDavid du Colombier 		f->bridge = 1;
3407dd7cddfSDavid du Colombier 	} else if(matchtoken(buf, "headersonly")){
3417dd7cddfSDavid du Colombier 		f->headersonly = 1;
3427dd7cddfSDavid du Colombier 	} else if((p = matchtoken(buf, "addmulti")) != 0){
3437dd7cddfSDavid du Colombier 		if(parseaddr(binaddr, p, nif->alen) < 0)
3447dd7cddfSDavid du Colombier 			error("bad address");
3457dd7cddfSDavid du Colombier 		p = netmulti(nif, f, binaddr, 1);
3467dd7cddfSDavid du Colombier 		if(p)
3477dd7cddfSDavid du Colombier 			error(p);
3487dd7cddfSDavid du Colombier 	} else if((p = matchtoken(buf, "remmulti")) != 0){
3497dd7cddfSDavid du Colombier 		if(parseaddr(binaddr, p, nif->alen) < 0)
3507dd7cddfSDavid du Colombier 			error("bad address");
3517dd7cddfSDavid du Colombier 		p = netmulti(nif, f, binaddr, 0);
3527dd7cddfSDavid du Colombier 		if(p)
3537dd7cddfSDavid du Colombier 			error(p);
35480ee5cbfSDavid du Colombier 	} else
35580ee5cbfSDavid du Colombier 		n = -1;
3567dd7cddfSDavid du Colombier 	qunlock(nif);
3577dd7cddfSDavid du Colombier 	poperror();
3587dd7cddfSDavid du Colombier 	return n;
3597dd7cddfSDavid du Colombier }
3607dd7cddfSDavid du Colombier 
3619a747e4fSDavid du Colombier int
netifwstat(Netif * nif,Chan * c,uchar * db,int n)3629a747e4fSDavid du Colombier netifwstat(Netif *nif, Chan *c, uchar *db, int n)
3637dd7cddfSDavid du Colombier {
3649a747e4fSDavid du Colombier 	Dir *dir;
3657dd7cddfSDavid du Colombier 	Netfile *f;
3669a747e4fSDavid du Colombier 	int m;
3677dd7cddfSDavid du Colombier 
3687dd7cddfSDavid du Colombier 	f = nif->f[NETID(c->qid.path)];
3697dd7cddfSDavid du Colombier 	if(f == 0)
3707dd7cddfSDavid du Colombier 		error(Enonexist);
3717dd7cddfSDavid du Colombier 
3727dd7cddfSDavid du Colombier 	if(netown(f, up->user, OWRITE) < 0)
3737dd7cddfSDavid du Colombier 		error(Eperm);
3747dd7cddfSDavid du Colombier 
3759a747e4fSDavid du Colombier 	dir = smalloc(sizeof(Dir)+n);
3769a747e4fSDavid du Colombier 	m = convM2D(db, n, &dir[0], (char*)&dir[1]);
3779a747e4fSDavid du Colombier 	if(m == 0){
3789a747e4fSDavid du Colombier 		free(dir);
3799a747e4fSDavid du Colombier 		error(Eshortstat);
3809a747e4fSDavid du Colombier 	}
381*75184bd4SDavid du Colombier 	if(!emptystr(dir[0].uid)){
382*75184bd4SDavid du Colombier 		strncpy(f->owner, dir[0].uid, KNAMELEN-1);
383*75184bd4SDavid du Colombier 		f->owner[KNAMELEN-1] = 0;
384*75184bd4SDavid du Colombier 	}
3859a747e4fSDavid du Colombier 	if(dir[0].mode != ~0UL)
3869a747e4fSDavid du Colombier 		f->mode = dir[0].mode;
3879a747e4fSDavid du Colombier 	free(dir);
3889a747e4fSDavid du Colombier 	return m;
3897dd7cddfSDavid du Colombier }
3907dd7cddfSDavid du Colombier 
3919a747e4fSDavid du Colombier int
netifstat(Netif * nif,Chan * c,uchar * db,int n)3929a747e4fSDavid du Colombier netifstat(Netif *nif, Chan *c, uchar *db, int n)
3937dd7cddfSDavid du Colombier {
3949a747e4fSDavid du Colombier 	return devstat(c, db, n, (Dirtab *)nif, 0, netifgen);
3957dd7cddfSDavid du Colombier }
3967dd7cddfSDavid du Colombier 
3977dd7cddfSDavid du Colombier void
netifclose(Netif * nif,Chan * c)3987dd7cddfSDavid du Colombier netifclose(Netif *nif, Chan *c)
3997dd7cddfSDavid du Colombier {
4007dd7cddfSDavid du Colombier 	Netfile *f;
4017dd7cddfSDavid du Colombier 	int t;
4027dd7cddfSDavid du Colombier 	Netaddr *ap;
4037dd7cddfSDavid du Colombier 
4047dd7cddfSDavid du Colombier 	if((c->flag & COPEN) == 0)
4057dd7cddfSDavid du Colombier 		return;
4067dd7cddfSDavid du Colombier 
4077dd7cddfSDavid du Colombier 	t = NETTYPE(c->qid.path);
4087dd7cddfSDavid du Colombier 	if(t != Ndataqid && t != Nctlqid)
4097dd7cddfSDavid du Colombier 		return;
4107dd7cddfSDavid du Colombier 
4117dd7cddfSDavid du Colombier 	f = nif->f[NETID(c->qid.path)];
4127dd7cddfSDavid du Colombier 	qlock(f);
4137dd7cddfSDavid du Colombier 	if(--(f->inuse) == 0){
4147dd7cddfSDavid du Colombier 		if(f->prom){
4157dd7cddfSDavid du Colombier 			qlock(nif);
4167dd7cddfSDavid du Colombier 			if(--(nif->prom) == 0 && nif->promiscuous != nil)
4177dd7cddfSDavid du Colombier 				nif->promiscuous(nif->arg, 0);
4187dd7cddfSDavid du Colombier 			qunlock(nif);
4197dd7cddfSDavid du Colombier 			f->prom = 0;
4207dd7cddfSDavid du Colombier 		}
42115763c87SDavid du Colombier 		if(f->scan){
42215763c87SDavid du Colombier 			qlock(nif);
42315763c87SDavid du Colombier 			if(--(nif->scan) == 0 && nif->scanbs != nil)
42415763c87SDavid du Colombier 				nif->scanbs(nif->arg, 0);
42515763c87SDavid du Colombier 			qunlock(nif);
42615763c87SDavid du Colombier 			f->prom = 0;
42715763c87SDavid du Colombier 			f->scan = 0;
42815763c87SDavid du Colombier 		}
4297dd7cddfSDavid du Colombier 		if(f->nmaddr){
4307dd7cddfSDavid du Colombier 			qlock(nif);
4317dd7cddfSDavid du Colombier 			t = 0;
4327dd7cddfSDavid du Colombier 			for(ap = nif->maddr; ap; ap = ap->next){
4337dd7cddfSDavid du Colombier 				if(f->maddr[t/8] & (1<<(t%8)))
4347dd7cddfSDavid du Colombier 					netmulti(nif, f, ap->addr, 0);
4357dd7cddfSDavid du Colombier 			}
4367dd7cddfSDavid du Colombier 			qunlock(nif);
4377dd7cddfSDavid du Colombier 			f->nmaddr = 0;
4387dd7cddfSDavid du Colombier 		}
4397dd7cddfSDavid du Colombier 		if(f->type < 0){
4407dd7cddfSDavid du Colombier 			qlock(nif);
4417dd7cddfSDavid du Colombier 			--(nif->all);
4427dd7cddfSDavid du Colombier 			qunlock(nif);
4437dd7cddfSDavid du Colombier 		}
4447dd7cddfSDavid du Colombier 		f->owner[0] = 0;
4457dd7cddfSDavid du Colombier 		f->type = 0;
4469a747e4fSDavid du Colombier 		f->bridge = 0;
4479a747e4fSDavid du Colombier 		f->headersonly = 0;
4487dd7cddfSDavid du Colombier 		qclose(f->in);
4497dd7cddfSDavid du Colombier 	}
4507dd7cddfSDavid du Colombier 	qunlock(f);
4517dd7cddfSDavid du Colombier }
4527dd7cddfSDavid du Colombier 
4537dd7cddfSDavid du Colombier Lock netlock;
4547dd7cddfSDavid du Colombier 
4557dd7cddfSDavid du Colombier static int
netown(Netfile * p,char * o,int omode)4567dd7cddfSDavid du Colombier netown(Netfile *p, char *o, int omode)
4577dd7cddfSDavid du Colombier {
4587dd7cddfSDavid du Colombier 	static int access[] = { 0400, 0200, 0600, 0100 };
4597dd7cddfSDavid du Colombier 	int mode;
4607dd7cddfSDavid du Colombier 	int t;
4617dd7cddfSDavid du Colombier 
4627dd7cddfSDavid du Colombier 	lock(&netlock);
4637dd7cddfSDavid du Colombier 	if(*p->owner){
4649a747e4fSDavid du Colombier 		if(strncmp(o, p->owner, KNAMELEN) == 0)	/* User */
4657dd7cddfSDavid du Colombier 			mode = p->mode;
4669a747e4fSDavid du Colombier 		else if(strncmp(o, eve, KNAMELEN) == 0)	/* Bootes is group */
4677dd7cddfSDavid du Colombier 			mode = p->mode<<3;
4687dd7cddfSDavid du Colombier 		else
4697dd7cddfSDavid du Colombier 			mode = p->mode<<6;		/* Other */
4707dd7cddfSDavid du Colombier 
4717dd7cddfSDavid du Colombier 		t = access[omode&3];
4727dd7cddfSDavid du Colombier 		if((t & mode) == t){
4737dd7cddfSDavid du Colombier 			unlock(&netlock);
4747dd7cddfSDavid du Colombier 			return 0;
4757dd7cddfSDavid du Colombier 		} else {
4767dd7cddfSDavid du Colombier 			unlock(&netlock);
4777dd7cddfSDavid du Colombier 			return -1;
4787dd7cddfSDavid du Colombier 		}
4797dd7cddfSDavid du Colombier 	}
480*75184bd4SDavid du Colombier 	strncpy(p->owner, o, KNAMELEN-1);
481*75184bd4SDavid du Colombier 	p->owner[KNAMELEN-1] = 0;
4827dd7cddfSDavid du Colombier 	p->mode = 0660;
4837dd7cddfSDavid du Colombier 	unlock(&netlock);
4847dd7cddfSDavid du Colombier 	return 0;
4857dd7cddfSDavid du Colombier }
4867dd7cddfSDavid du Colombier 
4877dd7cddfSDavid du Colombier /*
4887dd7cddfSDavid du Colombier  *  Increment the reference count of a network device.
4897dd7cddfSDavid du Colombier  *  If id < 0, return an unused ether device.
4907dd7cddfSDavid du Colombier  */
4917dd7cddfSDavid du Colombier static int
openfile(Netif * nif,int id)4927dd7cddfSDavid du Colombier openfile(Netif *nif, int id)
4937dd7cddfSDavid du Colombier {
4947dd7cddfSDavid du Colombier 	Netfile *f, **fp, **efp;
4957dd7cddfSDavid du Colombier 
4967dd7cddfSDavid du Colombier 	if(id >= 0){
4977dd7cddfSDavid du Colombier 		f = nif->f[id];
4987dd7cddfSDavid du Colombier 		if(f == 0)
4997dd7cddfSDavid du Colombier 			error(Enodev);
5007dd7cddfSDavid du Colombier 		qlock(f);
5017dd7cddfSDavid du Colombier 		qreopen(f->in);
5027dd7cddfSDavid du Colombier 		f->inuse++;
5037dd7cddfSDavid du Colombier 		qunlock(f);
5047dd7cddfSDavid du Colombier 		return id;
5057dd7cddfSDavid du Colombier 	}
5067dd7cddfSDavid du Colombier 
5077dd7cddfSDavid du Colombier 	qlock(nif);
5087dd7cddfSDavid du Colombier 	if(waserror()){
5097dd7cddfSDavid du Colombier 		qunlock(nif);
5107dd7cddfSDavid du Colombier 		nexterror();
5117dd7cddfSDavid du Colombier 	}
5127dd7cddfSDavid du Colombier 	efp = &nif->f[nif->nfile];
5137dd7cddfSDavid du Colombier 	for(fp = nif->f; fp < efp; fp++){
5147dd7cddfSDavid du Colombier 		f = *fp;
5157dd7cddfSDavid du Colombier 		if(f == 0){
5167dd7cddfSDavid du Colombier 			f = malloc(sizeof(Netfile));
5177dd7cddfSDavid du Colombier 			if(f == 0)
5187dd7cddfSDavid du Colombier 				exhausted("memory");
5193ff48bf5SDavid du Colombier 			f->in = qopen(nif->limit, Qmsg, 0, 0);
5207dd7cddfSDavid du Colombier 			if(f->in == nil){
5217dd7cddfSDavid du Colombier 				free(f);
5227dd7cddfSDavid du Colombier 				exhausted("memory");
5237dd7cddfSDavid du Colombier 			}
5247dd7cddfSDavid du Colombier 			*fp = f;
5257dd7cddfSDavid du Colombier 			qlock(f);
5267dd7cddfSDavid du Colombier 		} else {
5277dd7cddfSDavid du Colombier 			qlock(f);
5287dd7cddfSDavid du Colombier 			if(f->inuse){
5297dd7cddfSDavid du Colombier 				qunlock(f);
5307dd7cddfSDavid du Colombier 				continue;
5317dd7cddfSDavid du Colombier 			}
5327dd7cddfSDavid du Colombier 		}
5337dd7cddfSDavid du Colombier 		f->inuse = 1;
5347dd7cddfSDavid du Colombier 		qreopen(f->in);
5357dd7cddfSDavid du Colombier 		netown(f, up->user, 0);
5367dd7cddfSDavid du Colombier 		qunlock(f);
5377dd7cddfSDavid du Colombier 		qunlock(nif);
5387dd7cddfSDavid du Colombier 		poperror();
5397dd7cddfSDavid du Colombier 		return fp - nif->f;
5407dd7cddfSDavid du Colombier 	}
5417dd7cddfSDavid du Colombier 	error(Enodev);
5427dd7cddfSDavid du Colombier 	return -1;	/* not reached */
5437dd7cddfSDavid du Colombier }
5447dd7cddfSDavid du Colombier 
5457dd7cddfSDavid du Colombier /*
5467dd7cddfSDavid du Colombier  *  look for a token starting a string,
5477dd7cddfSDavid du Colombier  *  return a pointer to first non-space char after it
5487dd7cddfSDavid du Colombier  */
5497dd7cddfSDavid du Colombier static char*
matchtoken(char * p,char * token)5507dd7cddfSDavid du Colombier matchtoken(char *p, char *token)
5517dd7cddfSDavid du Colombier {
5527dd7cddfSDavid du Colombier 	int n;
5537dd7cddfSDavid du Colombier 
5547dd7cddfSDavid du Colombier 	n = strlen(token);
5557dd7cddfSDavid du Colombier 	if(strncmp(p, token, n))
5567dd7cddfSDavid du Colombier 		return 0;
5577dd7cddfSDavid du Colombier 	p += n;
5587dd7cddfSDavid du Colombier 	if(*p == 0)
5597dd7cddfSDavid du Colombier 		return p;
5607dd7cddfSDavid du Colombier 	if(*p != ' ' && *p != '\t' && *p != '\n')
5617dd7cddfSDavid du Colombier 		return 0;
5627dd7cddfSDavid du Colombier 	while(*p == ' ' || *p == '\t' || *p == '\n')
5637dd7cddfSDavid du Colombier 		p++;
5647dd7cddfSDavid du Colombier 	return p;
5657dd7cddfSDavid du Colombier }
5667dd7cddfSDavid du Colombier 
5677dd7cddfSDavid du Colombier void
hnputv(void * p,uvlong v)56887dfdc75SDavid du Colombier hnputv(void *p, uvlong v)
5697dd7cddfSDavid du Colombier {
5707dd7cddfSDavid du Colombier 	uchar *a;
5717dd7cddfSDavid du Colombier 
5727dd7cddfSDavid du Colombier 	a = p;
5737dd7cddfSDavid du Colombier 	hnputl(a, v>>32);
5747dd7cddfSDavid du Colombier 	hnputl(a+4, v);
5757dd7cddfSDavid du Colombier }
5767dd7cddfSDavid du Colombier 
5777dd7cddfSDavid du Colombier void
hnputl(void * p,uint v)57887dfdc75SDavid du Colombier hnputl(void *p, uint v)
5797dd7cddfSDavid du Colombier {
5807dd7cddfSDavid du Colombier 	uchar *a;
5817dd7cddfSDavid du Colombier 
5827dd7cddfSDavid du Colombier 	a = p;
5837dd7cddfSDavid du Colombier 	a[0] = v>>24;
5847dd7cddfSDavid du Colombier 	a[1] = v>>16;
5857dd7cddfSDavid du Colombier 	a[2] = v>>8;
5867dd7cddfSDavid du Colombier 	a[3] = v;
5877dd7cddfSDavid du Colombier }
5887dd7cddfSDavid du Colombier 
5897dd7cddfSDavid du Colombier void
hnputs(void * p,ushort v)5907dd7cddfSDavid du Colombier hnputs(void *p, ushort v)
5917dd7cddfSDavid du Colombier {
5927dd7cddfSDavid du Colombier 	uchar *a;
5937dd7cddfSDavid du Colombier 
5947dd7cddfSDavid du Colombier 	a = p;
5957dd7cddfSDavid du Colombier 	a[0] = v>>8;
5967dd7cddfSDavid du Colombier 	a[1] = v;
5977dd7cddfSDavid du Colombier }
5987dd7cddfSDavid du Colombier 
59987dfdc75SDavid du Colombier uvlong
nhgetv(void * p)6007dd7cddfSDavid du Colombier nhgetv(void *p)
6017dd7cddfSDavid du Colombier {
6027dd7cddfSDavid du Colombier 	uchar *a;
6037dd7cddfSDavid du Colombier 
6047dd7cddfSDavid du Colombier 	a = p;
6057dd7cddfSDavid du Colombier 	return ((vlong)nhgetl(a) << 32) | nhgetl(a+4);
6067dd7cddfSDavid du Colombier }
6077dd7cddfSDavid du Colombier 
60887dfdc75SDavid du Colombier uint
nhgetl(void * p)6097dd7cddfSDavid du Colombier nhgetl(void *p)
6107dd7cddfSDavid du Colombier {
6117dd7cddfSDavid du Colombier 	uchar *a;
6127dd7cddfSDavid du Colombier 
6137dd7cddfSDavid du Colombier 	a = p;
6147dd7cddfSDavid du Colombier 	return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0);
6157dd7cddfSDavid du Colombier }
6167dd7cddfSDavid du Colombier 
6177dd7cddfSDavid du Colombier ushort
nhgets(void * p)6187dd7cddfSDavid du Colombier nhgets(void *p)
6197dd7cddfSDavid du Colombier {
6207dd7cddfSDavid du Colombier 	uchar *a;
6217dd7cddfSDavid du Colombier 
6227dd7cddfSDavid du Colombier 	a = p;
6237dd7cddfSDavid du Colombier 	return (a[0]<<8)|(a[1]<<0);
6247dd7cddfSDavid du Colombier }
6257dd7cddfSDavid du Colombier 
6267dd7cddfSDavid du Colombier static ulong
hash(uchar * a,int len)6277dd7cddfSDavid du Colombier hash(uchar *a, int len)
6287dd7cddfSDavid du Colombier {
6297dd7cddfSDavid du Colombier 	ulong sum = 0;
6307dd7cddfSDavid du Colombier 
6317dd7cddfSDavid du Colombier 	while(len-- > 0)
6327dd7cddfSDavid du Colombier 		sum = (sum << 1) + *a++;
6337dd7cddfSDavid du Colombier 	return sum%Nmhash;
6347dd7cddfSDavid du Colombier }
6357dd7cddfSDavid du Colombier 
6367dd7cddfSDavid du Colombier int
activemulti(Netif * nif,uchar * addr,int alen)6377dd7cddfSDavid du Colombier activemulti(Netif *nif, uchar *addr, int alen)
6387dd7cddfSDavid du Colombier {
6397dd7cddfSDavid du Colombier 	Netaddr *hp;
6407dd7cddfSDavid du Colombier 
6417dd7cddfSDavid du Colombier 	for(hp = nif->mhash[hash(addr, alen)]; hp; hp = hp->hnext)
6427dd7cddfSDavid du Colombier 		if(memcmp(addr, hp->addr, alen) == 0){
6437dd7cddfSDavid du Colombier 			if(hp->ref)
6447dd7cddfSDavid du Colombier 				return 1;
6457dd7cddfSDavid du Colombier 			else
6467dd7cddfSDavid du Colombier 				break;
6477dd7cddfSDavid du Colombier 		}
6487dd7cddfSDavid du Colombier 	return 0;
6497dd7cddfSDavid du Colombier }
6507dd7cddfSDavid du Colombier 
6517dd7cddfSDavid du Colombier static int
parseaddr(uchar * to,char * from,int alen)6527dd7cddfSDavid du Colombier parseaddr(uchar *to, char *from, int alen)
6537dd7cddfSDavid du Colombier {
6547dd7cddfSDavid du Colombier 	char nip[4];
6557dd7cddfSDavid du Colombier 	char *p;
6567dd7cddfSDavid du Colombier 	int i;
6577dd7cddfSDavid du Colombier 
6587dd7cddfSDavid du Colombier 	p = from;
6597dd7cddfSDavid du Colombier 	for(i = 0; i < alen; i++){
6607dd7cddfSDavid du Colombier 		if(*p == 0)
6617dd7cddfSDavid du Colombier 			return -1;
6627dd7cddfSDavid du Colombier 		nip[0] = *p++;
6637dd7cddfSDavid du Colombier 		if(*p == 0)
6647dd7cddfSDavid du Colombier 			return -1;
6657dd7cddfSDavid du Colombier 		nip[1] = *p++;
6667dd7cddfSDavid du Colombier 		nip[2] = 0;
6677dd7cddfSDavid du Colombier 		to[i] = strtoul(nip, 0, 16);
6687dd7cddfSDavid du Colombier 		if(*p == ':')
6697dd7cddfSDavid du Colombier 			p++;
6707dd7cddfSDavid du Colombier 	}
6717dd7cddfSDavid du Colombier 	return 0;
6727dd7cddfSDavid du Colombier }
6737dd7cddfSDavid du Colombier 
6747dd7cddfSDavid du Colombier /*
6757dd7cddfSDavid du Colombier  *  keep track of multicast addresses
6767dd7cddfSDavid du Colombier  */
6777dd7cddfSDavid du Colombier static char*
netmulti(Netif * nif,Netfile * f,uchar * addr,int add)6787dd7cddfSDavid du Colombier netmulti(Netif *nif, Netfile *f, uchar *addr, int add)
6797dd7cddfSDavid du Colombier {
6807dd7cddfSDavid du Colombier 	Netaddr **l, *ap;
6817dd7cddfSDavid du Colombier 	int i;
6827dd7cddfSDavid du Colombier 	ulong h;
6837dd7cddfSDavid du Colombier 
6847dd7cddfSDavid du Colombier 	if(nif->multicast == nil)
6857dd7cddfSDavid du Colombier 		return "interface does not support multicast";
6867dd7cddfSDavid du Colombier 
6877dd7cddfSDavid du Colombier 	l = &nif->maddr;
6887dd7cddfSDavid du Colombier 	i = 0;
6897dd7cddfSDavid du Colombier 	for(ap = *l; ap; ap = *l){
6907dd7cddfSDavid du Colombier 		if(memcmp(addr, ap->addr, nif->alen) == 0)
6917dd7cddfSDavid du Colombier 			break;
6927dd7cddfSDavid du Colombier 		i++;
6937dd7cddfSDavid du Colombier 		l = &ap->next;
6947dd7cddfSDavid du Colombier 	}
6957dd7cddfSDavid du Colombier 
6967dd7cddfSDavid du Colombier 	if(add){
6977dd7cddfSDavid du Colombier 		if(ap == 0){
6987dd7cddfSDavid du Colombier 			*l = ap = smalloc(sizeof(*ap));
6997dd7cddfSDavid du Colombier 			memmove(ap->addr, addr, nif->alen);
7007dd7cddfSDavid du Colombier 			ap->next = 0;
7017dd7cddfSDavid du Colombier 			ap->ref = 1;
7027dd7cddfSDavid du Colombier 			h = hash(addr, nif->alen);
7037dd7cddfSDavid du Colombier 			ap->hnext = nif->mhash[h];
7047dd7cddfSDavid du Colombier 			nif->mhash[h] = ap;
7057dd7cddfSDavid du Colombier 		} else {
7067dd7cddfSDavid du Colombier 			ap->ref++;
7077dd7cddfSDavid du Colombier 		}
7087dd7cddfSDavid du Colombier 		if(ap->ref == 1){
7097dd7cddfSDavid du Colombier 			nif->nmaddr++;
7107dd7cddfSDavid du Colombier 			nif->multicast(nif->arg, addr, 1);
7117dd7cddfSDavid du Colombier 		}
7127dd7cddfSDavid du Colombier 		if(i < 8*sizeof(f->maddr)){
7137dd7cddfSDavid du Colombier 			if((f->maddr[i/8] & (1<<(i%8))) == 0)
7147dd7cddfSDavid du Colombier 				f->nmaddr++;
7157dd7cddfSDavid du Colombier 			f->maddr[i/8] |= 1<<(i%8);
7167dd7cddfSDavid du Colombier 		}
7177dd7cddfSDavid du Colombier 	} else {
7187dd7cddfSDavid du Colombier 		if(ap == 0 || ap->ref == 0)
7197dd7cddfSDavid du Colombier 			return 0;
7207dd7cddfSDavid du Colombier 		ap->ref--;
7217dd7cddfSDavid du Colombier 		if(ap->ref == 0){
7227dd7cddfSDavid du Colombier 			nif->nmaddr--;
7237dd7cddfSDavid du Colombier 			nif->multicast(nif->arg, addr, 0);
7247dd7cddfSDavid du Colombier 		}
7257dd7cddfSDavid du Colombier 		if(i < 8*sizeof(f->maddr)){
7267dd7cddfSDavid du Colombier 			if((f->maddr[i/8] & (1<<(i%8))) != 0)
7277dd7cddfSDavid du Colombier 				f->nmaddr--;
7287dd7cddfSDavid du Colombier 			f->maddr[i/8] &= ~(1<<(i%8));
7297dd7cddfSDavid du Colombier 		}
7307dd7cddfSDavid du Colombier 	}
7317dd7cddfSDavid du Colombier 	return 0;
7327dd7cddfSDavid du Colombier }
733