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