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

source code of linux/drivers/char/ipmi/ipmi_devintf.c