docs: authors: add Doug as minor contr. (thanks)
[netsniff-ng.git] / src / pcap_mmap.c
blob6f76270049abc19e2b629a3e789da1317d6a4786
1 /*
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.
6 */
8 #define _GNU_SOURCE
9 #include <stdio.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <unistd.h>
14 #include <sys/mman.h>
16 #include "pcap.h"
17 #include "xio.h"
18 #include "xutils.h"
19 #include "locking.h"
20 #include "built_in.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)
38 ssize_t ret;
39 struct pcap_filehdr hdr;
41 ret = read(fd, &hdr, sizeof(hdr));
42 if (unlikely(ret != sizeof(hdr)))
43 return -EIO;
45 pcap_validate_header(&hdr);
47 *linktype = hdr.linktype;
49 return 0;
52 static int pcap_mmap_push_file_header(int fd, uint32_t linktype)
54 ssize_t ret;
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");
63 return -EIO;
66 return 0;
69 static int pcap_mmap_prepare_writing_pcap(int fd)
71 int ret;
72 off_t pos;
73 struct stat sb;
75 set_ioprio_be();
77 spinlock_lock(&lock);
79 map_size = get_map_size();
81 ret = fstat(fd, &sb);
82 if (ret < 0)
83 panic("Cannot fstat pcap file!\n");
84 if (!S_ISREG (sb.st_mode))
85 panic("pcap dump file is not a regular file!\n");
87 pos = lseek(fd, map_size, SEEK_SET);
88 if (pos < 0)
89 panic("Cannot lseek pcap file!\n");
91 ret = write_or_die(fd, "", 1);
92 if (ret != 1)
93 panic("Cannot write file!\n");
95 pstart = mmap(0, map_size, PROT_WRITE, MAP_SHARED
96 /*| MAP_HUGETLB*/, fd, 0);
97 if (pstart == MAP_FAILED)
98 panic("mmap of file failed!");
100 ret = madvise(pstart, map_size, MADV_SEQUENTIAL);
101 if (ret < 0)
102 panic("Failed to give kernel mmap advise!\n");
104 pcurr = pstart + sizeof(struct pcap_filehdr);
106 spinlock_unlock(&lock);
108 return 0;
111 static ssize_t pcap_mmap_write_pcap_pkt(int fd, struct pcap_pkthdr *hdr,
112 uint8_t *packet, size_t len)
114 int ret;
115 off_t pos;
117 spinlock_lock(&lock);
119 if ((off_t) (pcurr - pstart) + sizeof(*hdr) + len > map_size) {
120 off_t map_size_old = map_size;
121 off_t offset = (pcurr - pstart);
123 map_size = PAGE_ALIGN(map_size_old * 10 / 8);
125 pos = lseek(fd, map_size, SEEK_SET);
126 if (pos < 0)
127 panic("Cannot lseek pcap file!\n");
129 ret = write_or_die(fd, "", 1);
130 if (ret != 1)
131 panic("Cannot write file!\n");
133 pstart = mremap(pstart, map_size_old, map_size, MREMAP_MAYMOVE);
134 if (pstart == MAP_FAILED)
135 panic("mmap of file failed!");
137 ret = madvise(pstart, map_size, MADV_SEQUENTIAL);
138 if (ret < 0)
139 panic("Failed to give kernel mmap advise!\n");
141 pcurr = pstart + offset;
144 fmemcpy(pcurr, hdr, sizeof(*hdr));
145 pcurr += sizeof(*hdr);
147 fmemcpy(pcurr, packet, len);
148 pcurr += len;
150 spinlock_unlock(&lock);
152 return sizeof(*hdr) + len;
155 static int pcap_mmap_prepare_reading_pcap(int fd)
157 int ret;
158 struct stat sb;
160 set_ioprio_be();
162 spinlock_lock(&lock);
164 ret = fstat(fd, &sb);
165 if (ret < 0)
166 panic("Cannot fstat pcap file!\n");
168 if (!S_ISREG (sb.st_mode))
169 panic("pcap dump file is not a regular file!\n");
171 map_size = sb.st_size;
173 pstart = mmap(0, map_size, PROT_READ, MAP_SHARED | MAP_LOCKED
174 /*| MAP_HUGETLB*/, fd, 0);
175 if (pstart == MAP_FAILED)
176 panic("mmap of file failed!");
178 ret = madvise(pstart, map_size, MADV_SEQUENTIAL);
179 if (ret < 0)
180 panic("Failed to give kernel mmap advise!\n");
182 pcurr = pstart + sizeof(struct pcap_filehdr);
184 spinlock_unlock(&lock);
186 return 0;
189 static ssize_t pcap_mmap_read_pcap_pkt(int fd, struct pcap_pkthdr *hdr,
190 uint8_t *packet, size_t len)
192 ssize_t ret;
193 spinlock_lock(&lock);
195 if (unlikely((off_t) (pcurr + sizeof(*hdr) - pstart) > map_size)) {
196 spinlock_unlock(&lock);
197 return -ENOMEM;
200 fmemcpy(hdr, pcurr, sizeof(*hdr));
201 pcurr += sizeof(*hdr);
203 if (unlikely((off_t) (pcurr + hdr->caplen - pstart) > map_size)) {
204 ret = -ENOMEM;
205 goto out_err;
208 if (unlikely(hdr->caplen == 0 || hdr->caplen > len)) {
209 ret = -EINVAL; /* Bogus packet */
210 goto out_err;
213 fmemcpy(packet, pcurr, hdr->caplen);
214 pcurr += hdr->caplen;
216 spinlock_unlock(&lock);
218 return sizeof(*hdr) + hdr->caplen;
220 out_err:
221 spinlock_unlock(&lock);
222 return ret;
225 static void pcap_mmap_fsync_pcap(int fd)
227 spinlock_lock(&lock);
229 msync(pstart, (off_t) (pcurr - pstart), MS_ASYNC);
231 spinlock_unlock(&lock);
234 static void pcap_mmap_prepare_close_pcap(int fd, enum pcap_mode mode)
236 int ret;
238 spinlock_lock(&lock);
240 ret = munmap(pstart, map_size);
241 if (ret < 0)
242 panic("Cannot unmap the pcap file!\n");
244 if (mode == PCAP_MODE_WRITE) {
245 ret = ftruncate(fd, (off_t) (pcurr - pstart));
246 if (ret)
247 panic("Cannot truncate the pcap file!\n");
250 spinlock_unlock(&lock);
253 const struct pcap_file_ops pcap_mmap_ops = {
254 .name = "mmap",
255 .pull_file_header = pcap_mmap_pull_file_header,
256 .push_file_header = pcap_mmap_push_file_header,
257 .prepare_writing_pcap = pcap_mmap_prepare_writing_pcap,
258 .write_pcap_pkt = pcap_mmap_write_pcap_pkt,
259 .prepare_reading_pcap = pcap_mmap_prepare_reading_pcap,
260 .read_pcap_pkt = pcap_mmap_read_pcap_pkt,
261 .fsync_pcap = pcap_mmap_fsync_pcap,
262 .prepare_close_pcap = pcap_mmap_prepare_close_pcap,
265 int init_pcap_mmap(int jumbo_support)
267 spinlock_init(&lock);
269 jumbo_frames = jumbo_support;
271 return pcap_ops_group_register(&pcap_mmap_ops, PCAP_OPS_MMAP);
274 void cleanup_pcap_mmap(void)
276 spinlock_destroy(&lock);
278 pcap_ops_group_unregister(PCAP_OPS_MMAP);