Merge from vendor branch GCC:
[dragonfly.git] / contrib / dhcp-3.0 / 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) 2004 by Internet Systems Consortium, Inc. ("ISC")
8  * Copyright (c) 1996-2003 by Internet Software Consortium
9  *
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.
13  *
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.
21  *
22  *   Internet Systems Consortium, Inc.
23  *   950 Charter Street
24  *   Redwood City, CA 94063
25  *   <info@isc.org>
26  *   http://www.isc.org/
27  */
28
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 */
33
34 #include "dhcpd.h"
35 #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
36 #include <sys/ioctl.h>
37 #include <sys/uio.h>
38
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"
46
47 /* Reinitializes the specified interface after an address change.   This
48    is not required for packet-filter APIs. */
49
50 #ifdef USE_LPF_SEND
51 void if_reinitialize_send (info)
52         struct interface_info *info;
53 {
54 }
55 #endif
56
57 #ifdef USE_LPF_RECEIVE
58 void if_reinitialize_receive (info)
59         struct interface_info *info;
60 {
61 }
62 #endif
63
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. */
67
68 int if_register_lpf (info)
69         struct interface_info *info;
70 {
71         int sock;
72         char filename[50];
73         int b;
74         struct sockaddr sa;
75
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!");
88                 }
89                 log_fatal ("Open a socket for LPF: %m");
90         }
91
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!");
106                 }
107                 log_fatal ("Bind socket to interface: %m");
108         }
109
110         return sock;
111 }
112 #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
113
114 #ifdef USE_LPF_SEND
115 void if_register_send (info)
116         struct interface_info *info;
117 {
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 : ""));
134 }
135
136 void if_deregister_send (info)
137         struct interface_info *info;
138 {
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 : ""));
156 }
157 #endif /* USE_LPF_SEND */
158
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;
164
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
170
171 static void lpf_gen_filter_setup (struct interface_info *);
172
173 void if_register_receive (info)
174         struct interface_info *info;
175 {
176         /* Open a LPF device and hang it on this interface... */
177         info -> rfdesc = if_register_lpf (info);
178
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);
185
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 : ""));
195 }
196
197 void if_deregister_receive (info)
198         struct interface_info *info;
199 {
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 : ""));
213 }
214
215 static void lpf_gen_filter_setup (info)
216         struct interface_info *info;
217 {
218         struct sock_fprog p;
219
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;
224
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);
229
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!");
241                 }
242                 log_fatal ("Can't install packet filter program: %m");
243         }
244 }
245
246 #if defined (HAVE_TR_SUPPORT)
247 static void lpf_tr_filter_setup (info)
248         struct interface_info *info;
249 {
250         struct sock_fprog p;
251
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;
256
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); */
263
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!");
275                 }
276                 log_fatal ("Can't install packet filter program: %m");
277         }
278 }
279 #endif /* HAVE_TR_SUPPORT */
280 #endif /* USE_LPF_RECEIVE */
281
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;
291 {
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;
299
300         if (!strcmp (interface -> name, "fallback"))
301                 return send_fallback (interface, packet, raw,
302                                       len, from, to, hto);
303
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);
313
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);
320
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;
326 }
327 #endif /* USE_LPF_SEND */
328
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;
336 {
337         int nread;
338         int length = 0;
339         int offset = 0;
340         unsigned char ibuf [1536];
341         unsigned bufix = 0;
342
343         length = read (interface -> rfdesc, ibuf, sizeof ibuf);
344         if (length <= 0)
345                 return length;
346
347         bufix = 0;
348         /* Decode the physical header... */
349         offset = decode_hw_header (interface, ibuf, bufix, hfrom);
350
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;
356         }
357
358         bufix += offset;
359         length -= offset;
360
361         /* Decode the IP and UDP headers... */
362         offset = decode_udp_ip_header (interface, ibuf, bufix, from,
363                                        (unsigned)length);
364
365         /* If the IP or UDP checksum was bad, skip the packet... */
366         if (offset < 0)
367                 return 0;
368
369         bufix += offset;
370         length -= offset;
371
372         /* Copy out the data in the packet... */
373         memcpy (buf, &ibuf [bufix], length);
374         return length;
375 }
376
377 int can_unicast_without_arp (ip)
378         struct interface_info *ip;
379 {
380         return 1;
381 }
382
383 int can_receive_unicast_unconfigured (ip)
384         struct interface_info *ip;
385 {
386         return 1;
387 }
388
389 int supports_multiple_interfaces (ip)
390         struct interface_info *ip;
391 {
392         return 1;
393 }
394
395 void maybe_setup_fallback ()
396 {
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);
408         }
409 }
410 #endif