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