uipc_syscalls_40.c revision 1.13
1/*	$NetBSD: uipc_syscalls_40.c,v 1.13 2017/03/14 09:03:08 ozaki-r 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.13 2017/03/14 09:03:08 ozaki-r Exp $");
7
8/*
9 * System call interface to the socket abstraction.
10 */
11
12#include <sys/param.h>
13#include <sys/kernel.h>
14#include <sys/msg.h>
15#include <sys/sysctl.h>
16#include <sys/syscallargs.h>
17#include <sys/errno.h>
18
19#include <net/if.h>
20
21#include <compat/sys/socket.h>
22#include <compat/sys/sockio.h>
23
24#ifdef COMPAT_OIFREQ
25/*
26 * Return interface configuration
27 * of system.  List may be used
28 * in later ioctl's (above) to get
29 * other information.
30 */
31/*ARGSUSED*/
32int
33compat_ifconf(u_long cmd, void *data)
34{
35	struct oifconf *ifc = data;
36	struct ifnet *ifp;
37	struct oifreq ifr, *ifrp = NULL;
38	int space = 0, error = 0;
39	const int sz = (int)sizeof(ifr);
40	const bool docopy = ifc->ifc_req != NULL;
41	int s;
42	int bound;
43	struct psref psref;
44
45	if (docopy) {
46		space = ifc->ifc_len;
47		ifrp = ifc->ifc_req;
48	}
49
50	bound = curlwp_bind();
51	s = pserialize_read_enter();
52	IFNET_READER_FOREACH(ifp) {
53		struct ifaddr *ifa;
54
55		if_acquire(ifp, &psref);
56
57		(void)strncpy(ifr.ifr_name, ifp->if_xname,
58		    sizeof(ifr.ifr_name));
59		if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') {
60			error = ENAMETOOLONG;
61			goto release_exit;
62		}
63		if (IFADDR_READER_EMPTY(ifp)) {
64			memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
65			if (space >= sz) {
66				error = copyout(&ifr, ifrp, sz);
67				if (error != 0)
68					goto release_exit;
69				ifrp++;
70			}
71			space -= sizeof(ifr);
72			continue;
73		}
74
75		IFADDR_READER_FOREACH(ifa, ifp) {
76			struct sockaddr *sa = ifa->ifa_addr;
77			struct psref psref_ifa;
78
79			ifa_acquire(ifa, &psref_ifa);
80			pserialize_read_exit(s);
81#ifdef COMPAT_OSOCK
82			if (cmd == OOSIOCGIFCONF) {
83				struct osockaddr *osa =
84				    (struct osockaddr *)&ifr.ifr_addr;
85				/*
86				 * If it does not fit, we don't bother with it
87				 */
88				if (sa->sa_len > sizeof(*osa)) {
89					s = pserialize_read_enter();
90					ifa_release(ifa, &psref_ifa);
91					continue;
92				}
93				memcpy(&ifr.ifr_addr, sa, sa->sa_len);
94				osa->sa_family = sa->sa_family;
95				if (space >= sz) {
96					error = copyout(&ifr, ifrp, sz);
97					ifrp++;
98				}
99			} else
100#endif
101			if (sa->sa_len <= sizeof(*sa)) {
102				memcpy(&ifr.ifr_addr, sa, sa->sa_len);
103				if (space >= sz) {
104					error = copyout(&ifr, ifrp, sz);
105					ifrp++;
106				}
107			} else {
108				space -= sa->sa_len - sizeof(*sa);
109				if (space >= sz) {
110					error = copyout(&ifr, ifrp,
111					    sizeof(ifr.ifr_name));
112					if (error == 0) {
113						error = copyout(sa,
114						    &ifrp->ifr_addr,
115						    sa->sa_len);
116					}
117					ifrp = (struct oifreq *)
118						(sa->sa_len +
119						 (char *)&ifrp->ifr_addr);
120				}
121			}
122			s = pserialize_read_enter();
123			ifa_release(ifa, &psref_ifa);
124			if (error != 0)
125				goto release_exit;
126			space -= sz;
127		}
128
129		if_release(ifp, &psref);
130	}
131	pserialize_read_exit(s);
132	curlwp_bindx(bound);
133
134	if (docopy)
135		ifc->ifc_len -= space;
136	else
137		ifc->ifc_len = -space;
138	return (0);
139
140release_exit:
141	pserialize_read_exit(s);
142	if_release(ifp, &psref);
143	curlwp_bindx(bound);
144	return error;
145}
146#endif
147