3 Linux packet filter code, contributed by Brian Murrel at Interlinx
4 Support Services in Vancouver, B.C. */
7 * Copyright (c) 1995, 1996, 1998, 1999
8 * The Internet Software Consortium. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of The Internet Software Consortium nor the names
20 * of its contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
24 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
31 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
32 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * This software has been written for the Internet Software Consortium
38 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
39 * Enterprises. To learn more about the Internet Software Consortium,
40 * see ``http://www.vix.com/isc''. To learn more about Vixie
41 * Enterprises, see ``http://www.vix.com''.
45 static char copyright[] =
46 "$Id: lpf.c,v 1.1.2.9 1999/05/27 17:44:52 mellon Exp $ Copyright (c) 1995, 1996, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
50 #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
51 #include <sys/ioctl.h>
54 #include <asm/types.h>
55 #include <linux/filter.h>
56 #include <linux/if_ether.h>
57 #include <netinet/in_systm.h>
58 #include "includes/netinet/ip.h"
59 #include "includes/netinet/udp.h"
60 #include "includes/netinet/if_ether.h"
62 static void lpf_gen_filter_setup PROTO ((struct interface_info *));
63 static void lpf_tr_filter_setup PROTO ((struct interface_info *));
65 /* Reinitializes the specified interface after an address change. This
66 is not required for packet-filter APIs. */
69 void if_reinitialize_send (info)
70 struct interface_info *info;
75 #ifdef USE_LPF_RECEIVE
76 void if_reinitialize_receive (info)
77 struct interface_info *info;
82 /* Called by get_interface_list for each interface that's discovered.
83 Opens a packet filter for each interface and adds it to the select
86 int if_register_lpf (info)
87 struct interface_info *info;
94 /* Make an LPF socket. */
95 if ((sock = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ALL))) < 0) {
96 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
97 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
98 errno == EAFNOSUPPORT || errno == EINVAL) {
100 error ("Make sure to set %s %s!",
101 "CONFIG_PACKET=y and CONFIG_FILTER=y",
102 "in your kernel configuration");
104 error("Open a socket for LPF: %m");
107 /* Bind to the interface name */
108 memset (&sa, 0, sizeof sa);
109 sa.sa_family = AF_PACKET;
110 strncpy (sa.sa_data, (const char *)info -> ifp, sizeof sa.sa_data);
111 if (bind (sock, &sa, sizeof sa)) {
112 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
113 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
114 errno == EAFNOSUPPORT || errno == EINVAL) {
117 "CONFIG_PACKET=y and CONFIG_FILTER=y",
118 "in your kernel configuration");
120 error("Bind socket to interface: %m");
125 #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
128 void if_register_send (info)
129 struct interface_info *info;
131 /* If we're using the lpf API for sending and receiving,
132 we don't need to register this interface twice. */
133 #ifndef USE_LPF_RECEIVE
134 info -> wfdesc = if_register_lpf (info, interface);
136 info -> wfdesc = info -> rfdesc;
138 if (!quiet_interface_discovery)
139 note ("Sending on LPF/%s/%s%s%s",
141 print_hw_addr (info -> hw_address.htype,
142 info -> hw_address.hlen,
143 info -> hw_address.haddr),
144 (info -> shared_network ? "/" : ""),
145 (info -> shared_network ?
146 info -> shared_network -> name : ""));
148 #endif /* USE_LPF_SEND */
150 #ifdef USE_LPF_RECEIVE
151 /* Defined in bpf.c. We can't extern these in dhcpd.h without pulling
152 in bpf includes... */
153 extern struct sock_filter dhcp_bpf_filter [];
154 extern int dhcp_bpf_filter_len;
155 extern struct sock_filter dhcp_bpf_tr_filter [];
156 extern int dhcp_bpf_tr_filter_len;
158 void if_register_receive (info)
159 struct interface_info *info;
161 /* Open a LPF device and hang it on this interface... */
162 info -> rfdesc = if_register_lpf (info);
164 if (info -> hw_address.htype == HTYPE_IEEE802)
165 lpf_tr_filter_setup (info);
167 lpf_gen_filter_setup (info);
169 if (!quiet_interface_discovery)
170 note ("Listening on LPF/%s/%s%s%s",
172 print_hw_addr (info -> hw_address.htype,
173 info -> hw_address.hlen,
174 info -> hw_address.haddr),
175 (info -> shared_network ? "/" : ""),
176 (info -> shared_network ?
177 info -> shared_network -> name : ""));
180 static void lpf_gen_filter_setup (info)
181 struct interface_info *info;
185 /* Set up the bpf filter program structure. This is defined in
187 p.len = dhcp_bpf_filter_len;
188 p.filter = dhcp_bpf_filter;
190 /* Patch the server port into the LPF program...
191 XXX changes to filter program may require changes
192 to the insn number(s) used below! XXX */
193 dhcp_bpf_filter [8].k = ntohs (local_port);
195 if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
197 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
198 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
199 errno == EAFNOSUPPORT)
200 error ("socket: %m - make sure %s %s!",
201 "CONFIG_PACKET and CONFIG_FILTER are defined",
202 "in your kernel configuration");
203 error ("Can't install packet filter program: %m");
207 static void lpf_tr_filter_setup (info)
208 struct interface_info *info;
212 /* Set up the bpf filter program structure. This is defined in
214 p.len = dhcp_bpf_tr_filter_len;
215 p.filter = dhcp_bpf_tr_filter;
217 /* Patch the server port into the LPF program...
218 XXX changes to filter program may require changes
219 XXX to the insn number(s) used below!
220 XXX Token ring filter is null - when/if we have a filter
221 XXX that's not, we'll need this code.
222 XXX dhcp_bpf_filter [?].k = ntohs (local_port); */
224 if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
226 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
227 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
228 errno == EAFNOSUPPORT)
229 error ("socket: %m - make sure %s %s!",
230 "CONFIG_PACKET and CONFIG_FILTER are defined",
231 "in your kernel configuration");
232 error ("Can't install packet filter program: %m");
235 #endif /* USE_LPF_RECEIVE */
238 ssize_t send_packet (interface, packet, raw, len, from, to, hto)
239 struct interface_info *interface;
240 struct packet *packet;
241 struct dhcp_packet *raw;
244 struct sockaddr_in *to;
245 struct hardware *hto;
248 unsigned char buf [1500];
252 if (!strcmp (interface -> name, "fallback"))
253 return send_fallback (interface, packet, raw,
256 /* Assemble the headers... */
257 assemble_hw_header (interface, buf, &bufp, hto);
258 assemble_udp_ip_header (interface, buf, &bufp, from.s_addr,
259 to -> sin_addr.s_addr, to -> sin_port,
260 (unsigned char *)raw, len);
261 memcpy (buf + bufp, raw, len);
263 /* For some reason, SOCK_PACKET sockets can't be connected,
264 so we have to do a sentdo every time. */
265 memset (&sa, 0, sizeof sa);
266 sa.sa_family = AF_PACKET;
268 (const char *)interface -> ifp, sizeof sa.sa_data);
270 result = sendto (interface -> wfdesc, buf, bufp + len, 0,
273 warn ("send_packet: %m");
276 #endif /* USE_LPF_SEND */
278 #ifdef USE_LPF_RECEIVE
279 ssize_t receive_packet (interface, buf, len, from, hfrom)
280 struct interface_info *interface;
283 struct sockaddr_in *from;
284 struct hardware *hfrom;
289 unsigned char ibuf [1500];
292 length = read (interface -> rfdesc, ibuf, sizeof ibuf);
297 /* Decode the physical header... */
298 offset = decode_hw_header (interface, ibuf, bufix, hfrom);
300 /* If a physical layer checksum failed (dunno of any
301 physical layer that supports this, but WTH), skip this
310 /* Decode the IP and UDP headers... */
311 offset = decode_udp_ip_header (interface, ibuf, bufix,
312 from, (unsigned char *)0, length);
314 /* If the IP or UDP checksum was bad, skip the packet... */
321 /* Copy out the data in the packet... */
322 memcpy (buf, &ibuf [bufix], length);
326 int can_unicast_without_arp ()
331 int can_receive_unicast_unconfigured (ip)
332 struct interface_info *ip;
337 void maybe_setup_fallback ()
339 struct interface_info *fbi;
340 fbi = setup_fallback ();
342 if_register_fallback (fbi);
343 add_protocol ("fallback", fallback_interface -> wfdesc,
344 fallback_discard, fallback_interface);