203 lines · 3.3 KB · C
RawDownload
/* * ethertap: tap device ethernet driver * copyright © 2008 erik quanstrom * copyright © 2010 Tully Gray * copyright © 2010 Jesus Galan Lopez */ #include "u.h"#include "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "error.h"#include "netif.h"#include "etherif.h"#include "vether.h" #if defined(__APPLE__)#include <sys/socket.h>#endif#include <net/if.h>#include <sys/ioctl.h> #ifdef linux#include <netpacket/packet.h>#include <linux/if_tun.h>#elif defined(__FreeBSD__)#include <net/if_tun.h>#endif typedef struct Ctlr Ctlr;struct Ctlr {	int	fd;	int	txerrs;	uchar	ea[Eaddrlen];}; static	uchar	anyea[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff,}; #ifdef linuxstatic intopentap(char *dev){	int fd;	char *tap0 = "tap0";	struct ifreq ifr; 	if(dev == nil)		dev = tap0;	if((fd = open("/dev/net/tun", O_RDWR)) < 0)		return -1;	memset(&ifr, 0, sizeof ifr);	strncpy(ifr.ifr_name, dev, sizeof ifr.ifr_name);	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;	if(ioctl(fd, TUNSETIFF, &ifr) < 0){		close(fd);		return -1;	}	return fd;}#elif defined(__FreeBSD__)static intopentap(char *dev){	int fd;	struct stat s; 	if((fd = open("/dev/tap", O_RDWR)) < 0)		return -1;	return fd;}#elif defined(__APPLE__)static intopentap(char *dev){	int fd;	char *tap0 = "/dev/tap0"; 	if(dev == nil)		dev = tap0;	if((fd = open(dev, O_RDWR)) < 0) {		iprint("tap: open failed with: %d\n", errno);		return -1;	}	return fd;}#endif static intsetup(char *dev){	return opentap(dev);} Block*tappkt(Ctlr *c){	int n;	Block *b; 	b = allocb(1514);	for(;;){		n = read(c->fd, b->rp, BALLOC(b));		if(n <= 0)			panic("fd %d read %d", c->fd, n);		if(memcmp(b->rp + 0, anyea, 6) == 0		|| memcmp(b->rp + 0, c->ea, 6) == 0)			break;	}	b->wp += n;	b->flag |= Btcpck|Budpck|Bpktck;	return b;} static voidtaprecvkproc(void *v){	Block *b;	Ether *e; 	e = v;	while((b = tappkt(e->ctlr)))		etheriq(e, b, 1);	pexit("read fail", 1);} static voidtaptransmit(Ether* e){	Block *b, *h;	Ctlr *c; 	c = e->ctlr;	while ((b = qget(e->oq)) != nil) {		if(memcmp(b->rp + 6, anyea, 6) == 0 ||		memcmp(b->rp + 0, c->ea, 6) == 0){			h = allocb(BLEN(b));			memcpy(h->rp, b->wp, BLEN(b));			h->wp += BLEN(b);			h->flag |= Btcpck|Budpck|Bpktck;			etheriq(e, h, 1);		}		if(write(c->fd, b->rp, BLEN(b)) == -1)			c->txerrs++;		freeb(b);	}} static longtapifstat(Ether *e, void *a, long n, ulong offset){	char buf[128];	Ctlr *c; 	c = a;	snprint(buf, sizeof buf, "txerrors: %lud\n", c->txerrs);	return readstr(offset, a, n, buf);} static voidtapattach(Ether* e){	kproc("taprecv", taprecvkproc, e);} static inttappnp(Ether* e){	Ctlr c;	static int cve = 0; 	while(cve < MaxEther && ve[cve].tap == 0)		cve++;	if(cve == MaxEther || ve[cve].dev == nil)		return -1; 	memset(&c, 0, sizeof c);	c.fd = setup(ve[cve].dev);	memcpy(c.ea, ve[cve].ea, Eaddrlen);	if(c.fd== -1){		iprint("ve: tap failed to initialize\n");		cve++;		return -1;	}	e->ctlr = malloc(sizeof c);	memcpy(e->ctlr, &c, sizeof c);	e->tbdf = BUSUNKNOWN;	memcpy(e->ea, ve[cve].ea, Eaddrlen);	e->attach = tapattach;	e->transmit = taptransmit;	e->ifstat = tapifstat;	e->ni.arg = e;	e->ni.link = 1;	cve++;	return 0;} voidethertaplink(void){	addethercard("tap", tappnp);}