1/*
2 * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
3 *
4 *  S390 version
5 *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 *    Author(s): Gerhard Tonn (ton@de.ibm.com)
7 *
8 * Heavily inspired by the 32-bit Sparc compat code which is
9 * Copyright (C) 2000 Silicon Graphics, Inc.
10 * Written by Ulf Carlsson (ulfc@engr.sgi.com)
11 *
12 */
13
14#include <linux/types.h>
15#include <linux/kernel.h>
16#include <linux/fs.h>
17#include <linux/sched.h>
18#include <linux/mm.h>
19#include <linux/init.h>
20#include <linux/file.h>
21#include <linux/vt.h>
22#include <linux/kd.h>
23#include <linux/netdevice.h>
24#include <linux/route.h>
25#include <linux/ext2_fs.h>
26#include <linux/hdreg.h>
27#include <linux/if_bonding.h>
28#include <asm/types.h>
29#include <asm/uaccess.h>
30#include <asm/dasd.h>
31#include <asm/sockios.h>
32
33#include "linux32.h"
34
35long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
36
37struct hd_geometry32 {
38	unsigned char	heads;
39	unsigned char	sectors;
40	unsigned short	cylinders;
41	__u32		start;
42};
43
44static inline int hd_geometry_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
45{
46	struct hd_geometry32 *hg32 = (struct hd_geometry32 *) A(arg);
47	struct hd_geometry hg;
48	int ret;
49	mm_segment_t old_fs = get_fs();
50
51	set_fs (KERNEL_DS);
52	ret = sys_ioctl (fd, cmd, (long)&hg);
53	set_fs (old_fs);
54
55	if (ret)
56		return ret;
57
58	ret = put_user (hg.heads, &(hg32->heads));
59	ret |= __put_user (hg.sectors, &(hg32->sectors));
60	ret |= __put_user (hg.cylinders, &(hg32->cylinders));
61	ret |= __put_user (hg.start, &(hg32->start));
62
63	return ret;
64}
65
66struct timeval32 {
67	int tv_sec;
68	int tv_usec;
69};
70
71#define EXT2_IOC32_GETFLAGS               _IOR('f', 1, int)
72#define EXT2_IOC32_SETFLAGS               _IOW('f', 2, int)
73#define EXT2_IOC32_GETVERSION             _IOR('v', 1, int)
74#define EXT2_IOC32_SETVERSION             _IOW('v', 2, int)
75
76struct ifmap32 {
77	unsigned int mem_start;
78	unsigned int mem_end;
79	unsigned short base_addr;
80	unsigned char irq;
81	unsigned char dma;
82	unsigned char port;
83};
84
85struct ifreq32 {
86#define IFHWADDRLEN     6
87#define IFNAMSIZ        16
88        union {
89                char    ifrn_name[IFNAMSIZ];	/* if name, e.g. "en0" */
90        } ifr_ifrn;
91        union {
92                struct  sockaddr ifru_addr;
93                struct  sockaddr ifru_dstaddr;
94                struct  sockaddr ifru_broadaddr;
95                struct  sockaddr ifru_netmask;
96                struct  sockaddr ifru_hwaddr;
97                short   ifru_flags;
98                int     ifru_ivalue;
99                int     ifru_mtu;
100                struct  ifmap32 ifru_map;
101                char    ifru_slave[IFNAMSIZ];   /* Just fits the size */
102		char	ifru_newname[IFNAMSIZ];
103                __u32	ifru_data;
104        } ifr_ifru;
105};
106
107struct ifconf32 {
108        int     ifc_len;                        /* size of buffer       */
109        __u32	ifcbuf;
110};
111
112static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg)
113{
114	struct ireq32 *uir32 = (struct ireq32 *) A(arg);
115	struct net_device *dev;
116	struct ifreq32 ifr32;
117
118	if (copy_from_user(&ifr32, uir32, sizeof(struct ifreq32)))
119		return -EFAULT;
120
121	read_lock(&dev_base_lock);
122	dev = __dev_get_by_index(ifr32.ifr_ifindex);
123	if (!dev) {
124		read_unlock(&dev_base_lock);
125		return -ENODEV;
126	}
127
128	strcpy(ifr32.ifr_name, dev->name);
129	read_unlock(&dev_base_lock);
130
131	if (copy_to_user(uir32, &ifr32, sizeof(struct ifreq32)))
132	    return -EFAULT;
133
134	return 0;
135}
136
137static inline int dev_ifconf(unsigned int fd, unsigned int cmd,
138			     unsigned long arg)
139{
140	struct ioconf32 *uifc32 = (struct ioconf32 *) A(arg);
141	struct ifconf32 ifc32;
142	struct ifconf ifc;
143	struct ifreq32 *ifr32;
144	struct ifreq *ifr;
145	mm_segment_t old_fs;
146	int len;
147	int err;
148
149	if (copy_from_user(&ifc32, uifc32, sizeof(struct ifconf32)))
150		return -EFAULT;
151
152	if(ifc32.ifcbuf == 0) {
153		ifc32.ifc_len = 0;
154		ifc.ifc_len = 0;
155		ifc.ifc_buf = NULL;
156	} else {
157		ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32))) *
158			sizeof (struct ifreq);
159		ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL);
160		if (!ifc.ifc_buf)
161			return -ENOMEM;
162	}
163	ifr = ifc.ifc_req;
164	ifr32 = (struct ifreq32 *) A(ifc32.ifcbuf);
165	len = ifc32.ifc_len / sizeof (struct ifreq32);
166	while (len--) {
167		if (copy_from_user(ifr++, ifr32++, sizeof (struct ifreq32))) {
168			err = -EFAULT;
169			goto out;
170		}
171	}
172
173	old_fs = get_fs();
174	set_fs (KERNEL_DS);
175	err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc);
176	set_fs (old_fs);
177	if (err)
178		goto out;
179
180	ifr = ifc.ifc_req;
181	ifr32 = (struct ifreq32 *) A(ifc32.ifcbuf);
182	len = ifc.ifc_len / sizeof (struct ifreq);
183	ifc32.ifc_len = len * sizeof (struct ifreq32);
184
185	while (len--) {
186		if (copy_to_user(ifr32++, ifr++, sizeof (struct ifreq32))) {
187			err = -EFAULT;
188			goto out;
189		}
190	}
191
192	if (copy_to_user(uifc32, &ifc32, sizeof(struct ifconf32))) {
193		err = -EFAULT;
194		goto out;
195	}
196out:
197	if(ifc.ifc_buf != NULL)
198		kfree (ifc.ifc_buf);
199	return err;
200}
201
202static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg)
203{
204	struct ifreq ifr;
205	mm_segment_t old_fs;
206	int err, len;
207	u32 data;
208
209	if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
210		return -EFAULT;
211	ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
212	if (!ifr.ifr_data)
213		return -EAGAIN;
214
215	switch (cmd) {
216	case SIOCBONDENSLAVE:
217	case SIOCBONDRELEASE:
218	case SIOCBONDSETHWADDR:
219	case SIOCBONDCHANGEACTIVE:
220		len = IFNAMSIZ * sizeof(char);
221		break;
222	case SIOCBONDSLAVEINFOQUERY:
223		len = sizeof(struct ifslave);
224		break;
225	case SIOCBONDINFOQUERY:
226		len = sizeof(struct ifbond);
227		break;
228	default:
229		err = -EINVAL;
230		goto out;
231	};
232
233	__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
234	if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) {
235		err = -EFAULT;
236		goto out;
237	}
238
239	old_fs = get_fs();
240	set_fs (KERNEL_DS);
241	err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
242	set_fs (old_fs);
243	if (!err) {
244		len = copy_to_user((char *)A(data), ifr.ifr_data, len);
245		if (len)
246			err = -EFAULT;
247	}
248
249out:
250	free_page((unsigned long)ifr.ifr_data);
251	return err;
252}
253
254static inline int dev_ifsioc(unsigned int fd, unsigned int cmd,
255			     unsigned long arg)
256{
257	struct ifreq32 *uifr = (struct ifreq32 *) A(arg);
258	struct ifreq ifr;
259	mm_segment_t old_fs;
260	int err;
261
262	switch (cmd) {
263	case SIOCSIFMAP:
264		err = copy_from_user(&ifr, uifr, sizeof(ifr.ifr_name));
265		err |= __get_user(ifr.ifr_map.mem_start, &(uifr->ifr_ifru.ifru_map.mem_start));
266		err |= __get_user(ifr.ifr_map.mem_end, &(uifr->ifr_ifru.ifru_map.mem_end));
267		err |= __get_user(ifr.ifr_map.base_addr, &(uifr->ifr_ifru.ifru_map.base_addr));
268		err |= __get_user(ifr.ifr_map.irq, &(uifr->ifr_ifru.ifru_map.irq));
269		err |= __get_user(ifr.ifr_map.dma, &(uifr->ifr_ifru.ifru_map.dma));
270		err |= __get_user(ifr.ifr_map.port, &(uifr->ifr_ifru.ifru_map.port));
271		if (err)
272			return -EFAULT;
273		break;
274	default:
275		if (copy_from_user(&ifr, uifr, sizeof(struct ifreq32)))
276			return -EFAULT;
277		break;
278	}
279	old_fs = get_fs();
280	set_fs (KERNEL_DS);
281	err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
282	set_fs (old_fs);
283	if (!err) {
284		switch (cmd) {
285		case SIOCGIFFLAGS:
286		case SIOCGIFMETRIC:
287		case SIOCGIFMTU:
288		case SIOCGIFMEM:
289		case SIOCGIFHWADDR:
290		case SIOCGIFINDEX:
291		case SIOCGIFADDR:
292		case SIOCGIFBRDADDR:
293		case SIOCGIFDSTADDR:
294		case SIOCGIFNETMASK:
295		case SIOCGIFTXQLEN:
296			if (copy_to_user(uifr, &ifr, sizeof(struct ifreq32)))
297				return -EFAULT;
298			break;
299		case SIOCGIFMAP:
300			err = copy_to_user(uifr, &ifr, sizeof(ifr.ifr_name));
301			err |= __put_user(ifr.ifr_map.mem_start, &(uifr->ifr_ifru.ifru_map.mem_start));
302			err |= __put_user(ifr.ifr_map.mem_end, &(uifr->ifr_ifru.ifru_map.mem_end));
303			err |= __put_user(ifr.ifr_map.base_addr, &(uifr->ifr_ifru.ifru_map.base_addr));
304			err |= __put_user(ifr.ifr_map.irq, &(uifr->ifr_ifru.ifru_map.irq));
305			err |= __put_user(ifr.ifr_map.dma, &(uifr->ifr_ifru.ifru_map.dma));
306			err |= __put_user(ifr.ifr_map.port, &(uifr->ifr_ifru.ifru_map.port));
307			if (err)
308				err = -EFAULT;
309			break;
310		}
311	}
312	return err;
313}
314
315struct rtentry32
316{
317	unsigned int	rt_pad1;
318	struct sockaddr	rt_dst;		/* target address		*/
319	struct sockaddr	rt_gateway;	/* gateway addr (RTF_GATEWAY)	*/
320	struct sockaddr	rt_genmask;	/* target network mask (IP)	*/
321	unsigned short	rt_flags;
322	short		rt_pad2;
323	unsigned int	rt_pad3;
324	unsigned int	rt_pad4;
325	short		rt_metric;	/* +1 for binary compatibility!	*/
326	unsigned int	rt_dev;		/* forcing the device at add	*/
327	unsigned int	rt_mtu;		/* per route MTU/Window 	*/
328#ifndef __KERNEL__
329#define rt_mss	rt_mtu			/* Compatibility :-(            */
330#endif
331	unsigned int	rt_window;	/* Window clamping 		*/
332	unsigned short	rt_irtt;	/* Initial RTT			*/
333};
334
335static inline int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
336{
337	struct rtentry32 *ur = (struct rtentry32 *) A(arg);
338	struct rtentry r;
339	char devname[16];
340	u32 rtdev;
341	int ret;
342	mm_segment_t old_fs = get_fs();
343
344	ret = copy_from_user (&r.rt_dst, &(ur->rt_dst), 3 * sizeof(struct sockaddr));
345	ret |= __get_user (r.rt_flags, &(ur->rt_flags));
346	ret |= __get_user (r.rt_metric, &(ur->rt_metric));
347	ret |= __get_user (r.rt_mtu, &(ur->rt_mtu));
348	ret |= __get_user (r.rt_window, &(ur->rt_window));
349	ret |= __get_user (r.rt_irtt, &(ur->rt_irtt));
350	ret |= __get_user (rtdev, &(ur->rt_dev));
351	if (rtdev) {
352		ret |= copy_from_user (devname, (char *) A(rtdev), 15);
353		r.rt_dev = devname; devname[15] = 0;
354	} else
355		r.rt_dev = 0;
356	if (ret)
357		return -EFAULT;
358	set_fs (KERNEL_DS);
359	ret = sys_ioctl (fd, cmd, (long)&r);
360	set_fs (old_fs);
361	return ret;
362}
363
364static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
365{
366	/* These are just misnamed, they actually get/put from/to user an int */
367	switch (cmd) {
368	case EXT2_IOC32_GETFLAGS: cmd = EXT2_IOC_GETFLAGS; break;
369	case EXT2_IOC32_SETFLAGS: cmd = EXT2_IOC_SETFLAGS; break;
370	case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break;
371	case EXT2_IOC32_SETVERSION: cmd = EXT2_IOC_SETVERSION; break;
372	}
373	return sys_ioctl(fd, cmd, arg);
374}
375
376static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg)
377{
378	mm_segment_t old_fs = get_fs();
379	int err;
380	unsigned long val;
381
382	set_fs (KERNEL_DS);
383	err = sys_ioctl(fd, cmd, (unsigned long)&val);
384	set_fs (old_fs);
385	if (!err && put_user((unsigned int) val, (u32 *)arg))
386		return -EFAULT;
387	return err;
388}
389
390struct ioctl32_handler {
391	unsigned int cmd;
392	int (*function)(unsigned int, unsigned int, unsigned long);
393};
394
395struct ioctl32_list {
396	struct ioctl32_handler handler;
397	struct ioctl32_list *next;
398};
399
400#define IOCTL32_DEFAULT(cmd)		{ { cmd, (void *) sys_ioctl }, 0 }
401#define IOCTL32_HANDLER(cmd, handler)	{ { cmd, (void *) handler }, 0 }
402
403static struct ioctl32_list ioctl32_handler_table[] = {
404	IOCTL32_DEFAULT(FIBMAP),
405	IOCTL32_DEFAULT(FIGETBSZ),
406
407	IOCTL32_DEFAULT(DASDAPIVER),
408	IOCTL32_DEFAULT(BIODASDDISABLE),
409	IOCTL32_DEFAULT(BIODASDENABLE),
410	IOCTL32_DEFAULT(BIODASDRSRV),
411	IOCTL32_DEFAULT(BIODASDRLSE),
412	IOCTL32_DEFAULT(BIODASDSLCK),
413	IOCTL32_DEFAULT(BIODASDINFO),
414	IOCTL32_DEFAULT(BIODASDFMT),
415
416	IOCTL32_DEFAULT(BLKRRPART),
417
418	IOCTL32_HANDLER(HDIO_GETGEO, hd_geometry_ioctl),
419
420	IOCTL32_DEFAULT(TCGETA),
421	IOCTL32_DEFAULT(TCSETA),
422	IOCTL32_DEFAULT(TCSETAW),
423	IOCTL32_DEFAULT(TCSETAF),
424	IOCTL32_DEFAULT(TCSBRK),
425	IOCTL32_DEFAULT(TCXONC),
426	IOCTL32_DEFAULT(TCFLSH),
427	IOCTL32_DEFAULT(TCGETS),
428	IOCTL32_DEFAULT(TCSETS),
429	IOCTL32_DEFAULT(TCSETSW),
430	IOCTL32_DEFAULT(TCSETSF),
431	IOCTL32_DEFAULT(TIOCLINUX),
432
433	IOCTL32_DEFAULT(TIOCGETD),
434	IOCTL32_DEFAULT(TIOCSETD),
435	IOCTL32_DEFAULT(TIOCEXCL),
436	IOCTL32_DEFAULT(TIOCNXCL),
437	IOCTL32_DEFAULT(TIOCCONS),
438	IOCTL32_DEFAULT(TIOCGSOFTCAR),
439	IOCTL32_DEFAULT(TIOCSSOFTCAR),
440	IOCTL32_DEFAULT(TIOCSWINSZ),
441	IOCTL32_DEFAULT(TIOCGWINSZ),
442	IOCTL32_DEFAULT(TIOCMGET),
443	IOCTL32_DEFAULT(TIOCMBIC),
444	IOCTL32_DEFAULT(TIOCMBIS),
445	IOCTL32_DEFAULT(TIOCMSET),
446	IOCTL32_DEFAULT(TIOCPKT),
447	IOCTL32_DEFAULT(TIOCNOTTY),
448	IOCTL32_DEFAULT(TIOCSTI),
449	IOCTL32_DEFAULT(TIOCOUTQ),
450	IOCTL32_DEFAULT(TIOCSPGRP),
451	IOCTL32_DEFAULT(TIOCGPGRP),
452	IOCTL32_DEFAULT(TIOCSCTTY),
453	IOCTL32_DEFAULT(TIOCGPTN),
454	IOCTL32_DEFAULT(TIOCSPTLCK),
455	IOCTL32_DEFAULT(TIOCGSERIAL),
456	IOCTL32_DEFAULT(TIOCSSERIAL),
457	IOCTL32_DEFAULT(TIOCSERGETLSR),
458
459	IOCTL32_DEFAULT(FIOCLEX),
460	IOCTL32_DEFAULT(FIONCLEX),
461	IOCTL32_DEFAULT(FIOASYNC),
462	IOCTL32_DEFAULT(FIONBIO),
463	IOCTL32_DEFAULT(FIONREAD),
464
465	IOCTL32_DEFAULT(PIO_FONT),
466	IOCTL32_DEFAULT(GIO_FONT),
467	IOCTL32_DEFAULT(KDSIGACCEPT),
468	IOCTL32_DEFAULT(KDGETKEYCODE),
469	IOCTL32_DEFAULT(KDSETKEYCODE),
470	IOCTL32_DEFAULT(KIOCSOUND),
471	IOCTL32_DEFAULT(KDMKTONE),
472	IOCTL32_DEFAULT(KDGKBTYPE),
473	IOCTL32_DEFAULT(KDSETMODE),
474	IOCTL32_DEFAULT(KDGETMODE),
475	IOCTL32_DEFAULT(KDSKBMODE),
476	IOCTL32_DEFAULT(KDGKBMODE),
477	IOCTL32_DEFAULT(KDSKBMETA),
478	IOCTL32_DEFAULT(KDGKBMETA),
479	IOCTL32_DEFAULT(KDGKBENT),
480	IOCTL32_DEFAULT(KDSKBENT),
481	IOCTL32_DEFAULT(KDGKBSENT),
482	IOCTL32_DEFAULT(KDSKBSENT),
483	IOCTL32_DEFAULT(KDGKBDIACR),
484	IOCTL32_DEFAULT(KDSKBDIACR),
485	IOCTL32_DEFAULT(KDGKBLED),
486	IOCTL32_DEFAULT(KDSKBLED),
487	IOCTL32_DEFAULT(KDGETLED),
488	IOCTL32_DEFAULT(KDSETLED),
489	IOCTL32_DEFAULT(GIO_SCRNMAP),
490	IOCTL32_DEFAULT(PIO_SCRNMAP),
491	IOCTL32_DEFAULT(GIO_UNISCRNMAP),
492	IOCTL32_DEFAULT(PIO_UNISCRNMAP),
493	IOCTL32_DEFAULT(PIO_FONTRESET),
494	IOCTL32_DEFAULT(PIO_UNIMAPCLR),
495
496	IOCTL32_DEFAULT(VT_SETMODE),
497	IOCTL32_DEFAULT(VT_GETMODE),
498	IOCTL32_DEFAULT(VT_GETSTATE),
499	IOCTL32_DEFAULT(VT_OPENQRY),
500	IOCTL32_DEFAULT(VT_ACTIVATE),
501	IOCTL32_DEFAULT(VT_WAITACTIVE),
502	IOCTL32_DEFAULT(VT_RELDISP),
503	IOCTL32_DEFAULT(VT_DISALLOCATE),
504	IOCTL32_DEFAULT(VT_RESIZE),
505	IOCTL32_DEFAULT(VT_RESIZEX),
506	IOCTL32_DEFAULT(VT_LOCKSWITCH),
507	IOCTL32_DEFAULT(VT_UNLOCKSWITCH),
508
509	IOCTL32_DEFAULT(SIOCGSTAMP),
510
511	IOCTL32_HANDLER(SIOCGIFNAME, dev_ifname32),
512	IOCTL32_HANDLER(SIOCGIFCONF, dev_ifconf),
513	IOCTL32_HANDLER(SIOCGIFFLAGS, dev_ifsioc),
514	IOCTL32_HANDLER(SIOCSIFFLAGS, dev_ifsioc),
515	IOCTL32_HANDLER(SIOCGIFMETRIC, dev_ifsioc),
516	IOCTL32_HANDLER(SIOCSIFMETRIC, dev_ifsioc),
517	IOCTL32_HANDLER(SIOCGIFMTU, dev_ifsioc),
518	IOCTL32_HANDLER(SIOCSIFMTU, dev_ifsioc),
519	IOCTL32_HANDLER(SIOCGIFMEM, dev_ifsioc),
520	IOCTL32_HANDLER(SIOCSIFMEM, dev_ifsioc),
521	IOCTL32_HANDLER(SIOCGIFHWADDR, dev_ifsioc),
522	IOCTL32_HANDLER(SIOCSIFHWADDR, dev_ifsioc),
523	IOCTL32_HANDLER(SIOCADDMULTI, dev_ifsioc),
524	IOCTL32_HANDLER(SIOCDELMULTI, dev_ifsioc),
525	IOCTL32_HANDLER(SIOCGIFINDEX, dev_ifsioc),
526	IOCTL32_HANDLER(SIOCGIFMAP, dev_ifsioc),
527	IOCTL32_HANDLER(SIOCSIFMAP, dev_ifsioc),
528	IOCTL32_HANDLER(SIOCGIFADDR, dev_ifsioc),
529	IOCTL32_HANDLER(SIOCSIFADDR, dev_ifsioc),
530	IOCTL32_HANDLER(SIOCGIFBRDADDR, dev_ifsioc),
531	IOCTL32_HANDLER(SIOCSIFBRDADDR, dev_ifsioc),
532	IOCTL32_HANDLER(SIOCGIFDSTADDR, dev_ifsioc),
533	IOCTL32_HANDLER(SIOCSIFDSTADDR, dev_ifsioc),
534	IOCTL32_HANDLER(SIOCGIFNETMASK, dev_ifsioc),
535	IOCTL32_HANDLER(SIOCSIFNETMASK, dev_ifsioc),
536	IOCTL32_HANDLER(SIOCSIFPFLAGS, dev_ifsioc),
537	IOCTL32_HANDLER(SIOCGIFPFLAGS, dev_ifsioc),
538	IOCTL32_HANDLER(SIOCGIFTXQLEN, dev_ifsioc),
539	IOCTL32_HANDLER(SIOCSIFTXQLEN, dev_ifsioc),
540	IOCTL32_HANDLER(SIOCADDRT, routing_ioctl),
541	IOCTL32_HANDLER(SIOCDELRT, routing_ioctl),
542
543	IOCTL32_HANDLER(SIOCBONDENSLAVE, bond_ioctl),
544	IOCTL32_HANDLER(SIOCBONDRELEASE, bond_ioctl),
545	IOCTL32_HANDLER(SIOCBONDSETHWADDR, bond_ioctl),
546	IOCTL32_HANDLER(SIOCBONDSLAVEINFOQUERY, bond_ioctl),
547	IOCTL32_HANDLER(SIOCBONDINFOQUERY, bond_ioctl),
548	IOCTL32_HANDLER(SIOCBONDCHANGEACTIVE, bond_ioctl),
549
550	IOCTL32_HANDLER(EXT2_IOC32_GETFLAGS, do_ext2_ioctl),
551	IOCTL32_HANDLER(EXT2_IOC32_SETFLAGS, do_ext2_ioctl),
552	IOCTL32_HANDLER(EXT2_IOC32_GETVERSION, do_ext2_ioctl),
553	IOCTL32_HANDLER(EXT2_IOC32_SETVERSION, do_ext2_ioctl),
554
555	IOCTL32_HANDLER(BLKGETSIZE, w_long)
556
557};
558
559#define NR_IOCTL32_HANDLERS	(sizeof(ioctl32_handler_table) /	\
560				 sizeof(ioctl32_handler_table[0]))
561
562static struct ioctl32_list *ioctl32_hash_table[1024];
563
564static inline int ioctl32_hash(unsigned int cmd)
565{
566	return ((cmd >> 6) ^ (cmd >> 4) ^ cmd) & 0x3ff;
567}
568
569int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
570{
571	int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
572	struct file *filp;
573	struct ioctl32_list *l;
574	int error;
575
576	l = ioctl32_hash_table[ioctl32_hash(cmd)];
577
578	error = -EBADF;
579
580	filp = fget(fd);
581	if (!filp)
582		return error;
583
584	if (!filp->f_op || !filp->f_op->ioctl) {
585		error = sys_ioctl (fd, cmd, arg);
586		goto out;
587	}
588
589	while (l && l->handler.cmd != cmd)
590		l = l->next;
591
592	if (l) {
593		handler = (void *)l->handler.function;
594		error = handler(fd, cmd, arg, filp);
595	} else {
596		error = -EINVAL;
597		printk("unknown ioctl: %08x\n", cmd);
598	}
599out:
600	fput(filp);
601	return error;
602}
603
604static void ioctl32_insert(struct ioctl32_list *entry)
605{
606	int hash = ioctl32_hash(entry->handler.cmd);
607	if (!ioctl32_hash_table[hash])
608		ioctl32_hash_table[hash] = entry;
609	else {
610		struct ioctl32_list *l;
611		l = ioctl32_hash_table[hash];
612		while (l->next)
613			l = l->next;
614		l->next = entry;
615		entry->next = 0;
616	}
617}
618
619static int __init init_ioctl32(void)
620{
621	int i;
622	for (i = 0; i < NR_IOCTL32_HANDLERS; i++)
623		ioctl32_insert(&ioctl32_handler_table[i]);
624	return 0;
625}
626
627__initcall(init_ioctl32);
628