#include #include "sd-netlink.h" #include "netlink-internal.h" #include "alloc-util.h" typedef struct { const char* name; uint8_t version; } genl_family; static const genl_family genl_families[] = { [SD_GENL_ID_CTRL] = { .name = "", .version = 1 }, [SD_GENL_WIREGUARD] = { .name = "wireguard", .version = 1 }, }; int sd_genl_socket_open(sd_netlink **ret) { return netlink_open_family(ret, NETLINK_GENERIC); } static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id); static int genl_message_new(sd_netlink *nl, sd_genl_family family, uint16_t nlmsg_type, uint8_t cmd, sd_netlink_message **ret) { int r; struct genlmsghdr *genl; const NLType *genl_cmd_type, *nl_type; const NLTypeSystem *type_system; size_t size; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL); r = type_system_get_type(&genl_family_type_system_root, &genl_cmd_type, family); if (r < 0) return r; r = message_new_empty(nl, &m); if (r < 0) return r; size = NLMSG_SPACE(sizeof(struct genlmsghdr)); m->hdr = malloc0(size); if (!m->hdr) return -ENOMEM; m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; type_get_type_system(genl_cmd_type, &type_system); r = type_system_get_type(type_system, &nl_type, cmd); if (r < 0) return r; m->hdr->nlmsg_len = size; m->hdr->nlmsg_type = nlmsg_type; type_get_type_system(nl_type, &m->containers[0].type_system); genl = NLMSG_DATA(m->hdr); genl->cmd = cmd; genl->version = genl_families[family].version; *ret = TAKE_PTR(m); return 0; } int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **ret) { int r; uint16_t id = GENL_ID_CTRL; if (family != SD_GENL_ID_CTRL) { r = lookup_id(nl, family, &id); if (r < 0) return r; } return genl_message_new(nl, family, id, cmd, ret); } static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id) { int r; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; r = sd_genl_message_new(nl, SD_GENL_ID_CTRL, CTRL_CMD_GETFAMILY, &req); if (r < 0) return r; r = sd_netlink_message_append_string(req, CTRL_ATTR_FAMILY_NAME, genl_families[family].name); if (r < 0) return r; r = sd_netlink_call(nl, req, 0, &reply); if (r < 0) return r; return sd_netlink_message_read_u16(reply, CTRL_ATTR_FAMILY_ID, id); }