]> git.ipfire.org Git - thirdparty/dhcp.git/blob - common/bpf.c
Update license.
[thirdparty/dhcp.git] / common / bpf.c
1 /* bpf.c
2
3 BPF socket interface code, originally contributed by Archie Cobbs. */
4
5 /*
6 * Copyright (c) 1996-1999 Internet Software Consortium.
7 * Use is subject to license terms which appear in the file named
8 * ISC-LICENSE that should have accompanied this file when you
9 * received it. If a file named ISC-LICENSE did not accompany this
10 * file, or you are not sure the one you have is correct, you may
11 * obtain an applicable copy of the license at:
12 *
13 * http://www.isc.org/isc-license-1.0.html.
14 *
15 * This file is part of the ISC DHCP distribution. The documentation
16 * associated with this file is listed in the file DOCUMENTATION,
17 * included in the top-level directory of this release.
18 *
19 * Support and other services are available for ISC products - see
20 * http://www.isc.org for more information.
21 */
22
23 #ifndef lint
24 static char copyright[] =
25 "$Id: bpf.c,v 1.25 1999/03/16 05:50:31 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
26 #endif /* not lint */
27
28 #include "dhcpd.h"
29 #if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE) \
30 || defined (USE_LPF_RECEIVE)
31 # if defined (USE_LPF_RECEIVE)
32 # include <asm/types.h>
33 # include <linux/filter.h>
34 # define bpf_insn sock_filter /* Linux: dare to be gratuitously different. */
35 # else
36 # include <sys/ioctl.h>
37 # include <sys/uio.h>
38 # include <net/bpf.h>
39 # if defined (NEED_OSF_PFILT_HACKS)
40 # include <net/pfilt.h>
41 # endif
42 # endif
43
44 #include <netinet/in_systm.h>
45 #include "includes/netinet/ip.h"
46 #include "includes/netinet/udp.h"
47 #include "includes/netinet/if_ether.h"
48 #endif
49
50 /* Reinitializes the specified interface after an address change. This
51 is not required for packet-filter APIs. */
52
53 #ifdef USE_BPF_SEND
54 void if_reinitialize_send (info)
55 struct interface_info *info;
56 {
57 }
58 #endif
59
60 #ifdef USE_BPF_RECEIVE
61 void if_reinitialize_receive (info)
62 struct interface_info *info;
63 {
64 }
65 #endif
66
67 /* Called by get_interface_list for each interface that's discovered.
68 Opens a packet filter for each interface and adds it to the select
69 mask. */
70
71 #if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE)
72 int if_register_bpf (info)
73 struct interface_info *info;
74 {
75 int sock;
76 char filename[50];
77 int b;
78
79 /* Open a BPF device */
80 for (b = 0; 1; b++) {
81 #ifndef NO_SNPRINTF
82 snprintf(filename, sizeof(filename), BPF_FORMAT, b);
83 #else
84 sprintf(filename, BPF_FORMAT, b);
85 #endif
86 sock = open (filename, O_RDWR, 0);
87 if (sock < 0) {
88 if (errno == EBUSY) {
89 continue;
90 } else {
91 if (!b)
92 log_fatal ("No bpf devices.%s%s%s",
93 " Please read the README",
94 " section for your operating",
95 " system.");
96 log_fatal ("Can't find free bpf: %m");
97 }
98 } else {
99 break;
100 }
101 }
102
103 /* Set the BPF device to point at this interface. */
104 if (ioctl (sock, BIOCSETIF, info -> ifp) < 0)
105 log_fatal ("Can't attach interface %s to bpf device %s: %m",
106 info -> name, filename);
107
108 return sock;
109 }
110 #endif /* USE_BPF_SEND || USE_BPF_RECEIVE */
111
112 #ifdef USE_BPF_SEND
113 void if_register_send (info)
114 struct interface_info *info;
115 {
116 /* If we're using the bpf API for sending and receiving,
117 we don't need to register this interface twice. */
118 #ifndef USE_BPF_RECEIVE
119 info -> wfdesc = if_register_bpf (info, interface);
120 #else
121 info -> wfdesc = info -> rfdesc;
122 #endif
123 if (!quiet_interface_discovery)
124 log_info ("Sending on BPF/%s/%s%s%s",
125 info -> name,
126 print_hw_addr (info -> hw_address.htype,
127 info -> hw_address.hlen,
128 info -> hw_address.haddr),
129 (info -> shared_network ? "/" : ""),
130 (info -> shared_network ?
131 info -> shared_network -> name : ""));
132 }
133 #endif /* USE_BPF_SEND */
134
135 #if defined (USE_BPF_RECEIVE) || defined (USE_LPF_RECEIVE)
136 /* Packet filter program...
137 XXX Changes to the filter program may require changes to the constant
138 offsets used in if_register_send to patch the BPF program! XXX */
139
140 struct bpf_insn dhcp_bpf_filter [] = {
141 /* Make sure this is an IP packet... */
142 BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12),
143 BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8),
144
145 /* Make sure it's a UDP packet... */
146 BPF_STMT (BPF_LD + BPF_B + BPF_ABS, 23),
147 BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6),
148
149 /* Make sure this isn't a fragment... */
150 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
151 BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
152
153 /* Get the IP header length... */
154 BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14),
155
156 /* Make sure it's to the right port... */
157 BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16),
158 BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), /* patch */
159
160 /* If we passed all the tests, ask for the whole packet. */
161 BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
162
163 /* Otherwise, drop it. */
164 BPF_STMT(BPF_RET+BPF_K, 0),
165 };
166
167 int dhcp_bpf_filter_len = sizeof dhcp_bpf_filter / sizeof (struct bpf_insn);
168 #endif
169
170 #if defined (USE_BPF_RECEIVE)
171 void if_register_receive (info)
172 struct interface_info *info;
173 {
174 int flag = 1;
175 struct bpf_version v;
176 u_int32_t addr;
177 struct bpf_program p;
178 u_int32_t bits;
179
180 /* Open a BPF device and hang it on this interface... */
181 info -> rfdesc = if_register_bpf (info);
182
183 /* Make sure the BPF version is in range... */
184 if (ioctl (info -> rfdesc, BIOCVERSION, &v) < 0)
185 log_fatal ("Can't get BPF version: %m");
186
187 if (v.bv_major != BPF_MAJOR_VERSION ||
188 v.bv_minor < BPF_MINOR_VERSION)
189 log_fatal ("Kernel BPF version out of range - recompile dhcpd!");
190
191 /* Set immediate mode so that reads return as soon as a packet
192 comes in, rather than waiting for the input buffer to fill with
193 packets. */
194 if (ioctl (info -> rfdesc, BIOCIMMEDIATE, &flag) < 0)
195 log_fatal ("Can't set immediate mode on bpf device: %m");
196
197 #ifdef NEED_OSF_PFILT_HACKS
198 /* Allow the copyall flag to be set... */
199 if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0)
200 log_fatal ("Can't set ALLOWCOPYALL: %m");
201
202 /* Clear all the packet filter mode bits first... */
203 bits = 0;
204 if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
205 log_fatal ("Can't clear pfilt bits: %m");
206
207 /* Set the ENBATCH, ENCOPYALL, ENBPFHDR bits... */
208 bits = ENBATCH | ENCOPYALL | ENBPFHDR;
209 if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
210 log_fatal ("Can't set ENBATCH|ENCOPYALL|ENBPFHDR: %m");
211 #endif
212 /* Get the required BPF buffer length from the kernel. */
213 if (ioctl (info -> rfdesc, BIOCGBLEN, &info -> rbuf_max) < 0)
214 log_fatal ("Can't get bpf buffer length: %m");
215 info -> rbuf = malloc (info -> rbuf_max);
216 if (!info -> rbuf)
217 log_fatal ("Can't allocate %d bytes for bpf input buffer.");
218 info -> rbuf_offset = 0;
219 info -> rbuf_len = 0;
220
221 /* Set up the bpf filter program structure. */
222 p.bf_len = dhcp_bpf_filter_len;
223 p.bf_insns = dhcp_bpf_filter;
224
225 /* Patch the server port into the BPF program...
226 XXX changes to filter program may require changes
227 to the insn number(s) used below! XXX */
228 dhcp_bpf_filter [8].k = ntohs (local_port);
229
230 if (ioctl (info -> rfdesc, BIOCSETF, &p) < 0)
231 log_fatal ("Can't install packet filter program: %m");
232 if (!quiet_interface_discovery)
233 log_info ("Listening on BPF/%s/%s%s%s",
234 info -> name,
235 print_hw_addr (info -> hw_address.htype,
236 info -> hw_address.hlen,
237 info -> hw_address.haddr),
238 (info -> shared_network ? "/" : ""),
239 (info -> shared_network ?
240 info -> shared_network -> name : ""));
241 }
242 #endif /* USE_BPF_RECEIVE */
243
244 #ifdef USE_BPF_SEND
245 ssize_t send_packet (interface, packet, raw, len, from, to, hto)
246 struct interface_info *interface;
247 struct packet *packet;
248 struct dhcp_packet *raw;
249 size_t len;
250 struct in_addr from;
251 struct sockaddr_in *to;
252 struct hardware *hto;
253 {
254 int bufp = 0;
255 unsigned char buf [256];
256 struct iovec iov [2];
257 int result;
258
259 if (!strcmp (interface -> name, "fallback"))
260 return send_fallback (interface, packet, raw,
261 len, from, to, hto);
262
263 /* Assemble the headers... */
264 assemble_hw_header (interface, buf, &bufp, hto);
265 assemble_udp_ip_header (interface, buf, &bufp, from.s_addr,
266 to -> sin_addr.s_addr, to -> sin_port,
267 (unsigned char *)raw, len);
268
269 /* Fire it off */
270 iov [0].iov_base = (char *)buf;
271 iov [0].iov_len = bufp;
272 iov [1].iov_base = (char *)raw;
273 iov [1].iov_len = len;
274
275 result = writev(interface -> wfdesc, iov, 2);
276 if (result < 0)
277 warn ("send_packet: %m");
278 return result;
279 }
280 #endif /* USE_BPF_SEND */
281
282 #ifdef USE_BPF_RECEIVE
283 ssize_t receive_packet (interface, buf, len, from, hfrom)
284 struct interface_info *interface;
285 unsigned char *buf;
286 size_t len;
287 struct sockaddr_in *from;
288 struct hardware *hfrom;
289 {
290 int length = 0;
291 int offset = 0;
292 struct bpf_hdr hdr;
293
294 /* All this complexity is because BPF doesn't guarantee
295 that only one packet will be returned at a time. We're
296 getting what we deserve, though - this is a terrible abuse
297 of the BPF interface. Sigh. */
298
299 /* Process packets until we get one we can return or until we've
300 done a read and gotten nothing we can return... */
301
302 do {
303 /* If the buffer is empty, fill it. */
304 if (interface -> rbuf_offset == interface -> rbuf_len) {
305 length = read (interface -> rfdesc,
306 interface -> rbuf,
307 interface -> rbuf_max);
308 if (length <= 0)
309 return length;
310 interface -> rbuf_offset = 0;
311 interface -> rbuf_len = length;
312 }
313
314 /* If there isn't room for a whole bpf header, something went
315 wrong, but we'll ignore it and hope it goes away... XXX */
316 if (interface -> rbuf_len -
317 interface -> rbuf_offset < sizeof hdr) {
318 interface -> rbuf_offset = interface -> rbuf_len;
319 continue;
320 }
321
322 /* Copy out a bpf header... */
323 memcpy (&hdr, &interface -> rbuf [interface -> rbuf_offset],
324 sizeof hdr);
325
326 /* If the bpf header plus data doesn't fit in what's left
327 of the buffer, stick head in sand yet again... */
328 if (interface -> rbuf_offset +
329 hdr.bh_hdrlen + hdr.bh_caplen > interface -> rbuf_len) {
330 interface -> rbuf_offset = interface -> rbuf_len;
331 continue;
332 }
333
334 /* If the captured data wasn't the whole packet, or if
335 the packet won't fit in the input buffer, all we
336 can do is drop it. */
337 if (hdr.bh_caplen != hdr.bh_datalen) {
338 interface -> rbuf_offset +=
339 hdr.bh_hdrlen = hdr.bh_caplen;
340 continue;
341 }
342
343 /* Skip over the BPF header... */
344 interface -> rbuf_offset += hdr.bh_hdrlen;
345
346 /* Decode the physical header... */
347 offset = decode_hw_header (interface,
348 interface -> rbuf,
349 interface -> rbuf_offset,
350 hfrom);
351
352 /* If a physical layer checksum failed (dunno of any
353 physical layer that supports this, but WTH), skip this
354 packet. */
355 if (offset < 0) {
356 interface -> rbuf_offset += hdr.bh_caplen;
357 continue;
358 }
359 interface -> rbuf_offset += offset;
360 hdr.bh_caplen -= offset;
361
362 /* Decode the IP and UDP headers... */
363 offset = decode_udp_ip_header (interface,
364 interface -> rbuf,
365 interface -> rbuf_offset,
366 from,
367 (unsigned char *)0,
368 hdr.bh_caplen);
369
370 /* If the IP or UDP checksum was bad, skip the packet... */
371 if (offset < 0) {
372 interface -> rbuf_offset += hdr.bh_caplen;
373 continue;
374 }
375 interface -> rbuf_offset += offset;
376 hdr.bh_caplen -= offset;
377
378 /* If there's not enough room to stash the packet data,
379 we have to skip it (this shouldn't happen in real
380 life, though). */
381 if (hdr.bh_caplen > len) {
382 interface -> rbuf_offset += hdr.bh_caplen;
383 continue;
384 }
385
386 /* Copy out the data in the packet... */
387 memcpy (buf, interface -> rbuf + interface -> rbuf_offset,
388 hdr.bh_caplen);
389 interface -> rbuf_offset += hdr.bh_caplen;
390 return hdr.bh_caplen;
391 } while (!length);
392 return 0;
393 }
394
395 int can_unicast_without_arp (ip)
396 struct interface_info *ip;
397 {
398 return 1;
399 }
400
401 int can_receive_unicast_unconfigured (ip)
402 struct interface_info *ip;
403 {
404 return 1;
405 }
406
407 void maybe_setup_fallback ()
408 {
409 struct interface_info *fbi;
410 fbi = setup_fallback ();
411 if (fbi) {
412 if_register_fallback (fbi);
413 add_protocol ("fallback", fallback_interface -> wfdesc,
414 fallback_discard, fallback_interface);
415 }
416 }
417 #endif