File: rtnetlink.c

package info (click to toggle)
numactl 2.0.12-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, bullseye-backports, buster
  • size: 1,960 kB
  • sloc: ansic: 6,594; sh: 4,710; makefile: 119
file content (89 lines) | stat: -rw-r--r-- 2,105 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/* Simple LPGLed rtnetlink library */
#include <sys/socket.h>
#include <linux/rtnetlink.h>
#include <linux/netlink.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#define hidden __attribute__((visibility("hidden")))
#include "rtnetlink.h"

hidden void *rta_put(struct nlmsghdr *m, int type, int len)
{
	struct rtattr *rta = (void *)m + NLMSG_ALIGN(m->nlmsg_len);
	int rtalen = RTA_LENGTH(len);

	rta->rta_type = type;
	rta->rta_len = rtalen;
	m->nlmsg_len = NLMSG_ALIGN(m->nlmsg_len) + RTA_ALIGN(rtalen);
	return RTA_DATA(rta);
}

hidden struct rtattr *rta_get(struct nlmsghdr *m, struct rtattr *p, int offset)
{
	struct rtattr *rta;

	if (p) {
		rta = RTA_NEXT(p, m->nlmsg_len);
		if (!RTA_OK(rta, m->nlmsg_len))
			return NULL;
	} else {
		rta = (void *)m + NLMSG_ALIGN(offset);
	}
	return rta;
}

hidden int
rta_put_address(struct nlmsghdr *msg, int type, struct sockaddr *adr)
{
	switch (adr->sa_family) {
	case AF_INET: {
		struct in_addr *i = rta_put(msg, type, 4);
		*i = ((struct sockaddr_in *)adr)->sin_addr;
		break;
	}
	case AF_INET6: {
		struct in6_addr *i6 = rta_put(msg, type, 16);
		*i6 = ((struct sockaddr_in6 *)adr)->sin6_addr;
		break;
	}
	default:
		return -1;
	}
	return 0;
}

/* Assumes no truncation. Make the buffer large enough. */
hidden int
rtnetlink_request(struct nlmsghdr *msg, int buflen, struct sockaddr_nl *adr)
{
	int rsk;
	int n;
	int e;

	/* Use a private socket to avoid having to keep state
	   for a sequence number. */
	rsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
	if (rsk < 0)
		return -1;
	n = sendto(rsk, msg, msg->nlmsg_len, 0, (struct sockaddr *)adr,
		   sizeof(struct sockaddr_nl));
	if (n >= 0) {
		socklen_t adrlen = sizeof(struct sockaddr_nl);
		n = recvfrom(rsk, msg, buflen, 0, (struct sockaddr *)adr,
			     &adrlen);
	}
	e = errno;
	close(rsk);
	errno = e;
	if (n < 0)
		return -1;
	/* Assume we only get a single reply back. This is (hopefully?)
	   safe because it's a single use socket. */
	if (msg->nlmsg_type == NLMSG_ERROR) {
		struct nlmsgerr *err = NLMSG_DATA(msg);
		errno = -err->error;
		return -1;
	}
	return 0;
}