]>
Commit | Line | Data |
---|---|---|
179f54ab TL |
1 | /* upf.c |
2 | ||
2d1b06e0 | 3 | Ultrix PacketFilter interface code. */ |
179f54ab TL |
4 | |
5 | /* | |
49733f31 TL |
6 | * Copyright (c) 1996-2000 Internet Software Consortium. |
7 | * All rights reserved. | |
179f54ab | 8 | * |
49733f31 TL |
9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
179f54ab | 12 | * |
49733f31 TL |
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. | |
179f54ab | 21 | * |
49733f31 TL |
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 in cooperation with Vixie Enterprises and Nominum, Inc. | |
38 | * To learn more about the Internet Software Consortium, see | |
39 | * ``http://www.isc.org/''. To learn more about Vixie Enterprises, | |
40 | * see ``http://www.vix.com''. To learn more about Nominum, Inc., see | |
41 | * ``http://www.nominum.com''. | |
179f54ab TL |
42 | */ |
43 | ||
44 | #ifndef lint | |
45 | static char copyright[] = | |
49733f31 | 46 | "$Id: upf.c,v 1.17 2000/03/17 03:59:02 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n"; |
179f54ab TL |
47 | #endif /* not lint */ |
48 | ||
49 | #include "dhcpd.h" | |
50 | #if defined (USE_UPF_SEND) || defined (USE_UPF_RECEIVE) | |
51 | #include <sys/ioctl.h> | |
52 | #include <sys/uio.h> | |
53 | ||
54 | #include <net/pfilt.h> | |
55 | #include <netinet/in_systm.h> | |
56 | #include "includes/netinet/ip.h" | |
57 | #include "includes/netinet/udp.h" | |
58 | #include "includes/netinet/if_ether.h" | |
59 | ||
60 | /* Reinitializes the specified interface after an address change. This | |
61 | is not required for packet-filter APIs. */ | |
62 | ||
63 | #ifdef USE_UPF_SEND | |
64 | void if_reinitialize_send (info) | |
65 | struct interface_info *info; | |
66 | { | |
67 | } | |
68 | #endif | |
69 | ||
70 | #ifdef USE_UPF_RECEIVE | |
71 | void if_reinitialize_receive (info) | |
72 | struct interface_info *info; | |
73 | { | |
74 | } | |
75 | #endif | |
76 | ||
77 | /* Called by get_interface_list for each interface that's discovered. | |
78 | Opens a packet filter for each interface and adds it to the select | |
79 | mask. */ | |
80 | ||
81 | int if_register_upf (info) | |
82 | struct interface_info *info; | |
83 | { | |
84 | int sock; | |
85 | char filename[50]; | |
86 | int b; | |
87 | struct endevp param; | |
88 | ||
89 | /* Open a UPF device */ | |
90 | for (b = 0; 1; b++) { | |
91 | #ifndef NO_SNPRINTF | |
92 | snprintf(filename, sizeof(filename), "/dev/pf/pfilt%d", b); | |
93 | #else | |
94 | sprintf(filename, "/dev/pf/pfilt%d", b); | |
95 | #endif | |
96 | sock = open (filename, O_RDWR, 0); | |
97 | if (sock < 0) { | |
98 | if (errno == EBUSY) { | |
99 | continue; | |
100 | } else { | |
8ae2d595 | 101 | log_fatal ("Can't find free upf: %m"); |
179f54ab TL |
102 | } |
103 | } else { | |
104 | break; | |
105 | } | |
106 | } | |
107 | ||
108 | /* Set the UPF device to point at this interface. */ | |
109 | if (ioctl (sock, EIOCSETIF, info -> ifp) < 0) | |
8ae2d595 | 110 | log_fatal ("Can't attach interface %s to upf device %s: %m", |
179f54ab TL |
111 | info -> name, filename); |
112 | ||
113 | /* Get the hardware address. */ | |
114 | if (ioctl (sock, EIOCDEVP, ¶m) < 0) | |
8ae2d595 | 115 | log_fatal ("Can't get interface %s hardware address: %m", |
179f54ab TL |
116 | info -> name); |
117 | ||
118 | /* We only know how to do ethernet. */ | |
119 | if (param.end_dev_type != ENDT_10MB) | |
8ae2d595 | 120 | log_fatal ("Invalid device type on network interface %s: %d", |
179f54ab TL |
121 | info -> name, param.end_dev_type); |
122 | ||
123 | if (param.end_addr_len != 6) | |
8ae2d595 | 124 | log_fatal ("Invalid hardware address length on %s: %d", |
179f54ab TL |
125 | info -> name, param.end_addr_len); |
126 | ||
218eee75 TL |
127 | info -> hw_address.hlen = 7; |
128 | info -> hw_address.hbuf [0] = ARPHRD_ETHER; | |
129 | memcpy (&info -> hw_address.hbuf [1], param.end_addr, 6); | |
179f54ab TL |
130 | |
131 | return sock; | |
132 | } | |
133 | #endif /* USE_UPF_SEND || USE_UPF_RECEIVE */ | |
134 | ||
135 | #ifdef USE_UPF_SEND | |
136 | void if_register_send (info) | |
137 | struct interface_info *info; | |
138 | { | |
139 | /* If we're using the upf API for sending and receiving, | |
140 | we don't need to register this interface twice. */ | |
141 | #ifndef USE_UPF_RECEIVE | |
142 | info -> wfdesc = if_register_upf (info, interface); | |
143 | #else | |
144 | info -> wfdesc = info -> rfdesc; | |
145 | #endif | |
3648a2a1 | 146 | if (!quiet_interface_discovery) |
74f45f96 | 147 | log_info ("Sending on UPF/%s/%s%s%s", |
3648a2a1 | 148 | info -> name, |
218eee75 TL |
149 | print_hw_addr (info -> hw_address.hbuf [0], |
150 | info -> hw_address.hlen - 1, | |
151 | &info -> hw_address.hbuf [1]), | |
74f45f96 | 152 | (info -> shared_network ? "/" : ""), |
3648a2a1 | 153 | (info -> shared_network ? |
74f45f96 | 154 | info -> shared_network -> name : "")); |
179f54ab | 155 | } |
7203e8ee TL |
156 | |
157 | void if_deregister_send (info) | |
158 | struct interface_info *info; | |
159 | { | |
160 | #ifndef USE_UPF_RECEIVE | |
161 | close (info -> wfdesc); | |
162 | #endif | |
163 | info -> wfdesc = -1; | |
164 | if (!quiet_interface_discovery) | |
165 | log_info ("Disabling output on UPF/%s/%s%s%s", | |
166 | info -> name, | |
167 | print_hw_addr (info -> hw_address.hbuf [0], | |
168 | info -> hw_address.hlen - 1, | |
169 | &info -> hw_address.hbuf [1]), | |
170 | (info -> shared_network ? "/" : ""), | |
171 | (info -> shared_network ? | |
172 | info -> shared_network -> name : "")); | |
173 | } | |
179f54ab TL |
174 | #endif /* USE_UPF_SEND */ |
175 | ||
176 | #ifdef USE_UPF_RECEIVE | |
177 | /* Packet filter program... | |
178 | XXX Changes to the filter program may require changes to the constant | |
179 | offsets used in if_register_send to patch the UPF program! XXX */ | |
180 | ||
181 | ||
182 | void if_register_receive (info) | |
183 | struct interface_info *info; | |
184 | { | |
185 | int flag = 1; | |
186 | u_int32_t addr; | |
187 | struct enfilter pf; | |
188 | u_int32_t bits; | |
189 | ||
190 | /* Open a UPF device and hang it on this interface... */ | |
191 | info -> rfdesc = if_register_upf (info); | |
192 | ||
193 | /* Allow the copyall flag to be set... */ | |
194 | if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0) | |
8ae2d595 | 195 | log_fatal ("Can't set ALLOWCOPYALL: %m"); |
179f54ab TL |
196 | |
197 | /* Clear all the packet filter mode bits first... */ | |
198 | flag = (ENHOLDSIG | ENBATCH | ENTSTAMP | ENPROMISC | | |
199 | ENNONEXCL | ENCOPYALL); | |
200 | if (ioctl (info -> rfdesc, EIOCMBIC, &flag) < 0) | |
8ae2d595 | 201 | log_fatal ("Can't clear pfilt bits: %m"); |
179f54ab TL |
202 | |
203 | /* Set the ENBATCH and ENCOPYALL bits... */ | |
204 | bits = ENBATCH | ENCOPYALL; | |
205 | if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) | |
8ae2d595 | 206 | log_fatal ("Can't set ENBATCH|ENCOPYALL: %m"); |
179f54ab TL |
207 | |
208 | /* Set up the UPF filter program. */ | |
209 | /* XXX Unlike the BPF filter program, this one won't work if the | |
210 | XXX IP packet is fragmented or if there are options on the IP | |
211 | XXX header. */ | |
212 | pf.enf_Priority = 0; | |
213 | pf.enf_FilterLen = 0; | |
214 | ||
215 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 6; | |
216 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND; | |
217 | pf.enf_Filter [pf.enf_FilterLen++] = htons (ETHERTYPE_IP); | |
218 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT; | |
219 | pf.enf_Filter [pf.enf_FilterLen++] = htons (IPPROTO_UDP); | |
220 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 11; | |
221 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_AND; | |
222 | pf.enf_Filter [pf.enf_FilterLen++] = htons (0xFF); | |
223 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_CAND; | |
224 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 18; | |
225 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND; | |
226 | pf.enf_Filter [pf.enf_FilterLen++] = local_port; | |
227 | ||
228 | if (ioctl (info -> rfdesc, EIOCSETF, &pf) < 0) | |
8ae2d595 | 229 | log_fatal ("Can't install packet filter program: %m"); |
3648a2a1 | 230 | if (!quiet_interface_discovery) |
74f45f96 | 231 | log_info ("Listening on UPF/%s/%s%s%s", |
3648a2a1 | 232 | info -> name, |
218eee75 TL |
233 | print_hw_addr (info -> hw_address.hbuf [0], |
234 | info -> hw_address.hlen - 1, | |
235 | &info -> hw_address.hbuf [1]), | |
74f45f96 | 236 | (info -> shared_network ? "/" : ""), |
3648a2a1 | 237 | (info -> shared_network ? |
74f45f96 | 238 | info -> shared_network -> name : "")); |
179f54ab | 239 | } |
7203e8ee TL |
240 | |
241 | void if_deregister_receive (info) | |
242 | struct interface_info *info; | |
243 | { | |
244 | close (info -> rfdesc); | |
245 | info -> rfdesc = -1; | |
246 | if (!quiet_interface_discovery) | |
247 | log_info ("Disabling input on UPF/%s/%s%s%s", | |
248 | info -> name, | |
249 | print_hw_addr (info -> hw_address.hbuf [0], | |
250 | info -> hw_address.hlen - 1, | |
251 | &info -> hw_address.hbuf [1]), | |
252 | (info -> shared_network ? "/" : ""), | |
253 | (info -> shared_network ? | |
254 | info -> shared_network -> name : "")); | |
255 | } | |
179f54ab TL |
256 | #endif /* USE_UPF_RECEIVE */ |
257 | ||
258 | #ifdef USE_UPF_SEND | |
4595a58c | 259 | ssize_t send_packet (interface, packet, raw, len, from, to, hto) |
179f54ab TL |
260 | struct interface_info *interface; |
261 | struct packet *packet; | |
262 | struct dhcp_packet *raw; | |
263 | size_t len; | |
264 | struct in_addr from; | |
265 | struct sockaddr_in *to; | |
266 | struct hardware *hto; | |
267 | { | |
8ca11339 | 268 | unsigned bufp = 0; |
179f54ab TL |
269 | unsigned char buf [256]; |
270 | struct iovec iov [2]; | |
74f45f96 | 271 | int result; |
179f54ab | 272 | |
d2bc90bd TL |
273 | if (!strcmp (interface -> name, "fallback")) |
274 | return send_fallback (interface, packet, raw, | |
275 | len, from, to, hto); | |
276 | ||
179f54ab TL |
277 | /* Assemble the headers... */ |
278 | assemble_hw_header (interface, buf, &bufp, hto); | |
279 | assemble_udp_ip_header (interface, buf, &bufp, from.s_addr, | |
280 | to -> sin_addr.s_addr, to -> sin_port, | |
281 | (unsigned char *)raw, len); | |
282 | ||
283 | /* Fire it off */ | |
284 | iov [0].iov_base = (char *)buf; | |
285 | iov [0].iov_len = bufp; | |
286 | iov [1].iov_base = (char *)raw; | |
287 | iov [1].iov_len = len; | |
288 | ||
74f45f96 TL |
289 | result = writev(interface -> wfdesc, iov, 2); |
290 | if (result < 0) | |
c5b0f529 | 291 | log_error ("send_packet: %m"); |
74f45f96 | 292 | return result; |
179f54ab TL |
293 | } |
294 | #endif /* USE_UPF_SEND */ | |
295 | ||
296 | #ifdef USE_UPF_RECEIVE | |
4595a58c | 297 | ssize_t receive_packet (interface, buf, len, from, hfrom) |
179f54ab TL |
298 | struct interface_info *interface; |
299 | unsigned char *buf; | |
300 | size_t len; | |
301 | struct sockaddr_in *from; | |
302 | struct hardware *hfrom; | |
303 | { | |
304 | int nread; | |
305 | int length = 0; | |
306 | int offset = 0; | |
307 | unsigned char ibuf [1500 + sizeof (struct enstamp)]; | |
308 | int bufix = 0; | |
309 | ||
310 | length = read (interface -> rfdesc, ibuf, sizeof ibuf); | |
311 | if (length <= 0) | |
312 | return length; | |
313 | ||
314 | bufix = sizeof (struct enstamp); | |
315 | /* Decode the physical header... */ | |
316 | offset = decode_hw_header (interface, ibuf, bufix, hfrom); | |
317 | ||
318 | /* If a physical layer checksum failed (dunno of any | |
319 | physical layer that supports this, but WTH), skip this | |
320 | packet. */ | |
321 | if (offset < 0) { | |
322 | return 0; | |
323 | } | |
324 | ||
325 | bufix += offset; | |
326 | length -= offset; | |
327 | ||
328 | /* Decode the IP and UDP headers... */ | |
329 | offset = decode_udp_ip_header (interface, ibuf, bufix, | |
330 | from, (unsigned char *)0, length); | |
331 | ||
332 | /* If the IP or UDP checksum was bad, skip the packet... */ | |
333 | if (offset < 0) | |
334 | return 0; | |
335 | ||
336 | bufix += offset; | |
337 | length -= offset; | |
338 | ||
339 | /* Copy out the data in the packet... */ | |
340 | memcpy (buf, &ibuf [bufix], length); | |
341 | return length; | |
342 | } | |
d2bc90bd | 343 | |
21d21e91 TL |
344 | int can_unicast_without_arp (ip) |
345 | struct interface_info *ip; | |
d2bc90bd TL |
346 | { |
347 | return 1; | |
348 | } | |
349 | ||
21d21e91 TL |
350 | int can_receive_unicast_unconfigured (ip) |
351 | struct interface_info *ip; | |
b547818b TL |
352 | { |
353 | return 1; | |
354 | } | |
355 | ||
d2bc90bd TL |
356 | void maybe_setup_fallback () |
357 | { | |
acc21512 | 358 | isc_result_t status; |
d2bc90bd TL |
359 | struct interface_info *fbi; |
360 | fbi = setup_fallback (); | |
361 | if (fbi) { | |
362 | if_register_fallback (fbi); | |
acc21512 TL |
363 | fbi -> refcnt = 1; |
364 | fbi -> type = dhcp_type_interface; | |
e92653f1 | 365 | status = omapi_register_io_object ((omapi_object_t *)fbi, |
acc21512 TL |
366 | if_readsocket, 0, |
367 | fallback_discard, 0, 0); | |
368 | if (status != ISC_R_SUCCESS) | |
369 | log_fatal ("Can't register I/O handle for %s: %s", | |
370 | fbi -> name, isc_result_totext (status)); | |
d2bc90bd TL |
371 | } |
372 | } | |
179f54ab | 373 | #endif |