LCOV - code coverage report
Current view: top level - libbpfilter - matcher.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 17.7 % 419 74
Test Date: 2025-09-30 16:37:25 Functions: 22.8 % 57 13

            Line data    Source code
       1              : /* SPDX-License-Identifier: GPL-2.0-only */
       2              : /*
       3              :  * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
       4              :  */
       5              : 
       6              : #include "bpfilter/matcher.h"
       7              : 
       8              : #include <linux/icmp.h>
       9              : #include <linux/icmpv6.h>
      10              : #include <linux/if_ether.h>
      11              : #include <linux/in.h>
      12              : #include <linux/in6.h>
      13              : #include <linux/ip.h>
      14              : #include <linux/ipv6.h>
      15              : #include <linux/tcp.h>
      16              : #include <linux/udp.h>
      17              : 
      18              : #include <ctype.h>
      19              : #include <endian.h>
      20              : #include <errno.h>
      21              : #include <inttypes.h>
      22              : #include <limits.h>
      23              : #include <stdint.h>
      24              : #include <stdlib.h>
      25              : #include <string.h>
      26              : 
      27              : #include "bpfilter/dump.h"
      28              : #include "bpfilter/helper.h"
      29              : #include "bpfilter/if.h"
      30              : #include "bpfilter/logger.h"
      31              : #include "bpfilter/pack.h"
      32              : #include "bpfilter/runtime.h"
      33              : 
      34              : #define INET4_ADDRSTRLEN 16
      35              : #define INET6_ADDRSTRLEN 46
      36              : 
      37              : #define BF_PAYLOAD_OPS(type, size, parser_cb, printer_cb)                      \
      38              :     [type] = {size, parser_cb, printer_cb}
      39              : 
      40              : extern int inet_pton(int, const char *, void *);
      41              : extern const char *inet_ntop(int, const void *, char *, socklen_t);
      42              : 
      43              : /**
      44              :  * Matcher definition.
      45              :  *
      46              :  * Matchers are criterias to match the packet against. A set of matcher defines
      47              :  * what a rule should match on.
      48              :  *
      49              :  * @todo `bf_matcher`'s payload should be a union of all the possible payload
      50              :  * types.
      51              :  */
      52              : struct bf_matcher
      53              : {
      54              :     /// Matcher type.
      55              :     enum bf_matcher_type type;
      56              :     /// Comparison operator.
      57              :     enum bf_matcher_op op;
      58              :     /// Total matcher size (including payload).
      59              :     size_t len;
      60              :     /// Payload to match the packet against (if any).
      61              :     uint8_t payload[];
      62              : };
      63              : 
      64            0 : int _bf_parse_iface(enum bf_matcher_type type, enum bf_matcher_op op,
      65              :                     void *payload, const char *raw_payload)
      66              : {
      67            0 :     bf_assert(payload && raw_payload);
      68              : 
      69              :     int idx;
      70              :     unsigned long ifindex;
      71              :     char *endptr;
      72              : 
      73            0 :     idx = bf_if_index_from_name(raw_payload);
      74            0 :     if (idx > 0) {
      75            0 :         *(uint32_t *)payload = (uint32_t)idx;
      76            0 :         return 0;
      77              :     }
      78              : 
      79            0 :     ifindex = strtoul(raw_payload, &endptr, BF_BASE_10);
      80            0 :     if (*endptr == '\0' && 0 < ifindex && ifindex <= UINT32_MAX) {
      81            0 :         *(uint32_t *)payload = (uint32_t)ifindex;
      82            0 :         return 0;
      83              :     }
      84              : 
      85            0 :     bf_err(
      86              :         "\"%s %s\" expects an interface name (e.g., \"eth0\", \"wlan0\") or a decimal interface index (e.g., \"1\", \"2\"), not '%s'",
      87              :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
      88              : 
      89              :     return -EINVAL;
      90              : }
      91              : 
      92            0 : void _bf_print_iface(const void *payload)
      93              : {
      94            0 :     bf_assert(payload);
      95              : 
      96              :     const char *ifname;
      97            0 :     uint32_t ifindex = *(uint32_t *)payload;
      98              : 
      99            0 :     ifname = bf_if_name_from_index((int)ifindex);
     100            0 :     if (ifname)
     101            0 :         (void)fprintf(stdout, "%s", ifname);
     102              :     else
     103            0 :         (void)fprintf(stdout, "%" PRIu32, ifindex);
     104            0 : }
     105              : 
     106            0 : int _bf_parse_l3_proto(enum bf_matcher_type type, enum bf_matcher_op op,
     107              :                        void *payload, const char *raw_payload)
     108              : {
     109            0 :     bf_assert(payload && raw_payload);
     110              : 
     111              :     unsigned long ethertype;
     112              :     char *endptr;
     113              :     int r;
     114              : 
     115            0 :     r = bf_ethertype_from_str(raw_payload, payload);
     116            0 :     if (!r)
     117              :         return 0;
     118              : 
     119            0 :     ethertype = strtoul(raw_payload, &endptr, BF_BASE_10);
     120            0 :     if (*endptr == '\0' && ethertype <= UINT16_MAX) {
     121            0 :         *(uint16_t *)payload = (uint16_t)ethertype;
     122            0 :         return 0;
     123              :     }
     124              : 
     125            0 :     ethertype = strtoul(raw_payload, &endptr, BF_BASE_16);
     126            0 :     if (*endptr == '\0' && ethertype <= UINT16_MAX) {
     127            0 :         *(uint16_t *)payload = (uint16_t)ethertype;
     128            0 :         return 0;
     129              :     }
     130              : 
     131            0 :     bf_err(
     132              :         "\"%s %s\" expects an internet layer protocol name (e.g. \"IPv6\", case insensitive), or a valid decimal or hexadecimal IEEE 802 number, not '%s'",
     133              :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     134              : 
     135              :     return -EINVAL;
     136              : }
     137              : 
     138            0 : void _bf_print_l3_proto(const void *payload)
     139              : {
     140            0 :     bf_assert(payload);
     141              : 
     142            0 :     const char *ethertype = bf_ethertype_to_str(*(uint16_t *)payload);
     143              : 
     144            0 :     if (ethertype)
     145            0 :         (void)fprintf(stdout, "%s", ethertype);
     146              :     else
     147            0 :         (void)fprintf(stdout, "0x%04" PRIx16, *(uint16_t *)payload);
     148            0 : }
     149              : 
     150           24 : int _bf_parse_l4_proto(enum bf_matcher_type type, enum bf_matcher_op op,
     151              :                        void *payload, const char *raw_payload)
     152              : {
     153           24 :     bf_assert(payload && raw_payload);
     154              : 
     155              :     unsigned long ipproto;
     156              :     char *endptr;
     157              :     int r;
     158              : 
     159           24 :     r = bf_ipproto_from_str(raw_payload, payload);
     160           24 :     if (!r)
     161              :         return 0;
     162              : 
     163            0 :     ipproto = strtoul(raw_payload, &endptr, BF_BASE_10);
     164            0 :     if (*endptr == '\0' && ipproto <= UINT8_MAX) {
     165            0 :         *(uint8_t *)payload = (uint8_t)ipproto;
     166            0 :         return 0;
     167              :     }
     168              : 
     169            0 :     bf_err(
     170              :         "\"%s %s\" expects a transport layer protocol name (e.g. \"ICMP\", case insensitive), or a valid decimal internet protocol number, not '%s'",
     171              :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     172              : 
     173              :     return -EINVAL;
     174              : }
     175              : 
     176            0 : void _bf_print_l4_proto(const void *payload)
     177              : {
     178            0 :     bf_assert(payload);
     179              : 
     180            0 :     const char *ipproto = bf_ipproto_to_str(*(uint8_t *)payload);
     181              : 
     182            0 :     if (ipproto)
     183            0 :         (void)fprintf(stdout, "%s", ipproto);
     184              :     else
     185            0 :         (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
     186            0 : }
     187              : 
     188            0 : int _bf_parse_l4_port(enum bf_matcher_type type, enum bf_matcher_op op,
     189              :                       void *payload, const char *raw_payload)
     190              : {
     191            0 :     bf_assert(payload && raw_payload);
     192              : 
     193              :     unsigned long port;
     194              :     char *endptr;
     195              : 
     196            0 :     port = strtoul(raw_payload, &endptr, BF_BASE_10);
     197            0 :     if (*endptr == '\0' && port <= UINT16_MAX) {
     198            0 :         *(uint16_t *)payload = htobe16((uint16_t)port);
     199            0 :         return 0;
     200              :     }
     201              : 
     202            0 :     bf_err("\"%s %s\" expects a valid decimal port number, not '%s'",
     203              :            bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     204              : 
     205              :     return -EINVAL;
     206              : }
     207              : 
     208            0 : void _bf_print_l4_port(const void *payload)
     209              : {
     210            0 :     bf_assert(payload);
     211              : 
     212            0 :     (void)fprintf(stdout, "%" PRIu16, (uint16_t)be16toh(*(uint16_t *)payload));
     213            0 : }
     214              : 
     215              : #define BF_PORT_RANGE_MAX_LEN 16 // 65535-65535, with nul char, round to **2
     216              : 
     217            0 : static int _bf_parse_l4_port_range(enum bf_matcher_type type,
     218              :                                    enum bf_matcher_op op, void *payload,
     219              :                                    const char *raw_payload)
     220              : {
     221            0 :     bf_assert(payload && raw_payload);
     222              : 
     223              :     uint16_t *ports = (uint16_t *)payload;
     224              :     unsigned long port;
     225              :     char buf[BF_PORT_RANGE_MAX_LEN];
     226              :     char *first;
     227              :     char *second;
     228              :     char *endptr;
     229              : 
     230            0 :     bf_strncpy(buf, BF_PORT_RANGE_MAX_LEN, raw_payload);
     231              : 
     232            0 :     if (!isdigit(*raw_payload))
     233            0 :         goto err;
     234              : 
     235            0 :     first = strtok_r(buf, "-", &second);
     236            0 :     if (!first)
     237            0 :         goto err;
     238              : 
     239            0 :     if (!*second)
     240            0 :         goto err;
     241              : 
     242            0 :     port = strtoul(first, &endptr, BF_BASE_10);
     243            0 :     if (*endptr != '\0' || port > UINT16_MAX)
     244            0 :         goto err;
     245            0 :     ports[0] = (uint16_t)port;
     246              : 
     247            0 :     port = strtoul(second, &endptr, BF_BASE_10);
     248            0 :     if (*endptr != '\0' || port > UINT16_MAX)
     249            0 :         goto err;
     250            0 :     ports[1] = (uint16_t)port;
     251              : 
     252            0 :     if (ports[1] < ports[0])
     253            0 :         goto err;
     254              : 
     255              :     return 0;
     256              : 
     257            0 : err:
     258            0 :     bf_err(
     259              :         "\"%s %s\" expects two positive decimal port numbers as `$START-$END`, with `$START <= $END`, not '%s'",
     260              :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     261              : 
     262              :     return -EINVAL;
     263              : }
     264              : 
     265            0 : void _bf_print_l4_port_range(const void *payload)
     266              : {
     267            0 :     bf_assert(payload);
     268              : 
     269              :     uint16_t *ports = (uint16_t *)payload;
     270              : 
     271            0 :     (void)fprintf(stdout, "%" PRIu16 "-%" PRIu16, ports[0], ports[1]);
     272            0 : }
     273              : 
     274            0 : static int _bf_parse_probability(enum bf_matcher_type type,
     275              :                                  enum bf_matcher_op op, void *payload,
     276              :                                  const char *raw_payload)
     277              : {
     278            0 :     bf_assert(payload && raw_payload);
     279              : 
     280              :     unsigned long proba;
     281              :     char *endptr;
     282              : 
     283            0 :     proba = strtoul(raw_payload, &endptr, BF_BASE_10);
     284            0 :     if (endptr[0] == '%' && endptr[1] == '\0' && proba <= 100) {
     285            0 :         *(uint8_t *)payload = (uint8_t)proba;
     286            0 :         return 0;
     287              :     }
     288              : 
     289            0 :     bf_err(
     290              :         "\"%s %s\" expects a valid decimal percentage value (i.e., within [0%%, 100%%]), not '%s'",
     291              :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     292              : 
     293              :     return -EINVAL;
     294              : }
     295              : 
     296            0 : void _bf_print_probability(const void *payload)
     297              : {
     298            0 :     bf_assert(payload);
     299              : 
     300            0 :     (void)fprintf(stdout, "%" PRIu8 "%%", *(uint8_t *)payload);
     301            0 : }
     302              : 
     303            0 : static int _bf_parse_mark(enum bf_matcher_type type, enum bf_matcher_op op,
     304              :                           void *payload, const char *raw_payload)
     305              : {
     306              :     long long mark;
     307              :     char *endptr;
     308              : 
     309              :     UNUSED(type);
     310              :     UNUSED(op);
     311              : 
     312            0 :     bf_assert(payload);
     313            0 :     bf_assert(raw_payload);
     314              : 
     315            0 :     mark = strtoll(raw_payload, &endptr, 0);
     316            0 :     if (*endptr) {
     317            0 :         return bf_err_r(-EINVAL,
     318              :                         "mark value '%s' can't be parsed as a positive integer",
     319              :                         raw_payload);
     320              :     }
     321            0 :     if (mark < 0) {
     322            0 :         return bf_err_r(-EINVAL, "mark should be positive, not '%s'",
     323              :                         raw_payload);
     324              :     }
     325            0 :     if (mark > UINT32_MAX)
     326            0 :         return bf_err_r(-EINVAL, "mark should be at most 0x%x", UINT32_MAX);
     327              : 
     328            0 :     *(uint32_t *)payload = (uint32_t)mark;
     329              : 
     330            0 :     return 0;
     331              : }
     332              : 
     333            0 : void _bf_print_mark(const void *payload)
     334              : {
     335            0 :     bf_assert(payload);
     336              : 
     337            0 :     (void)fprintf(stdout, "0x%" PRIx32, *(uint32_t *)payload);
     338            0 : }
     339              : 
     340           20 : static int _bf_parse_ipv4_addr(enum bf_matcher_type type, enum bf_matcher_op op,
     341              :                                void *payload, const char *raw_payload)
     342              : {
     343           20 :     bf_assert(payload && raw_payload);
     344              : 
     345              :     int r;
     346              : 
     347           20 :     r = inet_pton(AF_INET, raw_payload, payload);
     348           20 :     if (r == 1)
     349              :         return 0;
     350              : 
     351            0 :     bf_err(
     352              :         "\"%s %s\" expects an IPv4 address in dotted-decimal format, \"ddd.ddd.ddd.ddd\", where ddd is a decimal number of up to three digits in the range 0 to 255, not '%s' ",
     353              :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     354              : 
     355              :     return -EINVAL;
     356              : }
     357              : 
     358            0 : void _bf_print_ipv4_addr(const void *payload)
     359              : {
     360            0 :     bf_assert(payload);
     361              : 
     362              :     char str[INET4_ADDRSTRLEN];
     363              : 
     364            0 :     if (inet_ntop(AF_INET, payload, str, INET4_ADDRSTRLEN))
     365            0 :         (void)fprintf(stdout, "%s", str);
     366              :     else
     367            0 :         (void)fprintf(stdout, "<failed to print IPv4 address>");
     368            0 : }
     369              : 
     370              : #define BF_IPV4_NET_MAX_LEN                                                    \
     371              :     32 // 255.255.255.255/32, with nul char, round to **2
     372              : 
     373            0 : static int _bf_parse_ipv4_net(enum bf_matcher_type type, enum bf_matcher_op op,
     374              :                               void *payload, const char *raw_payload)
     375              : {
     376            0 :     bf_assert(payload && raw_payload);
     377              : 
     378              :     struct bf_ip4_lpm_key *addr = payload;
     379              :     char buf[BF_IPV4_NET_MAX_LEN];
     380              :     char *strip, *strmask, *endptr;
     381              :     int r;
     382              : 
     383            0 :     bf_strncpy(buf, BF_IPV4_NET_MAX_LEN, raw_payload);
     384              : 
     385            0 :     if (!isdigit(*raw_payload))
     386            0 :         goto err;
     387              : 
     388            0 :     strip = strtok_r(buf, "/", &strmask);
     389            0 :     if (!strip || !*strmask)
     390            0 :         goto err;
     391              : 
     392            0 :     r = inet_pton(AF_INET, strip, &addr->data);
     393            0 :     if (r != 1)
     394            0 :         goto err;
     395              : 
     396            0 :     addr->prefixlen = strtoul(strmask, &endptr, BF_BASE_10);
     397            0 :     if (*endptr != '\0' || addr->prefixlen > 32)
     398            0 :         goto err;
     399              : 
     400              :     return 0;
     401              : 
     402            0 : err:
     403            0 :     bf_err(
     404              :         "\"%s %s\" expects an IPv4 network address in dotted-decimal format, \"ddd.ddd.ddd.ddd\", where ddd is a decimal number of up to three digits in the range 0 to 255 followed by a subnet mask (e.g., \"124.24.12.5/30\"), not '%s' ",
     405              :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     406              : 
     407              :     return -EINVAL;
     408              : }
     409              : 
     410            0 : void _bf_print_ipv4_net(const void *payload)
     411              : {
     412            0 :     bf_assert(payload);
     413              : 
     414              :     char str[INET4_ADDRSTRLEN];
     415              :     const struct bf_ip4_lpm_key *addr = payload;
     416              : 
     417            0 :     if (inet_ntop(AF_INET, &addr->data, str, INET4_ADDRSTRLEN))
     418            0 :         (void)fprintf(stdout, "%s/%u", str, addr->prefixlen);
     419              :     else
     420            0 :         (void)fprintf(stdout, "<failed to print IPv4 network>");
     421            0 : }
     422              : 
     423            0 : static int _bf_parse_ipv6_addr(enum bf_matcher_type type, enum bf_matcher_op op,
     424              :                                void *payload, const char *raw_payload)
     425              : {
     426            0 :     bf_assert(payload && raw_payload);
     427              : 
     428              :     int r;
     429              : 
     430            0 :     r = inet_pton(AF_INET6, raw_payload, payload);
     431            0 :     if (r == 1)
     432              :         return 0;
     433              : 
     434            0 :     bf_err(
     435              :         "\"%s %s\" expects an IPv6 address composed of 8 hexadecimal numbers (abbreviations are supported), not '%s' ",
     436              :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     437              : 
     438              :     return -EINVAL;
     439              : }
     440              : 
     441            0 : void _bf_print_ipv6_addr(const void *payload)
     442              : {
     443            0 :     bf_assert(payload);
     444              : 
     445              :     char str[INET6_ADDRSTRLEN];
     446              : 
     447            0 :     if (inet_ntop(AF_INET6, payload, str, INET6_ADDRSTRLEN))
     448            0 :         (void)fprintf(stdout, "%s", str);
     449              :     else
     450            0 :         (void)fprintf(stdout, "<failed to print IPv6 address>");
     451            0 : }
     452              : 
     453              : #define BF_IPV6_NET_MAX_LEN (INET6_ADDRSTRLEN + 4)
     454              : 
     455            0 : static int _bf_parse_ipv6_net(enum bf_matcher_type type, enum bf_matcher_op op,
     456              :                               void *payload, const char *raw_payload)
     457              : {
     458            0 :     bf_assert(payload && raw_payload);
     459              : 
     460              :     struct bf_ip6_lpm_key *addr = payload;
     461              :     char buf[BF_IPV6_NET_MAX_LEN];
     462              :     char *strip, *strmask, *endptr;
     463              :     int r;
     464              : 
     465            0 :     bf_strncpy(buf, BF_IPV6_NET_MAX_LEN, raw_payload);
     466              : 
     467            0 :     if (!isalpha(*raw_payload) && !isdigit(*raw_payload) && *raw_payload != ':')
     468            0 :         goto err;
     469              : 
     470            0 :     strip = strtok_r(buf, "/", &strmask);
     471            0 :     if (!strip || !*strmask)
     472            0 :         goto err;
     473              : 
     474            0 :     r = inet_pton(AF_INET6, strip, &addr->data);
     475            0 :     if (r != 1)
     476            0 :         goto err;
     477              : 
     478            0 :     addr->prefixlen = strtoul(strmask, &endptr, BF_BASE_10);
     479            0 :     if (*endptr != '\0' || addr->prefixlen > 128)
     480            0 :         goto err;
     481              : 
     482              :     return 0;
     483              : 
     484            0 : err:
     485            0 :     bf_err(
     486              :         "\"%s %s\" expects an IPv6 network address composed of 8 hexadecimal numbers (abbreviations are supported) followed by a subnet mask (e.g., \"2001:db8:85a3::/48\"), not '%s' ",
     487              :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     488              : 
     489              :     return -EINVAL;
     490              : }
     491              : 
     492            0 : void _bf_print_ipv6_net(const void *payload)
     493              : {
     494            0 :     bf_assert(payload);
     495              : 
     496              :     const struct bf_ip6_lpm_key *addr = payload;
     497              :     char str[INET6_ADDRSTRLEN];
     498              : 
     499            0 :     if (inet_ntop(AF_INET6, addr->data, str, INET6_ADDRSTRLEN))
     500            0 :         (void)fprintf(stdout, "%s/%u", str, addr->prefixlen);
     501              :     else
     502            0 :         (void)fprintf(stdout, "<failed to print IPv6 address>");
     503            0 : }
     504              : 
     505            0 : static int _bf_parse_tcp_flags(enum bf_matcher_type type, enum bf_matcher_op op,
     506              :                                void *payload, const char *raw_payload)
     507              : {
     508            0 :     bf_assert(payload && raw_payload);
     509              : 
     510              :     _cleanup_free_ char *_raw_payload = NULL;
     511              :     char *tmp;
     512              :     char *saveptr;
     513              :     char *token;
     514              :     uint8_t *flags = payload;
     515              : 
     516            0 :     _raw_payload = strdup(raw_payload);
     517              :     if (!raw_payload)
     518              :         goto err;
     519              : 
     520            0 :     *flags = 0;
     521              :     tmp = _raw_payload;
     522              : 
     523            0 :     while ((token = strtok_r(tmp, ",", &saveptr))) {
     524              :         enum bf_tcp_flag new_flag;
     525              :         int r;
     526              : 
     527            0 :         r = bf_tcp_flag_from_str(token, &new_flag);
     528            0 :         if (r)
     529            0 :             goto err;
     530              : 
     531            0 :         *flags |= (uint8_t)(1 << new_flag);
     532              : 
     533              :         tmp = NULL;
     534              :     }
     535              : 
     536              :     return 0;
     537              : 
     538              : err:
     539            0 :     bf_err(
     540              :         "\"%s %s\" expects a comma-separated list of one or more TCP flags (fin, syn, rst, psh, ack, urg, ece, or cwr), not '%s' ",
     541              :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     542              : 
     543              :     return -EINVAL;
     544              : }
     545              : 
     546            0 : void _bf_print_tcp_flags(const void *payload)
     547              : {
     548            0 :     bf_assert(payload);
     549              : 
     550            0 :     uint8_t flag = *(uint8_t *)payload;
     551              : 
     552            0 :     for (uint32_t i = 0; i < _BF_TCP_MAX; ++i) {
     553            0 :         if (flag & (1 << i)) {
     554            0 :             flag &= ~(1 << i);
     555            0 :             (void)fprintf(stdout, "%s%s", bf_tcp_flag_to_str(i),
     556              :                           flag ? "," : "");
     557              :         }
     558              :     }
     559            0 : }
     560              : 
     561            0 : static int _bf_parse_icmp_type(enum bf_matcher_type type, enum bf_matcher_op op,
     562              :                                void *payload, const char *raw_payload)
     563              : {
     564            0 :     bf_assert(payload && raw_payload);
     565              : 
     566              :     unsigned long icmptype;
     567              :     char *endptr;
     568              :     int r;
     569              : 
     570            0 :     r = bf_icmp_type_from_str(raw_payload, payload);
     571            0 :     if (!r)
     572              :         return 0;
     573              : 
     574            0 :     icmptype = strtoul(raw_payload, &endptr, BF_BASE_10);
     575              : 
     576            0 :     if (*endptr == '\0' && icmptype <= UINT8_MAX) {
     577            0 :         *(uint8_t *)payload = (uint8_t)icmptype;
     578            0 :         return 0;
     579              :     }
     580              : 
     581            0 :     icmptype = strtoul(raw_payload, &endptr, BF_BASE_16);
     582            0 :     if (*endptr == '\0' && icmptype <= UINT8_MAX) {
     583            0 :         *(uint8_t *)payload = (uint8_t)icmptype;
     584            0 :         return 0;
     585              :     }
     586              : 
     587            0 :     bf_err(
     588              :         "\"%s %s\" expects an ICMP type name (e.g. \"echo-reply\", case insensitive), or or a decimal or hexadecimal ICMP type value, not '%s'",
     589              :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     590              : 
     591              :     return -EINVAL;
     592              : }
     593              : 
     594            0 : void _bf_print_icmp_type(const void *payload)
     595              : {
     596            0 :     bf_assert(payload);
     597              : 
     598            0 :     const char *type = bf_icmp_type_to_str(*(uint8_t *)payload);
     599              : 
     600            0 :     if (type)
     601            0 :         (void)fprintf(stdout, "%s", type);
     602              :     else
     603            0 :         (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
     604            0 : }
     605              : 
     606            0 : static int _bf_parse_icmp_code(enum bf_matcher_type type, enum bf_matcher_op op,
     607              :                                void *payload, const char *raw_payload)
     608              : {
     609            0 :     bf_assert(payload && raw_payload);
     610              : 
     611              :     unsigned long code;
     612              :     char *endptr;
     613              : 
     614            0 :     code = strtoul(raw_payload, &endptr, BF_BASE_10);
     615            0 :     if (*endptr == '\0' && code <= UINT8_MAX) {
     616            0 :         *(uint8_t *)payload = (uint8_t)code;
     617            0 :         return 0;
     618              :     }
     619              : 
     620            0 :     code = strtoul(raw_payload, &endptr, BF_BASE_16);
     621            0 :     if (*endptr == '\0' && code <= UINT8_MAX) {
     622            0 :         *(uint8_t *)payload = (uint8_t)code;
     623            0 :         return 0;
     624              :     }
     625              : 
     626            0 :     bf_err(
     627              :         "\"%s %s\" expects a decimal or hexadecimal ICMP or ICMPv6 code value, not '%s'",
     628              :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     629              : 
     630              :     return -EINVAL;
     631              : }
     632              : 
     633            0 : void _bf_print_icmp_code(const void *payload)
     634              : {
     635            0 :     bf_assert(payload);
     636              : 
     637            0 :     (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
     638            0 : }
     639              : 
     640            0 : static int _bf_parse_icmpv6_type(enum bf_matcher_type type,
     641              :                                  enum bf_matcher_op op, void *payload,
     642              :                                  const char *raw_payload)
     643              : {
     644            0 :     bf_assert(payload && raw_payload);
     645              : 
     646              :     unsigned long icmptype;
     647              :     char *endptr;
     648              :     int r;
     649              : 
     650            0 :     r = bf_icmpv6_type_from_str(raw_payload, payload);
     651            0 :     if (!r)
     652              :         return 0;
     653              : 
     654            0 :     icmptype = strtoul(raw_payload, &endptr, BF_BASE_10);
     655              : 
     656            0 :     if (*endptr == '\0' && icmptype <= UINT8_MAX) {
     657            0 :         *(uint8_t *)payload = (uint8_t)icmptype;
     658            0 :         return 0;
     659              :     }
     660              : 
     661            0 :     icmptype = strtoul(raw_payload, &endptr, BF_BASE_16);
     662            0 :     if (*endptr == '\0' && icmptype <= UINT8_MAX) {
     663            0 :         *(uint8_t *)payload = (uint8_t)icmptype;
     664            0 :         return 0;
     665              :     }
     666              : 
     667            0 :     bf_err(
     668              :         "\"%s %s\" expects an ICMPv6 type name (e.g. \"echo-reply\", case insensitive), or a decimal or hexadecimal ICMPv6 type value, not '%s'",
     669              :         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
     670              : 
     671              :     return -EINVAL;
     672              : }
     673              : 
     674            0 : void _bf_print_icmpv6_type(const void *payload)
     675              : {
     676            0 :     bf_assert(payload);
     677              : 
     678            0 :     const char *type = bf_icmpv6_type_to_str(*(uint8_t *)payload);
     679              : 
     680            0 :     if (type)
     681            0 :         (void)fprintf(stdout, "%s", type);
     682              :     else
     683            0 :         (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
     684            0 : }
     685              : 
     686              : #define BF_MATCHER_OPS(op, payload_size, parse_cb, print_cb)                   \
     687              :     [op] = {payload_size, parse_cb, print_cb}
     688              : 
     689              : #define _BF_TCP_FLAGS_OFFSET 13
     690              : 
     691              : static struct bf_matcher_meta _bf_matcher_metas[_BF_MATCHER_TYPE_MAX] = {
     692              :     [BF_MATCHER_META_IFACE] =
     693              :         {
     694              :             .layer = BF_MATCHER_NO_LAYER,
     695              :             .ops =
     696              :                 {
     697              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
     698              :                                    _bf_parse_iface, _bf_print_iface),
     699              :                 },
     700              :         },
     701              :     [BF_MATCHER_META_L3_PROTO] =
     702              :         {
     703              :             .layer = BF_MATCHER_NO_LAYER,
     704              :             .ops =
     705              :                 {
     706              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
     707              :                                    _bf_parse_l3_proto, _bf_print_l3_proto),
     708              :                 },
     709              :         },
     710              :     [BF_MATCHER_META_L4_PROTO] =
     711              :         {
     712              :             .layer = BF_MATCHER_NO_LAYER,
     713              :             .ops =
     714              :                 {
     715              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
     716              :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
     717              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
     718              :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
     719              :                 },
     720              :         },
     721              :     [BF_MATCHER_META_SPORT] =
     722              :         {
     723              :             .layer = BF_MATCHER_NO_LAYER,
     724              :             .ops =
     725              :                 {
     726              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
     727              :                                    _bf_parse_l4_port, _bf_print_l4_port),
     728              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
     729              :                                    _bf_parse_l4_port, _bf_print_l4_port),
     730              :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
     731              :                                    _bf_parse_l4_port_range,
     732              :                                    _bf_print_l4_port_range),
     733              :                 },
     734              :         },
     735              :     [BF_MATCHER_META_DPORT] =
     736              :         {
     737              :             .layer = BF_MATCHER_NO_LAYER,
     738              :             .ops =
     739              :                 {
     740              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
     741              :                                    _bf_parse_l4_port, _bf_print_l4_port),
     742              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
     743              :                                    _bf_parse_l4_port, _bf_print_l4_port),
     744              :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
     745              :                                    _bf_parse_l4_port_range,
     746              :                                    _bf_print_l4_port_range),
     747              :                 },
     748              :         },
     749              :     [BF_MATCHER_META_PROBABILITY] =
     750              :         {
     751              :             .layer = BF_MATCHER_NO_LAYER,
     752              :             .ops =
     753              :                 {
     754              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
     755              :                                    _bf_parse_probability,
     756              :                                    _bf_print_probability),
     757              :                 },
     758              :         },
     759              :     [BF_MATCHER_META_MARK] =
     760              :         {
     761              :             .layer = BF_MATCHER_NO_LAYER,
     762              :             .ops =
     763              :                 {
     764              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
     765              :                                    _bf_parse_mark, _bf_print_mark),
     766              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint32_t),
     767              :                                    _bf_parse_mark, _bf_print_mark),
     768              :                 },
     769              :         },
     770              :     [BF_MATCHER_IP4_SADDR] =
     771              :         {
     772              :             .layer = BF_MATCHER_LAYER_3,
     773              :             .hdr_id = ETH_P_IP,
     774              :             .hdr_payload_size = sizeof(uint32_t),
     775              :             .hdr_payload_offset = offsetof(struct iphdr, saddr),
     776              :             .ops =
     777              :                 {
     778              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
     779              :                                    _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
     780              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint32_t),
     781              :                                    _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
     782              :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint32_t),
     783              :                                    _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
     784              :                 },
     785              :         },
     786              :     [BF_MATCHER_IP4_DADDR] =
     787              :         {
     788              :             .layer = BF_MATCHER_LAYER_3,
     789              :             .hdr_id = ETH_P_IP,
     790              :             .hdr_payload_size = sizeof(uint32_t),
     791              :             .hdr_payload_offset = offsetof(struct iphdr, daddr),
     792              :             .ops =
     793              :                 {
     794              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
     795              :                                    _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
     796              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint32_t),
     797              :                                    _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
     798              :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint32_t),
     799              :                                    _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
     800              :                 },
     801              :         },
     802              :     [BF_MATCHER_IP4_SNET] =
     803              :         {
     804              :             .layer = BF_MATCHER_LAYER_3,
     805              :             .hdr_id = ETH_P_IP,
     806              :             .hdr_payload_size = sizeof(uint32_t),
     807              :             .hdr_payload_offset = offsetof(struct iphdr, saddr),
     808              :             .ops =
     809              :                 {
     810              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip4_lpm_key),
     811              :                                    _bf_parse_ipv4_net, _bf_print_ipv4_net),
     812              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct bf_ip4_lpm_key),
     813              :                                    _bf_parse_ipv4_net, _bf_print_ipv4_net),
     814              :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip4_lpm_key),
     815              :                                    _bf_parse_ipv4_net, _bf_print_ipv4_net),
     816              :                 },
     817              :         },
     818              :     [BF_MATCHER_IP4_DNET] =
     819              :         {
     820              :             .layer = BF_MATCHER_LAYER_3,
     821              :             .hdr_id = ETH_P_IP,
     822              :             .hdr_payload_size = sizeof(uint32_t),
     823              :             .hdr_payload_offset = offsetof(struct iphdr, daddr),
     824              :             .ops =
     825              :                 {
     826              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip4_lpm_key),
     827              :                                    _bf_parse_ipv4_net, _bf_print_ipv4_net),
     828              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct bf_ip4_lpm_key),
     829              :                                    _bf_parse_ipv4_net, _bf_print_ipv4_net),
     830              :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip4_lpm_key),
     831              :                                    _bf_parse_ipv4_net, _bf_print_ipv4_net),
     832              :                 },
     833              :         },
     834              :     [BF_MATCHER_IP4_PROTO] =
     835              :         {
     836              :             .layer = BF_MATCHER_LAYER_3,
     837              :             .hdr_id = ETH_P_IP,
     838              :             .hdr_payload_size = sizeof(uint8_t),
     839              :             .hdr_payload_offset = offsetof(struct iphdr, protocol),
     840              :             .ops =
     841              :                 {
     842              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
     843              :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
     844              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
     845              :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
     846              :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
     847              :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
     848              :                 },
     849              :         },
     850              :     [BF_MATCHER_IP6_SADDR] =
     851              :         {
     852              :             .layer = BF_MATCHER_LAYER_3,
     853              :             .hdr_id = ETH_P_IPV6,
     854              :             .hdr_payload_size = sizeof(struct in6_addr),
     855              :             .hdr_payload_offset = offsetof(struct ipv6hdr, saddr),
     856              :             .ops =
     857              :                 {
     858              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct in6_addr),
     859              :                                    _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
     860              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct in6_addr),
     861              :                                    _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
     862              :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct in6_addr),
     863              :                                    _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
     864              :                 },
     865              :         },
     866              :     [BF_MATCHER_IP6_DADDR] =
     867              :         {
     868              :             .layer = BF_MATCHER_LAYER_3,
     869              :             .hdr_id = ETH_P_IPV6,
     870              :             .hdr_payload_size = sizeof(struct in6_addr),
     871              :             .hdr_payload_offset = offsetof(struct ipv6hdr, daddr),
     872              :             .ops =
     873              :                 {
     874              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct in6_addr),
     875              :                                    _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
     876              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct in6_addr),
     877              :                                    _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
     878              :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct in6_addr),
     879              :                                    _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
     880              :                 },
     881              :         },
     882              :     [BF_MATCHER_IP6_SNET] =
     883              :         {
     884              :             .layer = BF_MATCHER_LAYER_3,
     885              :             .hdr_id = ETH_P_IPV6,
     886              :             .hdr_payload_size = sizeof(struct in6_addr),
     887              :             .hdr_payload_offset = offsetof(struct ipv6hdr, saddr),
     888              :             .ops =
     889              :                 {
     890              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip6_lpm_key),
     891              :                                    _bf_parse_ipv6_net, _bf_print_ipv6_net),
     892              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct bf_ip6_lpm_key),
     893              :                                    _bf_parse_ipv6_net, _bf_print_ipv6_net),
     894              :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip6_lpm_key),
     895              :                                    _bf_parse_ipv6_net, _bf_print_ipv6_net),
     896              :                 },
     897              :         },
     898              :     [BF_MATCHER_IP6_DNET] =
     899              :         {
     900              :             .layer = BF_MATCHER_LAYER_3,
     901              :             .hdr_id = ETH_P_IPV6,
     902              :             .hdr_payload_size = sizeof(struct in6_addr),
     903              :             .hdr_payload_offset = offsetof(struct ipv6hdr, daddr),
     904              :             .ops =
     905              :                 {
     906              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip6_lpm_key),
     907              :                                    _bf_parse_ipv6_net, _bf_print_ipv6_net),
     908              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct bf_ip6_lpm_key),
     909              :                                    _bf_parse_ipv6_net, _bf_print_ipv6_net),
     910              :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip6_lpm_key),
     911              :                                    _bf_parse_ipv6_net, _bf_print_ipv6_net),
     912              :                 },
     913              :         },
     914              :     [BF_MATCHER_IP6_NEXTHDR] =
     915              :         {
     916              :             .layer = BF_MATCHER_LAYER_3,
     917              :             .hdr_id = ETH_P_IPV6,
     918              :             .hdr_payload_size = sizeof(uint8_t),
     919              :             .hdr_payload_offset = offsetof(struct ipv6hdr, nexthdr),
     920              :             .ops =
     921              :                 {
     922              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
     923              :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
     924              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
     925              :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
     926              :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
     927              :                                    _bf_parse_l4_proto, _bf_print_l4_proto),
     928              :                 },
     929              :         },
     930              :     [BF_MATCHER_TCP_SPORT] =
     931              :         {
     932              :             .layer = BF_MATCHER_LAYER_4,
     933              :             .hdr_id = IPPROTO_TCP,
     934              :             .hdr_payload_size = sizeof(uint16_t),
     935              :             .hdr_payload_offset = offsetof(struct tcphdr, source),
     936              :             .ops =
     937              :                 {
     938              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
     939              :                                    _bf_parse_l4_port, _bf_print_l4_port),
     940              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
     941              :                                    _bf_parse_l4_port, _bf_print_l4_port),
     942              :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
     943              :                                    _bf_parse_l4_port, _bf_print_l4_port),
     944              :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
     945              :                                    _bf_parse_l4_port_range,
     946              :                                    _bf_print_l4_port_range),
     947              :                 },
     948              :         },
     949              :     [BF_MATCHER_TCP_DPORT] =
     950              :         {
     951              :             .layer = BF_MATCHER_LAYER_4,
     952              :             .hdr_id = IPPROTO_TCP,
     953              :             .hdr_payload_size = sizeof(uint16_t),
     954              :             .hdr_payload_offset = offsetof(struct tcphdr, dest),
     955              :             .ops =
     956              :                 {
     957              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
     958              :                                    _bf_parse_l4_port, _bf_print_l4_port),
     959              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
     960              :                                    _bf_parse_l4_port, _bf_print_l4_port),
     961              :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
     962              :                                    _bf_parse_l4_port, _bf_print_l4_port),
     963              :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
     964              :                                    _bf_parse_l4_port_range,
     965              :                                    _bf_print_l4_port_range),
     966              :                 },
     967              :         },
     968              :     [BF_MATCHER_TCP_FLAGS] =
     969              :         {
     970              :             .layer = BF_MATCHER_LAYER_4,
     971              :             .hdr_id = IPPROTO_TCP,
     972              :             .hdr_payload_size = sizeof(uint8_t),
     973              :             .hdr_payload_offset = _BF_TCP_FLAGS_OFFSET,
     974              :             .ops =
     975              :                 {
     976              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
     977              :                                    _bf_parse_tcp_flags, _bf_print_tcp_flags),
     978              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
     979              :                                    _bf_parse_tcp_flags, _bf_print_tcp_flags),
     980              :                     BF_MATCHER_OPS(BF_MATCHER_ANY, sizeof(uint8_t),
     981              :                                    _bf_parse_tcp_flags, _bf_print_tcp_flags),
     982              :                     BF_MATCHER_OPS(BF_MATCHER_ALL, sizeof(uint8_t),
     983              :                                    _bf_parse_tcp_flags, _bf_print_tcp_flags),
     984              :                 },
     985              :         },
     986              :     [BF_MATCHER_UDP_SPORT] =
     987              :         {
     988              :             .layer = BF_MATCHER_LAYER_4,
     989              :             .hdr_id = IPPROTO_UDP,
     990              :             .hdr_payload_size = sizeof(uint16_t),
     991              :             .hdr_payload_offset = offsetof(struct udphdr, source),
     992              :             .ops =
     993              :                 {
     994              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
     995              :                                    _bf_parse_l4_port, _bf_print_l4_port),
     996              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
     997              :                                    _bf_parse_l4_port, _bf_print_l4_port),
     998              :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
     999              :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1000              :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
    1001              :                                    _bf_parse_l4_port_range,
    1002              :                                    _bf_print_l4_port_range),
    1003              :                 },
    1004              :         },
    1005              :     [BF_MATCHER_UDP_DPORT] =
    1006              :         {
    1007              :             .layer = BF_MATCHER_LAYER_4,
    1008              :             .hdr_id = IPPROTO_UDP,
    1009              :             .hdr_payload_size = sizeof(uint16_t),
    1010              :             .hdr_payload_offset = offsetof(struct udphdr, dest),
    1011              :             .ops =
    1012              :                 {
    1013              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
    1014              :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1015              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
    1016              :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1017              :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
    1018              :                                    _bf_parse_l4_port, _bf_print_l4_port),
    1019              :                     BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
    1020              :                                    _bf_parse_l4_port_range,
    1021              :                                    _bf_print_l4_port_range),
    1022              :                 },
    1023              :         },
    1024              :     [BF_MATCHER_ICMP_TYPE] =
    1025              :         {
    1026              :             .layer = BF_MATCHER_LAYER_4,
    1027              :             .hdr_id = IPPROTO_ICMP,
    1028              :             .hdr_payload_size = sizeof(uint8_t),
    1029              :             .hdr_payload_offset = offsetof(struct icmphdr, type),
    1030              :             .ops =
    1031              :                 {
    1032              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
    1033              :                                    _bf_parse_icmp_type, _bf_print_icmp_type),
    1034              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
    1035              :                                    _bf_parse_icmp_type, _bf_print_icmp_type),
    1036              :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
    1037              :                                    _bf_parse_icmp_type, _bf_print_icmp_type),
    1038              :                 },
    1039              :         },
    1040              :     [BF_MATCHER_ICMP_CODE] =
    1041              :         {
    1042              :             .layer = BF_MATCHER_LAYER_4,
    1043              :             .hdr_id = IPPROTO_ICMP,
    1044              :             .hdr_payload_size = sizeof(uint8_t),
    1045              :             .hdr_payload_offset = offsetof(struct icmphdr, code),
    1046              :             .ops =
    1047              :                 {
    1048              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
    1049              :                                    _bf_parse_icmp_code, _bf_print_icmp_code),
    1050              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
    1051              :                                    _bf_parse_icmp_code, _bf_print_icmp_code),
    1052              :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
    1053              :                                    _bf_parse_icmp_code, _bf_print_icmp_code),
    1054              :                 },
    1055              :         },
    1056              :     [BF_MATCHER_ICMPV6_TYPE] =
    1057              :         {
    1058              :             .layer = BF_MATCHER_LAYER_4,
    1059              :             .hdr_id = IPPROTO_ICMPV6,
    1060              :             .hdr_payload_size = sizeof(uint8_t),
    1061              :             .hdr_payload_offset = offsetof(struct icmp6hdr, icmp6_type),
    1062              :             .ops =
    1063              :                 {
    1064              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
    1065              :                                    _bf_parse_icmpv6_type,
    1066              :                                    _bf_print_icmpv6_type),
    1067              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
    1068              :                                    _bf_parse_icmpv6_type,
    1069              :                                    _bf_print_icmpv6_type),
    1070              :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
    1071              :                                    _bf_parse_icmpv6_type,
    1072              :                                    _bf_print_icmpv6_type),
    1073              :                 },
    1074              :         },
    1075              :     [BF_MATCHER_ICMPV6_CODE] =
    1076              :         {
    1077              :             .layer = BF_MATCHER_LAYER_4,
    1078              :             .hdr_id = IPPROTO_ICMPV6,
    1079              :             .hdr_payload_size = sizeof(uint8_t),
    1080              :             .hdr_payload_offset = offsetof(struct icmp6hdr, icmp6_code),
    1081              :             .ops =
    1082              :                 {
    1083              :                     BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
    1084              :                                    _bf_parse_icmp_code, _bf_print_icmp_code),
    1085              :                     BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
    1086              :                                    _bf_parse_icmp_code, _bf_print_icmp_code),
    1087              :                     BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
    1088              :                                    _bf_parse_icmp_code, _bf_print_icmp_code),
    1089              :                 },
    1090              :         },
    1091              : };
    1092              : 
    1093           76 : const struct bf_matcher_meta *bf_matcher_get_meta(enum bf_matcher_type type)
    1094              : {
    1095           76 :     if (type < 0 || _BF_MATCHER_TYPE_MAX <= type)
    1096              :         return NULL;
    1097              : 
    1098           75 :     return _bf_matcher_metas[type].layer == _BF_MATCHER_LAYER_UNDEFINED ?
    1099           75 :                NULL :
    1100              :                &_bf_matcher_metas[type];
    1101              : }
    1102              : 
    1103           76 : const struct bf_matcher_ops *bf_matcher_get_ops(enum bf_matcher_type type,
    1104              :                                                 enum bf_matcher_op op)
    1105              : {
    1106           76 :     const struct bf_matcher_meta *meta = bf_matcher_get_meta(type);
    1107              : 
    1108           76 :     if (!meta)
    1109              :         return NULL;
    1110              : 
    1111           75 :     return meta->ops[op].ref_payload_size ? &meta->ops[op] : NULL;
    1112              : }
    1113              : 
    1114           58 : int bf_matcher_new(struct bf_matcher **matcher, enum bf_matcher_type type,
    1115              :                    enum bf_matcher_op op, const void *payload,
    1116              :                    size_t payload_len)
    1117              : {
    1118           56 :     _free_bf_matcher_ struct bf_matcher *_matcher = NULL;
    1119              : 
    1120           58 :     bf_assert(matcher);
    1121           57 :     bf_assert((payload && payload_len) || (!payload && !payload_len));
    1122              : 
    1123           56 :     _matcher = malloc(sizeof(struct bf_matcher) + payload_len);
    1124           56 :     if (!_matcher)
    1125              :         return -ENOMEM;
    1126              : 
    1127           54 :     _matcher->type = type;
    1128           54 :     _matcher->op = op;
    1129           54 :     _matcher->len = sizeof(struct bf_matcher) + payload_len;
    1130           54 :     bf_memcpy(_matcher->payload, payload, payload_len);
    1131              : 
    1132           54 :     *matcher = TAKE_PTR(_matcher);
    1133              : 
    1134           54 :     return 0;
    1135              : }
    1136              : 
    1137            0 : int bf_matcher_new_from_raw(struct bf_matcher **matcher,
    1138              :                             enum bf_matcher_type type, enum bf_matcher_op op,
    1139              :                             const char *payload)
    1140              : {
    1141            0 :     _free_bf_matcher_ struct bf_matcher *_matcher = NULL;
    1142              :     const struct bf_matcher_ops *ops;
    1143              :     int r;
    1144              : 
    1145            0 :     bf_assert(matcher && payload);
    1146              : 
    1147            0 :     ops = bf_matcher_get_ops(type, op);
    1148            0 :     if (!ops) {
    1149            0 :         return bf_err_r(-ENOENT, "payload ops not found for '%s %s'",
    1150              :                         bf_matcher_type_to_str(type), bf_matcher_op_to_str(op));
    1151              :     }
    1152              : 
    1153            0 :     _matcher = malloc(sizeof(*_matcher) + ops->ref_payload_size);
    1154            0 :     if (!_matcher)
    1155              :         return -ENOMEM;
    1156              : 
    1157            0 :     _matcher->type = type;
    1158            0 :     _matcher->op = op;
    1159            0 :     _matcher->len = sizeof(*_matcher) + ops->ref_payload_size;
    1160              : 
    1161            0 :     r = ops->parse(_matcher->type, _matcher->op, &_matcher->payload, payload);
    1162            0 :     if (r)
    1163              :         return r;
    1164              : 
    1165            0 :     *matcher = TAKE_PTR(_matcher);
    1166              : 
    1167            0 :     return 0;
    1168              : }
    1169              : 
    1170           23 : int bf_matcher_new_from_pack(struct bf_matcher **matcher, bf_rpack_node_t node)
    1171              : {
    1172           23 :     _free_bf_matcher_ struct bf_matcher *_matcher = NULL;
    1173              :     enum bf_matcher_type type;
    1174              :     enum bf_matcher_op op;
    1175              :     const void *payload;
    1176              :     size_t payload_len;
    1177              :     int r;
    1178              : 
    1179           23 :     bf_assert(matcher);
    1180              : 
    1181           23 :     r = bf_rpack_kv_enum(node, "type", &type);
    1182              :     if (r)
    1183            0 :         return bf_rpack_key_err(r, "bf_matcher.type");
    1184              : 
    1185           23 :     r = bf_rpack_kv_enum(node, "op", &op);
    1186              :     if (r)
    1187            0 :         return bf_rpack_key_err(r, "bf_matcher.op");
    1188              : 
    1189           23 :     r = bf_rpack_kv_bin(node, "payload", &payload, &payload_len);
    1190           23 :     if (r)
    1191            0 :         return bf_rpack_key_err(r, "bf_matcher.payload");
    1192              : 
    1193           23 :     r = bf_matcher_new(&_matcher, type, op, payload, payload_len);
    1194           23 :     if (r)
    1195            0 :         return bf_err_r(r, "failed to create bf_matcher from pack");
    1196              : 
    1197           23 :     *matcher = TAKE_PTR(_matcher);
    1198              : 
    1199           23 :     return 0;
    1200              : }
    1201              : 
    1202          166 : void bf_matcher_free(struct bf_matcher **matcher)
    1203              : {
    1204          166 :     bf_assert(matcher);
    1205              : 
    1206          165 :     if (!*matcher)
    1207              :         return;
    1208              : 
    1209           54 :     free(*matcher);
    1210           54 :     *matcher = NULL;
    1211              : }
    1212              : 
    1213           25 : int bf_matcher_pack(const struct bf_matcher *matcher, bf_wpack_t *pack)
    1214              : {
    1215           25 :     bf_assert(matcher);
    1216           24 :     bf_assert(pack);
    1217              : 
    1218           23 :     bf_wpack_kv_int(pack, "type", matcher->type);
    1219           23 :     bf_wpack_kv_int(pack, "op", matcher->op);
    1220           23 :     bf_wpack_kv_bin(pack, "payload", matcher->payload,
    1221           23 :                     matcher->len - sizeof(*matcher));
    1222              : 
    1223           23 :     return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
    1224              : }
    1225              : 
    1226            0 : void bf_matcher_dump(const struct bf_matcher *matcher, prefix_t *prefix)
    1227              : {
    1228            0 :     bf_assert(matcher);
    1229            0 :     bf_assert(prefix);
    1230              : 
    1231            0 :     DUMP(prefix, "struct bf_matcher at %p", matcher);
    1232              : 
    1233            0 :     bf_dump_prefix_push(prefix);
    1234              : 
    1235            0 :     DUMP(prefix, "type: %s", bf_matcher_type_to_str(matcher->type));
    1236            0 :     DUMP(prefix, "op: %s", bf_matcher_op_to_str(matcher->op));
    1237            0 :     DUMP(prefix, "len: %ld", matcher->len);
    1238            0 :     DUMP(bf_dump_prefix_last(prefix), "payload:");
    1239            0 :     bf_dump_prefix_push(prefix);
    1240            0 :     bf_dump_hex(prefix, matcher->payload,
    1241            0 :                 matcher->len - sizeof(struct bf_matcher));
    1242            0 :     bf_dump_prefix_pop(prefix);
    1243              : 
    1244            0 :     bf_dump_prefix_pop(prefix);
    1245            0 : }
    1246              : 
    1247           60 : enum bf_matcher_type bf_matcher_get_type(const struct bf_matcher *matcher)
    1248              : {
    1249           60 :     bf_assert(matcher);
    1250           60 :     return matcher->type;
    1251              : }
    1252              : 
    1253            0 : enum bf_matcher_op bf_matcher_get_op(const struct bf_matcher *matcher)
    1254              : {
    1255            0 :     bf_assert(matcher);
    1256            0 :     return matcher->op;
    1257              : }
    1258              : 
    1259            0 : const void *bf_matcher_payload(const struct bf_matcher *matcher)
    1260              : {
    1261            0 :     bf_assert(matcher);
    1262            0 :     return matcher->payload;
    1263              : }
    1264              : 
    1265            0 : size_t bf_matcher_payload_len(const struct bf_matcher *matcher)
    1266              : {
    1267            0 :     bf_assert(matcher);
    1268            0 :     return matcher->len - sizeof(*matcher);
    1269              : }
    1270              : 
    1271            0 : size_t bf_matcher_len(const struct bf_matcher *matcher)
    1272              : {
    1273            0 :     bf_assert(matcher);
    1274            0 :     return matcher->len;
    1275              : }
    1276              : 
    1277              : static const char *_bf_matcher_type_strs[] = {
    1278              :     [BF_MATCHER_META_IFACE] = "meta.iface",
    1279              :     [BF_MATCHER_META_L3_PROTO] = "meta.l3_proto",
    1280              :     [BF_MATCHER_META_L4_PROTO] = "meta.l4_proto",
    1281              :     [BF_MATCHER_META_PROBABILITY] = "meta.probability",
    1282              :     [BF_MATCHER_META_SPORT] = "meta.sport",
    1283              :     [BF_MATCHER_META_DPORT] = "meta.dport",
    1284              :     [BF_MATCHER_META_MARK] = "meta.mark",
    1285              :     [BF_MATCHER_IP4_SADDR] = "ip4.saddr",
    1286              :     [BF_MATCHER_IP4_SNET] = "ip4.snet",
    1287              :     [BF_MATCHER_IP4_DADDR] = "ip4.daddr",
    1288              :     [BF_MATCHER_IP4_DNET] = "ip4.dnet",
    1289              :     [BF_MATCHER_IP4_PROTO] = "ip4.proto",
    1290              :     [BF_MATCHER_IP6_SADDR] = "ip6.saddr",
    1291              :     [BF_MATCHER_IP6_SNET] = "ip6.snet",
    1292              :     [BF_MATCHER_IP6_DADDR] = "ip6.daddr",
    1293              :     [BF_MATCHER_IP6_DNET] = "ip6.dnet",
    1294              :     [BF_MATCHER_IP6_NEXTHDR] = "ip6.nexthdr",
    1295              :     [BF_MATCHER_TCP_SPORT] = "tcp.sport",
    1296              :     [BF_MATCHER_TCP_DPORT] = "tcp.dport",
    1297              :     [BF_MATCHER_TCP_FLAGS] = "tcp.flags",
    1298              :     [BF_MATCHER_UDP_SPORT] = "udp.sport",
    1299              :     [BF_MATCHER_UDP_DPORT] = "udp.dport",
    1300              :     [BF_MATCHER_ICMP_TYPE] = "icmp.type",
    1301              :     [BF_MATCHER_ICMP_CODE] = "icmp.code",
    1302              :     [BF_MATCHER_ICMPV6_TYPE] = "icmpv6.type",
    1303              :     [BF_MATCHER_ICMPV6_CODE] = "icmpv6.code",
    1304              :     [BF_MATCHER_SET] = "<set>",
    1305              : };
    1306              : 
    1307              : static_assert(ARRAY_SIZE(_bf_matcher_type_strs) == _BF_MATCHER_TYPE_MAX,
    1308              :               "missing entries in the matcher type array");
    1309              : 
    1310           31 : const char *bf_matcher_type_to_str(enum bf_matcher_type type)
    1311              : {
    1312           31 :     if (type < 0 || _BF_MATCHER_TYPE_MAX <= type)
    1313              :         return "<invalid>";
    1314              : 
    1315           30 :     return _bf_matcher_type_strs[type];
    1316              : }
    1317              : 
    1318           60 : int bf_matcher_type_from_str(const char *str, enum bf_matcher_type *type)
    1319              : {
    1320           60 :     bf_assert(str);
    1321           59 :     bf_assert(type);
    1322              : 
    1323          790 :     for (size_t i = 0; i < _BF_MATCHER_TYPE_MAX; ++i) {
    1324          786 :         if (bf_streq(_bf_matcher_type_strs[i], str)) {
    1325           54 :             *type = i;
    1326           54 :             return 0;
    1327              :         }
    1328              :     }
    1329              : 
    1330              :     return -EINVAL;
    1331              : }
    1332              : 
    1333              : static const char *_bf_matcher_ops_strs[] = {
    1334              :     [BF_MATCHER_EQ] = "eq",   [BF_MATCHER_NE] = "not",
    1335              :     [BF_MATCHER_ANY] = "any", [BF_MATCHER_ALL] = "all",
    1336              :     [BF_MATCHER_IN] = "in",   [BF_MATCHER_RANGE] = "range",
    1337              : };
    1338              : 
    1339              : static_assert(ARRAY_SIZE(_bf_matcher_ops_strs) == _BF_MATCHER_OP_MAX);
    1340              : 
    1341            8 : const char *bf_matcher_op_to_str(enum bf_matcher_op op)
    1342              : {
    1343            8 :     bf_assert(0 <= op && op < _BF_MATCHER_OP_MAX);
    1344              : 
    1345            6 :     return _bf_matcher_ops_strs[op];
    1346              : }
    1347              : 
    1348            0 : int bf_matcher_op_from_str(const char *str, enum bf_matcher_op *op)
    1349              : {
    1350            0 :     bf_assert(str);
    1351            0 :     bf_assert(op);
    1352              : 
    1353            0 :     for (size_t i = 0; i < _BF_MATCHER_OP_MAX; ++i) {
    1354            0 :         if (bf_streq(_bf_matcher_ops_strs[i], str)) {
    1355            0 :             *op = i;
    1356            0 :             return 0;
    1357              :         }
    1358              :     }
    1359              : 
    1360              :     return -EINVAL;
    1361              : }
    1362              : 
    1363              : static const char *_bf_tcp_flags_strs[] = {
    1364              :     [BF_TCP_FIN] = "fin", [BF_TCP_SYN] = "syn", [BF_TCP_RST] = "rst",
    1365              :     [BF_TCP_PSH] = "psh", [BF_TCP_ACK] = "ack", [BF_TCP_URG] = "urg",
    1366              :     [BF_TCP_ECE] = "ece", [BF_TCP_CWR] = "cwr",
    1367              : };
    1368              : static_assert(ARRAY_SIZE(_bf_tcp_flags_strs) == _BF_TCP_MAX);
    1369              : 
    1370            0 : const char *bf_tcp_flag_to_str(enum bf_tcp_flag flag)
    1371              : {
    1372            0 :     bf_assert(0 <= flag && flag < _BF_TCP_MAX);
    1373              : 
    1374            0 :     return _bf_tcp_flags_strs[flag];
    1375              : }
    1376              : 
    1377            0 : int bf_tcp_flag_from_str(const char *str, enum bf_tcp_flag *flag)
    1378              : {
    1379            0 :     bf_assert(str);
    1380            0 :     bf_assert(flag);
    1381              : 
    1382            0 :     for (size_t i = 0; i < _BF_TCP_MAX; ++i) {
    1383            0 :         if (bf_streq_i(_bf_tcp_flags_strs[i], str)) {
    1384            0 :             *flag = i;
    1385            0 :             return 0;
    1386              :         }
    1387              :     }
    1388              : 
    1389              :     return -EINVAL;
    1390              : }
    1391              : 
    1392            0 : const char *bf_ethertype_to_str(uint16_t ethertype)
    1393              : {
    1394            0 :     switch (ethertype) {
    1395              :     case ETH_P_IP:
    1396              :         return "ipv4";
    1397            0 :     case ETH_P_IPV6:
    1398            0 :         return "ipv6";
    1399            0 :     default:
    1400            0 :         return NULL;
    1401              :     }
    1402              : }
    1403              : 
    1404            0 : int bf_ethertype_from_str(const char *str, uint16_t *ethertype)
    1405              : {
    1406            0 :     bf_assert(str && ethertype);
    1407              : 
    1408            0 :     if (bf_streq_i(str, "ipv4")) {
    1409            0 :         *ethertype = ETH_P_IP;
    1410            0 :         return 0;
    1411              :     }
    1412              : 
    1413            0 :     if (bf_streq_i(str, "ipv6")) {
    1414            0 :         *ethertype = ETH_P_IPV6;
    1415            0 :         return 0;
    1416              :     }
    1417              : 
    1418              :     return -EINVAL;
    1419              : }
    1420              : 
    1421              : static const char *_bf_ipproto_strs[UINT8_MAX + 1] = {
    1422              :     [IPPROTO_HOPOPTS] = "hop",   [IPPROTO_ICMP] = "icmp",
    1423              :     [IPPROTO_IGMP] = "igmp",     [IPPROTO_TCP] = "tcp",
    1424              :     [IPPROTO_UDP] = "udp",       [IPPROTO_ROUTING] = "routing",
    1425              :     [IPPROTO_FRAGMENT] = "frag", [IPPROTO_AH] = "ah",
    1426              :     [IPPROTO_DSTOPTS] = "dst",   [IPPROTO_ICMPV6] = "icmpv6",
    1427              :     [IPPROTO_MH] = "mh",
    1428              : };
    1429              : static_assert(ARRAY_SIZE(_bf_ipproto_strs) == (UINT8_MAX + 1),
    1430              :               "missing entries in IP protocols strings array");
    1431              : 
    1432            0 : const char *bf_ipproto_to_str(uint8_t ipproto)
    1433              : {
    1434            0 :     return _bf_ipproto_strs[ipproto];
    1435              : }
    1436              : 
    1437           24 : int bf_ipproto_from_str(const char *str, uint8_t *ipproto)
    1438              : {
    1439           24 :     bf_assert(str && ipproto);
    1440              : 
    1441          236 :     for (size_t i = 0; i <= UINT8_MAX; ++i) {
    1442          236 :         if (bf_streq_i(str, _bf_ipproto_strs[i])) {
    1443           24 :             *ipproto = (uint8_t)i;
    1444           24 :             return 0;
    1445              :         }
    1446              :     }
    1447              : 
    1448              :     return -EINVAL;
    1449              : }
    1450              : 
    1451              : #define ICMP_ROUTERADVERT 9
    1452              : #define ICMP_ROUTERSOLICIT 10
    1453              : 
    1454              : static const char *_bf_icmp_type_strs[UINT8_MAX + 1] = {
    1455              :     [ICMP_ECHOREPLY] = "echo-reply",
    1456              :     [ICMP_DEST_UNREACH] = "destination-unreachable",
    1457              :     [ICMP_SOURCE_QUENCH] = "source-quench",
    1458              :     [ICMP_REDIRECT] = "redirect",
    1459              :     [ICMP_ECHO] = "echo-request",
    1460              :     [ICMP_ROUTERADVERT] = "router-advertisement",
    1461              :     [ICMP_ROUTERSOLICIT] = "router-solicitation",
    1462              :     [ICMP_TIME_EXCEEDED] = "time-exceeded",
    1463              :     [ICMP_PARAMETERPROB] = "parameter-problem",
    1464              :     [ICMP_TIMESTAMP] = "timestamp-request",
    1465              :     [ICMP_TIMESTAMPREPLY] = "timestamp-reply",
    1466              :     [ICMP_INFO_REQUEST] = "info-request",
    1467              :     [ICMP_INFO_REPLY] = "info-reply",
    1468              :     [ICMP_ADDRESS] = "address-mask-request",
    1469              :     [ICMP_ADDRESSREPLY] = "address-mask-reply",
    1470              : };
    1471              : static_assert(ARRAY_SIZE(_bf_icmp_type_strs) == (UINT8_MAX + 1),
    1472              :               "missing entries in ICMP types strings array");
    1473              : 
    1474            0 : const char *bf_icmp_type_to_str(uint8_t type)
    1475              : {
    1476            0 :     return _bf_icmp_type_strs[type];
    1477              : }
    1478              : 
    1479            0 : int bf_icmp_type_from_str(const char *str, uint8_t *type)
    1480              : {
    1481            0 :     bf_assert(str && type);
    1482              : 
    1483            0 :     for (size_t i = 0; i <= UINT8_MAX; ++i) {
    1484            0 :         if (bf_streq_i(str, _bf_icmp_type_strs[i])) {
    1485            0 :             *type = (uint8_t)i;
    1486            0 :             return 0;
    1487              :         }
    1488              :     }
    1489              : 
    1490              :     return -EINVAL;
    1491              : }
    1492              : 
    1493              : #define ICMPV6_ND_ROUTERSOLICIT 133
    1494              : #define ICMPV6_ND_ROUTERADVERT 134
    1495              : #define ICMPV6_ND_NEIGHSOLICIT 135
    1496              : #define ICMPV6_ND_NEIGHADVERT 136
    1497              : 
    1498              : static const char *_bf_icmpv6_type_strs[UINT8_MAX + 1] = {
    1499              :     [ICMPV6_DEST_UNREACH] = "destination-unreachable",
    1500              :     [ICMPV6_PKT_TOOBIG] = "packet-too-big",
    1501              :     [ICMPV6_TIME_EXCEED] = "time-exceeded",
    1502              :     [ICMPV6_PARAMPROB] = "parameter-problem",
    1503              :     [ICMPV6_ECHO_REQUEST] = "echo-request",
    1504              :     [ICMPV6_ECHO_REPLY] = "echo-reply",
    1505              :     [ICMPV6_MGM_QUERY] = "mld-listener-query",
    1506              :     [ICMPV6_MGM_REPORT] = "mld-listener-report",
    1507              :     [ICMPV6_MGM_REDUCTION] = "mld-listener-reduction",
    1508              :     [ICMPV6_ND_ROUTERSOLICIT] = "nd-router-solicit",
    1509              :     [ICMPV6_ND_ROUTERADVERT] = "nd-router-advert",
    1510              :     [ICMPV6_ND_NEIGHSOLICIT] = "nd-neighbor-solicit",
    1511              :     [ICMPV6_ND_NEIGHADVERT] = "nd-neighbor-advert",
    1512              :     [ICMPV6_MLD2_REPORT] = "mld2-listener-report",
    1513              : };
    1514              : static_assert(ARRAY_SIZE(_bf_icmpv6_type_strs) == (UINT8_MAX + 1),
    1515              :               "missing entries in ICMPv6 types strings array");
    1516              : 
    1517            0 : const char *bf_icmpv6_type_to_str(uint8_t type)
    1518              : {
    1519            0 :     return _bf_icmpv6_type_strs[type];
    1520              : }
    1521              : 
    1522            0 : int bf_icmpv6_type_from_str(const char *str, uint8_t *type)
    1523              : {
    1524            0 :     bf_assert(str && type);
    1525              : 
    1526            0 :     for (size_t i = 0; i <= UINT8_MAX; ++i) {
    1527            0 :         if (bf_streq_i(str, _bf_icmpv6_type_strs[i])) {
    1528            0 :             *type = (uint8_t)i;
    1529            0 :             return 0;
    1530              :         }
    1531              :     }
    1532              : 
    1533              :     return -EINVAL;
    1534              : }
        

Generated by: LCOV version 2.0-1