1/*
2 * lib/netfilter/queue_msg_obj.c	Netfilter Queue Message Object
3 *
4 *	This library is free software; you can redistribute it and/or
5 *	modify it under the terms of the GNU Lesser General Public
6 *	License as published by the Free Software Foundation version 2.1
7 *	of the License.
8 *
9 * Copyright (c) 2007, 2008 Patrick McHardy <kaber@trash.net>
10 */
11
12#include <netlink-local.h>
13#include <netlink/netfilter/nfnl.h>
14#include <netlink/netfilter/netfilter.h>
15#include <netlink/netfilter/queue_msg.h>
16#include <linux/netfilter.h>
17
18/** @cond SKIP */
19#define QUEUE_MSG_ATTR_GROUP		(1UL << 0)
20#define QUEUE_MSG_ATTR_FAMILY		(1UL << 1)
21#define QUEUE_MSG_ATTR_PACKETID		(1UL << 2)
22#define QUEUE_MSG_ATTR_HWPROTO		(1UL << 3)
23#define QUEUE_MSG_ATTR_HOOK		(1UL << 4)
24#define QUEUE_MSG_ATTR_MARK		(1UL << 5)
25#define QUEUE_MSG_ATTR_TIMESTAMP	(1UL << 6)
26#define QUEUE_MSG_ATTR_INDEV		(1UL << 7)
27#define QUEUE_MSG_ATTR_OUTDEV		(1UL << 8)
28#define QUEUE_MSG_ATTR_PHYSINDEV	(1UL << 9)
29#define QUEUE_MSG_ATTR_PHYSOUTDEV	(1UL << 10)
30#define QUEUE_MSG_ATTR_HWADDR		(1UL << 11)
31#define QUEUE_MSG_ATTR_PAYLOAD		(1UL << 12)
32#define QUEUE_MSG_ATTR_VERDICT		(1UL << 13)
33/** @endcond */
34
35static void nfnl_queue_msg_free_data(struct nl_object *c)
36{
37	struct nfnl_queue_msg *msg = (struct nfnl_queue_msg *) c;
38
39	if (msg == NULL)
40		return;
41
42	free(msg->queue_msg_payload);
43}
44
45static int nfnl_queue_msg_clone(struct nl_object *_dst, struct nl_object *_src)
46{
47	struct nfnl_queue_msg *dst = (struct nfnl_queue_msg *) _dst;
48	struct nfnl_queue_msg *src = (struct nfnl_queue_msg *) _src;
49	int err;
50
51	if (src->queue_msg_payload) {
52		err = nfnl_queue_msg_set_payload(dst, src->queue_msg_payload,
53						 src->queue_msg_payload_len);
54		if (err < 0)
55			goto errout;
56	}
57
58	return 0;
59errout:
60	return err;
61}
62
63static void nfnl_queue_msg_dump(struct nl_object *a, struct nl_dump_params *p)
64{
65	struct nfnl_queue_msg *msg = (struct nfnl_queue_msg *) a;
66	struct nl_cache *link_cache;
67	char buf[64];
68
69	link_cache = nl_cache_mngt_require("route/link");
70
71	nl_new_line(p);
72
73	if (msg->ce_mask & QUEUE_MSG_ATTR_GROUP)
74		nl_dump(p, "GROUP=%u ", msg->queue_msg_group);
75
76	if (msg->ce_mask & QUEUE_MSG_ATTR_INDEV) {
77		if (link_cache)
78			nl_dump(p, "IN=%s ",
79				rtnl_link_i2name(link_cache,
80						 msg->queue_msg_indev,
81						 buf, sizeof(buf)));
82		else
83			nl_dump(p, "IN=%d ", msg->queue_msg_indev);
84	}
85
86	if (msg->ce_mask & QUEUE_MSG_ATTR_PHYSINDEV) {
87		if (link_cache)
88			nl_dump(p, "PHYSIN=%s ",
89				rtnl_link_i2name(link_cache,
90						 msg->queue_msg_physindev,
91						 buf, sizeof(buf)));
92		else
93			nl_dump(p, "IN=%d ", msg->queue_msg_physindev);
94	}
95
96	if (msg->ce_mask & QUEUE_MSG_ATTR_OUTDEV) {
97		if (link_cache)
98			nl_dump(p, "OUT=%s ",
99				rtnl_link_i2name(link_cache,
100						 msg->queue_msg_outdev,
101						 buf, sizeof(buf)));
102		else
103			nl_dump(p, "OUT=%d ", msg->queue_msg_outdev);
104	}
105
106	if (msg->ce_mask & QUEUE_MSG_ATTR_PHYSOUTDEV) {
107		if (link_cache)
108			nl_dump(p, "PHYSOUT=%s ",
109				rtnl_link_i2name(link_cache,
110						 msg->queue_msg_physoutdev,
111						 buf, sizeof(buf)));
112		else
113			nl_dump(p, "PHYSOUT=%d ", msg->queue_msg_physoutdev);
114	}
115
116	if (msg->ce_mask & QUEUE_MSG_ATTR_HWADDR) {
117		int i;
118
119		nl_dump(p, "MAC");
120		for (i = 0; i < msg->queue_msg_hwaddr_len; i++)
121			nl_dump(p, "%c%02x", i?':':'=',
122				msg->queue_msg_hwaddr[i]);
123		nl_dump(p, " ");
124	}
125
126	if (msg->ce_mask & QUEUE_MSG_ATTR_FAMILY)
127		nl_dump(p, "FAMILY=%s ",
128			nl_af2str(msg->queue_msg_family, buf, sizeof(buf)));
129
130	if (msg->ce_mask & QUEUE_MSG_ATTR_HWPROTO)
131		nl_dump(p, "HWPROTO=%s ",
132			nl_ether_proto2str(ntohs(msg->queue_msg_hwproto),
133					   buf, sizeof(buf)));
134
135	if (msg->ce_mask & QUEUE_MSG_ATTR_HOOK)
136		nl_dump(p, "HOOK=%s ",
137			nfnl_inet_hook2str(msg->queue_msg_hook,
138					   buf, sizeof(buf)));
139
140	if (msg->ce_mask & QUEUE_MSG_ATTR_MARK)
141		nl_dump(p, "MARK=%d ", msg->queue_msg_mark);
142
143	if (msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD)
144		nl_dump(p, "PAYLOADLEN=%d ", msg->queue_msg_payload_len);
145
146	if (msg->ce_mask & QUEUE_MSG_ATTR_PACKETID)
147		nl_dump(p, "PACKETID=%u ", msg->queue_msg_packetid);
148
149	if (msg->ce_mask & QUEUE_MSG_ATTR_VERDICT)
150		nl_dump(p, "VERDICT=%s ",
151			nfnl_verdict2str(msg->queue_msg_verdict,
152					 buf, sizeof(buf)));
153
154	nl_dump(p, "\n");
155}
156
157/**
158 * @name Allocation/Freeing
159 * @{
160 */
161
162struct nfnl_queue_msg *nfnl_queue_msg_alloc(void)
163{
164	return (struct nfnl_queue_msg *) nl_object_alloc(&queue_msg_obj_ops);
165}
166
167void nfnl_queue_msg_get(struct nfnl_queue_msg *msg)
168{
169	nl_object_get((struct nl_object *) msg);
170}
171
172void nfnl_queue_msg_put(struct nfnl_queue_msg *msg)
173{
174	nl_object_put((struct nl_object *) msg);
175}
176
177/** @} */
178
179/**
180 * @name Attributes
181 * @{
182 */
183
184void nfnl_queue_msg_set_group(struct nfnl_queue_msg *msg, uint16_t group)
185{
186	msg->queue_msg_group = group;
187	msg->ce_mask |= QUEUE_MSG_ATTR_GROUP;
188}
189
190int nfnl_queue_msg_test_group(const struct nfnl_queue_msg *msg)
191{
192	return !!(msg->ce_mask & QUEUE_MSG_ATTR_GROUP);
193}
194
195uint16_t nfnl_queue_msg_get_group(const struct nfnl_queue_msg *msg)
196{
197	return msg->queue_msg_group;
198}
199
200/**
201* Set the protocol family
202* @arg msg         NF queue message
203* @arg family      AF_XXX  address family  example: AF_INET, AF_UNIX, etc
204*/
205void nfnl_queue_msg_set_family(struct nfnl_queue_msg *msg, uint8_t family)
206{
207	msg->queue_msg_family = family;
208	msg->ce_mask |= QUEUE_MSG_ATTR_FAMILY;
209}
210
211int nfnl_queue_msg_test_family(const struct nfnl_queue_msg *msg)
212{
213	return !!(msg->ce_mask & QUEUE_MSG_ATTR_FAMILY);
214}
215
216uint8_t nfnl_queue_msg_get_family(const struct nfnl_queue_msg *msg)
217{
218	if (msg->ce_mask & QUEUE_MSG_ATTR_FAMILY)
219		return msg->queue_msg_family;
220	else
221		return AF_UNSPEC;
222}
223
224void nfnl_queue_msg_set_packetid(struct nfnl_queue_msg *msg, uint32_t packetid)
225{
226	msg->queue_msg_packetid = packetid;
227	msg->ce_mask |= QUEUE_MSG_ATTR_PACKETID;
228}
229
230int nfnl_queue_msg_test_packetid(const struct nfnl_queue_msg *msg)
231{
232	return !!(msg->ce_mask & QUEUE_MSG_ATTR_PACKETID);
233}
234
235uint32_t nfnl_queue_msg_get_packetid(const struct nfnl_queue_msg *msg)
236{
237	return msg->queue_msg_packetid;
238}
239
240void nfnl_queue_msg_set_hwproto(struct nfnl_queue_msg *msg, uint16_t hwproto)
241{
242	msg->queue_msg_hwproto = hwproto;
243	msg->ce_mask |= QUEUE_MSG_ATTR_HWPROTO;
244}
245
246int nfnl_queue_msg_test_hwproto(const struct nfnl_queue_msg *msg)
247{
248	return !!(msg->ce_mask & QUEUE_MSG_ATTR_HWPROTO);
249}
250
251uint16_t nfnl_queue_msg_get_hwproto(const struct nfnl_queue_msg *msg)
252{
253	return msg->queue_msg_hwproto;
254}
255
256void nfnl_queue_msg_set_hook(struct nfnl_queue_msg *msg, uint8_t hook)
257{
258	msg->queue_msg_hook = hook;
259	msg->ce_mask |= QUEUE_MSG_ATTR_HOOK;
260}
261
262int nfnl_queue_msg_test_hook(const struct nfnl_queue_msg *msg)
263{
264	return !!(msg->ce_mask & QUEUE_MSG_ATTR_HOOK);
265}
266
267uint8_t nfnl_queue_msg_get_hook(const struct nfnl_queue_msg *msg)
268{
269	return msg->queue_msg_hook;
270}
271
272void nfnl_queue_msg_set_mark(struct nfnl_queue_msg *msg, uint32_t mark)
273{
274	msg->queue_msg_mark = mark;
275	msg->ce_mask |= QUEUE_MSG_ATTR_MARK;
276}
277
278int nfnl_queue_msg_test_mark(const struct nfnl_queue_msg *msg)
279{
280	return !!(msg->ce_mask & QUEUE_MSG_ATTR_MARK);
281}
282
283uint32_t nfnl_queue_msg_get_mark(const struct nfnl_queue_msg *msg)
284{
285	return msg->queue_msg_mark;
286}
287
288void nfnl_queue_msg_set_timestamp(struct nfnl_queue_msg *msg,
289				  struct timeval *tv)
290{
291	msg->queue_msg_timestamp.tv_sec = tv->tv_sec;
292	msg->queue_msg_timestamp.tv_usec = tv->tv_usec;
293	msg->ce_mask |= QUEUE_MSG_ATTR_TIMESTAMP;
294}
295
296int nfnl_queue_msg_test_timestamp(const struct nfnl_queue_msg *msg)
297{
298	return !!(msg->ce_mask & QUEUE_MSG_ATTR_TIMESTAMP);
299}
300
301const struct timeval *nfnl_queue_msg_get_timestamp(const struct nfnl_queue_msg *msg)
302{
303	if (!(msg->ce_mask & QUEUE_MSG_ATTR_TIMESTAMP))
304		return NULL;
305	return &msg->queue_msg_timestamp;
306}
307
308void nfnl_queue_msg_set_indev(struct nfnl_queue_msg *msg, uint32_t indev)
309{
310	msg->queue_msg_indev = indev;
311	msg->ce_mask |= QUEUE_MSG_ATTR_INDEV;
312}
313
314int nfnl_queue_msg_test_indev(const struct nfnl_queue_msg *msg)
315{
316	return !!(msg->ce_mask & QUEUE_MSG_ATTR_INDEV);
317}
318
319uint32_t nfnl_queue_msg_get_indev(const struct nfnl_queue_msg *msg)
320{
321	return msg->queue_msg_indev;
322}
323
324void nfnl_queue_msg_set_outdev(struct nfnl_queue_msg *msg, uint32_t outdev)
325{
326	msg->queue_msg_outdev = outdev;
327	msg->ce_mask |= QUEUE_MSG_ATTR_OUTDEV;
328}
329
330int nfnl_queue_msg_test_outdev(const struct nfnl_queue_msg *msg)
331{
332	return !!(msg->ce_mask & QUEUE_MSG_ATTR_OUTDEV);
333}
334
335uint32_t nfnl_queue_msg_get_outdev(const struct nfnl_queue_msg *msg)
336{
337	return msg->queue_msg_outdev;
338}
339
340void nfnl_queue_msg_set_physindev(struct nfnl_queue_msg *msg,
341				  uint32_t physindev)
342{
343	msg->queue_msg_physindev = physindev;
344	msg->ce_mask |= QUEUE_MSG_ATTR_PHYSINDEV;
345}
346
347int nfnl_queue_msg_test_physindev(const struct nfnl_queue_msg *msg)
348{
349	return !!(msg->ce_mask & QUEUE_MSG_ATTR_PHYSINDEV);
350}
351
352uint32_t nfnl_queue_msg_get_physindev(const struct nfnl_queue_msg *msg)
353{
354	return msg->queue_msg_physindev;
355}
356
357void nfnl_queue_msg_set_physoutdev(struct nfnl_queue_msg *msg,
358				   uint32_t physoutdev)
359{
360	msg->queue_msg_physoutdev = physoutdev;
361	msg->ce_mask |= QUEUE_MSG_ATTR_PHYSOUTDEV;
362}
363
364int nfnl_queue_msg_test_physoutdev(const struct nfnl_queue_msg *msg)
365{
366	return !!(msg->ce_mask & QUEUE_MSG_ATTR_PHYSOUTDEV);
367}
368
369uint32_t nfnl_queue_msg_get_physoutdev(const struct nfnl_queue_msg *msg)
370{
371	return msg->queue_msg_physoutdev;
372}
373
374void nfnl_queue_msg_set_hwaddr(struct nfnl_queue_msg *msg, uint8_t *hwaddr,
375			       int len)
376{
377	if (len > sizeof(msg->queue_msg_hwaddr))
378		len = sizeof(msg->queue_msg_hwaddr);
379
380	msg->queue_msg_hwaddr_len = len;
381	memcpy(msg->queue_msg_hwaddr, hwaddr, len);
382	msg->ce_mask |= QUEUE_MSG_ATTR_HWADDR;
383}
384
385int nfnl_queue_msg_test_hwaddr(const struct nfnl_queue_msg *msg)
386{
387	return !!(msg->ce_mask & QUEUE_MSG_ATTR_HWADDR);
388}
389
390const uint8_t *nfnl_queue_msg_get_hwaddr(const struct nfnl_queue_msg *msg,
391					 int *len)
392{
393	if (!(msg->ce_mask & QUEUE_MSG_ATTR_HWADDR)) {
394		*len = 0;
395		return NULL;
396	}
397
398	*len = msg->queue_msg_hwaddr_len;
399	return msg->queue_msg_hwaddr;
400}
401
402int nfnl_queue_msg_set_payload(struct nfnl_queue_msg *msg, uint8_t *payload,
403			       int len)
404{
405	free(msg->queue_msg_payload);
406	msg->queue_msg_payload = malloc(len);
407	if (!msg->queue_msg_payload)
408		return -NLE_NOMEM;
409
410	memcpy(msg->queue_msg_payload, payload, len);
411	msg->queue_msg_payload_len = len;
412	msg->ce_mask |= QUEUE_MSG_ATTR_PAYLOAD;
413	return 0;
414}
415
416int nfnl_queue_msg_test_payload(const struct nfnl_queue_msg *msg)
417{
418	return !!(msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD);
419}
420
421const void *nfnl_queue_msg_get_payload(const struct nfnl_queue_msg *msg, int *len)
422{
423	if (!(msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD)) {
424		*len = 0;
425		return NULL;
426	}
427
428	*len = msg->queue_msg_payload_len;
429	return msg->queue_msg_payload;
430}
431
432/**
433* Return the number of items matching a filter in the cache
434* @arg msg        queue msg
435* @arg verdict    NF_DROP, NF_ACCEPT, NF_REPEAT, etc
436*/
437void nfnl_queue_msg_set_verdict(struct nfnl_queue_msg *msg,
438				unsigned int verdict)
439{
440	msg->queue_msg_verdict = verdict;
441	msg->ce_mask |= QUEUE_MSG_ATTR_VERDICT;
442}
443
444int nfnl_queue_msg_test_verdict(const struct nfnl_queue_msg *msg)
445{
446	return !!(msg->ce_mask & QUEUE_MSG_ATTR_VERDICT);
447}
448
449unsigned int nfnl_queue_msg_get_verdict(const struct nfnl_queue_msg *msg)
450{
451	return msg->queue_msg_verdict;
452}
453
454static struct trans_tbl nfnl_queue_msg_attrs[] = {
455	__ADD(QUEUE_MSG_ATTR_GROUP,		group)
456	__ADD(QUEUE_MSG_ATTR_FAMILY,		family)
457	__ADD(QUEUE_MSG_ATTR_PACKETID,		packetid)
458	__ADD(QUEUE_MSG_ATTR_HWPROTO,		hwproto)
459	__ADD(QUEUE_MSG_ATTR_HOOK,		hook)
460	__ADD(QUEUE_MSG_ATTR_MARK,		mark)
461	__ADD(QUEUE_MSG_ATTR_TIMESTAMP,		timestamp)
462	__ADD(QUEUE_MSG_ATTR_INDEV,		indev)
463	__ADD(QUEUE_MSG_ATTR_OUTDEV,		outdev)
464	__ADD(QUEUE_MSG_ATTR_PHYSINDEV,		physindev)
465	__ADD(QUEUE_MSG_ATTR_PHYSOUTDEV,	physoutdev)
466	__ADD(QUEUE_MSG_ATTR_HWADDR,		hwaddr)
467	__ADD(QUEUE_MSG_ATTR_PAYLOAD,		payload)
468	__ADD(QUEUE_MSG_ATTR_VERDICT,		verdict)
469};
470
471static char *nfnl_queue_msg_attrs2str(int attrs, char *buf, size_t len)
472{
473	return __flags2str(attrs, buf, len, nfnl_queue_msg_attrs,
474			   ARRAY_SIZE(nfnl_queue_msg_attrs));
475}
476
477/** @} */
478
479struct nl_object_ops queue_msg_obj_ops = {
480	.oo_name		= "netfilter/queuemsg",
481	.oo_size		= sizeof(struct nfnl_queue_msg),
482	.oo_free_data		= nfnl_queue_msg_free_data,
483	.oo_clone		= nfnl_queue_msg_clone,
484	.oo_dump = {
485	    [NL_DUMP_LINE]	= nfnl_queue_msg_dump,
486	    [NL_DUMP_DETAILS]	= nfnl_queue_msg_dump,
487	    [NL_DUMP_STATS]	= nfnl_queue_msg_dump,
488	},
489	.oo_attrs2str		= nfnl_queue_msg_attrs2str,
490};
491
492/** @} */
493