aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Alpe <richard.alpe@ericsson.com>2015-02-09 03:50:05 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-09 16:20:47 -0500
commit9ab154658a7ff2c5076607e02f18581c6859fc2a (patch)
treeba24e4c4be11b9d61d290d1cd9423dd15eaf84c1
parentd0796d1ef63deb38147729664691ba3090930b26 (diff)
tipc: convert legacy nl bearer enable/disable to nl compat
Introduce a framework for transcoding legacy nl action into actions (.doit) calls from the new nl API. This is done by converting the incoming TLV data into netlink data with nested netlink attributes. Unfortunately due to the randomness of the legacy API we can't do this generically so each legacy netlink command requires a specific transcoding recipe. In this case for bearer enable and bearer disable. Convert TIPC_CMD_ENABLE_BEARER and TIPC_CMD_DISABLE_BEARER into doit compat calls. Signed-off-by: Richard Alpe <richard.alpe@ericsson.com> Reviewed-by: Erik Hugne <erik.hugne@ericsson.com> Reviewed-by: Ying Xue <ying.xue@windriver.com> Reviewed-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/uapi/linux/tipc_config.h5
-rw-r--r--net/tipc/bearer.c26
-rw-r--r--net/tipc/bearer.h3
-rw-r--r--net/tipc/config.c33
-rw-r--r--net/tipc/netlink_compat.c144
5 files changed, 154 insertions, 57 deletions
diff --git a/include/uapi/linux/tipc_config.h b/include/uapi/linux/tipc_config.h
index e1f4f05f4c5c..f9226566c1b8 100644
--- a/include/uapi/linux/tipc_config.h
+++ b/include/uapi/linux/tipc_config.h
@@ -277,6 +277,11 @@ static inline int TLV_GET_LEN(struct tlv_desc *tlv)
277 return ntohs(tlv->tlv_len); 277 return ntohs(tlv->tlv_len);
278} 278}
279 279
280static inline int TLV_CHECK_TYPE(struct tlv_desc *tlv, __u16 type)
281{
282 return (ntohs(tlv->tlv_type) == type);
283}
284
280static inline int TLV_SET(void *tlv, __u16 type, void *data, __u16 len) 285static inline int TLV_SET(void *tlv, __u16 type, void *data, __u16 len)
281{ 286{
282 struct tlv_desc *tlv_ptr; 287 struct tlv_desc *tlv_ptr;
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 7a9e29641e61..de1c800ef806 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -236,8 +236,8 @@ void tipc_bearer_remove_dest(struct net *net, u32 bearer_id, u32 dest)
236/** 236/**
237 * tipc_enable_bearer - enable bearer with the given name 237 * tipc_enable_bearer - enable bearer with the given name
238 */ 238 */
239int tipc_enable_bearer(struct net *net, const char *name, u32 disc_domain, 239static int tipc_enable_bearer(struct net *net, const char *name,
240 u32 priority) 240 u32 disc_domain, u32 priority)
241{ 241{
242 struct tipc_net *tn = net_generic(net, tipc_net_id); 242 struct tipc_net *tn = net_generic(net, tipc_net_id);
243 struct tipc_bearer *b_ptr; 243 struct tipc_bearer *b_ptr;
@@ -393,22 +393,6 @@ static void bearer_disable(struct net *net, struct tipc_bearer *b_ptr,
393 kfree_rcu(b_ptr, rcu); 393 kfree_rcu(b_ptr, rcu);
394} 394}
395 395
396int tipc_disable_bearer(struct net *net, const char *name)
397{
398 struct tipc_bearer *b_ptr;
399 int res;
400
401 b_ptr = tipc_bearer_find(net, name);
402 if (b_ptr == NULL) {
403 pr_warn("Attempt to disable unknown bearer <%s>\n", name);
404 res = -EINVAL;
405 } else {
406 bearer_disable(net, b_ptr, false);
407 res = 0;
408 }
409 return res;
410}
411
412int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b) 396int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b)
413{ 397{
414 struct net_device *dev; 398 struct net_device *dev;
@@ -756,7 +740,7 @@ int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
756 char *name; 740 char *name;
757 struct tipc_bearer *bearer; 741 struct tipc_bearer *bearer;
758 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1]; 742 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
759 struct net *net = genl_info_net(info); 743 struct net *net = sock_net(skb->sk);
760 744
761 if (!info->attrs[TIPC_NLA_BEARER]) 745 if (!info->attrs[TIPC_NLA_BEARER])
762 return -EINVAL; 746 return -EINVAL;
@@ -787,11 +771,11 @@ int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
787 771
788int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info) 772int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
789{ 773{
790 struct net *net = genl_info_net(info);
791 struct tipc_net *tn = net_generic(net, tipc_net_id);
792 int err; 774 int err;
793 char *bearer; 775 char *bearer;
794 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1]; 776 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
777 struct net *net = sock_net(skb->sk);
778 struct tipc_net *tn = net_generic(net, tipc_net_id);
795 u32 domain; 779 u32 domain;
796 u32 prio; 780 u32 prio;
797 781
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index 956858276d93..06f25d144871 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -173,9 +173,6 @@ struct tipc_bearer_names {
173 */ 173 */
174 174
175void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr); 175void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr);
176int tipc_enable_bearer(struct net *net, const char *bearer_name,
177 u32 disc_domain, u32 priority);
178int tipc_disable_bearer(struct net *net, const char *name);
179 176
180/* 177/*
181 * Routines made available to TIPC by supported media types 178 * Routines made available to TIPC by supported media types
diff --git a/net/tipc/config.c b/net/tipc/config.c
index 52e84b0ac48a..f8cd5e1b545f 100644
--- a/net/tipc/config.c
+++ b/net/tipc/config.c
@@ -134,33 +134,6 @@ static struct sk_buff *tipc_show_stats(void)
134 return buf; 134 return buf;
135} 135}
136 136
137static struct sk_buff *cfg_enable_bearer(struct net *net)
138{
139 struct tipc_bearer_config *args;
140
141 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_CONFIG))
142 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
143
144 args = (struct tipc_bearer_config *)TLV_DATA(req_tlv_area);
145 if (tipc_enable_bearer(net, args->name,
146 ntohl(args->disc_domain),
147 ntohl(args->priority)))
148 return tipc_cfg_reply_error_string("unable to enable bearer");
149
150 return tipc_cfg_reply_none();
151}
152
153static struct sk_buff *cfg_disable_bearer(struct net *net)
154{
155 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_NAME))
156 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
157
158 if (tipc_disable_bearer(net, (char *)TLV_DATA(req_tlv_area)))
159 return tipc_cfg_reply_error_string("unable to disable bearer");
160
161 return tipc_cfg_reply_none();
162}
163
164static struct sk_buff *cfg_set_own_addr(struct net *net) 137static struct sk_buff *cfg_set_own_addr(struct net *net)
165{ 138{
166 struct tipc_net *tn = net_generic(net, tipc_net_id); 139 struct tipc_net *tn = net_generic(net, tipc_net_id);
@@ -267,12 +240,6 @@ struct sk_buff *tipc_cfg_do_cmd(struct net *net, u32 orig_node, u16 cmd,
267 rep_tlv_buf = tipc_link_cmd_config(net, req_tlv_area, 240 rep_tlv_buf = tipc_link_cmd_config(net, req_tlv_area,
268 req_tlv_space, cmd); 241 req_tlv_space, cmd);
269 break; 242 break;
270 case TIPC_CMD_ENABLE_BEARER:
271 rep_tlv_buf = cfg_enable_bearer(net);
272 break;
273 case TIPC_CMD_DISABLE_BEARER:
274 rep_tlv_buf = cfg_disable_bearer(net);
275 break;
276 case TIPC_CMD_SET_NODE_ADDR: 243 case TIPC_CMD_SET_NODE_ADDR:
277 rep_tlv_buf = cfg_set_own_addr(net); 244 rep_tlv_buf = cfg_set_own_addr(net);
278 break; 245 break;
diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c
index bd75ea290e3a..12b0f4424797 100644
--- a/net/tipc/netlink_compat.c
+++ b/net/tipc/netlink_compat.c
@@ -49,6 +49,7 @@
49struct tipc_nl_compat_msg { 49struct tipc_nl_compat_msg {
50 u16 cmd; 50 u16 cmd;
51 int rep_size; 51 int rep_size;
52 int req_type;
52 struct sk_buff *rep; 53 struct sk_buff *rep;
53 struct tlv_desc *req; 54 struct tlv_desc *req;
54 struct sock *dst_sk; 55 struct sock *dst_sk;
@@ -59,6 +60,11 @@ struct tipc_nl_compat_cmd_dump {
59 int (*format)(struct tipc_nl_compat_msg *msg, struct nlattr **attrs); 60 int (*format)(struct tipc_nl_compat_msg *msg, struct nlattr **attrs);
60}; 61};
61 62
63struct tipc_nl_compat_cmd_doit {
64 int (*doit)(struct sk_buff *skb, struct genl_info *info);
65 int (*transcode)(struct sk_buff *skb, struct tipc_nl_compat_msg *msg);
66};
67
62static int tipc_skb_tailroom(struct sk_buff *skb) 68static int tipc_skb_tailroom(struct sk_buff *skb)
63{ 69{
64 int tailroom; 70 int tailroom;
@@ -213,6 +219,78 @@ static int tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,
213 return err; 219 return err;
214} 220}
215 221
222static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
223 struct tipc_nl_compat_msg *msg)
224{
225 int err;
226 struct sk_buff *doit_buf;
227 struct sk_buff *trans_buf;
228 struct nlattr **attrbuf;
229 struct genl_info info;
230
231 trans_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
232 if (!trans_buf)
233 return -ENOMEM;
234
235 err = (*cmd->transcode)(trans_buf, msg);
236 if (err)
237 goto trans_out;
238
239 attrbuf = kmalloc((tipc_genl_family.maxattr + 1) *
240 sizeof(struct nlattr *), GFP_KERNEL);
241 if (!attrbuf) {
242 err = -ENOMEM;
243 goto trans_out;
244 }
245
246 err = nla_parse(attrbuf, tipc_genl_family.maxattr,
247 (const struct nlattr *)trans_buf->data,
248 trans_buf->len, NULL);
249 if (err)
250 goto parse_out;
251
252 doit_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
253 if (!doit_buf) {
254 err = -ENOMEM;
255 goto parse_out;
256 }
257
258 doit_buf->sk = msg->dst_sk;
259
260 memset(&info, 0, sizeof(info));
261 info.attrs = attrbuf;
262
263 err = (*cmd->doit)(doit_buf, &info);
264
265 kfree_skb(doit_buf);
266parse_out:
267 kfree(attrbuf);
268trans_out:
269 kfree_skb(trans_buf);
270
271 return err;
272}
273
274static int tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
275 struct tipc_nl_compat_msg *msg)
276{
277 int err;
278
279 if (msg->req_type && !TLV_CHECK_TYPE(msg->req, msg->req_type))
280 return -EINVAL;
281
282 err = __tipc_nl_compat_doit(cmd, msg);
283 if (err)
284 return err;
285
286 /* The legacy API considered an empty message a success message */
287 msg->rep = tipc_tlv_alloc(0);
288 if (!msg->rep)
289 return -ENOMEM;
290
291 return 0;
292}
293
216static int tipc_nl_compat_bearer_dump(struct tipc_nl_compat_msg *msg, 294static int tipc_nl_compat_bearer_dump(struct tipc_nl_compat_msg *msg,
217 struct nlattr **attrs) 295 struct nlattr **attrs)
218{ 296{
@@ -226,11 +304,65 @@ static int tipc_nl_compat_bearer_dump(struct tipc_nl_compat_msg *msg,
226 nla_len(bearer[TIPC_NLA_BEARER_NAME])); 304 nla_len(bearer[TIPC_NLA_BEARER_NAME]));
227} 305}
228 306
307static int tipc_nl_compat_bearer_enable(struct sk_buff *skb,
308 struct tipc_nl_compat_msg *msg)
309{
310 struct nlattr *prop;
311 struct nlattr *bearer;
312 struct tipc_bearer_config *b;
313
314 b = (struct tipc_bearer_config *)TLV_DATA(msg->req);
315
316 bearer = nla_nest_start(skb, TIPC_NLA_BEARER);
317 if (!bearer)
318 return -EMSGSIZE;
319
320 if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, b->name))
321 return -EMSGSIZE;
322
323 if (nla_put_u32(skb, TIPC_NLA_BEARER_DOMAIN, ntohl(b->disc_domain)))
324 return -EMSGSIZE;
325
326 if (ntohl(b->priority) <= TIPC_MAX_LINK_PRI) {
327 prop = nla_nest_start(skb, TIPC_NLA_BEARER_PROP);
328 if (!prop)
329 return -EMSGSIZE;
330 if (nla_put_u32(skb, TIPC_NLA_PROP_PRIO, ntohl(b->priority)))
331 return -EMSGSIZE;
332 nla_nest_end(skb, prop);
333 }
334 nla_nest_end(skb, bearer);
335
336 return 0;
337}
338
339static int tipc_nl_compat_bearer_disable(struct sk_buff *skb,
340 struct tipc_nl_compat_msg *msg)
341{
342 char *name;
343 struct nlattr *bearer;
344
345 name = (char *)TLV_DATA(msg->req);
346
347 bearer = nla_nest_start(skb, TIPC_NLA_BEARER);
348 if (!bearer)
349 return -EMSGSIZE;
350
351 if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, name))
352 return -EMSGSIZE;
353
354 nla_nest_end(skb, bearer);
355
356 return 0;
357}
358
229static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg) 359static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg)
230{ 360{
231 struct tipc_nl_compat_cmd_dump dump; 361 struct tipc_nl_compat_cmd_dump dump;
362 struct tipc_nl_compat_cmd_doit doit;
232 363
233 memset(&dump, 0, sizeof(dump)); 364 memset(&dump, 0, sizeof(dump));
365 memset(&doit, 0, sizeof(doit));
234 366
235 switch (msg->cmd) { 367 switch (msg->cmd) {
236 case TIPC_CMD_GET_BEARER_NAMES: 368 case TIPC_CMD_GET_BEARER_NAMES:
@@ -238,6 +370,16 @@ static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg)
238 dump.dumpit = tipc_nl_bearer_dump; 370 dump.dumpit = tipc_nl_bearer_dump;
239 dump.format = tipc_nl_compat_bearer_dump; 371 dump.format = tipc_nl_compat_bearer_dump;
240 return tipc_nl_compat_dumpit(&dump, msg); 372 return tipc_nl_compat_dumpit(&dump, msg);
373 case TIPC_CMD_ENABLE_BEARER:
374 msg->req_type = TIPC_TLV_BEARER_CONFIG;
375 doit.doit = tipc_nl_bearer_enable;
376 doit.transcode = tipc_nl_compat_bearer_enable;
377 return tipc_nl_compat_doit(&doit, msg);
378 case TIPC_CMD_DISABLE_BEARER:
379 msg->req_type = TIPC_TLV_BEARER_NAME;
380 doit.doit = tipc_nl_bearer_disable;
381 doit.transcode = tipc_nl_compat_bearer_disable;
382 return tipc_nl_compat_doit(&doit, msg);
241 } 383 }
242 384
243 return -EOPNOTSUPP; 385 return -EOPNOTSUPP;
@@ -335,6 +477,8 @@ static int tipc_nl_compat_tmp_wrap(struct sk_buff *skb, struct genl_info *info)
335 477
336 switch (req->cmd) { 478 switch (req->cmd) {
337 case TIPC_CMD_GET_BEARER_NAMES: 479 case TIPC_CMD_GET_BEARER_NAMES:
480 case TIPC_CMD_ENABLE_BEARER:
481 case TIPC_CMD_DISABLE_BEARER:
338 return tipc_nl_compat_recv(skb, info); 482 return tipc_nl_compat_recv(skb, info);
339 } 483 }
340 484