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-private/netlink.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_safe("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	if (link_cache)
157		nl_cache_put(link_cache);
158}
159
160/**
161 * @name Allocation/Freeing
162 * @{
163 */
164
165struct nfnl_queue_msg *nfnl_queue_msg_alloc(void)
166{
167	return (struct nfnl_queue_msg *) nl_object_alloc(&queue_msg_obj_ops);
168}
169
170void nfnl_queue_msg_get(struct nfnl_queue_msg *msg)
171{
172	nl_object_get((struct nl_object *) msg);
173}
174
175void nfnl_queue_msg_put(struct nfnl_queue_msg *msg)
176{
177	nl_object_put((struct nl_object *) msg);
178}
179
180/** @} */
181
182/**
183 * @name Attributes
184 * @{
185 */
186
187void nfnl_queue_msg_set_group(struct nfnl_queue_msg *msg, uint16_t group)
188{
189	msg->queue_msg_group = group;
190	msg->ce_mask |= QUEUE_MSG_ATTR_GROUP;
191}
192
193int nfnl_queue_msg_test_group(const struct nfnl_queue_msg *msg)
194{
195	return !!(msg->ce_mask & QUEUE_MSG_ATTR_GROUP);
196}
197
198uint16_t nfnl_queue_msg_get_group(const struct nfnl_queue_msg *msg)
199{
200	return msg->queue_msg_group;
201}
202
203/**
204* Set the protocol family
205* @arg msg         NF queue message
206* @arg family      AF_XXX  address family  example: AF_INET, AF_UNIX, etc
207*/
208void nfnl_queue_msg_set_family(struct nfnl_queue_msg *msg, uint8_t family)
209{
210	msg->queue_msg_family = family;
211	msg->ce_mask |= QUEUE_MSG_ATTR_FAMILY;
212}
213
214int nfnl_queue_msg_test_family(const struct nfnl_queue_msg *msg)
215{
216	return !!(msg->ce_mask & QUEUE_MSG_ATTR_FAMILY);
217}
218
219uint8_t nfnl_queue_msg_get_family(const struct nfnl_queue_msg *msg)
220{
221	if (msg->ce_mask & QUEUE_MSG_ATTR_FAMILY)
222		return msg->queue_msg_family;
223	else
224		return AF_UNSPEC;
225}
226
227void nfnl_queue_msg_set_packetid(struct nfnl_queue_msg *msg, uint32_t packetid)
228{
229	msg->queue_msg_packetid = packetid;
230	msg->ce_mask |= QUEUE_MSG_ATTR_PACKETID;
231}
232
233int nfnl_queue_msg_test_packetid(const struct nfnl_queue_msg *msg)
234{
235	return !!(msg->ce_mask & QUEUE_MSG_ATTR_PACKETID);
236}
237
238uint32_t nfnl_queue_msg_get_packetid(const struct nfnl_queue_msg *msg)
239{
240	return msg->queue_msg_packetid;
241}
242
243void nfnl_queue_msg_set_hwproto(struct nfnl_queue_msg *msg, uint16_t hwproto)
244{
245	msg->queue_msg_hwproto = hwproto;
246	msg->ce_mask |= QUEUE_MSG_ATTR_HWPROTO;
247}
248
249int nfnl_queue_msg_test_hwproto(const struct nfnl_queue_msg *msg)
250{
251	return !!(msg->ce_mask & QUEUE_MSG_ATTR_HWPROTO);
252}
253
254uint16_t nfnl_queue_msg_get_hwproto(const struct nfnl_queue_msg *msg)
255{
256	return msg->queue_msg_hwproto;
257}
258
259void nfnl_queue_msg_set_hook(struct nfnl_queue_msg *msg, uint8_t hook)
260{
261	msg->queue_msg_hook = hook;
262	msg->ce_mask |= QUEUE_MSG_ATTR_HOOK;
263}
264
265int nfnl_queue_msg_test_hook(const struct nfnl_queue_msg *msg)
266{
267	return !!(msg->ce_mask & QUEUE_MSG_ATTR_HOOK);
268}
269
270uint8_t nfnl_queue_msg_get_hook(const struct nfnl_queue_msg *msg)
271{
272	return msg->queue_msg_hook;
273}
274
275void nfnl_queue_msg_set_mark(struct nfnl_queue_msg *msg, uint32_t mark)
276{
277	msg->queue_msg_mark = mark;
278	msg->ce_mask |= QUEUE_MSG_ATTR_MARK;
279}
280
281int nfnl_queue_msg_test_mark(const struct nfnl_queue_msg *msg)
282{
283	return !!(msg->ce_mask & QUEUE_MSG_ATTR_MARK);
284}
285
286uint32_t nfnl_queue_msg_get_mark(const struct nfnl_queue_msg *msg)
287{
288	return msg->queue_msg_mark;
289}
290
291void nfnl_queue_msg_set_timestamp(struct nfnl_queue_msg *msg,
292				  struct timeval *tv)
293{
294	msg->queue_msg_timestamp.tv_sec = tv->tv_sec;
295	msg->queue_msg_timestamp.tv_usec = tv->tv_usec;
296	msg->ce_mask |= QUEUE_MSG_ATTR_TIMESTAMP;
297}
298
299int nfnl_queue_msg_test_timestamp(const struct nfnl_queue_msg *msg)
300{
301	return !!(msg->ce_mask & QUEUE_MSG_ATTR_TIMESTAMP);
302}
303
304const struct timeval *nfnl_queue_msg_get_timestamp(const struct nfnl_queue_msg *msg)
305{
306	if (!(msg->ce_mask & QUEUE_MSG_ATTR_TIMESTAMP))
307		return NULL;
308	return &msg->queue_msg_timestamp;
309}
310
311void nfnl_queue_msg_set_indev(struct nfnl_queue_msg *msg, uint32_t indev)
312{
313	msg->queue_msg_indev = indev;
314	msg->ce_mask |= QUEUE_MSG_ATTR_INDEV;
315}
316
317int nfnl_queue_msg_test_indev(const struct nfnl_queue_msg *msg)
318{
319	return !!(msg->ce_mask & QUEUE_MSG_ATTR_INDEV);
320}
321
322uint32_t nfnl_queue_msg_get_indev(const struct nfnl_queue_msg *msg)
323{
324	return msg->queue_msg_indev;
325}
326
327void nfnl_queue_msg_set_outdev(struct nfnl_queue_msg *msg, uint32_t outdev)
328{
329	msg->queue_msg_outdev = outdev;
330	msg->ce_mask |= QUEUE_MSG_ATTR_OUTDEV;
331}
332
333int nfnl_queue_msg_test_outdev(const struct nfnl_queue_msg *msg)
334{
335	return !!(msg->ce_mask & QUEUE_MSG_ATTR_OUTDEV);
336}
337
338uint32_t nfnl_queue_msg_get_outdev(const struct nfnl_queue_msg *msg)
339{
340	return msg->queue_msg_outdev;
341}
342
343void nfnl_queue_msg_set_physindev(struct nfnl_queue_msg *msg,
344				  uint32_t physindev)
345{
346	msg->queue_msg_physindev = physindev;
347	msg->ce_mask |= QUEUE_MSG_ATTR_PHYSINDEV;
348}
349
350int nfnl_queue_msg_test_physindev(const struct nfnl_queue_msg *msg)
351{
352	return !!(msg->ce_mask & QUEUE_MSG_ATTR_PHYSINDEV);
353}
354
355uint32_t nfnl_queue_msg_get_physindev(const struct nfnl_queue_msg *msg)
356{
357	return msg->queue_msg_physindev;
358}
359
360void nfnl_queue_msg_set_physoutdev(struct nfnl_queue_msg *msg,
361				   uint32_t physoutdev)
362{
363	msg->queue_msg_physoutdev = physoutdev;
364	msg->ce_mask |= QUEUE_MSG_ATTR_PHYSOUTDEV;
365}
366
367int nfnl_queue_msg_test_physoutdev(const struct nfnl_queue_msg *msg)
368{
369	return !!(msg->ce_mask & QUEUE_MSG_ATTR_PHYSOUTDEV);
370}
371
372uint32_t nfnl_queue_msg_get_physoutdev(const struct nfnl_queue_msg *msg)
373{
374	return msg->queue_msg_physoutdev;
375}
376
377void nfnl_queue_msg_set_hwaddr(struct nfnl_queue_msg *msg, uint8_t *hwaddr,
378			       int len)
379{
380	if (len > sizeof(msg->queue_msg_hwaddr))
381		len = sizeof(msg->queue_msg_hwaddr);
382
383	msg->queue_msg_hwaddr_len = len;
384	memcpy(msg->queue_msg_hwaddr, hwaddr, len);
385	msg->ce_mask |= QUEUE_MSG_ATTR_HWADDR;
386}
387
388int nfnl_queue_msg_test_hwaddr(const struct nfnl_queue_msg *msg)
389{
390	return !!(msg->ce_mask & QUEUE_MSG_ATTR_HWADDR);
391}
392
393const uint8_t *nfnl_queue_msg_get_hwaddr(const struct nfnl_queue_msg *msg,
394					 int *len)
395{
396	if (!(msg->ce_mask & QUEUE_MSG_ATTR_HWADDR)) {
397		*len = 0;
398		return NULL;
399	}
400
401	*len = msg->queue_msg_hwaddr_len;
402	return msg->queue_msg_hwaddr;
403}
404
405int nfnl_queue_msg_set_payload(struct nfnl_queue_msg *msg, uint8_t *payload,
406			       int len)
407{
408	free(msg->queue_msg_payload);
409	msg->queue_msg_payload = malloc(len);
410	if (!msg->queue_msg_payload)
411		return -NLE_NOMEM;
412
413	memcpy(msg->queue_msg_payload, payload, len);
414	msg->queue_msg_payload_len = len;
415	msg->ce_mask |= QUEUE_MSG_ATTR_PAYLOAD;
416	return 0;
417}
418
419int nfnl_queue_msg_test_payload(const struct nfnl_queue_msg *msg)
420{
421	return !!(msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD);
422}
423
424const void *nfnl_queue_msg_get_payload(const struct nfnl_queue_msg *msg, int *len)
425{
426	if (!(msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD)) {
427		*len = 0;
428		return NULL;
429	}
430
431	*len = msg->queue_msg_payload_len;
432	return msg->queue_msg_payload;
433}
434
435/**
436* Return the number of items matching a filter in the cache
437* @arg msg        queue msg
438* @arg verdict    NF_DROP, NF_ACCEPT, NF_REPEAT, etc
439*/
440void nfnl_queue_msg_set_verdict(struct nfnl_queue_msg *msg,
441				unsigned int verdict)
442{
443	msg->queue_msg_verdict = verdict;
444	msg->ce_mask |= QUEUE_MSG_ATTR_VERDICT;
445}
446
447int nfnl_queue_msg_test_verdict(const struct nfnl_queue_msg *msg)
448{
449	return !!(msg->ce_mask & QUEUE_MSG_ATTR_VERDICT);
450}
451
452unsigned int nfnl_queue_msg_get_verdict(const struct nfnl_queue_msg *msg)
453{
454	return msg->queue_msg_verdict;
455}
456
457static const struct trans_tbl nfnl_queue_msg_attrs[] = {
458	__ADD(QUEUE_MSG_ATTR_GROUP,		group)
459	__ADD(QUEUE_MSG_ATTR_FAMILY,		family)
460	__ADD(QUEUE_MSG_ATTR_PACKETID,		packetid)
461	__ADD(QUEUE_MSG_ATTR_HWPROTO,		hwproto)
462	__ADD(QUEUE_MSG_ATTR_HOOK,		hook)
463	__ADD(QUEUE_MSG_ATTR_MARK,		mark)
464	__ADD(QUEUE_MSG_ATTR_TIMESTAMP,		timestamp)
465	__ADD(QUEUE_MSG_ATTR_INDEV,		indev)
466	__ADD(QUEUE_MSG_ATTR_OUTDEV,		outdev)
467	__ADD(QUEUE_MSG_ATTR_PHYSINDEV,		physindev)
468	__ADD(QUEUE_MSG_ATTR_PHYSOUTDEV,	physoutdev)
469	__ADD(QUEUE_MSG_ATTR_HWADDR,		hwaddr)
470	__ADD(QUEUE_MSG_ATTR_PAYLOAD,		payload)
471	__ADD(QUEUE_MSG_ATTR_VERDICT,		verdict)
472};
473
474static char *nfnl_queue_msg_attrs2str(int attrs, char *buf, size_t len)
475{
476	return __flags2str(attrs, buf, len, nfnl_queue_msg_attrs,
477			   ARRAY_SIZE(nfnl_queue_msg_attrs));
478}
479
480/** @} */
481
482struct nl_object_ops queue_msg_obj_ops = {
483	.oo_name		= "netfilter/queuemsg",
484	.oo_size		= sizeof(struct nfnl_queue_msg),
485	.oo_free_data		= nfnl_queue_msg_free_data,
486	.oo_clone		= nfnl_queue_msg_clone,
487	.oo_dump = {
488	    [NL_DUMP_LINE]	= nfnl_queue_msg_dump,
489	    [NL_DUMP_DETAILS]	= nfnl_queue_msg_dump,
490	    [NL_DUMP_STATS]	= nfnl_queue_msg_dump,
491	},
492	.oo_attrs2str		= nfnl_queue_msg_attrs2str,
493};
494
495/** @} */
496