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