etherpcap.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       etherpcap.c (3312B)
       ---
            1 /*
            2  * etherpcap - portable Virtual Ethernet driver for 9vx.
            3  * 
            4  * Copyright (c) 2008 Devon H. O'Dell
            5  * copyright © 2008 erik quanstrom
            6  * copyright © 2010 Jesus Galan Lopez
            7  *
            8  * Released under 2-clause BSD license.
            9  */
           10 
           11 #include "u.h"
           12 
           13 #include "lib.h"
           14 #include "mem.h"
           15 #include "dat.h"
           16 #include "fns.h"
           17 #include "io.h"
           18 #include "error.h"
           19 #include "netif.h"
           20 #include "etherif.h"
           21 #include "vether.h"
           22 
           23 #include <pcap.h>
           24 
           25 static        uvlong        txerrs;
           26 
           27 extern        int        eafrom(char *ma, uchar ea[6]);
           28 
           29 typedef struct Ctlr Ctlr;
           30 struct Ctlr {
           31         pcap_t        *pd;
           32 };
           33 
           34 static void *
           35 veerror(char* err)
           36 {
           37         iprint("ve: %s\n", err);
           38         return nil;
           39 }
           40 
           41 static pcap_t *
           42 setup(char *dev, uchar *ea)
           43 {
           44         char        filter[30];
           45         char        errbuf[PCAP_ERRBUF_SIZE];
           46         pcap_t        *pd;
           47         struct bpf_program prog;
           48         bpf_u_int32 net;
           49         bpf_u_int32 mask;
           50 
           51         if(sprint(filter, "ether dst %2.2ux:%2.2ux:%2.2ux:%2.2ux:%2.2ux:%2.2ux",
           52         ea[0], ea[1], ea[2],ea[3], ea[4], ea[5]) == -1)
           53                 return veerror("cannot create pcap filter");
           54 
           55         if ((pd = pcap_open_live(dev, 65000, 1, 1, errbuf)) == nil){
           56                 // try to find a device
           57                 if ((dev = pcap_lookupdev(errbuf)) == nil)
           58                         return veerror("cannot find network device");
           59                 if ((pd = pcap_open_live(dev, 65000, 1, 1, errbuf)) == nil)
           60                         return nil;
           61         }
           62 
           63         pcap_lookupnet(dev, &net, &mask, errbuf);
           64         pcap_compile(pd, &prog, filter, 0, net);
           65 
           66         if (pcap_setfilter(pd, &prog) == -1)
           67                 return nil;
           68 
           69         pcap_freecode(&prog);
           70 
           71         return pd;
           72 }
           73 
           74 static Block *
           75 pcappkt(Ctlr *c)
           76 {
           77         struct pcap_pkthdr hdr;
           78         uchar *p;
           79         Block *b;
           80 
           81         while ((p = pcap_next(c->pd, &hdr)) == nil);
           82 
           83         b = allocb(hdr.caplen);
           84         memcpy(b->rp, p, hdr.caplen);
           85         b->wp += hdr.caplen;
           86         b->flag |= Btcpck|Budpck|Bpktck;
           87 
           88 /*
           89         iprint("+++++++++++ packet %d (len %d):\n", ++fn, hdr.caplen);
           90         int i=0; uchar* u;
           91         static int fn=0;
           92 
           93         for(u=b->rp; u<b->wp; u++){
           94                 if (i%16 == 0) iprint("%.4ux", i);
           95                 if (i%8 == 0) iprint("   ");
           96                 iprint("%2.2ux ", *u);
           97                 if (++i%16 == 0) iprint("\n");
           98         }
           99         iprint("\n-------------\n");
          100 */
          101 
          102         return b;
          103 
          104 }
          105 
          106 static void
          107 pcaprecvkproc(void *v)
          108 {
          109         Ether *e;
          110         Block *b;
          111 
          112         e = v;
          113         while ((b = pcappkt(e->ctlr))) 
          114                 if (b != nil)
          115                         etheriq(e, b, 1);
          116 }
          117 
          118 static void
          119 pcaptransmit(Ether* e)
          120 {
          121         const u_char *u;
          122         Block *b;
          123         Ctlr *c;
          124 
          125         c = e->ctlr;
          126         while ((b = qget(e->oq)) != nil) {
          127                 int wlen;
          128 
          129                 u = (const u_char*)b->rp;
          130 
          131                 wlen = pcap_inject(c->pd, u, BLEN(b));
          132                 // iprint("injected packet len %d\n", wlen);
          133                 if (wlen == -1)
          134                         txerrs++;
          135 
          136                 freeb(b);
          137         }
          138 }
          139 
          140 static long
          141 pcapifstat(Ether *e, void *a, long n, ulong offset)
          142 {
          143         char buf[128];
          144 
          145         snprint(buf, sizeof buf, "txerrors: %lud\n", txerrs);
          146         return readstr(offset, a, n, buf);
          147 }
          148 
          149 static void
          150 pcapattach(Ether* e)
          151 {
          152         kproc("pcaprecv", pcaprecvkproc, e);
          153 }
          154 
          155 static int
          156 pcappnp(Ether* e)
          157 {
          158         Ctlr c;
          159         static int cve = 0;
          160 
          161         while(cve < MaxEther && ve[cve].tap == 1)
          162                 cve++;
          163         if(cve == MaxEther || ve[cve].dev == nil)
          164                 return -1;
          165 
          166         memset(&c, 0, sizeof(c));
          167         c.pd = setup(ve[cve].dev, ve[cve].ea);
          168         if (c.pd == nil) {
          169                 iprint("ve: pcap failed to initialize\n");
          170                 cve++;
          171                 return -1;
          172         }
          173         e->ctlr = malloc(sizeof(c));
          174         memcpy(e->ctlr, &c, sizeof(c));
          175         e->tbdf = BUSUNKNOWN;
          176         memcpy(e->ea, ve[cve].ea, Eaddrlen);
          177         e->attach = pcapattach;
          178         e->transmit = pcaptransmit;
          179         e->ifstat = pcapifstat;
          180         e->ni.arg = e;
          181         e->ni.link = 1;
          182         cve++;
          183         return 0;
          184 }
          185 
          186 void
          187 etherpcaplink(void)
          188 {
          189         addethercard("pcap", pcappnp);
          190 }