uipc_syscalls_40.c revision 1.19
1/*	$NetBSD: uipc_syscalls_40.c,v 1.19 2019/04/18 17:45:12 christos 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.19 2019/04/18 17:45:12 christos 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
33 * of system.  List may be used
34 * in later ioctl's (above) to get
35 * other information.
36 */
37/*ARGSUSED*/
38static int
39compat_ifconf(u_long cmd, void *data)
40{
41	struct oifconf *ifc = data;
42	struct ifnet *ifp;
43	struct oifreq ifr, *ifrp = NULL;
44	int space = 0, error = 0;
45	const int sz = (int)sizeof(ifr);
46	const bool docopy = ifc->ifc_req != NULL;
47	int s;
48	int bound;
49	struct psref psref;
50
51	switch (cmd) {
52	case OSIOCGIFCONF:
53	case OOSIOCGIFCONF:
54		break;
55	default:
56		return ENOSYS;
57	}
58
59	memset(&ifr, 0, sizeof(ifr));
60	if (docopy) {
61		space = ifc->ifc_len;
62		ifrp = ifc->ifc_req;
63	}
64
65	bound = curlwp_bind();
66	s = pserialize_read_enter();
67	IFNET_READER_FOREACH(ifp) {
68		struct ifaddr *ifa;
69
70		if_acquire(ifp, &psref);
71		pserialize_read_exit(s);
72
73		(void)strncpy(ifr.ifr_name, ifp->if_xname,
74		    sizeof(ifr.ifr_name));
75		if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') {
76			error = ENAMETOOLONG;
77			goto release_exit;
78		}
79		if (IFADDR_READER_EMPTY(ifp)) {
80			memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
81			if (space >= sz) {
82				error = copyout(&ifr, ifrp, sz);
83				if (error != 0)
84					goto release_exit;
85				ifrp++;
86			}
87			space -= sizeof(ifr);
88			goto next;
89		}
90
91		s = pserialize_read_enter();
92		IFADDR_READER_FOREACH(ifa, ifp) {
93			struct sockaddr *sa = ifa->ifa_addr;
94			struct psref psref_ifa;
95
96			ifa_acquire(ifa, &psref_ifa);
97			pserialize_read_exit(s);
98#ifdef COMPAT_OSOCK
99			if (cmd == OOSIOCGIFCONF) {
100				struct osockaddr *osa =
101				    (struct osockaddr *)&ifr.ifr_addr;
102				/*
103				 * If it does not fit, we don't bother with it
104				 */
105				if (sa->sa_len > sizeof(*osa))
106					goto next_ifa;
107				memcpy(&ifr.ifr_addr, sa, sa->sa_len);
108				osa->sa_family = sa->sa_family;
109				if (space >= sz) {
110					error = copyout(&ifr, ifrp, sz);
111					ifrp++;
112				}
113			} else
114#endif
115			if (sa->sa_len <= sizeof(*sa)) {
116				memcpy(&ifr.ifr_addr, sa, sa->sa_len);
117				if (space >= sz) {
118					error = copyout(&ifr, ifrp, sz);
119					ifrp++;
120				}
121			} else {
122				space -= sa->sa_len - sizeof(*sa);
123				if (space >= sz) {
124					error = copyout(&ifr, ifrp,
125					    sizeof(ifr.ifr_name));
126					if (error == 0) {
127						error = copyout(sa,
128						    &ifrp->ifr_addr,
129						    sa->sa_len);
130					}
131					ifrp = (struct oifreq *)
132						(sa->sa_len +
133						 (char *)&ifrp->ifr_addr);
134				}
135			}
136			if (error != 0) {
137				ifa_release(ifa, &psref_ifa);
138				goto release_exit;
139			}
140			space -= sz;
141
142#ifdef COMPAT_OSOCK
143		next_ifa:
144#endif
145			s = pserialize_read_enter();
146			ifa_release(ifa, &psref_ifa);
147		}
148		pserialize_read_exit(s);
149
150	next:
151		s = pserialize_read_enter();
152		if_release(ifp, &psref);
153	}
154	pserialize_read_exit(s);
155	curlwp_bindx(bound);
156
157	if (docopy)
158		ifc->ifc_len -= space;
159	else
160		ifc->ifc_len = -space;
161	return (0);
162
163release_exit:
164	if_release(ifp, &psref);
165	curlwp_bindx(bound);
166	return error;
167}
168
169void
170uipc_syscalls_40_init(void)
171{
172
173	MODULE_HOOK_SET(uipc_syscalls_40_hook, "uipc40", compat_ifconf);
174}
175
176void
177uipc_syscalls_40_fini(void)
178{
179
180	MODULE_HOOK_UNSET(uipc_syscalls_40_hook);
181}
182