1/* 2 * em_cmp.c Simle coparison 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 <syslog.h> 16#include <fcntl.h> 17#include <sys/socket.h> 18#include <netinet/in.h> 19#include <arpa/inet.h> 20#include <string.h> 21#include <dlfcn.h> 22#include <errno.h> 23 24#include "m_ematch.h" 25#include <linux/tc_ematch/tc_em_cmp.h> 26 27extern struct ematch_util cmp_ematch_util; 28 29static void cmp_print_usage(FILE *fd) 30{ 31 fprintf(fd, 32 "Usage: cmp(ALIGN at OFFSET [ ATTRS ] { eq | lt | gt } VALUE)\n" \ 33 "where: ALIGN := { u8 | u16 | u32 }\n" \ 34 " ATTRS := [ layer LAYER ] [ mask MASK ] [ trans ]\n" \ 35 " LAYER := { link | header | next-header | 0..%d }\n" \ 36 "\n" \ 37 "Example: cmp(u16 at 3 layer 2 mask 0xff00 gt 20)\n", 38 TCF_LAYER_MAX); 39} 40 41static int cmp_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, 42 struct bstr *args) 43{ 44 struct bstr *a; 45 int align, opnd = 0; 46 unsigned long offset = 0, layer = TCF_LAYER_NETWORK, mask = 0, value = 0; 47 int offset_present = 0, value_present = 0; 48 struct tcf_em_cmp cmp; 49 50 memset(&cmp, 0, sizeof(cmp)); 51 52#define PARSE_ERR(CARG, FMT, ARGS...) \ 53 em_parse_error(EINVAL, args, CARG, &cmp_ematch_util, FMT ,##ARGS) 54 55 if (args == NULL) 56 return PARSE_ERR(args, "cmp: missing arguments"); 57 58 if (!bstrcmp(args, "u8")) 59 align = TCF_EM_ALIGN_U8; 60 else if (!bstrcmp(args, "u16")) 61 align = TCF_EM_ALIGN_U16; 62 else if (!bstrcmp(args, "u32")) 63 align = TCF_EM_ALIGN_U32; 64 else 65 return PARSE_ERR(args, "cmp: invalid alignment"); 66 67 for (a = bstr_next(args); a; a = bstr_next(a)) { 68 if (!bstrcmp(a, "at")) { 69 if (a->next == NULL) 70 return PARSE_ERR(a, "cmp: missing argument"); 71 a = bstr_next(a); 72 73 offset = bstrtoul(a); 74 if (offset == ULONG_MAX) 75 return PARSE_ERR(a, "cmp: invalid offset, " \ 76 "must be numeric"); 77 78 offset_present = 1; 79 } else if (!bstrcmp(a, "layer")) { 80 if (a->next == NULL) 81 return PARSE_ERR(a, "cmp: missing argument"); 82 a = bstr_next(a); 83 84 layer = parse_layer(a); 85 if (layer == INT_MAX) { 86 layer = bstrtoul(a); 87 if (layer == ULONG_MAX) 88 return PARSE_ERR(a, "cmp: invalid " \ 89 "layer"); 90 } 91 92 if (layer > TCF_LAYER_MAX) 93 return PARSE_ERR(a, "cmp: illegal layer, " \ 94 "must be in 0..%d", TCF_LAYER_MAX); 95 } else if (!bstrcmp(a, "mask")) { 96 if (a->next == NULL) 97 return PARSE_ERR(a, "cmp: missing argument"); 98 a = bstr_next(a); 99 100 mask = bstrtoul(a); 101 if (mask == ULONG_MAX) 102 return PARSE_ERR(a, "cmp: invalid mask"); 103 } else if (!bstrcmp(a, "trans")) { 104 cmp.flags |= TCF_EM_CMP_TRANS; 105 } else if (!bstrcmp(a, "eq") || !bstrcmp(a, "gt") || 106 !bstrcmp(a, "lt")) { 107 108 if (!bstrcmp(a, "eq")) 109 opnd = TCF_EM_OPND_EQ; 110 else if (!bstrcmp(a, "gt")) 111 opnd = TCF_EM_OPND_GT; 112 else if (!bstrcmp(a, "lt")) 113 opnd = TCF_EM_OPND_LT; 114 115 if (a->next == NULL) 116 return PARSE_ERR(a, "cmp: missing argument"); 117 a = bstr_next(a); 118 119 value = bstrtoul(a); 120 if (value == ULONG_MAX) 121 return PARSE_ERR(a, "cmp: invalid value"); 122 123 value_present = 1; 124 } else 125 return PARSE_ERR(a, "nbyte: unknown parameter"); 126 } 127 128 if (offset_present == 0 || value_present == 0) 129 return PARSE_ERR(a, "cmp: offset and value required"); 130 131 cmp.val = (__u32) value; 132 cmp.mask = (__u32) mask; 133 cmp.off = (__u16) offset; 134 cmp.align = (__u8) align; 135 cmp.layer = (__u8) layer; 136 cmp.opnd = (__u8) opnd; 137 138 addraw_l(n, MAX_MSG, hdr, sizeof(*hdr)); 139 addraw_l(n, MAX_MSG, &cmp, sizeof(cmp)); 140 141#undef PARSE_ERR 142 return 0; 143} 144 145static int cmp_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data, 146 int data_len) 147{ 148 struct tcf_em_cmp *cmp = data; 149 150 if (data_len < sizeof(*cmp)) { 151 fprintf(stderr, "CMP header size mismatch\n"); 152 return -1; 153 } 154 155 if (cmp->align == TCF_EM_ALIGN_U8) 156 fprintf(fd, "u8 "); 157 else if (cmp->align == TCF_EM_ALIGN_U16) 158 fprintf(fd, "u16 "); 159 else if (cmp->align == TCF_EM_ALIGN_U16) 160 fprintf(fd, "u32 "); 161 162 fprintf(fd, "at %d layer %d ", cmp->off, cmp->layer); 163 164 if (cmp->mask) 165 fprintf(fd, "mask 0x%x ", cmp->mask); 166 167 if (cmp->flags & TCF_EM_CMP_TRANS) 168 fprintf(fd, "trans "); 169 170 if (cmp->opnd == TCF_EM_OPND_EQ) 171 fprintf(fd, "eq "); 172 else if (cmp->opnd == TCF_EM_OPND_LT) 173 fprintf(fd, "lt "); 174 else if (cmp->opnd == TCF_EM_OPND_GT) 175 fprintf(fd, "gt "); 176 177 fprintf(fd, "%d", cmp->val); 178 179 return 0; 180} 181 182struct ematch_util cmp_ematch_util = { 183 .kind = "cmp", 184 .kind_num = TCF_EM_CMP, 185 .parse_eopt = cmp_parse_eopt, 186 .print_eopt = cmp_print_eopt, 187 .print_usage = cmp_print_usage 188}; 189