1 | /* $NetBSD: if_43.c,v 1.13 2016/11/05 23:30:22 pgoyette 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.13 2016/11/05 23:30:22 pgoyette 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 | |
58 | #include <sys/syscallargs.h> |
59 | |
60 | #include <net/if.h> |
61 | #include <net/bpf.h> |
62 | #include <net/route.h> |
63 | #include <netinet/in.h> |
64 | #include <netinet/in_systm.h> |
65 | #include <netinet/ip.h> |
66 | #include <net/if_gre.h> |
67 | #include <net/if_atm.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/if_43.h> |
77 | #include <uvm/uvm_extern.h> |
78 | |
79 | u_long |
80 | compat_cvtcmd(u_long cmd) |
81 | { |
82 | u_long ncmd; |
83 | |
84 | if (IOCPARM_LEN(cmd) != sizeof(struct oifreq)) |
85 | return cmd; |
86 | |
87 | switch (cmd) { |
88 | case OSIOCSIFADDR: |
89 | return SIOCSIFADDR; |
90 | case OOSIOCGIFADDR: |
91 | return SIOCGIFADDR; |
92 | case OSIOCSIFDSTADDR: |
93 | return SIOCSIFDSTADDR; |
94 | case OOSIOCGIFDSTADDR: |
95 | return SIOCGIFDSTADDR; |
96 | case OSIOCSIFFLAGS: |
97 | return SIOCSIFFLAGS; |
98 | case OSIOCGIFFLAGS: |
99 | return SIOCGIFFLAGS; |
100 | case OOSIOCGIFBRDADDR: |
101 | return SIOCGIFBRDADDR; |
102 | case OSIOCSIFBRDADDR: |
103 | return SIOCSIFBRDADDR; |
104 | case OOSIOCGIFCONF: |
105 | return SIOCGIFCONF; |
106 | case OOSIOCGIFNETMASK: |
107 | return SIOCGIFNETMASK; |
108 | case OSIOCSIFNETMASK: |
109 | return SIOCSIFNETMASK; |
110 | case OSIOCGIFCONF: |
111 | return SIOCGIFCONF; |
112 | case OSIOCADDMULTI: |
113 | return SIOCADDMULTI; |
114 | case OSIOCDELMULTI: |
115 | return SIOCDELMULTI; |
116 | case OSIOCSIFMEDIA: |
117 | return SIOCSIFMEDIA; |
118 | case OSIOCGIFMTU: |
119 | return SIOCGIFMTU; |
120 | case OSIOCGIFDATA: |
121 | return SIOCGIFDATA; |
122 | case OSIOCZIFDATA: |
123 | return SIOCZIFDATA; |
124 | case OBIOCGETIF: |
125 | return BIOCGETIF; |
126 | case OBIOCSETIF: |
127 | return BIOCSETIF; |
128 | case OTAPGIFNAME: |
129 | return TAPGIFNAME; |
130 | default: |
131 | /* |
132 | * XXX: the following code should be removed and the |
133 | * needing treatment ioctls should move to the switch |
134 | * above. |
135 | */ |
136 | ncmd = ((cmd) & ~(IOCPARM_MASK << IOCPARM_SHIFT)) | |
137 | (sizeof(struct ifreq) << IOCPARM_SHIFT); |
138 | switch (ncmd) { |
139 | case BIOCGETIF: |
140 | case BIOCSETIF: |
141 | case GREDSOCK: |
142 | case GREGADDRD: |
143 | case GREGADDRS: |
144 | case GREGPROTO: |
145 | case GRESADDRD: |
146 | case GRESADDRS: |
147 | case GRESPROTO: |
148 | case GRESSOCK: |
149 | #ifdef COMPAT_20 |
150 | case OSIOCG80211STATS: |
151 | case OSIOCG80211ZSTATS: |
152 | #endif /* COMPAT_20 */ |
153 | case SIOCADDMULTI: |
154 | case SIOCDELMULTI: |
155 | case SIOCDIFADDR: |
156 | case SIOCDIFADDR_IN6: |
157 | case SIOCDIFPHYADDR: |
158 | case SIOCGDEFIFACE_IN6: |
159 | case SIOCG80211NWID: |
160 | case SIOCG80211STATS: |
161 | case SIOCG80211ZSTATS: |
162 | case SIOCGIFADDR: |
163 | case SIOCGIFADDR_IN6: |
164 | case SIOCGIFAFLAG_IN6: |
165 | case SIOCGIFALIFETIME_IN6: |
166 | case SIOCGIFBRDADDR: |
167 | case SIOCGIFDLT: |
168 | case SIOCGIFDSTADDR: |
169 | case SIOCGIFDSTADDR_IN6: |
170 | case SIOCGIFFLAGS: |
171 | case SIOCGIFGENERIC: |
172 | case SIOCGIFMETRIC: |
173 | case SIOCGIFMTU: |
174 | case SIOCGIFNETMASK: |
175 | case SIOCGIFNETMASK_IN6: |
176 | case SIOCGIFPDSTADDR: |
177 | case SIOCGIFPDSTADDR_IN6: |
178 | case SIOCGIFPSRCADDR: |
179 | case SIOCGIFPSRCADDR_IN6: |
180 | case SIOCGIFSTAT_ICMP6: |
181 | case SIOCGIFSTAT_IN6: |
182 | case SIOCGPVCSIF: |
183 | case SIOCGVH: |
184 | case SIOCIFCREATE: |
185 | case SIOCIFDESTROY: |
186 | case SIOCS80211NWID: |
187 | case SIOCSDEFIFACE_IN6: |
188 | case SIOCSIFADDR: |
189 | case SIOCSIFADDR_IN6: |
190 | case SIOCSIFBRDADDR: |
191 | case SIOCSIFDSTADDR: |
192 | case SIOCSIFDSTADDR_IN6: |
193 | case SIOCSIFFLAGS: |
194 | case SIOCSIFGENERIC: |
195 | case SIOCSIFMEDIA: |
196 | case SIOCSIFMETRIC: |
197 | case SIOCSIFMTU: |
198 | case SIOCSIFNETMASK: |
199 | case SIOCSIFNETMASK_IN6: |
200 | case SIOCSNDFLUSH_IN6: |
201 | case SIOCSPFXFLUSH_IN6: |
202 | case SIOCSPVCSIF: |
203 | case SIOCSRTRFLUSH_IN6: |
204 | case SIOCSVH: |
205 | case TAPGIFNAME: |
206 | return ncmd; |
207 | default: |
208 | return cmd; |
209 | } |
210 | } |
211 | } |
212 | |
213 | int |
214 | compat_ifioctl(struct socket *so, u_long ocmd, u_long cmd, void *data, |
215 | struct lwp *l) |
216 | { |
217 | int error; |
218 | struct ifreq *ifr = (struct ifreq *)data; |
219 | struct ifreq ifrb; |
220 | struct oifreq *oifr = NULL; |
221 | struct ifnet *ifp; |
222 | struct sockaddr *sa; |
223 | struct psref psref; |
224 | int bound = curlwp_bind(); |
225 | |
226 | ifp = if_get(ifr->ifr_name, &psref); |
227 | if (ifp == NULL) { |
228 | curlwp_bindx(bound); |
229 | return ENXIO; |
230 | } |
231 | |
232 | /* |
233 | * If we have not been converted, make sure that we are. |
234 | * (because the upper layer handles old socket calls, but |
235 | * not oifreq calls. |
236 | */ |
237 | if (cmd == ocmd) { |
238 | cmd = compat_cvtcmd(ocmd); |
239 | } |
240 | if (cmd != ocmd) { |
241 | oifr = data; |
242 | data = ifr = &ifrb; |
243 | ifreqo2n(oifr, ifr); |
244 | } |
245 | |
246 | switch (ocmd) { |
247 | case OSIOCSIFADDR: |
248 | case OSIOCSIFDSTADDR: |
249 | case OSIOCSIFBRDADDR: |
250 | case OSIOCSIFNETMASK: |
251 | sa = &ifr->ifr_addr; |
252 | #if BYTE_ORDER != BIG_ENDIAN |
253 | if (sa->sa_family == 0 && sa->sa_len < 16) { |
254 | sa->sa_family = sa->sa_len; |
255 | sa->sa_len = 16; |
256 | } |
257 | #else |
258 | if (sa->sa_len == 0) |
259 | sa->sa_len = 16; |
260 | #endif |
261 | break; |
262 | } |
263 | |
264 | error = (*so->so_proto->pr_usrreqs->pr_ioctl)(so, cmd, ifr, ifp); |
265 | if_put(ifp, &psref); |
266 | curlwp_bindx(bound); |
267 | |
268 | switch (ocmd) { |
269 | case OOSIOCGIFADDR: |
270 | case OOSIOCGIFDSTADDR: |
271 | case OOSIOCGIFBRDADDR: |
272 | case OOSIOCGIFNETMASK: |
273 | *(u_int16_t *)&ifr->ifr_addr = |
274 | ((struct sockaddr *)&ifr->ifr_addr)->sa_family; |
275 | break; |
276 | } |
277 | |
278 | if (cmd != ocmd) |
279 | ifreqn2o(oifr, ifr); |
280 | |
281 | return error; |
282 | } |
283 | |
284 | #if defined(COMPAT_43) |
285 | static u_long (*orig_compat_cvtcmd)(u_long); |
286 | static int (*orig_compat_ifioctl)(struct socket *, u_long, u_long, |
287 | void *, struct lwp *); |
288 | |
289 | void |
290 | if_43_init(void) |
291 | { |
292 | extern u_long (*vec_compat_cvtcmd)(u_long); |
293 | extern int (*vec_compat_ifioctl)(struct socket *, u_long, u_long, |
294 | void *, struct lwp *); |
295 | |
296 | orig_compat_cvtcmd = vec_compat_cvtcmd; |
297 | vec_compat_cvtcmd = compat_cvtcmd; |
298 | |
299 | orig_compat_ifioctl = vec_compat_ifioctl; |
300 | vec_compat_ifioctl = compat_ifioctl; |
301 | } |
302 | |
303 | void |
304 | if_43_fini(void) |
305 | { |
306 | |
307 | vec_compat_cvtcmd = orig_compat_cvtcmd; |
308 | vec_compat_ifioctl = orig_compat_ifioctl; |
309 | } |
310 | #endif /* defined(COMPAT_43) */ |
311 | |