plan 9 kernel history: overview | file list | diff list

1999/0320/port/netif.c (diff list | history)

port/netif.c on 1993/0525
1993/0525    
#include	"u.h" 
#include	"../port/lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"../port/error.h" 
#include	"../port/netif.h" 
 
static int netown(Netfile*, char*, int); 
static int openfile(Netif*, int); 
static char* matchtoken(char*, char*); 
1997/0404    
static char* netmulti(Netif*, Netfile*, uchar*, int); 
static int parseaddr(uchar*, char*, int); 
1993/0525    
 
/* 
 *  set up a new network interface 
 */ 
void 
netifinit(Netif *nif, char *name, int nfile, ulong limit) 
{ 
1997/0327    
	strncpy(nif->name, name, NAMELEN-1); 
	nif->name[NAMELEN-1] = 0; 
1993/0525    
	nif->nfile = nfile; 
	nif->f = xalloc(nfile*sizeof(Netfile*)); 
	memset(nif->f, 0, nfile*sizeof(Netfile*)); 
	nif->limit = limit; 
} 
 
/* 
 *  generate a 3 level directory 
 */ 
static int 
1999/0320    
netifgen(Chan *c, Dirtab *vp, int, int i, Dir *dp) 
1993/0525    
{ 
	Qid q; 
	char buf[32]; 
1999/0320    
	Netif *nif = (Netif*)vp; 
1993/0525    
	Netfile *f; 
	int t; 
	int perm; 
	char *o; 
 
	q.vers = 0; 
 
	/* top level directory contains the name of the network */ 
	if(c->qid.path == CHDIR){ 
		switch(i){ 
		case 0: 
			q.path = CHDIR | N2ndqid; 
			strcpy(buf, nif->name); 
			devdir(c, q, buf, 0, eve, 0555, dp); 
			break; 
		default: 
			return -1; 
		} 
		return 1; 
	} 
 
	/* second level contains clone plus all the conversations */ 
	t = NETTYPE(c->qid.path); 
	if(t == N2ndqid || t == Ncloneqid){ 
1999/0316    
		switch(i) { 
		case 0: 
1993/0525    
			q.path = Ncloneqid; 
			devdir(c, q, "clone", 0, eve, 0666, dp); 
1999/0316    
			break; 
		case 1: 
			q.path = Naddrqid; 
			devdir(c, q, "addr", 0, eve, 0666, dp); 
			break; 
		default: 
			i -= 2; 
			if(i >= nif->nfile) 
				return -1; 
			if(nif->f[i] == 0) 
1993/0525    
				return 0; 
1999/0316    
			q.path = CHDIR|NETQID(i, N3rdqid); 
			sprint(buf, "%d", i); 
1993/0525    
			devdir(c, q, buf, 0, eve, 0555, dp); 
1999/0316    
			break; 
		} 
1993/0525    
		return 1; 
	} 
 
	/* third level */ 
	f = nif->f[NETID(c->qid.path)]; 
	if(f == 0) 
		return 0; 
	if(*f->owner){ 
		o = f->owner; 
		perm = f->mode; 
	} else { 
		o = eve; 
		perm = 0666; 
	} 
	switch(i){ 
	case 0: 
		q.path = NETQID(NETID(c->qid.path), Ndataqid); 
		devdir(c, q, "data", 0, o, perm, dp); 
		break; 
	case 1: 
		q.path = NETQID(NETID(c->qid.path), Nctlqid); 
		devdir(c, q, "ctl", 0, o, perm, dp); 
		break; 
	case 2: 
		q.path = NETQID(NETID(c->qid.path), Nstatqid); 
1993/0725    
		devdir(c, q, "stats", 0, eve, 0444, dp); 
1993/0525    
		break; 
	case 3: 
		q.path = NETQID(NETID(c->qid.path), Ntypeqid); 
		devdir(c, q, "type", 0, eve, 0444, dp); 
		break; 
1995/0804    
	case 4: 
		q.path = NETQID(NETID(c->qid.path), Nifstatqid); 
		devdir(c, q, "ifstats", 0, eve, 0444, dp); 
		break; 
1993/0525    
	default: 
		return -1; 
	} 
	return 1; 
} 
 
