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>
18 #include "opt_memcpy.h"
21 #define DEFAULT_SLOTS 1000
23 #define PAGE_SIZE (getpagesize())
24 #define PAGE_MASK (~(PAGE_SIZE - 1))
25 #define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
27 static struct spinlock lock
;
28 static off_t map_size
= 0;
29 static char *pstart
, *pcurr
;
30 static int jumbo_frames
= 0;
32 static inline off_t
get_map_size(void)
34 int allocsz
= jumbo_frames
? 16 : 3;
35 return PAGE_ALIGN(sizeof(struct pcap_filehdr
) +
36 (PAGE_SIZE
* allocsz
) * DEFAULT_SLOTS
);
39 static int pcap_mmap_pull_file_header(int fd
)
42 struct pcap_filehdr hdr
;
44 ret
= read(fd
, &hdr
, sizeof(hdr
));
45 if (unlikely(ret
!= sizeof(hdr
)))
47 pcap_validate_header_maybe_die(&hdr
);
52 static int pcap_mmap_push_file_header(int fd
)
55 struct pcap_filehdr hdr
;
57 memset(&hdr
, 0, sizeof(hdr
));
58 pcap_prepare_header(&hdr
, LINKTYPE_EN10MB
, 0,
59 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
)
75 map_size
= get_map_size();
78 panic("Cannot fstat pcap file!\n");
79 if (!S_ISREG (sb
.st_mode
))
80 panic("pcap dump file is not a regular file!\n");
81 /* Expand file buffer, so that mmap can be done. */
82 ret
= lseek(fd
, map_size
, SEEK_SET
);
84 panic("Cannot lseek pcap file!\n");
85 ret
= write_or_die(fd
, "", 1);
87 panic("Cannot write file!\n");
88 pstart
= mmap(0, map_size
, PROT_WRITE
, MAP_SHARED
89 /*| MAP_HUGETLB*/, fd
, 0);
90 if (pstart
== MAP_FAILED
)
91 panic("mmap of file failed!");
92 ret
= madvise(pstart
, map_size
, MADV_SEQUENTIAL
);
94 panic("Failed to give kernel mmap advise!\n");
95 pcurr
= pstart
+ sizeof(struct pcap_filehdr
);
96 spinlock_unlock(&lock
);
101 static ssize_t
pcap_mmap_write_pcap_pkt(int fd
, struct pcap_pkthdr
*hdr
,
102 uint8_t *packet
, size_t len
)
106 spinlock_lock(&lock
);
107 if ((off_t
) (pcurr
- pstart
) + sizeof(*hdr
) + len
> map_size
) {
108 off_t map_size_old
= map_size
;
109 off_t offset
= (pcurr
- pstart
);
110 map_size
= PAGE_ALIGN(map_size_old
* 3 / 2);
111 ret
= lseek(fd
, map_size
, SEEK_SET
);
113 panic("Cannot lseek pcap file!\n");
114 ret
= write_or_die(fd
, "", 1);
116 panic("Cannot write file!\n");
117 pstart
= mremap(pstart
, map_size_old
, map_size
, MREMAP_MAYMOVE
);
118 if (pstart
== MAP_FAILED
)
119 panic("mmap of file failed!");
120 ret
= madvise(pstart
, map_size
, MADV_SEQUENTIAL
);
122 panic("Failed to give kernel mmap advise!\n");
123 pcurr
= pstart
+ offset
;
125 __memcpy_small(pcurr
, hdr
, sizeof(*hdr
));
126 pcurr
+= sizeof(*hdr
);
127 __memcpy(pcurr
, packet
, len
);
129 spinlock_unlock(&lock
);
131 return sizeof(*hdr
) + len
;
134 static int pcap_mmap_prepare_reading_pcap(int fd
)
139 spinlock_lock(&lock
);
140 ret
= fstat(fd
, &sb
);
142 panic("Cannot fstat pcap file!\n");
143 if (!S_ISREG (sb
.st_mode
))
144 panic("pcap dump file is not a regular file!\n");
145 map_size
= sb
.st_size
;
146 pstart
= mmap(0, map_size
, PROT_READ
, MAP_SHARED
| MAP_LOCKED
147 /*| MAP_HUGETLB*/, fd
, 0);
148 if (pstart
== MAP_FAILED
)
149 panic("mmap of file failed!");
150 ret
= madvise(pstart
, map_size
, MADV_SEQUENTIAL
);
152 panic("Failed to give kernel mmap advise!\n");
153 pcurr
= pstart
+ sizeof(struct pcap_filehdr
);
154 spinlock_unlock(&lock
);
159 static ssize_t
pcap_mmap_read_pcap_pkt(int fd
, struct pcap_pkthdr
*hdr
,
160 uint8_t *packet
, size_t len
)
162 spinlock_lock(&lock
);
163 if (unlikely((off_t
) (pcurr
+ sizeof(*hdr
) - pstart
) > map_size
)) {
164 spinlock_unlock(&lock
);
167 __memcpy_small(hdr
, pcurr
, sizeof(*hdr
));
168 pcurr
+= sizeof(*hdr
);
169 if (unlikely((off_t
) (pcurr
+ hdr
->len
- pstart
) > map_size
)) {
170 spinlock_unlock(&lock
);
173 __memcpy(packet
, pcurr
, hdr
->len
);
175 spinlock_unlock(&lock
);
177 if (unlikely(hdr
->len
== 0))
178 return -EINVAL
; /* Bogus packet */
179 return sizeof(*hdr
) + hdr
->len
;
182 static void pcap_mmap_fsync_pcap(int fd
)
184 spinlock_lock(&lock
);
185 msync(pstart
, (off_t
) (pcurr
- pstart
), MS_ASYNC
);
186 spinlock_unlock(&lock
);
189 static void pcap_mmap_prepare_close_pcap(int fd
, enum pcap_mode mode
)
191 spinlock_lock(&lock
);
192 int ret
= munmap(pstart
, map_size
);
194 panic("Cannot unmap the pcap file!\n");
195 if (mode
== PCAP_MODE_WRITE
) {
196 ret
= ftruncate(fd
, (off_t
) (pcurr
- pstart
));
198 panic("Cannot truncate the pcap file!\n");
200 spinlock_unlock(&lock
);
203 struct pcap_file_ops pcap_mmap_ops __read_mostly
= {
205 .pull_file_header
= pcap_mmap_pull_file_header
,
206 .push_file_header
= pcap_mmap_push_file_header
,
207 .prepare_writing_pcap
= pcap_mmap_prepare_writing_pcap
,
208 .write_pcap_pkt
= pcap_mmap_write_pcap_pkt
,
209 .prepare_reading_pcap
= pcap_mmap_prepare_reading_pcap
,
210 .read_pcap_pkt
= pcap_mmap_read_pcap_pkt
,
211 .fsync_pcap
= pcap_mmap_fsync_pcap
,
212 .prepare_close_pcap
= pcap_mmap_prepare_close_pcap
,
215 int init_pcap_mmap(int jumbo_support
)
217 spinlock_init(&lock
);
218 jumbo_frames
= jumbo_support
;
219 return pcap_ops_group_register(&pcap_mmap_ops
, PCAP_OPS_MMAP
);
222 void cleanup_pcap_mmap(void)
224 spinlock_destroy(&lock
);
225 pcap_ops_group_unregister(PCAP_OPS_MMAP
);