Coverage Report

Created: 2026-01-16 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/util-ioctl.c
Line
Count
Source
1
/* Copyright (C) 2010 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
 * \author Victor Julien <victor@inliniac.net>
23
 */
24
25
#include "suricata-common.h"
26
#include "util-ioctl.h"
27
#include "conf.h"
28
#include "decode.h"
29
#include "decode-sll.h"
30
31
#ifdef HAVE_SYS_IOCTL_H
32
#include <sys/ioctl.h>
33
#endif
34
35
#ifdef HAVE_LINUX_ETHTOOL_H
36
#include <linux/types.h>
37
#include <linux/ethtool.h>
38
#ifdef HAVE_LINUX_SOCKIOS_H
39
#include <linux/sockios.h>
40
#else
41
#error "ethtool.h present but sockios.h is missing"
42
#endif /* HAVE_LINUX_SOCKIOS_H */
43
#endif /* HAVE_LINUX_ETHTOOL_H */
44
45
#ifdef HAVE_NET_IF_H
46
#include <net/if.h>
47
#endif
48
49
#ifdef OS_WIN32
50
#include "win32-syscall.h"
51
#endif
52
53
/**
54
 * \brief output a majorant of hardware header length
55
 *
56
 * \param Name of a network interface
57
 */
58
static int GetIfaceMaxHWHeaderLength(const char *dev)
59
0
{
60
0
    if ((!strcmp("eth", dev)) || (!strcmp("br", dev)) || (!strcmp("bond", dev)) ||
61
0
            (!strcmp("wlan", dev)) || (!strcmp("tun", dev)) || (!strcmp("tap", dev)) ||
62
0
            (!strcmp("lo", dev))) {
63
        /* Add possible VLAN tag or Qing headers */
64
0
        return 8 + ETHERNET_HEADER_LEN;
65
0
    }
66
67
0
    if (!strcmp("ppp", dev))
68
0
        return SLL_HEADER_LEN;
69
    /* SLL_HEADER_LEN is the biggest one and
70
       add possible VLAN tag and Qing headers */
71
0
    return 8 + SLL_HEADER_LEN;
72
0
}
73
74
75
/**
76
 * \brief output the link MTU
77
 *
78
 * \param Name of link
79
 * \retval -1 in case of error, 0 if MTU can not be found
80
 */
