1/*
2 * lib/route/rule.c          Routing Rules
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) 2003-2008 Thomas Graf <tgraf@suug.ch>
10 */
11
12/**
13 * @ingroup rtnl
14 * @defgroup rule Routing Rules
15 * @brief
16 * @{
17 */
18
19#include <netlink-local.h>
20#include <netlink/netlink.h>
21#include <netlink/utils.h>
22#include <netlink/route/rtnl.h>
23#include <netlink/route/rule.h>
24#include <inttypes.h>
25
26/** @cond SKIP */
27#define RULE_ATTR_FAMILY	0x0001
28#define RULE_ATTR_PRIO		0x0002
29#define RULE_ATTR_MARK		0x0004
30#define RULE_ATTR_IIF		0x0008
31#define RULE_ATTR_REALMS	0x0010
32#define RULE_ATTR_SRC		0x0020
33#define RULE_ATTR_DST		0x0040
34#define RULE_ATTR_DSFIELD	0x0080
35#define RULE_ATTR_TABLE		0x0100
36#define RULE_ATTR_TYPE		0x0200
37#define RULE_ATTR_SRC_LEN	0x0400
38#define RULE_ATTR_DST_LEN	0x0800
39#define RULE_ATTR_SRCMAP	0x1000
40
41static struct nl_cache_ops rtnl_rule_ops;
42static struct nl_object_ops rule_obj_ops;
43/** @endcond */
44
45static void rule_free_data(struct nl_object *c)
46{
47	struct rtnl_rule *rule = nl_object_priv(c);
48
49	if (!rule)
50		return;
51
52	nl_addr_put(rule->r_src);
53	nl_addr_put(rule->r_dst);
54}
55
56static int rule_clone(struct nl_object *_dst, struct nl_object *_src)
57{
58	struct rtnl_rule *dst = nl_object_priv(_dst);
59	struct rtnl_rule *src = nl_object_priv(_src);
60
61	if (src->r_src)
62		if (!(dst->r_src = nl_addr_clone(src->r_src)))
63			return -NLE_NOMEM;
64
65	if (src->r_dst)
66		if (!(dst->r_dst = nl_addr_clone(src->r_dst)))
67			return -NLE_NOMEM;
68
69	return 0;
70}
71
72static struct nla_policy rule_policy[RTA_MAX+1] = {
73	[RTA_PRIORITY]	= { .type = NLA_U32 },
74	[RTA_FLOW]	= { .type = NLA_U32 },
75	[RTA_PROTOINFO]	= { .type = NLA_U32 },
76	[RTA_IIF]	= { .type = NLA_STRING,
77			    .maxlen = IFNAMSIZ, },
78};
79
80static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
81			   struct nlmsghdr *n, struct nl_parser_param *pp)
82{
83	struct rtnl_rule *rule;
84	struct rtmsg *r;
85	struct nlattr *tb[RTA_MAX+1];
86	int err = 1, family;
87
88	rule = rtnl_rule_alloc();
89	if (!rule) {
90		err = -NLE_NOMEM;
91		goto errout;
92	}
93
94	rule->ce_msgtype = n->nlmsg_type;
95	r = nlmsg_data(n);
96
97	err = nlmsg_parse(n, sizeof(*r), tb, RTA_MAX, rule_policy);
98	if (err < 0)
99		goto errout;
100
101	rule->r_family = family = r->rtm_family;
102	rule->r_type = r->rtm_type;
103	rule->r_dsfield = r->rtm_tos;
104	rule->r_src_len = r->rtm_src_len;
105	rule->r_dst_len = r->rtm_dst_len;
106	rule->r_table = r->rtm_table;
107	rule->ce_mask = (RULE_ATTR_FAMILY | RULE_ATTR_TYPE | RULE_ATTR_DSFIELD |
108			 RULE_ATTR_SRC_LEN | RULE_ATTR_DST_LEN |RULE_ATTR_TYPE |
109			 RULE_ATTR_TABLE);
110
111	if (tb[RTA_PRIORITY]) {
112		rule->r_prio = nla_get_u32(tb[RTA_PRIORITY]);
113		rule->ce_mask |= RULE_ATTR_PRIO;
114	}
115
116	if (tb[RTA_SRC]) {
117		if (!(rule->r_src = nl_addr_alloc_attr(tb[RTA_SRC], family)))
118			goto errout_enomem;
119		nl_addr_set_prefixlen(rule->r_src, r->rtm_src_len);
120		rule->ce_mask |= RULE_ATTR_SRC;
121	}
122
123	if (tb[RTA_DST]) {
124		if (!(rule->r_dst = nl_addr_alloc_attr(tb[RTA_DST], family)))
125			goto errout_enomem;
126		nl_addr_set_prefixlen(rule->r_dst, r->rtm_dst_len);
127		rule->ce_mask |= RULE_ATTR_DST;
128	}
129
130	if (tb[RTA_PROTOINFO]) {
131		rule->r_mark = nla_get_u32(tb[RTA_PROTOINFO]);
132		rule->ce_mask |= RULE_ATTR_MARK;
133	}
134
135	if (tb[RTA_IIF]) {
136		nla_strlcpy(rule->r_iif, tb[RTA_IIF], IFNAMSIZ);
137		rule->ce_mask |= RULE_ATTR_IIF;
138	}
139
140	if (tb[RTA_FLOW]) {
141		rule->r_realms = nla_get_u32(tb[RTA_FLOW]);
142		rule->ce_mask |= RULE_ATTR_REALMS;
143	}
144
145	if (tb[RTA_GATEWAY]) {
146		rule->r_srcmap = nl_addr_alloc_attr(tb[RTA_GATEWAY], family);
147		if (!rule->r_srcmap)
148			goto errout_enomem;
149		rule->ce_mask |= RULE_ATTR_SRCMAP;
150	}
151
152	if (tb[RTA_TABLE]) {
153            rule->r_table = nla_get_u32(tb[RTA_TABLE]);
154            rule->ce_mask |= RULE_ATTR_TABLE;
155        }
156
157	err = pp->pp_cb((struct nl_object *) rule, pp);
158errout:
159	rtnl_rule_put(rule);
160	return err;
161
162errout_enomem:
163	err = -NLE_NOMEM;
164	goto errout;
165}
166
167static int rule_request_update(struct nl_cache *c, struct nl_sock *h)
168{
169	return nl_rtgen_request(h, RTM_GETRULE, AF_UNSPEC, NLM_F_DUMP);
170}
171
172static void rule_dump_line(struct nl_object *o, struct nl_dump_params *p)
173{
174	struct rtnl_rule *r = (struct rtnl_rule *) o;
175	char buf[128];
176
177	nl_dump_line(p, "%8d ", (r->ce_mask & RULE_ATTR_PRIO) ? r->r_prio : 0);
178	nl_dump(p, "%s ", nl_af2str(r->r_family, buf, sizeof(buf)));
179
180	if (r->ce_mask & RULE_ATTR_SRC)
181		nl_dump(p, "from %s ",
182			nl_addr2str(r->r_src, buf, sizeof(buf)));
183	else if (r->ce_mask & RULE_ATTR_SRC_LEN && r->r_src_len)
184		nl_dump(p, "from 0/%d ", r->r_src_len);
185
186	if (r->ce_mask & RULE_ATTR_DST)
187		nl_dump(p, "to %s ",
188			nl_addr2str(r->r_dst, buf, sizeof(buf)));
189	else if (r->ce_mask & RULE_ATTR_DST_LEN && r->r_dst_len)
190		nl_dump(p, "to 0/%d ", r->r_dst_len);
191
192	if (r->ce_mask & RULE_ATTR_DSFIELD && r->r_dsfield)
193		nl_dump(p, "tos %d ", r->r_dsfield);
194
195	if (r->ce_mask & RULE_ATTR_MARK)
196		nl_dump(p, "mark %" PRIx64 , r->r_mark);
197
198	if (r->ce_mask & RULE_ATTR_IIF)
199		nl_dump(p, "iif %s ", r->r_iif);
200
201	if (r->ce_mask & RULE_ATTR_TABLE)
202		nl_dump(p, "lookup %s ",
203			rtnl_route_table2str(r->r_table, buf, sizeof(buf)));
204
205	if (r->ce_mask & RULE_ATTR_REALMS)
206		nl_dump(p, "realms %s ",
207			rtnl_realms2str(r->r_realms, buf, sizeof(buf)));
208
209	nl_dump(p, "action %s\n",
210		nl_rtntype2str(r->r_type, buf, sizeof(buf)));
211}
212
213static void rule_dump_details(struct nl_object *obj, struct nl_dump_params *p)
214{
215	struct rtnl_rule *rule = (struct rtnl_rule *) obj;
216	char buf[128];
217
218	rule_dump_line(obj, p);
219
220	if (rule->ce_mask & RULE_ATTR_SRCMAP)
221		nl_dump_line(p, "  srcmap %s\n",
222			nl_addr2str(rule->r_srcmap, buf, sizeof(buf)));
223}
224
225static void rule_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
226{
227	rule_dump_details(obj, p);
228}
229
230static void rule_dump_env(struct nl_object *obj, struct nl_dump_params *p)
231{
232	struct rtnl_rule *rule = (struct rtnl_rule *) obj;
233	char buf[128];
234
235	nl_dump_line(p, "RULE_PRIORITY=%u\n", rule->r_prio);
236	nl_dump_line(p, "RULE_FAMILY=%s\n",
237		     nl_af2str(rule->r_family, buf, sizeof(buf)));
238
239	if (rule->ce_mask & RULE_ATTR_DST)
240		nl_dump_line(p, "RULE_DST=%s\n",
241			     nl_addr2str(rule->r_dst, buf, sizeof(buf)));
242
243	if (rule->ce_mask & RULE_ATTR_DST_LEN)
244		nl_dump_line(p, "RULE_DSTLEN=%u\n", rule->r_dst_len);
245
246	if (rule->ce_mask & RULE_ATTR_SRC)
247		nl_dump_line(p, "RULE_SRC=%s\n",
248			     nl_addr2str(rule->r_src, buf, sizeof(buf)));
249
250	if (rule->ce_mask & RULE_ATTR_SRC_LEN)
251		nl_dump_line(p, "RULE_SRCLEN=%u\n", rule->r_src_len);
252
253	if (rule->ce_mask & RULE_ATTR_IIF)
254		nl_dump_line(p, "RULE_IIF=%s\n", rule->r_iif);
255
256	if (rule->ce_mask & RULE_ATTR_TABLE)
257		nl_dump_line(p, "RULE_TABLE=%u\n", rule->r_table);
258
259	if (rule->ce_mask & RULE_ATTR_REALMS)
260		nl_dump_line(p, "RULE_REALM=%u\n", rule->r_realms);
261
262	if (rule->ce_mask & RULE_ATTR_MARK)
263		nl_dump_line(p, "RULE_MARK=0x%" PRIx64 "\n", rule->r_mark);
264
265	if (rule->ce_mask & RULE_ATTR_DSFIELD)
266		nl_dump_line(p, "RULE_DSFIELD=%u\n", rule->r_dsfield);
267
268	if (rule->ce_mask & RULE_ATTR_TYPE)
269		nl_dump_line(p, "RULE_TYPE=%s\n",
270			     nl_rtntype2str(rule->r_type, buf, sizeof(buf)));
271
272	if (rule->ce_mask & RULE_ATTR_SRCMAP)
273		nl_dump_line(p, "RULE_SRCMAP=%s\n",
274			     nl_addr2str(rule->r_srcmap, buf, sizeof(buf)));
275}
276
277static int rule_compare(struct nl_object *_a, struct nl_object *_b,
278			uint32_t attrs, int flags)
279{
280	struct rtnl_rule *a = (struct rtnl_rule *) _a;
281	struct rtnl_rule *b = (struct rtnl_rule *) _b;
282	int diff = 0;
283
284#define RULE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, RULE_ATTR_##ATTR, a, b, EXPR)
285
286	diff |= RULE_DIFF(FAMILY,	a->r_family != b->r_family);
287	diff |= RULE_DIFF(TABLE,	a->r_table != b->r_table);
288	diff |= RULE_DIFF(REALMS,	a->r_realms != b->r_realms);
289	diff |= RULE_DIFF(DSFIELD,	a->r_dsfield != b->r_dsfield);
290	diff |= RULE_DIFF(TYPE,		a->r_type != b->r_type);
291	diff |= RULE_DIFF(PRIO,		a->r_prio != b->r_prio);
292	diff |= RULE_DIFF(MARK,		a->r_mark != b->r_mark);
293	diff |= RULE_DIFF(SRC_LEN,	a->r_src_len != b->r_src_len);
294	diff |= RULE_DIFF(DST_LEN,	a->r_dst_len != b->r_dst_len);
295	diff |= RULE_DIFF(SRC,		nl_addr_cmp(a->r_src, b->r_src));
296	diff |= RULE_DIFF(DST,		nl_addr_cmp(a->r_dst, b->r_dst));
297	diff |= RULE_DIFF(IIF,		strcmp(a->r_iif, b->r_iif));
298
299#undef RULE_DIFF
300
301	return diff;
302}
303
304static struct trans_tbl rule_attrs[] = {
305	__ADD(RULE_ATTR_FAMILY, family)
306	__ADD(RULE_ATTR_PRIO, prio)
307	__ADD(RULE_ATTR_MARK, mark)
308	__ADD(RULE_ATTR_IIF, iif)
309	__ADD(RULE_ATTR_REALMS, realms)
310	__ADD(RULE_ATTR_SRC, src)
311	__ADD(RULE_ATTR_DST, dst)
312	__ADD(RULE_ATTR_DSFIELD, dsfield)
313	__ADD(RULE_ATTR_TABLE, table)
314	__ADD(RULE_ATTR_TYPE, type)
315	__ADD(RULE_ATTR_SRC_LEN, src_len)
316	__ADD(RULE_ATTR_DST_LEN, dst_len)
317	__ADD(RULE_ATTR_SRCMAP, srcmap)
318};
319
320static char *rule_attrs2str(int attrs, char *buf, size_t len)
321{
322	return __flags2str(attrs, buf, len, rule_attrs,
323			   ARRAY_SIZE(rule_attrs));
324}
325
326/**
327 * @name Allocation/Freeing
328 * @{
329 */
330
331struct rtnl_rule *rtnl_rule_alloc(void)
332{
333	return (struct rtnl_rule *) nl_object_alloc(&rule_obj_ops);
334}
335
336void rtnl_rule_put(struct rtnl_rule *rule)
337{
338	nl_object_put((struct nl_object *) rule);
339}
340
341/** @} */
342
343/**
344 * @name Cache Management
345 * @{
346 */
347
348/**
349 * Build a rule cache including all rules currently configured in the kernel.
350 * @arg sk		Netlink socket.
351 * @arg family		Address family or AF_UNSPEC.
352 * @arg result		Pointer to store resulting cache.
353 *
354 * Allocates a new rule cache, initializes it properly and updates it
355 * to include all rules currently configured in the kernel.
356 *
357 * @return 0 on success or a negative error code.
358 */
359int rtnl_rule_alloc_cache(struct nl_sock *sock, int family,
360			  struct nl_cache **result)
361{
362	struct nl_cache * cache;
363	int err;
364
365	if (!(cache = nl_cache_alloc(&rtnl_rule_ops)))
366		return -NLE_NOMEM;
367
368	cache->c_iarg1 = family;
369
370	if (sock && (err = nl_cache_refill(sock, cache)) < 0) {
371		free(cache);
372		return err;
373	}
374
375	*result = cache;
376	return 0;
377}
378
379/** @} */
380
381/**
382 * @name Rule Addition
383 * @{
384 */
385
386static int build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags,
387			  struct nl_msg **result)
388{
389	struct nl_msg *msg;
390	struct rtmsg rtm = {
391		.rtm_type = RTN_UNSPEC
392	};
393
394	if (cmd == RTM_NEWRULE)
395		rtm.rtm_type = RTN_UNICAST;
396
397	if (tmpl->ce_mask & RULE_ATTR_FAMILY)
398		rtm.rtm_family = tmpl->r_family;
399
400	if (tmpl->ce_mask & RULE_ATTR_TABLE)
401		rtm.rtm_table = tmpl->r_table;
402
403	if (tmpl->ce_mask & RULE_ATTR_DSFIELD)
404		rtm.rtm_tos = tmpl->r_dsfield;
405
406	if (tmpl->ce_mask & RULE_ATTR_TYPE)
407		rtm.rtm_type = tmpl->r_type;
408
409	if (tmpl->ce_mask & RULE_ATTR_SRC_LEN)
410		rtm.rtm_src_len = tmpl->r_src_len;
411
412	if (tmpl->ce_mask & RULE_ATTR_DST_LEN)
413		rtm.rtm_dst_len = tmpl->r_dst_len;
414
415	msg = nlmsg_alloc_simple(cmd, flags);
416	if (!msg)
417		return -NLE_NOMEM;
418
419	if (nlmsg_append(msg, &rtm, sizeof(rtm), NLMSG_ALIGNTO) < 0)
420		goto nla_put_failure;
421
422	if (tmpl->ce_mask & RULE_ATTR_SRC)
423		NLA_PUT_ADDR(msg, RTA_SRC, tmpl->r_src);
424
425	if (tmpl->ce_mask & RULE_ATTR_DST)
426		NLA_PUT_ADDR(msg, RTA_DST, tmpl->r_dst);
427
428	if (tmpl->ce_mask & RULE_ATTR_PRIO)
429		NLA_PUT_U32(msg, RTA_PRIORITY, tmpl->r_prio);
430
431	if (tmpl->ce_mask & RULE_ATTR_MARK)
432		NLA_PUT_U32(msg, RTA_PROTOINFO, tmpl->r_mark);
433
434	if (tmpl->ce_mask & RULE_ATTR_REALMS)
435		NLA_PUT_U32(msg, RTA_FLOW, tmpl->r_realms);
436
437	if (tmpl->ce_mask & RULE_ATTR_IIF)
438		NLA_PUT_STRING(msg, RTA_IIF, tmpl->r_iif);
439
440	*result = msg;
441	return 0;
442
443nla_put_failure:
444	nlmsg_free(msg);
445	return -NLE_MSGSIZE;
446}
447
448/**
449 * Build netlink request message to add a new rule
450 * @arg tmpl		template with data of new rule
451 * @arg flags		additional netlink message flags
452 *
453 * Builds a new netlink message requesting a addition of a new
454 * rule. The netlink message header isn't fully equipped with
455 * all relevant fields and must thus be sent out via nl_send_auto_complete()
456 * or supplemented as needed. \a tmpl must contain the attributes of the new
457 * address set via \c rtnl_rule_set_* functions.
458 *
459 * @return The netlink message
460 */
461int rtnl_rule_build_add_request(struct rtnl_rule *tmpl, int flags,
462				struct nl_msg **result)
463{
464	return build_rule_msg(tmpl, RTM_NEWRULE, NLM_F_CREATE | flags,
465			      result);
466}
467
468/**
469 * Add a new rule
470 * @arg sk		Netlink socket.
471 * @arg tmpl		template with requested changes
472 * @arg flags		additional netlink message flags
473 *
474 * Builds a netlink message by calling rtnl_rule_build_add_request(),
475 * sends the request to the kernel and waits for the next ACK to be
476 * received and thus blocks until the request has been fullfilled.
477 *
478 * @return 0 on sucess or a negative error if an error occured.
479 */
480int rtnl_rule_add(struct nl_sock *sk, struct rtnl_rule *tmpl, int flags)
481{
482	struct nl_msg *msg;
483	int err;
484
485	if ((err = rtnl_rule_build_add_request(tmpl, flags, &msg)) < 0)
486		return err;
487
488	err = nl_send_auto_complete(sk, msg);
489	nlmsg_free(msg);
490	if (err < 0)
491		return err;
492
493	return wait_for_ack(sk);
494}
495
496/** @} */
497
498/**
499 * @name Rule Deletion
500 * @{
501 */
502
503/**
504 * Build a netlink request message to delete a rule
505 * @arg rule		rule to delete
506 * @arg flags		additional netlink message flags
507 *
508 * Builds a new netlink message requesting a deletion of a rule.
509 * The netlink message header isn't fully equipped with all relevant
510 * fields and must thus be sent out via nl_send_auto_complete()
511 * or supplemented as needed. \a rule must point to an existing
512 * address.
513 *
514 * @return The netlink message
515 */
516int rtnl_rule_build_delete_request(struct rtnl_rule *rule, int flags,
517				   struct nl_msg **result)
518{
519	return build_rule_msg(rule, RTM_DELRULE, flags, result);
520}
521
522/**
523 * Delete a rule
524 * @arg sk		Netlink socket.
525 * @arg rule		rule to delete
526 * @arg flags		additional netlink message flags
527 *
528 * Builds a netlink message by calling rtnl_rule_build_delete_request(),
529 * sends the request to the kernel and waits for the next ACK to be
530 * received and thus blocks until the request has been fullfilled.
531 *
532 * @return 0 on sucess or a negative error if an error occured.
533 */
534int rtnl_rule_delete(struct nl_sock *sk, struct rtnl_rule *rule, int flags)
535{
536	struct nl_msg *msg;
537	int err;
538
539	if ((err = rtnl_rule_build_delete_request(rule, flags, &msg)) < 0)
540		return err;
541
542	err = nl_send_auto_complete(sk, msg);
543	nlmsg_free(msg);
544	if (err < 0)
545		return err;
546
547	return wait_for_ack(sk);
548}
549
550/** @} */
551
552/**
553 * @name Attribute Modification
554 * @{
555 */
556
557void rtnl_rule_set_family(struct rtnl_rule *rule, int family)
558{
559	rule->r_family = family;
560	rule->ce_mask |= RULE_ATTR_FAMILY;
561}
562
563int rtnl_rule_get_family(struct rtnl_rule *rule)
564{
565	if (rule->ce_mask & RULE_ATTR_FAMILY)
566		return rule->r_family;
567	else
568		return AF_UNSPEC;
569}
570
571void rtnl_rule_set_prio(struct rtnl_rule *rule, int prio)
572{
573	rule->r_prio = prio;
574	rule->ce_mask |= RULE_ATTR_PRIO;
575}
576
577int rtnl_rule_get_prio(struct rtnl_rule *rule)
578{
579	if (rule->ce_mask & RULE_ATTR_PRIO)
580		return rule->r_prio;
581	else
582		return -1;
583}
584
585void rtnl_rule_set_mark(struct rtnl_rule *rule, uint64_t mark)
586{
587	rule->r_mark = mark;
588	rule->ce_mask |= RULE_ATTR_MARK;
589}
590
591uint64_t rtnl_rule_get_mark(struct rtnl_rule *rule)
592{
593	if (rule->ce_mask & RULE_ATTR_MARK)
594		return rule->r_mark;
595	else
596		return UINT_LEAST64_MAX;
597}
598
599void rtnl_rule_set_table(struct rtnl_rule *rule, int table)
600{
601	rule->r_table = table;
602	rule->ce_mask |= RULE_ATTR_TABLE;
603}
604
605int rtnl_rule_get_table(struct rtnl_rule *rule)
606{
607	if (rule->ce_mask & RULE_ATTR_TABLE)
608		return rule->r_table;
609	else
610		return -1;
611}
612
613void rtnl_rule_set_dsfield(struct rtnl_rule *rule, int dsfield)
614{
615	rule->r_dsfield = dsfield;
616	rule->ce_mask |= RULE_ATTR_DSFIELD;
617}
618
619int rtnl_rule_get_dsfield(struct rtnl_rule *rule)
620{
621	if (rule->ce_mask & RULE_ATTR_DSFIELD)
622		return rule->r_dsfield;
623	else
624		return -1;
625}
626
627void rtnl_rule_set_src_len(struct rtnl_rule *rule, int len)
628{
629	rule->r_src_len = len;
630	if (rule->ce_mask & RULE_ATTR_SRC)
631		nl_addr_set_prefixlen(rule->r_src, len);
632	rule->ce_mask |= RULE_ATTR_SRC_LEN;
633}
634
635int rtnl_rule_get_src_len(struct rtnl_rule *rule)
636{
637	if (rule->ce_mask & RULE_ATTR_SRC_LEN)
638		return rule->r_src_len;
639	else
640		return -1;
641}
642
643void rtnl_rule_set_dst_len(struct rtnl_rule *rule, int len)
644{
645	rule->r_dst_len = len;
646	if (rule->ce_mask & RULE_ATTR_DST)
647		nl_addr_set_prefixlen(rule->r_dst, len);
648	rule->ce_mask |= RULE_ATTR_DST_LEN;
649}
650
651int rtnl_rule_get_dst_len(struct rtnl_rule *rule)
652{
653	if (rule->ce_mask & RULE_ATTR_DST_LEN)
654		return rule->r_dst_len;
655	else
656		return -1;
657}
658
659static inline int __assign_addr(struct rtnl_rule *rule, struct nl_addr **pos,
660			        struct nl_addr *new, uint8_t *len, int flag)
661{
662	if (rule->ce_mask & RULE_ATTR_FAMILY) {
663		if (new->a_family != rule->r_family)
664			return -NLE_AF_MISMATCH;
665	} else
666		rule->r_family = new->a_family;
667
668	if (*pos)
669		nl_addr_put(*pos);
670
671	nl_addr_get(new);
672	*pos = new;
673	*len = nl_addr_get_prefixlen(new);
674
675	rule->ce_mask |= (flag | RULE_ATTR_FAMILY);
676
677	return 0;
678}
679
680int rtnl_rule_set_src(struct rtnl_rule *rule, struct nl_addr *src)
681{
682	return __assign_addr(rule, &rule->r_src, src, &rule->r_src_len,
683			     RULE_ATTR_SRC | RULE_ATTR_SRC_LEN);
684}
685
686struct nl_addr *rtnl_rule_get_src(struct rtnl_rule *rule)
687{
688	if (rule->ce_mask & RULE_ATTR_SRC)
689		return rule->r_src;
690	else
691		return NULL;
692}
693
694int rtnl_rule_set_dst(struct rtnl_rule *rule, struct nl_addr *dst)
695{
696	return __assign_addr(rule, &rule->r_dst, dst, &rule->r_dst_len,
697			     RULE_ATTR_DST | RULE_ATTR_DST_LEN);
698}
699
700struct nl_addr *rtnl_rule_get_dst(struct rtnl_rule *rule)
701{
702	if (rule->ce_mask & RULE_ATTR_DST)
703		return rule->r_dst;
704	else
705		return NULL;
706}
707
708int rtnl_rule_set_iif(struct rtnl_rule *rule, const char *dev)
709{
710	if (strlen(dev) > IFNAMSIZ-1)
711		return -NLE_RANGE;
712
713	strcpy(rule->r_iif, dev);
714	rule->ce_mask |= RULE_ATTR_IIF;
715	return 0;
716}
717
718char *rtnl_rule_get_iif(struct rtnl_rule *rule)
719{
720	if (rule->ce_mask & RULE_ATTR_IIF)
721		return rule->r_iif;
722	else
723		return NULL;
724}
725
726void rtnl_rule_set_action(struct rtnl_rule *rule, int type)
727{
728	rule->r_type = type;
729	rule->ce_mask |= RULE_ATTR_TYPE;
730}
731
732int rtnl_rule_get_action(struct rtnl_rule *rule)
733{
734	if (rule->ce_mask & RULE_ATTR_TYPE)
735		return rule->r_type;
736	else
737		return -NLE_NOATTR;
738}
739
740void rtnl_rule_set_realms(struct rtnl_rule *rule, uint32_t realms)
741{
742	rule->r_realms = realms;
743	rule->ce_mask |= RULE_ATTR_REALMS;
744}
745
746uint32_t rtnl_rule_get_realms(struct rtnl_rule *rule)
747{
748	if (rule->ce_mask & RULE_ATTR_REALMS)
749		return rule->r_realms;
750	else
751		return 0;
752}
753
754/** @} */
755
756static struct nl_object_ops rule_obj_ops = {
757	.oo_name		= "route/rule",
758	.oo_size		= sizeof(struct rtnl_rule),
759	.oo_free_data		= rule_free_data,
760	.oo_clone		= rule_clone,
761	.oo_dump = {
762	    [NL_DUMP_LINE]	= rule_dump_line,
763	    [NL_DUMP_DETAILS]	= rule_dump_details,
764	    [NL_DUMP_STATS]	= rule_dump_stats,
765	    [NL_DUMP_ENV]	= rule_dump_env,
766	},
767	.oo_compare		= rule_compare,
768	.oo_attrs2str		= rule_attrs2str,
769	.oo_id_attrs		= ~0,
770};
771
772static struct nl_cache_ops rtnl_rule_ops = {
773	.co_name		= "route/rule",
774	.co_hdrsize		= sizeof(struct rtmsg),
775	.co_msgtypes		= {
776					{ RTM_NEWRULE, NL_ACT_NEW, "new" },
777					{ RTM_DELRULE, NL_ACT_DEL, "del" },
778					{ RTM_GETRULE, NL_ACT_GET, "get" },
779					END_OF_MSGTYPES_LIST,
780				  },
781	.co_protocol		= NETLINK_ROUTE,
782	.co_request_update	= rule_request_update,
783	.co_msg_parser		= rule_msg_parser,
784	.co_obj_ops		= &rule_obj_ops,
785};
786
787static void __init rule_init(void)
788{
789	nl_cache_mngt_register(&rtnl_rule_ops);
790}
791
792static void __exit rule_exit(void)
793{
794	nl_cache_mngt_unregister(&rtnl_rule_ops);
795}
796
797/** @} */
798