<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">
From: Corey Minyard &lt;cminyard@mvista.com&gt;

IPMI is a management standard that allows intelligent management
controllers to monitor things about the system (temperature, fan speed,
etc.).  The management controllers sit on a bus, and have addresses, and
such.  After seeing the ugliness required for the 32-bit ioctl
compatability layers for 64-bit kernels, I have decided that the network
interface for IPMI is a good thing, as the IPMI device ioctls have pointers
and require ugly hacks.  None should be needed for the network interface.

This patch adds that layer.

Signed-off-by: Andrew Morton &lt;akpm@osdl.org&gt;
---

 25-akpm/Documentation/IPMI.txt |  122 ++++++++
 25-akpm/include/linux/net.h    |    2 
 25-akpm/include/linux/socket.h |    4 
 25-akpm/include/net/af_ipmi.h  |   59 +++
 25-akpm/net/Kconfig            |   11 
 25-akpm/net/Makefile           |    1 
 25-akpm/net/ipmi/Makefile      |    1 
 25-akpm/net/ipmi/af_ipmi.c     |  608 +++++++++++++++++++++++++++++++++++++++++
 8 files changed, 805 insertions(+), 3 deletions(-)

diff -puN Documentation/IPMI.txt~network-interface-for-ipmi Documentation/IPMI.txt
--- 25/Documentation/IPMI.txt~network-interface-for-ipmi	Wed Nov 17 14:41:27 2004
+++ 25-akpm/Documentation/IPMI.txt	Wed Nov 17 14:41:27 2004
@@ -104,7 +104,7 @@ over the SMBus.
 af_ipmi - A network socket interface to IPMI.  This doesn't take up
 a character device in your system.
 
-Note that the KCS-only interface ahs been removed.
+Note that the KCS-only interface has been removed.
 
 Much documentation for the interface is in the include files.  The
 IPMI include files are:
@@ -218,6 +218,125 @@ You should look at the receive type and 
 appropriately.
 
 
+Using the Socket Interface
+--------------------------
+
+The socket interface to IPMI removes a lot of the evils of the ioctl
+interface, including taking a character device and passing pointers
+between userland and the kernel in ioctl structures.  Plus, IPMI is
+really kind of a network, you have addressing, message options, and
+things of that nature that fit naturally into the socket interface.  I
+should have done that from the beginning.
+
+This is the recommended interface to use for IPMI.  It is a lot
+cleaner than the ioctl interface.
+
+To create an IPMI socket, do something like the following:
+
+    int                  fd;
+    int                  rv;
+    struct sockaddr_ipmi addr;
+
+    fd = socket(PF_IPMI, SOCK_DGRAM, 0);
+    if (fd == -1)
+	&lt;return error&gt;
+    addr.sipmi_family = AF_IPMI;
+    addr.if_num = if_num;
+    rv = bind(fd, (struct sockaddr *) &amp;addr, sizeof(addr));
+    if (rv != -1) {
+        close(fd)
+	&lt;return error&gt;
+    }
+
+The "if_num" variable above is which IPMI interface you are binding
+to, generally zero.  To send a message, do something like:
+
+    struct sockaddr_ipmi     saddr;
+    char                     smsg_data[sizeof(struct ipmi_sock_msg)
+                                       + IPMI_MAX_MSG_LENGTH];
+    struct ipmi_sock_msg     *smsg = (void *) smsg_data;
+
+    saddr.sipmi_family = AF_IPMI;
+    memcpy(&amp;saddr.ipmi_addr, addr, addr_len);
+
+    smsg-&gt;netfn = netfn;
+    smsg-&gt;cmd = cmd;
+    smsg-&gt;data_len = data_len;
+    smsg-&gt;msgid = msgid;
+    memcpy(smsg-&gt;data, data, smsg-&gt;data_len);
+
+    rv = sendto(fd, smsg, sizeof(*smsg) + msg-&gt;data_len, 0,
+                (struct sockaddr *) &amp;saddr,
+                addr_len + SOCKADDR_IPMI_OVERHEAD);
+
+The "addr" variable here is an address as described by the addressing
+section above.  The message data is the same as described in the
+messaging section above.
+
+    struct sockaddr_ipmi addr;
+    socklen_t            addr_len;
+    struct ipmi_sock_msg *smsg;
+    unsigned char        data[MAX_IPMI_DATA_SIZE + sizeof(*smsg)];
+
+
+    addr_len = sizeof(addr);
+    rv = recvfrom(fd, data, sizeof(data), 0,
+		  (struct sockaddr *) &amp;addr, &amp;addr_len);
+    if (rv &lt; 0) {
+        &lt;handle error&gt;
+    }
+
+    if (rv &lt; sizeof(*smsg)) {
+        &lt;handle error, msg too short&gt;
+    }
+
+    smsg = (struct ipmi_sock_msg *) data;
+    if (rv &lt; (sizeof(*smsg) + smsg-&gt;data_len)) {
+        &lt;handle error, msg too short&gt;
+    }
+
+    recv_type = smsg-&gt;recv_type;
+    ipmi_addr = (struct ipmi_addr *) &amp;addr.ipmi_addr;
+    ipmi_addr_len = addr_len - SOCKADDR_IPMI_OVERHEAD;
+    msgid = smsg-&gt;msgid;
+    msg.netfn = smsg-&gt;netfn;
+    msg.cmd = smsg-&gt;cmd;
+    msg.data = smsg-&gt;data;
+    msg.data_len = smsg-&gt;data_len;
+
+You must handle the received message based upon the receive type.
+
+There are a few other things that are ioctls for the socket.  This is
+a few things that cannot be done in any easy way besides an ioctl, but
+these don't contain any nasty things like pointers.
+
+The following sets the local address for the BMC.  IPMI provides no
+way for the driver to discover what the IPMB address for the BMC
+should be.  So this has to be set by the software using it.
+
+    unsigned int slave_addr;
+    rv = ioctl(fd, SIOCIPMISETADDR, &amp;slave_addr);
+
+The following enabled events to be received from the interface.  If
+you set this to true, incoming events will be delivered to the fd.
+
+    int enable_events;
+    rv = ioctl(fd, SIOCIPMIGETEVENT, &amp;enable_events);
+
+To receive external command addressed to LUN 2 of the BMC, register
+with the following ioctl:
+
+    struct ipmi_cmdspec reg;
+    reg.netfn = netfn;
+    reg.cmd = cmd;
+    rv = ioctl(fd, SIOCIPMIREGCMD, &amp;reg);
+
+The deregistration call is:
+
+    rv = ioctl(fd, SIOCIPMIUNREGCMD, &amp;reg);
+
+
+
 The Upper Layer Interface (Message Handler)
 -------------------------------------------
 
