1570af302Sopenharmony_ci#include <errno.h>
2570af302Sopenharmony_ci#include <string.h>
3570af302Sopenharmony_ci#include <syscall.h>
4570af302Sopenharmony_ci#include <sys/socket.h>
5570af302Sopenharmony_ci#include "netlink.h"
6570af302Sopenharmony_ci
7570af302Sopenharmony_cistatic int __netlink_enumerate(int fd, unsigned int seq, int type, int af,
8570af302Sopenharmony_ci	int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx)
9570af302Sopenharmony_ci{
10570af302Sopenharmony_ci	struct nlmsghdr *h;
11570af302Sopenharmony_ci	union {
12570af302Sopenharmony_ci		uint8_t buf[8192];
13570af302Sopenharmony_ci		struct {
14570af302Sopenharmony_ci			struct nlmsghdr nlh;
15570af302Sopenharmony_ci			struct rtgenmsg g;
16570af302Sopenharmony_ci		} req;
17570af302Sopenharmony_ci		struct nlmsghdr reply;
18570af302Sopenharmony_ci	} u;
19570af302Sopenharmony_ci	int r, ret;
20570af302Sopenharmony_ci
21570af302Sopenharmony_ci	memset(&u.req, 0, sizeof(u.req));
22570af302Sopenharmony_ci	u.req.nlh.nlmsg_len = sizeof(u.req);
23570af302Sopenharmony_ci	u.req.nlh.nlmsg_type = type;
24570af302Sopenharmony_ci	u.req.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
25570af302Sopenharmony_ci	u.req.nlh.nlmsg_seq = seq;
26570af302Sopenharmony_ci	u.req.g.rtgen_family = af;
27570af302Sopenharmony_ci	r = send(fd, &u.req, sizeof(u.req), 0);
28570af302Sopenharmony_ci	if (r < 0) return r;
29570af302Sopenharmony_ci
30570af302Sopenharmony_ci	while (1) {
31570af302Sopenharmony_ci		r = recv(fd, u.buf, sizeof(u.buf), MSG_DONTWAIT);
32570af302Sopenharmony_ci		if (r <= 0) return -1;
33570af302Sopenharmony_ci		for (h = &u.reply; NLMSG_OK(h, (void*)&u.buf[r]); h = NLMSG_NEXT(h)) {
34570af302Sopenharmony_ci			if (h->nlmsg_type == NLMSG_DONE) return 0;
35570af302Sopenharmony_ci			if (h->nlmsg_type == NLMSG_ERROR) return -1;
36570af302Sopenharmony_ci			ret = cb(ctx, h);
37570af302Sopenharmony_ci			if (ret) return ret;
38570af302Sopenharmony_ci		}
39570af302Sopenharmony_ci	}
40570af302Sopenharmony_ci}
41570af302Sopenharmony_ci
42570af302Sopenharmony_ciint __rtnetlink_enumerate(int link_af, int addr_af, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx)
43570af302Sopenharmony_ci{
44570af302Sopenharmony_ci	int fd, r;
45570af302Sopenharmony_ci
46570af302Sopenharmony_ci	fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE);
47570af302Sopenharmony_ci	if (fd < 0) return -1;
48570af302Sopenharmony_ci	r = __netlink_enumerate(fd, 1, RTM_GETLINK, link_af, cb, ctx);
49570af302Sopenharmony_ci	if (!r) r = __netlink_enumerate(fd, 2, RTM_GETADDR, addr_af, cb, ctx);
50570af302Sopenharmony_ci	__syscall(SYS_close,fd);
51570af302Sopenharmony_ci	return r;
52570af302Sopenharmony_ci}
53570af302Sopenharmony_ci
54570af302Sopenharmony_ciint __rtnetlink_enumerate_new(int link_af, int addr_af, int (*cb)(void *ctx, struct nlmsghdr *h),
55570af302Sopenharmony_ci	void *ctx, int *getlink)
56570af302Sopenharmony_ci{
57570af302Sopenharmony_ci	int fd, r;
58570af302Sopenharmony_ci
59570af302Sopenharmony_ci	fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
60570af302Sopenharmony_ci	if (fd < 0) {
61570af302Sopenharmony_ci		return -1;
62570af302Sopenharmony_ci	}
63570af302Sopenharmony_ci	*getlink = __netlink_enumerate(fd, 1, RTM_GETLINK, link_af, cb, ctx);
64570af302Sopenharmony_ci	r = __netlink_enumerate(fd, 2, RTM_GETADDR, addr_af, cb, ctx);
65570af302Sopenharmony_ci	__syscall(SYS_close, fd);
66570af302Sopenharmony_ci	return r;
67570af302Sopenharmony_ci}
68