81
int GetIfaceMTU(const char *dev)
82
0
{
83
0
#if defined SIOCGIFMTU
84
0
    struct ifreq ifr;
85
0
    int fd;
86
87
0
    (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
88
0
    fd = socket(AF_INET, SOCK_DGRAM, 0);
89
0
    if (fd == -1) {
90
0
        return -1;
91
0
    }
92
93
0
    if (ioctl(fd, SIOCGIFMTU, (char *)&ifr) < 0) {
94
0
        SCLogWarning("Failure when trying to get MTU via ioctl for '%s': %s (%d)", dev,
95
0
                strerror(errno), errno);
96
0
        close(fd);
97
0
        return -1;
98
0
    }
99
0
    close(fd);
100
0
    SCLogInfo("%s: MTU %d", dev, ifr.ifr_mtu);
101
0
    return ifr.ifr_mtu;
102
#elif defined OS_WIN32
103
    return GetIfaceMTUWin32(dev);
104
#else
105
    /* ioctl is not defined, let's pretend returning 0 is ok */
106
    return 0;
107
#endif
108
0
}
109
110
/**
111
 * \brief output max packet size for a link
112
 *
113
 * This does a best effort to find the maximum packet size
114
 * for the link. In case of uncertainty, it will output a
115
 * majorant to be sure avoid the cost of dynamic allocation.
116
 *
117
 * \param LiveDevice object
118
 * \retval 0 in case of error
119
 */
120
int GetIfaceMaxPacketSize(LiveDevice *ld)
121
0
{
122
0
    if (ld == NULL)
123
0
        return 0;
124
125
0
    const char *dev = ld->dev;
126
0
    if ((dev == NULL) || strlen(dev) == 0)
127
0
        return 0;
128
129
0
    int mtu = GetIfaceMTU(dev);
130
0
    switch (mtu) {
131
0
        case 0:
132
0
        case -1:
133
0
            return 0;
134
0
    }
135
0
    ld->mtu = mtu;
136
0
    int ll_header = GetIfaceMaxHWHeaderLength(dev);
137
0
    return ll_header + mtu;
138
0
}
139
140
#ifdef SIOCGIFFLAGS
141
/**
142
 * \brief Get interface flags.
143
 * \param ifname Interface name.
144
 * \return Interface flags or -1 on error
145
 */
146
int GetIfaceFlags(const char *ifname)
147
0
{
148
0
    struct ifreq ifr;
149
150
0
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
151
0
    if (fd < 0) {
152
0
        return -1;
153
0
    }
154
155
0
    memset(&ifr, 0, sizeof(ifr));
156
0
    strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
157
158
0
    if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) {
159
0
        SCLogError("%s: failed to get device flags: %s", ifname, strerror(errno));
160
0
        close(fd);
161
0
        return -1;
162
0
    }
163
164
0
    close(fd);
165
#ifdef OS_FREEBSD
166
    int flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
167
    return flags;
168
#else
169
0
    return ifr.ifr_flags;
170
0
#endif
171
0
}
172
#endif
173
174
#ifdef SIOCSIFFLAGS
175
/**
176
 * \brief Set interface flags.
177
 * \param ifname Interface name.
178
 * \param flags Flags to set.
179
 * \return Zero on success.
180
 */
181
int SetIfaceFlags(const char *ifname, int flags)
182
0
{
183
0
    struct ifreq ifr;
184
185
0
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
186
0
    if (fd < 0) {
187
0
        return -1;
188
0
    }
189
190
0
    memset(&ifr, 0, sizeof(ifr));
191
0
    strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
192
#ifdef OS_FREEBSD
193
    ifr.ifr_flags = flags & 0xffff;
194
    ifr.ifr_flagshigh = flags >> 16;
195
#else
196
0
    ifr.ifr_flags = (uint16_t)flags;
197
0
#endif
198
199
0
    if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) {
200
0
        SCLogError("%s: unable to set device flags: %s", ifname, strerror(errno));
201
0
        close(fd);
202
0
        return -1;
203
0
    }
204
205
0
    close(fd);
206
0
    return 0;
