]> git.ipfire.org Git - thirdparty/dhcp.git/blame - common/upf.c
copy rights update
[thirdparty/dhcp.git] / common / upf.c
CommitLineData
179f54ab
TL
1/* upf.c
2
2d1b06e0 3 Ultrix PacketFilter interface code. */
179f54ab
TL
4
5/*
49a7fb58 6 * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
98311e4b 7 * Copyright (c) 1996-2003 by Internet Software Consortium
179f54ab 8 *
7512d88b
TM
9 * This Source Code Form is subject to the terms of the Mozilla Public
10 * License, v. 2.0. If a copy of the MPL was not distributed with this
11 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
179f54ab 12 *
98311e4b
DH
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
179f54ab 20 *
98311e4b 21 * Internet Systems Consortium, Inc.
429a56d7
TM
22 * PO Box 360
23 * Newmarket, NH 03857 USA
98311e4b 24 * <info@isc.org>
2c85ac9b 25 * https://www.isc.org/
49733f31 26 *
179f54ab
TL
27 */
28
179f54ab
TL
29#include "dhcpd.h"
30#if defined (USE_UPF_SEND) || defined (USE_UPF_RECEIVE)
31#include <sys/ioctl.h>
32#include <sys/uio.h>
33
34#include <net/pfilt.h>
35#include <netinet/in_systm.h>
36#include "includes/netinet/ip.h"
37#include "includes/netinet/udp.h"
38#include "includes/netinet/if_ether.h"
39
40/* Reinitializes the specified interface after an address change. This
41 is not required for packet-filter APIs. */
42
43#ifdef USE_UPF_SEND
44void if_reinitialize_send (info)
45 struct interface_info *info;
46{
47}
48#endif
49
50#ifdef USE_UPF_RECEIVE
51void if_reinitialize_receive (info)
52 struct interface_info *info;
53{
54}
55#endif
56
57/* Called by get_interface_list for each interface that's discovered.
58 Opens a packet filter for each interface and adds it to the select
59 mask. */
60
61int if_register_upf (info)
62 struct interface_info *info;
63{
64 int sock;
65 char filename[50];
66 int b;
67 struct endevp param;
68
69 /* Open a UPF device */
70 for (b = 0; 1; b++) {
98311e4b 71 /* %Audit% Cannot exceed 36 bytes. %2004.06.17,Safe% */
179f54ab 72 sprintf(filename, "/dev/pf/pfilt%d", b);
98311e4b 73
179f54ab
TL
74 sock = open (filename, O_RDWR, 0);
75 if (sock < 0) {
76 if (errno == EBUSY) {
77 continue;
78 } else {
8ae2d595 79 log_fatal ("Can't find free upf: %m");
179f54ab
TL
80 }
81 } else {
82 break;
83 }
84 }
85
86 /* Set the UPF device to point at this interface. */
87 if (ioctl (sock, EIOCSETIF, info -> ifp) < 0)
8ae2d595 88 log_fatal ("Can't attach interface %s to upf device %s: %m",
179f54ab
TL
89 info -> name, filename);
90
91 /* Get the hardware address. */
92 if (ioctl (sock, EIOCDEVP, &param) < 0)
8ae2d595 93 log_fatal ("Can't get interface %s hardware address: %m",
179f54ab
TL
94 info -> name);
95
96 /* We only know how to do ethernet. */
f6b8f48d 97 if (param.end_dev_type != ENDT_10MB)
8ae2d595 98 log_fatal ("Invalid device type on network interface %s: %d",
179f54ab
TL
99 info -> name, param.end_dev_type);
100
101 if (param.end_addr_len != 6)
8ae2d595 102 log_fatal ("Invalid hardware address length on %s: %d",
179f54ab
TL
103 info -> name, param.end_addr_len);
104
218eee75
TL
105 info -> hw_address.hlen = 7;
106 info -> hw_address.hbuf [0] = ARPHRD_ETHER;
107 memcpy (&info -> hw_address.hbuf [1], param.end_addr, 6);
179f54ab
TL
108
109 return sock;
110}
111#endif /* USE_UPF_SEND || USE_UPF_RECEIVE */
112
113#ifdef USE_UPF_SEND
114void if_register_send (info)
115 struct interface_info *info;
116{
117 /* If we're using the upf API for sending and receiving,
118 we don't need to register this interface twice. */
119#ifndef USE_UPF_RECEIVE
120 info -> wfdesc = if_register_upf (info, interface);
121#else
122 info -> wfdesc = info -> rfdesc;
123#endif
3648a2a1 124 if (!quiet_interface_discovery)
74f45f96 125 log_info ("Sending on UPF/%s/%s%s%s",
3648a2a1 126 info -> name,
218eee75
TL
127 print_hw_addr (info -> hw_address.hbuf [0],
128 info -> hw_address.hlen - 1,
129 &info -> hw_address.hbuf [1]),
74f45f96 130 (info -> shared_network ? "/" : ""),
3648a2a1 131 (info -> shared_network ?
74f45f96 132 info -> shared_network -> name : ""));
179f54ab 133}
7203e8ee
TL
134
135void if_deregister_send (info)
136 struct interface_info *info;
137{
138#ifndef USE_UPF_RECEIVE
139 close (info -> wfdesc);
140#endif
141 info -> wfdesc = -1;
142 if (!quiet_interface_discovery)
143 log_info ("Disabling output on UPF/%s/%s%s%s",
144 info -> name,
145 print_hw_addr (info -> hw_address.hbuf [0],
146 info -> hw_address.hlen - 1,
147 &info -> hw_address.hbuf [1]),
148 (info -> shared_network ? "/" : ""),
149 (info -> shared_network ?
150 info -> shared_network -> name : ""));
151}
179f54ab
TL
152#endif /* USE_UPF_SEND */
153
154#ifdef USE_UPF_RECEIVE
155/* Packet filter program...
156 XXX Changes to the filter program may require changes to the constant
157 offsets used in if_register_send to patch the UPF program! XXX */
158
563f0b8a
FD
159#if defined(RELAY_PORT)
160#error "Relay port is not yet supported for UPF"
161#endif
179f54ab
TL
162
163void if_register_receive (info)
164 struct interface_info *info;
165{
166 int flag = 1;
167 u_int32_t addr;
168 struct enfilter pf;
169 u_int32_t bits;
170
171 /* Open a UPF device and hang it on this interface... */
172 info -> rfdesc = if_register_upf (info);
173
174 /* Allow the copyall flag to be set... */
175 if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0)
8ae2d595 176 log_fatal ("Can't set ALLOWCOPYALL: %m");
179f54ab
TL
177
178 /* Clear all the packet filter mode bits first... */
179 flag = (ENHOLDSIG | ENBATCH | ENTSTAMP | ENPROMISC |
180 ENNONEXCL | ENCOPYALL);
181 if (ioctl (info -> rfdesc, EIOCMBIC, &flag) < 0)
8ae2d595 182 log_fatal ("Can't clear pfilt bits: %m");
179f54ab
TL
183
184 /* Set the ENBATCH and ENCOPYALL bits... */
185 bits = ENBATCH | ENCOPYALL;
186 if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
8ae2d595 187 log_fatal ("Can't set ENBATCH|ENCOPYALL: %m");
179f54ab
TL
188
189 /* Set up the UPF filter program. */
190 /* XXX Unlike the BPF filter program, this one won't work if the
191 XXX IP packet is fragmented or if there are options on the IP
192 XXX header. */
193 pf.enf_Priority = 0;
194 pf.enf_FilterLen = 0;
195
196 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 6;
197 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
198 pf.enf_Filter [pf.enf_FilterLen++] = htons (ETHERTYPE_IP);
199 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT;
200 pf.enf_Filter [pf.enf_FilterLen++] = htons (IPPROTO_UDP);
201 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 11;
202 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_AND;
203 pf.enf_Filter [pf.enf_FilterLen++] = htons (0xFF);
204 pf.enf_Filter [pf.enf_FilterLen++] = ENF_CAND;
205 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 18;
206 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
207 pf.enf_Filter [pf.enf_FilterLen++] = local_port;
208
209 if (ioctl (info -> rfdesc, EIOCSETF, &pf) < 0)
8ae2d595 210 log_fatal ("Can't install packet filter program: %m");
3648a2a1 211 if (!quiet_interface_discovery)
74f45f96 212 log_info ("Listening on UPF/%s/%s%s%s",
3648a2a1 213 info -> name,
218eee75
TL
214 print_hw_addr (info -> hw_address.hbuf [0],
215 info -> hw_address.hlen - 1,
216 &info -> hw_address.hbuf [1]),
74f45f96 217 (info -> shared_network ? "/" : ""),
3648a2a1 218 (info -> shared_network ?
74f45f96 219 info -> shared_network -> name : ""));
179f54ab 220}
7203e8ee
TL
221
222void if_deregister_receive (info)
223 struct interface_info *info;
224{
225 close (info -> rfdesc);
226 info -> rfdesc = -1;
227 if (!quiet_interface_discovery)
228 log_info ("Disabling input on UPF/%s/%s%s%s",
229 info -> name,
230 print_hw_addr (info -> hw_address.hbuf [0],
231 info -> hw_address.hlen - 1,
232 &info -> hw_address.hbuf [1]),
233 (info -> shared_network ? "/" : ""),
234 (info -> shared_network ?
235 info -> shared_network -> name : ""));
236}
179f54ab
TL
237#endif /* USE_UPF_RECEIVE */
238
239#ifdef USE_UPF_SEND
4595a58c 240ssize_t send_packet (interface, packet, raw, len, from, to, hto)
179f54ab
TL
241 struct interface_info *interface;
242 struct packet *packet;
243 struct dhcp_packet *raw;
244 size_t len;
245 struct in_addr from;
246 struct sockaddr_in *to;
247 struct hardware *hto;
248{
6ceb9118
TL
249 unsigned hbufp = 0, ibufp = 0;
250 double hw [4];
251 double ip [32];
252 struct iovec iov [3];
74f45f96 253 int result;
6ceb9118 254 int fudge;
179f54ab 255
d2bc90bd
TL
256 if (!strcmp (interface -> name, "fallback"))
257 return send_fallback (interface, packet, raw,
258 len, from, to, hto);
259
0829d595
DH
260 if (hto == NULL && interface->anycast_mac_addr.hlen)
261 hto = &interface->anycast_mac_addr;
262
179f54ab 263 /* Assemble the headers... */
6ceb9118
TL
264 assemble_hw_header (interface, (unsigned char *)hw, &hbufp, hto);
265 assemble_udp_ip_header (interface,
266 (unsigned char *)ip, &ibufp, from.s_addr,
179f54ab
TL
267 to -> sin_addr.s_addr, to -> sin_port,
268 (unsigned char *)raw, len);
269
270 /* Fire it off */
6ceb9118
TL
271 iov [0].iov_base = ((char *)hw);
272 iov [0].iov_len = hbufp;
273 iov [1].iov_base = ((char *)ip);
274 iov [1].iov_len = ibufp;
275 iov [2].iov_base = (char *)raw;
276 iov [2].iov_len = len;
277
278 result = writev(interface -> wfdesc, iov, 3);
74f45f96 279 if (result < 0)
c5b0f529 280 log_error ("send_packet: %m");
74f45f96 281 return result;
179f54ab
TL
282}
283#endif /* USE_UPF_SEND */
284
285#ifdef USE_UPF_RECEIVE
4595a58c 286ssize_t receive_packet (interface, buf, len, from, hfrom)
179f54ab
TL
287 struct interface_info *interface;
288 unsigned char *buf;
289 size_t len;
290 struct sockaddr_in *from;
291 struct hardware *hfrom;
292{
293 int nread;
294 int length = 0;
295 int offset = 0;
296 unsigned char ibuf [1500 + sizeof (struct enstamp)];
297 int bufix = 0;
83c0372e 298 unsigned paylen;
179f54ab
TL
299
300 length = read (interface -> rfdesc, ibuf, sizeof ibuf);
301 if (length <= 0)
302 return length;
303
304 bufix = sizeof (struct enstamp);
305 /* Decode the physical header... */
306 offset = decode_hw_header (interface, ibuf, bufix, hfrom);
307
308 /* If a physical layer checksum failed (dunno of any
309 physical layer that supports this, but WTH), skip this
310 packet. */
311 if (offset < 0) {
312 return 0;
313 }
314
315 bufix += offset;
316 length -= offset;
317
318 /* Decode the IP and UDP headers... */
319 offset = decode_udp_ip_header (interface, ibuf, bufix,
7ff6ae5a 320 from, length, &paylen, 1);
179f54ab
TL
321
322 /* If the IP or UDP checksum was bad, skip the packet... */
323 if (offset < 0)
324 return 0;
325
326 bufix += offset;
327 length -= offset;
328
83c0372e
EH
329 if (length < paylen)
330 log_fatal("Internal inconsistency at %s:%d.", MDL);
331
179f54ab 332 /* Copy out the data in the packet... */
83c0372e
EH
333 memcpy (buf, &ibuf[bufix], paylen);
334 return paylen;
179f54ab 335}
d2bc90bd 336
21d21e91
TL
337int can_unicast_without_arp (ip)
338 struct interface_info *ip;
d2bc90bd
TL
339{
340 return 1;
341}
342
21d21e91
TL
343int can_receive_unicast_unconfigured (ip)
344 struct interface_info *ip;
b547818b
TL
345{
346 return 1;
347}
348
5cefe5e5
TL
349int supports_multiple_interfaces (ip)
350 struct interface_info *ip;
351{
352 return 1;
353}
354
d2bc90bd
TL
355void maybe_setup_fallback ()
356{
acc21512 357 isc_result_t status;
20916cae
TL
358 struct interface_info *fbi = (struct interface_info *)0;
359 if (setup_fallback (&fbi, MDL)) {
d2bc90bd 360 if_register_fallback (fbi);
e92653f1 361 status = omapi_register_io_object ((omapi_object_t *)fbi,
acc21512
TL
362 if_readsocket, 0,
363 fallback_discard, 0, 0);
364 if (status != ISC_R_SUCCESS)
365 log_fatal ("Can't register I/O handle for %s: %s",
366 fbi -> name, isc_result_totext (status));
68e1f67a 367 interface_dereference (&fbi, MDL);
d2bc90bd
TL
368 }
369}
179f54ab 370#endif