proto_ipv4: don't trim length of pkt_buff
[netsniff-ng.git] / src / pcap_mmap.c
blob23a16279d0fc5a41b0a4c1844dee450cd7446c35
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;
33 static inline off_t get_map_size(void)
35 int allocsz = jumbo_frames ? 16 : 3;
37 return PAGE_ALIGN(sizeof(struct pcap_filehdr) +
38 (PAGE_SIZE * allocsz) * DEFAULT_SLOTS);
41 static int pcap_mmap_pull_file_header(int fd, uint32_t *linktype)
43 ssize_t ret;
44 struct pcap_filehdr hdr;
46 ret = read(fd, &hdr, sizeof(hdr));
47 if (unlikely(ret != sizeof(hdr)))
48 return -EIO;
50 pcap_validate_header(&hdr);
52 *linktype = hdr.linktype;
54 return 0;
57 static int pcap_mmap_push_file_header(int fd, uint32_t linktype)
59 ssize_t ret;
60 struct pcap_filehdr hdr;
62 fmemset(&hdr, 0, sizeof(hdr));
63 pcap_prepare_header(&hdr, linktype, 0, PCAP_DEFAULT_SNAPSHOT_LEN);
65 ret = write_or_die(fd, &hdr, sizeof(hdr));
66 if (unlikely(ret != sizeof(hdr))) {
67 whine("Failed to write pkt file header!\n");
68 return -EIO;
71 return 0;
74 static int pcap_mmap_prepare_writing_pcap(int fd)
76 int ret;
77 struct stat sb;
79 set_ioprio_be();
81 spinlock_lock(&lock);
83 map_size = get_map_size();
85 ret = fstat(fd, &sb);
86 if (ret < 0)
87 panic("Cannot fstat pcap file!\n");
88 if (!S_ISREG (sb.st_mode))
89 panic("pcap dump file is not a regular file!\n");
91 /* Expand file buffer, so that mmap can be done. */
92 ret = lseek(fd, map_size, SEEK_SET);
93 if (ret < 0)
94 panic("Cannot lseek pcap file!\n");
96 ret = write_or_die(fd, "", 1);
97 if (ret != 1)
98 panic("Cannot write file!\n");
100 pstart = mmap(0, map_size, PROT_WRITE, MAP_SHARED
101 /*| MAP_HUGETLB*/, fd, 0);
102 if (pstart == MAP_FAILED)
103 panic("mmap of file failed!");
105 ret = madvise(pstart, map_size, MADV_SEQUENTIAL);
106 if (ret < 0)
107 panic("Failed to give kernel mmap advise!\n");
109 pcurr = pstart + sizeof(struct pcap_filehdr);
111 spinlock_unlock(&lock);
113 return 0;
116 static ssize_t pcap_mmap_write_pcap_pkt(int fd, struct pcap_pkthdr *hdr,
117 uint8_t *packet, size_t len)
119 int ret;
121 spinlock_lock(&lock);
123 if ((off_t) (pcurr - pstart) + sizeof(*hdr) + len > map_size) {
124 off_t map_size_old = map_size;
125 off_t offset = (pcurr - pstart);
127 map_size = PAGE_ALIGN(map_size_old * 3 / 2);
129 ret = lseek(fd, map_size, SEEK_SET);
130 if (ret < 0)
131 panic("Cannot lseek pcap file!\n");
133 ret = write_or_die(fd, "", 1);
134 if (ret != 1)
135 panic("Cannot write file!\n");
137 pstart = mremap(pstart, map_size_old, map_size, MREMAP_MAYMOVE);
138 if (pstart == MAP_FAILED)
139 panic("mmap of file failed!");
141 ret = madvise(pstart, map_size, MADV_SEQUENTIAL);
142 if (ret < 0)
143 panic("Failed to give kernel mmap advise!\n");
145 pcurr = pstart + offset;
148 fmemcpy(pcurr, hdr, sizeof(*hdr));
149 pcurr += sizeof(*hdr);
151 fmemcpy(pcurr, packet, len);
152 pcurr += len;
154 spinlock_unlock(&lock);
156 return sizeof(*hdr) + len;
159 static int pcap_mmap_prepare_reading_pcap(int fd)
161 int ret;
162 struct stat sb;
164 set_ioprio_be();
166 spinlock_lock(&lock);
168 ret = fstat(fd, &sb);
169 if (ret < 0)
170 panic("Cannot fstat pcap file!\n");
172 if (!S_ISREG (sb.st_mode))
173 panic("pcap dump file is not a regular file!\n");
175 map_size = sb.st_size;
177 pstart = mmap(0, map_size, PROT_READ, MAP_SHARED | MAP_LOCKED
178 /*| MAP_HUGETLB*/, fd, 0);
179 if (pstart == MAP_FAILED)
180 panic("mmap of file failed!");
182 ret = madvise(pstart, map_size, MADV_SEQUENTIAL);
183 if (ret < 0)
184 panic("Failed to give kernel mmap advise!\n");
186 pcurr = pstart + sizeof(struct pcap_filehdr);
188 spinlock_unlock(&lock);
190 return 0;
193 static ssize_t pcap_mmap_read_pcap_pkt(int fd, struct pcap_pkthdr *hdr,
194 uint8_t *packet, size_t len)
196 ssize_t ret;
197 spinlock_lock(&lock);
199 if (unlikely((off_t) (pcurr + sizeof(*hdr) - pstart) > map_size)) {
200 spinlock_unlock(&lock);
201 return -ENOMEM;
204 fmemcpy(hdr, pcurr, sizeof(*hdr));
205 pcurr += sizeof(*hdr);
207 if (unlikely((off_t) (pcurr + hdr->caplen - pstart) > map_size)) {
208 ret = -ENOMEM;
209 goto out_err;
212 if (unlikely(hdr->caplen == 0 || hdr->caplen > len)) {
213 ret = -EINVAL; /* Bogus packet */
214 goto out_err;
217 fmemcpy(packet, pcurr, hdr->caplen);
218 pcurr += hdr->caplen;
220 spinlock_unlock(&lock);
222 return sizeof(*hdr) + hdr->caplen;
224 out_err:
225 spinlock_unlock(&lock);
226 return ret;
229 static void pcap_mmap_fsync_pcap(int fd)
231 spinlock_lock(&lock);
233 msync(pstart, (off_t) (pcurr - pstart), MS_ASYNC);
235 spinlock_unlock(&lock);
238 static void pcap_mmap_prepare_close_pcap(int fd, enum pcap_mode mode)
240 spinlock_lock(&lock);
242 int ret = munmap(pstart, map_size);
243 if (ret < 0)
244 panic("Cannot unmap the pcap file!\n");
246 if (mode == PCAP_MODE_WRITE) {
247 ret = ftruncate(fd, (off_t) (pcurr - pstart));
248 if (ret)
249 panic("Cannot truncate the pcap file!\n");
252 spinlock_unlock(&lock);
255 struct pcap_file_ops pcap_mmap_ops __read_mostly = {
256 .name = "mmap",
257 .pull_file_header = pcap_mmap_pull_file_header,
258 .push_file_header = pcap_mmap_push_file_header,
259 .prepare_writing_pcap = pcap_mmap_prepare_writing_pcap,
260 .write_pcap_pkt = pcap_mmap_write_pcap_pkt,
261 .prepare_reading_pcap = pcap_mmap_prepare_reading_pcap,
262 .read_pcap_pkt = pcap_mmap_read_pcap_pkt,
263 .fsync_pcap = pcap_mmap_fsync_pcap,
264 .prepare_close_pcap = pcap_mmap_prepare_close_pcap,
267 int init_pcap_mmap(int jumbo_support)
269 spinlock_init(&lock);
271 jumbo_frames = jumbo_support;
273 return pcap_ops_group_register(&pcap_mmap_ops, PCAP_OPS_MMAP);
276 void cleanup_pcap_mmap(void)
278 spinlock_destroy(&lock);
280 pcap_ops_group_unregister(PCAP_OPS_MMAP);