Home | History | Annotate | Download | only in dhcpcd
      1 /*
      2  * dhcpcd - DHCP client daemon
      3  * Copyright 2006-2008 Roy Marples <roy (at) marples.name>
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     24  * SUCH DAMAGE.
     25  */
     26 
     27 #include <sys/types.h>
     28 #include <sys/ioctl.h>
     29 #include <sys/socket.h>
     30 
     31 #include <net/if.h>
     32 #include <netinet/in_systm.h>
     33 #include <netinet/in.h>
     34 #include <arpa/inet.h>
     35 
     36 #ifdef __linux__
     37 # include <asm/types.h> /* needed for 2.4 kernels for the below header */
     38 # include <linux/filter.h>
     39 # include <netpacket/packet.h>
     40 # define bpf_insn sock_filter
     41 # define BPF_SKIPTYPE
     42 # define BPF_ETHCOOK		-ETH_HLEN
     43 # define BPF_WHOLEPACKET	0x0fffffff /* work around buggy LPF filters */
     44 #endif
     45 
     46 #include <errno.h>
     47 #include <fcntl.h>
     48 #include <stdio.h>
     49 #include <stdlib.h>
     50 #include <string.h>
     51 #include <time.h>
     52 #include <unistd.h>
     53 
     54 #include "config.h"
     55 #include "common.h"
     56 #include "dhcp.h"
     57 #include "net.h"
     58 #include "bpf-filter.h"
     59 
     60 /* Broadcast address for IPoIB */
     61 static const uint8_t ipv4_bcast_addr[] = {
     62 	0x00, 0xff, 0xff, 0xff,
     63 	0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00,
     64 	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
     65 };
     66 
     67 int
     68 open_socket(struct interface *iface, int protocol)
     69 {
     70 	int s;
     71 	union sockunion {
     72 		struct sockaddr sa;
     73 		struct sockaddr_in sin;
     74 		struct sockaddr_ll sll;
     75 		struct sockaddr_storage ss;
     76 	} su;
     77 	struct sock_fprog pf;
     78 	int *fd;
     79 
     80 	if ((s = socket(PF_PACKET, SOCK_DGRAM, htons(protocol))) == -1)
     81 		return -1;
     82 
     83 	memset(&su, 0, sizeof(su));
     84 	su.sll.sll_family = PF_PACKET;
     85 	su.sll.sll_protocol = htons(protocol);
     86 	if (!(su.sll.sll_ifindex = if_nametoindex(iface->name))) {
     87 		errno = ENOENT;
     88 		goto eexit;
     89 	}
     90 	/* Install the DHCP filter */
     91 	memset(&pf, 0, sizeof(pf));
     92 	if (protocol == ETHERTYPE_ARP) {
     93 		pf.filter = UNCONST(arp_bpf_filter);
     94 		pf.len = arp_bpf_filter_len;
     95 	} else {
     96 		pf.filter = UNCONST(dhcp_bpf_filter);
     97 		pf.len = dhcp_bpf_filter_len;
     98 	}
     99 	if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &pf, sizeof(pf)) != 0)
    100 		goto eexit;
    101 	if (set_cloexec(s) == -1)
    102 		goto eexit;
    103 	if (set_nonblock(s) == -1)
    104 		goto eexit;
    105 	if (bind(s, &su.sa, sizeof(su)) == -1)
    106 		goto eexit;
    107 	if (protocol == ETHERTYPE_ARP)
    108 		fd = &iface->arp_fd;
    109 	else
    110 		fd = &iface->raw_fd;
    111 	if (*fd != -1)
    112 		close(*fd);
    113 	*fd = s;
    114 	return s;
    115 
    116 eexit:
    117 	close(s);
    118 	return -1;
    119 }
    120 
    121 ssize_t
    122 send_raw_packet(const struct interface *iface, int protocol,
    123 		const void *data, ssize_t len)
    124 {
    125 	union sockunion {
    126 		struct sockaddr sa;
    127 		struct sockaddr_ll sll;
    128 		struct sockaddr_storage ss;
    129 	} su;
    130 	int fd;
    131 
    132 	memset(&su, 0, sizeof(su));
    133 	su.sll.sll_family = AF_PACKET;
    134 	su.sll.sll_protocol = htons(protocol);
    135 	if (!(su.sll.sll_ifindex = if_nametoindex(iface->name))) {
    136 		errno = ENOENT;
    137 		return -1;
    138 	}
    139 	su.sll.sll_hatype = htons(iface->family);
    140 	su.sll.sll_halen = iface->hwlen;
    141 	if (iface->family == ARPHRD_INFINIBAND)
    142 		memcpy(&su.sll.sll_addr,
    143 		       &ipv4_bcast_addr, sizeof(ipv4_bcast_addr));
    144 	else
    145 		memset(&su.sll.sll_addr, 0xff, iface->hwlen);
    146 	if (protocol == ETHERTYPE_ARP)
    147 		fd = iface->arp_fd;
    148 	else
    149 		fd = iface->raw_fd;
    150 
    151 	return sendto(fd, data, len, 0, &su.sa, sizeof(su));
    152 }
    153 
    154 ssize_t
    155 get_raw_packet(struct interface *iface, int protocol, void *data, ssize_t len)
    156 {
    157 	ssize_t bytes;
    158 	int fd = -1;
    159 
    160 	if (protocol == ETHERTYPE_ARP)
    161 		fd = iface->arp_fd;
    162 	else
    163 		fd = iface->raw_fd;
    164 	bytes = read(fd, data, len);
    165 	if (bytes == -1)
    166 		return errno == EAGAIN ? 0 : -1;
    167 	return bytes;
    168 }
    169