File: xio-netlink.c

package info (click to toggle)
socat 1.8.1.0-2
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 5,412 kB
  • sloc: ansic: 35,508; sh: 19,882; makefile: 159
file content (105 lines) | stat: -rw-r--r-- 2,992 bytes parent folder | download
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/* Source: socat.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* Published under the GNU General Public License V.2, see file COPYING */

/* This file contains code for the netlink operations */

#include "xiosysincludes.h"

#include "xioopen.h"

#include "xio-netlink.h"


#if HAVE_LINUX_RTNETLINK_H

int xio_netlink_mtu(
	int interface_index,
	unsigned int mtu)
{
	/* For request */
	struct {
		struct nlmsghdr  nh;
		struct ifinfomsg intf;
		char		 attrbuf[512];
	} req;
	struct rtattr *rta;
	int rtnetlink_sk;
	/* For answer */
	int len;
	struct nlmsghdr buf[8192/sizeof(struct nlmsghdr)];
	struct iovec iov = { buf, sizeof(buf) };
	struct sockaddr_nl sa;
	struct msghdr rtmsg = { &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
	struct nlmsghdr *nh;

	Info2("Setting interface %d MTU to %u using netlink", interface_index, mtu);

	/* Send the modified attributes - rtnetlink(7) */
	rtnetlink_sk = Socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
	if (rtnetlink_sk < 0) {
		Error3("xio_netlink_mtu(index=%d, mtu=%u): socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE): %s",
		       interface_index, mtu, strerror(errno));
		return STAT_NORETRY;
	}
	memset(&req, 0, sizeof(req));
	req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.intf));
	req.nh.nlmsg_flags = NLM_F_REQUEST;
	req.nh.nlmsg_type = RTM_NEWLINK;
	req.intf.ifi_family = AF_UNSPEC;
	req.intf.ifi_index = interface_index;
	req.intf.ifi_change = 0xffffffff; /* ??? */
	req.intf.ifi_change = 0x0; /* ??? */
	rta = (struct rtattr *)(((char *) &req) +
				NLMSG_ALIGN(req.nh.nlmsg_len));
	rta->rta_type = IFLA_MTU;
	rta->rta_len = RTA_LENGTH(sizeof(mtu));
	req.nh.nlmsg_len = NLMSG_ALIGN(req.nh.nlmsg_len) +
		RTA_LENGTH(sizeof(mtu));
	req.nh.nlmsg_flags |= NLM_F_ACK; /* netlink(7) */
	memcpy(RTA_DATA(rta), &mtu, sizeof(mtu));
	if (Send(rtnetlink_sk, &req, req.nh.nlmsg_len, 0) < 0) {
		Error3("xio_netlink_mtu(index=%d, mtu=%u): send(): %s",
		       interface_index, mtu, strerror(errno));
		Close(rtnetlink_sk);
		return STAT_NORETRY;
	}

	/* Try to read the answer - netlink(7) */
	if ((len = Recvmsg(rtnetlink_sk, &rtmsg, MSG_DONTWAIT)) < 0) {
		Warn3("xio_netlink_mtu(index=%d, mtu=%u): recvmsg(): %s",
		      interface_index, mtu, strerror(errno));
		Close(rtnetlink_sk);
		return STAT_NORETRY;
	}

	for (nh = (struct nlmsghdr *)buf; NLMSG_OK (nh, len);
	     nh = NLMSG_NEXT(nh, len)) {
		/* The end of multipart message */
		if (nh->nlmsg_type == NLMSG_DONE) {
		Close(rtnetlink_sk);
			return STAT_OK;
		}

		if (nh->nlmsg_type == NLMSG_ERROR) {
			/* Do some error handling */
			struct nlmsgerr *err;
			err = (struct nlmsgerr *)(NLMSG_DATA(&buf));
			if (err->error != 0) {
				Error3("xio_netlink_mtu(index=%d, mtu=%u): rtnetlink: %s",
				       interface_index, mtu, strerror(-err->error));
				Close(rtnetlink_sk);
				return STAT_NORETRY;
			}
			/* It is the acknowledgement, good */
		}

		/* Continue with parsing payload */

	}

	Close(rtnetlink_sk);
	return 0;
}

#endif /* HAVE_LINUX_RTNETLINK_H */