Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / tools / lib / thermal / thermal_nl.c
blobb05cf95698583525aa24281a814981c5a775c783
1 // SPDX-License-Identifier: LGPL-2.1+
2 // Copyright (C) 2022, Linaro Ltd - Daniel Lezcano <daniel.lezcano@linaro.org>
3 #include <errno.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <unistd.h>
8 #include <thermal.h>
9 #include "thermal_nl.h"
11 struct handler_args {
12 const char *group;
13 int id;
16 static __thread int err;
17 static __thread int done;
19 static int nl_seq_check_handler(struct nl_msg *msg, void *arg)
21 return NL_OK;
24 static int nl_error_handler(struct sockaddr_nl *nla, struct nlmsgerr *nl_err,
25 void *arg)
27 int *ret = arg;
29 if (ret)
30 *ret = nl_err->error;
32 return NL_STOP;
35 static int nl_finish_handler(struct nl_msg *msg, void *arg)
37 int *ret = arg;
39 if (ret)
40 *ret = 1;
42 return NL_OK;
45 static int nl_ack_handler(struct nl_msg *msg, void *arg)
47 int *ret = arg;
49 if (ret)
50 *ret = 1;
52 return NL_OK;
55 int nl_send_msg(struct nl_sock *sock, struct nl_cb *cb, struct nl_msg *msg,
56 int (*rx_handler)(struct nl_msg *, void *), void *data)
58 if (!rx_handler)
59 return THERMAL_ERROR;
61 err = nl_send_auto_complete(sock, msg);
62 if (err < 0)
63 return err;
65 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, rx_handler, data);
67 err = done = 0;
69 while (err == 0 && done == 0)
70 nl_recvmsgs(sock, cb);
72 return err;
75 static int nl_family_handler(struct nl_msg *msg, void *arg)
77 struct handler_args *grp = arg;
78 struct nlattr *tb[CTRL_ATTR_MAX + 1];
79 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
80 struct nlattr *mcgrp;
81 int rem_mcgrp;
83 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
84 genlmsg_attrlen(gnlh, 0), NULL);
86 if (!tb[CTRL_ATTR_MCAST_GROUPS])
87 return THERMAL_ERROR;
89 nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp) {
91 struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1];
93 nla_parse(tb_mcgrp, CTRL_ATTR_MCAST_GRP_MAX,
94 nla_data(mcgrp), nla_len(mcgrp), NULL);
96 if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME] ||
97 !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID])
98 continue;
100 if (strncmp(nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]),
101 grp->group,
102 nla_len(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME])))
103 continue;
105 grp->id = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]);
107 break;
110 return THERMAL_SUCCESS;
113 static int nl_get_multicast_id(struct nl_sock *sock, struct nl_cb *cb,
114 const char *family, const char *group)
116 struct nl_msg *msg;
117 int ret = 0, ctrlid;
118 struct handler_args grp = {
119 .group = group,
120 .id = -ENOENT,
123 msg = nlmsg_alloc();
124 if (!msg)
125 return THERMAL_ERROR;
127 ctrlid = genl_ctrl_resolve(sock, "nlctrl");
129 genlmsg_put(msg, 0, 0, ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0);
131 nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family);
133 ret = nl_send_msg(sock, cb, msg, nl_family_handler, &grp);
134 if (ret)
135 goto nla_put_failure;
137 ret = grp.id;
139 nla_put_failure:
140 nlmsg_free(msg);
141 return ret;
144 int nl_thermal_connect(struct nl_sock **nl_sock, struct nl_cb **nl_cb)
146 struct nl_cb *cb;
147 struct nl_sock *sock;
149 cb = nl_cb_alloc(NL_CB_DEFAULT);
150 if (!cb)
151 return THERMAL_ERROR;
153 sock = nl_socket_alloc();
154 if (!sock)
155 goto out_cb_free;
157 if (genl_connect(sock))
158 goto out_socket_free;
160 if (nl_cb_err(cb, NL_CB_CUSTOM, nl_error_handler, &err) ||
161 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, nl_finish_handler, &done) ||
162 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, nl_ack_handler, &done) ||
163 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl_seq_check_handler, &done))
164 return THERMAL_ERROR;
166 *nl_sock = sock;
167 *nl_cb = cb;
169 return THERMAL_SUCCESS;
171 out_socket_free:
172 nl_socket_free(sock);
173 out_cb_free:
174 nl_cb_put(cb);
175 return THERMAL_ERROR;
178 void nl_thermal_disconnect(struct nl_sock *nl_sock, struct nl_cb *nl_cb)
180 nl_close(nl_sock);
181 nl_socket_free(nl_sock);
182 nl_cb_put(nl_cb);
185 int nl_unsubscribe_thermal(struct nl_sock *nl_sock, struct nl_cb *nl_cb,
186 const char *group)
188 int mcid;
190 mcid = nl_get_multicast_id(nl_sock, nl_cb, THERMAL_GENL_FAMILY_NAME,
191 group);
192 if (mcid < 0)
193 return THERMAL_ERROR;
195 if (nl_socket_drop_membership(nl_sock, mcid))
196 return THERMAL_ERROR;
198 return THERMAL_SUCCESS;
201 int nl_subscribe_thermal(struct nl_sock *nl_sock, struct nl_cb *nl_cb,
202 const char *group)
204 int mcid;
206 mcid = nl_get_multicast_id(nl_sock, nl_cb, THERMAL_GENL_FAMILY_NAME,
207 group);
208 if (mcid < 0)
209 return THERMAL_ERROR;
211 if (nl_socket_add_membership(nl_sock, mcid))
212 return THERMAL_ERROR;
214 return THERMAL_SUCCESS;