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