📄 ipmi_msghandler.c
字号:
for (i = 0; i < MAX_IPMI_INTERFACES; i++) { if (ipmi_interfaces[i] == NULL) { intf->intf_num = i; /* Reserve the entry till we are done. */ ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY; rv = 0; break; } } spin_unlock_irqrestore(&interfaces_lock, flags); if (rv) goto out; /* FIXME - this is an ugly kludge, this sets the intf for the caller before sending any messages with it. */ *new_intf = intf; if ((version_major > 1) || ((version_major == 1) && (version_minor >= 5))) { /* Start scanning the channels to see what is available. */ intf->null_user_handler = channel_handler; intf->curr_channel = 0; rv = send_channel_info_cmd(intf, 0); if (rv) goto out; /* Wait for the channel info to be read. */ wait_event(intf->waitq, intf->curr_channel >= IPMI_MAX_CHANNELS); } else { /* Assume a single IPMB channel at zero. */ intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB; intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB; } if (rv == 0) rv = add_proc_entries(intf, i); out: if (rv) { if (intf->proc_dir) remove_proc_entries(intf); kref_put(&intf->refcount, intf_free); if (i < MAX_IPMI_INTERFACES) { spin_lock_irqsave(&interfaces_lock, flags); ipmi_interfaces[i] = NULL; spin_unlock_irqrestore(&interfaces_lock, flags); } } else { spin_lock_irqsave(&interfaces_lock, flags); ipmi_interfaces[i] = intf; spin_unlock_irqrestore(&interfaces_lock, flags); call_smi_watchers(i); } return rv;}int ipmi_unregister_smi(ipmi_smi_t intf){ int i; struct ipmi_smi_watcher *w; unsigned long flags; spin_lock_irqsave(&interfaces_lock, flags); for (i = 0; i < MAX_IPMI_INTERFACES; i++) { if (ipmi_interfaces[i] == intf) { /* Set the interface number reserved until we * are done. */ ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY; intf->intf_num = -1; break; } } spin_unlock_irqrestore(&interfaces_lock,flags); if (i == MAX_IPMI_INTERFACES) return -ENODEV; remove_proc_entries(intf); /* Call all the watcher interfaces to tell them that an interface is gone. */ down_read(&smi_watchers_sem); list_for_each_entry(w, &smi_watchers, link) w->smi_gone(i); up_read(&smi_watchers_sem); /* Allow the entry to be reused now. */ spin_lock_irqsave(&interfaces_lock, flags); ipmi_interfaces[i] = NULL; spin_unlock_irqrestore(&interfaces_lock,flags); kref_put(&intf->refcount, intf_free); return 0;}static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf, struct ipmi_smi_msg *msg){ struct ipmi_ipmb_addr ipmb_addr; struct ipmi_recv_msg *recv_msg; unsigned long flags; /* This is 11, not 10, because the response must contain a * completion code. */ if (msg->rsp_size < 11) { /* Message not big enough, just ignore it. */ spin_lock_irqsave(&intf->counter_lock, flags); intf->invalid_ipmb_responses++; spin_unlock_irqrestore(&intf->counter_lock, flags); return 0; } if (msg->rsp[2] != 0) { /* An error getting the response, just ignore it. */ return 0; } ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE; ipmb_addr.slave_addr = msg->rsp[6]; ipmb_addr.channel = msg->rsp[3] & 0x0f; ipmb_addr.lun = msg->rsp[7] & 3; /* It's a response from a remote entity. Look up the sequence number and handle the response. */ if (intf_find_seq(intf, msg->rsp[7] >> 2, msg->rsp[3] & 0x0f, msg->rsp[8], (msg->rsp[4] >> 2) & (~1), (struct ipmi_addr *) &(ipmb_addr), &recv_msg)) { /* We were unable to find the sequence number, so just nuke the message. */ spin_lock_irqsave(&intf->counter_lock, flags); intf->unhandled_ipmb_responses++; spin_unlock_irqrestore(&intf->counter_lock, flags); return 0; } memcpy(recv_msg->msg_data, &(msg->rsp[9]), msg->rsp_size - 9); /* THe other fields matched, so no need to set them, except for netfn, which needs to be the response that was returned, not the request value. */ recv_msg->msg.netfn = msg->rsp[4] >> 2; recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = msg->rsp_size - 10; recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE; spin_lock_irqsave(&intf->counter_lock, flags); intf->handled_ipmb_responses++; spin_unlock_irqrestore(&intf->counter_lock, flags); deliver_response(recv_msg); return 0;}static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, struct ipmi_smi_msg *msg){ struct cmd_rcvr *rcvr; int rv = 0; unsigned char netfn; unsigned char cmd; ipmi_user_t user = NULL; struct ipmi_ipmb_addr *ipmb_addr; struct ipmi_recv_msg *recv_msg; unsigned long flags; if (msg->rsp_size < 10) { /* Message not big enough, just ignore it. */ spin_lock_irqsave(&intf->counter_lock, flags); intf->invalid_commands++; spin_unlock_irqrestore(&intf->counter_lock, flags); return 0; } if (msg->rsp[2] != 0) { /* An error getting the response, just ignore it. */ return 0; } netfn = msg->rsp[4] >> 2; cmd = msg->rsp[8]; rcu_read_lock(); rcvr = find_cmd_rcvr(intf, netfn, cmd); if (rcvr) { user = rcvr->user; kref_get(&user->refcount); } else user = NULL; rcu_read_unlock(); if (user == NULL) { /* We didn't find a user, deliver an error response. */ spin_lock_irqsave(&intf->counter_lock, flags); intf->unhandled_commands++; spin_unlock_irqrestore(&intf->counter_lock, flags); msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2); msg->data[1] = IPMI_SEND_MSG_CMD; msg->data[2] = msg->rsp[3]; msg->data[3] = msg->rsp[6]; msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3); msg->data[5] = ipmb_checksum(&(msg->data[3]), 2); msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address; /* rqseq/lun */ msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3); msg->data[8] = msg->rsp[8]; /* cmd */ msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE; msg->data[10] = ipmb_checksum(&(msg->data[6]), 4); msg->data_size = 11;#ifdef DEBUG_MSGING { int m; printk("Invalid command:"); for (m = 0; m < msg->data_size; m++) printk(" %2.2x", msg->data[m]); printk("\n"); }#endif intf->handlers->sender(intf->send_info, msg, 0); rv = -1; /* We used the message, so return the value that causes it to not be freed or queued. */ } else { /* Deliver the message to the user. */ spin_lock_irqsave(&intf->counter_lock, flags); intf->handled_commands++; spin_unlock_irqrestore(&intf->counter_lock, flags); recv_msg = ipmi_alloc_recv_msg(); if (! recv_msg) { /* We couldn't allocate memory for the message, so requeue it for handling later. */ rv = 1; kref_put(&user->refcount, free_user); } else { /* Extract the source address from the data. */ ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr; ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE; ipmb_addr->slave_addr = msg->rsp[6]; ipmb_addr->lun = msg->rsp[7] & 3; ipmb_addr->channel = msg->rsp[3] & 0xf; /* Extract the rest of the message information from the IPMB header.*/ recv_msg->user = user; recv_msg->recv_type = IPMI_CMD_RECV_TYPE; recv_msg->msgid = msg->rsp[7] >> 2; recv_msg->msg.netfn = msg->rsp[4] >> 2; recv_msg->msg.cmd = msg->rsp[8]; recv_msg->msg.data = recv_msg->msg_data; /* We chop off 10, not 9 bytes because the checksum at the end also needs to be removed. */ recv_msg->msg.data_len = msg->rsp_size - 10; memcpy(recv_msg->msg_data, &(msg->rsp[9]), msg->rsp_size - 10); deliver_response(recv_msg); } } return rv;}static int handle_lan_get_msg_rsp(ipmi_smi_t intf, struct ipmi_smi_msg *msg){ struct ipmi_lan_addr lan_addr; struct ipmi_recv_msg *recv_msg; unsigned long flags; /* This is 13, not 12, because the response must contain a * completion code. */ if (msg->rsp_size < 13) { /* Message not big enough, just ignore it. */ spin_lock_irqsave(&intf->counter_lock, flags); intf->invalid_lan_responses++; spin_unlock_irqrestore(&intf->counter_lock, flags); return 0; } if (msg->rsp[2] != 0) { /* An error getting the response, just ignore it. */ return 0; } lan_addr.addr_type = IPMI_LAN_ADDR_TYPE; lan_addr.session_handle = msg->rsp[4]; lan_addr.remote_SWID = msg->rsp[8]; lan_addr.local_SWID = msg->rsp[5]; lan_addr.channel = msg->rsp[3] & 0x0f; lan_addr.privilege = msg->rsp[3] >> 4; lan_addr.lun = msg->rsp[9] & 3; /* It's a response from a remote entity. Look up the sequence number and handle the response. */ if (intf_find_seq(intf, msg->rsp[9] >> 2, msg->rsp[3] & 0x0f, msg->rsp[10], (msg->rsp[6] >> 2) & (~1), (struct ipmi_addr *) &(lan_addr), &recv_msg)) { /* We were unable to find the sequence number, so just nuke the message. */ spin_lock_irqsave(&intf->counter_lock, flags); intf->unhandled_lan_responses++; spin_unlock_irqrestore(&intf->counter_lock, flags); return 0; } memcpy(recv_msg->msg_data, &(msg->rsp[11]), msg->rsp_size - 11); /* The other fields matched, so no need to set them, except for netfn, which needs to be the response that was returned, not the request value. */ recv_msg->msg.netfn = msg->rsp[6] >> 2; recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = msg->rsp_size - 12; recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE; spin_lock_irqsave(&intf->counter_lock, flags); intf->handled_lan_responses++; spin_unlock_irqrestore(&intf->counter_lock, flags); deliver_response(recv_msg); return 0;}static int handle_lan_get_msg_cmd(ipmi_smi_t intf, struct ipmi_smi_msg *msg){ struct cmd_rcvr *rcvr; int rv = 0; unsigned char netfn; unsigned char cmd; ipmi_user_t user = NULL; struct ipmi_lan_addr *lan_addr; struct ipmi_recv_msg *recv_msg; unsigned long flags; if (msg->rsp_size < 12) { /* Message not big enough, just ignore it. */ spin_lock_irqsave(&intf->counter_lock, flags); intf->invalid_commands++; spin_unlock_irqrestore(&intf->counter_lock, flags); return 0; } if (msg->rsp[2] != 0) { /* An error getting the response, just ignore it. */ return 0; } netfn = msg->rsp[6] >> 2; cmd = msg->rsp[10]; rcu_read_lock(); rcvr = find_cmd_rcvr(intf, netfn, cmd); if (rcvr) { user = rcvr->user; kref_get(&user->refcount); } else user = NULL; rcu_read_unlock(); if (user == NULL) { /* We didn't find a user, just give up. */ spin_lock_irqsave(&intf->counter_lock, flags); intf->unhandled_commands++; spin_unlock_irqrestore(&intf->counter_lock, flags); rv = 0; /* Don't do anything with these messages, just allow them to be freed. */ } else { /* Deliver the message to the user. */ spin_lock_irqsave(&intf->counter_lock, flags); intf->handled_commands++; spin_unlock_irqrestore(&intf->counter_lock, flags); recv_msg = ipmi_alloc_recv_msg(); if (! recv_msg) { /* We couldn't allocate memory for the message, so requeue it for handling later. */ rv = 1; kref_put(&user->refcount, free_user); } else { /* Extract the source address from the data. */ lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr; lan_addr->addr_type = IPMI_LAN_ADDR_TYPE; lan_addr->session_handle = msg->rsp[4]; lan_addr->remote_SWID = msg->rsp[8]; lan_addr->local_SWID = msg->rsp[5]; lan_addr->lun = msg->rsp[9] & 3; lan_addr->channel = msg->rsp[3] & 0xf; lan_addr->privilege = msg->rsp[3] >> 4; /* Extract the rest of the message information from the IPMB header.*/ recv_msg->user = user; recv_msg->recv_type = IPMI_CMD_RECV_TYPE; recv_msg->msgid = msg->rsp[9] >> 2; recv_msg->msg.netfn = msg->rsp[6] >> 2; recv_msg->msg.cmd = msg->rsp[10]; recv_msg->msg.data = recv_msg->msg_data; /* We chop off 12, not 11 bytes because the checksum at the end also needs to be removed. */ recv_msg->msg.data_len = msg->rsp_size - 12; memcpy(recv_msg->msg_data, &(msg->rsp[11]), msg->rsp_size - 12); deliver_response(recv_msg); } } return rv;}static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg, struct ipmi_smi_msg *msg){ struct ipmi_system_interface_addr *smi_addr; recv_msg->msgid = 0; smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr); smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; smi_addr->channel = IPMI_BMC_CHANNEL; smi_addr->lun = msg->rsp[0] & 3; recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE; recv_msg->msg.netfn = msg->rsp[0] >> 2; recv_msg->msg.cmd = msg->rsp[1]; memcpy(recv_msg->msg_data, &(msg->rsp[3]), msg->rsp_size - 3); recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = msg->rsp_size - 3;}static int handle_read_event_rsp(ipmi_smi_t intf, struct ipmi_smi_msg *msg){ struct ipmi_recv_msg *recv_msg, *recv_msg2; struct list_head msgs; ipmi_user_t user; int rv = 0; int deliver_count = 0; unsigned long flags; if (msg->rsp_size < 19) { /* Message is too small to be an IPMB event. */ spin_lock_irqsave(&intf->counter_lock, flags); intf->inva
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -