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