Pre-2.0 release, MFC firewire disk changes to properly detach SIMs.
[dragonfly.git] / contrib / dhcp-3.0 / common / lpf.c
blob54c113883304c58c76fe381d5e01fd517df2104a
1 /* lpf.c
3 Linux packet filter code, contributed by Brian Murrel at Interlinx
4 Support Services in Vancouver, B.C. */
6 /*
7 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 1996-2003 by Internet Software Consortium
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
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.
22 * Internet Systems Consortium, Inc.
23 * 950 Charter Street
24 * Redwood City, CA 94063
25 * <info@isc.org>
26 * http://www.isc.org/
29 #ifndef lint
30 static char copyright[] =
31 "$Id: lpf.c,v 1.29.2.3 2004/11/24 17:39:15 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
32 #endif /* not lint */
34 #include "dhcpd.h"
35 #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
36 #include <sys/ioctl.h>
37 #include <sys/uio.h>
39 #include <asm/types.h>
40 #include <linux/filter.h>
41 #include <linux/if_ether.h>
42 #include <netinet/in_systm.h>
43 #include "includes/netinet/ip.h"
44 #include "includes/netinet/udp.h"
45 #include "includes/netinet/if_ether.h"
47 /* Reinitializes the specified interface after an address change. This
48 is not required for packet-filter APIs. */
50 #ifdef USE_LPF_SEND
51 void if_reinitialize_send (info)
52 struct interface_info *info;
55 #endif
57 #ifdef USE_LPF_RECEIVE
58 void if_reinitialize_receive (info)
59 struct interface_info *info;
62 #endif
64 /* Called by get_interface_list for each interface that's discovered.
65 Opens a packet filter for each interface and adds it to the select
66 mask. */
68 int if_register_lpf (info)
69 struct interface_info *info;
71 int sock;
72 char filename[50];
73 int b;
74 struct sockaddr sa;
76 /* Make an LPF socket. */
77 if ((sock = socket(PF_PACKET, SOCK_PACKET,
78 htons((short)ETH_P_ALL))) < 0) {
79 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
80 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
81 errno == EAFNOSUPPORT || errno == EINVAL) {
82 log_error ("socket: %m - make sure");
83 log_error ("CONFIG_PACKET (Packet socket) %s",
84 "and CONFIG_FILTER");
85 log_error ("(Socket Filtering) are enabled %s",
86 "in your kernel");
87 log_fatal ("configuration!");
89 log_fatal ("Open a socket for LPF: %m");
92 /* Bind to the interface name */
93 memset (&sa, 0, sizeof sa);
94 sa.sa_family = AF_PACKET;
95 strncpy (sa.sa_data, (const char *)info -> ifp, sizeof sa.sa_data);
96 if (bind (sock, &sa, sizeof sa)) {
97 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
98 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
99 errno == EAFNOSUPPORT || errno == EINVAL) {
100 log_error ("socket: %m - make sure");
101 log_error ("CONFIG_PACKET (Packet socket) %s",
102 "and CONFIG_FILTER");
103 log_error ("(Socket Filtering) are enabled %s",
104 "in your kernel");
105 log_fatal ("configuration!");
107 log_fatal ("Bind socket to interface: %m");
110 return sock;
112 #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
114 #ifdef USE_LPF_SEND
115 void if_register_send (info)
116 struct interface_info *info;
118 /* If we're using the lpf API for sending and receiving,
119 we don't need to register this interface twice. */
120 #ifndef USE_LPF_RECEIVE
121 info -> wfdesc = if_register_lpf (info);
122 #else
123 info -> wfdesc = info -> rfdesc;
124 #endif
125 if (!quiet_interface_discovery)
126 log_info ("Sending on LPF/%s/%s%s%s",
127 info -> name,
128 print_hw_addr (info -> hw_address.hbuf [0],
129 info -> hw_address.hlen - 1,
130 &info -> hw_address.hbuf [1]),
131 (info -> shared_network ? "/" : ""),
132 (info -> shared_network ?
133 info -> shared_network -> name : ""));
136 void if_deregister_send (info)
137 struct interface_info *info;
139 /* don't need to close twice if we are using lpf for sending and
140 receiving */
141 #ifndef USE_LPF_RECEIVE
142 /* for LPF this is simple, packet filters are removed when sockets
143 are closed */
144 close (info -> wfdesc);
145 #endif
146 info -> wfdesc = -1;
147 if (!quiet_interface_discovery)
148 log_info ("Disabling output on LPF/%s/%s%s%s",
149 info -> name,
150 print_hw_addr (info -> hw_address.hbuf [0],
151 info -> hw_address.hlen - 1,
152 &info -> hw_address.hbuf [1]),
153 (info -> shared_network ? "/" : ""),
154 (info -> shared_network ?
155 info -> shared_network -> name : ""));
157 #endif /* USE_LPF_SEND */
159 #ifdef USE_LPF_RECEIVE
160 /* Defined in bpf.c. We can't extern these in dhcpd.h without pulling
161 in bpf includes... */
162 extern struct sock_filter dhcp_bpf_filter [];
163 extern int dhcp_bpf_filter_len;
165 #if defined (HAVE_TR_SUPPORT)
166 extern struct sock_filter dhcp_bpf_tr_filter [];
167 extern int dhcp_bpf_tr_filter_len;
168 static void lpf_tr_filter_setup (struct interface_info *);
169 #endif
171 static void lpf_gen_filter_setup (struct interface_info *);
173 void if_register_receive (info)
174 struct interface_info *info;
176 /* Open a LPF device and hang it on this interface... */
177 info -> rfdesc = if_register_lpf (info);
179 #if defined (HAVE_TR_SUPPORT)
180 if (info -> hw_address.hbuf [0] == HTYPE_IEEE802)
181 lpf_tr_filter_setup (info);
182 else
183 #endif
184 lpf_gen_filter_setup (info);
186 if (!quiet_interface_discovery)
187 log_info ("Listening on LPF/%s/%s%s%s",
188 info -> name,
189 print_hw_addr (info -> hw_address.hbuf [0],
190 info -> hw_address.hlen - 1,
191 &info -> hw_address.hbuf [1]),
192 (info -> shared_network ? "/" : ""),
193 (info -> shared_network ?
194 info -> shared_network -> name : ""));
197 void if_deregister_receive (info)
198 struct interface_info *info;
200 /* for LPF this is simple, packet filters are removed when sockets
201 are closed */
202 close (info -> rfdesc);
203 info -> rfdesc = -1;
204 if (!quiet_interface_discovery)
205 log_info ("Disabling input on LPF/%s/%s%s%s",
206 info -> name,
207 print_hw_addr (info -> hw_address.hbuf [0],
208 info -> hw_address.hlen - 1,
209 &info -> hw_address.hbuf [1]),
210 (info -> shared_network ? "/" : ""),
211 (info -> shared_network ?
212 info -> shared_network -> name : ""));
215 static void lpf_gen_filter_setup (info)
216 struct interface_info *info;
218 struct sock_fprog p;
220 /* Set up the bpf filter program structure. This is defined in
221 bpf.c */
222 p.len = dhcp_bpf_filter_len;
223 p.filter = dhcp_bpf_filter;
225 /* Patch the server port into the LPF 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 ((short)local_port);
230 if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
231 sizeof p) < 0) {
232 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
233 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
234 errno == EAFNOSUPPORT) {
235 log_error ("socket: %m - make sure");
236 log_error ("CONFIG_PACKET (Packet socket) %s",
237 "and CONFIG_FILTER");
238 log_error ("(Socket Filtering) are enabled %s",
239 "in your kernel");
240 log_fatal ("configuration!");
242 log_fatal ("Can't install packet filter program: %m");
246 #if defined (HAVE_TR_SUPPORT)
247 static void lpf_tr_filter_setup (info)
248 struct interface_info *info;
250 struct sock_fprog p;
252 /* Set up the bpf filter program structure. This is defined in
253 bpf.c */
254 p.len = dhcp_bpf_tr_filter_len;
255 p.filter = dhcp_bpf_tr_filter;
257 /* Patch the server port into the LPF program...
258 XXX changes to filter program may require changes
259 XXX to the insn number(s) used below!
260 XXX Token ring filter is null - when/if we have a filter
261 XXX that's not, we'll need this code.
262 XXX dhcp_bpf_filter [?].k = ntohs (local_port); */
264 if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
265 sizeof p) < 0) {
266 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
267 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
268 errno == EAFNOSUPPORT) {
269 log_error ("socket: %m - make sure");
270 log_error ("CONFIG_PACKET (Packet socket) %s",
271 "and CONFIG_FILTER");
272 log_error ("(Socket Filtering) are enabled %s",
273 "in your kernel");
274 log_fatal ("configuration!");
276 log_fatal ("Can't install packet filter program: %m");
279 #endif /* HAVE_TR_SUPPORT */
280 #endif /* USE_LPF_RECEIVE */
282 #ifdef USE_LPF_SEND
283 ssize_t send_packet (interface, packet, raw, len, from, to, hto)
284 struct interface_info *interface;
285 struct packet *packet;
286 struct dhcp_packet *raw;
287 size_t len;
288 struct in_addr from;
289 struct sockaddr_in *to;
290 struct hardware *hto;
292 unsigned hbufp = 0, ibufp = 0;
293 double hh [16];
294 double ih [1536 / sizeof (double)];
295 unsigned char *buf = (unsigned char *)ih;
296 struct sockaddr sa;
297 int result;
298 int fudge;
300 if (!strcmp (interface -> name, "fallback"))
301 return send_fallback (interface, packet, raw,
302 len, from, to, hto);
304 /* Assemble the headers... */
305 assemble_hw_header (interface, (unsigned char *)hh, &hbufp, hto);
306 fudge = hbufp % 4; /* IP header must be word-aligned. */
307 memcpy (buf + fudge, (unsigned char *)hh, hbufp);
308 ibufp = hbufp + fudge;
309 assemble_udp_ip_header (interface, buf, &ibufp, from.s_addr,
310 to -> sin_addr.s_addr, to -> sin_port,
311 (unsigned char *)raw, len);
312 memcpy (buf + ibufp, raw, len);
314 /* For some reason, SOCK_PACKET sockets can't be connected,
315 so we have to do a sentdo every time. */
316 memset (&sa, 0, sizeof sa);
317 sa.sa_family = AF_PACKET;
318 strncpy (sa.sa_data,
319 (const char *)interface -> ifp, sizeof sa.sa_data);
321 result = sendto (interface -> wfdesc,
322 buf + fudge, ibufp + len - fudge, 0, &sa, sizeof sa);
323 if (result < 0)
324 log_error ("send_packet: %m");
325 return result;
327 #endif /* USE_LPF_SEND */
329 #ifdef USE_LPF_RECEIVE
330 ssize_t receive_packet (interface, buf, len, from, hfrom)
331 struct interface_info *interface;
332 unsigned char *buf;
333 size_t len;
334 struct sockaddr_in *from;
335 struct hardware *hfrom;
337 int nread;
338 int length = 0;
339 int offset = 0;
340 unsigned char ibuf [1536];
341 unsigned bufix = 0;
343 length = read (interface -> rfdesc, ibuf, sizeof ibuf);
344 if (length <= 0)
345 return length;
347 bufix = 0;
348 /* Decode the physical header... */
349 offset = decode_hw_header (interface, ibuf, bufix, hfrom);
351 /* If a physical layer checksum failed (dunno of any
352 physical layer that supports this, but WTH), skip this
353 packet. */
354 if (offset < 0) {
355 return 0;
358 bufix += offset;
359 length -= offset;
361 /* Decode the IP and UDP headers... */
362 offset = decode_udp_ip_header (interface, ibuf, bufix, from,
363 (unsigned)length);
365 /* If the IP or UDP checksum was bad, skip the packet... */
366 if (offset < 0)
367 return 0;
369 bufix += offset;
370 length -= offset;
372 /* Copy out the data in the packet... */
373 memcpy (buf, &ibuf [bufix], length);
374 return length;
377 int can_unicast_without_arp (ip)
378 struct interface_info *ip;
380 return 1;
383 int can_receive_unicast_unconfigured (ip)
384 struct interface_info *ip;
386 return 1;
389 int supports_multiple_interfaces (ip)
390 struct interface_info *ip;
392 return 1;
395 void maybe_setup_fallback ()
397 isc_result_t status;
398 struct interface_info *fbi = (struct interface_info *)0;
399 if (setup_fallback (&fbi, MDL)) {
400 if_register_fallback (fbi);
401 status = omapi_register_io_object ((omapi_object_t *)fbi,
402 if_readsocket, 0,
403 fallback_discard, 0, 0);
404 if (status != ISC_R_SUCCESS)
405 log_fatal ("Can't register I/O handle for %s: %s",
406 fbi -> name, isc_result_totext (status));
407 interface_dereference (&fbi, MDL);
410 #endif