#define _GNU_SOURCE #include #include #include #include #include #include #include "__netlink.h" struct __netlink_handle { int fd; unsigned int seq; size_t bufsize; }; struct __netlink_handle *__netlink_open(int type) { struct __netlink_handle *nh; int bufsize = getpagesize(); /* required buffer size is MIN(8192,pagesize)-sizeof(struct skb_shared_info) * the estimate for skb_shared_info size is conservative, but gives enough * space to fit struct __netlink_handle including malloc overhead in one page . */ if (bufsize > 8192) bufsize = 8192; bufsize -= 128; nh = malloc(sizeof(struct __netlink_handle) + bufsize); if (!nh) return 0; nh->fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, type); if (nh->fd < 0) { free(nh); return 0; } nh->seq = 1; nh->bufsize = bufsize; return nh; } void __netlink_close(struct __netlink_handle *nh) { close(nh->fd); free(nh); } int __netlink_enumerate(struct __netlink_handle *nh, int type, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx) { struct nlmsghdr *h; void *buf = (void*)(nh+1); struct { struct nlmsghdr nlh; struct rtgenmsg g; } *req = buf; int r, ret = 0; memset(req, 0, NETLINK_ALIGN(sizeof(*req))); req->nlh.nlmsg_len = sizeof(*req); req->nlh.nlmsg_type = type; req->nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; req->nlh.nlmsg_seq = nh->seq++; req->g.rtgen_family = AF_UNSPEC; r = send(nh->fd, req, sizeof(*req), 0); if (r < 0) return r; while (1) { r = recv(nh->fd, buf, nh->bufsize, MSG_DONTWAIT); if (r <= 0) return -1; for (h = (struct nlmsghdr*) buf; NLMSG_OK(h, (void*)((uint8_t*)buf+r)); h = NLMSG_NEXT(h)) { if (h->nlmsg_type == NLMSG_DONE) return ret; if (h->nlmsg_type == NLMSG_ERROR) return -1; if (!ret) ret = cb(ctx, h); } } }