lpf.c revision e86eee143ed21592f88a46623a81f71002430459
1/*
2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2009 Roy Marples <roy@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 */
61static 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
67int
68open_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
116eexit:
117	close(s);
118	return -1;
119}
120
121ssize_t
122send_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
154ssize_t
155get_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