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