thermal_nl.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // SPDX-License-Identifier: LGPL-2.1+
  2. // Copyright (C) 2022, Linaro Ltd - Daniel Lezcano <[email protected]>
  3. #include <errno.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <thermal.h>
  8. #include "thermal_nl.h"
  9. struct handler_args {
  10. const char *group;
  11. int id;
  12. };
  13. static __thread int err;
  14. static __thread int done;
  15. static int nl_seq_check_handler(struct nl_msg *msg, void *arg)
  16. {
  17. return NL_OK;
  18. }
  19. static int nl_error_handler(struct sockaddr_nl *nla, struct nlmsgerr *nl_err,
  20. void *arg)
  21. {
  22. int *ret = arg;
  23. if (ret)
  24. *ret = nl_err->error;
  25. return NL_STOP;
  26. }
  27. static int nl_finish_handler(struct nl_msg *msg, void *arg)
  28. {
  29. int *ret = arg;
  30. if (ret)
  31. *ret = 1;
  32. return NL_OK;
  33. }
  34. static int nl_ack_handler(struct nl_msg *msg, void *arg)
  35. {
  36. int *ret = arg;
  37. if (ret)
  38. *ret = 1;
  39. return NL_OK;
  40. }
  41. int nl_send_msg(struct nl_sock *sock, struct nl_cb *cb, struct nl_msg *msg,
  42. int (*rx_handler)(struct nl_msg *, void *), void *data)
  43. {
  44. if (!rx_handler)
  45. return THERMAL_ERROR;
  46. err = nl_send_auto_complete(sock, msg);
  47. if (err < 0)
  48. return err;
  49. nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, rx_handler, data);
  50. err = done = 0;
  51. while (err == 0 && done == 0)
  52. nl_recvmsgs(sock, cb);
  53. return err;
  54. }
  55. static int nl_family_handler(struct nl_msg *msg, void *arg)
  56. {
  57. struct handler_args *grp = arg;
  58. struct nlattr *tb[CTRL_ATTR_MAX + 1];
  59. struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
  60. struct nlattr *mcgrp;
  61. int rem_mcgrp;
  62. nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
  63. genlmsg_attrlen(gnlh, 0), NULL);
  64. if (!tb[CTRL_ATTR_MCAST_GROUPS])
  65. return THERMAL_ERROR;
  66. nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp) {
  67. struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1];
  68. nla_parse(tb_mcgrp, CTRL_ATTR_MCAST_GRP_MAX,
  69. nla_data(mcgrp), nla_len(mcgrp), NULL);
  70. if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME] ||
  71. !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID])
  72. continue;
  73. if (strncmp(nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]),
  74. grp->group,
  75. nla_len(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME])))
  76. continue;
  77. grp->id = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]);
  78. break;
  79. }
  80. return THERMAL_SUCCESS;
  81. }
  82. static int nl_get_multicast_id(struct nl_sock *sock, struct nl_cb *cb,
  83. const char *family, const char *group)
  84. {
  85. struct nl_msg *msg;
  86. int ret = 0, ctrlid;
  87. struct handler_args grp = {
  88. .group = group,
  89. .id = -ENOENT,
  90. };
  91. msg = nlmsg_alloc();
  92. if (!msg)
  93. return THERMAL_ERROR;
  94. ctrlid = genl_ctrl_resolve(sock, "nlctrl");
  95. genlmsg_put(msg, 0, 0, ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0);
  96. nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family);
  97. ret = nl_send_msg(sock, cb, msg, nl_family_handler, &grp);
  98. if (ret)
  99. goto nla_put_failure;
  100. ret = grp.id;
  101. nla_put_failure:
  102. nlmsg_free(msg);
  103. return ret;
  104. }
  105. int nl_thermal_connect(struct nl_sock **nl_sock, struct nl_cb **nl_cb)
  106. {
  107. struct nl_cb *cb;
  108. struct nl_sock *sock;
  109. cb = nl_cb_alloc(NL_CB_DEFAULT);
  110. if (!cb)
  111. return THERMAL_ERROR;
  112. sock = nl_socket_alloc();
  113. if (!sock)
  114. goto out_cb_free;
  115. if (genl_connect(sock))
  116. goto out_socket_free;
  117. if (nl_cb_err(cb, NL_CB_CUSTOM, nl_error_handler, &err) ||
  118. nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, nl_finish_handler, &done) ||
  119. nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, nl_ack_handler, &done) ||
  120. nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl_seq_check_handler, &done))
  121. return THERMAL_ERROR;
  122. *nl_sock = sock;
  123. *nl_cb = cb;
  124. return THERMAL_SUCCESS;
  125. out_socket_free:
  126. nl_socket_free(sock);
  127. out_cb_free:
  128. nl_cb_put(cb);
  129. return THERMAL_ERROR;
  130. }
  131. void nl_thermal_disconnect(struct nl_sock *nl_sock, struct nl_cb *nl_cb)
  132. {
  133. nl_close(nl_sock);
  134. nl_socket_free(nl_sock);
  135. nl_cb_put(nl_cb);
  136. }
  137. int nl_unsubscribe_thermal(struct nl_sock *nl_sock, struct nl_cb *nl_cb,
  138. const char *group)
  139. {
  140. int mcid;
  141. mcid = nl_get_multicast_id(nl_sock, nl_cb, THERMAL_GENL_FAMILY_NAME,
  142. group);
  143. if (mcid < 0)
  144. return THERMAL_ERROR;
  145. if (nl_socket_drop_membership(nl_sock, mcid))
  146. return THERMAL_ERROR;
  147. return THERMAL_SUCCESS;
  148. }
  149. int nl_subscribe_thermal(struct nl_sock *nl_sock, struct nl_cb *nl_cb,
  150. const char *group)
  151. {
  152. int mcid;
  153. mcid = nl_get_multicast_id(nl_sock, nl_cb, THERMAL_GENL_FAMILY_NAME,
  154. group);
  155. if (mcid < 0)
  156. return THERMAL_ERROR;
  157. if (nl_socket_add_membership(nl_sock, mcid))
  158. return THERMAL_ERROR;
  159. return THERMAL_SUCCESS;
  160. }