207
0
}
208
#endif /* SIOCGIFFLAGS */
209
210
#ifdef SIOCGIFCAP
211
int GetIfaceCaps(const char *ifname)
212
{
213
    struct ifreq ifr;
214
215
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
216
    if (fd < 0) {
217
        return -1;
218
    }
219
220
    memset(&ifr, 0, sizeof(ifr));
221
    strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
222
223
    if (ioctl(fd, SIOCGIFCAP, &ifr) == -1) {
224
        SCLogError("%s: unable to get device caps: %s", ifname, strerror(errno));
225
        close(fd);
226
        return -1;
227
    }
228
229
    close(fd);
230
    return ifr.ifr_curcap;
231
}
232
#endif
233
#ifdef SIOCSIFCAP
234
int SetIfaceCaps(const char *ifname, int caps)
235
{
236
    struct ifreq ifr;
237
238
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
239
    if (fd < 0) {
240
        return -1;
241
    }
242
243
    memset(&ifr, 0, sizeof(ifr));
244
    strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
245
    ifr.ifr_reqcap = caps;
246
247
    if (ioctl(fd, SIOCSIFCAP, &ifr) == -1) {
248
        SCLogError("%s: unable to set caps: %s", ifname, strerror(errno));
249
        close(fd);
250
        return -1;
251
    }
252
253
    close(fd);
254
    return 0;
255
}
256
#endif
257
258
259
#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
260
static int GetEthtoolValue(const char *dev, int cmd, uint32_t *value)
261
0
{
262
0
    struct ifreq ifr;
263
0
    int fd;
264
0
    struct ethtool_value ethv;
265
266
0
    fd = socket(AF_INET, SOCK_DGRAM, 0);
267
0
    if (fd == -1) {
268
0
        return -1;
269
0
    }
270
0
    (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
271
272
0
    ethv.cmd = cmd;
273
0
    ifr.ifr_data = (void *) &ethv;
274
0
    if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) {
275
0
        SCLogWarning("%s: failed to get SIOCETHTOOL ioctl: %s", dev, strerror(errno));
276
0
        close(fd);
277
0
        return -1;
278
0
    }
279
280
0
    *value = ethv.data;
281
0
    close(fd);
282
0
    return 0;
283
0
}
284
285
static int SetEthtoolValue(const char *dev, int cmd, uint32_t value)
286
0
{
287
0
    struct ifreq ifr;
288
0
    int fd;
289
0
    struct ethtool_value ethv;
290
291
0
    fd = socket(AF_INET, SOCK_DGRAM, 0);
292
0
    if (fd == -1) {
293
0
        return -1;
294
0
    }
295
0
    (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
296
297
0
    ethv.cmd = cmd;
298
0
    ethv.data = value;
299
0
    ifr.ifr_data = (void *) &ethv;
300
0
    if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) {
301
0
        SCLogWarning("%s: failed to set SIOCETHTOOL ioctl: %s", dev, strerror(errno));
302
0
        close(fd);
303
0
        return -1;
304
0
    }
305
306
0
    close(fd);
307
0
    return 0;
308
0
}
309
310
static int GetIfaceOffloadingLinux(const char *dev, int csum, int other)
311
0
{
312
0
    int ret = 0;
313
0
    uint32_t value = 0;
314
315
0
    if (csum) {
316
0
        const char *rx = "unset", *tx = "unset";
317
0
        int csum_ret = 0;
318
0
#ifdef ETHTOOL_GRXCSUM
319
0
        if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) {
320
0
            rx = "SET";
321
0
            csum_ret = 1;
322
0
        }
323
0
#endif
324
0
#ifdef ETHTOOL_GTXCSUM
325
0
        if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) {
326
0
            tx = "SET";
327
0
            csum_ret = 1;
328
0
        }
329
0
#endif
330
0
        if (csum_ret == 0)
331
0
            SCLogPerf("%s: NIC offloading: RX %s TX %s", dev, rx, tx);
332
0
        else {
333
0
            SCLogWarning("%s: NIC offloading: RX %s TX %s. Run: ethtool -K %s rx off tx off", dev,
334
0
                    rx, tx, dev);
335
0
            ret = 1;
336
0
        }
337
0
    }
338
339
0
    if (other) {
340
0
        const char *lro = "unset", *gro = "unset", *tso = "unset", *gso = "unset";
341
0
        const char *sg = "unset";
342
0
        int other_ret = 0;
343
0
#ifdef ETHTOOL_GGRO
344
0
        if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) {
345
0
            gro = "SET";
346
0
            other_ret = 1;
347
0
        }
348
0
#endif
349
0
#ifdef ETHTOOL_GTSO
350
0
        if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) {
351
0
            tso = "SET";
352
0
            other_ret = 1;
353
0
        }
354
0
#endif
355
0
#ifdef ETHTOOL_GGSO
356
0
        if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) {
357
0
            gso = "SET";
358
0
            other_ret = 1;
359
0
        }
360
0
#endif
361
0
#ifdef ETHTOOL_GSG
362
0
        if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) {
363
0
            sg = "SET";
364
0
            other_ret = 1;
365
0
        }
366
0
#endif
367
0
#ifdef ETHTOOL_GFLAGS
368
0
        if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
