4 * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
5 * Copyright (C) 1997 by Volker Lendecke
7 * Please add a note about your changes to smbfs in the ChangeLog file.
11 #include <linux/time.h>
12 #include <linux/errno.h>
13 #include <linux/socket.h>
14 #include <linux/fcntl.h>
15 #include <linux/file.h>
17 #include <linux/net.h>
18 #include <linux/tcp.h>
20 #include <linux/netdevice.h>
21 #include <linux/smp_lock.h>
22 #include <linux/workqueue.h>
26 #include <linux/smb_fs.h>
27 #include <linux/smb.h>
28 #include <linux/smbno.h>
30 #include <asm/uaccess.h>
31 #include <asm/ioctls.h>
33 #include "smb_debug.h"
39 _recvfrom(struct socket *socket, unsigned char *ubuf, int size, unsigned flags)
47 flags |= MSG_DONTWAIT | MSG_NOSIGNAL;
49 msg.msg_flags = flags;
54 msg.msg_control = NULL;
58 size = sock_recvmsg(socket, &msg, size, flags);
65 * Return the server this socket belongs to
67 static struct smb_sb_info *
68 server_from_socket(struct socket *socket)
70 return socket->sk->sk_user_data;
74 * Called when there is data on the socket.
77 smb_data_ready(struct sock *sk, int len)
79 struct smb_sb_info *server = server_from_socket(sk->sk_socket);
80 void (*data_ready)(struct sock *, int) = server->data_ready;
83 VERBOSE("(%p, %d)\n", sk, len);
88 smb_valid_socket(struct inode * inode)
90 return (inode && S_ISSOCK(inode->i_mode) &&
91 SOCKET_I(inode)->type == SOCK_STREAM);
94 static struct socket *
95 server_sock(struct smb_sb_info *server)
99 if (server && (file = server->sock_file))
101 #ifdef SMBFS_PARANOIA
102 if (!smb_valid_socket(file->f_dentry->d_inode))
103 PARANOIA("bad socket!\n");
105 return SOCKET_I(file->f_dentry->d_inode);
111 smb_close_socket(struct smb_sb_info *server)
113 struct file * file = server->sock_file;
116 struct socket *sock = server_sock(server);
118 VERBOSE("closing socket %p\n", sock);
119 sock->sk->sk_data_ready = server->data_ready;
120 server->sock_file = NULL;
126 smb_get_length(struct socket *socket, unsigned char *header)
130 result = _recvfrom(socket, header, 4, MSG_PEEK);
131 if (result == -EAGAIN)
134 PARANOIA("recv error = %d\n", -result);
146 DEBUG1("Got SESSION KEEP ALIVE\n");
147 _recvfrom(socket, header, 4, 0); /* read away */
151 PARANOIA("Invalid NBT packet, code=%x\n", header[0]);
155 /* The length in the RFC NB header is the raw data length */
156 return smb_len(header);
160 smb_recv_available(struct smb_sb_info *server)
164 struct socket *sock = server_sock(server);
168 err = sock->ops->ioctl(sock, SIOCINQ, (unsigned long) &avail);
170 return (err >= 0) ? avail : err;
174 * Adjust the iovec to move on 'n' bytes (from nfs/sunrpc)
177 smb_move_iov(struct msghdr *msg, struct iovec *niv, unsigned amount)
179 struct iovec *iv = msg->msg_iov;
184 * Eat any sent iovecs
186 while (iv->iov_len <= amount) {
187 amount -= iv->iov_len;
193 * And chew down the partial one
195 niv[0].iov_len = iv->iov_len-amount;
196 niv[0].iov_base =((unsigned char *)iv->iov_base)+amount;
199 len = niv[0].iov_len;
202 * And copy any others
204 for (i = 1; i < msg->msg_iovlen; i++) {
206 len += niv[i].iov_len;
215 * Only called by the smbiod thread.
218 smb_receive_header(struct smb_sb_info *server)
222 unsigned char peek_buf[4];
225 sock = server_sock(server);
228 if (sock->sk->sk_state != TCP_ESTABLISHED)
231 if (!server->smb_read) {
232 result = smb_get_length(sock, peek_buf);
234 if (result == -ENODATA)
238 server->smb_len = result + 4;
240 if (server->smb_len < SMB_HEADER_LEN) {
241 PARANOIA("short packet: %d\n", result);
242 server->rstate = SMB_RECV_DROP;
246 if (server->smb_len > SMB_MAX_PACKET_SIZE) {
247 PARANOIA("long packet: %d\n", result);
248 server->rstate = SMB_RECV_DROP;
254 result = _recvfrom(sock, server->header + server->smb_read,
255 SMB_HEADER_LEN - server->smb_read, 0);
256 VERBOSE("_recvfrom: %d\n", result);
258 VERBOSE("receive error: %d\n", result);
261 server->smb_read += result;
263 if (server->smb_read == SMB_HEADER_LEN)
264 server->rstate = SMB_RECV_HCOMPLETE;
269 static char drop_buffer[PAGE_SIZE];
272 * smb_receive_drop - read and throw away the data
273 * Only called by the smbiod thread.
275 * FIXME: we are in the kernel, could we just tell the socket that we want
276 * to drop stuff from the buffer?
279 smb_receive_drop(struct smb_sb_info *server)
286 int rlen = smb_len(server->header) - server->smb_read + 4;
289 sock = server_sock(server);
292 if (sock->sk->sk_state != TCP_ESTABLISHED)
298 flags = MSG_DONTWAIT | MSG_NOSIGNAL;
299 iov.iov_base = drop_buffer;
300 iov.iov_len = PAGE_SIZE;
301 msg.msg_flags = flags;
306 msg.msg_control = NULL;
308 if (rlen > PAGE_SIZE)
311 result = sock_recvmsg(sock, &msg, rlen, flags);
315 VERBOSE("read: %d\n", result);
317 VERBOSE("receive error: %d\n", result);
320 server->smb_read += result;
322 if (server->smb_read >= server->smb_len)
323 server->rstate = SMB_RECV_END;
331 * Only called by the smbiod thread.
334 smb_receive(struct smb_sb_info *server, struct smb_request *req)
344 sock = server_sock(server);
347 if (sock->sk->sk_state != TCP_ESTABLISHED)
353 flags = MSG_DONTWAIT | MSG_NOSIGNAL;
354 msg.msg_flags = flags;
357 msg.msg_iov = req->rq_iov;
358 msg.msg_iovlen = req->rq_iovlen;
359 msg.msg_control = NULL;
361 /* Dont repeat bytes and count available bufferspace */
362 rlen = smb_move_iov(&msg, iov, req->rq_bytes_recvd);
363 if (req->rq_rlen < rlen)
366 result = sock_recvmsg(sock, &msg, rlen, flags);
370 VERBOSE("read: %d\n", result);
372 VERBOSE("receive error: %d\n", result);
375 req->rq_bytes_recvd += result;
376 server->smb_read += result;
383 * Try to send a SMB request. This may return after sending only parts of the
384 * request. SMB_REQ_TRANSMITTED will be set if a request was fully sent.
386 * Parts of this was taken from xprt_sendmsg from net/sunrpc/xprt.c
389 smb_send_request(struct smb_request *req)
392 struct smb_sb_info *server = req->rq_server;
395 int slen = req->rq_slen - req->rq_bytes_sent;
399 sock = server_sock(server);
402 if (sock->sk->sk_state != TCP_ESTABLISHED)
407 msg.msg_control = NULL;
408 msg.msg_controllen = 0;
409 msg.msg_iov = req->rq_iov;
410 msg.msg_iovlen = req->rq_iovlen;
411 msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT;
413 /* Dont repeat bytes */
414 if (req->rq_bytes_sent)
415 smb_move_iov(&msg, iov, req->rq_bytes_sent);
419 result = sock_sendmsg(sock, &msg, slen);
423 req->rq_bytes_sent += result;
424 if (req->rq_bytes_sent >= req->rq_slen)
425 req->rq_flags |= SMB_REQ_TRANSMITTED;