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