123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- // SPDX-License-Identifier: LGPL-2.1+
- // Copyright (C) 2022, Linaro Ltd - Daniel Lezcano <[email protected]>
- #include <errno.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <thermal.h>
- #include "thermal_nl.h"
- struct handler_args {
- const char *group;
- int id;
- };
- static __thread int err;
- static __thread int done;
- static int nl_seq_check_handler(struct nl_msg *msg, void *arg)
- {
- return NL_OK;
- }
- static int nl_error_handler(struct sockaddr_nl *nla, struct nlmsgerr *nl_err,
- void *arg)
- {
- int *ret = arg;
- if (ret)
- *ret = nl_err->error;
- return NL_STOP;
- }
- static int nl_finish_handler(struct nl_msg *msg, void *arg)
- {
- int *ret = arg;
- if (ret)
- *ret = 1;
- return NL_OK;
- }
- static int nl_ack_handler(struct nl_msg *msg, void *arg)
- {
- int *ret = arg;
- if (ret)
- *ret = 1;
- return NL_OK;
- }
- int nl_send_msg(struct nl_sock *sock, struct nl_cb *cb, struct nl_msg *msg,
- int (*rx_handler)(struct nl_msg *, void *), void *data)
- {
- if (!rx_handler)
- return THERMAL_ERROR;
- err = nl_send_auto_complete(sock, msg);
- if (err < 0)
- return err;
- nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, rx_handler, data);
- err = done = 0;
- while (err == 0 && done == 0)
- nl_recvmsgs(sock, cb);
- return err;
- }
- static int nl_family_handler(struct nl_msg *msg, void *arg)
- {
- struct handler_args *grp = arg;
- struct nlattr *tb[CTRL_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct nlattr *mcgrp;
- int rem_mcgrp;
- nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
- if (!tb[CTRL_ATTR_MCAST_GROUPS])
- return THERMAL_ERROR;
- nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp) {
- struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1];
- nla_parse(tb_mcgrp, CTRL_ATTR_MCAST_GRP_MAX,
- nla_data(mcgrp), nla_len(mcgrp), NULL);
- if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME] ||
- !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID])
- continue;
- if (strncmp(nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]),
- grp->group,
- nla_len(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME])))
- continue;
- grp->id = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]);
- break;
- }
- return THERMAL_SUCCESS;
- }
- static int nl_get_multicast_id(struct nl_sock *sock, struct nl_cb *cb,
- const char *family, const char *group)
- {
- struct nl_msg *msg;
- int ret = 0, ctrlid;
- struct handler_args grp = {
- .group = group,
- .id = -ENOENT,
- };
- msg = nlmsg_alloc();
- if (!msg)
- return THERMAL_ERROR;
- ctrlid = genl_ctrl_resolve(sock, "nlctrl");
- genlmsg_put(msg, 0, 0, ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0);
- nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family);
- ret = nl_send_msg(sock, cb, msg, nl_family_handler, &grp);
- if (ret)
- goto nla_put_failure;
- ret = grp.id;
- nla_put_failure:
- nlmsg_free(msg);
- return ret;
- }
- int nl_thermal_connect(struct nl_sock **nl_sock, struct nl_cb **nl_cb)
- {
- struct nl_cb *cb;
- struct nl_sock *sock;
- cb = nl_cb_alloc(NL_CB_DEFAULT);
- if (!cb)
- return THERMAL_ERROR;
- sock = nl_socket_alloc();
- if (!sock)
- goto out_cb_free;
- if (genl_connect(sock))
- goto out_socket_free;
- if (nl_cb_err(cb, NL_CB_CUSTOM, nl_error_handler, &err) ||
- nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, nl_finish_handler, &done) ||
- nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, nl_ack_handler, &done) ||
- nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl_seq_check_handler, &done))
- return THERMAL_ERROR;
- *nl_sock = sock;
- *nl_cb = cb;
- return THERMAL_SUCCESS;
- out_socket_free:
- nl_socket_free(sock);
- out_cb_free:
- nl_cb_put(cb);
- return THERMAL_ERROR;
- }
- void nl_thermal_disconnect(struct nl_sock *nl_sock, struct nl_cb *nl_cb)
- {
- nl_close(nl_sock);
- nl_socket_free(nl_sock);
- nl_cb_put(nl_cb);
- }
- int nl_unsubscribe_thermal(struct nl_sock *nl_sock, struct nl_cb *nl_cb,
- const char *group)
- {
- int mcid;
- mcid = nl_get_multicast_id(nl_sock, nl_cb, THERMAL_GENL_FAMILY_NAME,
- group);
- if (mcid < 0)
- return THERMAL_ERROR;
- if (nl_socket_drop_membership(nl_sock, mcid))
- return THERMAL_ERROR;
- return THERMAL_SUCCESS;
- }
- int nl_subscribe_thermal(struct nl_sock *nl_sock, struct nl_cb *nl_cb,
- const char *group)
- {
- int mcid;
- mcid = nl_get_multicast_id(nl_sock, nl_cb, THERMAL_GENL_FAMILY_NAME,
- group);
- if (mcid < 0)
- return THERMAL_ERROR;
- if (nl_socket_add_membership(nl_sock, mcid))
- return THERMAL_ERROR;
- return THERMAL_SUCCESS;
- }
|