Merge branch 'master' of /home/trondmy/kernel/linux-2.6/ into merge_linus
[linux-2.6] / fs / smbfs / sock.c
1 /*
2  *  sock.c
3  *
4  *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
5  *  Copyright (C) 1997 by Volker Lendecke
6  *
7  *  Please add a note about your changes to smbfs in the ChangeLog file.
8  */
9
10 #include <linux/fs.h>
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>
16 #include <linux/in.h>
17 #include <linux/net.h>
18 #include <linux/mm.h>
19 #include <linux/netdevice.h>
20 #include <linux/smp_lock.h>
21 #include <linux/workqueue.h>
22 #include <net/scm.h>
23 #include <net/tcp_states.h>
24 #include <net/ip.h>
25
26 #include <linux/smb_fs.h>
27 #include <linux/smb.h>
28 #include <linux/smbno.h>
29
30 #include <asm/uaccess.h>
31 #include <asm/ioctls.h>
32
33 #include "smb_debug.h"
34 #include "proto.h"
35 #include "request.h"
36
37
38 static int
39 _recvfrom(struct socket *socket, unsigned char *ubuf, int size, unsigned flags)
40 {
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);
45 }
46
47 /*
48  * Return the server this socket belongs to
49  */
50 static struct smb_sb_info *
51 server_from_socket(struct socket *socket)
52 {
53         return socket->sk->sk_user_data;
54 }
55
56 /*
57  * Called when there is data on the socket.
58  */
59 void
60 smb_data_ready(struct sock *sk, int len)
61 {
62         struct smb_sb_info *server = server_from_socket(sk->sk_socket);
63         void (*data_ready)(struct sock *, int) = server->data_ready;
64
65         data_ready(sk, len);
66         VERBOSE("(%p, %d)\n", sk, len);
67         smbiod_wake_up();
68 }
69
70 int
71 smb_valid_socket(struct inode * inode)
72 {
73         return (inode && S_ISSOCK(inode->i_mode) && 
74                 SOCKET_I(inode)->type == SOCK_STREAM);
75 }
76
77 static struct socket *
78 server_sock(struct smb_sb_info *server)
79 {
80         struct file *file;
81
82         if (server && (file = server->sock_file))
83         {
84 #ifdef SMBFS_PARANOIA
85                 if (!smb_valid_socket(file->f_dentry->d_inode))
86                         PARANOIA("bad socket!\n");
87 #endif
88                 return SOCKET_I(file->f_dentry->d_inode);
89         }
90         return NULL;
91 }
92
93 void
94 smb_close_socket(struct smb_sb_info *server)
95 {
96         struct file * file = server->sock_file;
97
98         if (file) {
99                 struct socket *sock = server_sock(server);
100
101                 VERBOSE("closing socket %p\n", sock);
102                 sock->sk->sk_data_ready = server->data_ready;
103                 server->sock_file = NULL;
104                 fput(file);
105         }
106 }
107
108 static int
109 smb_get_length(struct socket *socket, unsigned char *header)
110 {
111         int result;
112
113         result = _recvfrom(socket, header, 4, MSG_PEEK);
114         if (result == -EAGAIN)
115                 return -ENODATA;
116         if (result < 0) {
117                 PARANOIA("recv error = %d\n", -result);
118                 return result;
119         }
120         if (result < 4)
121                 return -ENODATA;
122
123         switch (header[0]) {
124         case 0x00:
125         case 0x82:
126                 break;
127
128         case 0x85:
129                 DEBUG1("Got SESSION KEEP ALIVE\n");
130                 _recvfrom(socket, header, 4, 0);        /* read away */
131                 return -ENODATA;
132
133         default:
134                 PARANOIA("Invalid NBT packet, code=%x\n", header[0]);
135                 return -EIO;
136         }
137
138         /* The length in the RFC NB header is the raw data length */
139         return smb_len(header);
140 }
141
142 int
143 smb_recv_available(struct smb_sb_info *server)
144 {
145         mm_segment_t oldfs;
146         int avail, err;
147         struct socket *sock = server_sock(server);
148
149         oldfs = get_fs();
150         set_fs(get_ds());
151         err = sock->ops->ioctl(sock, SIOCINQ, (unsigned long) &avail);
152         set_fs(oldfs);
153         return (err >= 0) ? avail : err;
154 }
155
156 /*
157  * Adjust the kvec to move on 'n' bytes (from nfs/sunrpc)
158  */
159 static int
160 smb_move_iov(struct kvec **data, size_t *num, struct kvec *vec, unsigned amount)
161 {
162         struct kvec *iv = *data;
163         int i;
164         int len;
165
166         /*
167          *      Eat any sent kvecs
168          */
169         while (iv->iov_len <= amount) {
170                 amount -= iv->iov_len;
171                 iv++;
172                 (*num)--;
173         }
174
175         /*
176          *      And chew down the partial one
177          */
178         vec[0].iov_len = iv->iov_len-amount;
179         vec[0].iov_base =((unsigned char *)iv->iov_base)+amount;
180         iv++;
181
182         len = vec[0].iov_len;
183
184         /*
185          *      And copy any others
186          */
187         for (i = 1; i < *num; i++) {
188                 vec[i] = *iv++;
189                 len += vec[i].iov_len;
190         }
191
192         *data = vec;
193         return len;
194 }
195
196 /*
197  * smb_receive_header
198  * Only called by the smbiod thread.
199  */
200 int
201 smb_receive_header(struct smb_sb_info *server)
202 {
203         struct socket *sock;
204         int result = 0;
205         unsigned char peek_buf[4];
206
207         result = -EIO; 
208         sock = server_sock(server);
209         if (!sock)
210                 goto out;
211         if (sock->sk->sk_state != TCP_ESTABLISHED)
212                 goto out;
213
214         if (!server->smb_read) {
215                 result = smb_get_length(sock, peek_buf);
216                 if (result < 0) {
217                         if (result == -ENODATA)
218                                 result = 0;
219                         goto out;
220                 }
221                 server->smb_len = result + 4;
222
223                 if (server->smb_len < SMB_HEADER_LEN) {
224                         PARANOIA("short packet: %d\n", result);
225                         server->rstate = SMB_RECV_DROP;
226                         result = -EIO;
227                         goto out;
228                 }
229                 if (server->smb_len > SMB_MAX_PACKET_SIZE) {
230                         PARANOIA("long packet: %d\n", result);
231                         server->rstate = SMB_RECV_DROP;
232                         result = -EIO;
233                         goto out;
234                 }
235         }
236
237         result = _recvfrom(sock, server->header + server->smb_read,
238                            SMB_HEADER_LEN - server->smb_read, 0);
239         VERBOSE("_recvfrom: %d\n", result);
240         if (result < 0) {
241                 VERBOSE("receive error: %d\n", result);
242                 goto out;
243         }
244         server->smb_read += result;
245
246         if (server->smb_read == SMB_HEADER_LEN)
247                 server->rstate = SMB_RECV_HCOMPLETE;
248 out:
249         return result;
250 }
251
252 static char drop_buffer[PAGE_SIZE];
253
254 /*
255  * smb_receive_drop - read and throw away the data
256  * Only called by the smbiod thread.
257  *
258  * FIXME: we are in the kernel, could we just tell the socket that we want
259  * to drop stuff from the buffer?
260  */
261 int
262 smb_receive_drop(struct smb_sb_info *server)
263 {
264         struct socket *sock;
265         unsigned int flags;
266         struct kvec iov;
267         struct msghdr msg;
268         int rlen = smb_len(server->header) - server->smb_read + 4;
269         int result = -EIO;
270
271         if (rlen > PAGE_SIZE)
272                 rlen = PAGE_SIZE;
273
274         sock = server_sock(server);
275         if (!sock)
276                 goto out;
277         if (sock->sk->sk_state != TCP_ESTABLISHED)
278                 goto out;
279
280         flags = MSG_DONTWAIT | MSG_NOSIGNAL;
281         iov.iov_base = drop_buffer;
282         iov.iov_len = PAGE_SIZE;
283         msg.msg_flags = flags;
284         msg.msg_name = NULL;
285         msg.msg_namelen = 0;
286         msg.msg_control = NULL;
287
288         result = kernel_recvmsg(sock, &msg, &iov, 1, rlen, flags);
289
290         VERBOSE("read: %d\n", result);
291         if (result < 0) {
292                 VERBOSE("receive error: %d\n", result);
293                 goto out;
294         }
295         server->smb_read += result;
296
297         if (server->smb_read >= server->smb_len)
298                 server->rstate = SMB_RECV_END;
299
300 out:
301         return result;
302 }
303
304 /*
305  * smb_receive
306  * Only called by the smbiod thread.
307  */
308 int
309 smb_receive(struct smb_sb_info *server, struct smb_request *req)
310 {
311         struct socket *sock;
312         unsigned int flags;
313         struct kvec iov[4];
314         struct kvec *p = req->rq_iov;
315         size_t num = req->rq_iovlen;
316         struct msghdr msg;
317         int rlen;
318         int result = -EIO;
319
320         sock = server_sock(server);
321         if (!sock)
322                 goto out;
323         if (sock->sk->sk_state != TCP_ESTABLISHED)
324                 goto out;
325
326         flags = MSG_DONTWAIT | MSG_NOSIGNAL;
327         msg.msg_flags = flags;
328         msg.msg_name = NULL;
329         msg.msg_namelen = 0;
330         msg.msg_control = NULL;
331
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)
335                 rlen = req->rq_rlen;
336
337         result = kernel_recvmsg(sock, &msg, p, num, rlen, flags);
338
339         VERBOSE("read: %d\n", result);
340         if (result < 0) {
341                 VERBOSE("receive error: %d\n", result);
342                 goto out;
343         }
344         req->rq_bytes_recvd += result;
345         server->smb_read += result;
346
347 out:
348         return result;
349 }
350
351 /*
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.
354  *
355  * Parts of this was taken from xprt_sendmsg from net/sunrpc/xprt.c
356  */
357 int
358 smb_send_request(struct smb_request *req)
359 {
360         struct smb_sb_info *server = req->rq_server;
361         struct socket *sock;
362         struct msghdr msg = {.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT};
363         int slen = req->rq_slen - req->rq_bytes_sent;
364         int result = -EIO;
365         struct kvec iov[4];
366         struct kvec *p = req->rq_iov;
367         size_t num = req->rq_iovlen;
368
369         sock = server_sock(server);
370         if (!sock)
371                 goto out;
372         if (sock->sk->sk_state != TCP_ESTABLISHED)
373                 goto out;
374
375         /* Dont repeat bytes */
376         if (req->rq_bytes_sent)
377                 smb_move_iov(&p, &num, iov, req->rq_bytes_sent);
378
379         result = kernel_sendmsg(sock, &msg, p, num, slen);
380
381         if (result >= 0) {
382                 req->rq_bytes_sent += result;
383                 if (req->rq_bytes_sent >= req->rq_slen)
384                         req->rq_flags |= SMB_REQ_TRANSMITTED;
385         }
386 out:
387         return result;
388 }