staging: Remove autofs3
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / smbfs / sock.c
blob9e264090e611e5d99de0e23fdde578090074141e
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/mm.h>
19 #include <linux/netdevice.h>
20 #include <linux/workqueue.h>
21 #include <net/scm.h>
22 #include <net/tcp_states.h>
23 #include <net/ip.h>
25 #include <asm/uaccess.h>
26 #include <asm/ioctls.h>
28 #include "smb_fs.h"
29 #include "smb.h"
30 #include "smbno.h"
31 #include "smb_debug.h"
32 #include "proto.h"
33 #include "request.h"
36 static int
37 _recvfrom(struct socket *socket, unsigned char *ubuf, int size, unsigned flags)
39 struct kvec iov = {ubuf, size};
40 struct msghdr msg = {.msg_flags = flags};
41 msg.msg_flags |= MSG_DONTWAIT | MSG_NOSIGNAL;
42 return kernel_recvmsg(socket, &msg, &iov, 1, size, msg.msg_flags);
46 * Return the server this socket belongs to
48 static struct smb_sb_info *
49 server_from_socket(struct socket *socket)
51 return socket->sk->sk_user_data;
55 * Called when there is data on the socket.
57 void
58 smb_data_ready(struct sock *sk, int len)
60 struct smb_sb_info *server = server_from_socket(sk->sk_socket);
61 void (*data_ready)(struct sock *, int) = server->data_ready;
63 data_ready(sk, len);
64 VERBOSE("(%p, %d)\n", sk, len);
65 smbiod_wake_up();
68 int
69 smb_valid_socket(struct inode * inode)
71 return (inode && S_ISSOCK(inode->i_mode) &&
72 SOCKET_I(inode)->type == SOCK_STREAM);
75 static struct socket *
76 server_sock(struct smb_sb_info *server)
78 struct file *file;
80 if (server && (file = server->sock_file))
82 #ifdef SMBFS_PARANOIA
83 if (!smb_valid_socket(file->f_path.dentry->d_inode))
84 PARANOIA("bad socket!\n");
85 #endif
86 return SOCKET_I(file->f_path.dentry->d_inode);
88 return NULL;
91 void
92 smb_close_socket(struct smb_sb_info *server)
94 struct file * file = server->sock_file;
96 if (file) {
97 struct socket *sock = server_sock(server);
99 VERBOSE("closing socket %p\n", sock);
100 sock->sk->sk_data_ready = server->data_ready;
101 server->sock_file = NULL;
102 fput(file);
106 static int
107 smb_get_length(struct socket *socket, unsigned char *header)
109 int result;
111 result = _recvfrom(socket, header, 4, MSG_PEEK);
112 if (result == -EAGAIN)
113 return -ENODATA;
114 if (result < 0) {
115 PARANOIA("recv error = %d\n", -result);
116 return result;
118 if (result < 4)
119 return -ENODATA;
121 switch (header[0]) {
122 case 0x00:
123 case 0x82:
124 break;
126 case 0x85:
127 DEBUG1("Got SESSION KEEP ALIVE\n");
128 _recvfrom(socket, header, 4, 0); /* read away */
129 return -ENODATA;
131 default:
132 PARANOIA("Invalid NBT packet, code=%x\n", header[0]);
133 return -EIO;
136 /* The length in the RFC NB header is the raw data length */
137 return smb_len(header);
141 smb_recv_available(struct smb_sb_info *server)
143 mm_segment_t oldfs;
144 int avail, err;
145 struct socket *sock = server_sock(server);
147 oldfs = get_fs();
148 set_fs(get_ds());
149 err = sock->ops->ioctl(sock, SIOCINQ, (unsigned long) &avail);
150 set_fs(oldfs);
151 return (err >= 0) ? avail : err;
155 * Adjust the kvec to move on 'n' bytes (from nfs/sunrpc)
157 static int
158 smb_move_iov(struct kvec **data, size_t *num, struct kvec *vec, unsigned amount)
160 struct kvec *iv = *data;
161 int i;
162 int len;
165 * Eat any sent kvecs
167 while (iv->iov_len <= amount) {
168 amount -= iv->iov_len;
169 iv++;
170 (*num)--;
174 * And chew down the partial one
176 vec[0].iov_len = iv->iov_len-amount;
177 vec[0].iov_base =((unsigned char *)iv->iov_base)+amount;
178 iv++;
180 len = vec[0].iov_len;
183 * And copy any others
185 for (i = 1; i < *num; i++) {
186 vec[i] = *iv++;
187 len += vec[i].iov_len;
190 *data = vec;
191 return len;
195 * smb_receive_header
196 * Only called by the smbiod thread.
199 smb_receive_header(struct smb_sb_info *server)
201 struct socket *sock;
202 int result = 0;
203 unsigned char peek_buf[4];
205 result = -EIO;
206 sock = server_sock(server);
207 if (!sock)
208 goto out;
209 if (sock->sk->sk_state != TCP_ESTABLISHED)
210 goto out;
212 if (!server->smb_read) {
213 result = smb_get_length(sock, peek_buf);
214 if (result < 0) {
215 if (result == -ENODATA)
216 result = 0;
217 goto out;
219 server->smb_len = result + 4;
221 if (server->smb_len < SMB_HEADER_LEN) {
222 PARANOIA("short packet: %d\n", result);
223 server->rstate = SMB_RECV_DROP;
224 result = -EIO;
225 goto out;
227 if (server->smb_len > SMB_MAX_PACKET_SIZE) {
228 PARANOIA("long packet: %d\n", result);
229 server->rstate = SMB_RECV_DROP;
230 result = -EIO;
231 goto out;
235 result = _recvfrom(sock, server->header + server->smb_read,
236 SMB_HEADER_LEN - server->smb_read, 0);
237 VERBOSE("_recvfrom: %d\n", result);
238 if (result < 0) {
239 VERBOSE("receive error: %d\n", result);
240 goto out;
242 server->smb_read += result;
244 if (server->smb_read == SMB_HEADER_LEN)
245 server->rstate = SMB_RECV_HCOMPLETE;
246 out:
247 return result;
250 static char drop_buffer[PAGE_SIZE];
253 * smb_receive_drop - read and throw away the data
254 * Only called by the smbiod thread.
256 * FIXME: we are in the kernel, could we just tell the socket that we want
257 * to drop stuff from the buffer?
260 smb_receive_drop(struct smb_sb_info *server)
262 struct socket *sock;
263 unsigned int flags;
264 struct kvec iov;
265 struct msghdr msg;
266 int rlen = smb_len(server->header) - server->smb_read + 4;
267 int result = -EIO;
269 if (rlen > PAGE_SIZE)
270 rlen = PAGE_SIZE;
272 sock = server_sock(server);
273 if (!sock)
274 goto out;
275 if (sock->sk->sk_state != TCP_ESTABLISHED)
276 goto out;
278 flags = MSG_DONTWAIT | MSG_NOSIGNAL;
279 iov.iov_base = drop_buffer;
280 iov.iov_len = PAGE_SIZE;
281 msg.msg_flags = flags;
282 msg.msg_name = NULL;
283 msg.msg_namelen = 0;
284 msg.msg_control = NULL;
286 result = kernel_recvmsg(sock, &msg, &iov, 1, rlen, flags);
288 VERBOSE("read: %d\n", result);
289 if (result < 0) {
290 VERBOSE("receive error: %d\n", result);
291 goto out;
293 server->smb_read += result;
295 if (server->smb_read >= server->smb_len)
296 server->rstate = SMB_RECV_END;
298 out:
299 return result;
303 * smb_receive
304 * Only called by the smbiod thread.
307 smb_receive(struct smb_sb_info *server, struct smb_request *req)
309 struct socket *sock;
310 unsigned int flags;
311 struct kvec iov[4];
312 struct kvec *p = req->rq_iov;
313 size_t num = req->rq_iovlen;
314 struct msghdr msg;
315 int rlen;
316 int result = -EIO;
318 sock = server_sock(server);
319 if (!sock)
320 goto out;
321 if (sock->sk->sk_state != TCP_ESTABLISHED)
322 goto out;
324 flags = MSG_DONTWAIT | MSG_NOSIGNAL;
325 msg.msg_flags = flags;
326 msg.msg_name = NULL;
327 msg.msg_namelen = 0;
328 msg.msg_control = NULL;
330 /* Dont repeat bytes and count available bufferspace */
331 rlen = min_t(int, smb_move_iov(&p, &num, iov, req->rq_bytes_recvd),
332 (req->rq_rlen - req->rq_bytes_recvd));
334 result = kernel_recvmsg(sock, &msg, p, num, rlen, flags);
336 VERBOSE("read: %d\n", result);
337 if (result < 0) {
338 VERBOSE("receive error: %d\n", result);
339 goto out;
341 req->rq_bytes_recvd += result;
342 server->smb_read += result;
344 out:
345 return result;
349 * Try to send a SMB request. This may return after sending only parts of the
350 * request. SMB_REQ_TRANSMITTED will be set if a request was fully sent.
352 * Parts of this was taken from xprt_sendmsg from net/sunrpc/xprt.c
355 smb_send_request(struct smb_request *req)
357 struct smb_sb_info *server = req->rq_server;
358 struct socket *sock;
359 struct msghdr msg = {.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT};
360 int slen = req->rq_slen - req->rq_bytes_sent;
361 int result = -EIO;
362 struct kvec iov[4];
363 struct kvec *p = req->rq_iov;
364 size_t num = req->rq_iovlen;
366 sock = server_sock(server);
367 if (!sock)
368 goto out;
369 if (sock->sk->sk_state != TCP_ESTABLISHED)
370 goto out;
372 /* Dont repeat bytes */
373 if (req->rq_bytes_sent)
374 smb_move_iov(&p, &num, iov, req->rq_bytes_sent);
376 result = kernel_sendmsg(sock, &msg, p, num, slen);
378 if (result >= 0) {
379 req->rq_bytes_sent += result;
380 if (req->rq_bytes_sent >= req->rq_slen)
381 req->rq_flags |= SMB_REQ_TRANSMITTED;
383 out:
384 return result;