]>
Commit | Line | Data |
---|---|---|
c45d8985 EL |
1 | /* Copyright (C) 2011 Open Information Security Foundation |
2 | * | |
3 | * You can copy, redistribute or modify this Program under the terms of | |
4 | * the GNU General Public License version 2 as published by the Free | |
5 | * Software Foundation. | |
6 | * | |
7 | * This program is distributed in the hope that it will be useful, | |
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 | * GNU General Public License for more details. | |
11 | * | |
12 | * You should have received a copy of the GNU General Public License | |
13 | * version 2 along with this program; if not, write to the Free Software | |
14 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
15 | * 02110-1301, USA. | |
16 | */ | |
17 | ||
18 | /** | |
19 | * \file | |
20 | * | |
21 | * \author Eric Leblond <eric@regit.org> | |
22 | * | |
23 | * AF_PACKET socket acquisition support | |
24 | * | |
25 | * Fanouts socket from David Miller: | |
26 | * we need to support the split of flow in different socket | |
27 | * option: | |
e80b30c0 EL |
28 | * - packet_fanout type |
29 | * - fanout ID ?? seems it could be useful | |
30 | * - protocol is the IEEE 802.3 protocol number in network order (filtering | |
31 | * is great) | |
32 | * - runmode -> family of threads in parallel (acccount) | |
33 | * - add a new ratio or threads number (overwritten by cpu_affinity) | |
34 | * - add af_max_read_packets for batched reading | |
c45d8985 EL |
35 | * |
36 | * architecture | |
37 | * loop with read | |
38 | * code needed for iface name to int mapping | |
39 | * socket opening | |
40 | * socket call | |
41 | * bind | |
42 | * must switch to promiscous mode -> use PACKET_MR_PROMISC socket option | |
43 | * | |
e80b30c0 EL |
44 | * \todo watch other interface event to detect suppression of the monitored |
45 | * interface | |
c45d8985 EL |
46 | */ |
47 | ||
48 | #include "suricata-common.h" | |
e80b30c0 | 49 | #include "config.h" |
c45d8985 EL |
50 | #include "suricata.h" |
51 | #include "decode.h" | |
52 | #include "packet-queue.h" | |
53 | #include "threads.h" | |
54 | #include "threadvars.h" | |
55 | #include "tm-queuehandlers.h" | |
56 | #include "tm-modules.h" | |
57 | #include "tm-threads.h" | |
58 | #include "tm-threads-common.h" | |
59 | #include "conf.h" | |
60 | #include "util-debug.h" | |
51eb9605 | 61 | #include "util-device.h" |
c45d8985 EL |
62 | #include "util-error.h" |
63 | #include "util-privs.h" | |
e80b30c0 | 64 | #include "util-optimize.h" |
51eb9605 | 65 | #include "util-checksum.h" |
c45d8985 EL |
66 | #include "tmqh-packetpool.h" |
67 | #include "source-af-packet.h" | |
34b3f194 | 68 | #include "runmodes.h" |
c45d8985 | 69 | |
e80b30c0 | 70 | #ifdef HAVE_AF_PACKET |
2bc0be6e | 71 | #include <sys/ioctl.h> |
c45d8985 EL |
72 | #include <linux/if_ether.h> |
73 | #include <linux/if_packet.h> | |
74 | #include <linux/if_arp.h> | |
e80b30c0 | 75 | #endif |
c45d8985 | 76 | |
49b7b00f EL |
77 | #include <sys/mman.h> |
78 | ||
c45d8985 EL |
79 | extern uint8_t suricata_ctl_flags; |
80 | extern int max_pending_packets; | |
81 | ||
e80b30c0 EL |
82 | #ifndef HAVE_AF_PACKET |
83 | ||
84 | TmEcode NoAFPSupportExit(ThreadVars *, void *, void **); | |
85 | ||
86 | void TmModuleReceiveAFPRegister (void) { | |
87 | tmm_modules[TMM_RECEIVEAFP].name = "ReceiveAFP"; | |
88 | tmm_modules[TMM_RECEIVEAFP].ThreadInit = NoAFPSupportExit; | |
89 | tmm_modules[TMM_RECEIVEAFP].Func = NULL; | |
90 | tmm_modules[TMM_RECEIVEAFP].ThreadExitPrintStats = NULL; | |
91 | tmm_modules[TMM_RECEIVEAFP].ThreadDeinit = NULL; | |
92 | tmm_modules[TMM_RECEIVEAFP].RegisterTests = NULL; | |
93 | tmm_modules[TMM_RECEIVEAFP].cap_flags = 0; | |
3f1c4efc | 94 | tmm_modules[TMM_RECEIVEAFP].flags = TM_FLAG_RECEIVE_TM; |
e80b30c0 EL |
95 | } |
96 | ||
97 | /** | |
98 | * \brief Registration Function for DecodeAFP. | |
99 | * \todo Unit tests are needed for this module. | |
100 | */ | |
101 | void TmModuleDecodeAFPRegister (void) { | |
102 | tmm_modules[TMM_DECODEAFP].name = "DecodeAFP"; | |
103 | tmm_modules[TMM_DECODEAFP].ThreadInit = NoAFPSupportExit; | |
104 | tmm_modules[TMM_DECODEAFP].Func = NULL; | |
105 | tmm_modules[TMM_DECODEAFP].ThreadExitPrintStats = NULL; | |
106 | tmm_modules[TMM_DECODEAFP].ThreadDeinit = NULL; | |
107 | tmm_modules[TMM_DECODEAFP].RegisterTests = NULL; | |
108 | tmm_modules[TMM_DECODEAFP].cap_flags = 0; | |
bc6cf438 | 109 | tmm_modules[TMM_DECODEAFP].flags = TM_FLAG_DECODE_TM; |
e80b30c0 EL |
110 | } |
111 | ||
112 | /** | |
113 | * \brief this function prints an error message and exits. | |
114 | */ | |
115 | TmEcode NoAFPSupportExit(ThreadVars *tv, void *initdata, void **data) | |
116 | { | |
117 | SCLogError(SC_ERR_NO_AF_PACKET,"Error creating thread %s: you do not have " | |
118 | "support for AF_PACKET enabled, on Linux host please recompile " | |
119 | "with --enable-af-packet", tv->name); | |
120 | exit(EXIT_FAILURE); | |
121 | } | |
122 | ||
123 | #else /* We have AF_PACKET support */ | |
124 | ||
c45d8985 EL |
125 | #define AFP_IFACE_NAME_LENGTH 48 |
126 | ||
127 | #define AFP_STATE_DOWN 0 | |
128 | #define AFP_STATE_UP 1 | |
129 | ||
130 | #define AFP_RECONNECT_TIMEOUT 500000 | |
131 | ||
132 | #define POLL_TIMEOUT 100 | |
133 | ||
62e63e3f EL |
134 | enum { |
135 | AFP_READ_OK, | |
136 | AFP_READ_FAILURE, | |
137 | AFP_FAILURE, | |
138 | }; | |
139 | ||
49b7b00f EL |
140 | union thdr { |
141 | struct tpacket2_hdr *h2; | |
142 | void *raw; | |
143 | }; | |
144 | ||
c45d8985 EL |
145 | /** |
146 | * \brief Structure to hold thread specific variables. | |
147 | */ | |
148 | typedef struct AFPThreadVars_ | |
149 | { | |
150 | /* thread specific socket */ | |
151 | int socket; | |
152 | /* handle state */ | |
153 | unsigned char afp_state; | |
c45d8985 EL |
154 | |
155 | /* data link type for the thread */ | |
156 | int datalink; | |
157 | int cooked; | |
158 | ||
159 | /* counters */ | |
160 | uint32_t pkts; | |
161 | uint64_t bytes; | |
162 | uint32_t errs; | |
163 | ||
ff6365dd EL |
164 | ThreadVars *tv; |
165 | TmSlot *slot; | |
166 | ||
167 | uint8_t *data; /** Per function and thread data */ | |
168 | int datalen; /** Length of per function and thread data */ | |
169 | ||
170 | char iface[AFP_IFACE_NAME_LENGTH]; | |
51eb9605 EL |
171 | LiveDevice *livedev; |
172 | ||
e80b30c0 EL |
173 | /* socket buffer size */ |
174 | int buffer_size; | |
df7dbe36 | 175 | int promisc; |
6062e00c | 176 | ChecksumValidationMode checksum_mode; |
e80b30c0 | 177 | |
49b7b00f EL |
178 | int flags; |
179 | ||
e80b30c0 EL |
180 | int cluster_id; |
181 | int cluster_type; | |
c45d8985 | 182 | |
fbca1a4e EL |
183 | int threads; |
184 | ||
49b7b00f EL |
185 | struct tpacket_req req; |
186 | unsigned int tp_hdrlen; | |
187 | unsigned int ring_buflen; | |
188 | char *ring_buf; | |
189 | char *frame_buf; | |
190 | unsigned int frame_offset; | |
c45d8985 EL |
191 | } AFPThreadVars; |
192 | ||
193 | TmEcode ReceiveAFP(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); | |
194 | TmEcode ReceiveAFPThreadInit(ThreadVars *, void *, void **); | |
195 | void ReceiveAFPThreadExitStats(ThreadVars *, void *); | |
196 | TmEcode ReceiveAFPThreadDeinit(ThreadVars *, void *); | |
e80b30c0 | 197 | TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot); |
c45d8985 EL |
198 | |
199 | TmEcode DecodeAFPThreadInit(ThreadVars *, void *, void **); | |
200 | TmEcode DecodeAFP(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); | |
201 | ||
202 | /** | |
203 | * \brief Registration Function for RecieveAFP. | |
204 | * \todo Unit tests are needed for this module. | |
205 | */ | |
206 | void TmModuleReceiveAFPRegister (void) { | |
207 | tmm_modules[TMM_RECEIVEAFP].name = "ReceiveAFP"; | |
208 | tmm_modules[TMM_RECEIVEAFP].ThreadInit = ReceiveAFPThreadInit; | |
ff6365dd | 209 | tmm_modules[TMM_RECEIVEAFP].Func = NULL; |
e80b30c0 | 210 | tmm_modules[TMM_RECEIVEAFP].PktAcqLoop = ReceiveAFPLoop; |
c45d8985 EL |
211 | tmm_modules[TMM_RECEIVEAFP].ThreadExitPrintStats = ReceiveAFPThreadExitStats; |
212 | tmm_modules[TMM_RECEIVEAFP].ThreadDeinit = NULL; | |
213 | tmm_modules[TMM_RECEIVEAFP].RegisterTests = NULL; | |
214 | tmm_modules[TMM_RECEIVEAFP].cap_flags = SC_CAP_NET_RAW; | |
cd4705e6 | 215 | tmm_modules[TMM_RECEIVEAFP].flags = TM_FLAG_RECEIVE_TM; |
c45d8985 EL |
216 | } |
217 | ||
218 | /** | |
219 | * \brief Registration Function for DecodeAFP. | |
220 | * \todo Unit tests are needed for this module. | |
221 | */ | |
222 | void TmModuleDecodeAFPRegister (void) { | |
223 | tmm_modules[TMM_DECODEAFP].name = "DecodeAFP"; | |
224 | tmm_modules[TMM_DECODEAFP].ThreadInit = DecodeAFPThreadInit; | |
225 | tmm_modules[TMM_DECODEAFP].Func = DecodeAFP; | |
226 | tmm_modules[TMM_DECODEAFP].ThreadExitPrintStats = NULL; | |
227 | tmm_modules[TMM_DECODEAFP].ThreadDeinit = NULL; | |
228 | tmm_modules[TMM_DECODEAFP].RegisterTests = NULL; | |
229 | tmm_modules[TMM_DECODEAFP].cap_flags = 0; | |
bc6cf438 | 230 | tmm_modules[TMM_DECODEAFP].flags = TM_FLAG_DECODE_TM; |
c45d8985 EL |
231 | } |
232 | ||
e80b30c0 EL |
233 | static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose); |
234 | ||
c45d8985 EL |
235 | |
236 | /** | |
237 | * \brief AF packet read function. | |
238 | * | |
239 | * This function fills | |
240 | * From here the packets are picked up by the DecodeAFP thread. | |
241 | * | |
242 | * \param user pointer to AFPThreadVars | |
243 | * \retval TM_ECODE_FAILED on failure and TM_ECODE_OK on success | |
244 | */ | |
62e63e3f | 245 | int AFPRead(AFPThreadVars *ptv) |
c45d8985 EL |
246 | { |
247 | Packet *p = NULL; | |
248 | /* XXX should try to use read that get directly to packet */ | |
c45d8985 EL |
249 | int offset = 0; |
250 | int caplen; | |
251 | struct sockaddr_ll from; | |
252 | struct iovec iov; | |
253 | struct msghdr msg; | |
c45d8985 EL |
254 | struct cmsghdr *cmsg; |
255 | union { | |
256 | struct cmsghdr cmsg; | |
257 | char buf[CMSG_SPACE(sizeof(struct tpacket_auxdata))]; | |
258 | } cmsg_buf; | |
c45d8985 EL |
259 | |
260 | msg.msg_name = &from; | |
261 | msg.msg_namelen = sizeof(from); | |
262 | msg.msg_iov = &iov; | |
263 | msg.msg_iovlen = 1; | |
c45d8985 EL |
264 | msg.msg_control = &cmsg_buf; |
265 | msg.msg_controllen = sizeof(cmsg_buf); | |
c45d8985 EL |
266 | msg.msg_flags = 0; |
267 | ||
268 | if (ptv->cooked) | |
269 | offset = SLL_HEADER_LEN; | |
270 | else | |
271 | offset = 0; | |
e80b30c0 EL |
272 | iov.iov_len = ptv->datalen - offset; |
273 | iov.iov_base = ptv->data + offset; | |
c45d8985 EL |
274 | |
275 | caplen = recvmsg(ptv->socket, &msg, MSG_TRUNC); | |
276 | ||
277 | if (caplen < 0) { | |
278 | SCLogWarning(SC_ERR_AFP_READ, "recvmsg failed with error code %" PRId32, | |
279 | errno); | |
62e63e3f | 280 | SCReturnInt(AFP_READ_FAILURE); |
c45d8985 | 281 | } |
ff6365dd EL |
282 | |
283 | p = PacketGetFromQueueOrAlloc(); | |
c45d8985 | 284 | if (p == NULL) { |
62e63e3f | 285 | SCReturnInt(AFP_FAILURE); |
c45d8985 EL |
286 | } |
287 | ||
288 | /* get timestamp of packet via ioctl */ | |
289 | if (ioctl(ptv->socket, SIOCGSTAMP, &p->ts) == -1) { | |
290 | SCLogWarning(SC_ERR_AFP_READ, "recvmsg failed with error code %" PRId32, | |
291 | errno); | |
292 | TmqhOutputPacketpool(ptv->tv, p); | |
62e63e3f | 293 | SCReturnInt(AFP_READ_FAILURE); |
c45d8985 EL |
294 | } |
295 | ||
296 | ptv->pkts++; | |
297 | ptv->bytes += caplen + offset; | |
51eb9605 EL |
298 | SC_ATOMIC_ADD(ptv->livedev->pkts, 1); |
299 | p->livedev = ptv->livedev; | |
c45d8985 EL |
300 | |
301 | /* add forged header */ | |
302 | if (ptv->cooked) { | |
e80b30c0 | 303 | SllHdr * hdrp = (SllHdr *)ptv->data; |
c45d8985 EL |
304 | /* XXX this is minimalist, but this seems enough */ |
305 | hdrp->sll_protocol = from.sll_protocol; | |
306 | } | |
307 | ||
308 | p->datalink = ptv->datalink; | |
309 | SET_PKT_LEN(p, caplen + offset); | |
e80b30c0 | 310 | if (PacketCopyData(p, ptv->data, GET_PKT_LEN(p)) == -1) { |
c45d8985 | 311 | TmqhOutputPacketpool(ptv->tv, p); |
62e63e3f | 312 | SCReturnInt(AFP_FAILURE); |
c45d8985 | 313 | } |
e80b30c0 EL |
314 | SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)", |
315 | GET_PKT_LEN(p), p, GET_PKT_DATA(p)); | |
316 | ||
6062e00c EL |
317 | /* We only check for checksum disable */ |
318 | if (ptv->checksum_mode == CHECKSUM_VALIDATION_DISABLE) { | |
51eb9605 EL |
319 | p->flags |= PKT_IGNORE_CHECKSUM; |
320 | } else if (ptv->checksum_mode == CHECKSUM_VALIDATION_AUTO) { | |
321 | if (ptv->livedev->ignore_checksum) { | |
322 | p->flags |= PKT_IGNORE_CHECKSUM; | |
a565148f | 323 | } else if (ChecksumAutoModeCheck(ptv->pkts, |
51eb9605 EL |
324 | SC_ATOMIC_GET(ptv->livedev->pkts), |
325 | SC_ATOMIC_GET(ptv->livedev->invalid_checksums))) { | |
326 | ptv->livedev->ignore_checksum = 1; | |
6062e00c | 327 | p->flags |= PKT_IGNORE_CHECKSUM; |
51eb9605 | 328 | } |
6062e00c EL |
329 | } else { |
330 | /* List is NULL if we don't have activated auxiliary data */ | |
331 | for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { | |
332 | struct tpacket_auxdata *aux; | |
333 | ||
334 | if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct tpacket_auxdata)) || | |
335 | cmsg->cmsg_level != SOL_PACKET || | |
336 | cmsg->cmsg_type != PACKET_AUXDATA) | |
337 | continue; | |
f6ddaf33 | 338 | |
6062e00c | 339 | aux = (struct tpacket_auxdata *)CMSG_DATA(cmsg); |
f6ddaf33 | 340 | |
6062e00c EL |
341 | if (aux->tp_status & TP_STATUS_CSUMNOTREADY) { |
342 | p->flags |= PKT_IGNORE_CHECKSUM; | |
343 | } | |
344 | break; | |
f6ddaf33 EL |
345 | } |
346 | } | |
347 | ||
c469824b EL |
348 | if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) { |
349 | TmqhOutputPacketpool(ptv->tv, p); | |
62e63e3f | 350 | SCReturnInt(AFP_FAILURE); |
c469824b | 351 | } |
62e63e3f | 352 | SCReturnInt(AFP_READ_OK); |
c45d8985 EL |
353 | } |
354 | ||
49b7b00f EL |
355 | /** |
356 | * \brief AF packet read function for ring | |
357 | * | |
358 | * This function fills | |
359 | * From here the packets are picked up by the DecodeAFP thread. | |
360 | * | |
361 | * \param user pointer to AFPThreadVars | |
362 | * \retval TM_ECODE_FAILED on failure and TM_ECODE_OK on success | |
363 | */ | |
364 | int AFPReadFromRing(AFPThreadVars *ptv) | |
365 | { | |
366 | Packet *p = NULL; | |
367 | union thdr h; | |
368 | ||
369 | /* Read packet from ring */ | |
370 | h.raw = (((union thdr **)ptv->frame_buf)[ptv->frame_offset]); | |
371 | if (h.raw == NULL) { | |
372 | SCReturnInt(AFP_FAILURE); | |
373 | } | |
374 | if (h.h2->tp_status == 0) { | |
375 | SCReturnInt(AFP_READ_OK); | |
376 | } | |
377 | ||
378 | p = PacketGetFromQueueOrAlloc(); | |
379 | if (p == NULL) { | |
380 | SCReturnInt(AFP_FAILURE); | |
381 | } | |
382 | ||
383 | ptv->pkts++; | |
384 | ptv->bytes += h.h2->tp_len; | |
385 | SC_ATOMIC_ADD(ptv->livedev->pkts, 1); | |
386 | p->livedev = ptv->livedev; | |
387 | ||
388 | /* add forged header */ | |
389 | if (ptv->cooked) { | |
390 | SllHdr * hdrp = (SllHdr *)ptv->data; | |
391 | struct sockaddr_ll *from = (void *)h.raw + TPACKET_ALIGN(ptv->tp_hdrlen); | |
392 | /* XXX this is minimalist, but this seems enough */ | |
393 | hdrp->sll_protocol = from->sll_protocol; | |
394 | } | |
395 | ||
396 | p->datalink = ptv->datalink; | |
d8d9b098 EL |
397 | if (h.h2->tp_len > h.h2->tp_snaplen) { |
398 | SCLogDebug("Packet length (%d) > snaplen (%d), truncating", | |
399 | h.h2->tp_len, h.h2->tp_snaplen); | |
400 | } | |
34b3f194 | 401 | if (ptv->flags & AFP_ZERO_COPY) { |
d8d9b098 | 402 | if (PacketSetData(p, (unsigned char*)h.raw + h.h2->tp_mac, h.h2->tp_snaplen) == -1) { |
34b3f194 EL |
403 | TmqhOutputPacketpool(ptv->tv, p); |
404 | SCReturnInt(AFP_FAILURE); | |
405 | } | |
406 | } else { | |
d8d9b098 | 407 | if (PacketCopyData(p, (unsigned char*)h.raw + h.h2->tp_mac, h.h2->tp_snaplen) == -1) { |
34b3f194 EL |
408 | TmqhOutputPacketpool(ptv->tv, p); |
409 | SCReturnInt(AFP_FAILURE); | |
410 | } | |
49b7b00f EL |
411 | } |
412 | /* Timestamp */ | |
413 | p->ts.tv_sec = h.h2->tp_sec; | |
414 | p->ts.tv_usec = h.h2->tp_nsec/1000; | |
415 | SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)", | |
416 | GET_PKT_LEN(p), p, GET_PKT_DATA(p)); | |
417 | ||
418 | /* We only check for checksum disable */ | |
419 | if (ptv->checksum_mode == CHECKSUM_VALIDATION_DISABLE) { | |
420 | p->flags |= PKT_IGNORE_CHECKSUM; | |
421 | } else if (ptv->checksum_mode == CHECKSUM_VALIDATION_AUTO) { | |
422 | if (ptv->livedev->ignore_checksum) { | |
423 | p->flags |= PKT_IGNORE_CHECKSUM; | |
424 | } else if (ChecksumAutoModeCheck(ptv->pkts, | |
425 | SC_ATOMIC_GET(ptv->livedev->pkts), | |
426 | SC_ATOMIC_GET(ptv->livedev->invalid_checksums))) { | |
427 | ptv->livedev->ignore_checksum = 1; | |
428 | p->flags |= PKT_IGNORE_CHECKSUM; | |
429 | } | |
430 | } else { | |
431 | if (h.h2->tp_status & TP_STATUS_CSUMNOTREADY) { | |
432 | p->flags |= PKT_IGNORE_CHECKSUM; | |
433 | } | |
434 | } | |
49b7b00f EL |
435 | |
436 | if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) { | |
34b3f194 EL |
437 | h.h2->tp_status = TP_STATUS_KERNEL; |
438 | if (++ptv->frame_offset >= ptv->req.tp_frame_nr) { | |
439 | ptv->frame_offset = 0; | |
440 | } | |
49b7b00f EL |
441 | TmqhOutputPacketpool(ptv->tv, p); |
442 | SCReturnInt(AFP_FAILURE); | |
443 | } | |
444 | ||
34b3f194 EL |
445 | h.h2->tp_status = TP_STATUS_KERNEL; |
446 | if (++ptv->frame_offset >= ptv->req.tp_frame_nr) { | |
447 | ptv->frame_offset = 0; | |
448 | } | |
449 | ||
49b7b00f EL |
450 | SCReturnInt(AFP_READ_OK); |
451 | } | |
452 | ||
453 | ||
454 | ||
c45d8985 EL |
455 | static int AFPTryReopen(AFPThreadVars *ptv) |
456 | { | |
457 | int afp_activate_r; | |
458 | ||
459 | ptv->afp_state = AFP_STATE_DOWN; | |
460 | ||
e80b30c0 | 461 | afp_activate_r = AFPCreateSocket(ptv, ptv->iface, 0); |
c45d8985 EL |
462 | if (afp_activate_r != 0) { |
463 | return afp_activate_r; | |
464 | } | |
465 | ||
466 | SCLogInfo("Recovering interface listening"); | |
467 | ptv->afp_state = AFP_STATE_UP; | |
468 | return 0; | |
469 | } | |
470 | ||
e80b30c0 EL |
471 | /** |
472 | * \brief Main AF_PACKET reading Loop function | |
473 | */ | |
474 | TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) | |
475 | { | |
476 | uint16_t packet_q_len = 0; | |
477 | AFPThreadVars *ptv = (AFPThreadVars *)data; | |
478 | TmSlot *s = (TmSlot *)slot; | |
479 | ptv->slot = s->slot_next; | |
480 | struct pollfd fds; | |
481 | int r; | |
482 | ||
483 | SCEnter(); | |
484 | ||
485 | fds.fd = ptv->socket; | |
486 | fds.events = POLLIN; | |
487 | ||
488 | while (1) { | |
489 | /* Start by checking the state of our interface */ | |
490 | if (unlikely(ptv->afp_state == AFP_STATE_DOWN)) { | |
491 | int dbreak = 0; | |
492 | do { | |
493 | usleep(AFP_RECONNECT_TIMEOUT); | |
494 | if (suricata_ctl_flags != 0) { | |
495 | dbreak = 1; | |
496 | break; | |
497 | } | |
498 | r = AFPTryReopen(ptv); | |
499 | } while (r < 0); | |
500 | if (dbreak == 1) | |
501 | break; | |
502 | } | |
503 | ||
504 | /* make sure we have at least one packet in the packet pool, to prevent | |
505 | * us from alloc'ing packets at line rate */ | |
506 | do { | |
507 | packet_q_len = PacketPoolSize(); | |
508 | if (unlikely(packet_q_len == 0)) { | |
509 | PacketPoolWait(); | |
510 | } | |
511 | } while (packet_q_len == 0); | |
512 | ||
513 | r = poll(&fds, 1, POLL_TIMEOUT); | |
514 | ||
515 | if (suricata_ctl_flags != 0) { | |
516 | break; | |
517 | } | |
518 | ||
519 | if (r > 0 && | |
520 | (fds.revents & (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL))) { | |
521 | if (fds.revents & (POLLHUP | POLLRDHUP)) { | |
522 | close(ptv->socket); | |
523 | ptv->afp_state = AFP_STATE_DOWN; | |
524 | continue; | |
ff6365dd | 525 | } else if (fds.revents & POLLERR) { |
e80b30c0 EL |
526 | char c; |
527 | /* Do a recv to get errno */ | |
528 | if (recv(ptv->socket, &c, sizeof c, MSG_PEEK) != -1) | |
529 | continue; /* what, no error? */ | |
530 | SCLogError(SC_ERR_AFP_READ, "Error reading data from socket: (%d" PRIu32 ") %s", | |
531 | errno, strerror(errno)); | |
532 | close(ptv->socket); | |
533 | ptv->afp_state = AFP_STATE_DOWN; | |
534 | continue; | |
ff6365dd | 535 | } else if (fds.revents & POLLNVAL) { |
e80b30c0 EL |
536 | SCLogError(SC_ERR_AFP_READ, "Invalid polling request"); |
537 | close(ptv->socket); | |
538 | ptv->afp_state = AFP_STATE_DOWN; | |
539 | continue; | |
540 | } | |
541 | } else if (r > 0) { | |
49b7b00f EL |
542 | if (ptv->flags & AFP_RING_MODE) { |
543 | r = AFPReadFromRing(ptv); | |
544 | } else { | |
545 | /* AFPRead will call TmThreadsSlotProcessPkt on read packets */ | |
546 | r = AFPRead(ptv); | |
547 | } | |
62e63e3f EL |
548 | switch (r) { |
549 | case AFP_READ_FAILURE: | |
550 | /* AFPRead in error: best to reset the socket */ | |
551 | SCLogError(SC_ERR_AFP_READ, "AFPRead error reading data from socket: (%d" PRIu32 ") %s", | |
552 | errno, strerror(errno)); | |
553 | close(ptv->socket); | |
554 | ptv->afp_state = AFP_STATE_DOWN; | |
555 | continue; | |
556 | case AFP_FAILURE: | |
557 | SCReturnInt(TM_ECODE_FAILED); | |
558 | break; | |
559 | case AFP_READ_OK: | |
560 | break; | |
e80b30c0 EL |
561 | } |
562 | } else if ((r < 0) && (errno != EINTR)) { | |
563 | SCLogError(SC_ERR_AFP_READ, "Error reading data from socket: (%d" PRIu32 ") %s", | |
564 | errno, strerror(errno)); | |
565 | close(ptv->socket); | |
566 | ptv->afp_state = AFP_STATE_DOWN; | |
567 | continue; | |
568 | } | |
d68f182e | 569 | SCPerfSyncCountersIfSignalled(tv, 0); |
e80b30c0 EL |
570 | } |
571 | ||
e80b30c0 EL |
572 | SCReturnInt(TM_ECODE_OK); |
573 | } | |
574 | ||
e80b30c0 | 575 | static int AFPGetIfnumByDev(int fd, const char *ifname, int verbose) |
c45d8985 EL |
576 | { |
577 | struct ifreq ifr; | |
578 | ||
579 | memset(&ifr, 0, sizeof(ifr)); | |
e80b30c0 | 580 | strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
c45d8985 EL |
581 | |
582 | if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1) { | |
583 | if (verbose) | |
584 | SCLogError(SC_ERR_AFP_CREATE, "Unable to find iface %s: %s", | |
585 | ifname, strerror(errno)); | |
586 | return -1; | |
587 | } | |
588 | ||
589 | return ifr.ifr_ifindex; | |
590 | } | |
591 | ||
e80b30c0 | 592 | static int AFPGetDevLinktype(int fd, const char *ifname) |
c45d8985 EL |
593 | { |
594 | struct ifreq ifr; | |
595 | ||
596 | memset(&ifr, 0, sizeof(ifr)); | |
e80b30c0 | 597 | strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
c45d8985 EL |
598 | |
599 | if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) { | |
600 | SCLogError(SC_ERR_AFP_CREATE, "Unable to find type for iface \"%s\": %s", | |
601 | ifname, strerror(errno)); | |
602 | return -1; | |
603 | } | |
604 | ||
e80b30c0 EL |
605 | switch (ifr.ifr_hwaddr.sa_family) { |
606 | case ARPHRD_LOOPBACK: | |
607 | return LINKTYPE_ETHERNET; | |
608 | case ARPHRD_PPP: | |
609 | return LINKTYPE_RAW; | |
610 | default: | |
611 | return ifr.ifr_hwaddr.sa_family; | |
612 | } | |
c45d8985 EL |
613 | } |
614 | ||
49b7b00f EL |
615 | static int AFPComputeRingParams(AFPThreadVars *ptv, int order) |
616 | { | |
617 | /* Compute structure: | |
618 | Target is to store all pending packets | |
619 | with a size equal to MTU + auxdata | |
620 | And we keep a decent number of block | |
621 | ||
622 | To do so: | |
623 | Compute frame_size (aligned to be able to fit in block | |
624 | Check which block size we need. Blocksize is a 2^n * pagesize | |
625 | We then need to get order, big enough to have | |
626 | frame_size < block size | |
627 | Find number of frame per block (divide) | |
628 | Fill in packet_req | |
629 | ||
630 | Compute frame size: | |
631 | described in packet_mmap.txt | |
632 | dependant on snaplen (need to use a variable ?) | |
633 | snaplen: MTU ? | |
634 | tp_hdrlen determine_version in daq_afpacket | |
635 | in V1: sizeof(struct tpacket_hdr); | |
636 | in V2: val in getsockopt(instance->fd, SOL_PACKET, PACKET_HDRLEN, &val, &len) | |
637 | frame size: TPACKET_ALIGN(snaplen + TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + sizeof(struct sockaddr_ll) + ETH_HLEN) - ETH_HLEN); | |
638 | ||
639 | */ | |
640 | int tp_hdrlen = sizeof(struct tpacket_hdr); | |
641 | int snaplen = default_packet_size; | |
642 | ||
643 | ptv->req.tp_frame_size = TPACKET_ALIGN(snaplen +TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + sizeof(struct sockaddr_ll) + ETH_HLEN) - ETH_HLEN); | |
644 | ptv->req.tp_block_size = getpagesize() << order; | |
645 | int frames_per_block = ptv->req.tp_block_size / ptv->req.tp_frame_size; | |
646 | if (frames_per_block == 0) { | |
647 | SCLogInfo("frame size to big"); | |
648 | return -1; | |
649 | } | |
650 | ptv->req.tp_frame_nr = max_pending_packets; /* Warrior mode */ | |
d8d9b098 | 651 | ptv->req.tp_block_nr = ptv->req.tp_frame_nr / frames_per_block + 1; |
49b7b00f EL |
652 | /* exact division */ |
653 | ptv->req.tp_frame_nr = ptv->req.tp_block_nr * frames_per_block; | |
654 | SCLogInfo("AF_PACKET RX Ring params: block_size=%d block_nr=%d frame_size=%d frame_nr=%d", | |
655 | ptv->req.tp_block_size, ptv->req.tp_block_nr, | |
656 | ptv->req.tp_frame_size, ptv->req.tp_frame_nr); | |
657 | return 1; | |
658 | } | |
659 | ||
e80b30c0 | 660 | static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) |
c45d8985 EL |
661 | { |
662 | int r; | |
663 | struct packet_mreq sock_params; | |
664 | struct sockaddr_ll bind_address; | |
49b7b00f EL |
665 | int order; |
666 | unsigned int i; | |
667 | ||
c45d8985 EL |
668 | /* open socket */ |
669 | ptv->socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); | |
670 | if (ptv->socket == -1) { | |
e80b30c0 | 671 | SCLogError(SC_ERR_AFP_CREATE, "Couldn't create a AF_PACKET socket, error %s", strerror(errno)); |
c45d8985 EL |
672 | return -1; |
673 | } | |
361bf221 | 674 | SCLogDebug("using interface %s", (char *)devname); |
c45d8985 EL |
675 | /* bind socket */ |
676 | memset(&bind_address, 0, sizeof(bind_address)); | |
677 | bind_address.sll_family = AF_PACKET; | |
678 | bind_address.sll_protocol = htons(ETH_P_ALL); | |
e80b30c0 | 679 | bind_address.sll_ifindex = AFPGetIfnumByDev(ptv->socket, devname, verbose); |
c45d8985 EL |
680 | if (bind_address.sll_ifindex == -1) { |
681 | if (verbose) | |
e80b30c0 | 682 | SCLogError(SC_ERR_AFP_CREATE, "Couldn't find iface %s", devname); |
c45d8985 EL |
683 | return -1; |
684 | } | |
49b7b00f EL |
685 | |
686 | if (ptv->flags & AFP_RING_MODE) { | |
687 | int val = TPACKET_V2; | |
688 | unsigned int len = sizeof(val); | |
689 | if (getsockopt(ptv->socket, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) { | |
690 | if (errno == ENOPROTOOPT) { | |
691 | SCLogError(SC_ERR_AFP_CREATE, | |
692 | "Too old kernel giving up (need 2.6.27 at least)"); | |
693 | } | |
694 | SCLogError(SC_ERR_AFP_CREATE, "Error when retrieving packet header len"); | |
695 | return -1; | |
696 | } | |
697 | ptv->tp_hdrlen = val; | |
698 | ||
699 | val = TPACKET_V2; | |
700 | if (setsockopt(ptv->socket, SOL_PACKET, PACKET_VERSION, &val, | |
701 | sizeof(val)) < 0) { | |
702 | SCLogError(SC_ERR_AFP_CREATE, | |
703 | "Can't activate TPACKET_V2 on packet socket: %s", | |
704 | strerror(errno)); | |
705 | return -1; | |
706 | } | |
707 | ||
708 | /* Allocate RX ring */ | |
709 | #define DEFAULT_ORDER 3 | |
710 | for (order = DEFAULT_ORDER; order >= 0; order--) { | |
711 | if (AFPComputeRingParams(ptv, order) != 1) { | |
712 | SCLogInfo("Ring parameter are incorrect. Please correct the devel"); | |
713 | } | |
714 | ||
715 | r = setsockopt(ptv->socket, SOL_PACKET, PACKET_RX_RING, (void *) &ptv->req, sizeof(ptv->req)); | |
716 | if (r < 0) { | |
717 | if (errno == ENOMEM) { | |
718 | SCLogInfo("Memory issue with ring parameters. Retrying."); | |
719 | continue; | |
720 | } | |
721 | SCLogError(SC_ERR_MEM_ALLOC, | |
722 | "Unable to allocate RX Ring for iface %s: (%d) %s", | |
723 | devname, | |
724 | errno, | |
725 | strerror(errno)); | |
726 | return -1; | |
727 | } else { | |
728 | break; | |
729 | } | |
730 | } | |
731 | ||
732 | if (order < 0) { | |
733 | SCLogError(SC_ERR_MEM_ALLOC, | |
734 | "Unable to allocate RX Ring for iface %s (order 0 failed)", | |
735 | devname); | |
736 | return -1; | |
737 | } | |
738 | ||
739 | /* Allocate the Ring */ | |
740 | ptv->ring_buflen = ptv->req.tp_block_nr * ptv->req.tp_block_size; | |
741 | ptv->ring_buf = mmap(0, ptv->ring_buflen, PROT_READ|PROT_WRITE, | |
742 | MAP_SHARED, ptv->socket, 0); | |
743 | if (ptv->ring_buf == MAP_FAILED) { | |
744 | SCLogError(SC_ERR_MEM_ALLOC, "Unable to mmap"); | |
745 | return -1; | |
746 | } | |
747 | /* allocate a ring for each frame header pointer*/ | |
748 | ptv->frame_buf = SCMalloc(ptv->req.tp_frame_nr * sizeof (union thdr *)); | |
749 | if (ptv->frame_buf == NULL) { | |
750 | SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate frame buf"); | |
751 | return -1; | |
752 | } | |
753 | memset(ptv->frame_buf, 0, ptv->req.tp_frame_nr * sizeof (union thdr *)); | |
754 | /* fill the header ring with proper frame ptr*/ | |
755 | ptv->frame_offset = 0; | |
756 | for (i = 0; i < ptv->req.tp_block_nr; ++i) { | |
757 | void *base = &ptv->ring_buf[i * ptv->req.tp_block_size]; | |
758 | unsigned int j; | |
759 | for (j = 0; j < ptv->req.tp_block_size / ptv->req.tp_frame_size; ++j, ++ptv->frame_offset) { | |
760 | (((union thdr **)ptv->frame_buf)[ptv->frame_offset]) = base; | |
761 | base += ptv->req.tp_frame_size; | |
762 | } | |
763 | } | |
764 | ptv->frame_offset = 0; | |
765 | } | |
766 | ||
c45d8985 EL |
767 | r = bind(ptv->socket, (struct sockaddr *)&bind_address, sizeof(bind_address)); |
768 | if (r < 0) { | |
769 | if (verbose) { | |
770 | if (errno == ENETDOWN) { | |
771 | SCLogError(SC_ERR_AFP_CREATE, | |
772 | "Couldn't bind AF_PACKET socket, iface %s is down", | |
773 | devname); | |
774 | } else { | |
775 | SCLogError(SC_ERR_AFP_CREATE, | |
776 | "Couldn't bind AF_PACKET socket to iface %s, error %s", | |
777 | devname, | |
778 | strerror(errno)); | |
779 | } | |
780 | } | |
781 | close(ptv->socket); | |
782 | return -1; | |
783 | } | |
df7dbe36 EL |
784 | if (ptv->promisc != 0) { |
785 | /* Force promiscuous mode */ | |
786 | memset(&sock_params, 0, sizeof(sock_params)); | |
787 | sock_params.mr_type = PACKET_MR_PROMISC; | |
788 | sock_params.mr_ifindex = bind_address.sll_ifindex; | |
789 | r = setsockopt(ptv->socket, SOL_PACKET, PACKET_ADD_MEMBERSHIP,(void *)&sock_params, sizeof(sock_params)); | |
790 | if (r < 0) { | |
791 | SCLogError(SC_ERR_AFP_CREATE, | |
792 | "Couldn't switch iface %s to promiscuous, error %s", | |
793 | devname, | |
794 | strerror(errno)); | |
795 | close(ptv->socket); | |
796 | return -1; | |
797 | } | |
c45d8985 | 798 | } |
f6ddaf33 | 799 | |
6062e00c | 800 | if (ptv->checksum_mode == CHECKSUM_VALIDATION_KERNEL) { |
51eb9605 | 801 | int val = 1; |
67f791e8 EL |
802 | if (setsockopt(ptv->socket, SOL_PACKET, PACKET_AUXDATA, &val, |
803 | sizeof(val)) == -1 && errno != ENOPROTOOPT) { | |
a565148f EL |
804 | SCLogWarning(SC_ERR_NO_AF_PACKET, |
805 | "'kernel' checksum mode not supported, failling back to full mode."); | |
806 | ptv->checksum_mode = CHECKSUM_VALIDATION_ENABLE; | |
67f791e8 | 807 | } |
f6ddaf33 | 808 | } |
f6ddaf33 | 809 | |
e80b30c0 EL |
810 | /* set socket recv buffer size */ |
811 | if (ptv->buffer_size != 0) { | |
812 | /* | |
813 | * Set the socket buffer size to the specified value. | |
814 | */ | |
815 | SCLogInfo("Setting AF_PACKET socket buffer to %d", ptv->buffer_size); | |
816 | if (setsockopt(ptv->socket, SOL_SOCKET, SO_RCVBUF, | |
817 | &ptv->buffer_size, | |
818 | sizeof(ptv->buffer_size)) == -1) { | |
819 | SCLogError(SC_ERR_AFP_CREATE, | |
820 | "Couldn't set buffer size to %d on iface %s, error %s", | |
821 | ptv->buffer_size, | |
822 | devname, | |
823 | strerror(errno)); | |
824 | close(ptv->socket); | |
825 | return -1; | |
826 | } | |
827 | } | |
828 | ||
c45d8985 EL |
829 | #ifdef HAVE_PACKET_FANOUT |
830 | /* add binded socket to fanout group */ | |
fbca1a4e | 831 | if (ptv->threads > 1) { |
c45d8985 | 832 | uint32_t option = 0; |
e80b30c0 EL |
833 | uint16_t mode = ptv->cluster_type; |
834 | uint16_t id = ptv->cluster_id; | |
c45d8985 EL |
835 | option = (mode << 16) | (id & 0xffff); |
836 | r = setsockopt(ptv->socket, SOL_PACKET, PACKET_FANOUT,(void *)&option, sizeof(option)); | |
837 | if (r < 0) { | |
838 | SCLogError(SC_ERR_AFP_CREATE, | |
839 | "Coudn't set fanout mode, error %s", | |
840 | strerror(errno)); | |
e80b30c0 | 841 | close(ptv->socket); |
c45d8985 EL |
842 | return -1; |
843 | } | |
844 | } | |
845 | #endif | |
846 | ||
c85ee1e3 EL |
847 | ptv->datalink = AFPGetDevLinktype(ptv->socket, ptv->iface); |
848 | switch (ptv->datalink) { | |
849 | case ARPHRD_PPP: | |
850 | case ARPHRD_ATM: | |
851 | ptv->cooked = 1; | |
852 | } | |
853 | ||
49b7b00f | 854 | /* Init is ok */ |
c45d8985 EL |
855 | ptv->afp_state = AFP_STATE_UP; |
856 | return 0; | |
857 | } | |
858 | ||
859 | ||
860 | /** | |
861 | * \brief Init function for ReceiveAFP. | |
862 | * | |
863 | * \param tv pointer to ThreadVars | |
864 | * \param initdata pointer to the interface passed from the user | |
865 | * \param data pointer gets populated with AFPThreadVars | |
866 | * | |
867 | * \todo Create a general AFP setup function. | |
868 | */ | |
869 | TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) { | |
870 | SCEnter(); | |
871 | int r; | |
fbca1a4e | 872 | AFPIfaceConfig *afpconfig = initdata; |
c45d8985 | 873 | |
c45d8985 EL |
874 | if (initdata == NULL) { |
875 | SCLogError(SC_ERR_INVALID_ARGUMENT, "initdata == NULL"); | |
876 | SCReturnInt(TM_ECODE_FAILED); | |
877 | } | |
878 | ||
879 | AFPThreadVars *ptv = SCMalloc(sizeof(AFPThreadVars)); | |
45d5c3ca EL |
880 | if (ptv == NULL) { |
881 | afpconfig->DerefFunc(afpconfig); | |
c45d8985 | 882 | SCReturnInt(TM_ECODE_FAILED); |
45d5c3ca | 883 | } |
c45d8985 EL |
884 | memset(ptv, 0, sizeof(AFPThreadVars)); |
885 | ||
886 | ptv->tv = tv; | |
887 | ptv->cooked = 0; | |
888 | ||
fbca1a4e | 889 | strlcpy(ptv->iface, afpconfig->iface, AFP_IFACE_NAME_LENGTH); |
c45d8985 EL |
890 | ptv->iface[AFP_IFACE_NAME_LENGTH - 1]= '\0'; |
891 | ||
51eb9605 EL |
892 | ptv->livedev = LiveGetDevice(ptv->iface); |
893 | if (ptv->livedev == NULL) { | |
894 | SCLogError(SC_ERR_INVALID_VALUE, "Unable to find Live device"); | |
11bdf483 | 895 | SCFree(ptv); |
51eb9605 EL |
896 | SCReturnInt(TM_ECODE_FAILED); |
897 | } | |
898 | ||
fbca1a4e | 899 | ptv->buffer_size = afpconfig->buffer_size; |
e80b30c0 | 900 | |
df7dbe36 | 901 | ptv->promisc = afpconfig->promisc; |
6062e00c | 902 | ptv->checksum_mode = afpconfig->checksum_mode; |
df7dbe36 | 903 | |
fbca1a4e | 904 | ptv->threads = 1; |
e80b30c0 EL |
905 | #ifdef HAVE_PACKET_FANOUT |
906 | ptv->cluster_type = PACKET_FANOUT_LB; | |
907 | ptv->cluster_id = 1; | |
908 | /* We only set cluster info if the number of reader threads is greater than 1 */ | |
fbca1a4e EL |
909 | if (afpconfig->threads > 1) { |
910 | ptv->cluster_id = afpconfig->cluster_id; | |
911 | ptv->cluster_type = afpconfig->cluster_type; | |
912 | ptv->threads = afpconfig->threads; | |
e80b30c0 EL |
913 | } |
914 | #endif | |
49b7b00f | 915 | ptv->flags = afpconfig->flags; |
e80b30c0 | 916 | |
34b3f194 EL |
917 | char *active_runmode = RunmodeGetActive(); |
918 | ||
919 | if (active_runmode && !strcmp("workers", active_runmode)) { | |
920 | ptv->flags |= AFP_ZERO_COPY; | |
921 | SCLogInfo("Enabling zero copy mode"); | |
922 | } | |
923 | ||
fbca1a4e | 924 | r = AFPCreateSocket(ptv, ptv->iface, 1); |
c45d8985 | 925 | if (r < 0) { |
e80b30c0 | 926 | SCLogError(SC_ERR_AFP_CREATE, "Couldn't init AF_PACKET socket"); |
c45d8985 | 927 | SCFree(ptv); |
45d5c3ca | 928 | afpconfig->DerefFunc(afpconfig); |
c45d8985 EL |
929 | SCReturnInt(TM_ECODE_FAILED); |
930 | } | |
931 | ||
c85ee1e3 | 932 | |
c45d8985 | 933 | |
e80b30c0 EL |
934 | #define T_DATA_SIZE 70000 |
935 | ptv->data = SCMalloc(T_DATA_SIZE); | |
936 | if (ptv->data == NULL) { | |
45d5c3ca | 937 | afpconfig->DerefFunc(afpconfig); |
6019ae3d | 938 | SCFree(ptv); |
e80b30c0 | 939 | SCReturnInt(TM_ECODE_FAILED); |
c45d8985 | 940 | } |
e80b30c0 EL |
941 | ptv->datalen = T_DATA_SIZE; |
942 | #undef T_DATA_SIZE | |
943 | ||
c45d8985 EL |
944 | |
945 | *data = (void *)ptv; | |
fbca1a4e | 946 | |
45d5c3ca | 947 | afpconfig->DerefFunc(afpconfig); |
c45d8985 EL |
948 | SCReturnInt(TM_ECODE_OK); |
949 | } | |
950 | ||
951 | /** | |
952 | * \brief This function prints stats to the screen at exit. | |
953 | * \param tv pointer to ThreadVars | |
954 | * \param data pointer that gets cast into AFPThreadVars for ptv | |
955 | */ | |
956 | void ReceiveAFPThreadExitStats(ThreadVars *tv, void *data) { | |
957 | SCEnter(); | |
958 | AFPThreadVars *ptv = (AFPThreadVars *)data; | |
9549faae EL |
959 | #ifdef PACKET_STATISTICS |
960 | struct tpacket_stats kstats; | |
961 | socklen_t len = sizeof (struct tpacket_stats); | |
962 | #endif | |
963 | ||
964 | #ifdef PACKET_STATISTICS | |
965 | if (getsockopt(ptv->socket, SOL_PACKET, PACKET_STATISTICS, | |
966 | &kstats, &len) > -1) { | |
967 | SCLogInfo("(%s) Kernel: Packets %" PRIu32 ", dropped %" PRIu32 "", | |
968 | tv->name, | |
969 | kstats.tp_packets, kstats.tp_drops); | |
970 | } | |
971 | #endif | |
e80b30c0 EL |
972 | |
973 | SCLogInfo("(%s) Packets %" PRIu32 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); | |
c45d8985 EL |
974 | } |
975 | ||
976 | /** | |
977 | * \brief DeInit function closes af packet socket at exit. | |
978 | * \param tv pointer to ThreadVars | |
979 | * \param data pointer that gets cast into AFPThreadVars for ptv | |
980 | */ | |
981 | TmEcode ReceiveAFPThreadDeinit(ThreadVars *tv, void *data) { | |
982 | AFPThreadVars *ptv = (AFPThreadVars *)data; | |
983 | ||
e80b30c0 EL |
984 | if (ptv->data != NULL) { |
985 | SCFree(ptv->data); | |
986 | ptv->data = NULL; | |
987 | } | |
988 | ptv->datalen = 0; | |
989 | ||
c45d8985 EL |
990 | close(ptv->socket); |
991 | SCReturnInt(TM_ECODE_OK); | |
992 | } | |
993 | ||
994 | /** | |
995 | * \brief This function passes off to link type decoders. | |
996 | * | |
997 | * DecodeAFP reads packets from the PacketQueue and passes | |
998 | * them off to the proper link type decoder. | |
999 | * | |
1000 | * \param t pointer to ThreadVars | |
1001 | * \param p pointer to the current packet | |
1002 | * \param data pointer that gets cast into AFPThreadVars for ptv | |
1003 | * \param pq pointer to the current PacketQueue | |
1004 | */ | |
1005 | TmEcode DecodeAFP(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) | |
1006 | { | |
1007 | SCEnter(); | |
1008 | DecodeThreadVars *dtv = (DecodeThreadVars *)data; | |
1009 | ||
1010 | /* update counters */ | |
1011 | SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); | |
1012 | SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); | |
1013 | ||
1014 | SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); | |
1015 | #if 0 | |
1016 | SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); | |
1017 | SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, | |
1018 | (GET_PKT_LEN(p) * 8)/1000000.0); | |
1019 | #endif | |
1020 | ||
1021 | SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); | |
1022 | SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); | |
1023 | ||
1024 | /* call the decoder */ | |
1025 | switch(p->datalink) { | |
1026 | case LINKTYPE_LINUX_SLL: | |
1027 | DecodeSll(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); | |
1028 | break; | |
1029 | case LINKTYPE_ETHERNET: | |
1030 | DecodeEthernet(tv, dtv, p,GET_PKT_DATA(p), GET_PKT_LEN(p), pq); | |
1031 | break; | |
1032 | case LINKTYPE_PPP: | |
1033 | DecodePPP(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); | |
1034 | break; | |
1035 | case LINKTYPE_RAW: | |
1036 | DecodeRaw(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); | |
1037 | break; | |
1038 | default: | |
1039 | SCLogError(SC_ERR_DATALINK_UNIMPLEMENTED, "Error: datalink type %" PRId32 " not yet supported in module DecodeAFP", p->datalink); | |
1040 | break; | |
1041 | } | |
1042 | ||
1043 | SCReturnInt(TM_ECODE_OK); | |
1044 | } | |
1045 | ||
1046 | TmEcode DecodeAFPThreadInit(ThreadVars *tv, void *initdata, void **data) | |
1047 | { | |
1048 | SCEnter(); | |
1049 | DecodeThreadVars *dtv = NULL; | |
1050 | ||
1051 | dtv = DecodeThreadVarsAlloc(); | |
1052 | ||
1053 | if (dtv == NULL) | |
1054 | SCReturnInt(TM_ECODE_FAILED); | |
1055 | ||
1056 | DecodeRegisterPerfCounters(dtv, tv); | |
1057 | ||
1058 | *data = (void *)dtv; | |
1059 | ||
1060 | SCReturnInt(TM_ECODE_OK); | |
1061 | } | |
1062 | ||
e80b30c0 | 1063 | #endif /* HAVE_AF_PACKET */ |
c45d8985 | 1064 | /* eof */ |