2 * Copyright (C) 2009, 2010 Daniel Borkmann <daniel@netsniff-ng.org> and
3 * Emmanuel Roullit <emmanuel@netsniff-ng.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
34 #include <arpa/inet.h>
36 #include <sys/ioctl.h>
39 #include <sys/types.h>
41 #include <linux/if_ether.h>
42 #include <linux/if_packet.h>
43 #include <linux/filter.h>
45 #include <netsniff-ng/pcap.h>
46 #include <netsniff-ng/cursor.h>
47 #include <netsniff-ng/dump.h>
48 #include <netsniff-ng/macros.h>
49 #include <netsniff-ng/types.h>
50 #include <netsniff-ng/rx_ring.h>
51 #include <netsniff-ng/netdev.h>
52 #include <netsniff-ng/config.h>
53 #include <netsniff-ng/signal.h>
56 * destroy_virt_rx_ring - Destroys virtual RX_RING buffer
60 void destroy_virt_rx_ring(int sock
, ring_buff_t
* rb
)
64 memset(&(rb
->layout
), 0, sizeof(rb
->layout
));
65 setsockopt(sock
, SOL_PACKET
, PACKET_RX_RING
, (void *)&(rb
->layout
), sizeof(rb
->layout
));
77 * create_virt_rx_ring - Creates virtual RX_RING buffer
81 void create_virt_rx_ring(int sock
, ring_buff_t
* rb
, char *ifname
, unsigned int usize
)
89 nic_flags
= get_nic_flags(ifname
);
91 if ((nic_flags
& IFF_UP
) != IFF_UP
) {
92 warn("The interface %s is not up\n\n", ifname
);
96 if ((nic_flags
& IFF_RUNNING
) != IFF_RUNNING
) {
97 warn("The interface %s is not running\n\n", ifname
);
101 dev_speed
= get_device_bitrate_generic_fallback(ifname
);
102 memset(&(rb
->layout
), 0, sizeof(rb
->layout
));
104 /* max: getpagesize() << 11 for i386 */
105 rb
->layout
.tp_block_size
= getpagesize() << 2;
106 rb
->layout
.tp_frame_size
= TPACKET_ALIGNMENT
<< 7;
108 /* max: 15 for i386, old default: 1 << 13, now: approximated bandwidth size */
110 rb
->layout
.tp_block_nr
= ((dev_speed
* 1024 * 1024) / rb
->layout
.tp_block_size
);
112 rb
->layout
.tp_block_nr
= usize
/ (rb
->layout
.tp_block_size
/ 1024);
115 rb
->layout
.tp_frame_nr
= rb
->layout
.tp_block_size
/ rb
->layout
.tp_frame_size
* rb
->layout
.tp_block_nr
;
118 ret
= setsockopt(sock
, SOL_PACKET
, PACKET_RX_RING
, (void *)&(rb
->layout
), sizeof(rb
->layout
));
120 if (errno
== ENOMEM
&& rb
->layout
.tp_block_nr
> 1) {
121 rb
->layout
.tp_block_nr
>>= 1;
122 rb
->layout
.tp_frame_nr
= rb
->layout
.tp_block_size
/ rb
->layout
.tp_frame_size
* rb
->layout
.tp_block_nr
;
128 err("setsockopt: creation of rx_ring failed");
133 rb
->len
= rb
->layout
.tp_block_size
* rb
->layout
.tp_block_nr
;
135 info("%.2f MB allocated for receive ring \n", 1.f
* rb
->len
/ (1024 * 1024));
136 info(" [ %d blocks, %d frames ] \n", rb
->layout
.tp_block_nr
, rb
->layout
.tp_frame_nr
);
137 info(" [ %d frames per block ]\n", rb
->layout
.tp_block_size
/ rb
->layout
.tp_frame_size
);
138 info(" [ framesize: %d bytes, blocksize: %d bytes ]\n\n", rb
->layout
.tp_frame_size
, rb
->layout
.tp_block_size
);
142 * mmap_virt_rx_ring - Memory maps virtual RX_RING kernel buffer into userspace
143 * in order to avoid syscalls for fetching packet buffers
147 void mmap_virt_rx_ring(int sock
, ring_buff_t
* rb
)
151 rb
->buffer
= mmap(0, rb
->len
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, sock
, 0);
152 if (rb
->buffer
== MAP_FAILED
) {
153 err("mmap: cannot mmap the rx_ring");
155 destroy_virt_rx_ring(sock
, rb
);
162 * bind_dev_to_rx_ring - Binds virtual RX_RING to network device
164 * @ifindex: device number
167 void bind_dev_to_rx_ring(int sock
, int ifindex
, ring_buff_t
* rb
)
173 memset(&(rb
->params
), 0, sizeof(rb
->params
));
175 rb
->params
.sll_family
= AF_PACKET
;
176 rb
->params
.sll_protocol
= htons(ETH_P_ALL
);
177 rb
->params
.sll_ifindex
= ifindex
;
178 rb
->params
.sll_hatype
= 0;
179 rb
->params
.sll_halen
= 0;
180 rb
->params
.sll_pkttype
= 0;
182 ret
= bind(sock
, (struct sockaddr
*)&(rb
->params
), sizeof(struct sockaddr_ll
));
184 err("bind: cannot bind device");
192 * fetch_packets_and_print - Traverses RX_RING and prints content
194 * @pfd: file descriptor for polling
196 void fetch_packets(system_data_t
* sd
, int sock
, ring_buff_t
* rb
, struct pollfd
*pfd
)
206 info("--- Listening ---\n\n");
209 enable_print_progress_spinner();
211 if (sd
->pcap_fd
!= PCAP_NO_DUMP
) {
212 pcap_write_header(sd
->pcap_fd
, LINKTYPE_EN10MB
, 0, PCAP_DEFAULT_SNAPSHOT_LEN
);
214 if (!sd
->print_pkt
) {
216 pthread_create(&progress
, NULL
, print_progress_spinner_static
,
217 "Receive ring dumping ... |");
219 err("Cannot create thread");
225 /* This is our critical path ... */
226 while (likely(!sigint
)) {
227 while (mem_notify_user_for_rx(rb
->frames
[i
]) && likely(!sigint
)) {
228 struct frame_map
*fm
= rb
->frames
[i
].iov_base
;
229 ring_buff_bytes_t
*rbb
=
230 (ring_buff_bytes_t
*) ((uint8_t *) rb
->frames
[i
].iov_base
+ sizeof(*fm
) + sizeof(short));
232 /* Check if the user wants to have a specific
234 if (sd
->packet_type
!= PACKET_DONT_CARE
) {
235 if (fm
->s_ll
.sll_pkttype
!= sd
->packet_type
) {
236 goto __out_notify_kernel
;
240 if (sd
->pcap_fd
!= PCAP_NO_DUMP
) {
241 pcap_dump(sd
->pcap_fd
, &fm
->tp_h
, (struct ethhdr
*)rbb
);
242 print_progress_spinner_dynamic_trigger();
246 /* This path here slows us down ... well, but
247 the user wants to see what's going on */
248 sd
->print_pkt(rbb
, &fm
->tp_h
);
251 /* Pending singals will be delivered after netstat
253 hold_softirq(2, SIGUSR1
, SIGALRM
);
255 pthread_mutex_lock(&gs_loc_mutex
);
257 netstat
.per_sec
.frames
++;
258 netstat
.per_sec
.bytes
+= fm
->tp_h
.tp_len
;
260 netstat
.total
.frames
++;
261 netstat
.total
.bytes
+= fm
->tp_h
.tp_len
;
263 pthread_mutex_unlock(&gs_loc_mutex
);
264 restore_softirq(2, SIGUSR1
, SIGALRM
);
267 i
= (i
+ 1) % rb
->layout
.tp_frame_nr
;
270 /* This is very important, otherwise kernel starts
272 mem_notify_kernel_for_rx(&(fm
->tp_h
));
275 while ((ret
= poll(pfd
, 1, sd
->blocking_mode
)) <= 0) {
277 printf("Got SIGINT here!\n");
280 disable_print_progress_spinner();
286 if (ret
> 0 && (pfd
->revents
& (POLLHUP
| POLLRDHUP
| POLLERR
| POLLNVAL
))) {
287 if (pfd
->revents
& (POLLHUP
| POLLRDHUP
)) {
288 err("Hangup on socket occured");
291 disable_print_progress_spinner();
294 } else if (pfd
->revents
& POLLERR
) {
295 /* recv is more specififc on the error */
297 if (recv(sock
, &foo
, sizeof(foo
), MSG_PEEK
) != -1)
298 goto __out_grab_frame
; /* Hmm... no error */
299 if (errno
== ENETDOWN
) {
300 err("Interface went down");
302 err("Receive error");
306 disable_print_progress_spinner();
309 } else if (pfd
->revents
& POLLNVAL
) {
310 err("Invalid polling request on socket");
313 disable_print_progress_spinner();
320 /* Look-ahead if current frame is status kernel, otherwise we have
321 have incoming frames and poll spins / hangs all the time :( */
322 for (; ((struct tpacket_hdr
*)rb
->frames
[i
].iov_base
)->tp_status
323 != TP_STATUS_USER
; i
= (i
+ 1) % rb
->layout
.tp_frame_nr
)
325 /* Why this should be okay:
326 1) Current frame[i] is TP_STATUS_USER:
327 This is our original case that occurs without
329 2) Current frame[i] is not TP_STATUS_USER:
330 poll returns correctly with return value 1 (number of
331 file descriptors), so an event has occured which has
332 to be POLLIN since all error conditions have been
333 caught previously. Furthermore, during ring traversal
334 a frame that has been set to TP_STATUS_USER will be
335 given back to kernel on finish with TP_STATUS_KERNEL.
336 So, if we look ahead all skipped frames are not ready
337 for user access. Since the kernel decides to put
338 frames, which are 'behind' our pointer, into
339 TP_STATUS_USER we do one loop and return at the
340 correct position after passing the for loop again. If
341 we grab frame which are 'in front of' our pointer
342 we'll fetch them within the first for loop.
347 disable_print_progress_spinner();