sockev_nlmcast.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /*
  2. * Copyright (c) 2014-2015, 2018 The Linux Foundation. All rights reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 and
  6. * only version 2 as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. *
  14. * Default SOCKEV client implementation
  15. *
  16. */
  17. #include <linux/module.h>
  18. #include <linux/kernel.h>
  19. #include <linux/export.h>
  20. #include <linux/netlink.h>
  21. #include <linux/sockev.h>
  22. #include <net/sock.h>
  23. static int registration_status;
  24. static struct sock *socknlmsgsk;
  25. static void sockev_skmsg_recv(struct sk_buff *skb)
  26. {
  27. pr_debug("%s(): Got unsolicited request\n", __func__);
  28. }
  29. static struct netlink_kernel_cfg nlcfg = {
  30. .input = sockev_skmsg_recv
  31. };
  32. static void _sockev_event(unsigned long event, __u8 *evstr, int buflen)
  33. {
  34. switch (event) {
  35. case SOCKEV_SOCKET:
  36. strlcpy(evstr, "SOCKEV_SOCKET", buflen);
  37. break;
  38. case SOCKEV_BIND:
  39. strlcpy(evstr, "SOCKEV_BIND", buflen);
  40. break;
  41. case SOCKEV_LISTEN:
  42. strlcpy(evstr, "SOCKEV_LISTEN", buflen);
  43. break;
  44. case SOCKEV_ACCEPT:
  45. strlcpy(evstr, "SOCKEV_ACCEPT", buflen);
  46. break;
  47. case SOCKEV_CONNECT:
  48. strlcpy(evstr, "SOCKEV_CONNECT", buflen);
  49. break;
  50. case SOCKEV_SHUTDOWN:
  51. strlcpy(evstr, "SOCKEV_SHUTDOWN", buflen);
  52. break;
  53. default:
  54. strlcpy(evstr, "UNKNOWN", buflen);
  55. }
  56. }
  57. static int sockev_client_cb(struct notifier_block *nb,
  58. unsigned long event, void *data)
  59. {
  60. struct sk_buff *skb;
  61. struct nlmsghdr *nlh;
  62. struct sknlsockevmsg *smsg;
  63. struct socket *sock;
  64. struct sock *sk;
  65. sock = (struct socket *)data;
  66. if (!socknlmsgsk || !sock)
  67. goto done;
  68. sk = sock->sk;
  69. if (!sk)
  70. goto done;
  71. if (sk->sk_family != AF_INET && sk->sk_family != AF_INET6)
  72. goto done;
  73. if (event != SOCKEV_BIND && event != SOCKEV_LISTEN)
  74. goto done;
  75. skb = nlmsg_new(sizeof(struct sknlsockevmsg), GFP_KERNEL);
  76. if (!skb)
  77. goto done;
  78. nlh = nlmsg_put(skb, 0, 0, event, sizeof(struct sknlsockevmsg), 0);
  79. if (!nlh) {
  80. kfree_skb(skb);
  81. goto done;
  82. }
  83. NETLINK_CB(skb).dst_group = SKNLGRP_SOCKEV;
  84. smsg = nlmsg_data(nlh);
  85. memset(smsg, 0, sizeof(struct sknlsockevmsg));
  86. smsg->pid = current->pid;
  87. _sockev_event(event, smsg->event, sizeof(smsg->event));
  88. smsg->skfamily = sk->sk_family;
  89. smsg->skstate = sk->sk_state;
  90. smsg->skprotocol = sk->sk_protocol;
  91. smsg->sktype = sk->sk_type;
  92. smsg->skflags = sk->sk_flags;
  93. nlmsg_notify(socknlmsgsk, skb, 0, SKNLGRP_SOCKEV, 0, GFP_KERNEL);
  94. done:
  95. return 0;
  96. }
  97. static struct notifier_block sockev_notifier_client = {
  98. .notifier_call = sockev_client_cb,
  99. .next = 0,
  100. .priority = 0
  101. };
  102. /* ***************** Startup/Shutdown *************************************** */
  103. static int __init sockev_client_init(void)
  104. {
  105. int rc;
  106. registration_status = 1;
  107. rc = sockev_register_notify(&sockev_notifier_client);
  108. if (rc != 0) {
  109. registration_status = 0;
  110. pr_err("%s(): Failed to register cb (%d)\n", __func__, rc);
  111. }
  112. socknlmsgsk = netlink_kernel_create(&init_net, NETLINK_SOCKEV, &nlcfg);
  113. if (!socknlmsgsk) {
  114. pr_err("%s(): Failed to initialize netlink socket\n", __func__);
  115. if (registration_status)
  116. sockev_unregister_notify(&sockev_notifier_client);
  117. registration_status = 0;
  118. }
  119. return rc;
  120. }
  121. static void __exit sockev_client_exit(void)
  122. {
  123. if (registration_status)
  124. sockev_unregister_notify(&sockev_notifier_client);
  125. }
  126. module_init(sockev_client_init)
  127. module_exit(sockev_client_exit)
  128. MODULE_LICENSE("GPL v2");