netlink_k.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /*
  2. * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
  3. *
  4. * This software is licensed under the terms of the GNU General Public
  5. * License version 2, as published by the Free Software Foundation, and
  6. * may be copied, distributed, and modified under those terms.
  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. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  14. #include <linux/export.h>
  15. #include <linux/etherdevice.h>
  16. #include <linux/netlink.h>
  17. #include <asm/byteorder.h>
  18. #include <net/sock.h>
  19. #include "netlink_k.h"
  20. #if defined(DEFINE_MUTEX)
  21. static DEFINE_MUTEX(netlink_mutex);
  22. #else
  23. static struct semaphore netlink_mutex;
  24. #define mutex_lock(x) down(x)
  25. #define mutex_unlock(x) up(x)
  26. #endif
  27. #define ND_MAX_GROUP 30
  28. #define ND_IFINDEX_LEN sizeof(int)
  29. #define ND_NLMSG_SPACE(len) (NLMSG_SPACE(len) + ND_IFINDEX_LEN)
  30. #define ND_NLMSG_DATA(nlh) ((void *)((char *)NLMSG_DATA(nlh) + \
  31. ND_IFINDEX_LEN))
  32. #define ND_NLMSG_S_LEN(len) (len + ND_IFINDEX_LEN)
  33. #define ND_NLMSG_R_LEN(nlh) (nlh->nlmsg_len - ND_IFINDEX_LEN)
  34. #define ND_NLMSG_IFIDX(nlh) NLMSG_DATA(nlh)
  35. #define ND_MAX_MSG_LEN (1024 * 32)
  36. static void (*rcv_cb)(struct net_device *dev, u16 type, void *msg, int len);
  37. static void netlink_rcv_cb(struct sk_buff *skb)
  38. {
  39. struct nlmsghdr *nlh;
  40. struct net_device *dev;
  41. u32 mlen;
  42. void *msg;
  43. int ifindex;
  44. if (!rcv_cb) {
  45. pr_err("nl cb - unregistered\n");
  46. return;
  47. }
  48. if (skb->len < NLMSG_HDRLEN) {
  49. pr_err("nl cb - invalid skb length\n");
  50. return;
  51. }
  52. nlh = (struct nlmsghdr *)skb->data;
  53. if (skb->len < nlh->nlmsg_len || nlh->nlmsg_len > ND_MAX_MSG_LEN) {
  54. pr_err("nl cb - invalid length (%d,%d)\n",
  55. skb->len, nlh->nlmsg_len);
  56. return;
  57. }
  58. memcpy(&ifindex, ND_NLMSG_IFIDX(nlh), ND_IFINDEX_LEN);
  59. msg = ND_NLMSG_DATA(nlh);
  60. mlen = ND_NLMSG_R_LEN(nlh);
  61. dev = dev_get_by_index(&init_net, ifindex);
  62. if (dev) {
  63. rcv_cb(dev, nlh->nlmsg_type, msg, mlen);
  64. dev_put(dev);
  65. } else {
  66. pr_err("nl cb - dev (%d) not found\n", ifindex);
  67. }
  68. }
  69. static void netlink_rcv(struct sk_buff *skb)
  70. {
  71. mutex_lock(&netlink_mutex);
  72. netlink_rcv_cb(skb);
  73. mutex_unlock(&netlink_mutex);
  74. }
  75. struct sock *netlink_init(int unit,
  76. void (*cb)(struct net_device *dev, u16 type, void *msg, int len))
  77. {
  78. struct sock *sock;
  79. struct netlink_kernel_cfg cfg = {
  80. .input = netlink_rcv,
  81. };
  82. #if !defined(DEFINE_MUTEX)
  83. init_MUTEX(&netlink_mutex);
  84. #endif
  85. sock = netlink_kernel_create(&init_net, unit, &cfg);
  86. if (sock)
  87. rcv_cb = cb;
  88. return sock;
  89. }
  90. void netlink_exit(struct sock *sock)
  91. {
  92. sock_release(sock->sk_socket);
  93. }
  94. int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len)
  95. {
  96. static u32 seq;
  97. struct sk_buff *skb = NULL;
  98. struct nlmsghdr *nlh;
  99. int ret = 0;
  100. if (group > ND_MAX_GROUP)
  101. return -EINVAL;
  102. if (!netlink_has_listeners(sock, group + 1))
  103. return -ESRCH;
  104. skb = alloc_skb(NLMSG_SPACE(len), GFP_ATOMIC);
  105. if (!skb)
  106. return -ENOMEM;
  107. seq++;
  108. nlh = nlmsg_put(skb, 0, seq, type, len, 0);
  109. memcpy(NLMSG_DATA(nlh), msg, len);
  110. NETLINK_CB(skb).portid = 0;
  111. NETLINK_CB(skb).dst_group = 0;
  112. ret = netlink_broadcast(sock, skb, 0, group + 1, GFP_ATOMIC);
  113. if (!ret)
  114. return len;
  115. if (ret != -ESRCH)
  116. pr_err("nl broadcast g=%d, t=%d, l=%d, r=%d\n",
  117. group, type, len, ret);
  118. else if (netlink_has_listeners(sock, group + 1))
  119. return -EAGAIN;
  120. return ret;
  121. }