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 }