blob: a958d75dc0f64deb812c5989555c7a2ecd3d52a5 [file] [edit]
/* 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
/* rest is 0 or NULL */ };
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 */