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