]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - tools/tools/netmap/pcap.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / tools / tools / netmap / pcap.c
1 /*
2  * (C) 2011-2012 Luigi Rizzo
3  *
4  * BSD license
5  *
6  * A simple library that maps some pcap functions onto netmap
7  * This is not 100% complete but enough to let tcpdump, trafshow
8  * and other apps work.
9  *
10  * $FreeBSD$
11  */
12
13 #define MY_PCAP
14 #include "nm_util.h"
15
16 char *version = "$Id$";
17 int verbose = 0;
18
19 /*
20  * We redefine here a number of structures that are in pcap.h
21  * so we can compile this file without the system header.
22  */
23 #ifndef PCAP_ERRBUF_SIZE
24 #define PCAP_ERRBUF_SIZE 128
25 /*
26  * Each packet is accompanied by a header including the timestamp,
27  * captured size and actual size.
28  */
29 struct pcap_pkthdr {
30         struct timeval ts;      /* time stamp */
31         uint32_t caplen;        /* length of portion present */
32         uint32_t len;           /* length this packet (off wire) */
33 };
34
35 typedef struct pcap_if pcap_if_t;
36
37 /*
38  * Representation of an interface address.
39  */
40 struct pcap_addr {
41         struct pcap_addr *next;
42         struct sockaddr *addr;          /* address */
43         struct sockaddr *netmask;       /* netmask for the above */
44         struct sockaddr *broadaddr;     /* broadcast addr for the above */
45         struct sockaddr *dstaddr;       /* P2P dest. address for the above */
46 };
47
48 struct pcap_if {
49         struct pcap_if *next;
50         char *name;             /* name to hand to "pcap_open_live()" */
51         char *description;      /* textual description of interface, or NULL */
52         struct pcap_addr *addresses;
53         uint32_t flags;      /* PCAP_IF_ interface flags */
54 };
55
56 /*
57  * We do not support stats (yet)
58  */
59 struct pcap_stat {
60         u_int ps_recv;          /* number of packets received */
61         u_int ps_drop;          /* number of packets dropped */
62         u_int ps_ifdrop;        /* drops by interface XXX not yet supported */
63 #ifdef WIN32
64         u_int bs_capt;          /* number of packets that reach the app. */
65 #endif /* WIN32 */
66 };
67
68 typedef void    pcap_t;
69 typedef enum {
70         PCAP_D_INOUT = 0,
71         PCAP_D_IN,
72         PCAP_D_OUT
73 } pcap_direction_t;
74  
75
76
77 typedef void (*pcap_handler)(u_char *user,
78                 const struct pcap_pkthdr *h, const u_char *bytes);
79
80 char errbuf[PCAP_ERRBUF_SIZE];
81
82 pcap_t *pcap_open_live(const char *device, int snaplen,
83                int promisc, int to_ms, char *errbuf);
84
85 int pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf);
86 void pcap_close(pcap_t *p);
87 int pcap_get_selectable_fd(pcap_t *p);
88 int pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user);
89 int pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf);
90 int pcap_setdirection(pcap_t *p, pcap_direction_t d);
91 char *pcap_lookupdev(char *errbuf);
92 int pcap_inject(pcap_t *p, const void *buf, size_t size);
93 int pcap_fileno(pcap_t *p);
94 const char *pcap_lib_version(void);
95
96
97 struct eproto {
98         const char *s;
99         u_short p;
100 };
101 #endif /* !PCAP_ERRBUF_SIZE */
102
103 #ifndef TEST
104 /*
105  * build as a shared library
106  */
107
108 char pcap_version[] = "libnetmap version 0.3";
109
110 /*
111  * Our equivalent of pcap_t
112  */
113 struct pcap_ring {
114         struct my_ring me;
115 #if 0
116         const char *ifname;
117
118         //struct nmreq nmr;
119
120         int fd;
121         char *mem;                      /* userspace mmap address */
122         u_int memsize;
123         u_int queueid;
124         u_int begin, end;               /* first..last+1 rings to check */
125         struct netmap_if *nifp;
126
127         uint32_t if_flags;
128         uint32_t if_reqcap;
129         uint32_t if_curcap;
130 #endif
131         int snaplen;
132         char *errbuf;
133         int promisc;
134         int to_ms;
135
136         struct pcap_pkthdr hdr;
137
138
139         struct pcap_stat st;
140
141         char msg[PCAP_ERRBUF_SIZE];
142 };
143
144
145
146 /*
147  * There is a set of functions that tcpdump expects even if probably
148  * not used
149  */
150 struct eproto eproto_db[] = {
151         { "ip", ETHERTYPE_IP },
152         { "arp", ETHERTYPE_ARP },
153         { (char *)0, 0 }
154 };
155
156
157 const char *pcap_lib_version(void)
158 {
159         return pcap_version;
160 }
161
162 int
163 pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
164 {
165         pcap_if_t *top = NULL;
166 #ifndef linux
167         struct ifaddrs *i_head, *i;
168         pcap_if_t *cur;
169         struct pcap_addr *tail = NULL;
170         int l;
171
172         D("listing all devs");
173         *alldevsp = NULL;
174         i_head = NULL;
175
176         if (getifaddrs(&i_head)) {
177                 D("cannot get if addresses");
178                 return -1;
179         }
180         for (i = i_head; i; i = i->ifa_next) {
181                 //struct ifaddrs   *ifa;
182                 struct pcap_addr *pca;
183                 //struct sockaddr *sa;
184
185                 D("got interface %s", i->ifa_name);
186                 if (!top || strcmp(top->name, i->ifa_name)) {
187                         /* new interface */
188                         l = sizeof(*top) + strlen(i->ifa_name) + 1;
189                         cur = calloc(1, l);
190                         if (cur == NULL) {
191                                 D("no space for if descriptor");
192                                 continue;
193                         }
194                         cur->name = (char *)(cur + 1);
195                         //cur->flags = i->ifa_flags;
196                         strcpy(cur->name, i->ifa_name);
197                         cur->description = NULL;
198                         cur->next = top;
199                         top = cur;
200                         tail = NULL;
201                 }
202                 /* now deal with addresses */
203                 D("%s addr family %d len %d %s %s",
204                         top->name,
205                         i->ifa_addr->sa_family, i->ifa_addr->sa_len,
206                         i->ifa_netmask ? "Netmask" : "",
207                         i->ifa_broadaddr ? "Broadcast" : "");
208                 l = sizeof(struct pcap_addr) +
209                         (i->ifa_addr ? i->ifa_addr->sa_len:0) +
210                         (i->ifa_netmask ? i->ifa_netmask->sa_len:0) +
211                         (i->ifa_broadaddr? i->ifa_broadaddr->sa_len:0);
212                 pca = calloc(1, l);
213                 if (pca == NULL) {
214                         D("no space for if addr");
215                         continue;
216                 }
217 #define SA_NEXT(x) ((struct sockaddr *)((char *)(x) + (x)->sa_len))
218                 pca->addr = (struct sockaddr *)(pca + 1);
219                 pkt_copy(i->ifa_addr, pca->addr, i->ifa_addr->sa_len);
220                 if (i->ifa_netmask) {
221                         pca->netmask = SA_NEXT(pca->addr);
222                         bcopy(i->ifa_netmask, pca->netmask, i->ifa_netmask->sa_len);
223                         if (i->ifa_broadaddr) {
224                                 pca->broadaddr = SA_NEXT(pca->netmask);
225                                 bcopy(i->ifa_broadaddr, pca->broadaddr, i->ifa_broadaddr->sa_len);
226                         }
227                 }
228                 if (tail == NULL) {
229                         top->addresses = pca;
230                 } else {
231                         tail->next = pca;
232                 }
233                 tail = pca;
234
235         }
236         freeifaddrs(i_head);
237 #endif /* !linux */
238         (void)errbuf;   /* UNUSED */
239         *alldevsp = top;
240         return 0;
241 }
242
243 void pcap_freealldevs(pcap_if_t *alldevs)
244 {
245         (void)alldevs;  /* UNUSED */
246         D("unimplemented");
247 }
248
249 char *
250 pcap_lookupdev(char *buf)
251 {
252         D("%s", buf);
253         strcpy(buf, "/dev/netmap");
254         return buf;
255 }
256
257 pcap_t *
258 pcap_create(const char *source, char *errbuf)
259 {
260         D("src %s (call open liveted)", source);
261         return pcap_open_live(source, 0, 1, 100, errbuf);
262 }
263
264 int
265 pcap_activate(pcap_t *p)
266 {
267         D("pcap %p running", p);
268         return 0;
269 }
270
271 int
272 pcap_can_set_rfmon(pcap_t *p)
273 {
274         (void)p;        /* UNUSED */
275         D("");
276         return 0;       /* no we can't */
277 }
278
279 int
280 pcap_set_snaplen(pcap_t *p, int snaplen)
281 {
282         struct pcap_ring *me = p;
283
284         D("len %d", snaplen);
285         me->snaplen = snaplen;
286         return 0;
287 }
288
289 int
290 pcap_snapshot(pcap_t *p)
291 {
292         struct pcap_ring *me = p;
293
294         D("len %d", me->snaplen);
295         return me->snaplen;
296 }
297
298 int
299 pcap_lookupnet(const char *device, uint32_t *netp,
300         uint32_t *maskp, char *errbuf)
301 {
302
303         (void)errbuf;   /* UNUSED */
304         D("device %s", device);
305         inet_aton("10.0.0.255", (struct in_addr *)netp);
306         inet_aton("255.255.255.0",(struct in_addr *) maskp);
307         return 0;
308 }
309
310 int
311 pcap_set_promisc(pcap_t *p, int promisc)
312 {
313         struct pcap_ring *me = p;
314
315         D("promisc %d", promisc);
316         if (nm_do_ioctl(&me->me, SIOCGIFFLAGS, 0))
317                 D("SIOCGIFFLAGS failed");
318         if (promisc) {
319                 me->me.if_flags |= IFF_PPROMISC;
320         } else {
321                 me->me.if_flags &= ~IFF_PPROMISC;
322         }
323         if (nm_do_ioctl(&me->me, SIOCSIFFLAGS, 0))
324                 D("SIOCSIFFLAGS failed");
325         return 0;
326 }
327
328 int
329 pcap_set_timeout(pcap_t *p, int to_ms)
330 {
331         struct pcap_ring *me = p;
332
333         D("%d ms", to_ms);
334         me->to_ms = to_ms;
335         return 0;
336 }
337
338 struct bpf_program;
339
340 int
341 pcap_compile(pcap_t *p, struct bpf_program *fp,
342         const char *str, int optimize, uint32_t netmask)
343 {
344         (void)p;        /* UNUSED */
345         (void)fp;       /* UNUSED */
346         (void)optimize; /* UNUSED */
347         (void)netmask;  /* UNUSED */
348         D("%s", str);
349         return 0;
350 }
351
352 int
353 pcap_setfilter(pcap_t *p, struct bpf_program *fp)
354 {
355         (void)p;        /* UNUSED */
356         (void)fp;       /* UNUSED */
357         D("");
358         return 0;
359 }
360
361 int
362 pcap_datalink(pcap_t *p)
363 {
364         (void)p;        /* UNUSED */
365         D("returns 1");
366         return 1;       // ethernet
367 }
368
369 const char *
370 pcap_datalink_val_to_name(int dlt)
371 {
372         D("%d returns DLT_EN10MB", dlt);
373         return "DLT_EN10MB";
374 }
375
376 const char *
377 pcap_datalink_val_to_description(int dlt)
378 {
379         D("%d returns Ethernet link", dlt);
380         return "Ethernet link";
381 }
382
383 struct pcap_stat;
384 int
385 pcap_stats(pcap_t *p, struct pcap_stat *ps)
386 {
387         struct pcap_ring *me = p;
388         ND("");
389
390         *ps = me->st;
391         return 0;       /* accumulate from pcap_dispatch() */
392 };
393
394 char *
395 pcap_geterr(pcap_t *p)
396 {
397         struct pcap_ring *me = p;
398
399         D("");
400         return me->msg;
401 }
402
403 pcap_t *
404 pcap_open_live(const char *device, int snaplen,
405                int promisc, int to_ms, char *errbuf)
406 {
407         struct pcap_ring *me;
408         int l;
409
410         (void)snaplen;  /* UNUSED */
411         (void)errbuf;   /* UNUSED */
412         if (!device) {
413                 D("missing device name");
414                 return NULL;
415         }
416
417         l = strlen(device) + 1;
418         D("request to open %s snaplen %d promisc %d timeout %dms",
419                 device, snaplen, promisc, to_ms);
420         me = calloc(1, sizeof(*me) + l);
421         if (me == NULL) {
422                 D("failed to allocate struct for %s", device);
423                 return NULL;
424         }
425         me->me.ifname = (char *)(me + 1);
426         strcpy((char *)me->me.ifname, device);
427         if (netmap_open(&me->me, 0, promisc)) {
428                 D("error opening %s", device);
429                 free(me);
430                 return NULL;
431         }
432         me->to_ms = to_ms;
433
434         return (pcap_t *)me;
435 }
436
437 void
438 pcap_close(pcap_t *p)
439 {
440         struct my_ring *me = p;
441
442         D("");
443         if (!me)
444                 return;
445         if (me->mem)
446                 munmap(me->mem, me->memsize);
447         /* restore original flags ? */
448         close(me->fd);
449         bzero(me, sizeof(*me));
450         free(me);
451 }
452
453 int
454 pcap_fileno(pcap_t *p)
455 {
456         struct my_ring *me = p;
457         D("returns %d", me->fd);
458         return me->fd;
459 }
460
461 int
462 pcap_get_selectable_fd(pcap_t *p)
463 {
464         struct my_ring *me = p;
465
466         ND("");
467         return me->fd;
468 }
469
470 int
471 pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf)
472 {
473         (void)p;        /* UNUSED */
474         (void)errbuf;   /* UNUSED */
475         D("mode is %d", nonblock);
476         return 0;       /* ignore */
477 }
478
479 int
480 pcap_setdirection(pcap_t *p, pcap_direction_t d)
481 {
482         (void)p;        /* UNUSED */
483         (void)d;        /* UNUSED */
484         D("");
485         return 0;       /* ignore */
486 };
487
488 int
489 pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
490 {
491         struct pcap_ring *pme = p;
492         struct my_ring *me = &pme->me;
493         int got = 0;
494         u_int si;
495
496         ND("cnt %d", cnt);
497         if (cnt == 0)
498                 cnt = -1;
499         /* scan all rings */
500         for (si = me->begin; si < me->end; si++) {
501                 struct netmap_ring *ring = NETMAP_RXRING(me->nifp, si);
502                 ND("ring has %d pkts", ring->avail);
503                 if (ring->avail == 0)
504                         continue;
505                 pme->hdr.ts = ring->ts;
506                 /*
507                  * XXX a proper prefetch should be done as
508                  *      prefetch(i); callback(i-1); ...
509                  */
510                 while ((cnt == -1 || cnt != got) && ring->avail > 0) {
511                         u_int i = ring->cur;
512                         u_int idx = ring->slot[i].buf_idx;
513                         if (idx < 2) {
514                                 D("%s bogus RX index %d at offset %d",
515                                         me->nifp->ni_name, idx, i);
516                                 sleep(2);
517                         }
518                         u_char *buf = (u_char *)NETMAP_BUF(ring, idx);
519                         prefetch(buf);
520                         pme->hdr.len = pme->hdr.caplen = ring->slot[i].len;
521                         // D("call %p len %d", p, me->hdr.len);
522                         callback(user, &pme->hdr, buf);
523                         ring->cur = NETMAP_RING_NEXT(ring, i);
524                         ring->avail--;
525                         got++;
526                 }
527         }
528         pme->st.ps_recv += got;
529         return got;
530 }
531
532 int
533 pcap_inject(pcap_t *p, const void *buf, size_t size)
534 {
535         struct my_ring *me = p;
536         u_int si;
537  
538         ND("cnt %d", cnt);
539         /* scan all rings */
540         for (si = me->begin; si < me->end; si++) {
541                 struct netmap_ring *ring = NETMAP_TXRING(me->nifp, si);
542  
543                 ND("ring has %d pkts", ring->avail);
544                 if (ring->avail == 0)
545                         continue;
546                 u_int i = ring->cur;
547                 u_int idx = ring->slot[i].buf_idx;
548                 if (idx < 2) {
549                         D("%s bogus TX index %d at offset %d",
550                                 me->nifp->ni_name, idx, i);
551                         sleep(2);
552                 }
553                 u_char *dst = (u_char *)NETMAP_BUF(ring, idx);
554                 ring->slot[i].len = size;
555                 pkt_copy(buf, dst, size);
556                 ring->cur = NETMAP_RING_NEXT(ring, i);
557                 ring->avail--;
558                 // if (ring->avail == 0) ioctl(me->fd, NIOCTXSYNC, NULL);
559                 return size;
560         }
561         errno = ENOBUFS;
562         return -1;
563 }
564
565 int
566 pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
567 {
568         struct pcap_ring *me = p;
569         struct pollfd fds[1];
570         int i;
571
572         ND("cnt %d", cnt);
573         memset(fds, 0, sizeof(fds));
574         fds[0].fd = me->me.fd;
575         fds[0].events = (POLLIN);
576
577         while (cnt == -1 || cnt > 0) {
578                 if (poll(fds, 1, me->to_ms) <= 0) {
579                         D("poll error/timeout");
580                         continue;
581                 }
582                 i = pcap_dispatch(p, cnt, callback, user);
583                 if (cnt > 0)
584                         cnt -= i;
585         }
586         return 0;
587 }
588
589 #endif /* !TEST */
590
591 #ifdef TEST     /* build test code */
592 void do_send(u_char *user, const struct pcap_pkthdr *h, const u_char *buf)
593 {
594         pcap_inject((pcap_t *)user, buf, h->caplen);
595 }
596
597 /*
598  * a simple pcap test program, bridge between two interfaces.
599  */
600 int
601 main(int argc, char **argv)
602 {
603         pcap_t *p0, *p1;
604         int burst = 1024;
605         struct pollfd pollfd[2];
606
607         fprintf(stderr, "%s %s built %s %s\n",
608                 argv[0], version, __DATE__, __TIME__);
609                 
610         while (argc > 1 && !strcmp(argv[1], "-v")) {
611                 verbose++;
612                 argv++;
613                 argc--;
614         }
615
616         if (argc < 3 || argc > 4 || !strcmp(argv[1], argv[2])) {
617                 D("Usage: %s IFNAME1 IFNAME2 [BURST]", argv[0]);
618                 return (1);
619         }
620         if (argc > 3)
621                 burst = atoi(argv[3]);
622
623         p0 = pcap_open_live(argv[1], 0, 1, 100, NULL);
624         p1 = pcap_open_live(argv[2], 0, 1, 100, NULL);
625         D("%s", version);
626         D("open returns %p %p", p0, p1);
627         if (!p0 || !p1)
628                 return(1);
629         bzero(pollfd, sizeof(pollfd));
630         pollfd[0].fd = pcap_fileno(p0);
631         pollfd[1].fd = pcap_fileno(p1);
632         pollfd[0].events = pollfd[1].events = POLLIN;
633         for (;;) {
634                 /* do i need to reset ? */
635                 pollfd[0].revents = pollfd[1].revents = 0;
636                 int ret = poll(pollfd, 2, 1000);
637                 if (ret <= 0 || verbose)
638                    D("poll %s [0] ev %x %x [1] ev %x %x",
639                         ret <= 0 ? "timeout" : "ok",
640                                 pollfd[0].events,
641                                 pollfd[0].revents,
642                                 pollfd[1].events,
643                                 pollfd[1].revents);
644                 if (ret < 0)
645                         continue;
646                 if (pollfd[0].revents & POLLIN)
647                         pcap_dispatch(p0, burst, do_send, p1);
648                 if (pollfd[1].revents & POLLIN)
649                         pcap_dispatch(p1, burst, do_send, p0);
650         }
651
652         return (0);
653 }
654 #endif /* TEST */