1 /* Copyright (C) 2016 B.A.T.M.A.N. contributors: 2 * 3 * Matthias Schiffer 4 * 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. 8 * 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. 13 * 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/>. 16 */ 17 18 #include "netlink.h" 19 #include "main.h" 20 21 #include <linux/errno.h> 22 #include <linux/fs.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> 34 35 #include "hard-interface.h" 36 #include "soft-interface.h" 37 #include "tp_meter.h" 38 39 struct sk_buff; 40 41 static struct genl_family batadv_netlink_family = { 42 .id = GENL_ID_GENERATE, 43 .hdrsize = 0, 44 .name = BATADV_NL_NAME, 45 .version = 1, 46 .maxattr = BATADV_ATTR_MAX, 47 }; 48 49 /* multicast groups */ 50 enum batadv_netlink_multicast_groups { 51 BATADV_NL_MCGRP_TPMETER, 52 }; 53 54 static struct genl_multicast_group batadv_netlink_mcgrps[] = { 55 [BATADV_NL_MCGRP_TPMETER] = { .name = BATADV_NL_MCAST_GROUP_TPMETER }, 56 }; 57 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 }, 72 }; 73 74 /** 75 * batadv_netlink_mesh_info_put - fill in generic information about mesh 76 * interface 77 * @msg: netlink message to be sent back 78 * @soft_iface: interface for which the data should be taken 79 * 80 * Return: 0 on success, < 0 on error 81 */ 82 static int 83 batadv_netlink_mesh_info_put(struct sk_buff *msg, struct net_device *soft_iface) 84 { 85 struct batadv_priv *bat_priv = netdev_priv(soft_iface); 86 struct batadv_hard_iface *primary_if = NULL; 87 struct net_device *hard_iface; 88 int ret = -ENOBUFS; 89 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)) 97 goto out; 98 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; 102 103 if (nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, 104 hard_iface->ifindex) || 105 nla_put_string(msg, BATADV_ATTR_HARD_IFNAME, 106 hard_iface->name) || 107 nla_put(msg, BATADV_ATTR_HARD_ADDRESS, ETH_ALEN, 108 hard_iface->dev_addr)) 109 goto out; 110 } 111 112 ret = 0; 113 114 out: 115 if (primary_if) 116 batadv_hardif_put(primary_if); 117 118 return ret; 119 } 120 121 /** 122 * batadv_netlink_get_mesh_info - handle incoming BATADV_CMD_GET_MESH_INFO 123 * netlink request 124 * @skb: received netlink message 125 * @info: receiver information 126 * 127 * Return: 0 on success, < 0 on error 128 */ 129 static int 130 batadv_netlink_get_mesh_info(struct sk_buff *skb, struct genl_info *info) 131 { 132 struct net *net = genl_info_net(info); 133 struct net_device *soft_iface; 134 struct sk_buff *msg = NULL; 135 void *msg_head; 136 int ifindex; 137 int ret; 138 139 if (!info->attrs[BATADV_ATTR_MESH_IFINDEX]) 140 return -EINVAL; 141 142 ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]); 143 if (!ifindex) 144 return -EINVAL; 145 146 soft_iface = dev_get_by_index(net, ifindex); 147 if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { 148 ret = -ENODEV; 149 goto out; 150 } 151 152 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 153 if (!msg) { 154 ret = -ENOMEM; 155 goto out; 156 } 157 158 msg_head = genlmsg_put(msg, info->snd_portid, info->snd_seq, 159 &batadv_netlink_family, 0, 160 BATADV_CMD_GET_MESH_INFO); 161 if (!msg_head) { 162 ret = -ENOBUFS; 163 goto out; 164 } 165 166 ret = batadv_netlink_mesh_info_put(msg, soft_iface); 167 168 out: 169 if (soft_iface) 170 dev_put(soft_iface); 171 172 if (ret) { 173 if (msg) 174 nlmsg_free(msg); 175 return ret; 176 } 177 178 genlmsg_end(msg, msg_head); 179 return genlmsg_reply(msg, info); 180 } 181 182 /** 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 186 * 187 * Return: 0 on success, < 0 on error 188 */ 189 static int 190 batadv_netlink_tp_meter_put(struct sk_buff *msg, u32 cookie) 191 { 192 if (nla_put_u32(msg, BATADV_ATTR_TPMETER_COOKIE, cookie)) 193 return -ENOBUFS; 194 195 return 0; 196 } 197 198 /** 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 206 * 207 * Return: 0 on success, < 0 on error 208 */ 209 int batadv_netlink_tpmeter_notify(struct batadv_priv *bat_priv, const u8 *dst, 210 u8 result, u32 test_time, u64 total_bytes, 211 u32 cookie) 212 { 213 struct sk_buff *msg; 214 void *hdr; 215 int ret; 216 217 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 218 if (!msg) 219 return -ENOMEM; 220 221 hdr = genlmsg_put(msg, 0, 0, &batadv_netlink_family, 0, 222 BATADV_CMD_TP_METER); 223 if (!hdr) { 224 ret = -ENOBUFS; 225 goto err_genlmsg; 226 } 227 228 if (nla_put_u32(msg, BATADV_ATTR_TPMETER_COOKIE, cookie)) 229 goto nla_put_failure; 230 231 if (nla_put_u32(msg, BATADV_ATTR_TPMETER_TEST_TIME, test_time)) 232 goto nla_put_failure; 233 234 if (nla_put_u64_64bit(msg, BATADV_ATTR_TPMETER_BYTES, total_bytes, 235 BATADV_ATTR_PAD)) 236 goto nla_put_failure; 237 238 if (nla_put_u8(msg, BATADV_ATTR_TPMETER_RESULT, result)) 239 goto nla_put_failure; 240 241 if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, dst)) 242 goto nla_put_failure; 243 244 genlmsg_end(msg, hdr); 245 246 genlmsg_multicast_netns(&batadv_netlink_family, 247 dev_net(bat_priv->soft_iface), msg, 0, 248 BATADV_NL_MCGRP_TPMETER, GFP_KERNEL); 249 250 return 0; 251 252 nla_put_failure: 253 genlmsg_cancel(msg, hdr); 254 ret = -EMSGSIZE; 255 256 err_genlmsg: 257 nlmsg_free(msg); 258 return ret; 259 } 260 261 /** 262 * batadv_netlink_tp_meter_start - Start a new tp_meter session 263 * @skb: received netlink message 264 * @info: receiver information 265 * 266 * Return: 0 on success, < 0 on error 267 */ 268 static int 269 batadv_netlink_tp_meter_start(struct sk_buff *skb, struct genl_info *info) 270 { 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; 275 u32 test_length; 276 void *msg_head; 277 int ifindex; 278 u32 cookie; 279 u8 *dst; 280 int ret; 281 282 if (!info->attrs[BATADV_ATTR_MESH_IFINDEX]) 283 return -EINVAL; 284 285 if (!info->attrs[BATADV_ATTR_ORIG_ADDRESS]) 286 return -EINVAL; 287 288 if (!info->attrs[BATADV_ATTR_TPMETER_TEST_TIME]) 289 return -EINVAL; 290 291 ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]); 292 if (!ifindex) 293 return -EINVAL; 294 295 dst = nla_data(info->attrs[BATADV_ATTR_ORIG_ADDRESS]); 296 297 test_length = nla_get_u32(info->attrs[BATADV_ATTR_TPMETER_TEST_TIME]); 298 299 soft_iface = dev_get_by_index(net, ifindex); 300 if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { 301 ret = -ENODEV; 302 goto out; 303 } 304 305 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 306 if (!msg) { 307 ret = -ENOMEM; 308 goto out; 309 } 310 311 msg_head = genlmsg_put(msg, info->snd_portid, info->snd_seq, 312 &batadv_netlink_family, 0, 313 BATADV_CMD_TP_METER); 314 if (!msg_head) { 315 ret = -ENOBUFS; 316 goto out; 317 } 318 319 bat_priv = netdev_priv(soft_iface); 320 batadv_tp_start(bat_priv, dst, test_length, &cookie); 321 322 ret = batadv_netlink_tp_meter_put(msg, cookie); 323 324 out: 325 if (soft_iface) 326 dev_put(soft_iface); 327 328 if (ret) { 329 if (msg) 330 nlmsg_free(msg); 331 return ret; 332 } 333 334 genlmsg_end(msg, msg_head); 335 return genlmsg_reply(msg, info); 336 } 337 338 /** 339 * batadv_netlink_tp_meter_start - Cancel a running tp_meter session 340 * @skb: received netlink message 341 * @info: receiver information 342 * 343 * Return: 0 on success, < 0 on error 344 */ 345 static int 346 batadv_netlink_tp_meter_cancel(struct sk_buff *skb, struct genl_info *info) 347 { 348 struct net *net = genl_info_net(info); 349 struct net_device *soft_iface; 350 struct batadv_priv *bat_priv; 351 int ifindex; 352 u8 *dst; 353 int ret = 0; 354 355 if (!info->attrs[BATADV_ATTR_MESH_IFINDEX]) 356 return -EINVAL; 357 358 if (!info->attrs[BATADV_ATTR_ORIG_ADDRESS]) 359 return -EINVAL; 360 361 ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]); 362 if (!ifindex) 363 return -EINVAL; 364 365 dst = nla_data(info->attrs[BATADV_ATTR_ORIG_ADDRESS]); 366 367 soft_iface = dev_get_by_index(net, ifindex); 368 if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { 369 ret = -ENODEV; 370 goto out; 371 } 372 373 bat_priv = netdev_priv(soft_iface); 374 batadv_tp_stop(bat_priv, dst, BATADV_TP_REASON_CANCEL); 375 376 out: 377 if (soft_iface) 378 dev_put(soft_iface); 379 380 return ret; 381 } 382 383 static struct genl_ops batadv_netlink_ops[] = { 384 { 385 .cmd = BATADV_CMD_GET_MESH_INFO, 386 .flags = GENL_ADMIN_PERM, 387 .policy = batadv_netlink_policy, 388 .doit = batadv_netlink_get_mesh_info, 389 }, 390 { 391 .cmd = BATADV_CMD_TP_METER, 392 .flags = GENL_ADMIN_PERM, 393 .policy = batadv_netlink_policy, 394 .doit = batadv_netlink_tp_meter_start, 395 }, 396 { 397 .cmd = BATADV_CMD_TP_METER_CANCEL, 398 .flags = GENL_ADMIN_PERM, 399 .policy = batadv_netlink_policy, 400 .doit = batadv_netlink_tp_meter_cancel, 401 }, 402 }; 403 404 /** 405 * batadv_netlink_register - register batadv genl netlink family 406 */ 407 void __init batadv_netlink_register(void) 408 { 409 int ret; 410 411 ret = genl_register_family_with_ops_groups(&batadv_netlink_family, 412 batadv_netlink_ops, 413 batadv_netlink_mcgrps); 414 if (ret) 415 pr_warn("unable to register netlink family"); 416 } 417 418 /** 419 * batadv_netlink_unregister - unregister batadv genl netlink family 420 */ 421 void batadv_netlink_unregister(void) 422 { 423 genl_unregister_family(&batadv_netlink_family); 424 } 425