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