1 | /* $NetBSD: if_43.c,v 1.22 2019/05/17 07:37:11 msaitoh Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1982, 1986, 1989, 1990, 1993 |
5 | * The Regents of the University of California. All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * 3. Neither the name of the University nor the names of its contributors |
16 | * may be used to endorse or promote products derived from this software |
17 | * without specific prior written permission. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 | * SUCH DAMAGE. |
30 | * |
31 | * @(#)uipc_syscalls.c 8.4 (Berkeley) 2/21/94 |
32 | */ |
33 | |
34 | #include <sys/cdefs.h> |
35 | __KERNEL_RCSID(0, "$NetBSD: if_43.c,v 1.22 2019/05/17 07:37:11 msaitoh Exp $" ); |
36 | |
37 | #if defined(_KERNEL_OPT) |
38 | #include "opt_compat_netbsd.h" |
39 | #endif |
40 | |
41 | #include <sys/param.h> |
42 | #include <sys/systm.h> |
43 | #include <sys/filedesc.h> |
44 | #include <sys/kernel.h> |
45 | #include <sys/proc.h> |
46 | #include <sys/file.h> |
47 | #include <sys/socket.h> |
48 | #include <sys/socketvar.h> |
49 | #include <sys/stat.h> |
50 | #include <sys/ioctl.h> |
51 | #include <sys/fcntl.h> |
52 | #include <sys/syslog.h> |
53 | #include <sys/unistd.h> |
54 | #include <sys/resourcevar.h> |
55 | #include <sys/mbuf.h> /* for MLEN */ |
56 | #include <sys/protosw.h> |
57 | #include <sys/compat_stub.h> |
58 | |
59 | #include <sys/syscallargs.h> |
60 | |
61 | #include <net/if.h> |
62 | #include <net/bpf.h> |
63 | #include <net/route.h> |
64 | #include <netinet/in.h> |
65 | #include <netinet/in_systm.h> |
66 | #include <netinet/ip.h> |
67 | #include <net/if_gre.h> |
68 | #include <net/if_tap.h> |
69 | #include <net80211/ieee80211_ioctl.h> |
70 | #include <netinet6/in6_var.h> |
71 | #include <netinet6/nd6.h> |
72 | #include <compat/sys/socket.h> |
73 | #include <compat/sys/sockio.h> |
74 | |
75 | #include <compat/common/compat_util.h> |
76 | #include <compat/common/compat_mod.h> |
77 | #include <uvm/uvm_extern.h> |
78 | |
79 | #if defined(COMPAT_43) |
80 | |
81 | /* |
82 | * Use a wrapper so that the compat_cvtcmd() can return a u_long |
83 | */ |
84 | static int |
85 | do_compat_cvtcmd(u_long *ncmd, u_long ocmd) |
86 | { |
87 | |
88 | *ncmd = compat_cvtcmd(ocmd); |
89 | return 0; |
90 | } |
91 | |
92 | u_long |
93 | compat_cvtcmd(u_long cmd) |
94 | { |
95 | u_long ncmd; |
96 | |
97 | if (IOCPARM_LEN(cmd) != sizeof(struct oifreq)) |
98 | return cmd; |
99 | |
100 | switch (cmd) { |
101 | case OSIOCSIFADDR: |
102 | return SIOCSIFADDR; |
103 | case OOSIOCGIFADDR: |
104 | return SIOCGIFADDR; |
105 | case OSIOCSIFDSTADDR: |
106 | return SIOCSIFDSTADDR; |
107 | case OOSIOCGIFDSTADDR: |
108 | return SIOCGIFDSTADDR; |
109 | case OSIOCSIFFLAGS: |
110 | return SIOCSIFFLAGS; |
111 | case OSIOCGIFFLAGS: |
112 | return SIOCGIFFLAGS; |
113 | case OOSIOCGIFBRDADDR: |
114 | return SIOCGIFBRDADDR; |
115 | case OSIOCSIFBRDADDR: |
116 | return SIOCSIFBRDADDR; |
117 | case OOSIOCGIFCONF: |
118 | return SIOCGIFCONF; |
119 | case OOSIOCGIFNETMASK: |
120 | return SIOCGIFNETMASK; |
121 | case OSIOCSIFNETMASK: |
122 | return SIOCSIFNETMASK; |
123 | case OSIOCGIFCONF: |
124 | return SIOCGIFCONF; |
125 | case OSIOCADDMULTI: |
126 | return SIOCADDMULTI; |
127 | case OSIOCDELMULTI: |
128 | return SIOCDELMULTI; |
129 | case SIOCSIFMEDIA_43: |
130 | return SIOCSIFMEDIA_80; |
131 | case OSIOCGIFMTU: |
132 | return SIOCGIFMTU; |
133 | case OSIOCGIFDATA: |
134 | return SIOCGIFDATA; |
135 | case OSIOCZIFDATA: |
136 | return SIOCZIFDATA; |
137 | case OBIOCGETIF: |
138 | return BIOCGETIF; |
139 | case OBIOCSETIF: |
140 | return BIOCSETIF; |
141 | case OTAPGIFNAME: |
142 | return TAPGIFNAME; |
143 | default: |
144 | /* |
145 | * XXX: the following code should be removed and the |
146 | * needing treatment ioctls should move to the switch |
147 | * above. |
148 | */ |
149 | ncmd = ((cmd) & ~(IOCPARM_MASK << IOCPARM_SHIFT)) | |
150 | (sizeof(struct ifreq) << IOCPARM_SHIFT); |
151 | switch (ncmd) { |
152 | case BIOCGETIF: |
153 | case BIOCSETIF: |
154 | case GREDSOCK: |
155 | case GREGADDRD: |
156 | case GREGADDRS: |
157 | case GREGPROTO: |
158 | case GRESADDRD: |
159 | case GRESADDRS: |
160 | case GRESPROTO: |
161 | case GRESSOCK: |
162 | case SIOCADDMULTI: |
163 | case SIOCDELMULTI: |
164 | case SIOCDIFADDR: |
165 | case SIOCDIFADDR_IN6: |
166 | case SIOCDIFPHYADDR: |
167 | case SIOCGDEFIFACE_IN6: |
168 | case SIOCG80211NWID: |
169 | case SIOCG80211STATS: |
170 | case SIOCG80211ZSTATS: |
171 | case SIOCGIFADDR: |
172 | case SIOCGIFADDR_IN6: |
173 | case SIOCGIFAFLAG_IN6: |
174 | case SIOCGIFALIFETIME_IN6: |
175 | case SIOCGIFBRDADDR: |
176 | case SIOCGIFDLT: |
177 | case SIOCGIFDSTADDR: |
178 | case SIOCGIFDSTADDR_IN6: |
179 | case SIOCGIFFLAGS: |
180 | case SIOCGIFGENERIC: |
181 | case SIOCGIFMETRIC: |
182 | case SIOCGIFMTU: |
183 | case SIOCGIFNETMASK: |
184 | case SIOCGIFNETMASK_IN6: |
185 | case SIOCGIFPDSTADDR: |
186 | case SIOCGIFPDSTADDR_IN6: |
187 | case SIOCGIFPSRCADDR: |
188 | case SIOCGIFPSRCADDR_IN6: |
189 | case SIOCGIFSTAT_ICMP6: |
190 | case SIOCGIFSTAT_IN6: |
191 | case SIOCGVH: |
192 | case SIOCIFCREATE: |
193 | case SIOCIFDESTROY: |
194 | case SIOCS80211NWID: |
195 | case SIOCSDEFIFACE_IN6: |
196 | case SIOCSIFADDR: |
197 | case SIOCSIFADDR_IN6: |
198 | case SIOCSIFBRDADDR: |
199 | case SIOCSIFDSTADDR: |
200 | case SIOCSIFDSTADDR_IN6: |
201 | case SIOCSIFFLAGS: |
202 | case SIOCSIFGENERIC: |
203 | case SIOCSIFMEDIA: |
204 | case SIOCSIFMETRIC: |
205 | case SIOCSIFMTU: |
206 | case SIOCSIFNETMASK: |
207 | case SIOCSIFNETMASK_IN6: |
208 | case SIOCSNDFLUSH_IN6: |
209 | case SIOCSPFXFLUSH_IN6: |
210 | case SIOCSRTRFLUSH_IN6: |
211 | case SIOCSVH: |
212 | case TAPGIFNAME: |
213 | return ncmd; |
214 | default: |
215 | { int rv; |
216 | |
217 | MODULE_HOOK_CALL(if43_cvtcmd_20_hook, (ncmd), enosys(), |
218 | rv); |
219 | if (rv == 0) |
220 | return ncmd; |
221 | return cmd; |
222 | } |
223 | } |
224 | } |
225 | } |
226 | |
227 | int |
228 | compat_ifioctl(struct socket *so, u_long ocmd, u_long cmd, void *data, |
229 | struct lwp *l) |
230 | { |
231 | int error; |
232 | struct ifreq *ifr = (struct ifreq *)data; |
233 | struct ifreq ifrb; |
234 | struct oifreq *oifr = NULL; |
235 | struct ifnet *ifp; |
236 | struct sockaddr *sa; |
237 | struct psref psref; |
238 | int bound = curlwp_bind(); |
239 | |
240 | ifp = if_get(ifr->ifr_name, &psref); |
241 | if (ifp == NULL) { |
242 | curlwp_bindx(bound); |
243 | return ENXIO; |
244 | } |
245 | |
246 | /* |
247 | * If we have not been converted, make sure that we are. |
248 | * (because the upper layer handles old socket calls, but |
249 | * not oifreq calls. |
250 | */ |
251 | if (cmd == ocmd) { |
252 | cmd = compat_cvtcmd(ocmd); |
253 | } |
254 | if (cmd != ocmd) { |
255 | oifr = data; |
256 | data = ifr = &ifrb; |
257 | IFREQO2N_43(oifr, ifr); |
258 | } |
259 | |
260 | switch (ocmd) { |
261 | case OSIOCSIFADDR: |
262 | case OSIOCSIFDSTADDR: |
263 | case OSIOCSIFBRDADDR: |
264 | case OSIOCSIFNETMASK: |
265 | sa = &ifr->ifr_addr; |
266 | #if BYTE_ORDER != BIG_ENDIAN |
267 | if (sa->sa_family == 0 && sa->sa_len < 16) { |
268 | sa->sa_family = sa->sa_len; |
269 | sa->sa_len = 16; |
270 | } |
271 | #else |
272 | if (sa->sa_len == 0) |
273 | sa->sa_len = 16; |
274 | #endif |
275 | break; |
276 | } |
277 | |
278 | error = (*so->so_proto->pr_usrreqs->pr_ioctl)(so, cmd, ifr, ifp); |
279 | if_put(ifp, &psref); |
280 | curlwp_bindx(bound); |
281 | |
282 | switch (ocmd) { |
283 | case OOSIOCGIFADDR: |
284 | case OOSIOCGIFDSTADDR: |
285 | case OOSIOCGIFBRDADDR: |
286 | case OOSIOCGIFNETMASK: |
287 | *(u_int16_t *)&ifr->ifr_addr = |
288 | ((struct sockaddr *)&ifr->ifr_addr)->sa_family; |
289 | break; |
290 | } |
291 | |
292 | if (cmd != ocmd) |
293 | IFREQN2O_43(oifr, ifr); |
294 | |
295 | return error; |
296 | } |
297 | |
298 | int |
299 | if_43_init(void) |
300 | { |
301 | |
302 | MODULE_HOOK_SET(if_cvtcmd_43_hook, "if_43" , do_compat_cvtcmd); |
303 | MODULE_HOOK_SET(if_ifioctl_43_hook, "if_43" , compat_ifioctl); |
304 | return 0; |
305 | } |
306 | |
307 | int |
308 | if_43_fini(void) |
309 | { |
310 | |
311 | MODULE_HOOK_UNSET(if_cvtcmd_43_hook); |
312 | MODULE_HOOK_UNSET(if_ifioctl_43_hook); |
313 | return 0; |
314 | } |
315 | #endif /* defined(COMPAT_43) */ |
316 | |