Fix pmd_populate.
[linux-2.6/linux-mips.git] / fs / smbfs / sock.c
blob8e70f349174e2411dbdceaa89ec82802c7167841
1 /*
2 * sock.c
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.
8 */
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/tcp.h>
19 #include <linux/mm.h>
20 #include <linux/netdevice.h>
21 #include <linux/smp_lock.h>
22 #include <linux/workqueue.h>
23 #include <linux/net.h>
24 #include <net/scm.h>
25 #include <net/ip.h>
27 #include <linux/smb_fs.h>
28 #include <linux/smb.h>
29 #include <linux/smbno.h>
31 #include <asm/uaccess.h>
32 #include <asm/ioctls.h>
34 #include "smb_debug.h"
35 #include "proto.h"
36 #include "request.h"
39 static int
40 _recvfrom(struct socket *socket, unsigned char *ubuf, int size, unsigned flags)
42 struct iovec iov;
43 struct msghdr msg;
44 mm_segment_t fs;
46 fs = get_fs();
47 set_fs(get_ds());
48 flags |= MSG_DONTWAIT | MSG_NOSIGNAL;
50 msg.msg_flags = flags;
51 msg.msg_name = NULL;
52 msg.msg_namelen = 0;
53 msg.msg_iov = &iov;
54 msg.msg_iovlen = 1;
55 msg.msg_control = NULL;
56 iov.iov_base = ubuf;
57 iov.iov_len = size;
59 size = sock_recvmsg(socket, &msg, size, flags);
61 set_fs(fs);
62 return size;
66 * Return the server this socket belongs to
68 static struct smb_sb_info *
69 server_from_socket(struct socket *socket)
71 return socket->sk->sk_user_data;
75 * Called when there is data on the socket.
77 void
78 smb_data_ready(struct sock *sk, int len)
80 struct smb_sb_info *server = server_from_socket(sk->sk_socket);
81 void (*data_ready)(struct sock *, int) = server->data_ready;
83 data_ready(sk, len);
84 VERBOSE("(%p, %d)\n", sk, len);
85 smbiod_wake_up();
88 int
89 smb_valid_socket(struct inode * inode)
91 return (inode && S_ISSOCK(inode->i_mode) &&
92 SOCKET_I(inode)->type == SOCK_STREAM);
95 static struct socket *
96 server_sock(struct smb_sb_info *server)
98 struct file *file;
100 if (server && (file = server->sock_file))
102 #ifdef SMBFS_PARANOIA
103 if (!smb_valid_socket(file->f_dentry->d_inode))
104 PARANOIA("bad socket!\n");
105 #endif
106 return SOCKET_I(file->f_dentry->d_inode);
108 return NULL;
111 void
112 smb_close_socket(struct smb_sb_info *server)
114 struct file * file = server->sock_file;
116 if (file) {
117 struct socket *sock = server_sock(server);
119 VERBOSE("closing socket %p\n", sock);
120 sock->sk->sk_data_ready = server->data_ready;
121 server->sock_file = NULL;
122 fput(file);
126 static int
127 smb_get_length(struct socket *socket, unsigned char *header)
129 int result;
131 result = _recvfrom(socket, header, 4, MSG_PEEK);
132 if (result == -EAGAIN)
133 return -ENODATA;
134 if (result < 0) {
135 PARANOIA("recv error = %d\n", -result);
136 return result;
138 if (result < 4)
139 return -ENODATA;
141 switch (header[0]) {
142 case 0x00:
143 case 0x82:
144 break;
146 case 0x85:
147 DEBUG1("Got SESSION KEEP ALIVE\n");
148 _recvfrom(socket, header, 4, 0); /* read away */
149 return -ENODATA;
151 default:
152 PARANOIA("Invalid NBT packet, code=%x\n", header[0]);
153 return -EIO;
156 /* The length in the RFC NB header is the raw data length */
157 return smb_len(header);
161 smb_recv_available(struct smb_sb_info *server)
163 mm_segment_t oldfs;
164 int avail, err;
165 struct socket *sock = server_sock(server);
167 oldfs = get_fs();
168 set_fs(get_ds());
169 err = sock->ops->ioctl(sock, SIOCINQ, (unsigned long) &avail);
170 set_fs(oldfs);
171 return (err >= 0) ? avail : err;
175 * Adjust the iovec to move on 'n' bytes (from nfs/sunrpc)
177 static int
178 smb_move_iov(struct msghdr *msg, struct iovec *niv, unsigned amount)
180 struct iovec *iv = msg->msg_iov;
181 int i;
182 int len;
185 * Eat any sent iovecs
187 while (iv->iov_len <= amount) {
188 amount -= iv->iov_len;
189 iv++;
190 msg->msg_iovlen--;
194 * And chew down the partial one
196 niv[0].iov_len = iv->iov_len-amount;
197 niv[0].iov_base =((unsigned char *)iv->iov_base)+amount;
198 iv++;
200 len = niv[0].iov_len;
203 * And copy any others
205 for (i = 1; i < msg->msg_iovlen; i++) {
206 niv[i] = *iv++;
207 len += niv[i].iov_len;
210 msg->msg_iov = niv;
211 return len;
215 * smb_receive_header
216 * Only called by the smbiod thread.
219 smb_receive_header(struct smb_sb_info *server)
221 struct socket *sock;
222 int result = 0;
223 unsigned char peek_buf[4];
225 result = -EIO;
226 sock = server_sock(server);
227 if (!sock)
228 goto out;
229 if (sock->sk->sk_state != TCP_ESTABLISHED)
230 goto out;
232 if (!server->smb_read) {
233 result = smb_get_length(sock, peek_buf);
234 if (result < 0) {
235 if (result == -ENODATA)
236 result = 0;
237 goto out;
239 server->smb_len = result + 4;
241 if (server->smb_len < SMB_HEADER_LEN) {
242 PARANOIA("short packet: %d\n", result);
243 server->rstate = SMB_RECV_DROP;
244 result = -EIO;
245 goto out;
247 if (server->smb_len > SMB_MAX_PACKET_SIZE) {
248 PARANOIA("long packet: %d\n", result);
249 server->rstate = SMB_RECV_DROP;
250 result = -EIO;
251 goto out;
255 result = _recvfrom(sock, server->header + server->smb_read,
256 SMB_HEADER_LEN - server->smb_read, 0);
257 VERBOSE("_recvfrom: %d\n", result);
258 if (result < 0) {
259 VERBOSE("receive error: %d\n", result);
260 goto out;
262 server->smb_read += result;
264 if (server->smb_read == SMB_HEADER_LEN)
265 server->rstate = SMB_RECV_HCOMPLETE;
266 out:
267 return result;
270 static char drop_buffer[PAGE_SIZE];
273 * smb_receive_drop - read and throw away the data
274 * Only called by the smbiod thread.
276 * FIXME: we are in the kernel, could we just tell the socket that we want
277 * to drop stuff from the buffer?
280 smb_receive_drop(struct smb_sb_info *server)
282 struct socket *sock;
283 unsigned int flags;
284 struct iovec iov;
285 struct msghdr msg;
286 mm_segment_t fs;
287 int rlen = smb_len(server->header) - server->smb_read + 4;
288 int result = -EIO;
290 sock = server_sock(server);
291 if (!sock)
292 goto out;
293 if (sock->sk->sk_state != TCP_ESTABLISHED)
294 goto out;
296 fs = get_fs();
297 set_fs(get_ds());
299 flags = MSG_DONTWAIT | MSG_NOSIGNAL;
300 iov.iov_base = drop_buffer;
301 iov.iov_len = PAGE_SIZE;
302 msg.msg_flags = flags;
303 msg.msg_name = NULL;
304 msg.msg_namelen = 0;
305 msg.msg_iov = &iov;
306 msg.msg_iovlen = 1;
307 msg.msg_control = NULL;
309 if (rlen > PAGE_SIZE)
310 rlen = PAGE_SIZE;
312 result = sock_recvmsg(sock, &msg, rlen, flags);
314 set_fs(fs);
316 VERBOSE("read: %d\n", result);
317 if (result < 0) {
318 VERBOSE("receive error: %d\n", result);
319 goto out;
321 server->smb_read += result;
323 if (server->smb_read >= server->smb_len)
324 server->rstate = SMB_RECV_END;
326 out:
327 return result;
331 * smb_receive
332 * Only called by the smbiod thread.
335 smb_receive(struct smb_sb_info *server, struct smb_request *req)
337 struct socket *sock;
338 unsigned int flags;
339 struct iovec iov[4];
340 struct msghdr msg;
341 mm_segment_t fs;
342 int rlen;
343 int result = -EIO;
345 sock = server_sock(server);
346 if (!sock)
347 goto out;
348 if (sock->sk->sk_state != TCP_ESTABLISHED)
349 goto out;
351 fs = get_fs();
352 set_fs(get_ds());
354 flags = MSG_DONTWAIT | MSG_NOSIGNAL;;
355 msg.msg_flags = flags;
356 msg.msg_name = NULL;
357 msg.msg_namelen = 0;
358 msg.msg_iov = req->rq_iov;
359 msg.msg_iovlen = req->rq_iovlen;
360 msg.msg_control = NULL;
362 /* Dont repeat bytes and count available bufferspace */
363 rlen = smb_move_iov(&msg, iov, req->rq_bytes_recvd);
364 if (req->rq_rlen < rlen)
365 rlen = req->rq_rlen;
367 result = sock_recvmsg(sock, &msg, rlen, flags);
369 set_fs(fs);
371 VERBOSE("read: %d\n", result);
372 if (result < 0) {
373 VERBOSE("receive error: %d\n", result);
374 goto out;
376 req->rq_bytes_recvd += result;
377 server->smb_read += result;
379 out:
380 return result;
384 * Try to send a SMB request. This may return after sending only parts of the
385 * request. SMB_REQ_TRANSMITTED will be set if a request was fully sent.
387 * Parts of this was taken from xprt_sendmsg from net/sunrpc/xprt.c
390 smb_send_request(struct smb_request *req)
392 mm_segment_t fs;
393 struct smb_sb_info *server = req->rq_server;
394 struct socket *sock;
395 struct msghdr msg;
396 int slen = req->rq_slen - req->rq_bytes_sent;
397 int result = -EIO;
398 struct iovec iov[4];
400 sock = server_sock(server);
401 if (!sock)
402 goto out;
403 if (sock->sk->sk_state != TCP_ESTABLISHED)
404 goto out;
406 msg.msg_name = NULL;
407 msg.msg_namelen = 0;
408 msg.msg_control = NULL;
409 msg.msg_controllen = 0;
410 msg.msg_iov = req->rq_iov;
411 msg.msg_iovlen = req->rq_iovlen;
412 msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT;
414 /* Dont repeat bytes */
415 if (req->rq_bytes_sent)
416 smb_move_iov(&msg, iov, req->rq_bytes_sent);
418 fs = get_fs();
419 set_fs(get_ds());
420 result = sock_sendmsg(sock, &msg, slen);
421 set_fs(fs);
423 if (result >= 0) {
424 req->rq_bytes_sent += result;
425 if (req->rq_bytes_sent >= req->rq_slen)
426 req->rq_flags |= SMB_REQ_TRANSMITTED;
428 out:
429 return result;