2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2011 - 2013 Daniel Borkmann.
5 * Subject to the GPL, version 2.
10 #include <sys/types.h>
22 static size_t map_size
= 0;
23 static char *ptr_va_start
, *ptr_va_curr
;
25 static void __pcap_mmap_write_need_remap(int fd
)
28 off_t pos
, map_size_old
= map_size
;
29 off_t offset
= ptr_va_curr
- ptr_va_start
;
31 map_size
= PAGE_ALIGN(map_size_old
* 10 / 8);
33 pos
= lseek(fd
, map_size
, SEEK_SET
);
35 panic("Cannot lseek pcap file!\n");
37 ret
= write_or_die(fd
, "", 1);
39 panic("Cannot write file!\n");
41 ptr_va_start
= mremap(ptr_va_start
, map_size_old
, map_size
, MREMAP_MAYMOVE
);
42 if (ptr_va_start
== MAP_FAILED
)
43 panic("mmap of file failed!");
45 ret
= madvise(ptr_va_start
, map_size
, MADV_SEQUENTIAL
);
47 panic("Failed to give kernel mmap advise!\n");
49 ptr_va_curr
= ptr_va_start
+ offset
;
52 static ssize_t
pcap_mm_write(int fd
, pcap_pkthdr_t
*phdr
, enum pcap_type type
,
53 const uint8_t *packet
, size_t len
)
55 size_t hdrsize
= pcap_get_hdr_length(phdr
, type
);
57 if ((off_t
) (ptr_va_curr
- ptr_va_start
) + hdrsize
+ len
> map_size
)
58 __pcap_mmap_write_need_remap(fd
);
61 #define CASE_HDR_WRITE(what, __member__) \
63 fmemcpy(ptr_va_curr, &phdr->__member__, hdrsize); \
65 CASE_HDR_WRITE(DEFAULT
, ppo
);
66 CASE_HDR_WRITE(NSEC
, ppn
);
67 CASE_HDR_WRITE(KUZNETZOV
, ppk
);
68 CASE_HDR_WRITE(BORKMANN
, ppb
);
73 ptr_va_curr
+= hdrsize
;
74 fmemcpy(ptr_va_curr
, packet
, len
);
80 static ssize_t
pcap_mm_read(int fd
, pcap_pkthdr_t
*phdr
, enum pcap_type type
,
81 uint8_t *packet
, size_t len
)
83 size_t hdrsize
= pcap_get_hdr_length(phdr
, type
), hdrlen
;
85 if (unlikely((off_t
) (ptr_va_curr
+ hdrsize
- ptr_va_start
) > map_size
))
89 #define CASE_HDR_READ(what, __member__) \
91 fmemcpy(&phdr->__member__, ptr_va_curr, hdrsize); \
93 CASE_HDR_READ(DEFAULT
, ppo
);
94 CASE_HDR_READ(NSEC
, ppn
);
95 CASE_HDR_READ(KUZNETZOV
, ppk
);
96 CASE_HDR_READ(BORKMANN
, ppb
);
101 ptr_va_curr
+= hdrsize
;
102 hdrlen
= pcap_get_length(phdr
, type
);
104 if (unlikely((off_t
) (ptr_va_curr
+ hdrlen
- ptr_va_start
) > map_size
))
106 if (unlikely(hdrlen
== 0 || hdrlen
> len
))
109 fmemcpy(packet
, ptr_va_curr
, hdrlen
);
110 ptr_va_curr
+= hdrlen
;
112 return hdrsize
+ hdrlen
;
115 static inline off_t
____get_map_size(bool jumbo
)
117 int allocsz
= jumbo
? 16 : 3;
119 return PAGE_ALIGN(sizeof(struct pcap_filehdr
) + (PAGE_SIZE
* allocsz
) * 1024);
122 static void __pcap_mm_prepare_access_wr(int fd
, bool jumbo
)
128 map_size
= ____get_map_size(jumbo
);
130 ret
= fstat(fd
, &sb
);
132 panic("Cannot fstat pcap file!\n");
133 if (!S_ISREG (sb
.st_mode
))
134 panic("pcap dump file is not a regular file!\n");
136 pos
= lseek(fd
, map_size
, SEEK_SET
);
138 panic("Cannot lseek pcap file!\n");
140 ret
= write_or_die(fd
, "", 1);
142 panic("Cannot write file!\n");
144 ptr_va_start
= mmap(0, map_size
, PROT_WRITE
, MAP_SHARED
, fd
, 0);
145 if (ptr_va_start
== MAP_FAILED
)
146 panic("mmap of file failed!");
147 ret
= madvise(ptr_va_start
, map_size
, MADV_SEQUENTIAL
);
149 panic("Failed to give kernel mmap advise!\n");
151 ptr_va_curr
= ptr_va_start
+ sizeof(struct pcap_filehdr
);
154 static void __pcap_mm_prepare_access_rd(int fd
)
159 ret
= fstat(fd
, &sb
);
161 panic("Cannot fstat pcap file!\n");
162 if (!S_ISREG (sb
.st_mode
))
163 panic("pcap dump file is not a regular file!\n");
165 map_size
= sb
.st_size
;
166 ptr_va_start
= mmap(0, map_size
, PROT_READ
, MAP_SHARED
| MAP_LOCKED
, fd
, 0);
167 if (ptr_va_start
== MAP_FAILED
)
168 panic("mmap of file failed!");
169 ret
= madvise(ptr_va_start
, map_size
, MADV_SEQUENTIAL
);
171 panic("Failed to give kernel mmap advise!\n");
173 ptr_va_curr
= ptr_va_start
+ sizeof(struct pcap_filehdr
);
176 static int pcap_mm_prepare_access(int fd
, enum pcap_mode mode
, bool jumbo
)
182 __pcap_mm_prepare_access_rd(fd
);
185 __pcap_mm_prepare_access_wr(fd
, jumbo
);
194 static void pcap_mm_fsync(int fd
)
196 msync(ptr_va_start
, (off_t
) (ptr_va_curr
- ptr_va_start
), MS_ASYNC
);
199 static void pcap_mm_prepare_close(int fd
, enum pcap_mode mode
)
203 ret
= munmap(ptr_va_start
, map_size
);
205 panic("Cannot unmap the pcap file!\n");
207 if (mode
== PCAP_MODE_WR
) {
208 ret
= ftruncate(fd
, (off_t
) (ptr_va_curr
- ptr_va_start
));
210 panic("Cannot truncate the pcap file!\n");
214 const struct pcap_file_ops pcap_mm_ops
= {
215 .pull_fhdr_pcap
= pcap_generic_pull_fhdr
,
216 .push_fhdr_pcap
= pcap_generic_push_fhdr
,
217 .prepare_access_pcap
= pcap_mm_prepare_access
,
218 .prepare_close_pcap
= pcap_mm_prepare_close
,
219 .read_pcap
= pcap_mm_read
,
220 .write_pcap
= pcap_mm_write
,
221 .fsync_pcap
= pcap_mm_fsync
,