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.
10 #include <sys/types.h>
22 #define DEFAULT_SLOTS 1000
24 static struct spinlock lock
;
25 static off_t map_size
= 0;
26 static char *pstart
, *pcurr
;
27 static int jumbo_frames
= 0;
29 static inline off_t
get_map_size(void)
31 int allocsz
= jumbo_frames
? 16 : 3;
32 return PAGE_ALIGN(sizeof(struct pcap_filehdr
) +
33 (PAGE_SIZE
* allocsz
) * DEFAULT_SLOTS
);
36 static int pcap_mmap_pull_file_header(int fd
, uint32_t *linktype
)
39 struct pcap_filehdr hdr
;
41 ret
= read(fd
, &hdr
, sizeof(hdr
));
42 if (unlikely(ret
!= sizeof(hdr
)))
45 pcap_validate_header(&hdr
);
47 *linktype
= hdr
.linktype
;
52 static int pcap_mmap_push_file_header(int fd
, uint32_t linktype
)
55 struct pcap_filehdr hdr
;
57 fmemset(&hdr
, 0, sizeof(hdr
));
58 pcap_prepare_header(&hdr
, linktype
, 0, PCAP_DEFAULT_SNAPSHOT_LEN
);
60 ret
= write_or_die(fd
, &hdr
, sizeof(hdr
));
61 if (unlikely(ret
!= sizeof(hdr
))) {
62 whine("Failed to write pkt file header!\n");
69 static int pcap_mmap_prepare_writing_pcap(int fd
)
77 map_size
= get_map_size();
81 panic("Cannot fstat pcap file!\n");
82 if (!S_ISREG (sb
.st_mode
))
83 panic("pcap dump file is not a regular file!\n");
85 pos
= lseek(fd
, map_size
, SEEK_SET
);
87 panic("Cannot lseek pcap file!\n");
89 ret
= write_or_die(fd
, "", 1);
91 panic("Cannot write file!\n");
93 pstart
= mmap(0, map_size
, PROT_WRITE
, MAP_SHARED
94 /*| MAP_HUGETLB*/, fd
, 0);
95 if (pstart
== MAP_FAILED
)
96 panic("mmap of file failed!");
98 ret
= madvise(pstart
, map_size
, MADV_SEQUENTIAL
);
100 panic("Failed to give kernel mmap advise!\n");
102 pcurr
= pstart
+ sizeof(struct pcap_filehdr
);
104 spinlock_unlock(&lock
);
109 static ssize_t
pcap_mmap_write_pcap_pkt(int fd
, struct pcap_pkthdr
*hdr
,
110 uint8_t *packet
, size_t len
)
115 spinlock_lock(&lock
);
117 if ((off_t
) (pcurr
- pstart
) + sizeof(*hdr
) + len
> map_size
) {
118 off_t map_size_old
= map_size
;
119 off_t offset
= (pcurr
- pstart
);
121 map_size
= PAGE_ALIGN(map_size_old
* 10 / 8);
123 pos
= lseek(fd
, map_size
, SEEK_SET
);
125 panic("Cannot lseek pcap file!\n");
127 ret
= write_or_die(fd
, "", 1);
129 panic("Cannot write file!\n");
131 pstart
= mremap(pstart
, map_size_old
, map_size
, MREMAP_MAYMOVE
);
132 if (pstart
== MAP_FAILED
)
133 panic("mmap of file failed!");
135 ret
= madvise(pstart
, map_size
, MADV_SEQUENTIAL
);
137 panic("Failed to give kernel mmap advise!\n");
139 pcurr
= pstart
+ offset
;
142 fmemcpy(pcurr
, hdr
, sizeof(*hdr
));
143 pcurr
+= sizeof(*hdr
);
145 fmemcpy(pcurr
, packet
, len
);
148 spinlock_unlock(&lock
);
150 return sizeof(*hdr
) + len
;
153 static int pcap_mmap_prepare_reading_pcap(int fd
)
158 spinlock_lock(&lock
);
160 ret
= fstat(fd
, &sb
);
162 panic("Cannot fstat pcap file!\n");
164 if (!S_ISREG (sb
.st_mode
))
165 panic("pcap dump file is not a regular file!\n");
167 map_size
= sb
.st_size
;
169 pstart
= mmap(0, map_size
, PROT_READ
, MAP_SHARED
| MAP_LOCKED
170 /*| MAP_HUGETLB*/, fd
, 0);
171 if (pstart
== MAP_FAILED
)
172 panic("mmap of file failed!");
174 ret
= madvise(pstart
, map_size
, MADV_SEQUENTIAL
);
176 panic("Failed to give kernel mmap advise!\n");
178 pcurr
= pstart
+ sizeof(struct pcap_filehdr
);
180 spinlock_unlock(&lock
);
185 static ssize_t
pcap_mmap_read_pcap_pkt(int fd
, struct pcap_pkthdr
*hdr
,
186 uint8_t *packet
, size_t len
)
189 spinlock_lock(&lock
);
191 if (unlikely((off_t
) (pcurr
+ sizeof(*hdr
) - pstart
) > map_size
)) {
192 spinlock_unlock(&lock
);
196 fmemcpy(hdr
, pcurr
, sizeof(*hdr
));
197 pcurr
+= sizeof(*hdr
);
199 if (unlikely((off_t
) (pcurr
+ hdr
->caplen
- pstart
) > map_size
)) {
204 if (unlikely(hdr
->caplen
== 0 || hdr
->caplen
> len
)) {
205 ret
= -EINVAL
; /* Bogus packet */
209 fmemcpy(packet
, pcurr
, hdr
->caplen
);
210 pcurr
+= hdr
->caplen
;
212 spinlock_unlock(&lock
);
214 return sizeof(*hdr
) + hdr
->caplen
;
217 spinlock_unlock(&lock
);
221 static void pcap_mmap_fsync_pcap(int fd
)
223 spinlock_lock(&lock
);
225 msync(pstart
, (off_t
) (pcurr
- pstart
), MS_ASYNC
);
227 spinlock_unlock(&lock
);
230 static void pcap_mmap_prepare_close_pcap(int fd
, enum pcap_mode mode
)
234 spinlock_lock(&lock
);
236 ret
= munmap(pstart
, map_size
);
238 panic("Cannot unmap the pcap file!\n");
240 if (mode
== PCAP_MODE_WRITE
) {
241 ret
= ftruncate(fd
, (off_t
) (pcurr
- pstart
));
243 panic("Cannot truncate the pcap file!\n");
246 spinlock_unlock(&lock
);
249 const struct pcap_file_ops pcap_mmap_ops
= {
251 .pull_file_header
= pcap_mmap_pull_file_header
,
252 .push_file_header
= pcap_mmap_push_file_header
,
253 .prepare_writing_pcap
= pcap_mmap_prepare_writing_pcap
,
254 .write_pcap_pkt
= pcap_mmap_write_pcap_pkt
,
255 .prepare_reading_pcap
= pcap_mmap_prepare_reading_pcap
,
256 .read_pcap_pkt
= pcap_mmap_read_pcap_pkt
,
257 .fsync_pcap
= pcap_mmap_fsync_pcap
,
258 .prepare_close_pcap
= pcap_mmap_prepare_close_pcap
,
261 int init_pcap_mmap(int jumbo_support
)
263 spinlock_init(&lock
);
265 jumbo_frames
= jumbo_support
;
269 return pcap_ops_group_register(&pcap_mmap_ops
, PCAP_OPS_MMAP
);
272 void cleanup_pcap_mmap(void)
274 spinlock_destroy(&lock
);
276 pcap_ops_group_unregister(PCAP_OPS_MMAP
);