1 /* 2 * Copyright (c) 2011, 2017-2019 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 #include <wlan_cfg80211.h> 30 31 /** 32 * os_if_spectral_remove_nbuf_debug_entry() - Remove nbuf from nbuf debug table 33 * @nbuf - nbuf to remove from the nbuf debug table 34 * 35 * Remove nbuf from the nbuf debug hash table and decrement the nbuf count 36 * 37 * Return: None 38 */ 39 static inline void os_if_spectral_remove_nbuf_debug_entry(qdf_nbuf_t nbuf) 40 { 41 qdf_nbuf_count_dec(nbuf); 42 qdf_net_buf_debug_release_skb(nbuf); 43 } 44 45 #ifndef CNSS_GENL 46 static struct sock *os_if_spectral_nl_sock; 47 static atomic_t spectral_nl_users = ATOMIC_INIT(0); 48 #endif 49 50 #if (KERNEL_VERSION(2, 6, 31) > LINUX_VERSION_CODE) 51 void 52 os_if_spectral_nl_data_ready(struct sock *sk, int len) 53 { 54 spectral_debug("%d", __LINE__); 55 } 56 57 #else 58 void 59 os_if_spectral_nl_data_ready(struct sk_buff *skb) 60 { 61 spectral_debug("%d", __LINE__); 62 } 63 #endif /* VERSION */ 64 65 #ifndef CNSS_GENL 66 /** 67 * os_if_spectral_init_nl_cfg() - Initialize netlink kernel 68 * configuration parameters 69 * @cfg : Pointer to netlink_kernel_cfg 70 * 71 * Initialize netlink kernel configuration parameters required 72 * for spectral module 73 * 74 * Return: None 75 */ 76 #if KERNEL_VERSION(3, 6, 0) <= LINUX_VERSION_CODE 77 static void 78 os_if_spectral_init_nl_cfg(struct netlink_kernel_cfg *cfg) 79 { 80 cfg->groups = 1; 81 cfg->input = os_if_spectral_nl_data_ready; 82 } 83 #else 84 static void 85 os_if_spectral_init_nl_cfg(struct netlink_kernel_cfg *cfg) 86 { 87 } 88 #endif 89 /** 90 * os_if_spectral_create_nl_sock() - Create Netlink socket 91 * @cfg : Pointer to netlink_kernel_cfg 92 * 93 * Create Netlink socket required for spectral module 94 * 95 * Return: None 96 */ 97 #if KERNEL_VERSION(3, 7, 0) <= LINUX_VERSION_CODE 98 static void 99 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg) 100 { 101 os_if_spectral_nl_sock = 102 (struct sock *)netlink_kernel_create(&init_net, 103 SPECTRAL_NETLINK, cfg); 104 } 105 #elif KERNEL_VERSION(3, 6, 0) <= LINUX_VERSION_CODE 106 static void 107 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg) 108 { 109 os_if_spectral_nl_sock = 110 (struct sock *)netlink_kernel_create(&init_net, 111 SPECTRAL_NETLINK, 112 THIS_MODULE, cfg); 113 } 114 #elif (KERNEL_VERSION(2, 6, 31) > LINUX_VERSION_CODE) 115 static void 116 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg) 117 { 118 os_if_spectral_nl_sock = 119 (struct sock *)netlink_kernel_create( 120 SPECTRAL_NETLINK, 1, 121 &os_if_spectral_nl_data_ready, 122 THIS_MODULE); 123 } 124 #else 125 #if (KERNEL_VERSION(3, 10, 0) <= LINUX_VERSION_CODE) 126 static void 127 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg) 128 { 129 memset(cfg, 0, sizeof(*cfg)); 130 cfg->groups = 1; 131 cfg->input = &os_if_spectral_nl_data_ready; 132 os_if_spectral_nl_sock = 133 (struct sock *)netlink_kernel_create(&init_net, 134 SPECTRAL_NETLINK, cfg); 135 } 136 #else 137 static void 138 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg) 139 { 140 os_if_spectral_nl_sock = 141 (struct sock *)netlink_kernel_create( 142 &init_net, 143 SPECTRAL_NETLINK, 1, 144 &os_if_spectral_nl_data_ready, 145 NULL, THIS_MODULE); 146 } 147 #endif 148 #endif 149 150 /** 151 * os_if_spectral_init_nl() - Initialize netlink data structures for 152 * spectral module 153 * @pdev : Pointer to pdev 154 * 155 * Return: 0 on success else failure 156 */ 157 static int 158 os_if_spectral_init_nl(struct wlan_objmgr_pdev *pdev) 159 { 160 struct pdev_spectral *ps = NULL; 161 struct netlink_kernel_cfg cfg; 162 163 memset(&cfg, 0, sizeof(cfg)); 164 if (!pdev) { 165 osif_err("PDEV is NULL!"); 166 return -EINVAL; 167 } 168 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 169 WLAN_UMAC_COMP_SPECTRAL); 170 171 if (!ps) { 172 osif_err("PDEV SPECTRAL object is NULL!"); 173 return -EINVAL; 174 } 175 os_if_spectral_init_nl_cfg(&cfg); 176 177 if (!os_if_spectral_nl_sock) { 178 os_if_spectral_create_nl_sock(&cfg); 179 180 if (!os_if_spectral_nl_sock) { 181 osif_err("NETLINK_KERNEL_CREATE FAILED"); 182 return -ENODEV; 183 } 184 } 185 ps->spectral_sock = os_if_spectral_nl_sock; 186 187 if (!ps->spectral_sock) { 188 osif_err("ps->spectral_sock is NULL"); 189 return -ENODEV; 190 } 191 atomic_inc(&spectral_nl_users); 192 193 return 0; 194 } 195 196 /** 197 * os_if_spectral_destroy_netlink() - De-initialize netlink data structures for 198 * spectral module 199 * @pdev : Pointer to pdev 200 * 201 * Return: Success/Failure 202 */ 203 static int 204 os_if_spectral_destroy_netlink(struct wlan_objmgr_pdev *pdev) 205 { 206 struct pdev_spectral *ps = NULL; 207 208 if (!pdev) { 209 osif_err("PDEV is NULL!"); 210 return -EINVAL; 211 } 212 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 213 WLAN_UMAC_COMP_SPECTRAL); 214 215 if (!ps) { 216 osif_err("PDEV SPECTRAL object is NULL!"); 217 return -EINVAL; 218 } 219 ps->spectral_sock = NULL; 220 if (atomic_dec_and_test(&spectral_nl_users)) { 221 sock_release(os_if_spectral_nl_sock->sk_socket); 222 os_if_spectral_nl_sock = NULL; 223 } 224 return 0; 225 } 226 #else 227 228 static int 229 os_if_spectral_init_nl(struct wlan_objmgr_pdev *pdev) 230 { 231 return 0; 232 } 233 234 static int 235 os_if_spectral_destroy_netlink(struct wlan_objmgr_pdev *pdev) 236 { 237 return 0; 238 } 239 #endif 240 241 void * 242 os_if_spectral_prep_skb(struct wlan_objmgr_pdev *pdev, 243 enum spectral_msg_type smsg_type, 244 enum spectral_msg_buf_type buf_type) 245 { 246 struct pdev_spectral *ps = NULL; 247 struct nlmsghdr *spectral_nlh = NULL; 248 void *buf = NULL; 249 250 if (!pdev) { 251 osif_err("PDEV is NULL!"); 252 return NULL; 253 } 254 255 if (smsg_type >= SPECTRAL_MSG_TYPE_MAX) { 256 osif_err("Invalid Spectral message type %u", smsg_type); 257 return NULL; 258 } 259 260 if (buf_type >= SPECTRAL_MSG_BUF_TYPE_MAX) { 261 osif_err("Invalid Spectral message buffer type %u", 262 buf_type); 263 return NULL; 264 } 265 266 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 267 WLAN_UMAC_COMP_SPECTRAL); 268 269 if (!ps) { 270 osif_err("PDEV SPECTRAL object is NULL!"); 271 return NULL; 272 } 273 274 if (buf_type == SPECTRAL_MSG_BUF_NEW) { 275 QDF_ASSERT(!ps->skb[smsg_type]); 276 ps->skb[smsg_type] = 277 qdf_nbuf_alloc(NULL, MAX_SPECTRAL_PAYLOAD, 278 0, 0, false); 279 280 if (!ps->skb[smsg_type]) { 281 osif_err("alloc skb (len=%u, msg_type=%u) failed", 282 MAX_SPECTRAL_PAYLOAD, smsg_type); 283 return NULL; 284 } 285 286 qdf_nbuf_put_tail(ps->skb[smsg_type], MAX_SPECTRAL_PAYLOAD); 287 spectral_nlh = (struct nlmsghdr *)ps->skb[smsg_type]->data; 288 289 qdf_mem_zero(spectral_nlh, sizeof(*spectral_nlh)); 290 291 /* 292 * Possible bug that size of struct spectral_samp_msg and 293 * SPECTRAL_MSG differ by 3 bytes so we miss 3 bytes 294 */ 295 296 spectral_nlh->nlmsg_len = 297 NLMSG_SPACE(sizeof(struct spectral_samp_msg)); 298 spectral_nlh->nlmsg_pid = 0; 299 spectral_nlh->nlmsg_flags = 0; 300 spectral_nlh->nlmsg_type = WLAN_NL_MSG_SPECTRAL_SCAN; 301 302 qdf_mem_zero(NLMSG_DATA(spectral_nlh), 303 sizeof(struct spectral_samp_msg)); 304 buf = NLMSG_DATA(spectral_nlh); 305 } else if (buf_type == SPECTRAL_MSG_BUF_SAVED) { 306 QDF_ASSERT(ps->skb[smsg_type]); 307 spectral_nlh = (struct nlmsghdr *)ps->skb[smsg_type]->data; 308 buf = NLMSG_DATA(spectral_nlh); 309 } else { 310 osif_err("Failed to get spectral report buffer"); 311 buf = NULL; 312 } 313 314 return buf; 315 } 316 317 #if (KERNEL_VERSION(2, 6, 31) > LINUX_VERSION_CODE) 318 static inline void 319 os_if_init_spectral_skb_dst_pid( 320 struct sk_buff *skb, 321 struct pdev_spectral *ps) 322 { 323 NETLINK_CB(skb).dst_pid = 324 ps->spectral_pid; 325 } 326 #else 327 static inline void 328 os_if_init_spectral_skb_dst_pid( 329 struct sk_buff *skb, 330 struct pdev_spectral *ps) 331 { 332 } 333 #endif /* VERSION - field deprecated by newer kernels */ 334 335 #if KERNEL_VERSION(3, 7, 0) > LINUX_VERSION_CODE 336 static inline void 337 os_if_init_spectral_skb_pid_portid(struct sk_buff *skb) 338 { 339 NETLINK_CB(skb).pid = 0; /* from kernel */ 340 } 341 #else 342 static inline void 343 os_if_init_spectral_skb_pid_portid(struct sk_buff *skb) 344 { 345 NETLINK_CB(skb).portid = 0; /* from kernel */ 346 } 347 #endif 348 349 350 /** 351 * os_if_spectral_nl_unicast_msg() - Sends unicast Spectral message to user 352 * space 353 * @pdev : Pointer to pdev 354 * @smsg_type: Spectral message type 355 * 356 * Return: void 357 */ 358 #ifndef CNSS_GENL 359 static int 360 os_if_spectral_nl_unicast_msg(struct wlan_objmgr_pdev *pdev, 361 enum spectral_msg_type smsg_type) 362 { 363 struct pdev_spectral *ps = NULL; 364 int status; 365 366 if (!pdev) { 367 osif_err("PDEV is NULL!"); 368 return -EINVAL; 369 } 370 371 if (smsg_type >= SPECTRAL_MSG_TYPE_MAX) { 372 osif_err("Invalid Spectral message type %u", smsg_type); 373 return -EINVAL; 374 } 375 376 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 377 WLAN_UMAC_COMP_SPECTRAL); 378 if (!ps) { 379 osif_err("PDEV SPECTRAL object is NULL!"); 380 return -EINVAL; 381 } 382 383 if (!ps->skb[smsg_type]) { 384 osif_err("Socket buffer is null, msg_type= %u", smsg_type); 385 return -EINVAL; 386 } 387 388 if (!ps->spectral_sock) { 389 osif_err("Spectral Socket is invalid, msg_type= %u", 390 smsg_type); 391 qdf_nbuf_free(ps->skb[smsg_type]); 392 ps->skb[smsg_type] = NULL; 393 394 return -EINVAL; 395 } 396 397 os_if_init_spectral_skb_dst_pid(ps->skb[smsg_type], ps); 398 399 os_if_init_spectral_skb_pid_portid(ps->skb[smsg_type]); 400 401 /* to mcast group 1<<0 */ 402 NETLINK_CB(ps->skb[smsg_type]).dst_group = 0; 403 404 os_if_spectral_remove_nbuf_debug_entry(ps->skb[smsg_type]); 405 status = netlink_unicast(ps->spectral_sock, 406 ps->skb[smsg_type], 407 ps->spectral_pid, MSG_DONTWAIT); 408 409 /* clear the local copy, free would be done by netlink layer */ 410 ps->skb[smsg_type] = NULL; 411 412 return status; 413 } 414 #else 415 416 static int 417 os_if_spectral_nl_unicast_msg(struct wlan_objmgr_pdev *pdev, 418 enum spectral_msg_type smsg_type) 419 { 420 struct pdev_spectral *ps = NULL; 421 int status; 422 423 if (!pdev) { 424 osif_err("PDEV is NULL!"); 425 return -EINVAL; 426 } 427 428 if (smsg_type >= SPECTRAL_MSG_TYPE_MAX) { 429 osif_err("Invalid Spectral message type %u", smsg_type); 430 return -EINVAL; 431 } 432 433 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 434 WLAN_UMAC_COMP_SPECTRAL); 435 if (!ps) { 436 osif_err("PDEV SPECTRAL object is NULL!"); 437 return -EINVAL; 438 } 439 440 if (!ps->skb[smsg_type]) { 441 osif_err("Socket buffer is null, msg_type= %u", smsg_type); 442 return -EINVAL; 443 } 444 445 os_if_init_spectral_skb_pid_portid(ps->skb[smsg_type]); 446 447 os_if_spectral_remove_nbuf_debug_entry(ps->skb[smsg_type]); 448 status = nl_srv_ucast(ps->skb[smsg_type], ps->spectral_pid, 449 MSG_DONTWAIT, WLAN_NL_MSG_SPECTRAL_SCAN, 450 CLD80211_MCGRP_OEM_MSGS); 451 if (status < 0) 452 osif_err("failed to send to spectral scan app"); 453 454 /* clear the local copy, free would be done by netlink layer */ 455 ps->skb[smsg_type] = NULL; 456 457 return status; 458 } 459 460 #endif 461 462 /** 463 * os_if_spectral_nl_bcast_msg() - Sends broadcast Spectral message to user 464 * space 465 * @pdev : Pointer to pdev 466 * @smsg_type: Spectral message type 467 * 468 * Return: void 469 */ 470 static int 471 os_if_spectral_nl_bcast_msg(struct wlan_objmgr_pdev *pdev, 472 enum spectral_msg_type smsg_type) 473 { 474 #if (KERNEL_VERSION(2, 6, 31) >= LINUX_VERSION_CODE) 475 fd_set write_set; 476 #endif 477 int status; 478 struct pdev_spectral *ps = NULL; 479 480 #if (KERNEL_VERSION(2, 6, 31) >= LINUX_VERSION_CODE) 481 FD_ZERO(&write_set); 482 #endif 483 484 if (!pdev) { 485 osif_err("PDEV is NULL!"); 486 return -EINVAL; 487 } 488 489 if (smsg_type >= SPECTRAL_MSG_TYPE_MAX) { 490 osif_err("Invalid Spectral message type %u", smsg_type); 491 return -EINVAL; 492 } 493 494 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 495 WLAN_UMAC_COMP_SPECTRAL); 496 497 if (!ps) { 498 osif_err("PDEV SPECTRAL object is NULL!"); 499 return -EINVAL; 500 } 501 502 if (!ps->skb[smsg_type]) { 503 osif_err("Socket buffer is null, msg_type= %u", smsg_type); 504 return -EINVAL; 505 } 506 507 if (!ps->spectral_sock) { 508 qdf_nbuf_free(ps->skb[smsg_type]); 509 ps->skb[smsg_type] = NULL; 510 511 return -EINVAL; 512 } 513 514 os_if_spectral_remove_nbuf_debug_entry(ps->skb[smsg_type]); 515 status = netlink_broadcast(ps->spectral_sock, 516 ps->skb[smsg_type], 517 0, 1, GFP_ATOMIC); 518 519 /* clear the local copy, free would be done by netlink layer */ 520 ps->skb[smsg_type] = NULL; 521 522 return status; 523 } 524 525 /** 526 * os_if_spectral_free_skb() - Free spectral SAMP message skb 527 * 528 * @pdev : Pointer to pdev 529 * @smsg_type: Spectral message type 530 * 531 * Return: void 532 */ 533 static void 534 os_if_spectral_free_skb(struct wlan_objmgr_pdev *pdev, 535 enum spectral_msg_type smsg_type) 536 { 537 struct pdev_spectral *ps = NULL; 538 539 if (!pdev) { 540 osif_err("PDEV is NULL!"); 541 return; 542 } 543 544 if (smsg_type >= SPECTRAL_MSG_TYPE_MAX) { 545 osif_err("Invalid Spectral message type %u", smsg_type); 546 return; 547 } 548 549 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 550 WLAN_UMAC_COMP_SPECTRAL); 551 552 if (!ps) { 553 osif_err("PDEV SPECTRAL object is NULL!"); 554 return; 555 } 556 557 if (!ps->skb[smsg_type]) { 558 osif_info("Socket buffer is null, msg_type= %u", smsg_type); 559 return; 560 } 561 562 /* Free buffer */ 563 qdf_nbuf_free(ps->skb[smsg_type]); 564 565 /* clear the local copy */ 566 ps->skb[smsg_type] = NULL; 567 } 568 569 qdf_export_symbol(os_if_spectral_free_skb); 570 571 void 572 os_if_spectral_netlink_init(struct wlan_objmgr_pdev *pdev) 573 { 574 struct spectral_nl_cb nl_cb = {0}; 575 struct spectral_context *sptrl_ctx; 576 577 if (!pdev) { 578 osif_err("PDEV is NULL!"); 579 return; 580 } 581 582 sptrl_ctx = spectral_get_spectral_ctx_from_pdev(pdev); 583 584 if (!sptrl_ctx) { 585 osif_err("Spectral context is NULL!"); 586 return; 587 } 588 589 os_if_spectral_init_nl(pdev); 590 591 /* Register Netlink handlers */ 592 nl_cb.get_sbuff = os_if_spectral_prep_skb; 593 nl_cb.send_nl_bcast = os_if_spectral_nl_bcast_msg; 594 nl_cb.send_nl_unicast = os_if_spectral_nl_unicast_msg; 595 nl_cb.free_sbuff = os_if_spectral_free_skb; 596 597 if (sptrl_ctx->sptrlc_register_netlink_cb) 598 sptrl_ctx->sptrlc_register_netlink_cb(pdev, &nl_cb); 599 } 600 qdf_export_symbol(os_if_spectral_netlink_init); 601 602 void os_if_spectral_netlink_deinit(struct wlan_objmgr_pdev *pdev) 603 { 604 struct spectral_context *sptrl_ctx; 605 enum spectral_msg_type msg_type = SPECTRAL_MSG_NORMAL_MODE; 606 607 if (!pdev) { 608 osif_err("PDEV is NULL!"); 609 return; 610 } 611 612 sptrl_ctx = spectral_get_spectral_ctx_from_pdev(pdev); 613 614 if (!sptrl_ctx) { 615 osif_err("Spectral context is NULL!"); 616 return; 617 } 618 619 for (; msg_type < SPECTRAL_MSG_TYPE_MAX; msg_type++) 620 os_if_spectral_free_skb(pdev, msg_type); 621 622 if (sptrl_ctx->sptrlc_deregister_netlink_cb) 623 sptrl_ctx->sptrlc_deregister_netlink_cb(pdev); 624 625 os_if_spectral_destroy_netlink(pdev); 626 } 627 qdf_export_symbol(os_if_spectral_netlink_deinit); 628