PageRenderTime 61ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/fs/smbfs/sock.c

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