int 
netifwalk(Netif *nif, Chan *c, char *name) 
{ 
	return devwalk(c, name, (Dirtab *)nif, 0, netifgen); 
} 
 
Chan* 
netifopen(Netif *nif, Chan *c, int omode) 
{ 
1997/0417    
	int id; 
1993/0525    
	Netfile *f; 
 
1997/0417    
	id = 0; 
1993/0525    
	if(c->qid.path & CHDIR){ 
		if(omode != OREAD) 
			error(Eperm); 
	} else { 
		switch(NETTYPE(c->qid.path)){ 
		case Ndataqid: 
		case Nctlqid: 
			id = NETID(c->qid.path); 
			openfile(nif, id); 
			break; 
		case Ncloneqid: 
			id = openfile(nif, -1); 
			c->qid.path = NETQID(id, Nctlqid); 
			ptclone(c, 0, id); 
			break; 
		default: 
			if(omode != OREAD) 
				error(Ebadarg); 
		} 
		switch(NETTYPE(c->qid.path)){ 
		case Ndataqid: 
		case Nctlqid: 
			f = nif->f[id]; 
			if(netown(f, up->user, omode&7) < 0) 
				error(Eperm); 
			break; 
		} 
	} 
	c->mode = openmode(omode); 
	c->flag |= COPEN; 
	c->offset = 0; 
	return c; 
} 
 
long 
netifread(Netif *nif, Chan *c, void *a, long n, ulong offset) 
{ 
1993/0725    
	int i, j; 
1993/0525    
	Netfile *f; 
1997/0417    
	char *p; 
1993/0525    
 
	if(c->qid.path&CHDIR) 
		return devdirread(c, a, n, (Dirtab*)nif, 0, netifgen); 
 
	switch(NETTYPE(c->qid.path)){ 
	case Ndataqid: 
		f = nif->f[NETID(c->qid.path)]; 
		return qread(f->in, a, n); 
	case Nctlqid: 
		return readnum(offset, a, n, NETID(c->qid.path), NUMSIZE); 
	case Nstatqid: 
1997/0417    
		p = malloc(READSTR); 
		j = snprint(p, READSTR, "in: %d\n", nif->inpackets); 
		j += snprint(p+j, READSTR-j, "out: %d\n", nif->outpackets); 
		j += snprint(p+j, READSTR-j, "crc errs: %d\n", nif->crcs); 
		j += snprint(p+j, READSTR-j, "overflows: %d\n", nif->overflows); 
		j += snprint(p+j, READSTR-j, "soft overflows: %d\n", nif->soverflows); 
		j += snprint(p+j, READSTR-j, "framing errs: %d\n", nif->frames); 
		j += snprint(p+j, READSTR-j, "buffer errs: %d\n", nif->buffs); 
		j += snprint(p+j, READSTR-j, "output errs: %d\n", nif->oerrs); 
		j += snprint(p+j, READSTR-j, "prom: %d\n", nif->prom); 
		j += snprint(p+j, READSTR-j, "addr: "); 
1993/0525    
		for(i = 0; i < nif->alen; i++) 
1997/0417    
			j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]); 
		snprint(p+j, READSTR-j, "\n"); 
1999/0316    
		n = readstr(offset, a, n, p); 
		free(p); 
		return n; 
	case Naddrqid: 
		p = malloc(READSTR); 
		j = 0; 
		for(i = 0; i < nif->alen; i++) 
			j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]); 
1997/0417    
		n = readstr(offset, a, n, p); 
		free(p); 
		return n; 
1993/0525    
	case Ntypeqid: 
		f = nif->f[NETID(c->qid.path)]; 
		return readnum(offset, a, n, f->type, NUMSIZE); 
1995/0804    
	case Nifstatqid: 
		return 0; 
1993/0525    
	} 
	error(Ebadarg); 
	return -1;	/* not reached */ 
} 
 
1997/0327    
Block* 
netifbread(Netif *nif, Chan *c, long n, ulong offset) 
{ 
	if((c->qid.path & CHDIR) || NETTYPE(c->qid.path) != Ndataqid) 
		return devbread(c, n, offset); 
 
	return qbread(nif->f[NETID(c->qid.path)]->in, n); 
} 
 
1993/0525    
/* 
1997/1106    
 *  make sure this type isn't already in use on this device 
 */ 
