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

📄 ipmi_msghandler.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * ipmi_msghandler.c * * Incoming and outgoing message routing for an IPMI interface. * * Author: MontaVista Software, Inc. *         Corey Minyard <minyard@mvista.com> *         source@mvista.com * * Copyright 2002 MontaVista Software Inc. * *  This program is free software; you can redistribute it and/or modify it *  under the terms of the GNU General Public License as published by the *  Free Software Foundation; either version 2 of the License, or (at your *  option) any later version. * * *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *  You should have received a copy of the GNU General Public License along *  with this program; if not, write to the Free Software Foundation, Inc., *  675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/config.h>#include <linux/module.h>#include <linux/errno.h>#include <asm/system.h>#include <linux/sched.h>#include <linux/poll.h>#include <linux/spinlock.h>#include <linux/rwsem.h>#include <linux/slab.h>#include <linux/ipmi.h>#include <linux/ipmi_smi.h>#include <linux/notifier.h>#include <linux/init.h>struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);static int ipmi_init_msghandler(void);static int initialized = 0;#define MAX_EVENTS_IN_QUEUE	25struct ipmi_user{	struct list_head link;	/* The upper layer that handles receive messages. */	struct ipmi_user_hndl *handler;	void             *handler_data;	/* The interface this user is bound to. */	ipmi_smi_t intf;	/* Does this interface receive IPMI events? */	int gets_events;};struct cmd_rcvr{	struct list_head link;	ipmi_user_t   user;	unsigned char netfn;	unsigned char cmd;};#define IPMI_IPMB_NUM_SEQ	64struct ipmi_smi{	/* The list of upper layers that are using me.  We read-lock           this when delivering messages to the upper layer to keep           the user from going away while we are processing the           message.  This means that you cannot add or delete a user           from the receive callback. */	rwlock_t                users_lock;	struct list_head        users;	/* The IPMI version of the BMC on the other end. */	unsigned char       version_major;	unsigned char       version_minor;	/* This is the lower-layer's sender routine. */	struct ipmi_smi_handlers *handlers;	void                     *send_info;	/* A table of sequence numbers for this interface.  We use the           sequence numbers for IPMB messages that go out of the           interface to match them up with their responses.  A routine           is called periodically to time the items in this list. */	spinlock_t              seq_lock;	struct {		unsigned long   timeout;		int             inuse;		struct ipmi_recv_msg *recv_msg;	} seq_table[IPMI_IPMB_NUM_SEQ];	int curr_seq;	/* Messages that were delayed for some reason (out of memory,           for instance), will go in here to be processed later in a           periodic timer interrupt. */	spinlock_t       waiting_msgs_lock;	struct list_head waiting_msgs;	/* The list of command receivers that are registered for commands	   on this interface. */	rwlock_t	 cmd_rcvr_lock;	struct list_head cmd_rcvrs;	/* Events that were queues because no one was there to receive           them. */	spinlock_t       events_lock; /* For dealing with event stuff. */	struct list_head waiting_events;	unsigned int     waiting_events_count; /* How many events in queue? */	/* This will be non-null if someone registers to receive all	   IPMI commands (this is for interface emulation).  There	   may not be any things in the cmd_rcvrs list above when	   this is registered. */	ipmi_user_t all_cmd_rcvr;	/* My slave address.  This is initialized to IPMI_BMC_SLAVE_ADDR,	   but may be changed by the user. */	unsigned char my_address;	/* My LUN.  This should generally stay the SMS LUN, but just in	   case... */	unsigned char my_lun;};intipmi_register_all_cmd_rcvr(ipmi_user_t user){	int flags;	int rv = -EBUSY;	write_lock_irqsave(&(user->intf->users_lock), flags);	write_lock(&(user->intf->cmd_rcvr_lock));	if ((user->intf->all_cmd_rcvr == NULL)	    && (list_empty(&(user->intf->cmd_rcvrs))))	{		user->intf->all_cmd_rcvr = user;		rv = 0;	}	write_unlock(&(user->intf->cmd_rcvr_lock));	write_unlock_irqrestore(&(user->intf->users_lock), flags);	return rv;}intipmi_unregister_all_cmd_rcvr(ipmi_user_t user){	int flags;	int rv = -EINVAL;	write_lock_irqsave(&(user->intf->users_lock), flags);	write_lock(&(user->intf->cmd_rcvr_lock));	if (user->intf->all_cmd_rcvr == user)	{		user->intf->all_cmd_rcvr = NULL;		rv = 0;	}	write_unlock(&(user->intf->cmd_rcvr_lock));	write_unlock_irqrestore(&(user->intf->users_lock), flags);	return rv;}#define MAX_IPMI_INTERFACES 4static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES];/* Used to keep interfaces from going away while operations are   operating on interfaces.  Grab read if you are not modifying the   interfaces, write if you are. */static DECLARE_RWSEM(interfaces_sem);/* Directly protects the ipmi_interfaces data structure.  This is   claimed in the timer interrupt. */static spinlock_t interfaces_lock = SPIN_LOCK_UNLOCKED;/* List of watchers that want to know when smi's are added and   deleted. */static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);static DECLARE_RWSEM(smi_watchers_sem);int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher){	int i;	down_read(&interfaces_sem);	down_write(&smi_watchers_sem);	list_add(&(watcher->link), &smi_watchers);	for (i=0; i<MAX_IPMI_INTERFACES; i++) {		if (ipmi_interfaces[i] != NULL) {			watcher->new_smi(i);		}	}	up_write(&smi_watchers_sem);	up_read(&interfaces_sem);	return 0;}int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher){	down_write(&smi_watchers_sem);	list_del(&(watcher->link));	up_write(&smi_watchers_sem);	return 0;}intipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2){	if (addr1->addr_type != addr2->addr_type)		return 0;	if (addr1->channel != addr2->channel)		return 0;	if (addr1->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {		struct ipmi_system_interface_addr *smi_addr1		    = (struct ipmi_system_interface_addr *) addr1;		struct ipmi_system_interface_addr *smi_addr2		    = (struct ipmi_system_interface_addr *) addr2;		return (smi_addr1->lun == smi_addr2->lun);	}	if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)	    || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))	{		struct ipmi_ipmb_addr *ipmb_addr1		    = (struct ipmi_ipmb_addr *) addr1;		struct ipmi_ipmb_addr *ipmb_addr2		    = (struct ipmi_ipmb_addr *) addr2;		return ((ipmb_addr1->slave_addr == ipmb_addr2->slave_addr)			&& (ipmb_addr1->lun == ipmb_addr2->lun));	}	return 1;}int ipmi_validate_addr(struct ipmi_addr *addr, int len){	if (len < sizeof(struct ipmi_system_interface_addr)) {		return -EINVAL;	}	if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {		if (addr->channel != IPMI_BMC_CHANNEL)			return -EINVAL;		return 0;	}	if ((addr->channel == IPMI_BMC_CHANNEL)	    || (addr->channel >= IPMI_NUM_CHANNELS)	    || (addr->channel < 0))		return -EINVAL;	if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)	    || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))	{		if (len < sizeof(struct ipmi_ipmb_addr)) {			return -EINVAL;		}		return 0;	}	return -EINVAL;}unsigned int ipmi_addr_length(int addr_type){	if (addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)		return sizeof(struct ipmi_system_interface_addr);	if ((addr_type == IPMI_IPMB_ADDR_TYPE)	    || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))	{		return sizeof(struct ipmi_ipmb_addr);	}	return 0;}static void deliver_response(struct ipmi_recv_msg *msg){    msg->user->handler->ipmi_recv_hndl(msg, msg->user->handler_data);}/* Find the next sequence number not being used and add the given   message with the given timeout to the sequence table. */static int intf_next_seq(ipmi_smi_t           intf,			 struct ipmi_recv_msg *recv_msg,			 unsigned long        timeout,			 unsigned char        *seq){	int           rv = 0;	unsigned long flags;	unsigned int  i;	spin_lock_irqsave(&(intf->seq_lock), flags);	for (i=intf->curr_seq;	     i!=(intf->curr_seq-1);	     i=(i+1)%IPMI_IPMB_NUM_SEQ)	{		if (! intf->seq_table[i].inuse)			break;	}	if (! intf->seq_table[i].inuse) {		intf->seq_table[i].recv_msg = recv_msg;		intf->seq_table[i].timeout = timeout;		intf->seq_table[i].inuse = 1;		*seq = i;		intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ;	} else {		rv = -EAGAIN;	}		spin_unlock_irqrestore(&(intf->seq_lock), flags);	return rv;}/* Return the receive message for the given sequence number and   release the sequence number so it can be reused.  Some other data   is passed in to be sure the message matches up correctly (to help   guard against message coming in after their timeout and the   sequence number being reused). */static int intf_find_seq(ipmi_smi_t           intf,			 unsigned char        seq,			 short                channel,			 unsigned char        cmd,			 unsigned char        netfn,			 struct ipmi_addr     *addr,			 struct ipmi_recv_msg **recv_msg){	int           rv = -ENODEV;	unsigned long flags;	if (seq >= IPMI_IPMB_NUM_SEQ)		return -EINVAL;	spin_lock_irqsave(&(intf->seq_lock), flags);	if (intf->seq_table[seq].inuse) {		struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg;		if ((msg->addr.channel == channel)		    && (msg->msg.cmd == cmd)		    && (msg->msg.netfn == netfn)		    && (ipmi_addr_equal(addr, &(msg->addr))))		{			*recv_msg = msg;			intf->seq_table[seq].inuse = 0;			rv = 0;		}	}	spin_unlock_irqrestore(&(intf->seq_lock), flags);	return rv;}int ipmi_create_user(unsigned int          if_num,		     struct ipmi_user_hndl *handler,		     void                  *handler_data,		     ipmi_user_t           *user){	unsigned long flags;	ipmi_user_t   new_user;	int           rv = 0;	/* There is no module usecount here, because it's not           required.  Since this can only be used by and called from           other modules, they will implicitly use this module, and           thus this can't be removed unless the other modules are           removed. */	if (handler == NULL)		return -EINVAL;	/* Make sure the driver is actually initialized, this handles	   problems with initialization order. */	if (!initialized) {		rv = ipmi_init_msghandler();		if (rv)			return rv;		/* The init code doesn't return an error if it was turned		   off, but it won't initialize.  Check that. */		if (!initialized)			return -ENODEV;	}	new_user = kmalloc(sizeof(*new_user), GFP_KERNEL);	if (! new_user)		return -ENOMEM;	down_read(&interfaces_sem);	if ((if_num > MAX_IPMI_INTERFACES) || ipmi_interfaces[if_num] == NULL)	{		rv = -EINVAL;		goto out_unlock;	}	new_user->handler = handler;	new_user->handler_data = handler_data;	new_user->intf = ipmi_interfaces[if_num];	new_user->gets_events = 0;	rv = new_user->intf->handlers->new_user(new_user->intf->send_info);	if (rv)		goto out_unlock;	write_lock_irqsave(&(new_user->intf->users_lock), flags);	list_add_tail(&(new_user->link), &(new_user->intf->users));	write_unlock_irqrestore(&(new_user->intf->users_lock), flags); out_unlock:		if (rv) {		kfree(new_user);	} else {		*user = new_user;	}	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) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -