source: rtems-libbsd/dhcpcd/bpf.c @ b2eb48c

55-freebsd-126-freebsd-12
Last change on this file since b2eb48c was f2ed769, checked in by Sebastian Huber <sebastian.huber@…>, on 01/30/14 at 12:29:46

DHCPCD(8): Import

Import DHCPCD(8) from:

http://roy.marples.name/projects/dhcpcd/

The upstream sources can be obtained via:

fossil clone http://roy.marples.name/projects/dhcpcd

The imported version is 2014-01-29 19:46:44 [6b209507bb].

  • Property mode set to 100644
File size: 5.6 KB
Line 
1/*
2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2014 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/time.h>
29#include <sys/ioctl.h>
30#include <sys/socket.h>
31#include <sys/uio.h>
32
33#include <net/bpf.h>
34#include <net/if.h>
35#include <arpa/inet.h>
36
37#include <errno.h>
38#include <fcntl.h>
39#include <paths.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <syslog.h>
44#include <unistd.h>
45
46#include "config.h"
47#include "common.h"
48#include "dhcp.h"
49#include "ipv4.h"
50#include "bpf-filter.h"
51
52int
53ipv4_opensocket(struct interface *ifp, int protocol)
54{
55        struct dhcp_state *state;
56        int fd = -1;
57        struct ifreq ifr;
58        int buf_len = 0;
59        struct bpf_version pv;
60        struct bpf_program pf;
61#ifdef BIOCIMMEDIATE
62        int flags;
63#endif
64#ifdef _PATH_BPF
65        fd = open(_PATH_BPF, O_RDWR | O_NONBLOCK);
66#else
67        char *device;
68        int n = 0;
69
70        device = malloc(sizeof(char) * PATH_MAX);
71        if (device == NULL)
72                return -1;
73        do {
74                snprintf(device, PATH_MAX, "/dev/bpf%d", n++);
75                fd = open(device, O_RDWR | O_NONBLOCK);
76        } while (fd == -1 && errno == EBUSY);
77        free(device);
78#endif
79
80        if (fd == -1)
81                return -1;
82
83        state = D_STATE(ifp);
84
85        if (ioctl(fd, BIOCVERSION, &pv) == -1)
86                goto eexit;
87        if (pv.bv_major != BPF_MAJOR_VERSION ||
88            pv.bv_minor < BPF_MINOR_VERSION) {
89                syslog(LOG_ERR, "BPF version mismatch - recompile");
90                goto eexit;
91        }
92
93        memset(&ifr, 0, sizeof(ifr));
94        strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
95        if (ioctl(fd, BIOCSETIF, &ifr) == -1)
96                goto eexit;
97
98        /* Get the required BPF buffer length from the kernel. */
99        if (ioctl(fd, BIOCGBLEN, &buf_len) == -1)
100                goto eexit;
101        if (state->buffer_size != (size_t)buf_len) {
102                free(state->buffer);
103                state->buffer = malloc(buf_len);
104                if (state->buffer == NULL)
105                        goto eexit;
106                state->buffer_size = buf_len;
107                state->buffer_len = state->buffer_pos = 0;
108        }
109
110#ifdef BIOCIMMEDIATE
111        flags = 1;
112        if (ioctl(fd, BIOCIMMEDIATE, &flags) == -1)
113                goto eexit;
114#endif
115
116        /* Install the DHCP filter */
117        if (protocol == ETHERTYPE_ARP) {
118                pf.bf_insns = UNCONST(arp_bpf_filter);
119                pf.bf_len = arp_bpf_filter_len;
120        } else {
121                pf.bf_insns = UNCONST(dhcp_bpf_filter);
122                pf.bf_len = dhcp_bpf_filter_len;
123        }
124        if (ioctl(fd, BIOCSETF, &pf) == -1)
125                goto eexit;
126        if (set_cloexec(fd) == -1)
127                goto eexit;
128        return fd;
129
130eexit:
131        free(state->buffer);
132        state->buffer = NULL;
133        close(fd);
134        return -1;
135}
136
137ssize_t
138ipv4_sendrawpacket(const struct interface *ifp, int protocol,
139    const void *data, ssize_t len)
140{
141        struct iovec iov[2];
142        struct ether_header hw;
143        int fd;
144        const struct dhcp_state *state;
145
146        memset(&hw, 0, ETHER_HDR_LEN);
147        memset(&hw.ether_dhost, 0xff, ETHER_ADDR_LEN);
148        hw.ether_type = htons(protocol);
149        iov[0].iov_base = &hw;
150        iov[0].iov_len = ETHER_HDR_LEN;
151        iov[1].iov_base = UNCONST(data);
152        iov[1].iov_len = len;
153        state = D_CSTATE(ifp);
154        if (protocol == ETHERTYPE_ARP)
155                fd = state->arp_fd;
156        else
157                fd = state->raw_fd;
158        return writev(fd, iov, 2);
159}
160
161/* BPF requires that we read the entire buffer.
162 * So we pass the buffer in the API so we can loop on >1 packet. */
163ssize_t
164ipv4_getrawpacket(struct interface *ifp, int protocol,
165    void *data, ssize_t len, int *partialcsum)
166{
167        int fd = -1;
168        struct bpf_hdr packet;
169        ssize_t bytes;
170        const unsigned char *payload;
171        struct dhcp_state *state;
172
173        state = D_STATE(ifp);
174        if (protocol == ETHERTYPE_ARP)
175                fd = state->arp_fd;
176        else
177                fd = state->raw_fd;
178
179        if (partialcsum != NULL)
180                *partialcsum = 0; /* Not supported on BSD */
181
182        for (;;) {
183                if (state->buffer_len == 0) {
184                        bytes = read(fd, state->buffer, state->buffer_size);
185                        if (bytes == -1)
186                                return errno == EAGAIN ? 0 : -1;
187                        else if ((size_t)bytes < sizeof(packet))
188                                return -1;
189                        state->buffer_len = bytes;
190                        state->buffer_pos = 0;
191                }
192                bytes = -1;
193                memcpy(&packet, state->buffer + state->buffer_pos,
194                    sizeof(packet));
195                if (packet.bh_caplen != packet.bh_datalen)
196                        goto next; /* Incomplete packet, drop. */
197                if (state->buffer_pos + packet.bh_caplen + packet.bh_hdrlen >
198                    state->buffer_len)
199                        goto next; /* Packet beyond buffer, drop. */
200                payload = state->buffer + state->buffer_pos +
201                    packet.bh_hdrlen + ETHER_HDR_LEN;
202                bytes = packet.bh_caplen - ETHER_HDR_LEN;
203                if (bytes > len)
204                        bytes = len;
205                memcpy(data, payload, bytes);
206next:
207                state->buffer_pos += BPF_WORDALIGN(packet.bh_hdrlen +
208                    packet.bh_caplen);
209                if (state->buffer_pos >= state->buffer_len)
210                        state->buffer_len = state->buffer_pos = 0;
211                if (bytes != -1)
212                        return bytes;
213        }
214}
Note: See TracBrowser for help on using the repository browser.