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

1993/0525/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	"io.h" 
#include	"../port/error.h" 
#include	"../port/netif.h" 
 
uchar etherbcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 
 
static int netown(Netfile*, char*, int); 
static int openfile(Netif*, int); 
static char* matchtoken(char*, char*); 
 
/* 
 *  set up a new network interface 
 */ 
void 
netifinit(Netif *nif, char *name, int nfile, ulong limit) 
{ 
	nif->name = name; 
	nif->nfile = nfile; 
	nif->f = xalloc(nfile*sizeof(Netfile*)); 
	memset(nif->f, 0, nfile*sizeof(Netfile*)); 
	nif->limit = limit; 
	nif->out = qopen(limit, 0, 0); 
} 
 
/* 
 *  generate a 3 level directory 
 */ 
static int 
netifgen(Chan *c, void *vp, int ntab, int i, Dir *dp) 
{ 
	Qid q; 
	char buf[32]; 
	Netif *nif = vp; 
	Netfile *f; 
	int t; 
	int perm; 
	char *o; 
 
	USED(ntab); 
	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); 
		devdir(c, q, "stat", 0, eve, 0444, dp); 
		break; 
	case 3: 
		q.path = NETQID(NETID(c->qid.path), Ntypeqid); 
		devdir(c, q, "type", 0, eve, 0444, dp); 
		break; 
	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) 
{ 
	Netfile *f; 
	int i; 
	char buf[256]; 
 
	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: 
		n = sprint(buf, "in: %d\n", nif->inpackets); 
		n += sprint(buf+n, "out: %d\n", nif->outpackets); 
		n += sprint(buf+n, "crc errs: %d\n", nif->crcs); 
		n += sprint(buf+n, "overflows: %d\n", nif->overflows); 
		n += sprint(buf+n, "framing errs: %d\n", nif->frames); 
		n += sprint(buf+n, "buffer errs: %d\n", nif->buffs); 
		n += sprint(buf+n, "output errs: %d\n", nif->oerrs); 
		n += sprint(buf+n, "addr:", nif->oerrs); 
		for(i = 0; i < nif->alen; i++) 
			n += sprint(buf+n, "%2.2ux", nif->addr[i]); 
		n += sprint(buf+n, "\n"); 
		return readstr(offset, a, n, buf); 
	case Ntypeqid: 
		f = nif->f[NETID(c->qid.path)]; 
		return readnum(offset, a, n, f->type, NUMSIZE); 
	} 
	error(Ebadarg); 
	return -1;	/* not reached */ 
} 
 
/* 
 *  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)]; 
	if(p = matchtoken(buf, "connect")){ 
		f->type = atoi(p); 
	} else if(matchtoken(buf, "promiscuous")){ 
		f->prom = 1; 
		nif->prom++; 
		if(nif->prom == 1) 
			(*nif->promiscuous)(nif->arg, 1); 
	} 
	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; 
 
	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); 
			if(--(nif->prom) == 0) 
				(*nif->promiscuous)(nif->arg, 0); 
			qunlock(nif); 
		} 
		f->owner[0] = 0; 
	} 
	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); 
		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; 
			f->in = qopen(nif->limit, 0, 0); 
			qlock(f); 
		} else { 
			qlock(f); 
			if(f->inuse){ 
				qunlock(f); 
				continue; 
			} 
		} 
		f->inuse = 1; 
		netown(f, up->user, 0); 
		qunlock(f); 
		qunlock(nif); 
		return fp - nif->f; 
	} 
	qunlock(nif); 
	error(Enodev); 
	return -1;	/* not reached */ 
} 
 
/* 
 *  look for a token starting a string, return a pointer to first non-space char after it 
 */ 
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; 
} 


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