xutils: break out promisc mode functions
[netsniff-ng.git] / pcap_sg.c
blobea4a709b6cb27ea19d3f354c4ba262e6a78f3b2a
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * Copyright 2011 - 2013 Daniel Borkmann.
4 * Subject to the GPL, version 2.
5 */
7 #include <stdio.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <fcntl.h>
11 #include <sys/uio.h>
12 #include <unistd.h>
14 #include "pcap_io.h"
15 #include "xmalloc.h"
16 #include "xutils.h"
17 #include "built_in.h"
18 #include "iosched.h"
19 #include "ioops.h"
21 static struct iovec iov[1024] __cacheline_aligned;
22 static off_t iov_off_rd = 0, iov_slot = 0;
24 static ssize_t pcap_sg_write(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
25 const uint8_t *packet, size_t len)
27 ssize_t ret, hdrsize = pcap_get_hdr_length(phdr, type);
29 if (unlikely(iov_slot == array_size(iov))) {
30 ret = writev(fd, iov, array_size(iov));
31 if (ret < 0)
32 panic("Writev I/O error: %s!\n", strerror(errno));
34 iov_slot = 0;
37 fmemcpy(iov[iov_slot].iov_base, &phdr->raw, hdrsize);
38 iov[iov_slot].iov_len = hdrsize;
40 fmemcpy(iov[iov_slot].iov_base + iov[iov_slot].iov_len, packet, len);
41 ret = (iov[iov_slot].iov_len += len);
43 iov_slot++;
44 return ret;
47 static ssize_t __pcap_sg_inter_iov_hdr_read(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
48 uint8_t *packet, size_t len, size_t hdrsize)
50 int ret;
51 size_t offset = 0;
52 ssize_t remainder;
54 offset = iov[iov_slot].iov_len - iov_off_rd;
55 remainder = hdrsize - offset;
56 if (remainder < 0)
57 remainder = 0;
59 bug_on(offset + remainder != hdrsize);
61 fmemcpy(&phdr->raw, iov[iov_slot].iov_base + iov_off_rd, offset);
62 iov_off_rd = 0;
63 iov_slot++;
65 if (iov_slot == array_size(iov)) {
66 iov_slot = 0;
67 ret = readv(fd, iov, array_size(iov));
68 if (unlikely(ret <= 0))
69 return -EIO;
72 fmemcpy(&phdr->raw + offset, iov[iov_slot].iov_base + iov_off_rd, remainder);
73 iov_off_rd += remainder;
75 return hdrsize;
78 static ssize_t __pcap_sg_inter_iov_data_read(int fd, uint8_t *packet, size_t len, size_t hdrlen)
80 int ret;
81 size_t offset = 0;
82 ssize_t remainder;
84 offset = iov[iov_slot].iov_len - iov_off_rd;
85 remainder = hdrlen - offset;
86 if (remainder < 0)
87 remainder = 0;
89 bug_on(offset + remainder != hdrlen);
91 fmemcpy(packet, iov[iov_slot].iov_base + iov_off_rd, offset);
92 iov_off_rd = 0;
93 iov_slot++;
95 if (iov_slot == array_size(iov)) {
96 iov_slot = 0;
97 ret = readv(fd, iov, array_size(iov));
98 if (unlikely(ret <= 0))
99 return -EIO;
102 fmemcpy(packet + offset, iov[iov_slot].iov_base + iov_off_rd, remainder);
103 iov_off_rd += remainder;
105 return hdrlen;
108 static ssize_t pcap_sg_read(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
109 uint8_t *packet, size_t len)
111 ssize_t ret = 0;
112 size_t hdrsize = pcap_get_hdr_length(phdr, type), hdrlen;
114 if (likely(iov[iov_slot].iov_len - iov_off_rd >= hdrsize)) {
115 fmemcpy(&phdr->raw, iov[iov_slot].iov_base + iov_off_rd, hdrsize);
116 iov_off_rd += hdrsize;
117 } else {
118 ret = __pcap_sg_inter_iov_hdr_read(fd, phdr, type, packet,
119 len, hdrsize);
120 if (unlikely(ret < 0))
121 return ret;
124 hdrlen = pcap_get_length(phdr, type);
125 if (unlikely(hdrlen == 0 || hdrlen > len))
126 return -EINVAL;
128 if (likely(iov[iov_slot].iov_len - iov_off_rd >= hdrlen)) {
129 fmemcpy(packet, iov[iov_slot].iov_base + iov_off_rd, hdrlen);
130 iov_off_rd += hdrlen;
131 } else {
132 ret = __pcap_sg_inter_iov_data_read(fd, packet, len, hdrlen);
133 if (unlikely(ret < 0))
134 return ret;
137 return hdrsize + hdrlen;
140 static void pcap_sg_fsync(int fd)
142 ssize_t ret = writev(fd, iov, iov_slot);
143 if (ret < 0)
144 panic("Writev I/O error: %s!\n", strerror(errno));
146 iov_slot = 0;
147 fdatasync(fd);
150 static void pcap_sg_init_once(void)
152 set_ioprio_rt();
155 static int pcap_sg_prepare_access(int fd, enum pcap_mode mode, bool jumbo)
157 int i, ret;
158 size_t len = 0;
160 iov_slot = 0;
161 len = jumbo ? (PAGE_SIZE * 16) /* 64k max */ :
162 (PAGE_SIZE * 3) /* 12k max */;
164 for (i = 0; i < array_size(iov); ++i) {
165 iov[i].iov_base = xzmalloc_aligned(len, 64);
166 iov[i].iov_len = len;
169 if (mode == PCAP_MODE_RD) {
170 ret = readv(fd, iov, array_size(iov));
171 if (ret <= 0)
172 return -EIO;
174 iov_off_rd = 0;
175 iov_slot = 0;
178 return 0;
181 static void pcap_sg_prepare_close(int fd, enum pcap_mode mode)
183 int i;
185 for (i = 0; i < array_size(iov); ++i)
186 xfree(iov[i].iov_base);
189 const struct pcap_file_ops pcap_sg_ops = {
190 .init_once_pcap = pcap_sg_init_once,
191 .pull_fhdr_pcap = pcap_generic_pull_fhdr,
192 .push_fhdr_pcap = pcap_generic_push_fhdr,
193 .prepare_access_pcap = pcap_sg_prepare_access,
194 .prepare_close_pcap = pcap_sg_prepare_close,
195 .read_pcap = pcap_sg_read,
196 .write_pcap = pcap_sg_write,
197 .fsync_pcap = pcap_sg_fsync,