2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2011 Daniel Borkmann.
5 * Subject to the GPL, version 2.
23 #define ALLSIZ (PAGE_SIZE * 3)
24 #define ALLSIZ_2K (PAGE_SIZE * 3) // 12K max
25 #define ALLSIZ_JUMBO (PAGE_SIZE * 16) // 64K max
27 static struct iovec iov
[IOVSIZ
];
28 static unsigned long c
= 0;
29 static struct spinlock lock
;
30 static ssize_t iov_used
;
32 static int pcap_sg_pull_file_header(int fd
, uint32_t *linktype
)
35 struct pcap_filehdr hdr
;
37 ret
= read(fd
, &hdr
, sizeof(hdr
));
38 if (unlikely(ret
!= sizeof(hdr
)))
41 pcap_validate_header(&hdr
);
43 *linktype
= hdr
.linktype
;
48 static int pcap_sg_push_file_header(int fd
, uint32_t linktype
)
51 struct pcap_filehdr hdr
;
53 fmemset(&hdr
, 0, sizeof(hdr
));
54 pcap_prepare_header(&hdr
, linktype
, 0, PCAP_DEFAULT_SNAPSHOT_LEN
);
56 ret
= write_or_die(fd
, &hdr
, sizeof(hdr
));
57 if (unlikely(ret
!= sizeof(hdr
))) {
58 whine("Failed to write pkt file header!\n");
65 static int pcap_sg_prepare_writing_pcap(int fd
)
71 static ssize_t
pcap_sg_write_pcap_pkt(int fd
, struct pcap_pkthdr
*hdr
,
72 uint8_t *packet
, size_t len
)
78 if (unlikely(c
== IOVSIZ
)) {
79 ret
= writev(fd
, iov
, IOVSIZ
);
81 panic("writev I/O error!\n");
87 fmemcpy(iov
[c
].iov_base
, hdr
, sizeof(*hdr
));
89 iov
[c
].iov_len
+= sizeof(*hdr
);
90 fmemcpy(iov
[c
].iov_base
+ iov
[c
].iov_len
, packet
, len
);
92 iov
[c
].iov_len
+= len
;
97 spinlock_unlock(&lock
);
102 static int pcap_sg_prepare_reading_pcap(int fd
)
106 spinlock_lock(&lock
);
107 if (readv(fd
, iov
, IOVSIZ
) <= 0)
112 spinlock_unlock(&lock
);
117 static ssize_t
pcap_sg_read_pcap_pkt(int fd
, struct pcap_pkthdr
*hdr
,
118 uint8_t *packet
, size_t len
)
122 /* In contrast to writing, reading gets really ugly ... */
123 spinlock_lock(&lock
);
125 if (likely(iov
[c
].iov_len
- iov_used
>= sizeof(*hdr
))) {
126 fmemcpy(hdr
, iov
[c
].iov_base
+ iov_used
, sizeof(*hdr
));
127 iov_used
+= sizeof(*hdr
);
132 offset
= iov
[c
].iov_len
- iov_used
;
133 remainder
= sizeof(*hdr
) - offset
;
137 bug_on(offset
+ remainder
!= sizeof(*hdr
));
139 fmemcpy(hdr
, iov
[c
].iov_base
+ iov_used
, offset
);
145 /* We need to refetch! */
147 if (readv(fd
, iov
, IOVSIZ
) <= 0) {
153 /* Now we copy the remainder and go on with business ... */
154 fmemcpy((uint8_t *) hdr
+ offset
,
155 iov
[c
].iov_base
+ iov_used
, remainder
);
156 iov_used
+= remainder
;
159 /* header read completed */
161 if (unlikely(hdr
->caplen
== 0 || hdr
->caplen
> len
)) {
162 ret
= -EINVAL
; /* Bogus packet */
166 /* now we read data ... */
168 if (likely(iov
[c
].iov_len
- iov_used
>= hdr
->caplen
)) {
169 fmemcpy(packet
, iov
[c
].iov_base
+ iov_used
, hdr
->caplen
);
170 iov_used
+= hdr
->caplen
;
175 offset
= iov
[c
].iov_len
- iov_used
;
176 remainder
= hdr
->caplen
- offset
;
180 bug_on(offset
+ remainder
!= hdr
->caplen
);
182 fmemcpy(packet
, iov
[c
].iov_base
+ iov_used
, offset
);
188 /* We need to refetch! */
190 if (readv(fd
, iov
, IOVSIZ
) <= 0) {
196 /* Now we copy the remainder and go on with business ... */
197 fmemcpy(packet
+ offset
, iov
[c
].iov_base
+ iov_used
, remainder
);
198 iov_used
+= remainder
;
201 spinlock_unlock(&lock
);
203 return sizeof(*hdr
) + hdr
->caplen
;
206 spinlock_unlock(&lock
);
210 static void pcap_sg_fsync_pcap(int fd
)
214 spinlock_lock(&lock
);
215 ret
= writev(fd
, iov
, c
);
217 panic("writev I/O error!\n");
222 spinlock_unlock(&lock
);
225 const struct pcap_file_ops pcap_sg_ops
= {
226 .name
= "scatter-gather",
227 .pull_file_header
= pcap_sg_pull_file_header
,
228 .push_file_header
= pcap_sg_push_file_header
,
229 .write_pcap_pkt
= pcap_sg_write_pcap_pkt
,
230 .prepare_reading_pcap
= pcap_sg_prepare_reading_pcap
,
231 .prepare_writing_pcap
= pcap_sg_prepare_writing_pcap
,
232 .read_pcap_pkt
= pcap_sg_read_pcap_pkt
,
233 .fsync_pcap
= pcap_sg_fsync_pcap
,
236 int init_pcap_sg(int jumbo_support
)
243 fmemset(iov
, 0, sizeof(iov
));
246 allocsz
= ALLSIZ_JUMBO
;
250 for (i
= 0; i
< IOVSIZ
; ++i
) {
251 iov
[i
].iov_base
= xzmalloc_aligned(allocsz
, 64);
252 iov
[i
].iov_len
= allocsz
;
255 spinlock_init(&lock
);
257 return pcap_ops_group_register(&pcap_sg_ops
, PCAP_OPS_SG
);
260 void cleanup_pcap_sg(void)
264 spinlock_destroy(&lock
);
266 for (i
= 0; i
< IOVSIZ
; ++i
)
267 xfree(iov
[i
].iov_base
);
269 pcap_ops_group_unregister(PCAP_OPS_SG
);