busybox/networking/libiproute/libnetlink.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * This program is free software; you can redistribute it and/or
   4 * modify it under the terms of the GNU General Public License
   5 * as published by the Free Software Foundation; either version
   6 * 2 of the License, or (at your option) any later version.
   7 *
   8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
   9 */
  10
  11#include <sys/socket.h>
  12#include <sys/uio.h>
  13
  14#include "libbb.h"
  15#include "libnetlink.h"
  16
  17void FAST_FUNC xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/)
  18{
  19        socklen_t addr_len;
  20
  21        memset(rth, 0, sizeof(*rth));
  22        rth->fd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  23        rth->local.nl_family = AF_NETLINK;
  24        /*rth->local.nl_groups = subscriptions;*/
  25
  26        xbind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local));
  27        addr_len = sizeof(rth->local);
  28        getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len);
  29
  30/* too much paranoia
  31        if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0)
  32                bb_perror_msg_and_die("getsockname");
  33        if (addr_len != sizeof(rth->local))
  34                bb_error_msg_and_die("wrong address length %d", addr_len);
  35        if (rth->local.nl_family != AF_NETLINK)
  36                bb_error_msg_and_die("wrong address family %d", rth->local.nl_family);
  37*/
  38        rth->seq = time(NULL);
  39}
  40
  41int FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
  42{
  43        struct {
  44                struct nlmsghdr nlh;
  45                struct rtgenmsg g;
  46        } req;
  47
  48        req.nlh.nlmsg_len = sizeof(req);
  49        req.nlh.nlmsg_type = type;
  50        req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
  51        req.nlh.nlmsg_pid = 0;
  52        req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
  53        req.g.rtgen_family = family;
  54
  55        return rtnl_send(rth, (void*)&req, sizeof(req));
  56}
  57
  58//TODO: pass rth->fd instead of full rth?
  59int FAST_FUNC rtnl_send(struct rtnl_handle *rth, char *buf, int len)
  60{
  61        struct sockaddr_nl nladdr;
  62
  63        memset(&nladdr, 0, sizeof(nladdr));
  64        nladdr.nl_family = AF_NETLINK;
  65
  66        return xsendto(rth->fd, buf, len, (struct sockaddr*)&nladdr, sizeof(nladdr));
  67}
  68
  69int FAST_FUNC rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
  70{
  71        struct nlmsghdr nlh;
  72        struct sockaddr_nl nladdr;
  73        struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } };
  74        struct msghdr msg = {
  75                (void*)&nladdr, sizeof(nladdr),
  76                iov,  2,
  77                NULL, 0,
  78                0
  79        };
  80
  81        memset(&nladdr, 0, sizeof(nladdr));
  82        nladdr.nl_family = AF_NETLINK;
  83
  84        nlh.nlmsg_len = NLMSG_LENGTH(len);
  85        nlh.nlmsg_type = type;
  86        nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
  87        nlh.nlmsg_pid = 0;
  88        nlh.nlmsg_seq = rth->dump = ++rth->seq;
  89
  90        return sendmsg(rth->fd, &msg, 0);
  91}
  92
  93static int rtnl_dump_filter(struct rtnl_handle *rth,
  94                int (*filter)(const struct sockaddr_nl *, struct nlmsghdr *n, void *) FAST_FUNC,
  95                void *arg1/*,
  96                int (*junk)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
  97                void *arg2*/)
  98{
  99        int retval = -1;
 100        char *buf = xmalloc(8*1024); /* avoid big stack buffer */
 101        struct sockaddr_nl nladdr;
 102        struct iovec iov = { buf, 8*1024 };
 103
 104        while (1) {
 105                int status;
 106                struct nlmsghdr *h;
 107
 108                struct msghdr msg = {
 109                        (void*)&nladdr, sizeof(nladdr),
 110                        &iov, 1,
 111                        NULL, 0,
 112                        0
 113                };
 114
 115                status = recvmsg(rth->fd, &msg, 0);
 116
 117                if (status < 0) {
 118                        if (errno == EINTR)
 119                                continue;
 120                        bb_perror_msg("OVERRUN");
 121                        continue;
 122                }
 123                if (status == 0) {
 124                        bb_error_msg("EOF on netlink");
 125                        goto ret;
 126                }
 127                if (msg.msg_namelen != sizeof(nladdr)) {
 128                        bb_error_msg_and_die("sender address length == %d", msg.msg_namelen);
 129                }
 130
 131                h = (struct nlmsghdr*)buf;
 132                while (NLMSG_OK(h, status)) {
 133                        int err;
 134
 135                        if (nladdr.nl_pid != 0 ||
 136                            h->nlmsg_pid != rth->local.nl_pid ||
 137                            h->nlmsg_seq != rth->dump
 138                        ) {
 139//                              if (junk) {
 140//                                      err = junk(&nladdr, h, arg2);
 141//                                      if (err < 0) {
 142//                                              retval = err;
 143//                                              goto ret;
 144//                                      }
 145//                              }
 146                                goto skip_it;
 147                        }
 148
 149                        if (h->nlmsg_type == NLMSG_DONE) {
 150                                goto ret_0;
 151                        }
 152                        if (h->nlmsg_type == NLMSG_ERROR) {
 153                                struct nlmsgerr *l_err = (struct nlmsgerr*)NLMSG_DATA(h);
 154                                if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
 155                                        bb_error_msg("ERROR truncated");
 156                                } else {
 157                                        errno = -l_err->error;
 158                                        bb_perror_msg("RTNETLINK answers");
 159                                }
 160                                goto ret;
 161                        }
 162                        err = filter(&nladdr, h, arg1);
 163                        if (err < 0) {
 164                                retval = err;
 165                                goto ret;
 166                        }
 167
 168 skip_it:
 169                        h = NLMSG_NEXT(h, status);
 170                }
 171                if (msg.msg_flags & MSG_TRUNC) {
 172                        bb_error_msg("message truncated");
 173                        continue;
 174                }
 175                if (status) {
 176                        bb_error_msg_and_die("remnant of size %d!", status);
 177                }
 178        } /* while (1) */
 179 ret_0:
 180        retval++; /* = 0 */
 181 ret:
 182        free(buf);
 183        return retval;
 184}
 185
 186int FAST_FUNC xrtnl_dump_filter(struct rtnl_handle *rth,
 187                int (*filter)(const struct sockaddr_nl *, struct nlmsghdr *, void *) FAST_FUNC,
 188                void *arg1)
 189{
 190        int ret = rtnl_dump_filter(rth, filter, arg1/*, NULL, NULL*/);
 191        if (ret < 0)
 192                bb_error_msg_and_die("dump terminated");
 193        return ret;
 194}
 195
 196int FAST_FUNC rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
 197                pid_t peer, unsigned groups,
 198                struct nlmsghdr *answer,
 199                int (*junk)(struct sockaddr_nl *, struct nlmsghdr *, void *),
 200                void *jarg)
 201{
 202/* bbox doesn't use parameters no. 3, 4, 6, 7, they are stubbed out */
 203#define peer   0
 204#define groups 0
 205#define junk   NULL
 206#define jarg   NULL
 207        int retval = -1;
 208        int status;
 209        unsigned seq;
 210        struct nlmsghdr *h;
 211        struct sockaddr_nl nladdr;
 212        struct iovec iov = { (void*)n, n->nlmsg_len };
 213        char   *buf = xmalloc(8*1024); /* avoid big stack buffer */
 214        struct msghdr msg = {
 215                (void*)&nladdr, sizeof(nladdr),
 216                &iov, 1,
 217                NULL, 0,
 218                0
 219        };
 220
 221        memset(&nladdr, 0, sizeof(nladdr));
 222        nladdr.nl_family = AF_NETLINK;
 223//      nladdr.nl_pid = peer;
 224//      nladdr.nl_groups = groups;
 225
 226        n->nlmsg_seq = seq = ++rtnl->seq;
 227        if (answer == NULL) {
 228                n->nlmsg_flags |= NLM_F_ACK;
 229        }
 230        status = sendmsg(rtnl->fd, &msg, 0);
 231
 232        if (status < 0) {
 233                bb_perror_msg("can't talk to rtnetlink");
 234                goto ret;
 235        }
 236
 237        iov.iov_base = buf;
 238
 239        while (1) {
 240                iov.iov_len = 8*1024;
 241                status = recvmsg(rtnl->fd, &msg, 0);
 242
 243                if (status < 0) {
 244                        if (errno == EINTR) {
 245                                continue;
 246                        }
 247                        bb_perror_msg("OVERRUN");
 248                        continue;
 249                }
 250                if (status == 0) {
 251                        bb_error_msg("EOF on netlink");
 252                        goto ret;
 253                }
 254                if (msg.msg_namelen != sizeof(nladdr)) {
 255                        bb_error_msg_and_die("sender address length == %d", msg.msg_namelen);
 256                }
 257                for (h = (struct nlmsghdr*)buf; status >= (int)sizeof(*h); ) {
 258//                      int l_err;
 259                        int len = h->nlmsg_len;
 260                        int l = len - sizeof(*h);
 261
 262                        if (l < 0 || len > status) {
 263                                if (msg.msg_flags & MSG_TRUNC) {
 264                                        bb_error_msg("truncated message");
 265                                        goto ret;
 266                                }
 267                                bb_error_msg_and_die("malformed message: len=%d!", len);
 268                        }
 269
 270                        if (nladdr.nl_pid != peer ||
 271                            h->nlmsg_pid != rtnl->local.nl_pid ||
 272                            h->nlmsg_seq != seq
 273                        ) {
 274//                              if (junk) {
 275//                                      l_err = junk(&nladdr, h, jarg);
 276//                                      if (l_err < 0) {
 277//                                              retval = l_err;
 278//                                              goto ret;
 279//                                      }
 280//                              }
 281                                continue;
 282                        }
 283
 284                        if (h->nlmsg_type == NLMSG_ERROR) {
 285                                struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
 286                                if (l < (int)sizeof(struct nlmsgerr)) {
 287                                        bb_error_msg("ERROR truncated");
 288                                } else {
 289                                        errno = - err->error;
 290                                        if (errno == 0) {
 291                                                if (answer) {
 292                                                        memcpy(answer, h, h->nlmsg_len);
 293                                                }
 294                                                goto ret_0;
 295                                        }
 296                                        bb_perror_msg("RTNETLINK answers");
 297                                }
 298                                goto ret;
 299                        }
 300                        if (answer) {
 301                                memcpy(answer, h, h->nlmsg_len);
 302                                goto ret_0;
 303                        }
 304
 305                        bb_error_msg("unexpected reply!");
 306
 307                        status -= NLMSG_ALIGN(len);
 308                        h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
 309                }
 310                if (msg.msg_flags & MSG_TRUNC) {
 311                        bb_error_msg("message truncated");
 312                        continue;
 313                }
 314                if (status) {
 315                        bb_error_msg_and_die("remnant of size %d!", status);
 316                }
 317        } /* while (1) */
 318 ret_0:
 319        retval++; /* = 0 */
 320 ret:
 321        free(buf);
 322        return retval;
 323}
 324
 325int FAST_FUNC addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data)
 326{
 327        int len = RTA_LENGTH(4);
 328        struct rtattr *rta;
 329
 330        if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) {
 331                return -1;
 332        }
 333        rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
 334        rta->rta_type = type;
 335        rta->rta_len = len;
 336        move_to_unaligned32(RTA_DATA(rta), data);
 337        n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
 338        return 0;
 339}
 340
 341int FAST_FUNC addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
 342{
 343        int len = RTA_LENGTH(alen);
 344        struct rtattr *rta;
 345
 346        if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) {
 347                return -1;
 348        }
 349        rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
 350        rta->rta_type = type;
 351        rta->rta_len = len;
 352        memcpy(RTA_DATA(rta), data, alen);
 353        n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
 354        return 0;
 355}
 356
 357int FAST_FUNC rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data)
 358{
 359        int len = RTA_LENGTH(4);
 360        struct rtattr *subrta;
 361
 362        if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
 363                return -1;
 364        }
 365        subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
 366        subrta->rta_type = type;
 367        subrta->rta_len = len;
 368        move_to_unaligned32(RTA_DATA(subrta), data);
 369        rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
 370        return 0;
 371}
 372
 373int FAST_FUNC rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen)
 374{
 375        struct rtattr *subrta;
 376        int len = RTA_LENGTH(alen);
 377
 378        if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
 379                return -1;
 380        }
 381        subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
 382        subrta->rta_type = type;
 383        subrta->rta_len = len;
 384        memcpy(RTA_DATA(subrta), data, alen);
 385        rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
 386        return 0;
 387}
 388
 389
 390void FAST_FUNC parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
 391{
 392        while (RTA_OK(rta, len)) {
 393                if (rta->rta_type <= max) {
 394                        tb[rta->rta_type] = rta;
 395                }
 396                rta = RTA_NEXT(rta, len);
 397        }
 398        if (len) {
 399                bb_error_msg("deficit %d, rta_len=%d!", len, rta->rta_len);
 400        }
 401}
 402