369
0
            if (value & ETH_FLAG_LRO) {
370
0
                lro = "SET";
371
0
                other_ret = 1;
372
0
            }
373
0
        }
374
0
#endif
375
0
        if (other_ret == 0) {
376
0
            SCLogPerf("%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s", dev, sg,
377
0
                    gro, lro, tso, gso);
378
0
        } else {
379
0
            SCLogWarning("%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s. Run: "
380
0
                         "ethtool -K %s sg off gro off lro off tso off gso off",
381
0
                    dev, sg, gro, lro, tso, gso, dev);
382
0
            ret = 1;
383
0
        }
384
0
    }
385
0
    return ret;
386
0
}
387
388
static int DisableIfaceOffloadingLinux(LiveDevice *ldev, int csum, int other)
389
0
{
390
0
    int ret = 0;
391
0
    uint32_t value = 0;
392
393
0
    if (ldev == NULL)
394
0
        return -1;
395
396
0
    const char *dev = ldev->dev;
397
398
0
    if (csum) {
399
0
#ifdef ETHTOOL_GRXCSUM
400
0
        if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) {
401
0
            SCLogPerf("%s: disabling rxcsum offloading", dev);
402
0
            SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 0);
403
0
            ldev->offload_orig |= OFFLOAD_FLAG_RXCSUM;
404
0
        }
405
0
#endif
406
0
#ifdef ETHTOOL_GTXCSUM
407
0
        if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) {
408
0
            SCLogPerf("%s: disabling txcsum offloading", dev);
409
0
            SetEthtoolValue(dev, ETHTOOL_STXCSUM, 0);
410
0
            ldev->offload_orig |= OFFLOAD_FLAG_TXCSUM;
411
0
        }
412
0
#endif
413
0
    }
414
0
    if (other) {
415
0
#ifdef ETHTOOL_GGRO
416
0
        if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) {
417
0
            SCLogPerf("%s: disabling gro offloading", dev);
418
0
            SetEthtoolValue(dev, ETHTOOL_SGRO, 0);
419
0
            ldev->offload_orig |= OFFLOAD_FLAG_GRO;
420
0
        }
421
0
#endif
422
0
#ifdef ETHTOOL_GTSO
423
0
        if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) {
424
0
            SCLogPerf("%s: disabling tso offloading", dev);
425
0
            SetEthtoolValue(dev, ETHTOOL_STSO, 0);
426
0
            ldev->offload_orig |= OFFLOAD_FLAG_TSO;
427
0
        }
428
0
#endif
429
0
#ifdef ETHTOOL_GGSO
430
0
        if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) {
431
0
            SCLogPerf("%s: disabling gso offloading", dev);
432
0
            SetEthtoolValue(dev, ETHTOOL_SGSO, 0);
433
0
            ldev->offload_orig |= OFFLOAD_FLAG_GSO;
434
0
        }
435
0
#endif
436
0
#ifdef ETHTOOL_GSG
437
0
        if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) {
438
0
            SCLogPerf("%s: disabling sg offloading", dev);
439
0
            SetEthtoolValue(dev, ETHTOOL_SSG, 0);
440
0
            ldev->offload_orig |= OFFLOAD_FLAG_SG;
441
0
        }
442
0
#endif
443
0
#ifdef ETHTOOL_GFLAGS
444
0
        if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
445
0
            if (value & ETH_FLAG_LRO) {
446
0
                SCLogPerf("%s: disabling lro offloading", dev);
447
0
                SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ~ETH_FLAG_LRO);
448
0
                ldev->offload_orig |= OFFLOAD_FLAG_LRO;
449
0
            }
450
0
        }
451
0
#endif
452
0
    }
453
0
    return ret;
