1 /* 2 * Copyright (c) 2012-2021 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 #ifdef CONFIG_CNSS_OUT_OF_TREE 269 #include "cnss_nl.h" 270 #else 271 #include <net/cnss_nl.h> 272 #endif 273 274 void cld80211_oem_send_reply(struct sk_buff *msg, void *hdr, 275 struct nlattr *nest, int flags) 276 { 277 struct genl_family *cld80211_fam = cld80211_get_genl_family(); 278 279 nla_nest_end(msg, nest); 280 genlmsg_end(msg, hdr); 281 282 genlmsg_multicast_netns(cld80211_fam, &init_net, msg, 0, 283 CLD80211_MCGRP_OEM_MSGS, flags); 284 } 285 286 struct sk_buff * 287 cld80211_oem_rsp_alloc_skb(uint32_t portid, void **hdr, struct nlattr **nest, 288 int *flags) 289 { 290 struct sk_buff *msg; 291 292 if (in_interrupt() || irqs_disabled() || in_atomic()) 293 *flags = GFP_ATOMIC; 294 295 msg = nlmsg_new(WLAN_CLD80211_MAX_SIZE, *flags); 296 if (!msg) { 297 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 298 "nlmsg malloc fails"); 299 return NULL; 300 } 301 302 *hdr = nl80211hdr_put(msg, portid, 0, *flags, WLAN_NL_MSG_OEM); 303 if (*hdr == NULL) { 304 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 305 "nl80211 hdr put failed"); 306 goto nla_put_failure; 307 } 308 309 *nest = nla_nest_start(msg, CLD80211_ATTR_VENDOR_DATA); 310 if (*nest == NULL) { 311 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 312 "nla_nest_start failed"); 313 goto nla_put_failure; 314 } 315 return msg; 316 nla_put_failure: 317 genlmsg_cancel(msg, *hdr); 318 nlmsg_free(msg); 319 return NULL; 320 } 321 322 /* For CNSS_GENL netlink sockets will be initialized by CNSS Kernel Module */ 323 int nl_srv_init(void *wiphy, int proto) 324 { 325 return 0; 326 } 327 328 void nl_srv_exit(void) 329 { 330 } 331 332 int nl_srv_is_initialized(void) 333 { 334 return 0; 335 } 336 337 /* Not implemented by CNSS kernel module */ 338 int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) 339 { 340 return 0; 341 } 342 343 int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) 344 { 345 return 0; 346 } 347 348 void *nl80211hdr_put(struct sk_buff *skb, uint32_t portid, 349 uint32_t seq, int flags, uint8_t cmd) 350 { 351 struct genl_family *cld80211_fam = cld80211_get_genl_family(); 352 353 return genlmsg_put(skb, portid, seq, cld80211_fam, flags, cmd); 354 } 355 356 /** 357 * cld80211_fill_data() - API to fill payload to nl message 358 * @msg: Sk buffer 359 * @portid: Port ID 360 * @seq: Sequence number 361 * @flags: Flags 362 * @cmd: Command ID 363 * @buf: data buffer/payload to be filled 364 * @len: length of the payload ie. @buf 365 * 366 * API to fill the payload/data of the nl message to be sent 367 * 368 * Return: zero on success 369 */ 370 static int cld80211_fill_data(struct sk_buff *msg, uint32_t portid, 371 uint32_t seq, int flags, uint8_t cmd, 372 uint8_t *buf, int len) 373 { 374 void *hdr; 375 struct nlattr *nest; 376 377 hdr = nl80211hdr_put(msg, portid, seq, flags, cmd); 378 if (!hdr) { 379 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 380 "nl80211 hdr put failed"); 381 return -EPERM; 382 } 383 384 nest = nla_nest_start(msg, CLD80211_ATTR_VENDOR_DATA); 385 if (!nest) { 386 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 387 "nla_nest_start failed"); 388 goto nla_put_failure; 389 } 390 391 if (nla_put(msg, CLD80211_ATTR_DATA, len, buf)) { 392 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 393 "nla_put failed"); 394 goto nla_put_failure; 395 } 396 397 nla_nest_end(msg, nest); 398 genlmsg_end(msg, hdr); 399 400 return 0; 401 nla_put_failure: 402 genlmsg_cancel(msg, hdr); 403 return -EPERM; 404 } 405 406 /** 407 * send_msg_to_cld80211() - API to send message to user space Application 408 * @mcgroup_id: Multicast group ID 409 * @pid: Port ID 410 * @app_id: Application ID 411 * @buf: Data/payload buffer to be sent 412 * @len: Length of the data ie. @buf 413 * 414 * API to send the nl message to user space application. 415 * 416 * Return: zero on success 417 */ 418 static int send_msg_to_cld80211(int mcgroup_id, int pid, int app_id, 419 uint8_t *buf, int len) 420 { 421 struct sk_buff *msg; 422 struct genl_family *cld80211_fam = cld80211_get_genl_family(); 423 int status; 424 int flags = GFP_KERNEL; 425 426 if (in_interrupt() || irqs_disabled() || in_atomic()) 427 flags = GFP_ATOMIC; 428 429 if (len > NLMSG_DEFAULT_SIZE) { 430 if (len > WLAN_CLD80211_MAX_SIZE) { 431 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 432 "buf size:%d if more than max size: %d", 433 len, (int) WLAN_CLD80211_MAX_SIZE); 434 return -ENOMEM; 435 } 436 msg = nlmsg_new(WLAN_CLD80211_MAX_SIZE, flags); 437 } else { 438 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, flags); 439 } 440 if (!msg) { 441 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 442 "nlmsg malloc fails"); 443 return -EPERM; 444 } 445 446 status = cld80211_fill_data(msg, pid, 0, 0, app_id, buf, len); 447 if (status) { 448 nlmsg_free(msg); 449 return -EPERM; 450 } 451 452 genlmsg_multicast_netns(cld80211_fam, &init_net, msg, 0, 453 mcgroup_id, flags); 454 return 0; 455 } 456 457 /** 458 * nl_srv_bcast() - wrapper function to do broadcast events to user space apps 459 * @skb: the socket buffer to send 460 * @mcgroup_id: multicast group id 461 * @app_id: application id 462 * 463 * This function is common wrapper to send broadcast events to different 464 * user space applications. 465 * 466 * return: none 467 */ 468 int nl_srv_bcast(struct sk_buff *skb, int mcgroup_id, int app_id) 469 { 470 struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data; 471 void *msg = NLMSG_DATA(nlh); 472 uint32_t msg_len = nlmsg_len(nlh); 473 int status; 474 475 status = send_msg_to_cld80211(mcgroup_id, 0, app_id, msg, msg_len); 476 if (status) { 477 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 478 "send msg to cld80211 fails for app id %d", app_id); 479 dev_kfree_skb(skb); 480 return -EPERM; 481 } 482 483 dev_kfree_skb(skb); 484 return 0; 485 } 486 qdf_export_symbol(nl_srv_bcast); 487 488 /** 489 * nl_srv_ucast() - wrapper function to do unicast events to user space apps 490 * @skb: the socket buffer to send 491 * @dst_pid: destination process IF 492 * @flag: flags 493 * @app_id: application id 494 * @mcgroup_id: Multicast group ID 495 * 496 * This function is common wrapper to send unicast events to different 497 * user space applications. This internally used broadcast API with multicast 498 * group mcgrp_id. This wrapper serves as a common API in both 499 * new generic netlink infra and legacy implementation. 500 * 501 * return: zero on success, error code otherwise 502 */ 503 int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag, 504 int app_id, int mcgroup_id) 505 { 506 struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data; 507 void *msg = NLMSG_DATA(nlh); 508 uint32_t msg_len = nlmsg_len(nlh); 509 int status; 510 511 status = send_msg_to_cld80211(mcgroup_id, dst_pid, app_id, 512 msg, msg_len); 513 if (status) { 514 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 515 "send msg to cld80211 fails for app id %d", app_id); 516 dev_kfree_skb(skb); 517 return -EPERM; 518 } 519 520 dev_kfree_skb(skb); 521 return 0; 522 } 523 524 #elif !defined(MULTI_IF_NAME) || defined(MULTI_IF_LOG) 525 526 /* Global variables */ 527 static DEFINE_MUTEX(nl_srv_sem); 528 static struct sock *nl_srv_sock; 529 static nl_srv_msg_callback nl_srv_msg_handler[NLINK_MAX_CALLBACKS]; 530 531 /* Forward declaration */ 532 static void nl_srv_rcv(struct sk_buff *sk); 533 static void nl_srv_rcv_skb(struct sk_buff *skb); 534 static void nl_srv_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh); 535 536 /* 537 * Initialize the netlink service. 538 * Netlink service is usable after this. 539 */ 540 int nl_srv_init(void *wiphy, int proto) 541 { 542 int retcode = 0; 543 struct netlink_kernel_cfg cfg = { 544 .groups = WLAN_NLINK_MCAST_GRP_ID, 545 .input = nl_srv_rcv 546 }; 547 548 nl_srv_sock = netlink_kernel_create(&init_net, proto, 549 &cfg); 550 551 if (nl_srv_sock) { 552 memset(nl_srv_msg_handler, 0, sizeof(nl_srv_msg_handler)); 553 } else { 554 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, 555 "NLINK: netlink_kernel_create failed"); 556 retcode = -ECONNREFUSED; 557 } 558 return retcode; 559 } 560 561 /* 562 * Deinit the netlink service. 563 * Netlink service is unusable after this. 564 */ 565 void nl_srv_exit(void) 566 { 567 if (nl_srv_is_initialized() == 0) 568 netlink_kernel_release(nl_srv_sock); 569 570 nl_srv_sock = NULL; 571 } 572 573 /* 574 * Register a message handler for a specified module. 575 * Each module (e.g. WLAN_NL_MSG_BTC )will register a 576 * handler to handle messages addressed to it. 577 */ 578 int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) 579 { 580 int retcode = 0; 581 582 if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) && 583 msg_handler) { 584 nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] = msg_handler; 585 } else { 586 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 587 "NLINK: nl_srv_register failed for msg_type %d", 588 msg_type); 589 retcode = -EINVAL; 590 } 591 592 return retcode; 593 } 594 595 qdf_export_symbol(nl_srv_register); 596 597 /* 598 * Unregister the message handler for a specified module. 599 */ 600 int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) 601 { 602 int retcode = 0; 603 604 if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) && 605 (nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] == msg_handler)) { 606 nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] = NULL; 607 } else { 608 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 609 "NLINK: nl_srv_unregister failed for msg_type %d", 610 msg_type); 611 retcode = -EINVAL; 612 } 613 614 return retcode; 615 } 616 617 /* 618 * Unicast the message to the process in user space identfied 619 * by the dst-pid 620 */ 621 int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag) 622 { 623 int err = -EINVAL; 624 625 NETLINK_CB(skb).portid = 0; /* sender's pid */ 626 NETLINK_CB(skb).dst_group = 0; /* not multicast */ 627 628 if (nl_srv_sock) { 629 err = netlink_unicast(nl_srv_sock, skb, dst_pid, flag); 630 if (err < 0) 631 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 632 "NLINK: netlink_unicast to pid[%d] failed, ret[%d]", 633 dst_pid, err); 634 } else { 635 dev_kfree_skb(skb); 636 } 637 638 return err; 639 } 640 641 /* 642 * Broadcast the message. Broadcast will return an error if 643 * there are no listeners 644 */ 645 int nl_srv_bcast(struct sk_buff *skb) 646 { 647 int err = -EINVAL; 648 int flags = GFP_KERNEL; 649 650 if (in_interrupt() || irqs_disabled() || in_atomic()) 651 flags = GFP_ATOMIC; 652 653 NETLINK_CB(skb).portid = 0; /* sender's pid */ 654 NETLINK_CB(skb).dst_group = WLAN_NLINK_MCAST_GRP_ID; /* destination group */ 655 656 if (nl_srv_sock) { 657 err = netlink_broadcast(nl_srv_sock, skb, 0, 658 WLAN_NLINK_MCAST_GRP_ID, flags); 659 if ((err < 0) && (err != -ESRCH)) { 660 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 661 "NLINK: netlink_broadcast failed err = %d", 662 err); 663 dev_kfree_skb(skb); 664 } 665 } else 666 dev_kfree_skb(skb); 667 return err; 668 } 669 qdf_export_symbol(nl_srv_bcast); 670 671 /* 672 * Processes the Netlink socket input queue. 673 * Dequeue skb's from the socket input queue and process 674 * all the netlink messages in that skb, before moving 675 * to the next skb. 676 */ 677 static void nl_srv_rcv(struct sk_buff *sk) 678 { 679 mutex_lock(&nl_srv_sem); 680 nl_srv_rcv_skb(sk); 681 mutex_unlock(&nl_srv_sem); 682 } 683 684 /* 685 * Each skb could contain multiple Netlink messages. Process all the 686 * messages in one skb and discard malformed skb's silently. 687 */ 688 static void nl_srv_rcv_skb(struct sk_buff *skb) 689 { 690 struct nlmsghdr *nlh; 691 692 while (skb->len >= NLMSG_SPACE(0)) { 693 u32 rlen; 694 695 nlh = (struct nlmsghdr *)skb->data; 696 697 if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) { 698 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 699 "NLINK: Invalid " 700 "Netlink message: skb[%pK], len[%d], nlhdr[%pK], nlmsg_len[%d]", 701 skb, skb->len, nlh, nlh->nlmsg_len); 702 return; 703 } 704 705 rlen = NLMSG_ALIGN(nlh->nlmsg_len); 706 if (rlen > skb->len) 707 rlen = skb->len; 708 nl_srv_rcv_msg(skb, nlh); 709 skb_pull(skb, rlen); 710 } 711 } 712 713 /* 714 * Process a netlink message. 715 * Each netlink message will have a message of type tAniMsgHdr inside. 716 */ 717 static void nl_srv_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 718 { 719 int type; 720 721 /* Only requests are handled by kernel now */ 722 if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) { 723 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 724 "NLINK: Received Invalid NL Req type [%x]", 725 nlh->nlmsg_flags); 726 return; 727 } 728 729 type = nlh->nlmsg_type; 730 731 /* Unknown message */ 732 if (type < WLAN_NL_MSG_BASE || type >= WLAN_NL_MSG_MAX) { 733 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 734 "NLINK: Received Invalid NL Msg type [%x]", type); 735 return; 736 } 737 738 /* 739 * All the messages must at least carry the tAniMsgHdr 740 * Drop any message with invalid length 741 */ 742 if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(tAniMsgHdr))) { 743 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 744 "NLINK: Received NL Msg with invalid len[%x]", 745 nlh->nlmsg_len); 746 return; 747 } 748 749 /* turn type into dispatch table offset */ 750 type -= WLAN_NL_MSG_BASE; 751 752 /* dispatch to handler */ 753 if (nl_srv_msg_handler[type]) { 754 (nl_srv_msg_handler[type])(skb); 755 } else { 756 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, 757 "NLINK: No handler for Netlink Msg [0x%X]", type); 758 } 759 } 760 761 /** 762 * nl_srv_is_initialized() - This function is used check if the netlink 763 * service is initialized 764 * 765 * This function is used check if the netlink service is initialized 766 * 767 * Return: Return -EPERM if the service is not initialized 768 * 769 */ 770 int nl_srv_is_initialized(void) 771 { 772 if (nl_srv_sock) 773 return 0; 774 775 return -EPERM; 776 } 777 qdf_export_symbol(nl_srv_is_initialized); 778 779 #else 780 781 int nl_srv_init(void *wiphy, int proto) 782 { 783 return 0; 784 } 785 786 void nl_srv_exit(void) 787 { 788 } 789 790 int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) 791 { 792 return 0; 793 } 794 795 int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) 796 { 797 return 0; 798 } 799 800 int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag) 801 { 802 dev_kfree_skb(skb); 803 return 0; 804 } 805 806 int nl_srv_bcast(struct sk_buff *skb) 807 { 808 dev_kfree_skb(skb); 809 return 0; 810 } 811 qdf_export_symbol(nl_srv_bcast); 812 813 int nl_srv_is_initialized(void) 814 { 815 return -EPERM; 816 } 817 qdf_export_symbol(nl_srv_is_initialized); 818 #endif 819 820 /** 821 * nl_srv_ucast_oem() - Wrapper function to send ucast msgs to OEM 822 * @skb: sk buffer pointer 823 * @dst_pid: Destination PID 824 * @flag: flags 825 * 826 * Sends the ucast message to OEM with generic nl socket if CNSS_GENL 827 * is enabled. Else, use the legacy netlink socket to send. 828 * 829 * Return: None 830 */ 831 #ifdef CNSS_GENL 832 void nl_srv_ucast_oem(struct sk_buff *skb, int dst_pid, int flag) 833 { 834 nl_srv_ucast(skb, dst_pid, flag, WLAN_NL_MSG_OEM, 835 CLD80211_MCGRP_OEM_MSGS); 836 } 837 #else 838 void nl_srv_ucast_oem(struct sk_buff *skb, int dst_pid, int flag) 839 { 840 nl_srv_ucast(skb, dst_pid, flag); 841 } 842 843 qdf_export_symbol(nl_srv_ucast_oem); 844 #endif 845