static int 
typeinuse(Netif *nif, int type) 
{ 
	Netfile *f, **fp, **efp; 
 
	if(type <= 0) 
		return 0; 
 
	efp = &nif->f[nif->nfile]; 
	for(fp = nif->f; fp < efp; fp++){ 
		f = *fp; 
		if(f == 0) 
			continue; 
		if(f->type == type) 
			return 1; 
	} 
	return 0; 
} 
 
/* 
1993/0525    
 *  the devxxx.c that calls us handles writing data, it knows best 
 */ 
long 
netifwrite(Netif *nif, Chan *c, void *a, long n) 
{ 
	Netfile *f; 
1997/1106    
	int type; 
1997/0417    
	char *p, buf[64]; 
1997/0404    
	uchar binaddr[Nmaxaddr]; 
1993/0525    
 
	if(NETTYPE(c->qid.path) != Nctlqid) 
		error(Eperm); 
 
	if(n >= sizeof(buf)) 
		n = sizeof(buf)-1; 
	memmove(buf, a, n); 
	buf[n] = 0; 
 
1997/0404    
	if(waserror()){ 
		qunlock(nif); 
		nexterror(); 
	} 
 
1993/0525    
	qlock(nif); 
	f = nif->f[NETID(c->qid.path)]; 
1997/0403    
	if((p = matchtoken(buf, "connect")) != 0){ 
1997/1106    
		type = atoi(p); 
		if(typeinuse(nif, type)) 
			error(Einuse); 
		f->type = type; 
1994/0629    
		if(f->type < 0) 
			nif->all++; 
1993/0525    
	} else if(matchtoken(buf, "promiscuous")){ 
		f->prom = 1; 
		nif->prom++; 
1997/0327    
		if(nif->prom == 1 && nif->promiscuous != nil) 
			nif->promiscuous(nif->arg, 1); 
1997/0403    
	} else if((p = matchtoken(buf, "addmulti")) != 0){ 
1997/0404    
		if(parseaddr(binaddr, p, nif->alen) < 0) 
			error("bad address"); 
		p = netmulti(nif, f, binaddr, 1); 
		if(p) 
			error(p); 
1997/0403    
	} else if((p = matchtoken(buf, "remmulti")) != 0){ 
1997/0404    
		if(parseaddr(binaddr, p, nif->alen) < 0) 
			error("bad address"); 
		p = netmulti(nif, f, binaddr, 0); 
		if(p) 
			error(p); 
1993/0525    
	} 
	qunlock(nif); 
1997/0404    
	poperror(); 
1993/0525    
	return n; 
} 
 
void 
netifwstat(Netif *nif, Chan *c, char *db) 
{ 
	Dir dir; 
	Netfile *f; 
 
	f = nif->f[NETID(c->qid.path)]; 
	if(f == 0) 
		error(Enonexist); 
 
	if(netown(f, up->user, OWRITE) < 0) 
		error(Eperm); 
 
	convM2D(db, &dir); 
	strncpy(f->owner, dir.uid, NAMELEN); 
	f->mode = dir.mode; 
} 
 
void 
netifstat(Netif *nif, Chan *c, char *db) 
{ 
	devstat(c, db, (Dirtab *)nif, 0, netifgen); 
} 
 
void 
netifclose(Netif *nif, Chan *c) 
{ 
	Netfile *f; 
	int t; 
1997/0403    
	Netaddr *ap; 
1993/0525    
 
1994/0915    
	if((c->flag & COPEN) == 0) 
		return; 
 
1993/0525    
	t = NETTYPE(c->qid.path); 
	if(t != Ndataqid && t != Nctlqid) 
		return; 
 
	f = nif->f[NETID(c->qid.path)]; 
	qlock(f); 
	if(--(f->inuse) == 0){ 
		if(f->prom){ 
			qlock(nif); 
1997/0327    
			if(--(nif->prom) == 0 && nif->promiscuous != nil) 
				nif->promiscuous(nif->arg, 0); 
1994/0629    
			qunlock(nif); 
1995/1104    
			f->prom = 0; 
1994/0629    
		} 
1997/0403    
		if(f->nmaddr){ 
			qlock(nif); 
			t = 0; 
			for(ap = nif->maddr; ap; ap = ap->next){ 
				if(f->maddr[t/8] & (1<<(t%8))) 
					netmulti(nif, f, ap->addr, 0); 
			} 
			qunlock(nif); 
			f->nmaddr = 0; 
		} 
1994/0629    
		if(f->type < 0){ 
			qlock(nif); 
			--(nif->all); 
1993/0525    
			qunlock(nif); 
		} 
		f->owner[0] = 0; 
1993/0528    
		f->type = 0; 
		qclose(f->in); 
1993/0525    
	} 
	qunlock(f); 
} 
 
