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