454
0
}
455
456
static int RestoreIfaceOffloadingLinux(LiveDevice *ldev)
457
0
{
458
0
    if (ldev == NULL)
459
0
        return -1;
460
461
0
    const char *dev = ldev->dev;
462
463
0
#ifdef ETHTOOL_GRXCSUM
464
0
    if (ldev->offload_orig & OFFLOAD_FLAG_RXCSUM) {
465
0
        SCLogPerf("%s: restoring rxcsum offloading", dev);
466
0
        SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 1);
467
0
    }
468
0
#endif
469
0
#ifdef ETHTOOL_GTXCSUM
470
0
    if (ldev->offload_orig & OFFLOAD_FLAG_TXCSUM) {
471
0
        SCLogPerf("%s: restoring txcsum offloading", dev);
472
0
        SetEthtoolValue(dev, ETHTOOL_STXCSUM, 1);
473
0
    }
474
0
#endif
475
0
#ifdef ETHTOOL_GGRO
476
0
    if (ldev->offload_orig & OFFLOAD_FLAG_GRO) {
477
0
        SCLogPerf("%s: restoring gro offloading", dev);
478
0
        SetEthtoolValue(dev, ETHTOOL_SGRO, 1);
479
0
    }
480
0
#endif
481
0
#ifdef ETHTOOL_GTSO
482
0
    if (ldev->offload_orig & OFFLOAD_FLAG_TSO) {
483
0
        SCLogPerf("%s: restoring tso offloading", dev);
484
0
        SetEthtoolValue(dev, ETHTOOL_STSO, 1);
485
0
    }
486
0
#endif
487
0
#ifdef ETHTOOL_GGSO
488
0
    if (ldev->offload_orig & OFFLOAD_FLAG_GSO) {
489
0
        SCLogPerf("%s: restoring gso offloading", dev);
490
0
        SetEthtoolValue(dev, ETHTOOL_SGSO, 1);
491
0
    }
492
0
#endif
493
0
#ifdef ETHTOOL_GSG
494
0
    if (ldev->offload_orig & OFFLOAD_FLAG_SG) {
495
0
        SCLogPerf("%s: restoring sg offloading", dev);
496
0
        SetEthtoolValue(dev, ETHTOOL_SSG, 1);
497
0
    }
498
0
#endif
499
0
#ifdef ETHTOOL_GFLAGS
500
0
    if (ldev->offload_orig & OFFLOAD_FLAG_LRO) {
501
0
        uint32_t value = 0;
502
0
        if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) {
503
0
            SCLogPerf("%s: restoring lro offloading", dev);
504
0
            SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ETH_FLAG_LRO);
505
0
        }
506
0
    }
507
0
#endif
508
0
    return 0;
509
0
}
510
511
#endif /* defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL */
512
513
#ifdef SIOCGIFCAP
514
static int GetIfaceOffloadingBSD(const char *ifname)
515
{
516
    int ret = 0;
517
    int if_caps = GetIfaceCaps(ifname);
518
    if (if_caps == -1) {
519
        return -1;
520
    }
521
    SCLogDebug("if_caps %X", if_caps);
522
523
    if (if_caps & IFCAP_RXCSUM) {
524
        SCLogWarning("%s: RXCSUM activated can lead to capture problems. Run: ifconfig %s -rxcsum",
525
                ifname, ifname);
526
        ret = 1;
527
    }
528
#ifdef IFCAP_TOE
529
    if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) {
530
        SCLogWarning("%s: TSO, TOE or LRO activated can lead to capture problems. Run: ifconfig %s "
531
                     "-tso -toe -lro",
532
                ifname, ifname);
533
        ret = 1;
534
    }
535
#else
536
    if (if_caps & (IFCAP_TSO|IFCAP_LRO)) {
537
        SCLogWarning(
538
                "%s: TSO or LRO activated can lead to capture problems. Run: ifconfig %s -tso -lro",
539
                ifname, ifname);
540
        ret = 1;
541
    }
542
#endif
543
    return ret;
