xref: /aosp_15_r20/external/iproute2/tc/em_meta.c (revision de1e4e894b0c224df933550f0afdecc354b238c4)
1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker  * em_meta.c		Metadata Ematch
3*de1e4e89SAndroid Build Coastguard Worker  *
4*de1e4e89SAndroid Build Coastguard Worker  *		This program is free software; you can distribute it and/or
5*de1e4e89SAndroid Build Coastguard Worker  *		modify it under the terms of the GNU General Public License
6*de1e4e89SAndroid Build Coastguard Worker  *		as published by the Free Software Foundation; either version
7*de1e4e89SAndroid Build Coastguard Worker  *		2 of the License, or (at your option) any later version.
8*de1e4e89SAndroid Build Coastguard Worker  *
9*de1e4e89SAndroid Build Coastguard Worker  * Authors:	Thomas Graf <[email protected]>
10*de1e4e89SAndroid Build Coastguard Worker  */
11*de1e4e89SAndroid Build Coastguard Worker 
12*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
13*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
14*de1e4e89SAndroid Build Coastguard Worker #include <unistd.h>
15*de1e4e89SAndroid Build Coastguard Worker #include <syslog.h>
16*de1e4e89SAndroid Build Coastguard Worker #include <fcntl.h>
17*de1e4e89SAndroid Build Coastguard Worker #include <sys/socket.h>
18*de1e4e89SAndroid Build Coastguard Worker #include <netinet/in.h>
19*de1e4e89SAndroid Build Coastguard Worker #include <arpa/inet.h>
20*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
21*de1e4e89SAndroid Build Coastguard Worker #include <errno.h>
22*de1e4e89SAndroid Build Coastguard Worker 
23*de1e4e89SAndroid Build Coastguard Worker #include "m_ematch.h"
24*de1e4e89SAndroid Build Coastguard Worker #include <linux/tc_ematch/tc_em_meta.h>
25*de1e4e89SAndroid Build Coastguard Worker 
26*de1e4e89SAndroid Build Coastguard Worker extern struct ematch_util meta_ematch_util;
27*de1e4e89SAndroid Build Coastguard Worker 
meta_print_usage(FILE * fd)28*de1e4e89SAndroid Build Coastguard Worker static void meta_print_usage(FILE *fd)
29*de1e4e89SAndroid Build Coastguard Worker {
30*de1e4e89SAndroid Build Coastguard Worker 	fprintf(fd,
31*de1e4e89SAndroid Build Coastguard Worker 	    "Usage: meta(OBJECT { eq | lt | gt } OBJECT)\n" \
32*de1e4e89SAndroid Build Coastguard Worker 	    "where: OBJECT  := { META_ID | VALUE }\n" \
33*de1e4e89SAndroid Build Coastguard Worker 	    "       META_ID := id [ shift SHIFT ] [ mask MASK ]\n" \
34*de1e4e89SAndroid Build Coastguard Worker 	    "\n" \
35*de1e4e89SAndroid Build Coastguard Worker 	    "Example: meta(nf_mark gt 24)\n" \
36*de1e4e89SAndroid Build Coastguard Worker 	    "         meta(indev shift 1 eq \"ppp\")\n" \
37*de1e4e89SAndroid Build Coastguard Worker 	    "         meta(tcindex mask 0xf0 eq 0xf0)\n" \
38*de1e4e89SAndroid Build Coastguard Worker 	    "\n" \
39*de1e4e89SAndroid Build Coastguard Worker 	    "For a list of meta identifiers, use meta(list).\n");
40*de1e4e89SAndroid Build Coastguard Worker }
41*de1e4e89SAndroid Build Coastguard Worker 
42*de1e4e89SAndroid Build Coastguard Worker struct meta_entry {
43*de1e4e89SAndroid Build Coastguard Worker 	int		id;
44*de1e4e89SAndroid Build Coastguard Worker 	char *kind;
45*de1e4e89SAndroid Build Coastguard Worker 	char *mask;
46*de1e4e89SAndroid Build Coastguard Worker 	char *desc;
47*de1e4e89SAndroid Build Coastguard Worker } meta_table[] = {
48*de1e4e89SAndroid Build Coastguard Worker #define TCF_META_ID_SECTION 0
49*de1e4e89SAndroid Build Coastguard Worker #define __A(id, name, mask, desc) { TCF_META_ID_##id, name, mask, desc }
50*de1e4e89SAndroid Build Coastguard Worker 	__A(SECTION,		"Generic", "", ""),
51*de1e4e89SAndroid Build Coastguard Worker 	__A(RANDOM,		"random",	"i",
52*de1e4e89SAndroid Build Coastguard Worker 				"Random value (32 bit)"),
53*de1e4e89SAndroid Build Coastguard Worker 	__A(LOADAVG_0,		"loadavg_1",	"i",
54*de1e4e89SAndroid Build Coastguard Worker 				"Load average in last minute"),
55*de1e4e89SAndroid Build Coastguard Worker 	__A(LOADAVG_1,		"loadavg_5",	"i",
56*de1e4e89SAndroid Build Coastguard Worker 				"Load average in last 5 minutes"),
57*de1e4e89SAndroid Build Coastguard Worker 	__A(LOADAVG_2,		"loadavg_15",	"i",
58*de1e4e89SAndroid Build Coastguard Worker 				"Load average in last 15 minutes"),
59*de1e4e89SAndroid Build Coastguard Worker 
60*de1e4e89SAndroid Build Coastguard Worker 	__A(SECTION,		"Interfaces", "", ""),
61*de1e4e89SAndroid Build Coastguard Worker 	__A(DEV,		"dev",		"iv",
62*de1e4e89SAndroid Build Coastguard Worker 				"Device the packet is on"),
63*de1e4e89SAndroid Build Coastguard Worker 	__A(SECTION,		"Packet attributes", "", ""),
64*de1e4e89SAndroid Build Coastguard Worker 	__A(PRIORITY,		"priority",	"i",
65*de1e4e89SAndroid Build Coastguard Worker 				"Priority of packet"),
66*de1e4e89SAndroid Build Coastguard Worker 	__A(PROTOCOL,		"protocol",	"i",
67*de1e4e89SAndroid Build Coastguard Worker 				"Link layer protocol"),
68*de1e4e89SAndroid Build Coastguard Worker 	__A(PKTTYPE,		"pkt_type",	"i",
69*de1e4e89SAndroid Build Coastguard Worker 				"Packet type (uni|multi|broad|...)cast"),
70*de1e4e89SAndroid Build Coastguard Worker 	__A(PKTLEN,		"pkt_len",	"i",
71*de1e4e89SAndroid Build Coastguard Worker 				"Length of packet"),
72*de1e4e89SAndroid Build Coastguard Worker 	__A(DATALEN,		"data_len",	"i",
73*de1e4e89SAndroid Build Coastguard Worker 				"Length of data in packet"),
74*de1e4e89SAndroid Build Coastguard Worker 	__A(MACLEN,		"mac_len",	"i",
75*de1e4e89SAndroid Build Coastguard Worker 				"Length of link layer header"),
76*de1e4e89SAndroid Build Coastguard Worker 
77*de1e4e89SAndroid Build Coastguard Worker 	__A(SECTION,		"Netfilter", "", ""),
78*de1e4e89SAndroid Build Coastguard Worker 	__A(NFMARK,		"nf_mark",	"i",
79*de1e4e89SAndroid Build Coastguard Worker 				"Netfilter mark"),
80*de1e4e89SAndroid Build Coastguard Worker 	__A(NFMARK,		"fwmark",	"i",
81*de1e4e89SAndroid Build Coastguard Worker 				"Alias for nf_mark"),
82*de1e4e89SAndroid Build Coastguard Worker 
83*de1e4e89SAndroid Build Coastguard Worker 	__A(SECTION,		"Traffic Control", "", ""),
84*de1e4e89SAndroid Build Coastguard Worker 	__A(TCINDEX,		"tc_index",	"i",	"TC Index"),
85*de1e4e89SAndroid Build Coastguard Worker 	__A(SECTION,		"Routing", "", ""),
86*de1e4e89SAndroid Build Coastguard Worker 	__A(RTCLASSID,		"rt_classid",	"i",
87*de1e4e89SAndroid Build Coastguard Worker 				"Routing ClassID (cls_route)"),
88*de1e4e89SAndroid Build Coastguard Worker 	__A(RTIIF,		"rt_iif",	"i",
89*de1e4e89SAndroid Build Coastguard Worker 				"Incoming interface index"),
90*de1e4e89SAndroid Build Coastguard Worker 	__A(VLAN_TAG,		"vlan",		"i",	"Vlan tag"),
91*de1e4e89SAndroid Build Coastguard Worker 
92*de1e4e89SAndroid Build Coastguard Worker 	__A(SECTION,		"Sockets", "", ""),
93*de1e4e89SAndroid Build Coastguard Worker 	__A(SK_FAMILY,		"sk_family",	"i",	"Address family"),
94*de1e4e89SAndroid Build Coastguard Worker 	__A(SK_STATE,		"sk_state",	"i",	"State"),
95*de1e4e89SAndroid Build Coastguard Worker 	__A(SK_REUSE,		"sk_reuse",	"i",	"Reuse Flag"),
96*de1e4e89SAndroid Build Coastguard Worker 	__A(SK_BOUND_IF,	"sk_bind_if",	"iv",	"Bound interface"),
97*de1e4e89SAndroid Build Coastguard Worker 	__A(SK_REFCNT,		"sk_refcnt",	"i",	"Reference counter"),
98*de1e4e89SAndroid Build Coastguard Worker 	__A(SK_SHUTDOWN,	"sk_shutdown",	"i",	"Shutdown mask"),
99*de1e4e89SAndroid Build Coastguard Worker 	__A(SK_PROTO,		"sk_proto",	"i",	"Protocol"),
100*de1e4e89SAndroid Build Coastguard Worker 	__A(SK_TYPE,		"sk_type",	"i",	"Type"),
101*de1e4e89SAndroid Build Coastguard Worker 	__A(SK_RCVBUF,		"sk_rcvbuf",	"i",	"Receive buffer size"),
102*de1e4e89SAndroid Build Coastguard Worker 	__A(SK_RMEM_ALLOC,	"sk_rmem",	"i",	"RMEM"),
103*de1e4e89SAndroid Build Coastguard Worker 	__A(SK_WMEM_ALLOC,	"sk_wmem",	"i",	"WMEM"),
104*de1e4e89SAndroid Build Coastguard Worker 	__A(SK_OMEM_ALLOC,	"sk_omem",	"i",	"OMEM"),
105*de1e4e89SAndroid Build Coastguard Worker 	__A(SK_WMEM_QUEUED,	"sk_wmem_queue", "i",	"WMEM queue"),
106*de1e4e89SAndroid Build Coastguard Worker 	__A(SK_SND_QLEN,	"sk_snd_queue",	"i",	"Send queue length"),
107*de1e4e89SAndroid Build Coastguard Worker 	__A(SK_RCV_QLEN,	"sk_rcv_queue",	"i",	"Receive queue length"),
108*de1e4e89SAndroid Build Coastguard Worker 	__A(SK_ERR_QLEN,	"sk_err_queue",	"i",	"Error queue length"),
109*de1e4e89SAndroid Build Coastguard Worker 	__A(SK_FORWARD_ALLOCS,	"sk_fwd_alloc",	"i",	"Forward allocations"),
110*de1e4e89SAndroid Build Coastguard Worker 	__A(SK_SNDBUF,		"sk_sndbuf",	"i",	"Send buffer size"),
111*de1e4e89SAndroid Build Coastguard Worker #undef __A
112*de1e4e89SAndroid Build Coastguard Worker };
113*de1e4e89SAndroid Build Coastguard Worker 
map_type(char k)114*de1e4e89SAndroid Build Coastguard Worker static inline int map_type(char k)
115*de1e4e89SAndroid Build Coastguard Worker {
116*de1e4e89SAndroid Build Coastguard Worker 	switch (k) {
117*de1e4e89SAndroid Build Coastguard Worker 		case 'i': return TCF_META_TYPE_INT;
118*de1e4e89SAndroid Build Coastguard Worker 		case 'v': return TCF_META_TYPE_VAR;
119*de1e4e89SAndroid Build Coastguard Worker 	}
120*de1e4e89SAndroid Build Coastguard Worker 
121*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "BUG: Unknown map character '%c'\n", k);
122*de1e4e89SAndroid Build Coastguard Worker 	return INT_MAX;
123*de1e4e89SAndroid Build Coastguard Worker }
124*de1e4e89SAndroid Build Coastguard Worker 
lookup_meta_entry(struct bstr * kind)125*de1e4e89SAndroid Build Coastguard Worker static struct meta_entry *lookup_meta_entry(struct bstr *kind)
126*de1e4e89SAndroid Build Coastguard Worker {
127*de1e4e89SAndroid Build Coastguard Worker 	int i;
128*de1e4e89SAndroid Build Coastguard Worker 
129*de1e4e89SAndroid Build Coastguard Worker 	for (i = 0; i < ARRAY_SIZE(meta_table); i++)
130*de1e4e89SAndroid Build Coastguard Worker 		if (!bstrcmp(kind, meta_table[i].kind) &&
131*de1e4e89SAndroid Build Coastguard Worker 		    meta_table[i].id != 0)
132*de1e4e89SAndroid Build Coastguard Worker 			return &meta_table[i];
133*de1e4e89SAndroid Build Coastguard Worker 
134*de1e4e89SAndroid Build Coastguard Worker 	return NULL;
135*de1e4e89SAndroid Build Coastguard Worker }
136*de1e4e89SAndroid Build Coastguard Worker 
lookup_meta_entry_byid(int id)137*de1e4e89SAndroid Build Coastguard Worker static struct meta_entry *lookup_meta_entry_byid(int id)
138*de1e4e89SAndroid Build Coastguard Worker {
139*de1e4e89SAndroid Build Coastguard Worker 	int i;
140*de1e4e89SAndroid Build Coastguard Worker 
141*de1e4e89SAndroid Build Coastguard Worker 	for (i = 0; i < ARRAY_SIZE(meta_table); i++)
142*de1e4e89SAndroid Build Coastguard Worker 		if (meta_table[i].id == id)
143*de1e4e89SAndroid Build Coastguard Worker 			return &meta_table[i];
144*de1e4e89SAndroid Build Coastguard Worker 
145*de1e4e89SAndroid Build Coastguard Worker 	return NULL;
146*de1e4e89SAndroid Build Coastguard Worker }
147*de1e4e89SAndroid Build Coastguard Worker 
dump_value(struct nlmsghdr * n,int tlv,unsigned long val,struct tcf_meta_val * hdr)148*de1e4e89SAndroid Build Coastguard Worker static inline void dump_value(struct nlmsghdr *n, int tlv, unsigned long val,
149*de1e4e89SAndroid Build Coastguard Worker 			      struct tcf_meta_val *hdr)
150*de1e4e89SAndroid Build Coastguard Worker {
151*de1e4e89SAndroid Build Coastguard Worker 	__u32 t;
152*de1e4e89SAndroid Build Coastguard Worker 
153*de1e4e89SAndroid Build Coastguard Worker 	switch (TCF_META_TYPE(hdr->kind)) {
154*de1e4e89SAndroid Build Coastguard Worker 		case TCF_META_TYPE_INT:
155*de1e4e89SAndroid Build Coastguard Worker 			t = val;
156*de1e4e89SAndroid Build Coastguard Worker 			addattr_l(n, MAX_MSG, tlv, &t, sizeof(t));
157*de1e4e89SAndroid Build Coastguard Worker 			break;
158*de1e4e89SAndroid Build Coastguard Worker 
159*de1e4e89SAndroid Build Coastguard Worker 		case TCF_META_TYPE_VAR:
160*de1e4e89SAndroid Build Coastguard Worker 			if (TCF_META_ID(hdr->kind) == TCF_META_ID_VALUE) {
161*de1e4e89SAndroid Build Coastguard Worker 				struct bstr *a = (struct bstr *) val;
162*de1e4e89SAndroid Build Coastguard Worker 
163*de1e4e89SAndroid Build Coastguard Worker 				addattr_l(n, MAX_MSG, tlv, a->data, a->len);
164*de1e4e89SAndroid Build Coastguard Worker 			}
165*de1e4e89SAndroid Build Coastguard Worker 			break;
166*de1e4e89SAndroid Build Coastguard Worker 	}
167*de1e4e89SAndroid Build Coastguard Worker }
168*de1e4e89SAndroid Build Coastguard Worker 
is_compatible(struct tcf_meta_val * what,struct tcf_meta_val * needed)169*de1e4e89SAndroid Build Coastguard Worker static inline int is_compatible(struct tcf_meta_val *what,
170*de1e4e89SAndroid Build Coastguard Worker 				struct tcf_meta_val *needed)
171*de1e4e89SAndroid Build Coastguard Worker {
172*de1e4e89SAndroid Build Coastguard Worker 	char *p;
173*de1e4e89SAndroid Build Coastguard Worker 	struct meta_entry *entry;
174*de1e4e89SAndroid Build Coastguard Worker 
175*de1e4e89SAndroid Build Coastguard Worker 	entry = lookup_meta_entry_byid(TCF_META_ID(what->kind));
176*de1e4e89SAndroid Build Coastguard Worker 
177*de1e4e89SAndroid Build Coastguard Worker 	if (entry == NULL)
178*de1e4e89SAndroid Build Coastguard Worker 		return 0;
179*de1e4e89SAndroid Build Coastguard Worker 
180*de1e4e89SAndroid Build Coastguard Worker 	for (p = entry->mask; p; p++)
181*de1e4e89SAndroid Build Coastguard Worker 		if (map_type(*p) == TCF_META_TYPE(needed->kind))
182*de1e4e89SAndroid Build Coastguard Worker 			return 1;
183*de1e4e89SAndroid Build Coastguard Worker 
184*de1e4e89SAndroid Build Coastguard Worker 	return 0;
185*de1e4e89SAndroid Build Coastguard Worker }
186*de1e4e89SAndroid Build Coastguard Worker 
list_meta_ids(FILE * fd)187*de1e4e89SAndroid Build Coastguard Worker static void list_meta_ids(FILE *fd)
188*de1e4e89SAndroid Build Coastguard Worker {
189*de1e4e89SAndroid Build Coastguard Worker 	int i;
190*de1e4e89SAndroid Build Coastguard Worker 
191*de1e4e89SAndroid Build Coastguard Worker 	fprintf(fd,
192*de1e4e89SAndroid Build Coastguard Worker 	    "--------------------------------------------------------\n" \
193*de1e4e89SAndroid Build Coastguard Worker 	    "  ID               Type       Description\n" \
194*de1e4e89SAndroid Build Coastguard Worker 	    "--------------------------------------------------------");
195*de1e4e89SAndroid Build Coastguard Worker 
196*de1e4e89SAndroid Build Coastguard Worker 	for (i = 0; i < ARRAY_SIZE(meta_table); i++) {
197*de1e4e89SAndroid Build Coastguard Worker 		if (meta_table[i].id == TCF_META_ID_SECTION) {
198*de1e4e89SAndroid Build Coastguard Worker 			fprintf(fd, "\n%s:\n", meta_table[i].kind);
199*de1e4e89SAndroid Build Coastguard Worker 		} else {
200*de1e4e89SAndroid Build Coastguard Worker 			char *p = meta_table[i].mask;
201*de1e4e89SAndroid Build Coastguard Worker 			char buf[64] = {0};
202*de1e4e89SAndroid Build Coastguard Worker 
203*de1e4e89SAndroid Build Coastguard Worker 			fprintf(fd, "  %-16s ", meta_table[i].kind);
204*de1e4e89SAndroid Build Coastguard Worker 
205*de1e4e89SAndroid Build Coastguard Worker 			while (*p) {
206*de1e4e89SAndroid Build Coastguard Worker 				int type = map_type(*p);
207*de1e4e89SAndroid Build Coastguard Worker 
208*de1e4e89SAndroid Build Coastguard Worker 				switch (type) {
209*de1e4e89SAndroid Build Coastguard Worker 					case TCF_META_TYPE_INT:
210*de1e4e89SAndroid Build Coastguard Worker 						strcat(buf, "INT");
211*de1e4e89SAndroid Build Coastguard Worker 						break;
212*de1e4e89SAndroid Build Coastguard Worker 
213*de1e4e89SAndroid Build Coastguard Worker 					case TCF_META_TYPE_VAR:
214*de1e4e89SAndroid Build Coastguard Worker 						strcat(buf, "VAR");
215*de1e4e89SAndroid Build Coastguard Worker 						break;
216*de1e4e89SAndroid Build Coastguard Worker 				}
217*de1e4e89SAndroid Build Coastguard Worker 
218*de1e4e89SAndroid Build Coastguard Worker 				if (*(++p))
219*de1e4e89SAndroid Build Coastguard Worker 					strcat(buf, ",");
220*de1e4e89SAndroid Build Coastguard Worker 			}
221*de1e4e89SAndroid Build Coastguard Worker 
222*de1e4e89SAndroid Build Coastguard Worker 			fprintf(fd, "%-10s %s\n", buf, meta_table[i].desc);
223*de1e4e89SAndroid Build Coastguard Worker 		}
224*de1e4e89SAndroid Build Coastguard Worker 	}
225*de1e4e89SAndroid Build Coastguard Worker 
226*de1e4e89SAndroid Build Coastguard Worker 	fprintf(fd,
227*de1e4e89SAndroid Build Coastguard Worker 	    "--------------------------------------------------------\n");
228*de1e4e89SAndroid Build Coastguard Worker }
229*de1e4e89SAndroid Build Coastguard Worker 
230*de1e4e89SAndroid Build Coastguard Worker #undef TCF_META_ID_SECTION
231*de1e4e89SAndroid Build Coastguard Worker 
232*de1e4e89SAndroid Build Coastguard Worker #define PARSE_FAILURE ((void *) (-1))
233*de1e4e89SAndroid Build Coastguard Worker 
234*de1e4e89SAndroid Build Coastguard Worker #define PARSE_ERR(CARG, FMT, ARGS...) \
235*de1e4e89SAndroid Build Coastguard Worker 	em_parse_error(EINVAL, args, CARG, &meta_ematch_util, FMT, ##ARGS)
236*de1e4e89SAndroid Build Coastguard Worker 
can_adopt(struct tcf_meta_val * val)237*de1e4e89SAndroid Build Coastguard Worker static inline int can_adopt(struct tcf_meta_val *val)
238*de1e4e89SAndroid Build Coastguard Worker {
239*de1e4e89SAndroid Build Coastguard Worker 	return !!TCF_META_ID(val->kind);
240*de1e4e89SAndroid Build Coastguard Worker }
241*de1e4e89SAndroid Build Coastguard Worker 
overwrite_type(struct tcf_meta_val * src,struct tcf_meta_val * dst)242*de1e4e89SAndroid Build Coastguard Worker static inline int overwrite_type(struct tcf_meta_val *src,
243*de1e4e89SAndroid Build Coastguard Worker 				 struct tcf_meta_val *dst)
244*de1e4e89SAndroid Build Coastguard Worker {
245*de1e4e89SAndroid Build Coastguard Worker 	return (TCF_META_TYPE(dst->kind) << 12) | TCF_META_ID(src->kind);
246*de1e4e89SAndroid Build Coastguard Worker }
247*de1e4e89SAndroid Build Coastguard Worker 
248*de1e4e89SAndroid Build Coastguard Worker 
249*de1e4e89SAndroid Build Coastguard Worker static inline struct bstr *
parse_object(struct bstr * args,struct bstr * arg,struct tcf_meta_val * obj,unsigned long * dst,struct tcf_meta_val * left)250*de1e4e89SAndroid Build Coastguard Worker parse_object(struct bstr *args, struct bstr *arg, struct tcf_meta_val *obj,
251*de1e4e89SAndroid Build Coastguard Worker 	     unsigned long *dst, struct tcf_meta_val *left)
252*de1e4e89SAndroid Build Coastguard Worker {
253*de1e4e89SAndroid Build Coastguard Worker 	struct meta_entry *entry;
254*de1e4e89SAndroid Build Coastguard Worker 	unsigned long num;
255*de1e4e89SAndroid Build Coastguard Worker 	struct bstr *a;
256*de1e4e89SAndroid Build Coastguard Worker 
257*de1e4e89SAndroid Build Coastguard Worker 	if (arg->quoted) {
258*de1e4e89SAndroid Build Coastguard Worker 		obj->kind = TCF_META_TYPE_VAR << 12;
259*de1e4e89SAndroid Build Coastguard Worker 		obj->kind |= TCF_META_ID_VALUE;
260*de1e4e89SAndroid Build Coastguard Worker 		*dst = (unsigned long) arg;
261*de1e4e89SAndroid Build Coastguard Worker 		return bstr_next(arg);
262*de1e4e89SAndroid Build Coastguard Worker 	}
263*de1e4e89SAndroid Build Coastguard Worker 
264*de1e4e89SAndroid Build Coastguard Worker 	num = bstrtoul(arg);
265*de1e4e89SAndroid Build Coastguard Worker 	if (num != ULONG_MAX) {
266*de1e4e89SAndroid Build Coastguard Worker 		obj->kind = TCF_META_TYPE_INT << 12;
267*de1e4e89SAndroid Build Coastguard Worker 		obj->kind |= TCF_META_ID_VALUE;
268*de1e4e89SAndroid Build Coastguard Worker 		*dst = (unsigned long) num;
269*de1e4e89SAndroid Build Coastguard Worker 		return bstr_next(arg);
270*de1e4e89SAndroid Build Coastguard Worker 	}
271*de1e4e89SAndroid Build Coastguard Worker 
272*de1e4e89SAndroid Build Coastguard Worker 	entry = lookup_meta_entry(arg);
273*de1e4e89SAndroid Build Coastguard Worker 
274*de1e4e89SAndroid Build Coastguard Worker 	if (entry == NULL) {
275*de1e4e89SAndroid Build Coastguard Worker 		PARSE_ERR(arg, "meta: unknown meta id\n");
276*de1e4e89SAndroid Build Coastguard Worker 		return PARSE_FAILURE;
277*de1e4e89SAndroid Build Coastguard Worker 	}
278*de1e4e89SAndroid Build Coastguard Worker 
279*de1e4e89SAndroid Build Coastguard Worker 	obj->kind = entry->id | (map_type(entry->mask[0]) << 12);
280*de1e4e89SAndroid Build Coastguard Worker 
281*de1e4e89SAndroid Build Coastguard Worker 	if (left) {
282*de1e4e89SAndroid Build Coastguard Worker 		struct tcf_meta_val *right = obj;
283*de1e4e89SAndroid Build Coastguard Worker 
284*de1e4e89SAndroid Build Coastguard Worker 		if (TCF_META_TYPE(right->kind) == TCF_META_TYPE(left->kind))
285*de1e4e89SAndroid Build Coastguard Worker 			goto compatible;
286*de1e4e89SAndroid Build Coastguard Worker 
287*de1e4e89SAndroid Build Coastguard Worker 		if (can_adopt(left) && !can_adopt(right)) {
288*de1e4e89SAndroid Build Coastguard Worker 			if (is_compatible(left, right))
289*de1e4e89SAndroid Build Coastguard Worker 				left->kind = overwrite_type(left, right);
290*de1e4e89SAndroid Build Coastguard Worker 			else
291*de1e4e89SAndroid Build Coastguard Worker 				goto not_compatible;
292*de1e4e89SAndroid Build Coastguard Worker 		} else if (can_adopt(right) && !can_adopt(left)) {
293*de1e4e89SAndroid Build Coastguard Worker 			if (is_compatible(right, left))
294*de1e4e89SAndroid Build Coastguard Worker 				right->kind = overwrite_type(right, left);
295*de1e4e89SAndroid Build Coastguard Worker 			else
296*de1e4e89SAndroid Build Coastguard Worker 				goto not_compatible;
297*de1e4e89SAndroid Build Coastguard Worker 		} else if (can_adopt(left) && can_adopt(right)) {
298*de1e4e89SAndroid Build Coastguard Worker 			if (is_compatible(left, right))
299*de1e4e89SAndroid Build Coastguard Worker 				left->kind = overwrite_type(left, right);
300*de1e4e89SAndroid Build Coastguard Worker 			else if (is_compatible(right, left))
301*de1e4e89SAndroid Build Coastguard Worker 				right->kind = overwrite_type(right, left);
302*de1e4e89SAndroid Build Coastguard Worker 			else
303*de1e4e89SAndroid Build Coastguard Worker 				goto not_compatible;
304*de1e4e89SAndroid Build Coastguard Worker 		} else
305*de1e4e89SAndroid Build Coastguard Worker 			goto not_compatible;
306*de1e4e89SAndroid Build Coastguard Worker 	}
307*de1e4e89SAndroid Build Coastguard Worker 
308*de1e4e89SAndroid Build Coastguard Worker compatible:
309*de1e4e89SAndroid Build Coastguard Worker 
310*de1e4e89SAndroid Build Coastguard Worker 	a = bstr_next(arg);
311*de1e4e89SAndroid Build Coastguard Worker 
312*de1e4e89SAndroid Build Coastguard Worker 	while (a) {
313*de1e4e89SAndroid Build Coastguard Worker 		if (!bstrcmp(a, "shift")) {
314*de1e4e89SAndroid Build Coastguard Worker 			unsigned long shift;
315*de1e4e89SAndroid Build Coastguard Worker 
316*de1e4e89SAndroid Build Coastguard Worker 			if (a->next == NULL) {
317*de1e4e89SAndroid Build Coastguard Worker 				PARSE_ERR(a, "meta: missing argument");
318*de1e4e89SAndroid Build Coastguard Worker 				return PARSE_FAILURE;
319*de1e4e89SAndroid Build Coastguard Worker 			}
320*de1e4e89SAndroid Build Coastguard Worker 			a = bstr_next(a);
321*de1e4e89SAndroid Build Coastguard Worker 
322*de1e4e89SAndroid Build Coastguard Worker 			shift = bstrtoul(a);
323*de1e4e89SAndroid Build Coastguard Worker 			if (shift == ULONG_MAX) {
324*de1e4e89SAndroid Build Coastguard Worker 				PARSE_ERR(a, "meta: invalid shift, must " \
325*de1e4e89SAndroid Build Coastguard Worker 				    "be numeric");
326*de1e4e89SAndroid Build Coastguard Worker 				return PARSE_FAILURE;
327*de1e4e89SAndroid Build Coastguard Worker 			}
328*de1e4e89SAndroid Build Coastguard Worker 
329*de1e4e89SAndroid Build Coastguard Worker 			obj->shift = (__u8) shift;
330*de1e4e89SAndroid Build Coastguard Worker 			a = bstr_next(a);
331*de1e4e89SAndroid Build Coastguard Worker 		} else if (!bstrcmp(a, "mask")) {
332*de1e4e89SAndroid Build Coastguard Worker 			unsigned long mask;
333*de1e4e89SAndroid Build Coastguard Worker 
334*de1e4e89SAndroid Build Coastguard Worker 			if (a->next == NULL) {
335*de1e4e89SAndroid Build Coastguard Worker 				PARSE_ERR(a, "meta: missing argument");
336*de1e4e89SAndroid Build Coastguard Worker 				return PARSE_FAILURE;
337*de1e4e89SAndroid Build Coastguard Worker 			}
338*de1e4e89SAndroid Build Coastguard Worker 			a = bstr_next(a);
339*de1e4e89SAndroid Build Coastguard Worker 
340*de1e4e89SAndroid Build Coastguard Worker 			mask = bstrtoul(a);
341*de1e4e89SAndroid Build Coastguard Worker 			if (mask == ULONG_MAX) {
342*de1e4e89SAndroid Build Coastguard Worker 				PARSE_ERR(a, "meta: invalid mask, must be " \
343*de1e4e89SAndroid Build Coastguard Worker 				    "numeric");
344*de1e4e89SAndroid Build Coastguard Worker 				return PARSE_FAILURE;
345*de1e4e89SAndroid Build Coastguard Worker 			}
346*de1e4e89SAndroid Build Coastguard Worker 			*dst = (unsigned long) mask;
347*de1e4e89SAndroid Build Coastguard Worker 			a = bstr_next(a);
348*de1e4e89SAndroid Build Coastguard Worker 		} else
349*de1e4e89SAndroid Build Coastguard Worker 			break;
350*de1e4e89SAndroid Build Coastguard Worker 	}
351*de1e4e89SAndroid Build Coastguard Worker 
352*de1e4e89SAndroid Build Coastguard Worker 	return a;
353*de1e4e89SAndroid Build Coastguard Worker 
354*de1e4e89SAndroid Build Coastguard Worker not_compatible:
355*de1e4e89SAndroid Build Coastguard Worker 	PARSE_ERR(arg, "lvalue and rvalue are not compatible.");
356*de1e4e89SAndroid Build Coastguard Worker 	return PARSE_FAILURE;
357*de1e4e89SAndroid Build Coastguard Worker }
358*de1e4e89SAndroid Build Coastguard Worker 
meta_parse_eopt(struct nlmsghdr * n,struct tcf_ematch_hdr * hdr,struct bstr * args)359*de1e4e89SAndroid Build Coastguard Worker static int meta_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
360*de1e4e89SAndroid Build Coastguard Worker 			   struct bstr *args)
361*de1e4e89SAndroid Build Coastguard Worker {
362*de1e4e89SAndroid Build Coastguard Worker 	int opnd;
363*de1e4e89SAndroid Build Coastguard Worker 	struct bstr *a;
364*de1e4e89SAndroid Build Coastguard Worker 	struct tcf_meta_hdr meta_hdr = {};
365*de1e4e89SAndroid Build Coastguard Worker 	unsigned long lvalue = 0, rvalue = 0;
366*de1e4e89SAndroid Build Coastguard Worker 
367*de1e4e89SAndroid Build Coastguard Worker 	if (args == NULL)
368*de1e4e89SAndroid Build Coastguard Worker 		return PARSE_ERR(args, "meta: missing arguments");
369*de1e4e89SAndroid Build Coastguard Worker 
370*de1e4e89SAndroid Build Coastguard Worker 	if (!bstrcmp(args, "list")) {
371*de1e4e89SAndroid Build Coastguard Worker 		list_meta_ids(stderr);
372*de1e4e89SAndroid Build Coastguard Worker 		return -1;
373*de1e4e89SAndroid Build Coastguard Worker 	}
374*de1e4e89SAndroid Build Coastguard Worker 
375*de1e4e89SAndroid Build Coastguard Worker 	a = parse_object(args, args, &meta_hdr.left, &lvalue, NULL);
376*de1e4e89SAndroid Build Coastguard Worker 	if (a == PARSE_FAILURE)
377*de1e4e89SAndroid Build Coastguard Worker 		return -1;
378*de1e4e89SAndroid Build Coastguard Worker 	else if (a == NULL)
379*de1e4e89SAndroid Build Coastguard Worker 		return PARSE_ERR(args, "meta: missing operand");
380*de1e4e89SAndroid Build Coastguard Worker 
381*de1e4e89SAndroid Build Coastguard Worker 	if (!bstrcmp(a, "eq"))
382*de1e4e89SAndroid Build Coastguard Worker 		opnd = TCF_EM_OPND_EQ;
383*de1e4e89SAndroid Build Coastguard Worker 	else if (!bstrcmp(a, "gt"))
384*de1e4e89SAndroid Build Coastguard Worker 		opnd = TCF_EM_OPND_GT;
385*de1e4e89SAndroid Build Coastguard Worker 	else if (!bstrcmp(a, "lt"))
386*de1e4e89SAndroid Build Coastguard Worker 		opnd = TCF_EM_OPND_LT;
387*de1e4e89SAndroid Build Coastguard Worker 	else
388*de1e4e89SAndroid Build Coastguard Worker 		return PARSE_ERR(a, "meta: invalid operand");
389*de1e4e89SAndroid Build Coastguard Worker 
390*de1e4e89SAndroid Build Coastguard Worker 	meta_hdr.left.op = (__u8) opnd;
391*de1e4e89SAndroid Build Coastguard Worker 
392*de1e4e89SAndroid Build Coastguard Worker 	if (a->next == NULL)
393*de1e4e89SAndroid Build Coastguard Worker 		return PARSE_ERR(args, "meta: missing rvalue");
394*de1e4e89SAndroid Build Coastguard Worker 	a = bstr_next(a);
395*de1e4e89SAndroid Build Coastguard Worker 
396*de1e4e89SAndroid Build Coastguard Worker 	a = parse_object(args, a, &meta_hdr.right, &rvalue, &meta_hdr.left);
397*de1e4e89SAndroid Build Coastguard Worker 	if (a == PARSE_FAILURE)
398*de1e4e89SAndroid Build Coastguard Worker 		return -1;
399*de1e4e89SAndroid Build Coastguard Worker 	else if (a != NULL)
400*de1e4e89SAndroid Build Coastguard Worker 		return PARSE_ERR(a, "meta: unexpected trailer");
401*de1e4e89SAndroid Build Coastguard Worker 
402*de1e4e89SAndroid Build Coastguard Worker 
403*de1e4e89SAndroid Build Coastguard Worker 	addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
404*de1e4e89SAndroid Build Coastguard Worker 
405*de1e4e89SAndroid Build Coastguard Worker 	addattr_l(n, MAX_MSG, TCA_EM_META_HDR, &meta_hdr, sizeof(meta_hdr));
406*de1e4e89SAndroid Build Coastguard Worker 
407*de1e4e89SAndroid Build Coastguard Worker 	dump_value(n, TCA_EM_META_LVALUE, lvalue, &meta_hdr.left);
408*de1e4e89SAndroid Build Coastguard Worker 	dump_value(n, TCA_EM_META_RVALUE, rvalue, &meta_hdr.right);
409*de1e4e89SAndroid Build Coastguard Worker 
410*de1e4e89SAndroid Build Coastguard Worker 	return 0;
411*de1e4e89SAndroid Build Coastguard Worker }
412*de1e4e89SAndroid Build Coastguard Worker #undef PARSE_ERR
413*de1e4e89SAndroid Build Coastguard Worker 
print_binary(FILE * fd,unsigned char * str,int len)414*de1e4e89SAndroid Build Coastguard Worker static inline void print_binary(FILE *fd, unsigned char *str, int len)
415*de1e4e89SAndroid Build Coastguard Worker {
416*de1e4e89SAndroid Build Coastguard Worker 	int i;
417*de1e4e89SAndroid Build Coastguard Worker 
418*de1e4e89SAndroid Build Coastguard Worker 	for (i = 0; i < len; i++)
419*de1e4e89SAndroid Build Coastguard Worker 		if (!isprint(str[i]))
420*de1e4e89SAndroid Build Coastguard Worker 			goto binary;
421*de1e4e89SAndroid Build Coastguard Worker 
422*de1e4e89SAndroid Build Coastguard Worker 	for (i = 0; i < len; i++)
423*de1e4e89SAndroid Build Coastguard Worker 		fprintf(fd, "%c", str[i]);
424*de1e4e89SAndroid Build Coastguard Worker 	return;
425*de1e4e89SAndroid Build Coastguard Worker 
426*de1e4e89SAndroid Build Coastguard Worker binary:
427*de1e4e89SAndroid Build Coastguard Worker 	for (i = 0; i < len; i++)
428*de1e4e89SAndroid Build Coastguard Worker 		fprintf(fd, "%02x ", str[i]);
429*de1e4e89SAndroid Build Coastguard Worker 
430*de1e4e89SAndroid Build Coastguard Worker 	fprintf(fd, "\"");
431*de1e4e89SAndroid Build Coastguard Worker 	for (i = 0; i < len; i++)
432*de1e4e89SAndroid Build Coastguard Worker 		fprintf(fd, "%c", isprint(str[i]) ? str[i] : '.');
433*de1e4e89SAndroid Build Coastguard Worker 	fprintf(fd, "\"");
434*de1e4e89SAndroid Build Coastguard Worker }
435*de1e4e89SAndroid Build Coastguard Worker 
print_value(FILE * fd,int type,struct rtattr * rta)436*de1e4e89SAndroid Build Coastguard Worker static inline int print_value(FILE *fd, int type, struct rtattr *rta)
437*de1e4e89SAndroid Build Coastguard Worker {
438*de1e4e89SAndroid Build Coastguard Worker 	if (rta == NULL) {
439*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Missing value TLV\n");
440*de1e4e89SAndroid Build Coastguard Worker 		return -1;
441*de1e4e89SAndroid Build Coastguard Worker 	}
442*de1e4e89SAndroid Build Coastguard Worker 
443*de1e4e89SAndroid Build Coastguard Worker 	switch (type) {
444*de1e4e89SAndroid Build Coastguard Worker 		case TCF_META_TYPE_INT:
445*de1e4e89SAndroid Build Coastguard Worker 			if (RTA_PAYLOAD(rta) < sizeof(__u32)) {
446*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "meta int type value TLV " \
447*de1e4e89SAndroid Build Coastguard Worker 				    "size mismatch.\n");
448*de1e4e89SAndroid Build Coastguard Worker 				return -1;
449*de1e4e89SAndroid Build Coastguard Worker 			}
450*de1e4e89SAndroid Build Coastguard Worker 			fprintf(fd, "%d", rta_getattr_u32(rta));
451*de1e4e89SAndroid Build Coastguard Worker 			break;
452*de1e4e89SAndroid Build Coastguard Worker 
453*de1e4e89SAndroid Build Coastguard Worker 		case TCF_META_TYPE_VAR:
454*de1e4e89SAndroid Build Coastguard Worker 			print_binary(fd, RTA_DATA(rta), RTA_PAYLOAD(rta));
455*de1e4e89SAndroid Build Coastguard Worker 			break;
456*de1e4e89SAndroid Build Coastguard Worker 	}
457*de1e4e89SAndroid Build Coastguard Worker 
458*de1e4e89SAndroid Build Coastguard Worker 	return 0;
459*de1e4e89SAndroid Build Coastguard Worker }
460*de1e4e89SAndroid Build Coastguard Worker 
print_object(FILE * fd,struct tcf_meta_val * obj,struct rtattr * rta)461*de1e4e89SAndroid Build Coastguard Worker static int print_object(FILE *fd, struct tcf_meta_val *obj, struct rtattr *rta)
462*de1e4e89SAndroid Build Coastguard Worker {
463*de1e4e89SAndroid Build Coastguard Worker 	int id = TCF_META_ID(obj->kind);
464*de1e4e89SAndroid Build Coastguard Worker 	int type = TCF_META_TYPE(obj->kind);
465*de1e4e89SAndroid Build Coastguard Worker 	struct meta_entry *entry;
466*de1e4e89SAndroid Build Coastguard Worker 
467*de1e4e89SAndroid Build Coastguard Worker 	if (id == TCF_META_ID_VALUE)
468*de1e4e89SAndroid Build Coastguard Worker 		return print_value(fd, type, rta);
469*de1e4e89SAndroid Build Coastguard Worker 
470*de1e4e89SAndroid Build Coastguard Worker 	entry = lookup_meta_entry_byid(id);
471*de1e4e89SAndroid Build Coastguard Worker 
472*de1e4e89SAndroid Build Coastguard Worker 	if (entry == NULL)
473*de1e4e89SAndroid Build Coastguard Worker 		fprintf(fd, "[unknown meta id %d]", id);
474*de1e4e89SAndroid Build Coastguard Worker 	else
475*de1e4e89SAndroid Build Coastguard Worker 		fprintf(fd, "%s", entry->kind);
476*de1e4e89SAndroid Build Coastguard Worker 
477*de1e4e89SAndroid Build Coastguard Worker 	if (obj->shift)
478*de1e4e89SAndroid Build Coastguard Worker 		fprintf(fd, " shift %d", obj->shift);
479*de1e4e89SAndroid Build Coastguard Worker 
480*de1e4e89SAndroid Build Coastguard Worker 	switch (type) {
481*de1e4e89SAndroid Build Coastguard Worker 		case TCF_META_TYPE_INT:
482*de1e4e89SAndroid Build Coastguard Worker 			if (rta) {
483*de1e4e89SAndroid Build Coastguard Worker 				if (RTA_PAYLOAD(rta) < sizeof(__u32))
484*de1e4e89SAndroid Build Coastguard Worker 					goto size_mismatch;
485*de1e4e89SAndroid Build Coastguard Worker 
486*de1e4e89SAndroid Build Coastguard Worker 				if (rta_getattr_u32(rta))
487*de1e4e89SAndroid Build Coastguard Worker 					fprintf(fd, " mask 0x%08x",
488*de1e4e89SAndroid Build Coastguard Worker 						rta_getattr_u32(rta));
489*de1e4e89SAndroid Build Coastguard Worker 			}
490*de1e4e89SAndroid Build Coastguard Worker 			break;
491*de1e4e89SAndroid Build Coastguard Worker 	}
492*de1e4e89SAndroid Build Coastguard Worker 
493*de1e4e89SAndroid Build Coastguard Worker 	return 0;
494*de1e4e89SAndroid Build Coastguard Worker 
495*de1e4e89SAndroid Build Coastguard Worker size_mismatch:
496*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "meta int type mask TLV size mismatch\n");
497*de1e4e89SAndroid Build Coastguard Worker 	return -1;
498*de1e4e89SAndroid Build Coastguard Worker }
499*de1e4e89SAndroid Build Coastguard Worker 
500*de1e4e89SAndroid Build Coastguard Worker 
meta_print_eopt(FILE * fd,struct tcf_ematch_hdr * hdr,void * data,int data_len)501*de1e4e89SAndroid Build Coastguard Worker static int meta_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
502*de1e4e89SAndroid Build Coastguard Worker 			   int data_len)
503*de1e4e89SAndroid Build Coastguard Worker {
504*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tb[TCA_EM_META_MAX+1];
505*de1e4e89SAndroid Build Coastguard Worker 	struct tcf_meta_hdr *meta_hdr;
506*de1e4e89SAndroid Build Coastguard Worker 
507*de1e4e89SAndroid Build Coastguard Worker 	if (parse_rtattr(tb, TCA_EM_META_MAX, data, data_len) < 0)
508*de1e4e89SAndroid Build Coastguard Worker 		return -1;
509*de1e4e89SAndroid Build Coastguard Worker 
510*de1e4e89SAndroid Build Coastguard Worker 	if (tb[TCA_EM_META_HDR] == NULL) {
511*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Missing meta header\n");
512*de1e4e89SAndroid Build Coastguard Worker 		return -1;
513*de1e4e89SAndroid Build Coastguard Worker 	}
514*de1e4e89SAndroid Build Coastguard Worker 
515*de1e4e89SAndroid Build Coastguard Worker 	if (RTA_PAYLOAD(tb[TCA_EM_META_HDR]) < sizeof(*meta_hdr)) {
516*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Meta header size mismatch\n");
517*de1e4e89SAndroid Build Coastguard Worker 		return -1;
518*de1e4e89SAndroid Build Coastguard Worker 	}
519*de1e4e89SAndroid Build Coastguard Worker 
520*de1e4e89SAndroid Build Coastguard Worker 	meta_hdr = RTA_DATA(tb[TCA_EM_META_HDR]);
521*de1e4e89SAndroid Build Coastguard Worker 
522*de1e4e89SAndroid Build Coastguard Worker 	if (print_object(fd, &meta_hdr->left, tb[TCA_EM_META_LVALUE]) < 0)
523*de1e4e89SAndroid Build Coastguard Worker 		return -1;
524*de1e4e89SAndroid Build Coastguard Worker 
525*de1e4e89SAndroid Build Coastguard Worker 	switch (meta_hdr->left.op) {
526*de1e4e89SAndroid Build Coastguard Worker 		case TCF_EM_OPND_EQ:
527*de1e4e89SAndroid Build Coastguard Worker 			fprintf(fd, " eq ");
528*de1e4e89SAndroid Build Coastguard Worker 			break;
529*de1e4e89SAndroid Build Coastguard Worker 		case TCF_EM_OPND_LT:
530*de1e4e89SAndroid Build Coastguard Worker 			fprintf(fd, " lt ");
531*de1e4e89SAndroid Build Coastguard Worker 			break;
532*de1e4e89SAndroid Build Coastguard Worker 		case TCF_EM_OPND_GT:
533*de1e4e89SAndroid Build Coastguard Worker 			fprintf(fd, " gt ");
534*de1e4e89SAndroid Build Coastguard Worker 			break;
535*de1e4e89SAndroid Build Coastguard Worker 	}
536*de1e4e89SAndroid Build Coastguard Worker 
537*de1e4e89SAndroid Build Coastguard Worker 	return print_object(fd, &meta_hdr->right, tb[TCA_EM_META_RVALUE]);
538*de1e4e89SAndroid Build Coastguard Worker }
539*de1e4e89SAndroid Build Coastguard Worker 
540*de1e4e89SAndroid Build Coastguard Worker struct ematch_util meta_ematch_util = {
541*de1e4e89SAndroid Build Coastguard Worker 	.kind = "meta",
542*de1e4e89SAndroid Build Coastguard Worker 	.kind_num = TCF_EM_META,
543*de1e4e89SAndroid Build Coastguard Worker 	.parse_eopt = meta_parse_eopt,
544*de1e4e89SAndroid Build Coastguard Worker 	.print_eopt = meta_print_eopt,
545*de1e4e89SAndroid Build Coastguard Worker 	.print_usage = meta_print_usage
546*de1e4e89SAndroid Build Coastguard Worker };
547