📄 ipmi_msghandler.c
字号:
up_read(&interfaces_sem); return rv;}static int ipmi_destroy_user_nolock(ipmi_user_t user){ int rv = -ENODEV; ipmi_user_t t_user; struct list_head *entry, *entry2; int i; unsigned long flags; /* Find the user and delete them from the list. */ list_for_each(entry, &(user->intf->users)) { t_user = list_entry(entry, struct ipmi_user, link); if (t_user == user) { list_del(entry); rv = 0; break; } } if (rv) { goto out_unlock; } /* Remove the user from the interfaces sequence table. */ spin_lock_irqsave(&(user->intf->seq_lock), flags); for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) { if (user->intf->seq_table[i].inuse && (user->intf->seq_table[i].recv_msg->user == user)) { user->intf->seq_table[i].inuse = 0; } } spin_unlock_irqrestore(&(user->intf->seq_lock), flags); /* Remove the user from the command receiver's table. */ write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags); list_for_each_safe(entry, entry2, &(user->intf->cmd_rcvrs)) { struct cmd_rcvr *rcvr; rcvr = list_entry(entry, struct cmd_rcvr, link); if (rcvr->user == user) { list_del(entry); kfree(rcvr); } } write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags); kfree(user); out_unlock: return rv;}int ipmi_destroy_user(ipmi_user_t user){ int rv; ipmi_smi_t intf = user->intf; unsigned long flags; down_read(&interfaces_sem); write_lock_irqsave(&(intf->users_lock), flags); rv = ipmi_destroy_user_nolock(user); if (!rv) intf->handlers->user_left(intf->send_info); write_unlock_irqrestore(&(intf->users_lock), flags); up_read(&interfaces_sem); return rv;}void ipmi_get_version(ipmi_user_t user, unsigned char *major, unsigned char *minor){ *major = user->intf->version_major; *minor = user->intf->version_minor;}void ipmi_set_my_address(ipmi_user_t user, unsigned char address){ user->intf->my_address = address;}unsigned char ipmi_get_my_address(ipmi_user_t user){ return user->intf->my_address;}void ipmi_set_my_LUN(ipmi_user_t user, unsigned char LUN){ user->intf->my_lun = LUN & 0x3;}unsigned char ipmi_get_my_LUN(ipmi_user_t user){ return user->intf->my_lun;}int ipmi_set_gets_events(ipmi_user_t user, int val){ unsigned long flags; struct list_head *e, *e2; struct ipmi_recv_msg *msg; read_lock(&(user->intf->users_lock)); spin_lock_irqsave(&(user->intf->events_lock), flags); user->gets_events = val; if (val) { /* Deliver any queued events. */ list_for_each_safe(e, e2, &(user->intf->waiting_events)) { msg = list_entry(e, struct ipmi_recv_msg, link); list_del(e); msg->user = user; deliver_response(msg); } } spin_unlock_irqrestore(&(user->intf->events_lock), flags); read_unlock(&(user->intf->users_lock)); return 0;}int ipmi_register_for_cmd(ipmi_user_t user, unsigned char netfn, unsigned char cmd){ struct list_head *entry; unsigned long flags; struct cmd_rcvr *rcvr; int rv = 0; rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL); if (! rcvr) return -ENOMEM; read_lock(&(user->intf->users_lock)); write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags); if (user->intf->all_cmd_rcvr != NULL) { rv = -EBUSY; goto out_unlock; } /* Make sure the command/netfn is not already registered. */ list_for_each(entry, &(user->intf->cmd_rcvrs)) { struct cmd_rcvr *cmp; cmp = list_entry(entry, struct cmd_rcvr, link); if ((cmp->netfn == netfn) && (cmp->cmd == cmd)) { rv = -EBUSY; break; } } if (! rv) { rcvr->cmd = cmd; rcvr->netfn = netfn; rcvr->user = user; list_add_tail(&(rcvr->link), &(user->intf->cmd_rcvrs)); } out_unlock: write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags); read_unlock(&(user->intf->users_lock)); if (rv) kfree(rcvr); return rv;}int ipmi_unregister_for_cmd(ipmi_user_t user, unsigned char netfn, unsigned char cmd){ struct list_head *entry; unsigned long flags; struct cmd_rcvr *rcvr; int rv = -ENOENT; read_lock(&(user->intf->users_lock)); write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags); /* Make sure the command/netfn is not already registered. */ list_for_each(entry, &(user->intf->cmd_rcvrs)) { rcvr = list_entry(entry, struct cmd_rcvr, link); if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) { rv = 0; list_del(entry); kfree(rcvr); break; } } write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags); read_unlock(&(user->intf->users_lock)); return rv;}static unsigned charipmb_checksum(unsigned char *data, int size){ unsigned char csum = 0; for (; size > 0; size--, data++) csum += *data; return -csum;}static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg, struct ipmi_msg *msg, struct ipmi_ipmb_addr *ipmb_addr, long msgid, unsigned char ipmb_seq, int broadcast, unsigned char source_address, unsigned char source_lun){ int i = broadcast; /* Format the IPMB header data. */ smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2); smi_msg->data[1] = IPMI_SEND_MSG_CMD; smi_msg->data[2] = ipmb_addr->channel; if (broadcast) smi_msg->data[3] = 0; smi_msg->data[i+3] = ipmb_addr->slave_addr; smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3); smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2); smi_msg->data[i+6] = source_address; smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun; smi_msg->data[i+8] = msg->cmd; /* Now tack on the data to the message. */ if (msg->data_len > 0) memcpy(&(smi_msg->data[i+9]), msg->data, msg->data_len); smi_msg->data_size = msg->data_len + 9; /* Now calculate the checksum and tack it on. */ smi_msg->data[i+smi_msg->data_size] = ipmb_checksum(&(smi_msg->data[i+6]), smi_msg->data_size-6); /* Add on the checksum size and the offset from the broadcast. */ smi_msg->data_size += 1 + i; smi_msg->msgid = msgid;}/* Separate from ipmi_request so that the user does not have to be supplied in certain circumstances (mainly at panic time). If messages are supplied, they will be freed, even if an error occurs. */static inline int i_ipmi_request(ipmi_user_t user, ipmi_smi_t intf, struct ipmi_addr *addr, long msgid, struct ipmi_msg *msg, void *supplied_smi, struct ipmi_recv_msg *supplied_recv, int priority, unsigned char source_address, unsigned char source_lun){ int rv = 0; struct ipmi_smi_msg *smi_msg; struct ipmi_recv_msg *recv_msg; unsigned long flags; if (supplied_recv) { recv_msg = supplied_recv; } else { recv_msg = ipmi_alloc_recv_msg(); if (recv_msg == NULL) { return -ENOMEM; } } if (supplied_smi) { smi_msg = (struct ipmi_smi_msg *) supplied_smi; } else { smi_msg = ipmi_alloc_smi_msg(); if (smi_msg == NULL) { ipmi_free_recv_msg(recv_msg); return -ENOMEM; } } if (addr->channel > IPMI_NUM_CHANNELS) { rv = -EINVAL; goto out_err; } recv_msg->user = user; recv_msg->msgid = msgid; /* Store the message to send in the receive message so timeout responses can get the proper response data. */ recv_msg->msg = *msg; if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) { struct ipmi_system_interface_addr *smi_addr; smi_addr = (struct ipmi_system_interface_addr *) addr; if (smi_addr->lun > 3) return -EINVAL; memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr)); if ((msg->netfn == IPMI_NETFN_APP_REQUEST) && ((msg->cmd == IPMI_SEND_MSG_CMD) || (msg->cmd == IPMI_GET_MSG_CMD) || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD))) { /* We don't let the user do these, since we manage the sequence numbers. */ rv = -EINVAL; goto out_err; } if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) { rv = -EMSGSIZE; goto out_err; } smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3); smi_msg->data[1] = msg->cmd; smi_msg->msgid = msgid; smi_msg->user_data = recv_msg; if (msg->data_len > 0) memcpy(&(smi_msg->data[2]), msg->data, msg->data_len); smi_msg->data_size = msg->data_len + 2; } else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE) || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) { struct ipmi_ipmb_addr *ipmb_addr; unsigned char ipmb_seq; long seqid; int broadcast; int retries; if (addr == NULL) { rv = -EINVAL; goto out_err; } if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) { /* Broadcasts add a zero at the beginning of the message, but otherwise is the same as an IPMB address. */ addr->addr_type = IPMI_IPMB_ADDR_TYPE; broadcast = 1; retries = 0; /* Don't retry broadcasts. */ } else { broadcast = 0; retries = 4; } /* 9 for the header and 1 for the checksum, plus possibly one for the broadcast. */ if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) { rv = -EMSGSIZE; goto out_err; } ipmb_addr = (struct ipmi_ipmb_addr *) addr; if (ipmb_addr->lun > 3) { rv = -EINVAL; goto out_err; } memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr)); if (recv_msg->msg.netfn & 0x1) { /* It's a response, so use the user's sequence from msgid. */ format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid, msgid, broadcast, source_address, source_lun); } else { /* It's a command, so get a sequence for it. */ spin_lock_irqsave(&(intf->seq_lock), flags); /* Create a sequence number with a 1 second timeout and 4 retries. */ /* FIXME - magic number for the timeout. */ rv = intf_next_seq(intf, recv_msg, 1000, retries, &ipmb_seq, &seqid); if (rv) { /* We have used up all the sequence numbers, probably, so abort. */ spin_unlock_irqrestore(&(intf->seq_lock), flags); goto out_err; } /* Store the sequence number in the message, so that when the send message response comes back we can start the timer. */ format_ipmb_msg(smi_msg, msg, ipmb_addr, STORE_SEQ_IN_MSGID(ipmb_seq, seqid), ipmb_seq, broadcast, source_address, source_lun); /* Copy the message into the recv message data, so we can retransmit it later if necessary. */ memcpy(recv_msg->msg_data, smi_msg->data, smi_msg->data_size); recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = smi_msg->data_size; /* We don't unlock until here, because we need to copy the completed message into the recv_msg before we release the lock. Otherwise, race conditions may bite us. I know that's pretty paranoid, but I prefer to be correct. */ spin_unlock_irqrestore(&(intf->seq_lock), flags); } } else { /* Unknown address type. */ rv = -EINVAL; goto out_err; }#if DEBUG_MSGING { int m; for (m=0; m<smi_msg->data_size; m++) printk(" %2.2x", smi_msg->data[m]); printk("\n"); }#endif intf->handlers->sender(intf->send_info, smi_msg, priority); return 0; out_err: ipmi_free_smi_msg(smi_msg); ipmi_free_recv_msg(recv_msg); return rv;}int ipmi_request(ipmi_user_t user, struct ipmi_addr *addr, long msgid, struct ipmi_msg *msg, int priority){ return i_ipmi_request(user, user->intf, addr, msgid, msg, NULL, NULL, priority, user->intf->my_address, user->intf->my_lun);}int ipmi_request_supply_msgs(ipmi_user_t user, struct ipmi_addr *addr, long msgid, struct ipmi_msg *msg, void *supplied_smi, struct ipmi_recv_msg *supplied_recv, int priority){ return i_ipmi_request(user, user->intf, addr, msgid, msg, supplied_smi, supplied_recv, priority, user->intf->my_address, user->intf->my_lun);}int ipmi_request_with_source(ipmi_user_t user, struct ipmi_addr *addr, long msgid, struct ipmi_msg *msg, int priority, unsigned char source_address, unsigned char source_lun)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -