1 /* vi: set sw=4 ts=4: */
3 * RTnetlink service routines.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
10 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
13 #include <sys/socket.h>
17 #include "libnetlink.h"
19 void FAST_FUNC xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/)
23 memset(rth, 0, sizeof(*rth));
24 rth->fd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
25 rth->local.nl_family = AF_NETLINK;
26 /*rth->local.nl_groups = subscriptions;*/
28 xbind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local));
29 addr_len = sizeof(rth->local);
30 getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len);
33 if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0)
34 bb_perror_msg_and_die("getsockname");
35 if (addr_len != sizeof(rth->local))
36 bb_error_msg_and_die("wrong address length %d", addr_len);
37 if (rth->local.nl_family != AF_NETLINK)
38 bb_error_msg_and_die("wrong address family %d", rth->local.nl_family);
40 rth->seq = time(NULL);
43 int FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
50 req.nlh.nlmsg_len = sizeof(req);
51 req.nlh.nlmsg_type = type;
52 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
53 req.nlh.nlmsg_pid = 0;
54 req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
55 req.g.rtgen_family = family;
57 return rtnl_send(rth, (void*)&req, sizeof(req));
60 int FAST_FUNC rtnl_send(struct rtnl_handle *rth, char *buf, int len)
62 struct sockaddr_nl nladdr;
64 memset(&nladdr, 0, sizeof(nladdr));
65 nladdr.nl_family = AF_NETLINK;
67 return xsendto(rth->fd, buf, len, (struct sockaddr*)&nladdr, sizeof(nladdr));
70 int FAST_FUNC rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
73 struct sockaddr_nl nladdr;
74 struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } };
76 (void*)&nladdr, sizeof(nladdr),
82 memset(&nladdr, 0, sizeof(nladdr));
83 nladdr.nl_family = AF_NETLINK;
85 nlh.nlmsg_len = NLMSG_LENGTH(len);
86 nlh.nlmsg_type = type;
87 nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
89 nlh.nlmsg_seq = rth->dump = ++rth->seq;
91 return sendmsg(rth->fd, &msg, 0);
94 static int rtnl_dump_filter(struct rtnl_handle *rth,
95 int (*filter)(const struct sockaddr_nl *, struct nlmsghdr *n, void *) FAST_FUNC,
97 int (*junk)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
101 char *buf = xmalloc(8*1024); /* avoid big stack buffer */
102 struct sockaddr_nl nladdr;
103 struct iovec iov = { buf, 8*1024 };
109 struct msghdr msg = {
110 (void*)&nladdr, sizeof(nladdr),
116 status = recvmsg(rth->fd, &msg, 0);
121 bb_perror_msg("OVERRUN");
125 bb_error_msg("EOF on netlink");
128 if (msg.msg_namelen != sizeof(nladdr)) {
129 bb_error_msg_and_die("sender address length == %d", msg.msg_namelen);
132 h = (struct nlmsghdr*)buf;
133 while (NLMSG_OK(h, status)) {
136 if (nladdr.nl_pid != 0 ||
137 h->nlmsg_pid != rth->local.nl_pid ||
138 h->nlmsg_seq != rth->dump
141 // err = junk(&nladdr, h, arg2);
150 if (h->nlmsg_type == NLMSG_DONE) {
153 if (h->nlmsg_type == NLMSG_ERROR) {
154 struct nlmsgerr *l_err = (struct nlmsgerr*)NLMSG_DATA(h);
155 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
156 bb_error_msg("ERROR truncated");
158 errno = -l_err->error;
159 bb_perror_msg("RTNETLINK answers");
163 err = filter(&nladdr, h, arg1);
170 h = NLMSG_NEXT(h, status);
172 if (msg.msg_flags & MSG_TRUNC) {
173 bb_error_msg("message truncated");
177 bb_error_msg_and_die("remnant of size %d!", status);
187 int FAST_FUNC xrtnl_dump_filter(struct rtnl_handle *rth,
188 int (*filter)(const struct sockaddr_nl *, struct nlmsghdr *, void *) FAST_FUNC,
191 int ret = rtnl_dump_filter(rth, filter, arg1/*, NULL, NULL*/);
193 bb_error_msg_and_die("dump terminated");
197 int FAST_FUNC rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
198 pid_t peer, unsigned groups,
199 struct nlmsghdr *answer,
200 int (*junk)(struct sockaddr_nl *, struct nlmsghdr *, void *),
203 /* bbox doesn't use parameters no. 3, 4, 6, 7, they are stubbed out */
212 struct sockaddr_nl nladdr;
213 struct iovec iov = { (void*)n, n->nlmsg_len };
214 char *buf = xmalloc(8*1024); /* avoid big stack buffer */
215 struct msghdr msg = {
216 (void*)&nladdr, sizeof(nladdr),
222 memset(&nladdr, 0, sizeof(nladdr));
223 nladdr.nl_family = AF_NETLINK;
224 // nladdr.nl_pid = peer;
225 // nladdr.nl_groups = groups;
227 n->nlmsg_seq = seq = ++rtnl->seq;
228 if (answer == NULL) {
229 n->nlmsg_flags |= NLM_F_ACK;
231 status = sendmsg(rtnl->fd, &msg, 0);
234 bb_perror_msg("can't talk to rtnetlink");
241 iov.iov_len = 8*1024;
242 status = recvmsg(rtnl->fd, &msg, 0);
245 if (errno == EINTR) {
248 bb_perror_msg("OVERRUN");
252 bb_error_msg("EOF on netlink");
255 if (msg.msg_namelen != sizeof(nladdr)) {
256 bb_error_msg_and_die("sender address length == %d", msg.msg_namelen);
258 for (h = (struct nlmsghdr*)buf; status >= (int)sizeof(*h); ) {
260 int len = h->nlmsg_len;
261 int l = len - sizeof(*h);
263 if (l < 0 || len > status) {
264 if (msg.msg_flags & MSG_TRUNC) {
265 bb_error_msg("truncated message");
268 bb_error_msg_and_die("malformed message: len=%d!", len);
271 if (nladdr.nl_pid != peer ||
272 h->nlmsg_pid != rtnl->local.nl_pid ||
276 // l_err = junk(&nladdr, h, jarg);
285 if (h->nlmsg_type == NLMSG_ERROR) {
286 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
287 if (l < (int)sizeof(struct nlmsgerr)) {
288 bb_error_msg("ERROR truncated");
290 errno = - err->error;
293 memcpy(answer, h, h->nlmsg_len);
297 bb_perror_msg("RTNETLINK answers");
302 memcpy(answer, h, h->nlmsg_len);
306 bb_error_msg("unexpected reply!");
308 status -= NLMSG_ALIGN(len);
309 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
311 if (msg.msg_flags & MSG_TRUNC) {
312 bb_error_msg("message truncated");
316 bb_error_msg_and_die("remnant of size %d!", status);
326 int FAST_FUNC addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data)
328 int len = RTA_LENGTH(4);
331 if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) {
334 rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
335 rta->rta_type = type;
337 move_to_unaligned32(RTA_DATA(rta), data);
338 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
342 int FAST_FUNC addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
344 int len = RTA_LENGTH(alen);
347 if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) {
350 rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
351 rta->rta_type = type;
353 memcpy(RTA_DATA(rta), data, alen);
354 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
358 int FAST_FUNC rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data)
360 int len = RTA_LENGTH(4);
361 struct rtattr *subrta;
363 if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
366 subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
367 subrta->rta_type = type;
368 subrta->rta_len = len;
369 move_to_unaligned32(RTA_DATA(subrta), data);
370 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
374 int FAST_FUNC rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen)
376 struct rtattr *subrta;
377 int len = RTA_LENGTH(alen);
379 if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
382 subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
383 subrta->rta_type = type;
384 subrta->rta_len = len;
385 memcpy(RTA_DATA(subrta), data, alen);
386 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
391 void FAST_FUNC parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
393 while (RTA_OK(rta, len)) {
394 if (rta->rta_type <= max) {
395 tb[rta->rta_type] = rta;
397 rta = RTA_NEXT(rta,len);
400 bb_error_msg("deficit %d, rta_len=%d!", len, rta->rta_len);