]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/isc-dhcp/common/lpf.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.git] / contrib / isc-dhcp / common / lpf.c
1 /* lpf.c
2
3    Linux packet filter code, contributed by Brian Murrel at Interlinx
4    Support Services in Vancouver, B.C. */
5
6 /*
7  * Copyright (c) 1995, 1996, 1998, 1999
8  * The Internet Software Consortium.    All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
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.
22  *
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
35  * SUCH DAMAGE.
36  *
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''.
42  */
43
44 #ifndef lint
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";
47 #endif /* not lint */
48
49 #include "dhcpd.h"
50 #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
51 #include <sys/ioctl.h>
52 #include <sys/uio.h>
53
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"
61
62 static void lpf_gen_filter_setup PROTO ((struct interface_info *));
63 static void lpf_tr_filter_setup PROTO ((struct interface_info *));
64
65 /* Reinitializes the specified interface after an address change.   This
66    is not required for packet-filter APIs. */
67
68 #ifdef USE_LPF_SEND
69 void if_reinitialize_send (info)
70         struct interface_info *info;
71 {
72 }
73 #endif
74
75 #ifdef USE_LPF_RECEIVE
76 void if_reinitialize_receive (info)
77         struct interface_info *info;
78 {
79 }
80 #endif
81
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
84    mask. */
85
86 int if_register_lpf (info)
87         struct interface_info *info;
88 {
89         int sock;
90         char filename[50];
91         int b;
92         struct sockaddr sa;
93
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) {
99                         warn ("socket: %m");
100                         error ("Make sure to set %s %s!",
101                                "CONFIG_PACKET=y and CONFIG_FILTER=y",
102                                "in your kernel configuration");
103                 }
104                 error("Open a socket for LPF: %m");
105         }
106
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) {
115                         warn ("bind: %m");
116                         error ("Set %s %s!",
117                                "CONFIG_PACKET=y and CONFIG_FILTER=y",
118                                "in your kernel configuration");
119                 }
120                 error("Bind socket to interface: %m");
121         }
122
123         return sock;
124 }
125 #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
126
127 #ifdef USE_LPF_SEND
128 void if_register_send (info)
129         struct interface_info *info;
130 {
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);
135 #else
136         info -> wfdesc = info -> rfdesc;
137 #endif
138         if (!quiet_interface_discovery)
139                 note ("Sending on   LPF/%s/%s%s%s",
140                       info -> name,
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 : ""));
147 }
148 #endif /* USE_LPF_SEND */
149
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;
157
158 void if_register_receive (info)
159         struct interface_info *info;
160 {
161         /* Open a LPF device and hang it on this interface... */
162         info -> rfdesc = if_register_lpf (info);
163
164         if (info -> hw_address.htype == HTYPE_IEEE802)
165                 lpf_tr_filter_setup (info);
166         else
167                 lpf_gen_filter_setup (info);
168
169         if (!quiet_interface_discovery)
170                 note ("Listening on LPF/%s/%s%s%s",
171                       info -> name,
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 : ""));
178 }
179
180 static void lpf_gen_filter_setup (info)
181         struct interface_info *info;
182 {
183         struct sock_fprog p;
184
185         /* Set up the bpf filter program structure.    This is defined in
186            bpf.c */
187         p.len = dhcp_bpf_filter_len;
188         p.filter = dhcp_bpf_filter;
189
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);
194
195         if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
196                         sizeof p) < 0) {
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");
204         }
205 }
206
207 static void lpf_tr_filter_setup (info)
208         struct interface_info *info;
209 {
210         struct sock_fprog p;
211
212         /* Set up the bpf filter program structure.    This is defined in
213            bpf.c */
214         p.len = dhcp_bpf_tr_filter_len;
215         p.filter = dhcp_bpf_tr_filter;
216
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); */
223
224         if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
225                         sizeof p) < 0) {
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");
233         }
234 }
235 #endif /* USE_LPF_RECEIVE */
236
237 #ifdef USE_LPF_SEND
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;
242         size_t len;
243         struct in_addr from;
244         struct sockaddr_in *to;
245         struct hardware *hto;
246 {
247         int bufp = 0;
248         unsigned char buf [1500];
249         struct sockaddr sa;
250         int result;
251
252         if (!strcmp (interface -> name, "fallback"))
253                 return send_fallback (interface, packet, raw,
254                                       len, from, to, hto);
255
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);
262
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;
267         strncpy (sa.sa_data,
268                  (const char *)interface -> ifp, sizeof sa.sa_data);
269
270         result = sendto (interface -> wfdesc, buf, bufp + len, 0,
271                          &sa, sizeof sa);
272         if (result < 0)
273                 warn ("send_packet: %m");
274         return result;
275 }
276 #endif /* USE_LPF_SEND */
277
278 #ifdef USE_LPF_RECEIVE
279 ssize_t receive_packet (interface, buf, len, from, hfrom)
280         struct interface_info *interface;
281         unsigned char *buf;
282         size_t len;
283         struct sockaddr_in *from;
284         struct hardware *hfrom;
285 {
286         int nread;
287         int length = 0;
288         int offset = 0;
289         unsigned char ibuf [1500];
290         int bufix = 0;
291
292         length = read (interface -> rfdesc, ibuf, sizeof ibuf);
293         if (length <= 0)
294                 return length;
295
296         bufix = 0;
297         /* Decode the physical header... */
298         offset = decode_hw_header (interface, ibuf, bufix, hfrom);
299
300         /* If a physical layer checksum failed (dunno of any
301            physical layer that supports this, but WTH), skip this
302            packet. */
303         if (offset < 0) {
304                 return 0;
305         }
306
307         bufix += offset;
308         length -= offset;
309
310         /* Decode the IP and UDP headers... */
311         offset = decode_udp_ip_header (interface, ibuf, bufix,
312                                        from, (unsigned char *)0, length);
313
314         /* If the IP or UDP checksum was bad, skip the packet... */
315         if (offset < 0)
316                 return 0;
317
318         bufix += offset;
319         length -= offset;
320
321         /* Copy out the data in the packet... */
322         memcpy (buf, &ibuf [bufix], length);
323         return length;
324 }
325
326 int can_unicast_without_arp ()
327 {
328         return 1;
329 }
330
331 int can_receive_unicast_unconfigured (ip)
332         struct interface_info *ip;
333 {
334         return 1;
335 }
336
337 void maybe_setup_fallback ()
338 {
339         struct interface_info *fbi;
340         fbi = setup_fallback ();
341         if (fbi) {
342                 if_register_fallback (fbi);
343                 add_protocol ("fallback", fallback_interface -> wfdesc,
344                               fallback_discard, fallback_interface);
345         }
346 }
347 #endif