aboutsummaryrefslogtreecommitdiffstats
path: root/net.c
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:20 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:20 -0800
commitd97c47cad830d00c9da685cc4ea157d6185f6c97 (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /net.c
parent4c5a5fb53bccceff331bae70f748bf9b4609fe0a (diff)
downloadandroid_external_dhcpcd-d97c47cad830d00c9da685cc4ea157d6185f6c97.tar.gz
android_external_dhcpcd-d97c47cad830d00c9da685cc4ea157d6185f6c97.tar.bz2
android_external_dhcpcd-d97c47cad830d00c9da685cc4ea157d6185f6c97.zip
auto import from //depot/cupcake/@135843
Diffstat (limited to 'net.c')
-rw-r--r--net.c707
1 files changed, 0 insertions, 707 deletions
diff --git a/net.c b/net.c
deleted file mode 100644
index b905573..0000000
--- a/net.c
+++ /dev/null
@@ -1,707 +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 <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <arpa/inet.h>
-#include <netinet/in_systm.h>
-#ifdef __linux__
-#include <netinet/ether.h>
-#include <netpacket/packet.h>
-#endif
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#define __FAVOR_BSD /* Nasty glibc hack so we can use BSD semantics for UDP */
-#include <netinet/udp.h>
-#undef __FAVOR_BSD
-#ifdef SIOCGIFMEDIA
-#include <net/if_media.h>
-#endif
-#include <arpa/inet.h>
-#ifdef AF_LINK
-# include <net/if_dl.h>
-#endif
-
-#include <ctype.h>
-#include <errno.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "config.h"
-#include "common.h"
-#include "dhcp.h"
-#include "logger.h"
-#include "net.h"
-#include "signals.h"
-
-int
-inet_ntocidr(struct in_addr address)
-{
- int cidr = 0;
- uint32_t mask = htonl(address.s_addr);
-
- while (mask) {
- cidr++;
- mask <<= 1;
- }
-
- return cidr;
-}
-
-int
-inet_cidrtoaddr(int cidr, struct in_addr *addr)
-{
- int ocets;
-
- if (cidr < 0 || cidr > 32) {
- errno = EINVAL;
- return -1;
- }
- ocets = (cidr + 7) / 8;
-
- addr->s_addr = 0;
- if (ocets > 0) {
- memset(&addr->s_addr, 255, (size_t)ocets - 1);
- memset((unsigned char *)&addr->s_addr + (ocets - 1),
- (256 - (1 << (32 - cidr) % 8)), 1);
- }
-
- return 0;
-}
-
-uint32_t
-get_netmask(uint32_t addr)
-{
- uint32_t dst;
-
- if (addr == 0)
- return 0;
-
- dst = htonl(addr);
- if (IN_CLASSA(dst))
- return ntohl(IN_CLASSA_NET);
- if (IN_CLASSB (dst))
- return ntohl(IN_CLASSB_NET);
- if (IN_CLASSC (dst))
- return ntohl(IN_CLASSC_NET);
-
- return 0;
-}
-
-char *
-hwaddr_ntoa(const unsigned char *hwaddr, size_t hwlen)
-{
- static char buffer[(HWADDR_LEN * 3) + 1];
- char *p = buffer;
- size_t i;
-
- for (i = 0; i < hwlen && i < HWADDR_LEN; i++) {
- if (i > 0)
- *p ++= ':';
- p += snprintf(p, 3, "%.2x", hwaddr[i]);
- }
-
- *p ++= '\0';
-
- return buffer;
-}
-
-size_t
-hwaddr_aton(unsigned char *buffer, const char *addr)
-{
- char c[3];
- const char *p = addr;
- unsigned char *bp = buffer;
- size_t len = 0;
-
- c[2] = '\0';
- while (*p) {
- c[0] = *p++;
- c[1] = *p++;
- /* Ensure that digits are hex */
- if (isxdigit((unsigned char)c[0]) == 0 ||
- isxdigit((unsigned char)c[1]) == 0)
- {
- errno = EINVAL;
- return 0;
- }
- /* We should have at least two entries 00:01 */
- if (len == 0 && *p == '\0') {
- errno = EINVAL;
- return 0;
- }
- /* Ensure that next data is EOL or a seperator with data */
- if (!(*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) {
- errno = EINVAL;
- return 0;
- }
- if (*p)
- p++;
- if (bp)
- *bp++ = (unsigned char)strtol(c, NULL, 16);
- len++;
- }
- return len;
-}
-
-int
-do_interface(const char *ifname,
- _unused unsigned char *hwaddr, _unused size_t *hwlen,
- struct in_addr *addr, struct in_addr *net, int get)
-{
- int s;
- struct ifconf ifc;
- int retval = 0, found = 0;
- int len = 10 * sizeof(struct ifreq);
- int lastlen = 0;
- char *p;
- union {
- char *buffer;
- struct ifreq *ifr;
- } ifreqs;
- struct sockaddr_in address;
- struct ifreq *ifr;
- struct sockaddr_in netmask;
-#ifdef AF_LINK
- struct sockaddr_dl *sdl;
-#endif
-
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
- return -1;
-
- /* Not all implementations return the needed buffer size for
- * SIOGIFCONF so we loop like so for all until it works */
- memset(&ifc, 0, sizeof(ifc));
- for (;;) {
- ifc.ifc_len = len;
- ifc.ifc_buf = xmalloc((size_t)len);
- if (ioctl(s, SIOCGIFCONF, &ifc) == -1) {
- if (errno != EINVAL || lastlen != 0) {
- close(s);
- free(ifc.ifc_buf);
- return -1;
- }
- } else {
- if (ifc.ifc_len == lastlen)
- break;
- lastlen = ifc.ifc_len;
- }
-
- free(ifc.ifc_buf);
- ifc.ifc_buf = NULL;
- len *= 2;
- }
-
- for (p = (char *)ifc.ifc_buf; p < (char *)ifc.ifc_buf + ifc.ifc_len;) {
- /* Cast the ifc buffer to an ifreq cleanly */
- ifreqs.buffer = p;
- ifr = ifreqs.ifr;
-
-#ifndef __linux__
- if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_ifru))
- p += offsetof(struct ifreq, ifr_ifru) +
- ifr->ifr_addr.sa_len;
- else
-#endif
- p += sizeof(*ifr);
-
- if (strcmp(ifname, ifr->ifr_name) != 0)
- continue;
-
- found = 1;
-
-#ifdef AF_LINK
- if (hwaddr && hwlen && ifr->ifr_addr.sa_family == AF_LINK) {
- sdl = xmalloc(ifr->ifr_addr.sa_len);
- memcpy(sdl, &ifr->ifr_addr, ifr->ifr_addr.sa_len);
- *hwlen = sdl->sdl_alen;
- memcpy(hwaddr, LLADDR(sdl), *hwlen);
- free(sdl);
- retval = 1;
- break;
- }
-#endif
-
- if (ifr->ifr_addr.sa_family == AF_INET) {
- memcpy(&address, &ifr->ifr_addr, sizeof(address));
- if (ioctl(s, SIOCGIFNETMASK, ifr) == -1)
- continue;
- memcpy(&netmask, &ifr->ifr_addr, sizeof(netmask));
- if (get) {
- addr->s_addr = address.sin_addr.s_addr;
- net->s_addr = netmask.sin_addr.s_addr;
- retval = 1;
- break;
- } else {
- if (address.sin_addr.s_addr == addr->s_addr &&
- (!net ||
- netmask.sin_addr.s_addr == net->s_addr))
- {
- retval = 1;
- break;
- }
- }
- }
-
- }
-
- if (!found)
- errno = ENXIO;
- close(s);
- free(ifc.ifc_buf);
- return retval;
-}
-
-int
-up_interface(const char *ifname)
-{
- int s;
- struct ifreq ifr;
- int retval = -1;
-#ifdef __linux__
- char *p;
-#endif
-
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
- return -1;
- memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
-#ifdef __linux__
- /* We can only bring the real interface up */
- if ((p = strchr(ifr.ifr_name, ':')))
- *p = '\0';
-#endif
- if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0) {
- if ((ifr.ifr_flags & IFF_UP))
- retval = 0;
- else {
- ifr.ifr_flags |= IFF_UP;
- if (ioctl(s, SIOCSIFFLAGS, &ifr) == 0)
- retval = 0;
- }
- }
- close(s);
- return retval;
-}
-
-int
-carrier_status(const char *ifname)
-{
- int s;
- struct ifreq ifr;
- int retval = -1;
-#ifdef SIOCGIFMEDIA
- struct ifmediareq ifmr;
-#endif
-#ifdef __linux__
- char *p;
-#endif
-
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
- return -1;
- memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
-#ifdef __linux__
- /* We can only test the real interface up */
- if ((p = strchr(ifr.ifr_name, ':')))
- *p = '\0';
-#endif
- if ((retval = ioctl(s, SIOCGIFFLAGS, &ifr)) == 0) {
- if (ifr.ifr_flags & IFF_UP && ifr.ifr_flags & IFF_RUNNING)
- retval = 1;
- else
- retval = 0;
- }
-
-#ifdef SIOCGIFMEDIA
- if (retval == 1) {
- memset(&ifmr, 0, sizeof(ifmr));
- strncpy(ifmr.ifm_name, ifr.ifr_name, sizeof(ifmr.ifm_name));
- if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1 &&
- ifmr.ifm_status & IFM_AVALID)
- {
- if (!(ifmr.ifm_status & IFM_ACTIVE))
- retval = 0;
- }
- }
-#endif
- close(s);
- return retval;
-}
-
-struct interface *
-read_interface(const char *ifname, _unused int metric)
-{
- int s;
- struct ifreq ifr;
- struct interface *iface = NULL;
- unsigned char *hwaddr = NULL;
- size_t hwlen = 0;
- sa_family_t family = 0;
-
- memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
-
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
- return NULL;
-
-#ifdef __linux__
- strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
- if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1)
- goto eexit;
-
- switch (ifr.ifr_hwaddr.sa_family) {
- case ARPHRD_ETHER:
- case ARPHRD_IEEE802:
- hwlen = ETHER_ADDR_LEN;
- break;
- case ARPHRD_IEEE1394:
- hwlen = EUI64_ADDR_LEN;
- case ARPHRD_INFINIBAND:
- hwlen = INFINIBAND_ADDR_LEN;
- break;
- }
-
- hwaddr = xmalloc(sizeof(unsigned char) * HWADDR_LEN);
- memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, hwlen);
- family = ifr.ifr_hwaddr.sa_family;
-#else
- ifr.ifr_metric = metric;
- strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
- if (ioctl(s, SIOCSIFMETRIC, &ifr) == -1)
- goto eexit;
-
- hwaddr = xmalloc(sizeof(unsigned char) * HWADDR_LEN);
- if (do_interface(ifname, hwaddr, &hwlen, NULL, NULL, 0) != 1)
- goto eexit;
-
- family = ARPHRD_ETHER;
-#endif
-
- strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
- if (ioctl(s, SIOCGIFMTU, &ifr) == -1)
- goto eexit;
-
- /* Ensure that the MTU is big enough for DHCP */
- if (ifr.ifr_mtu < MTU_MIN) {
- ifr.ifr_mtu = MTU_MIN;
- strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
- if (ioctl(s, SIOCSIFMTU, &ifr) == -1)
- goto eexit;
- }
-
- if (up_interface(ifname) != 0)
- goto eexit;
-
- iface = xzalloc(sizeof(*iface));
- strlcpy(iface->name, ifname, IF_NAMESIZE);
- snprintf(iface->leasefile, PATH_MAX, LEASEFILE, ifname);
- memcpy(&iface->hwaddr, hwaddr, hwlen);
- iface->hwlen = hwlen;
-
- iface->family = family;
- iface->arpable = !(ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK));
-
- /* 0 is a valid fd, so init to -1 */
- iface->raw_fd = -1;
- iface->udp_fd = -1;
- iface->arp_fd = -1;
- iface->link_fd = -1;
-
-eexit:
- close(s);
- free(hwaddr);
- return iface;
-}
-
-int
-do_mtu(const char *ifname, short int mtu)
-{
- struct ifreq ifr;
- int r;
- int s;
-
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
- return -1;
-
- memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
- ifr.ifr_mtu = mtu;
- r = ioctl(s, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr);
- close(s);
- if (r == -1)
- return -1;
- return ifr.ifr_mtu;
-}
-
-void
-free_routes(struct rt *routes)
-{
- struct rt *r;
-
- while (routes) {
- r = routes->next;
- free(routes);
- routes = r;
- }
-}
-
-int
-open_udp_socket(struct interface *iface)
-{
- int s;
- union sockunion {
- struct sockaddr sa;
- struct sockaddr_in sin;
- } su;
- int n;
-#ifdef SO_BINDTODEVICE
- struct ifreq ifr;
-#endif
-
- if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
- return -1;
-
- n = 1;
- if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1)
- goto eexit;
-#ifdef SO_BINDTODEVICE
- memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
- if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1)
- goto eexit;
-#endif
- /* As we don't use this socket for receiving, set the
- * receive buffer to 1 */
- n = 1;
- if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1)
- goto eexit;
- memset(&su, 0, sizeof(su));
- su.sin.sin_family = AF_INET;
- su.sin.sin_port = htons(DHCP_CLIENT_PORT);
- su.sin.sin_addr.s_addr = iface->addr.s_addr;
- if (bind(s, &su.sa, sizeof(su)) == -1)
- goto eexit;
-
- iface->udp_fd = s;
- set_cloexec(s);
- return 0;
-
-eexit:
- close(s);
- return -1;
-}
-
-ssize_t
-send_packet(const struct interface *iface, struct in_addr to,
- const uint8_t *data, ssize_t len)
-{
- union sockunion {
- struct sockaddr sa;
- struct sockaddr_in sin;
- } su;
-
- memset(&su, 0, sizeof(su));
- su.sin.sin_family = AF_INET;
- su.sin.sin_addr.s_addr = to.s_addr;
- su.sin.sin_port = htons(DHCP_SERVER_PORT);
-
- return sendto(iface->udp_fd, data, len, 0, &su.sa, sizeof(su));
-}
-
-struct udp_dhcp_packet
-{
- struct ip ip;
- struct udphdr udp;
- struct dhcp_message dhcp;
-};
-const size_t udp_dhcp_len = sizeof(struct udp_dhcp_packet);
-
-static uint16_t
-checksum(const void *data, uint16_t len)
-{
- const uint8_t *addr = data;
- uint32_t sum = 0;
-
- while (len > 1) {
- sum += addr[0] * 256 + addr[1];
- addr += 2;
- len -= 2;
- }
-
- if (len == 1)
- sum += *addr * 256;
-
- sum = (sum >> 16) + (sum & 0xffff);
- sum += (sum >> 16);
-
- sum = htons(sum);
-
- return ~sum;
-}
-
-ssize_t
-make_udp_packet(uint8_t **packet, const uint8_t *data, size_t length,
- struct in_addr source, struct in_addr dest)
-{
- struct udp_dhcp_packet *udpp;
- struct ip *ip;
- struct udphdr *udp;
-
- udpp = xzalloc(sizeof(*udpp));
- ip = &udpp->ip;
- udp = &udpp->udp;
-
- /* OK, this is important :)
- * We copy the data to our packet and then create a small part of the
- * ip structure and an invalid ip_len (basically udp length).
- * We then fill the udp structure and put the checksum
- * of the whole packet into the udp checksum.
- * Finally we complete the ip structure and ip checksum.
- * If we don't do the ordering like so then the udp checksum will be
- * broken, so find another way of doing it! */
-
- memcpy(&udpp->dhcp, data, length);
-
- ip->ip_p = IPPROTO_UDP;
- ip->ip_src.s_addr = source.s_addr;
- if (dest.s_addr == 0)
- ip->ip_dst.s_addr = INADDR_BROADCAST;
- else
- ip->ip_dst.s_addr = dest.s_addr;
-
- udp->uh_sport = htons(DHCP_CLIENT_PORT);
- udp->uh_dport = htons(DHCP_SERVER_PORT);
- udp->uh_ulen = htons(sizeof(*udp) + length);
- ip->ip_len = udp->uh_ulen;
- udp->uh_sum = checksum(udpp, sizeof(*udpp));
-
- ip->ip_v = IPVERSION;
- ip->ip_hl = 5;
- ip->ip_id = 0;
- ip->ip_tos = IPTOS_LOWDELAY;
- ip->ip_len = htons (sizeof(*ip) + sizeof(*udp) + length);
- ip->ip_id = 0;
- ip->ip_off = htons(IP_DF); /* Don't fragment */
- ip->ip_ttl = IPDEFTTL;
-
- ip->ip_sum = checksum(ip, sizeof(*ip));
-
- *packet = (uint8_t *)udpp;
- return sizeof(*ip) + sizeof(*udp) + length;
-}
-
-ssize_t
-get_udp_data(const uint8_t **data, const uint8_t *udp)
-{
- struct udp_dhcp_packet packet;
-
- memcpy(&packet, udp, sizeof(packet));
- *data = udp + offsetof(struct udp_dhcp_packet, dhcp);
- return ntohs(packet.ip.ip_len) - sizeof(packet.ip) - sizeof(packet.udp);
-}
-
-int
-valid_udp_packet(const uint8_t *data)
-{
- struct udp_dhcp_packet packet;
- uint16_t bytes;
- uint16_t ipsum;
- uint16_t iplen;
- uint16_t udpsum;
- struct in_addr source;
- struct in_addr dest;
- int retval = 0;
-
- memcpy(&packet, data, sizeof(packet));
- bytes = ntohs(packet.ip.ip_len);
- ipsum = packet.ip.ip_sum;
- iplen = packet.ip.ip_len;
- udpsum = packet.udp.uh_sum;
-
- if (0 != checksum(&packet.ip, sizeof(packet.ip))) {
- errno = EINVAL;
- return -1;
- }
-
- packet.ip.ip_sum = 0;
- memcpy(&source, &packet.ip.ip_src, sizeof(packet.ip.ip_src));
- memcpy(&dest, &packet.ip.ip_dst, sizeof(packet.ip.ip_dst));
- memset(&packet.ip, 0, sizeof(packet.ip));
- packet.udp.uh_sum = 0;
-
- packet.ip.ip_p = IPPROTO_UDP;
- memcpy(&packet.ip.ip_src, &source, sizeof(packet.ip.ip_src));
- memcpy(&packet.ip.ip_dst, &dest, sizeof(packet.ip.ip_dst));
- packet.ip.ip_len = packet.udp.uh_ulen;
- if (udpsum && udpsum != checksum(&packet, bytes)) {
- errno = EINVAL;
- retval = -1;
- }
-
- return retval;
-}
-
-int
-send_arp(const struct interface *iface, int op, in_addr_t sip, in_addr_t tip)
-{
- struct arphdr *arp;
- size_t arpsize;
- uint8_t *p;
- int retval;
-
- arpsize = sizeof(*arp) + 2 * iface->hwlen + 2 * sizeof(sip);
- arp = xmalloc(arpsize);
- arp->ar_hrd = htons(iface->family);
- arp->ar_pro = htons(ETHERTYPE_IP);
- arp->ar_hln = iface->hwlen;
- arp->ar_pln = sizeof(sip);
- arp->ar_op = htons(op);
- p = (uint8_t *)arp;
- p += sizeof(*arp);
- memcpy(p, iface->hwaddr, iface->hwlen);
- p += iface->hwlen;
- memcpy(p, &sip, sizeof(sip));
- p += sizeof(sip);
- /* ARP requests should ignore this */
- retval = iface->hwlen;
- while (retval--)
- *p++ = '\0';
- memcpy(p, &tip, sizeof(tip));
- p += sizeof(tip);
- retval = send_raw_packet(iface, ETHERTYPE_ARP, arp, arpsize);
- free(arp);
- return retval;
-}