544
}
545
#endif
546
547
#ifdef SIOCSIFCAP
548
static int DisableIfaceOffloadingBSD(LiveDevice *ldev)
549
{
550
    int ret = 0;
551
552
    if (ldev == NULL)
553
        return -1;
554
555
    const char *ifname = ldev->dev;
556
    int if_caps = GetIfaceCaps(ifname);
557
    int set_caps = if_caps;
558
    if (if_caps == -1) {
559
        return -1;
560
    }
561
    SCLogDebug("if_caps %X", if_caps);
562
563
    if (if_caps & IFCAP_RXCSUM) {
564
        SCLogPerf("%s: disabling rxcsum offloading", ifname);
565
        set_caps &= ~IFCAP_RXCSUM;
566
    }
567
    if (if_caps & IFCAP_TXCSUM) {
568
        SCLogPerf("%s: disabling txcsum offloading", ifname);
569
        set_caps &= ~IFCAP_TXCSUM;
570
    }
571
#ifdef IFCAP_RXCSUM_IPV6
572
    if (if_caps & IFCAP_RXCSUM_IPV6) {
573
        SCLogPerf("%s: disabling rxcsum6 offloading", ifname);
574
        set_caps &= ~IFCAP_RXCSUM_IPV6;
575
    }
576
#endif
577
#ifdef IFCAP_TXCSUM_IPV6
578
    if (if_caps & IFCAP_TXCSUM_IPV6) {
579
        SCLogPerf("%s: disabling txcsum6 offloading", ifname);
580
        set_caps &= ~IFCAP_TXCSUM_IPV6;
581
    }
582
#endif
583
#ifdef IFCAP_TOE
584
    if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) {
585
        SCLogPerf("%s: disabling tso|toe|lro offloading", ifname);
586
        set_caps &= ~(IFCAP_TSO|IFCAP_LRO);
587
    }
588
#else
589
    if (if_caps & (IFCAP_TSO|IFCAP_LRO)) {
590
        SCLogPerf("%s: disabling tso|lro offloading", ifname);
591
        set_caps &= ~(IFCAP_TSO|IFCAP_LRO);
592
    }
593
#endif
594
    if (set_caps != if_caps) {
595
        if (if_caps & IFCAP_RXCSUM)
596
            ldev->offload_orig |= OFFLOAD_FLAG_RXCSUM;
597
        if (if_caps & IFCAP_TSO)
598
            ldev->offload_orig |= OFFLOAD_FLAG_TSO;
599
#ifdef IFCAP_TOE
600
        if (if_caps & IFCAP_TOE)
601
            ldev->offload_orig |= OFFLOAD_FLAG_TOE;
602
#endif
603
        if (if_caps & IFCAP_LRO)
604
            ldev->offload_orig |= OFFLOAD_FLAG_LRO;
605
606
        SetIfaceCaps(ifname, set_caps);
607
    }
608
    return ret;
609
}
610
611
static int RestoreIfaceOffloadingBSD(LiveDevice *ldev)
612
{
613
    int ret = 0;
614
615
    if (ldev == NULL)
616
        return -1;
617
618
    const char *ifname = ldev->dev;
619
    int if_caps = GetIfaceCaps(ifname);
620
    int set_caps = if_caps;
621
    if (if_caps == -1) {
622
        return -1;
623
    }
624
    SCLogDebug("if_caps %X", if_caps);
625
626
    if (ldev->offload_orig & OFFLOAD_FLAG_RXCSUM) {
627
        SCLogPerf("%s: restoring rxcsum offloading", ifname);
628
        set_caps |= IFCAP_RXCSUM;
629
    }
630
    if (ldev->offload_orig & OFFLOAD_FLAG_TSO) {
631
        SCLogPerf("%s: restoring tso offloading", ifname);
632
        set_caps |= IFCAP_TSO;
633
    }
634
#ifdef IFCAP_TOE
635
    if (ldev->offload_orig & OFFLOAD_FLAG_TOE) {
636
        SCLogPerf("%s: restoring toe offloading", ifname);
637
        set_caps |= IFCAP_TOE;
638
    }
639
#endif
640
    if (ldev->offload_orig & OFFLOAD_FLAG_LRO) {
641
        SCLogPerf("%s: restoring lro offloading", ifname);
642
        set_caps |= IFCAP_LRO;
643
    }
644
645
    if (set_caps != if_caps) {
646
        SetIfaceCaps(ifname, set_caps);
647
    }
648
    return ret;
649
}
650
#endif
651
652
/**
653
 * \brief output offloading status of the link
654
 *
655
 * Test interface for offloading features. If one of them is
656
 * activated then suricata mays received packets merge at reception.
657
 * The result is oversized packets and this may cause some serious
658
 * problem in some capture mode where the size of the packet is
659
 * limited (AF_PACKET in V2 more for example).
660
 *
661
 * \param Name of link
662
 * \param csum check if checksums are offloaded
663
 * \param other check if other things are offloaded: TSO, GRO, etc.
664
 * \retval -1 in case of error, 0 if none, 1 if some
665
 */
