2 * (C) 2011-2012 Luigi Rizzo
6 * A simple library that maps some pcap functions onto netmap
7 * This is not 100% complete but enough to let tcpdump, trafshow
16 char *version = "$Id$";
20 * We redefine here a number of structures that are in pcap.h
21 * so we can compile this file without the system header.
23 #ifndef PCAP_ERRBUF_SIZE
24 #define PCAP_ERRBUF_SIZE 128
26 * Each packet is accompanied by a header including the timestamp,
27 * captured size and actual size.
30 struct timeval ts; /* time stamp */
31 uint32_t caplen; /* length of portion present */
32 uint32_t len; /* length this packet (off wire) */
35 typedef struct pcap_if pcap_if_t;
38 * Representation of an interface address.
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 */
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 */
57 * We do not support stats (yet)
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 */
64 u_int bs_capt; /* number of packets that reach the app. */
77 typedef void (*pcap_handler)(u_char *user,
78 const struct pcap_pkthdr *h, const u_char *bytes);
80 char errbuf[PCAP_ERRBUF_SIZE];
82 pcap_t *pcap_open_live(const char *device, int snaplen,
83 int promisc, int to_ms, char *errbuf);
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);
101 #endif /* !PCAP_ERRBUF_SIZE */
105 * build as a shared library
108 char pcap_version[] = "libnetmap version 0.3";
111 * Our equivalent of pcap_t
121 char *mem; /* userspace mmap address */
124 u_int begin, end; /* first..last+1 rings to check */
125 struct netmap_if *nifp;
136 struct pcap_pkthdr hdr;
141 char msg[PCAP_ERRBUF_SIZE];
147 * There is a set of functions that tcpdump expects even if probably
150 struct eproto eproto_db[] = {
151 { "ip", ETHERTYPE_IP },
152 { "arp", ETHERTYPE_ARP },
157 const char *pcap_lib_version(void)
163 pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
165 pcap_if_t *top = NULL;
167 struct ifaddrs *i_head, *i;
169 struct pcap_addr *tail = NULL;
172 D("listing all devs");
176 if (getifaddrs(&i_head)) {
177 D("cannot get if addresses");
180 for (i = i_head; i; i = i->ifa_next) {
181 //struct ifaddrs *ifa;
182 struct pcap_addr *pca;
183 //struct sockaddr *sa;
185 D("got interface %s", i->ifa_name);
186 if (!top || strcmp(top->name, i->ifa_name)) {
188 l = sizeof(*top) + strlen(i->ifa_name) + 1;
191 D("no space for if descriptor");
194 cur->name = (char *)(cur + 1);
195 //cur->flags = i->ifa_flags;
196 strcpy(cur->name, i->ifa_name);
197 cur->description = NULL;
202 /* now deal with addresses */
203 D("%s addr family %d len %d %s %s",
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);
214 D("no space for if addr");
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);
229 top->addresses = pca;
238 (void)errbuf; /* UNUSED */
243 void pcap_freealldevs(pcap_if_t *alldevs)
245 (void)alldevs; /* UNUSED */
250 pcap_lookupdev(char *buf)
253 strcpy(buf, "/dev/netmap");
258 pcap_create(const char *source, char *errbuf)
260 D("src %s (call open liveted)", source);
261 return pcap_open_live(source, 0, 1, 100, errbuf);
265 pcap_activate(pcap_t *p)
267 D("pcap %p running", p);
272 pcap_can_set_rfmon(pcap_t *p)
274 (void)p; /* UNUSED */
276 return 0; /* no we can't */
280 pcap_set_snaplen(pcap_t *p, int snaplen)
282 struct pcap_ring *me = p;
284 D("len %d", snaplen);
285 me->snaplen = snaplen;
290 pcap_snapshot(pcap_t *p)
292 struct pcap_ring *me = p;
294 D("len %d", me->snaplen);
299 pcap_lookupnet(const char *device, uint32_t *netp,
300 uint32_t *maskp, char *errbuf)
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);
311 pcap_set_promisc(pcap_t *p, int promisc)
313 struct pcap_ring *me = p;
315 D("promisc %d", promisc);
316 if (nm_do_ioctl(&me->me, SIOCGIFFLAGS, 0))
317 D("SIOCGIFFLAGS failed");
319 me->me.if_flags |= IFF_PPROMISC;
321 me->me.if_flags &= ~IFF_PPROMISC;
323 if (nm_do_ioctl(&me->me, SIOCSIFFLAGS, 0))
324 D("SIOCSIFFLAGS failed");
329 pcap_set_timeout(pcap_t *p, int to_ms)
331 struct pcap_ring *me = p;
341 pcap_compile(pcap_t *p, struct bpf_program *fp,
342 const char *str, int optimize, uint32_t netmask)
344 (void)p; /* UNUSED */
345 (void)fp; /* UNUSED */
346 (void)optimize; /* UNUSED */
347 (void)netmask; /* UNUSED */
353 pcap_setfilter(pcap_t *p, struct bpf_program *fp)
355 (void)p; /* UNUSED */
356 (void)fp; /* UNUSED */
362 pcap_datalink(pcap_t *p)
364 (void)p; /* UNUSED */
366 return 1; // ethernet
370 pcap_datalink_val_to_name(int dlt)
372 D("%d returns DLT_EN10MB", dlt);
377 pcap_datalink_val_to_description(int dlt)
379 D("%d returns Ethernet link", dlt);
380 return "Ethernet link";
385 pcap_stats(pcap_t *p, struct pcap_stat *ps)
387 struct pcap_ring *me = p;
391 return 0; /* accumulate from pcap_dispatch() */
395 pcap_geterr(pcap_t *p)
397 struct pcap_ring *me = p;
404 pcap_open_live(const char *device, int snaplen,
405 int promisc, int to_ms, char *errbuf)
407 struct pcap_ring *me;
410 (void)snaplen; /* UNUSED */
411 (void)errbuf; /* UNUSED */
413 D("missing device name");
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);
422 D("failed to allocate struct for %s", device);
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);
438 pcap_close(pcap_t *p)
440 struct my_ring *me = p;
446 munmap(me->mem, me->memsize);
447 /* restore original flags ? */
449 bzero(me, sizeof(*me));
454 pcap_fileno(pcap_t *p)
456 struct my_ring *me = p;
457 D("returns %d", me->fd);
462 pcap_get_selectable_fd(pcap_t *p)
464 struct my_ring *me = p;
471 pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf)
473 (void)p; /* UNUSED */
474 (void)errbuf; /* UNUSED */
475 D("mode is %d", nonblock);
476 return 0; /* ignore */
480 pcap_setdirection(pcap_t *p, pcap_direction_t d)
482 (void)p; /* UNUSED */
483 (void)d; /* UNUSED */
485 return 0; /* ignore */
489 pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
491 struct pcap_ring *pme = p;
492 struct my_ring *me = &pme->me;
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)
505 pme->hdr.ts = ring->ts;
507 * XXX a proper prefetch should be done as
508 * prefetch(i); callback(i-1); ...
510 while ((cnt == -1 || cnt != got) && ring->avail > 0) {
512 u_int idx = ring->slot[i].buf_idx;
514 D("%s bogus RX index %d at offset %d",
515 me->nifp->ni_name, idx, i);
518 u_char *buf = (u_char *)NETMAP_BUF(ring, idx);
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);
528 pme->st.ps_recv += got;
533 pcap_inject(pcap_t *p, const void *buf, size_t size)
535 struct my_ring *me = p;
540 for (si = me->begin; si < me->end; si++) {
541 struct netmap_ring *ring = NETMAP_TXRING(me->nifp, si);
543 ND("ring has %d pkts", ring->avail);
544 if (ring->avail == 0)
547 u_int idx = ring->slot[i].buf_idx;
549 D("%s bogus TX index %d at offset %d",
550 me->nifp->ni_name, idx, i);
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);
558 // if (ring->avail == 0) ioctl(me->fd, NIOCTXSYNC, NULL);
566 pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
568 struct pcap_ring *me = p;
569 struct pollfd fds[1];
573 memset(fds, 0, sizeof(fds));
574 fds[0].fd = me->me.fd;
575 fds[0].events = (POLLIN);
577 while (cnt == -1 || cnt > 0) {
578 if (poll(fds, 1, me->to_ms) <= 0) {
579 D("poll error/timeout");
582 i = pcap_dispatch(p, cnt, callback, user);
591 #ifdef TEST /* build test code */
592 void do_send(u_char *user, const struct pcap_pkthdr *h, const u_char *buf)
594 pcap_inject((pcap_t *)user, buf, h->caplen);
598 * a simple pcap test program, bridge between two interfaces.
601 main(int argc, char **argv)
605 struct pollfd pollfd[2];
607 fprintf(stderr, "%s %s built %s %s\n",
608 argv[0], version, __DATE__, __TIME__);
610 while (argc > 1 && !strcmp(argv[1], "-v")) {
616 if (argc < 3 || argc > 4 || !strcmp(argv[1], argv[2])) {
617 D("Usage: %s IFNAME1 IFNAME2 [BURST]", argv[0]);
621 burst = atoi(argv[3]);
623 p0 = pcap_open_live(argv[1], 0, 1, 100, NULL);
624 p1 = pcap_open_live(argv[2], 0, 1, 100, NULL);
626 D("open returns %p %p", p0, p1);
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;
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",
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);