@@ -293,6 +412,7 @@ though, since it is tricky to manage you
 
 
 Events and Incoming Commands
+----------------------------
 
 The driver takes care of polling for IPMI events and receiving
 commands (commands are messages that are not responses, they are
diff -puN include/linux/net.h~network-interface-for-ipmi include/linux/net.h
--- 25/include/linux/net.h~network-interface-for-ipmi	Wed Nov 17 14:41:27 2004
+++ 25-akpm/include/linux/net.h	Wed Nov 17 14:41:27 2004
@@ -26,7 +26,7 @@
 struct poll_table_struct;
 struct inode;
 
-#define NPROTO		32		/* should be enough for now..	*/
+#define NPROTO		33		/* should be enough for now..	*/
 
 #define SYS_SOCKET	1		/* sys_socket(2)		*/
 #define SYS_BIND	2		/* sys_bind(2)			*/
diff -puN include/linux/socket.h~network-interface-for-ipmi include/linux/socket.h
--- 25/include/linux/socket.h~network-interface-for-ipmi	Wed Nov 17 14:41:27 2004
+++ 25-akpm/include/linux/socket.h	Wed Nov 17 14:41:27 2004
@@ -177,7 +177,8 @@ struct ucred {
 #define AF_WANPIPE	25	/* Wanpipe API Sockets */
 #define AF_LLC		26	/* Linux LLC			*/
 #define AF_BLUETOOTH	31	/* Bluetooth sockets 		*/
-#define AF_MAX		32	/* For now.. */
+#define AF_IPMI		32	/* IPMI sockers 		*/
+#define AF_MAX		33	/* For now.. */
 
 /* Protocol families, same as address families. */
 #define PF_UNSPEC	AF_UNSPEC
@@ -209,6 +210,7 @@ struct ucred {
 #define PF_WANPIPE	AF_WANPIPE
 #define PF_LLC		AF_LLC
 #define PF_BLUETOOTH	AF_BLUETOOTH
+#define PF_IPMI		AF_IPMI
 #define PF_MAX		AF_MAX
 
 /* Maximum queue length specifiable by listen.  */
diff -puN /dev/null include/net/af_ipmi.h
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/include/net/af_ipmi.h	Wed Nov 17 14:41:27 2004
@@ -0,0 +1,59 @@
+/*
+ * IPMI Socket Glue
+ *
+ * Author:	Louis Zhuang &lt;louis.zhuang@linux.intel.com&gt;
+ * Copyright by Intel Corp., 2003
+ */
+#ifndef _NET_IPMI_H
+#define _NET_IPMI_H
+
+#include &lt;linux/ipmi.h&gt;
+
+/*
+ * This is ipmi address for socket
+ */
+struct sockaddr_ipmi {
+	sa_family_t      sipmi_family; /* AF_IPMI */
+	int              if_num; /* IPMI interface number */
+	struct ipmi_addr ipmi_addr;
+};
+#define SOCKADDR_IPMI_OVERHEAD (sizeof(struct sockaddr_ipmi) \
+				- sizeof(struct ipmi_addr))
+
+/* A msg_control item, this takes a 'struct ipmi_timing_parms' */
+#define IPMI_CMSG_TIMING_PARMS	0x01
+
+/*
+ * This is ipmi message for socket
+ */
+struct ipmi_sock_msg {
+	int                   recv_type;
+	long                  msgid;
+
+	unsigned char         netfn;
+	unsigned char         cmd;
+	int                   data_len;
+	unsigned char         data[0];
+};
+
+#define IPMI_MAX_SOCK_MSG_LENGTH (sizeof(struct ipmi_sock_msg)+IPMI_MAX_MSG_LENGTH)
+
+/* Register/unregister to receive specific commands.  Uses struct
+   ipmi_cmdspec from linux/ipmi.h */
+#define SIOCIPMIREGCMD		(SIOCPROTOPRIVATE + 0)
+#define SIOCIPMIUNREGCMD	(SIOCPROTOPRIVATE + 1)
+
+/* Register to receive events.  Takes an integer */
+#define SIOCIPMIGETEVENT	(SIOCPROTOPRIVATE + 2)
+
+/* Set the default timing parameters for the socket.  Takes a struct
+   ipmi_timing_parms from linux/ipmi.h */
+#define SIOCIPMISETTIMING	(SIOCPROTOPRIVATE + 3)
+#define SIOCIPMIGETTIMING	(SIOCPROTOPRIVATE + 4)
+
+/* Set/Get the IPMB address of the MC we are connected to, takes an
+   unsigned int. */
+#define SIOCIPMISETADDR		(SIOCPROTOPRIVATE + 5)
+#define SIOCIPMIGETADDR		(SIOCPROTOPRIVATE + 6)
+
+#endif/*_NET_IPMI_H*/
diff -puN /dev/null net/ipmi/af_ipmi.c
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/net/ipmi/af_ipmi.c	Wed Nov 17 14:41:27 2004
@@ -0,0 +1,608 @@
+/*
+ * IPMI Socket Glue
+ *
+ * Author:	Louis Zhuang &lt;louis.zhuang@linux.intel.com&gt;
+ * Copyright by Intel Corp., 2003
+ */
+#include &lt;linux/module.h&gt;
+#include &lt;linux/moduleparam.h&gt;
+#include &lt;linux/config.h&gt;
+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/major.h&gt;
+#include &lt;linux/signal.h&gt;
+#include &lt;linux/sched.h&gt;
+#include &lt;linux/errno.h&gt;
+#include &lt;linux/string.h&gt;
+#include &lt;linux/stat.h&gt;
+#include &lt;linux/socket.h&gt;
+#include &lt;linux/fcntl.h&gt;
+#include &lt;linux/sockios.h&gt;
+#include &lt;linux/net.h&gt;
+#include &lt;linux/in.h&gt;
+#include &lt;linux/fs.h&gt;
+#include &lt;linux/slab.h&gt;
+#include &lt;asm/uaccess.h&gt;
+#include &lt;linux/skbuff.h&gt;
+#include &lt;linux/tcp.h&gt;
+#include &lt;net/sock.h&gt;
+#include &lt;linux/proc_fs.h&gt;
+#include &lt;linux/init.h&gt;
+#include &lt;linux/poll.h&gt;
+#include &lt;linux/smp_lock.h&gt;
+#include &lt;linux/mount.h&gt;
+#include &lt;linux/security.h&gt;
+#include &lt;linux/ipmi.h&gt;
+#include &lt;net/af_ipmi.h&gt;
+
+#define IPMI_SOCKINTF_VERSION "v33"
+
+#ifdef CONFIG_DEBUG_KERNEL
+static int debug = 0;
+#define dbg(format, arg...)                                     \
+        do {                                                    \
+                if(debug)                                    \
+                        printk (KERN_DEBUG "%s: " format "\n",  \
+                                __FUNCTION__, ## arg);          \
+        } while(0)
+#else
+#define dbg(format, arg...)
+#endif /* CONFIG_DEBUG_KERNEL */
+
+#define err(format, arg...) \
+                printk(KERN_ERR "%s: " format "\n", \
+                       __FUNCTION__ , ## arg)
+#define info(format, arg...) \
+                printk(KERN_INFO "%s: " format "\n", \
+                       __FUNCTION__ , ## arg)
+#define warn(format, arg...) \
+                printk(KERN_WARNING "%s: " format "\n", \
+                       __FUNCTION__ , ## arg)
+#define trace(format, arg...) \
+                printk(KERN_INFO "%s(" format ")\n", \
+                       __FUNCTION__ , ## arg)
+
+struct ipmi_sock {
+	/* WARNING: sk has to be the first member */
+	struct sock sk;
+
+	ipmi_user_t user;
+	struct sockaddr_ipmi addr;
+	struct list_head msg_list;
+
+	wait_queue_head_t wait;
+	spinlock_t lock;
+
+	int          default_retries;
+	unsigned int default_retry_time_ms;
+};
+
+static kmem_cache_t *ipmi_sk_cachep = NULL;
+
+static atomic_t ipmi_nr_socks = ATOMIC_INIT(0);
+
+
+
+/*
+ * utility functions
+ */
+static inline struct ipmi_sock *to_ipmi_sock(struct sock *sk)
+{
+	return container_of(sk, struct ipmi_sock, sk);
+}
+
+static inline void ipmi_release_sock(struct sock *sk, int embrion)
+{
+	struct ipmi_sock *i = to_ipmi_sock(sk);
+	struct sk_buff   *skb;
+
+	if (i-&gt;user) {
+		ipmi_destroy_user(i-&gt;user);
+		i-&gt;user = NULL;
+	}
+
+	sock_orphan(&amp;i-&gt;sk);
+	sk-&gt;sk_shutdown = SHUTDOWN_MASK;
+	sk-&gt;sk_state = TCP_CLOSE;
+
+	while((skb=skb_dequeue(&amp;sk-&gt;sk_receive_queue))!=NULL)
+		kfree_skb(skb);
+
+	sock_put(sk);
+}
+
+static inline long ipmi_wait_for_queue(struct ipmi_sock *i, long timeo)
+{
+
+	DECLARE_WAITQUEUE(wait, current);
+
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue_exclusive(&amp;i-&gt;wait, &amp;wait);
+	timeo = schedule_timeout(timeo);
+	remove_wait_queue(&amp;i-&gt;wait, &amp;wait);
+	return timeo;
+}
+
+/*
+ * IPMI operation functions
+ */
+static void sock_receive_handler(struct ipmi_recv_msg *msg,
+				 void                 *handler_data)
+{
+	struct ipmi_sock *i = (struct ipmi_sock *)handler_data;
+	unsigned long    flags;
+
+	spin_lock_irqsave(&amp;i-&gt;lock, flags);
+	list_add_tail(&amp;msg-&gt;link, &amp;i-&gt;msg_list);
+	spin_unlock_irqrestore(&amp;i-&gt;lock, flags);
+
+	wake_up_interruptible(&amp;i-&gt;wait);
+}
+
+/*
+ * protocol operation functions
+ */
+static int ipmi_release(struct socket *sock)
+{
+	struct sock *sk = sock-&gt;sk;
+
+	if (!sk)
+		return 0;
+
+	sock-&gt;sk=NULL;
+	ipmi_release_sock(sk, 0);
+	return 0;
+}
+
+static struct ipmi_user_hndl ipmi_hnd = {
+	.ipmi_recv_hndl = sock_receive_handler
+};
+
+static int ipmi_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+{
+	struct ipmi_sock *i = to_ipmi_sock(sock-&gt;sk);
+	struct sockaddr_ipmi *addr = (struct sockaddr_ipmi *)uaddr;
+	int err = -EINVAL;
+
+	if (i-&gt;user != NULL) {
+		dbg("Cannot bind twice: %p", i-&gt;user);
+		return -EINVAL;
+	}
+
+	err = ipmi_create_user(addr-&gt;if_num, &amp;ipmi_hnd, i, &amp;i-&gt;user);
+	if (err) {
+		dbg("Cannot create user for the socket: %p", i-&gt;user);
+		return err;
+	}
+
+	memcpy(&amp;i-&gt;addr, addr, sizeof(i-&gt;addr));
+	return 0;
+}
+
+static int ipmi_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer)
+{
+	struct ipmi_sock *i = to_ipmi_sock(sock-&gt;sk);
+	memcpy(uaddr, &amp;i-&gt;addr, sizeof(i-&gt;addr));
+	return 0;
+}
+
+static unsigned int ipmi_poll(struct file * file, struct socket *sock, poll_table *wait)
+{
+	unsigned int     has_msg = 0;
+	struct ipmi_sock *i = to_ipmi_sock(sock-&gt;sk);
+	unsigned long    flags;
+
+	poll_wait(file, &amp;i-&gt;wait, wait);
+	spin_lock_irqsave(&amp;i-&gt;lock, flags);
+	if (!list_empty(&amp;i-&gt;msg_list))
+		has_msg = 1;
+	spin_unlock_irqrestore(&amp;i-&gt;lock, flags);
+
+	if (has_msg)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+static int ipmi_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+	struct ipmi_sock    *i = to_ipmi_sock(sock-&gt;sk);
+	struct ipmi_cmdspec val;
+	int                 ival;
+	unsigned int        uival;
+	int                 err;
+
+	dbg("cmd=%#x, arg=%#lx", cmd, arg);
+	switch(cmd) {
+	case SIOCIPMIREGCMD:
+		err = copy_from_user((void *)&amp;val, (void *)arg,
+				     sizeof(cmd));
+		if (err) {
+			err = -EFAULT;
+			break;
+		}
+
+		err = ipmi_register_for_cmd(i-&gt;user, val.netfn,
+					    val.cmd);
+		break;
+
+	case SIOCIPMIUNREGCMD:
+		err = copy_from_user((void *)&amp;val, (void *)arg,
+				     sizeof(cmd));
+		if (err) {
+			err = -EFAULT;
+			break;
+		}
+
+		err = ipmi_unregister_for_cmd(i-&gt;user, val.netfn,
+					      val.cmd);
+		break;
+
+	case SIOCIPMIGETEVENT:
+		err = copy_from_user((void *)&amp;ival, (void *)arg,
+				     sizeof(ival));
+		if (err) {
+			err = -EFAULT;
+			break;
+		}
+
+		err = ipmi_set_gets_events(i-&gt;user, ival);
+		break;
+
+	case SIOCIPMISETADDR:
+		err = copy_from_user((void *)&amp;uival, (void *)arg,
+				     sizeof(uival));
+		if (err) {
+			err = -EFAULT;
+			break;
+		}
+
+		ipmi_set_my_address(i-&gt;user, uival);
+		break;
+
+	case SIOCIPMIGETADDR:
+		uival = ipmi_get_my_address(i-&gt;user);
+
+		if (copy_to_user((void *) arg, &amp;uival, sizeof(uival))) {
+			err = -EFAULT;
+			break;
+		}
+		err = 0;
+		break;
+
+	case SIOCIPMISETTIMING:
+	{
+		struct ipmi_timing_parms parms;
+
+		if (copy_from_user(&amp;parms, (void *) arg, sizeof(parms))) {
+			err = -EFAULT;
+			break;
+		}
+
+		i-&gt;default_retries = parms.retries;
+		i-&gt;default_retry_time_ms = parms.retry_time_ms;
+		err = 0;
+		break;
+	}
+
+	case SIOCIPMIGETTIMING:
+	{
+		struct ipmi_timing_parms parms;
+
+		parms.retries = i-&gt;default_retries;
+		parms.retry_time_ms = i-&gt;default_retry_time_ms;
+
+		if (copy_to_user((void *) arg, &amp;parms, sizeof(parms))) {
+			err = -EFAULT;
+			break;
+		}
+
+		err = 0;
+		break;
+	}
+
+	default:
+		err = dev_ioctl(cmd, (void *)arg);
+		break;
+	}
+
+	return err;
+}
+
+static int ipmi_recvmsg(struct kiocb *iocb, struct socket *sock,
+			struct msghdr *msg, size_t size,
+			int rflags)
+{
+	struct ipmi_sock     *i = to_ipmi_sock(sock-&gt;sk);
+	long                 timeo;
+	struct ipmi_recv_msg *rcvmsg;
+	struct sockaddr_ipmi addr;
+	char                 buf[IPMI_MAX_SOCK_MSG_LENGTH];
+	struct ipmi_sock_msg *smsg = (struct ipmi_sock_msg *)buf;
+	int                  err;
+	unsigned long        flags;
+
+
+	timeo = sock_rcvtimeo(&amp;i-&gt;sk, rflags &amp; MSG_DONTWAIT);
+
+	while (1) {
+		spin_lock_irqsave(&amp;i-&gt;lock, flags);
+		if (!list_empty(&amp;i-&gt;msg_list))
+			break;
+		spin_unlock_irqrestore(&amp;i-&gt;lock, flags);
+		if (!timeo) {
+			return -EAGAIN;
+		} else if (signal_pending (current)) {
+			dbg("Signal pending: %d", 1);
+			return -EINTR;
+		}
+
+		timeo = ipmi_wait_for_queue(i, timeo);
+	}
+
+	rcvmsg = list_entry(i-&gt;msg_list.next, struct ipmi_recv_msg, link);
+	list_del(&amp;rcvmsg-&gt;link);
+	spin_unlock_irqrestore(&amp;i-&gt;lock, flags);
+
+	memcpy(&amp;addr.ipmi_addr, &amp;rcvmsg-&gt;addr, sizeof(addr.ipmi_addr));
+	addr.if_num = i-&gt;addr.if_num;
+	addr.sipmi_family = i-&gt;addr.sipmi_family;
+	memcpy(msg-&gt;msg_name, &amp;addr, sizeof(addr));
+	msg-&gt;msg_namelen = (SOCKADDR_IPMI_OVERHEAD
+			    + ipmi_addr_length(rcvmsg-&gt;addr.addr_type));
+
+	smsg-&gt;recv_type		= rcvmsg-&gt;recv_type;
+	smsg-&gt;msgid		= rcvmsg-&gt;msgid;
+	smsg-&gt;netfn		= rcvmsg-&gt;msg.netfn;
+	smsg-&gt;cmd		= rcvmsg-&gt;msg.cmd;
+	smsg-&gt;data_len		= rcvmsg-&gt;msg.data_len;
+	memcpy(smsg-&gt;data, rcvmsg-&gt;msg.data, smsg-&gt;data_len);
+
+	ipmi_free_recv_msg(rcvmsg);
+
+	err = memcpy_toiovec(msg-&gt;msg_iov, (void *)smsg,
+			     sizeof(struct ipmi_sock_msg) + smsg-&gt;data_len);
+	if (err) {
+		dbg("Cannot copy data to user: %p", i-&gt;user);
+		return err;
+	}
+
+	dbg("user=%p", i-&gt;user);
+	dbg("addr_type=%x, channel=%x",
+	    addr.ipmi_addr.addr_type, addr.ipmi_addr.channel);
+	dbg("netfn=%#02x, cmd=%#02x, data=%p, data_len=%x",
+	    smsg-&gt;netfn, smsg-&gt;cmd, smsg-&gt;data, smsg-&gt;data_len);
+
+	return (sizeof(struct ipmi_sock_msg) + smsg-&gt;data_len);
+}
+
+static int ipmi_sendmsg(struct kiocb *iocb, struct socket *sock,
+			struct msghdr *msg, size_t len)
+{
+	struct ipmi_sock         *i = to_ipmi_sock(sock-&gt;sk);
+	struct sockaddr_ipmi     *addr = (struct sockaddr_ipmi *)msg-&gt;msg_name;
+	struct kernel_ipmi_msg   imsg;
+	unsigned char            buf[IPMI_MAX_SOCK_MSG_LENGTH];
+	struct ipmi_sock_msg     *smsg = (struct ipmi_sock_msg *) buf;
+	int                      err;
+	struct ipmi_timing_parms tparms;
+	struct cmsghdr           *cmsg;
+
+	err = ipmi_validate_addr(&amp;addr-&gt;ipmi_addr,
+				 msg-&gt;msg_namelen - SOCKADDR_IPMI_OVERHEAD);
+	if (err) {
+		dbg("Invalid IPMI address: %p", i-&gt;user);
+		goto err;
+	}
+
+	if (len &gt; IPMI_MAX_SOCK_MSG_LENGTH) {
+		err = -EINVAL;
+		dbg("Message too long: %p", i-&gt;user);
+		goto err;
+	}
+
+	if (len &lt; sizeof(struct ipmi_sock_msg)) {
+		err = -EINVAL;
+		dbg("Msg data too small for header: %p", i-&gt;user);
+		goto err;
+	}
+
+	err = memcpy_fromiovec((void *)smsg, msg-&gt;msg_iov, len);
+	if (err) {
+		dbg("Cannot copy data to kernel: %p", i-&gt;user);
+		goto err;
+	}
+
+	if (len &lt; smsg-&gt;data_len+sizeof(struct ipmi_sock_msg)) {
+		err = -EINVAL;
+		dbg("Msg data is out of bound: %p", i-&gt;user);
+		goto err;
+	}
+
+	/* Set defaults. */
+	tparms.retries = i-&gt;default_retries;
+	tparms.retry_time_ms = i-&gt;default_retry_time_ms;
+
+	for (cmsg=CMSG_FIRSTHDR(msg);
+	     cmsg;
+	     cmsg = CMSG_NXTHDR(msg, cmsg))
+	{
+		if (cmsg-&gt;cmsg_len &lt; sizeof(struct cmsghdr)) {
+			err = -EINVAL;
+			dbg("cmsg length too short: %p", i-&gt;user);
+			goto err;
+		}
+
+		if (cmsg-&gt;cmsg_level != SOL_SOCKET)
+			continue;
+
+		if (cmsg-&gt;cmsg_type == IPMI_CMSG_TIMING_PARMS) {
+			struct ipmi_timing_parms *pparms;
+
+			if (cmsg-&gt;cmsg_len != CMSG_LEN(sizeof(*pparms))) {
+				err = -EINVAL;
+				dbg("timing parms cmsg not right size: %p",
+				    i-&gt;user);
+				goto err;
+			}
+			pparms = (struct ipmi_timing_parms *) CMSG_DATA(cmsg);
+			tparms.retries = pparms-&gt;retries;
+			tparms.retry_time_ms = pparms-&gt;retry_time_ms;
+		}
+	}
+
+	imsg.netfn 	= smsg-&gt;netfn;
+	imsg.cmd	= smsg-&gt;cmd;
+	imsg.data 	= smsg-&gt;data;
+	imsg.data_len 	= smsg-&gt;data_len;
+
+	dbg("user=%p", i-&gt;user);
+	dbg("addr_type=%x, channel=%x",
+	    addr-&gt;ipmi_addr.addr_type, addr-&gt;ipmi_addr.channel);
+	dbg("netfn=%#02x, cmd=%#02x, data=%p, data_len=%x",
+	    imsg.netfn, imsg.cmd, imsg.data, imsg.data_len);
+	err = ipmi_request_settime(i-&gt;user, &amp;addr-&gt;ipmi_addr,
+				   smsg-&gt;msgid, &amp;imsg, NULL, 0,
+				   tparms.retries, tparms.retry_time_ms);
+	if (err) {
+		dbg("Cannot send message: %p", i-&gt;user);
+		goto err;
+	}
+
+err:
+	return err;
+}
+
+static struct proto_ops ipmi_ops = {
+	.family =	PF_IPMI,
+	.owner =	THIS_MODULE,
+	.release =	ipmi_release,
+	.bind =		ipmi_bind,
+	.connect =	sock_no_connect,
+	.socketpair =	sock_no_socketpair,
+	.accept =	sock_no_accept,
+	.getname =	ipmi_getname,
+	.poll =		ipmi_poll,
+	.ioctl =	ipmi_ioctl,
+	.listen =	sock_no_listen,
+	.shutdown =	sock_no_shutdown,
+	.setsockopt =	sock_no_setsockopt,
+	.getsockopt =	sock_no_getsockopt,
+	.sendmsg =	ipmi_sendmsg,
+	.recvmsg =	ipmi_recvmsg,
+	.mmap =		sock_no_mmap,
+	.sendpage =	sock_no_sendpage
+};
+
+
+static void ipmi_sock_destructor(struct sock *sk)
+{
+	skb_queue_purge(&amp;sk-&gt;sk_receive_queue);
+
+	BUG_TRAP(!atomic_read(&amp;sk-&gt;sk_wmem_alloc));
+	BUG_TRAP(sk_unhashed(sk));
+	BUG_TRAP(!sk-&gt;sk_socket);
+	if (!sock_flag(sk, SOCK_DEAD)) {
+		printk("Attempt to release alive ipmi socket: %p\n", sk);
+		return;
+	}
+
+	atomic_dec(&amp;ipmi_nr_socks);
+}
+
+/*
+ * net protocol functions
+ */
+static struct ipmi_sock *ipmi_socket_create1(struct socket *sock)
+{
+	struct ipmi_sock *i;
+
+	i = (struct ipmi_sock *)sk_alloc(PF_IPMI, GFP_KERNEL,
+					 sizeof(struct ipmi_sock), ipmi_sk_cachep);
+	if (!i) {
+		return NULL;
+	}
+
+	sock_init_data(sock, &amp;i-&gt;sk);
+	sk_set_owner(&amp;i-&gt;sk, THIS_MODULE);
+	i-&gt;sk.sk_destruct = ipmi_sock_destructor;
+	i-&gt;sk.sk_rcvtimeo = 5*HZ;
+	spin_lock_init(&amp;i-&gt;lock);
+	INIT_LIST_HEAD(&amp;i-&gt;msg_list);
+	init_waitqueue_head(&amp;i-&gt;wait);
+
+	/* Set to use default values. */
+	i-&gt;default_retries = -1;
+	i-&gt;default_retry_time_ms = 0;
+
+	atomic_inc(&amp;ipmi_nr_socks);
+	return i;
+}
+
+static int ipmi_socket_create(struct socket *sock, int protocol)
+{
+	if (!capable(CAP_NET_RAW))
+		return -EPERM;
+	if (protocol &amp;&amp; protocol != PF_IPMI)
+		return -EPROTONOSUPPORT;
+
+	sock-&gt;state = SS_UNCONNECTED;
+
+	switch (sock-&gt;type) {
+	case SOCK_RAW:
+		sock-&gt;type=SOCK_DGRAM;
+	case SOCK_DGRAM:
+		sock-&gt;ops = &amp;ipmi_ops;
+		break;
+	default:
+		return -EPROTONOSUPPORT;
+	}
+
+	return ipmi_socket_create1(sock)? 0 : -ENOMEM;
+}
+
+static struct net_proto_family ipmi_family_ops = {
+	.family = PF_IPMI,
+	.create = ipmi_socket_create,
+	.owner	= THIS_MODULE,
+};
+
+
+/*
+ * init/exit functions
+ */
+static int __init ipmi_socket_init(void)
+{
+
+	int err=0;
+
+	printk(KERN_INFO "ipmi socket interface version "
+	       IPMI_SOCKINTF_VERSION "\n");
+
+	ipmi_sk_cachep = kmem_cache_create("ipmi_sock",
+					   sizeof(struct ipmi_sock), 0,
+					   SLAB_HWCACHE_ALIGN, 0, 0);
+	if (!ipmi_sk_cachep) {
+		printk(KERN_CRIT "%s: Unable to create ipmi_sock SLAB cache!\n", __func__);
+		err = -ENOMEM;
+		goto out;
+	}
+
+	err = sock_register(&amp;ipmi_family_ops);
+	if (err)
+		kmem_cache_destroy(ipmi_sk_cachep);
+out:
+	return err;
+}
+
+static void __exit ipmi_socket_exit(void)
+{
+	sock_unregister(PF_IPMI);
+	kmem_cache_destroy(ipmi_sk_cachep);
+}
+
+#ifdef CONFIG_DEBUG_KERNEL
+module_param(debug, int, 0);
+#endif
+module_init(ipmi_socket_init);
+module_exit(ipmi_socket_exit);
+
+MODULE_LICENSE("GPL");
diff -puN /dev/null net/ipmi/Makefile
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/net/ipmi/Makefile	Wed Nov 17 14:41:27 2004
@@ -0,0 +1 @@
+obj-$(CONFIG_IPMI_SOCKET) = af_ipmi.o
diff -puN net/Kconfig~network-interface-for-ipmi net/Kconfig
--- 25/net/Kconfig~network-interface-for-ipmi	Wed Nov 17 14:41:27 2004
+++ 25-akpm/net/Kconfig	Wed Nov 17 14:41:27 2004
@@ -71,6 +71,17 @@ config UNIX
 
 	  Say Y unless you know what you are doing.
 
+config IPMI_SOCKET
+	tristate "IPMI sockets"
+	depends on IPMI_HANDLER
+	---help---
+	  If you say Y here, you will include support for IPMI sockets;
+	  This way you don't have to use devices to access IPMI.  You
+	  must also enable the IPMI message handler and a low-level
+	  driver in the Character Drivers if you enable this.
+
+	  If unsure, say N.
+
 config NET_KEY
 	tristate "PF_KEY sockets"
 	select XFRM
diff -puN net/Makefile~network-interface-for-ipmi net/Makefile
--- 25/net/Makefile~network-interface-for-ipmi	Wed Nov 17 14:41:27 2004
+++ 25-akpm/net/Makefile	Wed Nov 17 14:41:27 2004
@@ -42,6 +42,7 @@ obj-$(CONFIG_DECNET)		+= decnet/
 obj-$(CONFIG_ECONET)		+= econet/
 obj-$(CONFIG_VLAN_8021Q)	+= 8021q/
 obj-$(CONFIG_IP_SCTP)		+= sctp/
+obj-$(CONFIG_IPMI_SOCKET)	+= ipmi/
 
 ifeq ($(CONFIG_NET),y)
 obj-$(CONFIG_SYSCTL)		+= sysctl_net.o
_
</pre></body></html>