ipmi_msghandler.c

来自「linux 内核源代码」· C语言 代码 · 共 2,407 行 · 第 1/5 页

C
2,407
字号
			intf->sent_invalid_commands++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			rv = -EINVAL;			goto out_err;		}		if (retries < 0) {		    if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)			retries = 0; /* Don't retry broadcasts. */		    else			retries = 4;		}		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;		}		/* Default to 1 second retries. */		if (retry_time_ms == 0)		    retry_time_ms = 1000;		/* 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) {			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_invalid_commands++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			rv = -EMSGSIZE;			goto out_err;		}		ipmb_addr = (struct ipmi_ipmb_addr *) addr;		if (ipmb_addr->lun > 3) {			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_invalid_commands++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			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. */			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_ipmb_responses++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,					msgid, broadcast,					source_address, source_lun);			/* Save the receive message so we can use it			   to deliver the response. */			smi_msg->user_data = recv_msg;		} else {			/* It's a command, so get a sequence for it. */			spin_lock_irqsave(&(intf->seq_lock), flags);			spin_lock(&intf->counter_lock);			intf->sent_ipmb_commands++;			spin_unlock(&intf->counter_lock);			/* Create a sequence number with a 1 second                           timeout and 4 retries. */			rv = intf_next_seq(intf,					   recv_msg,					   retry_time_ms,					   retries,					   broadcast,					   &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 if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {		struct ipmi_lan_addr  *lan_addr;		unsigned char         ipmb_seq;		long                  seqid;		if (addr->channel >= IPMI_MAX_CHANNELS) {			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_invalid_commands++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			rv = -EINVAL;			goto out_err;		}		if ((intf->channels[addr->channel].medium		    != IPMI_CHANNEL_MEDIUM_8023LAN)		    && (intf->channels[addr->channel].medium			!= IPMI_CHANNEL_MEDIUM_ASYNC))		{			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_invalid_commands++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			rv = -EINVAL;			goto out_err;		}		retries = 4;		/* Default to 1 second retries. */		if (retry_time_ms == 0)		    retry_time_ms = 1000;		/* 11 for the header and 1 for the checksum. */		if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_invalid_commands++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			rv = -EMSGSIZE;			goto out_err;		}		lan_addr = (struct ipmi_lan_addr *) addr;		if (lan_addr->lun > 3) {			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_invalid_commands++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			rv = -EINVAL;			goto out_err;		}		memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));		if (recv_msg->msg.netfn & 0x1) {			/* It's a response, so use the user's sequence                           from msgid. */			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_lan_responses++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			format_lan_msg(smi_msg, msg, lan_addr, msgid,				       msgid, source_lun);			/* Save the receive message so we can use it			   to deliver the response. */			smi_msg->user_data = recv_msg;		} else {			/* It's a command, so get a sequence for it. */			spin_lock_irqsave(&(intf->seq_lock), flags);			spin_lock(&intf->counter_lock);			intf->sent_lan_commands++;			spin_unlock(&intf->counter_lock);			/* Create a sequence number with a 1 second                           timeout and 4 retries. */			rv = intf_next_seq(intf,					   recv_msg,					   retry_time_ms,					   retries,					   0,					   &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_lan_msg(smi_msg, msg, lan_addr,				       STORE_SEQ_IN_MSGID(ipmb_seq, seqid),				       ipmb_seq, 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. */		spin_lock_irqsave(&intf->counter_lock, flags);		intf->sent_invalid_commands++;		spin_unlock_irqrestore(&intf->counter_lock, flags);		rv = -EINVAL;		goto out_err;	}#ifdef DEBUG_MSGING	{		int m;		for (m = 0; m < smi_msg->data_size; m++)			printk(" %2.2x", smi_msg->data[m]);		printk("\n");	}#endif	handlers->sender(intf->send_info, smi_msg, priority);	rcu_read_unlock();	return 0; out_err:	rcu_read_unlock();	ipmi_free_smi_msg(smi_msg);	ipmi_free_recv_msg(recv_msg);	return rv;}static int check_addr(ipmi_smi_t       intf,		      struct ipmi_addr *addr,		      unsigned char    *saddr,		      unsigned char    *lun){	if (addr->channel >= IPMI_MAX_CHANNELS)		return -EINVAL;	*lun = intf->channels[addr->channel].lun;	*saddr = intf->channels[addr->channel].address;	return 0;}int ipmi_request_settime(ipmi_user_t      user,			 struct ipmi_addr *addr,			 long             msgid,			 struct kernel_ipmi_msg  *msg,			 void             *user_msg_data,			 int              priority,			 int              retries,			 unsigned int     retry_time_ms){	unsigned char saddr, lun;	int           rv;	if (!user)		return -EINVAL;	rv = check_addr(user->intf, addr, &saddr, &lun);	if (rv)		return rv;	return i_ipmi_request(user,			      user->intf,			      addr,			      msgid,			      msg,			      user_msg_data,			      NULL, NULL,			      priority,			      saddr,			      lun,			      retries,			      retry_time_ms);}int ipmi_request_supply_msgs(ipmi_user_t          user,			     struct ipmi_addr     *addr,			     long                 msgid,			     struct kernel_ipmi_msg *msg,			     void                 *user_msg_data,			     void                 *supplied_smi,			     struct ipmi_recv_msg *supplied_recv,			     int                  priority){	unsigned char saddr, lun;	int           rv;	if (!user)		return -EINVAL;	rv = check_addr(user->intf, addr, &saddr, &lun);	if (rv)		return rv;	return i_ipmi_request(user,			      user->intf,			      addr,			      msgid,			      msg,			      user_msg_data,			      supplied_smi,			      supplied_recv,			      priority,			      saddr,			      lun,			      -1, 0);}#ifdef CONFIG_PROC_FSstatic int ipmb_file_read_proc(char *page, char **start, off_t off,			       int count, int *eof, void *data){	char       *out = (char *) page;	ipmi_smi_t intf = data;	int        i;	int        rv = 0;	for (i = 0; i < IPMI_MAX_CHANNELS; i++)		rv += sprintf(out+rv, "%x ", intf->channels[i].address);	out[rv-1] = '\n'; /* Replace the final space with a newline */	out[rv] = '\0';	rv++;	return rv;}static int version_file_read_proc(char *page, char **start, off_t off,				  int count, int *eof, void *data){	char       *out = (char *) page;	ipmi_smi_t intf = data;	return sprintf(out, "%d.%d\n",		       ipmi_version_major(&intf->bmc->id),		       ipmi_version_minor(&intf->bmc->id));}static int stat_file_read_proc(char *page, char **start, off_t off,			       int count, int *eof, void *data){	char       *out = (char *) page;	ipmi_smi_t intf = data;	out += sprintf(out, "sent_invalid_commands:       %d\n",		       intf->sent_invalid_commands);	out += sprintf(out, "sent_local_commands:         %d\n",		       intf->sent_local_commands);	out += sprintf(out, "handled_local_responses:     %d\n",		       intf->handled_local_responses);	out += sprintf(out, "unhandled_local_responses:   %d\n",		       intf->unhandled_local_responses);	out += sprintf(out, "sent_ipmb_commands:          %d\n",		       intf->sent_ipmb_commands);	out += sprintf(out, "sent_ipmb_command_errs:      %d\n",		       intf->sent_ipmb_command_errs);	out += sprintf(out, "retransmitted_ipmb_commands: %d\n",		       intf->retransmitted_ipmb_commands);	out += sprintf(out, "timed_out_ipmb_commands:     %d\n",		       intf->timed_out_ipmb_commands);	out += sprintf(out, "timed_out_ipmb_broadcasts:   %d\n",		       intf->timed_out_ipmb_broadcasts);	out += sprintf(out, "sent_ipmb_responses:         %d\n",		       intf->sent_ipmb_responses);	out += sprintf(out, "handled_ipmb_responses:      %d\n",		       intf->handled_ipmb_responses);	out += sprintf(out, "invalid_ipmb_responses:      %d\n",		       intf->invalid_ipmb_responses);	out += sprintf(out, "unhandled_ipmb_responses:    %d\n",		       intf->unhandled_ipmb_responses);	out += sprintf(out, "sent_lan_commands:           %d\n",		       intf->sent_lan_commands);	out += sprintf(out, "sent_lan_command_errs:       %d\n",		       intf->sent_lan_command_errs);	out += sprintf(out, "retransmitted_lan_commands:  %d\n",		       intf->retransmitted_lan_commands);	out += sprintf(out, "timed_out_lan_commands:      %d\n",		       intf->timed_out_lan_commands);	out += sprintf(out, "sent_lan_responses:          %d\n",		       intf->sent_lan_responses);	out += sprintf(out, "handled_lan_responses:       %d\n",		       intf->handled_lan_responses);	out += sprintf(out, "invalid_lan_responses:       %d\n",		       intf->invalid_lan_responses);	out += sprintf(out, "unhandled_lan_responses:     %d\n",		       intf->unhandled_lan_responses);	out += sprintf(out, "handled_commands:            %d\n",		       intf->handled_commands);	out += sprintf(out, "invalid_commands:            %d\n",		       intf->invalid_commands);	out += sprintf(out, "unhandled_commands:          %d\n",		       intf->unhandled_commands);	out += sprintf(out, "invalid_events:              %d\n",		       intf->invalid_events);	out += sprintf(out, "events:                      %d\n",		       intf->events);	return (out - ((char *) page));}#endif /* CONFIG_PROC_FS */int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,			    read_proc_t *read_proc, write_proc_t *write_proc,			    void *data, struct module *owner){	int                    rv = 0;#ifdef CONFIG_PROC_FS	struct proc_dir_entry  *file;	struct ipmi_proc_entry *entry;	/* Create a list element. */	entry = kmalloc(sizeof(*entry), GFP_KERNEL);	if (!entry)		return -ENOMEM;	entry->name = kmalloc(strlen(name)+1, GFP_KERNEL);	if (!entry->name) {		kfree(entry);		return -ENOMEM;	}	strcpy(entry->name, name);	file = create_proc_entry(name, 0, smi->proc_dir);	if (!file) {		kfree(entry->name);		kfree(entry);		rv = -ENOMEM;	} else {		file->data = data;		file->read_proc = read_proc;		file->write_proc = write_proc;		file->owner = owner;		mutex_lock(&smi->proc_entry_lock);		/* Stick it on the list. */		entry->next = smi->proc_entries;		smi->proc_entries = entry;		mutex_unlock(&smi->proc_entry_lock);	}#endif /* CONFIG_PROC_FS */	return rv;}static int add_proc_entries(ipmi_smi_t smi, int num){	int rv = 0;#ifdef CONFIG_PROC_FS	sprintf(smi->proc_dir_name, "%d", num);	smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);	if (!smi->proc_dir)		rv = -ENOMEM;	else {		smi->proc_dir->owner = THIS_MODULE;	}	if (rv == 0)		rv = ipmi_smi_add_proc_entry(smi, "stats",					     stat_file_read_proc, NULL,					     smi, THIS_MODULE);	if (rv == 0)		rv = ipmi_smi_add_proc_entry(smi, "ipmb",					     ipmb_file_read_proc, NULL,					     smi, THIS_MODULE);	if (rv == 0)		rv = ipmi_smi_add_proc_entry(smi, "version",					     version_file_read_proc, NULL,

⌨️ 快捷键说明

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