rminnichinitial1fcdf7916 years agoHistory
993 lines · 15.4 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <thread.h>#include <bio.h>#include <auth.h>#include <fcall.h>#include <9p.h> #include "usb.h" typedef struct Tab Tab;typedef struct Qbuf Qbuf;typedef struct Dq Dq;typedef struct Conn Conn;typedef struct Ehdr Ehdr;typedef struct Stats Stats; enum{	SC_ACM = 2,	SC_ETHER = 6, 	FUNCTION = 0x24,	FN_HEADER = 0,	FN_UNION = 6,	FN_ETHER = 15,}; enum{	Qroot,	Qiface,	Qclone,	Qstats,	Qaddr,	Qndir,	Qctl,	Qdata,	Qtype,	Qmax,}; struct Tab{	char *name;	ulong mode;}; Tab tab[] ={	"/",		DMDIR|0555,	"etherU",	DMDIR|0555,	/* calling it *ether* makes snoopy(8) happy */	"clone",	0666,	"stats",	0666,	"addr",	0444,	"%ud",	DMDIR|0555,	"ctl",		0666,	"data",	0666,	"type",	0444,}; struct Qbuf{	Qbuf		*next;	int		ndata;	uchar	data[];}; struct Dq{	QLock	l;	Dq		*next;	Req		*r;	Req		**rt;	Qbuf		*q;	Qbuf		**qt; 	int		nb;}; struct Conn{	QLock	l;	int		used;	int		type;	int		prom;	Dq		*dq;}; struct Ehdr{	uchar	d[6];	uchar	s[6];	uchar	type[2];}; struct Stats{	int		in;	int		out;}; Conn conn[32];int nconn = 0; int debug;ulong time0;int usbfdin = -1;int usbfdout = -1; Stats stats; uchar macaddr[6];int iunion[8][2];int niunion;int maxpacket = 64; char *uname; #define PATH(type, n)		((type)|((n)<<8))#define TYPE(path)			(((uint)(path) & 0x000000FF)>>0)#define NUM(path)			(((uint)(path) & 0xFFFFFF00)>>8)#define NUMCONN(c)		(((long)(c)-(long)&conn[0])/sizeof(conn[0])) static intreceivepacket(void *buf, int len); static voidfillstat(Dir *d, uvlong path){	Tab *t; 	memset(d, 0, sizeof(*d));	d->uid = estrdup9p(uname);	d->gid = estrdup9p(uname);	d->qid.path = path;	d->atime = d->mtime = time0;	t = &tab[TYPE(path)];	d->name = smprint(t->name, NUM(path));	d->qid.type = t->mode>>24;	d->mode = t->mode;} static voidfsattach(Req *r){	if(r->ifcall.aname && r->ifcall.aname[0]){		respond(r, "invalid attach specifier");		return;	}	if(uname == nil)		uname = estrdup9p(r->ifcall.uname);	r->fid->qid.path = PATH(Qroot, 0);	r->fid->qid.type = QTDIR;	r->fid->qid.vers = 0;	r->ofcall.qid = r->fid->qid;	respond(r, nil);} static voidfsstat(Req *r){	fillstat(&r->d, r->fid->qid.path);	respond(r, nil);} static introotgen(int i, Dir *d, void*){	i += Qroot+1;	if(i == Qiface){		fillstat(d, i);		return 0;	}	return -1;} static intifacegen(int i, Dir *d, void*){	i += Qiface+1;	if(i < Qndir){		fillstat(d, i);		return 0;	}	i -= Qndir;	if(i < nconn){		fillstat(d, PATH(Qndir, i));		return 0;	}	return -1;} static intndirgen(int i, Dir *d, void *aux){	i += Qndir+1;	if(i < Qmax){		fillstat(d, PATH(i, NUMCONN(aux)));		return 0;	}	return -1;} static char*fswalk1(Fid *fid, char *name, Qid *qid){	int i, n;	char buf[32];	ulong path; 	path = fid->qid.path;	if(!(fid->qid.type&QTDIR))		return "walk in non-directory"; 	if(strcmp(name, "..") == 0){		switch(TYPE(path)){		case Qroot:			return nil;		case Qiface:			qid->path = PATH(Qroot, 0);			qid->type = tab[Qroot].mode>>24;			return nil;		case Qndir:			qid->path = PATH(Qiface, 0);			qid->type = tab[Qiface].mode>>24;			return nil;		default:			return "bug in fswalk1";		}	} 	for(i = TYPE(path)+1; i<nelem(tab); i++){		if(i==Qndir){			n = atoi(name);			snprint(buf, sizeof buf, "%d", n);			if(n < nconn && strcmp(buf, name) == 0){				qid->path = PATH(i, n);				qid->type = tab[i].mode>>24;				return nil;			}			break;		}		if(strcmp(name, tab[i].name) == 0){			qid->path = PATH(i, NUM(path));			qid->type = tab[i].mode>>24;			return nil;		}		if(tab[i].mode&DMDIR)			break;	}	return "directory entry not found";} static voidmatchrq(Dq *d){	Req *r;	Qbuf *b; 	while(r = d->r){		int n; 		if((b = d->q) == nil)			break;		if((d->q = b->next) == nil)			d->qt = &d->q;		if((d->r = (Req*)r->aux) == nil)			d->rt = &d->r; 		n = r->ifcall.count;		if(n > b->ndata)			n = b->ndata;		memmove(r->ofcall.data, b->data, n);		free(b);		r->ofcall.count = n;		respond(r, nil);	}} static voidreadconndata(Req *r){	Dq *d; 	d = r->fid->aux;	qlock(&d->l);	if(d->q==nil && d->nb){		qunlock(&d->l);		r->ofcall.count = 0;		respond(r, nil);		return;	}	// enqueue request	r->aux = nil;	*d->rt = r;	d->rt = (Req**)&r->aux;	matchrq(d);	qunlock(&d->l);} static voidwriteconndata(Req *r){	char e[ERRMAX];	Dq *d;	void *p;	int n; 	d = r->fid->aux;	p = r->ifcall.data;	n = r->ifcall.count; 	if((n == 11) && memcmp(p, "nonblocking", n)==0){		d->nb = 1;		goto out;	} 	n = write(usbfdout, p, n);	if(n < 0){		rerrstr(e, sizeof(e));		respond(r, e);		return;	}	/*	 * this may not work with all CDC devices. the	 * linux driver sends one more random byte	 * instead of a zero byte transaction. maybe we	 * should do the same?	 */	if(n % maxpacket == 0)		write(usbfdout, "", 0); 	if(receivepacket(p, n) == 0)		stats.out++;out:	r->ofcall.count = n;	respond(r, nil);} static char*mac2str(uchar *m){	int i;	char *t = "0123456789abcdef";	static char buf[13];	buf[13] = 0;	for(i=0; i<6; i++){		buf[i*2] = t[m[i]>>4];		buf[i*2+1] = t[m[i]&0xF];	}	return buf;} static intstr2mac(uchar *m, char *s){	int i; 	if(strlen(s) != 12)		return -1; 	for(i=0; i<12; i++){		uchar v; 		if(s[i] >= 'A' && s[i] <= 'F'){			v = 10 + s[i] - 'A';		} else if(s[i] >= 'a' && s[i] <= 'f'){			v = 10 + s[i] - 'a';		} else if(s[i] >= '0' && s[i] <= '9'){			v = s[i] - '0';		} else {			v = 0;		}		if(i&1){			m[i/2] |= v;		} else {			m[i/2] = v<<4;		}	}	return 0;} static voidfsread(Req *r){	char buf[200];	char e[ERRMAX];	ulong path; 	path = r->fid->qid.path; 	switch(TYPE(path)){	default:		snprint(e, sizeof e, "bug in fsread path=%lux", path);		respond(r, e);		break; 	case Qroot:		dirread9p(r, rootgen, nil);		respond(r, nil);		break; 	case Qiface:		dirread9p(r, ifacegen, nil);		respond(r, nil);		break; 	case Qstats:		snprint(buf, sizeof(buf),			"in: %d\n"			"out: %d\n"			"mbps: %d\n"			"addr: %s\n",			stats.in, stats.out, 10, mac2str(macaddr));		readstr(r, buf);		respond(r, nil);		break; 	case Qaddr:		readstr(r, mac2str(macaddr));		respond(r, nil);		break; 	case Qndir:		dirread9p(r, ndirgen, &conn[NUM(path)]);		respond(r, nil);		break; 	case Qctl:		snprint(buf, sizeof(buf), "%11d ", NUM(path));		readstr(r, buf);		respond(r, nil);		break; 	case Qtype:		snprint(buf, sizeof(buf), "%11d ", conn[NUM(path)].type);		readstr(r, buf);		respond(r, nil);		break; 	case Qdata:		readconndata(r);		break;	}} static voidfswrite(Req *r){	char e[ERRMAX];	ulong path;	char *p;	int n; 	path = r->fid->qid.path;	switch(TYPE(path)){	case Qctl:		n = r->ifcall.count;		p = (char*)r->ifcall.data;		if((n == 11) && memcmp(p, "promiscuous", 11)==0)			conn[NUM(path)].prom = 1;		if((n > 8) && memcmp(p, "connect ", 8)==0){			char x[12]; 			if(n - 8 >= sizeof(x)){				respond(r, "invalid control msg");				return;			} 			p += 8;			memcpy(x, p, n-8);			x[n-8] = 0; 			conn[NUM(path)].type = atoi(p);		}		r->ofcall.count = n;		respond(r, nil);		break;	case Qdata:		writeconndata(r);		break;	default:		snprint(e, sizeof e, "bug in fswrite path=%lux", path);		respond(r, e);	}} static voidfsopen(Req *r){	static int need[4] = { 4, 2, 6, 1 };	ulong path;	int i, n;	Tab *t;	Dq *d;	Conn *c;  	/*

Lines 1–500 of 993.