1 /* Copyright (C) 2016 B.A.T.M.A.N. contributors:
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU General Public
7 * License as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include <linux/errno.h>
23 #include <linux/genetlink.h>
24 #include <linux/if_ether.h>
25 #include <linux/init.h>
26 #include <linux/netdevice.h>
27 #include <linux/netlink.h>
28 #include <linux/printk.h>
29 #include <linux/stddef.h>
30 #include <linux/types.h>
31 #include <net/genetlink.h>
32 #include <net/netlink.h>
33 #include <uapi/linux/batman_adv.h>
35 #include "hard-interface.h"
36 #include "soft-interface.h"
41 static struct genl_family batadv_netlink_family
= {
42 .id
= GENL_ID_GENERATE
,
44 .name
= BATADV_NL_NAME
,
46 .maxattr
= BATADV_ATTR_MAX
,
49 /* multicast groups */
50 enum batadv_netlink_multicast_groups
{
51 BATADV_NL_MCGRP_TPMETER
,
54 static struct genl_multicast_group batadv_netlink_mcgrps
[] = {
55 [BATADV_NL_MCGRP_TPMETER
] = { .name
= BATADV_NL_MCAST_GROUP_TPMETER
},
58 static struct nla_policy batadv_netlink_policy
[NUM_BATADV_ATTR
] = {
59 [BATADV_ATTR_VERSION
] = { .type
= NLA_STRING
},
60 [BATADV_ATTR_ALGO_NAME
] = { .type
= NLA_STRING
},
61 [BATADV_ATTR_MESH_IFINDEX
] = { .type
= NLA_U32
},
62 [BATADV_ATTR_MESH_IFNAME
] = { .type
= NLA_STRING
},
63 [BATADV_ATTR_MESH_ADDRESS
] = { .len
= ETH_ALEN
},
64 [BATADV_ATTR_HARD_IFINDEX
] = { .type
= NLA_U32
},
65 [BATADV_ATTR_HARD_IFNAME
] = { .type
= NLA_STRING
},
66 [BATADV_ATTR_HARD_ADDRESS
] = { .len
= ETH_ALEN
},
67 [BATADV_ATTR_ORIG_ADDRESS
] = { .len
= ETH_ALEN
},
68 [BATADV_ATTR_TPMETER_RESULT
] = { .type
= NLA_U8
},
69 [BATADV_ATTR_TPMETER_TEST_TIME
] = { .type
= NLA_U32
},
70 [BATADV_ATTR_TPMETER_BYTES
] = { .type
= NLA_U64
},
71 [BATADV_ATTR_TPMETER_COOKIE
] = { .type
= NLA_U32
},
75 * batadv_netlink_mesh_info_put - fill in generic information about mesh
77 * @msg: netlink message to be sent back
78 * @soft_iface: interface for which the data should be taken
80 * Return: 0 on success, < 0 on error
83 batadv_netlink_mesh_info_put(struct sk_buff
*msg
, struct net_device
*soft_iface
)
85 struct batadv_priv
*bat_priv
= netdev_priv(soft_iface
);
86 struct batadv_hard_iface
*primary_if
= NULL
;
87 struct net_device
*hard_iface
;
90 if (nla_put_string(msg
, BATADV_ATTR_VERSION
, BATADV_SOURCE_VERSION
) ||
91 nla_put_string(msg
, BATADV_ATTR_ALGO_NAME
,
92 bat_priv
->algo_ops
->name
) ||
93 nla_put_u32(msg
, BATADV_ATTR_MESH_IFINDEX
, soft_iface
->ifindex
) ||
94 nla_put_string(msg
, BATADV_ATTR_MESH_IFNAME
, soft_iface
->name
) ||
95 nla_put(msg
, BATADV_ATTR_MESH_ADDRESS
, ETH_ALEN
,
96 soft_iface
->dev_addr
))
99 primary_if
= batadv_primary_if_get_selected(bat_priv
);
100 if (primary_if
&& primary_if
->if_status
== BATADV_IF_ACTIVE
) {
101 hard_iface
= primary_if
->net_dev
;
103 if (nla_put_u32(msg
, BATADV_ATTR_HARD_IFINDEX
,
104 hard_iface
->ifindex
) ||
105 nla_put_string(msg
, BATADV_ATTR_HARD_IFNAME
,
107 nla_put(msg
, BATADV_ATTR_HARD_ADDRESS
, ETH_ALEN
,
108 hard_iface
->dev_addr
))
116 batadv_hardif_put(primary_if
);
122 * batadv_netlink_get_mesh_info - handle incoming BATADV_CMD_GET_MESH_INFO
124 * @skb: received netlink message
125 * @info: receiver information
127 * Return: 0 on success, < 0 on error
130 batadv_netlink_get_mesh_info(struct sk_buff
*skb
, struct genl_info
*info
)
132 struct net
*net
= genl_info_net(info
);
133 struct net_device
*soft_iface
;
134 struct sk_buff
*msg
= NULL
;
139 if (!info
->attrs
[BATADV_ATTR_MESH_IFINDEX
])
142 ifindex
= nla_get_u32(info
->attrs
[BATADV_ATTR_MESH_IFINDEX
]);
146 soft_iface
= dev_get_by_index(net
, ifindex
);
147 if (!soft_iface
|| !batadv_softif_is_valid(soft_iface
)) {
152 msg
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
158 msg_head
= genlmsg_put(msg
, info
->snd_portid
, info
->snd_seq
,
159 &batadv_netlink_family
, 0,
160 BATADV_CMD_GET_MESH_INFO
);
166 ret
= batadv_netlink_mesh_info_put(msg
, soft_iface
);
178 genlmsg_end(msg
, msg_head
);
179 return genlmsg_reply(msg
, info
);
183 * batadv_netlink_tp_meter_put - Fill information of started tp_meter session
184 * @msg: netlink message to be sent back
185 * @cookie: tp meter session cookie
187 * Return: 0 on success, < 0 on error
190 batadv_netlink_tp_meter_put(struct sk_buff
*msg
, u32 cookie
)
192 if (nla_put_u32(msg
, BATADV_ATTR_TPMETER_COOKIE
, cookie
))
199 * batadv_netlink_tpmeter_notify - send tp_meter result via netlink to client
200 * @bat_priv: the bat priv with all the soft interface information
201 * @dst: destination of tp_meter session
202 * @result: reason for tp meter session stop
203 * @test_time: total time ot the tp_meter session
204 * @total_bytes: bytes acked to the receiver
205 * @cookie: cookie of tp_meter session
207 * Return: 0 on success, < 0 on error
209 int batadv_netlink_tpmeter_notify(struct batadv_priv
*bat_priv
, const u8
*dst
,
210 u8 result
, u32 test_time
, u64 total_bytes
,
217 msg
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
221 hdr
= genlmsg_put(msg
, 0, 0, &batadv_netlink_family
, 0,
222 BATADV_CMD_TP_METER
);
228 if (nla_put_u32(msg
, BATADV_ATTR_TPMETER_COOKIE
, cookie
))
229 goto nla_put_failure
;
231 if (nla_put_u32(msg
, BATADV_ATTR_TPMETER_TEST_TIME
, test_time
))
232 goto nla_put_failure
;
234 if (nla_put_u64_64bit(msg
, BATADV_ATTR_TPMETER_BYTES
, total_bytes
,
236 goto nla_put_failure
;
238 if (nla_put_u8(msg
, BATADV_ATTR_TPMETER_RESULT
, result
))
239 goto nla_put_failure
;
241 if (nla_put(msg
, BATADV_ATTR_ORIG_ADDRESS
, ETH_ALEN
, dst
))
242 goto nla_put_failure
;
244 genlmsg_end(msg
, hdr
);
246 genlmsg_multicast_netns(&batadv_netlink_family
,
247 dev_net(bat_priv
->soft_iface
), msg
, 0,
248 BATADV_NL_MCGRP_TPMETER
, GFP_KERNEL
);
253 genlmsg_cancel(msg
, hdr
);
262 * batadv_netlink_tp_meter_start - Start a new tp_meter session
263 * @skb: received netlink message
264 * @info: receiver information
266 * Return: 0 on success, < 0 on error
269 batadv_netlink_tp_meter_start(struct sk_buff
*skb
, struct genl_info
*info
)
271 struct net
*net
= genl_info_net(info
);
272 struct net_device
*soft_iface
;
273 struct batadv_priv
*bat_priv
;
274 struct sk_buff
*msg
= NULL
;
282 if (!info
->attrs
[BATADV_ATTR_MESH_IFINDEX
])
285 if (!info
->attrs
[BATADV_ATTR_ORIG_ADDRESS
])
288 if (!info
->attrs
[BATADV_ATTR_TPMETER_TEST_TIME
])
291 ifindex
= nla_get_u32(info
->attrs
[BATADV_ATTR_MESH_IFINDEX
]);
295 dst
= nla_data(info
->attrs
[BATADV_ATTR_ORIG_ADDRESS
]);
297 test_length
= nla_get_u32(info
->attrs
[BATADV_ATTR_TPMETER_TEST_TIME
]);
299 soft_iface
= dev_get_by_index(net
, ifindex
);
300 if (!soft_iface
|| !batadv_softif_is_valid(soft_iface
)) {
305 msg
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
311 msg_head
= genlmsg_put(msg
, info
->snd_portid
, info
->snd_seq
,
312 &batadv_netlink_family
, 0,
313 BATADV_CMD_TP_METER
);
319 bat_priv
= netdev_priv(soft_iface
);
320 batadv_tp_start(bat_priv
, dst
, test_length
, &cookie
);
322 ret
= batadv_netlink_tp_meter_put(msg
, cookie
);
334 genlmsg_end(msg
, msg_head
);
335 return genlmsg_reply(msg
, info
);
339 * batadv_netlink_tp_meter_start - Cancel a running tp_meter session
340 * @skb: received netlink message
341 * @info: receiver information
343 * Return: 0 on success, < 0 on error
346 batadv_netlink_tp_meter_cancel(struct sk_buff
*skb
, struct genl_info
*info
)
348 struct net
*net
= genl_info_net(info
);
349 struct net_device
*soft_iface
;
350 struct batadv_priv
*bat_priv
;
355 if (!info
->attrs
[BATADV_ATTR_MESH_IFINDEX
])
358 if (!info
->attrs
[BATADV_ATTR_ORIG_ADDRESS
])
361 ifindex
= nla_get_u32(info
->attrs
[BATADV_ATTR_MESH_IFINDEX
]);
365 dst
= nla_data(info
->attrs
[BATADV_ATTR_ORIG_ADDRESS
]);
367 soft_iface
= dev_get_by_index(net
, ifindex
);
368 if (!soft_iface
|| !batadv_softif_is_valid(soft_iface
)) {
373 bat_priv
= netdev_priv(soft_iface
);
374 batadv_tp_stop(bat_priv
, dst
, BATADV_TP_REASON_CANCEL
);
383 static struct genl_ops batadv_netlink_ops
[] = {
385 .cmd
= BATADV_CMD_GET_MESH_INFO
,
386 .flags
= GENL_ADMIN_PERM
,
387 .policy
= batadv_netlink_policy
,
388 .doit
= batadv_netlink_get_mesh_info
,
391 .cmd
= BATADV_CMD_TP_METER
,
392 .flags
= GENL_ADMIN_PERM
,
393 .policy
= batadv_netlink_policy
,
394 .doit
= batadv_netlink_tp_meter_start
,
397 .cmd
= BATADV_CMD_TP_METER_CANCEL
,
398 .flags
= GENL_ADMIN_PERM
,
399 .policy
= batadv_netlink_policy
,
400 .doit
= batadv_netlink_tp_meter_cancel
,
405 * batadv_netlink_register - register batadv genl netlink family
407 void __init
batadv_netlink_register(void)
411 ret
= genl_register_family_with_ops_groups(&batadv_netlink_family
,
413 batadv_netlink_mcgrps
);
415 pr_warn("unable to register netlink family");
419 * batadv_netlink_unregister - unregister batadv genl netlink family
421 void batadv_netlink_unregister(void)
423 genl_unregister_family(&batadv_netlink_family
);