1 /* Netlink helpers for zbuf
2 * Copyright (c) 2014-2015 Timo Teräs
4 * This file is free software: you may copy, redistribute and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <linux/netlink.h>
17 #include <linux/rtnetlink.h>
21 #define ZNL_ALIGN(len) (((len)+3) & ~3)
23 void *znl_push(struct zbuf *zb, size_t n)
25 return zbuf_pushn(zb, ZNL_ALIGN(n));
28 void *znl_pull(struct zbuf *zb, size_t n)
30 return zbuf_pulln(zb, ZNL_ALIGN(n));
33 struct nlmsghdr *znl_nlmsg_push(struct zbuf *zb, uint16_t type, uint16_t flags)
37 n = znl_push(zb, sizeof(*n));
40 *n = (struct nlmsghdr) {
47 void znl_nlmsg_complete(struct zbuf *zb, struct nlmsghdr *n)
49 n->nlmsg_len = zb->tail - (uint8_t*)n;
52 struct nlmsghdr *znl_nlmsg_pull(struct zbuf *zb, struct zbuf *payload)
57 n = znl_pull(zb, sizeof(*n));
60 plen = n->nlmsg_len - sizeof(*n);
61 zbuf_init(payload, znl_pull(zb, plen), plen, plen);
62 zbuf_may_pulln(zb, ZNL_ALIGN(plen) - plen);
67 struct rtattr *znl_rta_push(struct zbuf *zb, uint16_t type, const void *val, size_t len)
72 rta = znl_push(zb, ZNL_ALIGN(sizeof(*rta)) + ZNL_ALIGN(len));
73 if (!rta) return NULL;
75 *rta = (struct rtattr) {
77 .rta_len = ZNL_ALIGN(sizeof(*rta)) + len,
80 dst = (uint8_t *)(rta+1);
81 memcpy(dst, val, len);
82 memset(dst+len, 0, ZNL_ALIGN(len) - len);
87 struct rtattr *znl_rta_push_u32(struct zbuf *zb, uint16_t type, uint32_t val)
89 return znl_rta_push(zb, type, &val, sizeof(val));
92 struct rtattr *znl_rta_nested_push(struct zbuf *zb, uint16_t type)
96 rta = znl_push(zb, sizeof(*rta));
97 if (!rta) return NULL;
99 *rta = (struct rtattr) {
105 void znl_rta_nested_complete(struct zbuf *zb, struct rtattr *rta)
107 size_t len = zb->tail - (uint8_t*) rta;
108 size_t align = ZNL_ALIGN(len) - len;
111 void *dst = zbuf_pushn(zb, align);
112 if (dst) memset(dst, 0, align);
117 struct rtattr *znl_rta_pull(struct zbuf *zb, struct zbuf *payload)
122 rta = znl_pull(zb, sizeof(*rta));
123 if (!rta) return NULL;
125 if (rta->rta_len > sizeof(*rta)) {
126 plen = rta->rta_len - sizeof(*rta);
127 zbuf_init(payload, znl_pull(zb, plen), plen, plen);
129 zbuf_init(payload, NULL, 0, 0);
135 int znl_open(int protocol, int groups)
137 struct sockaddr_nl addr;
138 int fd, buf = 128 * 1024;
140 fd = socket(AF_NETLINK, SOCK_RAW, protocol);
144 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
145 fcntl(fd, F_SETFD, FD_CLOEXEC);
146 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buf, sizeof(buf)) < 0)
149 memset(&addr, 0, sizeof(addr));
150 addr.nl_family = AF_NETLINK;
151 addr.nl_groups = groups;
152 if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)