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>
19 #include <linux/netdevice.h>
20 #include <linux/workqueue.h>
22 #include <net/tcp_states.h>
25 #include <linux/smb_fs.h>
26 #include <linux/smb.h>
27 #include <linux/smbno.h>
29 #include <asm/uaccess.h>
30 #include <asm/ioctls.h>
32 #include "smb_debug.h"
38 _recvfrom(struct socket *socket, unsigned char *ubuf, int size, unsigned flags)
40 struct kvec iov = {ubuf, size};
41 struct msghdr msg = {.msg_flags = flags};
42 msg.msg_flags |= MSG_DONTWAIT | MSG_NOSIGNAL;
43 return kernel_recvmsg(socket, &msg, &iov, 1, size, msg.msg_flags);
47 * Return the server this socket belongs to
49 static struct smb_sb_info *
50 server_from_socket(struct socket *socket)
52 return socket->sk->sk_user_data;
56 * Called when there is data on the socket.
59 smb_data_ready(struct sock *sk, int len)
61 struct smb_sb_info *server = server_from_socket(sk->sk_socket);
62 void (*data_ready)(struct sock *, int) = server->data_ready;
65 VERBOSE("(%p, %d)\n", sk, len);
70 smb_valid_socket(struct inode * inode)
72 return (inode && S_ISSOCK(inode->i_mode) &&
73 SOCKET_I(inode)->type == SOCK_STREAM);
76 static struct socket *
77 server_sock(struct smb_sb_info *server)
81 if (server && (file = server->sock_file))
84 if (!smb_valid_socket(file->f_path.dentry->d_inode))
85 PARANOIA("bad socket!\n");
87 return SOCKET_I(file->f_path.dentry->d_inode);
93 smb_close_socket(struct smb_sb_info *server)
95 struct file * file = server->sock_file;
98 struct socket *sock = server_sock(server);
100 VERBOSE("closing socket %p\n", sock);
101 sock->sk->sk_data_ready = server->data_ready;
102 server->sock_file = NULL;
108 smb_get_length(struct socket *socket, unsigned char *header)
112 result = _recvfrom(socket, header, 4, MSG_PEEK);
113 if (result == -EAGAIN)
116 PARANOIA("recv error = %d\n", -result);
128 DEBUG1("Got SESSION KEEP ALIVE\n");
129 _recvfrom(socket, header, 4, 0); /* read away */
133 PARANOIA("Invalid NBT packet, code=%x\n", header[0]);
137 /* The length in the RFC NB header is the raw data length */
138 return smb_len(header);
142 smb_recv_available(struct smb_sb_info *server)
146 struct socket *sock = server_sock(server);
150 err = sock->ops->ioctl(sock, SIOCINQ, (unsigned long) &avail);
152 return (err >= 0) ? avail : err;
156 * Adjust the kvec to move on 'n' bytes (from nfs/sunrpc)
159 smb_move_iov(struct kvec **data, size_t *num, struct kvec *vec, unsigned amount)
161 struct kvec *iv = *data;
168 while (iv->iov_len <= amount) {
169 amount -= iv->iov_len;
175 * And chew down the partial one
177 vec[0].iov_len = iv->iov_len-amount;
178 vec[0].iov_base =((unsigned char *)iv->iov_base)+amount;
181 len = vec[0].iov_len;
184 * And copy any others
186 for (i = 1; i < *num; i++) {
188 len += vec[i].iov_len;
197 * Only called by the smbiod thread.
200 smb_receive_header(struct smb_sb_info *server)
204 unsigned char peek_buf[4];
207 sock = server_sock(server);
210 if (sock->sk->sk_state != TCP_ESTABLISHED)
213 if (!server->smb_read) {
214 result = smb_get_length(sock, peek_buf);
216 if (result == -ENODATA)
220 server->smb_len = result + 4;
222 if (server->smb_len < SMB_HEADER_LEN) {
223 PARANOIA("short packet: %d\n", result);
224 server->rstate = SMB_RECV_DROP;
228 if (server->smb_len > SMB_MAX_PACKET_SIZE) {
229 PARANOIA("long packet: %d\n", result);
230 server->rstate = SMB_RECV_DROP;
236 result = _recvfrom(sock, server->header + server->smb_read,
237 SMB_HEADER_LEN - server->smb_read, 0);
238 VERBOSE("_recvfrom: %d\n", result);
240 VERBOSE("receive error: %d\n", result);
243 server->smb_read += result;
245 if (server->smb_read == SMB_HEADER_LEN)
246 server->rstate = SMB_RECV_HCOMPLETE;
251 static char drop_buffer[PAGE_SIZE];
254 * smb_receive_drop - read and throw away the data
255 * Only called by the smbiod thread.
257 * FIXME: we are in the kernel, could we just tell the socket that we want
258 * to drop stuff from the buffer?
261 smb_receive_drop(struct smb_sb_info *server)
267 int rlen = smb_len(server->header) - server->smb_read + 4;
270 if (rlen > PAGE_SIZE)
273 sock = server_sock(server);
276 if (sock->sk->sk_state != TCP_ESTABLISHED)
279 flags = MSG_DONTWAIT | MSG_NOSIGNAL;
280 iov.iov_base = drop_buffer;
281 iov.iov_len = PAGE_SIZE;
282 msg.msg_flags = flags;
285 msg.msg_control = NULL;
287 result = kernel_recvmsg(sock, &msg, &iov, 1, rlen, flags);
289 VERBOSE("read: %d\n", result);
291 VERBOSE("receive error: %d\n", result);
294 server->smb_read += result;
296 if (server->smb_read >= server->smb_len)
297 server->rstate = SMB_RECV_END;
305 * Only called by the smbiod thread.
308 smb_receive(struct smb_sb_info *server, struct smb_request *req)
313 struct kvec *p = req->rq_iov;
314 size_t num = req->rq_iovlen;
319 sock = server_sock(server);
322 if (sock->sk->sk_state != TCP_ESTABLISHED)
325 flags = MSG_DONTWAIT | MSG_NOSIGNAL;
326 msg.msg_flags = flags;
329 msg.msg_control = NULL;
331 /* Dont repeat bytes and count available bufferspace */
332 rlen = smb_move_iov(&p, &num, iov, req->rq_bytes_recvd);
333 if (req->rq_rlen < rlen)
336 result = kernel_recvmsg(sock, &msg, p, num, rlen, flags);
338 VERBOSE("read: %d\n", result);
340 VERBOSE("receive error: %d\n", result);
343 req->rq_bytes_recvd += result;
344 server->smb_read += result;
351 * Try to send a SMB request. This may return after sending only parts of the
352 * request. SMB_REQ_TRANSMITTED will be set if a request was fully sent.
354 * Parts of this was taken from xprt_sendmsg from net/sunrpc/xprt.c
357 smb_send_request(struct smb_request *req)
359 struct smb_sb_info *server = req->rq_server;
361 struct msghdr msg = {.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT};
362 int slen = req->rq_slen - req->rq_bytes_sent;
365 struct kvec *p = req->rq_iov;
366 size_t num = req->rq_iovlen;
368 sock = server_sock(server);
371 if (sock->sk->sk_state != TCP_ESTABLISHED)
374 /* Dont repeat bytes */
375 if (req->rq_bytes_sent)
376 smb_move_iov(&p, &num, iov, req->rq_bytes_sent);
378 result = kernel_sendmsg(sock, &msg, p, num, slen);
381 req->rq_bytes_sent += result;
382 if (req->rq_bytes_sent >= req->rq_slen)
383 req->rq_flags |= SMB_REQ_TRANSMITTED;