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