linux/drivers/char/ipmi/ipmi_devintf.c
<<
>>
Prefs
   1/*
   2 * ipmi_devintf.c
   3 *
   4 * Linux device interface for the IPMI message handler.
   5 *
   6 * Author: MontaVista Software, Inc.
   7 *         Corey Minyard <minyard@mvista.com>
   8 *         source@mvista.com
   9 *
  10 * Copyright 2002 MontaVista Software Inc.
  11 *
  12 *  This program is free software; you can redistribute it and/or modify it
  13 *  under the terms of the GNU General Public License as published by the
  14 *  Free Software Foundation; either version 2 of the License, or (at your
  15 *  option) any later version.
  16 *
  17 *
  18 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  19 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  20 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  21 *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  22 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  24 *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  26 *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  27 *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28 *
  29 *  You should have received a copy of the GNU General Public License along
  30 *  with this program; if not, write to the Free Software Foundation, Inc.,
  31 *  675 Mass Ave, Cambridge, MA 02139, USA.
  32 */
  33
  34#include <linux/module.h>
  35#include <linux/moduleparam.h>
  36#include <linux/errno.h>
  37#include <asm/system.h>
  38#include <linux/poll.h>
  39#include <linux/sched.h>
  40#include <linux/spinlock.h>
  41#include <linux/slab.h>
  42#include <linux/ipmi.h>
  43#include <linux/mutex.h>
  44#include <linux/init.h>
  45#include <linux/device.h>
  46#include <linux/compat.h>
  47
  48struct ipmi_file_private
  49{
  50        ipmi_user_t          user;
  51        spinlock_t           recv_msg_lock;
  52        struct list_head     recv_msgs;
  53        struct file          *file;
  54        struct fasync_struct *fasync_queue;
  55        wait_queue_head_t    wait;
  56        struct mutex         recv_mutex;
  57        int                  default_retries;
  58        unsigned int         default_retry_time_ms;
  59};
  60
  61static DEFINE_MUTEX(ipmi_mutex);
  62static void file_receive_handler(struct ipmi_recv_msg *msg,
  63                                 void                 *handler_data)
  64{
  65        struct ipmi_file_private *priv = handler_data;
  66        int                      was_empty;
  67        unsigned long            flags;
  68
  69        spin_lock_irqsave(&(priv->recv_msg_lock), flags);
  70
  71        was_empty = list_empty(&(priv->recv_msgs));
  72        list_add_tail(&(msg->link), &(priv->recv_msgs));
  73
  74        if (was_empty) {
  75                wake_up_interruptible(&priv->wait);
  76                kill_fasync(&priv->fasync_queue, SIGIO, POLL_IN);
  77        }
  78
  79        spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
  80}
  81
  82static unsigned int ipmi_poll(struct file *file, poll_table *wait)
  83{
  84        struct ipmi_file_private *priv = file->private_data;
  85        unsigned int             mask = 0;
  86        unsigned long            flags;
  87
  88        poll_wait(file, &priv->wait, wait);
  89
  90        spin_lock_irqsave(&priv->recv_msg_lock, flags);
  91
  92        if (!list_empty(&(priv->recv_msgs)))
  93                mask |= (POLLIN | POLLRDNORM);
  94
  95        spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
  96
  97        return mask;
  98}
  99
 100static int ipmi_fasync(int fd, struct file *file, int on)
 101{
 102        struct ipmi_file_private *priv = file->private_data;
 103        int                      result;
 104
 105        mutex_lock(&ipmi_mutex); /* could race against open() otherwise */
 106        result = fasync_helper(fd, file, on, &priv->fasync_queue);
 107        mutex_unlock(&ipmi_mutex);
 108
 109        return (result);
 110}
 111
 112static struct ipmi_user_hndl ipmi_hndlrs =
 113{
 114        .ipmi_recv_hndl = file_receive_handler,
 115};
 116
 117static int ipmi_open(struct inode *inode, struct file *file)
 118{
 119        int                      if_num = iminor(inode);
 120        int                      rv;
 121        struct ipmi_file_private *priv;
 122
 123
 124        priv = kmalloc(sizeof(*priv), GFP_KERNEL);
 125        if (!priv)
 126                return -ENOMEM;
 127
 128        mutex_lock(&ipmi_mutex);
 129        priv->file = file;
 130
 131        rv = ipmi_create_user(if_num,
 132                              &ipmi_hndlrs,
 133                              priv,
 134                              &(priv->user));
 135        if (rv) {
 136                kfree(priv);
 137                goto out;
 138        }
 139
 140        file->private_data = priv;
 141
 142        spin_lock_init(&(priv->recv_msg_lock));
 143        INIT_LIST_HEAD(&(priv->recv_msgs));
 144        init_waitqueue_head(&priv->wait);
 145        priv->fasync_queue = NULL;
 146        mutex_init(&priv->recv_mutex);
 147
 148        /* Use the low-level defaults. */
 149        priv->default_retries = -1;
 150        priv->default_retry_time_ms = 0;
 151
 152out:
 153        mutex_unlock(&ipmi_mutex);
 154        return rv;
 155}
 156
 157static int ipmi_release(struct inode *inode, struct file *file)
 158{
 159        struct ipmi_file_private *priv = file->private_data;
 160        int                      rv;
 161
 162        rv = ipmi_destroy_user(priv->user);
 163        if (rv)
 164                return rv;
 165
 166        /* FIXME - free the messages in the list. */
 167        kfree(priv);
 168
 169        return 0;
 170}
 171
 172static int handle_send_req(ipmi_user_t     user,
 173                           struct ipmi_req *req,
 174                           int             retries,
 175                           unsigned int    retry_time_ms)
 176{
 177        int              rv;
 178        struct ipmi_addr addr;
 179        struct kernel_ipmi_msg msg;
 180
 181        if (req->addr_len > sizeof(struct ipmi_addr))
 182                return -EINVAL;
 183
 184        if (copy_from_user(&addr, req->addr, req->addr_len))
 185                return -EFAULT;
 186
 187        msg.netfn = req->msg.netfn;
 188        msg.cmd = req->msg.cmd;
 189        msg.data_len = req->msg.data_len;
 190        msg.data = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
 191        if (!msg.data)
 192                return -ENOMEM;
 193
 194        /* From here out we cannot return, we must jump to "out" for
 195           error exits to free msgdata. */
 196
 197        rv = ipmi_validate_addr(&addr, req->addr_len);
 198        if (rv)
 199                goto out;
 200
 201        if (req->msg.data != NULL) {
 202                if (req->msg.data_len > IPMI_MAX_MSG_LENGTH) {
 203                        rv = -EMSGSIZE;
 204                        goto out;
 205                }
 206
 207                if (copy_from_user(msg.data,
 208                                   req->msg.data,
 209                                   req->msg.data_len))
 210                {
 211                        rv = -EFAULT;
 212                        goto out;
 213                }
 214        } else {
 215                msg.data_len = 0;
 216        }
 217
 218        rv = ipmi_request_settime(user,
 219                                  &addr,
 220                                  req->msgid,
 221                                  &msg,
 222                                  NULL,
 223                                  0,
 224                                  retries,
 225                                  retry_time_ms);
 226 out:
 227        kfree(msg.data);
 228        return rv;
 229}
 230
 231static int ipmi_ioctl(struct file   *file,
 232                      unsigned int  cmd,
 233                      unsigned long data)
 234{
 235        int                      rv = -EINVAL;
 236        struct ipmi_file_private *priv = file->private_data;
 237        void __user *arg = (void __user *)data;
 238
 239        switch (cmd) 
 240        {
 241        case IPMICTL_SEND_COMMAND:
 242        {
 243                struct ipmi_req req;
 244
 245                if (copy_from_user(&req, arg, sizeof(req))) {
 246                        rv = -EFAULT;
 247                        break;
 248                }
 249
 250                rv = handle_send_req(priv->user,
 251                                     &req,
 252                                     priv->default_retries,
 253                                     priv->default_retry_time_ms);
 254                break;
 255        }
 256
 257        case IPMICTL_SEND_COMMAND_SETTIME:
 258        {
 259                struct ipmi_req_settime req;
 260
 261                if (copy_from_user(&req, arg, sizeof(req))) {
 262                        rv = -EFAULT;
 263                        break;
 264                }
 265
 266                rv = handle_send_req(priv->user,
 267                                     &req.req,
 268                                     req.retries,
 269                                     req.retry_time_ms);
 270                break;
 271        }
 272
 273        case IPMICTL_RECEIVE_MSG:
 274        case IPMICTL_RECEIVE_MSG_TRUNC:
 275        {
 276                struct ipmi_recv      rsp;
 277                int              addr_len;
 278                struct list_head *entry;
 279                struct ipmi_recv_msg  *msg;
 280                unsigned long    flags;
 281                
 282
 283                rv = 0;
 284                if (copy_from_user(&rsp, arg, sizeof(rsp))) {
 285                        rv = -EFAULT;
 286                        break;
 287                }
 288
 289                /* We claim a mutex because we don't want two
 290                   users getting something from the queue at a time.
 291                   Since we have to release the spinlock before we can
 292                   copy the data to the user, it's possible another
 293                   user will grab something from the queue, too.  Then
 294                   the messages might get out of order if something
 295                   fails and the message gets put back onto the
 296                   queue.  This mutex prevents that problem. */
 297                mutex_lock(&priv->recv_mutex);
 298
 299                /* Grab the message off the list. */
 300                spin_lock_irqsave(&(priv->recv_msg_lock), flags);
 301                if (list_empty(&(priv->recv_msgs))) {
 302                        spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
 303                        rv = -EAGAIN;
 304                        goto recv_err;
 305                }
 306                entry = priv->recv_msgs.next;
 307                msg = list_entry(entry, struct ipmi_recv_msg, link);
 308                list_del(entry);
 309                spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
 310
 311                addr_len = ipmi_addr_length(msg->addr.addr_type);
 312                if (rsp.addr_len < addr_len)
 313                {
 314                        rv = -EINVAL;
 315                        goto recv_putback_on_err;
 316                }
 317
 318                if (copy_to_user(rsp.addr, &(msg->addr), addr_len)) {
 319                        rv = -EFAULT;
 320                        goto recv_putback_on_err;
 321                }
 322                rsp.addr_len = addr_len;
 323
 324                rsp.recv_type = msg->recv_type;
 325                rsp.msgid = msg->msgid;
 326                rsp.msg.netfn = msg->msg.netfn;
 327                rsp.msg.cmd = msg->msg.cmd;
 328
 329                if (msg->msg.data_len > 0) {
 330                        if (rsp.msg.data_len < msg->msg.data_len) {
 331                                rv = -EMSGSIZE;
 332                                if (cmd == IPMICTL_RECEIVE_MSG_TRUNC) {
 333                                        msg->msg.data_len = rsp.msg.data_len;
 334                                } else {
 335                                        goto recv_putback_on_err;
 336                                }
 337                        }
 338
 339                        if (copy_to_user(rsp.msg.data,
 340                                         msg->msg.data,
 341                                         msg->msg.data_len))
 342                        {
 343                                rv = -EFAULT;
 344                                goto recv_putback_on_err;
 345                        }
 346                        rsp.msg.data_len = msg->msg.data_len;
 347                } else {
 348                        rsp.msg.data_len = 0;
 349                }
 350
 351                if (copy_to_user(arg, &rsp, sizeof(rsp))) {
 352                        rv = -EFAULT;
 353                        goto recv_putback_on_err;
 354                }
 355
 356                mutex_unlock(&priv->recv_mutex);
 357                ipmi_free_recv_msg(msg);
 358                break;
 359
 360        recv_putback_on_err:
 361                /* If we got an error, put the message back onto
 362                   the head of the queue. */
 363                spin_lock_irqsave(&(priv->recv_msg_lock), flags);
 364                list_add(entry, &(priv->recv_msgs));
 365                spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
 366                mutex_unlock(&priv->recv_mutex);
 367                break;
 368
 369        recv_err:
 370                mutex_unlock(&priv->recv_mutex);
 371                break;
 372        }
 373
 374        case IPMICTL_REGISTER_FOR_CMD:
 375        {
 376                struct ipmi_cmdspec val;
 377
 378                if (copy_from_user(&val, arg, sizeof(val))) {
 379                        rv = -EFAULT;
 380                        break;
 381                }
 382
 383                rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd,
 384                                           IPMI_CHAN_ALL);
 385                break;
 386        }
 387
 388        case IPMICTL_UNREGISTER_FOR_CMD:
 389        {
 390                struct ipmi_cmdspec   val;
 391
 392                if (copy_from_user(&val, arg, sizeof(val))) {
 393                        rv = -EFAULT;
 394                        break;
 395                }
 396
 397                rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd,
 398                                             IPMI_CHAN_ALL);
 399                break;
 400        }
 401
 402        case IPMICTL_REGISTER_FOR_CMD_CHANS:
 403        {
 404                struct ipmi_cmdspec_chans val;
 405
 406                if (copy_from_user(&val, arg, sizeof(val))) {
 407                        rv = -EFAULT;
 408                        break;
 409                }
 410
 411                rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd,
 412                                           val.chans);
 413                break;
 414        }
 415
 416        case IPMICTL_UNREGISTER_FOR_CMD_CHANS:
 417        {
 418                struct ipmi_cmdspec_chans val;
 419
 420                if (copy_from_user(&val, arg, sizeof(val))) {
 421                        rv = -EFAULT;
 422                        break;
 423                }
 424
 425                rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd,
 426                                             val.chans);
 427                break;
 428        }
 429
 430        case IPMICTL_SET_GETS_EVENTS_CMD:
 431        {
 432                int val;
 433
 434                if (copy_from_user(&val, arg, sizeof(val))) {
 435                        rv = -EFAULT;
 436                        break;
 437                }
 438
 439                rv = ipmi_set_gets_events(priv->user, val);
 440                break;
 441        }
 442
 443        /* The next four are legacy, not per-channel. */
 444        case IPMICTL_SET_MY_ADDRESS_CMD:
 445        {
 446                unsigned int val;
 447
 448                if (copy_from_user(&val, arg, sizeof(val))) {
 449                        rv = -EFAULT;
 450                        break;
 451                }
 452
 453                rv = ipmi_set_my_address(priv->user, 0, val);
 454                break;
 455        }
 456
 457        case IPMICTL_GET_MY_ADDRESS_CMD:
 458        {
 459                unsigned int  val;
 460                unsigned char rval;
 461
 462                rv = ipmi_get_my_address(priv->user, 0, &rval);
 463                if (rv)
 464                        break;
 465
 466                val = rval;
 467
 468                if (copy_to_user(arg, &val, sizeof(val))) {
 469                        rv = -EFAULT;
 470                        break;
 471                }
 472                break;
 473        }
 474
 475        case IPMICTL_SET_MY_LUN_CMD:
 476        {
 477                unsigned int val;
 478
 479                if (copy_from_user(&val, arg, sizeof(val))) {
 480                        rv = -EFAULT;
 481                        break;
 482                }
 483
 484                rv = ipmi_set_my_LUN(priv->user, 0, val);
 485                break;
 486        }
 487
 488        case IPMICTL_GET_MY_LUN_CMD:
 489        {
 490                unsigned int  val;
 491                unsigned char rval;
 492
 493                rv = ipmi_get_my_LUN(priv->user, 0, &rval);
 494                if (rv)
 495                        break;
 496
 497                val = rval;
 498
 499                if (copy_to_user(arg, &val, sizeof(val))) {
 500                        rv = -EFAULT;
 501                        break;
 502                }
 503                break;
 504        }
 505
 506        case IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD:
 507        {
 508                struct ipmi_channel_lun_address_set val;
 509
 510                if (copy_from_user(&val, arg, sizeof(val))) {
 511                        rv = -EFAULT;
 512                        break;
 513                }
 514
 515                return ipmi_set_my_address(priv->user, val.channel, val.value);
 516                break;
 517        }
 518
 519        case IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD:
 520        {
 521                struct ipmi_channel_lun_address_set val;
 522
 523                if (copy_from_user(&val, arg, sizeof(val))) {
 524                        rv = -EFAULT;
 525                        break;
 526                }
 527
 528                rv = ipmi_get_my_address(priv->user, val.channel, &val.value);
 529                if (rv)
 530                        break;
 531
 532                if (copy_to_user(arg, &val, sizeof(val))) {
 533                        rv = -EFAULT;
 534                        break;
 535                }
 536                break;
 537        }
 538
 539        case IPMICTL_SET_MY_CHANNEL_LUN_CMD:
 540        {
 541                struct ipmi_channel_lun_address_set val;
 542
 543                if (copy_from_user(&val, arg, sizeof(val))) {
 544                        rv = -EFAULT;
 545                        break;
 546                }
 547
 548                rv = ipmi_set_my_LUN(priv->user, val.channel, val.value);
 549                break;
 550        }
 551
 552        case IPMICTL_GET_MY_CHANNEL_LUN_CMD:
 553        {
 554                struct ipmi_channel_lun_address_set val;
 555
 556                if (copy_from_user(&val, arg, sizeof(val))) {
 557                        rv = -EFAULT;
 558                        break;
 559                }
 560
 561                rv = ipmi_get_my_LUN(priv->user, val.channel, &val.value);
 562                if (rv)
 563                        break;
 564
 565                if (copy_to_user(arg, &val, sizeof(val))) {
 566                        rv = -EFAULT;
 567                        break;
 568                }
 569                break;
 570        }
 571
 572        case IPMICTL_SET_TIMING_PARMS_CMD:
 573        {
 574                struct ipmi_timing_parms parms;
 575
 576                if (copy_from_user(&parms, arg, sizeof(parms))) {
 577                        rv = -EFAULT;
 578                        break;
 579                }
 580
 581                priv->default_retries = parms.retries;
 582                priv->default_retry_time_ms = parms.retry_time_ms;
 583                rv = 0;
 584                break;
 585        }
 586
 587        case IPMICTL_GET_TIMING_PARMS_CMD:
 588        {
 589                struct ipmi_timing_parms parms;
 590
 591                parms.retries = priv->default_retries;
 592                parms.retry_time_ms = priv->default_retry_time_ms;
 593
 594                if (copy_to_user(arg, &parms, sizeof(parms))) {
 595                        rv = -EFAULT;
 596                        break;
 597                }
 598
 599                rv = 0;
 600                break;
 601        }
 602
 603        case IPMICTL_GET_MAINTENANCE_MODE_CMD:
 604        {
 605                int mode;
 606
 607                mode = ipmi_get_maintenance_mode(priv->user);
 608                if (copy_to_user(arg, &mode, sizeof(mode))) {
 609                        rv = -EFAULT;
 610                        break;
 611                }
 612                rv = 0;
 613                break;
 614        }
 615
 616        case IPMICTL_SET_MAINTENANCE_MODE_CMD:
 617        {
 618                int mode;
 619
 620                if (copy_from_user(&mode, arg, sizeof(mode))) {
 621                        rv = -EFAULT;
 622                        break;
 623                }
 624                rv = ipmi_set_maintenance_mode(priv->user, mode);
 625                break;
 626        }
 627        }
 628  
 629        return rv;
 630}
 631
 632/*
 633 * Note: it doesn't make sense to take the BKL here but
 634 *       not in compat_ipmi_ioctl. -arnd
 635 */
 636static long ipmi_unlocked_ioctl(struct file   *file,
 637                                unsigned int  cmd,
 638                                unsigned long data)
 639{
 640        int ret;
 641
 642        mutex_lock(&ipmi_mutex);
 643        ret = ipmi_ioctl(file, cmd, data);
 644        mutex_unlock(&ipmi_mutex);
 645
 646        return ret;
 647}
 648
 649#ifdef CONFIG_COMPAT
 650
 651/*
 652 * The following code contains code for supporting 32-bit compatible
 653 * ioctls on 64-bit kernels.  This allows running 32-bit apps on the
 654 * 64-bit kernel
 655 */
 656#define COMPAT_IPMICTL_SEND_COMMAND     \
 657        _IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req)
 658#define COMPAT_IPMICTL_SEND_COMMAND_SETTIME     \
 659        _IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime)
 660#define COMPAT_IPMICTL_RECEIVE_MSG      \
 661        _IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv)
 662#define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC        \
 663        _IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv)
 664
 665struct compat_ipmi_msg {
 666        u8              netfn;
 667        u8              cmd;
 668        u16             data_len;
 669        compat_uptr_t   data;
 670};
 671
 672struct compat_ipmi_req {
 673        compat_uptr_t           addr;
 674        compat_uint_t           addr_len;
 675        compat_long_t           msgid;
 676        struct compat_ipmi_msg  msg;
 677};
 678
 679struct compat_ipmi_recv {
 680        compat_int_t            recv_type;
 681        compat_uptr_t           addr;
 682        compat_uint_t           addr_len;
 683        compat_long_t           msgid;
 684        struct compat_ipmi_msg  msg;
 685};
 686
 687struct compat_ipmi_req_settime {
 688        struct compat_ipmi_req  req;
 689        compat_int_t            retries;
 690        compat_uint_t           retry_time_ms;
 691};
 692
 693/*
 694 * Define some helper functions for copying IPMI data
 695 */
 696static long get_compat_ipmi_msg(struct ipmi_msg *p64,
 697                                struct compat_ipmi_msg __user *p32)
 698{
 699        compat_uptr_t tmp;
 700
 701        if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
 702                        __get_user(p64->netfn, &p32->netfn) ||
 703                        __get_user(p64->cmd, &p32->cmd) ||
 704                        __get_user(p64->data_len, &p32->data_len) ||
 705                        __get_user(tmp, &p32->data))
 706                return -EFAULT;
 707        p64->data = compat_ptr(tmp);
 708        return 0;
 709}
 710
 711static long put_compat_ipmi_msg(struct ipmi_msg *p64,
 712                                struct compat_ipmi_msg __user *p32)
 713{
 714        if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
 715                        __put_user(p64->netfn, &p32->netfn) ||
 716                        __put_user(p64->cmd, &p32->cmd) ||
 717                        __put_user(p64->data_len, &p32->data_len))
 718                return -EFAULT;
 719        return 0;
 720}
 721
 722static long get_compat_ipmi_req(struct ipmi_req *p64,
 723                                struct compat_ipmi_req __user *p32)
 724{
 725
 726        compat_uptr_t   tmp;
 727
 728        if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
 729                        __get_user(tmp, &p32->addr) ||
 730                        __get_user(p64->addr_len, &p32->addr_len) ||
 731                        __get_user(p64->msgid, &p32->msgid) ||
 732                        get_compat_ipmi_msg(&p64->msg, &p32->msg))
 733                return -EFAULT;
 734        p64->addr = compat_ptr(tmp);
 735        return 0;
 736}
 737
 738static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
 739                struct compat_ipmi_req_settime __user *p32)
 740{
 741        if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
 742                        get_compat_ipmi_req(&p64->req, &p32->req) ||
 743                        __get_user(p64->retries, &p32->retries) ||
 744                        __get_user(p64->retry_time_ms, &p32->retry_time_ms))
 745                return -EFAULT;
 746        return 0;
 747}
 748
 749static long get_compat_ipmi_recv(struct ipmi_recv *p64,
 750                                 struct compat_ipmi_recv __user *p32)
 751{
 752        compat_uptr_t tmp;
 753
 754        if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
 755                        __get_user(p64->recv_type, &p32->recv_type) ||
 756                        __get_user(tmp, &p32->addr) ||
 757                        __get_user(p64->addr_len, &p32->addr_len) ||
 758                        __get_user(p64->msgid, &p32->msgid) ||
 759                        get_compat_ipmi_msg(&p64->msg, &p32->msg))
 760                return -EFAULT;
 761        p64->addr = compat_ptr(tmp);
 762        return 0;
 763}
 764
 765static long put_compat_ipmi_recv(struct ipmi_recv *p64,
 766                                 struct compat_ipmi_recv __user *p32)
 767{
 768        if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
 769                        __put_user(p64->recv_type, &p32->recv_type) ||
 770                        __put_user(p64->addr_len, &p32->addr_len) ||
 771                        __put_user(p64->msgid, &p32->msgid) ||
 772                        put_compat_ipmi_msg(&p64->msg, &p32->msg))
 773                return -EFAULT;
 774        return 0;
 775}
 776
 777/*
 778 * Handle compatibility ioctls
 779 */
 780static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
 781                              unsigned long arg)
 782{
 783        int rc;
 784        struct ipmi_file_private *priv = filep->private_data;
 785
 786        switch(cmd) {
 787        case COMPAT_IPMICTL_SEND_COMMAND:
 788        {
 789                struct ipmi_req rp;
 790
 791                if (get_compat_ipmi_req(&rp, compat_ptr(arg)))
 792                        return -EFAULT;
 793
 794                return handle_send_req(priv->user, &rp,
 795                                priv->default_retries,
 796                                priv->default_retry_time_ms);
 797        }
 798        case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
 799        {
 800                struct ipmi_req_settime sp;
 801
 802                if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg)))
 803                        return -EFAULT;
 804
 805                return handle_send_req(priv->user, &sp.req,
 806                                sp.retries, sp.retry_time_ms);
 807        }
 808        case COMPAT_IPMICTL_RECEIVE_MSG:
 809        case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
 810        {
 811                struct ipmi_recv   __user *precv64;
 812                struct ipmi_recv   recv64;
 813
 814                if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
 815                        return -EFAULT;
 816
 817                precv64 = compat_alloc_user_space(sizeof(recv64));
 818                if (copy_to_user(precv64, &recv64, sizeof(recv64)))
 819                        return -EFAULT;
 820
 821                rc = ipmi_ioctl(filep,
 822                                ((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
 823                                 ? IPMICTL_RECEIVE_MSG
 824                                 : IPMICTL_RECEIVE_MSG_TRUNC),
 825                                (unsigned long) precv64);
 826                if (rc != 0)
 827                        return rc;
 828
 829                if (copy_from_user(&recv64, precv64, sizeof(recv64)))
 830                        return -EFAULT;
 831
 832                if (put_compat_ipmi_recv(&recv64, compat_ptr(arg)))
 833                        return -EFAULT;
 834
 835                return rc;
 836        }
 837        default:
 838                return ipmi_ioctl(filep, cmd, arg);
 839        }
 840}
 841#endif
 842
 843static const struct file_operations ipmi_fops = {
 844        .owner          = THIS_MODULE,
 845        .unlocked_ioctl = ipmi_unlocked_ioctl,
 846#ifdef CONFIG_COMPAT
 847        .compat_ioctl   = compat_ipmi_ioctl,
 848#endif
 849        .open           = ipmi_open,
 850        .release        = ipmi_release,
 851        .fasync         = ipmi_fasync,
 852        .poll           = ipmi_poll,
 853        .llseek         = noop_llseek,
 854};
 855
 856#define DEVICE_NAME     "ipmidev"
 857
 858static int ipmi_major;
 859module_param(ipmi_major, int, 0);
 860MODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device.  By"
 861                 " default, or if you set it to zero, it will choose the next"
 862                 " available device.  Setting it to -1 will disable the"
 863                 " interface.  Other values will set the major device number"
 864                 " to that value.");
 865
 866/* Keep track of the devices that are registered. */
 867struct ipmi_reg_list {
 868        dev_t            dev;
 869        struct list_head link;
 870};
 871static LIST_HEAD(reg_list);
 872static DEFINE_MUTEX(reg_list_mutex);
 873
 874static struct class *ipmi_class;
 875
 876static void ipmi_new_smi(int if_num, struct device *device)
 877{
 878        dev_t dev = MKDEV(ipmi_major, if_num);
 879        struct ipmi_reg_list *entry;
 880
 881        entry = kmalloc(sizeof(*entry), GFP_KERNEL);
 882        if (!entry) {
 883                printk(KERN_ERR "ipmi_devintf: Unable to create the"
 884                       " ipmi class device link\n");
 885                return;
 886        }
 887        entry->dev = dev;
 888
 889        mutex_lock(&reg_list_mutex);
 890        device_create(ipmi_class, device, dev, NULL, "ipmi%d", if_num);
 891        list_add(&entry->link, &reg_list);
 892        mutex_unlock(&reg_list_mutex);
 893}
 894
 895static void ipmi_smi_gone(int if_num)
 896{
 897        dev_t dev = MKDEV(ipmi_major, if_num);
 898        struct ipmi_reg_list *entry;
 899
 900        mutex_lock(&reg_list_mutex);
 901        list_for_each_entry(entry, &reg_list, link) {
 902                if (entry->dev == dev) {
 903                        list_del(&entry->link);
 904                        kfree(entry);
 905                        break;
 906                }
 907        }
 908        device_destroy(ipmi_class, dev);
 909        mutex_unlock(&reg_list_mutex);
 910}
 911
 912static struct ipmi_smi_watcher smi_watcher =
 913{
 914        .owner    = THIS_MODULE,
 915        .new_smi  = ipmi_new_smi,
 916        .smi_gone = ipmi_smi_gone,
 917};
 918
 919static int __init init_ipmi_devintf(void)
 920{
 921        int rv;
 922
 923        if (ipmi_major < 0)
 924                return -EINVAL;
 925
 926        printk(KERN_INFO "ipmi device interface\n");
 927
 928        ipmi_class = class_create(THIS_MODULE, "ipmi");
 929        if (IS_ERR(ipmi_class)) {
 930                printk(KERN_ERR "ipmi: can't register device class\n");
 931                return PTR_ERR(ipmi_class);
 932        }
 933
 934        rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
 935        if (rv < 0) {
 936                class_destroy(ipmi_class);
 937                printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
 938                return rv;
 939        }
 940
 941        if (ipmi_major == 0) {
 942                ipmi_major = rv;
 943        }
 944
 945        rv = ipmi_smi_watcher_register(&smi_watcher);
 946        if (rv) {
 947                unregister_chrdev(ipmi_major, DEVICE_NAME);
 948                class_destroy(ipmi_class);
 949                printk(KERN_WARNING "ipmi: can't register smi watcher\n");
 950                return rv;
 951        }
 952
 953        return 0;
 954}
 955module_init(init_ipmi_devintf);
 956
 957static void __exit cleanup_ipmi(void)
 958{
 959        struct ipmi_reg_list *entry, *entry2;
 960        mutex_lock(&reg_list_mutex);
 961        list_for_each_entry_safe(entry, entry2, &reg_list, link) {
 962                list_del(&entry->link);
 963                device_destroy(ipmi_class, entry->dev);
 964                kfree(entry);
 965        }
 966        mutex_unlock(&reg_list_mutex);
 967        class_destroy(ipmi_class);
 968        ipmi_smi_watcher_unregister(&smi_watcher);
 969        unregister_chrdev(ipmi_major, DEVICE_NAME);
 970}
 971module_exit(cleanup_ipmi);
 972
 973MODULE_LICENSE("GPL");
 974MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
 975MODULE_DESCRIPTION("Linux device interface for the IPMI message handler.");
 976MODULE_ALIAS("platform:ipmi_si");
 977
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.