2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2011 Daniel Borkmann.
17 #include "write_or_die.h"
18 #include "opt_memcpy.h"
24 static struct iovec iov
[IOVSIZ
];
25 static unsigned long c
= 0;
26 static struct spinlock lock
;
27 static ssize_t avail
, used
, iov_used
;
29 static int sg_pcap_pull_file_header(int fd
)
32 struct pcap_filehdr hdr
;
34 ret
= read(fd
, &hdr
, sizeof(hdr
));
35 if (unlikely(ret
!= sizeof(hdr
)))
37 pcap_validate_header_maybe_die(&hdr
);
42 static int sg_pcap_push_file_header(int fd
)
45 struct pcap_filehdr hdr
;
47 memset(&hdr
, 0, sizeof(hdr
));
48 pcap_prepare_header(&hdr
, LINKTYPE_EN10MB
, 0,
49 PCAP_DEFAULT_SNAPSHOT_LEN
);
50 ret
= write_or_die(fd
, &hdr
, sizeof(hdr
));
51 if (unlikely(ret
!= sizeof(hdr
))) {
52 whine("Failed to write pkt file header!\n");
59 static ssize_t
sg_pcap_write_pcap_pkt(int fd
, struct pcap_pkthdr
*hdr
,
60 uint8_t *packet
, size_t len
)
65 ret
= writev(fd
, iov
, IOVSIZ
);
67 panic("writev I/O error!\n");
71 __memcpy_small(iov
[c
].iov_base
, hdr
, sizeof(*hdr
));
72 iov
[c
].iov_len
+= sizeof(*hdr
);
73 __memcpy(iov
[c
].iov_base
+ iov
[c
].iov_len
, packet
, len
);
74 iov
[c
].iov_len
+= len
;
77 spinlock_unlock(&lock
);
81 static int sg_pcap_prepare_reading_pcap(int fd
)
84 avail
= readv(fd
, iov
, IOVSIZ
);
89 spinlock_unlock(&lock
);
93 static ssize_t
sg_pcap_read_pcap_pkt(int fd
, struct pcap_pkthdr
*hdr
,
94 uint8_t *packet
, size_t len
)
96 /* In contrast to writing, reading gets really ugly ... */
98 if (likely(avail
- used
>= sizeof(*hdr
) &&
99 iov
[c
].iov_len
- iov_used
>= sizeof(*hdr
))) {
100 __memcpy_small(hdr
, iov
[c
].iov_base
+ iov_used
, sizeof(*hdr
));
101 iov_used
+= sizeof(*hdr
);
102 used
+= sizeof(*hdr
);
104 size_t remainder
, offset
= 0;
105 if (avail
- used
< sizeof(*hdr
))
107 offset
= iov
[c
].iov_len
- iov_used
;
108 remainder
= sizeof(*hdr
) - offset
;
109 assert(offset
+ remainder
== sizeof(*hdr
));
110 __memcpy_small(hdr
, iov
[c
].iov_base
+ iov_used
, offset
);
115 /* We need to refetch! */
117 avail
= readv(fd
, iov
, IOVSIZ
);
122 /* Now we copy the remainder and go on with business ... */
123 __memcpy_small(hdr
, iov
[c
].iov_base
+ iov_used
, remainder
);
124 iov_used
+= remainder
;
127 if (likely(avail
- used
>= hdr
->len
&&
128 iov
[c
].iov_len
- iov_used
>= hdr
->len
)) {
129 __memcpy(packet
, iov
[c
].iov_base
+ iov_used
, hdr
->len
);
130 iov_used
+= hdr
->len
;
133 size_t remainder
, offset
= 0;
134 if (avail
- used
< hdr
->len
)
136 offset
= iov
[c
].iov_len
- iov_used
;
137 remainder
= hdr
->len
- offset
;
138 assert(offset
+ remainder
== hdr
->len
);
139 __memcpy(packet
, iov
[c
].iov_base
+ iov_used
, offset
);
144 /* We need to refetch! */
146 avail
= readv(fd
, iov
, IOVSIZ
);
151 /* Now we copy the remainder and go on with business ... */
152 __memcpy(packet
, iov
[c
].iov_base
+ iov_used
, remainder
);
153 iov_used
+= remainder
;
156 spinlock_unlock(&lock
);
157 if (unlikely(hdr
->len
== 0))
158 return -EINVAL
; /* Bogus packet */
159 return sizeof(*hdr
) + hdr
->len
;
162 static void sg_pcap_fsync_pcap(int fd
)
165 spinlock_lock(&lock
);
166 ret
= writev(fd
, iov
, c
);
168 panic("writev I/O error!\n");
170 spinlock_unlock(&lock
);
173 struct pcap_file_ops sg_pcap_ops __read_mostly
= {
174 .name
= "SCATTER/GATHER",
175 .pull_file_header
= sg_pcap_pull_file_header
,
176 .push_file_header
= sg_pcap_push_file_header
,
177 .write_pcap_pkt
= sg_pcap_write_pcap_pkt
,
178 .read_pcap_pkt
= sg_pcap_read_pcap_pkt
,
179 .prepare_reading_pcap
= sg_pcap_prepare_reading_pcap
,
180 .fsync_pcap
= sg_pcap_fsync_pcap
,
183 int init_sg_pcap(void)
187 memset(iov
, 0, sizeof(iov
));
188 for (i
= 0; i
< IOVSIZ
; ++i
) {
189 iov
[i
].iov_base
= xtlsf_malloc(ALLSIZ
);
190 iov
[i
].iov_len
= ALLSIZ
;
192 spinlock_init(&lock
);
193 return pcap_ops_group_register(&sg_pcap_ops
, PCAP_OPS_SG
);
196 void cleanup_sg_pcap(void)
199 spinlock_destroy(&lock
);
200 for (i
= 0; i
< IOVSIZ
; ++i
)
201 xtlsf_free(iov
[i
].iov_base
);
202 pcap_ops_group_unregister(PCAP_OPS_SG
);