Remove building with NOCRYPTO option
[minix.git] / external / bsd / dhcp / dist / common / lpf.c
blob5c0772f8049202ec770dab48f0fe976f1bcbf182
1 /* $NetBSD: lpf.c,v 1.1.1.4 2014/07/12 11:57:44 spz Exp $ */
2 /* lpf.c
4 Linux packet filter code, contributed by Brian Murrel at Interlinx
5 Support Services in Vancouver, B.C. */
7 /*
8 * Copyright (c) 2009,2012 by Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
10 * Copyright (c) 1996-2003 by Internet Software Consortium
12 * Permission to use, copy, modify, and distribute this software for any
13 * purpose with or without fee is hereby granted, provided that the above
14 * copyright notice and this permission notice appear in all copies.
16 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
17 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
19 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
21 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
22 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * Internet Systems Consortium, Inc.
25 * 950 Charter Street
26 * Redwood City, CA 94063
27 * <info@isc.org>
28 * https://www.isc.org/
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: lpf.c,v 1.1.1.4 2014/07/12 11:57:44 spz Exp $");
34 #include "dhcpd.h"
35 #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
36 #include <sys/uio.h>
37 #include <errno.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 <net/if_packet.h>
44 #include "includes/netinet/ip.h"
45 #include "includes/netinet/udp.h"
46 #include "includes/netinet/if_ether.h"
47 #endif
49 #if defined (USE_LPF_RECEIVE) || defined (USE_LPF_HWADDR)
50 #include <sys/ioctl.h>
51 #include <net/if.h>
52 #endif
54 #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
55 /* Reinitializes the specified interface after an address change. This
56 is not required for packet-filter APIs. */
58 #ifdef USE_LPF_SEND
59 void if_reinitialize_send (info)
60 struct interface_info *info;
63 #endif
65 #ifdef USE_LPF_RECEIVE
66 void if_reinitialize_receive (info)
67 struct interface_info *info;
70 #endif
72 /* Called by get_interface_list for each interface that's discovered.
73 Opens a packet filter for each interface and adds it to the select
74 mask. */
76 int if_register_lpf (info)
77 struct interface_info *info;
79 int sock;
80 struct sockaddr sa;
82 /* Make an LPF socket. */
83 if ((sock = socket(PF_PACKET, SOCK_PACKET,
84 htons((short)ETH_P_ALL))) < 0) {
85 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
86 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
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!");
95 log_fatal ("Open a socket for LPF: %m");
98 /* Bind to the interface name */
99 memset (&sa, 0, sizeof sa);
100 sa.sa_family = AF_PACKET;
101 strncpy (sa.sa_data, (const char *)info -> ifp, sizeof sa.sa_data);
102 if (bind (sock, &sa, sizeof sa)) {
103 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
104 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
105 errno == EAFNOSUPPORT || errno == EINVAL) {
106 log_error ("socket: %m - make sure");
107 log_error ("CONFIG_PACKET (Packet socket) %s",
108 "and CONFIG_FILTER");
109 log_error ("(Socket Filtering) are enabled %s",
110 "in your kernel");
111 log_fatal ("configuration!");
113 log_fatal ("Bind socket to interface: %m");
116 get_hw_addr(info->name, &info->hw_address);
118 return sock;
120 #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
122 #ifdef USE_LPF_SEND
123 void if_register_send (info)
124 struct interface_info *info;
126 /* If we're using the lpf API for sending and receiving,
127 we don't need to register this interface twice. */
128 #ifndef USE_LPF_RECEIVE
129 info -> wfdesc = if_register_lpf (info);
130 #else
131 info -> wfdesc = info -> rfdesc;
132 #endif
133 if (!quiet_interface_discovery)
134 log_info ("Sending on LPF/%s/%s%s%s",
135 info -> name,
136 print_hw_addr (info -> hw_address.hbuf [0],
137 info -> hw_address.hlen - 1,
138 &info -> hw_address.hbuf [1]),
139 (info -> shared_network ? "/" : ""),
140 (info -> shared_network ?
141 info -> shared_network -> name : ""));
144 void if_deregister_send (info)
145 struct interface_info *info;
147 /* don't need to close twice if we are using lpf for sending and
148 receiving */
149 #ifndef USE_LPF_RECEIVE
150 /* for LPF this is simple, packet filters are removed when sockets
151 are closed */
152 close (info -> wfdesc);
153 #endif
154 info -> wfdesc = -1;
155 if (!quiet_interface_discovery)
156 log_info ("Disabling output on LPF/%s/%s%s%s",
157 info -> name,
158 print_hw_addr (info -> hw_address.hbuf [0],
159 info -> hw_address.hlen - 1,
160 &info -> hw_address.hbuf [1]),
161 (info -> shared_network ? "/" : ""),
162 (info -> shared_network ?
163 info -> shared_network -> name : ""));
165 #endif /* USE_LPF_SEND */
167 #ifdef USE_LPF_RECEIVE
168 /* Defined in bpf.c. We can't extern these in dhcpd.h without pulling
169 in bpf includes... */
170 extern struct sock_filter dhcp_bpf_filter [];
171 extern int dhcp_bpf_filter_len;
173 #if defined (HAVE_TR_SUPPORT)
174 extern struct sock_filter dhcp_bpf_tr_filter [];
175 extern int dhcp_bpf_tr_filter_len;
176 static void lpf_tr_filter_setup (struct interface_info *);
177 #endif
179 static void lpf_gen_filter_setup (struct interface_info *);
181 void if_register_receive (info)
182 struct interface_info *info;
184 /* Open a LPF device and hang it on this interface... */
185 info -> rfdesc = if_register_lpf (info);
187 #if defined (HAVE_TR_SUPPORT)
188 if (info -> hw_address.hbuf [0] == HTYPE_IEEE802)
189 lpf_tr_filter_setup (info);
190 else
191 #endif
192 lpf_gen_filter_setup (info);
194 if (!quiet_interface_discovery)
195 log_info ("Listening on LPF/%s/%s%s%s",
196 info -> name,
197 print_hw_addr (info -> hw_address.hbuf [0],
198 info -> hw_address.hlen - 1,
199 &info -> hw_address.hbuf [1]),
200 (info -> shared_network ? "/" : ""),
201 (info -> shared_network ?
202 info -> shared_network -> name : ""));
205 void if_deregister_receive (info)
206 struct interface_info *info;
208 /* for LPF this is simple, packet filters are removed when sockets
209 are closed */
210 close (info -> rfdesc);
211 info -> rfdesc = -1;
212 if (!quiet_interface_discovery)
213 log_info ("Disabling input on LPF/%s/%s%s%s",
214 info -> name,
215 print_hw_addr (info -> hw_address.hbuf [0],
216 info -> hw_address.hlen - 1,
217 &info -> hw_address.hbuf [1]),
218 (info -> shared_network ? "/" : ""),
219 (info -> shared_network ?
220 info -> shared_network -> name : ""));
223 static void lpf_gen_filter_setup (info)
224 struct interface_info *info;
226 struct sock_fprog p;
228 memset(&p, 0, sizeof(p));
230 /* Set up the bpf filter program structure. This is defined in
231 bpf.c */
232 p.len = dhcp_bpf_filter_len;
233 p.filter = dhcp_bpf_filter;
235 /* Patch the server port into the LPF program...
236 XXX changes to filter program may require changes
237 to the insn number(s) used below! XXX */
238 dhcp_bpf_filter [8].k = ntohs ((short)local_port);
240 if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
241 sizeof p) < 0) {
242 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
243 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
244 errno == EAFNOSUPPORT) {
245 log_error ("socket: %m - make sure");
246 log_error ("CONFIG_PACKET (Packet socket) %s",
247 "and CONFIG_FILTER");
248 log_error ("(Socket Filtering) are enabled %s",
249 "in your kernel");
250 log_fatal ("configuration!");
252 log_fatal ("Can't install packet filter program: %m");
256 #if defined (HAVE_TR_SUPPORT)
257 static void lpf_tr_filter_setup (info)
258 struct interface_info *info;
260 struct sock_fprog p;
262 memset(&p, 0, sizeof(p));
264 /* Set up the bpf filter program structure. This is defined in
265 bpf.c */
266 p.len = dhcp_bpf_tr_filter_len;
267 p.filter = dhcp_bpf_tr_filter;
269 /* Patch the server port into the LPF program...
270 XXX changes to filter program may require changes
271 XXX to the insn number(s) used below!
272 XXX Token ring filter is null - when/if we have a filter
273 XXX that's not, we'll need this code.
274 XXX dhcp_bpf_filter [?].k = ntohs (local_port); */
276 if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
277 sizeof p) < 0) {
278 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
279 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
280 errno == EAFNOSUPPORT) {
281 log_error ("socket: %m - make sure");
282 log_error ("CONFIG_PACKET (Packet socket) %s",
283 "and CONFIG_FILTER");
284 log_error ("(Socket Filtering) are enabled %s",
285 "in your kernel");
286 log_fatal ("configuration!");
288 log_fatal ("Can't install packet filter program: %m");
291 #endif /* HAVE_TR_SUPPORT */
292 #endif /* USE_LPF_RECEIVE */
294 #ifdef USE_LPF_SEND
295 ssize_t send_packet (interface, packet, raw, len, from, to, hto)
296 struct interface_info *interface;
297 struct packet *packet;
298 struct dhcp_packet *raw;
299 size_t len;
300 struct in_addr from;
301 struct sockaddr_in *to;
302 struct hardware *hto;
304 unsigned hbufp = 0, ibufp = 0;
305 double hh [16];
306 double ih [1536 / sizeof (double)];
307 unsigned char *buf = (unsigned char *)ih;
308 struct sockaddr_pkt sa;
309 int result;
310 int fudge;
312 if (!strcmp (interface -> name, "fallback"))
313 return send_fallback (interface, packet, raw,
314 len, from, to, hto);
316 if (hto == NULL && interface->anycast_mac_addr.hlen)
317 hto = &interface->anycast_mac_addr;
319 /* Assemble the headers... */
320 assemble_hw_header (interface, (unsigned char *)hh, &hbufp, hto);
321 fudge = hbufp % 4; /* IP header must be word-aligned. */
322 memcpy (buf + fudge, (unsigned char *)hh, hbufp);
323 ibufp = hbufp + fudge;
324 assemble_udp_ip_header (interface, buf, &ibufp, from.s_addr,
325 to -> sin_addr.s_addr, to -> sin_port,
326 (unsigned char *)raw, len);
327 memcpy (buf + ibufp, raw, len);
329 /* For some reason, SOCK_PACKET sockets can't be connected,
330 so we have to do a sentdo every time. */
331 memset (&sa, 0, sizeof sa);
332 sa.spkt_family = AF_PACKET;
333 strncpy ((char *)sa.spkt_device,
334 (const char *)interface -> ifp, sizeof sa.spkt_device);
335 sa.spkt_protocol = htons(ETH_P_IP);
337 result = sendto (interface -> wfdesc,
338 buf + fudge, ibufp + len - fudge, 0,
339 (const struct sockaddr *)&sa, sizeof sa);
340 if (result < 0)
341 log_error ("send_packet: %m");
342 return result;
344 #endif /* USE_LPF_SEND */
346 #ifdef USE_LPF_RECEIVE
347 ssize_t receive_packet (interface, buf, len, from, hfrom)
348 struct interface_info *interface;
349 unsigned char *buf;
350 size_t len;
351 struct sockaddr_in *from;
352 struct hardware *hfrom;
354 int length = 0;
355 int offset = 0;
356 unsigned char ibuf [1536];
357 unsigned bufix = 0;
358 unsigned paylen;
360 length = read (interface -> rfdesc, ibuf, sizeof ibuf);
361 if (length <= 0)
362 return length;
364 bufix = 0;
365 /* Decode the physical header... */
366 offset = decode_hw_header (interface, ibuf, bufix, hfrom);
368 /* If a physical layer checksum failed (dunno of any
369 physical layer that supports this, but WTH), skip this
370 packet. */
371 if (offset < 0) {
372 return 0;
375 bufix += offset;
376 length -= offset;
378 /* Decode the IP and UDP headers... */
379 offset = decode_udp_ip_header (interface, ibuf, bufix, from,
380 (unsigned)length, &paylen);
382 /* If the IP or UDP checksum was bad, skip the packet... */
383 if (offset < 0)
384 return 0;
386 bufix += offset;
387 length -= offset;
389 if (length < paylen)
390 log_fatal("Internal inconsistency at %s:%d.", MDL);
392 /* Copy out the data in the packet... */
393 memcpy(buf, &ibuf[bufix], paylen);
394 return paylen;
397 int can_unicast_without_arp (ip)
398 struct interface_info *ip;
400 return 1;
403 int can_receive_unicast_unconfigured (ip)
404 struct interface_info *ip;
406 return 1;
409 int supports_multiple_interfaces (ip)
410 struct interface_info *ip;
412 return 1;
415 void maybe_setup_fallback ()
417 isc_result_t status;
418 struct interface_info *fbi = (struct interface_info *)0;
419 if (setup_fallback (&fbi, MDL)) {
420 if_register_fallback (fbi);
421 status = omapi_register_io_object ((omapi_object_t *)fbi,
422 if_readsocket, 0,
423 fallback_discard, 0, 0);
424 if (status != ISC_R_SUCCESS)
425 log_fatal ("Can't register I/O handle for \"%s\": %s",
426 fbi -> name, isc_result_totext (status));
427 interface_dereference (&fbi, MDL);
430 #endif
432 #if defined (USE_LPF_RECEIVE) || defined (USE_LPF_HWADDR)
433 void
434 get_hw_addr(const char *name, struct hardware *hw) {
435 int sock;
436 struct ifreq tmp;
437 struct sockaddr *sa;
439 if (strlen(name) >= sizeof(tmp.ifr_name)) {
440 log_fatal("Device name too long: \"%s\"", name);
443 sock = socket(AF_INET, SOCK_DGRAM, 0);
444 if (sock < 0) {
445 log_fatal("Can't create socket for \"%s\": %m", name);
448 memset(&tmp, 0, sizeof(tmp));
449 strcpy(tmp.ifr_name, name);
450 if (ioctl(sock, SIOCGIFHWADDR, &tmp) < 0) {
451 log_fatal("Error getting hardware address for \"%s\": %m",
452 name);
455 sa = &tmp.ifr_hwaddr;
456 switch (sa->sa_family) {
457 case ARPHRD_ETHER:
458 hw->hlen = 7;
459 hw->hbuf[0] = HTYPE_ETHER;
460 memcpy(&hw->hbuf[1], sa->sa_data, 6);
461 break;
462 case ARPHRD_IEEE802:
463 #ifdef ARPHRD_IEEE802_TR
464 case ARPHRD_IEEE802_TR:
465 #endif /* ARPHRD_IEEE802_TR */
466 hw->hlen = 7;
467 hw->hbuf[0] = HTYPE_IEEE802;
468 memcpy(&hw->hbuf[1], sa->sa_data, 6);
469 break;
470 case ARPHRD_FDDI:
471 hw->hlen = 7;
472 hw->hbuf[0] = HTYPE_FDDI;
473 memcpy(&hw->hbuf[1], sa->sa_data, 6);
474 break;
475 default:
476 log_fatal("Unsupported device type %ld for \"%s\"",
477 (long int)sa->sa_family, name);
480 close(sock);
482 #endif