666
int GetIfaceOffloading(const char *dev, int csum, int other)
667
0
{
668
0
#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
669
0
    return GetIfaceOffloadingLinux(dev, csum, other);
670
#elif defined SIOCGIFCAP
671
    return GetIfaceOffloadingBSD(dev);
672
#elif defined OS_WIN32
673
    return GetIfaceOffloadingWin32(dev, csum, other);
674
#else
675
    return 0;
676
#endif
677
0
}
678
679
int DisableIfaceOffloading(LiveDevice *dev, int csum, int other)
680
0
{
681
    /* already set */
682
0
    if (dev->offload_orig != 0)
683
0
        return 0;
684
0
#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
685
0
    return DisableIfaceOffloadingLinux(dev, csum, other);
686
#elif defined SIOCSIFCAP
687
    return DisableIfaceOffloadingBSD(dev);
688
#elif defined OS_WIN32
689
    return DisableIfaceOffloadingWin32(dev, csum, other);
690
#else
691
    return 0;
692
#endif
693
694
0
}
695
696
void RestoreIfaceOffloading(LiveDevice *dev)
697
0
{
698
0
    if (dev->offload_orig != 0) {
699
0
#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL
700
0
        RestoreIfaceOffloadingLinux(dev);
701
#elif defined SIOCSIFCAP
702
        RestoreIfaceOffloadingBSD(dev);
703
#elif defined OS_WIN32
704
        RestoreIfaceOffloadingWin32(dev);
705
#endif
706
0
    }
707
0
}
708
709
int GetIfaceRSSQueuesNum(const char *dev)
710
0
{
711
0
#if defined HAVE_LINUX_ETHTOOL_H && defined ETHTOOL_GRXRINGS
712
0
    struct ifreq ifr;
713
0
    struct ethtool_rxnfc nfccmd;
714
0
    int fd;
715
716
0
    (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
717
0
    fd = socket(AF_INET, SOCK_DGRAM, 0);
718
0
    if (fd == -1) {
719
0
        SCLogWarning("%s: failed to open socket for ioctl: %s", dev, strerror(errno));
720
0
        return -1;
721
0
    }
722
723
0
    nfccmd.cmd = ETHTOOL_GRXRINGS;
724
0
    ifr.ifr_data = (void*) &nfccmd;
725
726
0
    if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) {
727
0
        if (errno != ENOTSUP) {
728
0
            SCLogWarning("%s: failed get number of RSS queue ioctl: %s", dev, strerror(errno));
729
0
        }
730
0
        close(fd);
731
0
        return 0;
732
0
    }
733
0
    close(fd);
734
0
    SCLogInfo("%s: RX RSS queues: %d", dev, (int)nfccmd.data);
735
0
    return (int)nfccmd.data;
736
#else
737
    return 0;
738
#endif
739
0
}