⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipmi_msghandler.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -