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