proto_icmpv6.h: intermediate state
[netsniff-ng.git] / src / pcap_mmap.c
blob76130dc2b153bee09cdee30f43adfdf621c11077
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 "xsys.h"
19 #include "locking.h"
20 #include "built_in.h"
22 #define DEFAULT_SLOTS 1000
24 #define PAGE_SIZE (getpagesize())
25 #define PAGE_MASK (~(PAGE_SIZE - 1))
26 #define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
28 static struct spinlock lock;
29 static off_t map_size = 0;
30 static char *pstart, *pcurr;
31 static int jumbo_frames = 0;
32 static int valid_header = 1;
34 static inline off_t get_map_size(void)
36 int allocsz = jumbo_frames ? 16 : 3;
38 return PAGE_ALIGN(sizeof(struct pcap_filehdr) +
39 (PAGE_SIZE * allocsz) * DEFAULT_SLOTS);
42 static int pcap_mmap_pull_file_header(int fd)
44 ssize_t ret;
45 struct pcap_filehdr hdr;
47 ret = read(fd, &hdr, sizeof(hdr));
48 if (unlikely(ret != sizeof(hdr)))
49 return -EIO;
51 ret = pcap_validate_header(&hdr);
52 if (ret < 0) {
53 lseek(fd, -sizeof(hdr), SEEK_CUR);
54 valid_header = 0;
57 return 0;
60 static int pcap_mmap_push_file_header(int fd)
62 ssize_t ret;
63 struct pcap_filehdr hdr;
65 fmemset(&hdr, 0, sizeof(hdr));
66 pcap_prepare_header(&hdr, LINKTYPE_EN10MB, 0,
67 PCAP_DEFAULT_SNAPSHOT_LEN);
69 ret = write_or_die(fd, &hdr, sizeof(hdr));
70 if (unlikely(ret != sizeof(hdr))) {
71 whine("Failed to write pkt file header!\n");
72 return -EIO;
75 return 0;
78 static int pcap_mmap_prepare_writing_pcap(int fd)
80 int ret;
81 struct stat sb;
83 set_ioprio_be();
85 spinlock_lock(&lock);
87 map_size = get_map_size();
89 ret = fstat(fd, &sb);
90 if (ret < 0)
91 panic("Cannot fstat pcap file!\n");
92 if (!S_ISREG (sb.st_mode))
93 panic("pcap dump file is not a regular file!\n");
95 /* Expand file buffer, so that mmap can be done. */
96 ret = lseek(fd, map_size, SEEK_SET);
97 if (ret < 0)
98 panic("Cannot lseek pcap file!\n");
100 ret = write_or_die(fd, "", 1);
101 if (ret != 1)
102 panic("Cannot write file!\n");
104 pstart = mmap(0, map_size, PROT_WRITE, MAP_SHARED
105 /*| MAP_HUGETLB*/, fd, 0);
106 if (pstart == MAP_FAILED)
107 panic("mmap of file failed!");
109 ret = madvise(pstart, map_size, MADV_SEQUENTIAL);
110 if (ret < 0)
111 panic("Failed to give kernel mmap advise!\n");
113 pcurr = pstart + sizeof(struct pcap_filehdr);
115 spinlock_unlock(&lock);
117 return 0;
120 static ssize_t pcap_mmap_write_pcap_pkt(int fd, struct pcap_pkthdr *hdr,
121 uint8_t *packet, size_t len)
123 int ret;
125 spinlock_lock(&lock);
127 if ((off_t) (pcurr - pstart) + sizeof(*hdr) + len > map_size) {
128 off_t map_size_old = map_size;
129 off_t offset = (pcurr - pstart);
131 map_size = PAGE_ALIGN(map_size_old * 3 / 2);
133 ret = lseek(fd, map_size, SEEK_SET);
134 if (ret < 0)
135 panic("Cannot lseek pcap file!\n");
137 ret = write_or_die(fd, "", 1);
138 if (ret != 1)
139 panic("Cannot write file!\n");
141 pstart = mremap(pstart, map_size_old, map_size, MREMAP_MAYMOVE);
142 if (pstart == MAP_FAILED)
143 panic("mmap of file failed!");
145 ret = madvise(pstart, map_size, MADV_SEQUENTIAL);
146 if (ret < 0)
147 panic("Failed to give kernel mmap advise!\n");
149 pcurr = pstart + offset;
152 fmemcpy(pcurr, hdr, sizeof(*hdr));
153 pcurr += sizeof(*hdr);
155 fmemcpy(pcurr, packet, len);
156 pcurr += len;
158 spinlock_unlock(&lock);
160 return sizeof(*hdr) + len;
163 static int pcap_mmap_prepare_reading_pcap(int fd)
165 int ret;
166 struct stat sb;
168 set_ioprio_be();
170 spinlock_lock(&lock);
172 ret = fstat(fd, &sb);
173 if (ret < 0)
174 panic("Cannot fstat pcap file!\n");
176 if (!S_ISREG (sb.st_mode))
177 panic("pcap dump file is not a regular file!\n");
179 map_size = sb.st_size;
181 pstart = mmap(0, map_size, PROT_READ, MAP_SHARED | MAP_LOCKED
182 /*| MAP_HUGETLB*/, fd, 0);
183 if (pstart == MAP_FAILED)
184 panic("mmap of file failed!");
186 ret = madvise(pstart, map_size, MADV_SEQUENTIAL);
187 if (ret < 0)
188 panic("Failed to give kernel mmap advise!\n");
190 pcurr = pstart + sizeof(struct pcap_filehdr) * valid_header;
192 spinlock_unlock(&lock);
194 return 0;
197 static ssize_t pcap_mmap_read_pcap_pkt(int fd, struct pcap_pkthdr *hdr,
198 uint8_t *packet, size_t len)
200 spinlock_lock(&lock);
202 if (unlikely((off_t) (pcurr + sizeof(*hdr) - pstart) > map_size)) {
203 spinlock_unlock(&lock);
204 return -ENOMEM;
207 fmemcpy(hdr, pcurr, sizeof(*hdr));
208 pcurr += sizeof(*hdr);
210 if (unlikely((off_t) (pcurr + hdr->len - pstart) > map_size)) {
211 spinlock_unlock(&lock);
212 return -ENOMEM;
215 fmemcpy(packet, pcurr, hdr->len);
216 pcurr += hdr->len;
218 spinlock_unlock(&lock);
220 if (unlikely(hdr->len == 0))
221 return -EINVAL; /* Bogus packet */
223 return sizeof(*hdr) + hdr->len;
226 static void pcap_mmap_fsync_pcap(int fd)
228 spinlock_lock(&lock);
230 msync(pstart, (off_t) (pcurr - pstart), MS_ASYNC);
232 spinlock_unlock(&lock);
235 static void pcap_mmap_prepare_close_pcap(int fd, enum pcap_mode mode)
237 spinlock_lock(&lock);
239 int ret = munmap(pstart, map_size);
240 if (ret < 0)
241 panic("Cannot unmap the pcap file!\n");
243 if (mode == PCAP_MODE_WRITE) {
244 ret = ftruncate(fd, (off_t) (pcurr - pstart));
245 if (ret)
246 panic("Cannot truncate the pcap file!\n");
249 spinlock_unlock(&lock);
252 struct pcap_file_ops pcap_mmap_ops __read_mostly = {
253 .name = "mmap",
254 .pull_file_header = pcap_mmap_pull_file_header,
255 .push_file_header = pcap_mmap_push_file_header,
256 .prepare_writing_pcap = pcap_mmap_prepare_writing_pcap,
257 .write_pcap_pkt = pcap_mmap_write_pcap_pkt,
258 .prepare_reading_pcap = pcap_mmap_prepare_reading_pcap,
259 .read_pcap_pkt = pcap_mmap_read_pcap_pkt,
260 .fsync_pcap = pcap_mmap_fsync_pcap,
261 .prepare_close_pcap = pcap_mmap_prepare_close_pcap,
264 int init_pcap_mmap(int jumbo_support)
266 spinlock_init(&lock);
268 jumbo_frames = jumbo_support;
270 return pcap_ops_group_register(&pcap_mmap_ops, PCAP_OPS_MMAP);
273 void cleanup_pcap_mmap(void)
275 spinlock_destroy(&lock);
277 pcap_ops_group_unregister(PCAP_OPS_MMAP);