uipc_syscalls_40.c revision 1.24
1/*	$NetBSD: uipc_syscalls_40.c,v 1.24 2022/07/07 18:17:33 riastradh Exp $	*/
2
3/* written by Pavel Cahyna, 2006. Public domain. */
4
5#include <sys/cdefs.h>
6__KERNEL_RCSID(0, "$NetBSD: uipc_syscalls_40.c,v 1.24 2022/07/07 18:17:33 riastradh Exp $");
7
8#if defined(_KERNEL_OPT)
9#include "opt_compat_netbsd.h"
10#endif
11
12/*
13 * System call interface to the socket abstraction.
14 */
15
16#include <sys/param.h>
17#include <sys/kernel.h>
18#include <sys/msg.h>
19#include <sys/sysctl.h>
20#include <sys/syscallargs.h>
21#include <sys/errno.h>
22#include <sys/compat_stub.h>
23
24#include <net/if.h>
25
26#include <compat/sys/socket.h>
27#include <compat/sys/sockio.h>
28
29#include <compat/common/compat_mod.h>
30
31/*
32 * Return interface configuration of system.  List may be used in later
33 * ioctl's (above) to get other information.
34 */
35/*ARGSUSED*/
36static int
37compat_ifconf(u_long cmd, void *data)
38{
39	struct oifconf *ifc = data;
40	struct ifnet *ifp;
41	struct oifreq ifr, *ifrp = NULL;
42	int space = 0, error = 0;
43	const int sz = (int)sizeof(ifr);
44	int s;
45	int bound;
46	struct psref psref;
47
48	switch (cmd) {
49	case OSIOCGIFCONF:
50	case OOSIOCGIFCONF:
51		break;
52	default:
53		return ENOSYS;
54	}
55
56	const bool docopy = ifc->ifc_req != NULL;
57	if (docopy) {
58		if (ifc->ifc_len < 0)
59			return EINVAL;
60
61		space = ifc->ifc_len;
62		ifrp = ifc->ifc_req;
63	}
64	memset(&ifr, 0, sizeof(ifr));
65
66	bound = curlwp_bind();
67	s = pserialize_read_enter();
68	IFNET_READER_FOREACH(ifp) {
69		struct ifaddr *ifa;
70
71		if_acquire(ifp, &psref);
72		pserialize_read_exit(s);
73
74		(void)strncpy(ifr.ifr_name, ifp->if_xname,
75		    sizeof(ifr.ifr_name));
76		if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') {
77			error = ENAMETOOLONG;
78			goto release_exit;
79		}
80		if (IFADDR_READER_EMPTY(ifp)) {
81			memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
82			if (space >= sz) {
83				error = copyout(&ifr, ifrp, sz);
84				if (error != 0)
85					goto release_exit;
86				ifrp++;
87			}
88			space -= sizeof(ifr);
89			goto next;
90		}
91
92		s = pserialize_read_enter();
93		IFADDR_READER_FOREACH(ifa, ifp) {
94			struct sockaddr *sa = ifa->ifa_addr;
95			struct psref psref_ifa;
96
97			ifa_acquire(ifa, &psref_ifa);
98			pserialize_read_exit(s);
99#ifdef COMPAT_OSOCK
100			if (cmd == OOSIOCGIFCONF) {
101				struct osockaddr *osa =
102				    (struct osockaddr *)&ifr.ifr_addr;
103				/*
104				 * If it does not fit, we don't bother with it
105				 */
106				if (sa->sa_len > sizeof(*osa))
107					goto next_ifa;
108				memcpy(&ifr.ifr_addr, sa, sa->sa_len);
109				osa->sa_family = sa->sa_family;
110				if (space >= sz) {
111					error = copyout(&ifr, ifrp, sz);
112					ifrp++;
113				}
114			} else
115#endif
116			if (sa->sa_len <= sizeof(*sa)) {
117				memcpy(&ifr.ifr_addr, sa, sa->sa_len);
118				if (space >= sz) {
119					error = copyout(&ifr, ifrp, sz);
120					ifrp++;
121				}
122			} else {
123				space -= sa->sa_len - sizeof(*sa);
124				if (space >= sz) {
125					error = copyout(&ifr.ifr_name, ifrp,
126					    sizeof(ifr.ifr_name));
127					if (error == 0) {
128						error = copyout(sa,
129						    &ifrp->ifr_addr,
130						    sa->sa_len);
131					}
132					ifrp = (struct oifreq *)
133						(sa->sa_len +
134						 (char *)&ifrp->ifr_addr);
135				}
136			}
137			if (error != 0) {
138				ifa_release(ifa, &psref_ifa);
139				goto release_exit;
140			}
141			space -= sz;
142
143#ifdef COMPAT_OSOCK
144		next_ifa:
145#endif
146			s = pserialize_read_enter();
147			ifa_release(ifa, &psref_ifa);
148		}
149		pserialize_read_exit(s);
150
151	next:
152		s = pserialize_read_enter();
153		if_release(ifp, &psref);
154	}
155	pserialize_read_exit(s);
156	curlwp_bindx(bound);
157
158	if (docopy)
159		ifc->ifc_len -= space;
160	else
161		ifc->ifc_len = -space;
162	return 0;
163
164release_exit:
165	if_release(ifp, &psref);
166	curlwp_bindx(bound);
167	return error;
168}
169
170void
171uipc_syscalls_40_init(void)
172{
173
174	MODULE_HOOK_SET(uipc_syscalls_40_hook, compat_ifconf);
175}
176
177void
178uipc_syscalls_40_fini(void)
179{
180
181	MODULE_HOOK_UNSET(uipc_syscalls_40_hook);
182}
183