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 <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 <errno.h> 22 23#include "m_ematch.h" 24 25extern struct ematch_util u32_ematch_util; 26 27static void u32_print_usage(FILE *fd) 28{ 29 fprintf(fd, 30 "Usage: u32(ALIGN VALUE MASK at [ nexthdr+ ] OFFSET)\n" \ 31 "where: ALIGN := { u8 | u16 | u32 }\n" \ 32 "\n" \ 33 "Example: u32(u16 0x1122 0xffff at nexthdr+4)\n"); 34} 35 36static int u32_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, 37 struct bstr *args) 38{ 39 struct bstr *a; 40 int align, nh_len; 41 unsigned long key, mask, offmask = 0, offset; 42 struct tc_u32_key u_key; 43 44 memset(&u_key, 0, sizeof(u_key)); 45 46#define PARSE_ERR(CARG, FMT, ARGS...) \ 47 em_parse_error(EINVAL, args, CARG, &u32_ematch_util, FMT ,##ARGS) 48 49 if (args == NULL) 50 return PARSE_ERR(args, "u32: missing arguments"); 51 52 if (!bstrcmp(args, "u8")) 53 align = 1; 54 else if (!bstrcmp(args, "u16")) 55 align = 2; 56 else if (!bstrcmp(args, "u32")) 57 align = 4; 58 else 59 return PARSE_ERR(args, "u32: invalid alignment"); 60 61 a = bstr_next(args); 62 if (a == NULL) 63 return PARSE_ERR(a, "u32: missing key"); 64 65 key = bstrtoul(a); 66 if (key == ULONG_MAX) 67 return PARSE_ERR(a, "u32: invalid key, must be numeric"); 68 69 a = bstr_next(a); 70 if (a == NULL) 71 return PARSE_ERR(a, "u32: missing mask"); 72 73 mask = bstrtoul(a); 74 if (mask == ULONG_MAX) 75 return PARSE_ERR(a, "u32: invalid mask, must be numeric"); 76 77 a = bstr_next(a); 78 if (a == NULL || bstrcmp(a, "at") != 0) 79 return PARSE_ERR(a, "u32: missing \"at\""); 80 81 a = bstr_next(a); 82 if (a == NULL) 83 return PARSE_ERR(a, "u32: missing offset"); 84 85 nh_len = strlen("nexthdr+"); 86 if (a->len > nh_len && !memcmp(a->data, "nexthdr+", nh_len)) { 87 char buf[a->len - nh_len + 1]; 88 offmask = -1; 89 memcpy(buf, a->data + nh_len, a->len - nh_len); 90 offset = strtoul(buf, NULL, 0); 91 } else if (!bstrcmp(a, "nexthdr+")) { 92 a = bstr_next(a); 93 if (a == NULL) 94 return PARSE_ERR(a, "u32: missing offset"); 95 offset = bstrtoul(a); 96 } else 97 offset = bstrtoul(a); 98 99 if (offset == ULONG_MAX) 100 return PARSE_ERR(a, "u32: invalid offset"); 101 102 if (a->next) 103 return PARSE_ERR(a->next, "u32: unexpected trailer"); 104 105 switch (align) { 106 case 1: 107 if (key > 0xFF) 108 return PARSE_ERR(a, "Illegal key (>0xFF)"); 109 if (mask > 0xFF) 110 return PARSE_ERR(a, "Illegal mask (>0xFF)"); 111 112 key <<= 24 - ((offset & 3) * 8); 113 mask <<= 24 - ((offset & 3) * 8); 114 offset &= ~3; 115 break; 116 117 case 2: 118 if (key > 0xFFFF) 119 return PARSE_ERR(a, "Illegal key (>0xFFFF)"); 120 if (mask > 0xFFFF) 121 return PARSE_ERR(a, "Illegal mask (>0xFFFF)"); 122 123 if ((offset & 3) == 0) { 124 key <<= 16; 125 mask <<= 16; 126 } 127 offset &= ~3; 128 break; 129 } 130 131 key = htonl(key); 132 mask = htonl(mask); 133 134 if (offset % 4) 135 return PARSE_ERR(a, "u32: invalid offset alignment, " \ 136 "must be aligned to 4."); 137 138 key &= mask; 139 140 u_key.mask = mask; 141 u_key.val = key; 142 u_key.off = offset; 143 u_key.offmask = offmask; 144 145 addraw_l(n, MAX_MSG, hdr, sizeof(*hdr)); 146 addraw_l(n, MAX_MSG, &u_key, sizeof(u_key)); 147 148#undef PARSE_ERR 149 return 0; 150} 151 152static int u32_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data, 153 int data_len) 154{ 155 struct tc_u32_key *u_key = data; 156 157 if (data_len < sizeof(*u_key)) { 158 fprintf(stderr, "U32 header size mismatch\n"); 159 return -1; 160 } 161 162 fprintf(fd, "%08x/%08x at %s%d", 163 (unsigned int) ntohl(u_key->val), 164 (unsigned int) ntohl(u_key->mask), 165 u_key->offmask ? "nexthdr+" : "", 166 u_key->off); 167 168 return 0; 169} 170 171struct ematch_util u32_ematch_util = { 172 .kind = "u32", 173 .kind_num = TCF_EM_U32, 174 .parse_eopt = u32_parse_eopt, 175 .print_eopt = u32_print_eopt, 176 .print_usage = u32_print_usage 177}; 178