]> git.ipfire.org Git - thirdparty/dhcp.git/blob - common/upf.c
Pull up recent 2.0 changes.
[thirdparty/dhcp.git] / common / upf.c
1 /* upf.c
2
3 Ultrix PacketFilter interface code.
4
5 /*
6 * Copyright (c) 1995, 1996, 1997, 1998, 1999
7 * The Internet Software Consortium. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38 * Enterprises. To learn more about the Internet Software Consortium,
39 * see ``http://www.vix.com/isc''. To learn more about Vixie
40 * Enterprises, see ``http://www.vix.com''.
41 */
42
43 #ifndef lint
44 static char copyright[] =
45 "$Id: upf.c,v 1.4 1999/02/14 18:57:19 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
46 #endif /* not lint */
47
48 #include "dhcpd.h"
49 #if defined (USE_UPF_SEND) || defined (USE_UPF_RECEIVE)
50 #include <sys/ioctl.h>
51 #include <sys/uio.h>
52
53 #include <net/pfilt.h>
54 #include <netinet/in_systm.h>
55 #include "includes/netinet/ip.h"
56 #include "includes/netinet/udp.h"
57 #include "includes/netinet/if_ether.h"
58
59 /* Reinitializes the specified interface after an address change. This
60 is not required for packet-filter APIs. */
61
62 #ifdef USE_UPF_SEND
63 void if_reinitialize_send (info)
64 struct interface_info *info;
65 {
66 }
67 #endif
68
69 #ifdef USE_UPF_RECEIVE
70 void if_reinitialize_receive (info)
71 struct interface_info *info;
72 {
73 }
74 #endif
75
76 /* Called by get_interface_list for each interface that's discovered.
77 Opens a packet filter for each interface and adds it to the select
78 mask. */
79
80 int if_register_upf (info)
81 struct interface_info *info;
82 {
83 int sock;
84 char filename[50];
85 int b;
86 struct endevp param;
87
88 /* Open a UPF device */
89 for (b = 0; 1; b++) {
90 #ifndef NO_SNPRINTF
91 snprintf(filename, sizeof(filename), "/dev/pf/pfilt%d", b);
92 #else
93 sprintf(filename, "/dev/pf/pfilt%d", b);
94 #endif
95 sock = open (filename, O_RDWR, 0);
96 if (sock < 0) {
97 if (errno == EBUSY) {
98 continue;
99 } else {
100 error ("Can't find free upf: %m");
101 }
102 } else {
103 break;
104 }
105 }
106
107 /* Set the UPF device to point at this interface. */
108 if (ioctl (sock, EIOCSETIF, info -> ifp) < 0)
109 error ("Can't attach interface %s to upf device %s: %m",
110 info -> name, filename);
111
112 /* Get the hardware address. */
113 if (ioctl (sock, EIOCDEVP, &param) < 0)
114 error ("Can't get interface %s hardware address: %m",
115 info -> name);
116
117 /* We only know how to do ethernet. */
118 if (param.end_dev_type != ENDT_10MB)
119 error ("Invalid device type on network interface %s: %d",
120 info -> name, param.end_dev_type);
121
122 if (param.end_addr_len != 6)
123 error ("Invalid hardware address length on %s: %d",
124 info -> name, param.end_addr_len);
125
126 info -> hw_address.hlen = 6;
127 info -> hw_address.htype = ARPHRD_ETHER;
128 memcpy (&info -> hw_address.haddr [0], param.end_addr, 6);
129
130 return sock;
131 }
132 #endif /* USE_UPF_SEND || USE_UPF_RECEIVE */
133
134 #ifdef USE_UPF_SEND
135 void if_register_send (info)
136 struct interface_info *info;
137 {
138 /* If we're using the upf API for sending and receiving,
139 we don't need to register this interface twice. */
140 #ifndef USE_UPF_RECEIVE
141 info -> wfdesc = if_register_upf (info, interface);
142 #else
143 info -> wfdesc = info -> rfdesc;
144 #endif
145 if (!quiet_interface_discovery)
146 note ("Sending on UPF/%s/%s/%s",
147 info -> name,
148 print_hw_addr (info -> hw_address.htype,
149 info -> hw_address.hlen,
150 info -> hw_address.haddr),
151 (info -> shared_network ?
152 info -> shared_network -> name : "unattached"));
153 }
154 #endif /* USE_UPF_SEND */
155
156 #ifdef USE_UPF_RECEIVE
157 /* Packet filter program...
158 XXX Changes to the filter program may require changes to the constant
159 offsets used in if_register_send to patch the UPF program! XXX */
160
161
162 void if_register_receive (info)
163 struct interface_info *info;
164 {
165 int flag = 1;
166 u_int32_t addr;
167 struct enfilter pf;
168 u_int32_t bits;
169
170 /* Open a UPF device and hang it on this interface... */
171 info -> rfdesc = if_register_upf (info);
172
173 /* Allow the copyall flag to be set... */
174 if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0)
175 error ("Can't set ALLOWCOPYALL: %m");
176
177 /* Clear all the packet filter mode bits first... */
178 flag = (ENHOLDSIG | ENBATCH | ENTSTAMP | ENPROMISC |
179 ENNONEXCL | ENCOPYALL);
180 if (ioctl (info -> rfdesc, EIOCMBIC, &flag) < 0)
181 error ("Can't clear pfilt bits: %m");
182
183 /* Set the ENBATCH and ENCOPYALL bits... */
184 bits = ENBATCH | ENCOPYALL;
185 if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
186 error ("Can't set ENBATCH|ENCOPYALL: %m");
187
188 /* Set up the UPF filter program. */
189 /* XXX Unlike the BPF filter program, this one won't work if the
190 XXX IP packet is fragmented or if there are options on the IP
191 XXX header. */
192 pf.enf_Priority = 0;
193 pf.enf_FilterLen = 0;
194
195 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 6;
196 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
197 pf.enf_Filter [pf.enf_FilterLen++] = htons (ETHERTYPE_IP);
198 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT;
199 pf.enf_Filter [pf.enf_FilterLen++] = htons (IPPROTO_UDP);
200 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 11;
201 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_AND;
202 pf.enf_Filter [pf.enf_FilterLen++] = htons (0xFF);
203 pf.enf_Filter [pf.enf_FilterLen++] = ENF_CAND;
204 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 18;
205 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
206 pf.enf_Filter [pf.enf_FilterLen++] = local_port;
207
208 if (ioctl (info -> rfdesc, EIOCSETF, &pf) < 0)
209 error ("Can't install packet filter program: %m");
210 if (!quiet_interface_discovery)
211 note ("Listening on UPF/%s/%s/%s",
212 info -> name,
213 print_hw_addr (info -> hw_address.htype,
214 info -> hw_address.hlen,
215 info -> hw_address.haddr),
216 (info -> shared_network ?
217 info -> shared_network -> name : "unattached"));
218 }
219 #endif /* USE_UPF_RECEIVE */
220
221 #ifdef USE_UPF_SEND
222 ssize_t send_packet (interface, packet, raw, len, from, to, hto)
223 struct interface_info *interface;
224 struct packet *packet;
225 struct dhcp_packet *raw;
226 size_t len;
227 struct in_addr from;
228 struct sockaddr_in *to;
229 struct hardware *hto;
230 {
231 int bufp = 0;
232 unsigned char buf [256];
233 struct iovec iov [2];
234
235 if (!strcmp (interface -> name, "fallback"))
236 return send_fallback (interface, packet, raw,
237 len, from, to, hto);
238
239 /* Assemble the headers... */
240 assemble_hw_header (interface, buf, &bufp, hto);
241 assemble_udp_ip_header (interface, buf, &bufp, from.s_addr,
242 to -> sin_addr.s_addr, to -> sin_port,
243 (unsigned char *)raw, len);
244
245 /* Fire it off */
246 iov [0].iov_base = (char *)buf;
247 iov [0].iov_len = bufp;
248 iov [1].iov_base = (char *)raw;
249 iov [1].iov_len = len;
250
251 return writev(interface -> wfdesc, iov, 2);
252 }
253 #endif /* USE_UPF_SEND */
254
255 #ifdef USE_UPF_RECEIVE
256 ssize_t receive_packet (interface, buf, len, from, hfrom)
257 struct interface_info *interface;
258 unsigned char *buf;
259 size_t len;
260 struct sockaddr_in *from;
261 struct hardware *hfrom;
262 {
263 int nread;
264 int length = 0;
265 int offset = 0;
266 unsigned char ibuf [1500 + sizeof (struct enstamp)];
267 int bufix = 0;
268
269 length = read (interface -> rfdesc, ibuf, sizeof ibuf);
270 if (length <= 0)
271 return length;
272
273 bufix = sizeof (struct enstamp);
274 /* Decode the physical header... */
275 offset = decode_hw_header (interface, ibuf, bufix, hfrom);
276
277 /* If a physical layer checksum failed (dunno of any
278 physical layer that supports this, but WTH), skip this
279 packet. */
280 if (offset < 0) {
281 return 0;
282 }
283
284 bufix += offset;
285 length -= offset;
286
287 /* Decode the IP and UDP headers... */
288 offset = decode_udp_ip_header (interface, ibuf, bufix,
289 from, (unsigned char *)0, length);
290
291 /* If the IP or UDP checksum was bad, skip the packet... */
292 if (offset < 0)
293 return 0;
294
295 bufix += offset;
296 length -= offset;
297
298 /* Copy out the data in the packet... */
299 memcpy (buf, &ibuf [bufix], length);
300 return length;
301 }
302
303 int can_unicast_without_arp ()
304 {
305 return 1;
306 }
307
308 void maybe_setup_fallback ()
309 {
310 struct interface_info *fbi;
311 fbi = setup_fallback ();
312 if (fbi) {
313 if_register_fallback (fbi);
314 add_protocol ("fallback", fallback_interface -> wfdesc,
315 fallback_discard, fallback_interface);
316 }
317 }
318 #endif