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 #ifndef CNSS_GENL 31 static struct sock *os_if_spectral_nl_sock; 32 static atomic_t spectral_nl_users = ATOMIC_INIT(0); 33 #endif 34 35 #if (KERNEL_VERSION(2, 6, 31) > LINUX_VERSION_CODE) 36 void 37 os_if_spectral_nl_data_ready(struct sock *sk, int len) 38 { 39 spectral_debug("%d", __LINE__); 40 } 41 42 #else 43 void 44 os_if_spectral_nl_data_ready(struct sk_buff *skb) 45 { 46 spectral_debug("%d", __LINE__); 47 } 48 #endif /* VERSION */ 49 50 #ifndef CNSS_GENL 51 /** 52 * os_if_spectral_init_nl_cfg() - Initialize netlink kernel 53 * configuration parameters 54 * @cfg : Pointer to netlink_kernel_cfg 55 * 56 * Initialize netlink kernel configuration parameters required 57 * for spectral module 58 * 59 * Return: None 60 */ 61 #if KERNEL_VERSION(3, 6, 0) <= LINUX_VERSION_CODE 62 static void 63 os_if_spectral_init_nl_cfg(struct netlink_kernel_cfg *cfg) 64 { 65 cfg->groups = 1; 66 cfg->input = os_if_spectral_nl_data_ready; 67 } 68 #else 69 static void 70 os_if_spectral_init_nl_cfg(struct netlink_kernel_cfg *cfg) 71 { 72 } 73 #endif 74 /** 75 * os_if_spectral_create_nl_sock() - Create Netlink socket 76 * @cfg : Pointer to netlink_kernel_cfg 77 * 78 * Create Netlink socket required for spectral module 79 * 80 * Return: None 81 */ 82 #if KERNEL_VERSION(3, 7, 0) <= LINUX_VERSION_CODE 83 static void 84 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg) 85 { 86 os_if_spectral_nl_sock = 87 (struct sock *)netlink_kernel_create(&init_net, 88 SPECTRAL_NETLINK, cfg); 89 } 90 #elif KERNEL_VERSION(3, 6, 0) <= LINUX_VERSION_CODE 91 static void 92 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg) 93 { 94 os_if_spectral_nl_sock = 95 (struct sock *)netlink_kernel_create(&init_net, 96 SPECTRAL_NETLINK, 97 THIS_MODULE, cfg); 98 } 99 #elif (KERNEL_VERSION(2, 6, 31) > LINUX_VERSION_CODE) 100 static void 101 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg) 102 { 103 os_if_spectral_nl_sock = 104 (struct sock *)netlink_kernel_create( 105 SPECTRAL_NETLINK, 1, 106 &os_if_spectral_nl_data_ready, 107 THIS_MODULE); 108 } 109 #else 110 #if (KERNEL_VERSION(3, 10, 0) <= LINUX_VERSION_CODE) 111 static void 112 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg) 113 { 114 memset(cfg, 0, sizeof(*cfg)); 115 cfg->groups = 1; 116 cfg->input = &os_if_spectral_nl_data_ready; 117 os_if_spectral_nl_sock = 118 (struct sock *)netlink_kernel_create(&init_net, 119 SPECTRAL_NETLINK, cfg); 120 } 121 #else 122 static void 123 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg) 124 { 125 os_if_spectral_nl_sock = 126 (struct sock *)netlink_kernel_create( 127 &init_net, 128 SPECTRAL_NETLINK, 1, 129 &os_if_spectral_nl_data_ready, 130 NULL, THIS_MODULE); 131 } 132 #endif 133 #endif 134 135 /** 136 * os_if_spectral_init_nl() - Initialize netlink data structures for 137 * spectral module 138 * @pdev : Pointer to pdev 139 * 140 * Return: 0 on success else failure 141 */ 142 static int 143 os_if_spectral_init_nl(struct wlan_objmgr_pdev *pdev) 144 { 145 struct pdev_spectral *ps = NULL; 146 struct netlink_kernel_cfg cfg; 147 148 memset(&cfg, 0, sizeof(cfg)); 149 if (!pdev) { 150 spectral_err("PDEV is NULL!"); 151 return -EINVAL; 152 } 153 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 154 WLAN_UMAC_COMP_SPECTRAL); 155 156 if (!ps) { 157 spectral_err("PDEV SPECTRAL object is NULL!"); 158 return -EINVAL; 159 } 160 os_if_spectral_init_nl_cfg(&cfg); 161 162 if (!os_if_spectral_nl_sock) { 163 os_if_spectral_create_nl_sock(&cfg); 164 165 if (!os_if_spectral_nl_sock) { 166 spectral_err("NETLINK_KERNEL_CREATE FAILED"); 167 return -ENODEV; 168 } 169 } 170 ps->spectral_sock = os_if_spectral_nl_sock; 171 172 if (!ps->spectral_sock) { 173 spectral_err("ps->spectral_sock is NULL"); 174 return -ENODEV; 175 } 176 atomic_inc(&spectral_nl_users); 177 178 return 0; 179 } 180 181 /** 182 * os_if_spectral_destroy_netlink() - De-initialize netlink data structures for 183 * spectral module 184 * @pdev : Pointer to pdev 185 * 186 * Return: Success/Failure 187 */ 188 static int 189 os_if_spectral_destroy_netlink(struct wlan_objmgr_pdev *pdev) 190 { 191 struct pdev_spectral *ps = NULL; 192 193 if (!pdev) { 194 spectral_err("PDEV is NULL!"); 195 return -EINVAL; 196 } 197 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 198 WLAN_UMAC_COMP_SPECTRAL); 199 200 if (!ps) { 201 spectral_err("PDEV SPECTRAL object is NULL!"); 202 return -EINVAL; 203 } 204 ps->spectral_sock = NULL; 205 if (atomic_dec_and_test(&spectral_nl_users)) { 206 sock_release(os_if_spectral_nl_sock->sk_socket); 207 os_if_spectral_nl_sock = NULL; 208 } 209 return 0; 210 } 211 #else 212 213 static int 214 os_if_spectral_init_nl(struct wlan_objmgr_pdev *pdev) 215 { 216 return 0; 217 } 218 219 static int 220 os_if_spectral_destroy_netlink(struct wlan_objmgr_pdev *pdev) 221 { 222 return 0; 223 } 224 #endif 225 226 void * 227 os_if_spectral_prep_skb(struct wlan_objmgr_pdev *pdev) 228 { 229 struct pdev_spectral *ps = NULL; 230 struct nlmsghdr *spectral_nlh = NULL; 231 232 if (!pdev) { 233 spectral_err("PDEV is NULL!"); 234 return NULL; 235 } 236 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 237 WLAN_UMAC_COMP_SPECTRAL); 238 239 if (!ps) { 240 spectral_err("PDEV SPECTRAL object is NULL!"); 241 return NULL; 242 } 243 ps->skb = qdf_nbuf_alloc(NULL, MAX_SPECTRAL_PAYLOAD, 0, 0, false); 244 245 if (!ps->skb) { 246 spectral_err("allocate skb (len=%u) failed", 247 MAX_SPECTRAL_PAYLOAD); 248 return NULL; 249 } 250 251 qdf_nbuf_put_tail(ps->skb, MAX_SPECTRAL_PAYLOAD); 252 spectral_nlh = (struct nlmsghdr *)ps->skb->data; 253 254 OS_MEMZERO(spectral_nlh, sizeof(*spectral_nlh)); 255 256 /* 257 * Possible bug that size of struct spectral_samp_msg and 258 * SPECTRAL_MSG differ by 3 bytes so we miss 3 bytes 259 */ 260 261 spectral_nlh->nlmsg_len = NLMSG_SPACE(sizeof(struct spectral_samp_msg)); 262 spectral_nlh->nlmsg_pid = 0; 263 spectral_nlh->nlmsg_flags = 0; 264 spectral_nlh->nlmsg_type = WLAN_NL_MSG_SPECTRAL_SCAN; 265 266 return NLMSG_DATA(spectral_nlh); 267 } 268 269 #if (KERNEL_VERSION(2, 6, 31) > LINUX_VERSION_CODE) 270 static inline void 271 os_if_init_spectral_skb_dst_pid( 272 struct sk_buff *skb, 273 struct pdev_spectral *ps) 274 { 275 NETLINK_CB(skb).dst_pid = 276 ps->spectral_pid; 277 } 278 #else 279 static inline void 280 os_if_init_spectral_skb_dst_pid( 281 struct sk_buff *skb, 282 struct pdev_spectral *ps) 283 { 284 } 285 #endif /* VERSION - field deprecated by newer kernels */ 286 287 #if KERNEL_VERSION(3, 7, 0) > LINUX_VERSION_CODE 288 static inline void 289 os_if_init_spectral_skb_pid_portid(struct sk_buff *skb) 290 { 291 NETLINK_CB(skb).pid = 0; /* from kernel */ 292 } 293 #else 294 static inline void 295 os_if_init_spectral_skb_pid_portid(struct sk_buff *skb) 296 { 297 NETLINK_CB(skb).portid = 0; /* from kernel */ 298 } 299 #endif 300 301 302 /** 303 * os_if_spectral_nl_unicast_msg() - Sends unicast Spectral message to user 304 * space 305 * @pdev : Pointer to pdev 306 * 307 * Return: void 308 */ 309 #ifndef CNSS_GENL 310 static int 311 os_if_spectral_nl_unicast_msg(struct wlan_objmgr_pdev *pdev) 312 { 313 struct pdev_spectral *ps = NULL; 314 int status; 315 316 if (!pdev) { 317 spectral_err("PDEV is NULL!"); 318 return -EINVAL; 319 } 320 321 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 322 WLAN_UMAC_COMP_SPECTRAL); 323 if (!ps) { 324 spectral_err("PDEV SPECTRAL object is NULL!"); 325 return -EINVAL; 326 } 327 328 if (!ps->skb) { 329 spectral_err("Socket buffer is null"); 330 return -EINVAL; 331 } 332 333 if (!ps->spectral_sock) { 334 spectral_err("Spectral Socket is invalid"); 335 dev_kfree_skb(ps->skb); 336 return -EINVAL; 337 } 338 339 os_if_init_spectral_skb_dst_pid(ps->skb, ps); 340 341 os_if_init_spectral_skb_pid_portid(ps->skb); 342 343 /* to mcast group 1<<0 */ 344 NETLINK_CB(ps->skb).dst_group = 0; 345 346 status = netlink_unicast(ps->spectral_sock, 347 ps->skb, 348 ps->spectral_pid, MSG_DONTWAIT); 349 350 return status; 351 } 352 #else 353 354 static int 355 os_if_spectral_nl_unicast_msg(struct wlan_objmgr_pdev *pdev) 356 { 357 struct pdev_spectral *ps = NULL; 358 int status; 359 360 if (!pdev) { 361 spectral_err("PDEV is NULL!"); 362 return -EINVAL; 363 } 364 365 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 366 WLAN_UMAC_COMP_SPECTRAL); 367 if (!ps) { 368 spectral_err("PDEV SPECTRAL object is NULL!"); 369 return -EINVAL; 370 } 371 372 if (!ps->skb) { 373 spectral_err("Socket buffer is null"); 374 return -EINVAL; 375 } 376 377 spectral_debug("spectral unicast message"); 378 os_if_init_spectral_skb_pid_portid(ps->skb); 379 380 status = nl_srv_ucast(ps->skb, ps->spectral_pid, MSG_DONTWAIT, 381 WLAN_NL_MSG_SPECTRAL_SCAN, CLD80211_MCGRP_OEM_MSGS); 382 if (status < 0) 383 spectral_err("failed to send to spectral scan app"); 384 385 return status; 386 } 387 388 #endif 389 /** 390 * os_if_spectral_nl_bcast_msg() - Sends broadcast Spectral message to user 391 * space 392 * @pdev : Pointer to pdev 393 * 394 * Return: void 395 */ 396 static int 397 os_if_spectral_nl_bcast_msg(struct wlan_objmgr_pdev *pdev) 398 { 399 #if (KERNEL_VERSION(2, 6, 31) >= LINUX_VERSION_CODE) 400 fd_set write_set; 401 #endif 402 int status; 403 struct pdev_spectral *ps = NULL; 404 405 #if (KERNEL_VERSION(2, 6, 31) >= LINUX_VERSION_CODE) 406 FD_ZERO(&write_set); 407 #endif 408 409 if (!pdev) { 410 spectral_err("PDEV is NULL!"); 411 return -EINVAL; 412 } 413 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 414 WLAN_UMAC_COMP_SPECTRAL); 415 416 if (!ps) { 417 spectral_err("PDEV SPECTRAL object is NULL!"); 418 return -EINVAL; 419 } 420 421 if (!ps->skb) { 422 spectral_err("Socket buffer is null"); 423 return -EINVAL; 424 } 425 426 if (!ps->spectral_sock) { 427 dev_kfree_skb(ps->skb); 428 return -EINVAL; 429 } 430 431 status = netlink_broadcast(ps->spectral_sock, 432 ps->skb, 433 0, 1, GFP_ATOMIC); 434 435 return status; 436 } 437 438 void 439 os_if_spectral_netlink_init(struct wlan_objmgr_pdev *pdev) 440 { 441 struct spectral_nl_cb nl_cb = {0}; 442 struct spectral_context *sptrl_ctx; 443 444 if (!pdev) { 445 spectral_err("PDEV is NULL!"); 446 return; 447 } 448 449 sptrl_ctx = spectral_get_spectral_ctx_from_pdev(pdev); 450 451 if (!sptrl_ctx) { 452 spectral_err("Spectral context is NULL!"); 453 return; 454 } 455 456 os_if_spectral_init_nl(pdev); 457 458 /* Register Netlink handlers */ 459 nl_cb.get_nbuff = os_if_spectral_prep_skb; 460 nl_cb.send_nl_bcast = os_if_spectral_nl_bcast_msg; 461 nl_cb.send_nl_unicast = os_if_spectral_nl_unicast_msg; 462 463 if (sptrl_ctx->sptrlc_register_netlink_cb) 464 sptrl_ctx->sptrlc_register_netlink_cb(pdev, &nl_cb); 465 } 466 qdf_export_symbol(os_if_spectral_netlink_init); 467 468 void os_if_spectral_netlink_deinit(struct wlan_objmgr_pdev *pdev) 469 { 470 struct spectral_context *sptrl_ctx; 471 472 if (!pdev) { 473 spectral_err("PDEV is NULL!"); 474 return; 475 } 476 477 sptrl_ctx = spectral_get_spectral_ctx_from_pdev(pdev); 478 479 if (!sptrl_ctx) { 480 spectral_err("Spectral context is NULL!"); 481 return; 482 } 483 484 if (sptrl_ctx->sptrlc_deregister_netlink_cb) 485 sptrl_ctx->sptrlc_deregister_netlink_cb(pdev); 486 487 os_if_spectral_destroy_netlink(pdev); 488 } 489 qdf_export_symbol(os_if_spectral_netlink_deinit); 490