• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>
4  * Copyright (c) 2006 Petr Gotthard <petr.gotthard@siemens.com>
5  * Copyright (c) 2006 Siemens AG Oesterreich
6  */
7 
8 /**
9  * @ingroup cls
10  * @defgroup cls_fw Firewall Classifier
11  *
12  * @{
13  */
14 
15 #include <netlink-private/netlink.h>
16 #include <netlink-private/tc.h>
17 #include <netlink/netlink.h>
18 #include <netlink-private/route/tc-api.h>
19 #include <netlink/route/classifier.h>
20 #include <netlink/route/cls/fw.h>
21 
22 /** @cond SKIP */
23 #define FW_ATTR_CLASSID      0x001
24 #define FW_ATTR_ACTION       0x002
25 #define FW_ATTR_POLICE       0x004
26 #define FW_ATTR_INDEV        0x008
27 #define FW_ATTR_MASK         0x010
28 /** @endcond */
29 
30 static struct nla_policy fw_policy[TCA_FW_MAX+1] = {
31 	[TCA_FW_CLASSID]	= { .type = NLA_U32 },
32 	[TCA_FW_INDEV]		= { .type = NLA_STRING,
33 				    .maxlen = IFNAMSIZ },
34 	[TCA_FW_MASK]		= { .type = NLA_U32 },
35 };
36 
fw_msg_parser(struct rtnl_tc * tc,void * data)37 static int fw_msg_parser(struct rtnl_tc *tc, void *data)
38 {
39 	struct nlattr *tb[TCA_FW_MAX + 1];
40 	struct rtnl_fw *f = data;
41 	int err;
42 
43 	err = tca_parse(tb, TCA_FW_MAX, tc, fw_policy);
44 	if (err < 0)
45 		return err;
46 
47 	if (tb[TCA_FW_CLASSID]) {
48 		f->cf_classid = nla_get_u32(tb[TCA_FW_CLASSID]);
49 		f->cf_mask |= FW_ATTR_CLASSID;
50 	}
51 
52 	if (tb[TCA_FW_ACT]) {
53 		f->cf_act = nl_data_alloc_attr(tb[TCA_FW_ACT]);
54 		if (!f->cf_act)
55 			return -NLE_NOMEM;
56 		f->cf_mask |= FW_ATTR_ACTION;
57 	}
58 
59 	if (tb[TCA_FW_POLICE]) {
60 		f->cf_police = nl_data_alloc_attr(tb[TCA_FW_POLICE]);
61 		if (!f->cf_police)
62 			return -NLE_NOMEM;
63 		f->cf_mask |= FW_ATTR_POLICE;
64 	}
65 
66 	if (tb[TCA_FW_INDEV]) {
67 		nla_strlcpy(f->cf_indev, tb[TCA_FW_INDEV], IFNAMSIZ);
68 		f->cf_mask |= FW_ATTR_INDEV;
69 	}
70 
71 	if (tb[TCA_FW_MASK]) {
72 		f->cf_fwmask = nla_get_u32(tb[TCA_FW_MASK]);
73 		f->cf_mask |= FW_ATTR_MASK;
74 	}
75 
76 	return 0;
77 }
78 
fw_free_data(struct rtnl_tc * tc,void * data)79 static void fw_free_data(struct rtnl_tc *tc, void *data)
80 {
81 	struct rtnl_fw *f = data;
82 
83 	nl_data_free(f->cf_act);
84 	nl_data_free(f->cf_police);
85 }
86 
fw_clone(void * _dst,void * _src)87 static int fw_clone(void *_dst, void *_src)
88 {
89 	struct rtnl_fw *dst = _dst, *src = _src;
90 
91 	dst->cf_act = NULL;
92 	dst->cf_police = NULL;
93 
94 	if (src->cf_act && !(dst->cf_act = nl_data_clone(src->cf_act)))
95 		return -NLE_NOMEM;
96 
97 	if (src->cf_police && !(dst->cf_police = nl_data_clone(src->cf_police)))
98 		return -NLE_NOMEM;
99 
100 	return 0;
101 }
102 
fw_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)103 static void fw_dump_line(struct rtnl_tc *tc, void *data,
104 			 struct nl_dump_params *p)
105 {
106 	struct rtnl_fw *f = data;
107 
108 	if (!f)
109 		return;
110 
111 	if (f->cf_mask & FW_ATTR_CLASSID) {
112 		char buf[32];
113 
114 		nl_dump(p, " target %s",
115 			rtnl_tc_handle2str(f->cf_classid, buf, sizeof(buf)));
116 	}
117 
118 	if (f->cf_mask & FW_ATTR_MASK)
119 		nl_dump(p, " mask 0x%x", f->cf_fwmask);
120 }
121 
fw_dump_details(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)122 static void fw_dump_details(struct rtnl_tc *tc, void *data,
123 			    struct nl_dump_params *p)
124 {
125 	struct rtnl_fw *f = data;
126 
127 	if (f && f->cf_mask & FW_ATTR_INDEV)
128 		nl_dump(p, "indev %s ", f->cf_indev);
129 }
130 
fw_msg_fill(struct rtnl_tc * tc,void * data,struct nl_msg * msg)131 static int fw_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
132 {
133 	struct rtnl_fw *f = data;
134 
135 	if (!f)
136 		return 0;
137 
138 	if (f->cf_mask & FW_ATTR_CLASSID)
139 		NLA_PUT_U32(msg, TCA_FW_CLASSID, f->cf_classid);
140 
141 	if (f->cf_mask & FW_ATTR_ACTION)
142 		NLA_PUT_DATA(msg, TCA_FW_ACT, f->cf_act);
143 
144 	if (f->cf_mask & FW_ATTR_POLICE)
145 		NLA_PUT_DATA(msg, TCA_FW_POLICE, f->cf_police);
146 
147 	if (f->cf_mask & FW_ATTR_INDEV)
148 		NLA_PUT_STRING(msg, TCA_FW_INDEV, f->cf_indev);
149 
150 	if (f->cf_mask & FW_ATTR_MASK)
151 		NLA_PUT_U32(msg, TCA_FW_MASK, f->cf_fwmask);
152 
153 	return 0;
154 
155 nla_put_failure:
156 	return -NLE_MSGSIZE;
157 }
158 
159 /**
160  * @name Attribute Modifications
161  * @{
162  */
163 
rtnl_fw_set_classid(struct rtnl_cls * cls,uint32_t classid)164 int rtnl_fw_set_classid(struct rtnl_cls *cls, uint32_t classid)
165 {
166 	struct rtnl_fw *f;
167 
168 	if (!(f = rtnl_tc_data(TC_CAST(cls))))
169 		return -NLE_NOMEM;
170 
171 	f->cf_classid = classid;
172 	f->cf_mask |= FW_ATTR_CLASSID;
173 
174 	return 0;
175 }
176 
rtnl_fw_set_mask(struct rtnl_cls * cls,uint32_t mask)177 int rtnl_fw_set_mask(struct rtnl_cls *cls, uint32_t mask)
178 {
179 	struct rtnl_fw *f;
180 
181 	if (!(f = rtnl_tc_data(TC_CAST(cls))))
182 		return -NLE_NOMEM;
183 
184 	f->cf_fwmask = mask;
185 	f->cf_mask |= FW_ATTR_MASK;
186 
187 	return 0;
188 }
189 
190 /** @} */
191 
192 static struct rtnl_tc_ops fw_ops = {
193 	.to_kind		= "fw",
194 	.to_type		= RTNL_TC_TYPE_CLS,
195 	.to_size		= sizeof(struct rtnl_fw),
196 	.to_msg_parser		= fw_msg_parser,
197 	.to_msg_fill		= fw_msg_fill,
198 	.to_free_data		= fw_free_data,
199 	.to_clone		= fw_clone,
200 	.to_dump = {
201 	    [NL_DUMP_LINE]	= fw_dump_line,
202 	    [NL_DUMP_DETAILS]	= fw_dump_details,
203 	},
204 };
205 
fw_init(void)206 static void __init fw_init(void)
207 {
208 	rtnl_tc_register(&fw_ops);
209 }
210 
fw_exit(void)211 static void __exit fw_exit(void)
212 {
213 	rtnl_tc_unregister(&fw_ops);
214 }
215 
216 /** @} */
217