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