patch-2.1.14 linux/fs/smbfs/sock.c
Next file: linux/include/asm-alpha/termbits.h
Previous file: linux/fs/smbfs/proc.c
Back to the patch index
Back to the overall index
- Lines: 1337
- Date:
Sun Dec 1 18:26:22 1996
- Orig file:
v2.1.13/linux/fs/smbfs/sock.c
- Orig date:
Tue Oct 29 19:58:44 1996
diff -u --recursive --new-file v2.1.13/linux/fs/smbfs/sock.c linux/fs/smbfs/sock.c
@@ -1,7 +1,7 @@
/*
* sock.c
*
- * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
*
*/
@@ -11,7 +11,6 @@
#include <linux/socket.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
-#include <asm/uaccess.h>
#include <linux/in.h>
#include <linux/net.h>
#include <linux/mm.h>
@@ -21,6 +20,7 @@
#include <linux/smb.h>
#include <linux/smbno.h>
+#include <asm/uaccess.h>
#define _S(nr) (1<<((nr)-1))
@@ -28,747 +28,687 @@
_recvfrom(struct socket *sock, unsigned char *ubuf, int size,
int noblock, unsigned flags, struct sockaddr_in *sa, int *addr_len)
{
- struct iovec iov;
- struct msghdr msg;
+ struct iovec iov;
+ struct msghdr msg;
- iov.iov_base = ubuf;
- iov.iov_len = size;
+ iov.iov_base = ubuf;
+ iov.iov_len = size;
- msg.msg_name = (void *)sa;
- msg.msg_namelen = 0;
- if (addr_len)
- msg.msg_namelen = *addr_len;
- msg.msg_control = NULL;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
+ msg.msg_name = (void *) sa;
+ msg.msg_namelen = 0;
+ if (addr_len)
+ msg.msg_namelen = *addr_len;
+ msg.msg_control = NULL;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
- return sock->ops->recvmsg(sock, &msg, size, noblock, flags, addr_len);
+ return sock->ops->recvmsg(sock, &msg, size, noblock, flags, addr_len);
}
static int
_send(struct socket *sock, const void *buff, int len,
int nonblock, unsigned flags)
{
- struct iovec iov;
- struct msghdr msg;
+ struct iovec iov;
+ struct msghdr msg;
- iov.iov_base = (void *)buff;
- iov.iov_len = len;
+ iov.iov_base = (void *) buff;
+ iov.iov_len = len;
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_control = NULL;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_control = NULL;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
- return sock->ops->sendmsg(sock, &msg, len, nonblock, flags);
+ return sock->ops->sendmsg(sock, &msg, len, nonblock, flags);
}
static void
-smb_data_callback(struct sock *sk,int len)
+smb_data_callback(struct sock *sk, int len)
{
- struct socket *sock = sk->socket;
+ struct socket *sock = sk->socket;
- if(!sk->dead)
+ if (!sk->dead)
{
- unsigned char peek_buf[4];
- int result;
- unsigned short fs;
-
- fs = get_fs();
- set_fs(get_ds());
-
- result = _recvfrom(sock, (void *)peek_buf, 1, 1,
- MSG_PEEK, NULL, NULL);
-
- while ((result != -EAGAIN) && (peek_buf[0] == 0x85)) {
-
- /* got SESSION KEEP ALIVE */
- result = _recvfrom(sock, (void *)peek_buf,
- 4, 1, 0, NULL, NULL);
-
- DDPRINTK("smb_data_callback:"
- " got SESSION KEEP ALIVE\n");
-
- if (result == -EAGAIN)
- break;
+ unsigned char peek_buf[4];
+ int result;
+ unsigned short fs;
+
+ fs = get_fs();
+ set_fs(get_ds());
+
+ result = _recvfrom(sock, (void *) peek_buf, 1, 1,
+ MSG_PEEK, NULL, NULL);
+
+ while ((result != -EAGAIN) && (peek_buf[0] == 0x85))
+ {
+ /* got SESSION KEEP ALIVE */
+ result = _recvfrom(sock, (void *) peek_buf,
+ 4, 1, 0, NULL, NULL);
+
+ DDPRINTK("smb_data_callback:"
+ " got SESSION KEEP ALIVE\n");
+
+ if (result == -EAGAIN)
+ {
+ break;
+ }
+ result = _recvfrom(sock, (void *) peek_buf,
+ 1, 1, MSG_PEEK,
+ NULL, NULL);
+ }
+ set_fs(fs);
+
+ if (result != -EAGAIN)
+ {
+ wake_up_interruptible(sk->sleep);
+ }
+ }
+}
- result = _recvfrom(sock, (void *)peek_buf,
- 1, 1, MSG_PEEK,
- NULL, NULL);
+int
+smb_catch_keepalive(struct smb_server *server)
+{
+ struct file *file;
+ struct inode *inode;
+ struct socket *sock;
+ struct sock *sk;
+
+ if ((server == NULL)
+ || ((file = server->sock_file) == NULL)
+ || ((inode = file->f_inode) == NULL)
+ || (!S_ISSOCK(inode->i_mode)))
+ {
+ printk("smb_catch_keepalive: did not get valid server!\n");
+ server->data_ready = NULL;
+ return -EINVAL;
+ }
+ sock = &(inode->u.socket_i);
- }
+ if (sock->type != SOCK_STREAM)
+ {
+ printk("smb_catch_keepalive: did not get SOCK_STREAM\n");
+ server->data_ready = NULL;
+ return -EINVAL;
+ }
+ sk = (struct sock *) (sock->data);
- set_fs(fs);
+ if (sk == NULL)
+ {
+ printk("smb_catch_keepalive: sk == NULL");
+ server->data_ready = NULL;
+ return -EINVAL;
+ }
+ DDPRINTK("smb_catch_keepalive.: sk->d_r = %x, server->d_r = %x\n",
+ (unsigned int) (sk->data_ready),
+ (unsigned int) (server->data_ready));
- if (result != -EAGAIN) {
- wake_up_interruptible(sk->sleep);
- }
+ if (sk->data_ready == smb_data_callback)
+ {
+ printk("smb_catch_keepalive: already done\n");
+ return -EINVAL;
}
+ server->data_ready = sk->data_ready;
+ sk->data_ready = smb_data_callback;
+ return 0;
}
int
-smb_catch_keepalive(struct smb_server *server)
+smb_dont_catch_keepalive(struct smb_server *server)
{
- struct file *file;
- struct inode *inode;
- struct socket *sock;
- struct sock *sk;
-
- if ( (server == NULL)
- || ((file = server->sock_file) == NULL)
- || ((inode = file->f_inode) == NULL)
- || (!S_ISSOCK(inode->i_mode))) {
-
- printk("smb_catch_keepalive: did not get valid server!\n");
- server->data_ready = NULL;
- return -EINVAL;
- }
-
- sock = &(inode->u.socket_i);
-
- if (sock->type != SOCK_STREAM) {
- printk("smb_catch_keepalive: did not get SOCK_STREAM\n");
- server->data_ready = NULL;
- return -EINVAL;
- }
-
- sk = (struct sock *)(sock->data);
-
- if (sk == NULL) {
- printk("smb_catch_keepalive: sk == NULL");
- server->data_ready = NULL;
- return -EINVAL;
- }
-
- DDPRINTK("smb_catch_keepalive.: sk->d_r = %x, server->d_r = %x\n",
- (unsigned int)(sk->data_ready),
- (unsigned int)(server->data_ready));
-
- if (sk->data_ready == smb_data_callback) {
- printk("smb_catch_keepalive: already done\n");
- return -EINVAL;
- }
-
- server->data_ready = sk->data_ready;
- sk->data_ready = smb_data_callback;
- return 0;
+ struct file *file;
+ struct inode *inode;
+ struct socket *sock;
+ struct sock *sk;
+
+ if ((server == NULL)
+ || ((file = server->sock_file) == NULL)
+ || ((inode = file->f_inode) == NULL)
+ || (!S_ISSOCK(inode->i_mode)))
+ {
+ printk("smb_dont_catch_keepalive: "
+ "did not get valid server!\n");
+ return -EINVAL;
+ }
+ sock = &(inode->u.socket_i);
+
+ if (sock->type != SOCK_STREAM)
+ {
+ printk("smb_dont_catch_keepalive: did not get SOCK_STREAM\n");
+ return -EINVAL;
+ }
+ sk = (struct sock *) (sock->data);
+
+ if (sk == NULL)
+ {
+ printk("smb_dont_catch_keepalive: sk == NULL");
+ return -EINVAL;
+ }
+ if (server->data_ready == NULL)
+ {
+ printk("smb_dont_catch_keepalive: "
+ "server->data_ready == NULL\n");
+ return -EINVAL;
+ }
+ if (sk->data_ready != smb_data_callback)
+ {
+ printk("smb_dont_catch_keepalive: "
+ "sk->data_callback != smb_data_callback\n");
+ return -EINVAL;
+ }
+ DDPRINTK("smb_dont_catch_keepalive: sk->d_r = %x, server->d_r = %x\n",
+ (unsigned int) (sk->data_ready),
+ (unsigned int) (server->data_ready));
+
+ sk->data_ready = server->data_ready;
+ server->data_ready = NULL;
+ return 0;
}
-
-int
-smb_dont_catch_keepalive(struct smb_server *server)
+
+static int
+smb_send_raw(struct socket *sock, unsigned char *source, int length)
{
- struct file *file;
- struct inode *inode;
- struct socket *sock;
- struct sock *sk;
-
- if ( (server == NULL)
- || ((file = server->sock_file) == NULL)
- || ((inode = file->f_inode) == NULL)
- || (!S_ISSOCK(inode->i_mode))) {
-
- printk("smb_dont_catch_keepalive: "
- "did not get valid server!\n");
- return -EINVAL;
- }
-
- sock = &(inode->u.socket_i);
-
- if (sock->type != SOCK_STREAM) {
- printk("smb_dont_catch_keepalive: did not get SOCK_STREAM\n");
- return -EINVAL;
- }
-
- sk = (struct sock *)(sock->data);
-
- if (sk == NULL) {
- printk("smb_dont_catch_keepalive: sk == NULL");
- return -EINVAL;
- }
-
- if (server->data_ready == NULL) {
- printk("smb_dont_catch_keepalive: "
- "server->data_ready == NULL\n");
- return -EINVAL;
- }
-
- if (sk->data_ready != smb_data_callback) {
- printk("smb_dont_catch_keepalive: "
- "sk->data_callback != smb_data_callback\n");
- return -EINVAL;
- }
-
- DDPRINTK("smb_dont_catch_keepalive: sk->d_r = %x, server->d_r = %x\n",
- (unsigned int)(sk->data_ready),
- (unsigned int)(server->data_ready));
-
- sk->data_ready = server->data_ready;
- server->data_ready = NULL;
- return 0;
+ int result;
+ int already_sent = 0;
+
+ while (already_sent < length)
+ {
+ result = _send(sock,
+ (void *) (source + already_sent),
+ length - already_sent, 0, 0);
+
+ if (result < 0)
+ {
+ DPRINTK("smb_send_raw: sendto error = %d\n",
+ -result);
+ return result;
+ }
+ already_sent += result;
+ }
+ return already_sent;
}
-/*
- * smb_receive_raw
- * fs points to the correct segment, sock != NULL, target != NULL
- * The smb header is only stored if want_header != 0.
- */
static int
-smb_receive_raw(struct socket *sock, unsigned char *target,
- int max_raw_length, int want_header)
+smb_receive_raw(struct socket *sock, unsigned char *target, int length)
{
- int len, result;
- int already_read;
- unsigned char peek_buf[4];
- unsigned short fs; /* We fool the kernel to believe
- we call from user space. */
+ int result;
+ int already_read = 0;
+ while (already_read < length)
+ {
+ result = _recvfrom(sock,
+ (void *) (target + already_read),
+ length - already_read, 0, 0,
+ NULL, NULL);
+
+ if (result < 0)
+ {
+ DPRINTK("smb_receive_raw: recvfrom error = %d\n",
+ -result);
+ return result;
+ }
+ already_read += result;
+ }
+ return already_read;
+}
- re_recv:
+static int
+smb_get_length(struct socket *sock, unsigned char *header)
+{
+ int result;
+ unsigned char peek_buf[4];
+ unsigned short fs;
+ re_recv:
fs = get_fs();
set_fs(get_ds());
- result = _recvfrom(sock, (void *)peek_buf, 4, 0,
- 0, NULL, NULL);
- set_fs(fs);
-
- if (result < 0) {
- DPRINTK("smb_receive_raw: recv error = %d\n", -result);
- return result;
- }
-
- if (result < 4) {
- DPRINTK("smb_receive_raw: got less than 4 bytes\n");
- return -EIO;
- }
-
- switch (peek_buf[0]) {
-
- case 0x00:
- case 0x82:
- break;
-
- case 0x85:
- DPRINTK("smb_receive_raw: Got SESSION KEEP ALIVE\n");
- goto re_recv;
-
- default:
- printk("smb_receive_raw: Invalid packet\n");
- return -EIO;
- }
-
- /* The length in the RFC NB header is the raw data length */
- len = smb_len(peek_buf);
- if (len > max_raw_length) {
- printk("smb_receive_raw: Received length (%d) > max_xmit (%d)!\n",
- len, max_raw_length);
- return -EIO;
- }
-
- if (want_header != 0) {
- copy_to_user(target, peek_buf, 4);
- target += 4;
- }
-
- already_read = 0;
-
- while (already_read < len) {
-
- result = _recvfrom(sock,
- (void *)(target+already_read),
- len - already_read, 0, 0,
- NULL, NULL);
-
- if (result < 0) {
- printk("smb_receive_raw: recvfrom error = %d\n",
- -result);
- return result;
- }
-
- already_read += result;
- }
- return already_read;
+ result = smb_receive_raw(sock, peek_buf, 4);
+ set_fs(fs);
+
+ if (result < 0)
+ {
+ DPRINTK("smb_get_length: recv error = %d\n", -result);
+ return result;
+ }
+ switch (peek_buf[0])
+ {
+ case 0x00:
+ case 0x82:
+ break;
+
+ case 0x85:
+ DPRINTK("smb_get_length: Got SESSION KEEP ALIVE\n");
+ goto re_recv;
+
+ default:
+ printk("smb_get_length: Invalid NBT packet\n");
+ return -EIO;
+ }
+
+ if (header != NULL)
+ {
+ memcpy(header, peek_buf, 4);
+ }
+ /* The length in the RFC NB header is the raw data length */
+ return smb_len(peek_buf);
+}
+
+static struct socket *
+server_sock(struct smb_server *server)
+{
+ struct file *file;
+ struct inode *inode;
+
+ if (server == NULL)
+ return NULL;
+ if ((file = server->sock_file) == NULL)
+ return NULL;
+ if ((inode = file->f_inode) == NULL)
+ return NULL;
+ return &(inode->u.socket_i);
}
/*
* smb_receive
- * fs points to the correct segment, server != NULL, sock!=NULL
+ * fs points to the correct segment
*/
static int
-smb_receive(struct smb_server *server, struct socket *sock)
+smb_receive(struct smb_server *server)
{
- int result;
-
- result = smb_receive_raw(sock, server->packet,
- server->max_xmit - 4, /* max_xmit in server
- includes NB header */
- 1); /* We want the header */
+ struct socket *sock = server_sock(server);
+ int len;
+ int result;
+ unsigned char peek_buf[4];
- if (result < 0) {
- printk("smb_receive: receive error: %d\n", result);
- return result;
- }
+ len = smb_get_length(sock, peek_buf);
- server->rcls = *((unsigned char *)(server->packet+9));
- server->err = *((unsigned short *)(server->packet+11));
+ if (len < 0)
+ {
+ return len;
+ }
+ if (len + 4 > server->packet_size)
+ {
+ /* Some servers do not care about our max_xmit. They
+ send larger packets */
+ DPRINTK("smb_receive: Increase packet size from %d to %d\n",
+ server->packet_size, len + 4);
+ smb_vfree(server->packet);
+ server->packet_size = 0;
+ server->packet = smb_vmalloc(len + 4);
+ if (server->packet == NULL)
+ {
+ return -ENOMEM;
+ }
+ server->packet_size = len + 4;
+ }
+ memcpy(server->packet, peek_buf, 4);
+ result = smb_receive_raw(sock, server->packet + 4, len);
- if (server->rcls != 0) {
- DPRINTK("smb_receive: rcls=%d, err=%d\n",
- server->rcls, server->err);
- }
+ if (result < 0)
+ {
+ printk("smb_receive: receive error: %d\n", result);
+ return result;
+ }
+ server->rcls = BVAL(server->packet, 9);
+ server->err = WVAL(server->packet, 11);
- return result;
+ if (server->rcls != 0)
+ {
+ DPRINTK("smb_receive: rcls=%d, err=%d\n",
+ server->rcls, server->err);
+ }
+ return result;
}
-
-/*
- * smb_receive's preconditions also apply here.
- */
static int
-smb_receive_trans2(struct smb_server *server, struct socket *sock,
- int *data_len, int *param_len,
- char **data, char **param)
-{
- int total_data=0;
- int total_param=0;
- int result;
- unsigned char *inbuf = server->packet;
-
- *data_len = *param_len = 0;
-
- DDPRINTK("smb_receive_trans2: enter\n");
-
- if ((result = smb_receive(server, sock)) < 0) {
- return result;
- }
-
- if (server->rcls != 0) {
- return result;
- }
-
- /* parse out the lengths */
- total_data = WVAL(inbuf,smb_tdrcnt);
- total_param = WVAL(inbuf,smb_tprcnt);
-
- if ( (total_data > TRANS2_MAX_TRANSFER)
- || (total_param > TRANS2_MAX_TRANSFER)) {
- printk("smb_receive_trans2: data/param too long\n");
- return -EIO;
- }
-
- /* allocate it */
- if ((*data = smb_kmalloc(total_data, GFP_KERNEL)) == NULL) {
- printk("smb_receive_trans2: could not alloc data area\n");
- return -ENOMEM;
- }
-
- if ((*param = smb_kmalloc(total_param, GFP_KERNEL)) == NULL) {
- printk("smb_receive_trans2: could not alloc param area\n");
- smb_kfree_s(*data, total_data);
- return -ENOMEM;
- }
-
- DDPRINTK("smb_rec_trans2: total_data/param: %d/%d\n",
- total_data, total_param);
-
- while (1)
- {
- if (WVAL(inbuf,smb_prdisp)+WVAL(inbuf, smb_prcnt)
- > total_param) {
- printk("smb_receive_trans2: invalid parameters\n");
- result = -EIO;
- goto fail;
- }
- memcpy(*param + WVAL(inbuf,smb_prdisp),
- smb_base(inbuf) + WVAL(inbuf,smb_proff),
- WVAL(inbuf,smb_prcnt));
- *param_len += WVAL(inbuf,smb_prcnt);
-
-
- if (WVAL(inbuf,smb_drdisp)+WVAL(inbuf, smb_drcnt)>total_data) {
- printk("smb_receive_trans2: invalid data block\n");
- result = -EIO;
- goto fail;
- }
- memcpy(*data + WVAL(inbuf,smb_drdisp),
- smb_base(inbuf) + WVAL(inbuf,smb_droff),
- WVAL(inbuf,smb_drcnt));
- *data_len += WVAL(inbuf,smb_drcnt);
-
- DDPRINTK("smb_rec_trans2: drcnt/prcnt: %d/%d\n",
- WVAL(inbuf, smb_drcnt), WVAL(inbuf, smb_prcnt));
-
- /* parse out the total lengths again - they can shrink! */
-
- if ( (WVAL(inbuf,smb_tdrcnt) > total_data)
- || (WVAL(inbuf,smb_tprcnt) > total_param)) {
- printk("smb_receive_trans2: data/params grew!\n");
- result = -EIO;
- goto fail;
- }
-
- total_data = WVAL(inbuf,smb_tdrcnt);
- total_param = WVAL(inbuf,smb_tprcnt);
-
- if (total_data <= *data_len && total_param <= *param_len)
- break;
-
- if ((result = smb_receive(server, sock)) < 0) {
- goto fail;
- }
- if (server->rcls != 0) {
- result = -EIO;
- goto fail;
- }
- }
-
- DDPRINTK("smb_receive_trans2: normal exit\n");
-
- return 0;
-
- fail:
- DPRINTK("smb_receive_trans2: failed exit\n");
-
- smb_kfree_s(*param, 0); *param = NULL;
- smb_kfree_s(*data, 0); *data = NULL;
- return result;
-}
+smb_receive_trans2(struct smb_server *server,
+ int *ldata, unsigned char **data,
+ int *lparam, unsigned char **param)
+{
+ int total_data = 0;
+ int total_param = 0;
+ int result;
+ unsigned char *inbuf = server->packet;
+ unsigned char *rcv_buf;
+ int buf_len;
+ int data_len = 0;
+ int param_len = 0;
-static inline struct socket *
-server_sock(struct smb_server *server)
-{
- struct file *file;
- struct inode *inode;
+ if ((result = smb_receive(server)) < 0)
+ {
+ return result;
+ }
+ if (server->rcls != 0)
+ {
+ *param = *data = server->packet;
+ *ldata = *lparam = 0;
+ return 0;
+ }
+ total_data = WVAL(inbuf, smb_tdrcnt);
+ total_param = WVAL(inbuf, smb_tprcnt);
+
+ DDPRINTK("smb_receive_trans2: td=%d,tp=%d\n", total_data, total_param);
+
+ if ((total_data > TRANS2_MAX_TRANSFER)
+ || (total_param > TRANS2_MAX_TRANSFER))
+ {
+ DPRINTK("smb_receive_trans2: data/param too long\n");
+ return -EIO;
+ }
+ buf_len = total_data + total_param;
+ if (server->packet_size > buf_len)
+ {
+ buf_len = server->packet_size;
+ }
+ if ((rcv_buf = smb_vmalloc(buf_len)) == NULL)
+ {
+ DPRINTK("smb_receive_trans2: could not alloc data area\n");
+ return -ENOMEM;
+ }
+ *param = rcv_buf;
+ *data = rcv_buf + total_param;
+
+ while (1)
+ {
+ if (WVAL(inbuf, smb_prdisp) + WVAL(inbuf, smb_prcnt)
+ > total_param)
+ {
+ DPRINTK("smb_receive_trans2: invalid parameters\n");
+ result = -EIO;
+ goto fail;
+ }
+ memcpy(*param + WVAL(inbuf, smb_prdisp),
+ smb_base(inbuf) + WVAL(inbuf, smb_proff),
+ WVAL(inbuf, smb_prcnt));
+ param_len += WVAL(inbuf, smb_prcnt);
+
+ if (WVAL(inbuf, smb_drdisp) + WVAL(inbuf, smb_drcnt)
+ > total_data)
+ {
+ DPRINTK("smb_receive_trans2: invalid data block\n");
+ result = -EIO;
+ goto fail;
+ }
+ DDPRINTK("target: %X\n", *data + WVAL(inbuf, smb_drdisp));
+ DDPRINTK("source: %X\n",
+ smb_base(inbuf) + WVAL(inbuf, smb_droff));
+ DDPRINTK("disp: %d, off: %d, cnt: %d\n",
+ WVAL(inbuf, smb_drdisp), WVAL(inbuf, smb_droff),
+ WVAL(inbuf, smb_drcnt));
+
+ memcpy(*data + WVAL(inbuf, smb_drdisp),
+ smb_base(inbuf) + WVAL(inbuf, smb_droff),
+ WVAL(inbuf, smb_drcnt));
+ data_len += WVAL(inbuf, smb_drcnt);
+
+ if ((WVAL(inbuf, smb_tdrcnt) > total_data)
+ || (WVAL(inbuf, smb_tprcnt) > total_param))
+ {
+ printk("smb_receive_trans2: data/params grew!\n");
+ result = -EIO;
+ goto fail;
+ }
+ /* the total lengths might shrink! */
+ total_data = WVAL(inbuf, smb_tdrcnt);
+ total_param = WVAL(inbuf, smb_tprcnt);
+
+ if ((data_len >= total_data) && (param_len >= total_param))
+ {
+ break;
+ }
+ if ((result = smb_receive(server)) < 0)
+ {
+ goto fail;
+ }
+ if (server->rcls != 0)
+ {
+ result = -EIO;
+ goto fail;
+ }
+ }
+ *ldata = data_len;
+ *lparam = param_len;
- if (server == NULL)
- return NULL;
- if ((file = server->sock_file) == NULL)
- return NULL;
- if ((inode = file->f_inode) == NULL)
- return NULL;
- return &(inode->u.socket_i);
+ smb_vfree(server->packet);
+ server->packet = rcv_buf;
+ server->packet_size = buf_len;
+ return 0;
+
+ fail:
+ smb_vfree(rcv_buf);
+ return result;
}
int
smb_release(struct smb_server *server)
{
- struct socket *sock = server_sock(server);
- int result;
+ struct socket *sock = server_sock(server);
+ int result;
- if (sock == NULL)
- return -EINVAL;
+ if (sock == NULL)
+ {
+ return -EINVAL;
+ }
+ result = sock->ops->release(sock, NULL);
+ DPRINTK("smb_release: sock->ops->release = %d\n", result);
- result = sock->ops->release(sock, NULL);
- DPRINTK("smb_release: sock->ops->release = %d\n", result);
+ /* inet_release does not set sock->state. Maybe someone is
+ confused about sock->state being SS_CONNECTED while there
+ is nothing behind it, so I set it to SS_UNCONNECTED. */
+ sock->state = SS_UNCONNECTED;
- /* inet_release does not set sock->state. Maybe someone is
- confused about sock->state being SS_CONNECTED while there
- is nothing behind it, so I set it to SS_UNCONNECTED.*/
- sock->state = SS_UNCONNECTED;
-
- result = sock->ops->create(sock, 0);
- DPRINTK("smb_release: sock->ops->create = %d\n", result);
- return result;
+ result = sock->ops->create(sock, 0);
+ DPRINTK("smb_release: sock->ops->create = %d\n", result);
+ return result;
}
int
smb_connect(struct smb_server *server)
{
- struct socket *sock = server_sock(server);
- if (sock == NULL)
- return -EINVAL;
- if (sock->state != SS_UNCONNECTED) {
- DPRINTK("smb_connect: socket is not unconnected: %d\n",
- sock->state);
- }
- return sock->ops->connect(sock, (struct sockaddr *)&(server->m.addr),
- sizeof(struct sockaddr_in), 0);
-}
-
-/*****************************************************************************/
-/* */
-/* This routine was once taken from nfs, which is for udp. Here TCP does */
-/* most of the ugly stuff for us (thanks, Alan!) */
-/* */
-/*****************************************************************************/
-int
-smb_request(struct smb_server *server)
-{
- unsigned long old_mask;
- unsigned short fs; /* We fool the kernel to believe
- we call from user space. */
- int len, result, result2;
-
struct socket *sock = server_sock(server);
- unsigned char *buffer = (server == NULL) ? NULL : server->packet;
-
- if ((sock == NULL) || (buffer == NULL)) {
- printk("smb_request: Bad server!\n");
- return -EBADF;
+ if (sock == NULL)
+ {
+ return -EINVAL;
}
-
- if (server->state != CONN_VALID)
- return -EIO;
-
- if ((result = smb_dont_catch_keepalive(server)) != 0) {
- server->state = CONN_INVALID;
- smb_invalidate_all_inodes(server);
- return result;
- }
-
- len = smb_len(buffer) + 4;
-
- DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
-
- old_mask = current->blocked;
- current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
- fs = get_fs();
- set_fs(get_ds());
-
- result = _send(sock, (void *)buffer, len, 0, 0);
- if (result < 0) {
- printk("smb_request: send error = %d\n", result);
- }
- else {
- result = smb_receive(server, sock);
- }
-
- /* read/write errors are handled by errno */
- current->signal &= ~_S(SIGPIPE);
-
- current->blocked = old_mask;
- set_fs(fs);
-
- if ((result2 = smb_catch_keepalive(server)) < 0) {
- result = result2;
- }
-
- if (result < 0) {
- server->state = CONN_INVALID;
- smb_invalidate_all_inodes(server);
- }
-
- DDPRINTK("smb_request: result = %d\n", result);
-
- return result;
+ if (sock->state != SS_UNCONNECTED)
+ {
+ DPRINTK("smb_connect: socket is not unconnected: %d\n",
+ sock->state);
+ }
+ return sock->ops->connect(sock, (struct sockaddr *) &(server->m.addr),
+ sizeof(struct sockaddr_in), 0);
}
-/*
- * This is not really a trans2 request, we assume that you only have
- * one packet to send.
- */
int
-smb_trans2_request(struct smb_server *server,
- int *data_len, int *param_len,
- char **data, char **param)
+smb_request(struct smb_server *server)
{
unsigned long old_mask;
- unsigned short fs; /* We fool the kernel to believe
- we call from user space. */
- int len, result, result2;
+ unsigned short fs;
+ int len, result;
- struct socket *sock = server_sock(server);
unsigned char *buffer = (server == NULL) ? NULL : server->packet;
- if ((sock == NULL) || (buffer == NULL)) {
- printk("smb_trans2_request: Bad server!\n");
+ if (buffer == NULL)
+ {
+ printk("smb_request: Bad server!\n");
return -EBADF;
}
+ if (server->state != CONN_VALID)
+ {
+ return -EIO;
+ }
+ if ((result = smb_dont_catch_keepalive(server)) != 0)
+ {
+ server->state = CONN_INVALID;
+ smb_invalidate_all_inodes(server);
+ return result;
+ }
+ len = smb_len(buffer) + 4;
- if (server->state != CONN_VALID)
- return -EIO;
-
- if ((result = smb_dont_catch_keepalive(server)) != 0) {
- server->state = CONN_INVALID;
- smb_invalidate_all_inodes(server);
- return result;
- }
-
- len = smb_len(buffer) + 4;
+ DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
old_mask = current->blocked;
current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
fs = get_fs();
set_fs(get_ds());
- DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
-
- result = _send(sock, (void *)buffer, len, 0, 0);
- if (result < 0) {
- printk("smb_trans2_request: send error = %d\n", result);
- }
- else {
- result = smb_receive_trans2(server, sock,
- data_len, param_len,
- data, param);
- }
-
- /* read/write errors are handled by errno */
- current->signal &= ~_S(SIGPIPE);
-
+ result = smb_send_raw(server_sock(server), (void *) buffer, len);
+ if (result > 0)
+ {
+ result = smb_receive(server);
+ }
+ /* read/write errors are handled by errno */
+ current->signal &= ~_S(SIGPIPE);
current->blocked = old_mask;
set_fs(fs);
- if ((result2 = smb_catch_keepalive(server)) < 0) {
- result = result2;
- }
-
- if (result < 0) {
- server->state = CONN_INVALID;
- smb_invalidate_all_inodes(server);
- }
-
- DDPRINTK("smb_trans2_request: result = %d\n", result);
+ if (result >= 0)
+ {
+ int result2 = smb_catch_keepalive(server);
+ if (result2 < 0)
+ {
+ result = result2;
+ }
+ }
+ if (result < 0)
+ {
+ server->state = CONN_INVALID;
+ smb_invalidate_all_inodes(server);
+ }
+ DDPRINTK("smb_request: result = %d\n", result);
return result;
}
-/* target must be in user space */
-int
-smb_request_read_raw(struct smb_server *server,
- unsigned char *target, int max_len)
+#define ROUND_UP(x) (((x)+3) & ~3)
+static int
+smb_send_trans2(struct smb_server *server, __u16 trans2_command,
+ int ldata, unsigned char *data,
+ int lparam, unsigned char *param)
{
- unsigned long old_mask;
- int len, result, result2;
- unsigned short fs; /* We fool the kernel to believe
- we call from user space. */
-
struct socket *sock = server_sock(server);
- unsigned char *buffer = (server == NULL) ? NULL : server->packet;
- if ((sock == NULL) || (buffer == NULL)) {
- printk("smb_request_read_raw: Bad server!\n");
- return -EBADF;
- }
+ /* I know the following is very ugly, but I want to build the
+ smb packet as efficiently as possible. */
- if (server->state != CONN_VALID)
- return -EIO;
-
- if ((result = smb_dont_catch_keepalive(server)) != 0) {
- server->state = CONN_INVALID;
- smb_invalidate_all_inodes(server);
- return result;
- }
+ const int smb_parameters = 15;
+ const int oparam =
+ ROUND_UP(SMB_HEADER_LEN + 2 * smb_parameters + 2 + 3);
+ const int odata =
+ ROUND_UP(oparam + lparam);
+ const int bcc =
+ odata + ldata - (SMB_HEADER_LEN + 2 * smb_parameters + 2);
+ const int packet_length =
+ SMB_HEADER_LEN + 2 * smb_parameters + bcc + 2;
+
+ unsigned char padding[4] =
+ {0,};
+ char *p;
- len = smb_len(buffer) + 4;
+ struct iovec iov[4];
+ struct msghdr msg;
- old_mask = current->blocked;
- current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
- fs = get_fs();
- set_fs(get_ds());
-
- DPRINTK("smb_request_read_raw: len = %d cmd = 0x%X\n",
- len, buffer[8]);
- DPRINTK("smb_request_read_raw: target=%X, max_len=%d\n",
- (unsigned int)target, max_len);
- DPRINTK("smb_request_read_raw: buffer=%X, sock=%X\n",
- (unsigned int)buffer, (unsigned int)sock);
-
- result = _send(sock, (void *)buffer, len, 0, 0);
-
- DPRINTK("smb_request_read_raw: send returned %d\n", result);
-
- set_fs(fs); /* We recv into user space */
-
- if (result < 0) {
- printk("smb_request_read_raw: send error = %d\n", result);
- }
- else {
- result = smb_receive_raw(sock, target, max_len, 0);
- }
-
- /* read/write errors are handled by errno */
- current->signal &= ~_S(SIGPIPE);
- current->blocked = old_mask;
+ if ((bcc + oparam) > server->max_xmit)
+ {
+ return -ENOMEM;
+ }
+ p = smb_setup_header(server, SMBtrans2, smb_parameters, bcc);
- if ((result2 = smb_catch_keepalive(server)) < 0) {
- result = result2;
- }
-
- if (result < 0) {
- server->state = CONN_INVALID;
- smb_invalidate_all_inodes(server);
- }
-
- DPRINTK("smb_request_read_raw: result = %d\n", result);
+ WSET(server->packet, smb_tpscnt, lparam);
+ WSET(server->packet, smb_tdscnt, ldata);
+ WSET(server->packet, smb_mprcnt, TRANS2_MAX_TRANSFER);
+ WSET(server->packet, smb_mdrcnt, TRANS2_MAX_TRANSFER);
+ WSET(server->packet, smb_msrcnt, 0);
+ WSET(server->packet, smb_flags, 0);
+ DSET(server->packet, smb_timeout, 0);
+ WSET(server->packet, smb_pscnt, lparam);
+ WSET(server->packet, smb_psoff, oparam - 4);
+ WSET(server->packet, smb_dscnt, ldata);
+ WSET(server->packet, smb_dsoff, odata - 4);
+ WSET(server->packet, smb_suwcnt, 1);
+ WSET(server->packet, smb_setup0, trans2_command);
+ *p++ = 0; /* null smb_name for trans2 */
+ *p++ = 'D'; /* this was added because OS/2 does it */
+ *p++ = ' ';
+
+ iov[0].iov_base = (void *) server->packet;
+ iov[0].iov_len = oparam;
+ iov[1].iov_base = (param == NULL) ? padding : param;
+ iov[1].iov_len = lparam;
+ iov[2].iov_base = padding;
+ iov[2].iov_len = odata - oparam - lparam;
+ iov[3].iov_base = (data == NULL) ? padding : data;
+ iov[3].iov_len = ldata;
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_control = NULL;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 4;
- return result;
+ return sock->ops->sendmsg(sock, &msg, packet_length, 0, 0);
}
-/* Source must be in user space. smb_request_write_raw assumes that
- * the request SMBwriteBraw has been completed successfully, so that
- * we can send the raw data now. */
+/*
+ * This is not really a trans2 request, we assume that you only have
+ * one packet to send.
+ */
int
-smb_request_write_raw(struct smb_server *server,
- unsigned const char *source, int length)
+smb_trans2_request(struct smb_server *server, __u16 trans2_command,
+ int ldata, unsigned char *data,
+ int lparam, unsigned char *param,
+ int *lrdata, unsigned char **rdata,
+ int *lrparam, unsigned char **rparam)
{
unsigned long old_mask;
- int result, result2;
- unsigned short fs; /* We fool the kernel to believe
- we call from user space. */
- byte nb_header[4];
+ unsigned short fs;
+ int result;
- struct socket *sock = server_sock(server);
- unsigned char *buffer = (server == NULL) ? NULL : server->packet;
+ DDPRINTK("smb_trans2_request: com=%d, ld=%d, lp=%d\n",
+ trans2_command, ldata, lparam);
- if ((sock == NULL) || (buffer == NULL)) {
- printk("smb_request_write_raw: Bad server!\n");
- return -EBADF;
+ if (server->state != CONN_VALID)
+ {
+ return -EIO;
+ }
+ if ((result = smb_dont_catch_keepalive(server)) != 0)
+ {
+ server->state = CONN_INVALID;
+ smb_invalidate_all_inodes(server);
+ return result;
}
-
- if (server->state != CONN_VALID)
- return -EIO;
-
- if ((result = smb_dont_catch_keepalive(server)) != 0) {
- server->state = CONN_INVALID;
- smb_invalidate_all_inodes(server);
- return result;
- }
-
old_mask = current->blocked;
current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
fs = get_fs();
set_fs(get_ds());
- smb_encode_smb_length(nb_header, length);
-
- result = _send(sock, (void *)nb_header, 4, 0, 0);
-
- if (result == 4) {
- set_fs(fs); /* source is in user-land */
- result = _send(sock, (void *)source, length, 0, 0);
- set_fs(get_ds());
- } else {
- result = -EIO;
- }
-
- DPRINTK("smb_request_write_raw: send returned %d\n", result);
-
- if (result == length) {
- result = smb_receive(server, sock);
- } else {
- result = -EIO;
- }
-
- /* read/write errors are handled by errno */
- current->signal &= ~_S(SIGPIPE);
+ result = smb_send_trans2(server, trans2_command,
+ ldata, data, lparam, param);
+ if (result >= 0)
+ {
+ result = smb_receive_trans2(server,
+ lrdata, rdata, lrparam, rparam);
+ }
+ /* read/write errors are handled by errno */
+ current->signal &= ~_S(SIGPIPE);
current->blocked = old_mask;
set_fs(fs);
- if ((result2 = smb_catch_keepalive(server)) < 0) {
- result = result2;
- }
-
- if (result < 0) {
- server->state = CONN_INVALID;
- smb_invalidate_all_inodes(server);
- }
-
- if (result > 0) {
- result = length;
- }
-
- DPRINTK("smb_request_write_raw: result = %d\n", result);
+ if (result >= 0)
+ {
+ int result2 = smb_catch_keepalive(server);
+ if (result2 < 0)
+ {
+ result = result2;
+ }
+ }
+ if (result < 0)
+ {
+ server->state = CONN_INVALID;
+ smb_invalidate_all_inodes(server);
+ }
+ DDPRINTK("smb_trans2_request: result = %d\n", result);
return result;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov