]>
Commit | Line | Data |
---|---|---|
8cb33098 TL |
1 | /* bpf.c |
2 | ||
3 | BPF socket interface code, originally contributed by Archie Cobbs. */ | |
4 | ||
5 | /* | |
49733f31 TL |
6 | * Copyright (c) 1996-2000 Internet Software Consortium. |
7 | * All rights reserved. | |
8cb33098 | 8 | * |
49733f31 TL |
9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
8cb33098 | 12 | * |
49733f31 TL |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. Neither the name of The Internet Software Consortium nor the names | |
19 | * of its contributors may be used to endorse or promote products derived | |
20 | * from this software without specific prior written permission. | |
8cb33098 | 21 | * |
49733f31 TL |
22 | * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND |
23 | * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
24 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
25 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
26 | * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR | |
27 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
29 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
30 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
31 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
32 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
33 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
34 | * SUCH DAMAGE. | |
35 | * | |
0e944b06 TL |
36 | * This software was contributed to the Internet Software Consortium |
37 | * by Archie Cobbs, and is now maintained by Ted Lemon in cooperation | |
38 | * with Nominum, Inc. To learn more about the Internet Software | |
39 | * Consortium, see ``http://www.isc.org/''. To learn more about Vixie | |
40 | * Enterprises, see ``http://www.vix.com''. To learn more about | |
41 | * Nominum, Inc., see ``http://www.nominum.com''. | |
201601d5 TL |
42 | * |
43 | * Patches for FDDI support on Digital Unix were written by Bill | |
44 | * Stapleton, and maintained for a while by Mike Meredith before he | |
45 | * managed to get me to integrate them. | |
8cb33098 TL |
46 | */ |
47 | ||
48 | #ifndef lint | |
49 | static char copyright[] = | |
5cefe5e5 | 50 | "$Id: bpf.c,v 1.42 2000/09/01 23:03:31 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n"; |
8cb33098 TL |
51 | #endif /* not lint */ |
52 | ||
53 | #include "dhcpd.h" | |
d2bc90bd TL |
54 | #if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE) \ |
55 | || defined (USE_LPF_RECEIVE) | |
56 | # if defined (USE_LPF_RECEIVE) | |
57 | # include <asm/types.h> | |
58 | # include <linux/filter.h> | |
59 | # define bpf_insn sock_filter /* Linux: dare to be gratuitously different. */ | |
60 | # else | |
61 | # include <sys/ioctl.h> | |
62 | # include <sys/uio.h> | |
63 | # include <net/bpf.h> | |
64 | # if defined (NEED_OSF_PFILT_HACKS) | |
65 | # include <net/pfilt.h> | |
66 | # endif | |
67 | # endif | |
8cb33098 | 68 | |
8cb33098 | 69 | #include <netinet/in_systm.h> |
c41e81e4 TL |
70 | #include "includes/netinet/ip.h" |
71 | #include "includes/netinet/udp.h" | |
72 | #include "includes/netinet/if_ether.h" | |
d2bc90bd | 73 | #endif |
8cb33098 | 74 | |
c3585217 TL |
75 | /* Reinitializes the specified interface after an address change. This |
76 | is not required for packet-filter APIs. */ | |
77 | ||
78 | #ifdef USE_BPF_SEND | |
79 | void if_reinitialize_send (info) | |
80 | struct interface_info *info; | |
81 | { | |
82 | } | |
83 | #endif | |
84 | ||
85 | #ifdef USE_BPF_RECEIVE | |
86 | void if_reinitialize_receive (info) | |
87 | struct interface_info *info; | |
88 | { | |
89 | } | |
90 | #endif | |
91 | ||
8cb33098 TL |
92 | /* Called by get_interface_list for each interface that's discovered. |
93 | Opens a packet filter for each interface and adds it to the select | |
94 | mask. */ | |
95 | ||
d2bc90bd | 96 | #if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE) |
c3585217 | 97 | int if_register_bpf (info) |
045820ee | 98 | struct interface_info *info; |
8cb33098 | 99 | { |
045820ee | 100 | int sock; |
8cb33098 | 101 | char filename[50]; |
045820ee | 102 | int b; |
8cb33098 TL |
103 | |
104 | /* Open a BPF device */ | |
105 | for (b = 0; 1; b++) { | |
d64c8816 | 106 | #ifndef NO_SNPRINTF |
019f8a12 | 107 | snprintf(filename, sizeof(filename), BPF_FORMAT, b); |
d64c8816 | 108 | #else |
019f8a12 | 109 | sprintf(filename, BPF_FORMAT, b); |
d64c8816 | 110 | #endif |
045820ee TL |
111 | sock = open (filename, O_RDWR, 0); |
112 | if (sock < 0) { | |
8cb33098 TL |
113 | if (errno == EBUSY) { |
114 | continue; | |
115 | } else { | |
d2bc90bd | 116 | if (!b) |
8ae2d595 | 117 | log_fatal ("No bpf devices.%s%s%s", |
d2bc90bd TL |
118 | " Please read the README", |
119 | " section for your operating", | |
120 | " system."); | |
8ae2d595 | 121 | log_fatal ("Can't find free bpf: %m"); |
8cb33098 TL |
122 | } |
123 | } else { | |
124 | break; | |
125 | } | |
126 | } | |
127 | ||
128 | /* Set the BPF device to point at this interface. */ | |
c3585217 | 129 | if (ioctl (sock, BIOCSETIF, info -> ifp) < 0) |
8ae2d595 | 130 | log_fatal ("Can't attach interface %s to bpf device %s: %m", |
c255efc9 | 131 | info -> name, filename); |
045820ee TL |
132 | |
133 | return sock; | |
134 | } | |
135 | #endif /* USE_BPF_SEND || USE_BPF_RECEIVE */ | |
136 | ||
137 | #ifdef USE_BPF_SEND | |
c3585217 | 138 | void if_register_send (info) |
045820ee | 139 | struct interface_info *info; |
045820ee TL |
140 | { |
141 | /* If we're using the bpf API for sending and receiving, | |
142 | we don't need to register this interface twice. */ | |
143 | #ifndef USE_BPF_RECEIVE | |
144 | info -> wfdesc = if_register_bpf (info, interface); | |
145 | #else | |
146 | info -> wfdesc = info -> rfdesc; | |
147 | #endif | |
3648a2a1 | 148 | if (!quiet_interface_discovery) |
74f45f96 | 149 | log_info ("Sending on BPF/%s/%s%s%s", |
3648a2a1 | 150 | info -> name, |
31730f17 TL |
151 | print_hw_addr (info -> hw_address.hbuf [0], |
152 | info -> hw_address.hlen - 1, | |
153 | &info -> hw_address.hbuf [1]), | |
74f45f96 | 154 | (info -> shared_network ? "/" : ""), |
3648a2a1 | 155 | (info -> shared_network ? |
74f45f96 | 156 | info -> shared_network -> name : "")); |
8cb33098 | 157 | } |
7203e8ee TL |
158 | |
159 | void if_deregister_send (info) | |
160 | struct interface_info *info; | |
161 | { | |
162 | /* If we're using the bpf API for sending and receiving, | |
163 | we don't need to register this interface twice. */ | |
164 | #ifndef USE_BPF_RECEIVE | |
165 | close (info -> wfdesc); | |
166 | #endif | |
167 | info -> wfdesc = -1; | |
168 | ||
169 | if (!quiet_interface_discovery) | |
170 | log_info ("Disabling output on BPF/%s/%s%s%s", | |
171 | info -> name, | |
172 | print_hw_addr (info -> hw_address.hbuf [0], | |
173 | info -> hw_address.hlen - 1, | |
174 | &info -> hw_address.hbuf [1]), | |
175 | (info -> shared_network ? "/" : ""), | |
176 | (info -> shared_network ? | |
177 | info -> shared_network -> name : "")); | |
178 | } | |
045820ee TL |
179 | #endif /* USE_BPF_SEND */ |
180 | ||
d2bc90bd | 181 | #if defined (USE_BPF_RECEIVE) || defined (USE_LPF_RECEIVE) |
045820ee TL |
182 | /* Packet filter program... |
183 | XXX Changes to the filter program may require changes to the constant | |
184 | offsets used in if_register_send to patch the BPF program! XXX */ | |
185 | ||
d2bc90bd | 186 | struct bpf_insn dhcp_bpf_filter [] = { |
045820ee TL |
187 | /* Make sure this is an IP packet... */ |
188 | BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12), | |
f1c1b296 | 189 | BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8), |
045820ee TL |
190 | |
191 | /* Make sure it's a UDP packet... */ | |
192 | BPF_STMT (BPF_LD + BPF_B + BPF_ABS, 23), | |
f1c1b296 | 193 | BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6), |
045820ee TL |
194 | |
195 | /* Make sure this isn't a fragment... */ | |
196 | BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), | |
f1c1b296 | 197 | BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0), |
045820ee TL |
198 | |
199 | /* Get the IP header length... */ | |
200 | BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14), | |
201 | ||
202 | /* Make sure it's to the right port... */ | |
203 | BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16), | |
f1c1b296 | 204 | BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), /* patch */ |
8cb33098 | 205 | |
045820ee TL |
206 | /* If we passed all the tests, ask for the whole packet. */ |
207 | BPF_STMT(BPF_RET+BPF_K, (u_int)-1), | |
208 | ||
209 | /* Otherwise, drop it. */ | |
210 | BPF_STMT(BPF_RET+BPF_K, 0), | |
211 | }; | |
212 | ||
95e58554 TL |
213 | struct bpf_insn *bpf_fddi_filter; |
214 | ||
d2bc90bd | 215 | int dhcp_bpf_filter_len = sizeof dhcp_bpf_filter / sizeof (struct bpf_insn); |
7d29d66d TL |
216 | struct bpf_insn dhcp_bpf_tr_filter [] = { |
217 | /* accept all token ring packets due to variable length header */ | |
218 | /* if we want to get clever, insert the program here */ | |
219 | ||
220 | /* If we passed all the tests, ask for the whole packet. */ | |
221 | BPF_STMT(BPF_RET+BPF_K, (u_int)-1), | |
222 | ||
223 | /* Otherwise, drop it. */ | |
224 | BPF_STMT(BPF_RET+BPF_K, 0), | |
225 | }; | |
226 | ||
227 | int dhcp_bpf_tr_filter_len = (sizeof dhcp_bpf_tr_filter / | |
228 | sizeof (struct bpf_insn)); | |
d2bc90bd TL |
229 | #endif |
230 | ||
231 | #if defined (USE_BPF_RECEIVE) | |
c3585217 | 232 | void if_register_receive (info) |
045820ee | 233 | struct interface_info *info; |
045820ee TL |
234 | { |
235 | int flag = 1; | |
236 | struct bpf_version v; | |
237 | u_int32_t addr; | |
238 | struct bpf_program p; | |
019f8a12 | 239 | u_int32_t bits; |
95e58554 TL |
240 | #ifdef DEC_FDDI |
241 | int link_layer; | |
242 | #endif /* DEC_FDDI */ | |
045820ee TL |
243 | |
244 | /* Open a BPF device and hang it on this interface... */ | |
c3585217 | 245 | info -> rfdesc = if_register_bpf (info); |
045820ee TL |
246 | |
247 | /* Make sure the BPF version is in range... */ | |
248 | if (ioctl (info -> rfdesc, BIOCVERSION, &v) < 0) | |
8ae2d595 | 249 | log_fatal ("Can't get BPF version: %m"); |
045820ee TL |
250 | |
251 | if (v.bv_major != BPF_MAJOR_VERSION || | |
252 | v.bv_minor < BPF_MINOR_VERSION) | |
8ae2d595 | 253 | log_fatal ("Kernel BPF version out of range - recompile dhcpd!"); |
045820ee TL |
254 | |
255 | /* Set immediate mode so that reads return as soon as a packet | |
256 | comes in, rather than waiting for the input buffer to fill with | |
257 | packets. */ | |
258 | if (ioctl (info -> rfdesc, BIOCIMMEDIATE, &flag) < 0) | |
8ae2d595 | 259 | log_fatal ("Can't set immediate mode on bpf device: %m"); |
045820ee | 260 | |
019f8a12 TL |
261 | #ifdef NEED_OSF_PFILT_HACKS |
262 | /* Allow the copyall flag to be set... */ | |
263 | if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0) | |
8ae2d595 | 264 | log_fatal ("Can't set ALLOWCOPYALL: %m"); |
019f8a12 TL |
265 | |
266 | /* Clear all the packet filter mode bits first... */ | |
267 | bits = 0; | |
268 | if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) | |
8ae2d595 | 269 | log_fatal ("Can't clear pfilt bits: %m"); |
019f8a12 TL |
270 | |
271 | /* Set the ENBATCH, ENCOPYALL, ENBPFHDR bits... */ | |
272 | bits = ENBATCH | ENCOPYALL | ENBPFHDR; | |
273 | if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) | |
8ae2d595 | 274 | log_fatal ("Can't set ENBATCH|ENCOPYALL|ENBPFHDR: %m"); |
019f8a12 | 275 | #endif |
045820ee TL |
276 | /* Get the required BPF buffer length from the kernel. */ |
277 | if (ioctl (info -> rfdesc, BIOCGBLEN, &info -> rbuf_max) < 0) | |
8ae2d595 | 278 | log_fatal ("Can't get bpf buffer length: %m"); |
4bd8800e | 279 | info -> rbuf = dmalloc (info -> rbuf_max, MDL); |
045820ee | 280 | if (!info -> rbuf) |
ab58ff49 TL |
281 | log_fatal ("Can't allocate %d bytes for bpf input buffer.", |
282 | info -> rbuf_max); | |
045820ee TL |
283 | info -> rbuf_offset = 0; |
284 | info -> rbuf_len = 0; | |
285 | ||
045820ee | 286 | /* Set up the bpf filter program structure. */ |
d2bc90bd | 287 | p.bf_len = dhcp_bpf_filter_len; |
95e58554 TL |
288 | |
289 | #ifdef DEC_FDDI | |
290 | /* See if this is an FDDI interface, flag it for later. */ | |
291 | if (ioctl(info -> rfdesc, BIOCGDLT, &link_layer) >= 0 && | |
292 | link_layer == DLT_FDDI) { | |
201601d5 TL |
293 | if (!bpf_fddi_filter) { |
294 | bpf_fddi_filter = dmalloc (sizeof bpf_fddi_filter, | |
95e58554 | 295 | MDL); |
201601d5 | 296 | if (!bpf_fddi_filter) |
95e58554 | 297 | log_fatal ("No memory for FDDI filter."); |
201601d5 | 298 | memcpy (bpf_fddi_filter, |
95e58554 TL |
299 | dhcp_bpf_filter, sizeof dhcp_bpf_filter); |
300 | /* Patch the BPF program to account for the difference | |
301 | in length between ethernet headers (14), FDDI and | |
302 | 802.2 headers (16 +8=24, +10). | |
303 | XXX changes to filter program may require changes to | |
304 | XXX the insn number(s) used below! */ | |
201601d5 TL |
305 | bpf_fddi_filter[0].k += 10; |
306 | bpf_fddi_filter[2].k += 10; | |
307 | bpf_fddi_filter[4].k += 10; | |
308 | bpf_fddi_filter[6].k += 10; | |
309 | bpf_fddi_filter[7].k += 10; | |
95e58554 | 310 | } |
201601d5 | 311 | p.bf_insns = bpf_fddi_filter; |
95e58554 TL |
312 | } else |
313 | #endif /* DEC_FDDI */ | |
d2bc90bd | 314 | p.bf_insns = dhcp_bpf_filter; |
045820ee | 315 | |
229b6208 TL |
316 | /* Patch the server port into the BPF program... |
317 | XXX changes to filter program may require changes | |
318 | to the insn number(s) used below! XXX */ | |
d2bc90bd | 319 | dhcp_bpf_filter [8].k = ntohs (local_port); |
229b6208 | 320 | |
045820ee | 321 | if (ioctl (info -> rfdesc, BIOCSETF, &p) < 0) |
8ae2d595 | 322 | log_fatal ("Can't install packet filter program: %m"); |
3648a2a1 | 323 | if (!quiet_interface_discovery) |
74f45f96 | 324 | log_info ("Listening on BPF/%s/%s%s%s", |
3648a2a1 | 325 | info -> name, |
31730f17 | 326 | print_hw_addr (info -> hw_address.hbuf [0], |
7203e8ee TL |
327 | info -> hw_address.hlen - 1, |
328 | &info -> hw_address.hbuf [1]), | |
329 | (info -> shared_network ? "/" : ""), | |
330 | (info -> shared_network ? | |
331 | info -> shared_network -> name : "")); | |
332 | } | |
333 | ||
334 | void if_deregister_receive (info) | |
335 | struct interface_info *info; | |
336 | { | |
337 | close (info -> rfdesc); | |
338 | info -> rfdesc = -1; | |
339 | ||
340 | if (!quiet_interface_discovery) | |
341 | log_info ("Disabling input on BPF/%s/%s%s%s", | |
342 | info -> name, | |
343 | print_hw_addr (info -> hw_address.hbuf [0], | |
31730f17 TL |
344 | info -> hw_address.hlen - 1, |
345 | &info -> hw_address.hbuf [1]), | |
74f45f96 | 346 | (info -> shared_network ? "/" : ""), |
3648a2a1 | 347 | (info -> shared_network ? |
74f45f96 | 348 | info -> shared_network -> name : "")); |
045820ee TL |
349 | } |
350 | #endif /* USE_BPF_RECEIVE */ | |
351 | ||
352 | #ifdef USE_BPF_SEND | |
4595a58c | 353 | ssize_t send_packet (interface, packet, raw, len, from, to, hto) |
045820ee TL |
354 | struct interface_info *interface; |
355 | struct packet *packet; | |
356 | struct dhcp_packet *raw; | |
357 | size_t len; | |
f1c1b296 | 358 | struct in_addr from; |
045820ee TL |
359 | struct sockaddr_in *to; |
360 | struct hardware *hto; | |
361 | { | |
6ceb9118 TL |
362 | unsigned hbufp = 0, ibufp = 0; |
363 | double hw [4]; | |
364 | double ip [32]; | |
365 | struct iovec iov [3]; | |
74f45f96 | 366 | int result; |
6ceb9118 | 367 | int fudge; |
045820ee | 368 | |
d2bc90bd TL |
369 | if (!strcmp (interface -> name, "fallback")) |
370 | return send_fallback (interface, packet, raw, | |
371 | len, from, to, hto); | |
372 | ||
045820ee | 373 | /* Assemble the headers... */ |
6ceb9118 TL |
374 | assemble_hw_header (interface, (unsigned char *)hw, &hbufp, hto); |
375 | assemble_udp_ip_header (interface, | |
376 | (unsigned char *)ip, &ibufp, from.s_addr, | |
045820ee TL |
377 | to -> sin_addr.s_addr, to -> sin_port, |
378 | (unsigned char *)raw, len); | |
379 | ||
380 | /* Fire it off */ | |
6ceb9118 TL |
381 | iov [0].iov_base = ((char *)hw); |
382 | iov [0].iov_len = hbufp; | |
383 | iov [1].iov_base = ((char *)ip); | |
384 | iov [1].iov_len = ibufp; | |
385 | iov [2].iov_base = (char *)raw; | |
386 | iov [2].iov_len = len; | |
387 | ||
388 | result = writev(interface -> wfdesc, iov, 3); | |
74f45f96 | 389 | if (result < 0) |
c5b0f529 | 390 | log_error ("send_packet: %m"); |
74f45f96 | 391 | return result; |
045820ee TL |
392 | } |
393 | #endif /* USE_BPF_SEND */ | |
394 | ||
395 | #ifdef USE_BPF_RECEIVE | |
4595a58c | 396 | ssize_t receive_packet (interface, buf, len, from, hfrom) |
045820ee TL |
397 | struct interface_info *interface; |
398 | unsigned char *buf; | |
399 | size_t len; | |
400 | struct sockaddr_in *from; | |
401 | struct hardware *hfrom; | |
402 | { | |
403 | int length = 0; | |
404 | int offset = 0; | |
405 | struct bpf_hdr hdr; | |
406 | ||
407 | /* All this complexity is because BPF doesn't guarantee | |
408 | that only one packet will be returned at a time. We're | |
409 | getting what we deserve, though - this is a terrible abuse | |
410 | of the BPF interface. Sigh. */ | |
411 | ||
412 | /* Process packets until we get one we can return or until we've | |
413 | done a read and gotten nothing we can return... */ | |
414 | ||
415 | do { | |
416 | /* If the buffer is empty, fill it. */ | |
417 | if (interface -> rbuf_offset == interface -> rbuf_len) { | |
418 | length = read (interface -> rfdesc, | |
419 | interface -> rbuf, | |
420 | interface -> rbuf_max); | |
421 | if (length <= 0) | |
422 | return length; | |
423 | interface -> rbuf_offset = 0; | |
424 | interface -> rbuf_len = length; | |
425 | } | |
426 | ||
427 | /* If there isn't room for a whole bpf header, something went | |
428 | wrong, but we'll ignore it and hope it goes away... XXX */ | |
429 | if (interface -> rbuf_len - | |
430 | interface -> rbuf_offset < sizeof hdr) { | |
431 | interface -> rbuf_offset = interface -> rbuf_len; | |
432 | continue; | |
433 | } | |
434 | ||
435 | /* Copy out a bpf header... */ | |
436 | memcpy (&hdr, &interface -> rbuf [interface -> rbuf_offset], | |
437 | sizeof hdr); | |
438 | ||
439 | /* If the bpf header plus data doesn't fit in what's left | |
440 | of the buffer, stick head in sand yet again... */ | |
441 | if (interface -> rbuf_offset + | |
442 | hdr.bh_hdrlen + hdr.bh_caplen > interface -> rbuf_len) { | |
443 | interface -> rbuf_offset = interface -> rbuf_len; | |
444 | continue; | |
445 | } | |
446 | ||
447 | /* If the captured data wasn't the whole packet, or if | |
448 | the packet won't fit in the input buffer, all we | |
449 | can do is drop it. */ | |
450 | if (hdr.bh_caplen != hdr.bh_datalen) { | |
451 | interface -> rbuf_offset += | |
452 | hdr.bh_hdrlen = hdr.bh_caplen; | |
453 | continue; | |
454 | } | |
455 | ||
456 | /* Skip over the BPF header... */ | |
457 | interface -> rbuf_offset += hdr.bh_hdrlen; | |
458 | ||
459 | /* Decode the physical header... */ | |
460 | offset = decode_hw_header (interface, | |
461 | interface -> rbuf, | |
462 | interface -> rbuf_offset, | |
463 | hfrom); | |
464 | ||
465 | /* If a physical layer checksum failed (dunno of any | |
466 | physical layer that supports this, but WTH), skip this | |
467 | packet. */ | |
468 | if (offset < 0) { | |
469 | interface -> rbuf_offset += hdr.bh_caplen; | |
470 | continue; | |
471 | } | |
472 | interface -> rbuf_offset += offset; | |
473 | hdr.bh_caplen -= offset; | |
474 | ||
475 | /* Decode the IP and UDP headers... */ | |
476 | offset = decode_udp_ip_header (interface, | |
477 | interface -> rbuf, | |
478 | interface -> rbuf_offset, | |
479 | from, | |
480 | (unsigned char *)0, | |
481 | hdr.bh_caplen); | |
482 | ||
483 | /* If the IP or UDP checksum was bad, skip the packet... */ | |
484 | if (offset < 0) { | |
485 | interface -> rbuf_offset += hdr.bh_caplen; | |
486 | continue; | |
487 | } | |
488 | interface -> rbuf_offset += offset; | |
489 | hdr.bh_caplen -= offset; | |
490 | ||
491 | /* If there's not enough room to stash the packet data, | |
492 | we have to skip it (this shouldn't happen in real | |
493 | life, though). */ | |
494 | if (hdr.bh_caplen > len) { | |
495 | interface -> rbuf_offset += hdr.bh_caplen; | |
496 | continue; | |
497 | } | |
498 | ||
499 | /* Copy out the data in the packet... */ | |
500 | memcpy (buf, interface -> rbuf + interface -> rbuf_offset, | |
501 | hdr.bh_caplen); | |
502 | interface -> rbuf_offset += hdr.bh_caplen; | |
503 | return hdr.bh_caplen; | |
504 | } while (!length); | |
505 | return 0; | |
506 | } | |
d2bc90bd | 507 | |
21d21e91 TL |
508 | int can_unicast_without_arp (ip) |
509 | struct interface_info *ip; | |
d2bc90bd TL |
510 | { |
511 | return 1; | |
512 | } | |
513 | ||
21d21e91 TL |
514 | int can_receive_unicast_unconfigured (ip) |
515 | struct interface_info *ip; | |
b547818b TL |
516 | { |
517 | return 1; | |
518 | } | |
519 | ||
5cefe5e5 TL |
520 | int supports_multiple_interfaces (ip) |
521 | struct interface_info *ip; | |
522 | { | |
523 | return 1; | |
524 | } | |
525 | ||
d2bc90bd TL |
526 | void maybe_setup_fallback () |
527 | { | |
acc21512 | 528 | isc_result_t status; |
20916cae TL |
529 | struct interface_info *fbi = (struct interface_info *)0; |
530 | if (setup_fallback (&fbi, MDL)) { | |
d2bc90bd | 531 | if_register_fallback (fbi); |
e92653f1 | 532 | status = omapi_register_io_object ((omapi_object_t *)fbi, |
acc21512 TL |
533 | if_readsocket, 0, |
534 | fallback_discard, 0, 0); | |
535 | if (status != ISC_R_SUCCESS) | |
536 | log_fatal ("Can't register I/O handle for %s: %s", | |
537 | fbi -> name, isc_result_totext (status)); | |
68e1f67a | 538 | interface_dereference (&fbi, MDL); |
d2bc90bd TL |
539 | } |
540 | } | |
045820ee | 541 | #endif |