]>
Commit | Line | Data |
---|---|---|
31c08e37 TL |
1 | /* lpf.c |
2 | ||
3 | Linux packet filter code, contributed by Brian Murrel at Interlinx | |
4 | Support Services in Vancouver, B.C. */ | |
5 | ||
6 | /* | |
49a7fb58 | 7 | * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC") |
98311e4b | 8 | * Copyright (c) 1996-2003 by Internet Software Consortium |
31c08e37 | 9 | * |
7512d88b TM |
10 | * This Source Code Form is subject to the terms of the Mozilla Public |
11 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |
12 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
31c08e37 | 13 | * |
98311e4b DH |
14 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES |
15 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
16 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR | |
17 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
18 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
19 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | |
20 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
31c08e37 | 21 | * |
98311e4b | 22 | * Internet Systems Consortium, Inc. |
429a56d7 TM |
23 | * PO Box 360 |
24 | * Newmarket, NH 03857 USA | |
98311e4b | 25 | * <info@isc.org> |
2c85ac9b | 26 | * https://www.isc.org/ |
31c08e37 TL |
27 | */ |
28 | ||
31c08e37 TL |
29 | #include "dhcpd.h" |
30 | #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE) | |
31c08e37 | 31 | #include <sys/uio.h> |
fe5b0fdd | 32 | #include <errno.h> |
31c08e37 | 33 | |
2dddca22 TL |
34 | #include <asm/types.h> |
35 | #include <linux/filter.h> | |
36 | #include <linux/if_ether.h> | |
7ff6ae5a | 37 | #include <linux/if_packet.h> |
31c08e37 TL |
38 | #include <netinet/in_systm.h> |
39 | #include "includes/netinet/ip.h" | |
40 | #include "includes/netinet/udp.h" | |
41 | #include "includes/netinet/if_ether.h" | |
32e651c4 SR |
42 | #endif |
43 | ||
44 | #if defined (USE_LPF_RECEIVE) || defined (USE_LPF_HWADDR) | |
45 | #include <sys/ioctl.h> | |
7ff6ae5a | 46 | #include <sys/socket.h> |
98bd7ca0 | 47 | #include <net/if.h> |
32e651c4 | 48 | #endif |
31c08e37 | 49 | |
32e651c4 | 50 | #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE) |
31c08e37 TL |
51 | /* Reinitializes the specified interface after an address change. This |
52 | is not required for packet-filter APIs. */ | |
53 | ||
54 | #ifdef USE_LPF_SEND | |
55 | void if_reinitialize_send (info) | |
56 | struct interface_info *info; | |
57 | { | |
58 | } | |
59 | #endif | |
60 | ||
61 | #ifdef USE_LPF_RECEIVE | |
62 | void if_reinitialize_receive (info) | |
63 | struct interface_info *info; | |
64 | { | |
65 | } | |
66 | #endif | |
67 | ||
68 | /* Called by get_interface_list for each interface that's discovered. | |
69 | Opens a packet filter for each interface and adds it to the select | |
70 | mask. */ | |
71 | ||
72 | int if_register_lpf (info) | |
73 | struct interface_info *info; | |
74 | { | |
75 | int sock; | |
7ff6ae5a TM |
76 | union { |
77 | struct sockaddr_ll ll; | |
78 | struct sockaddr common; | |
79 | } sa; | |
80 | struct ifreq ifr; | |
31c08e37 TL |
81 | |
82 | /* Make an LPF socket. */ | |
7ff6ae5a | 83 | if ((sock = socket(PF_PACKET, SOCK_RAW, |
6ceb9118 | 84 | htons((short)ETH_P_ALL))) < 0) { |
2dddca22 TL |
85 | if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || |
86 | errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || | |
6ceb9118 TL |
87 | errno == EAFNOSUPPORT || errno == EINVAL) { |
88 | log_error ("socket: %m - make sure"); | |
89 | log_error ("CONFIG_PACKET (Packet socket) %s", | |
90 | "and CONFIG_FILTER"); | |
91 | log_error ("(Socket Filtering) are enabled %s", | |
92 | "in your kernel"); | |
93 | log_fatal ("configuration!"); | |
94 | } | |
0536c3ef | 95 | log_fatal ("Open a socket for LPF: %m"); |
2dddca22 | 96 | } |
31c08e37 | 97 | |
7ff6ae5a TM |
98 | memset (&ifr, 0, sizeof ifr); |
99 | strncpy (ifr.ifr_name, (const char *)info -> ifp, sizeof ifr.ifr_name); | |
100 | ifr.ifr_name[IFNAMSIZ-1] = '\0'; | |
101 | if (ioctl (sock, SIOCGIFINDEX, &ifr)) | |
102 | log_fatal ("Failed to get interface index: %m"); | |
103 | ||
31c08e37 TL |
104 | /* Bind to the interface name */ |
105 | memset (&sa, 0, sizeof sa); | |
7ff6ae5a TM |
106 | sa.ll.sll_family = AF_PACKET; |
107 | sa.ll.sll_ifindex = ifr.ifr_ifindex; | |
108 | if (bind (sock, &sa.common, sizeof sa)) { | |
2dddca22 TL |
109 | if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || |
110 | errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || | |
6ceb9118 TL |
111 | errno == EAFNOSUPPORT || errno == EINVAL) { |
112 | log_error ("socket: %m - make sure"); | |
113 | log_error ("CONFIG_PACKET (Packet socket) %s", | |
114 | "and CONFIG_FILTER"); | |
115 | log_error ("(Socket Filtering) are enabled %s", | |
116 | "in your kernel"); | |
117 | log_fatal ("configuration!"); | |
118 | } | |
0536c3ef | 119 | log_fatal ("Bind socket to interface: %m"); |
36e2c224 | 120 | |
2dddca22 | 121 | } |
31c08e37 | 122 | |
4ba58919 DH |
123 | get_hw_addr(info->name, &info->hw_address); |
124 | ||
31c08e37 TL |
125 | return sock; |
126 | } | |
127 | #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */ | |
128 | ||
129 | #ifdef USE_LPF_SEND | |
130 | void if_register_send (info) | |
131 | struct interface_info *info; | |
132 | { | |
133 | /* If we're using the lpf API for sending and receiving, | |
134 | we don't need to register this interface twice. */ | |
135 | #ifndef USE_LPF_RECEIVE | |
bdcaf7b9 | 136 | info -> wfdesc = if_register_lpf (info); |
31c08e37 TL |
137 | #else |
138 | info -> wfdesc = info -> rfdesc; | |
139 | #endif | |
140 | if (!quiet_interface_discovery) | |
74f45f96 | 141 | log_info ("Sending on LPF/%s/%s%s%s", |
31c08e37 | 142 | info -> name, |
d4feef65 TL |
143 | print_hw_addr (info -> hw_address.hbuf [0], |
144 | info -> hw_address.hlen - 1, | |
145 | &info -> hw_address.hbuf [1]), | |
74f45f96 | 146 | (info -> shared_network ? "/" : ""), |
31c08e37 | 147 | (info -> shared_network ? |
74f45f96 | 148 | info -> shared_network -> name : "")); |
31c08e37 | 149 | } |
bdcaf7b9 TL |
150 | |
151 | void if_deregister_send (info) | |
152 | struct interface_info *info; | |
153 | { | |
154 | /* don't need to close twice if we are using lpf for sending and | |
155 | receiving */ | |
156 | #ifndef USE_LPF_RECEIVE | |
157 | /* for LPF this is simple, packet filters are removed when sockets | |
158 | are closed */ | |
159 | close (info -> wfdesc); | |
160 | #endif | |
7203e8ee | 161 | info -> wfdesc = -1; |
bdcaf7b9 | 162 | if (!quiet_interface_discovery) |
7203e8ee | 163 | log_info ("Disabling output on LPF/%s/%s%s%s", |
bdcaf7b9 TL |
164 | info -> name, |
165 | print_hw_addr (info -> hw_address.hbuf [0], | |
166 | info -> hw_address.hlen - 1, | |
167 | &info -> hw_address.hbuf [1]), | |
168 | (info -> shared_network ? "/" : ""), | |
169 | (info -> shared_network ? | |
170 | info -> shared_network -> name : "")); | |
171 | } | |
31c08e37 TL |
172 | #endif /* USE_LPF_SEND */ |
173 | ||
174 | #ifdef USE_LPF_RECEIVE | |
175 | /* Defined in bpf.c. We can't extern these in dhcpd.h without pulling | |
176 | in bpf includes... */ | |
2dddca22 | 177 | extern struct sock_filter dhcp_bpf_filter []; |
31c08e37 | 178 | extern int dhcp_bpf_filter_len; |
e31656de | 179 | |
563f0b8a FD |
180 | #if defined(RELAY_PORT) |
181 | extern struct sock_filter dhcp_bpf_relay_filter []; | |
182 | extern int dhcp_bpf_relay_filter_len; | |
183 | #endif | |
184 | ||
e31656de | 185 | #if defined (HAVE_TR_SUPPORT) |
7d29d66d TL |
186 | extern struct sock_filter dhcp_bpf_tr_filter []; |
187 | extern int dhcp_bpf_tr_filter_len; | |
e31656de TL |
188 | static void lpf_tr_filter_setup (struct interface_info *); |
189 | #endif | |
31c08e37 | 190 | |
c4906ac0 | 191 | static void lpf_gen_filter_setup (struct interface_info *); |
c4906ac0 | 192 | |
31c08e37 TL |
193 | void if_register_receive (info) |
194 | struct interface_info *info; | |
195 | { | |
196 | /* Open a LPF device and hang it on this interface... */ | |
197 | info -> rfdesc = if_register_lpf (info); | |
198 | ||
7ff6ae5a TM |
199 | #ifdef PACKET_AUXDATA |
200 | { | |
201 | int val = 1; | |
202 | ||
203 | if (setsockopt(info->rfdesc, SOL_PACKET, PACKET_AUXDATA, | |
204 | &val, sizeof(val)) < 0) { | |
205 | if (errno != ENOPROTOOPT) { | |
206 | log_fatal ("Failed to set auxiliary packet data: %m"); | |
207 | } | |
208 | } | |
209 | } | |
210 | #endif | |
211 | ||
212 | ||
e31656de | 213 | #if defined (HAVE_TR_SUPPORT) |
254f9d79 | 214 | if (info -> hw_address.hbuf [0] == HTYPE_IEEE802) |
7d29d66d TL |
215 | lpf_tr_filter_setup (info); |
216 | else | |
e31656de | 217 | #endif |
7d29d66d TL |
218 | lpf_gen_filter_setup (info); |
219 | ||
220 | if (!quiet_interface_discovery) | |
b733ed10 TL |
221 | log_info ("Listening on LPF/%s/%s%s%s", |
222 | info -> name, | |
d4feef65 TL |
223 | print_hw_addr (info -> hw_address.hbuf [0], |
224 | info -> hw_address.hlen - 1, | |
225 | &info -> hw_address.hbuf [1]), | |
b733ed10 TL |
226 | (info -> shared_network ? "/" : ""), |
227 | (info -> shared_network ? | |
228 | info -> shared_network -> name : "")); | |
7d29d66d TL |
229 | } |
230 | ||
bdcaf7b9 TL |
231 | void if_deregister_receive (info) |
232 | struct interface_info *info; | |
233 | { | |
234 | /* for LPF this is simple, packet filters are removed when sockets | |
235 | are closed */ | |
236 | close (info -> rfdesc); | |
7203e8ee | 237 | info -> rfdesc = -1; |
bdcaf7b9 | 238 | if (!quiet_interface_discovery) |
7203e8ee | 239 | log_info ("Disabling input on LPF/%s/%s%s%s", |
bdcaf7b9 TL |
240 | info -> name, |
241 | print_hw_addr (info -> hw_address.hbuf [0], | |
242 | info -> hw_address.hlen - 1, | |
243 | &info -> hw_address.hbuf [1]), | |
244 | (info -> shared_network ? "/" : ""), | |
245 | (info -> shared_network ? | |
246 | info -> shared_network -> name : "")); | |
247 | } | |
248 | ||
7d29d66d TL |
249 | static void lpf_gen_filter_setup (info) |
250 | struct interface_info *info; | |
251 | { | |
252 | struct sock_fprog p; | |
253 | ||
4619c0a2 DH |
254 | memset(&p, 0, sizeof(p)); |
255 | ||
31c08e37 TL |
256 | /* Set up the bpf filter program structure. This is defined in |
257 | bpf.c */ | |
2dddca22 TL |
258 | p.len = dhcp_bpf_filter_len; |
259 | p.filter = dhcp_bpf_filter; | |
31c08e37 TL |
260 | |
261 | /* Patch the server port into the LPF program... | |
262 | XXX changes to filter program may require changes | |
263 | to the insn number(s) used below! XXX */ | |
563f0b8a FD |
264 | #if defined(RELAY_PORT) |
265 | if (relay_port) { | |
266 | /* | |
267 | * If user defined relay UDP port, we need to filter | |
268 | * also on the user UDP port. | |
269 | */ | |
270 | p.len = dhcp_bpf_relay_filter_len; | |
271 | p.filter = dhcp_bpf_relay_filter; | |
272 | ||
273 | dhcp_bpf_relay_filter [10].k = ntohs (relay_port); | |
274 | } | |
275 | #endif | |
276 | dhcp_bpf_filter [8].k = ntohs (local_port); | |
31c08e37 TL |
277 | |
278 | if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p, | |
2dddca22 TL |
279 | sizeof p) < 0) { |
280 | if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || | |
281 | errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || | |
6ceb9118 TL |
282 | errno == EAFNOSUPPORT) { |
283 | log_error ("socket: %m - make sure"); | |
284 | log_error ("CONFIG_PACKET (Packet socket) %s", | |
285 | "and CONFIG_FILTER"); | |
286 | log_error ("(Socket Filtering) are enabled %s", | |
287 | "in your kernel"); | |
288 | log_fatal ("configuration!"); | |
289 | } | |
fd6f298f | 290 | log_fatal ("Can't install packet filter program: %m"); |
7d29d66d TL |
291 | } |
292 | } | |
293 | ||
e31656de | 294 | #if defined (HAVE_TR_SUPPORT) |
7d29d66d TL |
295 | static void lpf_tr_filter_setup (info) |
296 | struct interface_info *info; | |
297 | { | |
298 | struct sock_fprog p; | |
299 | ||
819186b7 DH |
300 | memset(&p, 0, sizeof(p)); |
301 | ||
7d29d66d TL |
302 | /* Set up the bpf filter program structure. This is defined in |
303 | bpf.c */ | |
304 | p.len = dhcp_bpf_tr_filter_len; | |
305 | p.filter = dhcp_bpf_tr_filter; | |
306 | ||
307 | /* Patch the server port into the LPF program... | |
308 | XXX changes to filter program may require changes | |
309 | XXX to the insn number(s) used below! | |
f6b8f48d | 310 | XXX Token ring filter is null - when/if we have a filter |
7d29d66d TL |
311 | XXX that's not, we'll need this code. |
312 | XXX dhcp_bpf_filter [?].k = ntohs (local_port); */ | |
313 | ||
314 | if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p, | |
315 | sizeof p) < 0) { | |
316 | if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || | |
317 | errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || | |
6ceb9118 TL |
318 | errno == EAFNOSUPPORT) { |
319 | log_error ("socket: %m - make sure"); | |
320 | log_error ("CONFIG_PACKET (Packet socket) %s", | |
321 | "and CONFIG_FILTER"); | |
322 | log_error ("(Socket Filtering) are enabled %s", | |
323 | "in your kernel"); | |
324 | log_fatal ("configuration!"); | |
325 | } | |
fd6f298f | 326 | log_fatal ("Can't install packet filter program: %m"); |
2dddca22 | 327 | } |
31c08e37 | 328 | } |
e31656de | 329 | #endif /* HAVE_TR_SUPPORT */ |
31c08e37 TL |
330 | #endif /* USE_LPF_RECEIVE */ |
331 | ||
332 | #ifdef USE_LPF_SEND | |
333 | ssize_t send_packet (interface, packet, raw, len, from, to, hto) | |
334 | struct interface_info *interface; | |
335 | struct packet *packet; | |
336 | struct dhcp_packet *raw; | |
337 | size_t len; | |
338 | struct in_addr from; | |
339 | struct sockaddr_in *to; | |
340 | struct hardware *hto; | |
341 | { | |
6ceb9118 TL |
342 | unsigned hbufp = 0, ibufp = 0; |
343 | double hh [16]; | |
344 | double ih [1536 / sizeof (double)]; | |
345 | unsigned char *buf = (unsigned char *)ih; | |
74f45f96 | 346 | int result; |
6ceb9118 | 347 | int fudge; |
31c08e37 TL |
348 | |
349 | if (!strcmp (interface -> name, "fallback")) | |
350 | return send_fallback (interface, packet, raw, | |
351 | len, from, to, hto); | |
352 | ||
0829d595 DH |
353 | if (hto == NULL && interface->anycast_mac_addr.hlen) |
354 | hto = &interface->anycast_mac_addr; | |
355 | ||
31c08e37 | 356 | /* Assemble the headers... */ |
6ceb9118 TL |
357 | assemble_hw_header (interface, (unsigned char *)hh, &hbufp, hto); |
358 | fudge = hbufp % 4; /* IP header must be word-aligned. */ | |
359 | memcpy (buf + fudge, (unsigned char *)hh, hbufp); | |
360 | ibufp = hbufp + fudge; | |
361 | assemble_udp_ip_header (interface, buf, &ibufp, from.s_addr, | |
31c08e37 TL |
362 | to -> sin_addr.s_addr, to -> sin_port, |
363 | (unsigned char *)raw, len); | |
6ceb9118 | 364 | memcpy (buf + ibufp, raw, len); |
7ff6ae5a | 365 | result = write(interface->wfdesc, buf + fudge, ibufp + len - fudge); |
74f45f96 | 366 | if (result < 0) |
c5b0f529 | 367 | log_error ("send_packet: %m"); |
74f45f96 | 368 | return result; |
31c08e37 TL |
369 | } |
370 | #endif /* USE_LPF_SEND */ | |
371 | ||
372 | #ifdef USE_LPF_RECEIVE | |
373 | ssize_t receive_packet (interface, buf, len, from, hfrom) | |
374 | struct interface_info *interface; | |
375 | unsigned char *buf; | |
376 | size_t len; | |
377 | struct sockaddr_in *from; | |
378 | struct hardware *hfrom; | |
379 | { | |
31c08e37 TL |
380 | int length = 0; |
381 | int offset = 0; | |
7ff6ae5a | 382 | int csum_ready = 1; |
05dcd093 | 383 | unsigned char ibuf [1536]; |
6ceb9118 | 384 | unsigned bufix = 0; |
83c0372e | 385 | unsigned paylen; |
7ff6ae5a TM |
386 | struct iovec iov = { |
387 | .iov_base = ibuf, | |
388 | .iov_len = sizeof ibuf, | |
389 | }; | |
1c0b7d66 SR |
390 | #ifdef PACKET_AUXDATA |
391 | /* | |
392 | * We only need cmsgbuf if we are getting the aux data and we | |
393 | * only get the auxdata if it is actually defined | |
394 | */ | |
395 | unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))]; | |
7ff6ae5a TM |
396 | struct msghdr msg = { |
397 | .msg_iov = &iov, | |
398 | .msg_iovlen = 1, | |
399 | .msg_control = cmsgbuf, | |
400 | .msg_controllen = sizeof(cmsgbuf), | |
401 | }; | |
1c0b7d66 SR |
402 | #else |
403 | struct msghdr msg = { | |
404 | .msg_iov = &iov, | |
405 | .msg_iovlen = 1, | |
406 | .msg_control = NULL, | |
407 | .msg_controllen = 0, | |
408 | }; | |
409 | #endif /* PACKET_AUXDATA */ | |
7ff6ae5a TM |
410 | |
411 | length = recvmsg (interface->rfdesc, &msg, 0); | |
31c08e37 TL |
412 | if (length <= 0) |
413 | return length; | |
414 | ||
7ff6ae5a TM |
415 | #ifdef PACKET_AUXDATA |
416 | { | |
acbecb2e TM |
417 | /* Use auxiliary packet data to: |
418 | * | |
419 | * a. Weed out extraneous VLAN-tagged packets - If the NIC driver is | |
420 | * handling VLAN encapsulation (i.e. stripping/adding VLAN tags), | |
421 | * then an inbound VLAN packet will be seen twice: Once by | |
422 | * the parent interface (e.g. eth0) with a VLAN tag != 0; and once | |
423 | * by the vlan interface (e.g. eth0.n) with a VLAN tag of 0 (i.e none). | |
424 | * We want to discard the packet sent to the parent and thus respond | |
425 | * only over the vlan interface. (Drivers for Intel PRO/1000 series | |
426 | * NICs perform VLAN encapsulation, while drivers for PCnet series | |
427 | * do not, for example. The linux kernel makes stripped vlan info | |
428 | * visible to user space via CMSG/auxdata, this appears to not be | |
75d02fcf TM |
429 | * true for BSD OSs.). NOTE: this is only supported on linux flavors |
430 | * which define the tpacket_auxdata.tp_vlan_tci. | |
acbecb2e TM |
431 | * |
432 | * b. Determine if checksum is valid for use. It may not be if | |
433 | * checksum offloading is enabled on the interface. */ | |
7ff6ae5a TM |
434 | struct cmsghdr *cmsg; |
435 | ||
436 | for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { | |
437 | if (cmsg->cmsg_level == SOL_PACKET && | |
438 | cmsg->cmsg_type == PACKET_AUXDATA) { | |
439 | struct tpacket_auxdata *aux = (void *)CMSG_DATA(cmsg); | |
75d02fcf | 440 | #ifdef VLAN_TCI_PRESENT |
f10cbbfa TM |
441 | /* Discard packets with stripped vlan id */ |
442 | /* VLAN ID is only bottom 12-bits of TCI */ | |
443 | if (aux->tp_vlan_tci & 0x0fff) | |
acbecb2e | 444 | return 0; |
75d02fcf | 445 | #endif |
acbecb2e | 446 | |
7ff6ae5a TM |
447 | csum_ready = ((aux->tp_status & TP_STATUS_CSUMNOTREADY) |
448 | ? 0 : 1); | |
449 | } | |
450 | } | |
451 | ||
452 | } | |
1c0b7d66 | 453 | #endif /* PACKET_AUXDATA */ |
7ff6ae5a | 454 | |
2dddca22 | 455 | bufix = 0; |
31c08e37 TL |
456 | /* Decode the physical header... */ |
457 | offset = decode_hw_header (interface, ibuf, bufix, hfrom); | |
458 | ||
459 | /* If a physical layer checksum failed (dunno of any | |
460 | physical layer that supports this, but WTH), skip this | |
461 | packet. */ | |
462 | if (offset < 0) { | |
463 | return 0; | |
464 | } | |
465 | ||
466 | bufix += offset; | |
467 | length -= offset; | |
468 | ||
469 | /* Decode the IP and UDP headers... */ | |
6ceb9118 | 470 | offset = decode_udp_ip_header (interface, ibuf, bufix, from, |
7ff6ae5a | 471 | (unsigned)length, &paylen, csum_ready); |
31c08e37 TL |
472 | |
473 | /* If the IP or UDP checksum was bad, skip the packet... */ | |
474 | if (offset < 0) | |
475 | return 0; | |
476 | ||
477 | bufix += offset; | |
478 | length -= offset; | |
479 | ||
83c0372e EH |
480 | if (length < paylen) |
481 | log_fatal("Internal inconsistency at %s:%d.", MDL); | |
482 | ||
31c08e37 | 483 | /* Copy out the data in the packet... */ |
83c0372e EH |
484 | memcpy(buf, &ibuf[bufix], paylen); |
485 | return paylen; | |
31c08e37 TL |
486 | } |
487 | ||
21d21e91 TL |
488 | int can_unicast_without_arp (ip) |
489 | struct interface_info *ip; | |
31c08e37 TL |
490 | { |
491 | return 1; | |
492 | } | |
493 | ||
21d21e91 TL |
494 | int can_receive_unicast_unconfigured (ip) |
495 | struct interface_info *ip; | |
b547818b TL |
496 | { |
497 | return 1; | |
498 | } | |
499 | ||
5cefe5e5 TL |
500 | int supports_multiple_interfaces (ip) |
501 | struct interface_info *ip; | |
502 | { | |
503 | return 1; | |
504 | } | |
505 | ||
31c08e37 TL |
506 | void maybe_setup_fallback () |
507 | { | |
acc21512 | 508 | isc_result_t status; |
20916cae TL |
509 | struct interface_info *fbi = (struct interface_info *)0; |
510 | if (setup_fallback (&fbi, MDL)) { | |
31c08e37 | 511 | if_register_fallback (fbi); |
e92653f1 | 512 | status = omapi_register_io_object ((omapi_object_t *)fbi, |
acc21512 TL |
513 | if_readsocket, 0, |
514 | fallback_discard, 0, 0); | |
515 | if (status != ISC_R_SUCCESS) | |
98bd7ca0 | 516 | log_fatal ("Can't register I/O handle for \"%s\": %s", |
acc21512 | 517 | fbi -> name, isc_result_totext (status)); |
68e1f67a | 518 | interface_dereference (&fbi, MDL); |
31c08e37 TL |
519 | } |
520 | } | |
32e651c4 | 521 | #endif |
98bd7ca0 | 522 | |
32e651c4 | 523 | #if defined (USE_LPF_RECEIVE) || defined (USE_LPF_HWADDR) |
98bd7ca0 DH |
524 | void |
525 | get_hw_addr(const char *name, struct hardware *hw) { | |
526 | int sock; | |
527 | struct ifreq tmp; | |
528 | struct sockaddr *sa; | |
529 | ||
530 | if (strlen(name) >= sizeof(tmp.ifr_name)) { | |
531 | log_fatal("Device name too long: \"%s\"", name); | |
532 | } | |
533 | ||
534 | sock = socket(AF_INET, SOCK_DGRAM, 0); | |
535 | if (sock < 0) { | |
536 | log_fatal("Can't create socket for \"%s\": %m", name); | |
537 | } | |
538 | ||
539 | memset(&tmp, 0, sizeof(tmp)); | |
540 | strcpy(tmp.ifr_name, name); | |
541 | if (ioctl(sock, SIOCGIFHWADDR, &tmp) < 0) { | |
f6b8f48d | 542 | log_fatal("Error getting hardware address for \"%s\": %m", |
98bd7ca0 DH |
543 | name); |
544 | } | |
545 | ||
546 | sa = &tmp.ifr_hwaddr; | |
547 | switch (sa->sa_family) { | |
548 | case ARPHRD_ETHER: | |
549 | hw->hlen = 7; | |
550 | hw->hbuf[0] = HTYPE_ETHER; | |
551 | memcpy(&hw->hbuf[1], sa->sa_data, 6); | |
552 | break; | |
553 | case ARPHRD_IEEE802: | |
99fe695e | 554 | #ifdef ARPHRD_IEEE802_TR |
98bd7ca0 | 555 | case ARPHRD_IEEE802_TR: |
99fe695e | 556 | #endif /* ARPHRD_IEEE802_TR */ |
98bd7ca0 DH |
557 | hw->hlen = 7; |
558 | hw->hbuf[0] = HTYPE_IEEE802; | |
559 | memcpy(&hw->hbuf[1], sa->sa_data, 6); | |
560 | break; | |
561 | case ARPHRD_FDDI: | |
0f750c4f | 562 | hw->hlen = 7; |
98bd7ca0 | 563 | hw->hbuf[0] = HTYPE_FDDI; |
0f750c4f | 564 | memcpy(&hw->hbuf[1], sa->sa_data, 6); |
98bd7ca0 DH |
565 | break; |
566 | default: | |
567 | log_fatal("Unsupported device type %ld for \"%s\"", | |
28868515 | 568 | (long int)sa->sa_family, name); |
98bd7ca0 DH |
569 | } |
570 | ||
571 | close(sock); | |
572 | } | |
31c08e37 | 573 | #endif |