xref: /netbsd-src/sys/compat/common/uipc_syscalls_40.c (revision a24efa7dea9f1f56c3bdb15a927d3516792ace1c)
1 /*	$NetBSD: uipc_syscalls_40.c,v 1.9 2016/05/12 02:24:16 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.9 2016/05/12 02:24:16 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*/
32 int
33 compat_ifconf(u_long cmd, void *data)
34 {
35 	struct oifconf *ifc = data;
36 	struct ifnet *ifp;
37 	struct ifaddr *ifa;
38 	struct oifreq ifr, *ifrp = NULL;
39 	int space = 0, error = 0;
40 	const int sz = (int)sizeof(ifr);
41 	const bool docopy = ifc->ifc_req != NULL;
42 	int s;
43 	int bound = curlwp->l_pflag & LP_BOUND;
44 	struct psref psref;
45 
46 	if (docopy) {
47 		space = ifc->ifc_len;
48 		ifrp = ifc->ifc_req;
49 	}
50 
51 	curlwp->l_pflag |= LP_BOUND;
52 	s = pserialize_read_enter();
53 	IFNET_READER_FOREACH(ifp) {
54 		psref_acquire(&psref, &ifp->if_psref, ifnet_psref_class);
55 		pserialize_read_exit(s);
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_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_FOREACH(ifa, ifp) {
76 			struct sockaddr *sa = ifa->ifa_addr;
77 #ifdef COMPAT_OSOCK
78 			if (cmd == OOSIOCGIFCONF) {
79 				struct osockaddr *osa =
80 				    (struct osockaddr *)&ifr.ifr_addr;
81 				/*
82 				 * If it does not fit, we don't bother with it
83 				 */
84 				if (sa->sa_len > sizeof(*osa))
85 					continue;
86 				memcpy(&ifr.ifr_addr, sa, sa->sa_len);
87 				osa->sa_family = sa->sa_family;
88 				if (space >= sz) {
89 					error = copyout(&ifr, ifrp, sz);
90 					ifrp++;
91 				}
92 			} else
93 #endif
94 			if (sa->sa_len <= sizeof(*sa)) {
95 				memcpy(&ifr.ifr_addr, sa, sa->sa_len);
96 				if (space >= sz) {
97 					error = copyout(&ifr, ifrp, sz);
98 					ifrp++;
99 				}
100 			} else {
101 				space -= sa->sa_len - sizeof(*sa);
102 				if (space >= sz) {
103 					error = copyout(&ifr, ifrp,
104 					    sizeof(ifr.ifr_name));
105 					if (error == 0) {
106 						error = copyout(sa,
107 						    &ifrp->ifr_addr,
108 						    sa->sa_len);
109 					}
110 					ifrp = (struct oifreq *)
111 						(sa->sa_len +
112 						 (char *)&ifrp->ifr_addr);
113 				}
114 			}
115 			if (error != 0)
116 				goto release_exit;
117 			space -= sz;
118 		}
119 
120 		s = pserialize_read_enter();
121 		psref_release(&psref, &ifp->if_psref, ifnet_psref_class);
122 	}
123 	pserialize_read_exit(s);
124 	curlwp->l_pflag ^= bound ^ LP_BOUND;
125 
126 	if (docopy)
127 		ifc->ifc_len -= space;
128 	else
129 		ifc->ifc_len = -space;
130 	return (0);
131 
132 release_exit:
133 	psref_release(&psref, &ifp->if_psref, ifnet_psref_class);
134 	curlwp->l_pflag ^= bound ^ LP_BOUND;
135 	return error;
136 }
137 #endif
138