1 /* 2 * Copyright (c) 2011, 2017-2018 The Linux Foundation. All rights reserved. 3 * 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <os_if_spectral_netlink.h> 21 #include <spectral_cmn_api_i.h> 22 #include <spectral_defs_i.h> 23 #include <wlan_nlink_srv.h> 24 #include <wlan_nlink_common.h> 25 #include <qdf_module.h> 26 #ifdef CNSS_GENL 27 #include <net/cnss_nl.h> 28 #endif 29 30 /** 31 * os_if_spectral_remove_nbuf_debug_entry() - Remove nbuf from nbuf debug table 32 * @nbuf - nbuf to remove from the nbuf debug table 33 * 34 * Remove nbuf from the nbuf debug hash table and decrement the nbuf count 35 * 36 * Return: None 37 */ 38 static inline void os_if_spectral_remove_nbuf_debug_entry(qdf_nbuf_t nbuf) 39 { 40 qdf_nbuf_count_dec(nbuf); 41 qdf_net_buf_debug_release_skb(nbuf); 42 } 43 44 #ifndef CNSS_GENL 45 static struct sock *os_if_spectral_nl_sock; 46 static atomic_t spectral_nl_users = ATOMIC_INIT(0); 47 #endif 48 49 #if (KERNEL_VERSION(2, 6, 31) > LINUX_VERSION_CODE) 50 void 51 os_if_spectral_nl_data_ready(struct sock *sk, int len) 52 { 53 spectral_debug("%d", __LINE__); 54 } 55 56 #else 57 void 58 os_if_spectral_nl_data_ready(struct sk_buff *skb) 59 { 60 spectral_debug("%d", __LINE__); 61 } 62 #endif /* VERSION */ 63 64 #ifndef CNSS_GENL 65 /** 66 * os_if_spectral_init_nl_cfg() - Initialize netlink kernel 67 * configuration parameters 68 * @cfg : Pointer to netlink_kernel_cfg 69 * 70 * Initialize netlink kernel configuration parameters required 71 * for spectral module 72 * 73 * Return: None 74 */ 75 #if KERNEL_VERSION(3, 6, 0) <= LINUX_VERSION_CODE 76 static void 77 os_if_spectral_init_nl_cfg(struct netlink_kernel_cfg *cfg) 78 { 79 cfg->groups = 1; 80 cfg->input = os_if_spectral_nl_data_ready; 81 } 82 #else 83 static void 84 os_if_spectral_init_nl_cfg(struct netlink_kernel_cfg *cfg) 85 { 86 } 87 #endif 88 /** 89 * os_if_spectral_create_nl_sock() - Create Netlink socket 90 * @cfg : Pointer to netlink_kernel_cfg 91 * 92 * Create Netlink socket required for spectral module 93 * 94 * Return: None 95 */ 96 #if KERNEL_VERSION(3, 7, 0) <= LINUX_VERSION_CODE 97 static void 98 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg) 99 { 100 os_if_spectral_nl_sock = 101 (struct sock *)netlink_kernel_create(&init_net, 102 SPECTRAL_NETLINK, cfg); 103 } 104 #elif KERNEL_VERSION(3, 6, 0) <= LINUX_VERSION_CODE 105 static void 106 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg) 107 { 108 os_if_spectral_nl_sock = 109 (struct sock *)netlink_kernel_create(&init_net, 110 SPECTRAL_NETLINK, 111 THIS_MODULE, cfg); 112 } 113 #elif (KERNEL_VERSION(2, 6, 31) > LINUX_VERSION_CODE) 114 static void 115 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg) 116 { 117 os_if_spectral_nl_sock = 118 (struct sock *)netlink_kernel_create( 119 SPECTRAL_NETLINK, 1, 120 &os_if_spectral_nl_data_ready, 121 THIS_MODULE); 122 } 123 #else 124 #if (KERNEL_VERSION(3, 10, 0) <= LINUX_VERSION_CODE) 125 static void 126 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg) 127 { 128 memset(cfg, 0, sizeof(*cfg)); 129 cfg->groups = 1; 130 cfg->input = &os_if_spectral_nl_data_ready; 131 os_if_spectral_nl_sock = 132 (struct sock *)netlink_kernel_create(&init_net, 133 SPECTRAL_NETLINK, cfg); 134 } 135 #else 136 static void 137 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg) 138 { 139 os_if_spectral_nl_sock = 140 (struct sock *)netlink_kernel_create( 141 &init_net, 142 SPECTRAL_NETLINK, 1, 143 &os_if_spectral_nl_data_ready, 144 NULL, THIS_MODULE); 145 } 146 #endif 147 #endif 148 149 /** 150 * os_if_spectral_init_nl() - Initialize netlink data structures for 151 * spectral module 152 * @pdev : Pointer to pdev 153 * 154 * Return: 0 on success else failure 155 */ 156 static int 157 os_if_spectral_init_nl(struct wlan_objmgr_pdev *pdev) 158 { 159 struct pdev_spectral *ps = NULL; 160 struct netlink_kernel_cfg cfg; 161 162 memset(&cfg, 0, sizeof(cfg)); 163 if (!pdev) { 164 spectral_err("PDEV is NULL!"); 165 return -EINVAL; 166 } 167 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 168 WLAN_UMAC_COMP_SPECTRAL); 169 170 if (!ps) { 171 spectral_err("PDEV SPECTRAL object is NULL!"); 172 return -EINVAL; 173 } 174 os_if_spectral_init_nl_cfg(&cfg); 175 176 if (!os_if_spectral_nl_sock) { 177 os_if_spectral_create_nl_sock(&cfg); 178 179 if (!os_if_spectral_nl_sock) { 180 spectral_err("NETLINK_KERNEL_CREATE FAILED"); 181 return -ENODEV; 182 } 183 } 184 ps->spectral_sock = os_if_spectral_nl_sock; 185 186 if (!ps->spectral_sock) { 187 spectral_err("ps->spectral_sock is NULL"); 188 return -ENODEV; 189 } 190 atomic_inc(&spectral_nl_users); 191 192 return 0; 193 } 194 195 /** 196 * os_if_spectral_destroy_netlink() - De-initialize netlink data structures for 197 * spectral module 198 * @pdev : Pointer to pdev 199 * 200 * Return: Success/Failure 201 */ 202 static int 203 os_if_spectral_destroy_netlink(struct wlan_objmgr_pdev *pdev) 204 { 205 struct pdev_spectral *ps = NULL; 206 207 if (!pdev) { 208 spectral_err("PDEV is NULL!"); 209 return -EINVAL; 210 } 211 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 212 WLAN_UMAC_COMP_SPECTRAL); 213 214 if (!ps) { 215 spectral_err("PDEV SPECTRAL object is NULL!"); 216 return -EINVAL; 217 } 218 ps->spectral_sock = NULL; 219 if (atomic_dec_and_test(&spectral_nl_users)) { 220 sock_release(os_if_spectral_nl_sock->sk_socket); 221 os_if_spectral_nl_sock = NULL; 222 } 223 return 0; 224 } 225 #else 226 227 static int 228 os_if_spectral_init_nl(struct wlan_objmgr_pdev *pdev) 229 { 230 return 0; 231 } 232 233 static int 234 os_if_spectral_destroy_netlink(struct wlan_objmgr_pdev *pdev) 235 { 236 return 0; 237 } 238 #endif 239 240 void * 241 os_if_spectral_prep_skb(struct wlan_objmgr_pdev *pdev) 242 { 243 struct pdev_spectral *ps = NULL; 244 struct nlmsghdr *spectral_nlh = NULL; 245 246 if (!pdev) { 247 spectral_err("PDEV is NULL!"); 248 return NULL; 249 } 250 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 251 WLAN_UMAC_COMP_SPECTRAL); 252 253 if (!ps) { 254 spectral_err("PDEV SPECTRAL object is NULL!"); 255 return NULL; 256 } 257 ps->skb = qdf_nbuf_alloc(NULL, MAX_SPECTRAL_PAYLOAD, 0, 0, false); 258 259 if (!ps->skb) { 260 spectral_err("allocate skb (len=%u) failed", 261 MAX_SPECTRAL_PAYLOAD); 262 return NULL; 263 } 264 265 qdf_nbuf_put_tail(ps->skb, MAX_SPECTRAL_PAYLOAD); 266 spectral_nlh = (struct nlmsghdr *)ps->skb->data; 267 268 qdf_mem_zero(spectral_nlh, sizeof(*spectral_nlh)); 269 270 /* 271 * Possible bug that size of struct spectral_samp_msg and 272 * SPECTRAL_MSG differ by 3 bytes so we miss 3 bytes 273 */ 274 275 spectral_nlh->nlmsg_len = NLMSG_SPACE(sizeof(struct spectral_samp_msg)); 276 spectral_nlh->nlmsg_pid = 0; 277 spectral_nlh->nlmsg_flags = 0; 278 spectral_nlh->nlmsg_type = WLAN_NL_MSG_SPECTRAL_SCAN; 279 280 qdf_mem_zero(NLMSG_DATA(spectral_nlh), 281 sizeof(struct spectral_samp_msg)); 282 return NLMSG_DATA(spectral_nlh); 283 } 284 285 #if (KERNEL_VERSION(2, 6, 31) > LINUX_VERSION_CODE) 286 static inline void 287 os_if_init_spectral_skb_dst_pid( 288 struct sk_buff *skb, 289 struct pdev_spectral *ps) 290 { 291 NETLINK_CB(skb).dst_pid = 292 ps->spectral_pid; 293 } 294 #else 295 static inline void 296 os_if_init_spectral_skb_dst_pid( 297 struct sk_buff *skb, 298 struct pdev_spectral *ps) 299 { 300 } 301 #endif /* VERSION - field deprecated by newer kernels */ 302 303 #if KERNEL_VERSION(3, 7, 0) > LINUX_VERSION_CODE 304 static inline void 305 os_if_init_spectral_skb_pid_portid(struct sk_buff *skb) 306 { 307 NETLINK_CB(skb).pid = 0; /* from kernel */ 308 } 309 #else 310 static inline void 311 os_if_init_spectral_skb_pid_portid(struct sk_buff *skb) 312 { 313 NETLINK_CB(skb).portid = 0; /* from kernel */ 314 } 315 #endif 316 317 318 /** 319 * os_if_spectral_nl_unicast_msg() - Sends unicast Spectral message to user 320 * space 321 * @pdev : Pointer to pdev 322 * 323 * Return: void 324 */ 325 #ifndef CNSS_GENL 326 static int 327 os_if_spectral_nl_unicast_msg(struct wlan_objmgr_pdev *pdev) 328 { 329 struct pdev_spectral *ps = NULL; 330 int status; 331 332 if (!pdev) { 333 spectral_err("PDEV is NULL!"); 334 return -EINVAL; 335 } 336 337 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 338 WLAN_UMAC_COMP_SPECTRAL); 339 if (!ps) { 340 spectral_err("PDEV SPECTRAL object is NULL!"); 341 return -EINVAL; 342 } 343 344 if (!ps->skb) { 345 spectral_err("Socket buffer is null"); 346 return -EINVAL; 347 } 348 349 if (!ps->spectral_sock) { 350 spectral_err("Spectral Socket is invalid"); 351 qdf_nbuf_free(ps->skb); 352 return -EINVAL; 353 } 354 355 os_if_init_spectral_skb_dst_pid(ps->skb, ps); 356 357 os_if_init_spectral_skb_pid_portid(ps->skb); 358 359 /* to mcast group 1<<0 */ 360 NETLINK_CB(ps->skb).dst_group = 0; 361 362 os_if_spectral_remove_nbuf_debug_entry(ps->skb); 363 status = netlink_unicast(ps->spectral_sock, 364 ps->skb, 365 ps->spectral_pid, MSG_DONTWAIT); 366 367 return status; 368 } 369 #else 370 371 static int 372 os_if_spectral_nl_unicast_msg(struct wlan_objmgr_pdev *pdev) 373 { 374 struct pdev_spectral *ps = NULL; 375 int status; 376 377 if (!pdev) { 378 spectral_err("PDEV is NULL!"); 379 return -EINVAL; 380 } 381 382 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 383 WLAN_UMAC_COMP_SPECTRAL); 384 if (!ps) { 385 spectral_err("PDEV SPECTRAL object is NULL!"); 386 return -EINVAL; 387 } 388 389 if (!ps->skb) { 390 spectral_err("Socket buffer is null"); 391 return -EINVAL; 392 } 393 394 os_if_init_spectral_skb_pid_portid(ps->skb); 395 396 os_if_spectral_remove_nbuf_debug_entry(ps->skb); 397 status = nl_srv_ucast(ps->skb, ps->spectral_pid, MSG_DONTWAIT, 398 WLAN_NL_MSG_SPECTRAL_SCAN, CLD80211_MCGRP_OEM_MSGS); 399 if (status < 0) 400 spectral_err("failed to send to spectral scan app"); 401 402 return status; 403 } 404 405 #endif 406 407 /** 408 * os_if_spectral_nl_bcast_msg() - Sends broadcast Spectral message to user 409 * space 410 * @pdev : Pointer to pdev 411 * 412 * Return: void 413 */ 414 static int 415 os_if_spectral_nl_bcast_msg(struct wlan_objmgr_pdev *pdev) 416 { 417 #if (KERNEL_VERSION(2, 6, 31) >= LINUX_VERSION_CODE) 418 fd_set write_set; 419 #endif 420 int status; 421 struct pdev_spectral *ps = NULL; 422 423 #if (KERNEL_VERSION(2, 6, 31) >= LINUX_VERSION_CODE) 424 FD_ZERO(&write_set); 425 #endif 426 427 if (!pdev) { 428 spectral_err("PDEV is NULL!"); 429 return -EINVAL; 430 } 431 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 432 WLAN_UMAC_COMP_SPECTRAL); 433 434 if (!ps) { 435 spectral_err("PDEV SPECTRAL object is NULL!"); 436 return -EINVAL; 437 } 438 439 if (!ps->skb) { 440 spectral_err("Socket buffer is null"); 441 return -EINVAL; 442 } 443 444 if (!ps->spectral_sock) { 445 qdf_nbuf_free(ps->skb); 446 return -EINVAL; 447 } 448 449 os_if_spectral_remove_nbuf_debug_entry(ps->skb); 450 status = netlink_broadcast(ps->spectral_sock, 451 ps->skb, 452 0, 1, GFP_ATOMIC); 453 454 return status; 455 } 456 457 /** 458 * os_if_spectral_free_skb() - Free spectral SAMP message skb 459 * 460 * @pdev : Pointer to pdev 461 * 462 * Return: void 463 */ 464 static void 465 os_if_spectral_free_skb(struct wlan_objmgr_pdev *pdev) 466 { 467 struct pdev_spectral *ps = NULL; 468 469 if (!pdev) { 470 spectral_err("PDEV is NULL!"); 471 return; 472 } 473 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 474 WLAN_UMAC_COMP_SPECTRAL); 475 476 if (!ps) { 477 spectral_err("PDEV SPECTRAL object is NULL!"); 478 return; 479 } 480 481 if (!ps->skb) { 482 spectral_err("Socket buffer is null"); 483 return; 484 } 485 486 /* Free buffer */ 487 qdf_nbuf_free(ps->skb); 488 489 /* clear the local copy */ 490 ps->skb = NULL; 491 } 492 493 qdf_export_symbol(os_if_spectral_free_skb); 494 495 void 496 os_if_spectral_netlink_init(struct wlan_objmgr_pdev *pdev) 497 { 498 struct spectral_nl_cb nl_cb = {0}; 499 struct spectral_context *sptrl_ctx; 500 501 if (!pdev) { 502 spectral_err("PDEV is NULL!"); 503 return; 504 } 505 506 sptrl_ctx = spectral_get_spectral_ctx_from_pdev(pdev); 507 508 if (!sptrl_ctx) { 509 spectral_err("Spectral context is NULL!"); 510 return; 511 } 512 513 os_if_spectral_init_nl(pdev); 514 515 /* Register Netlink handlers */ 516 nl_cb.get_nbuff = os_if_spectral_prep_skb; 517 nl_cb.send_nl_bcast = os_if_spectral_nl_bcast_msg; 518 nl_cb.send_nl_unicast = os_if_spectral_nl_unicast_msg; 519 nl_cb.free_nbuff = os_if_spectral_free_skb; 520 521 if (sptrl_ctx->sptrlc_register_netlink_cb) 522 sptrl_ctx->sptrlc_register_netlink_cb(pdev, &nl_cb); 523 } 524 qdf_export_symbol(os_if_spectral_netlink_init); 525 526 void os_if_spectral_netlink_deinit(struct wlan_objmgr_pdev *pdev) 527 { 528 struct spectral_context *sptrl_ctx; 529 530 if (!pdev) { 531 spectral_err("PDEV is NULL!"); 532 return; 533 } 534 535 sptrl_ctx = spectral_get_spectral_ctx_from_pdev(pdev); 536 537 if (!sptrl_ctx) { 538 spectral_err("Spectral context is NULL!"); 539 return; 540 } 541 542 if (sptrl_ctx->sptrlc_deregister_netlink_cb) 543 sptrl_ctx->sptrlc_deregister_netlink_cb(pdev); 544 545 os_if_spectral_destroy_netlink(pdev); 546 } 547 qdf_export_symbol(os_if_spectral_netlink_deinit); 548