diff options
Diffstat (limited to 'if-linux.c')
-rw-r--r-- | if-linux.c | 379 |
1 files changed, 0 insertions, 379 deletions
diff --git a/if-linux.c b/if-linux.c deleted file mode 100644 index 1009270..0000000 --- a/if-linux.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples <roy@marples.name> - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <asm/types.h> /* Needed for 2.4 kernels */ - -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/ioctl.h> -#include <sys/param.h> - -#include <arpa/inet.h> -#include <linux/netlink.h> -#include <linux/rtnetlink.h> -#include <netinet/ether.h> -#include <netpacket/packet.h> - -#include <errno.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -/* Support older kernels */ -#ifndef IFLA_WIRELESS -# define IFLA_WIRELSSS (IFLFA_MASTER + 1) -#endif - -#include "config.h" -#include "common.h" -#include "dhcp.h" -#include "net.h" - -#define BUFFERLEN 256 - -int -open_link_socket(struct interface *iface) -{ - int fd; - struct sockaddr_nl nl; - - if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) - return -1; - memset(&nl, 0, sizeof(nl)); - nl.nl_family = AF_NETLINK; - nl.nl_groups = RTMGRP_LINK; - if (bind(fd, (struct sockaddr *)&nl, sizeof(nl)) == -1) - return -1; - set_cloexec(fd); - if (iface->link_fd != -1) - close(iface->link_fd); - iface->link_fd = fd; - return 0; -} - -static int -get_netlink(int fd, int flags, - int (*callback)(struct nlmsghdr *, const char *), - const char *ifname) -{ - char *buffer = NULL; - ssize_t bytes; - struct nlmsghdr *nlm; - int r = -1; - - buffer = xzalloc(sizeof(char) * BUFFERLEN); - for (;;) { - bytes = recv(fd, buffer, BUFFERLEN, flags); - if (bytes == -1) { - if (errno == EAGAIN) { - r = 0; - goto eexit; - } - if (errno == EINTR) - continue; - goto eexit; - } - for (nlm = (struct nlmsghdr *)buffer; - NLMSG_OK(nlm, (size_t)bytes); - nlm = NLMSG_NEXT(nlm, bytes)) - { - r = callback(nlm, ifname); - if (r != 0) - goto eexit; - } - } - -eexit: - free(buffer); - return r; -} - -static int -err_netlink(struct nlmsghdr *nlm, _unused const char *ifname) -{ - struct nlmsgerr *err; - int l; - - if (nlm->nlmsg_type != NLMSG_ERROR) - return 0; - l = nlm->nlmsg_len - sizeof(*nlm); - if ((size_t)l < sizeof(*err)) { - errno = EBADMSG; - return -1; - } - err = (struct nlmsgerr *)NLMSG_DATA(nlm); - if (err->error == 0) - return l; - errno = -err->error; - return -1; -} - -static int -link_netlink(struct nlmsghdr *nlm, const char *ifname) -{ - int len; - struct rtattr *rta; - struct ifinfomsg *ifi; - char ifn[IF_NAMESIZE + 1]; - - if (nlm->nlmsg_type != RTM_NEWLINK && nlm->nlmsg_type != RTM_DELLINK) - return 0; - len = nlm->nlmsg_len - sizeof(*nlm); - if ((size_t)len < sizeof(*ifi)) { - errno = EBADMSG; - return -1; - } - ifi = NLMSG_DATA(nlm); - if (ifi->ifi_flags & IFF_LOOPBACK) - return 0; - rta = (struct rtattr *) ((char *)ifi + NLMSG_ALIGN(sizeof(*ifi))); - len = NLMSG_PAYLOAD(nlm, sizeof(*ifi)); - *ifn = '\0'; - while (RTA_OK(rta, len)) { - switch (rta->rta_type) { - case IFLA_WIRELESS: - /* Ignore wireless messages */ - if (nlm->nlmsg_type == RTM_NEWLINK && - ifi->ifi_change == 0) - return 0; - break; - case IFLA_IFNAME: - strlcpy(ifn, RTA_DATA(rta), sizeof(ifn)); - break; - } - rta = RTA_NEXT(rta, len); - } - - if (strncmp(ifname, ifn, sizeof(ifn)) == 0) - return 1; - return 0; -} - -int -link_changed(struct interface *iface) -{ - return get_netlink(iface->link_fd, MSG_DONTWAIT, - &link_netlink, iface->name); -} - -static int -send_netlink(struct nlmsghdr *hdr) -{ - int fd, r; - struct sockaddr_nl nl; - struct iovec iov; - struct msghdr msg; - static unsigned int seq; - - if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) - return -1; - memset(&nl, 0, sizeof(nl)); - nl.nl_family = AF_NETLINK; - if (bind(fd, (struct sockaddr *)&nl, sizeof(nl)) == -1) { - close(fd); - return -1; - } - memset(&iov, 0, sizeof(iov)); - iov.iov_base = hdr; - iov.iov_len = hdr->nlmsg_len; - memset(&msg, 0, sizeof(msg)); - msg.msg_name = &nl; - msg.msg_namelen = sizeof(nl); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - /* Request a reply */ - hdr->nlmsg_flags |= NLM_F_ACK; - hdr->nlmsg_seq = ++seq; - - if (sendmsg(fd, &msg, 0) != -1) - r = get_netlink(fd, 0, &err_netlink, NULL); - else - r = -1; - close(fd); - return r; -} - -#define NLMSG_TAIL(nmsg) \ - ((struct rtattr *)(((ptrdiff_t)(nmsg))+NLMSG_ALIGN((nmsg)->nlmsg_len))) - -static int -add_attr_l(struct nlmsghdr *n, unsigned int maxlen, int type, - const void *data, int alen) -{ - int len = RTA_LENGTH(alen); - struct rtattr *rta; - - if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { - errno = ENOBUFS; - return -1; - } - - rta = NLMSG_TAIL(n); - rta->rta_type = type; - rta->rta_len = len; - memcpy(RTA_DATA(rta), data, alen); - n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); - - return 0; -} - -static int -add_attr_32(struct nlmsghdr *n, unsigned int maxlen, int type, uint32_t data) -{ - int len = RTA_LENGTH(sizeof(data)); - struct rtattr *rta; - - if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) { - errno = ENOBUFS; - return -1; - } - - rta = NLMSG_TAIL(n); - rta->rta_type = type; - rta->rta_len = len; - memcpy(RTA_DATA(rta), &data, sizeof(data)); - n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; - - return 0; -} - -struct nlma -{ - struct nlmsghdr hdr; - struct ifaddrmsg ifa; - char buffer[64]; -}; - -struct nlmr -{ - struct nlmsghdr hdr; - struct rtmsg rt; - char buffer[256]; -}; - -int -if_address(const char *ifname, - const struct in_addr *address, const struct in_addr *netmask, - const struct in_addr *broadcast, int action) -{ - struct nlma *nlm; - int retval = 0; - - nlm = xzalloc(sizeof(*nlm)); - nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); - nlm->hdr.nlmsg_flags = NLM_F_REQUEST; - if (action >= 0) { - nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE; - nlm->hdr.nlmsg_type = RTM_NEWADDR; - } else - nlm->hdr.nlmsg_type = RTM_DELADDR; - if (!(nlm->ifa.ifa_index = if_nametoindex(ifname))) { - free(nlm); - errno = ENODEV; - return -1; - } - nlm->ifa.ifa_family = AF_INET; - nlm->ifa.ifa_prefixlen = inet_ntocidr(*netmask); - /* This creates the aliased interface */ - add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LABEL, - ifname, strlen(ifname) + 1); - add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LOCAL, - &address->s_addr, sizeof(address->s_addr)); - if (action >= 0) - add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_BROADCAST, - &broadcast->s_addr, sizeof(broadcast->s_addr)); - - if (send_netlink(&nlm->hdr) == -1) - retval = -1; - free(nlm); - return retval; -} - -int -if_route(const char *ifname, - const struct in_addr *destination, const struct in_addr *netmask, - const struct in_addr *gateway, int metric, int action) -{ - struct nlmr *nlm; - unsigned int ifindex; - int retval = 0; - - - if (!(ifindex = if_nametoindex(ifname))) { - errno = ENODEV; - return -1; - } - - nlm = xzalloc(sizeof(*nlm)); - nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - nlm->hdr.nlmsg_type = RTM_NEWROUTE; - if (action == 0) - nlm->hdr.nlmsg_flags = NLM_F_REPLACE; - else if (action > 0) - /* - * ers@google: - * commented out NLM_F_EXCL here and below. We - * sometimes keep one interface up while we are - * configuring the other one, and this flag - * causes route addition to fail. - */ - nlm->hdr.nlmsg_flags = NLM_F_CREATE /* | NLM_F_EXCL */; - else - nlm->hdr.nlmsg_type = RTM_DELROUTE; - nlm->hdr.nlmsg_flags |= NLM_F_REQUEST; - nlm->rt.rtm_family = AF_INET; - nlm->rt.rtm_table = RT_TABLE_MAIN; - - if (action < 0) - nlm->rt.rtm_scope = RT_SCOPE_NOWHERE; - else { - nlm->hdr.nlmsg_flags |= NLM_F_CREATE /*| NLM_F_EXCL*/; - nlm->rt.rtm_protocol = RTPROT_BOOT; - if (gateway->s_addr == INADDR_ANY) - nlm->rt.rtm_scope = RT_SCOPE_LINK; - else - nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE; - nlm->rt.rtm_type = RTN_UNICAST; - } - - nlm->rt.rtm_dst_len = inet_ntocidr(*netmask); - add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_DST, - &destination->s_addr, sizeof(destination->s_addr)); - add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY, - &gateway->s_addr, sizeof(gateway->s_addr)); - - add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_OIF, ifindex); - add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_PRIORITY, metric); - - if (send_netlink(&nlm->hdr) == -1) - retval = -1; - free(nlm); - return retval; -} |