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/spinlock.h>
  40#include <linux/slab.h>
  41#include <linux/ipmi.h>
  42#include <linux/mutex.h>
  43#include <linux/init.h>
  44#include <linux/device.h>
  45#include <linux/compat.h>
  46#include <linux/smp_lock.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 void file_receive_handler(struct ipmi_recv_msg *msg,
  62                                 void                 *handler_data)
  63{
  64        struct ipmi_file_private *priv = handler_data;
  65        int                      was_empty;
  66        unsigned long            flags;
  67
  68        spin_lock_irqsave(&(priv->recv_msg_lock), flags);
  69
  70        was_empty = list_empty(&(priv->recv_msgs));
  71        list_add_tail(&(msg->link), &(priv->recv_msgs));
  72
  73        if (was_empty) {
  74                wake_up_interruptible(&priv->wait);
  75                kill_fasync(&priv->fasync_queue, SIGIO, POLL_IN);
  76        }
  77
  78        spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
  79}
  80
  81static unsigned int ipmi_poll(struct file *file, poll_table *wait)
  82{
  83        struct ipmi_file_private *priv = file->private_data;
  84        unsigned int             mask = 0;
  85        unsigned long            flags;
  86
  87        poll_wait(file, &priv->wait, wait);
  88
  89        spin_lock_irqsave(&priv->recv_msg_lock, flags);
  90
  91        if (!list_empty(&(priv->recv_msgs)))
  92                mask |= (POLLIN | POLLRDNORM);
  93
  94        spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
  95
  96        return mask;
  97}
  98
  99static int ipmi_fasync(int fd, struct file *file, int on)
 100{
 101        struct ipmi_file_private *priv = file->private_data;
 102        int                      result;
 103
 104        lock_kernel(); /* could race against open() otherwise */
 105        result = fasync_helper(fd, file, on, &priv->fasync_queue);
 106        unlock_kernel();
 107
 108        return (result);
 109}
 110
 111static struct ipmi_user_hndl ipmi_hndlrs =
 112{
 113        .ipmi_recv_hndl = file_receive_handler,
 114};
 115
 116static int ipmi_open(struct inode *inode, struct file *file)
 117{
 118        int                      if_num = iminor(inode);
 119        int                      rv;
 120        struct ipmi_file_private *priv;
 121
 122
 123        priv = kmalloc(sizeof(*priv), GFP_KERNEL);
 124        if (!priv)
 125                return -ENOMEM;
 126
 127        lock_kernel();
 128        priv->file = file;
 129
 130        rv = ipmi_create_user(if_num,
 131                              &ipmi_hndlrs,
 132                              priv,
 133                              &(priv->user));
 134        if (rv) {
 135                kfree(priv);
 136                goto out;
 137        }
 138
 139        file->private_data = priv;
 140
 141        spin_lock_init(&(priv->recv_msg_lock));
 142        INIT_LIST_HEAD(&(priv->recv_msgs));
 143        init_waitqueue_head(&priv->wait);
 144        priv->fasync_queue = NULL;
 145        mutex_init(&priv->recv_mutex);
 146
 147        /* Use the low-level defaults. */
 148        priv->default_retries = -1;
 149        priv->default_retry_time_ms = 0;
 150
 151out:
 152        unlock_kernel();
 153        return rv;
 154}
 155
 156static int ipmi_release(struct inode *inode, struct file *file)
 157{
 158        struct ipmi_file_private *priv = file->private_data;
 159        int                      rv;
 160
 161        rv = ipmi_destroy_user(priv->user);
 162        if (rv)
 163                return rv;
 164
 165        /* FIXME - free the messages in the list. */
 166        kfree(priv);
 167
 168        return 0;
 169}
 170
 171static int handle_send_req(ipmi_user_t     user,
 172                           struct ipmi_req *req,
 173                           int             retries,
 174                           unsigned int    retry_time_ms)
 175{
 176        int              rv;
 177        struct ipmi_addr addr;
 178        struct kernel_ipmi_msg msg;
 179
 180        if (req->addr_len > sizeof(struct ipmi_addr))
 181                return -EINVAL;
 182
 183        if (copy_from_user(&addr, req->addr, req->addr_len))
 184                return -EFAULT;
 185
 186        msg.netfn = req->msg.netfn;
 187        msg.cmd = req->msg.cmd;
 188        msg.data_len = req->msg.data_len;
 189        msg.data = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
 190        if (!msg.data)
 191                return -ENOMEM;
 192
 193        /* From here out we cannot return, we must jump to "out" for
 194           error exits to free msgdata. */
 195
 196        rv = ipmi_validate_addr(&addr, req->addr_len);
 197        if (rv)
 198                goto out;
 199
 200        if (req->msg.data != NULL) {
 201                if (req->msg.data_len > IPMI_MAX_MSG_LENGTH) {
 202                        rv = -EMSGSIZE;
 203                        goto out;
 204                }
 205
 206                if (copy_from_user(msg.data,
 207                                   req->msg.data,
 208                                   req->msg.data_len))
 209                {
 210                        rv = -EFAULT;
 211                        goto out;
 212                }
 213        } else {
 214                msg.data_len = 0;
 215        }
 216
 217        rv = ipmi_request_settime(user,
 218                                  &addr,
 219                                  req->msgid,
 220                                  &msg,
 221                                  NULL,
 222                                  0,
 223                                  retries,
 224                                  retry_time_ms);
 225 out:
 226        kfree(msg.data);
 227        return rv;
 228}
 229
 230static int ipmi_ioctl(struct inode  *inode,
 231                      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#ifdef CONFIG_COMPAT
 633
 634/*
 635 * The following code contains code for supporting 32-bit compatible
 636 * ioctls on 64-bit kernels.  This allows running 32-bit apps on the
 637 * 64-bit kernel
 638 */
 639#define COMPAT_IPMICTL_SEND_COMMAND     \
 640        _IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req)
 641#define COMPAT_IPMICTL_SEND_COMMAND_SETTIME     \
 642        _IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime)
 643#define COMPAT_IPMICTL_RECEIVE_MSG      \
 644        _IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv)
 645#define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC        \
 646        _IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv)
 647
 648struct compat_ipmi_msg {
 649        u8              netfn;
 650        u8              cmd;
 651        u16             data_len;
 652        compat_uptr_t   data;
 653};
 654
 655struct compat_ipmi_req {
 656        compat_uptr_t           addr;
 657        compat_uint_t           addr_len;
 658        compat_long_t           msgid;
 659        struct compat_ipmi_msg  msg;
 660};
 661
 662struct compat_ipmi_recv {
 663        compat_int_t            recv_type;
 664        compat_uptr_t           addr;
 665        compat_uint_t           addr_len;
 666        compat_long_t           msgid;
 667        struct compat_ipmi_msg  msg;
 668};
 669
 670struct compat_ipmi_req_settime {
 671        struct compat_ipmi_req  req;
 672        compat_int_t            retries;
 673        compat_uint_t           retry_time_ms;
 674};
 675
 676/*
 677 * Define some helper functions for copying IPMI data
 678 */
 679static long get_compat_ipmi_msg(struct ipmi_msg *p64,
 680                                struct compat_ipmi_msg __user *p32)
 681{
 682        compat_uptr_t tmp;
 683
 684        if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
 685                        __get_user(p64->netfn, &p32->netfn) ||
 686                        __get_user(p64->cmd, &p32->cmd) ||
 687                        __get_user(p64->data_len, &p32->data_len) ||
 688                        __get_user(tmp, &p32->data))
 689                return -EFAULT;
 690        p64->data = compat_ptr(tmp);
 691        return 0;
 692}
 693
 694static long put_compat_ipmi_msg(struct ipmi_msg *p64,
 695                                struct compat_ipmi_msg __user *p32)
 696{
 697        if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
 698                        __put_user(p64->netfn, &p32->netfn) ||
 699                        __put_user(p64->cmd, &p32->cmd) ||
 700                        __put_user(p64->data_len, &p32->data_len))
 701                return -EFAULT;
 702        return 0;
 703}
 704
 705static long get_compat_ipmi_req(struct ipmi_req *p64,
 706                                struct compat_ipmi_req __user *p32)
 707{
 708
 709        compat_uptr_t   tmp;
 710
 711        if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
 712                        __get_user(tmp, &p32->addr) ||
 713                        __get_user(p64->addr_len, &p32->addr_len) ||
 714                        __get_user(p64->msgid, &p32->msgid) ||
 715                        get_compat_ipmi_msg(&p64->msg, &p32->msg))
 716                return -EFAULT;
 717        p64->addr = compat_ptr(tmp);
 718        return 0;
 719}
 720
 721static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
 722                struct compat_ipmi_req_settime __user *p32)
 723{
 724        if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
 725                        get_compat_ipmi_req(&p64->req, &p32->req) ||
 726                        __get_user(p64->retries, &p32->retries) ||
 727                        __get_user(p64->retry_time_ms, &p32->retry_time_ms))
 728                return -EFAULT;
 729        return 0;
 730}
 731
 732static long get_compat_ipmi_recv(struct ipmi_recv *p64,
 733                                 struct compat_ipmi_recv __user *p32)
 734{
 735        compat_uptr_t tmp;
 736
 737        if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
 738                        __get_user(p64->recv_type, &p32->recv_type) ||
 739                        __get_user(tmp, &p32->addr) ||
 740                        __get_user(p64->addr_len, &p32->addr_len) ||
 741                        __get_user(p64->msgid, &p32->msgid) ||
 742                        get_compat_ipmi_msg(&p64->msg, &p32->msg))
 743                return -EFAULT;
 744        p64->addr = compat_ptr(tmp);
 745        return 0;
 746}
 747
 748static long put_compat_ipmi_recv(struct ipmi_recv *p64,
 749                                 struct compat_ipmi_recv __user *p32)
 750{
 751        if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
 752                        __put_user(p64->recv_type, &p32->recv_type) ||
 753                        __put_user(p64->addr_len, &p32->addr_len) ||
 754                        __put_user(p64->msgid, &p32->msgid) ||
 755                        put_compat_ipmi_msg(&p64->msg, &p32->msg))
 756                return -EFAULT;
 757        return 0;
 758}
 759
 760/*
 761 * Handle compatibility ioctls
 762 */
 763static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
 764                              unsigned long arg)
 765{
 766        int rc;
 767        struct ipmi_file_private *priv = filep->private_data;
 768
 769        switch(cmd) {
 770        case COMPAT_IPMICTL_SEND_COMMAND:
 771        {
 772                struct ipmi_req rp;
 773
 774                if (get_compat_ipmi_req(&rp, compat_ptr(arg)))
 775                        return -EFAULT;
 776
 777                return handle_send_req(priv->user, &rp,
 778                                priv->default_retries,
 779                                priv->default_retry_time_ms);
 780        }
 781        case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
 782        {
 783                struct ipmi_req_settime sp;
 784
 785                if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg)))
 786                        return -EFAULT;
 787
 788                return handle_send_req(priv->user, &sp.req,
 789                                sp.retries, sp.retry_time_ms);
 790        }
 791        case COMPAT_IPMICTL_RECEIVE_MSG:
 792        case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
 793        {
 794                struct ipmi_recv   __user *precv64;
 795                struct ipmi_recv   recv64;
 796
 797                if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
 798                        return -EFAULT;
 799
 800                precv64 = compat_alloc_user_space(sizeof(recv64));
 801                if (copy_to_user(precv64, &recv64, sizeof(recv64)))
 802                        return -EFAULT;
 803
 804                rc = ipmi_ioctl(filep->f_path.dentry->d_inode, filep,
 805                                ((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
 806                                 ? IPMICTL_RECEIVE_MSG
 807                                 : IPMICTL_RECEIVE_MSG_TRUNC),
 808                                (unsigned long) precv64);
 809                if (rc != 0)
 810                        return rc;
 811
 812                if (copy_from_user(&recv64, precv64, sizeof(recv64)))
 813                        return -EFAULT;
 814
 815                if (put_compat_ipmi_recv(&recv64, compat_ptr(arg)))
 816                        return -EFAULT;
 817
 818                return rc;
 819        }
 820        default:
 821                return ipmi_ioctl(filep->f_path.dentry->d_inode, filep, cmd, arg);
 822        }
 823}
 824#endif
 825
 826static const struct file_operations ipmi_fops = {
 827        .owner          = THIS_MODULE,
 828        .ioctl          = ipmi_ioctl,
 829#ifdef CONFIG_COMPAT
 830        .compat_ioctl   = compat_ipmi_ioctl,
 831#endif
 832        .open           = ipmi_open,
 833        .release        = ipmi_release,
 834        .fasync         = ipmi_fasync,
 835        .poll           = ipmi_poll,
 836};
 837
 838#define DEVICE_NAME     "ipmidev"
 839
 840static int ipmi_major;
 841module_param(ipmi_major, int, 0);
 842MODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device.  By"
 843                 " default, or if you set it to zero, it will choose the next"
 844                 " available device.  Setting it to -1 will disable the"
 845                 " interface.  Other values will set the major device number"
 846                 " to that value.");
 847
 848/* Keep track of the devices that are registered. */
 849struct ipmi_reg_list {
 850        dev_t            dev;
 851        struct list_head link;
 852};
 853static LIST_HEAD(reg_list);
 854static DEFINE_MUTEX(reg_list_mutex);
 855
 856static struct class *ipmi_class;
 857
 858static void ipmi_new_smi(int if_num, struct device *device)
 859{
 860        dev_t dev = MKDEV(ipmi_major, if_num);
 861        struct ipmi_reg_list *entry;
 862
 863        entry = kmalloc(sizeof(*entry), GFP_KERNEL);
 864        if (!entry) {
 865                printk(KERN_ERR "ipmi_devintf: Unable to create the"
 866                       " ipmi class device link\n");
 867                return;
 868        }
 869        entry->dev = dev;
 870
 871        mutex_lock(&reg_list_mutex);
 872        device_create(ipmi_class, device, dev, NULL, "ipmi%d", if_num);
 873        list_add(&entry->link, &reg_list);
 874        mutex_unlock(&reg_list_mutex);
 875}
 876
 877static void ipmi_smi_gone(int if_num)
 878{
 879        dev_t dev = MKDEV(ipmi_major, if_num);
 880        struct ipmi_reg_list *entry;
 881
 882        mutex_lock(&reg_list_mutex);
 883        list_for_each_entry(entry, &reg_list, link) {
 884                if (entry->dev == dev) {
 885                        list_del(&entry->link);
 886                        kfree(entry);
 887                        break;
 888                }
 889        }
 890        device_destroy(ipmi_class, dev);
 891        mutex_unlock(&reg_list_mutex);
 892}
 893
 894static struct ipmi_smi_watcher smi_watcher =
 895{
 896        .owner    = THIS_MODULE,
 897        .new_smi  = ipmi_new_smi,
 898        .smi_gone = ipmi_smi_gone,
 899};
 900
 901static __init int init_ipmi_devintf(void)
 902{
 903        int rv;
 904
 905        if (ipmi_major < 0)
 906                return -EINVAL;
 907
 908        printk(KERN_INFO "ipmi device interface\n");
 909
 910        ipmi_class = class_create(THIS_MODULE, "ipmi");
 911        if (IS_ERR(ipmi_class)) {
 912                printk(KERN_ERR "ipmi: can't register device class\n");
 913                return PTR_ERR(ipmi_class);
 914        }
 915
 916        rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
 917        if (rv < 0) {
 918                class_destroy(ipmi_class);
 919                printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
 920                return rv;
 921        }
 922
 923        if (ipmi_major == 0) {
 924                ipmi_major = rv;
 925        }
 926
 927        rv = ipmi_smi_watcher_register(&smi_watcher);
 928        if (rv) {
 929                unregister_chrdev(ipmi_major, DEVICE_NAME);
 930                class_destroy(ipmi_class);
 931                printk(KERN_WARNING "ipmi: can't register smi watcher\n");
 932                return rv;
 933        }
 934
 935        return 0;
 936}
 937module_init(init_ipmi_devintf);
 938
 939static __exit void cleanup_ipmi(void)
 940{
 941        struct ipmi_reg_list *entry, *entry2;
 942        mutex_lock(&reg_list_mutex);
 943        list_for_each_entry_safe(entry, entry2, &reg_list, link) {
 944                list_del(&entry->link);
 945                device_destroy(ipmi_class, entry->dev);
 946                kfree(entry);
 947        }
 948        mutex_unlock(&reg_list_mutex);
 949        class_destroy(ipmi_class);
 950        ipmi_smi_watcher_unregister(&smi_watcher);
 951        unregister_chrdev(ipmi_major, DEVICE_NAME);
 952}
 953module_exit(cleanup_ipmi);
 954
 955MODULE_LICENSE("GPL");
 956MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
 957MODULE_DESCRIPTION("Linux device interface for the IPMI message handler.");
 958MODULE_ALIAS("platform:ipmi_si");
 959
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.