1 /* 2 * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /****************************************************************************** 20 * wlan_nlink_srv.c 21 * 22 * This file contains the definitions specific to the wlan_nlink_srv 23 * 24 ******************************************************************************/ 25 26 #include <linux/version.h> 27 #include <linux/kernel.h> 28 #include <linux/module.h> 29 #include <linux/init.h> 30 #include <linux/netdevice.h> 31 #include <linux/netlink.h> 32 #include <linux/skbuff.h> 33 #include <net/sock.h> 34 #include <wlan_nlink_srv.h> 35 #include <qdf_trace.h> 36 #include <qdf_module.h> 37 38 #define WLAN_CLD80211_MAX_SIZE (SKB_WITH_OVERHEAD(8192UL) - NLMSG_HDRLEN) 39 40 #if defined(CONFIG_CNSS_LOGGER) 41 42 #include <net/cnss_logger.h> 43 44 static int radio_idx = -EINVAL; 45 static void *wiphy_ptr; 46 static bool logger_initialized; 47 48 /** 49 * nl_srv_init() - wrapper function to register to cnss_logger 50 * @wiphy: the pointer to the wiphy structure 51 * @proto: the host log netlink protocol 52 * 53 * The netlink socket is no longer initialized in the driver itself, instead 54 * will be initialized in the cnss_logger module, the driver should register 55 * itself to cnss_logger module to get the radio_index for all the netlink 56 * operation. (cfg80211 vendor command is using different netlink socket). 57 * 58 * The cnss_logger_device_register() use to register the driver with the 59 * wiphy structure and the module name (debug purpose) and then return the 60 * radio_index depending on the availibility. 61 * 62 * Return: radio index for success and -EINVAL for failure 63 */ 64 int nl_srv_init(void *wiphy, int proto) 65 { 66 if (logger_initialized) 67 goto initialized; 68 69 wiphy_ptr = wiphy; 70 radio_idx = cnss_logger_device_register(wiphy, THIS_MODULE->name); 71 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 72 "%s: radio_index: %d, wiphy_ptr: %pK", 73 __func__, radio_idx, wiphy_ptr); 74 75 if (radio_idx >= 0) 76 logger_initialized = true; 77 78 initialized: 79 return radio_idx; 80 } 81 82 /** 83 * nl_srv_exit() - wrapper function to unregister from cnss_logger 84 * 85 * The cnss_logger_device_unregister() use to unregister the driver with 86 * the radio_index assigned and wiphy structure from cnss_logger. 87 * 88 * Return: None 89 */ 90 void nl_srv_exit(void) 91 { 92 if (logger_initialized) { 93 cnss_logger_device_unregister(radio_idx, wiphy_ptr); 94 radio_idx = -EINVAL; 95 wiphy_ptr = NULL; 96 logger_initialized = false; 97 } 98 } 99 100 /** 101 * nl_srv_ucast() - wrapper function to do unicast tx through cnss_logger 102 * @skb: the socket buffer to send 103 * @dst_pid: the port id 104 * @flag: the blocking or nonblocking flag 105 * 106 * The nl_srv_is_initialized() is used to do sanity check if the netlink 107 * service is ready, e.g if the radio_index is assigned properly, if not 108 * the driver should take the responsibility to free the skb. 109 * 110 * The cnss_logger_nl_ucast() use the same parameters to send the socket 111 * buffers. 112 * 113 * Return: the error of the transmission status 114 */ 115 int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag) 116 { 117 int err = -EINVAL; 118 119 /* sender's pid */ 120 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) 121 NETLINK_CB(skb).pid = 0; 122 #else 123 NETLINK_CB(skb).portid = 0; 124 #endif 125 /* not multicast */ 126 NETLINK_CB(skb).dst_group = 0; 127 128 if (nl_srv_is_initialized() == 0) { 129 err = cnss_logger_nl_ucast(skb, dst_pid, flag); 130 if (err < 0) 131 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 132 "NLINK: netlink_unicast to pid[%d] failed, ret[%d]", 133 dst_pid, err); 134 } else { 135 dev_kfree_skb(skb); 136 } 137 138 return err; 139 } 140 141 /** 142 * nl_srv_bcast() - wrapper function to do broadcast tx through cnss_logger 143 * @skb: the socket buffer to send 144 * 145 * The cnss_logger_nl_bcast() is used to transmit the socket buffer. 146 * 147 * Return: status of transmission 148 */ 149 int nl_srv_bcast(struct sk_buff *skb) 150 { 151 int err = -EINVAL; 152 int flags = GFP_KERNEL; 153 154 if (in_interrupt() || irqs_disabled() || in_atomic()) 155 flags = GFP_ATOMIC; 156 157 /* sender's pid */ 158 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) 159 NETLINK_CB(skb).pid = 0; 160 #else 161 NETLINK_CB(skb).portid = 0; 162 #endif 163 /* destination group */ 164 NETLINK_CB(skb).dst_group = WLAN_NLINK_MCAST_GRP_ID; 165 166 if (nl_srv_is_initialized() == 0) { 167 err = cnss_logger_nl_bcast(skb, WLAN_NLINK_MCAST_GRP_ID, flags); 168 if ((err < 0) && (err != -ESRCH)) { 169 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 170 "NLINK: netlink_broadcast failed err = %d", 171 err); 172 dev_kfree_skb(skb); 173 } 174 } 175 else 176 dev_kfree_skb(skb); 177 return err; 178 } 179 qdf_export_symbol(nl_srv_bcast); 180 181 /** 182 * nl_srv_unregister() - wrapper function to unregister event to cnss_logger 183 * @msg_type: the message to unregister 184 * @msg_handler: the message handler 185 * 186 * The cnss_logger_event_unregister() is used to unregister the message and 187 * message handler. 188 * 189 * Return: 0 if successfully unregister, otherwise proper error code 190 */ 191 int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) 192 { 193 int ret = -EINVAL; 194 195 if (nl_srv_is_initialized() != 0) 196 return ret; 197 198 if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) && 199 msg_handler) { 200 ret = cnss_logger_event_unregister(radio_idx, msg_type, 201 msg_handler); 202 } else { 203 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 204 "NLINK: nl_srv_unregister failed for msg_type %d", 205 msg_type); 206 ret = -EINVAL; 207 } 208 209 return ret; 210 } 211 212 /** 213 * nl_srv_register() - wrapper function to register event to cnss_logger 214 * @msg_type: the message to register 215 * @msg_handler: the message handler 216 * 217 * The cnss_logger_event_register() is used to register the message and 218 * message handler. 219 * 220 * Return: 0 if successfully register, otherwise proper error code 221 */ 222 int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) 223 { 224 int ret = -EINVAL; 225 226 if (nl_srv_is_initialized() != 0) 227 return ret; 228 229 if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) && 230 msg_handler) { 231 ret = cnss_logger_event_register(radio_idx, msg_type, 232 msg_handler); 233 } else { 234 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 235 "NLINK: nl_srv_register failed for msg_type %d", 236 msg_type); 237 ret = -EINVAL; 238 } 239 240 return ret; 241 } 242 243 /** 244 * nl_srv_is_initialized() - check if netlink service is initialized 245 * 246 * Return: 0 if it is initialized, otherwise error code 247 */ 248 inline int nl_srv_is_initialized(void) 249 { 250 if (logger_initialized) 251 return 0; 252 else 253 return -EPERM; 254 } 255 qdf_export_symbol(nl_srv_is_initialized); 256 257 /* 258 * If MULTI_IF_NAME is not defined, then this is the primary instance of the 259 * driver and the diagnostics netlink socket will be available. If 260 * MULTI_IF_NAME is defined then this is not the primary instance of the driver 261 * and the diagnotics netlink socket will not be available since this 262 * diagnostics netlink socket can only be exposed by one instance of the driver. 263 */ 264 #elif defined(CNSS_GENL) 265 #include <qdf_mem.h> 266 #include <wlan_nlink_common.h> 267 #include <net/genetlink.h> 268 #include <net/cnss_nl.h> 269 270 void cld80211_oem_send_reply(struct sk_buff *msg, void *hdr, 271 struct nlattr *nest, int flags) 272 { 273 struct genl_family *cld80211_fam = cld80211_get_genl_family(); 274 275 nla_nest_end(msg, nest); 276 genlmsg_end(msg, hdr); 277 278 genlmsg_multicast_netns(cld80211_fam, &init_net, msg, 0, 279 CLD80211_MCGRP_OEM_MSGS, flags); 280 } 281 282 struct sk_buff * 283 cld80211_oem_rsp_alloc_skb(uint32_t portid, void **hdr, struct nlattr **nest, 284 int *flags) 285 { 286 static struct sk_buff *msg; 287 288 if (in_interrupt() || irqs_disabled() || in_atomic()) 289 *flags = GFP_ATOMIC; 290 291 msg = nlmsg_new(WLAN_CLD80211_MAX_SIZE, *flags); 292 if (!msg) { 293 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 294 "nlmsg malloc fails"); 295 return NULL; 296 } 297 298 *hdr = nl80211hdr_put(msg, portid, 0, *flags, WLAN_NL_MSG_OEM); 299 if (*hdr == NULL) { 300 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 301 "nl80211 hdr put failed"); 302 goto nla_put_failure; 303 } 304 305 *nest = nla_nest_start(msg, CLD80211_ATTR_VENDOR_DATA); 306 if (*nest == NULL) { 307 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 308 "nla_nest_start failed"); 309 goto nla_put_failure; 310 } 311 return msg; 312 nla_put_failure: 313 genlmsg_cancel(msg, *hdr); 314 nlmsg_free(msg); 315 return NULL; 316 } 317 318 /* For CNSS_GENL netlink sockets will be initialized by CNSS Kernel Module */ 319 int nl_srv_init(void *wiphy, int proto) 320 { 321 return 0; 322 } 323 324 void nl_srv_exit(void) 325 { 326 } 327 328 int nl_srv_is_initialized(void) 329 { 330 return 0; 331 } 332 333 /* Not implemented by CNSS kernel module */ 334 int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) 335 { 336 return 0; 337 } 338 339 int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) 340 { 341 return 0; 342 } 343 344 void *nl80211hdr_put(struct sk_buff *skb, uint32_t portid, 345 uint32_t seq, int flags, uint8_t cmd) 346 { 347 struct genl_family *cld80211_fam = cld80211_get_genl_family(); 348 349 return genlmsg_put(skb, portid, seq, cld80211_fam, flags, cmd); 350 } 351 352 /** 353 * cld80211_fill_data() - API to fill payload to nl message 354 * @msg: Sk buffer 355 * @portid: Port ID 356 * @seq: Sequence number 357 * @flags: Flags 358 * @cmd: Command ID 359 * @buf: data buffer/payload to be filled 360 * @len: length of the payload ie. @buf 361 * 362 * API to fill the payload/data of the nl message to be sent 363 * 364 * Return: zero on success 365 */ 366 static int cld80211_fill_data(struct sk_buff *msg, uint32_t portid, 367 uint32_t seq, int flags, uint8_t cmd, 368 uint8_t *buf, int len) 369 { 370 void *hdr; 371 struct nlattr *nest; 372 373 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd); 374 if (!hdr) { 375 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 376 "nl80211 hdr put failed"); 377 return -EPERM; 378 } 379 380 nest = nla_nest_start(msg, CLD80211_ATTR_VENDOR_DATA); 381 if (!nest) { 382 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 383 "nla_nest_start failed"); 384 goto nla_put_failure; 385 } 386 387 if (nla_put(msg, CLD80211_ATTR_DATA, len, buf)) { 388 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 389 "nla_put failed"); 390 goto nla_put_failure; 391 } 392 393 nla_nest_end(msg, nest); 394 genlmsg_end(msg, hdr); 395 396 return 0; 397 nla_put_failure: 398 genlmsg_cancel(msg, hdr); 399 return -EPERM; 400 } 401 402 /** 403 * send_msg_to_cld80211() - API to send message to user space Application 404 * @mcgroup_id: Multicast group ID 405 * @pid: Port ID 406 * @app_id: Application ID 407 * @buf: Data/payload buffer to be sent 408 * @len: Length of the data ie. @buf 409 * 410 * API to send the nl message to user space application. 411 * 412 * Return: zero on success 413 */ 414 static int send_msg_to_cld80211(int mcgroup_id, int pid, int app_id, 415 uint8_t *buf, int len) 416 { 417 struct sk_buff *msg; 418 struct genl_family *cld80211_fam = cld80211_get_genl_family(); 419 int status; 420 int flags = GFP_KERNEL; 421 422 if (in_interrupt() || irqs_disabled() || in_atomic()) 423 flags = GFP_ATOMIC; 424 425 if (len > NLMSG_DEFAULT_SIZE) { 426 if (len > WLAN_CLD80211_MAX_SIZE) { 427 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 428 "buf size:%d if more than max size: %d", 429 len, (int) WLAN_CLD80211_MAX_SIZE); 430 return -ENOMEM; 431 } 432 msg = nlmsg_new(WLAN_CLD80211_MAX_SIZE, flags); 433 } else { 434 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, flags); 435 } 436 if (!msg) { 437 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 438 "nlmsg malloc fails"); 439 return -EPERM; 440 } 441 442 status = cld80211_fill_data(msg, pid, 0, 0, app_id, buf, len); 443 if (status) { 444 nlmsg_free(msg); 445 return -EPERM; 446 } 447 448 genlmsg_multicast_netns(cld80211_fam, &init_net, msg, 0, 449 mcgroup_id, flags); 450 return 0; 451 } 452 453 /** 454 * nl_srv_bcast() - wrapper function to do broadcast events to user space apps 455 * @skb: the socket buffer to send 456 * @mcgroup_id: multicast group id 457 * @app_id: application id 458 * 459 * This function is common wrapper to send broadcast events to different 460 * user space applications. 461 * 462 * return: none 463 */ 464 int nl_srv_bcast(struct sk_buff *skb, int mcgroup_id, int app_id) 465 { 466 struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data; 467 void *msg = NLMSG_DATA(nlh); 468 uint32_t msg_len = nlmsg_len(nlh); 469 int status; 470 471 status = send_msg_to_cld80211(mcgroup_id, 0, app_id, msg, msg_len); 472 if (status) { 473 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 474 "send msg to cld80211 fails for app id %d", app_id); 475 dev_kfree_skb(skb); 476 return -EPERM; 477 } 478 479 dev_kfree_skb(skb); 480 return 0; 481 } 482 qdf_export_symbol(nl_srv_bcast); 483 484 /** 485 * nl_srv_ucast() - wrapper function to do unicast events to user space apps 486 * @skb: the socket buffer to send 487 * @dst_pid: destination process IF 488 * @flag: flags 489 * @app_id: application id 490 * @mcgroup_id: Multicast group ID 491 * 492 * This function is common wrapper to send unicast events to different 493 * user space applications. This internally used broadcast API with multicast 494 * group mcgrp_id. This wrapper serves as a common API in both 495 * new generic netlink infra and legacy implementation. 496 * 497 * return: zero on success, error code otherwise 498 */ 499 int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag, 500 int app_id, int mcgroup_id) 501 { 502 struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data; 503 void *msg = NLMSG_DATA(nlh); 504 uint32_t msg_len = nlmsg_len(nlh); 505 int status; 506 507 status = send_msg_to_cld80211(mcgroup_id, dst_pid, app_id, 508 msg, msg_len); 509 if (status) { 510 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 511 "send msg to cld80211 fails for app id %d", app_id); 512 dev_kfree_skb(skb); 513 return -EPERM; 514 } 515 516 dev_kfree_skb(skb); 517 return 0; 518 } 519 520 #elif !defined(MULTI_IF_NAME) || defined(MULTI_IF_LOG) 521 522 /* Global variables */ 523 static DEFINE_MUTEX(nl_srv_sem); 524 static struct sock *nl_srv_sock; 525 static nl_srv_msg_callback nl_srv_msg_handler[NLINK_MAX_CALLBACKS]; 526 527 /* Forward declaration */ 528 static void nl_srv_rcv(struct sk_buff *sk); 529 static void nl_srv_rcv_skb(struct sk_buff *skb); 530 static void nl_srv_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh); 531 532 /* 533 * Initialize the netlink service. 534 * Netlink service is usable after this. 535 */ 536 int nl_srv_init(void *wiphy, int proto) 537 { 538 int retcode = 0; 539 struct netlink_kernel_cfg cfg = { 540 .groups = WLAN_NLINK_MCAST_GRP_ID, 541 .input = nl_srv_rcv 542 }; 543 544 nl_srv_sock = netlink_kernel_create(&init_net, proto, 545 &cfg); 546 547 if (nl_srv_sock) { 548 memset(nl_srv_msg_handler, 0, sizeof(nl_srv_msg_handler)); 549 } else { 550 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 551 "NLINK: netlink_kernel_create failed"); 552 retcode = -ECONNREFUSED; 553 } 554 return retcode; 555 } 556 557 /* 558 * Deinit the netlink service. 559 * Netlink service is unusable after this. 560 */ 561 void nl_srv_exit(void) 562 { 563 if (nl_srv_is_initialized() == 0) 564 netlink_kernel_release(nl_srv_sock); 565 566 nl_srv_sock = NULL; 567 } 568 569 /* 570 * Register a message handler for a specified module. 571 * Each module (e.g. WLAN_NL_MSG_BTC )will register a 572 * handler to handle messages addressed to it. 573 */ 574 int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) 575 { 576 int retcode = 0; 577 578 if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) && 579 msg_handler) { 580 nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] = msg_handler; 581 } else { 582 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 583 "NLINK: nl_srv_register failed for msg_type %d", 584 msg_type); 585 retcode = -EINVAL; 586 } 587 588 return retcode; 589 } 590 591 qdf_export_symbol(nl_srv_register); 592 593 /* 594 * Unregister the message handler for a specified module. 595 */ 596 int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) 597 { 598 int retcode = 0; 599 600 if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) && 601 (nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] == msg_handler)) { 602 nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] = NULL; 603 } else { 604 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 605 "NLINK: nl_srv_unregister failed for msg_type %d", 606 msg_type); 607 retcode = -EINVAL; 608 } 609 610 return retcode; 611 } 612 613 /* 614 * Unicast the message to the process in user space identfied 615 * by the dst-pid 616 */ 617 int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag) 618 { 619 int err = -EINVAL; 620 621 NETLINK_CB(skb).portid = 0; /* sender's pid */ 622 NETLINK_CB(skb).dst_group = 0; /* not multicast */ 623 624 if (nl_srv_sock) { 625 err = netlink_unicast(nl_srv_sock, skb, dst_pid, flag); 626 if (err < 0) 627 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 628 "NLINK: netlink_unicast to pid[%d] failed, ret[%d]", 629 dst_pid, err); 630 } else { 631 dev_kfree_skb(skb); 632 } 633 634 return err; 635 } 636 637 /* 638 * Broadcast the message. Broadcast will return an error if 639 * there are no listeners 640 */ 641 int nl_srv_bcast(struct sk_buff *skb) 642 { 643 int err = -EINVAL; 644 int flags = GFP_KERNEL; 645 646 if (in_interrupt() || irqs_disabled() || in_atomic()) 647 flags = GFP_ATOMIC; 648 649 NETLINK_CB(skb).portid = 0; /* sender's pid */ 650 NETLINK_CB(skb).dst_group = WLAN_NLINK_MCAST_GRP_ID; /* destination group */ 651 652 if (nl_srv_sock) { 653 err = netlink_broadcast(nl_srv_sock, skb, 0, 654 WLAN_NLINK_MCAST_GRP_ID, flags); 655 if ((err < 0) && (err != -ESRCH)) { 656 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 657 "NLINK: netlink_broadcast failed err = %d", 658 err); 659 dev_kfree_skb(skb); 660 } 661 } else 662 dev_kfree_skb(skb); 663 return err; 664 } 665 qdf_export_symbol(nl_srv_bcast); 666 667 /* 668 * Processes the Netlink socket input queue. 669 * Dequeue skb's from the socket input queue and process 670 * all the netlink messages in that skb, before moving 671 * to the next skb. 672 */ 673 static void nl_srv_rcv(struct sk_buff *sk) 674 { 675 mutex_lock(&nl_srv_sem); 676 nl_srv_rcv_skb(sk); 677 mutex_unlock(&nl_srv_sem); 678 } 679 680 /* 681 * Each skb could contain multiple Netlink messages. Process all the 682 * messages in one skb and discard malformed skb's silently. 683 */ 684 static void nl_srv_rcv_skb(struct sk_buff *skb) 685 { 686 struct nlmsghdr *nlh; 687 688 while (skb->len >= NLMSG_SPACE(0)) { 689 u32 rlen; 690 691 nlh = (struct nlmsghdr *)skb->data; 692 693 if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) { 694 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 695 "NLINK: Invalid " 696 "Netlink message: skb[%pK], len[%d], nlhdr[%pK], nlmsg_len[%d]", 697 skb, skb->len, nlh, nlh->nlmsg_len); 698 return; 699 } 700 701 rlen = NLMSG_ALIGN(nlh->nlmsg_len); 702 if (rlen > skb->len) 703 rlen = skb->len; 704 nl_srv_rcv_msg(skb, nlh); 705 skb_pull(skb, rlen); 706 } 707 } 708 709 /* 710 * Process a netlink message. 711 * Each netlink message will have a message of type tAniMsgHdr inside. 712 */ 713 static void nl_srv_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 714 { 715 int type; 716 717 /* Only requests are handled by kernel now */ 718 if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) { 719 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 720 "NLINK: Received Invalid NL Req type [%x]", 721 nlh->nlmsg_flags); 722 return; 723 } 724 725 type = nlh->nlmsg_type; 726 727 /* Unknown message */ 728 if (type < WLAN_NL_MSG_BASE || type >= WLAN_NL_MSG_MAX) { 729 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 730 "NLINK: Received Invalid NL Msg type [%x]", type); 731 return; 732 } 733 734 /* 735 * All the messages must at least carry the tAniMsgHdr 736 * Drop any message with invalid length 737 */ 738 if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(tAniMsgHdr))) { 739 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 740 "NLINK: Received NL Msg with invalid len[%x]", 741 nlh->nlmsg_len); 742 return; 743 } 744 745 /* turn type into dispatch table offset */ 746 type -= WLAN_NL_MSG_BASE; 747 748 /* dispatch to handler */ 749 if (nl_srv_msg_handler[type]) { 750 (nl_srv_msg_handler[type])(skb); 751 } else { 752 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 753 "NLINK: No handler for Netlink Msg [0x%X]", type); 754 } 755 } 756 757 /** 758 * nl_srv_is_initialized() - This function is used check if the netlink 759 * service is initialized 760 * 761 * This function is used check if the netlink service is initialized 762 * 763 * Return: Return -EPERM if the service is not initialized 764 * 765 */ 766 int nl_srv_is_initialized(void) 767 { 768 if (nl_srv_sock) 769 return 0; 770 771 return -EPERM; 772 } 773 qdf_export_symbol(nl_srv_is_initialized); 774 775 #else 776 777 int nl_srv_init(void *wiphy, int proto) 778 { 779 return 0; 780 } 781 782 void nl_srv_exit(void) 783 { 784 } 785 786 int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) 787 { 788 return 0; 789 } 790 791 int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) 792 { 793 return 0; 794 } 795 796 int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag) 797 { 798 dev_kfree_skb(skb); 799 return 0; 800 } 801 802 int nl_srv_bcast(struct sk_buff *skb) 803 { 804 dev_kfree_skb(skb); 805 return 0; 806 } 807 qdf_export_symbol(nl_srv_bcast); 808 809 int nl_srv_is_initialized(void) 810 { 811 return -EPERM; 812 } 813 qdf_export_symbol(nl_srv_is_initialized); 814 #endif 815 816 /** 817 * nl_srv_ucast_oem() - Wrapper function to send ucast msgs to OEM 818 * @skb: sk buffer pointer 819 * @dst_pid: Destination PID 820 * @flag: flags 821 * 822 * Sends the ucast message to OEM with generic nl socket if CNSS_GENL 823 * is enabled. Else, use the legacy netlink socket to send. 824 * 825 * Return: None 826 */ 827 #ifdef CNSS_GENL 828 void nl_srv_ucast_oem(struct sk_buff *skb, int dst_pid, int flag) 829 { 830 nl_srv_ucast(skb, dst_pid, flag, WLAN_NL_MSG_OEM, 831 CLD80211_MCGRP_OEM_MSGS); 832 } 833 #else 834 void nl_srv_ucast_oem(struct sk_buff *skb, int dst_pid, int flag) 835 { 836 nl_srv_ucast(skb, dst_pid, flag); 837 } 838 839 qdf_export_symbol(nl_srv_ucast_oem); 840 #endif 841