2 * netsniff-ng - the packet sniffing beast
3 * Copyright 2009, 2010 Daniel Borkmann.
4 * Subject to the GPL, version 2.
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <arpa/inet.h>
15 #include <linux/if_ether.h>
22 void destroy_rx_ring(int sock
, struct ring
*ring
)
25 bool v3
= get_sockopt_tpacket(sock
) == TPACKET_V3
;
27 munmap(ring
->mm_space
, ring
->mm_len
);
32 /* In general, this is freed during close(2) anyway. */
36 fmemset(&ring
->layout
, 0, sizeof(ring
->layout
));
37 ret
= setsockopt(sock
, SOL_PACKET
, PACKET_RX_RING
, &ring
->layout
,
38 sizeof(ring
->layout
));
40 panic("Cannot destroy the RX_RING: %s!\n", strerror(errno
));
43 void setup_rx_ring_layout(int sock
, struct ring
*ring
, size_t size
,
44 bool jumbo_support
, bool v3
)
46 fmemset(&ring
->layout
, 0, sizeof(ring
->layout
));
48 ring
->layout
.tp_block_size
= (jumbo_support
?
49 RUNTIME_PAGE_SIZE
<< 4 :
50 RUNTIME_PAGE_SIZE
<< 2);
52 ring
->layout
.tp_frame_size
= (jumbo_support
?
53 TPACKET_ALIGNMENT
<< 12 :
54 TPACKET_ALIGNMENT
<< 7);
56 ring
->layout
.tp_block_nr
= size
/ ring
->layout
.tp_block_size
;
57 ring
->layout
.tp_frame_nr
= ring
->layout
.tp_block_size
/
58 ring
->layout
.tp_frame_size
*
59 ring
->layout
.tp_block_nr
;
61 /* Pass out, if this will ever change and we do crap on it! */
62 build_bug_on(offsetof(struct tpacket_req
, tp_frame_nr
) !=
63 offsetof(struct tpacket_req3
, tp_frame_nr
) &&
64 sizeof(struct tpacket_req
) !=
65 offsetof(struct tpacket_req3
, tp_retire_blk_tov
));
67 ring
->layout3
.tp_retire_blk_tov
= 100; /* 0: let kernel decide */
68 ring
->layout3
.tp_sizeof_priv
= 0;
69 ring
->layout3
.tp_feature_req_word
= 0;
71 set_sockopt_tpacket_v3(sock
);
73 set_sockopt_tpacket_v2(sock
);
76 ring_verify_layout(ring
);
79 void create_rx_ring(int sock
, struct ring
*ring
, bool verbose
)
82 bool v3
= get_sockopt_tpacket(sock
) == TPACKET_V3
;
85 ret
= setsockopt(sock
, SOL_PACKET
, PACKET_RX_RING
, &ring
->raw
,
86 v3
? sizeof(ring
->layout3
) : sizeof(ring
->layout
));
88 if (errno
== ENOMEM
&& ring
->layout
.tp_block_nr
> 1) {
89 ring
->layout
.tp_block_nr
>>= 1;
90 ring
->layout
.tp_frame_nr
= ring
->layout
.tp_block_size
/
91 ring
->layout
.tp_frame_size
*
92 ring
->layout
.tp_block_nr
;
96 panic("Cannot allocate RX_RING!\n");
98 ring
->mm_len
= (size_t) ring
->layout
.tp_block_size
* ring
->layout
.tp_block_nr
;
102 printf("RX,V2: %.2Lf MiB, %u Frames, each %u Byte allocated\n",
103 (long double) ring
->mm_len
/ (1 << 20),
104 ring
->layout
.tp_frame_nr
, ring
->layout
.tp_frame_size
);
106 printf("RX,V3: %.2Lf MiB, %u Blocks, each %u Byte allocated\n",
107 (long double) ring
->mm_len
/ (1 << 20),
108 ring
->layout
.tp_block_nr
, ring
->layout
.tp_block_size
);
113 void mmap_rx_ring(int sock
, struct ring
*ring
)
115 mmap_ring_generic(sock
, ring
);
118 void alloc_rx_ring_frames(int sock
, struct ring
*ring
)
122 bool v3
= get_sockopt_tpacket(sock
) == TPACKET_V3
;
125 num
= ring
->layout3
.tp_block_nr
;
126 size
= ring
->layout3
.tp_block_size
;
128 num
= ring
->layout
.tp_frame_nr
;
129 size
= ring
->layout
.tp_frame_size
;
132 alloc_ring_frames_generic(ring
, num
, size
);
135 void bind_rx_ring(int sock
, struct ring
*ring
, int ifindex
)
137 bind_ring_generic(sock
, ring
, ifindex
, false);
140 void sock_rx_net_stats(int sock
, unsigned long seen
)
143 bool v3
= get_sockopt_tpacket(sock
) == TPACKET_V3
;
145 struct tpacket_stats k2
;
146 struct tpacket_stats_v3 k3
;
148 socklen_t slen
= v3
? sizeof(stats
.k3
) : sizeof(stats
.k2
);
150 memset(&stats
, 0, sizeof(stats
));
151 ret
= getsockopt(sock
, SOL_PACKET
, PACKET_STATISTICS
, &stats
, &slen
);
153 uint64_t packets
= stats
.k3
.tp_packets
;
154 uint64_t drops
= stats
.k3
.tp_drops
;
156 printf("\r%12ld packets incoming (%ld unread on exit)\n",
157 v3
? seen
: packets
, v3
? packets
- seen
: 0);
158 printf("\r%12ld packets passed filter\n", packets
- drops
);
159 printf("\r%12ld packets failed filter (out of space)\n", drops
);
160 if (stats
.k3
.tp_packets
> 0)
161 printf("\r%12.4lf%% packet droprate\n",
162 (1.0 * drops
/ packets
) * 100.0);