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