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