]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - tools/tools/netmap/pcap.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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: pcap.c 11463 2012-07-30 15:26:02Z luigi $";
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         ioctl(me->fd, NIOCUNREGIF, NULL);
449         close(me->fd);
450         bzero(me, sizeof(*me));
451         free(me);
452 }
453
454 int
455 pcap_fileno(pcap_t *p)
456 {
457         struct my_ring *me = p;
458         D("returns %d", me->fd);
459         return me->fd;
460 }
461
462 int
463 pcap_get_selectable_fd(pcap_t *p)
464 {
465         struct my_ring *me = p;
466
467         ND("");
468         return me->fd;
469 }
470
471 int
472 pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf)
473 {
474         (void)p;        /* UNUSED */
475         (void)errbuf;   /* UNUSED */
476         D("mode is %d", nonblock);
477         return 0;       /* ignore */
478 }
479
480 int
481 pcap_setdirection(pcap_t *p, pcap_direction_t d)
482 {
483         (void)p;        /* UNUSED */
484         (void)d;        /* UNUSED */
485         D("");
486         return 0;       /* ignore */
487 };
488
489 int
490 pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
491 {
492         struct pcap_ring *pme = p;
493         struct my_ring *me = &pme->me;
494         int got = 0;
495         u_int si;
496
497         ND("cnt %d", cnt);
498         if (cnt == 0)
499                 cnt = -1;
500         /* scan all rings */
501         for (si = me->begin; si < me->end; si++) {
502                 struct netmap_ring *ring = NETMAP_RXRING(me->nifp, si);
503                 ND("ring has %d pkts", ring->avail);
504                 if (ring->avail == 0)
505                         continue;
506                 pme->hdr.ts = ring->ts;
507                 /*
508                  * XXX a proper prefetch should be done as
509                  *      prefetch(i); callback(i-1); ...
510                  */
511                 while ((cnt == -1 || cnt != got) && ring->avail > 0) {
512                         u_int i = ring->cur;
513                         u_int idx = ring->slot[i].buf_idx;
514                         if (idx < 2) {
515                                 D("%s bogus RX index %d at offset %d",
516                                         me->nifp->ni_name, idx, i);
517                                 sleep(2);
518                         }
519                         u_char *buf = (u_char *)NETMAP_BUF(ring, idx);
520                         prefetch(buf);
521                         pme->hdr.len = pme->hdr.caplen = ring->slot[i].len;
522                         // D("call %p len %d", p, me->hdr.len);
523                         callback(user, &pme->hdr, buf);
524                         ring->cur = NETMAP_RING_NEXT(ring, i);
525                         ring->avail--;
526                         got++;
527                 }
528         }
529         pme->st.ps_recv += got;
530         return got;
531 }
532
533 int
534 pcap_inject(pcap_t *p, const void *buf, size_t size)
535 {
536         struct my_ring *me = p;
537         u_int si;
538  
539         ND("cnt %d", cnt);
540         /* scan all rings */
541         for (si = me->begin; si < me->end; si++) {
542                 struct netmap_ring *ring = NETMAP_TXRING(me->nifp, si);
543  
544                 ND("ring has %d pkts", ring->avail);
545                 if (ring->avail == 0)
546                         continue;
547                 u_int i = ring->cur;
548                 u_int idx = ring->slot[i].buf_idx;
549                 if (idx < 2) {
550                         D("%s bogus TX index %d at offset %d",
551                                 me->nifp->ni_name, idx, i);
552                         sleep(2);
553                 }
554                 u_char *dst = (u_char *)NETMAP_BUF(ring, idx);
555                 ring->slot[i].len = size;
556                 pkt_copy(buf, dst, size);
557                 ring->cur = NETMAP_RING_NEXT(ring, i);
558                 ring->avail--;
559                 // if (ring->avail == 0) ioctl(me->fd, NIOCTXSYNC, NULL);
560                 return size;
561         }
562         errno = ENOBUFS;
563         return -1;
564 }
565
566 int
567 pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
568 {
569         struct pcap_ring *me = p;
570         struct pollfd fds[1];
571         int i;
572
573         ND("cnt %d", cnt);
574         memset(fds, 0, sizeof(fds));
575         fds[0].fd = me->me.fd;
576         fds[0].events = (POLLIN);
577
578         while (cnt == -1 || cnt > 0) {
579                 if (poll(fds, 1, me->to_ms) <= 0) {
580                         D("poll error/timeout");
581                         continue;
582                 }
583                 i = pcap_dispatch(p, cnt, callback, user);
584                 if (cnt > 0)
585                         cnt -= i;
586         }
587         return 0;
588 }
589
590 #endif /* !TEST */
591
592 #ifdef TEST     /* build test code */
593 void do_send(u_char *user, const struct pcap_pkthdr *h, const u_char *buf)
594 {
595         pcap_inject((pcap_t *)user, buf, h->caplen);
596 }
597
598 /*
599  * a simple pcap test program, bridge between two interfaces.
600  */
601 int
602 main(int argc, char **argv)
603 {
604         pcap_t *p0, *p1;
605         int burst = 1024;
606         struct pollfd pollfd[2];
607
608         fprintf(stderr, "%s %s built %s %s\n",
609                 argv[0], version, __DATE__, __TIME__);
610                 
611         while (argc > 1 && !strcmp(argv[1], "-v")) {
612                 verbose++;
613                 argv++;
614                 argc--;
615         }
616
617         if (argc < 3 || argc > 4 || !strcmp(argv[1], argv[2])) {
618                 D("Usage: %s IFNAME1 IFNAME2 [BURST]", argv[0]);
619                 return (1);
620         }
621         if (argc > 3)
622                 burst = atoi(argv[3]);
623
624         p0 = pcap_open_live(argv[1], 0, 1, 100, NULL);
625         p1 = pcap_open_live(argv[2], 0, 1, 100, NULL);
626         D("%s", version);
627         D("open returns %p %p", p0, p1);
628         if (!p0 || !p1)
629                 return(1);
630         bzero(pollfd, sizeof(pollfd));
631         pollfd[0].fd = pcap_fileno(p0);
632         pollfd[1].fd = pcap_fileno(p1);
633         pollfd[0].events = pollfd[1].events = POLLIN;
634         for (;;) {
635                 /* do i need to reset ? */
636                 pollfd[0].revents = pollfd[1].revents = 0;
637                 int ret = poll(pollfd, 2, 1000);
638                 if (ret <= 0 || verbose)
639                    D("poll %s [0] ev %x %x [1] ev %x %x",
640                         ret <= 0 ? "timeout" : "ok",
641                                 pollfd[0].events,
642                                 pollfd[0].revents,
643                                 pollfd[1].events,
644                                 pollfd[1].revents);
645                 if (ret < 0)
646                         continue;
647                 if (pollfd[0].revents & POLLIN)
648                         pcap_dispatch(p0, burst, do_send, p1);
649                 if (pollfd[1].revents & POLLIN)
650                         pcap_dispatch(p1, burst, do_send, p0);
651         }
652
653         return (0);
654 }
655 #endif /* TEST */