1311b41454dc445639924c691a949bd15fbfab0cbshemminger/*
2311b41454dc445639924c691a949bd15fbfab0cbshemminger * em_meta.c		Metadata Ematch
3311b41454dc445639924c691a949bd15fbfab0cbshemminger *
4311b41454dc445639924c691a949bd15fbfab0cbshemminger *		This program is free software; you can distribute it and/or
5311b41454dc445639924c691a949bd15fbfab0cbshemminger *		modify it under the terms of the GNU General Public License
6311b41454dc445639924c691a949bd15fbfab0cbshemminger *		as published by the Free Software Foundation; either version
7311b41454dc445639924c691a949bd15fbfab0cbshemminger *		2 of the License, or (at your option) any later version.
8311b41454dc445639924c691a949bd15fbfab0cbshemminger *
9311b41454dc445639924c691a949bd15fbfab0cbshemminger * Authors:	Thomas Graf <tgraf@suug.ch>
10311b41454dc445639924c691a949bd15fbfab0cbshemminger */
11311b41454dc445639924c691a949bd15fbfab0cbshemminger
12311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <stdio.h>
13311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <stdlib.h>
14311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <unistd.h>
15311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <syslog.h>
16311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <fcntl.h>
17311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <sys/socket.h>
18311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <netinet/in.h>
19311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <arpa/inet.h>
20311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <string.h>
21311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <errno.h>
22311b41454dc445639924c691a949bd15fbfab0cbshemminger
23311b41454dc445639924c691a949bd15fbfab0cbshemminger#include "m_ematch.h"
24311b41454dc445639924c691a949bd15fbfab0cbshemminger#include <linux/tc_ematch/tc_em_meta.h>
25311b41454dc445639924c691a949bd15fbfab0cbshemminger
26311b41454dc445639924c691a949bd15fbfab0cbshemmingerextern struct ematch_util meta_ematch_util;
27311b41454dc445639924c691a949bd15fbfab0cbshemminger
28311b41454dc445639924c691a949bd15fbfab0cbshemmingerstatic void meta_print_usage(FILE *fd)
29311b41454dc445639924c691a949bd15fbfab0cbshemminger{
30311b41454dc445639924c691a949bd15fbfab0cbshemminger	fprintf(fd,
31311b41454dc445639924c691a949bd15fbfab0cbshemminger	    "Usage: meta(OBJECT { eq | lt | gt } OBJECT)\n" \
32311b41454dc445639924c691a949bd15fbfab0cbshemminger	    "where: OBJECT  := { META_ID | VALUE }\n" \
33311b41454dc445639924c691a949bd15fbfab0cbshemminger	    "       META_ID := id [ shift SHIFT ] [ mask MASK ]\n" \
34311b41454dc445639924c691a949bd15fbfab0cbshemminger	    "\n" \
35311b41454dc445639924c691a949bd15fbfab0cbshemminger	    "Example: meta(nfmark gt 24)\n" \
36ba26a6e853aeadc609238bf2f6258249fb2f47ceStephen Hemminger	    "         meta(indev shift 1 eq \"ppp\")\n" \
37311b41454dc445639924c691a949bd15fbfab0cbshemminger	    "         meta(tcindex mask 0xf0 eq 0xf0)\n" \
38311b41454dc445639924c691a949bd15fbfab0cbshemminger	    "\n" \
39311b41454dc445639924c691a949bd15fbfab0cbshemminger	    "For a list of meta identifiers, use meta(list).\n");
40311b41454dc445639924c691a949bd15fbfab0cbshemminger}
41311b41454dc445639924c691a949bd15fbfab0cbshemminger
42311b41454dc445639924c691a949bd15fbfab0cbshemmingerstruct meta_entry {
43311b41454dc445639924c691a949bd15fbfab0cbshemminger	int		id;
44311b41454dc445639924c691a949bd15fbfab0cbshemminger	char *		kind;
45311b41454dc445639924c691a949bd15fbfab0cbshemminger	char *		mask;
46311b41454dc445639924c691a949bd15fbfab0cbshemminger	char *		desc;
47311b41454dc445639924c691a949bd15fbfab0cbshemminger} meta_table[] = {
48311b41454dc445639924c691a949bd15fbfab0cbshemminger#define TCF_META_ID_SECTION 0
49311b41454dc445639924c691a949bd15fbfab0cbshemminger#define __A(id, name, mask, desc) { TCF_META_ID_##id, name, mask, desc }
50311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SECTION,		"Generic", "", ""),
51311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(RANDOM,		"random",	"i",
52311b41454dc445639924c691a949bd15fbfab0cbshemminger				"Random value (32 bit)"),
53311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(LOADAVG_0,		"loadavg_1",	"i",
54311b41454dc445639924c691a949bd15fbfab0cbshemminger				"Load average in last minute"),
55311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(LOADAVG_1,		"loadavg_5",	"i",
56311b41454dc445639924c691a949bd15fbfab0cbshemminger				"Load average in last 5 minutes"),
57311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(LOADAVG_2,		"loadavg_15",	"i",
58311b41454dc445639924c691a949bd15fbfab0cbshemminger				"Load average in last 15 minutes"),
59311b41454dc445639924c691a949bd15fbfab0cbshemminger
60311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SECTION,		"Interfaces", "", ""),
61311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(DEV,		"dev",		"iv",
62311b41454dc445639924c691a949bd15fbfab0cbshemminger				"Device the packet is on"),
63311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SECTION,		"Packet attributes", "", ""),
64311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(PRIORITY,		"priority",	"i",
65311b41454dc445639924c691a949bd15fbfab0cbshemminger				"Priority of packet"),
66311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(PROTOCOL,		"protocol",	"i",
67311b41454dc445639924c691a949bd15fbfab0cbshemminger				"Link layer protocol"),
68311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(PKTTYPE,		"pkt_type",	"i",
69311b41454dc445639924c691a949bd15fbfab0cbshemminger				"Packet type (uni|multi|broad|...)cast"),
70311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(PKTLEN,		"pkt_len",	"i",
71311b41454dc445639924c691a949bd15fbfab0cbshemminger				"Length of packet"),
72311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(DATALEN,		"data_len",	"i",
73311b41454dc445639924c691a949bd15fbfab0cbshemminger				"Length of data in packet"),
74311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(MACLEN,		"mac_len",	"i",
75311b41454dc445639924c691a949bd15fbfab0cbshemminger				"Length of link layer header"),
76311b41454dc445639924c691a949bd15fbfab0cbshemminger
77311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SECTION,		"Netfilter", "", ""),
78311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(NFMARK,		"nf_mark",	"i",
79311b41454dc445639924c691a949bd15fbfab0cbshemminger				"Netfilter mark"),
80311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(NFMARK,		"fwmark",	"i",
81311b41454dc445639924c691a949bd15fbfab0cbshemminger				"Alias for nf_mark"),
82311b41454dc445639924c691a949bd15fbfab0cbshemminger
83311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SECTION,		"Traffic Control", "", ""),
84311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(TCINDEX,		"tc_index",	"i",	"TC Index"),
85311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SECTION,		"Routing", "", ""),
86311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(RTCLASSID,		"rt_classid",	"i",
87311b41454dc445639924c691a949bd15fbfab0cbshemminger				"Routing ClassID (cls_route)"),
88311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(RTIIF,		"rt_iif",	"i",
89311b41454dc445639924c691a949bd15fbfab0cbshemminger				"Incoming interface index"),
905e76a87d4c87d15467a13268bac7380ee7acc9b7Stephen Hemminger	__A(VLAN_TAG,		"vlan",		"i",	"Vlan tag"),
91311b41454dc445639924c691a949bd15fbfab0cbshemminger
92311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SECTION,		"Sockets", "", ""),
93311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SK_FAMILY,		"sk_family",	"i",	"Address family"),
94311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SK_STATE,		"sk_state",	"i",	"State"),
95311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SK_REUSE,		"sk_reuse",	"i",	"Reuse Flag"),
96311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SK_BOUND_IF,	"sk_bind_if",	"iv",	"Bound interface"),
97311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SK_REFCNT,		"sk_refcnt",	"i",	"Reference counter"),
98311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SK_SHUTDOWN,	"sk_shutdown",	"i",	"Shutdown mask"),
99311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SK_PROTO,		"sk_proto",	"i",	"Protocol"),
100311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SK_TYPE,		"sk_type",	"i",	"Type"),
101311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SK_RCVBUF,		"sk_rcvbuf",	"i",	"Receive buffer size"),
102311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SK_RMEM_ALLOC,	"sk_rmem",	"i",	"RMEM"),
103311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SK_WMEM_ALLOC,	"sk_wmem",	"i",	"WMEM"),
104311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SK_OMEM_ALLOC,	"sk_omem",	"i",	"OMEM"),
105311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SK_WMEM_QUEUED,	"sk_wmem_queue","i",	"WMEM queue"),
106311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SK_SND_QLEN,	"sk_snd_queue",	"i",	"Send queue length"),
107311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SK_RCV_QLEN,	"sk_rcv_queue",	"i",	"Receive queue length"),
108311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SK_ERR_QLEN,	"sk_err_queue",	"i",	"Error queue length"),
109311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SK_FORWARD_ALLOCS,	"sk_fwd_alloc",	"i",	"Forward allocations"),
110311b41454dc445639924c691a949bd15fbfab0cbshemminger	__A(SK_SNDBUF,		"sk_sndbuf",	"i",	"Send buffer size"),
111311b41454dc445639924c691a949bd15fbfab0cbshemminger#undef __A
112311b41454dc445639924c691a949bd15fbfab0cbshemminger};
113311b41454dc445639924c691a949bd15fbfab0cbshemminger
114311b41454dc445639924c691a949bd15fbfab0cbshemmingerstatic inline int map_type(char k)
115311b41454dc445639924c691a949bd15fbfab0cbshemminger{
116311b41454dc445639924c691a949bd15fbfab0cbshemminger	switch (k) {
117311b41454dc445639924c691a949bd15fbfab0cbshemminger		case 'i': return TCF_META_TYPE_INT;
118311b41454dc445639924c691a949bd15fbfab0cbshemminger		case 'v': return TCF_META_TYPE_VAR;
119311b41454dc445639924c691a949bd15fbfab0cbshemminger	}
120311b41454dc445639924c691a949bd15fbfab0cbshemminger
121311b41454dc445639924c691a949bd15fbfab0cbshemminger	fprintf(stderr, "BUG: Unknown map character '%c'\n", k);
122311b41454dc445639924c691a949bd15fbfab0cbshemminger	return INT_MAX;
123311b41454dc445639924c691a949bd15fbfab0cbshemminger}
124311b41454dc445639924c691a949bd15fbfab0cbshemminger
125311b41454dc445639924c691a949bd15fbfab0cbshemmingerstatic struct meta_entry * lookup_meta_entry(struct bstr *kind)
126311b41454dc445639924c691a949bd15fbfab0cbshemminger{
127311b41454dc445639924c691a949bd15fbfab0cbshemminger	int i;
128311b41454dc445639924c691a949bd15fbfab0cbshemminger
129311b41454dc445639924c691a949bd15fbfab0cbshemminger	for (i = 0; i < (sizeof(meta_table)/sizeof(meta_table[0])); i++)
130311b41454dc445639924c691a949bd15fbfab0cbshemminger		if (!bstrcmp(kind, meta_table[i].kind) &&
131311b41454dc445639924c691a949bd15fbfab0cbshemminger		    meta_table[i].id != 0)
132311b41454dc445639924c691a949bd15fbfab0cbshemminger			return &meta_table[i];
133ae665a522bd46bea44c5ea84c89c8b1731954170Stephen Hemminger
134311b41454dc445639924c691a949bd15fbfab0cbshemminger	return NULL;
135311b41454dc445639924c691a949bd15fbfab0cbshemminger}
136311b41454dc445639924c691a949bd15fbfab0cbshemminger
137311b41454dc445639924c691a949bd15fbfab0cbshemmingerstatic struct meta_entry * lookup_meta_entry_byid(int id)
138311b41454dc445639924c691a949bd15fbfab0cbshemminger{
139311b41454dc445639924c691a949bd15fbfab0cbshemminger	int i;
140311b41454dc445639924c691a949bd15fbfab0cbshemminger
141311b41454dc445639924c691a949bd15fbfab0cbshemminger	for (i = 0; i < (sizeof(meta_table)/sizeof(meta_table[0])); i++)
142311b41454dc445639924c691a949bd15fbfab0cbshemminger		if (meta_table[i].id == id)
143311b41454dc445639924c691a949bd15fbfab0cbshemminger			return &meta_table[i];
144ae665a522bd46bea44c5ea84c89c8b1731954170Stephen Hemminger
145311b41454dc445639924c691a949bd15fbfab0cbshemminger	return NULL;
146311b41454dc445639924c691a949bd15fbfab0cbshemminger}
147311b41454dc445639924c691a949bd15fbfab0cbshemminger
148311b41454dc445639924c691a949bd15fbfab0cbshemmingerstatic inline void dump_value(struct nlmsghdr *n, int tlv, unsigned long val,
149311b41454dc445639924c691a949bd15fbfab0cbshemminger			      struct tcf_meta_val *hdr)
150311b41454dc445639924c691a949bd15fbfab0cbshemminger{
151311b41454dc445639924c691a949bd15fbfab0cbshemminger	__u32 t;
152311b41454dc445639924c691a949bd15fbfab0cbshemminger
153311b41454dc445639924c691a949bd15fbfab0cbshemminger	switch (TCF_META_TYPE(hdr->kind)) {
154311b41454dc445639924c691a949bd15fbfab0cbshemminger		case TCF_META_TYPE_INT:
155311b41454dc445639924c691a949bd15fbfab0cbshemminger			t = val;
156311b41454dc445639924c691a949bd15fbfab0cbshemminger			addattr_l(n, MAX_MSG, tlv, &t, sizeof(t));
157311b41454dc445639924c691a949bd15fbfab0cbshemminger			break;
158311b41454dc445639924c691a949bd15fbfab0cbshemminger
159311b41454dc445639924c691a949bd15fbfab0cbshemminger		case TCF_META_TYPE_VAR:
160311b41454dc445639924c691a949bd15fbfab0cbshemminger			if (TCF_META_ID(hdr->kind) == TCF_META_ID_VALUE) {
161311b41454dc445639924c691a949bd15fbfab0cbshemminger				struct bstr *a = (struct bstr *) val;
162311b41454dc445639924c691a949bd15fbfab0cbshemminger				addattr_l(n, MAX_MSG, tlv, a->data, a->len);
163311b41454dc445639924c691a949bd15fbfab0cbshemminger			}
164311b41454dc445639924c691a949bd15fbfab0cbshemminger			break;
165311b41454dc445639924c691a949bd15fbfab0cbshemminger	}
166311b41454dc445639924c691a949bd15fbfab0cbshemminger}
167311b41454dc445639924c691a949bd15fbfab0cbshemminger
168311b41454dc445639924c691a949bd15fbfab0cbshemmingerstatic inline int is_compatible(struct tcf_meta_val *what,
169311b41454dc445639924c691a949bd15fbfab0cbshemminger				struct tcf_meta_val *needed)
170311b41454dc445639924c691a949bd15fbfab0cbshemminger{
171311b41454dc445639924c691a949bd15fbfab0cbshemminger	char *p;
172311b41454dc445639924c691a949bd15fbfab0cbshemminger	struct meta_entry *entry;
173ae665a522bd46bea44c5ea84c89c8b1731954170Stephen Hemminger
174311b41454dc445639924c691a949bd15fbfab0cbshemminger	entry = lookup_meta_entry_byid(TCF_META_ID(what->kind));
175311b41454dc445639924c691a949bd15fbfab0cbshemminger
176311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (entry == NULL)
177311b41454dc445639924c691a949bd15fbfab0cbshemminger		return 0;
178ae665a522bd46bea44c5ea84c89c8b1731954170Stephen Hemminger
179311b41454dc445639924c691a949bd15fbfab0cbshemminger	for (p = entry->mask; p; p++)
180311b41454dc445639924c691a949bd15fbfab0cbshemminger		if (map_type(*p) == TCF_META_TYPE(needed->kind))
181311b41454dc445639924c691a949bd15fbfab0cbshemminger			return 1;
182311b41454dc445639924c691a949bd15fbfab0cbshemminger
183311b41454dc445639924c691a949bd15fbfab0cbshemminger	return 0;
184311b41454dc445639924c691a949bd15fbfab0cbshemminger}
185311b41454dc445639924c691a949bd15fbfab0cbshemminger
186311b41454dc445639924c691a949bd15fbfab0cbshemmingerstatic void list_meta_ids(FILE *fd)
187311b41454dc445639924c691a949bd15fbfab0cbshemminger{
188311b41454dc445639924c691a949bd15fbfab0cbshemminger	int i;
189311b41454dc445639924c691a949bd15fbfab0cbshemminger
190311b41454dc445639924c691a949bd15fbfab0cbshemminger	fprintf(fd,
191311b41454dc445639924c691a949bd15fbfab0cbshemminger	    "--------------------------------------------------------\n" \
192311b41454dc445639924c691a949bd15fbfab0cbshemminger	    "  ID               Type       Description\n" \
193311b41454dc445639924c691a949bd15fbfab0cbshemminger	    "--------------------------------------------------------");
194311b41454dc445639924c691a949bd15fbfab0cbshemminger
195311b41454dc445639924c691a949bd15fbfab0cbshemminger	for (i = 0; i < (sizeof(meta_table)/sizeof(meta_table[0])); i++) {
196311b41454dc445639924c691a949bd15fbfab0cbshemminger		if (meta_table[i].id == TCF_META_ID_SECTION) {
197311b41454dc445639924c691a949bd15fbfab0cbshemminger			fprintf(fd, "\n%s:\n", meta_table[i].kind);
198311b41454dc445639924c691a949bd15fbfab0cbshemminger		} else {
199311b41454dc445639924c691a949bd15fbfab0cbshemminger			char *p = meta_table[i].mask;
200311b41454dc445639924c691a949bd15fbfab0cbshemminger			char buf[64] = {0};
201311b41454dc445639924c691a949bd15fbfab0cbshemminger
202311b41454dc445639924c691a949bd15fbfab0cbshemminger			fprintf(fd, "  %-16s ", meta_table[i].kind);
203311b41454dc445639924c691a949bd15fbfab0cbshemminger
204311b41454dc445639924c691a949bd15fbfab0cbshemminger			while (*p) {
205311b41454dc445639924c691a949bd15fbfab0cbshemminger				int type = map_type(*p);
206311b41454dc445639924c691a949bd15fbfab0cbshemminger
207311b41454dc445639924c691a949bd15fbfab0cbshemminger				switch (type) {
208311b41454dc445639924c691a949bd15fbfab0cbshemminger					case TCF_META_TYPE_INT:
209311b41454dc445639924c691a949bd15fbfab0cbshemminger						strcat(buf, "INT");
210311b41454dc445639924c691a949bd15fbfab0cbshemminger						break;
211311b41454dc445639924c691a949bd15fbfab0cbshemminger
212311b41454dc445639924c691a949bd15fbfab0cbshemminger					case TCF_META_TYPE_VAR:
213311b41454dc445639924c691a949bd15fbfab0cbshemminger						strcat(buf, "VAR");
214311b41454dc445639924c691a949bd15fbfab0cbshemminger						break;
215311b41454dc445639924c691a949bd15fbfab0cbshemminger				}
216311b41454dc445639924c691a949bd15fbfab0cbshemminger
217311b41454dc445639924c691a949bd15fbfab0cbshemminger				if (*(++p))
218311b41454dc445639924c691a949bd15fbfab0cbshemminger					strcat(buf, ",");
219311b41454dc445639924c691a949bd15fbfab0cbshemminger			}
220311b41454dc445639924c691a949bd15fbfab0cbshemminger
221311b41454dc445639924c691a949bd15fbfab0cbshemminger			fprintf(fd, "%-10s %s\n", buf, meta_table[i].desc);
222311b41454dc445639924c691a949bd15fbfab0cbshemminger		}
223311b41454dc445639924c691a949bd15fbfab0cbshemminger	}
224311b41454dc445639924c691a949bd15fbfab0cbshemminger
225311b41454dc445639924c691a949bd15fbfab0cbshemminger	fprintf(fd,
226311b41454dc445639924c691a949bd15fbfab0cbshemminger	    "--------------------------------------------------------\n");
227311b41454dc445639924c691a949bd15fbfab0cbshemminger}
228311b41454dc445639924c691a949bd15fbfab0cbshemminger
229311b41454dc445639924c691a949bd15fbfab0cbshemminger#undef TCF_META_ID_SECTION
230311b41454dc445639924c691a949bd15fbfab0cbshemminger
231311b41454dc445639924c691a949bd15fbfab0cbshemminger#define PARSE_FAILURE ((void *) (-1))
232311b41454dc445639924c691a949bd15fbfab0cbshemminger
233311b41454dc445639924c691a949bd15fbfab0cbshemminger#define PARSE_ERR(CARG, FMT, ARGS...) \
234311b41454dc445639924c691a949bd15fbfab0cbshemminger	em_parse_error(EINVAL, args, CARG, &meta_ematch_util, FMT ,##ARGS)
235311b41454dc445639924c691a949bd15fbfab0cbshemminger
236311b41454dc445639924c691a949bd15fbfab0cbshemmingerstatic inline int can_adopt(struct tcf_meta_val *val)
237311b41454dc445639924c691a949bd15fbfab0cbshemminger{
238311b41454dc445639924c691a949bd15fbfab0cbshemminger	return !!TCF_META_ID(val->kind);
239311b41454dc445639924c691a949bd15fbfab0cbshemminger}
240311b41454dc445639924c691a949bd15fbfab0cbshemminger
241311b41454dc445639924c691a949bd15fbfab0cbshemmingerstatic inline int overwrite_type(struct tcf_meta_val *src,
242311b41454dc445639924c691a949bd15fbfab0cbshemminger				 struct tcf_meta_val *dst)
243311b41454dc445639924c691a949bd15fbfab0cbshemminger{
244311b41454dc445639924c691a949bd15fbfab0cbshemminger	return (TCF_META_TYPE(dst->kind) << 12) | TCF_META_ID(src->kind);
245311b41454dc445639924c691a949bd15fbfab0cbshemminger}
246ae665a522bd46bea44c5ea84c89c8b1731954170Stephen Hemminger
247311b41454dc445639924c691a949bd15fbfab0cbshemminger
248311b41454dc445639924c691a949bd15fbfab0cbshemmingerstatic inline struct bstr *
249311b41454dc445639924c691a949bd15fbfab0cbshemmingerparse_object(struct bstr *args, struct bstr *arg, struct tcf_meta_val *obj,
250311b41454dc445639924c691a949bd15fbfab0cbshemminger	     unsigned long *dst, struct tcf_meta_val *left)
251311b41454dc445639924c691a949bd15fbfab0cbshemminger{
252311b41454dc445639924c691a949bd15fbfab0cbshemminger	struct meta_entry *entry;
253311b41454dc445639924c691a949bd15fbfab0cbshemminger	unsigned long num;
254311b41454dc445639924c691a949bd15fbfab0cbshemminger	struct bstr *a;
255311b41454dc445639924c691a949bd15fbfab0cbshemminger
256311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (arg->quoted) {
257311b41454dc445639924c691a949bd15fbfab0cbshemminger		obj->kind = TCF_META_TYPE_VAR << 12;
258311b41454dc445639924c691a949bd15fbfab0cbshemminger		obj->kind |= TCF_META_ID_VALUE;
259311b41454dc445639924c691a949bd15fbfab0cbshemminger		*dst = (unsigned long) arg;
260311b41454dc445639924c691a949bd15fbfab0cbshemminger		return bstr_next(arg);
261311b41454dc445639924c691a949bd15fbfab0cbshemminger	}
262311b41454dc445639924c691a949bd15fbfab0cbshemminger
263311b41454dc445639924c691a949bd15fbfab0cbshemminger	num = bstrtoul(arg);
26411bbe7fd11d5b39e2a136f9d29acef02ce33bf00Denys Fedoryshchenko	if (num != ULONG_MAX) {
265311b41454dc445639924c691a949bd15fbfab0cbshemminger		obj->kind = TCF_META_TYPE_INT << 12;
266311b41454dc445639924c691a949bd15fbfab0cbshemminger		obj->kind |= TCF_META_ID_VALUE;
267311b41454dc445639924c691a949bd15fbfab0cbshemminger		*dst = (unsigned long) num;
268311b41454dc445639924c691a949bd15fbfab0cbshemminger		return bstr_next(arg);
269311b41454dc445639924c691a949bd15fbfab0cbshemminger	}
270311b41454dc445639924c691a949bd15fbfab0cbshemminger
271311b41454dc445639924c691a949bd15fbfab0cbshemminger	entry = lookup_meta_entry(arg);
272311b41454dc445639924c691a949bd15fbfab0cbshemminger
273311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (entry == NULL) {
274311b41454dc445639924c691a949bd15fbfab0cbshemminger		PARSE_ERR(arg, "meta: unknown meta id\n");
275311b41454dc445639924c691a949bd15fbfab0cbshemminger		return PARSE_FAILURE;
276311b41454dc445639924c691a949bd15fbfab0cbshemminger	}
277311b41454dc445639924c691a949bd15fbfab0cbshemminger
278311b41454dc445639924c691a949bd15fbfab0cbshemminger	obj->kind = entry->id | (map_type(entry->mask[0]) << 12);
279311b41454dc445639924c691a949bd15fbfab0cbshemminger
280311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (left) {
281311b41454dc445639924c691a949bd15fbfab0cbshemminger		struct tcf_meta_val *right = obj;
282ae665a522bd46bea44c5ea84c89c8b1731954170Stephen Hemminger
283311b41454dc445639924c691a949bd15fbfab0cbshemminger		if (TCF_META_TYPE(right->kind) == TCF_META_TYPE(left->kind))
284311b41454dc445639924c691a949bd15fbfab0cbshemminger			goto compatible;
285311b41454dc445639924c691a949bd15fbfab0cbshemminger
286311b41454dc445639924c691a949bd15fbfab0cbshemminger		if (can_adopt(left) && !can_adopt(right)) {
287311b41454dc445639924c691a949bd15fbfab0cbshemminger			if (is_compatible(left, right))
288311b41454dc445639924c691a949bd15fbfab0cbshemminger				left->kind = overwrite_type(left, right);
289311b41454dc445639924c691a949bd15fbfab0cbshemminger			else
290311b41454dc445639924c691a949bd15fbfab0cbshemminger				goto not_compatible;
291311b41454dc445639924c691a949bd15fbfab0cbshemminger		} else if (can_adopt(right) && !can_adopt(left)) {
292311b41454dc445639924c691a949bd15fbfab0cbshemminger			if (is_compatible(right, left))
293311b41454dc445639924c691a949bd15fbfab0cbshemminger				right->kind = overwrite_type(right, left);
294311b41454dc445639924c691a949bd15fbfab0cbshemminger			else
295311b41454dc445639924c691a949bd15fbfab0cbshemminger				goto not_compatible;
296311b41454dc445639924c691a949bd15fbfab0cbshemminger		} else if (can_adopt(left) && can_adopt(right)) {
297311b41454dc445639924c691a949bd15fbfab0cbshemminger			if (is_compatible(left, right))
298311b41454dc445639924c691a949bd15fbfab0cbshemminger				left->kind = overwrite_type(left, right);
299311b41454dc445639924c691a949bd15fbfab0cbshemminger			else if (is_compatible(right, left))
300311b41454dc445639924c691a949bd15fbfab0cbshemminger				right->kind = overwrite_type(right, left);
301311b41454dc445639924c691a949bd15fbfab0cbshemminger			else
302311b41454dc445639924c691a949bd15fbfab0cbshemminger				goto not_compatible;
303ae665a522bd46bea44c5ea84c89c8b1731954170Stephen Hemminger		} else
304311b41454dc445639924c691a949bd15fbfab0cbshemminger			goto not_compatible;
305311b41454dc445639924c691a949bd15fbfab0cbshemminger	}
306311b41454dc445639924c691a949bd15fbfab0cbshemminger
307311b41454dc445639924c691a949bd15fbfab0cbshemmingercompatible:
308311b41454dc445639924c691a949bd15fbfab0cbshemminger
309311b41454dc445639924c691a949bd15fbfab0cbshemminger	a = bstr_next(arg);
310311b41454dc445639924c691a949bd15fbfab0cbshemminger
311311b41454dc445639924c691a949bd15fbfab0cbshemminger	while(a) {
312311b41454dc445639924c691a949bd15fbfab0cbshemminger		if (!bstrcmp(a, "shift")) {
313311b41454dc445639924c691a949bd15fbfab0cbshemminger			unsigned long shift;
314311b41454dc445639924c691a949bd15fbfab0cbshemminger
315311b41454dc445639924c691a949bd15fbfab0cbshemminger			if (a->next == NULL) {
316311b41454dc445639924c691a949bd15fbfab0cbshemminger				PARSE_ERR(a, "meta: missing argument");
317311b41454dc445639924c691a949bd15fbfab0cbshemminger				return PARSE_FAILURE;
318311b41454dc445639924c691a949bd15fbfab0cbshemminger			}
319311b41454dc445639924c691a949bd15fbfab0cbshemminger			a = bstr_next(a);
320ae665a522bd46bea44c5ea84c89c8b1731954170Stephen Hemminger
321311b41454dc445639924c691a949bd15fbfab0cbshemminger			shift = bstrtoul(a);
32211bbe7fd11d5b39e2a136f9d29acef02ce33bf00Denys Fedoryshchenko			if (shift == ULONG_MAX) {
323311b41454dc445639924c691a949bd15fbfab0cbshemminger				PARSE_ERR(a, "meta: invalid shift, must " \
324311b41454dc445639924c691a949bd15fbfab0cbshemminger				    "be numeric");
325311b41454dc445639924c691a949bd15fbfab0cbshemminger				return PARSE_FAILURE;
326311b41454dc445639924c691a949bd15fbfab0cbshemminger			}
327311b41454dc445639924c691a949bd15fbfab0cbshemminger
328311b41454dc445639924c691a949bd15fbfab0cbshemminger			obj->shift = (__u8) shift;
329311b41454dc445639924c691a949bd15fbfab0cbshemminger			a = bstr_next(a);
330311b41454dc445639924c691a949bd15fbfab0cbshemminger		} else if (!bstrcmp(a, "mask")) {
331311b41454dc445639924c691a949bd15fbfab0cbshemminger			unsigned long mask;
332311b41454dc445639924c691a949bd15fbfab0cbshemminger
333311b41454dc445639924c691a949bd15fbfab0cbshemminger			if (a->next == NULL) {
334311b41454dc445639924c691a949bd15fbfab0cbshemminger				PARSE_ERR(a, "meta: missing argument");
335311b41454dc445639924c691a949bd15fbfab0cbshemminger				return PARSE_FAILURE;
336311b41454dc445639924c691a949bd15fbfab0cbshemminger			}
337311b41454dc445639924c691a949bd15fbfab0cbshemminger			a = bstr_next(a);
338ae665a522bd46bea44c5ea84c89c8b1731954170Stephen Hemminger
339311b41454dc445639924c691a949bd15fbfab0cbshemminger			mask = bstrtoul(a);
34011bbe7fd11d5b39e2a136f9d29acef02ce33bf00Denys Fedoryshchenko			if (mask == ULONG_MAX) {
341311b41454dc445639924c691a949bd15fbfab0cbshemminger				PARSE_ERR(a, "meta: invalid mask, must be " \
342311b41454dc445639924c691a949bd15fbfab0cbshemminger				    "numeric");
343311b41454dc445639924c691a949bd15fbfab0cbshemminger				return PARSE_FAILURE;
344311b41454dc445639924c691a949bd15fbfab0cbshemminger			}
345311b41454dc445639924c691a949bd15fbfab0cbshemminger			*dst = (unsigned long) mask;
346311b41454dc445639924c691a949bd15fbfab0cbshemminger			a = bstr_next(a);
347311b41454dc445639924c691a949bd15fbfab0cbshemminger		} else
348311b41454dc445639924c691a949bd15fbfab0cbshemminger			break;
349311b41454dc445639924c691a949bd15fbfab0cbshemminger	}
350311b41454dc445639924c691a949bd15fbfab0cbshemminger
351311b41454dc445639924c691a949bd15fbfab0cbshemminger	return a;
352311b41454dc445639924c691a949bd15fbfab0cbshemminger
353311b41454dc445639924c691a949bd15fbfab0cbshemmingernot_compatible:
354311b41454dc445639924c691a949bd15fbfab0cbshemminger	PARSE_ERR(arg, "lvalue and rvalue are not compatible.");
355311b41454dc445639924c691a949bd15fbfab0cbshemminger	return PARSE_FAILURE;
356311b41454dc445639924c691a949bd15fbfab0cbshemminger}
357311b41454dc445639924c691a949bd15fbfab0cbshemminger
358311b41454dc445639924c691a949bd15fbfab0cbshemmingerstatic int meta_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
359311b41454dc445639924c691a949bd15fbfab0cbshemminger			   struct bstr *args)
360311b41454dc445639924c691a949bd15fbfab0cbshemminger{
361311b41454dc445639924c691a949bd15fbfab0cbshemminger	int opnd;
362311b41454dc445639924c691a949bd15fbfab0cbshemminger	struct bstr *a;
363311b41454dc445639924c691a949bd15fbfab0cbshemminger	struct tcf_meta_hdr meta_hdr;
364311b41454dc445639924c691a949bd15fbfab0cbshemminger	unsigned long lvalue = 0, rvalue = 0;
365311b41454dc445639924c691a949bd15fbfab0cbshemminger
366311b41454dc445639924c691a949bd15fbfab0cbshemminger	memset(&meta_hdr, 0, sizeof(meta_hdr));
367311b41454dc445639924c691a949bd15fbfab0cbshemminger
368311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (args == NULL)
369311b41454dc445639924c691a949bd15fbfab0cbshemminger		return PARSE_ERR(args, "meta: missing arguments");
370311b41454dc445639924c691a949bd15fbfab0cbshemminger
371311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (!bstrcmp(args, "list")) {
372311b41454dc445639924c691a949bd15fbfab0cbshemminger		list_meta_ids(stderr);
373311b41454dc445639924c691a949bd15fbfab0cbshemminger		return -1;
374311b41454dc445639924c691a949bd15fbfab0cbshemminger	}
375311b41454dc445639924c691a949bd15fbfab0cbshemminger
376311b41454dc445639924c691a949bd15fbfab0cbshemminger	a = parse_object(args, args, &meta_hdr.left, &lvalue, NULL);
377311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (a == PARSE_FAILURE)
378311b41454dc445639924c691a949bd15fbfab0cbshemminger		return -1;
379311b41454dc445639924c691a949bd15fbfab0cbshemminger	else if (a == NULL)
380311b41454dc445639924c691a949bd15fbfab0cbshemminger		return PARSE_ERR(args, "meta: missing operand");
381311b41454dc445639924c691a949bd15fbfab0cbshemminger
382311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (!bstrcmp(a, "eq"))
383311b41454dc445639924c691a949bd15fbfab0cbshemminger		opnd = TCF_EM_OPND_EQ;
384311b41454dc445639924c691a949bd15fbfab0cbshemminger	else if (!bstrcmp(a, "gt"))
385311b41454dc445639924c691a949bd15fbfab0cbshemminger		opnd = TCF_EM_OPND_GT;
386311b41454dc445639924c691a949bd15fbfab0cbshemminger	else if (!bstrcmp(a, "lt"))
387311b41454dc445639924c691a949bd15fbfab0cbshemminger		opnd = TCF_EM_OPND_LT;
388311b41454dc445639924c691a949bd15fbfab0cbshemminger	else
389311b41454dc445639924c691a949bd15fbfab0cbshemminger		return PARSE_ERR(a, "meta: invalid operand");
390311b41454dc445639924c691a949bd15fbfab0cbshemminger
391311b41454dc445639924c691a949bd15fbfab0cbshemminger	meta_hdr.left.op = (__u8) opnd;
392311b41454dc445639924c691a949bd15fbfab0cbshemminger
393311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (a->next == NULL)
394311b41454dc445639924c691a949bd15fbfab0cbshemminger		return PARSE_ERR(args, "meta: missing rvalue");
395311b41454dc445639924c691a949bd15fbfab0cbshemminger	a = bstr_next(a);
396311b41454dc445639924c691a949bd15fbfab0cbshemminger
397311b41454dc445639924c691a949bd15fbfab0cbshemminger	a = parse_object(args, a, &meta_hdr.right, &rvalue, &meta_hdr.left);
398311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (a == PARSE_FAILURE)
399311b41454dc445639924c691a949bd15fbfab0cbshemminger		return -1;
400311b41454dc445639924c691a949bd15fbfab0cbshemminger	else if (a != NULL)
401311b41454dc445639924c691a949bd15fbfab0cbshemminger		return PARSE_ERR(a, "meta: unexpected trailer");
402ae665a522bd46bea44c5ea84c89c8b1731954170Stephen Hemminger
403311b41454dc445639924c691a949bd15fbfab0cbshemminger
404311b41454dc445639924c691a949bd15fbfab0cbshemminger	addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
405311b41454dc445639924c691a949bd15fbfab0cbshemminger
406311b41454dc445639924c691a949bd15fbfab0cbshemminger	addattr_l(n, MAX_MSG, TCA_EM_META_HDR, &meta_hdr, sizeof(meta_hdr));
407311b41454dc445639924c691a949bd15fbfab0cbshemminger
4086140785236f9dcddde0c61542dcbe9593e7ab650Patrick McHardy	dump_value(n, TCA_EM_META_LVALUE, lvalue, &meta_hdr.left);
4096140785236f9dcddde0c61542dcbe9593e7ab650Patrick McHardy	dump_value(n, TCA_EM_META_RVALUE, rvalue, &meta_hdr.right);
410311b41454dc445639924c691a949bd15fbfab0cbshemminger
411311b41454dc445639924c691a949bd15fbfab0cbshemminger	return 0;
412311b41454dc445639924c691a949bd15fbfab0cbshemminger}
413311b41454dc445639924c691a949bd15fbfab0cbshemminger#undef PARSE_ERR
414311b41454dc445639924c691a949bd15fbfab0cbshemminger
415311b41454dc445639924c691a949bd15fbfab0cbshemmingerstatic inline void print_binary(FILE *fd, unsigned char *str, int len)
416311b41454dc445639924c691a949bd15fbfab0cbshemminger{
417311b41454dc445639924c691a949bd15fbfab0cbshemminger	int i;
418311b41454dc445639924c691a949bd15fbfab0cbshemminger
419311b41454dc445639924c691a949bd15fbfab0cbshemminger	for (i = 0; i < len; i++)
420311b41454dc445639924c691a949bd15fbfab0cbshemminger		if (!isprint(str[i]))
421311b41454dc445639924c691a949bd15fbfab0cbshemminger			goto binary;
422311b41454dc445639924c691a949bd15fbfab0cbshemminger
423311b41454dc445639924c691a949bd15fbfab0cbshemminger	for (i = 0; i < len; i++)
424311b41454dc445639924c691a949bd15fbfab0cbshemminger		fprintf(fd, "%c", str[i]);
425311b41454dc445639924c691a949bd15fbfab0cbshemminger	return;
426311b41454dc445639924c691a949bd15fbfab0cbshemminger
427311b41454dc445639924c691a949bd15fbfab0cbshemmingerbinary:
428311b41454dc445639924c691a949bd15fbfab0cbshemminger	for (i = 0; i < len; i++)
429311b41454dc445639924c691a949bd15fbfab0cbshemminger		fprintf(fd, "%02x ", str[i]);
430311b41454dc445639924c691a949bd15fbfab0cbshemminger
431311b41454dc445639924c691a949bd15fbfab0cbshemminger	fprintf(fd, "\"");
432311b41454dc445639924c691a949bd15fbfab0cbshemminger	for (i = 0; i < len; i++)
433311b41454dc445639924c691a949bd15fbfab0cbshemminger		fprintf(fd, "%c", isprint(str[i]) ? str[i] : '.');
434311b41454dc445639924c691a949bd15fbfab0cbshemminger	fprintf(fd, "\"");
435311b41454dc445639924c691a949bd15fbfab0cbshemminger}
436311b41454dc445639924c691a949bd15fbfab0cbshemminger
437311b41454dc445639924c691a949bd15fbfab0cbshemmingerstatic inline int print_value(FILE *fd, int type, struct rtattr *rta)
438311b41454dc445639924c691a949bd15fbfab0cbshemminger{
439311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (rta == NULL) {
440311b41454dc445639924c691a949bd15fbfab0cbshemminger		fprintf(stderr, "Missing value TLV\n");
441311b41454dc445639924c691a949bd15fbfab0cbshemminger		return -1;
442311b41454dc445639924c691a949bd15fbfab0cbshemminger	}
443311b41454dc445639924c691a949bd15fbfab0cbshemminger
444311b41454dc445639924c691a949bd15fbfab0cbshemminger	switch(type) {
445311b41454dc445639924c691a949bd15fbfab0cbshemminger		case TCF_META_TYPE_INT:
446311b41454dc445639924c691a949bd15fbfab0cbshemminger			if (RTA_PAYLOAD(rta) < sizeof(__u32)) {
447311b41454dc445639924c691a949bd15fbfab0cbshemminger				fprintf(stderr, "meta int type value TLV " \
448311b41454dc445639924c691a949bd15fbfab0cbshemminger				    "size mismatch.\n");
449311b41454dc445639924c691a949bd15fbfab0cbshemminger				return -1;
450311b41454dc445639924c691a949bd15fbfab0cbshemminger			}
451ff24746cca1ef0c92d46614158e6672acd6b63d3Stephen Hemminger			fprintf(fd, "%d", rta_getattr_u32(rta));
452311b41454dc445639924c691a949bd15fbfab0cbshemminger			break;
453311b41454dc445639924c691a949bd15fbfab0cbshemminger
454311b41454dc445639924c691a949bd15fbfab0cbshemminger		case TCF_META_TYPE_VAR:
455311b41454dc445639924c691a949bd15fbfab0cbshemminger			print_binary(fd, RTA_DATA(rta), RTA_PAYLOAD(rta));
456311b41454dc445639924c691a949bd15fbfab0cbshemminger			break;
457311b41454dc445639924c691a949bd15fbfab0cbshemminger	}
458311b41454dc445639924c691a949bd15fbfab0cbshemminger
459311b41454dc445639924c691a949bd15fbfab0cbshemminger	return 0;
460311b41454dc445639924c691a949bd15fbfab0cbshemminger}
461311b41454dc445639924c691a949bd15fbfab0cbshemminger
462311b41454dc445639924c691a949bd15fbfab0cbshemmingerstatic int print_object(FILE *fd, struct tcf_meta_val *obj, struct rtattr *rta)
463311b41454dc445639924c691a949bd15fbfab0cbshemminger{
464311b41454dc445639924c691a949bd15fbfab0cbshemminger	int id = TCF_META_ID(obj->kind);
465311b41454dc445639924c691a949bd15fbfab0cbshemminger	int type = TCF_META_TYPE(obj->kind);
466311b41454dc445639924c691a949bd15fbfab0cbshemminger	struct meta_entry *entry;
467311b41454dc445639924c691a949bd15fbfab0cbshemminger
468311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (id == TCF_META_ID_VALUE)
469311b41454dc445639924c691a949bd15fbfab0cbshemminger		return print_value(fd, type, rta);
470311b41454dc445639924c691a949bd15fbfab0cbshemminger
471311b41454dc445639924c691a949bd15fbfab0cbshemminger	entry = lookup_meta_entry_byid(id);
472311b41454dc445639924c691a949bd15fbfab0cbshemminger
473311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (entry == NULL)
474311b41454dc445639924c691a949bd15fbfab0cbshemminger		fprintf(fd, "[unknown meta id %d]", id);
475311b41454dc445639924c691a949bd15fbfab0cbshemminger	else
476311b41454dc445639924c691a949bd15fbfab0cbshemminger		fprintf(fd, "%s", entry->kind);
477311b41454dc445639924c691a949bd15fbfab0cbshemminger
478311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (obj->shift)
479311b41454dc445639924c691a949bd15fbfab0cbshemminger		fprintf(fd, " shift %d", obj->shift);
480311b41454dc445639924c691a949bd15fbfab0cbshemminger
481311b41454dc445639924c691a949bd15fbfab0cbshemminger	switch (type) {
482311b41454dc445639924c691a949bd15fbfab0cbshemminger		case TCF_META_TYPE_INT:
483311b41454dc445639924c691a949bd15fbfab0cbshemminger			if (rta) {
484311b41454dc445639924c691a949bd15fbfab0cbshemminger				if (RTA_PAYLOAD(rta) < sizeof(__u32))
485311b41454dc445639924c691a949bd15fbfab0cbshemminger					goto size_mismatch;
486311b41454dc445639924c691a949bd15fbfab0cbshemminger
487311b41454dc445639924c691a949bd15fbfab0cbshemminger				fprintf(fd, " mask 0x%08x",
488ff24746cca1ef0c92d46614158e6672acd6b63d3Stephen Hemminger				    rta_getattr_u32(rta));
489311b41454dc445639924c691a949bd15fbfab0cbshemminger			}
490311b41454dc445639924c691a949bd15fbfab0cbshemminger			break;
491311b41454dc445639924c691a949bd15fbfab0cbshemminger	}
492311b41454dc445639924c691a949bd15fbfab0cbshemminger
493311b41454dc445639924c691a949bd15fbfab0cbshemminger	return 0;
494311b41454dc445639924c691a949bd15fbfab0cbshemminger
495311b41454dc445639924c691a949bd15fbfab0cbshemmingersize_mismatch:
496311b41454dc445639924c691a949bd15fbfab0cbshemminger	fprintf(stderr, "meta int type mask TLV size mismatch\n");
497311b41454dc445639924c691a949bd15fbfab0cbshemminger	return -1;
498311b41454dc445639924c691a949bd15fbfab0cbshemminger}
499311b41454dc445639924c691a949bd15fbfab0cbshemminger
500311b41454dc445639924c691a949bd15fbfab0cbshemminger
501311b41454dc445639924c691a949bd15fbfab0cbshemmingerstatic int meta_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
502311b41454dc445639924c691a949bd15fbfab0cbshemminger			   int data_len)
503311b41454dc445639924c691a949bd15fbfab0cbshemminger{
504311b41454dc445639924c691a949bd15fbfab0cbshemminger	struct rtattr *tb[TCA_EM_META_MAX+1];
505311b41454dc445639924c691a949bd15fbfab0cbshemminger	struct tcf_meta_hdr *meta_hdr;
506311b41454dc445639924c691a949bd15fbfab0cbshemminger
507311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (parse_rtattr(tb, TCA_EM_META_MAX, data, data_len) < 0)
508311b41454dc445639924c691a949bd15fbfab0cbshemminger		return -1;
509311b41454dc445639924c691a949bd15fbfab0cbshemminger
510311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (tb[TCA_EM_META_HDR] == NULL) {
511311b41454dc445639924c691a949bd15fbfab0cbshemminger		fprintf(stderr, "Missing meta header\n");
512311b41454dc445639924c691a949bd15fbfab0cbshemminger		return -1;
513311b41454dc445639924c691a949bd15fbfab0cbshemminger	}
514311b41454dc445639924c691a949bd15fbfab0cbshemminger
515311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (RTA_PAYLOAD(tb[TCA_EM_META_HDR]) < sizeof(*meta_hdr)) {
516311b41454dc445639924c691a949bd15fbfab0cbshemminger		fprintf(stderr, "Meta header size mismatch\n");
517311b41454dc445639924c691a949bd15fbfab0cbshemminger		return -1;
518311b41454dc445639924c691a949bd15fbfab0cbshemminger	}
519311b41454dc445639924c691a949bd15fbfab0cbshemminger
520311b41454dc445639924c691a949bd15fbfab0cbshemminger	meta_hdr = RTA_DATA(tb[TCA_EM_META_HDR]);
521311b41454dc445639924c691a949bd15fbfab0cbshemminger
522311b41454dc445639924c691a949bd15fbfab0cbshemminger	if (print_object(fd, &meta_hdr->left, tb[TCA_EM_META_LVALUE]) < 0)
523311b41454dc445639924c691a949bd15fbfab0cbshemminger		return -1;
524311b41454dc445639924c691a949bd15fbfab0cbshemminger
525311b41454dc445639924c691a949bd15fbfab0cbshemminger	switch (meta_hdr->left.op) {
526311b41454dc445639924c691a949bd15fbfab0cbshemminger		case TCF_EM_OPND_EQ:
527311b41454dc445639924c691a949bd15fbfab0cbshemminger			fprintf(fd, " eq ");
528311b41454dc445639924c691a949bd15fbfab0cbshemminger			break;
529311b41454dc445639924c691a949bd15fbfab0cbshemminger		case TCF_EM_OPND_LT:
530311b41454dc445639924c691a949bd15fbfab0cbshemminger			fprintf(fd, " lt ");
531311b41454dc445639924c691a949bd15fbfab0cbshemminger			break;
532311b41454dc445639924c691a949bd15fbfab0cbshemminger		case TCF_EM_OPND_GT:
533311b41454dc445639924c691a949bd15fbfab0cbshemminger			fprintf(fd, " gt ");
534311b41454dc445639924c691a949bd15fbfab0cbshemminger			break;
535311b41454dc445639924c691a949bd15fbfab0cbshemminger	}
536311b41454dc445639924c691a949bd15fbfab0cbshemminger
537311b41454dc445639924c691a949bd15fbfab0cbshemminger	return print_object(fd, &meta_hdr->right, tb[TCA_EM_META_RVALUE]);
538311b41454dc445639924c691a949bd15fbfab0cbshemminger}
539311b41454dc445639924c691a949bd15fbfab0cbshemminger
540311b41454dc445639924c691a949bd15fbfab0cbshemmingerstruct ematch_util meta_ematch_util = {
541311b41454dc445639924c691a949bd15fbfab0cbshemminger	.kind = "meta",
542311b41454dc445639924c691a949bd15fbfab0cbshemminger	.kind_num = TCF_EM_META,
543311b41454dc445639924c691a949bd15fbfab0cbshemminger	.parse_eopt = meta_parse_eopt,
544311b41454dc445639924c691a949bd15fbfab0cbshemminger	.print_eopt = meta_print_eopt,
545311b41454dc445639924c691a949bd15fbfab0cbshemminger	.print_usage = meta_print_usage
546311b41454dc445639924c691a949bd15fbfab0cbshemminger};
547