vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

ethertap.c (3334B)


      1 /*
      2  * ethertap: tap device ethernet driver
      3  * copyright © 2008 erik quanstrom
      4  * copyright © 2010 Tully Gray
      5  * copyright © 2010 Jesus Galan Lopez
      6  */
      7 
      8 #include "u.h"
      9 #include "lib.h"
     10 #include "mem.h"
     11 #include "dat.h"
     12 #include "fns.h"
     13 #include "io.h"
     14 #include "error.h"
     15 #include "netif.h"
     16 #include "etherif.h"
     17 #include "vether.h"
     18 
     19 #if defined(__APPLE__)
     20 #include <sys/socket.h>
     21 #endif
     22 #include <net/if.h>
     23 #include <sys/ioctl.h>
     24 
     25 #ifdef linux
     26 #include <netpacket/packet.h>
     27 #include <linux/if_tun.h>
     28 #elif defined(__FreeBSD__)
     29 #include <net/if_tun.h>
     30 #endif
     31 
     32 typedef struct Ctlr Ctlr;
     33 struct Ctlr {
     34 	int	fd;
     35 	int	txerrs;
     36 	uchar	ea[Eaddrlen];
     37 };
     38 
     39 static	uchar	anyea[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff,};
     40 
     41 #ifdef linux
     42 static int
     43 opentap(char *dev)
     44 {
     45 	int fd;
     46 	char *tap0 = "tap0";
     47 	struct ifreq ifr;
     48 
     49 	if(dev == nil)
     50 		dev = tap0;
     51 	if((fd = open("/dev/net/tun", O_RDWR)) < 0)
     52 		return -1;
     53 	memset(&ifr, 0, sizeof ifr);
     54 	strncpy(ifr.ifr_name, dev, sizeof ifr.ifr_name);
     55 	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
     56 	if(ioctl(fd, TUNSETIFF, &ifr) < 0){
     57 		close(fd);
     58 		return -1;
     59 	}
     60 	return fd;
     61 }
     62 #elif defined(__FreeBSD__)
     63 static int
     64 opentap(char *dev)
     65 {
     66 	int fd;
     67 	struct stat s;
     68 
     69 	if((fd = open("/dev/tap", O_RDWR)) < 0)
     70 		return -1;
     71 	return fd;
     72 }
     73 #elif defined(__APPLE__)
     74 static int
     75 opentap(char *dev)
     76 {
     77 	int fd;
     78 	char *tap0 = "/dev/tap0";
     79 
     80 	if(dev == nil)
     81 		dev = tap0;
     82 	if((fd = open(dev, O_RDWR)) < 0) {
     83 		iprint("tap: open failed with: %d\n", errno);
     84 		return -1;
     85 	}
     86 	return fd;
     87 }
     88 #endif
     89 
     90 static int
     91 setup(char *dev)
     92 {
     93 	return opentap(dev);
     94 }
     95 
     96 Block*
     97 tappkt(Ctlr *c)
     98 {
     99 	int n;
    100 	Block *b;
    101 
    102 	b = allocb(1514);
    103 	for(;;){
    104 		n = read(c->fd, b->rp, BALLOC(b));
    105 		if(n <= 0)
    106 			panic("fd %d read %d", c->fd, n);
    107 		if(memcmp(b->rp + 0, anyea, 6) == 0
    108 		|| memcmp(b->rp + 0, c->ea, 6) == 0)
    109 			break;
    110 	}
    111 	b->wp += n;
    112 	b->flag |= Btcpck|Budpck|Bpktck;
    113 	return b;
    114 }
    115 
    116 static void
    117 taprecvkproc(void *v)
    118 {
    119 	Block *b;
    120 	Ether *e;
    121 
    122 	e = v;
    123 	while((b = tappkt(e->ctlr)))
    124 		etheriq(e, b, 1);
    125 	pexit("read fail", 1);
    126 }
    127 
    128 static void
    129 taptransmit(Ether* e)
    130 {
    131 	Block *b, *h;
    132 	Ctlr *c;
    133 
    134 	c = e->ctlr;
    135 	while ((b = qget(e->oq)) != nil) {
    136 		if(memcmp(b->rp + 6, anyea, 6) == 0 ||
    137 		memcmp(b->rp + 0, c->ea, 6) == 0){
    138 			h = allocb(BLEN(b));
    139 			memcpy(h->rp, b->wp, BLEN(b));
    140 			h->wp += BLEN(b);
    141 			h->flag |= Btcpck|Budpck|Bpktck;
    142 			etheriq(e, h, 1);
    143 		}
    144 		if(write(c->fd, b->rp, BLEN(b)) == -1)
    145 			c->txerrs++;
    146 		freeb(b);
    147 	}
    148 }
    149 
    150 static long
    151 tapifstat(Ether *e, void *a, long n, ulong offset)
    152 {
    153 	char buf[128];
    154 	Ctlr *c;
    155 
    156 	c = a;
    157 	snprint(buf, sizeof buf, "txerrors: %lud\n", c->txerrs);
    158 	return readstr(offset, a, n, buf);
    159 }
    160 
    161 static void
    162 tapattach(Ether* e)
    163 {
    164 	kproc("taprecv", taprecvkproc, e);
    165 }
    166 
    167 static int
    168 tappnp(Ether* e)
    169 {
    170 	Ctlr c;
    171 	static int cve = 0;
    172 
    173 	while(cve < MaxEther && ve[cve].tap == 0)
    174 		cve++;
    175 	if(cve == MaxEther || ve[cve].dev == nil)
    176 		return -1;
    177 
    178 	memset(&c, 0, sizeof c);
    179 	c.fd = setup(ve[cve].dev);
    180 	memcpy(c.ea, ve[cve].ea, Eaddrlen);
    181 	if(c.fd== -1){
    182 		iprint("ve: tap failed to initialize\n");
    183 		cve++;
    184 		return -1;
    185 	}
    186 	e->ctlr = malloc(sizeof c);
    187 	memcpy(e->ctlr, &c, sizeof c);
    188 	e->tbdf = BUSUNKNOWN;
    189 	memcpy(e->ea, ve[cve].ea, Eaddrlen);
    190 	e->attach = tapattach;
    191 	e->transmit = taptransmit;
    192 	e->ifstat = tapifstat;
    193 	e->ni.arg = e;
    194 	e->ni.link = 1;
    195 	cve++;
    196 	return 0;
    197 }
    198 
    199 void
    200 ethertaplink(void)
    201 {
    202 	addethercard("tap", tappnp);
    203 }