xutils: Add common code to set up struct itimerval interval and value
[netsniff-ng.git] / pcap_mm.c
blob3d42888ce14cf27ad4061988e04a8f48ab362184
1 /*
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.
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 <stdbool.h>
15 #include <sys/mman.h>
17 #include "pcap.h"
18 #include "xio.h"
19 #include "xutils.h"
20 #include "built_in.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)
27 int ret;
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);
34 if (pos < 0)
35 panic("Cannot lseek pcap file!\n");
37 ret = write_or_die(fd, "", 1);
38 if (ret != 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);
46 if (ret < 0)
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);
60 fmemcpy(ptr_va_curr, &phdr->raw, hdrsize);
61 ptr_va_curr += hdrsize;
62 fmemcpy(ptr_va_curr, packet, len);
63 ptr_va_curr += len;
65 return hdrsize + len;
68 static ssize_t pcap_mm_read(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
69 uint8_t *packet, size_t len)
71 size_t hdrsize = pcap_get_hdr_length(phdr, type), hdrlen;
73 if (unlikely((off_t) (ptr_va_curr + hdrsize - ptr_va_start) > map_size))
74 return -EIO;
76 fmemcpy(&phdr->raw, ptr_va_curr, hdrsize);
77 ptr_va_curr += hdrsize;
78 hdrlen = pcap_get_length(phdr, type);
80 if (unlikely((off_t) (ptr_va_curr + hdrlen - ptr_va_start) > map_size))
81 return -EIO;
82 if (unlikely(hdrlen == 0 || hdrlen > len))
83 return -EINVAL;
85 fmemcpy(packet, ptr_va_curr, hdrlen);
86 ptr_va_curr += hdrlen;
88 return hdrsize + hdrlen;
91 static inline off_t ____get_map_size(bool jumbo)
93 int allocsz = jumbo ? 16 : 3;
95 return PAGE_ALIGN(sizeof(struct pcap_filehdr) + (PAGE_SIZE * allocsz) * 1024);
98 static void __pcap_mm_prepare_access_wr(int fd, bool jumbo)
100 int ret;
101 off_t pos;
102 struct stat sb;
104 map_size = ____get_map_size(jumbo);
106 ret = fstat(fd, &sb);
107 if (ret < 0)
108 panic("Cannot fstat pcap file!\n");
109 if (!S_ISREG (sb.st_mode))
110 panic("pcap dump file is not a regular file!\n");
112 pos = lseek(fd, map_size, SEEK_SET);
113 if (pos < 0)
114 panic("Cannot lseek pcap file!\n");
116 ret = write_or_die(fd, "", 1);
117 if (ret != 1)
118 panic("Cannot write file!\n");
120 ptr_va_start = mmap(0, map_size, PROT_WRITE, MAP_SHARED, fd, 0);
121 if (ptr_va_start == MAP_FAILED)
122 panic("mmap of file failed!");
123 ret = madvise(ptr_va_start, map_size, MADV_SEQUENTIAL);
124 if (ret < 0)
125 panic("Failed to give kernel mmap advise!\n");
127 ptr_va_curr = ptr_va_start + sizeof(struct pcap_filehdr);
130 static void __pcap_mm_prepare_access_rd(int fd)
132 int ret;
133 struct stat sb;
135 ret = fstat(fd, &sb);
136 if (ret < 0)
137 panic("Cannot fstat pcap file!\n");
138 if (!S_ISREG (sb.st_mode))
139 panic("pcap dump file is not a regular file!\n");
141 map_size = sb.st_size;
142 ptr_va_start = mmap(0, map_size, PROT_READ, MAP_SHARED | MAP_LOCKED, fd, 0);
143 if (ptr_va_start == MAP_FAILED)
144 panic("mmap of file failed!");
145 ret = madvise(ptr_va_start, map_size, MADV_SEQUENTIAL);
146 if (ret < 0)
147 panic("Failed to give kernel mmap advise!\n");
149 ptr_va_curr = ptr_va_start + sizeof(struct pcap_filehdr);
152 static int pcap_mm_prepare_access(int fd, enum pcap_mode mode, bool jumbo)
154 set_ioprio_be();
156 switch (mode) {
157 case PCAP_MODE_RD:
158 __pcap_mm_prepare_access_rd(fd);
159 break;
160 case PCAP_MODE_WR:
161 __pcap_mm_prepare_access_wr(fd, jumbo);
162 break;
163 default:
164 bug();
167 return 0;
170 static void pcap_mm_fsync(int fd)
172 msync(ptr_va_start, (off_t) (ptr_va_curr - ptr_va_start), MS_ASYNC);
175 static void pcap_mm_prepare_close(int fd, enum pcap_mode mode)
177 int ret;
179 ret = munmap(ptr_va_start, map_size);
180 if (ret < 0)
181 panic("Cannot unmap the pcap file!\n");
183 if (mode == PCAP_MODE_WR) {
184 ret = ftruncate(fd, (off_t) (ptr_va_curr - ptr_va_start));
185 if (ret)
186 panic("Cannot truncate the pcap file!\n");
190 const struct pcap_file_ops pcap_mm_ops = {
191 .pull_fhdr_pcap = pcap_generic_pull_fhdr,
192 .push_fhdr_pcap = pcap_generic_push_fhdr,
193 .prepare_access_pcap = pcap_mm_prepare_access,
194 .prepare_close_pcap = pcap_mm_prepare_close,
195 .read_pcap = pcap_mm_read,
196 .write_pcap = pcap_mm_write,
197 .fsync_pcap = pcap_mm_fsync,