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