Back to index

numactl  2.0.8~rc4
rtnetlink.c
Go to the documentation of this file.
00001 /* Simple LPGLed rtnetlink library */
00002 #include <sys/socket.h>
00003 #include <linux/rtnetlink.h>
00004 #include <linux/netlink.h>
00005 #include <netinet/in.h>
00006 #include <errno.h>
00007 #include <unistd.h>
00008 #define hidden __attribute__((visibility("hidden")))
00009 #include "rtnetlink.h"
00010 
00011 
00012 hidden void *rta_put(struct nlmsghdr *m, int type, int len)
00013 {
00014        struct rtattr *rta = (void *)m + NLMSG_ALIGN(m->nlmsg_len);
00015        int rtalen = RTA_LENGTH(len);
00016 
00017        rta->rta_type = type;
00018        rta->rta_len = rtalen;
00019        m->nlmsg_len = NLMSG_ALIGN(m->nlmsg_len) + RTA_ALIGN(rtalen);
00020        return RTA_DATA(rta);
00021 }
00022 
00023 hidden struct rtattr *rta_get(struct nlmsghdr *m, struct rtattr *p, int offset)
00024 {
00025        struct rtattr *rta;
00026 
00027        if (p) {
00028               rta = RTA_NEXT(p, m->nlmsg_len);
00029               if (!RTA_OK(rta, m->nlmsg_len))
00030                      return NULL;
00031        } else {
00032               rta = (void *)m + NLMSG_ALIGN(offset);
00033        }
00034        return rta;
00035 }
00036 
00037 hidden int
00038 rta_put_address(struct nlmsghdr *msg, int type, struct sockaddr *adr)
00039 {
00040        switch (adr->sa_family) {
00041        case AF_INET: {
00042               struct in_addr *i = rta_put(msg, type, 4);
00043               *i = ((struct sockaddr_in *)adr)->sin_addr;
00044               break;
00045        }
00046        case AF_INET6: {
00047               struct in6_addr *i6 = rta_put(msg, type, 16);
00048               *i6 = ((struct sockaddr_in6 *)adr)->sin6_addr;
00049               break;
00050        }
00051        default:
00052               return -1;
00053        }
00054        return 0;
00055 }
00056 
00057 /* Assumes no truncation. Make the buffer large enough. */
00058 hidden int
00059 rtnetlink_request(struct nlmsghdr *msg, int buflen, struct sockaddr_nl *adr)
00060 {
00061        int rsk;
00062        int n;
00063        int e;
00064 
00065        /* Use a private socket to avoid having to keep state
00066           for a sequence number. */
00067        rsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
00068        if (rsk < 0)
00069               return -1;
00070        n = sendto(rsk, msg, msg->nlmsg_len, 0, (struct sockaddr *)adr,
00071                  sizeof(struct sockaddr_nl));
00072        if (n >= 0) {
00073               socklen_t adrlen = sizeof(struct sockaddr_nl);
00074               n = recvfrom(rsk, msg, buflen, 0, (struct sockaddr *)adr,
00075                           &adrlen);
00076        }
00077        e = errno;
00078        close(rsk);
00079        errno = e;
00080        if (n < 0)
00081               return -1;
00082        /* Assume we only get a single reply back. This is (hopefully?)
00083           safe because it's a single use socket. */
00084        if (msg->nlmsg_type == NLMSG_ERROR) {
00085               struct nlmsgerr *err = NLMSG_DATA(msg);
00086               errno = -err->error;
00087               return -1;
00088        }
00089        return 0;
00090 }