aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/infiniband/core/user_mad.c49
-rw-r--r--include/rdma/ib_user_mad.h22
2 files changed, 61 insertions, 10 deletions
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index aee29139368c..b53eac4611de 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -44,6 +44,7 @@
44#include <linux/poll.h> 44#include <linux/poll.h>
45#include <linux/rwsem.h> 45#include <linux/rwsem.h>
46#include <linux/kref.h> 46#include <linux/kref.h>
47#include <linux/compat.h>
47 48
48#include <asm/uaccess.h> 49#include <asm/uaccess.h>
49#include <asm/semaphore.h> 50#include <asm/semaphore.h>
@@ -607,7 +608,8 @@ static unsigned int ib_umad_poll(struct file *filp, struct poll_table_struct *wa
607 return mask; 608 return mask;
608} 609}
609 610
610static int ib_umad_reg_agent(struct ib_umad_file *file, unsigned long arg) 611static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg,
612 int compat_method_mask)
611{ 613{
612 struct ib_user_mad_reg_req ureq; 614 struct ib_user_mad_reg_req ureq;
613 struct ib_mad_reg_req req; 615 struct ib_mad_reg_req req;
@@ -622,7 +624,7 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, unsigned long arg)
622 goto out; 624 goto out;
623 } 625 }
624 626
625 if (copy_from_user(&ureq, (void __user *) arg, sizeof ureq)) { 627 if (copy_from_user(&ureq, arg, sizeof ureq)) {
626 ret = -EFAULT; 628 ret = -EFAULT;
627 goto out; 629 goto out;
628 } 630 }
@@ -643,8 +645,18 @@ found:
643 if (ureq.mgmt_class) { 645 if (ureq.mgmt_class) {
644 req.mgmt_class = ureq.mgmt_class; 646 req.mgmt_class = ureq.mgmt_class;
645 req.mgmt_class_version = ureq.mgmt_class_version; 647 req.mgmt_class_version = ureq.mgmt_class_version;
646 memcpy(req.method_mask, ureq.method_mask, sizeof req.method_mask); 648 memcpy(req.oui, ureq.oui, sizeof req.oui);
647 memcpy(req.oui, ureq.oui, sizeof req.oui); 649
650 if (compat_method_mask) {
651 u32 *umm = (u32 *) ureq.method_mask;
652 int i;
653
654 for (i = 0; i < BITS_TO_LONGS(IB_MGMT_MAX_METHODS); ++i)
655 req.method_mask[i] =
656 umm[i * 2] | ((u64) umm[i * 2 + 1] << 32);
657 } else
658 memcpy(req.method_mask, ureq.method_mask,
659 sizeof req.method_mask);
648 } 660 }
649 661
650 agent = ib_register_mad_agent(file->port->ib_dev, file->port->port_num, 662 agent = ib_register_mad_agent(file->port->ib_dev, file->port->port_num,
@@ -682,13 +694,13 @@ out:
682 return ret; 694 return ret;
683} 695}
684 696
685static int ib_umad_unreg_agent(struct ib_umad_file *file, unsigned long arg) 697static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
686{ 698{
687 struct ib_mad_agent *agent = NULL; 699 struct ib_mad_agent *agent = NULL;
688 u32 id; 700 u32 id;
689 int ret = 0; 701 int ret = 0;
690 702
691 if (get_user(id, (u32 __user *) arg)) 703 if (get_user(id, arg))
692 return -EFAULT; 704 return -EFAULT;
693 705
694 down_write(&file->port->mutex); 706 down_write(&file->port->mutex);
@@ -729,9 +741,9 @@ static long ib_umad_ioctl(struct file *filp, unsigned int cmd,
729{ 741{
730 switch (cmd) { 742 switch (cmd) {
731 case IB_USER_MAD_REGISTER_AGENT: 743 case IB_USER_MAD_REGISTER_AGENT:
732 return ib_umad_reg_agent(filp->private_data, arg); 744 return ib_umad_reg_agent(filp->private_data, (void __user *) arg, 0);
733 case IB_USER_MAD_UNREGISTER_AGENT: 745 case IB_USER_MAD_UNREGISTER_AGENT:
734 return ib_umad_unreg_agent(filp->private_data, arg); 746 return ib_umad_unreg_agent(filp->private_data, (__u32 __user *) arg);
735 case IB_USER_MAD_ENABLE_PKEY: 747 case IB_USER_MAD_ENABLE_PKEY:
736 return ib_umad_enable_pkey(filp->private_data); 748 return ib_umad_enable_pkey(filp->private_data);
737 default: 749 default:
@@ -739,6 +751,23 @@ static long ib_umad_ioctl(struct file *filp, unsigned int cmd,
739 } 751 }
740} 752}
741 753
754#ifdef CONFIG_COMPAT
755static long ib_umad_compat_ioctl(struct file *filp, unsigned int cmd,
756 unsigned long arg)
757{
758 switch (cmd) {
759 case IB_USER_MAD_REGISTER_AGENT:
760 return ib_umad_reg_agent(filp->private_data, compat_ptr(arg), 1);
761 case IB_USER_MAD_UNREGISTER_AGENT:
762 return ib_umad_unreg_agent(filp->private_data, compat_ptr(arg));
763 case IB_USER_MAD_ENABLE_PKEY:
764 return ib_umad_enable_pkey(filp->private_data);
765 default:
766 return -ENOIOCTLCMD;
767 }
768}
769#endif
770
742static int ib_umad_open(struct inode *inode, struct file *filp) 771static int ib_umad_open(struct inode *inode, struct file *filp)
743{ 772{
744 struct ib_umad_port *port; 773 struct ib_umad_port *port;
@@ -826,7 +855,9 @@ static const struct file_operations umad_fops = {
826 .write = ib_umad_write, 855 .write = ib_umad_write,
827 .poll = ib_umad_poll, 856 .poll = ib_umad_poll,
828 .unlocked_ioctl = ib_umad_ioctl, 857 .unlocked_ioctl = ib_umad_ioctl,
829 .compat_ioctl = ib_umad_ioctl, 858#ifdef CONFIG_COMPAT
859 .compat_ioctl = ib_umad_compat_ioctl,
860#endif
830 .open = ib_umad_open, 861 .open = ib_umad_open,
831 .release = ib_umad_close 862 .release = ib_umad_close
832}; 863};
diff --git a/include/rdma/ib_user_mad.h b/include/rdma/ib_user_mad.h
index 2a32043d1abd..29d2c7205a90 100644
--- a/include/rdma/ib_user_mad.h
+++ b/include/rdma/ib_user_mad.h
@@ -147,6 +147,26 @@ struct ib_user_mad {
147 __u64 data[0]; 147 __u64 data[0];
148}; 148};
149 149
150/*
151 * Earlier versions of this interface definition declared the
152 * method_mask[] member as an array of __u32 but treated it as a
153 * bitmap made up of longs in the kernel. This ambiguity meant that
154 * 32-bit big-endian applications that can run on both 32-bit and
155 * 64-bit kernels had no consistent ABI to rely on, and 64-bit
156 * big-endian applications that treated method_mask as being made up
157 * of 32-bit words would have their bitmap misinterpreted.
158 *
159 * To clear up this confusion, we change the declaration of
160 * method_mask[] to use unsigned long and handle the conversion from
161 * 32-bit userspace to 64-bit kernel for big-endian systems in the
162 * compat_ioctl method. Unfortunately, to keep the structure layout
163 * the same, we need the method_mask[] array to be aligned only to 4
164 * bytes even when long is 64 bits, which forces us into this ugly
165 * typedef.
166 */
167typedef unsigned long __attribute__((aligned(4))) packed_ulong;
168#define IB_USER_MAD_LONGS_PER_METHOD_MASK (128 / (8 * sizeof (long)))
169
150/** 170/**
151 * ib_user_mad_reg_req - MAD registration request 171 * ib_user_mad_reg_req - MAD registration request
152 * @id - Set by the kernel; used to identify agent in future requests. 172 * @id - Set by the kernel; used to identify agent in future requests.
@@ -165,7 +185,7 @@ struct ib_user_mad {
165 */ 185 */
166struct ib_user_mad_reg_req { 186struct ib_user_mad_reg_req {
167 __u32 id; 187 __u32 id;
168 __u32 method_mask[4]; 188 packed_ulong method_mask[IB_USER_MAD_LONGS_PER_METHOD_MASK];
169 __u8 qpn; 189 __u8 qpn;
170 __u8 mgmt_class; 190 __u8 mgmt_class;
171 __u8 mgmt_class_version; 191 __u8 mgmt_class_version;