168b8534bSLuigi Rizzo /* 268b8534bSLuigi Rizzo * Copyright (C) 2011 Matteo Landi, Luigi Rizzo. All rights reserved. 3*f9790aebSLuigi Rizzo * Copyright (C) 2013 Universita` di Pisa 468b8534bSLuigi Rizzo * 568b8534bSLuigi Rizzo * Redistribution and use in source and binary forms, with or without 6*f9790aebSLuigi Rizzo * modification, are permitted provided that the following conditions 7*f9790aebSLuigi Rizzo * are met: 868b8534bSLuigi Rizzo * 968b8534bSLuigi Rizzo * 1. Redistributions of source code must retain the above copyright 1068b8534bSLuigi Rizzo * notice, this list of conditions and the following disclaimer. 1168b8534bSLuigi Rizzo * 2. Redistributions in binary form must reproduce the above copyright 1268b8534bSLuigi Rizzo * notice, this list of conditions and the following disclaimer in the 13*f9790aebSLuigi Rizzo * documentation and/or other materials provided with the distribution. 1468b8534bSLuigi Rizzo * 15*f9790aebSLuigi Rizzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1668b8534bSLuigi Rizzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*f9790aebSLuigi Rizzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*f9790aebSLuigi Rizzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*f9790aebSLuigi Rizzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*f9790aebSLuigi Rizzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*f9790aebSLuigi Rizzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*f9790aebSLuigi Rizzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*f9790aebSLuigi Rizzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*f9790aebSLuigi Rizzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*f9790aebSLuigi Rizzo * SUCH DAMAGE. 2668b8534bSLuigi Rizzo */ 2768b8534bSLuigi Rizzo 2868b8534bSLuigi Rizzo /* 2968b8534bSLuigi Rizzo * $FreeBSD$ 3068b8534bSLuigi Rizzo * 3168b8534bSLuigi Rizzo * This header contains the macros used to manipulate netmap structures 3268b8534bSLuigi Rizzo * and packets in userspace. See netmap(4) for more information. 3368b8534bSLuigi Rizzo * 3464ae02c3SLuigi Rizzo * The address of the struct netmap_if, say nifp, is computed from the 3564ae02c3SLuigi Rizzo * value returned from ioctl(.., NIOCREG, ...) and the mmap region: 3668b8534bSLuigi Rizzo * ioctl(fd, NIOCREG, &req); 3768b8534bSLuigi Rizzo * mem = mmap(0, ... ); 3868b8534bSLuigi Rizzo * nifp = NETMAP_IF(mem, req.nr_nifp); 3968b8534bSLuigi Rizzo * (so simple, we could just do it manually) 4068b8534bSLuigi Rizzo * 4168b8534bSLuigi Rizzo * From there: 4268b8534bSLuigi Rizzo * struct netmap_ring *NETMAP_TXRING(nifp, index) 4368b8534bSLuigi Rizzo * struct netmap_ring *NETMAP_RXRING(nifp, index) 4468b8534bSLuigi Rizzo * we can access ring->nr_cur, ring->nr_avail, ring->nr_flags 4568b8534bSLuigi Rizzo * 4668b8534bSLuigi Rizzo * ring->slot[i] gives us the i-th slot (we can access 4768b8534bSLuigi Rizzo * directly plen, flags, bufindex) 4868b8534bSLuigi Rizzo * 4927892e02SLuigi Rizzo * char *buf = NETMAP_BUF(ring, x) returns a pointer to 5027892e02SLuigi Rizzo * the buffer numbered x 5168b8534bSLuigi Rizzo * 5268b8534bSLuigi Rizzo * Since rings are circular, we have macros to compute the next index 5368b8534bSLuigi Rizzo * i = NETMAP_RING_NEXT(ring, i); 54*f9790aebSLuigi Rizzo * 55*f9790aebSLuigi Rizzo * To ease porting apps from pcap to netmap we supply a few fuctions 56*f9790aebSLuigi Rizzo * that can be called to open, close and read from netmap in a way 57*f9790aebSLuigi Rizzo * similar to libpcap. 58*f9790aebSLuigi Rizzo * 59*f9790aebSLuigi Rizzo * In order to use these, include #define NETMAP_WITH_LIBS 60*f9790aebSLuigi Rizzo * in the source file that invokes these functions. 6168b8534bSLuigi Rizzo */ 6268b8534bSLuigi Rizzo 6368b8534bSLuigi Rizzo #ifndef _NET_NETMAP_USER_H_ 6468b8534bSLuigi Rizzo #define _NET_NETMAP_USER_H_ 6568b8534bSLuigi Rizzo 66*f9790aebSLuigi Rizzo #include <stdint.h> 67*f9790aebSLuigi Rizzo #include <net/if.h> /* IFNAMSIZ */ 68*f9790aebSLuigi Rizzo #include <net/netmap.h> 69*f9790aebSLuigi Rizzo 70104d9fc7SEd Maste #define _NETMAP_OFFSET(type, ptr, offset) \ 71104d9fc7SEd Maste ((type)(void *)((char *)(ptr) + (offset))) 7268b8534bSLuigi Rizzo 73104d9fc7SEd Maste #define NETMAP_IF(b, o) _NETMAP_OFFSET(struct netmap_if *, b, o) 7468b8534bSLuigi Rizzo 75104d9fc7SEd Maste #define NETMAP_TXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *, \ 76104d9fc7SEd Maste nifp, (nifp)->ring_ofs[index] ) 77104d9fc7SEd Maste 78104d9fc7SEd Maste #define NETMAP_RXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *, \ 79104d9fc7SEd Maste nifp, (nifp)->ring_ofs[index + (nifp)->ni_tx_rings + 1] ) 8068b8534bSLuigi Rizzo 8168b8534bSLuigi Rizzo #define NETMAP_BUF(ring, index) \ 825819da83SLuigi Rizzo ((char *)(ring) + (ring)->buf_ofs + ((index)*(ring)->nr_buf_size)) 8368b8534bSLuigi Rizzo 8464ae02c3SLuigi Rizzo #define NETMAP_BUF_IDX(ring, buf) \ 8564ae02c3SLuigi Rizzo ( ((char *)(buf) - ((char *)(ring) + (ring)->buf_ofs) ) / \ 86a7250582SLuigi Rizzo (ring)->nr_buf_size ) 8764ae02c3SLuigi Rizzo 8868b8534bSLuigi Rizzo #define NETMAP_RING_NEXT(r, i) \ 8968b8534bSLuigi Rizzo ((i)+1 == (r)->num_slots ? 0 : (i) + 1 ) 9068b8534bSLuigi Rizzo 91a7250582SLuigi Rizzo #define NETMAP_RING_FIRST_RESERVED(r) \ 92a7250582SLuigi Rizzo ( (r)->cur < (r)->reserved ? \ 93a7250582SLuigi Rizzo (r)->cur + (r)->num_slots - (r)->reserved : \ 94a7250582SLuigi Rizzo (r)->cur - (r)->reserved ) 95a7250582SLuigi Rizzo 9668b8534bSLuigi Rizzo /* 9768b8534bSLuigi Rizzo * Return 1 if the given tx ring is empty. 9868b8534bSLuigi Rizzo */ 9968b8534bSLuigi Rizzo #define NETMAP_TX_RING_EMPTY(r) ((r)->avail >= (r)->num_slots - 1) 10068b8534bSLuigi Rizzo 101*f9790aebSLuigi Rizzo #ifdef NETMAP_WITH_LIBS 102*f9790aebSLuigi Rizzo /* 103*f9790aebSLuigi Rizzo * Support for simple I/O libraries. 104*f9790aebSLuigi Rizzo * Include other system headers required for compiling this. 105*f9790aebSLuigi Rizzo */ 106*f9790aebSLuigi Rizzo 107*f9790aebSLuigi Rizzo #ifndef HAVE_NETMAP_WITH_LIBS 108*f9790aebSLuigi Rizzo #define HAVE_NETMAP_WITH_LIBS 109*f9790aebSLuigi Rizzo 110*f9790aebSLuigi Rizzo #include <sys/time.h> 111*f9790aebSLuigi Rizzo #include <sys/mman.h> 112*f9790aebSLuigi Rizzo #include <string.h> /* memset */ 113*f9790aebSLuigi Rizzo #include <sys/ioctl.h> 114*f9790aebSLuigi Rizzo #include <sys/errno.h> /* EINVAL */ 115*f9790aebSLuigi Rizzo #include <fcntl.h> /* O_RDWR */ 116*f9790aebSLuigi Rizzo #include <malloc.h> 117*f9790aebSLuigi Rizzo 118*f9790aebSLuigi Rizzo struct nm_hdr_t { /* same as pcap_pkthdr */ 119*f9790aebSLuigi Rizzo struct timeval ts; 120*f9790aebSLuigi Rizzo uint32_t caplen; 121*f9790aebSLuigi Rizzo uint32_t len; 122*f9790aebSLuigi Rizzo }; 123*f9790aebSLuigi Rizzo 124*f9790aebSLuigi Rizzo struct nm_desc_t { 125*f9790aebSLuigi Rizzo struct nm_desc_t *self; 126*f9790aebSLuigi Rizzo int fd; 127*f9790aebSLuigi Rizzo void *mem; 128*f9790aebSLuigi Rizzo int memsize; 129*f9790aebSLuigi Rizzo struct netmap_if *nifp; 130*f9790aebSLuigi Rizzo uint16_t first_ring, last_ring, cur_ring; 131*f9790aebSLuigi Rizzo struct nmreq req; 132*f9790aebSLuigi Rizzo struct nm_hdr_t hdr; 133*f9790aebSLuigi Rizzo }; 134*f9790aebSLuigi Rizzo 135*f9790aebSLuigi Rizzo /* 136*f9790aebSLuigi Rizzo * when the descriptor is open correctly, d->self == d 137*f9790aebSLuigi Rizzo */ 138*f9790aebSLuigi Rizzo #define P2NMD(p) ((struct nm_desc_t *)(p)) 139*f9790aebSLuigi Rizzo #define IS_NETMAP_DESC(d) (P2NMD(d)->self == P2NMD(d)) 140*f9790aebSLuigi Rizzo #define NETMAP_FD(d) (P2NMD(d)->fd) 141*f9790aebSLuigi Rizzo 142*f9790aebSLuigi Rizzo /* 143*f9790aebSLuigi Rizzo * The callback, invoked on each received packet. Same as libpcap 144*f9790aebSLuigi Rizzo */ 145*f9790aebSLuigi Rizzo typedef void (*nm_cb_t)(u_char *, const struct nm_hdr_t *, const u_char *d); 146*f9790aebSLuigi Rizzo 147*f9790aebSLuigi Rizzo /* 148*f9790aebSLuigi Rizzo * The open routine accepts an ifname (netmap:foo or vale:foo) and 149*f9790aebSLuigi Rizzo * optionally a second (string) argument indicating the ring number 150*f9790aebSLuigi Rizzo * to open. If successful, t opens the fd and maps the memory. 151*f9790aebSLuigi Rizzo */ 152*f9790aebSLuigi Rizzo static struct nm_desc_t *nm_open(const char *ifname, 153*f9790aebSLuigi Rizzo const char *ring_no, int flags, int ring_flags); 154*f9790aebSLuigi Rizzo 155*f9790aebSLuigi Rizzo /* 156*f9790aebSLuigi Rizzo * nm_dispatch() is the same as pcap_dispatch() 157*f9790aebSLuigi Rizzo * nm_next() is the same as pcap_next() 158*f9790aebSLuigi Rizzo */ 159*f9790aebSLuigi Rizzo static int nm_dispatch(struct nm_desc_t *, int, nm_cb_t, u_char *); 160*f9790aebSLuigi Rizzo static u_char *nm_next(struct nm_desc_t *, struct nm_hdr_t *); 161*f9790aebSLuigi Rizzo 162*f9790aebSLuigi Rizzo /* 163*f9790aebSLuigi Rizzo * unmap memory, close file descriptor and free the descriptor. 164*f9790aebSLuigi Rizzo */ 165*f9790aebSLuigi Rizzo static int nm_close(struct nm_desc_t *); 166*f9790aebSLuigi Rizzo 167*f9790aebSLuigi Rizzo 168*f9790aebSLuigi Rizzo /* 169*f9790aebSLuigi Rizzo * Try to open, return descriptor if successful, NULL otherwise. 170*f9790aebSLuigi Rizzo * An invalid netmap name will return errno = 0; 171*f9790aebSLuigi Rizzo */ 172*f9790aebSLuigi Rizzo static struct nm_desc_t * 173*f9790aebSLuigi Rizzo nm_open(const char *ifname, const char *ring_name, int flags, int ring_flags) 174*f9790aebSLuigi Rizzo { 175*f9790aebSLuigi Rizzo struct nm_desc_t *d; 176*f9790aebSLuigi Rizzo u_int n; 177*f9790aebSLuigi Rizzo 178*f9790aebSLuigi Rizzo if (strncmp(ifname, "netmap:", 7) && strncmp(ifname, "vale", 4)) { 179*f9790aebSLuigi Rizzo errno = 0; /* name not recognised */ 180*f9790aebSLuigi Rizzo return NULL; 181*f9790aebSLuigi Rizzo } 182*f9790aebSLuigi Rizzo if (ifname[0] == 'n') 183*f9790aebSLuigi Rizzo ifname += 7; 184*f9790aebSLuigi Rizzo d = (struct nm_desc_t *)calloc(1, sizeof(*d)); 185*f9790aebSLuigi Rizzo if (d == NULL) { 186*f9790aebSLuigi Rizzo errno = ENOMEM; 187*f9790aebSLuigi Rizzo return NULL; 188*f9790aebSLuigi Rizzo } 189*f9790aebSLuigi Rizzo d->self = d; /* set this early so nm_close() works */ 190*f9790aebSLuigi Rizzo d->fd = open("/dev/netmap", O_RDWR); 191*f9790aebSLuigi Rizzo if (d->fd < 0) 192*f9790aebSLuigi Rizzo goto fail; 193*f9790aebSLuigi Rizzo 194*f9790aebSLuigi Rizzo if (flags & NETMAP_SW_RING) { 195*f9790aebSLuigi Rizzo d->req.nr_ringid = NETMAP_SW_RING; 196*f9790aebSLuigi Rizzo } else { 197*f9790aebSLuigi Rizzo u_int r; 198*f9790aebSLuigi Rizzo if (flags & NETMAP_HW_RING) /* interpret ring as int */ 199*f9790aebSLuigi Rizzo r = (uintptr_t)ring_name; 200*f9790aebSLuigi Rizzo else /* interpret ring as numeric string */ 201*f9790aebSLuigi Rizzo r = ring_name ? atoi(ring_name) : ~0; 202*f9790aebSLuigi Rizzo r = (r < NETMAP_RING_MASK) ? (r | NETMAP_HW_RING) : 0; 203*f9790aebSLuigi Rizzo d->req.nr_ringid = r; /* set the ring */ 204*f9790aebSLuigi Rizzo } 205*f9790aebSLuigi Rizzo d->req.nr_ringid |= (flags & ~NETMAP_RING_MASK); 206*f9790aebSLuigi Rizzo d->req.nr_version = NETMAP_API; 207*f9790aebSLuigi Rizzo strncpy(d->req.nr_name, ifname, sizeof(d->req.nr_name)); 208*f9790aebSLuigi Rizzo if (ioctl(d->fd, NIOCREGIF, &d->req)) 209*f9790aebSLuigi Rizzo goto fail; 210*f9790aebSLuigi Rizzo 211*f9790aebSLuigi Rizzo d->memsize = d->req.nr_memsize; 212*f9790aebSLuigi Rizzo d->mem = mmap(0, d->memsize, PROT_WRITE | PROT_READ, MAP_SHARED, 213*f9790aebSLuigi Rizzo d->fd, 0); 214*f9790aebSLuigi Rizzo if (d->mem == NULL) 215*f9790aebSLuigi Rizzo goto fail; 216*f9790aebSLuigi Rizzo d->nifp = NETMAP_IF(d->mem, d->req.nr_offset); 217*f9790aebSLuigi Rizzo if (d->req.nr_ringid & NETMAP_SW_RING) { 218*f9790aebSLuigi Rizzo d->first_ring = d->last_ring = d->req.nr_rx_rings; 219*f9790aebSLuigi Rizzo } else if (d->req.nr_ringid & NETMAP_HW_RING) { 220*f9790aebSLuigi Rizzo d->first_ring = d->last_ring = 221*f9790aebSLuigi Rizzo d->req.nr_ringid & NETMAP_RING_MASK; 222*f9790aebSLuigi Rizzo } else { 223*f9790aebSLuigi Rizzo d->first_ring = 0; 224*f9790aebSLuigi Rizzo d->last_ring = d->req.nr_rx_rings - 1; 225*f9790aebSLuigi Rizzo } 226*f9790aebSLuigi Rizzo d->cur_ring = d->first_ring; 227*f9790aebSLuigi Rizzo for (n = d->first_ring; n <= d->last_ring; n++) { 228*f9790aebSLuigi Rizzo struct netmap_ring *ring = NETMAP_RXRING(d->nifp, n); 229*f9790aebSLuigi Rizzo ring->flags |= ring_flags; 230*f9790aebSLuigi Rizzo } 231*f9790aebSLuigi Rizzo return d; 232*f9790aebSLuigi Rizzo 233*f9790aebSLuigi Rizzo fail: 234*f9790aebSLuigi Rizzo nm_close(d); 235*f9790aebSLuigi Rizzo errno = EINVAL; 236*f9790aebSLuigi Rizzo return NULL; 237*f9790aebSLuigi Rizzo } 238*f9790aebSLuigi Rizzo 239*f9790aebSLuigi Rizzo 240*f9790aebSLuigi Rizzo static int 241*f9790aebSLuigi Rizzo nm_close(struct nm_desc_t *d) 242*f9790aebSLuigi Rizzo { 243*f9790aebSLuigi Rizzo if (d == NULL || d->self != d) 244*f9790aebSLuigi Rizzo return EINVAL; 245*f9790aebSLuigi Rizzo if (d->mem) 246*f9790aebSLuigi Rizzo munmap(d->mem, d->memsize); 247*f9790aebSLuigi Rizzo if (d->fd != -1) 248*f9790aebSLuigi Rizzo close(d->fd); 249*f9790aebSLuigi Rizzo bzero(d, sizeof(*d)); 250*f9790aebSLuigi Rizzo free(d); 251*f9790aebSLuigi Rizzo return 0; 252*f9790aebSLuigi Rizzo } 253*f9790aebSLuigi Rizzo 254*f9790aebSLuigi Rizzo 255*f9790aebSLuigi Rizzo /* 256*f9790aebSLuigi Rizzo * Same prototype as pcap_dispatch(), only need to cast. 257*f9790aebSLuigi Rizzo */ 258*f9790aebSLuigi Rizzo inline /* not really, but disable unused warnings */ 259*f9790aebSLuigi Rizzo static int 260*f9790aebSLuigi Rizzo nm_dispatch(struct nm_desc_t *d, int cnt, nm_cb_t cb, u_char *arg) 261*f9790aebSLuigi Rizzo { 262*f9790aebSLuigi Rizzo int n = d->last_ring - d->first_ring + 1; 263*f9790aebSLuigi Rizzo int c, got = 0, ri = d->cur_ring; 264*f9790aebSLuigi Rizzo 265*f9790aebSLuigi Rizzo if (cnt == 0) 266*f9790aebSLuigi Rizzo cnt = -1; 267*f9790aebSLuigi Rizzo /* cnt == -1 means infinite, but rings have a finite amount 268*f9790aebSLuigi Rizzo * of buffers and the int is large enough that we never wrap, 269*f9790aebSLuigi Rizzo * so we can omit checking for -1 270*f9790aebSLuigi Rizzo */ 271*f9790aebSLuigi Rizzo for (c=0; c < n && cnt != got; c++) { 272*f9790aebSLuigi Rizzo /* compute current ring to use */ 273*f9790aebSLuigi Rizzo struct netmap_ring *ring; 274*f9790aebSLuigi Rizzo 275*f9790aebSLuigi Rizzo ri = d->cur_ring + c; 276*f9790aebSLuigi Rizzo if (ri > d->last_ring) 277*f9790aebSLuigi Rizzo ri = d->first_ring; 278*f9790aebSLuigi Rizzo ring = NETMAP_RXRING(d->nifp, ri); 279*f9790aebSLuigi Rizzo for ( ; ring->avail > 0 && cnt != got; got++) { 280*f9790aebSLuigi Rizzo u_int i = ring->cur; 281*f9790aebSLuigi Rizzo u_int idx = ring->slot[i].buf_idx; 282*f9790aebSLuigi Rizzo u_char *buf = (u_char *)NETMAP_BUF(ring, idx); 283*f9790aebSLuigi Rizzo // XXX should check valid buf 284*f9790aebSLuigi Rizzo // prefetch(buf); 285*f9790aebSLuigi Rizzo d->hdr.len = d->hdr.caplen = ring->slot[i].len; 286*f9790aebSLuigi Rizzo d->hdr.ts = ring->ts; 287*f9790aebSLuigi Rizzo cb(arg, &d->hdr, buf); 288*f9790aebSLuigi Rizzo ring->cur = NETMAP_RING_NEXT(ring, i); 289*f9790aebSLuigi Rizzo ring->avail--; 290*f9790aebSLuigi Rizzo } 291*f9790aebSLuigi Rizzo } 292*f9790aebSLuigi Rizzo d->cur_ring = ri; 293*f9790aebSLuigi Rizzo return got; 294*f9790aebSLuigi Rizzo } 295*f9790aebSLuigi Rizzo 296*f9790aebSLuigi Rizzo inline /* not really, but disable unused warnings */ 297*f9790aebSLuigi Rizzo static u_char * 298*f9790aebSLuigi Rizzo nm_next(struct nm_desc_t *d, struct nm_hdr_t *hdr) 299*f9790aebSLuigi Rizzo { 300*f9790aebSLuigi Rizzo int ri = d->cur_ring; 301*f9790aebSLuigi Rizzo 302*f9790aebSLuigi Rizzo do { 303*f9790aebSLuigi Rizzo /* compute current ring to use */ 304*f9790aebSLuigi Rizzo struct netmap_ring *ring = NETMAP_RXRING(d->nifp, ri); 305*f9790aebSLuigi Rizzo if (ring->avail > 0) { 306*f9790aebSLuigi Rizzo u_int i = ring->cur; 307*f9790aebSLuigi Rizzo u_int idx = ring->slot[i].buf_idx; 308*f9790aebSLuigi Rizzo u_char *buf = (u_char *)NETMAP_BUF(ring, idx); 309*f9790aebSLuigi Rizzo // XXX should check valid buf 310*f9790aebSLuigi Rizzo // prefetch(buf); 311*f9790aebSLuigi Rizzo hdr->ts = ring->ts; 312*f9790aebSLuigi Rizzo hdr->len = hdr->caplen = ring->slot[i].len; 313*f9790aebSLuigi Rizzo ring->cur = NETMAP_RING_NEXT(ring, i); 314*f9790aebSLuigi Rizzo ring->avail--; 315*f9790aebSLuigi Rizzo d->cur_ring = ri; 316*f9790aebSLuigi Rizzo return buf; 317*f9790aebSLuigi Rizzo } 318*f9790aebSLuigi Rizzo ri++; 319*f9790aebSLuigi Rizzo if (ri > d->last_ring) 320*f9790aebSLuigi Rizzo ri = d->first_ring; 321*f9790aebSLuigi Rizzo } while (ri != d->cur_ring); 322*f9790aebSLuigi Rizzo return NULL; /* nothing found */ 323*f9790aebSLuigi Rizzo } 324*f9790aebSLuigi Rizzo 325*f9790aebSLuigi Rizzo #endif /* !HAVE_NETMAP_WITH_LIBS */ 326*f9790aebSLuigi Rizzo 327*f9790aebSLuigi Rizzo #endif /* NETMAP_WITH_LIBS */ 328*f9790aebSLuigi Rizzo 32968b8534bSLuigi Rizzo #endif /* _NET_NETMAP_USER_H_ */ 330