Commit 6a94f920 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds
Browse files

[PATCH] ipmi: add 32-bit ioctl translations for 64-bit platforms




)

From: Corey Minyard <minyard@acm.org>

This contains the patch for supporting 32-bit compatible ioctls on x86_64
systems.  The current x86_64 driver will not work with 32-bit applications.

Signed-off-by: default avatarJordan Hargave <jordan_hargrave@dell.com>
Signed-off-by: default avatarCorey Minyard <minyard@acm.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 77cf3973
Loading
Loading
Loading
Loading
+196 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
#include <asm/semaphore.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/compat.h>

#define IPMI_DEVINTF_VERSION "v33"

@@ -500,10 +501,205 @@ static int ipmi_ioctl(struct inode *inode,
	return rv;
}

#ifdef CONFIG_COMPAT

/*
 * The following code contains code for supporting 32-bit compatible
 * ioctls on 64-bit kernels.  This allows running 32-bit apps on the
 * 64-bit kernel
 */
#define COMPAT_IPMICTL_SEND_COMMAND	\
	_IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req)
#define COMPAT_IPMICTL_SEND_COMMAND_SETTIME	\
	_IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime)
#define COMPAT_IPMICTL_RECEIVE_MSG	\
	_IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv)
#define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC	\
	_IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv)

struct compat_ipmi_msg {
	u8		netfn;
	u8		cmd;
	u16		data_len;
	compat_uptr_t	data;
};

struct compat_ipmi_req {
	compat_uptr_t		addr;
	compat_uint_t		addr_len;
	compat_long_t		msgid;
	struct compat_ipmi_msg	msg;
};

struct compat_ipmi_recv {
	compat_int_t		recv_type;
	compat_uptr_t		addr;
	compat_uint_t		addr_len;
	compat_long_t		msgid;
	struct compat_ipmi_msg	msg;
};

struct compat_ipmi_req_settime {
	struct compat_ipmi_req	req;
	compat_int_t		retries;
	compat_uint_t		retry_time_ms;
};

/*
 * Define some helper functions for copying IPMI data
 */
static long get_compat_ipmi_msg(struct ipmi_msg *p64,
				struct compat_ipmi_msg __user *p32)
{
	compat_uptr_t tmp;

	if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
			__get_user(p64->netfn, &p32->netfn) ||
			__get_user(p64->cmd, &p32->cmd) ||
			__get_user(p64->data_len, &p32->data_len) ||
			__get_user(tmp, &p32->data))
		return -EFAULT;
	p64->data = compat_ptr(tmp);
	return 0;
}

static long put_compat_ipmi_msg(struct ipmi_msg *p64,
				struct compat_ipmi_msg __user *p32)
{
	if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
			__put_user(p64->netfn, &p32->netfn) ||
			__put_user(p64->cmd, &p32->cmd) ||
			__put_user(p64->data_len, &p32->data_len))
		return -EFAULT;
	return 0;
}

static long get_compat_ipmi_req(struct ipmi_req *p64,
				struct compat_ipmi_req __user *p32)
{

	compat_uptr_t	tmp;

	if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
			__get_user(tmp, &p32->addr) ||
			__get_user(p64->addr_len, &p32->addr_len) ||
			__get_user(p64->msgid, &p32->msgid) ||
			get_compat_ipmi_msg(&p64->msg, &p32->msg))
		return -EFAULT;
	p64->addr = compat_ptr(tmp);
	return 0;
}

static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
		struct compat_ipmi_req_settime __user *p32)
{
	if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
			get_compat_ipmi_req(&p64->req, &p32->req) ||
			__get_user(p64->retries, &p32->retries) ||
			__get_user(p64->retry_time_ms, &p32->retry_time_ms))
		return -EFAULT;
	return 0;
}

static long get_compat_ipmi_recv(struct ipmi_recv *p64,
				 struct compat_ipmi_recv __user *p32)
{
	compat_uptr_t tmp;

	if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
			__get_user(p64->recv_type, &p32->recv_type) ||
			__get_user(tmp, &p32->addr) ||
			__get_user(p64->addr_len, &p32->addr_len) ||
			__get_user(p64->msgid, &p32->msgid) ||
			get_compat_ipmi_msg(&p64->msg, &p32->msg))
		return -EFAULT;
	p64->addr = compat_ptr(tmp);
	return 0;
}

static long put_compat_ipmi_recv(struct ipmi_recv *p64,
				 struct compat_ipmi_recv __user *p32)
{
	if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
			__put_user(p64->recv_type, &p32->recv_type) ||
			__put_user(p64->addr_len, &p32->addr_len) ||
			__put_user(p64->msgid, &p32->msgid) ||
			put_compat_ipmi_msg(&p64->msg, &p32->msg))
		return -EFAULT;
	return 0;
}

/*
 * Handle compatibility ioctls
 */
static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
			      unsigned long arg)
{
	int rc;
	struct ipmi_file_private *priv = filep->private_data;

	switch(cmd) {
	case COMPAT_IPMICTL_SEND_COMMAND:
	{
		struct ipmi_req	rp;

		if (get_compat_ipmi_req(&rp, compat_ptr(arg)))
			return -EFAULT;

		return handle_send_req(priv->user, &rp,
				priv->default_retries,
				priv->default_retry_time_ms);
	}
	case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
	{
		struct ipmi_req_settime	sp;

		if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg)))
			return -EFAULT;

		return handle_send_req(priv->user, &sp.req,
				sp.retries, sp.retry_time_ms);
	}
	case COMPAT_IPMICTL_RECEIVE_MSG:
	case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
	{
		struct ipmi_recv   *precv64, recv64;

		if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
			return -EFAULT;

		precv64 = compat_alloc_user_space(sizeof(recv64));
		if (copy_to_user(precv64, &recv64, sizeof(recv64)))
			return -EFAULT;

		rc = ipmi_ioctl(filep->f_dentry->d_inode, filep,
				((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
				 ? IPMICTL_RECEIVE_MSG
				 : IPMICTL_RECEIVE_MSG_TRUNC),
				(long) precv64);
		if (rc != 0)
			return rc;

		if (copy_from_user(&recv64, precv64, sizeof(recv64)))
			return -EFAULT;

		if (put_compat_ipmi_recv(&recv64, compat_ptr(arg)))
			return -EFAULT;

		return rc;
	}
	default:
		return ipmi_ioctl(filep->f_dentry->d_inode, filep, cmd, arg);
	}
}
#endif

static struct file_operations ipmi_fops = {
	.owner		= THIS_MODULE,
	.ioctl		= ipmi_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl   = compat_ipmi_ioctl,
#endif
	.open		= ipmi_open,
	.release	= ipmi_release,
	.fasync		= ipmi_fasync,