diff options
Diffstat (limited to 'fs/afs/use-rtnetlink.c')
| -rw-r--r-- | fs/afs/use-rtnetlink.c | 473 | 
1 files changed, 0 insertions, 473 deletions
diff --git a/fs/afs/use-rtnetlink.c b/fs/afs/use-rtnetlink.c deleted file mode 100644 index f8991c700e0..00000000000 --- a/fs/afs/use-rtnetlink.c +++ /dev/null @@ -1,473 +0,0 @@ -/* RTNETLINK client - * - * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/netlink.h> -#include <linux/rtnetlink.h> -#include <linux/if_addr.h> -#include <linux/if_arp.h> -#include <linux/inetdevice.h> -#include <net/netlink.h> -#include "internal.h" - -struct afs_rtm_desc { -	struct socket		*nlsock; -	struct afs_interface	*bufs; -	u8			*mac; -	size_t			nbufs; -	size_t			maxbufs; -	void			*data; -	ssize_t			datalen; -	size_t			datamax; -	int			msg_seq; -	unsigned		mac_index; -	bool			wantloopback; -	int (*parse)(struct afs_rtm_desc *, struct nlmsghdr *); -}; - -/* - * parse an RTM_GETADDR response - */ -static int afs_rtm_getaddr_parse(struct afs_rtm_desc *desc, -				 struct nlmsghdr *nlhdr) -{ -	struct afs_interface *this; -	struct ifaddrmsg *ifa; -	struct rtattr *rtattr; -	const char *name; -	size_t len; - -	ifa = (struct ifaddrmsg *) NLMSG_DATA(nlhdr); - -	_enter("{ix=%d,af=%d}", ifa->ifa_index, ifa->ifa_family); - -	if (ifa->ifa_family != AF_INET) { -		_leave(" = 0 [family %d]", ifa->ifa_family); -		return 0; -	} -	if (desc->nbufs >= desc->maxbufs) { -		_leave(" = 0 [max %zu/%zu]", desc->nbufs, desc->maxbufs); -		return 0; -	} - -	this = &desc->bufs[desc->nbufs]; - -	this->index = ifa->ifa_index; -	this->netmask.s_addr = inet_make_mask(ifa->ifa_prefixlen); -	this->mtu = 0; - -	rtattr = NLMSG_DATA(nlhdr) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)); -	len = NLMSG_PAYLOAD(nlhdr, sizeof(struct ifaddrmsg)); - -	name = "unknown"; -	for (; RTA_OK(rtattr, len); rtattr = RTA_NEXT(rtattr, len)) { -		switch (rtattr->rta_type) { -		case IFA_ADDRESS: -			memcpy(&this->address, RTA_DATA(rtattr), 4); -			break; -		case IFA_LABEL: -			name = RTA_DATA(rtattr); -			break; -		} -	} - -	_debug("%s: "NIPQUAD_FMT"/"NIPQUAD_FMT, -	       name, NIPQUAD(this->address), NIPQUAD(this->netmask)); - -	desc->nbufs++; -	_leave(" = 0"); -	return 0; -} - -/* - * parse an RTM_GETLINK response for MTUs - */ -static int afs_rtm_getlink_if_parse(struct afs_rtm_desc *desc, -				    struct nlmsghdr *nlhdr) -{ -	struct afs_interface *this; -	struct ifinfomsg *ifi; -	struct rtattr *rtattr; -	const char *name; -	size_t len, loop; - -	ifi = (struct ifinfomsg *) NLMSG_DATA(nlhdr); - -	_enter("{ix=%d}", ifi->ifi_index); - -	for (loop = 0; loop < desc->nbufs; loop++) { -		this = &desc->bufs[loop]; -		if (this->index == ifi->ifi_index) -			goto found; -	} - -	_leave(" = 0 [no match]"); -	return 0; - -found: -	if (ifi->ifi_type == ARPHRD_LOOPBACK && !desc->wantloopback) { -		_leave(" = 0 [loopback]"); -		return 0; -	} - -	rtattr = NLMSG_DATA(nlhdr) + NLMSG_ALIGN(sizeof(struct ifinfomsg)); -	len = NLMSG_PAYLOAD(nlhdr, sizeof(struct ifinfomsg)); - -	name = "unknown"; -	for (; RTA_OK(rtattr, len); rtattr = RTA_NEXT(rtattr, len)) { -		switch (rtattr->rta_type) { -		case IFLA_MTU: -			memcpy(&this->mtu, RTA_DATA(rtattr), 4); -			break; -		case IFLA_IFNAME: -			name = RTA_DATA(rtattr); -			break; -		} -	} - -	_debug("%s: "NIPQUAD_FMT"/"NIPQUAD_FMT" mtu %u", -	       name, NIPQUAD(this->address), NIPQUAD(this->netmask), -	       this->mtu); - -	_leave(" = 0"); -	return 0; -} - -/* - * parse an RTM_GETLINK response for the MAC address belonging to the lowest - * non-internal interface - */ -static int afs_rtm_getlink_mac_parse(struct afs_rtm_desc *desc, -				     struct nlmsghdr *nlhdr) -{ -	struct ifinfomsg *ifi; -	struct rtattr *rtattr; -	const char *name; -	size_t remain, len; -	bool set; - -	ifi = (struct ifinfomsg *) NLMSG_DATA(nlhdr); - -	_enter("{ix=%d}", ifi->ifi_index); - -	if (ifi->ifi_index >= desc->mac_index) { -		_leave(" = 0 [high]"); -		return 0; -	} -	if (ifi->ifi_type == ARPHRD_LOOPBACK) { -		_leave(" = 0 [loopback]"); -		return 0; -	} - -	rtattr = NLMSG_DATA(nlhdr) + NLMSG_ALIGN(sizeof(struct ifinfomsg)); -	remain = NLMSG_PAYLOAD(nlhdr, sizeof(struct ifinfomsg)); - -	name = "unknown"; -	set = false; -	for (; RTA_OK(rtattr, remain); rtattr = RTA_NEXT(rtattr, remain)) { -		switch (rtattr->rta_type) { -		case IFLA_ADDRESS: -			len = RTA_PAYLOAD(rtattr); -			memcpy(desc->mac, RTA_DATA(rtattr), -			       min_t(size_t, len, 6)); -			desc->mac_index = ifi->ifi_index; -			set = true; -			break; -		case IFLA_IFNAME: -			name = RTA_DATA(rtattr); -			break; -		} -	} - -	if (set) -		_debug("%s: %02x:%02x:%02x:%02x:%02x:%02x", -		       name, -		       desc->mac[0], desc->mac[1], desc->mac[2], -		       desc->mac[3], desc->mac[4], desc->mac[5]); - -	_leave(" = 0"); -	return 0; -} - -/* - * read the rtnetlink response and pass to parsing routine - */ -static int afs_read_rtm(struct afs_rtm_desc *desc) -{ -	struct nlmsghdr *nlhdr, tmphdr; -	struct msghdr msg; -	struct kvec iov[1]; -	void *data; -	bool last = false; -	int len, ret, remain; - -	_enter(""); - -	do { -		/* first of all peek to see how big the packet is */ -		memset(&msg, 0, sizeof(msg)); -		iov[0].iov_base = &tmphdr; -		iov[0].iov_len = sizeof(tmphdr); -		len = kernel_recvmsg(desc->nlsock, &msg, iov, 1, -				     sizeof(tmphdr), MSG_PEEK | MSG_TRUNC); -		if (len < 0) { -			_leave(" = %d [peek]", len); -			return len; -		} -		if (len == 0) -			continue; -		if (len < sizeof(tmphdr) || len < NLMSG_PAYLOAD(&tmphdr, 0)) { -			_leave(" = -EMSGSIZE"); -			return -EMSGSIZE; -		} - -		if (desc->datamax < len) { -			kfree(desc->data); -			desc->data = NULL; -			data = kmalloc(len, GFP_KERNEL); -			if (!data) -				return -ENOMEM; -			desc->data = data; -		} -		desc->datamax = len; - -		/* read all the data from this packet */ -		iov[0].iov_base = desc->data; -		iov[0].iov_len = desc->datamax; -		desc->datalen = kernel_recvmsg(desc->nlsock, &msg, iov, 1, -					       desc->datamax, 0); -		if (desc->datalen < 0) { -			_leave(" = %zd [recv]", desc->datalen); -			return desc->datalen; -		} - -		nlhdr = desc->data; - -		/* check if the header is valid */ -		if (!NLMSG_OK(nlhdr, desc->datalen) || -		    nlhdr->nlmsg_type == NLMSG_ERROR) { -			_leave(" = -EIO"); -			return -EIO; -		} - -		/* see if this is the last message */ -		if (nlhdr->nlmsg_type == NLMSG_DONE || -		    !(nlhdr->nlmsg_flags & NLM_F_MULTI)) -			last = true; - -		/* parse the bits we got this time */ -		nlmsg_for_each_msg(nlhdr, desc->data, desc->datalen, remain) { -			ret = desc->parse(desc, nlhdr); -			if (ret < 0) { -				_leave(" = %d [parse]", ret); -				return ret; -			} -		} - -	} while (!last); - -	_leave(" = 0"); -	return 0; -} - -/* - * list the interface bound addresses to get the address and netmask - */ -static int afs_rtm_getaddr(struct afs_rtm_desc *desc) -{ -	struct msghdr msg; -	struct kvec iov[1]; -	int ret; - -	struct { -		struct nlmsghdr nl_msg __attribute__((aligned(NLMSG_ALIGNTO))); -		struct ifaddrmsg addr_msg __attribute__((aligned(NLMSG_ALIGNTO))); -	} request; - -	_enter(""); - -	memset(&request, 0, sizeof(request)); - -	request.nl_msg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); -	request.nl_msg.nlmsg_type = RTM_GETADDR; -	request.nl_msg.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; -	request.nl_msg.nlmsg_seq = desc->msg_seq++; -	request.nl_msg.nlmsg_pid = 0; - -	memset(&msg, 0, sizeof(msg)); -	iov[0].iov_base = &request; -	iov[0].iov_len = sizeof(request); - -	ret = kernel_sendmsg(desc->nlsock, &msg, iov, 1, iov[0].iov_len); -	_leave(" = %d", ret); -	return ret; -} - -/* - * list the interface link statuses to get the MTUs - */ -static int afs_rtm_getlink(struct afs_rtm_desc *desc) -{ -	struct msghdr msg; -	struct kvec iov[1]; -	int ret; - -	struct { -		struct nlmsghdr nl_msg __attribute__((aligned(NLMSG_ALIGNTO))); -		struct ifinfomsg link_msg __attribute__((aligned(NLMSG_ALIGNTO))); -	} request; - -	_enter(""); - -	memset(&request, 0, sizeof(request)); - -	request.nl_msg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); -	request.nl_msg.nlmsg_type = RTM_GETLINK; -	request.nl_msg.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; -	request.nl_msg.nlmsg_seq = desc->msg_seq++; -	request.nl_msg.nlmsg_pid = 0; - -	memset(&msg, 0, sizeof(msg)); -	iov[0].iov_base = &request; -	iov[0].iov_len = sizeof(request); - -	ret = kernel_sendmsg(desc->nlsock, &msg, iov, 1, iov[0].iov_len); -	_leave(" = %d", ret); -	return ret; -} - -/* - * cull any interface records for which there isn't an MTU value - */ -static void afs_cull_interfaces(struct afs_rtm_desc *desc) -{ -	struct afs_interface *bufs = desc->bufs; -	size_t nbufs = desc->nbufs; -	int loop, point = 0; - -	_enter("{%zu}", nbufs); - -	for (loop = 0; loop < nbufs; loop++) { -		if (desc->bufs[loop].mtu != 0) { -			if (loop != point) { -				ASSERTCMP(loop, >, point); -				bufs[point] = bufs[loop]; -			} -			point++; -		} -	} - -	desc->nbufs = point; -	_leave(" [%zu/%zu]", desc->nbufs, nbufs); -} - -/* - * get a list of this system's interface IPv4 addresses, netmasks and MTUs - * - returns the number of interface records in the buffer - */ -int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs, -			    bool wantloopback) -{ -	struct afs_rtm_desc desc; -	int ret, loop; - -	_enter(""); - -	memset(&desc, 0, sizeof(desc)); -	desc.bufs = bufs; -	desc.maxbufs = maxbufs; -	desc.wantloopback = wantloopback; - -	ret = sock_create_kern(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, -			       &desc.nlsock); -	if (ret < 0) { -		_leave(" = %d [sock]", ret); -		return ret; -	} - -	/* issue RTM_GETADDR */ -	desc.parse = afs_rtm_getaddr_parse; -	ret = afs_rtm_getaddr(&desc); -	if (ret < 0) -		goto error; -	ret = afs_read_rtm(&desc); -	if (ret < 0) -		goto error; - -	/* issue RTM_GETLINK */ -	desc.parse = afs_rtm_getlink_if_parse; -	ret = afs_rtm_getlink(&desc); -	if (ret < 0) -		goto error; -	ret = afs_read_rtm(&desc); -	if (ret < 0) -		goto error; - -	afs_cull_interfaces(&desc); -	ret = desc.nbufs; - -	for (loop = 0; loop < ret; loop++) -		_debug("[%d] "NIPQUAD_FMT"/"NIPQUAD_FMT" mtu %u", -		       bufs[loop].index, -		       NIPQUAD(bufs[loop].address), -		       NIPQUAD(bufs[loop].netmask), -		       bufs[loop].mtu); - -error: -	kfree(desc.data); -	sock_release(desc.nlsock); -	_leave(" = %d", ret); -	return ret; -} - -/* - * get a MAC address from a random ethernet interface that has a real one - * - the buffer should be 6 bytes in size - */ -int afs_get_MAC_address(u8 mac[6]) -{ -	struct afs_rtm_desc desc; -	int ret; - -	_enter(""); - -	memset(&desc, 0, sizeof(desc)); -	desc.mac = mac; -	desc.mac_index = UINT_MAX; - -	ret = sock_create_kern(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, -			       &desc.nlsock); -	if (ret < 0) { -		_leave(" = %d [sock]", ret); -		return ret; -	} - -	/* issue RTM_GETLINK */ -	desc.parse = afs_rtm_getlink_mac_parse; -	ret = afs_rtm_getlink(&desc); -	if (ret < 0) -		goto error; -	ret = afs_read_rtm(&desc); -	if (ret < 0) -		goto error; - -	if (desc.mac_index < UINT_MAX) { -		/* got a MAC address */ -		_debug("[%d] %02x:%02x:%02x:%02x:%02x:%02x", -		       desc.mac_index, -		       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); -	} else { -		ret = -ENONET; -	} - -error: -	sock_release(desc.nlsock); -	_leave(" = %d", ret); -	return ret; -}  | 
