1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker * f_flower.c Flower Classifier
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: Jiri Pirko <[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 <string.h>
17*de1e4e89SAndroid Build Coastguard Worker #include <net/if.h>
18*de1e4e89SAndroid Build Coastguard Worker #include <linux/if_arp.h>
19*de1e4e89SAndroid Build Coastguard Worker #include <linux/if_ether.h>
20*de1e4e89SAndroid Build Coastguard Worker #include <linux/ip.h>
21*de1e4e89SAndroid Build Coastguard Worker #include <linux/tc_act/tc_vlan.h>
22*de1e4e89SAndroid Build Coastguard Worker
23*de1e4e89SAndroid Build Coastguard Worker #include "utils.h"
24*de1e4e89SAndroid Build Coastguard Worker #include "tc_util.h"
25*de1e4e89SAndroid Build Coastguard Worker #include "rt_names.h"
26*de1e4e89SAndroid Build Coastguard Worker
27*de1e4e89SAndroid Build Coastguard Worker enum flower_matching_flags {
28*de1e4e89SAndroid Build Coastguard Worker FLOWER_IP_FLAGS,
29*de1e4e89SAndroid Build Coastguard Worker };
30*de1e4e89SAndroid Build Coastguard Worker
31*de1e4e89SAndroid Build Coastguard Worker enum flower_endpoint {
32*de1e4e89SAndroid Build Coastguard Worker FLOWER_ENDPOINT_SRC,
33*de1e4e89SAndroid Build Coastguard Worker FLOWER_ENDPOINT_DST
34*de1e4e89SAndroid Build Coastguard Worker };
35*de1e4e89SAndroid Build Coastguard Worker
36*de1e4e89SAndroid Build Coastguard Worker enum flower_icmp_field {
37*de1e4e89SAndroid Build Coastguard Worker FLOWER_ICMP_FIELD_TYPE,
38*de1e4e89SAndroid Build Coastguard Worker FLOWER_ICMP_FIELD_CODE
39*de1e4e89SAndroid Build Coastguard Worker };
40*de1e4e89SAndroid Build Coastguard Worker
explain(void)41*de1e4e89SAndroid Build Coastguard Worker static void explain(void)
42*de1e4e89SAndroid Build Coastguard Worker {
43*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr,
44*de1e4e89SAndroid Build Coastguard Worker "Usage: ... flower [ MATCH-LIST ]\n"
45*de1e4e89SAndroid Build Coastguard Worker " [ skip_sw | skip_hw ]\n"
46*de1e4e89SAndroid Build Coastguard Worker " [ action ACTION-SPEC ] [ classid CLASSID ]\n"
47*de1e4e89SAndroid Build Coastguard Worker "\n"
48*de1e4e89SAndroid Build Coastguard Worker "Where: MATCH-LIST := [ MATCH-LIST ] MATCH\n"
49*de1e4e89SAndroid Build Coastguard Worker " MATCH := { indev DEV-NAME |\n"
50*de1e4e89SAndroid Build Coastguard Worker " vlan_id VID |\n"
51*de1e4e89SAndroid Build Coastguard Worker " vlan_prio PRIORITY |\n"
52*de1e4e89SAndroid Build Coastguard Worker " vlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n"
53*de1e4e89SAndroid Build Coastguard Worker " dst_mac MASKED-LLADDR |\n"
54*de1e4e89SAndroid Build Coastguard Worker " src_mac MASKED-LLADDR |\n"
55*de1e4e89SAndroid Build Coastguard Worker " ip_proto [tcp | udp | sctp | icmp | icmpv6 | IP-PROTO ] |\n"
56*de1e4e89SAndroid Build Coastguard Worker " ip_tos MASKED-IP_TOS |\n"
57*de1e4e89SAndroid Build Coastguard Worker " ip_ttl MASKED-IP_TTL |\n"
58*de1e4e89SAndroid Build Coastguard Worker " dst_ip PREFIX |\n"
59*de1e4e89SAndroid Build Coastguard Worker " src_ip PREFIX |\n"
60*de1e4e89SAndroid Build Coastguard Worker " dst_port PORT-NUMBER |\n"
61*de1e4e89SAndroid Build Coastguard Worker " src_port PORT-NUMBER |\n"
62*de1e4e89SAndroid Build Coastguard Worker " tcp_flags MASKED-TCP_FLAGS |\n"
63*de1e4e89SAndroid Build Coastguard Worker " type MASKED-ICMP-TYPE |\n"
64*de1e4e89SAndroid Build Coastguard Worker " code MASKED-ICMP-CODE |\n"
65*de1e4e89SAndroid Build Coastguard Worker " arp_tip IPV4-PREFIX |\n"
66*de1e4e89SAndroid Build Coastguard Worker " arp_sip IPV4-PREFIX |\n"
67*de1e4e89SAndroid Build Coastguard Worker " arp_op [ request | reply | OP ] |\n"
68*de1e4e89SAndroid Build Coastguard Worker " arp_tha MASKED-LLADDR |\n"
69*de1e4e89SAndroid Build Coastguard Worker " arp_sha MASKED-LLADDR |\n"
70*de1e4e89SAndroid Build Coastguard Worker " enc_dst_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
71*de1e4e89SAndroid Build Coastguard Worker " enc_src_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
72*de1e4e89SAndroid Build Coastguard Worker " enc_key_id [ KEY-ID ] |\n"
73*de1e4e89SAndroid Build Coastguard Worker " ip_flags IP-FLAGS | \n"
74*de1e4e89SAndroid Build Coastguard Worker " enc_dst_port [ port_number ] }\n"
75*de1e4e89SAndroid Build Coastguard Worker " FILTERID := X:Y:Z\n"
76*de1e4e89SAndroid Build Coastguard Worker " MASKED_LLADDR := { LLADDR | LLADDR/MASK | LLADDR/BITS }\n"
77*de1e4e89SAndroid Build Coastguard Worker " ACTION-SPEC := ... look at individual actions\n"
78*de1e4e89SAndroid Build Coastguard Worker "\n"
79*de1e4e89SAndroid Build Coastguard Worker "NOTE: CLASSID, IP-PROTO are parsed as hexadecimal input.\n"
80*de1e4e89SAndroid Build Coastguard Worker "NOTE: There can be only used one mask per one prio. If user needs\n"
81*de1e4e89SAndroid Build Coastguard Worker " to specify different mask, he has to use different prio.\n");
82*de1e4e89SAndroid Build Coastguard Worker }
83*de1e4e89SAndroid Build Coastguard Worker
flower_parse_eth_addr(char * str,int addr_type,int mask_type,struct nlmsghdr * n)84*de1e4e89SAndroid Build Coastguard Worker static int flower_parse_eth_addr(char *str, int addr_type, int mask_type,
85*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *n)
86*de1e4e89SAndroid Build Coastguard Worker {
87*de1e4e89SAndroid Build Coastguard Worker int ret, err = -1;
88*de1e4e89SAndroid Build Coastguard Worker char addr[ETH_ALEN], *slash;
89*de1e4e89SAndroid Build Coastguard Worker
90*de1e4e89SAndroid Build Coastguard Worker slash = strchr(str, '/');
91*de1e4e89SAndroid Build Coastguard Worker if (slash)
92*de1e4e89SAndroid Build Coastguard Worker *slash = '\0';
93*de1e4e89SAndroid Build Coastguard Worker
94*de1e4e89SAndroid Build Coastguard Worker ret = ll_addr_a2n(addr, sizeof(addr), str);
95*de1e4e89SAndroid Build Coastguard Worker if (ret < 0)
96*de1e4e89SAndroid Build Coastguard Worker goto err;
97*de1e4e89SAndroid Build Coastguard Worker addattr_l(n, MAX_MSG, addr_type, addr, sizeof(addr));
98*de1e4e89SAndroid Build Coastguard Worker
99*de1e4e89SAndroid Build Coastguard Worker if (slash) {
100*de1e4e89SAndroid Build Coastguard Worker unsigned bits;
101*de1e4e89SAndroid Build Coastguard Worker
102*de1e4e89SAndroid Build Coastguard Worker if (!get_unsigned(&bits, slash + 1, 10)) {
103*de1e4e89SAndroid Build Coastguard Worker uint64_t mask;
104*de1e4e89SAndroid Build Coastguard Worker
105*de1e4e89SAndroid Build Coastguard Worker /* Extra 16 bit shift to push mac address into
106*de1e4e89SAndroid Build Coastguard Worker * high bits of uint64_t
107*de1e4e89SAndroid Build Coastguard Worker */
108*de1e4e89SAndroid Build Coastguard Worker mask = htonll(0xffffffffffffULL << (16 + 48 - bits));
109*de1e4e89SAndroid Build Coastguard Worker memcpy(addr, &mask, ETH_ALEN);
110*de1e4e89SAndroid Build Coastguard Worker } else {
111*de1e4e89SAndroid Build Coastguard Worker ret = ll_addr_a2n(addr, sizeof(addr), slash + 1);
112*de1e4e89SAndroid Build Coastguard Worker if (ret < 0)
113*de1e4e89SAndroid Build Coastguard Worker goto err;
114*de1e4e89SAndroid Build Coastguard Worker }
115*de1e4e89SAndroid Build Coastguard Worker } else {
116*de1e4e89SAndroid Build Coastguard Worker memset(addr, 0xff, ETH_ALEN);
117*de1e4e89SAndroid Build Coastguard Worker }
118*de1e4e89SAndroid Build Coastguard Worker addattr_l(n, MAX_MSG, mask_type, addr, sizeof(addr));
119*de1e4e89SAndroid Build Coastguard Worker
120*de1e4e89SAndroid Build Coastguard Worker err = 0;
121*de1e4e89SAndroid Build Coastguard Worker err:
122*de1e4e89SAndroid Build Coastguard Worker if (slash)
123*de1e4e89SAndroid Build Coastguard Worker *slash = '/';
124*de1e4e89SAndroid Build Coastguard Worker return err;
125*de1e4e89SAndroid Build Coastguard Worker }
126*de1e4e89SAndroid Build Coastguard Worker
flower_parse_vlan_eth_type(char * str,__be16 eth_type,int type,__be16 * p_vlan_eth_type,struct nlmsghdr * n)127*de1e4e89SAndroid Build Coastguard Worker static int flower_parse_vlan_eth_type(char *str, __be16 eth_type, int type,
128*de1e4e89SAndroid Build Coastguard Worker __be16 *p_vlan_eth_type,
129*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *n)
130*de1e4e89SAndroid Build Coastguard Worker {
131*de1e4e89SAndroid Build Coastguard Worker __be16 vlan_eth_type;
132*de1e4e89SAndroid Build Coastguard Worker
133*de1e4e89SAndroid Build Coastguard Worker if (eth_type != htons(ETH_P_8021Q)) {
134*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr,
135*de1e4e89SAndroid Build Coastguard Worker "Can't set \"vlan_ethtype\" if ethertype isn't 802.1Q\n");
136*de1e4e89SAndroid Build Coastguard Worker return -1;
137*de1e4e89SAndroid Build Coastguard Worker }
138*de1e4e89SAndroid Build Coastguard Worker
139*de1e4e89SAndroid Build Coastguard Worker if (ll_proto_a2n(&vlan_eth_type, str))
140*de1e4e89SAndroid Build Coastguard Worker invarg("invalid vlan_ethtype", str);
141*de1e4e89SAndroid Build Coastguard Worker addattr16(n, MAX_MSG, type, vlan_eth_type);
142*de1e4e89SAndroid Build Coastguard Worker *p_vlan_eth_type = vlan_eth_type;
143*de1e4e89SAndroid Build Coastguard Worker return 0;
144*de1e4e89SAndroid Build Coastguard Worker }
145*de1e4e89SAndroid Build Coastguard Worker
146*de1e4e89SAndroid Build Coastguard Worker struct flag_to_string {
147*de1e4e89SAndroid Build Coastguard Worker int flag;
148*de1e4e89SAndroid Build Coastguard Worker enum flower_matching_flags type;
149*de1e4e89SAndroid Build Coastguard Worker char *string;
150*de1e4e89SAndroid Build Coastguard Worker };
151*de1e4e89SAndroid Build Coastguard Worker
152*de1e4e89SAndroid Build Coastguard Worker static struct flag_to_string flags_str[] = {
153*de1e4e89SAndroid Build Coastguard Worker { TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOWER_IP_FLAGS, "frag" },
154*de1e4e89SAndroid Build Coastguard Worker };
155*de1e4e89SAndroid Build Coastguard Worker
flower_parse_matching_flags(char * str,enum flower_matching_flags type,__u32 * mtf,__u32 * mtf_mask)156*de1e4e89SAndroid Build Coastguard Worker static int flower_parse_matching_flags(char *str,
157*de1e4e89SAndroid Build Coastguard Worker enum flower_matching_flags type,
158*de1e4e89SAndroid Build Coastguard Worker __u32 *mtf, __u32 *mtf_mask)
159*de1e4e89SAndroid Build Coastguard Worker {
160*de1e4e89SAndroid Build Coastguard Worker char *token;
161*de1e4e89SAndroid Build Coastguard Worker bool no;
162*de1e4e89SAndroid Build Coastguard Worker bool found;
163*de1e4e89SAndroid Build Coastguard Worker int i;
164*de1e4e89SAndroid Build Coastguard Worker
165*de1e4e89SAndroid Build Coastguard Worker token = strtok(str, "/");
166*de1e4e89SAndroid Build Coastguard Worker
167*de1e4e89SAndroid Build Coastguard Worker while (token) {
168*de1e4e89SAndroid Build Coastguard Worker if (!strncmp(token, "no", 2)) {
169*de1e4e89SAndroid Build Coastguard Worker no = true;
170*de1e4e89SAndroid Build Coastguard Worker token += 2;
171*de1e4e89SAndroid Build Coastguard Worker } else
172*de1e4e89SAndroid Build Coastguard Worker no = false;
173*de1e4e89SAndroid Build Coastguard Worker
174*de1e4e89SAndroid Build Coastguard Worker found = false;
175*de1e4e89SAndroid Build Coastguard Worker for (i = 0; i < ARRAY_SIZE(flags_str); i++) {
176*de1e4e89SAndroid Build Coastguard Worker if (type != flags_str[i].type)
177*de1e4e89SAndroid Build Coastguard Worker continue;
178*de1e4e89SAndroid Build Coastguard Worker
179*de1e4e89SAndroid Build Coastguard Worker if (!strcmp(token, flags_str[i].string)) {
180*de1e4e89SAndroid Build Coastguard Worker if (no)
181*de1e4e89SAndroid Build Coastguard Worker *mtf &= ~flags_str[i].flag;
182*de1e4e89SAndroid Build Coastguard Worker else
183*de1e4e89SAndroid Build Coastguard Worker *mtf |= flags_str[i].flag;
184*de1e4e89SAndroid Build Coastguard Worker
185*de1e4e89SAndroid Build Coastguard Worker *mtf_mask |= flags_str[i].flag;
186*de1e4e89SAndroid Build Coastguard Worker found = true;
187*de1e4e89SAndroid Build Coastguard Worker break;
188*de1e4e89SAndroid Build Coastguard Worker }
189*de1e4e89SAndroid Build Coastguard Worker }
190*de1e4e89SAndroid Build Coastguard Worker if (!found)
191*de1e4e89SAndroid Build Coastguard Worker return -1;
192*de1e4e89SAndroid Build Coastguard Worker
193*de1e4e89SAndroid Build Coastguard Worker token = strtok(NULL, "/");
194*de1e4e89SAndroid Build Coastguard Worker }
195*de1e4e89SAndroid Build Coastguard Worker
196*de1e4e89SAndroid Build Coastguard Worker return 0;
197*de1e4e89SAndroid Build Coastguard Worker }
198*de1e4e89SAndroid Build Coastguard Worker
flower_parse_ip_proto(char * str,__be16 eth_type,int type,__u8 * p_ip_proto,struct nlmsghdr * n)199*de1e4e89SAndroid Build Coastguard Worker static int flower_parse_ip_proto(char *str, __be16 eth_type, int type,
200*de1e4e89SAndroid Build Coastguard Worker __u8 *p_ip_proto, struct nlmsghdr *n)
201*de1e4e89SAndroid Build Coastguard Worker {
202*de1e4e89SAndroid Build Coastguard Worker int ret;
203*de1e4e89SAndroid Build Coastguard Worker __u8 ip_proto;
204*de1e4e89SAndroid Build Coastguard Worker
205*de1e4e89SAndroid Build Coastguard Worker if (eth_type != htons(ETH_P_IP) && eth_type != htons(ETH_P_IPV6))
206*de1e4e89SAndroid Build Coastguard Worker goto err;
207*de1e4e89SAndroid Build Coastguard Worker
208*de1e4e89SAndroid Build Coastguard Worker if (matches(str, "tcp") == 0) {
209*de1e4e89SAndroid Build Coastguard Worker ip_proto = IPPROTO_TCP;
210*de1e4e89SAndroid Build Coastguard Worker } else if (matches(str, "udp") == 0) {
211*de1e4e89SAndroid Build Coastguard Worker ip_proto = IPPROTO_UDP;
212*de1e4e89SAndroid Build Coastguard Worker } else if (matches(str, "sctp") == 0) {
213*de1e4e89SAndroid Build Coastguard Worker ip_proto = IPPROTO_SCTP;
214*de1e4e89SAndroid Build Coastguard Worker } else if (matches(str, "icmp") == 0) {
215*de1e4e89SAndroid Build Coastguard Worker if (eth_type != htons(ETH_P_IP))
216*de1e4e89SAndroid Build Coastguard Worker goto err;
217*de1e4e89SAndroid Build Coastguard Worker ip_proto = IPPROTO_ICMP;
218*de1e4e89SAndroid Build Coastguard Worker } else if (matches(str, "icmpv6") == 0) {
219*de1e4e89SAndroid Build Coastguard Worker if (eth_type != htons(ETH_P_IPV6))
220*de1e4e89SAndroid Build Coastguard Worker goto err;
221*de1e4e89SAndroid Build Coastguard Worker ip_proto = IPPROTO_ICMPV6;
222*de1e4e89SAndroid Build Coastguard Worker } else {
223*de1e4e89SAndroid Build Coastguard Worker ret = get_u8(&ip_proto, str, 16);
224*de1e4e89SAndroid Build Coastguard Worker if (ret)
225*de1e4e89SAndroid Build Coastguard Worker return -1;
226*de1e4e89SAndroid Build Coastguard Worker }
227*de1e4e89SAndroid Build Coastguard Worker addattr8(n, MAX_MSG, type, ip_proto);
228*de1e4e89SAndroid Build Coastguard Worker *p_ip_proto = ip_proto;
229*de1e4e89SAndroid Build Coastguard Worker return 0;
230*de1e4e89SAndroid Build Coastguard Worker
231*de1e4e89SAndroid Build Coastguard Worker err:
232*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"eth_type\" for ip proto\n");
233*de1e4e89SAndroid Build Coastguard Worker return -1;
234*de1e4e89SAndroid Build Coastguard Worker }
235*de1e4e89SAndroid Build Coastguard Worker
__flower_parse_ip_addr(char * str,int family,int addr4_type,int mask4_type,int addr6_type,int mask6_type,struct nlmsghdr * n)236*de1e4e89SAndroid Build Coastguard Worker static int __flower_parse_ip_addr(char *str, int family,
237*de1e4e89SAndroid Build Coastguard Worker int addr4_type, int mask4_type,
238*de1e4e89SAndroid Build Coastguard Worker int addr6_type, int mask6_type,
239*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *n)
240*de1e4e89SAndroid Build Coastguard Worker {
241*de1e4e89SAndroid Build Coastguard Worker int ret;
242*de1e4e89SAndroid Build Coastguard Worker inet_prefix addr;
243*de1e4e89SAndroid Build Coastguard Worker int bits;
244*de1e4e89SAndroid Build Coastguard Worker int i;
245*de1e4e89SAndroid Build Coastguard Worker
246*de1e4e89SAndroid Build Coastguard Worker ret = get_prefix(&addr, str, family);
247*de1e4e89SAndroid Build Coastguard Worker if (ret)
248*de1e4e89SAndroid Build Coastguard Worker return -1;
249*de1e4e89SAndroid Build Coastguard Worker
250*de1e4e89SAndroid Build Coastguard Worker if (family && (addr.family != family)) {
251*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"eth_type\" for ip address\n");
252*de1e4e89SAndroid Build Coastguard Worker return -1;
253*de1e4e89SAndroid Build Coastguard Worker }
254*de1e4e89SAndroid Build Coastguard Worker
255*de1e4e89SAndroid Build Coastguard Worker addattr_l(n, MAX_MSG, addr.family == AF_INET ? addr4_type : addr6_type,
256*de1e4e89SAndroid Build Coastguard Worker addr.data, addr.bytelen);
257*de1e4e89SAndroid Build Coastguard Worker
258*de1e4e89SAndroid Build Coastguard Worker memset(addr.data, 0xff, addr.bytelen);
259*de1e4e89SAndroid Build Coastguard Worker bits = addr.bitlen;
260*de1e4e89SAndroid Build Coastguard Worker for (i = 0; i < addr.bytelen / 4; i++) {
261*de1e4e89SAndroid Build Coastguard Worker if (!bits) {
262*de1e4e89SAndroid Build Coastguard Worker addr.data[i] = 0;
263*de1e4e89SAndroid Build Coastguard Worker } else if (bits / 32 >= 1) {
264*de1e4e89SAndroid Build Coastguard Worker bits -= 32;
265*de1e4e89SAndroid Build Coastguard Worker } else {
266*de1e4e89SAndroid Build Coastguard Worker addr.data[i] <<= 32 - bits;
267*de1e4e89SAndroid Build Coastguard Worker addr.data[i] = htonl(addr.data[i]);
268*de1e4e89SAndroid Build Coastguard Worker bits = 0;
269*de1e4e89SAndroid Build Coastguard Worker }
270*de1e4e89SAndroid Build Coastguard Worker }
271*de1e4e89SAndroid Build Coastguard Worker
272*de1e4e89SAndroid Build Coastguard Worker addattr_l(n, MAX_MSG, addr.family == AF_INET ? mask4_type : mask6_type,
273*de1e4e89SAndroid Build Coastguard Worker addr.data, addr.bytelen);
274*de1e4e89SAndroid Build Coastguard Worker
275*de1e4e89SAndroid Build Coastguard Worker return 0;
276*de1e4e89SAndroid Build Coastguard Worker }
277*de1e4e89SAndroid Build Coastguard Worker
flower_parse_ip_addr(char * str,__be16 eth_type,int addr4_type,int mask4_type,int addr6_type,int mask6_type,struct nlmsghdr * n)278*de1e4e89SAndroid Build Coastguard Worker static int flower_parse_ip_addr(char *str, __be16 eth_type,
279*de1e4e89SAndroid Build Coastguard Worker int addr4_type, int mask4_type,
280*de1e4e89SAndroid Build Coastguard Worker int addr6_type, int mask6_type,
281*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *n)
282*de1e4e89SAndroid Build Coastguard Worker {
283*de1e4e89SAndroid Build Coastguard Worker int family;
284*de1e4e89SAndroid Build Coastguard Worker
285*de1e4e89SAndroid Build Coastguard Worker if (eth_type == htons(ETH_P_IP)) {
286*de1e4e89SAndroid Build Coastguard Worker family = AF_INET;
287*de1e4e89SAndroid Build Coastguard Worker } else if (eth_type == htons(ETH_P_IPV6)) {
288*de1e4e89SAndroid Build Coastguard Worker family = AF_INET6;
289*de1e4e89SAndroid Build Coastguard Worker } else if (!eth_type) {
290*de1e4e89SAndroid Build Coastguard Worker family = AF_UNSPEC;
291*de1e4e89SAndroid Build Coastguard Worker } else {
292*de1e4e89SAndroid Build Coastguard Worker return -1;
293*de1e4e89SAndroid Build Coastguard Worker }
294*de1e4e89SAndroid Build Coastguard Worker
295*de1e4e89SAndroid Build Coastguard Worker return __flower_parse_ip_addr(str, family, addr4_type, mask4_type,
296*de1e4e89SAndroid Build Coastguard Worker addr6_type, mask6_type, n);
297*de1e4e89SAndroid Build Coastguard Worker }
298*de1e4e89SAndroid Build Coastguard Worker
flower_eth_type_arp(__be16 eth_type)299*de1e4e89SAndroid Build Coastguard Worker static bool flower_eth_type_arp(__be16 eth_type)
300*de1e4e89SAndroid Build Coastguard Worker {
301*de1e4e89SAndroid Build Coastguard Worker return eth_type == htons(ETH_P_ARP) || eth_type == htons(ETH_P_RARP);
302*de1e4e89SAndroid Build Coastguard Worker }
303*de1e4e89SAndroid Build Coastguard Worker
flower_parse_arp_ip_addr(char * str,__be16 eth_type,int addr_type,int mask_type,struct nlmsghdr * n)304*de1e4e89SAndroid Build Coastguard Worker static int flower_parse_arp_ip_addr(char *str, __be16 eth_type,
305*de1e4e89SAndroid Build Coastguard Worker int addr_type, int mask_type,
306*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *n)
307*de1e4e89SAndroid Build Coastguard Worker {
308*de1e4e89SAndroid Build Coastguard Worker if (!flower_eth_type_arp(eth_type))
309*de1e4e89SAndroid Build Coastguard Worker return -1;
310*de1e4e89SAndroid Build Coastguard Worker
311*de1e4e89SAndroid Build Coastguard Worker return __flower_parse_ip_addr(str, AF_INET, addr_type, mask_type,
312*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_UNSPEC, TCA_FLOWER_UNSPEC, n);
313*de1e4e89SAndroid Build Coastguard Worker }
314*de1e4e89SAndroid Build Coastguard Worker
flower_parse_u8(char * str,int value_type,int mask_type,int (* value_from_name)(const char * str,__u8 * value),bool (* value_validate)(__u8 value),struct nlmsghdr * n)315*de1e4e89SAndroid Build Coastguard Worker static int flower_parse_u8(char *str, int value_type, int mask_type,
316*de1e4e89SAndroid Build Coastguard Worker int (*value_from_name)(const char *str,
317*de1e4e89SAndroid Build Coastguard Worker __u8 *value),
318*de1e4e89SAndroid Build Coastguard Worker bool (*value_validate)(__u8 value),
319*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *n)
320*de1e4e89SAndroid Build Coastguard Worker {
321*de1e4e89SAndroid Build Coastguard Worker char *slash;
322*de1e4e89SAndroid Build Coastguard Worker int ret, err = -1;
323*de1e4e89SAndroid Build Coastguard Worker __u8 value, mask;
324*de1e4e89SAndroid Build Coastguard Worker
325*de1e4e89SAndroid Build Coastguard Worker slash = strchr(str, '/');
326*de1e4e89SAndroid Build Coastguard Worker if (slash)
327*de1e4e89SAndroid Build Coastguard Worker *slash = '\0';
328*de1e4e89SAndroid Build Coastguard Worker
329*de1e4e89SAndroid Build Coastguard Worker ret = value_from_name ? value_from_name(str, &value) : -1;
330*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
331*de1e4e89SAndroid Build Coastguard Worker ret = get_u8(&value, str, 10);
332*de1e4e89SAndroid Build Coastguard Worker if (ret)
333*de1e4e89SAndroid Build Coastguard Worker goto err;
334*de1e4e89SAndroid Build Coastguard Worker }
335*de1e4e89SAndroid Build Coastguard Worker
336*de1e4e89SAndroid Build Coastguard Worker if (value_validate && !value_validate(value))
337*de1e4e89SAndroid Build Coastguard Worker goto err;
338*de1e4e89SAndroid Build Coastguard Worker
339*de1e4e89SAndroid Build Coastguard Worker if (slash) {
340*de1e4e89SAndroid Build Coastguard Worker ret = get_u8(&mask, slash + 1, 10);
341*de1e4e89SAndroid Build Coastguard Worker if (ret)
342*de1e4e89SAndroid Build Coastguard Worker goto err;
343*de1e4e89SAndroid Build Coastguard Worker }
344*de1e4e89SAndroid Build Coastguard Worker else {
345*de1e4e89SAndroid Build Coastguard Worker mask = UINT8_MAX;
346*de1e4e89SAndroid Build Coastguard Worker }
347*de1e4e89SAndroid Build Coastguard Worker
348*de1e4e89SAndroid Build Coastguard Worker addattr8(n, MAX_MSG, value_type, value);
349*de1e4e89SAndroid Build Coastguard Worker addattr8(n, MAX_MSG, mask_type, mask);
350*de1e4e89SAndroid Build Coastguard Worker
351*de1e4e89SAndroid Build Coastguard Worker err = 0;
352*de1e4e89SAndroid Build Coastguard Worker err:
353*de1e4e89SAndroid Build Coastguard Worker if (slash)
354*de1e4e89SAndroid Build Coastguard Worker *slash = '/';
355*de1e4e89SAndroid Build Coastguard Worker return err;
356*de1e4e89SAndroid Build Coastguard Worker }
357*de1e4e89SAndroid Build Coastguard Worker
flower_print_arp_op_to_name(__u8 op)358*de1e4e89SAndroid Build Coastguard Worker static const char *flower_print_arp_op_to_name(__u8 op)
359*de1e4e89SAndroid Build Coastguard Worker {
360*de1e4e89SAndroid Build Coastguard Worker switch (op) {
361*de1e4e89SAndroid Build Coastguard Worker case ARPOP_REQUEST:
362*de1e4e89SAndroid Build Coastguard Worker return "request";
363*de1e4e89SAndroid Build Coastguard Worker case ARPOP_REPLY:
364*de1e4e89SAndroid Build Coastguard Worker return "reply";
365*de1e4e89SAndroid Build Coastguard Worker default:
366*de1e4e89SAndroid Build Coastguard Worker return NULL;
367*de1e4e89SAndroid Build Coastguard Worker }
368*de1e4e89SAndroid Build Coastguard Worker }
369*de1e4e89SAndroid Build Coastguard Worker
flower_arp_op_from_name(const char * name,__u8 * op)370*de1e4e89SAndroid Build Coastguard Worker static int flower_arp_op_from_name(const char *name, __u8 *op)
371*de1e4e89SAndroid Build Coastguard Worker {
372*de1e4e89SAndroid Build Coastguard Worker if (!strcmp(name, "request"))
373*de1e4e89SAndroid Build Coastguard Worker *op = ARPOP_REQUEST;
374*de1e4e89SAndroid Build Coastguard Worker else if (!strcmp(name, "reply"))
375*de1e4e89SAndroid Build Coastguard Worker *op = ARPOP_REPLY;
376*de1e4e89SAndroid Build Coastguard Worker else
377*de1e4e89SAndroid Build Coastguard Worker return -1;
378*de1e4e89SAndroid Build Coastguard Worker
379*de1e4e89SAndroid Build Coastguard Worker return 0;
380*de1e4e89SAndroid Build Coastguard Worker }
381*de1e4e89SAndroid Build Coastguard Worker
flow_arp_op_validate(__u8 op)382*de1e4e89SAndroid Build Coastguard Worker static bool flow_arp_op_validate(__u8 op)
383*de1e4e89SAndroid Build Coastguard Worker {
384*de1e4e89SAndroid Build Coastguard Worker return !op || op == ARPOP_REQUEST || op == ARPOP_REPLY;
385*de1e4e89SAndroid Build Coastguard Worker }
386*de1e4e89SAndroid Build Coastguard Worker
flower_parse_arp_op(char * str,__be16 eth_type,int op_type,int mask_type,struct nlmsghdr * n)387*de1e4e89SAndroid Build Coastguard Worker static int flower_parse_arp_op(char *str, __be16 eth_type,
388*de1e4e89SAndroid Build Coastguard Worker int op_type, int mask_type,
389*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *n)
390*de1e4e89SAndroid Build Coastguard Worker {
391*de1e4e89SAndroid Build Coastguard Worker if (!flower_eth_type_arp(eth_type))
392*de1e4e89SAndroid Build Coastguard Worker return -1;
393*de1e4e89SAndroid Build Coastguard Worker
394*de1e4e89SAndroid Build Coastguard Worker return flower_parse_u8(str, op_type, mask_type, flower_arp_op_from_name,
395*de1e4e89SAndroid Build Coastguard Worker flow_arp_op_validate, n);
396*de1e4e89SAndroid Build Coastguard Worker }
397*de1e4e89SAndroid Build Coastguard Worker
flower_icmp_attr_type(__be16 eth_type,__u8 ip_proto,enum flower_icmp_field field)398*de1e4e89SAndroid Build Coastguard Worker static int flower_icmp_attr_type(__be16 eth_type, __u8 ip_proto,
399*de1e4e89SAndroid Build Coastguard Worker enum flower_icmp_field field)
400*de1e4e89SAndroid Build Coastguard Worker {
401*de1e4e89SAndroid Build Coastguard Worker if (eth_type == htons(ETH_P_IP) && ip_proto == IPPROTO_ICMP)
402*de1e4e89SAndroid Build Coastguard Worker return field == FLOWER_ICMP_FIELD_CODE ?
403*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ICMPV4_CODE :
404*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ICMPV4_TYPE;
405*de1e4e89SAndroid Build Coastguard Worker else if (eth_type == htons(ETH_P_IPV6) && ip_proto == IPPROTO_ICMPV6)
406*de1e4e89SAndroid Build Coastguard Worker return field == FLOWER_ICMP_FIELD_CODE ?
407*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ICMPV6_CODE :
408*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ICMPV6_TYPE;
409*de1e4e89SAndroid Build Coastguard Worker
410*de1e4e89SAndroid Build Coastguard Worker return -1;
411*de1e4e89SAndroid Build Coastguard Worker }
412*de1e4e89SAndroid Build Coastguard Worker
flower_icmp_attr_mask_type(__be16 eth_type,__u8 ip_proto,enum flower_icmp_field field)413*de1e4e89SAndroid Build Coastguard Worker static int flower_icmp_attr_mask_type(__be16 eth_type, __u8 ip_proto,
414*de1e4e89SAndroid Build Coastguard Worker enum flower_icmp_field field)
415*de1e4e89SAndroid Build Coastguard Worker {
416*de1e4e89SAndroid Build Coastguard Worker if (eth_type == htons(ETH_P_IP) && ip_proto == IPPROTO_ICMP)
417*de1e4e89SAndroid Build Coastguard Worker return field == FLOWER_ICMP_FIELD_CODE ?
418*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ICMPV4_CODE_MASK :
419*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ICMPV4_TYPE_MASK;
420*de1e4e89SAndroid Build Coastguard Worker else if (eth_type == htons(ETH_P_IPV6) && ip_proto == IPPROTO_ICMPV6)
421*de1e4e89SAndroid Build Coastguard Worker return field == FLOWER_ICMP_FIELD_CODE ?
422*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ICMPV6_CODE_MASK :
423*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ICMPV6_TYPE_MASK;
424*de1e4e89SAndroid Build Coastguard Worker
425*de1e4e89SAndroid Build Coastguard Worker return -1;
426*de1e4e89SAndroid Build Coastguard Worker }
427*de1e4e89SAndroid Build Coastguard Worker
flower_parse_icmp(char * str,__u16 eth_type,__u8 ip_proto,enum flower_icmp_field field,struct nlmsghdr * n)428*de1e4e89SAndroid Build Coastguard Worker static int flower_parse_icmp(char *str, __u16 eth_type, __u8 ip_proto,
429*de1e4e89SAndroid Build Coastguard Worker enum flower_icmp_field field, struct nlmsghdr *n)
430*de1e4e89SAndroid Build Coastguard Worker {
431*de1e4e89SAndroid Build Coastguard Worker int value_type, mask_type;
432*de1e4e89SAndroid Build Coastguard Worker
433*de1e4e89SAndroid Build Coastguard Worker value_type = flower_icmp_attr_type(eth_type, ip_proto, field);
434*de1e4e89SAndroid Build Coastguard Worker mask_type = flower_icmp_attr_mask_type(eth_type, ip_proto, field);
435*de1e4e89SAndroid Build Coastguard Worker if (value_type < 0 || mask_type < 0)
436*de1e4e89SAndroid Build Coastguard Worker return -1;
437*de1e4e89SAndroid Build Coastguard Worker
438*de1e4e89SAndroid Build Coastguard Worker return flower_parse_u8(str, value_type, mask_type, NULL, NULL, n);
439*de1e4e89SAndroid Build Coastguard Worker }
440*de1e4e89SAndroid Build Coastguard Worker
flower_port_attr_type(__u8 ip_proto,enum flower_endpoint endpoint)441*de1e4e89SAndroid Build Coastguard Worker static int flower_port_attr_type(__u8 ip_proto, enum flower_endpoint endpoint)
442*de1e4e89SAndroid Build Coastguard Worker {
443*de1e4e89SAndroid Build Coastguard Worker if (ip_proto == IPPROTO_TCP)
444*de1e4e89SAndroid Build Coastguard Worker return endpoint == FLOWER_ENDPOINT_SRC ?
445*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_TCP_SRC :
446*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_TCP_DST;
447*de1e4e89SAndroid Build Coastguard Worker else if (ip_proto == IPPROTO_UDP)
448*de1e4e89SAndroid Build Coastguard Worker return endpoint == FLOWER_ENDPOINT_SRC ?
449*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_UDP_SRC :
450*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_UDP_DST;
451*de1e4e89SAndroid Build Coastguard Worker else if (ip_proto == IPPROTO_SCTP)
452*de1e4e89SAndroid Build Coastguard Worker return endpoint == FLOWER_ENDPOINT_SRC ?
453*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_SCTP_SRC :
454*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_SCTP_DST;
455*de1e4e89SAndroid Build Coastguard Worker else
456*de1e4e89SAndroid Build Coastguard Worker return -1;
457*de1e4e89SAndroid Build Coastguard Worker }
458*de1e4e89SAndroid Build Coastguard Worker
flower_parse_port(char * str,__u8 ip_proto,enum flower_endpoint endpoint,struct nlmsghdr * n)459*de1e4e89SAndroid Build Coastguard Worker static int flower_parse_port(char *str, __u8 ip_proto,
460*de1e4e89SAndroid Build Coastguard Worker enum flower_endpoint endpoint,
461*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *n)
462*de1e4e89SAndroid Build Coastguard Worker {
463*de1e4e89SAndroid Build Coastguard Worker int ret;
464*de1e4e89SAndroid Build Coastguard Worker int type;
465*de1e4e89SAndroid Build Coastguard Worker __be16 port;
466*de1e4e89SAndroid Build Coastguard Worker
467*de1e4e89SAndroid Build Coastguard Worker type = flower_port_attr_type(ip_proto, endpoint);
468*de1e4e89SAndroid Build Coastguard Worker if (type < 0)
469*de1e4e89SAndroid Build Coastguard Worker return -1;
470*de1e4e89SAndroid Build Coastguard Worker
471*de1e4e89SAndroid Build Coastguard Worker ret = get_be16(&port, str, 10);
472*de1e4e89SAndroid Build Coastguard Worker if (ret)
473*de1e4e89SAndroid Build Coastguard Worker return -1;
474*de1e4e89SAndroid Build Coastguard Worker
475*de1e4e89SAndroid Build Coastguard Worker addattr16(n, MAX_MSG, type, port);
476*de1e4e89SAndroid Build Coastguard Worker
477*de1e4e89SAndroid Build Coastguard Worker return 0;
478*de1e4e89SAndroid Build Coastguard Worker }
479*de1e4e89SAndroid Build Coastguard Worker
480*de1e4e89SAndroid Build Coastguard Worker #define TCP_FLAGS_MAX_MASK 0xfff
481*de1e4e89SAndroid Build Coastguard Worker
flower_parse_tcp_flags(char * str,int flags_type,int mask_type,struct nlmsghdr * n)482*de1e4e89SAndroid Build Coastguard Worker static int flower_parse_tcp_flags(char *str, int flags_type, int mask_type,
483*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *n)
484*de1e4e89SAndroid Build Coastguard Worker {
485*de1e4e89SAndroid Build Coastguard Worker char *slash;
486*de1e4e89SAndroid Build Coastguard Worker int ret, err = -1;
487*de1e4e89SAndroid Build Coastguard Worker __u16 flags;
488*de1e4e89SAndroid Build Coastguard Worker
489*de1e4e89SAndroid Build Coastguard Worker slash = strchr(str, '/');
490*de1e4e89SAndroid Build Coastguard Worker if (slash)
491*de1e4e89SAndroid Build Coastguard Worker *slash = '\0';
492*de1e4e89SAndroid Build Coastguard Worker
493*de1e4e89SAndroid Build Coastguard Worker ret = get_u16(&flags, str, 16);
494*de1e4e89SAndroid Build Coastguard Worker if (ret < 0 || flags & ~TCP_FLAGS_MAX_MASK)
495*de1e4e89SAndroid Build Coastguard Worker goto err;
496*de1e4e89SAndroid Build Coastguard Worker
497*de1e4e89SAndroid Build Coastguard Worker addattr16(n, MAX_MSG, flags_type, htons(flags));
498*de1e4e89SAndroid Build Coastguard Worker
499*de1e4e89SAndroid Build Coastguard Worker if (slash) {
500*de1e4e89SAndroid Build Coastguard Worker ret = get_u16(&flags, slash + 1, 16);
501*de1e4e89SAndroid Build Coastguard Worker if (ret < 0 || flags & ~TCP_FLAGS_MAX_MASK)
502*de1e4e89SAndroid Build Coastguard Worker goto err;
503*de1e4e89SAndroid Build Coastguard Worker } else {
504*de1e4e89SAndroid Build Coastguard Worker flags = TCP_FLAGS_MAX_MASK;
505*de1e4e89SAndroid Build Coastguard Worker }
506*de1e4e89SAndroid Build Coastguard Worker addattr16(n, MAX_MSG, mask_type, htons(flags));
507*de1e4e89SAndroid Build Coastguard Worker
508*de1e4e89SAndroid Build Coastguard Worker err = 0;
509*de1e4e89SAndroid Build Coastguard Worker err:
510*de1e4e89SAndroid Build Coastguard Worker if (slash)
511*de1e4e89SAndroid Build Coastguard Worker *slash = '/';
512*de1e4e89SAndroid Build Coastguard Worker return err;
513*de1e4e89SAndroid Build Coastguard Worker }
514*de1e4e89SAndroid Build Coastguard Worker
flower_parse_ip_tos_ttl(char * str,int key_type,int mask_type,struct nlmsghdr * n)515*de1e4e89SAndroid Build Coastguard Worker static int flower_parse_ip_tos_ttl(char *str, int key_type, int mask_type,
516*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *n)
517*de1e4e89SAndroid Build Coastguard Worker {
518*de1e4e89SAndroid Build Coastguard Worker char *slash;
519*de1e4e89SAndroid Build Coastguard Worker int ret, err = -1;
520*de1e4e89SAndroid Build Coastguard Worker __u8 tos_ttl;
521*de1e4e89SAndroid Build Coastguard Worker
522*de1e4e89SAndroid Build Coastguard Worker slash = strchr(str, '/');
523*de1e4e89SAndroid Build Coastguard Worker if (slash)
524*de1e4e89SAndroid Build Coastguard Worker *slash = '\0';
525*de1e4e89SAndroid Build Coastguard Worker
526*de1e4e89SAndroid Build Coastguard Worker ret = get_u8(&tos_ttl, str, 10);
527*de1e4e89SAndroid Build Coastguard Worker if (ret < 0)
528*de1e4e89SAndroid Build Coastguard Worker ret = get_u8(&tos_ttl, str, 16);
529*de1e4e89SAndroid Build Coastguard Worker if (ret < 0)
530*de1e4e89SAndroid Build Coastguard Worker goto err;
531*de1e4e89SAndroid Build Coastguard Worker
532*de1e4e89SAndroid Build Coastguard Worker addattr8(n, MAX_MSG, key_type, tos_ttl);
533*de1e4e89SAndroid Build Coastguard Worker
534*de1e4e89SAndroid Build Coastguard Worker if (slash) {
535*de1e4e89SAndroid Build Coastguard Worker ret = get_u8(&tos_ttl, slash + 1, 16);
536*de1e4e89SAndroid Build Coastguard Worker if (ret < 0)
537*de1e4e89SAndroid Build Coastguard Worker goto err;
538*de1e4e89SAndroid Build Coastguard Worker } else {
539*de1e4e89SAndroid Build Coastguard Worker tos_ttl = 0xff;
540*de1e4e89SAndroid Build Coastguard Worker }
541*de1e4e89SAndroid Build Coastguard Worker addattr8(n, MAX_MSG, mask_type, tos_ttl);
542*de1e4e89SAndroid Build Coastguard Worker
543*de1e4e89SAndroid Build Coastguard Worker err = 0;
544*de1e4e89SAndroid Build Coastguard Worker err:
545*de1e4e89SAndroid Build Coastguard Worker if (slash)
546*de1e4e89SAndroid Build Coastguard Worker *slash = '/';
547*de1e4e89SAndroid Build Coastguard Worker return err;
548*de1e4e89SAndroid Build Coastguard Worker }
549*de1e4e89SAndroid Build Coastguard Worker
flower_parse_key_id(const char * str,int type,struct nlmsghdr * n)550*de1e4e89SAndroid Build Coastguard Worker static int flower_parse_key_id(const char *str, int type, struct nlmsghdr *n)
551*de1e4e89SAndroid Build Coastguard Worker {
552*de1e4e89SAndroid Build Coastguard Worker int ret;
553*de1e4e89SAndroid Build Coastguard Worker __be32 key_id;
554*de1e4e89SAndroid Build Coastguard Worker
555*de1e4e89SAndroid Build Coastguard Worker ret = get_be32(&key_id, str, 10);
556*de1e4e89SAndroid Build Coastguard Worker if (!ret)
557*de1e4e89SAndroid Build Coastguard Worker addattr32(n, MAX_MSG, type, key_id);
558*de1e4e89SAndroid Build Coastguard Worker
559*de1e4e89SAndroid Build Coastguard Worker return ret;
560*de1e4e89SAndroid Build Coastguard Worker }
561*de1e4e89SAndroid Build Coastguard Worker
flower_parse_enc_port(char * str,int type,struct nlmsghdr * n)562*de1e4e89SAndroid Build Coastguard Worker static int flower_parse_enc_port(char *str, int type, struct nlmsghdr *n)
563*de1e4e89SAndroid Build Coastguard Worker {
564*de1e4e89SAndroid Build Coastguard Worker int ret;
565*de1e4e89SAndroid Build Coastguard Worker __be16 port;
566*de1e4e89SAndroid Build Coastguard Worker
567*de1e4e89SAndroid Build Coastguard Worker ret = get_be16(&port, str, 10);
568*de1e4e89SAndroid Build Coastguard Worker if (ret)
569*de1e4e89SAndroid Build Coastguard Worker return -1;
570*de1e4e89SAndroid Build Coastguard Worker
571*de1e4e89SAndroid Build Coastguard Worker addattr16(n, MAX_MSG, type, port);
572*de1e4e89SAndroid Build Coastguard Worker
573*de1e4e89SAndroid Build Coastguard Worker return 0;
574*de1e4e89SAndroid Build Coastguard Worker }
575*de1e4e89SAndroid Build Coastguard Worker
flower_parse_opt(struct filter_util * qu,char * handle,int argc,char ** argv,struct nlmsghdr * n)576*de1e4e89SAndroid Build Coastguard Worker static int flower_parse_opt(struct filter_util *qu, char *handle,
577*de1e4e89SAndroid Build Coastguard Worker int argc, char **argv, struct nlmsghdr *n)
578*de1e4e89SAndroid Build Coastguard Worker {
579*de1e4e89SAndroid Build Coastguard Worker int ret;
580*de1e4e89SAndroid Build Coastguard Worker struct tcmsg *t = NLMSG_DATA(n);
581*de1e4e89SAndroid Build Coastguard Worker struct rtattr *tail;
582*de1e4e89SAndroid Build Coastguard Worker __be16 eth_type = TC_H_MIN(t->tcm_info);
583*de1e4e89SAndroid Build Coastguard Worker __be16 vlan_ethtype = 0;
584*de1e4e89SAndroid Build Coastguard Worker __u8 ip_proto = 0xff;
585*de1e4e89SAndroid Build Coastguard Worker __u32 flags = 0;
586*de1e4e89SAndroid Build Coastguard Worker __u32 mtf = 0;
587*de1e4e89SAndroid Build Coastguard Worker __u32 mtf_mask = 0;
588*de1e4e89SAndroid Build Coastguard Worker
589*de1e4e89SAndroid Build Coastguard Worker if (handle) {
590*de1e4e89SAndroid Build Coastguard Worker ret = get_u32(&t->tcm_handle, handle, 0);
591*de1e4e89SAndroid Build Coastguard Worker if (ret) {
592*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"handle\"\n");
593*de1e4e89SAndroid Build Coastguard Worker return -1;
594*de1e4e89SAndroid Build Coastguard Worker }
595*de1e4e89SAndroid Build Coastguard Worker }
596*de1e4e89SAndroid Build Coastguard Worker
597*de1e4e89SAndroid Build Coastguard Worker tail = (struct rtattr *) (((void *) n) + NLMSG_ALIGN(n->nlmsg_len));
598*de1e4e89SAndroid Build Coastguard Worker addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
599*de1e4e89SAndroid Build Coastguard Worker
600*de1e4e89SAndroid Build Coastguard Worker if (argc == 0) {
601*de1e4e89SAndroid Build Coastguard Worker /*at minimal we will match all ethertype packets */
602*de1e4e89SAndroid Build Coastguard Worker goto parse_done;
603*de1e4e89SAndroid Build Coastguard Worker }
604*de1e4e89SAndroid Build Coastguard Worker
605*de1e4e89SAndroid Build Coastguard Worker while (argc > 0) {
606*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "classid") == 0 ||
607*de1e4e89SAndroid Build Coastguard Worker matches(*argv, "flowid") == 0) {
608*de1e4e89SAndroid Build Coastguard Worker unsigned int handle;
609*de1e4e89SAndroid Build Coastguard Worker
610*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
611*de1e4e89SAndroid Build Coastguard Worker ret = get_tc_classid(&handle, *argv);
612*de1e4e89SAndroid Build Coastguard Worker if (ret) {
613*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"classid\"\n");
614*de1e4e89SAndroid Build Coastguard Worker return -1;
615*de1e4e89SAndroid Build Coastguard Worker }
616*de1e4e89SAndroid Build Coastguard Worker addattr_l(n, MAX_MSG, TCA_FLOWER_CLASSID, &handle, 4);
617*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "ip_flags") == 0) {
618*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
619*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_matching_flags(*argv,
620*de1e4e89SAndroid Build Coastguard Worker FLOWER_IP_FLAGS,
621*de1e4e89SAndroid Build Coastguard Worker &mtf,
622*de1e4e89SAndroid Build Coastguard Worker &mtf_mask);
623*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
624*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"ip_flags\"\n");
625*de1e4e89SAndroid Build Coastguard Worker return -1;
626*de1e4e89SAndroid Build Coastguard Worker }
627*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "skip_hw") == 0) {
628*de1e4e89SAndroid Build Coastguard Worker flags |= TCA_CLS_FLAGS_SKIP_HW;
629*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "skip_sw") == 0) {
630*de1e4e89SAndroid Build Coastguard Worker flags |= TCA_CLS_FLAGS_SKIP_SW;
631*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "indev") == 0) {
632*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
633*de1e4e89SAndroid Build Coastguard Worker if (check_ifname(*argv))
634*de1e4e89SAndroid Build Coastguard Worker invarg("\"indev\" not a valid ifname", *argv);
635*de1e4e89SAndroid Build Coastguard Worker addattrstrz(n, MAX_MSG, TCA_FLOWER_INDEV, *argv);
636*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "vlan_id") == 0) {
637*de1e4e89SAndroid Build Coastguard Worker __u16 vid;
638*de1e4e89SAndroid Build Coastguard Worker
639*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
640*de1e4e89SAndroid Build Coastguard Worker if (eth_type != htons(ETH_P_8021Q)) {
641*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr,
642*de1e4e89SAndroid Build Coastguard Worker "Can't set \"vlan_id\" if ethertype isn't 802.1Q\n");
643*de1e4e89SAndroid Build Coastguard Worker return -1;
644*de1e4e89SAndroid Build Coastguard Worker }
645*de1e4e89SAndroid Build Coastguard Worker ret = get_u16(&vid, *argv, 10);
646*de1e4e89SAndroid Build Coastguard Worker if (ret < 0 || vid & ~0xfff) {
647*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"vlan_id\"\n");
648*de1e4e89SAndroid Build Coastguard Worker return -1;
649*de1e4e89SAndroid Build Coastguard Worker }
650*de1e4e89SAndroid Build Coastguard Worker addattr16(n, MAX_MSG, TCA_FLOWER_KEY_VLAN_ID, vid);
651*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "vlan_prio") == 0) {
652*de1e4e89SAndroid Build Coastguard Worker __u8 vlan_prio;
653*de1e4e89SAndroid Build Coastguard Worker
654*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
655*de1e4e89SAndroid Build Coastguard Worker if (eth_type != htons(ETH_P_8021Q)) {
656*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr,
657*de1e4e89SAndroid Build Coastguard Worker "Can't set \"vlan_prio\" if ethertype isn't 802.1Q\n");
658*de1e4e89SAndroid Build Coastguard Worker return -1;
659*de1e4e89SAndroid Build Coastguard Worker }
660*de1e4e89SAndroid Build Coastguard Worker ret = get_u8(&vlan_prio, *argv, 10);
661*de1e4e89SAndroid Build Coastguard Worker if (ret < 0 || vlan_prio & ~0x7) {
662*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"vlan_prio\"\n");
663*de1e4e89SAndroid Build Coastguard Worker return -1;
664*de1e4e89SAndroid Build Coastguard Worker }
665*de1e4e89SAndroid Build Coastguard Worker addattr8(n, MAX_MSG,
666*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_VLAN_PRIO, vlan_prio);
667*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "vlan_ethtype") == 0) {
668*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
669*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_vlan_eth_type(*argv, eth_type,
670*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_VLAN_ETH_TYPE,
671*de1e4e89SAndroid Build Coastguard Worker &vlan_ethtype, n);
672*de1e4e89SAndroid Build Coastguard Worker if (ret < 0)
673*de1e4e89SAndroid Build Coastguard Worker return -1;
674*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "dst_mac") == 0) {
675*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
676*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_eth_addr(*argv,
677*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ETH_DST,
678*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ETH_DST_MASK,
679*de1e4e89SAndroid Build Coastguard Worker n);
680*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
681*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"dst_mac\"\n");
682*de1e4e89SAndroid Build Coastguard Worker return -1;
683*de1e4e89SAndroid Build Coastguard Worker }
684*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "src_mac") == 0) {
685*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
686*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_eth_addr(*argv,
687*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ETH_SRC,
688*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ETH_SRC_MASK,
689*de1e4e89SAndroid Build Coastguard Worker n);
690*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
691*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"src_mac\"\n");
692*de1e4e89SAndroid Build Coastguard Worker return -1;
693*de1e4e89SAndroid Build Coastguard Worker }
694*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "ip_proto") == 0) {
695*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
696*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_ip_proto(*argv, vlan_ethtype ?
697*de1e4e89SAndroid Build Coastguard Worker vlan_ethtype : eth_type,
698*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_IP_PROTO,
699*de1e4e89SAndroid Build Coastguard Worker &ip_proto, n);
700*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
701*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"ip_proto\"\n");
702*de1e4e89SAndroid Build Coastguard Worker return -1;
703*de1e4e89SAndroid Build Coastguard Worker }
704*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "ip_tos") == 0) {
705*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
706*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_ip_tos_ttl(*argv,
707*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_IP_TOS,
708*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_IP_TOS_MASK,
709*de1e4e89SAndroid Build Coastguard Worker n);
710*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
711*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"ip_tos\"\n");
712*de1e4e89SAndroid Build Coastguard Worker return -1;
713*de1e4e89SAndroid Build Coastguard Worker }
714*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "ip_ttl") == 0) {
715*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
716*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_ip_tos_ttl(*argv,
717*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_IP_TTL,
718*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_IP_TTL_MASK,
719*de1e4e89SAndroid Build Coastguard Worker n);
720*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
721*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"ip_ttl\"\n");
722*de1e4e89SAndroid Build Coastguard Worker return -1;
723*de1e4e89SAndroid Build Coastguard Worker }
724*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "dst_ip") == 0) {
725*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
726*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_ip_addr(*argv, vlan_ethtype ?
727*de1e4e89SAndroid Build Coastguard Worker vlan_ethtype : eth_type,
728*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_IPV4_DST,
729*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_IPV4_DST_MASK,
730*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_IPV6_DST,
731*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_IPV6_DST_MASK,
732*de1e4e89SAndroid Build Coastguard Worker n);
733*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
734*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"dst_ip\"\n");
735*de1e4e89SAndroid Build Coastguard Worker return -1;
736*de1e4e89SAndroid Build Coastguard Worker }
737*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "src_ip") == 0) {
738*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
739*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_ip_addr(*argv, vlan_ethtype ?
740*de1e4e89SAndroid Build Coastguard Worker vlan_ethtype : eth_type,
741*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_IPV4_SRC,
742*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_IPV4_SRC_MASK,
743*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_IPV6_SRC,
744*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_IPV6_SRC_MASK,
745*de1e4e89SAndroid Build Coastguard Worker n);
746*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
747*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"src_ip\"\n");
748*de1e4e89SAndroid Build Coastguard Worker return -1;
749*de1e4e89SAndroid Build Coastguard Worker }
750*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "dst_port") == 0) {
751*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
752*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_port(*argv, ip_proto,
753*de1e4e89SAndroid Build Coastguard Worker FLOWER_ENDPOINT_DST, n);
754*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
755*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"dst_port\"\n");
756*de1e4e89SAndroid Build Coastguard Worker return -1;
757*de1e4e89SAndroid Build Coastguard Worker }
758*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "src_port") == 0) {
759*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
760*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_port(*argv, ip_proto,
761*de1e4e89SAndroid Build Coastguard Worker FLOWER_ENDPOINT_SRC, n);
762*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
763*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"src_port\"\n");
764*de1e4e89SAndroid Build Coastguard Worker return -1;
765*de1e4e89SAndroid Build Coastguard Worker }
766*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "tcp_flags") == 0) {
767*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
768*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_tcp_flags(*argv,
769*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_TCP_FLAGS,
770*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_TCP_FLAGS_MASK,
771*de1e4e89SAndroid Build Coastguard Worker n);
772*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
773*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"tcp_flags\"\n");
774*de1e4e89SAndroid Build Coastguard Worker return -1;
775*de1e4e89SAndroid Build Coastguard Worker }
776*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "type") == 0) {
777*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
778*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_icmp(*argv, eth_type, ip_proto,
779*de1e4e89SAndroid Build Coastguard Worker FLOWER_ICMP_FIELD_TYPE, n);
780*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
781*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"icmp type\"\n");
782*de1e4e89SAndroid Build Coastguard Worker return -1;
783*de1e4e89SAndroid Build Coastguard Worker }
784*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "code") == 0) {
785*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
786*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_icmp(*argv, eth_type, ip_proto,
787*de1e4e89SAndroid Build Coastguard Worker FLOWER_ICMP_FIELD_CODE, n);
788*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
789*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"icmp code\"\n");
790*de1e4e89SAndroid Build Coastguard Worker return -1;
791*de1e4e89SAndroid Build Coastguard Worker }
792*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "arp_tip") == 0) {
793*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
794*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_arp_ip_addr(*argv, vlan_ethtype ?
795*de1e4e89SAndroid Build Coastguard Worker vlan_ethtype : eth_type,
796*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ARP_TIP,
797*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ARP_TIP_MASK,
798*de1e4e89SAndroid Build Coastguard Worker n);
799*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
800*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"arp_tip\"\n");
801*de1e4e89SAndroid Build Coastguard Worker return -1;
802*de1e4e89SAndroid Build Coastguard Worker }
803*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "arp_sip") == 0) {
804*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
805*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_arp_ip_addr(*argv, vlan_ethtype ?
806*de1e4e89SAndroid Build Coastguard Worker vlan_ethtype : eth_type,
807*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ARP_SIP,
808*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ARP_SIP_MASK,
809*de1e4e89SAndroid Build Coastguard Worker n);
810*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
811*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"arp_sip\"\n");
812*de1e4e89SAndroid Build Coastguard Worker return -1;
813*de1e4e89SAndroid Build Coastguard Worker }
814*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "arp_op") == 0) {
815*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
816*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_arp_op(*argv, vlan_ethtype ?
817*de1e4e89SAndroid Build Coastguard Worker vlan_ethtype : eth_type,
818*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ARP_OP,
819*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ARP_OP_MASK,
820*de1e4e89SAndroid Build Coastguard Worker n);
821*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
822*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"arp_op\"\n");
823*de1e4e89SAndroid Build Coastguard Worker return -1;
824*de1e4e89SAndroid Build Coastguard Worker }
825*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "arp_tha") == 0) {
826*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
827*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_eth_addr(*argv,
828*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ARP_THA,
829*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ARP_THA_MASK,
830*de1e4e89SAndroid Build Coastguard Worker n);
831*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
832*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"arp_tha\"\n");
833*de1e4e89SAndroid Build Coastguard Worker return -1;
834*de1e4e89SAndroid Build Coastguard Worker }
835*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "arp_sha") == 0) {
836*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
837*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_eth_addr(*argv,
838*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ARP_SHA,
839*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ARP_SHA_MASK,
840*de1e4e89SAndroid Build Coastguard Worker n);
841*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
842*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"arp_sha\"\n");
843*de1e4e89SAndroid Build Coastguard Worker return -1;
844*de1e4e89SAndroid Build Coastguard Worker }
845*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "enc_dst_ip") == 0) {
846*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
847*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_ip_addr(*argv, 0,
848*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ENC_IPV4_DST,
849*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
850*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ENC_IPV6_DST,
851*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
852*de1e4e89SAndroid Build Coastguard Worker n);
853*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
854*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"enc_dst_ip\"\n");
855*de1e4e89SAndroid Build Coastguard Worker return -1;
856*de1e4e89SAndroid Build Coastguard Worker }
857*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "enc_src_ip") == 0) {
858*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
859*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_ip_addr(*argv, 0,
860*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ENC_IPV4_SRC,
861*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
862*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ENC_IPV6_SRC,
863*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
864*de1e4e89SAndroid Build Coastguard Worker n);
865*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
866*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"enc_src_ip\"\n");
867*de1e4e89SAndroid Build Coastguard Worker return -1;
868*de1e4e89SAndroid Build Coastguard Worker }
869*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "enc_key_id") == 0) {
870*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
871*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_key_id(*argv,
872*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ENC_KEY_ID, n);
873*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
874*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"enc_key_id\"\n");
875*de1e4e89SAndroid Build Coastguard Worker return -1;
876*de1e4e89SAndroid Build Coastguard Worker }
877*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "enc_dst_port") == 0) {
878*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
879*de1e4e89SAndroid Build Coastguard Worker ret = flower_parse_enc_port(*argv,
880*de1e4e89SAndroid Build Coastguard Worker TCA_FLOWER_KEY_ENC_UDP_DST_PORT, n);
881*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
882*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"enc_dst_port\"\n");
883*de1e4e89SAndroid Build Coastguard Worker return -1;
884*de1e4e89SAndroid Build Coastguard Worker }
885*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "action") == 0) {
886*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
887*de1e4e89SAndroid Build Coastguard Worker ret = parse_action(&argc, &argv, TCA_FLOWER_ACT, n);
888*de1e4e89SAndroid Build Coastguard Worker if (ret) {
889*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"action\"\n");
890*de1e4e89SAndroid Build Coastguard Worker return -1;
891*de1e4e89SAndroid Build Coastguard Worker }
892*de1e4e89SAndroid Build Coastguard Worker continue;
893*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "help") == 0) {
894*de1e4e89SAndroid Build Coastguard Worker explain();
895*de1e4e89SAndroid Build Coastguard Worker return -1;
896*de1e4e89SAndroid Build Coastguard Worker } else {
897*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "What is \"%s\"?\n", *argv);
898*de1e4e89SAndroid Build Coastguard Worker explain();
899*de1e4e89SAndroid Build Coastguard Worker return -1;
900*de1e4e89SAndroid Build Coastguard Worker }
901*de1e4e89SAndroid Build Coastguard Worker argc--; argv++;
902*de1e4e89SAndroid Build Coastguard Worker }
903*de1e4e89SAndroid Build Coastguard Worker
904*de1e4e89SAndroid Build Coastguard Worker parse_done:
905*de1e4e89SAndroid Build Coastguard Worker ret = addattr32(n, MAX_MSG, TCA_FLOWER_FLAGS, flags);
906*de1e4e89SAndroid Build Coastguard Worker if (ret)
907*de1e4e89SAndroid Build Coastguard Worker return ret;
908*de1e4e89SAndroid Build Coastguard Worker
909*de1e4e89SAndroid Build Coastguard Worker if (mtf_mask) {
910*de1e4e89SAndroid Build Coastguard Worker ret = addattr32(n, MAX_MSG, TCA_FLOWER_KEY_FLAGS, htonl(mtf));
911*de1e4e89SAndroid Build Coastguard Worker if (ret)
912*de1e4e89SAndroid Build Coastguard Worker return ret;
913*de1e4e89SAndroid Build Coastguard Worker
914*de1e4e89SAndroid Build Coastguard Worker ret = addattr32(n, MAX_MSG, TCA_FLOWER_KEY_FLAGS_MASK, htonl(mtf_mask));
915*de1e4e89SAndroid Build Coastguard Worker if (ret)
916*de1e4e89SAndroid Build Coastguard Worker return ret;
917*de1e4e89SAndroid Build Coastguard Worker }
918*de1e4e89SAndroid Build Coastguard Worker
919*de1e4e89SAndroid Build Coastguard Worker if (eth_type != htons(ETH_P_ALL)) {
920*de1e4e89SAndroid Build Coastguard Worker ret = addattr16(n, MAX_MSG, TCA_FLOWER_KEY_ETH_TYPE, eth_type);
921*de1e4e89SAndroid Build Coastguard Worker if (ret)
922*de1e4e89SAndroid Build Coastguard Worker return ret;
923*de1e4e89SAndroid Build Coastguard Worker }
924*de1e4e89SAndroid Build Coastguard Worker
925*de1e4e89SAndroid Build Coastguard Worker tail->rta_len = (((void *)n)+n->nlmsg_len) - (void *)tail;
926*de1e4e89SAndroid Build Coastguard Worker
927*de1e4e89SAndroid Build Coastguard Worker return 0;
928*de1e4e89SAndroid Build Coastguard Worker }
929*de1e4e89SAndroid Build Coastguard Worker
__mask_bits(char * addr,size_t len)930*de1e4e89SAndroid Build Coastguard Worker static int __mask_bits(char *addr, size_t len)
931*de1e4e89SAndroid Build Coastguard Worker {
932*de1e4e89SAndroid Build Coastguard Worker int bits = 0;
933*de1e4e89SAndroid Build Coastguard Worker bool hole = false;
934*de1e4e89SAndroid Build Coastguard Worker int i;
935*de1e4e89SAndroid Build Coastguard Worker int j;
936*de1e4e89SAndroid Build Coastguard Worker
937*de1e4e89SAndroid Build Coastguard Worker for (i = 0; i < len; i++, addr++) {
938*de1e4e89SAndroid Build Coastguard Worker for (j = 7; j >= 0; j--) {
939*de1e4e89SAndroid Build Coastguard Worker if (((*addr) >> j) & 0x1) {
940*de1e4e89SAndroid Build Coastguard Worker if (hole)
941*de1e4e89SAndroid Build Coastguard Worker return -1;
942*de1e4e89SAndroid Build Coastguard Worker bits++;
943*de1e4e89SAndroid Build Coastguard Worker } else if (bits) {
944*de1e4e89SAndroid Build Coastguard Worker hole = true;
945*de1e4e89SAndroid Build Coastguard Worker } else{
946*de1e4e89SAndroid Build Coastguard Worker return -1;
947*de1e4e89SAndroid Build Coastguard Worker }
948*de1e4e89SAndroid Build Coastguard Worker }
949*de1e4e89SAndroid Build Coastguard Worker }
950*de1e4e89SAndroid Build Coastguard Worker return bits;
951*de1e4e89SAndroid Build Coastguard Worker }
952*de1e4e89SAndroid Build Coastguard Worker
flower_print_eth_addr(FILE * f,char * name,struct rtattr * addr_attr,struct rtattr * mask_attr)953*de1e4e89SAndroid Build Coastguard Worker static void flower_print_eth_addr(FILE *f, char *name,
954*de1e4e89SAndroid Build Coastguard Worker struct rtattr *addr_attr,
955*de1e4e89SAndroid Build Coastguard Worker struct rtattr *mask_attr)
956*de1e4e89SAndroid Build Coastguard Worker {
957*de1e4e89SAndroid Build Coastguard Worker SPRINT_BUF(b1);
958*de1e4e89SAndroid Build Coastguard Worker int bits;
959*de1e4e89SAndroid Build Coastguard Worker
960*de1e4e89SAndroid Build Coastguard Worker if (!addr_attr || RTA_PAYLOAD(addr_attr) != ETH_ALEN)
961*de1e4e89SAndroid Build Coastguard Worker return;
962*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n %s %s", name, ll_addr_n2a(RTA_DATA(addr_attr), ETH_ALEN,
963*de1e4e89SAndroid Build Coastguard Worker 0, b1, sizeof(b1)));
964*de1e4e89SAndroid Build Coastguard Worker if (!mask_attr || RTA_PAYLOAD(mask_attr) != ETH_ALEN)
965*de1e4e89SAndroid Build Coastguard Worker return;
966*de1e4e89SAndroid Build Coastguard Worker bits = __mask_bits(RTA_DATA(mask_attr), ETH_ALEN);
967*de1e4e89SAndroid Build Coastguard Worker if (bits < 0)
968*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "/%s", ll_addr_n2a(RTA_DATA(mask_attr), ETH_ALEN,
969*de1e4e89SAndroid Build Coastguard Worker 0, b1, sizeof(b1)));
970*de1e4e89SAndroid Build Coastguard Worker else if (bits < ETH_ALEN * 8)
971*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "/%d", bits);
972*de1e4e89SAndroid Build Coastguard Worker }
973*de1e4e89SAndroid Build Coastguard Worker
flower_print_eth_type(FILE * f,__be16 * p_eth_type,struct rtattr * eth_type_attr)974*de1e4e89SAndroid Build Coastguard Worker static void flower_print_eth_type(FILE *f, __be16 *p_eth_type,
975*de1e4e89SAndroid Build Coastguard Worker struct rtattr *eth_type_attr)
976*de1e4e89SAndroid Build Coastguard Worker {
977*de1e4e89SAndroid Build Coastguard Worker __be16 eth_type;
978*de1e4e89SAndroid Build Coastguard Worker
979*de1e4e89SAndroid Build Coastguard Worker if (!eth_type_attr)
980*de1e4e89SAndroid Build Coastguard Worker return;
981*de1e4e89SAndroid Build Coastguard Worker
982*de1e4e89SAndroid Build Coastguard Worker eth_type = rta_getattr_u16(eth_type_attr);
983*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n eth_type ");
984*de1e4e89SAndroid Build Coastguard Worker if (eth_type == htons(ETH_P_IP))
985*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "ipv4");
986*de1e4e89SAndroid Build Coastguard Worker else if (eth_type == htons(ETH_P_IPV6))
987*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "ipv6");
988*de1e4e89SAndroid Build Coastguard Worker else if (eth_type == htons(ETH_P_ARP))
989*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "arp");
990*de1e4e89SAndroid Build Coastguard Worker else if (eth_type == htons(ETH_P_RARP))
991*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "rarp");
992*de1e4e89SAndroid Build Coastguard Worker else
993*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "%04x", ntohs(eth_type));
994*de1e4e89SAndroid Build Coastguard Worker *p_eth_type = eth_type;
995*de1e4e89SAndroid Build Coastguard Worker }
996*de1e4e89SAndroid Build Coastguard Worker
flower_print_ip_proto(FILE * f,__u8 * p_ip_proto,struct rtattr * ip_proto_attr)997*de1e4e89SAndroid Build Coastguard Worker static void flower_print_ip_proto(FILE *f, __u8 *p_ip_proto,
998*de1e4e89SAndroid Build Coastguard Worker struct rtattr *ip_proto_attr)
999*de1e4e89SAndroid Build Coastguard Worker {
1000*de1e4e89SAndroid Build Coastguard Worker __u8 ip_proto;
1001*de1e4e89SAndroid Build Coastguard Worker
1002*de1e4e89SAndroid Build Coastguard Worker if (!ip_proto_attr)
1003*de1e4e89SAndroid Build Coastguard Worker return;
1004*de1e4e89SAndroid Build Coastguard Worker
1005*de1e4e89SAndroid Build Coastguard Worker ip_proto = rta_getattr_u8(ip_proto_attr);
1006*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n ip_proto ");
1007*de1e4e89SAndroid Build Coastguard Worker if (ip_proto == IPPROTO_TCP)
1008*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "tcp");
1009*de1e4e89SAndroid Build Coastguard Worker else if (ip_proto == IPPROTO_UDP)
1010*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "udp");
1011*de1e4e89SAndroid Build Coastguard Worker else if (ip_proto == IPPROTO_SCTP)
1012*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "sctp");
1013*de1e4e89SAndroid Build Coastguard Worker else if (ip_proto == IPPROTO_ICMP)
1014*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "icmp");
1015*de1e4e89SAndroid Build Coastguard Worker else if (ip_proto == IPPROTO_ICMPV6)
1016*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "icmpv6");
1017*de1e4e89SAndroid Build Coastguard Worker else
1018*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "%02x", ip_proto);
1019*de1e4e89SAndroid Build Coastguard Worker *p_ip_proto = ip_proto;
1020*de1e4e89SAndroid Build Coastguard Worker }
1021*de1e4e89SAndroid Build Coastguard Worker
flower_print_ip_attr(FILE * f,char * name,struct rtattr * key_attr,struct rtattr * mask_attr)1022*de1e4e89SAndroid Build Coastguard Worker static void flower_print_ip_attr(FILE *f, char *name,
1023*de1e4e89SAndroid Build Coastguard Worker struct rtattr *key_attr,
1024*de1e4e89SAndroid Build Coastguard Worker struct rtattr *mask_attr)
1025*de1e4e89SAndroid Build Coastguard Worker {
1026*de1e4e89SAndroid Build Coastguard Worker if (!key_attr)
1027*de1e4e89SAndroid Build Coastguard Worker return;
1028*de1e4e89SAndroid Build Coastguard Worker
1029*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n %s %x", name, rta_getattr_u8(key_attr));
1030*de1e4e89SAndroid Build Coastguard Worker if (!mask_attr)
1031*de1e4e89SAndroid Build Coastguard Worker return;
1032*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "/%x", rta_getattr_u8(mask_attr));
1033*de1e4e89SAndroid Build Coastguard Worker }
1034*de1e4e89SAndroid Build Coastguard Worker
flower_print_matching_flags(FILE * f,char * name,enum flower_matching_flags type,struct rtattr * attr,struct rtattr * mask_attr)1035*de1e4e89SAndroid Build Coastguard Worker static void flower_print_matching_flags(FILE *f, char *name,
1036*de1e4e89SAndroid Build Coastguard Worker enum flower_matching_flags type,
1037*de1e4e89SAndroid Build Coastguard Worker struct rtattr *attr,
1038*de1e4e89SAndroid Build Coastguard Worker struct rtattr *mask_attr)
1039*de1e4e89SAndroid Build Coastguard Worker {
1040*de1e4e89SAndroid Build Coastguard Worker int i;
1041*de1e4e89SAndroid Build Coastguard Worker int count = 0;
1042*de1e4e89SAndroid Build Coastguard Worker __u32 mtf;
1043*de1e4e89SAndroid Build Coastguard Worker __u32 mtf_mask;
1044*de1e4e89SAndroid Build Coastguard Worker
1045*de1e4e89SAndroid Build Coastguard Worker if (!mask_attr || RTA_PAYLOAD(mask_attr) != 4)
1046*de1e4e89SAndroid Build Coastguard Worker return;
1047*de1e4e89SAndroid Build Coastguard Worker
1048*de1e4e89SAndroid Build Coastguard Worker mtf = ntohl(rta_getattr_u32(attr));
1049*de1e4e89SAndroid Build Coastguard Worker mtf_mask = ntohl(rta_getattr_u32(mask_attr));
1050*de1e4e89SAndroid Build Coastguard Worker
1051*de1e4e89SAndroid Build Coastguard Worker for (i = 0; i < ARRAY_SIZE(flags_str); i++) {
1052*de1e4e89SAndroid Build Coastguard Worker if (type != flags_str[i].type)
1053*de1e4e89SAndroid Build Coastguard Worker continue;
1054*de1e4e89SAndroid Build Coastguard Worker if (mtf_mask & flags_str[i].flag) {
1055*de1e4e89SAndroid Build Coastguard Worker if (++count == 1)
1056*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n %s ", name);
1057*de1e4e89SAndroid Build Coastguard Worker else
1058*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "/");
1059*de1e4e89SAndroid Build Coastguard Worker
1060*de1e4e89SAndroid Build Coastguard Worker if (mtf & flags_str[i].flag)
1061*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "%s", flags_str[i].string);
1062*de1e4e89SAndroid Build Coastguard Worker else
1063*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "no%s", flags_str[i].string);
1064*de1e4e89SAndroid Build Coastguard Worker }
1065*de1e4e89SAndroid Build Coastguard Worker }
1066*de1e4e89SAndroid Build Coastguard Worker }
1067*de1e4e89SAndroid Build Coastguard Worker
flower_print_ip_addr(FILE * f,char * name,__be16 eth_type,struct rtattr * addr4_attr,struct rtattr * mask4_attr,struct rtattr * addr6_attr,struct rtattr * mask6_attr)1068*de1e4e89SAndroid Build Coastguard Worker static void flower_print_ip_addr(FILE *f, char *name, __be16 eth_type,
1069*de1e4e89SAndroid Build Coastguard Worker struct rtattr *addr4_attr,
1070*de1e4e89SAndroid Build Coastguard Worker struct rtattr *mask4_attr,
1071*de1e4e89SAndroid Build Coastguard Worker struct rtattr *addr6_attr,
1072*de1e4e89SAndroid Build Coastguard Worker struct rtattr *mask6_attr)
1073*de1e4e89SAndroid Build Coastguard Worker {
1074*de1e4e89SAndroid Build Coastguard Worker struct rtattr *addr_attr;
1075*de1e4e89SAndroid Build Coastguard Worker struct rtattr *mask_attr;
1076*de1e4e89SAndroid Build Coastguard Worker int family;
1077*de1e4e89SAndroid Build Coastguard Worker size_t len;
1078*de1e4e89SAndroid Build Coastguard Worker int bits;
1079*de1e4e89SAndroid Build Coastguard Worker
1080*de1e4e89SAndroid Build Coastguard Worker if (eth_type == htons(ETH_P_IP)) {
1081*de1e4e89SAndroid Build Coastguard Worker family = AF_INET;
1082*de1e4e89SAndroid Build Coastguard Worker addr_attr = addr4_attr;
1083*de1e4e89SAndroid Build Coastguard Worker mask_attr = mask4_attr;
1084*de1e4e89SAndroid Build Coastguard Worker len = 4;
1085*de1e4e89SAndroid Build Coastguard Worker } else if (eth_type == htons(ETH_P_IPV6)) {
1086*de1e4e89SAndroid Build Coastguard Worker family = AF_INET6;
1087*de1e4e89SAndroid Build Coastguard Worker addr_attr = addr6_attr;
1088*de1e4e89SAndroid Build Coastguard Worker mask_attr = mask6_attr;
1089*de1e4e89SAndroid Build Coastguard Worker len = 16;
1090*de1e4e89SAndroid Build Coastguard Worker } else {
1091*de1e4e89SAndroid Build Coastguard Worker return;
1092*de1e4e89SAndroid Build Coastguard Worker }
1093*de1e4e89SAndroid Build Coastguard Worker if (!addr_attr || RTA_PAYLOAD(addr_attr) != len)
1094*de1e4e89SAndroid Build Coastguard Worker return;
1095*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n %s %s", name, rt_addr_n2a_rta(family, addr_attr));
1096*de1e4e89SAndroid Build Coastguard Worker if (!mask_attr || RTA_PAYLOAD(mask_attr) != len)
1097*de1e4e89SAndroid Build Coastguard Worker return;
1098*de1e4e89SAndroid Build Coastguard Worker bits = __mask_bits(RTA_DATA(mask_attr), len);
1099*de1e4e89SAndroid Build Coastguard Worker if (bits < 0)
1100*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "/%s", rt_addr_n2a_rta(family, mask_attr));
1101*de1e4e89SAndroid Build Coastguard Worker else if (bits < len * 8)
1102*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "/%d", bits);
1103*de1e4e89SAndroid Build Coastguard Worker }
flower_print_ip4_addr(FILE * f,char * name,struct rtattr * addr_attr,struct rtattr * mask_attr)1104*de1e4e89SAndroid Build Coastguard Worker static void flower_print_ip4_addr(FILE *f, char *name,
1105*de1e4e89SAndroid Build Coastguard Worker struct rtattr *addr_attr,
1106*de1e4e89SAndroid Build Coastguard Worker struct rtattr *mask_attr)
1107*de1e4e89SAndroid Build Coastguard Worker {
1108*de1e4e89SAndroid Build Coastguard Worker return flower_print_ip_addr(f, name, htons(ETH_P_IP),
1109*de1e4e89SAndroid Build Coastguard Worker addr_attr, mask_attr, 0, 0);
1110*de1e4e89SAndroid Build Coastguard Worker }
1111*de1e4e89SAndroid Build Coastguard Worker
flower_print_port(FILE * f,char * name,struct rtattr * attr)1112*de1e4e89SAndroid Build Coastguard Worker static void flower_print_port(FILE *f, char *name, struct rtattr *attr)
1113*de1e4e89SAndroid Build Coastguard Worker {
1114*de1e4e89SAndroid Build Coastguard Worker if (attr)
1115*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n %s %d", name, rta_getattr_be16(attr));
1116*de1e4e89SAndroid Build Coastguard Worker }
1117*de1e4e89SAndroid Build Coastguard Worker
flower_print_tcp_flags(FILE * f,char * name,struct rtattr * flags_attr,struct rtattr * mask_attr)1118*de1e4e89SAndroid Build Coastguard Worker static void flower_print_tcp_flags(FILE *f, char *name,
1119*de1e4e89SAndroid Build Coastguard Worker struct rtattr *flags_attr,
1120*de1e4e89SAndroid Build Coastguard Worker struct rtattr *mask_attr)
1121*de1e4e89SAndroid Build Coastguard Worker {
1122*de1e4e89SAndroid Build Coastguard Worker if (!flags_attr)
1123*de1e4e89SAndroid Build Coastguard Worker return;
1124*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n %s %x", name, rta_getattr_be16(flags_attr));
1125*de1e4e89SAndroid Build Coastguard Worker if (!mask_attr)
1126*de1e4e89SAndroid Build Coastguard Worker return;
1127*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "/%x", rta_getattr_be16(mask_attr));
1128*de1e4e89SAndroid Build Coastguard Worker }
1129*de1e4e89SAndroid Build Coastguard Worker
1130*de1e4e89SAndroid Build Coastguard Worker
flower_print_key_id(FILE * f,const char * name,struct rtattr * attr)1131*de1e4e89SAndroid Build Coastguard Worker static void flower_print_key_id(FILE *f, const char *name,
1132*de1e4e89SAndroid Build Coastguard Worker struct rtattr *attr)
1133*de1e4e89SAndroid Build Coastguard Worker {
1134*de1e4e89SAndroid Build Coastguard Worker if (attr)
1135*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n %s %d", name, rta_getattr_be32(attr));
1136*de1e4e89SAndroid Build Coastguard Worker }
1137*de1e4e89SAndroid Build Coastguard Worker
flower_print_masked_u8(FILE * f,const char * name,struct rtattr * attr,struct rtattr * mask_attr,const char * (* value_to_str)(__u8 value))1138*de1e4e89SAndroid Build Coastguard Worker static void flower_print_masked_u8(FILE *f, const char *name,
1139*de1e4e89SAndroid Build Coastguard Worker struct rtattr *attr,
1140*de1e4e89SAndroid Build Coastguard Worker struct rtattr *mask_attr,
1141*de1e4e89SAndroid Build Coastguard Worker const char *(*value_to_str)(__u8 value))
1142*de1e4e89SAndroid Build Coastguard Worker {
1143*de1e4e89SAndroid Build Coastguard Worker const char *value_str = NULL;
1144*de1e4e89SAndroid Build Coastguard Worker __u8 value, mask;
1145*de1e4e89SAndroid Build Coastguard Worker
1146*de1e4e89SAndroid Build Coastguard Worker if (!attr)
1147*de1e4e89SAndroid Build Coastguard Worker return;
1148*de1e4e89SAndroid Build Coastguard Worker
1149*de1e4e89SAndroid Build Coastguard Worker value = rta_getattr_u8(attr);
1150*de1e4e89SAndroid Build Coastguard Worker mask = mask_attr ? rta_getattr_u8(mask_attr) : UINT8_MAX;
1151*de1e4e89SAndroid Build Coastguard Worker if (mask == UINT8_MAX && value_to_str)
1152*de1e4e89SAndroid Build Coastguard Worker value_str = value_to_str(value);
1153*de1e4e89SAndroid Build Coastguard Worker
1154*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n %s ", name);
1155*de1e4e89SAndroid Build Coastguard Worker
1156*de1e4e89SAndroid Build Coastguard Worker if (value_str)
1157*de1e4e89SAndroid Build Coastguard Worker fputs(value_str, f);
1158*de1e4e89SAndroid Build Coastguard Worker else
1159*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "%d", value);
1160*de1e4e89SAndroid Build Coastguard Worker
1161*de1e4e89SAndroid Build Coastguard Worker if (mask != UINT8_MAX)
1162*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "/%d", mask);
1163*de1e4e89SAndroid Build Coastguard Worker }
1164*de1e4e89SAndroid Build Coastguard Worker
flower_print_arp_op(FILE * f,const char * name,struct rtattr * op_attr,struct rtattr * mask_attr)1165*de1e4e89SAndroid Build Coastguard Worker static void flower_print_arp_op(FILE *f, const char *name,
1166*de1e4e89SAndroid Build Coastguard Worker struct rtattr *op_attr,
1167*de1e4e89SAndroid Build Coastguard Worker struct rtattr *mask_attr)
1168*de1e4e89SAndroid Build Coastguard Worker {
1169*de1e4e89SAndroid Build Coastguard Worker flower_print_masked_u8(f, name, op_attr, mask_attr,
1170*de1e4e89SAndroid Build Coastguard Worker flower_print_arp_op_to_name);
1171*de1e4e89SAndroid Build Coastguard Worker }
1172*de1e4e89SAndroid Build Coastguard Worker
flower_print_opt(struct filter_util * qu,FILE * f,struct rtattr * opt,__u32 handle)1173*de1e4e89SAndroid Build Coastguard Worker static int flower_print_opt(struct filter_util *qu, FILE *f,
1174*de1e4e89SAndroid Build Coastguard Worker struct rtattr *opt, __u32 handle)
1175*de1e4e89SAndroid Build Coastguard Worker {
1176*de1e4e89SAndroid Build Coastguard Worker struct rtattr *tb[TCA_FLOWER_MAX + 1];
1177*de1e4e89SAndroid Build Coastguard Worker int nl_type, nl_mask_type;
1178*de1e4e89SAndroid Build Coastguard Worker __be16 eth_type = 0;
1179*de1e4e89SAndroid Build Coastguard Worker __u8 ip_proto = 0xff;
1180*de1e4e89SAndroid Build Coastguard Worker
1181*de1e4e89SAndroid Build Coastguard Worker if (!opt)
1182*de1e4e89SAndroid Build Coastguard Worker return 0;
1183*de1e4e89SAndroid Build Coastguard Worker
1184*de1e4e89SAndroid Build Coastguard Worker parse_rtattr_nested(tb, TCA_FLOWER_MAX, opt);
1185*de1e4e89SAndroid Build Coastguard Worker
1186*de1e4e89SAndroid Build Coastguard Worker if (handle)
1187*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "handle 0x%x ", handle);
1188*de1e4e89SAndroid Build Coastguard Worker
1189*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_FLOWER_CLASSID]) {
1190*de1e4e89SAndroid Build Coastguard Worker SPRINT_BUF(b1);
1191*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "classid %s ",
1192*de1e4e89SAndroid Build Coastguard Worker sprint_tc_classid(rta_getattr_u32(tb[TCA_FLOWER_CLASSID]),
1193*de1e4e89SAndroid Build Coastguard Worker b1));
1194*de1e4e89SAndroid Build Coastguard Worker }
1195*de1e4e89SAndroid Build Coastguard Worker
1196*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_FLOWER_INDEV]) {
1197*de1e4e89SAndroid Build Coastguard Worker struct rtattr *attr = tb[TCA_FLOWER_INDEV];
1198*de1e4e89SAndroid Build Coastguard Worker
1199*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n indev %s", rta_getattr_str(attr));
1200*de1e4e89SAndroid Build Coastguard Worker }
1201*de1e4e89SAndroid Build Coastguard Worker
1202*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_FLOWER_KEY_VLAN_ID]) {
1203*de1e4e89SAndroid Build Coastguard Worker struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_ID];
1204*de1e4e89SAndroid Build Coastguard Worker
1205*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n vlan_id %d", rta_getattr_u16(attr));
1206*de1e4e89SAndroid Build Coastguard Worker }
1207*de1e4e89SAndroid Build Coastguard Worker
1208*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) {
1209*de1e4e89SAndroid Build Coastguard Worker struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_PRIO];
1210*de1e4e89SAndroid Build Coastguard Worker
1211*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n vlan_prio %d", rta_getattr_u8(attr));
1212*de1e4e89SAndroid Build Coastguard Worker }
1213*de1e4e89SAndroid Build Coastguard Worker
1214*de1e4e89SAndroid Build Coastguard Worker flower_print_eth_addr(f, "dst_mac", tb[TCA_FLOWER_KEY_ETH_DST],
1215*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_ETH_DST_MASK]);
1216*de1e4e89SAndroid Build Coastguard Worker flower_print_eth_addr(f, "src_mac", tb[TCA_FLOWER_KEY_ETH_SRC],
1217*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_ETH_SRC_MASK]);
1218*de1e4e89SAndroid Build Coastguard Worker
1219*de1e4e89SAndroid Build Coastguard Worker flower_print_eth_type(f, ð_type, tb[TCA_FLOWER_KEY_ETH_TYPE]);
1220*de1e4e89SAndroid Build Coastguard Worker flower_print_ip_proto(f, &ip_proto, tb[TCA_FLOWER_KEY_IP_PROTO]);
1221*de1e4e89SAndroid Build Coastguard Worker
1222*de1e4e89SAndroid Build Coastguard Worker flower_print_ip_attr(f, "ip_tos", tb[TCA_FLOWER_KEY_IP_TOS],
1223*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_IP_TOS_MASK]);
1224*de1e4e89SAndroid Build Coastguard Worker flower_print_ip_attr(f, "ip_ttl", tb[TCA_FLOWER_KEY_IP_TTL],
1225*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_IP_TTL_MASK]);
1226*de1e4e89SAndroid Build Coastguard Worker
1227*de1e4e89SAndroid Build Coastguard Worker flower_print_ip_addr(f, "dst_ip", eth_type,
1228*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_IPV4_DST],
1229*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_IPV4_DST_MASK],
1230*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_IPV6_DST],
1231*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_IPV6_DST_MASK]);
1232*de1e4e89SAndroid Build Coastguard Worker
1233*de1e4e89SAndroid Build Coastguard Worker flower_print_ip_addr(f, "src_ip", eth_type,
1234*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_IPV4_SRC],
1235*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_IPV4_SRC_MASK],
1236*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_IPV6_SRC],
1237*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_IPV6_SRC_MASK]);
1238*de1e4e89SAndroid Build Coastguard Worker
1239*de1e4e89SAndroid Build Coastguard Worker nl_type = flower_port_attr_type(ip_proto, FLOWER_ENDPOINT_DST);
1240*de1e4e89SAndroid Build Coastguard Worker if (nl_type >= 0)
1241*de1e4e89SAndroid Build Coastguard Worker flower_print_port(f, "dst_port", tb[nl_type]);
1242*de1e4e89SAndroid Build Coastguard Worker nl_type = flower_port_attr_type(ip_proto, FLOWER_ENDPOINT_SRC);
1243*de1e4e89SAndroid Build Coastguard Worker if (nl_type >= 0)
1244*de1e4e89SAndroid Build Coastguard Worker flower_print_port(f, "src_port", tb[nl_type]);
1245*de1e4e89SAndroid Build Coastguard Worker
1246*de1e4e89SAndroid Build Coastguard Worker flower_print_tcp_flags(f, "tcp_flags", tb[TCA_FLOWER_KEY_TCP_FLAGS],
1247*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_TCP_FLAGS_MASK]);
1248*de1e4e89SAndroid Build Coastguard Worker
1249*de1e4e89SAndroid Build Coastguard Worker nl_type = flower_icmp_attr_type(eth_type, ip_proto,
1250*de1e4e89SAndroid Build Coastguard Worker FLOWER_ICMP_FIELD_TYPE);
1251*de1e4e89SAndroid Build Coastguard Worker nl_mask_type = flower_icmp_attr_mask_type(eth_type, ip_proto,
1252*de1e4e89SAndroid Build Coastguard Worker FLOWER_ICMP_FIELD_TYPE);
1253*de1e4e89SAndroid Build Coastguard Worker if (nl_type >= 0 && nl_mask_type >= 0)
1254*de1e4e89SAndroid Build Coastguard Worker flower_print_masked_u8(f, "icmp_type", tb[nl_type],
1255*de1e4e89SAndroid Build Coastguard Worker tb[nl_mask_type], NULL);
1256*de1e4e89SAndroid Build Coastguard Worker
1257*de1e4e89SAndroid Build Coastguard Worker nl_type = flower_icmp_attr_type(eth_type, ip_proto,
1258*de1e4e89SAndroid Build Coastguard Worker FLOWER_ICMP_FIELD_CODE);
1259*de1e4e89SAndroid Build Coastguard Worker nl_mask_type = flower_icmp_attr_mask_type(eth_type, ip_proto,
1260*de1e4e89SAndroid Build Coastguard Worker FLOWER_ICMP_FIELD_CODE);
1261*de1e4e89SAndroid Build Coastguard Worker if (nl_type >= 0 && nl_mask_type >= 0)
1262*de1e4e89SAndroid Build Coastguard Worker flower_print_masked_u8(f, "icmp_code", tb[nl_type],
1263*de1e4e89SAndroid Build Coastguard Worker tb[nl_mask_type], NULL);
1264*de1e4e89SAndroid Build Coastguard Worker
1265*de1e4e89SAndroid Build Coastguard Worker flower_print_ip4_addr(f, "arp_sip", tb[TCA_FLOWER_KEY_ARP_SIP],
1266*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_ARP_SIP_MASK]);
1267*de1e4e89SAndroid Build Coastguard Worker flower_print_ip4_addr(f, "arp_tip", tb[TCA_FLOWER_KEY_ARP_TIP],
1268*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_ARP_TIP_MASK]);
1269*de1e4e89SAndroid Build Coastguard Worker flower_print_arp_op(f, "arp_op", tb[TCA_FLOWER_KEY_ARP_OP],
1270*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_ARP_OP_MASK]);
1271*de1e4e89SAndroid Build Coastguard Worker flower_print_eth_addr(f, "arp_sha", tb[TCA_FLOWER_KEY_ARP_SHA],
1272*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_ARP_SHA_MASK]);
1273*de1e4e89SAndroid Build Coastguard Worker flower_print_eth_addr(f, "arp_tha", tb[TCA_FLOWER_KEY_ARP_THA],
1274*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_ARP_THA_MASK]);
1275*de1e4e89SAndroid Build Coastguard Worker
1276*de1e4e89SAndroid Build Coastguard Worker flower_print_ip_addr(f, "enc_dst_ip",
1277*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] ?
1278*de1e4e89SAndroid Build Coastguard Worker htons(ETH_P_IP) : htons(ETH_P_IPV6),
1279*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_ENC_IPV4_DST],
1280*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK],
1281*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_ENC_IPV6_DST],
1282*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK]);
1283*de1e4e89SAndroid Build Coastguard Worker
1284*de1e4e89SAndroid Build Coastguard Worker flower_print_ip_addr(f, "enc_src_ip",
1285*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] ?
1286*de1e4e89SAndroid Build Coastguard Worker htons(ETH_P_IP) : htons(ETH_P_IPV6),
1287*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_ENC_IPV4_SRC],
1288*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK],
1289*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_ENC_IPV6_SRC],
1290*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK]);
1291*de1e4e89SAndroid Build Coastguard Worker
1292*de1e4e89SAndroid Build Coastguard Worker flower_print_key_id(f, "enc_key_id",
1293*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_ENC_KEY_ID]);
1294*de1e4e89SAndroid Build Coastguard Worker
1295*de1e4e89SAndroid Build Coastguard Worker flower_print_port(f, "enc_dst_port",
1296*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]);
1297*de1e4e89SAndroid Build Coastguard Worker
1298*de1e4e89SAndroid Build Coastguard Worker flower_print_matching_flags(f, "ip_flags",
1299*de1e4e89SAndroid Build Coastguard Worker FLOWER_IP_FLAGS,
1300*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_FLAGS],
1301*de1e4e89SAndroid Build Coastguard Worker tb[TCA_FLOWER_KEY_FLAGS_MASK]);
1302*de1e4e89SAndroid Build Coastguard Worker
1303*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_FLOWER_FLAGS]) {
1304*de1e4e89SAndroid Build Coastguard Worker __u32 flags = rta_getattr_u32(tb[TCA_FLOWER_FLAGS]);
1305*de1e4e89SAndroid Build Coastguard Worker
1306*de1e4e89SAndroid Build Coastguard Worker if (flags & TCA_CLS_FLAGS_SKIP_HW)
1307*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n skip_hw");
1308*de1e4e89SAndroid Build Coastguard Worker if (flags & TCA_CLS_FLAGS_SKIP_SW)
1309*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n skip_sw");
1310*de1e4e89SAndroid Build Coastguard Worker
1311*de1e4e89SAndroid Build Coastguard Worker if (flags & TCA_CLS_FLAGS_IN_HW)
1312*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n in_hw");
1313*de1e4e89SAndroid Build Coastguard Worker else if (flags & TCA_CLS_FLAGS_NOT_IN_HW)
1314*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n not_in_hw");
1315*de1e4e89SAndroid Build Coastguard Worker }
1316*de1e4e89SAndroid Build Coastguard Worker
1317*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_FLOWER_ACT])
1318*de1e4e89SAndroid Build Coastguard Worker tc_print_action(f, tb[TCA_FLOWER_ACT], 0);
1319*de1e4e89SAndroid Build Coastguard Worker
1320*de1e4e89SAndroid Build Coastguard Worker return 0;
1321*de1e4e89SAndroid Build Coastguard Worker }
1322*de1e4e89SAndroid Build Coastguard Worker
1323*de1e4e89SAndroid Build Coastguard Worker struct filter_util flower_filter_util = {
1324*de1e4e89SAndroid Build Coastguard Worker .id = "flower",
1325*de1e4e89SAndroid Build Coastguard Worker .parse_fopt = flower_parse_opt,
1326*de1e4e89SAndroid Build Coastguard Worker .print_fopt = flower_print_opt,
1327*de1e4e89SAndroid Build Coastguard Worker };
1328