vx32

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