Lock netlock; 
 
static int 
netown(Netfile *p, char *o, int omode) 
{ 
	static int access[] = { 0400, 0200, 0600, 0100 }; 
	int mode; 
	int t; 
 
	lock(&netlock); 
	if(*p->owner){ 
		if(strncmp(o, p->owner, NAMELEN) == 0)	/* User */ 
			mode = p->mode; 
		else if(strncmp(o, eve, NAMELEN) == 0)	/* Bootes is group */ 
			mode = p->mode<<3; 
		else 
			mode = p->mode<<6;		/* Other */ 
 
		t = access[omode&3]; 
		if((t & mode) == t){ 
			unlock(&netlock); 
			return 0; 
		} else { 
			unlock(&netlock); 
			return -1; 
		} 
	} 
	strncpy(p->owner, o, NAMELEN); 
	p->mode = 0660; 
	unlock(&netlock); 
	return 0; 
} 
 
/* 
 *  Increment the reference count of a network device. 
 *  If id < 0, return an unused ether device. 
 */ 
static int 
openfile(Netif *nif, int id) 
{ 
	Netfile *f, **fp, **efp; 
 
	if(id >= 0){ 
		f = nif->f[id]; 
		if(f == 0) 
			error(Enodev); 
		qlock(f); 
1993/0528    
		qreopen(f->in); 
1993/0525    
		f->inuse++; 
		qunlock(f); 
		return id; 
	} 
 
	qlock(nif); 
1997/1105    
	if(waserror()){ 
		qunlock(nif); 
		nexterror(); 
	} 
1993/0525    
	efp = &nif->f[nif->nfile]; 
	for(fp = nif->f; fp < efp; fp++){ 
		f = *fp; 
		if(f == 0){ 
			f = malloc(sizeof(Netfile)); 
1997/1105    
			if(f == 0) 
				exhausted("memory"); 
			f->in = qopen(nif->limit, 1, 0, 0); 
			if(f->in == nil){ 
				free(f); 
				exhausted("memory"); 
1993/0525    
			} 
			*fp = f; 
			qlock(f); 
		} else { 
			qlock(f); 
			if(f->inuse){ 
				qunlock(f); 
				continue; 
			} 
		} 
		f->inuse = 1; 
1993/0528    
		qreopen(f->in); 
1993/0525    
		netown(f, up->user, 0); 
		qunlock(f); 
		qunlock(nif); 
1997/1105    
		poperror(); 
1993/0525    
		return fp - nif->f; 
	} 
	error(Enodev); 
	return -1;	/* not reached */ 
} 
 
/* 
1994/0214    
 *  look for a token starting a string, 
 *  return a pointer to first non-space char after it 
1993/0525    
 */ 
static char* 
matchtoken(char *p, char *token) 
{ 
	int n; 
 
	n = strlen(token); 
	if(strncmp(p, token, n)) 
		return 0; 
	p += n; 
	if(*p == 0) 
		return p; 
	if(*p != ' ' && *p != '\t' && *p != '\n') 
		return 0; 
	while(*p == ' ' || *p == '\t' || *p == '\n') 
		p++; 
	return p; 
} 
1995/0808    
 
void 
1998/0325    
hnputv(void *p, vlong v) 
{ 
	uchar *a; 
 
	a = p; 
	hnputl(a, v>>32); 
1998/0326    
	hnputl(a+4, v); 
1998/0325    
} 
 
void 
1995/0808    
hnputl(void *p, ulong v) 
{ 
	uchar *a; 
 
	a = p; 
	a[0] = v>>24; 
	a[1] = v>>16; 
	a[2] = v>>8; 
	a[3] = v; 
} 
 
void 
hnputs(void *p, ushort v) 
{ 
	uchar *a; 
 
	a = p; 
	a[0] = v>>8; 
	a[1] = v; 
1998/0325    
} 
 
