summaryrefslogtreecommitdiffstats
path: root/src/util-ioctl.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:39:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:39:49 +0000
commita0aa2307322cd47bbf416810ac0292925e03be87 (patch)
tree37076262a026c4b48c8a0e84f44ff9187556ca35 /src/util-ioctl.c
parentInitial commit. (diff)
downloadsuricata-a0aa2307322cd47bbf416810ac0292925e03be87.tar.xz
suricata-a0aa2307322cd47bbf416810ac0292925e03be87.zip
Adding upstream version 1:7.0.3.upstream/1%7.0.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/util-ioctl.c')
-rw-r--r--src/util-ioctl.c739
1 files changed, 739 insertions, 0 deletions
diff --git a/src/util-ioctl.c b/src/util-ioctl.c
new file mode 100644
index 0000000..f39662b
--- /dev/null
+++ b/src/util-ioctl.c
@@ -0,0 +1,739 @@
+/* Copyright (C) 2010 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Eric Leblond <eric@regit.org>
+ * \author Victor Julien <victor@inliniac.net>
+ */
+
+#include "suricata-common.h"
+#include "util-ioctl.h"
+#include "conf.h"
+#include "decode.h"
+#include "decode-sll.h"
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_LINUX_ETHTOOL_H
+#include <linux/types.h>
+#include <linux/ethtool.h>
+#ifdef HAVE_LINUX_SOCKIOS_H
+#include <linux/sockios.h>
+#else
+#error "ethtool.h present but sockios.h is missing"
+#endif /* HAVE_LINUX_SOCKIOS_H */
+#endif /* HAVE_LINUX_ETHTOOL_H */
+
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+
+#ifdef OS_WIN32
+#include "win32-syscall.h"
+#endif
+
+/**
+ * \brief output a majorant of hardware header length
+ *
+ * \param Name of a network interface
+ */
+static int GetIfaceMaxHWHeaderLength(const char *dev)
+{
+ if ((!strcmp("eth", dev)) || (!strcmp("br", dev)) || (!strcmp("bond", dev)) ||
+ (!strcmp("wlan", dev)) || (!strcmp("tun", dev)) || (!strcmp("tap", dev)) ||
+ (!strcmp("lo", dev))) {
+ /* Add possible VLAN tag or Qing headers */
+ return 8 + ETHERNET_HEADER_LEN;
+ }
+
+ if (!strcmp("ppp", dev))
+ return SLL_HEADER_LEN;
+ /* SLL_HEADER_LEN is the biggest one and
+ add possible VLAN tag and Qing headers */
+ return 8 + SLL_HEADER_LEN;
+}
+
+
+/**
+ * \brief output the link MTU
+ *
+ * \param Name of link
+ * \retval -1 in case of error, 0 if MTU can not be found
+ */
+int GetIfaceMTU(const char *dev)
+{
+#if defined SIOCGIFMTU
+ struct ifreq ifr;
+ int fd;
+
+ (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd == -1) {
+ return -1;
+ }
+
+ if (ioctl(fd, SIOCGIFMTU, (char *)&ifr) < 0) {
+ SCLogWarning("Failure when trying to get MTU via ioctl for '%s': %s (%d)", dev,
+ strerror(errno), errno);
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ SCLogInfo("%s: MTU %d", dev, ifr.ifr_mtu);
+ return ifr.ifr_mtu;
+#elif defined OS_WIN32
+ return GetIfaceMTUWin32(dev);
+#else
+ /* ioctl is not defined, let's pretend returning 0 is ok */
+ return 0;
+#endif
+}
+
+/**
+ * \brief output max packet size for a link
+ *
+ * This does a best effort to find the maximum packet size
+ * for the link. In case of uncertainty, it will output a
+ * majorant to be sure avoid the cost of dynamic allocation.
+ *
+ * \param LiveDevice object
+ * \retval 0 in case of error
+ */
+int GetIfaceMaxPacketSize(LiveDevice *ld)
+{
+ if (ld == NULL)
+ return 0;
+
+ const char *dev = ld->dev;
+ if ((dev == NULL) || strlen(dev) == 0)
+ return 0;
+
+ int mtu = GetIfaceMTU(dev);
+ switch (mtu) {
+ case 0:
+ case -1:
+ return 0;
+ }
+ ld->mtu = mtu;
+ int ll_header = GetIfaceMaxHWHeaderLength(dev);
+ return ll_header + mtu;
+}
+
+#ifdef SIOCGIFFLAGS
+/**
+ * \brief Get interface flags.
+ * \param ifname Interface name.
+ * \return Interface flags or -1 on error
+ */
+int GetIfaceFlags(const char *ifname)
+{
+ struct ifreq ifr;
+
+ int fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) {
+ SCLogError("%s: failed to get device flags: %s", ifname, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+#ifdef OS_FREEBSD
+ int flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
+ return flags;
+#else
+ return ifr.ifr_flags;
+#endif
+}
+#endif
+
+#ifdef SIOCSIFFLAGS
+/**
+ * \brief Set interface flags.
+ * \param ifname Interface name.
+ * \param flags Flags to set.
+ * \return Zero on success.
+ */
+int SetIfaceFlags(const char *ifname, int flags)
+{
+ struct ifreq ifr;
+
+ int fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+#ifdef OS_FREEBSD
+ ifr.ifr_flags = flags & 0xffff;
+ ifr.ifr_flagshigh = flags >> 16;
+#else
+ ifr.ifr_flags = (uint16_t)flags;
+#endif
+
+ if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) {
+ SCLogError("%s: unable to set device flags: %s", ifname, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+#endif /* SIOCGIFFLAGS */
+
+#ifdef SIOCGIFCAP
+int GetIfaceCaps(const char *ifname)
+{
+ struct ifreq ifr;
+
+ int fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+
+ if (ioctl(fd, SIOCGIFCAP, &ifr) == -1) {
+ SCLogError("%s: unable to get device caps: %s", ifname, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return ifr.ifr_curcap;
+}
+#endif
+#ifdef SIOCSIFCAP
+int SetIfaceCaps(const char *ifname, int caps)
+{
+ struct ifreq ifr;
+
+ int fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ ifr.ifr_reqcap = caps;
+
+ if (ioctl(fd, SIOCSIFCAP, &ifr) == -1) {
+ SCLogError("%s: unable to set caps: %s", ifname, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+#endif
+
+
+#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
+static int GetEthtoolValue(const char *dev, int cmd, uint32_t *value)
+{
+ struct ifreq ifr;
+ int fd;
+ struct ethtool_value ethv;
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd == -1) {
+ return -1;
+ }
+ (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
+
+ ethv.cmd = cmd;
+ ifr.ifr_data = (void *) &ethv;
+ if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) {
+ SCLogWarning("%s: failed to get SIOCETHTOOL ioctl: %s", dev, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ *value = ethv.data;
+ close(fd);
+ return 0;
+}
+
+static int SetEthtoolValue(const char *dev, int cmd, uint32_t value)
+{
+ struct ifreq ifr;
+ int fd;
+ struct ethtool_value ethv;
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd == -1) {
+ return -1;
+ }
+ (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
+
+ ethv.cmd = cmd;
+ ethv.data = value;
+ ifr.ifr_data = (void *) &ethv;
+ if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) {
+ SCLogWarning("%s: failed to set SIOCETHTOOL ioctl: %s", dev, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+static int GetIfaceOffloadingLinux(const char *dev, int csum, int other)
+{
+ int ret = 0;
+ uint32_t value = 0;
+
+ if (csum) {
+ const char *rx = "unset", *tx = "unset";
+ int csum_ret = 0;
+#ifdef ETHTOOL_GRXCSUM
+ if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) {
+ rx = "SET";
+ csum_ret = 1;
+ }
+#endif
+#ifdef ETHTOOL_GTXCSUM
+ if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) {
+ tx = "SET";
+ csum_ret = 1;
+ }
+#endif
+ if (csum_ret == 0)
+ SCLogPerf("%s: NIC offloading: RX %s TX %s", dev, rx, tx);
+ else {
+ SCLogWarning("%s: NIC offloading: RX %s TX %s. Run: ethtool -K %s rx off tx off", dev,
+ rx, tx, dev);
+ ret = 1;
+ }
+ }
+
+ if (other) {
+ const char *lro = "unset", *gro = "unset", *tso = "unset", *gso = "unset";
+ const char *sg = "unset";
+ int other_ret = 0;
+#ifdef ETHTOOL_GGRO
+ if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) {
+ gro = "SET";
+ other_ret = 1;
+ }
+#endif
+#ifdef ETHTOOL_GTSO
+ if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) {
+ tso = "SET";
+ other_ret = 1;
+ }
+#endif
+#ifdef ETHTOOL_GGSO
+ if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) {
+ gso = "SET";
+ other_ret = 1;
+ }
+#endif
+#ifdef ETHTOOL_GSG
+ if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) {
+ sg = "SET";
+ other_ret = 1;
+ }
+#endif
+#ifdef ETHTOOL_GFLAGS
+ if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
+ if (value & ETH_FLAG_LRO) {
+ lro = "SET";
+ other_ret = 1;
+ }
+ }
+#endif
+ if (other_ret == 0) {
+ SCLogPerf("%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s", dev, sg,
+ gro, lro, tso, gso);
+ } else {
+ SCLogWarning("%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s. Run: "
+ "ethtool -K %s sg off gro off lro off tso off gso off",
+ dev, sg, gro, lro, tso, gso, dev);
+ ret = 1;
+ }
+ }
+ return ret;
+}
+
+static int DisableIfaceOffloadingLinux(LiveDevice *ldev, int csum, int other)
+{
+ int ret = 0;
+ uint32_t value = 0;
+
+ if (ldev == NULL)
+ return -1;
+
+ const char *dev = ldev->dev;
+
+ if (csum) {
+#ifdef ETHTOOL_GRXCSUM
+ if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) {
+ SCLogPerf("%s: disabling rxcsum offloading", dev);
+ SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 0);
+ ldev->offload_orig |= OFFLOAD_FLAG_RXCSUM;
+ }
+#endif
+#ifdef ETHTOOL_GTXCSUM
+ if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) {
+ SCLogPerf("%s: disabling txcsum offloading", dev);
+ SetEthtoolValue(dev, ETHTOOL_STXCSUM, 0);
+ ldev->offload_orig |= OFFLOAD_FLAG_TXCSUM;
+ }
+#endif
+ }
+ if (other) {
+#ifdef ETHTOOL_GGRO
+ if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) {
+ SCLogPerf("%s: disabling gro offloading", dev);
+ SetEthtoolValue(dev, ETHTOOL_SGRO, 0);
+ ldev->offload_orig |= OFFLOAD_FLAG_GRO;
+ }
+#endif
+#ifdef ETHTOOL_GTSO
+ if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) {
+ SCLogPerf("%s: disabling tso offloading", dev);
+ SetEthtoolValue(dev, ETHTOOL_STSO, 0);
+ ldev->offload_orig |= OFFLOAD_FLAG_TSO;
+ }
+#endif
+#ifdef ETHTOOL_GGSO
+ if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) {
+ SCLogPerf("%s: disabling gso offloading", dev);
+ SetEthtoolValue(dev, ETHTOOL_SGSO, 0);
+ ldev->offload_orig |= OFFLOAD_FLAG_GSO;
+ }
+#endif
+#ifdef ETHTOOL_GSG
+ if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) {
+ SCLogPerf("%s: disabling sg offloading", dev);
+ SetEthtoolValue(dev, ETHTOOL_SSG, 0);
+ ldev->offload_orig |= OFFLOAD_FLAG_SG;
+ }
+#endif
+#ifdef ETHTOOL_GFLAGS
+ if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
+ if (value & ETH_FLAG_LRO) {
+ SCLogPerf("%s: disabling lro offloading", dev);
+ SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ~ETH_FLAG_LRO);
+ ldev->offload_orig |= OFFLOAD_FLAG_LRO;
+ }
+ }
+#endif
+ }
+ return ret;
+}
+
+static int RestoreIfaceOffloadingLinux(LiveDevice *ldev)
+{
+ if (ldev == NULL)
+ return -1;
+
+ const char *dev = ldev->dev;
+
+#ifdef ETHTOOL_GRXCSUM
+ if (ldev->offload_orig & OFFLOAD_FLAG_RXCSUM) {
+ SCLogPerf("%s: restoring rxcsum offloading", dev);
+ SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 1);
+ }
+#endif
+#ifdef ETHTOOL_GTXCSUM
+ if (ldev->offload_orig & OFFLOAD_FLAG_TXCSUM) {
+ SCLogPerf("%s: restoring txcsum offloading", dev);
+ SetEthtoolValue(dev, ETHTOOL_STXCSUM, 1);
+ }
+#endif
+#ifdef ETHTOOL_GGRO
+ if (ldev->offload_orig & OFFLOAD_FLAG_GRO) {
+ SCLogPerf("%s: restoring gro offloading", dev);
+ SetEthtoolValue(dev, ETHTOOL_SGRO, 1);
+ }
+#endif
+#ifdef ETHTOOL_GTSO
+ if (ldev->offload_orig & OFFLOAD_FLAG_TSO) {
+ SCLogPerf("%s: restoring tso offloading", dev);
+ SetEthtoolValue(dev, ETHTOOL_STSO, 1);
+ }
+#endif
+#ifdef ETHTOOL_GGSO
+ if (ldev->offload_orig & OFFLOAD_FLAG_GSO) {
+ SCLogPerf("%s: restoring gso offloading", dev);
+ SetEthtoolValue(dev, ETHTOOL_SGSO, 1);
+ }
+#endif
+#ifdef ETHTOOL_GSG
+ if (ldev->offload_orig & OFFLOAD_FLAG_SG) {
+ SCLogPerf("%s: restoring sg offloading", dev);
+ SetEthtoolValue(dev, ETHTOOL_SSG, 1);
+ }
+#endif
+#ifdef ETHTOOL_GFLAGS
+ if (ldev->offload_orig & OFFLOAD_FLAG_LRO) {
+ uint32_t value = 0;
+ if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
+ SCLogPerf("%s: restoring lro offloading", dev);
+ SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ETH_FLAG_LRO);
+ }
+ }
+#endif
+ return 0;
+}
+
+#endif /* defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL */
+
+#ifdef SIOCGIFCAP
+static int GetIfaceOffloadingBSD(const char *ifname)
+{
+ int ret = 0;
+ int if_caps = GetIfaceCaps(ifname);
+ if (if_caps == -1) {
+ return -1;
+ }
+ SCLogDebug("if_caps %X", if_caps);
+
+ if (if_caps & IFCAP_RXCSUM) {
+ SCLogWarning("%s: RXCSUM activated can lead to capture problems. Run: ifconfig %s -rxcsum",
+ ifname, ifname);
+ ret = 1;
+ }
+#ifdef IFCAP_TOE
+ if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) {
+ SCLogWarning("%s: TSO, TOE or LRO activated can lead to capture problems. Run: ifconfig %s "
+ "-tso -toe -lro",
+ ifname, ifname);
+ ret = 1;
+ }
+#else
+ if (if_caps & (IFCAP_TSO|IFCAP_LRO)) {
+ SCLogWarning(
+ "%s: TSO or LRO activated can lead to capture problems. Run: ifconfig %s -tso -lro",
+ ifname, ifname);
+ ret = 1;
+ }
+#endif
+ return ret;
+}
+#endif
+
+#ifdef SIOCSIFCAP
+static int DisableIfaceOffloadingBSD(LiveDevice *ldev)
+{
+ int ret = 0;
+
+ if (ldev == NULL)
+ return -1;
+
+ const char *ifname = ldev->dev;
+ int if_caps = GetIfaceCaps(ifname);
+ int set_caps = if_caps;
+ if (if_caps == -1) {
+ return -1;
+ }
+ SCLogDebug("if_caps %X", if_caps);
+
+ if (if_caps & IFCAP_RXCSUM) {
+ SCLogPerf("%s: disabling rxcsum offloading", ifname);
+ set_caps &= ~IFCAP_RXCSUM;
+ }
+ if (if_caps & IFCAP_TXCSUM) {
+ SCLogPerf("%s: disabling txcsum offloading", ifname);
+ set_caps &= ~IFCAP_TXCSUM;
+ }
+#ifdef IFCAP_RXCSUM_IPV6
+ if (if_caps & IFCAP_RXCSUM_IPV6) {
+ SCLogPerf("%s: disabling rxcsum6 offloading", ifname);
+ set_caps &= ~IFCAP_RXCSUM_IPV6;
+ }
+#endif
+#ifdef IFCAP_TXCSUM_IPV6
+ if (if_caps & IFCAP_TXCSUM_IPV6) {
+ SCLogPerf("%s: disabling txcsum6 offloading", ifname);
+ set_caps &= ~IFCAP_TXCSUM_IPV6;
+ }
+#endif
+#ifdef IFCAP_TOE
+ if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) {
+ SCLogPerf("%s: disabling tso|toe|lro offloading", ifname);
+ set_caps &= ~(IFCAP_TSO|IFCAP_LRO);
+ }
+#else
+ if (if_caps & (IFCAP_TSO|IFCAP_LRO)) {
+ SCLogPerf("%s: disabling tso|lro offloading", ifname);
+ set_caps &= ~(IFCAP_TSO|IFCAP_LRO);
+ }
+#endif
+ if (set_caps != if_caps) {
+ if (if_caps & IFCAP_RXCSUM)
+ ldev->offload_orig |= OFFLOAD_FLAG_RXCSUM;
+ if (if_caps & IFCAP_TSO)
+ ldev->offload_orig |= OFFLOAD_FLAG_TSO;
+#ifdef IFCAP_TOE
+ if (if_caps & IFCAP_TOE)
+ ldev->offload_orig |= OFFLOAD_FLAG_TOE;
+#endif
+ if (if_caps & IFCAP_LRO)
+ ldev->offload_orig |= OFFLOAD_FLAG_LRO;
+
+ SetIfaceCaps(ifname, set_caps);
+ }
+ return ret;
+}
+
+static int RestoreIfaceOffloadingBSD(LiveDevice *ldev)
+{
+ int ret = 0;
+
+ if (ldev == NULL)
+ return -1;
+
+ const char *ifname = ldev->dev;
+ int if_caps = GetIfaceCaps(ifname);
+ int set_caps = if_caps;
+ if (if_caps == -1) {
+ return -1;
+ }
+ SCLogDebug("if_caps %X", if_caps);
+
+ if (ldev->offload_orig & OFFLOAD_FLAG_RXCSUM) {
+ SCLogPerf("%s: restoring rxcsum offloading", ifname);
+ set_caps |= IFCAP_RXCSUM;
+ }
+ if (ldev->offload_orig & OFFLOAD_FLAG_TSO) {
+ SCLogPerf("%s: restoring tso offloading", ifname);
+ set_caps |= IFCAP_TSO;
+ }
+#ifdef IFCAP_TOE
+ if (ldev->offload_orig & OFFLOAD_FLAG_TOE) {
+ SCLogPerf("%s: restoring toe offloading", ifname);
+ set_caps |= IFCAP_TOE;
+ }
+#endif
+ if (ldev->offload_orig & OFFLOAD_FLAG_LRO) {
+ SCLogPerf("%s: restoring lro offloading", ifname);
+ set_caps |= IFCAP_LRO;
+ }
+
+ if (set_caps != if_caps) {
+ SetIfaceCaps(ifname, set_caps);
+ }
+ return ret;
+}
+#endif
+
+/**
+ * \brief output offloading status of the link
+ *
+ * Test interface for offloading features. If one of them is
+ * activated then suricata mays received packets merge at reception.
+ * The result is oversized packets and this may cause some serious
+ * problem in some capture mode where the size of the packet is
+ * limited (AF_PACKET in V2 more for example).
+ *
+ * \param Name of link
+ * \param csum check if checksums are offloaded
+ * \param other check if other things are offloaded: TSO, GRO, etc.
+ * \retval -1 in case of error, 0 if none, 1 if some
+ */
+int GetIfaceOffloading(const char *dev, int csum, int other)
+{
+#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
+ return GetIfaceOffloadingLinux(dev, csum, other);
+#elif defined SIOCGIFCAP
+ return GetIfaceOffloadingBSD(dev);
+#elif defined OS_WIN32
+ return GetIfaceOffloadingWin32(dev, csum, other);
+#else
+ return 0;
+#endif
+}
+
+int DisableIfaceOffloading(LiveDevice *dev, int csum, int other)
+{
+ /* already set */
+ if (dev->offload_orig != 0)
+ return 0;
+#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
+ return DisableIfaceOffloadingLinux(dev, csum, other);
+#elif defined SIOCSIFCAP
+ return DisableIfaceOffloadingBSD(dev);
+#elif defined OS_WIN32
+ return DisableIfaceOffloadingWin32(dev, csum, other);
+#else
+ return 0;
+#endif
+
+}
+
+void RestoreIfaceOffloading(LiveDevice *dev)
+{
+ if (dev->offload_orig != 0) {
+#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
+ RestoreIfaceOffloadingLinux(dev);
+#elif defined SIOCSIFCAP
+ RestoreIfaceOffloadingBSD(dev);
+#elif defined OS_WIN32
+ RestoreIfaceOffloadingWin32(dev);
+#endif
+ }
+}
+
+int GetIfaceRSSQueuesNum(const char *dev)
+{
+#if defined HAVE_LINUX_ETHTOOL_H && defined ETHTOOL_GRXRINGS
+ struct ifreq ifr;
+ struct ethtool_rxnfc nfccmd;
+ int fd;
+
+ (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd == -1) {
+ SCLogWarning("%s: failed to open socket for ioctl: %s", dev, strerror(errno));
+ return -1;
+ }
+
+ nfccmd.cmd = ETHTOOL_GRXRINGS;
+ ifr.ifr_data = (void*) &nfccmd;
+
+ if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) {
+ if (errno != ENOTSUP) {
+ SCLogWarning("%s: failed get number of RSS queue ioctl: %s", dev, strerror(errno));
+ }
+ close(fd);
+ return 0;
+ }
+ close(fd);
+ SCLogInfo("%s: RX RSS queues: %d", dev, (int)nfccmd.data);
+ return (int)nfccmd.data;
+#else
+ return 0;
+#endif
+}