iproute2/tc/em_u32.c
<<
>>
Prefs
   1/*
   2 * em_u32.c             U32 Ematch
   3 *
   4 *              This program is free software; you can distribute it and/or
   5 *              modify it under the terms of the GNU General Public License
   6 *              as published by the Free Software Foundation; either version
   7 *              2 of the License, or (at your option) any later version.
   8 *
   9 * Authors:     Thomas Graf <tgraf@suug.ch>
  10 */
  11
  12#include <stdio.h>
  13#include <stdlib.h>
  14#include <unistd.h>
  15#include <fcntl.h>
  16#include <sys/socket.h>
  17#include <netinet/in.h>
  18#include <arpa/inet.h>
  19#include <string.h>
  20#include <errno.h>
  21
  22#include "m_ematch.h"
  23
  24extern struct ematch_util u32_ematch_util;
  25
  26static void u32_print_usage(FILE *fd)
  27{
  28        fprintf(fd,
  29            "Usage: u32(ALIGN VALUE MASK at [ nexthdr+ ] OFFSET)\n" \
  30            "where: ALIGN  := { u8 | u16 | u32 }\n" \
  31            "\n" \
  32            "Example: u32(u16 0x1122 0xffff at nexthdr+4)\n");
  33}
  34
  35static int u32_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
  36                          struct bstr *args)
  37{
  38        struct bstr *a;
  39        int align, nh_len;
  40        unsigned long key, mask, offmask = 0, offset;
  41        struct tc_u32_key u_key = {};
  42
  43#define PARSE_ERR(CARG, FMT, ARGS...) \
  44        em_parse_error(EINVAL, args, CARG, &u32_ematch_util, FMT, ##ARGS)
  45
  46        if (args == NULL)
  47                return PARSE_ERR(args, "u32: missing arguments");
  48
  49        if (!bstrcmp(args, "u8"))
  50                align = 1;
  51        else if (!bstrcmp(args, "u16"))
  52                align = 2;
  53        else if (!bstrcmp(args, "u32"))
  54                align = 4;
  55        else
  56                return PARSE_ERR(args, "u32: invalid alignment");
  57
  58        a = bstr_next(args);
  59        if (a == NULL)
  60                return PARSE_ERR(a, "u32: missing key");
  61
  62        key = bstrtoul(a);
  63        if (key == ULONG_MAX)
  64                return PARSE_ERR(a, "u32: invalid key, must be numeric");
  65
  66        a = bstr_next(a);
  67        if (a == NULL)
  68                return PARSE_ERR(a, "u32: missing mask");
  69
  70        mask = bstrtoul(a);
  71        if (mask == ULONG_MAX)
  72                return PARSE_ERR(a, "u32: invalid mask, must be numeric");
  73
  74        a = bstr_next(a);
  75        if (a == NULL || bstrcmp(a, "at") != 0)
  76                return PARSE_ERR(a, "u32: missing \"at\"");
  77
  78        a = bstr_next(a);
  79        if (a == NULL)
  80                return PARSE_ERR(a, "u32: missing offset");
  81
  82        nh_len = strlen("nexthdr+");
  83        if (a->len > nh_len && !memcmp(a->data, "nexthdr+", nh_len)) {
  84                char buf[a->len - nh_len + 1];
  85
  86                offmask = -1;
  87                memcpy(buf, a->data + nh_len, a->len - nh_len);
  88                offset = strtoul(buf, NULL, 0);
  89        } else if (!bstrcmp(a, "nexthdr+")) {
  90                a = bstr_next(a);
  91                if (a == NULL)
  92                        return PARSE_ERR(a, "u32: missing offset");
  93                offset = bstrtoul(a);
  94        } else
  95                offset = bstrtoul(a);
  96
  97        if (offset == ULONG_MAX)
  98                return PARSE_ERR(a, "u32: invalid offset");
  99
 100        if (a->next)
 101                return PARSE_ERR(a->next, "u32: unexpected trailer");
 102
 103        switch (align) {
 104                case 1:
 105                        if (key > 0xFF)
 106                                return PARSE_ERR(a, "Illegal key (>0xFF)");
 107                        if (mask > 0xFF)
 108                                return PARSE_ERR(a, "Illegal mask (>0xFF)");
 109
 110                        key <<= 24 - ((offset & 3) * 8);
 111                        mask <<= 24 - ((offset & 3) * 8);
 112                        offset &= ~3;
 113                        break;
 114
 115                case 2:
 116                        if (key > 0xFFFF)
 117                                return PARSE_ERR(a, "Illegal key (>0xFFFF)");
 118                        if (mask > 0xFFFF)
 119                                return PARSE_ERR(a, "Illegal mask (>0xFFFF)");
 120
 121                        if ((offset & 3) == 0) {
 122                                key <<= 16;
 123                                mask <<= 16;
 124                        }
 125                        offset &= ~3;
 126                        break;
 127        }
 128
 129        key = htonl(key);
 130        mask = htonl(mask);
 131
 132        if (offset % 4)
 133                return PARSE_ERR(a, "u32: invalid offset alignment, " \
 134                    "must be aligned to 4.");
 135
 136        key &= mask;
 137
 138        u_key.mask = mask;
 139        u_key.val = key;
 140        u_key.off = offset;
 141        u_key.offmask = offmask;
 142
 143        addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
 144        addraw_l(n, MAX_MSG, &u_key, sizeof(u_key));
 145
 146#undef PARSE_ERR
 147        return 0;
 148}
 149
 150static int u32_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
 151                          int data_len)
 152{
 153        struct tc_u32_key *u_key = data;
 154
 155        if (data_len < sizeof(*u_key)) {
 156                fprintf(stderr, "U32 header size mismatch\n");
 157                return -1;
 158        }
 159
 160        fprintf(fd, "%08x/%08x at %s%d",
 161            (unsigned int) ntohl(u_key->val),
 162            (unsigned int) ntohl(u_key->mask),
 163            u_key->offmask ? "nexthdr+" : "",
 164            u_key->off);
 165
 166        return 0;
 167}
 168
 169struct ematch_util u32_ematch_util = {
 170        .kind = "u32",
 171        .kind_num = TCF_EM_U32,
 172        .parse_eopt = u32_parse_eopt,
 173        .print_eopt = u32_print_eopt,
 174        .print_usage = u32_print_usage
 175};
 176