blob: 7ca76191cfc891af6c7b91f23ae9c14968b259bb [file] [log] [blame]
Thomas Graf44d36242007-09-15 01:28:01 +02001/*
2 * lib/route/cls/fw.c fw classifier
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-2006 Thomas Graf <tgraf@suug.ch>
10 * Copyright (c) 2006 Petr Gotthard <petr.gotthard@siemens.com>
11 * Copyright (c) 2006 Siemens AG Oesterreich
12 */
13
14/**
15 * @ingroup cls_api
16 * @defgroup fw Firewall Classifier
17 *
18 * @{
19 */
20
21#include <netlink-local.h>
22#include <netlink-tc.h>
23#include <netlink/netlink.h>
24#include <netlink/route/classifier.h>
25#include <netlink/route/classifier-modules.h>
26#include <netlink/route/cls/fw.h>
27
28/** @cond SKIP */
29#define FW_ATTR_CLASSID 0x001
30#define FW_ATTR_ACTION 0x002
31#define FW_ATTR_POLICE 0x004
32#define FW_ATTR_INDEV 0x008
33/** @endcond */
34
35static inline struct rtnl_fw *fw_cls(struct rtnl_cls *cls)
36{
37 return (struct rtnl_fw *) cls->c_subdata;
38}
39
40static inline struct rtnl_fw *fw_alloc(struct rtnl_cls *cls)
41{
42 if (!cls->c_subdata)
43 cls->c_subdata = calloc(1, sizeof(struct rtnl_fw));
44
45 return fw_cls(cls);
46}
47
48static struct nla_policy fw_policy[TCA_FW_MAX+1] = {
49 [TCA_FW_CLASSID] = { .type = NLA_U32 },
50 [TCA_FW_INDEV] = { .type = NLA_STRING,
51 .maxlen = IFNAMSIZ },
52};
53
54static int fw_msg_parser(struct rtnl_cls *cls)
55{
56 int err;
57 struct nlattr *tb[TCA_FW_MAX + 1];
58 struct rtnl_fw *f;
59
60 err = tca_parse(tb, TCA_FW_MAX, (struct rtnl_tca *) cls, fw_policy);
61 if (err < 0)
62 return err;
63
64 f = fw_alloc(cls);
65 if (!f)
66 goto errout_nomem;
67
68 if (tb[TCA_FW_CLASSID]) {
69 f->cf_classid = nla_get_u32(tb[TCA_FW_CLASSID]);
70 f->cf_mask |= FW_ATTR_CLASSID;
71 }
72
73 if (tb[TCA_FW_ACT]) {
74 f->cf_act = nla_get_data(tb[TCA_FW_ACT]);
75 if (!f->cf_act)
76 goto errout_nomem;
77 f->cf_mask |= FW_ATTR_ACTION;
78 }
79
80 if (tb[TCA_FW_POLICE]) {
81 f->cf_police = nla_get_data(tb[TCA_FW_POLICE]);
82 if (!f->cf_police)
83 goto errout_nomem;
84 f->cf_mask |= FW_ATTR_POLICE;
85 }
86
87 if (tb[TCA_FW_INDEV]) {
88 nla_strlcpy(f->cf_indev, tb[TCA_FW_INDEV], IFNAMSIZ);
89 f->cf_mask |= FW_ATTR_INDEV;
90 }
91
92 return 0;
93
94errout_nomem:
95 err = nl_errno(ENOMEM);
96
97 return err;
98}
99
100static void fw_free_data(struct rtnl_cls *cls)
101{
102 struct rtnl_fw *f = fw_cls(cls);
103
104 if (!f)
105 return;
106
107 nl_data_free(f->cf_act);
108 nl_data_free(f->cf_police);
109
110 free(cls->c_subdata);
111}
112
113static int fw_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src)
114{
115 struct rtnl_fw *dst, *src = fw_cls(_src);
116
117 if (!src)
118 return 0;
119
120 dst = fw_alloc(_dst);
121 if (!dst)
122 return nl_errno(ENOMEM);
123
124 if (src->cf_act)
125 if (!(dst->cf_act = nl_data_clone(src->cf_act)))
126 goto errout;
127
128 if (src->cf_police)
129 if (!(dst->cf_police = nl_data_clone(src->cf_police)))
130 goto errout;
131
132 return 0;
133errout:
134 return nl_get_errno();
135}
136
137static int fw_dump_brief(struct rtnl_cls *cls, struct nl_dump_params *p,
138 int line)
139{
140 struct rtnl_fw *f = fw_cls(cls);
141 char buf[32];
142
143 if (!f)
144 goto ignore;
145
146 if (f->cf_mask & FW_ATTR_CLASSID)
147 dp_dump(p, " target %s",
148 rtnl_tc_handle2str(f->cf_classid, buf, sizeof(buf)));
149
150ignore:
151 return line;
152}
153
154static int fw_dump_full(struct rtnl_cls *cls, struct nl_dump_params *p,
155 int line)
156{
157 struct rtnl_fw *f = fw_cls(cls);
158
159 if (!f)
160 goto ignore;
161
162 if (f->cf_mask & FW_ATTR_INDEV)
163 dp_dump(p, "indev %s ", f->cf_indev);
164
165ignore:
166 return line;
167}
168
169static int fw_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p,
170 int line)
171{
172 struct rtnl_fw *f = fw_cls(cls);
173
174 if (!f)
175 goto ignore;
176
177ignore:
178 return line;
179}
180
181static struct nl_msg *fw_get_opts(struct rtnl_cls *cls)
182{
183 struct rtnl_fw *f;
184 struct nl_msg *msg;
185
186 f = fw_cls(cls);
187 if (!f)
188 return NULL;
189
190 msg = nlmsg_alloc();
191 if (!msg)
192 return NULL;
193
194 if (f->cf_mask & FW_ATTR_CLASSID)
195 nla_put_u32(msg, TCA_FW_CLASSID, f->cf_classid);
196
197 if (f->cf_mask & FW_ATTR_ACTION)
198 nla_put_data(msg, TCA_FW_ACT, f->cf_act);
199
200 if (f->cf_mask & FW_ATTR_POLICE)
201 nla_put_data(msg, TCA_FW_POLICE, f->cf_police);
202
203 if (f->cf_mask & FW_ATTR_INDEV)
204 nla_put_string(msg, TCA_FW_INDEV, f->cf_indev);
205
206 return msg;
207}
208
209/**
210 * @name Attribute Modifications
211 * @{
212 */
213
214int rtnl_fw_set_classid(struct rtnl_cls *cls, uint32_t classid)
215{
216 struct rtnl_fw *f;
217
218 f = fw_alloc(cls);
219 if (!f)
220 return nl_errno(ENOMEM);
221
222 f->cf_classid = classid;
223 f->cf_mask |= FW_ATTR_CLASSID;
224
225 return 0;
226}
227
228/** @} */
229
230static struct rtnl_cls_ops fw_ops = {
231 .co_kind = "fw",
232 .co_msg_parser = fw_msg_parser,
233 .co_free_data = fw_free_data,
234 .co_clone = fw_clone,
235 .co_get_opts = fw_get_opts,
236 .co_dump[NL_DUMP_BRIEF] = fw_dump_brief,
237 .co_dump[NL_DUMP_FULL] = fw_dump_full,
238 .co_dump[NL_DUMP_STATS] = fw_dump_stats,
239};
240
241static void __init fw_init(void)
242{
243 rtnl_cls_register(&fw_ops);
244}
245
246static void __exit fw_exit(void)
247{
248 rtnl_cls_unregister(&fw_ops);
249}
250
251/** @} */