ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / ppc64 / kernel / ioctl32.c
1 /* 
2  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
3  * 
4  * Based on sparc64 ioctl32.c by:
5  *
6  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
7  * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
8  *
9  * ppc64 changes:
10  *
11  * Copyright (C) 2000  Ken Aaker (kdaaker@rchland.vnet.ibm.com)
12  * Copyright (C) 2001  Anton Blanchard (antonb@au.ibm.com)
13  *
14  * These routines maintain argument size conversion between 32bit and 64bit
15  * ioctls.
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License
19  * as published by the Free Software Foundation; either version
20  * 2 of the License, or (at your option) any later version.
21  */
22
23 #define INCLUDES
24 #include "compat_ioctl.c"
25 #include <linux/ncp_fs.h>
26 #include <linux/syscalls.h>
27 #include <asm/ppc32.h>
28
29 #define CODE
30 #include "compat_ioctl.c"
31
32 struct ncp_ioctl_request_32 {
33         unsigned int function;
34         unsigned int size;
35         compat_caddr_t data;
36 };
37
38 struct ncp_fs_info_v2_32 {
39         int version;
40         unsigned int mounted_uid;
41         unsigned int connection;
42         unsigned int buffer_size;
43
44         unsigned int volume_number;
45         __u32 directory_id;
46
47         __u32 dummy1;
48         __u32 dummy2;
49         __u32 dummy3;
50 };
51
52 struct ncp_objectname_ioctl_32
53 {
54         int             auth_type;
55         unsigned int    object_name_len;
56         compat_caddr_t  object_name;    /* an userspace data, in most cases user name */
57 };
58
59 struct ncp_privatedata_ioctl_32
60 {
61         unsigned int    len;
62         compat_caddr_t  data;           /* ~1000 for NDS */
63 };
64
65 #define NCP_IOC_NCPREQUEST_32           _IOR('n', 1, struct ncp_ioctl_request_32)
66
67 #define NCP_IOC_GETMOUNTUID2_32         _IOW('n', 2, unsigned int)
68
69 #define NCP_IOC_GET_FS_INFO_V2_32       _IOWR('n', 4, struct ncp_fs_info_v2_32)
70
71 #define NCP_IOC_GETOBJECTNAME_32        _IOWR('n', 9, struct ncp_objectname_ioctl_32)
72 #define NCP_IOC_SETOBJECTNAME_32        _IOR('n', 9, struct ncp_objectname_ioctl_32)
73 #define NCP_IOC_GETPRIVATEDATA_32       _IOWR('n', 10, struct ncp_privatedata_ioctl_32)
74 #define NCP_IOC_SETPRIVATEDATA_32       _IOR('n', 10, struct ncp_privatedata_ioctl_32)
75
76 static int do_ncp_ncprequest(unsigned int fd, unsigned int cmd, unsigned long arg)
77 {
78         struct ncp_ioctl_request_32 n32;
79         struct ncp_ioctl_request n;
80         mm_segment_t old_fs;
81         int err;
82
83         if (copy_from_user(&n32, (struct ncp_ioctl_request_32*)arg,
84             sizeof(n32)))
85                 return -EFAULT;
86
87         n.function = n32.function;
88         n.size = n32.size;
89         if (n.size > 65536)
90                 return -EINVAL;
91         n.data = vmalloc(65536);        /* 65536 must be same as NCP_PACKET_SIZE_INTERNAL in ncpfs */
92         if (!n.data)
93                 return -ENOMEM;
94         err = -EFAULT;
95         if (copy_from_user(n.data, (void *)A(n32.data), n.size))
96                 goto out;
97
98         old_fs = get_fs(); set_fs (KERNEL_DS);
99         err = sys_ioctl (fd, NCP_IOC_NCPREQUEST, (unsigned long)&n);
100         set_fs (old_fs);
101         if(err <= 0)
102                 goto out;
103         if (err > 65536) {
104                 err = -EINVAL;
105                 goto out;
106         }
107         if (copy_to_user((void *)A(n32.data), n.data, err)) {
108                 err = -EFAULT;
109                 goto out;
110         }
111  out:
112         vfree(n.data);
113         return err;
114 }
115
116 static int do_ncp_getmountuid2(unsigned int fd, unsigned int cmd, unsigned long arg)
117 {
118         mm_segment_t old_fs = get_fs();
119         __kernel_uid_t kuid;
120         int err;
121
122         cmd = NCP_IOC_GETMOUNTUID2;
123
124         set_fs(KERNEL_DS);
125         err = sys_ioctl(fd, cmd, (unsigned long)&kuid);
126         set_fs(old_fs);
127
128         if (!err)
129                 err = put_user(kuid, (unsigned int*)arg);
130
131         return err;
132 }
133
134 static int do_ncp_getfsinfo2(unsigned int fd, unsigned int cmd, unsigned long arg)
135 {
136         mm_segment_t old_fs = get_fs();
137         struct ncp_fs_info_v2_32 n32;
138         struct ncp_fs_info_v2 n;
139         int err;
140
141         if (copy_from_user(&n32, (struct ncp_fs_info_v2_32*)arg, sizeof(n32)))
142                 return -EFAULT;
143         if (n32.version != NCP_GET_FS_INFO_VERSION_V2)
144                 return -EINVAL;
145         n.version = NCP_GET_FS_INFO_VERSION_V2;
146
147         set_fs(KERNEL_DS);
148         err = sys_ioctl(fd, NCP_IOC_GET_FS_INFO_V2, (unsigned long)&n);
149         set_fs(old_fs);
150
151         if (!err) {
152                 n32.version = n.version;
153                 n32.mounted_uid = n.mounted_uid;
154                 n32.connection = n.connection;
155                 n32.buffer_size = n.buffer_size;
156                 n32.volume_number = n.volume_number;
157                 n32.directory_id = n.directory_id;
158                 n32.dummy1 = n.dummy1;
159                 n32.dummy2 = n.dummy2;
160                 n32.dummy3 = n.dummy3;
161                 err = copy_to_user((struct ncp_fs_info_v2_32*)arg, &n32, sizeof(n32)) ? -EFAULT : 0;
162         }
163         return err;
164 }
165
166 static int do_ncp_getobjectname(unsigned int fd, unsigned int cmd, unsigned long arg)
167 {
168         struct ncp_objectname_ioctl_32 n32;
169         struct ncp_objectname_ioctl n;
170         mm_segment_t old_fs;
171         int err;
172         size_t tl;
173
174         if (copy_from_user(&n32, (struct ncp_objectname_ioctl_32*)arg,
175             sizeof(n32)))
176                 return -EFAULT;
177
178         n.object_name_len = tl = n32.object_name_len;
179         if (tl) {
180                 n.object_name = kmalloc(tl, GFP_KERNEL);
181                 if (!n.object_name)
182                         return -ENOMEM;
183         } else {
184                 n.object_name = NULL;
185         }
186
187         old_fs = get_fs(); set_fs (KERNEL_DS);
188         err = sys_ioctl (fd, NCP_IOC_GETOBJECTNAME, (unsigned long)&n);
189         set_fs (old_fs);
190         if(err)
191                 goto out;
192                 
193         if (tl > n.object_name_len)
194                 tl = n.object_name_len;
195
196         err = -EFAULT;
197         if (tl && copy_to_user((void *)A(n32.object_name), n.object_name, tl))
198                 goto out;
199
200         n32.auth_type = n.auth_type;
201         n32.object_name_len = n.object_name_len;
202         
203         if (copy_to_user((struct ncp_objectname_ioctl_32*)arg, &n32, sizeof(n32)))
204                 goto out;
205         
206         err = 0;
207  out:
208         if (n.object_name)
209                 kfree(n.object_name);
210
211         return err;
212 }
213
214 static int do_ncp_setobjectname(unsigned int fd, unsigned int cmd, unsigned long arg)
215 {
216         struct ncp_objectname_ioctl_32 n32;
217         struct ncp_objectname_ioctl n;
218         mm_segment_t old_fs;
219         int err;
220         size_t tl;
221
222         if (copy_from_user(&n32, (struct ncp_objectname_ioctl_32*)arg,
223             sizeof(n32)))
224                 return -EFAULT;
225
226         n.auth_type = n32.auth_type;
227         n.object_name_len = tl = n32.object_name_len;
228         if (tl) {
229                 n.object_name = kmalloc(tl, GFP_KERNEL);
230                 if (!n.object_name)
231                         return -ENOMEM;
232                 err = -EFAULT;
233                 if (copy_from_user(n.object_name, (void *)A(n32.object_name), tl))
234                         goto out;
235         } else {
236                 n.object_name = NULL;
237         }
238         
239         old_fs = get_fs(); set_fs (KERNEL_DS);
240         err = sys_ioctl (fd, NCP_IOC_SETOBJECTNAME, (unsigned long)&n);
241         set_fs (old_fs);
242                 
243  out:
244         if (n.object_name)
245                 kfree(n.object_name);
246
247         return err;
248 }
249
250 static int do_ncp_getprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg)
251 {
252         struct ncp_privatedata_ioctl_32 n32;
253         struct ncp_privatedata_ioctl n;
254         mm_segment_t old_fs;
255         int err;
256         size_t tl;
257
258         if (copy_from_user(&n32, (struct ncp_privatedata_ioctl_32*)arg,
259             sizeof(n32)))
260                 return -EFAULT;
261
262         n.len = tl = n32.len;
263         if (tl) {
264                 n.data = kmalloc(tl, GFP_KERNEL);
265                 if (!n.data)
266                         return -ENOMEM;
267         } else {
268                 n.data = NULL;
269         }
270
271         old_fs = get_fs(); set_fs (KERNEL_DS);
272         err = sys_ioctl (fd, NCP_IOC_GETPRIVATEDATA, (unsigned long)&n);
273         set_fs (old_fs);
274         if(err)
275                 goto out;
276                 
277         if (tl > n.len)
278                 tl = n.len;
279
280         err = -EFAULT;
281         if (tl && copy_to_user((void *)A(n32.data), n.data, tl))
282                 goto out;
283
284         n32.len = n.len;
285         
286         if (copy_to_user((struct ncp_privatedata_ioctl_32*)arg, &n32, sizeof(n32)))
287                 goto out;
288         
289         err = 0;
290  out:
291         if (n.data)
292                 kfree(n.data);
293
294         return err;
295 }
296
297 static int do_ncp_setprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg)
298 {
299         struct ncp_privatedata_ioctl_32 n32;
300         struct ncp_privatedata_ioctl n;
301         mm_segment_t old_fs;
302         int err;
303         size_t tl;
304
305         if (copy_from_user(&n32, (struct ncp_privatedata_ioctl_32*)arg,
306             sizeof(n32)))
307                 return -EFAULT;
308
309         n.len = tl = n32.len;
310         if (tl) {
311                 n.data = kmalloc(tl, GFP_KERNEL);
312                 if (!n.data)
313                         return -ENOMEM;
314                 err = -EFAULT;
315                 if (copy_from_user(n.data, (void *)A(n32.data), tl))
316                         goto out;
317         } else {
318                 n.data = NULL;
319         }
320         
321         old_fs = get_fs(); set_fs (KERNEL_DS);
322         err = sys_ioctl (fd, NCP_IOC_SETPRIVATEDATA, (unsigned long)&n);
323         set_fs (old_fs);
324                 
325  out:
326         if (n.data)
327                 kfree(n.data);
328
329         return err;
330 }
331
332
333 #define HANDLE_IOCTL(cmd,handler) { cmd, (ioctl_trans_handler_t)handler, 0 },
334 #define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL(cmd,sys_ioctl)
335
336 #define IOCTL_TABLE_START \
337         struct ioctl_trans ioctl_start[] = {
338 #define IOCTL_TABLE_END \
339         };
340
341 IOCTL_TABLE_START
342 #include <linux/compat_ioctl.h>
343 #define DECLARES
344 #include "compat_ioctl.c"
345 COMPATIBLE_IOCTL(TCSBRKP)
346 COMPATIBLE_IOCTL(TIOCSTART)
347 COMPATIBLE_IOCTL(TIOCSTOP)
348 COMPATIBLE_IOCTL(TIOCSLTC)
349 /* Little p (/dev/rtc, /dev/envctrl, etc.) */
350 COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */
351 COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */
352
353 /* And these ioctls need translation */
354
355 /* NCPFS */
356 HANDLE_IOCTL(NCP_IOC_NCPREQUEST_32, do_ncp_ncprequest)
357 HANDLE_IOCTL(NCP_IOC_GETMOUNTUID2_32, do_ncp_getmountuid2)
358 HANDLE_IOCTL(NCP_IOC_GET_FS_INFO_V2_32, do_ncp_getfsinfo2)
359 HANDLE_IOCTL(NCP_IOC_GETOBJECTNAME_32, do_ncp_getobjectname)
360 HANDLE_IOCTL(NCP_IOC_SETOBJECTNAME_32, do_ncp_setobjectname)
361 HANDLE_IOCTL(NCP_IOC_GETPRIVATEDATA_32, do_ncp_getprivatedata)
362 HANDLE_IOCTL(NCP_IOC_SETPRIVATEDATA_32, do_ncp_setprivatedata)
363
364 IOCTL_TABLE_END
365
366 int ioctl_table_size = ARRAY_SIZE(ioctl_start);