bpf.c revision 1.1 1 1.1 pooka /*
2 1.1 pooka * dhcpcd - DHCP client daemon
3 1.1 pooka * Copyright (c) 2006-2008 Roy Marples <roy (at) marples.name>
4 1.1 pooka *
5 1.1 pooka * Redistribution and use in source and binary forms, with or without
6 1.1 pooka * modification, are permitted provided that the following conditions
7 1.1 pooka * are met:
8 1.1 pooka * 1. Redistributions of source code must retain the above copyright
9 1.1 pooka * notice, this list of conditions and the following disclaimer.
10 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright
11 1.1 pooka * notice, this list of conditions and the following disclaimer in the
12 1.1 pooka * documentation and/or other materials provided with the distribution.
13 1.1 pooka *
14 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 1.1 pooka * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 1.1 pooka * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 1.1 pooka * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 1.1 pooka * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 1.1 pooka * SUCH DAMAGE.
25 1.1 pooka */
26 1.1 pooka
27 1.1 pooka #include <sys/types.h>
28 1.1 pooka #include <sys/ioctl.h>
29 1.1 pooka #include <sys/socket.h>
30 1.1 pooka #include <sys/uio.h>
31 1.1 pooka
32 1.1 pooka #include <net/bpf.h>
33 1.1 pooka #include <net/if.h>
34 1.1 pooka #include <arpa/inet.h>
35 1.1 pooka
36 1.1 pooka #include <errno.h>
37 1.1 pooka #include <fcntl.h>
38 1.1 pooka #include <paths.h>
39 1.1 pooka #include <stdio.h>
40 1.1 pooka #include <stdlib.h>
41 1.1 pooka #include <string.h>
42 1.1 pooka #include <unistd.h>
43 1.1 pooka
44 1.1 pooka #include "common.h"
45 1.1 pooka #include "dhcp.h"
46 1.1 pooka #include "net.h"
47 1.1 pooka #include "bpf-filter.h"
48 1.1 pooka
49 1.1 pooka #include <rump/rump.h>
50 1.1 pooka #include <rump/rump_syscalls.h>
51 1.1 pooka
52 1.1 pooka int
53 1.1 pooka open_socket(struct interface *iface, int protocol)
54 1.1 pooka {
55 1.1 pooka int fd = -1;
56 1.1 pooka int *fdp = NULL;
57 1.1 pooka struct ifreq ifr;
58 1.1 pooka int buf_len = 0;
59 1.1 pooka struct bpf_version pv;
60 1.1 pooka struct bpf_program pf;
61 1.1 pooka #ifdef BIOCIMMEDIATE
62 1.1 pooka int flags;
63 1.1 pooka #endif
64 1.1 pooka #ifdef _PATH_BPF
65 1.1 pooka fd = rump_sys_open(_PATH_BPF, O_RDWR | O_NONBLOCK);
66 1.1 pooka #else
67 1.1 pooka char *device;
68 1.1 pooka int n = 0;
69 1.1 pooka
70 1.1 pooka device = xmalloc(sizeof(char) * PATH_MAX);
71 1.1 pooka do {
72 1.1 pooka snprintf(device, PATH_MAX, "/dev/bpf%d", n++);
73 1.1 pooka fd = rump_sys_open(device, O_RDWR | O_NONBLOCK);
74 1.1 pooka } while (fd == -1 && errno == EBUSY);
75 1.1 pooka free(device);
76 1.1 pooka #endif
77 1.1 pooka
78 1.1 pooka if (fd == -1)
79 1.1 pooka return -1;
80 1.1 pooka
81 1.1 pooka if (rump_sys_ioctl(fd, BIOCVERSION, &pv) == -1)
82 1.1 pooka goto eexit;
83 1.1 pooka if (pv.bv_major != BPF_MAJOR_VERSION ||
84 1.1 pooka pv.bv_minor < BPF_MINOR_VERSION) {
85 1.1 pooka fprintf(stderr, "BPF version mismatch - recompile");
86 1.1 pooka goto eexit;
87 1.1 pooka }
88 1.1 pooka
89 1.1 pooka memset(&ifr, 0, sizeof(ifr));
90 1.1 pooka strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
91 1.1 pooka if (rump_sys_ioctl(fd, BIOCSETIF, &ifr) == -1)
92 1.1 pooka goto eexit;
93 1.1 pooka
94 1.1 pooka /* Get the required BPF buffer length from the kernel. */
95 1.1 pooka if (rump_sys_ioctl(fd, BIOCGBLEN, &buf_len) == -1)
96 1.1 pooka goto eexit;
97 1.1 pooka if (iface->buffer_size != (size_t)buf_len) {
98 1.1 pooka free(iface->buffer);
99 1.1 pooka iface->buffer_size = buf_len;
100 1.1 pooka iface->buffer = xmalloc(buf_len);
101 1.1 pooka iface->buffer_len = iface->buffer_pos = 0;
102 1.1 pooka }
103 1.1 pooka
104 1.1 pooka #ifdef BIOCIMMEDIATE
105 1.1 pooka flags = 1;
106 1.1 pooka if (rump_sys_ioctl(fd, BIOCIMMEDIATE, &flags) == -1)
107 1.1 pooka goto eexit;
108 1.1 pooka #endif
109 1.1 pooka
110 1.1 pooka /* Install the DHCP filter */
111 1.1 pooka if (protocol == ETHERTYPE_ARP) {
112 1.1 pooka pf.bf_insns = UNCONST(arp_bpf_filter);
113 1.1 pooka pf.bf_len = arp_bpf_filter_len;
114 1.1 pooka fdp = &iface->arp_fd;
115 1.1 pooka } else {
116 1.1 pooka pf.bf_insns = UNCONST(dhcp_bpf_filter);
117 1.1 pooka pf.bf_len = dhcp_bpf_filter_len;
118 1.1 pooka fdp = &iface->raw_fd;
119 1.1 pooka }
120 1.1 pooka if (rump_sys_ioctl(fd, BIOCSETF, &pf) == -1)
121 1.1 pooka goto eexit;
122 1.1 pooka if (fdp) {
123 1.1 pooka if (*fdp != -1)
124 1.1 pooka rump_sys_close(*fdp);
125 1.1 pooka *fdp = fd;
126 1.1 pooka }
127 1.1 pooka return fd;
128 1.1 pooka
129 1.1 pooka eexit:
130 1.1 pooka free(iface->buffer);
131 1.1 pooka iface->buffer = NULL;
132 1.1 pooka rump_sys_close(fd);
133 1.1 pooka return -1;
134 1.1 pooka }
135 1.1 pooka
136 1.1 pooka ssize_t
137 1.1 pooka send_raw_packet(const struct interface *iface, int protocol,
138 1.1 pooka const void *data, ssize_t len)
139 1.1 pooka {
140 1.1 pooka struct iovec iov[2];
141 1.1 pooka struct ether_header hw;
142 1.1 pooka int fd;
143 1.1 pooka
144 1.1 pooka memset(&hw, 0, ETHER_HDR_LEN);
145 1.1 pooka memset(&hw.ether_dhost, 0xff, ETHER_ADDR_LEN);
146 1.1 pooka hw.ether_type = htons(protocol);
147 1.1 pooka iov[0].iov_base = &hw;
148 1.1 pooka iov[0].iov_len = ETHER_HDR_LEN;
149 1.1 pooka iov[1].iov_base = UNCONST(data);
150 1.1 pooka iov[1].iov_len = len;
151 1.1 pooka if (protocol == ETHERTYPE_ARP)
152 1.1 pooka fd = iface->arp_fd;
153 1.1 pooka else
154 1.1 pooka fd = iface->raw_fd;
155 1.1 pooka return rump_sys_writev(fd, iov, 2);
156 1.1 pooka }
157 1.1 pooka
158 1.1 pooka /* BPF requires that we read the entire buffer.
159 1.1 pooka * So we pass the buffer in the API so we can loop on >1 packet. */
160 1.1 pooka ssize_t
161 1.1 pooka get_raw_packet(struct interface *iface, int protocol,
162 1.1 pooka void *data, ssize_t len)
163 1.1 pooka {
164 1.1 pooka int fd = -1;
165 1.1 pooka struct bpf_hdr packet;
166 1.1 pooka ssize_t bytes;
167 1.1 pooka const unsigned char *payload;
168 1.1 pooka
169 1.1 pooka if (protocol == ETHERTYPE_ARP)
170 1.1 pooka fd = iface->arp_fd;
171 1.1 pooka else
172 1.1 pooka fd = iface->raw_fd;
173 1.1 pooka
174 1.1 pooka for (;;) {
175 1.1 pooka if (iface->buffer_len == 0) {
176 1.1 pooka bytes = rump_sys_read(fd, iface->buffer, iface->buffer_size);
177 1.1 pooka if (bytes == -1)
178 1.1 pooka return errno == EAGAIN ? 0 : -1;
179 1.1 pooka else if ((size_t)bytes < sizeof(packet))
180 1.1 pooka return -1;
181 1.1 pooka iface->buffer_len = bytes;
182 1.1 pooka iface->buffer_pos = 0;
183 1.1 pooka }
184 1.1 pooka bytes = -1;
185 1.1 pooka memcpy(&packet, iface->buffer + iface->buffer_pos,
186 1.1 pooka sizeof(packet));
187 1.1 pooka if (packet.bh_caplen != packet.bh_datalen)
188 1.1 pooka goto next; /* Incomplete packet, drop. */
189 1.1 pooka if (iface->buffer_pos + packet.bh_caplen + packet.bh_hdrlen >
190 1.1 pooka iface->buffer_len)
191 1.1 pooka goto next; /* Packet beyond buffer, drop. */
192 1.1 pooka payload = iface->buffer + packet.bh_hdrlen + ETHER_HDR_LEN;
193 1.1 pooka bytes = packet.bh_caplen - ETHER_HDR_LEN;
194 1.1 pooka if (bytes > len)
195 1.1 pooka bytes = len;
196 1.1 pooka memcpy(data, payload, bytes);
197 1.1 pooka next:
198 1.1 pooka iface->buffer_pos += BPF_WORDALIGN(packet.bh_hdrlen +
199 1.1 pooka packet.bh_caplen);
200 1.1 pooka if (iface->buffer_pos >= iface->buffer_len)
201 1.1 pooka iface->buffer_len = iface->buffer_pos = 0;
202 1.1 pooka if (bytes != -1)
203 1.1 pooka return bytes;
204 1.1 pooka }
205 1.1 pooka }
206