diff options
author | Andrew Morton <akpm@osdl.org> | 2005-06-24 01:01:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-24 03:05:24 -0400 |
commit | 6a94f9209762a6eb286f668e1346ad87985cc765 (patch) | |
tree | 1dbff088e8340cde187fc581a549bacde26d798f /drivers/char/ipmi/ipmi_devintf.c | |
parent | 77cf3973f22c7e7158f5e2c3c3d6809125b77e4b (diff) |
[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: Jordan Hargave <jordan_hargrave@dell.com>
Signed-off-by: Corey Minyard <minyard@acm.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char/ipmi/ipmi_devintf.c')
-rw-r--r-- | drivers/char/ipmi/ipmi_devintf.c | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 88d1ad656e99..e0a53570fea1 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <asm/semaphore.h> | 45 | #include <asm/semaphore.h> |
46 | #include <linux/init.h> | 46 | #include <linux/init.h> |
47 | #include <linux/device.h> | 47 | #include <linux/device.h> |
48 | #include <linux/compat.h> | ||
48 | 49 | ||
49 | #define IPMI_DEVINTF_VERSION "v33" | 50 | #define IPMI_DEVINTF_VERSION "v33" |
50 | 51 | ||
@@ -500,10 +501,205 @@ static int ipmi_ioctl(struct inode *inode, | |||
500 | return rv; | 501 | return rv; |
501 | } | 502 | } |
502 | 503 | ||
504 | #ifdef CONFIG_COMPAT | ||
505 | |||
506 | /* | ||
507 | * The following code contains code for supporting 32-bit compatible | ||
508 | * ioctls on 64-bit kernels. This allows running 32-bit apps on the | ||
509 | * 64-bit kernel | ||
510 | */ | ||
511 | #define COMPAT_IPMICTL_SEND_COMMAND \ | ||
512 | _IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req) | ||
513 | #define COMPAT_IPMICTL_SEND_COMMAND_SETTIME \ | ||
514 | _IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime) | ||
515 | #define COMPAT_IPMICTL_RECEIVE_MSG \ | ||
516 | _IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv) | ||
517 | #define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC \ | ||
518 | _IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv) | ||
519 | |||
520 | struct compat_ipmi_msg { | ||
521 | u8 netfn; | ||
522 | u8 cmd; | ||
523 | u16 data_len; | ||
524 | compat_uptr_t data; | ||
525 | }; | ||
526 | |||
527 | struct compat_ipmi_req { | ||
528 | compat_uptr_t addr; | ||
529 | compat_uint_t addr_len; | ||
530 | compat_long_t msgid; | ||
531 | struct compat_ipmi_msg msg; | ||
532 | }; | ||
533 | |||
534 | struct compat_ipmi_recv { | ||
535 | compat_int_t recv_type; | ||
536 | compat_uptr_t addr; | ||
537 | compat_uint_t addr_len; | ||
538 | compat_long_t msgid; | ||
539 | struct compat_ipmi_msg msg; | ||
540 | }; | ||
541 | |||
542 | struct compat_ipmi_req_settime { | ||
543 | struct compat_ipmi_req req; | ||
544 | compat_int_t retries; | ||
545 | compat_uint_t retry_time_ms; | ||
546 | }; | ||
547 | |||
548 | /* | ||
549 | * Define some helper functions for copying IPMI data | ||
550 | */ | ||
551 | static long get_compat_ipmi_msg(struct ipmi_msg *p64, | ||
552 | struct compat_ipmi_msg __user *p32) | ||
553 | { | ||
554 | compat_uptr_t tmp; | ||
555 | |||
556 | if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || | ||
557 | __get_user(p64->netfn, &p32->netfn) || | ||
558 | __get_user(p64->cmd, &p32->cmd) || | ||
559 | __get_user(p64->data_len, &p32->data_len) || | ||
560 | __get_user(tmp, &p32->data)) | ||
561 | return -EFAULT; | ||
562 | p64->data = compat_ptr(tmp); | ||
563 | return 0; | ||
564 | } | ||
565 | |||
566 | static long put_compat_ipmi_msg(struct ipmi_msg *p64, | ||
567 | struct compat_ipmi_msg __user *p32) | ||
568 | { | ||
569 | if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) || | ||
570 | __put_user(p64->netfn, &p32->netfn) || | ||
571 | __put_user(p64->cmd, &p32->cmd) || | ||
572 | __put_user(p64->data_len, &p32->data_len)) | ||
573 | return -EFAULT; | ||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | static long get_compat_ipmi_req(struct ipmi_req *p64, | ||
578 | struct compat_ipmi_req __user *p32) | ||
579 | { | ||
580 | |||
581 | compat_uptr_t tmp; | ||
582 | |||
583 | if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || | ||
584 | __get_user(tmp, &p32->addr) || | ||
585 | __get_user(p64->addr_len, &p32->addr_len) || | ||
586 | __get_user(p64->msgid, &p32->msgid) || | ||
587 | get_compat_ipmi_msg(&p64->msg, &p32->msg)) | ||
588 | return -EFAULT; | ||
589 | p64->addr = compat_ptr(tmp); | ||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64, | ||
594 | struct compat_ipmi_req_settime __user *p32) | ||
595 | { | ||
596 | if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || | ||
597 | get_compat_ipmi_req(&p64->req, &p32->req) || | ||
598 | __get_user(p64->retries, &p32->retries) || | ||
599 | __get_user(p64->retry_time_ms, &p32->retry_time_ms)) | ||
600 | return -EFAULT; | ||
601 | return 0; | ||
602 | } | ||
603 | |||
604 | static long get_compat_ipmi_recv(struct ipmi_recv *p64, | ||
605 | struct compat_ipmi_recv __user *p32) | ||
606 | { | ||
607 | compat_uptr_t tmp; | ||
608 | |||
609 | if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || | ||
610 | __get_user(p64->recv_type, &p32->recv_type) || | ||
611 | __get_user(tmp, &p32->addr) || | ||
612 | __get_user(p64->addr_len, &p32->addr_len) || | ||
613 | __get_user(p64->msgid, &p32->msgid) || | ||
614 | get_compat_ipmi_msg(&p64->msg, &p32->msg)) | ||
615 | return -EFAULT; | ||
616 | p64->addr = compat_ptr(tmp); | ||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | static long put_compat_ipmi_recv(struct ipmi_recv *p64, | ||
621 | struct compat_ipmi_recv __user *p32) | ||
622 | { | ||
623 | if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) || | ||
624 | __put_user(p64->recv_type, &p32->recv_type) || | ||
625 | __put_user(p64->addr_len, &p32->addr_len) || | ||
626 | __put_user(p64->msgid, &p32->msgid) || | ||
627 | put_compat_ipmi_msg(&p64->msg, &p32->msg)) | ||
628 | return -EFAULT; | ||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | /* | ||
633 | * Handle compatibility ioctls | ||
634 | */ | ||
635 | static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd, | ||
636 | unsigned long arg) | ||
637 | { | ||
638 | int rc; | ||
639 | struct ipmi_file_private *priv = filep->private_data; | ||
640 | |||
641 | switch(cmd) { | ||
642 | case COMPAT_IPMICTL_SEND_COMMAND: | ||
643 | { | ||
644 | struct ipmi_req rp; | ||
645 | |||
646 | if (get_compat_ipmi_req(&rp, compat_ptr(arg))) | ||
647 | return -EFAULT; | ||
648 | |||
649 | return handle_send_req(priv->user, &rp, | ||
650 | priv->default_retries, | ||
651 | priv->default_retry_time_ms); | ||
652 | } | ||
653 | case COMPAT_IPMICTL_SEND_COMMAND_SETTIME: | ||
654 | { | ||
655 | struct ipmi_req_settime sp; | ||
656 | |||
657 | if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg))) | ||
658 | return -EFAULT; | ||
659 | |||
660 | return handle_send_req(priv->user, &sp.req, | ||
661 | sp.retries, sp.retry_time_ms); | ||
662 | } | ||
663 | case COMPAT_IPMICTL_RECEIVE_MSG: | ||
664 | case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC: | ||
665 | { | ||
666 | struct ipmi_recv *precv64, recv64; | ||
667 | |||
668 | if (get_compat_ipmi_recv(&recv64, compat_ptr(arg))) | ||
669 | return -EFAULT; | ||
670 | |||
671 | precv64 = compat_alloc_user_space(sizeof(recv64)); | ||
672 | if (copy_to_user(precv64, &recv64, sizeof(recv64))) | ||
673 | return -EFAULT; | ||
674 | |||
675 | rc = ipmi_ioctl(filep->f_dentry->d_inode, filep, | ||
676 | ((cmd == COMPAT_IPMICTL_RECEIVE_MSG) | ||
677 | ? IPMICTL_RECEIVE_MSG | ||
678 | : IPMICTL_RECEIVE_MSG_TRUNC), | ||
679 | (long) precv64); | ||
680 | if (rc != 0) | ||
681 | return rc; | ||
682 | |||
683 | if (copy_from_user(&recv64, precv64, sizeof(recv64))) | ||
684 | return -EFAULT; | ||
685 | |||
686 | if (put_compat_ipmi_recv(&recv64, compat_ptr(arg))) | ||
687 | return -EFAULT; | ||
688 | |||
689 | return rc; | ||
690 | } | ||
691 | default: | ||
692 | return ipmi_ioctl(filep->f_dentry->d_inode, filep, cmd, arg); | ||
693 | } | ||
694 | } | ||
695 | #endif | ||
503 | 696 | ||
504 | static struct file_operations ipmi_fops = { | 697 | static struct file_operations ipmi_fops = { |
505 | .owner = THIS_MODULE, | 698 | .owner = THIS_MODULE, |
506 | .ioctl = ipmi_ioctl, | 699 | .ioctl = ipmi_ioctl, |
700 | #ifdef CONFIG_COMPAT | ||
701 | .compat_ioctl = compat_ipmi_ioctl, | ||
702 | #endif | ||
507 | .open = ipmi_open, | 703 | .open = ipmi_open, |
508 | .release = ipmi_release, | 704 | .release = ipmi_release, |
509 | .fasync = ipmi_fasync, | 705 | .fasync = ipmi_fasync, |