sockev_nlmcast.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /*
  2. * Copyright (c) 2014, 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 void _sockev_event(unsigned long event, __u8 *evstr, int buflen)
  30. {
  31. switch (event) {
  32. case SOCKEV_SOCKET:
  33. strlcpy(evstr, "SOCKEV_SOCKET", buflen);
  34. break;
  35. case SOCKEV_BIND:
  36. strlcpy(evstr, "SOCKEV_BIND", buflen);
  37. break;
  38. case SOCKEV_LISTEN:
  39. strlcpy(evstr, "SOCKEV_LISTEN", buflen);
  40. break;
  41. case SOCKEV_ACCEPT:
  42. strlcpy(evstr, "SOCKEV_ACCEPT", buflen);
  43. break;
  44. case SOCKEV_CONNECT:
  45. strlcpy(evstr, "SOCKEV_CONNECT", buflen);
  46. break;
  47. case SOCKEV_SHUTDOWN:
  48. strlcpy(evstr, "SOCKEV_SHUTDOWN", buflen);
  49. break;
  50. default:
  51. strlcpy(evstr, "UNKOWN", buflen);
  52. }
  53. }
  54. static int sockev_client_cb(struct notifier_block *nb,
  55. unsigned long event, void *data)
  56. {
  57. struct sk_buff *skb;
  58. struct nlmsghdr *nlh;
  59. struct sknlsockevmsg *smsg;
  60. struct socket *sock;
  61. struct sock *sk;
  62. sock = (struct socket *)data;
  63. if (!socknlmsgsk || !sock)
  64. goto sk_null;
  65. sk = sock->sk;
  66. if (!sk)
  67. goto sk_null;
  68. sock_hold(sk);
  69. skb = nlmsg_new(sizeof(struct sknlsockevmsg), GFP_KERNEL);
  70. if (skb == NULL)
  71. goto done;
  72. nlh = nlmsg_put(skb, 0, 0, event, sizeof(struct sknlsockevmsg), 0);
  73. if (nlh == NULL) {
  74. kfree_skb(skb);
  75. goto done;
  76. }
  77. NETLINK_CB(skb).dst_group = SKNLGRP_SOCKEV;
  78. smsg = nlmsg_data(nlh);
  79. smsg->pid = current->pid;
  80. _sockev_event(event, smsg->event, sizeof(smsg->event));
  81. smsg->skfamily = sk->sk_family;
  82. smsg->skstate = sk->sk_state;
  83. smsg->skprotocol = sk->sk_protocol;
  84. smsg->sktype = sk->sk_type;
  85. smsg->skflags = sk->sk_flags;
  86. nlmsg_notify(socknlmsgsk, skb, 0, SKNLGRP_SOCKEV, 0, GFP_KERNEL);
  87. done:
  88. sock_put(sk);
  89. sk_null:
  90. return 0;
  91. }
  92. static struct notifier_block sockev_notifier_client = {
  93. .notifier_call = sockev_client_cb,
  94. .next = 0,
  95. .priority = 0
  96. };
  97. /* ***************** Startup/Shutdown *************************************** */
  98. static int __init sockev_client_init(void)
  99. {
  100. int rc;
  101. registration_status = 1;
  102. rc = sockev_register_notify(&sockev_notifier_client);
  103. if (rc != 0) {
  104. registration_status = 0;
  105. pr_err("%s(): Failed to register cb (%d)\n", __func__, rc);
  106. }
  107. socknlmsgsk = netlink_kernel_create(&init_net,
  108. NETLINK_SOCKEV,
  109. 0,
  110. sockev_skmsg_recv,
  111. NULL,
  112. THIS_MODULE);
  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");