1*0a2418c3SYiyang Chen // SPDX-License-Identifier: GPL-2.0 2*0a2418c3SYiyang Chen 3*0a2418c3SYiyang Chen #include <errno.h> 4*0a2418c3SYiyang Chen #include <stdint.h> 5*0a2418c3SYiyang Chen #include <string.h> 6*0a2418c3SYiyang Chen #include <sys/socket.h> 7*0a2418c3SYiyang Chen #include <sys/time.h> 8*0a2418c3SYiyang Chen #include <unistd.h> 9*0a2418c3SYiyang Chen #include <linux/genetlink.h> 10*0a2418c3SYiyang Chen 11*0a2418c3SYiyang Chen #include "netlink_helper.h" 12*0a2418c3SYiyang Chen 13*0a2418c3SYiyang Chen int netlink_open(void) 14*0a2418c3SYiyang Chen { 15*0a2418c3SYiyang Chen struct timeval tv = { .tv_sec = ACCT_RCV_TIMEOUT_SEC }; 16*0a2418c3SYiyang Chen struct sockaddr_nl addr = { 17*0a2418c3SYiyang Chen .nl_family = AF_NETLINK, 18*0a2418c3SYiyang Chen .nl_pid = getpid(), 19*0a2418c3SYiyang Chen }; 20*0a2418c3SYiyang Chen int fd; 21*0a2418c3SYiyang Chen 22*0a2418c3SYiyang Chen fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); 23*0a2418c3SYiyang Chen if (fd < 0) 24*0a2418c3SYiyang Chen return -errno; 25*0a2418c3SYiyang Chen 26*0a2418c3SYiyang Chen if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { 27*0a2418c3SYiyang Chen int err = -errno; 28*0a2418c3SYiyang Chen 29*0a2418c3SYiyang Chen close(fd); 30*0a2418c3SYiyang Chen return err; 31*0a2418c3SYiyang Chen } 32*0a2418c3SYiyang Chen 33*0a2418c3SYiyang Chen if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 34*0a2418c3SYiyang Chen int err = -errno; 35*0a2418c3SYiyang Chen 36*0a2418c3SYiyang Chen close(fd); 37*0a2418c3SYiyang Chen return err; 38*0a2418c3SYiyang Chen } 39*0a2418c3SYiyang Chen 40*0a2418c3SYiyang Chen return fd; 41*0a2418c3SYiyang Chen } 42*0a2418c3SYiyang Chen 43*0a2418c3SYiyang Chen int send_request(int fd, void *buf, size_t len) 44*0a2418c3SYiyang Chen { 45*0a2418c3SYiyang Chen struct sockaddr_nl addr = { 46*0a2418c3SYiyang Chen .nl_family = AF_NETLINK, 47*0a2418c3SYiyang Chen }; 48*0a2418c3SYiyang Chen 49*0a2418c3SYiyang Chen if (sendto(fd, buf, len, 0, (struct sockaddr *)&addr, sizeof(addr)) < 0) 50*0a2418c3SYiyang Chen return -errno; 51*0a2418c3SYiyang Chen 52*0a2418c3SYiyang Chen return 0; 53*0a2418c3SYiyang Chen } 54*0a2418c3SYiyang Chen 55*0a2418c3SYiyang Chen /* 56*0a2418c3SYiyang Chen * Resolve the generic netlink family ID for @name. 57*0a2418c3SYiyang Chen * Returns the family ID (>= 0) on success, negative errno on failure. 58*0a2418c3SYiyang Chen */ 59*0a2418c3SYiyang Chen int get_family_id(int fd, const char *name) 60*0a2418c3SYiyang Chen { 61*0a2418c3SYiyang Chen struct { 62*0a2418c3SYiyang Chen struct nlmsghdr nlh; 63*0a2418c3SYiyang Chen struct genlmsghdr genl; 64*0a2418c3SYiyang Chen char buf[256]; 65*0a2418c3SYiyang Chen } req = { 0 }; 66*0a2418c3SYiyang Chen char resp[8192]; 67*0a2418c3SYiyang Chen struct nlmsghdr *nlh; 68*0a2418c3SYiyang Chen struct genlmsghdr *genl; 69*0a2418c3SYiyang Chen struct nlattr *na; 70*0a2418c3SYiyang Chen int len; 71*0a2418c3SYiyang Chen int rem; 72*0a2418c3SYiyang Chen int ret; 73*0a2418c3SYiyang Chen 74*0a2418c3SYiyang Chen req.nlh.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); 75*0a2418c3SYiyang Chen req.nlh.nlmsg_type = GENL_ID_CTRL; 76*0a2418c3SYiyang Chen req.nlh.nlmsg_flags = NLM_F_REQUEST; 77*0a2418c3SYiyang Chen req.nlh.nlmsg_seq = 1; 78*0a2418c3SYiyang Chen req.nlh.nlmsg_pid = getpid(); 79*0a2418c3SYiyang Chen 80*0a2418c3SYiyang Chen req.genl.cmd = CTRL_CMD_GETFAMILY; 81*0a2418c3SYiyang Chen req.genl.version = 1; 82*0a2418c3SYiyang Chen 83*0a2418c3SYiyang Chen na = (struct nlattr *)((char *)&req + NLMSG_ALIGN(req.nlh.nlmsg_len)); 84*0a2418c3SYiyang Chen na->nla_type = CTRL_ATTR_FAMILY_NAME; 85*0a2418c3SYiyang Chen na->nla_len = NLA_HDRLEN + strlen(name) + 1; 86*0a2418c3SYiyang Chen memcpy(nla_data(na), name, strlen(name) + 1); 87*0a2418c3SYiyang Chen req.nlh.nlmsg_len = NLMSG_ALIGN(req.nlh.nlmsg_len) + NLA_ALIGN(na->nla_len); 88*0a2418c3SYiyang Chen 89*0a2418c3SYiyang Chen ret = send_request(fd, &req, req.nlh.nlmsg_len); 90*0a2418c3SYiyang Chen if (ret) 91*0a2418c3SYiyang Chen return ret; 92*0a2418c3SYiyang Chen 93*0a2418c3SYiyang Chen len = recv(fd, resp, sizeof(resp), 0); 94*0a2418c3SYiyang Chen if (len < 0) 95*0a2418c3SYiyang Chen return -errno; 96*0a2418c3SYiyang Chen 97*0a2418c3SYiyang Chen for (nlh = (struct nlmsghdr *)resp; NLMSG_OK(nlh, len); 98*0a2418c3SYiyang Chen nlh = NLMSG_NEXT(nlh, len)) { 99*0a2418c3SYiyang Chen if (nlh->nlmsg_type == NLMSG_ERROR) { 100*0a2418c3SYiyang Chen struct nlmsgerr *err = NLMSG_DATA(nlh); 101*0a2418c3SYiyang Chen 102*0a2418c3SYiyang Chen return err->error ? err->error : -ENOENT; 103*0a2418c3SYiyang Chen } 104*0a2418c3SYiyang Chen 105*0a2418c3SYiyang Chen genl = (struct genlmsghdr *)NLMSG_DATA(nlh); 106*0a2418c3SYiyang Chen rem = nlh->nlmsg_len - NLMSG_HDRLEN - GENL_HDRLEN; 107*0a2418c3SYiyang Chen na = (struct nlattr *)((char *)genl + GENL_HDRLEN); 108*0a2418c3SYiyang Chen while (nla_ok(na, rem)) { 109*0a2418c3SYiyang Chen if (na->nla_type == CTRL_ATTR_FAMILY_ID) 110*0a2418c3SYiyang Chen return *(uint16_t *)nla_data(na); 111*0a2418c3SYiyang Chen na = nla_next(na, &rem); 112*0a2418c3SYiyang Chen } 113*0a2418c3SYiyang Chen } 114*0a2418c3SYiyang Chen 115*0a2418c3SYiyang Chen return -ENOENT; 116*0a2418c3SYiyang Chen } 117