1*522d5c66SAsim Jamshed /*
2*522d5c66SAsim Jamshed  * Copyright (C) 2011-2014 Universita` di Pisa. All rights reserved.
3*522d5c66SAsim Jamshed  *
4*522d5c66SAsim Jamshed  * Redistribution and use in source and binary forms, with or without
5*522d5c66SAsim Jamshed  * modification, are permitted provided that the following conditions
6*522d5c66SAsim Jamshed  * are met:
7*522d5c66SAsim Jamshed  *
8*522d5c66SAsim Jamshed  *   1. Redistributions of source code must retain the above copyright
9*522d5c66SAsim Jamshed  *      notice, this list of conditions and the following disclaimer.
10*522d5c66SAsim Jamshed  *   2. Redistributions in binary form must reproduce the above copyright
11*522d5c66SAsim Jamshed  *      notice, this list of conditions and the following disclaimer in the
12*522d5c66SAsim Jamshed  *      documentation and/or other materials provided with the distribution.
13*522d5c66SAsim Jamshed  *
14*522d5c66SAsim Jamshed  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*522d5c66SAsim Jamshed  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*522d5c66SAsim Jamshed  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*522d5c66SAsim Jamshed  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*522d5c66SAsim Jamshed  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*522d5c66SAsim Jamshed  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*522d5c66SAsim Jamshed  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*522d5c66SAsim Jamshed  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*522d5c66SAsim Jamshed  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*522d5c66SAsim Jamshed  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*522d5c66SAsim Jamshed  * SUCH DAMAGE.
25*522d5c66SAsim Jamshed  */
26*522d5c66SAsim Jamshed 
27*522d5c66SAsim Jamshed /*
28*522d5c66SAsim Jamshed  * $FreeBSD$
29*522d5c66SAsim Jamshed  *
30*522d5c66SAsim Jamshed  * Functions and macros to manipulate netmap structures and packets
31*522d5c66SAsim Jamshed  * in userspace. See netmap(4) for more information.
32*522d5c66SAsim Jamshed  *
33*522d5c66SAsim Jamshed  * The address of the struct netmap_if, say nifp, is computed from the
34*522d5c66SAsim Jamshed  * value returned from ioctl(.., NIOCREG, ...) and the mmap region:
35*522d5c66SAsim Jamshed  *	ioctl(fd, NIOCREG, &req);
36*522d5c66SAsim Jamshed  *	mem = mmap(0, ... );
37*522d5c66SAsim Jamshed  *	nifp = NETMAP_IF(mem, req.nr_nifp);
38*522d5c66SAsim Jamshed  *		(so simple, we could just do it manually)
39*522d5c66SAsim Jamshed  *
40*522d5c66SAsim Jamshed  * From there:
41*522d5c66SAsim Jamshed  *	struct netmap_ring *NETMAP_TXRING(nifp, index)
42*522d5c66SAsim Jamshed  *	struct netmap_ring *NETMAP_RXRING(nifp, index)
43*522d5c66SAsim Jamshed  *		we can access ring->cur, ring->head, ring->tail, etc.
44*522d5c66SAsim Jamshed  *
45*522d5c66SAsim Jamshed  *	ring->slot[i] gives us the i-th slot (we can access
46*522d5c66SAsim Jamshed  *		directly len, flags, buf_idx)
47*522d5c66SAsim Jamshed  *
48*522d5c66SAsim Jamshed  *	char *buf = NETMAP_BUF(ring, x) returns a pointer to
49*522d5c66SAsim Jamshed  *		the buffer numbered x
50*522d5c66SAsim Jamshed  *
51*522d5c66SAsim Jamshed  * All ring indexes (head, cur, tail) should always move forward.
52*522d5c66SAsim Jamshed  * To compute the next index in a circular ring you can use
53*522d5c66SAsim Jamshed  *	i = nm_ring_next(ring, i);
54*522d5c66SAsim Jamshed  *
55*522d5c66SAsim Jamshed  * To ease porting apps from pcap to netmap we supply a few fuctions
56*522d5c66SAsim Jamshed  * that can be called to open, close, read and write on netmap in a way
57*522d5c66SAsim Jamshed  * similar to libpcap. Note that the read/write function depend on
58*522d5c66SAsim Jamshed  * an ioctl()/select()/poll() being issued to refill rings or push
59*522d5c66SAsim Jamshed  * packets out.
60*522d5c66SAsim Jamshed  *
61*522d5c66SAsim Jamshed  * In order to use these, include #define NETMAP_WITH_LIBS
62*522d5c66SAsim Jamshed  * in the source file that invokes these functions.
63*522d5c66SAsim Jamshed  */
64*522d5c66SAsim Jamshed 
65*522d5c66SAsim Jamshed #ifndef _NET_NETMAP_USER_H_
66*522d5c66SAsim Jamshed #define _NET_NETMAP_USER_H_
67*522d5c66SAsim Jamshed 
68*522d5c66SAsim Jamshed #define NETMAP_DEVICE_NAME "/dev/netmap"
69*522d5c66SAsim Jamshed #ifdef __CYGWIN__
70*522d5c66SAsim Jamshed /*
71*522d5c66SAsim Jamshed  * we can compile userspace apps with either cygwin or msvc,
72*522d5c66SAsim Jamshed  * and we use _WIN32 to identify windows specific code
73*522d5c66SAsim Jamshed  */
74*522d5c66SAsim Jamshed #ifndef _WIN32
75*522d5c66SAsim Jamshed #define _WIN32
76*522d5c66SAsim Jamshed #endif	/* _WIN32 */
77*522d5c66SAsim Jamshed 
78*522d5c66SAsim Jamshed #endif	/* __CYGWIN__ */
79*522d5c66SAsim Jamshed 
80*522d5c66SAsim Jamshed #ifdef _WIN32
81*522d5c66SAsim Jamshed #undef NETMAP_DEVICE_NAME
82*522d5c66SAsim Jamshed #define NETMAP_DEVICE_NAME "/proc/sys/DosDevices/Global/netmap"
83*522d5c66SAsim Jamshed #include <windows.h>
84*522d5c66SAsim Jamshed #include <WinDef.h>
85*522d5c66SAsim Jamshed #include <sys/cygwin.h>
86*522d5c66SAsim Jamshed //#include <netioapi.h>
87*522d5c66SAsim Jamshed //#include <winsock.h>
88*522d5c66SAsim Jamshed //#define	IFNAMSIZ 256
89*522d5c66SAsim Jamshed #endif
90*522d5c66SAsim Jamshed 
91*522d5c66SAsim Jamshed #include <stdint.h>
92*522d5c66SAsim Jamshed #include <sys/socket.h>		/* apple needs sockaddr */
93*522d5c66SAsim Jamshed #include <net/if.h>		/* IFNAMSIZ */
94*522d5c66SAsim Jamshed 
95*522d5c66SAsim Jamshed #ifndef likely
96*522d5c66SAsim Jamshed #define likely(x)	__builtin_expect(!!(x), 1)
97*522d5c66SAsim Jamshed #define unlikely(x)	__builtin_expect(!!(x), 0)
98*522d5c66SAsim Jamshed #endif /* likely and unlikely */
99*522d5c66SAsim Jamshed 
100*522d5c66SAsim Jamshed #include "netmap.h"
101*522d5c66SAsim Jamshed 
102*522d5c66SAsim Jamshed /* helper macro */
103*522d5c66SAsim Jamshed #define _NETMAP_OFFSET(type, ptr, offset) \
104*522d5c66SAsim Jamshed 	((type)(void *)((char *)(ptr) + (offset)))
105*522d5c66SAsim Jamshed 
106*522d5c66SAsim Jamshed #define NETMAP_IF(_base, _ofs)	_NETMAP_OFFSET(struct netmap_if *, _base, _ofs)
107*522d5c66SAsim Jamshed 
108*522d5c66SAsim Jamshed #define NETMAP_TXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *, \
109*522d5c66SAsim Jamshed 	nifp, (nifp)->ring_ofs[index] )
110*522d5c66SAsim Jamshed 
111*522d5c66SAsim Jamshed #define NETMAP_RXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *,	\
112*522d5c66SAsim Jamshed 	nifp, (nifp)->ring_ofs[index + (nifp)->ni_tx_rings + 1] )
113*522d5c66SAsim Jamshed 
114*522d5c66SAsim Jamshed #define NETMAP_BUF(ring, index)				\
115*522d5c66SAsim Jamshed 	((char *)(ring) + (ring)->buf_ofs + ((index)*(ring)->nr_buf_size))
116*522d5c66SAsim Jamshed 
117*522d5c66SAsim Jamshed #define NETMAP_BUF_IDX(ring, buf)			\
118*522d5c66SAsim Jamshed 	( ((char *)(buf) - ((char *)(ring) + (ring)->buf_ofs) ) / \
119*522d5c66SAsim Jamshed 		(ring)->nr_buf_size )
120*522d5c66SAsim Jamshed 
121*522d5c66SAsim Jamshed 
122*522d5c66SAsim Jamshed static inline uint32_t
nm_ring_next(struct netmap_ring * r,uint32_t i)123*522d5c66SAsim Jamshed nm_ring_next(struct netmap_ring *r, uint32_t i)
124*522d5c66SAsim Jamshed {
125*522d5c66SAsim Jamshed 	return ( unlikely(i + 1 == r->num_slots) ? 0 : i + 1);
126*522d5c66SAsim Jamshed }
127*522d5c66SAsim Jamshed 
128*522d5c66SAsim Jamshed 
129*522d5c66SAsim Jamshed /*
130*522d5c66SAsim Jamshed  * Return 1 if we have pending transmissions in the tx ring.
131*522d5c66SAsim Jamshed  * When everything is complete ring->head = ring->tail + 1 (modulo ring size)
132*522d5c66SAsim Jamshed  */
133*522d5c66SAsim Jamshed static inline int
nm_tx_pending(struct netmap_ring * r)134*522d5c66SAsim Jamshed nm_tx_pending(struct netmap_ring *r)
135*522d5c66SAsim Jamshed {
136*522d5c66SAsim Jamshed 	return nm_ring_next(r, r->tail) != r->head;
137*522d5c66SAsim Jamshed }
138*522d5c66SAsim Jamshed 
139*522d5c66SAsim Jamshed 
140*522d5c66SAsim Jamshed static inline uint32_t
nm_ring_space(struct netmap_ring * ring)141*522d5c66SAsim Jamshed nm_ring_space(struct netmap_ring *ring)
142*522d5c66SAsim Jamshed {
143*522d5c66SAsim Jamshed         int ret = ring->tail - ring->cur;
144*522d5c66SAsim Jamshed         if (ret < 0)
145*522d5c66SAsim Jamshed                 ret += ring->num_slots;
146*522d5c66SAsim Jamshed         return ret;
147*522d5c66SAsim Jamshed }
148*522d5c66SAsim Jamshed 
149*522d5c66SAsim Jamshed 
150*522d5c66SAsim Jamshed #ifdef NETMAP_WITH_LIBS
151*522d5c66SAsim Jamshed /*
152*522d5c66SAsim Jamshed  * Support for simple I/O libraries.
153*522d5c66SAsim Jamshed  * Include other system headers required for compiling this.
154*522d5c66SAsim Jamshed  */
155*522d5c66SAsim Jamshed 
156*522d5c66SAsim Jamshed #ifndef HAVE_NETMAP_WITH_LIBS
157*522d5c66SAsim Jamshed #define HAVE_NETMAP_WITH_LIBS
158*522d5c66SAsim Jamshed 
159*522d5c66SAsim Jamshed #include <stdio.h>
160*522d5c66SAsim Jamshed #include <sys/time.h>
161*522d5c66SAsim Jamshed #include <sys/mman.h>
162*522d5c66SAsim Jamshed #include <string.h>	/* memset */
163*522d5c66SAsim Jamshed #include <sys/ioctl.h>
164*522d5c66SAsim Jamshed #include <sys/errno.h>	/* EINVAL */
165*522d5c66SAsim Jamshed #include <fcntl.h>	/* O_RDWR */
166*522d5c66SAsim Jamshed #include <unistd.h>	/* close() */
167*522d5c66SAsim Jamshed #include <signal.h>
168*522d5c66SAsim Jamshed #include <stdlib.h>
169*522d5c66SAsim Jamshed 
170*522d5c66SAsim Jamshed #ifndef ND /* debug macros */
171*522d5c66SAsim Jamshed /* debug support */
172*522d5c66SAsim Jamshed #define ND(_fmt, ...) do {} while(0)
173*522d5c66SAsim Jamshed #define D(_fmt, ...)						\
174*522d5c66SAsim Jamshed 	do {							\
175*522d5c66SAsim Jamshed 		struct timeval _t0;				\
176*522d5c66SAsim Jamshed 		gettimeofday(&_t0, NULL);			\
177*522d5c66SAsim Jamshed 		fprintf(stderr, "%03d.%06d %s [%d] " _fmt "\n",	\
178*522d5c66SAsim Jamshed 		    (int)(_t0.tv_sec % 1000), (int)_t0.tv_usec,	\
179*522d5c66SAsim Jamshed 		    __FUNCTION__, __LINE__, ##__VA_ARGS__);	\
180*522d5c66SAsim Jamshed         } while (0)
181*522d5c66SAsim Jamshed 
182*522d5c66SAsim Jamshed /* Rate limited version of "D", lps indicates how many per second */
183*522d5c66SAsim Jamshed #define RD(lps, format, ...)                                    \
184*522d5c66SAsim Jamshed     do {                                                        \
185*522d5c66SAsim Jamshed         static int __t0, __cnt;                                 \
186*522d5c66SAsim Jamshed         struct timeval __xxts;                                  \
187*522d5c66SAsim Jamshed         gettimeofday(&__xxts, NULL);                            \
188*522d5c66SAsim Jamshed         if (__t0 != __xxts.tv_sec) {                            \
189*522d5c66SAsim Jamshed             __t0 = __xxts.tv_sec;                               \
190*522d5c66SAsim Jamshed             __cnt = 0;                                          \
191*522d5c66SAsim Jamshed         }                                                       \
192*522d5c66SAsim Jamshed         if (__cnt++ < lps) {                                    \
193*522d5c66SAsim Jamshed             D(format, ##__VA_ARGS__);                           \
194*522d5c66SAsim Jamshed         }                                                       \
195*522d5c66SAsim Jamshed     } while (0)
196*522d5c66SAsim Jamshed #endif
197*522d5c66SAsim Jamshed 
198*522d5c66SAsim Jamshed struct nm_pkthdr {	/* same as pcap_pkthdr */
199*522d5c66SAsim Jamshed 	struct timeval	ts;
200*522d5c66SAsim Jamshed 	uint32_t	caplen;
201*522d5c66SAsim Jamshed 	uint32_t	len;
202*522d5c66SAsim Jamshed };
203*522d5c66SAsim Jamshed 
204*522d5c66SAsim Jamshed struct nm_stat {	/* same as pcap_stat	*/
205*522d5c66SAsim Jamshed 	u_int	ps_recv;
206*522d5c66SAsim Jamshed 	u_int	ps_drop;
207*522d5c66SAsim Jamshed 	u_int	ps_ifdrop;
208*522d5c66SAsim Jamshed #ifdef WIN32
209*522d5c66SAsim Jamshed 	u_int	bs_capt;
210*522d5c66SAsim Jamshed #endif /* WIN32 */
211*522d5c66SAsim Jamshed };
212*522d5c66SAsim Jamshed 
213*522d5c66SAsim Jamshed #define NM_ERRBUF_SIZE	512
214*522d5c66SAsim Jamshed 
215*522d5c66SAsim Jamshed struct nm_desc {
216*522d5c66SAsim Jamshed 	struct nm_desc *self; /* point to self if netmap. */
217*522d5c66SAsim Jamshed 	int fd;
218*522d5c66SAsim Jamshed 	void *mem;
219*522d5c66SAsim Jamshed 	uint32_t memsize;
220*522d5c66SAsim Jamshed 	int done_mmap;	/* set if mem is the result of mmap */
221*522d5c66SAsim Jamshed 	struct netmap_if * const nifp;
222*522d5c66SAsim Jamshed 	uint16_t first_tx_ring, last_tx_ring, cur_tx_ring;
223*522d5c66SAsim Jamshed 	uint16_t first_rx_ring, last_rx_ring, cur_rx_ring;
224*522d5c66SAsim Jamshed 	struct nmreq req;	/* also contains the nr_name = ifname */
225*522d5c66SAsim Jamshed 	struct nm_pkthdr hdr;
226*522d5c66SAsim Jamshed 
227*522d5c66SAsim Jamshed 	/*
228*522d5c66SAsim Jamshed 	 * The memory contains netmap_if, rings and then buffers.
229*522d5c66SAsim Jamshed 	 * Given a pointer (e.g. to nm_inject) we can compare with
230*522d5c66SAsim Jamshed 	 * mem/buf_start/buf_end to tell if it is a buffer or
231*522d5c66SAsim Jamshed 	 * some other descriptor in our region.
232*522d5c66SAsim Jamshed 	 * We also store a pointer to some ring as it helps in the
233*522d5c66SAsim Jamshed 	 * translation from buffer indexes to addresses.
234*522d5c66SAsim Jamshed 	 */
235*522d5c66SAsim Jamshed 	struct netmap_ring * const some_ring;
236*522d5c66SAsim Jamshed 	void * const buf_start;
237*522d5c66SAsim Jamshed 	void * const buf_end;
238*522d5c66SAsim Jamshed 	/* parameters from pcap_open_live */
239*522d5c66SAsim Jamshed 	int snaplen;
240*522d5c66SAsim Jamshed 	int promisc;
241*522d5c66SAsim Jamshed 	int to_ms;
242*522d5c66SAsim Jamshed 	char *errbuf;
243*522d5c66SAsim Jamshed 
244*522d5c66SAsim Jamshed 	/* save flags so we can restore them on close */
245*522d5c66SAsim Jamshed 	uint32_t if_flags;
246*522d5c66SAsim Jamshed         uint32_t if_reqcap;
247*522d5c66SAsim Jamshed         uint32_t if_curcap;
248*522d5c66SAsim Jamshed 
249*522d5c66SAsim Jamshed 	struct nm_stat st;
250*522d5c66SAsim Jamshed 	char msg[NM_ERRBUF_SIZE];
251*522d5c66SAsim Jamshed };
252*522d5c66SAsim Jamshed 
253*522d5c66SAsim Jamshed /*
254*522d5c66SAsim Jamshed  * when the descriptor is open correctly, d->self == d
255*522d5c66SAsim Jamshed  * Eventually we should also use some magic number.
256*522d5c66SAsim Jamshed  */
257*522d5c66SAsim Jamshed #define P2NMD(p)		((struct nm_desc *)(p))
258*522d5c66SAsim Jamshed #define IS_NETMAP_DESC(d)	((d) && P2NMD(d)->self == P2NMD(d))
259*522d5c66SAsim Jamshed #define NETMAP_FD(d)		(P2NMD(d)->fd)
260*522d5c66SAsim Jamshed 
261*522d5c66SAsim Jamshed 
262*522d5c66SAsim Jamshed /*
263*522d5c66SAsim Jamshed  * this is a slightly optimized copy routine which rounds
264*522d5c66SAsim Jamshed  * to multiple of 64 bytes and is often faster than dealing
265*522d5c66SAsim Jamshed  * with other odd sizes. We assume there is enough room
266*522d5c66SAsim Jamshed  * in the source and destination buffers.
267*522d5c66SAsim Jamshed  *
268*522d5c66SAsim Jamshed  * XXX only for multiples of 64 bytes, non overlapped.
269*522d5c66SAsim Jamshed  */
270*522d5c66SAsim Jamshed static inline void
nm_pkt_copy(const void * _src,void * _dst,int l)271*522d5c66SAsim Jamshed nm_pkt_copy(const void *_src, void *_dst, int l)
272*522d5c66SAsim Jamshed {
273*522d5c66SAsim Jamshed 	const uint64_t *src = (const uint64_t *)_src;
274*522d5c66SAsim Jamshed 	uint64_t *dst = (uint64_t *)_dst;
275*522d5c66SAsim Jamshed 
276*522d5c66SAsim Jamshed 	if (unlikely(l >= 1024)) {
277*522d5c66SAsim Jamshed 		memcpy(dst, src, l);
278*522d5c66SAsim Jamshed 		return;
279*522d5c66SAsim Jamshed 	}
280*522d5c66SAsim Jamshed 	for (; likely(l > 0); l-=64) {
281*522d5c66SAsim Jamshed 		*dst++ = *src++;
282*522d5c66SAsim Jamshed 		*dst++ = *src++;
283*522d5c66SAsim Jamshed 		*dst++ = *src++;
284*522d5c66SAsim Jamshed 		*dst++ = *src++;
285*522d5c66SAsim Jamshed 		*dst++ = *src++;
286*522d5c66SAsim Jamshed 		*dst++ = *src++;
287*522d5c66SAsim Jamshed 		*dst++ = *src++;
288*522d5c66SAsim Jamshed 		*dst++ = *src++;
289*522d5c66SAsim Jamshed 	}
290*522d5c66SAsim Jamshed }
291*522d5c66SAsim Jamshed 
292*522d5c66SAsim Jamshed 
293*522d5c66SAsim Jamshed /*
294*522d5c66SAsim Jamshed  * The callback, invoked on each received packet. Same as libpcap
295*522d5c66SAsim Jamshed  */
296*522d5c66SAsim Jamshed typedef void (*nm_cb_t)(u_char *, const struct nm_pkthdr *, const u_char *d);
297*522d5c66SAsim Jamshed 
298*522d5c66SAsim Jamshed /*
299*522d5c66SAsim Jamshed  *--- the pcap-like API ---
300*522d5c66SAsim Jamshed  *
301*522d5c66SAsim Jamshed  * nm_open() opens a file descriptor, binds to a port and maps memory.
302*522d5c66SAsim Jamshed  *
303*522d5c66SAsim Jamshed  * ifname	(netmap:foo or vale:foo) is the port name
304*522d5c66SAsim Jamshed  *		a suffix can indicate the follwing:
305*522d5c66SAsim Jamshed  *		^		bind the host (sw) ring pair
306*522d5c66SAsim Jamshed  *		*		bind host and NIC ring pairs (transparent)
307*522d5c66SAsim Jamshed  *		-NN		bind individual NIC ring pair
308*522d5c66SAsim Jamshed  *		{NN		bind master side of pipe NN
309*522d5c66SAsim Jamshed  *		}NN		bind slave side of pipe NN
310*522d5c66SAsim Jamshed  *		a suffix starting with / and the following flags,
311*522d5c66SAsim Jamshed  *		in any order:
312*522d5c66SAsim Jamshed  *		x		exclusive access
313*522d5c66SAsim Jamshed  *		z		zero copy monitor
314*522d5c66SAsim Jamshed  *		t		monitor tx side
315*522d5c66SAsim Jamshed  *		r		monitor rx side
316*522d5c66SAsim Jamshed  *		R		bind only RX ring(s)
317*522d5c66SAsim Jamshed  *		T		bind only TX ring(s)
318*522d5c66SAsim Jamshed  *
319*522d5c66SAsim Jamshed  * req		provides the initial values of nmreq before parsing ifname.
320*522d5c66SAsim Jamshed  *		Remember that the ifname parsing will override the ring
321*522d5c66SAsim Jamshed  *		number in nm_ringid, and part of nm_flags;
322*522d5c66SAsim Jamshed  * flags	special functions, normally 0
323*522d5c66SAsim Jamshed  *		indicates which fields of *arg are significant
324*522d5c66SAsim Jamshed  * arg		special functions, normally NULL
325*522d5c66SAsim Jamshed  *		if passed a netmap_desc with mem != NULL,
326*522d5c66SAsim Jamshed  *		use that memory instead of mmap.
327*522d5c66SAsim Jamshed  */
328*522d5c66SAsim Jamshed 
329*522d5c66SAsim Jamshed static struct nm_desc *nm_open(const char *ifname, const struct nmreq *req,
330*522d5c66SAsim Jamshed 	uint64_t flags, const struct nm_desc *arg);
331*522d5c66SAsim Jamshed 
332*522d5c66SAsim Jamshed /*
333*522d5c66SAsim Jamshed  * nm_open can import some fields from the parent descriptor.
334*522d5c66SAsim Jamshed  * These flags control which ones.
335*522d5c66SAsim Jamshed  * Also in flags you can specify NETMAP_NO_TX_POLL and NETMAP_DO_RX_POLL,
336*522d5c66SAsim Jamshed  * which set the initial value for these flags.
337*522d5c66SAsim Jamshed  * Note that the 16 low bits of the flags are reserved for data
338*522d5c66SAsim Jamshed  * that may go into the nmreq.
339*522d5c66SAsim Jamshed  */
340*522d5c66SAsim Jamshed enum {
341*522d5c66SAsim Jamshed 	NM_OPEN_NO_MMAP =	0x040000, /* reuse mmap from parent */
342*522d5c66SAsim Jamshed 	NM_OPEN_IFNAME =	0x080000, /* nr_name, nr_ringid, nr_flags */
343*522d5c66SAsim Jamshed 	NM_OPEN_ARG1 =		0x100000,
344*522d5c66SAsim Jamshed 	NM_OPEN_ARG2 =		0x200000,
345*522d5c66SAsim Jamshed 	NM_OPEN_ARG3 =		0x400000,
346*522d5c66SAsim Jamshed 	NM_OPEN_RING_CFG =	0x800000, /* tx|rx rings|slots */
347*522d5c66SAsim Jamshed };
348*522d5c66SAsim Jamshed 
349*522d5c66SAsim Jamshed 
350*522d5c66SAsim Jamshed /*
351*522d5c66SAsim Jamshed  * nm_close()	closes and restores the port to its previous state
352*522d5c66SAsim Jamshed  */
353*522d5c66SAsim Jamshed 
354*522d5c66SAsim Jamshed static int nm_close(struct nm_desc *);
355*522d5c66SAsim Jamshed 
356*522d5c66SAsim Jamshed /*
357*522d5c66SAsim Jamshed  * nm_mmap()    do mmap or inherit from parent if the nr_arg2
358*522d5c66SAsim Jamshed  *              (memory block) matches.
359*522d5c66SAsim Jamshed  */
360*522d5c66SAsim Jamshed 
361*522d5c66SAsim Jamshed static int nm_mmap(struct nm_desc *, const struct nm_desc *);
362*522d5c66SAsim Jamshed 
363*522d5c66SAsim Jamshed /*
364*522d5c66SAsim Jamshed  * nm_inject() is the same as pcap_inject()
365*522d5c66SAsim Jamshed  * nm_dispatch() is the same as pcap_dispatch()
366*522d5c66SAsim Jamshed  * nm_nextpkt() is the same as pcap_next()
367*522d5c66SAsim Jamshed  */
368*522d5c66SAsim Jamshed 
369*522d5c66SAsim Jamshed static int nm_inject(struct nm_desc *, const void *, size_t);
370*522d5c66SAsim Jamshed static int nm_dispatch(struct nm_desc *, int, nm_cb_t, u_char *);
371*522d5c66SAsim Jamshed static u_char *nm_nextpkt(struct nm_desc *, struct nm_pkthdr *);
372*522d5c66SAsim Jamshed 
373*522d5c66SAsim Jamshed #ifdef _WIN32
374*522d5c66SAsim Jamshed 
375*522d5c66SAsim Jamshed intptr_t _get_osfhandle(int); /* defined in io.h in windows */
376*522d5c66SAsim Jamshed 
377*522d5c66SAsim Jamshed /*
378*522d5c66SAsim Jamshed  * In windows we do not have yet native poll support, so we keep track
379*522d5c66SAsim Jamshed  * of file descriptors associated to netmap ports to emulate poll on
380*522d5c66SAsim Jamshed  * them and fall back on regular poll on other file descriptors.
381*522d5c66SAsim Jamshed  */
382*522d5c66SAsim Jamshed struct win_netmap_fd_list {
383*522d5c66SAsim Jamshed 	struct win_netmap_fd_list *next;
384*522d5c66SAsim Jamshed 	int win_netmap_fd;
385*522d5c66SAsim Jamshed 	HANDLE win_netmap_handle;
386*522d5c66SAsim Jamshed };
387*522d5c66SAsim Jamshed 
388*522d5c66SAsim Jamshed /*
389*522d5c66SAsim Jamshed  * list head containing all the netmap opened fd and their
390*522d5c66SAsim Jamshed  * windows HANDLE counterparts
391*522d5c66SAsim Jamshed  */
392*522d5c66SAsim Jamshed static struct win_netmap_fd_list *win_netmap_fd_list_head;
393*522d5c66SAsim Jamshed 
394*522d5c66SAsim Jamshed static void
win_insert_fd_record(int fd)395*522d5c66SAsim Jamshed win_insert_fd_record(int fd)
396*522d5c66SAsim Jamshed {
397*522d5c66SAsim Jamshed 	struct win_netmap_fd_list *curr;
398*522d5c66SAsim Jamshed 
399*522d5c66SAsim Jamshed 	for (curr = win_netmap_fd_list_head; curr; curr = curr->next) {
400*522d5c66SAsim Jamshed 		if (fd == curr->win_netmap_fd) {
401*522d5c66SAsim Jamshed 			return;
402*522d5c66SAsim Jamshed 		}
403*522d5c66SAsim Jamshed 	}
404*522d5c66SAsim Jamshed 	curr = calloc(1, sizeof(*curr));
405*522d5c66SAsim Jamshed 	curr->next = win_netmap_fd_list_head;
406*522d5c66SAsim Jamshed 	curr->win_netmap_fd = fd;
407*522d5c66SAsim Jamshed 	curr->win_netmap_handle = IntToPtr(_get_osfhandle(fd));
408*522d5c66SAsim Jamshed 	win_netmap_fd_list_head = curr;
409*522d5c66SAsim Jamshed }
410*522d5c66SAsim Jamshed 
411*522d5c66SAsim Jamshed void
win_remove_fd_record(int fd)412*522d5c66SAsim Jamshed win_remove_fd_record(int fd)
413*522d5c66SAsim Jamshed {
414*522d5c66SAsim Jamshed 	struct win_netmap_fd_list *curr = win_netmap_fd_list_head;
415*522d5c66SAsim Jamshed 	struct win_netmap_fd_list *prev = NULL;
416*522d5c66SAsim Jamshed 	for (; curr ; prev = curr, curr = curr->next) {
417*522d5c66SAsim Jamshed 		if (fd != curr->win_netmap_fd)
418*522d5c66SAsim Jamshed 			continue;
419*522d5c66SAsim Jamshed 		/* found the entry */
420*522d5c66SAsim Jamshed 		if (prev == NULL) { /* we are freeing the first entry */
421*522d5c66SAsim Jamshed 			win_netmap_fd_list_head = curr->next;
422*522d5c66SAsim Jamshed 		} else {
423*522d5c66SAsim Jamshed 			prev->next = curr->next;
424*522d5c66SAsim Jamshed 		}
425*522d5c66SAsim Jamshed 		free(curr);
426*522d5c66SAsim Jamshed 		break;
427*522d5c66SAsim Jamshed 	}
428*522d5c66SAsim Jamshed }
429*522d5c66SAsim Jamshed 
430*522d5c66SAsim Jamshed 
431*522d5c66SAsim Jamshed HANDLE
win_get_netmap_handle(int fd)432*522d5c66SAsim Jamshed win_get_netmap_handle(int fd)
433*522d5c66SAsim Jamshed {
434*522d5c66SAsim Jamshed 	struct win_netmap_fd_list *curr;
435*522d5c66SAsim Jamshed 
436*522d5c66SAsim Jamshed 	for (curr = win_netmap_fd_list_head; curr; curr = curr->next) {
437*522d5c66SAsim Jamshed 		if (fd == curr->win_netmap_fd) {
438*522d5c66SAsim Jamshed 			return curr->win_netmap_handle;
439*522d5c66SAsim Jamshed 		}
440*522d5c66SAsim Jamshed 	}
441*522d5c66SAsim Jamshed 	return NULL;
442*522d5c66SAsim Jamshed }
443*522d5c66SAsim Jamshed 
444*522d5c66SAsim Jamshed /*
445*522d5c66SAsim Jamshed  * we need to wrap ioctl and mmap, at least for the netmap file descriptors
446*522d5c66SAsim Jamshed  */
447*522d5c66SAsim Jamshed 
448*522d5c66SAsim Jamshed /*
449*522d5c66SAsim Jamshed  * use this function only from netmap_user.h internal functions
450*522d5c66SAsim Jamshed  * same as ioctl, returns 0 on success and -1 on error
451*522d5c66SAsim Jamshed  */
452*522d5c66SAsim Jamshed static int
win_nm_ioctl_internal(HANDLE h,int32_t ctlCode,void * arg)453*522d5c66SAsim Jamshed win_nm_ioctl_internal(HANDLE h, int32_t ctlCode, void *arg)
454*522d5c66SAsim Jamshed {
455*522d5c66SAsim Jamshed 	DWORD bReturn = 0, szIn, szOut;
456*522d5c66SAsim Jamshed 	BOOL ioctlReturnStatus;
457*522d5c66SAsim Jamshed 	void *inParam = arg, *outParam = arg;
458*522d5c66SAsim Jamshed 
459*522d5c66SAsim Jamshed 	switch (ctlCode) {
460*522d5c66SAsim Jamshed 	case NETMAP_POLL:
461*522d5c66SAsim Jamshed 		szIn = sizeof(POLL_REQUEST_DATA);
462*522d5c66SAsim Jamshed 		szOut = sizeof(POLL_REQUEST_DATA);
463*522d5c66SAsim Jamshed 		break;
464*522d5c66SAsim Jamshed 	case NETMAP_MMAP:
465*522d5c66SAsim Jamshed 		szIn = 0;
466*522d5c66SAsim Jamshed 		szOut = sizeof(void*);
467*522d5c66SAsim Jamshed 		inParam = NULL; /* nothing on input */
468*522d5c66SAsim Jamshed 		break;
469*522d5c66SAsim Jamshed 	case NIOCTXSYNC:
470*522d5c66SAsim Jamshed 	case NIOCRXSYNC:
471*522d5c66SAsim Jamshed 		szIn = 0;
472*522d5c66SAsim Jamshed 		szOut = 0;
473*522d5c66SAsim Jamshed 		break;
474*522d5c66SAsim Jamshed 	case NIOCREGIF:
475*522d5c66SAsim Jamshed 		szIn = sizeof(struct nmreq);
476*522d5c66SAsim Jamshed 		szOut = sizeof(struct nmreq);
477*522d5c66SAsim Jamshed 		break;
478*522d5c66SAsim Jamshed 	case NIOCCONFIG:
479*522d5c66SAsim Jamshed 		D("unsupported NIOCCONFIG!");
480*522d5c66SAsim Jamshed 		return -1;
481*522d5c66SAsim Jamshed 
482*522d5c66SAsim Jamshed 	default: /* a regular ioctl */
483*522d5c66SAsim Jamshed 		D("invalid ioctl %x on netmap fd", ctlCode);
484*522d5c66SAsim Jamshed 		return -1;
485*522d5c66SAsim Jamshed 	}
486*522d5c66SAsim Jamshed 
487*522d5c66SAsim Jamshed 	ioctlReturnStatus = DeviceIoControl(h,
488*522d5c66SAsim Jamshed 				ctlCode, inParam, szIn,
489*522d5c66SAsim Jamshed 				outParam, szOut,
490*522d5c66SAsim Jamshed 				&bReturn, NULL);
491*522d5c66SAsim Jamshed 	// XXX note windows returns 0 on error or async call, 1 on success
492*522d5c66SAsim Jamshed 	// we could call GetLastError() to figure out what happened
493*522d5c66SAsim Jamshed 	return ioctlReturnStatus ? 0 : -1;
494*522d5c66SAsim Jamshed }
495*522d5c66SAsim Jamshed 
496*522d5c66SAsim Jamshed /*
497*522d5c66SAsim Jamshed  * this function is what must be called from user-space programs
498*522d5c66SAsim Jamshed  * same as ioctl, returns 0 on success and -1 on error
499*522d5c66SAsim Jamshed  */
500*522d5c66SAsim Jamshed static int
win_nm_ioctl(int fd,int32_t ctlCode,void * arg)501*522d5c66SAsim Jamshed win_nm_ioctl(int fd, int32_t ctlCode, void *arg)
502*522d5c66SAsim Jamshed {
503*522d5c66SAsim Jamshed 	HANDLE h = win_get_netmap_handle(fd);
504*522d5c66SAsim Jamshed 
505*522d5c66SAsim Jamshed 	if (h == NULL) {
506*522d5c66SAsim Jamshed 		return ioctl(fd, ctlCode, arg);
507*522d5c66SAsim Jamshed 	} else {
508*522d5c66SAsim Jamshed 		return win_nm_ioctl_internal(h, ctlCode, arg);
509*522d5c66SAsim Jamshed 	}
510*522d5c66SAsim Jamshed }
511*522d5c66SAsim Jamshed 
512*522d5c66SAsim Jamshed #define ioctl win_nm_ioctl /* from now on, within this file ... */
513*522d5c66SAsim Jamshed 
514*522d5c66SAsim Jamshed /*
515*522d5c66SAsim Jamshed  * We cannot use the native mmap on windows
516*522d5c66SAsim Jamshed  * The only parameter used is "fd", the other ones are just declared to
517*522d5c66SAsim Jamshed  * make this signature comparable to the FreeBSD/Linux one
518*522d5c66SAsim Jamshed  */
519*522d5c66SAsim Jamshed static void *
win32_mmap_emulated(void * addr,size_t length,int prot,int flags,int fd,int32_t offset)520*522d5c66SAsim Jamshed win32_mmap_emulated(void *addr, size_t length, int prot, int flags, int fd, int32_t offset)
521*522d5c66SAsim Jamshed {
522*522d5c66SAsim Jamshed 	HANDLE h = win_get_netmap_handle(fd);
523*522d5c66SAsim Jamshed 
524*522d5c66SAsim Jamshed 	if (h == NULL) {
525*522d5c66SAsim Jamshed 		return mmap(addr, length, prot, flags, fd, offset);
526*522d5c66SAsim Jamshed 	} else {
527*522d5c66SAsim Jamshed 		MEMORY_ENTRY ret;
528*522d5c66SAsim Jamshed 
529*522d5c66SAsim Jamshed 		return win_nm_ioctl_internal(h, NETMAP_MMAP, &ret) ?
530*522d5c66SAsim Jamshed 			NULL : ret.pUsermodeVirtualAddress;
531*522d5c66SAsim Jamshed 	}
532*522d5c66SAsim Jamshed }
533*522d5c66SAsim Jamshed 
534*522d5c66SAsim Jamshed #define mmap win32_mmap_emulated
535*522d5c66SAsim Jamshed 
536*522d5c66SAsim Jamshed #include <sys/poll.h> /* XXX needed to use the structure pollfd */
537*522d5c66SAsim Jamshed 
538*522d5c66SAsim Jamshed static int
win_nm_poll(struct pollfd * fds,int nfds,int timeout)539*522d5c66SAsim Jamshed win_nm_poll(struct pollfd *fds, int nfds, int timeout)
540*522d5c66SAsim Jamshed {
541*522d5c66SAsim Jamshed 	HANDLE h;
542*522d5c66SAsim Jamshed 
543*522d5c66SAsim Jamshed 	if (nfds != 1 || fds == NULL || (h = win_get_netmap_handle(fds->fd)) == NULL) {;
544*522d5c66SAsim Jamshed 		return poll(fds, nfds, timeout);
545*522d5c66SAsim Jamshed 	} else {
546*522d5c66SAsim Jamshed 		POLL_REQUEST_DATA prd;
547*522d5c66SAsim Jamshed 
548*522d5c66SAsim Jamshed 		prd.timeout = timeout;
549*522d5c66SAsim Jamshed 		prd.events = fds->events;
550*522d5c66SAsim Jamshed 
551*522d5c66SAsim Jamshed 		win_nm_ioctl_internal(h, NETMAP_POLL, &prd);
552*522d5c66SAsim Jamshed 		if ((prd.revents == POLLERR) || (prd.revents == STATUS_TIMEOUT)) {
553*522d5c66SAsim Jamshed 			return -1;
554*522d5c66SAsim Jamshed 		}
555*522d5c66SAsim Jamshed 		return 1;
556*522d5c66SAsim Jamshed 	}
557*522d5c66SAsim Jamshed }
558*522d5c66SAsim Jamshed 
559*522d5c66SAsim Jamshed #define poll win_nm_poll
560*522d5c66SAsim Jamshed 
561*522d5c66SAsim Jamshed static int
win_nm_open(char * pathname,int flags)562*522d5c66SAsim Jamshed win_nm_open(char* pathname, int flags){
563*522d5c66SAsim Jamshed 
564*522d5c66SAsim Jamshed 	if (strcmp(pathname, NETMAP_DEVICE_NAME) == 0){
565*522d5c66SAsim Jamshed 		int fd = open(NETMAP_DEVICE_NAME, O_RDWR);
566*522d5c66SAsim Jamshed 		if (fd < 0) {
567*522d5c66SAsim Jamshed 			return -1;
568*522d5c66SAsim Jamshed 		}
569*522d5c66SAsim Jamshed 
570*522d5c66SAsim Jamshed 		win_insert_fd_record(fd);
571*522d5c66SAsim Jamshed 		return fd;
572*522d5c66SAsim Jamshed 	}
573*522d5c66SAsim Jamshed 	else {
574*522d5c66SAsim Jamshed 
575*522d5c66SAsim Jamshed 		return open(pathname, flags);
576*522d5c66SAsim Jamshed 	}
577*522d5c66SAsim Jamshed }
578*522d5c66SAsim Jamshed 
579*522d5c66SAsim Jamshed #define open win_nm_open
580*522d5c66SAsim Jamshed 
581*522d5c66SAsim Jamshed static int
win_nm_close(int fd)582*522d5c66SAsim Jamshed win_nm_close(int fd){
583*522d5c66SAsim Jamshed 	if (fd != -1){
584*522d5c66SAsim Jamshed 		close(fd);
585*522d5c66SAsim Jamshed 		if (win_get_netmap_handle(fd) != NULL){
586*522d5c66SAsim Jamshed 			win_remove_fd_record(fd);
587*522d5c66SAsim Jamshed 		}
588*522d5c66SAsim Jamshed 	}
589*522d5c66SAsim Jamshed 	return 0;
590*522d5c66SAsim Jamshed }
591*522d5c66SAsim Jamshed 
592*522d5c66SAsim Jamshed #define close win_nm_close
593*522d5c66SAsim Jamshed 
594*522d5c66SAsim Jamshed #endif /* _WIN32 */
595*522d5c66SAsim Jamshed 
596*522d5c66SAsim Jamshed /*
597*522d5c66SAsim Jamshed  * Try to open, return descriptor if successful, NULL otherwise.
598*522d5c66SAsim Jamshed  * An invalid netmap name will return errno = 0;
599*522d5c66SAsim Jamshed  * You can pass a pointer to a pre-filled nm_desc to add special
600*522d5c66SAsim Jamshed  * parameters. Flags is used as follows
601*522d5c66SAsim Jamshed  * NM_OPEN_NO_MMAP	use the memory from arg, only XXX avoid mmap
602*522d5c66SAsim Jamshed  *			if the nr_arg2 (memory block) matches.
603*522d5c66SAsim Jamshed  * NM_OPEN_ARG1		use req.nr_arg1 from arg
604*522d5c66SAsim Jamshed  * NM_OPEN_ARG2		use req.nr_arg2 from arg
605*522d5c66SAsim Jamshed  * NM_OPEN_RING_CFG	user ring config from arg
606*522d5c66SAsim Jamshed  */
607*522d5c66SAsim Jamshed static struct nm_desc *
nm_open(const char * ifname,const struct nmreq * req,uint64_t new_flags,const struct nm_desc * arg)608*522d5c66SAsim Jamshed nm_open(const char *ifname, const struct nmreq *req,
609*522d5c66SAsim Jamshed 	uint64_t new_flags, const struct nm_desc *arg)
610*522d5c66SAsim Jamshed {
611*522d5c66SAsim Jamshed 	struct nm_desc *d = NULL;
612*522d5c66SAsim Jamshed 	const struct nm_desc *parent = arg;
613*522d5c66SAsim Jamshed 	u_int namelen;
614*522d5c66SAsim Jamshed 	uint32_t nr_ringid = 0, nr_flags, nr_reg;
615*522d5c66SAsim Jamshed 	const char *port = NULL;
616*522d5c66SAsim Jamshed #define MAXERRMSG 80
617*522d5c66SAsim Jamshed 	char errmsg[MAXERRMSG] = "";
618*522d5c66SAsim Jamshed 	enum { P_START, P_RNGSFXOK, P_GETNUM, P_FLAGS, P_FLAGSOK } p_state;
619*522d5c66SAsim Jamshed 	long num;
620*522d5c66SAsim Jamshed 
621*522d5c66SAsim Jamshed 	if (strncmp(ifname, "netmap:", 7) && strncmp(ifname, "vale", 4)) {
622*522d5c66SAsim Jamshed 		errno = 0; /* name not recognised, not an error */
623*522d5c66SAsim Jamshed 		return NULL;
624*522d5c66SAsim Jamshed 	}
625*522d5c66SAsim Jamshed 	if (ifname[0] == 'n')
626*522d5c66SAsim Jamshed 		ifname += 7;
627*522d5c66SAsim Jamshed 	/* scan for a separator */
628*522d5c66SAsim Jamshed 	for (port = ifname; *port && !index("-*^{}/", *port); port++)
629*522d5c66SAsim Jamshed 		;
630*522d5c66SAsim Jamshed 	namelen = port - ifname;
631*522d5c66SAsim Jamshed 	if (namelen >= sizeof(d->req.nr_name)) {
632*522d5c66SAsim Jamshed 		snprintf(errmsg, MAXERRMSG, "name too long");
633*522d5c66SAsim Jamshed 		goto fail;
634*522d5c66SAsim Jamshed 	}
635*522d5c66SAsim Jamshed 	p_state = P_START;
636*522d5c66SAsim Jamshed 	nr_flags = NR_REG_ALL_NIC; /* default for no suffix */
637*522d5c66SAsim Jamshed 	while (*port) {
638*522d5c66SAsim Jamshed 		switch (p_state) {
639*522d5c66SAsim Jamshed 		case P_START:
640*522d5c66SAsim Jamshed 			switch (*port) {
641*522d5c66SAsim Jamshed 			case '^': /* only SW ring */
642*522d5c66SAsim Jamshed 				nr_flags = NR_REG_SW;
643*522d5c66SAsim Jamshed 				p_state = P_RNGSFXOK;
644*522d5c66SAsim Jamshed 				break;
645*522d5c66SAsim Jamshed 			case '*': /* NIC and SW */
646*522d5c66SAsim Jamshed 				nr_flags = NR_REG_NIC_SW;
647*522d5c66SAsim Jamshed 				p_state = P_RNGSFXOK;
648*522d5c66SAsim Jamshed 				break;
649*522d5c66SAsim Jamshed 			case '-': /* one NIC ring pair */
650*522d5c66SAsim Jamshed 				nr_flags = NR_REG_ONE_NIC;
651*522d5c66SAsim Jamshed 				p_state = P_GETNUM;
652*522d5c66SAsim Jamshed 				break;
653*522d5c66SAsim Jamshed 			case '{': /* pipe (master endpoint) */
654*522d5c66SAsim Jamshed 				nr_flags = NR_REG_PIPE_MASTER;
655*522d5c66SAsim Jamshed 				p_state = P_GETNUM;
656*522d5c66SAsim Jamshed 				break;
657*522d5c66SAsim Jamshed 			case '}': /* pipe (slave endoint) */
658*522d5c66SAsim Jamshed 				nr_flags = NR_REG_PIPE_SLAVE;
659*522d5c66SAsim Jamshed 				p_state = P_GETNUM;
660*522d5c66SAsim Jamshed 				break;
661*522d5c66SAsim Jamshed 			case '/': /* start of flags */
662*522d5c66SAsim Jamshed 				p_state = P_FLAGS;
663*522d5c66SAsim Jamshed 				break;
664*522d5c66SAsim Jamshed 			default:
665*522d5c66SAsim Jamshed 				snprintf(errmsg, MAXERRMSG, "unknown modifier: '%c'", *port);
666*522d5c66SAsim Jamshed 				goto fail;
667*522d5c66SAsim Jamshed 			}
668*522d5c66SAsim Jamshed 			port++;
669*522d5c66SAsim Jamshed 			break;
670*522d5c66SAsim Jamshed 		case P_RNGSFXOK:
671*522d5c66SAsim Jamshed 			switch (*port) {
672*522d5c66SAsim Jamshed 			case '/':
673*522d5c66SAsim Jamshed 				p_state = P_FLAGS;
674*522d5c66SAsim Jamshed 				break;
675*522d5c66SAsim Jamshed 			default:
676*522d5c66SAsim Jamshed 				snprintf(errmsg, MAXERRMSG, "unexpected character: '%c'", *port);
677*522d5c66SAsim Jamshed 				goto fail;
678*522d5c66SAsim Jamshed 			}
679*522d5c66SAsim Jamshed 			port++;
680*522d5c66SAsim Jamshed 			break;
681*522d5c66SAsim Jamshed 		case P_GETNUM:
682*522d5c66SAsim Jamshed 			num = strtol(port, (char **)&port, 10);
683*522d5c66SAsim Jamshed 			if (num < 0 || num >= NETMAP_RING_MASK) {
684*522d5c66SAsim Jamshed 				snprintf(errmsg, MAXERRMSG, "'%ld' out of range [0, %d)",
685*522d5c66SAsim Jamshed 						num, NETMAP_RING_MASK);
686*522d5c66SAsim Jamshed 				goto fail;
687*522d5c66SAsim Jamshed 			}
688*522d5c66SAsim Jamshed 			nr_ringid = num & NETMAP_RING_MASK;
689*522d5c66SAsim Jamshed 			p_state = P_RNGSFXOK;
690*522d5c66SAsim Jamshed 			break;
691*522d5c66SAsim Jamshed 		case P_FLAGS:
692*522d5c66SAsim Jamshed 		case P_FLAGSOK:
693*522d5c66SAsim Jamshed 			switch (*port) {
694*522d5c66SAsim Jamshed 			case 'x':
695*522d5c66SAsim Jamshed 				nr_flags |= NR_EXCLUSIVE;
696*522d5c66SAsim Jamshed 				break;
697*522d5c66SAsim Jamshed 			case 'z':
698*522d5c66SAsim Jamshed 				nr_flags |= NR_ZCOPY_MON;
699*522d5c66SAsim Jamshed 				break;
700*522d5c66SAsim Jamshed 			case 't':
701*522d5c66SAsim Jamshed 				nr_flags |= NR_MONITOR_TX;
702*522d5c66SAsim Jamshed 				break;
703*522d5c66SAsim Jamshed 			case 'r':
704*522d5c66SAsim Jamshed 				nr_flags |= NR_MONITOR_RX;
705*522d5c66SAsim Jamshed 				break;
706*522d5c66SAsim Jamshed 			case 'R':
707*522d5c66SAsim Jamshed 				nr_flags |= NR_RX_RINGS_ONLY;
708*522d5c66SAsim Jamshed 				break;
709*522d5c66SAsim Jamshed 			case 'T':
710*522d5c66SAsim Jamshed 				nr_flags |= NR_TX_RINGS_ONLY;
711*522d5c66SAsim Jamshed 				break;
712*522d5c66SAsim Jamshed 			default:
713*522d5c66SAsim Jamshed 				snprintf(errmsg, MAXERRMSG, "unrecognized flag: '%c'", *port);
714*522d5c66SAsim Jamshed 				goto fail;
715*522d5c66SAsim Jamshed 			}
716*522d5c66SAsim Jamshed 			port++;
717*522d5c66SAsim Jamshed 			p_state = P_FLAGSOK;
718*522d5c66SAsim Jamshed 			break;
719*522d5c66SAsim Jamshed 		}
720*522d5c66SAsim Jamshed 	}
721*522d5c66SAsim Jamshed 	if (p_state != P_START && p_state != P_RNGSFXOK && p_state != P_FLAGSOK) {
722*522d5c66SAsim Jamshed 		snprintf(errmsg, MAXERRMSG, "unexpected end of port name");
723*522d5c66SAsim Jamshed 		goto fail;
724*522d5c66SAsim Jamshed 	}
725*522d5c66SAsim Jamshed 	ND("flags: %s %s %s %s",
726*522d5c66SAsim Jamshed 			(nr_flags & NR_EXCLUSIVE) ? "EXCLUSIVE" : "",
727*522d5c66SAsim Jamshed 			(nr_flags & NR_ZCOPY_MON) ? "ZCOPY_MON" : "",
728*522d5c66SAsim Jamshed 			(nr_flags & NR_MONITOR_TX) ? "MONITOR_TX" : "",
729*522d5c66SAsim Jamshed 			(nr_flags & NR_MONITOR_RX) ? "MONITOR_RX" : "");
730*522d5c66SAsim Jamshed 	d = (struct nm_desc *)calloc(1, sizeof(*d));
731*522d5c66SAsim Jamshed 	if (d == NULL) {
732*522d5c66SAsim Jamshed 		snprintf(errmsg, MAXERRMSG, "nm_desc alloc failure");
733*522d5c66SAsim Jamshed 		errno = ENOMEM;
734*522d5c66SAsim Jamshed 		return NULL;
735*522d5c66SAsim Jamshed 	}
736*522d5c66SAsim Jamshed 	d->self = d;	/* set this early so nm_close() works */
737*522d5c66SAsim Jamshed 	d->fd = open(NETMAP_DEVICE_NAME, O_RDWR);
738*522d5c66SAsim Jamshed 	if (d->fd < 0) {
739*522d5c66SAsim Jamshed 		snprintf(errmsg, MAXERRMSG, "cannot open /dev/netmap: %s", strerror(errno));
740*522d5c66SAsim Jamshed 		goto fail;
741*522d5c66SAsim Jamshed 	}
742*522d5c66SAsim Jamshed 
743*522d5c66SAsim Jamshed 	if (req)
744*522d5c66SAsim Jamshed 		d->req = *req;
745*522d5c66SAsim Jamshed 	d->req.nr_version = NETMAP_API;
746*522d5c66SAsim Jamshed 	d->req.nr_ringid &= ~NETMAP_RING_MASK;
747*522d5c66SAsim Jamshed 
748*522d5c66SAsim Jamshed 	/* these fields are overridden by ifname and flags processing */
749*522d5c66SAsim Jamshed 	d->req.nr_ringid |= nr_ringid;
750*522d5c66SAsim Jamshed 	d->req.nr_flags |= nr_flags;
751*522d5c66SAsim Jamshed 	memcpy(d->req.nr_name, ifname, namelen);
752*522d5c66SAsim Jamshed 	d->req.nr_name[namelen] = '\0';
753*522d5c66SAsim Jamshed 	/* optionally import info from parent */
754*522d5c66SAsim Jamshed 	if (IS_NETMAP_DESC(parent) && new_flags) {
755*522d5c66SAsim Jamshed 		if (new_flags & NM_OPEN_ARG1)
756*522d5c66SAsim Jamshed 			D("overriding ARG1 %d", parent->req.nr_arg1);
757*522d5c66SAsim Jamshed 		d->req.nr_arg1 = new_flags & NM_OPEN_ARG1 ?
758*522d5c66SAsim Jamshed 			parent->req.nr_arg1 : 4;
759*522d5c66SAsim Jamshed 		if (new_flags & NM_OPEN_ARG2)
760*522d5c66SAsim Jamshed 			D("overriding ARG2 %d", parent->req.nr_arg2);
761*522d5c66SAsim Jamshed 		d->req.nr_arg2 = new_flags & NM_OPEN_ARG2 ?
762*522d5c66SAsim Jamshed 			parent->req.nr_arg2 : 0;
763*522d5c66SAsim Jamshed 		if (new_flags & NM_OPEN_ARG3)
764*522d5c66SAsim Jamshed 			D("overriding ARG3 %d", parent->req.nr_arg3);
765*522d5c66SAsim Jamshed 		d->req.nr_arg3 = new_flags & NM_OPEN_ARG3 ?
766*522d5c66SAsim Jamshed 			parent->req.nr_arg3 : 0;
767*522d5c66SAsim Jamshed 		if (new_flags & NM_OPEN_RING_CFG) {
768*522d5c66SAsim Jamshed 			D("overriding RING_CFG");
769*522d5c66SAsim Jamshed 			d->req.nr_tx_slots = parent->req.nr_tx_slots;
770*522d5c66SAsim Jamshed 			d->req.nr_rx_slots = parent->req.nr_rx_slots;
771*522d5c66SAsim Jamshed 			d->req.nr_tx_rings = parent->req.nr_tx_rings;
772*522d5c66SAsim Jamshed 			d->req.nr_rx_rings = parent->req.nr_rx_rings;
773*522d5c66SAsim Jamshed 		}
774*522d5c66SAsim Jamshed 		if (new_flags & NM_OPEN_IFNAME) {
775*522d5c66SAsim Jamshed 			D("overriding ifname %s ringid 0x%x flags 0x%x",
776*522d5c66SAsim Jamshed 				parent->req.nr_name, parent->req.nr_ringid,
777*522d5c66SAsim Jamshed 				parent->req.nr_flags);
778*522d5c66SAsim Jamshed 			memcpy(d->req.nr_name, parent->req.nr_name,
779*522d5c66SAsim Jamshed 				sizeof(d->req.nr_name));
780*522d5c66SAsim Jamshed 			d->req.nr_ringid = parent->req.nr_ringid;
781*522d5c66SAsim Jamshed 			d->req.nr_flags = parent->req.nr_flags;
782*522d5c66SAsim Jamshed 		}
783*522d5c66SAsim Jamshed 	}
784*522d5c66SAsim Jamshed 	/* add the *XPOLL flags */
785*522d5c66SAsim Jamshed 	d->req.nr_ringid |= new_flags & (NETMAP_NO_TX_POLL | NETMAP_DO_RX_POLL);
786*522d5c66SAsim Jamshed 
787*522d5c66SAsim Jamshed 	if (ioctl(d->fd, NIOCREGIF, &d->req)) {
788*522d5c66SAsim Jamshed 		snprintf(errmsg, MAXERRMSG, "NIOCREGIF failed: %s", strerror(errno));
789*522d5c66SAsim Jamshed 		goto fail;
790*522d5c66SAsim Jamshed 	}
791*522d5c66SAsim Jamshed 
792*522d5c66SAsim Jamshed         /* if parent is defined, do nm_mmap() even if NM_OPEN_NO_MMAP is set */
793*522d5c66SAsim Jamshed 	if ((!(new_flags & NM_OPEN_NO_MMAP) || parent) && nm_mmap(d, parent)) {
794*522d5c66SAsim Jamshed 	        snprintf(errmsg, MAXERRMSG, "mmap failed: %s", strerror(errno));
795*522d5c66SAsim Jamshed 		goto fail;
796*522d5c66SAsim Jamshed 	}
797*522d5c66SAsim Jamshed 
798*522d5c66SAsim Jamshed 	nr_reg = d->req.nr_flags & NR_REG_MASK;
799*522d5c66SAsim Jamshed 
800*522d5c66SAsim Jamshed 	if (nr_reg ==  NR_REG_SW) { /* host stack */
801*522d5c66SAsim Jamshed 		d->first_tx_ring = d->last_tx_ring = d->req.nr_tx_rings;
802*522d5c66SAsim Jamshed 		d->first_rx_ring = d->last_rx_ring = d->req.nr_rx_rings;
803*522d5c66SAsim Jamshed 	} else if (nr_reg ==  NR_REG_ALL_NIC) { /* only nic */
804*522d5c66SAsim Jamshed 		d->first_tx_ring = 0;
805*522d5c66SAsim Jamshed 		d->first_rx_ring = 0;
806*522d5c66SAsim Jamshed 		d->last_tx_ring = d->req.nr_tx_rings - 1;
807*522d5c66SAsim Jamshed 		d->last_rx_ring = d->req.nr_rx_rings - 1;
808*522d5c66SAsim Jamshed 	} else if (nr_reg ==  NR_REG_NIC_SW) {
809*522d5c66SAsim Jamshed 		d->first_tx_ring = 0;
810*522d5c66SAsim Jamshed 		d->first_rx_ring = 0;
811*522d5c66SAsim Jamshed 		d->last_tx_ring = d->req.nr_tx_rings;
812*522d5c66SAsim Jamshed 		d->last_rx_ring = d->req.nr_rx_rings;
813*522d5c66SAsim Jamshed 	} else if (nr_reg == NR_REG_ONE_NIC) {
814*522d5c66SAsim Jamshed 		/* XXX check validity */
815*522d5c66SAsim Jamshed 		d->first_tx_ring = d->last_tx_ring =
816*522d5c66SAsim Jamshed 		d->first_rx_ring = d->last_rx_ring = d->req.nr_ringid & NETMAP_RING_MASK;
817*522d5c66SAsim Jamshed 	} else { /* pipes */
818*522d5c66SAsim Jamshed 		d->first_tx_ring = d->last_tx_ring = 0;
819*522d5c66SAsim Jamshed 		d->first_rx_ring = d->last_rx_ring = 0;
820*522d5c66SAsim Jamshed 	}
821*522d5c66SAsim Jamshed 
822*522d5c66SAsim Jamshed #ifdef DEBUG_NETMAP_USER
823*522d5c66SAsim Jamshed     { /* debugging code */
824*522d5c66SAsim Jamshed 	int i;
825*522d5c66SAsim Jamshed 
826*522d5c66SAsim Jamshed 	D("%s tx %d .. %d %d rx %d .. %d %d", ifname,
827*522d5c66SAsim Jamshed 		d->first_tx_ring, d->last_tx_ring, d->req.nr_tx_rings,
828*522d5c66SAsim Jamshed                 d->first_rx_ring, d->last_rx_ring, d->req.nr_rx_rings);
829*522d5c66SAsim Jamshed 	for (i = 0; i <= d->req.nr_tx_rings; i++) {
830*522d5c66SAsim Jamshed 		struct netmap_ring *r = NETMAP_TXRING(d->nifp, i);
831*522d5c66SAsim Jamshed 		D("TX%d %p h %d c %d t %d", i, r, r->head, r->cur, r->tail);
832*522d5c66SAsim Jamshed 	}
833*522d5c66SAsim Jamshed 	for (i = 0; i <= d->req.nr_rx_rings; i++) {
834*522d5c66SAsim Jamshed 		struct netmap_ring *r = NETMAP_RXRING(d->nifp, i);
835*522d5c66SAsim Jamshed 		D("RX%d %p h %d c %d t %d", i, r, r->head, r->cur, r->tail);
836*522d5c66SAsim Jamshed 	}
837*522d5c66SAsim Jamshed     }
838*522d5c66SAsim Jamshed #endif /* debugging */
839*522d5c66SAsim Jamshed 
840*522d5c66SAsim Jamshed 	d->cur_tx_ring = d->first_tx_ring;
841*522d5c66SAsim Jamshed 	d->cur_rx_ring = d->first_rx_ring;
842*522d5c66SAsim Jamshed 	return d;
843*522d5c66SAsim Jamshed 
844*522d5c66SAsim Jamshed fail:
845*522d5c66SAsim Jamshed 	nm_close(d);
846*522d5c66SAsim Jamshed 	if (errmsg[0])
847*522d5c66SAsim Jamshed 		D("%s %s", errmsg, ifname);
848*522d5c66SAsim Jamshed 	if (errno == 0)
849*522d5c66SAsim Jamshed 		errno = EINVAL;
850*522d5c66SAsim Jamshed 	return NULL;
851*522d5c66SAsim Jamshed }
852*522d5c66SAsim Jamshed 
853*522d5c66SAsim Jamshed 
854*522d5c66SAsim Jamshed static int
nm_close(struct nm_desc * d)855*522d5c66SAsim Jamshed nm_close(struct nm_desc *d)
856*522d5c66SAsim Jamshed {
857*522d5c66SAsim Jamshed 	/*
858*522d5c66SAsim Jamshed 	 * ugly trick to avoid unused warnings
859*522d5c66SAsim Jamshed 	 */
860*522d5c66SAsim Jamshed 	static void *__xxzt[] __attribute__ ((unused))  =
861*522d5c66SAsim Jamshed 		{ (void *)nm_open, (void *)nm_inject,
862*522d5c66SAsim Jamshed 		  (void *)nm_dispatch, (void *)nm_nextpkt } ;
863*522d5c66SAsim Jamshed 
864*522d5c66SAsim Jamshed 	if (d == NULL || d->self != d)
865*522d5c66SAsim Jamshed 		return EINVAL;
866*522d5c66SAsim Jamshed 	if (d->done_mmap && d->mem)
867*522d5c66SAsim Jamshed 		munmap(d->mem, d->memsize);
868*522d5c66SAsim Jamshed 	if (d->fd != -1){
869*522d5c66SAsim Jamshed 		close(d->fd);
870*522d5c66SAsim Jamshed 	}
871*522d5c66SAsim Jamshed 
872*522d5c66SAsim Jamshed 	bzero(d, sizeof(*d));
873*522d5c66SAsim Jamshed 	free(d);
874*522d5c66SAsim Jamshed 	return 0;
875*522d5c66SAsim Jamshed }
876*522d5c66SAsim Jamshed 
877*522d5c66SAsim Jamshed 
878*522d5c66SAsim Jamshed static int
nm_mmap(struct nm_desc * d,const struct nm_desc * parent)879*522d5c66SAsim Jamshed nm_mmap(struct nm_desc *d, const struct nm_desc *parent)
880*522d5c66SAsim Jamshed {
881*522d5c66SAsim Jamshed 	//XXX TODO: check if mmap is already done
882*522d5c66SAsim Jamshed 
883*522d5c66SAsim Jamshed 	if (IS_NETMAP_DESC(parent) && parent->mem &&
884*522d5c66SAsim Jamshed 	    parent->req.nr_arg2 == d->req.nr_arg2) {
885*522d5c66SAsim Jamshed 		/* do not mmap, inherit from parent */
886*522d5c66SAsim Jamshed 		D("do not mmap, inherit from parent");
887*522d5c66SAsim Jamshed 		d->memsize = parent->memsize;
888*522d5c66SAsim Jamshed 		d->mem = parent->mem;
889*522d5c66SAsim Jamshed 	} else {
890*522d5c66SAsim Jamshed 		/* XXX TODO: check if memsize is too large (or there is overflow) */
891*522d5c66SAsim Jamshed 		d->memsize = d->req.nr_memsize;
892*522d5c66SAsim Jamshed 		d->mem = mmap(0, d->memsize, PROT_WRITE | PROT_READ, MAP_SHARED,
893*522d5c66SAsim Jamshed 				d->fd, 0);
894*522d5c66SAsim Jamshed 		if (d->mem == MAP_FAILED) {
895*522d5c66SAsim Jamshed 			goto fail;
896*522d5c66SAsim Jamshed 		}
897*522d5c66SAsim Jamshed 		d->done_mmap = 1;
898*522d5c66SAsim Jamshed 	}
899*522d5c66SAsim Jamshed 	{
900*522d5c66SAsim Jamshed 		struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset);
901*522d5c66SAsim Jamshed 		struct netmap_ring *r = NETMAP_RXRING(nifp, );
902*522d5c66SAsim Jamshed 
903*522d5c66SAsim Jamshed 		*(struct netmap_if **)(uintptr_t)&(d->nifp) = nifp;
904*522d5c66SAsim Jamshed 		*(struct netmap_ring **)(uintptr_t)&d->some_ring = r;
905*522d5c66SAsim Jamshed 		*(void **)(uintptr_t)&d->buf_start = NETMAP_BUF(r, 0);
906*522d5c66SAsim Jamshed 		*(void **)(uintptr_t)&d->buf_end =
907*522d5c66SAsim Jamshed 			(char *)d->mem + d->memsize;
908*522d5c66SAsim Jamshed 	}
909*522d5c66SAsim Jamshed 
910*522d5c66SAsim Jamshed 	return 0;
911*522d5c66SAsim Jamshed 
912*522d5c66SAsim Jamshed fail:
913*522d5c66SAsim Jamshed 	return EINVAL;
914*522d5c66SAsim Jamshed }
915*522d5c66SAsim Jamshed 
916*522d5c66SAsim Jamshed /*
917*522d5c66SAsim Jamshed  * Same prototype as pcap_inject(), only need to cast.
918*522d5c66SAsim Jamshed  */
919*522d5c66SAsim Jamshed static int
nm_inject(struct nm_desc * d,const void * buf,size_t size)920*522d5c66SAsim Jamshed nm_inject(struct nm_desc *d, const void *buf, size_t size)
921*522d5c66SAsim Jamshed {
922*522d5c66SAsim Jamshed 	u_int c, n = d->last_tx_ring - d->first_tx_ring + 1;
923*522d5c66SAsim Jamshed 
924*522d5c66SAsim Jamshed 	for (c = 0; c < n ; c++) {
925*522d5c66SAsim Jamshed 		/* compute current ring to use */
926*522d5c66SAsim Jamshed 		struct netmap_ring *ring;
927*522d5c66SAsim Jamshed 		uint32_t i, idx;
928*522d5c66SAsim Jamshed 		uint32_t ri = d->cur_tx_ring + c;
929*522d5c66SAsim Jamshed 
930*522d5c66SAsim Jamshed 		if (ri > d->last_tx_ring)
931*522d5c66SAsim Jamshed 			ri = d->first_tx_ring;
932*522d5c66SAsim Jamshed 		ring = NETMAP_TXRING(d->nifp, ri);
933*522d5c66SAsim Jamshed 		if (nm_ring_empty(ring)) {
934*522d5c66SAsim Jamshed 			continue;
935*522d5c66SAsim Jamshed 		}
936*522d5c66SAsim Jamshed 		i = ring->cur;
937*522d5c66SAsim Jamshed 		idx = ring->slot[i].buf_idx;
938*522d5c66SAsim Jamshed 		ring->slot[i].len = size;
939*522d5c66SAsim Jamshed 		nm_pkt_copy(buf, NETMAP_BUF(ring, idx), size);
940*522d5c66SAsim Jamshed 		d->cur_tx_ring = ri;
941*522d5c66SAsim Jamshed 		ring->head = ring->cur = nm_ring_next(ring, i);
942*522d5c66SAsim Jamshed 		return size;
943*522d5c66SAsim Jamshed 	}
944*522d5c66SAsim Jamshed 	return 0; /* fail */
945*522d5c66SAsim Jamshed }
946*522d5c66SAsim Jamshed 
947*522d5c66SAsim Jamshed 
948*522d5c66SAsim Jamshed /*
949*522d5c66SAsim Jamshed  * Same prototype as pcap_dispatch(), only need to cast.
950*522d5c66SAsim Jamshed  */
951*522d5c66SAsim Jamshed static int
nm_dispatch(struct nm_desc * d,int cnt,nm_cb_t cb,u_char * arg)952*522d5c66SAsim Jamshed nm_dispatch(struct nm_desc *d, int cnt, nm_cb_t cb, u_char *arg)
953*522d5c66SAsim Jamshed {
954*522d5c66SAsim Jamshed 	int n = d->last_rx_ring - d->first_rx_ring + 1;
955*522d5c66SAsim Jamshed 	int c, got = 0, ri = d->cur_rx_ring;
956*522d5c66SAsim Jamshed 
957*522d5c66SAsim Jamshed 	if (cnt == 0)
958*522d5c66SAsim Jamshed 		cnt = -1;
959*522d5c66SAsim Jamshed 	/* cnt == -1 means infinite, but rings have a finite amount
960*522d5c66SAsim Jamshed 	 * of buffers and the int is large enough that we never wrap,
961*522d5c66SAsim Jamshed 	 * so we can omit checking for -1
962*522d5c66SAsim Jamshed 	 */
963*522d5c66SAsim Jamshed 	for (c=0; c < n && cnt != got; c++) {
964*522d5c66SAsim Jamshed 		/* compute current ring to use */
965*522d5c66SAsim Jamshed 		struct netmap_ring *ring;
966*522d5c66SAsim Jamshed 
967*522d5c66SAsim Jamshed 		ri = d->cur_rx_ring + c;
968*522d5c66SAsim Jamshed 		if (ri > d->last_rx_ring)
969*522d5c66SAsim Jamshed 			ri = d->first_rx_ring;
970*522d5c66SAsim Jamshed 		ring = NETMAP_RXRING(d->nifp, ri);
971*522d5c66SAsim Jamshed 		for ( ; !nm_ring_empty(ring) && cnt != got; got++) {
972*522d5c66SAsim Jamshed 			u_int i = ring->cur;
973*522d5c66SAsim Jamshed 			u_int idx = ring->slot[i].buf_idx;
974*522d5c66SAsim Jamshed 			u_char *buf = (u_char *)NETMAP_BUF(ring, idx);
975*522d5c66SAsim Jamshed 
976*522d5c66SAsim Jamshed 			// __builtin_prefetch(buf);
977*522d5c66SAsim Jamshed 			d->hdr.len = d->hdr.caplen = ring->slot[i].len;
978*522d5c66SAsim Jamshed 			d->hdr.ts = ring->ts;
979*522d5c66SAsim Jamshed 			cb(arg, &d->hdr, buf);
980*522d5c66SAsim Jamshed 			ring->head = ring->cur = nm_ring_next(ring, i);
981*522d5c66SAsim Jamshed 		}
982*522d5c66SAsim Jamshed 	}
983*522d5c66SAsim Jamshed 	d->cur_rx_ring = ri;
984*522d5c66SAsim Jamshed 	return got;
985*522d5c66SAsim Jamshed }
986*522d5c66SAsim Jamshed 
987*522d5c66SAsim Jamshed static u_char *
nm_nextpkt(struct nm_desc * d,struct nm_pkthdr * hdr)988*522d5c66SAsim Jamshed nm_nextpkt(struct nm_desc *d, struct nm_pkthdr *hdr)
989*522d5c66SAsim Jamshed {
990*522d5c66SAsim Jamshed 	int ri = d->cur_rx_ring;
991*522d5c66SAsim Jamshed 
992*522d5c66SAsim Jamshed 	do {
993*522d5c66SAsim Jamshed 		/* compute current ring to use */
994*522d5c66SAsim Jamshed 		struct netmap_ring *ring = NETMAP_RXRING(d->nifp, ri);
995*522d5c66SAsim Jamshed 		if (!nm_ring_empty(ring)) {
996*522d5c66SAsim Jamshed 			u_int i = ring->cur;
997*522d5c66SAsim Jamshed 			u_int idx = ring->slot[i].buf_idx;
998*522d5c66SAsim Jamshed 			u_char *buf = (u_char *)NETMAP_BUF(ring, idx);
999*522d5c66SAsim Jamshed 
1000*522d5c66SAsim Jamshed 			// __builtin_prefetch(buf);
1001*522d5c66SAsim Jamshed 			hdr->ts = ring->ts;
1002*522d5c66SAsim Jamshed 			hdr->len = hdr->caplen = ring->slot[i].len;
1003*522d5c66SAsim Jamshed 			ring->cur = nm_ring_next(ring, i);
1004*522d5c66SAsim Jamshed 			/* we could postpone advancing head if we want
1005*522d5c66SAsim Jamshed 			 * to hold the buffer. This can be supported in
1006*522d5c66SAsim Jamshed 			 * the future.
1007*522d5c66SAsim Jamshed 			 */
1008*522d5c66SAsim Jamshed 			ring->head = ring->cur;
1009*522d5c66SAsim Jamshed 			d->cur_rx_ring = ri;
1010*522d5c66SAsim Jamshed 			return buf;
1011*522d5c66SAsim Jamshed 		}
1012*522d5c66SAsim Jamshed 		ri++;
1013*522d5c66SAsim Jamshed 		if (ri > d->last_rx_ring)
1014*522d5c66SAsim Jamshed 			ri = d->first_rx_ring;
1015*522d5c66SAsim Jamshed 	} while (ri != d->cur_rx_ring);
1016*522d5c66SAsim Jamshed 	return NULL; /* nothing found */
1017*522d5c66SAsim Jamshed }
1018*522d5c66SAsim Jamshed 
1019*522d5c66SAsim Jamshed #endif /* !HAVE_NETMAP_WITH_LIBS */
1020*522d5c66SAsim Jamshed 
1021*522d5c66SAsim Jamshed #endif /* NETMAP_WITH_LIBS */
1022*522d5c66SAsim Jamshed 
1023*522d5c66SAsim Jamshed #endif /* _NET_NETMAP_USER_H_ */
1024