|
Packit Service |
db5786 |
/* Simple LPGLed rtnetlink library */
|
|
Packit Service |
db5786 |
#include <sys/socket.h>
|
|
Packit Service |
db5786 |
#include <linux/rtnetlink.h>
|
|
Packit Service |
db5786 |
#include <linux/netlink.h>
|
|
Packit Service |
db5786 |
#include <netinet/in.h>
|
|
Packit Service |
db5786 |
#include <errno.h>
|
|
Packit Service |
db5786 |
#include <unistd.h>
|
|
Packit Service |
db5786 |
#define hidden __attribute__((visibility("hidden")))
|
|
Packit Service |
db5786 |
#include "rtnetlink.h"
|
|
Packit Service |
db5786 |
|
|
Packit Service |
db5786 |
hidden void *rta_put(struct nlmsghdr *m, int type, int len)
|
|
Packit Service |
db5786 |
{
|
|
Packit Service |
db5786 |
struct rtattr *rta = (void *)m + NLMSG_ALIGN(m->nlmsg_len);
|
|
Packit Service |
db5786 |
int rtalen = RTA_LENGTH(len);
|
|
Packit Service |
db5786 |
|
|
Packit Service |
db5786 |
rta->rta_type = type;
|
|
Packit Service |
db5786 |
rta->rta_len = rtalen;
|
|
Packit Service |
db5786 |
m->nlmsg_len = NLMSG_ALIGN(m->nlmsg_len) + RTA_ALIGN(rtalen);
|
|
Packit Service |
db5786 |
return RTA_DATA(rta);
|
|
Packit Service |
db5786 |
}
|
|
Packit Service |
db5786 |
|
|
Packit Service |
db5786 |
hidden struct rtattr *rta_get(struct nlmsghdr *m, struct rtattr *p, int offset)
|
|
Packit Service |
db5786 |
{
|
|
Packit Service |
db5786 |
struct rtattr *rta;
|
|
Packit Service |
db5786 |
|
|
Packit Service |
db5786 |
if (p) {
|
|
Packit Service |
db5786 |
rta = RTA_NEXT(p, m->nlmsg_len);
|
|
Packit Service |
db5786 |
if (!RTA_OK(rta, m->nlmsg_len))
|
|
Packit Service |
db5786 |
return NULL;
|
|
Packit Service |
db5786 |
} else {
|
|
Packit Service |
db5786 |
rta = (void *)m + NLMSG_ALIGN(offset);
|
|
Packit Service |
db5786 |
}
|
|
Packit Service |
db5786 |
return rta;
|
|
Packit Service |
db5786 |
}
|
|
Packit Service |
db5786 |
|
|
Packit Service |
db5786 |
hidden int
|
|
Packit Service |
db5786 |
rta_put_address(struct nlmsghdr *msg, int type, struct sockaddr *adr)
|
|
Packit Service |
db5786 |
{
|
|
Packit Service |
db5786 |
switch (adr->sa_family) {
|
|
Packit Service |
db5786 |
case AF_INET: {
|
|
Packit Service |
db5786 |
struct in_addr *i = rta_put(msg, type, 4);
|
|
Packit Service |
db5786 |
*i = ((struct sockaddr_in *)adr)->sin_addr;
|
|
Packit Service |
db5786 |
break;
|
|
Packit Service |
db5786 |
}
|
|
Packit Service |
db5786 |
case AF_INET6: {
|
|
Packit Service |
db5786 |
struct in6_addr *i6 = rta_put(msg, type, 16);
|
|
Packit Service |
db5786 |
*i6 = ((struct sockaddr_in6 *)adr)->sin6_addr;
|
|
Packit Service |
db5786 |
break;
|
|
Packit Service |
db5786 |
}
|
|
Packit Service |
db5786 |
default:
|
|
Packit Service |
db5786 |
return -1;
|
|
Packit Service |
db5786 |
}
|
|
Packit Service |
db5786 |
return 0;
|
|
Packit Service |
db5786 |
}
|
|
Packit Service |
db5786 |
|
|
Packit Service |
db5786 |
/* Assumes no truncation. Make the buffer large enough. */
|
|
Packit Service |
db5786 |
hidden int
|
|
Packit Service |
db5786 |
rtnetlink_request(struct nlmsghdr *msg, int buflen, struct sockaddr_nl *adr)
|
|
Packit Service |
db5786 |
{
|
|
Packit Service |
db5786 |
int rsk;
|
|
Packit Service |
db5786 |
int n;
|
|
Packit Service |
db5786 |
int e;
|
|
Packit Service |
db5786 |
|
|
Packit Service |
db5786 |
/* Use a private socket to avoid having to keep state
|
|
Packit Service |
db5786 |
for a sequence number. */
|
|
Packit Service |
db5786 |
rsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
|
Packit Service |
db5786 |
if (rsk < 0)
|
|
Packit Service |
db5786 |
return -1;
|
|
Packit Service |
db5786 |
n = sendto(rsk, msg, msg->nlmsg_len, 0, (struct sockaddr *)adr,
|
|
Packit Service |
db5786 |
sizeof(struct sockaddr_nl));
|
|
Packit Service |
db5786 |
if (n >= 0) {
|
|
Packit Service |
db5786 |
socklen_t adrlen = sizeof(struct sockaddr_nl);
|
|
Packit Service |
db5786 |
n = recvfrom(rsk, msg, buflen, 0, (struct sockaddr *)adr,
|
|
Packit Service |
db5786 |
&adrlen);
|
|
Packit Service |
db5786 |
}
|
|
Packit Service |
db5786 |
e = errno;
|
|
Packit Service |
db5786 |
close(rsk);
|
|
Packit Service |
db5786 |
errno = e;
|
|
Packit Service |
db5786 |
if (n < 0)
|
|
Packit Service |
db5786 |
return -1;
|
|
Packit Service |
db5786 |
/* Assume we only get a single reply back. This is (hopefully?)
|
|
Packit Service |
db5786 |
safe because it's a single use socket. */
|
|
Packit Service |
db5786 |
if (msg->nlmsg_type == NLMSG_ERROR) {
|
|
Packit Service |
db5786 |
struct nlmsgerr *err = NLMSG_DATA(msg);
|
|
Packit Service |
db5786 |
errno = -err->error;
|
|
Packit Service |
db5786 |
return -1;
|
|
Packit Service |
db5786 |
}
|
|
Packit Service |
db5786 |
return 0;
|
|
Packit Service |
db5786 |
}
|