xref: /wlan-dirver/qca-wifi-host-cmn/utils/nlink/src/wlan_nlink_srv.c (revision a86b23ee68a2491aede2e03991f3fb37046f4e41)
1 /*
2  * Copyright (c) 2012-2020 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 void cld80211_oem_send_reply(struct sk_buff *msg, void *hdr,
271 				    struct nlattr *nest, int flags)
272 {
273 	struct genl_family *cld80211_fam = cld80211_get_genl_family();
274 
275 	nla_nest_end(msg, nest);
276 	genlmsg_end(msg, hdr);
277 
278 	genlmsg_multicast_netns(cld80211_fam, &init_net, msg, 0,
279 				CLD80211_MCGRP_OEM_MSGS, flags);
280 }
281 
282 struct sk_buff *
283 cld80211_oem_rsp_alloc_skb(uint32_t portid, void **hdr, struct nlattr **nest,
284 			   int *flags)
285 {
286 	static struct sk_buff *msg;
287 
288 	if (in_interrupt() || irqs_disabled() || in_atomic())
289 		*flags = GFP_ATOMIC;
290 
291 	msg = nlmsg_new(WLAN_CLD80211_MAX_SIZE, *flags);
292 	if (!msg) {
293 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
294 					"nlmsg malloc fails");
295 		return NULL;
296 	}
297 
298 	*hdr = nl80211hdr_put(msg, portid, 0, *flags, WLAN_NL_MSG_OEM);
299 	if (*hdr == NULL) {
300 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
301 					"nl80211 hdr put failed");
302 		goto nla_put_failure;
303 	}
304 
305 	*nest = nla_nest_start(msg, CLD80211_ATTR_VENDOR_DATA);
306 	if (*nest == NULL) {
307 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
308 					"nla_nest_start failed");
309 		goto nla_put_failure;
310 	}
311 	return msg;
312 nla_put_failure:
313 	genlmsg_cancel(msg, *hdr);
314 	nlmsg_free(msg);
315 	return NULL;
316 }
317 
318 /* For CNSS_GENL netlink sockets will be initialized by CNSS Kernel Module */
319 int nl_srv_init(void *wiphy, int proto)
320 {
321 	return 0;
322 }
323 
324 void nl_srv_exit(void)
325 {
326 }
327 
328 int nl_srv_is_initialized(void)
329 {
330 	return 0;
331 }
332 
333 /* Not implemented by CNSS kernel module */
334 int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
335 {
336 	return 0;
337 }
338 
339 int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
340 {
341 	return 0;
342 }
343 
344 void *nl80211hdr_put(struct sk_buff *skb, uint32_t portid,
345 		     uint32_t seq, int flags, uint8_t cmd)
346 {
347 	struct genl_family *cld80211_fam = cld80211_get_genl_family();
348 
349 	return genlmsg_put(skb, portid, seq, cld80211_fam, flags, cmd);
350 }
351 
352 /**
353  * cld80211_fill_data() - API to fill payload to nl message
354  * @msg: Sk buffer
355  * @portid: Port ID
356  * @seq: Sequence number
357  * @flags: Flags
358  * @cmd: Command ID
359  * @buf: data buffer/payload to be filled
360  * @len: length of the payload ie. @buf
361  *
362  * API to fill the payload/data of the nl message to be sent
363  *
364  * Return: zero on success
365  */
366 static int cld80211_fill_data(struct sk_buff *msg, uint32_t portid,
367 					uint32_t seq, int flags, uint8_t cmd,
368 					uint8_t *buf, int len)
369 {
370 	void *hdr;
371 	struct nlattr *nest;
372 
373 	hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
374 	if (!hdr) {
375 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
376 						"nl80211 hdr put failed");
377 		return -EPERM;
378 	}
379 
380 	nest = nla_nest_start(msg, CLD80211_ATTR_VENDOR_DATA);
381 	if (!nest) {
382 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
383 						"nla_nest_start failed");
384 		goto nla_put_failure;
385 	}
386 
387 	if (nla_put(msg, CLD80211_ATTR_DATA, len, buf)) {
388 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
389 							"nla_put failed");
390 		goto nla_put_failure;
391 	}
392 
393 	nla_nest_end(msg, nest);
394 	genlmsg_end(msg, hdr);
395 
396 	return 0;
397 nla_put_failure:
398 	genlmsg_cancel(msg, hdr);
399 	return -EPERM;
400 }
401 
402 /**
403  * send_msg_to_cld80211() - API to send message to user space Application
404  * @mcgroup_id: Multicast group ID
405  * @pid: Port ID
406  * @app_id: Application ID
407  * @buf: Data/payload buffer to be sent
408  * @len: Length of the data ie. @buf
409  *
410  * API to send the nl message to user space application.
411  *
412  * Return: zero on success
413  */
414 static int send_msg_to_cld80211(int mcgroup_id, int pid, int app_id,
415 						uint8_t *buf, int len)
416 {
417 	struct sk_buff *msg;
418 	struct genl_family *cld80211_fam = cld80211_get_genl_family();
419 	int status;
420 	int flags = GFP_KERNEL;
421 
422 	if (in_interrupt() || irqs_disabled() || in_atomic())
423 		flags = GFP_ATOMIC;
424 
425 	if (len > NLMSG_DEFAULT_SIZE) {
426 		if (len > WLAN_CLD80211_MAX_SIZE) {
427 			QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
428 				"buf size:%d if more than max size: %d",
429 				len, (int) WLAN_CLD80211_MAX_SIZE);
430 			return -ENOMEM;
431 		}
432 		msg = nlmsg_new(WLAN_CLD80211_MAX_SIZE, flags);
433 	} else {
434 		msg = nlmsg_new(NLMSG_DEFAULT_SIZE, flags);
435 	}
436 	if (!msg) {
437 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
438 						"nlmsg malloc fails");
439 		return -EPERM;
440 	}
441 
442 	status = cld80211_fill_data(msg, pid, 0, 0, app_id, buf, len);
443 	if (status) {
444 		nlmsg_free(msg);
445 		return -EPERM;
446 	}
447 
448 	genlmsg_multicast_netns(cld80211_fam, &init_net, msg, 0,
449 						mcgroup_id, flags);
450 	return 0;
451 }
452 
453 /**
454  * nl_srv_bcast() - wrapper function to do broadcast events to user space apps
455  * @skb: the socket buffer to send
456  * @mcgroup_id: multicast group id
457  * @app_id: application id
458  *
459  * This function is common wrapper to send broadcast events to different
460  * user space applications.
461  *
462  * return: none
463  */
464 int nl_srv_bcast(struct sk_buff *skb, int mcgroup_id, int app_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, 0, app_id, msg, msg_len);
472 	if (status) {
473 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
474 			"send msg to cld80211 fails for app id %d", app_id);
475 		dev_kfree_skb(skb);
476 		return -EPERM;
477 	}
478 
479 	dev_kfree_skb(skb);
480 	return 0;
481 }
482 qdf_export_symbol(nl_srv_bcast);
483 
484 /**
485  * nl_srv_ucast() - wrapper function to do unicast events to user space apps
486  * @skb: the socket buffer to send
487  * @dst_pid: destination process IF
488  * @flag: flags
489  * @app_id: application id
490  * @mcgroup_id: Multicast group ID
491  *
492  * This function is common wrapper to send unicast events to different
493  * user space applications. This internally used broadcast API with multicast
494  * group mcgrp_id. This wrapper serves as a common API in both
495  * new generic netlink infra and legacy implementation.
496  *
497  * return: zero on success, error code otherwise
498  */
499 int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag,
500 					int app_id, int mcgroup_id)
501 {
502 	struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data;
503 	void *msg = NLMSG_DATA(nlh);
504 	uint32_t msg_len = nlmsg_len(nlh);
505 	int status;
506 
507 	status = send_msg_to_cld80211(mcgroup_id, dst_pid, app_id,
508 					msg, msg_len);
509 	if (status) {
510 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
511 			"send msg to cld80211 fails for app id %d", app_id);
512 		dev_kfree_skb(skb);
513 		return -EPERM;
514 	}
515 
516 	dev_kfree_skb(skb);
517 	return 0;
518 }
519 
520 #elif !defined(MULTI_IF_NAME) || defined(MULTI_IF_LOG)
521 
522 /* Global variables */
523 static DEFINE_MUTEX(nl_srv_sem);
524 static struct sock *nl_srv_sock;
525 static nl_srv_msg_callback nl_srv_msg_handler[NLINK_MAX_CALLBACKS];
526 
527 /* Forward declaration */
528 static void nl_srv_rcv(struct sk_buff *sk);
529 static void nl_srv_rcv_skb(struct sk_buff *skb);
530 static void nl_srv_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh);
531 
532 /*
533  * Initialize the netlink service.
534  * Netlink service is usable after this.
535  */
536 int nl_srv_init(void *wiphy, int proto)
537 {
538 	int retcode = 0;
539 	struct netlink_kernel_cfg cfg = {
540 		.groups = WLAN_NLINK_MCAST_GRP_ID,
541 		.input = nl_srv_rcv
542 	};
543 
544 	nl_srv_sock = netlink_kernel_create(&init_net, proto,
545 					    &cfg);
546 
547 	if (nl_srv_sock) {
548 		memset(nl_srv_msg_handler, 0, sizeof(nl_srv_msg_handler));
549 	} else {
550 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
551 			  "NLINK: netlink_kernel_create failed");
552 		retcode = -ECONNREFUSED;
553 	}
554 	return retcode;
555 }
556 
557 /*
558  * Deinit the netlink service.
559  * Netlink service is unusable after this.
560  */
561 void nl_srv_exit(void)
562 {
563 	if (nl_srv_is_initialized() == 0)
564 		netlink_kernel_release(nl_srv_sock);
565 
566 	nl_srv_sock = NULL;
567 }
568 
569 /*
570  * Register a message handler for a specified module.
571  * Each module (e.g. WLAN_NL_MSG_BTC )will register a
572  * handler to handle messages addressed to it.
573  */
574 int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
575 {
576 	int retcode = 0;
577 
578 	if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) &&
579 	    msg_handler) {
580 		nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] = msg_handler;
581 	} else {
582 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
583 			  "NLINK: nl_srv_register failed for msg_type %d",
584 			  msg_type);
585 		retcode = -EINVAL;
586 	}
587 
588 	return retcode;
589 }
590 
591 qdf_export_symbol(nl_srv_register);
592 
593 /*
594  * Unregister the message handler for a specified module.
595  */
596 int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
597 {
598 	int retcode = 0;
599 
600 	if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) &&
601 	    (nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] == msg_handler)) {
602 		nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] = NULL;
603 	} else {
604 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
605 			  "NLINK: nl_srv_unregister failed for msg_type %d",
606 			  msg_type);
607 		retcode = -EINVAL;
608 	}
609 
610 	return retcode;
611 }
612 
613 /*
614  * Unicast the message to the process in user space identfied
615  * by the dst-pid
616  */
617 int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag)
618 {
619 	int err = -EINVAL;
620 
621 	NETLINK_CB(skb).portid = 0;     /* sender's pid */
622 	NETLINK_CB(skb).dst_group = 0;  /* not multicast */
623 
624 	if (nl_srv_sock) {
625 		err = netlink_unicast(nl_srv_sock, skb, dst_pid, flag);
626 		if (err < 0)
627 			QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
628 				  "NLINK: netlink_unicast to pid[%d] failed, ret[%d]",
629 				  dst_pid, err);
630 	} else {
631 		dev_kfree_skb(skb);
632 	}
633 
634 	return err;
635 }
636 
637 /*
638  *  Broadcast the message. Broadcast will return an error if
639  *  there are no listeners
640  */
641 int nl_srv_bcast(struct sk_buff *skb)
642 {
643 	int err = -EINVAL;
644 	int flags = GFP_KERNEL;
645 
646 	if (in_interrupt() || irqs_disabled() || in_atomic())
647 		flags = GFP_ATOMIC;
648 
649 	NETLINK_CB(skb).portid = 0;     /* sender's pid */
650 	NETLINK_CB(skb).dst_group = WLAN_NLINK_MCAST_GRP_ID;    /* destination group */
651 
652 	if (nl_srv_sock) {
653 		err = netlink_broadcast(nl_srv_sock, skb, 0,
654 					WLAN_NLINK_MCAST_GRP_ID, flags);
655 		if ((err < 0) && (err != -ESRCH)) {
656 			QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
657 				  "NLINK: netlink_broadcast failed err = %d",
658 				   err);
659 			dev_kfree_skb(skb);
660 		}
661 	} else
662 		dev_kfree_skb(skb);
663 	return err;
664 }
665 qdf_export_symbol(nl_srv_bcast);
666 
667 /*
668  *  Processes the Netlink socket input queue.
669  *  Dequeue skb's from the socket input queue and process
670  *  all the netlink messages in that skb, before moving
671  *  to the next skb.
672  */
673 static void nl_srv_rcv(struct sk_buff *sk)
674 {
675 	mutex_lock(&nl_srv_sem);
676 	nl_srv_rcv_skb(sk);
677 	mutex_unlock(&nl_srv_sem);
678 }
679 
680 /*
681  * Each skb could contain multiple Netlink messages. Process all the
682  * messages in one skb and discard malformed skb's silently.
683  */
684 static void nl_srv_rcv_skb(struct sk_buff *skb)
685 {
686 	struct nlmsghdr *nlh;
687 
688 	while (skb->len >= NLMSG_SPACE(0)) {
689 		u32 rlen;
690 
691 		nlh = (struct nlmsghdr *)skb->data;
692 
693 		if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) {
694 			QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
695 				  "NLINK: Invalid "
696 				  "Netlink message: skb[%pK], len[%d], nlhdr[%pK], nlmsg_len[%d]",
697 				  skb, skb->len, nlh, nlh->nlmsg_len);
698 			return;
699 		}
700 
701 		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
702 		if (rlen > skb->len)
703 			rlen = skb->len;
704 		nl_srv_rcv_msg(skb, nlh);
705 		skb_pull(skb, rlen);
706 	}
707 }
708 
709 /*
710  * Process a netlink message.
711  * Each netlink message will have a message of type tAniMsgHdr inside.
712  */
713 static void nl_srv_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
714 {
715 	int type;
716 
717 	/* Only requests are handled by kernel now */
718 	if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) {
719 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
720 			  "NLINK: Received Invalid NL Req type [%x]",
721 			  nlh->nlmsg_flags);
722 		return;
723 	}
724 
725 	type = nlh->nlmsg_type;
726 
727 	/* Unknown message */
728 	if (type < WLAN_NL_MSG_BASE || type >= WLAN_NL_MSG_MAX) {
729 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
730 			  "NLINK: Received Invalid NL Msg type [%x]", type);
731 		return;
732 	}
733 
734 	/*
735 	 * All the messages must at least carry the tAniMsgHdr
736 	 * Drop any message with invalid length
737 	 */
738 	if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(tAniMsgHdr))) {
739 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
740 			  "NLINK: Received NL Msg with invalid len[%x]",
741 			  nlh->nlmsg_len);
742 		return;
743 	}
744 
745 	/* turn type into dispatch table offset */
746 	type -= WLAN_NL_MSG_BASE;
747 
748 	/* dispatch to handler */
749 	if (nl_srv_msg_handler[type]) {
750 		(nl_srv_msg_handler[type])(skb);
751 	} else {
752 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
753 			  "NLINK: No handler for Netlink Msg [0x%X]", type);
754 	}
755 }
756 
757 /**
758  * nl_srv_is_initialized() - This function is used check if the netlink
759  * service is initialized
760  *
761  * This function is used check if the netlink service is initialized
762  *
763  * Return: Return -EPERM if the service is not initialized
764  *
765  */
766 int nl_srv_is_initialized(void)
767 {
768 	if (nl_srv_sock)
769 		return 0;
770 
771 	return -EPERM;
772 }
773 qdf_export_symbol(nl_srv_is_initialized);
774 
775 #else
776 
777 int nl_srv_init(void *wiphy, int proto)
778 {
779 	return 0;
780 }
781 
782 void nl_srv_exit(void)
783 {
784 }
785 
786 int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
787 {
788 	return 0;
789 }
790 
791 int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
792 {
793 	return 0;
794 }
795 
796 int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag)
797 {
798 	dev_kfree_skb(skb);
799 	return 0;
800 }
801 
802 int nl_srv_bcast(struct sk_buff *skb)
803 {
804 	dev_kfree_skb(skb);
805 	return 0;
806 }
807 qdf_export_symbol(nl_srv_bcast);
808 
809 int nl_srv_is_initialized(void)
810 {
811 	return -EPERM;
812 }
813 qdf_export_symbol(nl_srv_is_initialized);
814 #endif
815 
816 /**
817  * nl_srv_ucast_oem() - Wrapper function to send ucast msgs to OEM
818  * @skb: sk buffer pointer
819  * @dst_pid: Destination PID
820  * @flag: flags
821  *
822  * Sends the ucast message to OEM with generic nl socket if CNSS_GENL
823  * is enabled. Else, use the legacy netlink socket to send.
824  *
825  * Return: None
826  */
827 #ifdef CNSS_GENL
828 void nl_srv_ucast_oem(struct sk_buff *skb, int dst_pid, int flag)
829 {
830 	nl_srv_ucast(skb, dst_pid, flag, WLAN_NL_MSG_OEM,
831 					CLD80211_MCGRP_OEM_MSGS);
832 }
833 #else
834 void nl_srv_ucast_oem(struct sk_buff *skb, int dst_pid, int flag)
835 {
836 	nl_srv_ucast(skb, dst_pid, flag);
837 }
838 
839 qdf_export_symbol(nl_srv_ucast_oem);
840 #endif
841