#include #include #include #include #include #include #include #include #include "thermal.h" static int nl_error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) { int *ret = arg; *ret = err->error; printf("%s\n", __func__); return NL_STOP; } static int nl_finish_handler(struct nl_msg *msg, void *arg) { int *ret = arg; *ret = 1; /* printf("%s\n", __func__); */ return NL_OK; } static int nl_ack_handler(struct nl_msg *msg, void *arg) { int *ret = arg; *ret = 1; printf("%s\n", __func__); return NL_OK; } static int nl_overrun_handler(struct nl_msg *msg, void *arg) { printf("%s\n", __func__); return NL_SKIP; } static int nl_skipped_handler(struct nl_msg *msg, void *arg) { printf("%s\n", __func__); return NL_SKIP; } static int nl_seq_check_handler(struct nl_msg *msg, void *arg) { printf("%s\n", __func__); return NL_OK; } static int handle_event(struct nl_msg *n, void *arg) { struct nlmsghdr *nlh = nlmsg_hdr(n); struct genlmsghdr *genlhdr = genlmsg_hdr(nlh); struct nlattr *attrs[THERMAL_GENL_ATTR_MAX + 1]; genlmsg_parse(nlh, 0, attrs, THERMAL_GENL_ATTR_MAX, NULL); if (genlhdr->cmd == THERMAL_GENL_EVENT_TZ_TRIP_UP) { printf("THERMAL_GENL_EVENT_TZ_TRIP_UP\n"); if (attrs[THERMAL_GENL_ATTR_TZ_ID]) printf("Thermal zone %d\n", nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID])); if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]) printf("Thermal zone trip id %d\n", nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID])); } if (genlhdr->cmd == THERMAL_GENL_EVENT_TZ_TRIP_DOWN) { printf("THERMAL_GENL_EVENT_TZ_TRIP_DOWN\n"); if (attrs[THERMAL_GENL_ATTR_TZ_ID]) printf("Thermal zone %d\n", nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID])); if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]) printf("Thermal zone trip id %d\n", nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID])); } if (genlhdr->cmd == THERMAL_GENL_EVENT_CDEV_UPDATE) { printf("THERMAL_GENL_EVENT_CDEV_UPDATE\n"); if (attrs[THERMAL_GENL_ATTR_CDEV_ID]) printf("Cooling device id %d\n", nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_ID])); if (attrs[THERMAL_GENL_ATTR_CDEV_CUR_STATE]) printf("Cooling device current state %d\n", nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_CUR_STATE])); } if (genlhdr->cmd == THERMAL_GENL_EVENT_TZ_GOV_CHANGE) { printf("THERMAL_GENL_EVENT_TZ_GOV_CHANGE\n"); if (attrs[THERMAL_GENL_ATTR_TZ_ID]) printf("Thermal zone id %d\n", nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID])); if (attrs[THERMAL_GENL_ATTR_GOV_NAME]) printf("Governor name %s\n", nla_get_string(attrs[THERMAL_GENL_ATTR_GOV_NAME])); } if (genlhdr->cmd == THERMAL_GENL_EVENT_TZ_CREATE) { printf("THERMAL_GENL_EVENT_TZ_CREATE\n"); if (attrs[THERMAL_GENL_ATTR_TZ_ID]) printf("Thermal zone id %d\n", nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID])); if (attrs[THERMAL_GENL_ATTR_TZ_NAME]) printf("Thermal zone name %s\n", nla_get_string(attrs[THERMAL_GENL_ATTR_TZ_NAME])); } if (genlhdr->cmd == THERMAL_GENL_EVENT_TZ_DELETE) { printf("THERMAL_GENL_EVENT_TZ_DELETE\n"); if (attrs[THERMAL_GENL_ATTR_TZ_ID]) printf("Thermal zone id %d\n", nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID])); } if (genlhdr->cmd == THERMAL_GENL_EVENT_TZ_DISABLE) { printf("THERMAL_GENL_EVENT_TZ_DISABLE\n"); if (attrs[THERMAL_GENL_ATTR_TZ_ID]) printf("Thermal zone id %d\n", nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID])); } if (genlhdr->cmd == THERMAL_GENL_EVENT_TZ_ENABLE) { printf("THERMAL_GENL_EVENT_TZ_ENABLE\n"); if (attrs[THERMAL_GENL_ATTR_TZ_ID]) printf("Thermal zone id %d\n", nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID])); } if (genlhdr->cmd == THERMAL_GENL_EVENT_TZ_TRIP_CHANGE) { printf("THERMAL_GENL_EVENT_TZ_TRIP_CHANGE\n"); if (attrs[THERMAL_GENL_ATTR_TZ_ID]) printf("Thermal zone id %d\n", nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID])); if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]) printf("Trip id %d\n", nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID])); if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_TYPE]) printf("Trip type %d\n", nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TYPE])); if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_TEMP]) printf("Trip temp %d\n", nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TEMP])); if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_HYST]) printf("Trip hyst %d\n", nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_HYST])); } return 0; } struct handler_args { const char *group; int id; }; static int nl_send_msg(struct nl_sock *sock, struct nl_msg *msg, int (*rx_handler)(struct nl_msg *, void *), void *data) { struct nl_cb *cb; int err, done; cb = nl_cb_alloc(NL_CB_DEFAULT); if (cb == NULL) return -ENOMEM; err = nl_send_auto_complete(sock, msg); if (err < 0) { nl_cb_put(cb); return err; } err = done = 0; 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); if (rx_handler != NULL) nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, rx_handler, data); while (err == 0 && done == 0) nl_recvmsgs(sock, cb); nl_cb_put(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]) { fprintf(stderr, "Multicast group not found\n"); return -1; } 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 0; } static int nl_get_multicast_id(struct nl_sock *sock, const char *family, const char *group) { struct nl_msg *msg; int err = 0, ctrlid; struct handler_args grp = { .group = group, .id = -ENOENT, }; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; 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); err = nl_send_msg(sock, msg, nl_family_handler, &grp); if (err) goto nla_put_failure; err = grp.id; nla_put_failure: nlmsg_free(msg); return err; } int main(int argc, char *argv[]) { struct nl_sock *sk_event; int mcid; nl_debug = 0; /* Event receiving */ sk_event = nl_socket_alloc(); if (!sk_event) { fprintf(stderr, "nl_socket_alloc failed\n"); return -1; } if (genl_connect(sk_event)) { fprintf(stderr, "genl_connect(sk_event) failed\n"); return -1; } mcid = nl_get_multicast_id(sk_event, THERMAL_GENL_FAMILY_NAME, THERMAL_GENL_EVENT_GROUP_NAME); if (mcid < 0) { fprintf(stderr, "nl_get_multicast_id failed\n"); return -1; } if (nl_socket_add_membership(sk_event, mcid)) { fprintf(stderr, "nl_socket_add_membership failed"); return -1; } { struct nl_cb *cb; int err = 0, done = 0; cb = nl_cb_alloc(NL_CB_DEFAULT); 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_OVERRUN, NL_CB_CUSTOM, nl_overrun_handler, &done); // nl_cb_set(cb, NL_CB_SKIPPED, NL_CB_CUSTOM, nl_skipped_handler, &done); nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl_seq_check_handler, &done); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, handle_event, NULL); while (!done && !err) nl_recvmsgs(sk_event, cb); } return 0; }