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/smp_lock.h>
21 #include <linux/workqueue.h>
23 #include <net/tcp_states.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
)
41 struct kvec iov
= {ubuf
, size
};
42 struct msghdr msg
= {.msg_flags
= flags
};
43 msg
.msg_flags
|= MSG_DONTWAIT
| MSG_NOSIGNAL
;
44 return kernel_recvmsg(socket
, &msg
, &iov
, 1, size
, msg
.msg_flags
);
48 * Return the server this socket belongs to
50 static struct smb_sb_info
*
51 server_from_socket(struct socket
*socket
)
53 return socket
->sk
->sk_user_data
;
57 * Called when there is data on the socket.
60 smb_data_ready(struct sock
*sk
, int len
)
62 struct smb_sb_info
*server
= server_from_socket(sk
->sk_socket
);
63 void (*data_ready
)(struct sock
*, int) = server
->data_ready
;
66 VERBOSE("(%p, %d)\n", sk
, len
);
71 smb_valid_socket(struct inode
* inode
)
73 return (inode
&& S_ISSOCK(inode
->i_mode
) &&
74 SOCKET_I(inode
)->type
== SOCK_STREAM
);
77 static struct socket
*
78 server_sock(struct smb_sb_info
*server
)
82 if (server
&& (file
= server
->sock_file
))
85 if (!smb_valid_socket(file
->f_path
.dentry
->d_inode
))
86 PARANOIA("bad socket!\n");
88 return SOCKET_I(file
->f_path
.dentry
->d_inode
);
94 smb_close_socket(struct smb_sb_info
*server
)
96 struct file
* file
= server
->sock_file
;
99 struct socket
*sock
= server_sock(server
);
101 VERBOSE("closing socket %p\n", sock
);
102 sock
->sk
->sk_data_ready
= server
->data_ready
;
103 server
->sock_file
= NULL
;
109 smb_get_length(struct socket
*socket
, unsigned char *header
)
113 result
= _recvfrom(socket
, header
, 4, MSG_PEEK
);
114 if (result
== -EAGAIN
)
117 PARANOIA("recv error = %d\n", -result
);
129 DEBUG1("Got SESSION KEEP ALIVE\n");
130 _recvfrom(socket
, header
, 4, 0); /* read away */
134 PARANOIA("Invalid NBT packet, code=%x\n", header
[0]);
138 /* The length in the RFC NB header is the raw data length */
139 return smb_len(header
);
143 smb_recv_available(struct smb_sb_info
*server
)
147 struct socket
*sock
= server_sock(server
);
151 err
= sock
->ops
->ioctl(sock
, SIOCINQ
, (unsigned long) &avail
);
153 return (err
>= 0) ? avail
: err
;
157 * Adjust the kvec to move on 'n' bytes (from nfs/sunrpc)
160 smb_move_iov(struct kvec
**data
, size_t *num
, struct kvec
*vec
, unsigned amount
)
162 struct kvec
*iv
= *data
;
169 while (iv
->iov_len
<= amount
) {
170 amount
-= iv
->iov_len
;
176 * And chew down the partial one
178 vec
[0].iov_len
= iv
->iov_len
-amount
;
179 vec
[0].iov_base
=((unsigned char *)iv
->iov_base
)+amount
;
182 len
= vec
[0].iov_len
;
185 * And copy any others
187 for (i
= 1; i
< *num
; i
++) {
189 len
+= vec
[i
].iov_len
;
198 * Only called by the smbiod thread.
201 smb_receive_header(struct smb_sb_info
*server
)
205 unsigned char peek_buf
[4];
208 sock
= server_sock(server
);
211 if (sock
->sk
->sk_state
!= TCP_ESTABLISHED
)
214 if (!server
->smb_read
) {
215 result
= smb_get_length(sock
, peek_buf
);
217 if (result
== -ENODATA
)
221 server
->smb_len
= result
+ 4;
223 if (server
->smb_len
< SMB_HEADER_LEN
) {
224 PARANOIA("short packet: %d\n", result
);
225 server
->rstate
= SMB_RECV_DROP
;
229 if (server
->smb_len
> SMB_MAX_PACKET_SIZE
) {
230 PARANOIA("long packet: %d\n", result
);
231 server
->rstate
= SMB_RECV_DROP
;
237 result
= _recvfrom(sock
, server
->header
+ server
->smb_read
,
238 SMB_HEADER_LEN
- server
->smb_read
, 0);
239 VERBOSE("_recvfrom: %d\n", result
);
241 VERBOSE("receive error: %d\n", result
);
244 server
->smb_read
+= result
;
246 if (server
->smb_read
== SMB_HEADER_LEN
)
247 server
->rstate
= SMB_RECV_HCOMPLETE
;
252 static char drop_buffer
[PAGE_SIZE
];
255 * smb_receive_drop - read and throw away the data
256 * Only called by the smbiod thread.
258 * FIXME: we are in the kernel, could we just tell the socket that we want
259 * to drop stuff from the buffer?
262 smb_receive_drop(struct smb_sb_info
*server
)
268 int rlen
= smb_len(server
->header
) - server
->smb_read
+ 4;
271 if (rlen
> PAGE_SIZE
)
274 sock
= server_sock(server
);
277 if (sock
->sk
->sk_state
!= TCP_ESTABLISHED
)
280 flags
= MSG_DONTWAIT
| MSG_NOSIGNAL
;
281 iov
.iov_base
= drop_buffer
;
282 iov
.iov_len
= PAGE_SIZE
;
283 msg
.msg_flags
= flags
;
286 msg
.msg_control
= NULL
;
288 result
= kernel_recvmsg(sock
, &msg
, &iov
, 1, rlen
, flags
);
290 VERBOSE("read: %d\n", result
);
292 VERBOSE("receive error: %d\n", result
);
295 server
->smb_read
+= result
;
297 if (server
->smb_read
>= server
->smb_len
)
298 server
->rstate
= SMB_RECV_END
;
306 * Only called by the smbiod thread.
309 smb_receive(struct smb_sb_info
*server
, struct smb_request
*req
)
314 struct kvec
*p
= req
->rq_iov
;
315 size_t num
= req
->rq_iovlen
;
320 sock
= server_sock(server
);
323 if (sock
->sk
->sk_state
!= TCP_ESTABLISHED
)
326 flags
= MSG_DONTWAIT
| MSG_NOSIGNAL
;
327 msg
.msg_flags
= flags
;
330 msg
.msg_control
= NULL
;
332 /* Dont repeat bytes and count available bufferspace */
333 rlen
= smb_move_iov(&p
, &num
, iov
, req
->rq_bytes_recvd
);
334 if (req
->rq_rlen
< rlen
)
337 result
= kernel_recvmsg(sock
, &msg
, p
, num
, rlen
, flags
);
339 VERBOSE("read: %d\n", result
);
341 VERBOSE("receive error: %d\n", result
);
344 req
->rq_bytes_recvd
+= result
;
345 server
->smb_read
+= result
;
352 * Try to send a SMB request. This may return after sending only parts of the
353 * request. SMB_REQ_TRANSMITTED will be set if a request was fully sent.
355 * Parts of this was taken from xprt_sendmsg from net/sunrpc/xprt.c
358 smb_send_request(struct smb_request
*req
)
360 struct smb_sb_info
*server
= req
->rq_server
;
362 struct msghdr msg
= {.msg_flags
= MSG_NOSIGNAL
| MSG_DONTWAIT
};
363 int slen
= req
->rq_slen
- req
->rq_bytes_sent
;
366 struct kvec
*p
= req
->rq_iov
;
367 size_t num
= req
->rq_iovlen
;
369 sock
= server_sock(server
);
372 if (sock
->sk
->sk_state
!= TCP_ESTABLISHED
)
375 /* Dont repeat bytes */
376 if (req
->rq_bytes_sent
)
377 smb_move_iov(&p
, &num
, iov
, req
->rq_bytes_sent
);
379 result
= kernel_sendmsg(sock
, &msg
, p
, num
, slen
);
382 req
->rq_bytes_sent
+= result
;
383 if (req
->rq_bytes_sent
>= req
->rq_slen
)
384 req
->rq_flags
|= SMB_REQ_TRANSMITTED
;