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

1997/0403/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/0403    
static void netmulti(Netif*, Netfile*, 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 
1995/0804    
netifgen(Chan *c, void *vp, int, int i, Dir *dp) 
1993/0525    
{ 
	Qid q; 
	char buf[32]; 
	Netif *nif = vp; 
	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){ 
		if(i == 0){ 
			q.path = Ncloneqid; 
			devdir(c, q, "clone", 0, eve, 0666, dp); 
		}else if(i <= nif->nfile){ 
			if(nif->f[i-1] == 0) 
				return 0; 
			q.path = CHDIR|NETQID(i-1, N3rdqid); 
			sprint(buf, "%d", i-1); 
			devdir(c, q, buf, 0, eve, 0555, dp); 
		}else 
			return -1; 
		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) 
{ 
	int id = 0; 
	Netfile *f; 
 
	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; 
1995/0711    
	char buf[1024]; 
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: 
1993/0725    
		j = sprint(buf, "in: %d\n", nif->inpackets); 
		j += sprint(buf+j, "out: %d\n", nif->outpackets); 
		j += sprint(buf+j, "crc errs: %d\n", nif->crcs); 
		j += sprint(buf+j, "overflows: %d\n", nif->overflows); 
1995/0711    
		j += sprint(buf+j, "soft overflows: %d\n", nif->soverflows); 
1993/0725    
		j += sprint(buf+j, "framing errs: %d\n", nif->frames); 
		j += sprint(buf+j, "buffer errs: %d\n", nif->buffs); 
		j += sprint(buf+j, "output errs: %d\n", nif->oerrs); 
1995/1104    
		j += sprint(buf+j, "prom: %d\n", nif->prom); 
1993/0725    
		j += sprint(buf+j, "addr: "); 
1993/0525    
		for(i = 0; i < nif->alen; i++) 
1993/0725    
			j += sprint(buf+j, "%2.2ux", nif->addr[i]); 
		sprint(buf+j, "\n"); 
1993/0525    
		return readstr(offset, a, n, buf); 
	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    
/* 
 *  the devxxx.c that calls us handles writing data, it knows best 
 */ 
long 
netifwrite(Netif *nif, Chan *c, void *a, long n) 
{ 
	Netfile *f; 
	char *p; 
	char buf[256]; 
 
	if(NETTYPE(c->qid.path) != Nctlqid) 
		error(Eperm); 
 
	if(n >= sizeof(buf)) 
		n = sizeof(buf)-1; 
	memmove(buf, a, n); 
	buf[n] = 0; 
 
	qlock(nif); 
	f = nif->f[NETID(c->qid.path)]; 
1997/0403    
	if((p = matchtoken(buf, "connect")) != 0){ 
1993/0525    
		f->type = atoi(p); 
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){ 
		netmulti(nif, f, p, 1); 
	} else if((p = matchtoken(buf, "remmulti")) != 0){ 
		netmulti(nif, f, p, 0); 
1993/0525    
	} 
	qunlock(nif); 
	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); 
	efp = &nif->f[nif->nfile]; 
	for(fp = nif->f; fp < efp; fp++){ 
		f = *fp; 
		if(f == 0){ 
			f = malloc(sizeof(Netfile)); 
			if(f == 0){ 
				qunlock(nif); 
				error(Enodev); 
			} 
			*fp = f; 
1993/0530    
			f->in = qopen(nif->limit, 1, 0, 0); 
1993/0525    
			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); 
		return fp - nif->f; 
	} 
	qunlock(nif); 
	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 
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; 
} 
 
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/0403    
/* 
 *  keep track of multicast addresses 
 */ 
1997/0401    
static void 
1997/0403    
netmulti(Netif *nif, Netfile *f, char *addr, int add) 
1997/0401    
{ 
	Netaddr **l, *ap; 
1997/0403    
	int i; 
	uchar hexaddr[Nmaxaddr]; 
1997/0401    
 
	if(nif->multicast == nil) 
		return; 
 
1997/0403    
	if(strlen(addr) != 2*nif->alen) 
		return; 
 
1997/0401    
	l = &nif->maddr; 
1997/0403    
	i = 0; 
1997/0401    
	for(ap = *l; ap; ap = *l){ 
		if(strcmp(addr, ap->addr) == 0) 
			break; 
1997/0403    
		i++; 
1997/0401    
		l = &ap->next; 
	} 
 
	if(add){ 
		if(ap == 0){ 
1997/0403    
			*l = ap = smalloc(sizeof(*ap)); 
1997/0401    
			ap->addr = smalloc(strlen(addr)+1); 
			strcpy(ap->addr, addr); 
1997/0403    
			ap->next = 0; 
1997/0401    
			ap->ref = 1; 
		} 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) 
			return; 
		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    
	} 
1995/0808    
} 


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