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