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