wlan_nlink_srv.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. /*
  2. * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
  3. *
  4. * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  5. *
  6. *
  7. * Permission to use, copy, modify, and/or distribute this software for
  8. * any purpose with or without fee is hereby granted, provided that the
  9. * above copyright notice and this permission notice appear in all
  10. * copies.
  11. *
  12. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  13. * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
  14. * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
  15. * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  16. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  17. * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  18. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  19. * PERFORMANCE OF THIS SOFTWARE.
  20. */
  21. /*
  22. * This file was originally distributed by Qualcomm Atheros, Inc.
  23. * under proprietary terms before Copyright ownership was assigned
  24. * to the Linux Foundation.
  25. */
  26. /******************************************************************************
  27. * wlan_nlink_srv.c
  28. *
  29. * This file contains the definitions specific to the wlan_nlink_srv
  30. *
  31. ******************************************************************************/
  32. /*
  33. * If MULTI_IF_NAME is not defined, then this is the primary instance of the
  34. * driver and the diagnostics netlink socket will be available. If
  35. * MULTI_IF_NAME is defined then this is not the primary instance of the driver
  36. * and the diagnotics netlink socket will not be available since this
  37. * diagnostics netlink socket can only be exposed by one instance of the driver.
  38. */
  39. #ifndef MULTI_IF_NAME
  40. #include <linux/version.h>
  41. #include <linux/kernel.h>
  42. #include <linux/module.h>
  43. #include <linux/init.h>
  44. #include <linux/netdevice.h>
  45. #include <linux/netlink.h>
  46. #include <linux/skbuff.h>
  47. #include <net/sock.h>
  48. #include <wlan_nlink_srv.h>
  49. #include <qdf_trace.h>
  50. #if defined(CONFIG_CNSS_LOGGER)
  51. #include <net/cnss_logger.h>
  52. static int radio_idx = -EINVAL;
  53. static void *wiphy_ptr;
  54. static bool logger_initialized;
  55. /**
  56. * nl_srv_init() - wrapper function to register to cnss_logger
  57. * @wiphy: the pointer to the wiphy structure
  58. *
  59. * The netlink socket is no longer initialized in the driver itself, instead
  60. * will be initialized in the cnss_logger module, the driver should register
  61. * itself to cnss_logger module to get the radio_index for all the netlink
  62. * operation. (cfg80211 vendor command is using different netlink socket).
  63. *
  64. * The cnss_logger_device_register() use to register the driver with the
  65. * wiphy structure and the module name (debug purpose) and then return the
  66. * radio_index depending on the availibility.
  67. *
  68. * Return: radio index for success and -EINVAL for failure
  69. */
  70. int nl_srv_init(void *wiphy)
  71. {
  72. if (logger_initialized)
  73. goto initialized;
  74. wiphy_ptr = wiphy;
  75. radio_idx = cnss_logger_device_register(wiphy, THIS_MODULE->name);
  76. QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
  77. "%s: radio_index: %d, wiphy_ptr: %p",
  78. __func__, radio_idx, wiphy_ptr);
  79. if (radio_idx >= 0)
  80. logger_initialized = true;
  81. initialized:
  82. return radio_idx;
  83. }
  84. /**
  85. * nl_srv_exit() - wrapper function to unregister from cnss_logger
  86. *
  87. * The cnss_logger_device_unregister() use to unregister the driver with
  88. * the radio_index assigned and wiphy structure from cnss_logger.
  89. *
  90. * Return: None
  91. */
  92. void nl_srv_exit(void)
  93. {
  94. if (logger_initialized) {
  95. cnss_logger_device_unregister(radio_idx, wiphy_ptr);
  96. radio_idx = -EINVAL;
  97. wiphy_ptr = NULL;
  98. logger_initialized = false;
  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. */
  116. int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag)
  117. {
  118. int err = -EINVAL;
  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. if (nl_srv_is_initialized() == 0)
  128. err = cnss_logger_nl_ucast(skb, dst_pid, flag);
  129. else
  130. dev_kfree_skb(skb);
  131. return err;
  132. }
  133. /**
  134. * nl_srv_bcast() - wrapper function to do broadcast tx through cnss_logger
  135. * @skb: the socket buffer to send
  136. *
  137. * The cnss_logger_nl_bcast() is used to transmit the socket buffer.
  138. *
  139. * Return: status of transmission
  140. */
  141. int nl_srv_bcast(struct sk_buff *skb)
  142. {
  143. int err = -EINVAL;
  144. int flags = GFP_KERNEL;
  145. if (in_interrupt() || irqs_disabled() || in_atomic())
  146. flags = GFP_ATOMIC;
  147. /* sender's pid */
  148. #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0))
  149. NETLINK_CB(skb).pid = 0;
  150. #else
  151. NETLINK_CB(skb).portid = 0;
  152. #endif
  153. /* destination group */
  154. NETLINK_CB(skb).dst_group = WLAN_NLINK_MCAST_GRP_ID;
  155. if (nl_srv_is_initialized() == 0)
  156. err = cnss_logger_nl_bcast(skb, WLAN_NLINK_MCAST_GRP_ID, flags);
  157. else
  158. dev_kfree_skb(skb);
  159. return err;
  160. }
  161. /**
  162. * nl_srv_unregister() - wrapper function to unregister event to cnss_logger
  163. * @msg_type: the message to unregister
  164. * @msg_handler: the message handler
  165. *
  166. * The cnss_logger_event_unregister() is used to unregister the message and
  167. * message handler.
  168. *
  169. * Return: 0 if successfully unregister, otherwise proper error code
  170. */
  171. int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
  172. {
  173. int ret = -EINVAL;
  174. if (nl_srv_is_initialized() != 0)
  175. return ret;
  176. if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) &&
  177. msg_handler != NULL) {
  178. ret = cnss_logger_event_unregister(radio_idx, msg_type,
  179. msg_handler);
  180. } else {
  181. QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
  182. "NLINK: nl_srv_unregister failed for msg_type %d",
  183. msg_type);
  184. ret = -EINVAL;
  185. }
  186. return ret;
  187. }
  188. /**
  189. * nl_srv_register() - wrapper function to register event to cnss_logger
  190. * @msg_type: the message to register
  191. * @msg_handler: the message handler
  192. *
  193. * The cnss_logger_event_register() is used to register the message and
  194. * message handler.
  195. *
  196. * Return: 0 if successfully register, otherwise proper error code
  197. */
  198. int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
  199. {
  200. int ret = -EINVAL;
  201. if (nl_srv_is_initialized() != 0)
  202. return ret;
  203. if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) &&
  204. msg_handler != NULL) {
  205. ret = cnss_logger_event_register(radio_idx, msg_type,
  206. msg_handler);
  207. } else {
  208. QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
  209. "NLINK: nl_srv_register failed for msg_type %d",
  210. msg_type);
  211. ret = -EINVAL;
  212. }
  213. return ret;
  214. }
  215. /**
  216. * nl_srv_is_initialized() - check if netlink service is initialized
  217. *
  218. * Return: 0 if it is initialized, otherwise error code
  219. */
  220. inline int nl_srv_is_initialized(void)
  221. {
  222. if (logger_initialized)
  223. return 0;
  224. else
  225. return -EPERM;
  226. }
  227. #else
  228. /* Global variables */
  229. static DEFINE_MUTEX(nl_srv_sem);
  230. static struct sock *nl_srv_sock;
  231. static nl_srv_msg_callback nl_srv_msg_handler[NLINK_MAX_CALLBACKS];
  232. /* Forward declaration */
  233. static void nl_srv_rcv(struct sk_buff *sk);
  234. static void nl_srv_rcv_skb(struct sk_buff *skb);
  235. static void nl_srv_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh);
  236. /*
  237. * Initialize the netlink service.
  238. * Netlink service is usable after this.
  239. */
  240. int nl_srv_init(void *wiphy)
  241. {
  242. int retcode = 0;
  243. struct netlink_kernel_cfg cfg = {
  244. .groups = WLAN_NLINK_MCAST_GRP_ID,
  245. .input = nl_srv_rcv
  246. };
  247. nl_srv_sock = netlink_kernel_create(&init_net, WLAN_NLINK_PROTO_FAMILY,
  248. &cfg);
  249. if (nl_srv_sock != NULL) {
  250. memset(nl_srv_msg_handler, 0, sizeof(nl_srv_msg_handler));
  251. } else {
  252. QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
  253. "NLINK: netlink_kernel_create failed");
  254. retcode = -ECONNREFUSED;
  255. }
  256. return retcode;
  257. }
  258. /*
  259. * Deinit the netlink service.
  260. * Netlink service is unusable after this.
  261. */
  262. void nl_srv_exit(void)
  263. {
  264. if (nl_srv_is_initialized() == 0)
  265. netlink_kernel_release(nl_srv_sock);
  266. nl_srv_sock = NULL;
  267. }
  268. /*
  269. * Register a message handler for a specified module.
  270. * Each module (e.g. WLAN_NL_MSG_BTC )will register a
  271. * handler to handle messages addressed to it.
  272. */
  273. int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
  274. {
  275. int retcode = 0;
  276. if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) &&
  277. msg_handler != NULL) {
  278. nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] = msg_handler;
  279. } else {
  280. QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
  281. "NLINK: nl_srv_register failed for msg_type %d",
  282. msg_type);
  283. retcode = -EINVAL;
  284. }
  285. return retcode;
  286. }
  287. /*
  288. * Unregister the message handler for a specified module.
  289. */
  290. int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
  291. {
  292. int retcode = 0;
  293. if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) &&
  294. (nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] == msg_handler)) {
  295. nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] = NULL;
  296. } else {
  297. QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
  298. "NLINK: nl_srv_unregister failed for msg_type %d",
  299. msg_type);
  300. retcode = -EINVAL;
  301. }
  302. return retcode;
  303. }
  304. /*
  305. * Unicast the message to the process in user space identfied
  306. * by the dst-pid
  307. */
  308. int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag)
  309. {
  310. int err = 0;
  311. NETLINK_CB(skb).portid = 0; /* sender's pid */
  312. NETLINK_CB(skb).dst_group = 0; /* not multicast */
  313. if (nl_srv_sock)
  314. err = netlink_unicast(nl_srv_sock, skb, dst_pid, flag);
  315. if (err < 0)
  316. QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
  317. "NLINK: netlink_unicast to pid[%d] failed, ret[%d]",
  318. dst_pid, err);
  319. return err;
  320. }
  321. /*
  322. * Broadcast the message. Broadcast will return an error if
  323. * there are no listeners
  324. */
  325. int nl_srv_bcast(struct sk_buff *skb)
  326. {
  327. int err = 0;
  328. int flags = GFP_KERNEL;
  329. if (in_interrupt() || irqs_disabled() || in_atomic())
  330. flags = GFP_ATOMIC;
  331. NETLINK_CB(skb).portid = 0; /* sender's pid */
  332. NETLINK_CB(skb).dst_group = WLAN_NLINK_MCAST_GRP_ID; /* destination group */
  333. if (nl_srv_sock)
  334. err = netlink_broadcast(nl_srv_sock, skb, 0,
  335. WLAN_NLINK_MCAST_GRP_ID, flags);
  336. if ((err < 0) && (err != -ESRCH)) {
  337. QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
  338. "NLINK: netlink_broadcast failed err = %d", err);
  339. }
  340. return err;
  341. }
  342. /*
  343. * Processes the Netlink socket input queue.
  344. * Dequeue skb's from the socket input queue and process
  345. * all the netlink messages in that skb, before moving
  346. * to the next skb.
  347. */
  348. static void nl_srv_rcv(struct sk_buff *sk)
  349. {
  350. mutex_lock(&nl_srv_sem);
  351. nl_srv_rcv_skb(sk);
  352. mutex_unlock(&nl_srv_sem);
  353. }
  354. /*
  355. * Each skb could contain multiple Netlink messages. Process all the
  356. * messages in one skb and discard malformed skb's silently.
  357. */
  358. static void nl_srv_rcv_skb(struct sk_buff *skb)
  359. {
  360. struct nlmsghdr *nlh;
  361. while (skb->len >= NLMSG_SPACE(0)) {
  362. u32 rlen;
  363. nlh = (struct nlmsghdr *)skb->data;
  364. if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) {
  365. QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
  366. "NLINK: Invalid "
  367. "Netlink message: skb[%p], len[%d], nlhdr[%p], nlmsg_len[%d]",
  368. skb, skb->len, nlh, nlh->nlmsg_len);
  369. return;
  370. }
  371. rlen = NLMSG_ALIGN(nlh->nlmsg_len);
  372. if (rlen > skb->len)
  373. rlen = skb->len;
  374. nl_srv_rcv_msg(skb, nlh);
  375. skb_pull(skb, rlen);
  376. }
  377. }
  378. /*
  379. * Process a netlink message.
  380. * Each netlink message will have a message of type tAniMsgHdr inside.
  381. */
  382. static void nl_srv_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
  383. {
  384. int type;
  385. /* Only requests are handled by kernel now */
  386. if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) {
  387. QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
  388. "NLINK: Received Invalid NL Req type [%x]",
  389. nlh->nlmsg_flags);
  390. return;
  391. }
  392. type = nlh->nlmsg_type;
  393. /* Unknown message */
  394. if (type < WLAN_NL_MSG_BASE || type >= WLAN_NL_MSG_MAX) {
  395. QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
  396. "NLINK: Received Invalid NL Msg type [%x]", type);
  397. return;
  398. }
  399. /*
  400. * All the messages must at least carry the tAniMsgHdr
  401. * Drop any message with invalid length
  402. */
  403. if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(tAniMsgHdr))) {
  404. QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
  405. "NLINK: Received NL Msg with invalid len[%x]",
  406. nlh->nlmsg_len);
  407. return;
  408. }
  409. /* turn type into dispatch table offset */
  410. type -= WLAN_NL_MSG_BASE;
  411. /* dispatch to handler */
  412. if (nl_srv_msg_handler[type] != NULL) {
  413. (nl_srv_msg_handler[type])(skb);
  414. } else {
  415. QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
  416. "NLINK: No handler for Netlink Msg [0x%X]", type);
  417. }
  418. }
  419. /**
  420. * nl_srv_is_initialized() - This function is used check if the netlink
  421. * service is initialized
  422. *
  423. * This function is used check if the netlink service is initialized
  424. *
  425. * Return: Return -EPERM if the service is not initialized
  426. *
  427. */
  428. int nl_srv_is_initialized(void)
  429. {
  430. if (nl_srv_sock)
  431. return 0;
  432. return -EPERM;
  433. }
  434. #endif
  435. #else /* ifndef MULTI_IF_NAME */
  436. #include <wlan_nlink_srv.h>
  437. int nl_srv_init(void *wiphy)
  438. {
  439. return 0;
  440. }
  441. void nl_srv_exit(void)
  442. {
  443. }
  444. int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
  445. {
  446. return 0;
  447. }
  448. int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
  449. {
  450. return 0;
  451. }
  452. int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag)
  453. {
  454. return 0;
  455. }
  456. int nl_srv_bcast(struct sk_buff *skb)
  457. {
  458. return 0;
  459. }
  460. int nl_srv_is_initialized(void)
  461. {
  462. return 0;
  463. }
  464. #endif