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