aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c34
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c75
2 files changed, 88 insertions, 21 deletions
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index 68d7c61a864e..81fcf0ce21d1 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -377,7 +377,8 @@ static int ipmi_ioctl(struct inode *inode,
377 break; 377 break;
378 } 378 }
379 379
380 rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd); 380 rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd,
381 IPMI_CHAN_ALL);
381 break; 382 break;
382 } 383 }
383 384
@@ -390,7 +391,36 @@ static int ipmi_ioctl(struct inode *inode,
390 break; 391 break;
391 } 392 }
392 393
393 rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd); 394 rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd,
395 IPMI_CHAN_ALL);
396 break;
397 }
398
399 case IPMICTL_REGISTER_FOR_CMD_CHANS:
400 {
401 struct ipmi_cmdspec_chans val;
402
403 if (copy_from_user(&val, arg, sizeof(val))) {
404 rv = -EFAULT;
405 break;
406 }
407
408 rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd,
409 val.chans);
410 break;
411 }
412
413 case IPMICTL_UNREGISTER_FOR_CMD_CHANS:
414 {
415 struct ipmi_cmdspec_chans val;
416
417 if (copy_from_user(&val, arg, sizeof(val))) {
418 rv = -EFAULT;
419 break;
420 }
421
422 rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd,
423 val.chans);
394 break; 424 break;
395 } 425 }
396 426
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 843d34c8627c..2455e8d478ac 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -96,6 +96,7 @@ struct cmd_rcvr
96 ipmi_user_t user; 96 ipmi_user_t user;
97 unsigned char netfn; 97 unsigned char netfn;
98 unsigned char cmd; 98 unsigned char cmd;
99 unsigned int chans;
99 100
100 /* 101 /*
101 * This is used to form a linked lised during mass deletion. 102 * This is used to form a linked lised during mass deletion.
@@ -953,24 +954,41 @@ int ipmi_set_gets_events(ipmi_user_t user, int val)
953 954
954static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf, 955static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
955 unsigned char netfn, 956 unsigned char netfn,
956 unsigned char cmd) 957 unsigned char cmd,
958 unsigned char chan)
957{ 959{
958 struct cmd_rcvr *rcvr; 960 struct cmd_rcvr *rcvr;
959 961
960 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) { 962 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
961 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) 963 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
964 && (rcvr->chans & (1 << chan)))
962 return rcvr; 965 return rcvr;
963 } 966 }
964 return NULL; 967 return NULL;
965} 968}
966 969
970static int is_cmd_rcvr_exclusive(ipmi_smi_t intf,
971 unsigned char netfn,
972 unsigned char cmd,
973 unsigned int chans)
974{
975 struct cmd_rcvr *rcvr;
976
977 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
978 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
979 && (rcvr->chans & chans))
980 return 0;
981 }
982 return 1;
983}
984
967int ipmi_register_for_cmd(ipmi_user_t user, 985int ipmi_register_for_cmd(ipmi_user_t user,
968 unsigned char netfn, 986 unsigned char netfn,
969 unsigned char cmd) 987 unsigned char cmd,
988 unsigned int chans)
970{ 989{
971 ipmi_smi_t intf = user->intf; 990 ipmi_smi_t intf = user->intf;
972 struct cmd_rcvr *rcvr; 991 struct cmd_rcvr *rcvr;
973 struct cmd_rcvr *entry;
974 int rv = 0; 992 int rv = 0;
975 993
976 994
@@ -979,12 +997,12 @@ int ipmi_register_for_cmd(ipmi_user_t user,
979 return -ENOMEM; 997 return -ENOMEM;
980 rcvr->cmd = cmd; 998 rcvr->cmd = cmd;
981 rcvr->netfn = netfn; 999 rcvr->netfn = netfn;
1000 rcvr->chans = chans;
982 rcvr->user = user; 1001 rcvr->user = user;
983 1002
984 mutex_lock(&intf->cmd_rcvrs_mutex); 1003 mutex_lock(&intf->cmd_rcvrs_mutex);
985 /* Make sure the command/netfn is not already registered. */ 1004 /* Make sure the command/netfn is not already registered. */
986 entry = find_cmd_rcvr(intf, netfn, cmd); 1005 if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) {
987 if (entry) {
988 rv = -EBUSY; 1006 rv = -EBUSY;
989 goto out_unlock; 1007 goto out_unlock;
990 } 1008 }
@@ -1001,24 +1019,39 @@ int ipmi_register_for_cmd(ipmi_user_t user,
1001 1019
1002int ipmi_unregister_for_cmd(ipmi_user_t user, 1020int ipmi_unregister_for_cmd(ipmi_user_t user,
1003 unsigned char netfn, 1021 unsigned char netfn,
1004 unsigned char cmd) 1022 unsigned char cmd,
1023 unsigned int chans)
1005{ 1024{
1006 ipmi_smi_t intf = user->intf; 1025 ipmi_smi_t intf = user->intf;
1007 struct cmd_rcvr *rcvr; 1026 struct cmd_rcvr *rcvr;
1027 struct cmd_rcvr *rcvrs = NULL;
1028 int i, rv = -ENOENT;
1008 1029
1009 mutex_lock(&intf->cmd_rcvrs_mutex); 1030 mutex_lock(&intf->cmd_rcvrs_mutex);
1010 /* Make sure the command/netfn is not already registered. */ 1031 for (i = 0; i < IPMI_NUM_CHANNELS; i++) {
1011 rcvr = find_cmd_rcvr(intf, netfn, cmd); 1032 if (((1 << i) & chans) == 0)
1012 if ((rcvr) && (rcvr->user == user)) { 1033 continue;
1013 list_del_rcu(&rcvr->link); 1034 rcvr = find_cmd_rcvr(intf, netfn, cmd, i);
1014 mutex_unlock(&intf->cmd_rcvrs_mutex); 1035 if (rcvr == NULL)
1015 synchronize_rcu(); 1036 continue;
1037 if (rcvr->user == user) {
1038 rv = 0;
1039 rcvr->chans &= ~chans;
1040 if (rcvr->chans == 0) {
1041 list_del_rcu(&rcvr->link);
1042 rcvr->next = rcvrs;
1043 rcvrs = rcvr;
1044 }
1045 }
1046 }
1047 mutex_unlock(&intf->cmd_rcvrs_mutex);
1048 synchronize_rcu();
1049 while (rcvrs) {
1050 rcvr = rcvrs;
1051 rcvrs = rcvr->next;
1016 kfree(rcvr); 1052 kfree(rcvr);
1017 return 0;
1018 } else {
1019 mutex_unlock(&intf->cmd_rcvrs_mutex);
1020 return -ENOENT;
1021 } 1053 }
1054 return rv;
1022} 1055}
1023 1056
1024void ipmi_user_set_run_to_completion(ipmi_user_t user, int val) 1057void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
@@ -2548,6 +2581,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
2548 int rv = 0; 2581 int rv = 0;
2549 unsigned char netfn; 2582 unsigned char netfn;
2550 unsigned char cmd; 2583 unsigned char cmd;
2584 unsigned char chan;
2551 ipmi_user_t user = NULL; 2585 ipmi_user_t user = NULL;
2552 struct ipmi_ipmb_addr *ipmb_addr; 2586 struct ipmi_ipmb_addr *ipmb_addr;
2553 struct ipmi_recv_msg *recv_msg; 2587 struct ipmi_recv_msg *recv_msg;
@@ -2568,9 +2602,10 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
2568 2602
2569 netfn = msg->rsp[4] >> 2; 2603 netfn = msg->rsp[4] >> 2;
2570 cmd = msg->rsp[8]; 2604 cmd = msg->rsp[8];
2605 chan = msg->rsp[3] & 0xf;
2571 2606
2572 rcu_read_lock(); 2607 rcu_read_lock();
2573 rcvr = find_cmd_rcvr(intf, netfn, cmd); 2608 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
2574 if (rcvr) { 2609 if (rcvr) {
2575 user = rcvr->user; 2610 user = rcvr->user;
2576 kref_get(&user->refcount); 2611 kref_get(&user->refcount);
@@ -2728,6 +2763,7 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
2728 int rv = 0; 2763 int rv = 0;
2729 unsigned char netfn; 2764 unsigned char netfn;
2730 unsigned char cmd; 2765 unsigned char cmd;
2766 unsigned char chan;
2731 ipmi_user_t user = NULL; 2767 ipmi_user_t user = NULL;
2732 struct ipmi_lan_addr *lan_addr; 2768 struct ipmi_lan_addr *lan_addr;
2733 struct ipmi_recv_msg *recv_msg; 2769 struct ipmi_recv_msg *recv_msg;
@@ -2748,9 +2784,10 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
2748 2784
2749 netfn = msg->rsp[6] >> 2; 2785 netfn = msg->rsp[6] >> 2;
2750 cmd = msg->rsp[10]; 2786 cmd = msg->rsp[10];
2787 chan = msg->rsp[3] & 0xf;
2751 2788
2752 rcu_read_lock(); 2789 rcu_read_lock();
2753 rcvr = find_cmd_rcvr(intf, netfn, cmd); 2790 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
2754 if (rcvr) { 2791 if (rcvr) {
2755 user = rcvr->user; 2792 user = rcvr->user;
2756 kref_get(&user->refcount); 2793 kref_get(&user->refcount);