blob: 21ed70fd9b02742b226457c91f0d38bf7d1bd442 [file] [log] [blame]
shemminger311b4142005-06-23 20:25:16 +00001/*
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>
shemminger311b4142005-06-23 20:25:16 +000021#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);
Stephen Hemmingerae665a52006-12-05 10:10:22 -080098
shemminger311b4142005-06-23 20:25:16 +000099 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};