diff --git a/include/linux/sunrpc/smb.h b/include/linux/sunrpc/smb.h
new file mode 100644
index 0000000..304ab8c
--- /dev/null
+++ b/include/linux/sunrpc/smb.h
@@ -0,0 +1,42 @@
+/*
+ *   net/sunrpc/smb.h -- SMB transport for sunrpc
+ *
+ *   Copyright (c) 2009 Red Hat, Inc.
+ *   Author(s): Jeff Layton (jlayton@redhat.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * xprtsmb.h
+ *
+ * This file contains the public interfaces for the SMB transport for
+ * the sunrpc layer.
+ */
+
+#ifndef _LINUX_SUNRPC_SMB_H
+#define _LINUX_SUNRPC_SMB_H
+
+/*
+ * This is the generic SMB function. rqstp is either a rpc_rqst (client
+ * side) or svc_rqst pointer (server side).
+ * Encode functions always assume there's enough room in the buffer.
+ */
+typedef int     (*ksmbproc_t)(void *rqstp, __le32 *data, void *obj);
+
+void smb_encode(struct rpc_task *task);
+int smb_decode(struct rpc_task *task);
+
+#endif /* _LINUX_SUNRPC_SMB_H */
diff --git a/include/linux/sunrpc/xprtsmb.h b/include/linux/sunrpc/xprtsmb.h
index d55e85b..731cce2 100644
--- a/include/linux/sunrpc/xprtsmb.h
+++ b/include/linux/sunrpc/xprtsmb.h
@@ -34,9 +34,6 @@
  */
 #define XPRT_TRANSPORT_SMB	1024
 
-int init_smb_xprt(void);
-void cleanup_smb_xprt(void);
-
 /* standard SMB header */
 struct smb_header {
 	__u8		protocol[4];
@@ -56,4 +53,7 @@ struct smb_header {
 /* SMB Header Flags of interest */
 #define SMBFLG_RESPONSE 0x80	/* response from server */
 
+int init_smb_xprt(void);
+void cleanup_smb_xprt(void);
+
 #endif /* _LINUX_SUNRPC_XPRTSMB_H */
diff --git a/net/sunrpc/smb.c b/net/sunrpc/smb.c
new file mode 100644
index 0000000..5511bb2
--- /dev/null
+++ b/net/sunrpc/smb.c
@@ -0,0 +1,120 @@
+/*
+ * net/sunrpc/smb.c -- smb encode and decode routines
+ *
+ * Copyright (C) 2009 Red Hat, Inc -- Jeff Layton <jlayton@redhat.com>
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/xprtsmb.h>
+#include <linux/sunrpc/smb.h>
+#include <linux/smbno.h>
+
+static __le32 *
+smb_verify_header(struct rpc_task *task)
+{
+	struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0];
+	__le32	*p = iov->iov_base;
+
+	if (task->tk_rqstp->rq_rcv_buf.len < sizeof(struct smb_header)) {
+		task->tk_action = call_bind;
+		task->tk_client->cl_stats->rpcretrans++;
+		return ERR_PTR(-EAGAIN);
+	}
+
+	/* FIXME: check for errors and return them */
+
+	/*
+	 * with SMB, we occasionally need to refer back to the SMB header for
+	 * info (flags, etc). The header is fixed-length however, so just
+	 * return a pointer to the start of the SMB header.
+	 */
+	return p;
+}
+
+static __le32 *
+smb_encode_header(struct rpc_task *task)
+{
+	struct rpc_rqst *req = task->tk_rqstp;
+	u32 *p =  (u32 *) req->rq_svec[0].iov_base;
+	struct smb_header *h;
+
+	/* transport header is always 32 bits */
+	++p;
+	memset(p, 0, sizeof(*h));
+
+	h = (struct smb_header *) p;
+
+	h->protocol[0] = 0xFF;
+	h->protocol[1] = 'S';
+	h->protocol[2] = 'M';
+	h->protocol[3] = 'B';
+
+	h->command = task->tk_msg.rpc_proc->p_proc;
+	h->flags2 = SMB_FLAGS2_LONG_PATH_COMPONENTS;
+	h->pid = cpu_to_le16((u16) current->tgid);
+	h->pidhigh = cpu_to_le16((u16) (current->tgid >> 16));
+
+	/*
+	 * SMB MID's are similar to XID's in RPC, but they're only 16 bits.
+	 * For now we just use the xid field and mask off the upper bits.
+	 */
+	req->rq_xid &= 0x0000ffff;
+	h->mid = cpu_to_le16((u16) req->rq_xid);
+
+	req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], (__be32 *) (h + 1));
+
+	return (__le32 *) (h + 1);
+}
+
+void
+smb_encode(struct rpc_task *task)
+{
+	struct rpc_rqst *req = task->tk_rqstp;
+	__le32 *p;
+	ksmbproc_t encode = (ksmbproc_t) task->tk_msg.rpc_proc->p_encode;
+
+	rpc_xdr_buf_init(&req->rq_snd_buf, req->rq_buffer, req->rq_callsize);
+	rpc_xdr_buf_init(&req->rq_rcv_buf,
+			 (char *)req->rq_buffer + req->rq_callsize,
+			 req->rq_rcvsize);
+
+	p = smb_encode_header(task);
+
+	encode(req, p, NULL);
+	return;
+}
+EXPORT_SYMBOL_GPL(smb_encode);
+
+int
+smb_decode(struct rpc_task *task)
+{
+	struct rpc_rqst *req = task->tk_rqstp;
+	kxdrproc_t	decode = task->tk_msg.rpc_proc->p_decode;
+	__le32		*p;
+
+	p = smb_verify_header(task);
+	if (IS_ERR(p))
+		return  PTR_ERR(p);
+
+	if (decode)
+		task->tk_status = decode(req, p, task->tk_msg.rpc_resp);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(smb_decode);