vlong 
nhgetv(void *p) 
{ 
	uchar *a; 
 
	a = p; 
1998/0326    
	return ((vlong)nhgetl(a) << 32) | nhgetl(a+4); 
1995/0808    
} 
 
ulong 
nhgetl(void *p) 
{ 
	uchar *a; 
1997/0327    
 
1995/0808    
	a = p; 
	return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0); 
} 
 
ushort 
nhgets(void *p) 
{ 
	uchar *a; 
1997/0327    
 
1995/0808    
	a = p; 
	return (a[0]<<8)|(a[1]<<0); 
1997/0401    
} 
 
1997/0404    
static ulong 
hash(uchar *a, int len) 
{ 
	ulong sum = 0; 
 
	while(len-- > 0) 
		sum = (sum << 1) + *a++; 
	return sum%Nmhash; 
} 
 
int 
activemulti(Netif *nif, uchar *addr, int alen) 
{ 
	Netaddr *hp; 
 
	for(hp = nif->mhash[hash(addr, alen)]; hp; hp = hp->hnext) 
		if(memcmp(addr, hp->addr, alen) == 0){ 
			if(hp->ref) 
				return 1; 
			else 
				break; 
		} 
	return 0; 
} 
 
static int 
parseaddr(uchar *to, char *from, int alen) 
{ 
	char nip[4]; 
	char *p; 
	int i; 
 
	p = from; 
	for(i = 0; i < alen; i++){ 
		if(*p == 0) 
			return -1; 
		nip[0] = *p++; 
		if(*p == 0) 
			return -1; 
		nip[1] = *p++; 
		nip[2] = 0; 
		to[i] = strtoul(nip, 0, 16); 
		if(*p == ':') 
			p++; 
	} 
	return 0; 
} 
 
1997/0403    
/* 
 *  keep track of multicast addresses 
 */ 
1997/0404    
static char* 
netmulti(Netif *nif, Netfile *f, uchar *addr, int add) 
1997/0401    
{ 
	Netaddr **l, *ap; 
1997/0403    
	int i; 
1997/0404    
	ulong h; 
1997/0401    
 
	if(nif->multicast == nil) 
1997/0404    
		return "interface does not support multicast"; 
1997/0401    
 
	l = &nif->maddr; 
1997/0403    
	i = 0; 
1997/0401    
	for(ap = *l; ap; ap = *l){ 
1997/0404    
		if(memcmp(addr, ap->addr, nif->alen) == 0) 
1997/0401    
			break; 
1997/0403    
		i++; 
1997/0401    
		l = &ap->next; 
	} 
 
	if(add){ 
		if(ap == 0){ 
1997/0403    
			*l = ap = smalloc(sizeof(*ap)); 
1997/0404    
			memmove(ap->addr, addr, nif->alen); 
1997/0403    
			ap->next = 0; 
1997/0401    
			ap->ref = 1; 
1997/0404    
			h = hash(addr, nif->alen); 
			ap->hnext = nif->mhash[h]; 
			nif->mhash[h] = ap; 
1997/0401    
		} else { 
			ap->ref++; 
		} 
1997/0403    
		if(ap->ref == 1){ 
			nif->nmaddr++; 
1997/0401    
			nif->multicast(nif->arg, addr, 1); 
1997/0403    
		} 
		if(i < 8*sizeof(f->maddr)){ 
			if((f->maddr[i/8] & (1<<(i%8))) == 0) 
				f->nmaddr++; 
			f->maddr[i/8] |= 1<<(i%8); 
		} 
1997/0401    
	} else { 
		if(ap == 0 || ap->ref == 0) 
1997/0404    
			return 0; 
1997/0401    
		ap->ref--; 
1997/0403    
		if(ap->ref == 0){ 
			nif->nmaddr--; 
1997/0401    
			nif->multicast(nif->arg, addr, 0); 
1997/0403    
		} 
		if(i < 8*sizeof(f->maddr)){ 
			if((f->maddr[i/8] & (1<<(i%8))) != 0) 
				f->nmaddr--; 
			f->maddr[i/8] &= ~(1<<(i%8)); 
		} 
1997/0401    
	} 
1997/0404    
	return 0; 
1995/0808    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)