diff options
Diffstat (limited to 'fs/smbfs/sock.c')
-rw-r--r-- | fs/smbfs/sock.c | 386 |
1 files changed, 0 insertions, 386 deletions
diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c deleted file mode 100644 index e37fe4deebd0..000000000000 --- a/fs/smbfs/sock.c +++ /dev/null | |||
@@ -1,386 +0,0 @@ | |||
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 | ||
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 * | ||
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 | ||
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 | ||
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 * | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | } | ||