xref: /wlan-dirver/qca-wifi-host-cmn/utils/nlink/src/wlan_nlink_srv.c (revision 503663c6daafffe652fa360bde17243568cd6d2a)
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