ethertap.c - vx32 - Local 9vx git repository for patches.
(HTM) git clone git://r-36.net/vx32
(DIR) Log
(DIR) Files
(DIR) 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 }