]> git.ipfire.org Git - people/ms/suricata.git/blame - src/source-af-packet.c
decode: introduce checksum mode enum.
[people/ms/suricata.git] / src / source-af-packet.c
CommitLineData
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"
61#include "util-error.h"
62#include "util-privs.h"
e80b30c0 63#include "util-optimize.h"
c45d8985
EL
64#include "tmqh-packetpool.h"
65#include "source-af-packet.h"
66
e80b30c0 67#ifdef HAVE_AF_PACKET
2bc0be6e 68#include <sys/ioctl.h>
c45d8985
EL
69#include <linux/if_ether.h>
70#include <linux/if_packet.h>
71#include <linux/if_arp.h>
e80b30c0 72#endif
c45d8985
EL
73
74extern uint8_t suricata_ctl_flags;
75extern int max_pending_packets;
76
e80b30c0
EL
77#ifndef HAVE_AF_PACKET
78
79TmEcode NoAFPSupportExit(ThreadVars *, void *, void **);
80
81void TmModuleReceiveAFPRegister (void) {
82 tmm_modules[TMM_RECEIVEAFP].name = "ReceiveAFP";
83 tmm_modules[TMM_RECEIVEAFP].ThreadInit = NoAFPSupportExit;
84 tmm_modules[TMM_RECEIVEAFP].Func = NULL;
85 tmm_modules[TMM_RECEIVEAFP].ThreadExitPrintStats = NULL;
86 tmm_modules[TMM_RECEIVEAFP].ThreadDeinit = NULL;
87 tmm_modules[TMM_RECEIVEAFP].RegisterTests = NULL;
88 tmm_modules[TMM_RECEIVEAFP].cap_flags = 0;
3f1c4efc 89 tmm_modules[TMM_RECEIVEAFP].flags = TM_FLAG_RECEIVE_TM;
e80b30c0
EL
90}
91
92/**
93 * \brief Registration Function for DecodeAFP.
94 * \todo Unit tests are needed for this module.
95 */
96void TmModuleDecodeAFPRegister (void) {
97 tmm_modules[TMM_DECODEAFP].name = "DecodeAFP";
98 tmm_modules[TMM_DECODEAFP].ThreadInit = NoAFPSupportExit;
99 tmm_modules[TMM_DECODEAFP].Func = NULL;
100 tmm_modules[TMM_DECODEAFP].ThreadExitPrintStats = NULL;
101 tmm_modules[TMM_DECODEAFP].ThreadDeinit = NULL;
102 tmm_modules[TMM_DECODEAFP].RegisterTests = NULL;
103 tmm_modules[TMM_DECODEAFP].cap_flags = 0;
104}
105
106/**
107 * \brief this function prints an error message and exits.
108 */
109TmEcode NoAFPSupportExit(ThreadVars *tv, void *initdata, void **data)
110{
111 SCLogError(SC_ERR_NO_AF_PACKET,"Error creating thread %s: you do not have "
112 "support for AF_PACKET enabled, on Linux host please recompile "
113 "with --enable-af-packet", tv->name);
114 exit(EXIT_FAILURE);
115}
116
117#else /* We have AF_PACKET support */
118
c45d8985
EL
119#define AFP_IFACE_NAME_LENGTH 48
120
121#define AFP_STATE_DOWN 0
122#define AFP_STATE_UP 1
123
124#define AFP_RECONNECT_TIMEOUT 500000
125
126#define POLL_TIMEOUT 100
127
62e63e3f
EL
128enum {
129 AFP_READ_OK,
130 AFP_READ_FAILURE,
131 AFP_FAILURE,
132};
133
c45d8985
EL
134/**
135 * \brief Structure to hold thread specific variables.
136 */
137typedef struct AFPThreadVars_
138{
139 /* thread specific socket */
140 int socket;
141 /* handle state */
142 unsigned char afp_state;
c45d8985
EL
143
144 /* data link type for the thread */
145 int datalink;
146 int cooked;
147
148 /* counters */
149 uint32_t pkts;
150 uint64_t bytes;
151 uint32_t errs;
152
ff6365dd
EL
153 ThreadVars *tv;
154 TmSlot *slot;
155
156 uint8_t *data; /** Per function and thread data */
157 int datalen; /** Length of per function and thread data */
158
159 char iface[AFP_IFACE_NAME_LENGTH];
e80b30c0
EL
160 /* socket buffer size */
161 int buffer_size;
df7dbe36 162 int promisc;
67f791e8 163 int detect_offload;
e80b30c0
EL
164
165 int cluster_id;
166 int cluster_type;
c45d8985 167
fbca1a4e
EL
168 int threads;
169
c45d8985 170
c45d8985
EL
171} AFPThreadVars;
172
173TmEcode ReceiveAFP(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *);
174TmEcode ReceiveAFPThreadInit(ThreadVars *, void *, void **);
175void ReceiveAFPThreadExitStats(ThreadVars *, void *);
176TmEcode ReceiveAFPThreadDeinit(ThreadVars *, void *);
e80b30c0 177TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot);
c45d8985
EL
178
179TmEcode DecodeAFPThreadInit(ThreadVars *, void *, void **);
180TmEcode DecodeAFP(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *);
181
182/**
183 * \brief Registration Function for RecieveAFP.
184 * \todo Unit tests are needed for this module.
185 */
186void TmModuleReceiveAFPRegister (void) {
187 tmm_modules[TMM_RECEIVEAFP].name = "ReceiveAFP";
188 tmm_modules[TMM_RECEIVEAFP].ThreadInit = ReceiveAFPThreadInit;
ff6365dd 189 tmm_modules[TMM_RECEIVEAFP].Func = NULL;
e80b30c0 190 tmm_modules[TMM_RECEIVEAFP].PktAcqLoop = ReceiveAFPLoop;
c45d8985
EL
191 tmm_modules[TMM_RECEIVEAFP].ThreadExitPrintStats = ReceiveAFPThreadExitStats;
192 tmm_modules[TMM_RECEIVEAFP].ThreadDeinit = NULL;
193 tmm_modules[TMM_RECEIVEAFP].RegisterTests = NULL;
194 tmm_modules[TMM_RECEIVEAFP].cap_flags = SC_CAP_NET_RAW;
195}
196
197/**
198 * \brief Registration Function for DecodeAFP.
199 * \todo Unit tests are needed for this module.
200 */
201void TmModuleDecodeAFPRegister (void) {
202 tmm_modules[TMM_DECODEAFP].name = "DecodeAFP";
203 tmm_modules[TMM_DECODEAFP].ThreadInit = DecodeAFPThreadInit;
204 tmm_modules[TMM_DECODEAFP].Func = DecodeAFP;
205 tmm_modules[TMM_DECODEAFP].ThreadExitPrintStats = NULL;
206 tmm_modules[TMM_DECODEAFP].ThreadDeinit = NULL;
207 tmm_modules[TMM_DECODEAFP].RegisterTests = NULL;
208 tmm_modules[TMM_DECODEAFP].cap_flags = 0;
209}
210
e80b30c0
EL
211static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose);
212
c45d8985
EL
213
214/**
215 * \brief AF packet read function.
216 *
217 * This function fills
218 * From here the packets are picked up by the DecodeAFP thread.
219 *
220 * \param user pointer to AFPThreadVars
221 * \retval TM_ECODE_FAILED on failure and TM_ECODE_OK on success
222 */
62e63e3f 223int AFPRead(AFPThreadVars *ptv)
c45d8985
EL
224{
225 Packet *p = NULL;
226 /* XXX should try to use read that get directly to packet */
c45d8985
EL
227 int offset = 0;
228 int caplen;
229 struct sockaddr_ll from;
230 struct iovec iov;
231 struct msghdr msg;
c45d8985
EL
232 struct cmsghdr *cmsg;
233 union {
234 struct cmsghdr cmsg;
235 char buf[CMSG_SPACE(sizeof(struct tpacket_auxdata))];
236 } cmsg_buf;
c45d8985
EL
237
238 msg.msg_name = &from;
239 msg.msg_namelen = sizeof(from);
240 msg.msg_iov = &iov;
241 msg.msg_iovlen = 1;
c45d8985
EL
242 msg.msg_control = &cmsg_buf;
243 msg.msg_controllen = sizeof(cmsg_buf);
c45d8985
EL
244 msg.msg_flags = 0;
245
246 if (ptv->cooked)
247 offset = SLL_HEADER_LEN;
248 else
249 offset = 0;
e80b30c0
EL
250 iov.iov_len = ptv->datalen - offset;
251 iov.iov_base = ptv->data + offset;
c45d8985
EL
252
253 caplen = recvmsg(ptv->socket, &msg, MSG_TRUNC);
254
255 if (caplen < 0) {
256 SCLogWarning(SC_ERR_AFP_READ, "recvmsg failed with error code %" PRId32,
257 errno);
62e63e3f 258 SCReturnInt(AFP_READ_FAILURE);
c45d8985 259 }
ff6365dd
EL
260
261 p = PacketGetFromQueueOrAlloc();
c45d8985 262 if (p == NULL) {
62e63e3f 263 SCReturnInt(AFP_FAILURE);
c45d8985
EL
264 }
265
266 /* get timestamp of packet via ioctl */
267 if (ioctl(ptv->socket, SIOCGSTAMP, &p->ts) == -1) {
268 SCLogWarning(SC_ERR_AFP_READ, "recvmsg failed with error code %" PRId32,
269 errno);
270 TmqhOutputPacketpool(ptv->tv, p);
62e63e3f 271 SCReturnInt(AFP_READ_FAILURE);
c45d8985
EL
272 }
273
274 ptv->pkts++;
275 ptv->bytes += caplen + offset;
276
277 /* add forged header */
278 if (ptv->cooked) {
e80b30c0 279 SllHdr * hdrp = (SllHdr *)ptv->data;
c45d8985
EL
280 /* XXX this is minimalist, but this seems enough */
281 hdrp->sll_protocol = from.sll_protocol;
282 }
283
284 p->datalink = ptv->datalink;
285 SET_PKT_LEN(p, caplen + offset);
e80b30c0 286 if (PacketCopyData(p, ptv->data, GET_PKT_LEN(p)) == -1) {
c45d8985 287 TmqhOutputPacketpool(ptv->tv, p);
62e63e3f 288 SCReturnInt(AFP_FAILURE);
c45d8985 289 }
e80b30c0
EL
290 SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)",
291 GET_PKT_LEN(p), p, GET_PKT_DATA(p));
292
f6ddaf33
EL
293 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
294 struct tpacket_auxdata *aux;
295
296 if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct tpacket_auxdata)) ||
297 cmsg->cmsg_level != SOL_PACKET ||
298 cmsg->cmsg_type != PACKET_AUXDATA)
299 continue;
300
301 aux = (struct tpacket_auxdata *)CMSG_DATA(cmsg);
302
303 if (aux->tp_status & TP_STATUS_CSUMNOTREADY) {
304 p->flags |= PKT_IGNORE_CHECKSUM;
305 }
306 }
307
c469824b
EL
308 if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) {
309 TmqhOutputPacketpool(ptv->tv, p);
62e63e3f 310 SCReturnInt(AFP_FAILURE);
c469824b 311 }
62e63e3f 312 SCReturnInt(AFP_READ_OK);
c45d8985
EL
313}
314
315static int AFPTryReopen(AFPThreadVars *ptv)
316{
317 int afp_activate_r;
318
319 ptv->afp_state = AFP_STATE_DOWN;
320
e80b30c0 321 afp_activate_r = AFPCreateSocket(ptv, ptv->iface, 0);
c45d8985
EL
322 if (afp_activate_r != 0) {
323 return afp_activate_r;
324 }
325
326 SCLogInfo("Recovering interface listening");
327 ptv->afp_state = AFP_STATE_UP;
328 return 0;
329}
330
e80b30c0
EL
331/**
332 * \brief Main AF_PACKET reading Loop function
333 */
334TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot)
335{
336 uint16_t packet_q_len = 0;
337 AFPThreadVars *ptv = (AFPThreadVars *)data;
338 TmSlot *s = (TmSlot *)slot;
339 ptv->slot = s->slot_next;
340 struct pollfd fds;
341 int r;
342
343 SCEnter();
344
345 fds.fd = ptv->socket;
346 fds.events = POLLIN;
347
348 while (1) {
349 /* Start by checking the state of our interface */
350 if (unlikely(ptv->afp_state == AFP_STATE_DOWN)) {
351 int dbreak = 0;
352 do {
353 usleep(AFP_RECONNECT_TIMEOUT);
354 if (suricata_ctl_flags != 0) {
355 dbreak = 1;
356 break;
357 }
358 r = AFPTryReopen(ptv);
359 } while (r < 0);
360 if (dbreak == 1)
361 break;
362 }
363
364 /* make sure we have at least one packet in the packet pool, to prevent
365 * us from alloc'ing packets at line rate */
366 do {
367 packet_q_len = PacketPoolSize();
368 if (unlikely(packet_q_len == 0)) {
369 PacketPoolWait();
370 }
371 } while (packet_q_len == 0);
372
373 r = poll(&fds, 1, POLL_TIMEOUT);
374
375 if (suricata_ctl_flags != 0) {
376 break;
377 }
378
379 if (r > 0 &&
380 (fds.revents & (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL))) {
381 if (fds.revents & (POLLHUP | POLLRDHUP)) {
382 close(ptv->socket);
383 ptv->afp_state = AFP_STATE_DOWN;
384 continue;
ff6365dd 385 } else if (fds.revents & POLLERR) {
e80b30c0
EL
386 char c;
387 /* Do a recv to get errno */
388 if (recv(ptv->socket, &c, sizeof c, MSG_PEEK) != -1)
389 continue; /* what, no error? */
390 SCLogError(SC_ERR_AFP_READ, "Error reading data from socket: (%d" PRIu32 ") %s",
391 errno, strerror(errno));
392 close(ptv->socket);
393 ptv->afp_state = AFP_STATE_DOWN;
394 continue;
ff6365dd 395 } else if (fds.revents & POLLNVAL) {
e80b30c0
EL
396 SCLogError(SC_ERR_AFP_READ, "Invalid polling request");
397 close(ptv->socket);
398 ptv->afp_state = AFP_STATE_DOWN;
399 continue;
400 }
401 } else if (r > 0) {
402 /* AFPRead will call TmThreadsSlotProcessPkt on read packets */
ff6365dd 403 r = AFPRead(ptv);
62e63e3f
EL
404 switch (r) {
405 case AFP_READ_FAILURE:
406 /* AFPRead in error: best to reset the socket */
407 SCLogError(SC_ERR_AFP_READ, "AFPRead error reading data from socket: (%d" PRIu32 ") %s",
408 errno, strerror(errno));
409 close(ptv->socket);
410 ptv->afp_state = AFP_STATE_DOWN;
411 continue;
412 case AFP_FAILURE:
413 SCReturnInt(TM_ECODE_FAILED);
414 break;
415 case AFP_READ_OK:
416 break;
e80b30c0
EL
417 }
418 } else if ((r < 0) && (errno != EINTR)) {
419 SCLogError(SC_ERR_AFP_READ, "Error reading data from socket: (%d" PRIu32 ") %s",
420 errno, strerror(errno));
421 close(ptv->socket);
422 ptv->afp_state = AFP_STATE_DOWN;
423 continue;
424 }
d68f182e 425 SCPerfSyncCountersIfSignalled(tv, 0);
e80b30c0
EL
426 }
427
e80b30c0
EL
428 SCReturnInt(TM_ECODE_OK);
429}
430
e80b30c0 431static int AFPGetIfnumByDev(int fd, const char *ifname, int verbose)
c45d8985
EL
432{
433 struct ifreq ifr;
434
435 memset(&ifr, 0, sizeof(ifr));
e80b30c0 436 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
c45d8985
EL
437
438 if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1) {
439 if (verbose)
440 SCLogError(SC_ERR_AFP_CREATE, "Unable to find iface %s: %s",
441 ifname, strerror(errno));
442 return -1;
443 }
444
445 return ifr.ifr_ifindex;
446}
447
e80b30c0 448static int AFPGetDevLinktype(int fd, const char *ifname)
c45d8985
EL
449{
450 struct ifreq ifr;
451
452 memset(&ifr, 0, sizeof(ifr));
e80b30c0 453 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
c45d8985
EL
454
455 if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) {
456 SCLogError(SC_ERR_AFP_CREATE, "Unable to find type for iface \"%s\": %s",
457 ifname, strerror(errno));
458 return -1;
459 }
460
e80b30c0
EL
461 switch (ifr.ifr_hwaddr.sa_family) {
462 case ARPHRD_LOOPBACK:
463 return LINKTYPE_ETHERNET;
464 case ARPHRD_PPP:
465 return LINKTYPE_RAW;
466 default:
467 return ifr.ifr_hwaddr.sa_family;
468 }
c45d8985
EL
469}
470
e80b30c0 471static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose)
c45d8985
EL
472{
473 int r;
474 struct packet_mreq sock_params;
475 struct sockaddr_ll bind_address;
476 /* open socket */
477 ptv->socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
478 if (ptv->socket == -1) {
e80b30c0 479 SCLogError(SC_ERR_AFP_CREATE, "Couldn't create a AF_PACKET socket, error %s", strerror(errno));
c45d8985
EL
480 return -1;
481 }
361bf221 482 SCLogDebug("using interface %s", (char *)devname);
c45d8985
EL
483 /* bind socket */
484 memset(&bind_address, 0, sizeof(bind_address));
485 bind_address.sll_family = AF_PACKET;
486 bind_address.sll_protocol = htons(ETH_P_ALL);
e80b30c0 487 bind_address.sll_ifindex = AFPGetIfnumByDev(ptv->socket, devname, verbose);
c45d8985
EL
488 if (bind_address.sll_ifindex == -1) {
489 if (verbose)
e80b30c0 490 SCLogError(SC_ERR_AFP_CREATE, "Couldn't find iface %s", devname);
c45d8985
EL
491 return -1;
492 }
493 r = bind(ptv->socket, (struct sockaddr *)&bind_address, sizeof(bind_address));
494 if (r < 0) {
495 if (verbose) {
496 if (errno == ENETDOWN) {
497 SCLogError(SC_ERR_AFP_CREATE,
498 "Couldn't bind AF_PACKET socket, iface %s is down",
499 devname);
500 } else {
501 SCLogError(SC_ERR_AFP_CREATE,
502 "Couldn't bind AF_PACKET socket to iface %s, error %s",
503 devname,
504 strerror(errno));
505 }
506 }
507 close(ptv->socket);
508 return -1;
509 }
df7dbe36
EL
510 if (ptv->promisc != 0) {
511 /* Force promiscuous mode */
512 memset(&sock_params, 0, sizeof(sock_params));
513 sock_params.mr_type = PACKET_MR_PROMISC;
514 sock_params.mr_ifindex = bind_address.sll_ifindex;
515 r = setsockopt(ptv->socket, SOL_PACKET, PACKET_ADD_MEMBERSHIP,(void *)&sock_params, sizeof(sock_params));
516 if (r < 0) {
517 SCLogError(SC_ERR_AFP_CREATE,
518 "Couldn't switch iface %s to promiscuous, error %s",
519 devname,
520 strerror(errno));
521 close(ptv->socket);
522 return -1;
523 }
c45d8985 524 }
f6ddaf33 525
67f791e8
EL
526 if (ptv->detect_offload) {
527 int val = 1;
528 if (setsockopt(ptv->socket, SOL_PACKET, PACKET_AUXDATA, &val,
529 sizeof(val)) == -1 && errno != ENOPROTOOPT) {
530 SCLogError(SC_ERR_AFP_CREATE,
531 "Couldn't active auxdata on iface %s, error %s",
532 devname,
533 strerror(errno));
534 close(ptv->socket);
535 return -1;
536 }
f6ddaf33 537 }
f6ddaf33 538
e80b30c0
EL
539 /* set socket recv buffer size */
540 if (ptv->buffer_size != 0) {
541 /*
542 * Set the socket buffer size to the specified value.
543 */
544 SCLogInfo("Setting AF_PACKET socket buffer to %d", ptv->buffer_size);
545 if (setsockopt(ptv->socket, SOL_SOCKET, SO_RCVBUF,
546 &ptv->buffer_size,
547 sizeof(ptv->buffer_size)) == -1) {
548 SCLogError(SC_ERR_AFP_CREATE,
549 "Couldn't set buffer size to %d on iface %s, error %s",
550 ptv->buffer_size,
551 devname,
552 strerror(errno));
553 close(ptv->socket);
554 return -1;
555 }
556 }
557
c45d8985
EL
558#ifdef HAVE_PACKET_FANOUT
559 /* add binded socket to fanout group */
fbca1a4e 560 if (ptv->threads > 1) {
c45d8985 561 uint32_t option = 0;
e80b30c0
EL
562 uint16_t mode = ptv->cluster_type;
563 uint16_t id = ptv->cluster_id;
c45d8985
EL
564 option = (mode << 16) | (id & 0xffff);
565 r = setsockopt(ptv->socket, SOL_PACKET, PACKET_FANOUT,(void *)&option, sizeof(option));
566 if (r < 0) {
567 SCLogError(SC_ERR_AFP_CREATE,
568 "Coudn't set fanout mode, error %s",
569 strerror(errno));
e80b30c0 570 close(ptv->socket);
c45d8985
EL
571 return -1;
572 }
573 }
574#endif
575
576 ptv->afp_state = AFP_STATE_UP;
577 return 0;
578}
579
580
581/**
582 * \brief Init function for ReceiveAFP.
583 *
584 * \param tv pointer to ThreadVars
585 * \param initdata pointer to the interface passed from the user
586 * \param data pointer gets populated with AFPThreadVars
587 *
588 * \todo Create a general AFP setup function.
589 */
590TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) {
591 SCEnter();
592 int r;
fbca1a4e 593 AFPIfaceConfig *afpconfig = initdata;
c45d8985 594
c45d8985
EL
595 if (initdata == NULL) {
596 SCLogError(SC_ERR_INVALID_ARGUMENT, "initdata == NULL");
597 SCReturnInt(TM_ECODE_FAILED);
598 }
599
600 AFPThreadVars *ptv = SCMalloc(sizeof(AFPThreadVars));
45d5c3ca
EL
601 if (ptv == NULL) {
602 afpconfig->DerefFunc(afpconfig);
c45d8985 603 SCReturnInt(TM_ECODE_FAILED);
45d5c3ca 604 }
c45d8985
EL
605 memset(ptv, 0, sizeof(AFPThreadVars));
606
607 ptv->tv = tv;
608 ptv->cooked = 0;
609
fbca1a4e 610 strlcpy(ptv->iface, afpconfig->iface, AFP_IFACE_NAME_LENGTH);
c45d8985
EL
611 ptv->iface[AFP_IFACE_NAME_LENGTH - 1]= '\0';
612
fbca1a4e 613 ptv->buffer_size = afpconfig->buffer_size;
e80b30c0 614
df7dbe36 615 ptv->promisc = afpconfig->promisc;
67f791e8 616 ptv->detect_offload = afpconfig->detect_offload;
df7dbe36 617
fbca1a4e 618 ptv->threads = 1;
e80b30c0
EL
619#ifdef HAVE_PACKET_FANOUT
620 ptv->cluster_type = PACKET_FANOUT_LB;
621 ptv->cluster_id = 1;
622 /* We only set cluster info if the number of reader threads is greater than 1 */
fbca1a4e
EL
623 if (afpconfig->threads > 1) {
624 ptv->cluster_id = afpconfig->cluster_id;
625 ptv->cluster_type = afpconfig->cluster_type;
626 ptv->threads = afpconfig->threads;
e80b30c0
EL
627 }
628#endif
629
fbca1a4e 630 r = AFPCreateSocket(ptv, ptv->iface, 1);
c45d8985 631 if (r < 0) {
e80b30c0 632 SCLogError(SC_ERR_AFP_CREATE, "Couldn't init AF_PACKET socket");
c45d8985 633 SCFree(ptv);
45d5c3ca 634 afpconfig->DerefFunc(afpconfig);
c45d8985
EL
635 SCReturnInt(TM_ECODE_FAILED);
636 }
637
e80b30c0 638 ptv->datalink = AFPGetDevLinktype(ptv->socket, ptv->iface);
c45d8985
EL
639 switch (ptv->datalink) {
640 case ARPHRD_PPP:
641 case ARPHRD_ATM:
642 ptv->cooked = 1;
643 }
644
e80b30c0
EL
645#define T_DATA_SIZE 70000
646 ptv->data = SCMalloc(T_DATA_SIZE);
647 if (ptv->data == NULL) {
45d5c3ca 648 afpconfig->DerefFunc(afpconfig);
e80b30c0 649 SCReturnInt(TM_ECODE_FAILED);
c45d8985 650 }
e80b30c0
EL
651 ptv->datalen = T_DATA_SIZE;
652#undef T_DATA_SIZE
653
c45d8985
EL
654
655 *data = (void *)ptv;
fbca1a4e 656
45d5c3ca 657 afpconfig->DerefFunc(afpconfig);
c45d8985
EL
658 SCReturnInt(TM_ECODE_OK);
659}
660
661/**
662 * \brief This function prints stats to the screen at exit.
663 * \param tv pointer to ThreadVars
664 * \param data pointer that gets cast into AFPThreadVars for ptv
665 */
666void ReceiveAFPThreadExitStats(ThreadVars *tv, void *data) {
667 SCEnter();
668 AFPThreadVars *ptv = (AFPThreadVars *)data;
9549faae
EL
669#ifdef PACKET_STATISTICS
670 struct tpacket_stats kstats;
671 socklen_t len = sizeof (struct tpacket_stats);
672#endif
673
674#ifdef PACKET_STATISTICS
675 if (getsockopt(ptv->socket, SOL_PACKET, PACKET_STATISTICS,
676 &kstats, &len) > -1) {
677 SCLogInfo("(%s) Kernel: Packets %" PRIu32 ", dropped %" PRIu32 "",
678 tv->name,
679 kstats.tp_packets, kstats.tp_drops);
680 }
681#endif
e80b30c0
EL
682
683 SCLogInfo("(%s) Packets %" PRIu32 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes);
c45d8985
EL
684}
685
686/**
687 * \brief DeInit function closes af packet socket at exit.
688 * \param tv pointer to ThreadVars
689 * \param data pointer that gets cast into AFPThreadVars for ptv
690 */
691TmEcode ReceiveAFPThreadDeinit(ThreadVars *tv, void *data) {
692 AFPThreadVars *ptv = (AFPThreadVars *)data;
693
e80b30c0
EL
694 if (ptv->data != NULL) {
695 SCFree(ptv->data);
696 ptv->data = NULL;
697 }
698 ptv->datalen = 0;
699
c45d8985
EL
700 close(ptv->socket);
701 SCReturnInt(TM_ECODE_OK);
702}
703
704/**
705 * \brief This function passes off to link type decoders.
706 *
707 * DecodeAFP reads packets from the PacketQueue and passes
708 * them off to the proper link type decoder.
709 *
710 * \param t pointer to ThreadVars
711 * \param p pointer to the current packet
712 * \param data pointer that gets cast into AFPThreadVars for ptv
713 * \param pq pointer to the current PacketQueue
714 */
715TmEcode DecodeAFP(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq)
716{
717 SCEnter();
718 DecodeThreadVars *dtv = (DecodeThreadVars *)data;
719
720 /* update counters */
721 SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca);
722 SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca);
723
724 SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p));
725#if 0
726 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p));
727 SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca,
728 (GET_PKT_LEN(p) * 8)/1000000.0);
729#endif
730
731 SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p));
732 SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p));
733
734 /* call the decoder */
735 switch(p->datalink) {
736 case LINKTYPE_LINUX_SLL:
737 DecodeSll(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq);
738 break;
739 case LINKTYPE_ETHERNET:
740 DecodeEthernet(tv, dtv, p,GET_PKT_DATA(p), GET_PKT_LEN(p), pq);
741 break;
742 case LINKTYPE_PPP:
743 DecodePPP(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq);
744 break;
745 case LINKTYPE_RAW:
746 DecodeRaw(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq);
747 break;
748 default:
749 SCLogError(SC_ERR_DATALINK_UNIMPLEMENTED, "Error: datalink type %" PRId32 " not yet supported in module DecodeAFP", p->datalink);
750 break;
751 }
752
753 SCReturnInt(TM_ECODE_OK);
754}
755
756TmEcode DecodeAFPThreadInit(ThreadVars *tv, void *initdata, void **data)
757{
758 SCEnter();
759 DecodeThreadVars *dtv = NULL;
760
761 dtv = DecodeThreadVarsAlloc();
762
763 if (dtv == NULL)
764 SCReturnInt(TM_ECODE_FAILED);
765
766 DecodeRegisterPerfCounters(dtv, tv);
767
768 *data = (void *)dtv;
769
770 SCReturnInt(TM_ECODE_OK);
771}
772
e80b30c0 773#endif /* HAVE_AF_PACKET */
c45d8985 774/* eof */