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 37static 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 */ 49static struct smb_sb_info * 50server_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 */ 58void 59smb_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 69int 70smb_valid_socket(struct inode * inode) 71{ 72 return (inode && S_ISSOCK(inode->i_mode) && 73 SOCKET_I(inode)->type == SOCK_STREAM); 74} 75 76static struct socket * 77server_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 92void 93smb_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 107static int 108smb_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 141int 142smb_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 */ 158static int 159smb_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 */ 199int 200smb_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; 247out: 248 return result; 249} 250 251static char drop_buffer[PAGE_SIZE]; 252 253int 254smb_receive_drop(struct smb_sb_info *server) 255{ 256 struct socket *sock; 257 unsigned int flags; 258 struct kvec iov; 259 struct msghdr msg; 260 int rlen = smb_len(server->header) - server->smb_read + 4; 261 int result = -EIO; 262 263 if (rlen > PAGE_SIZE) 264 rlen = PAGE_SIZE; 265 266 sock = server_sock(server); 267 if (!sock) 268 goto out; 269 if (sock->sk->sk_state != TCP_ESTABLISHED) 270 goto out; 271 272 flags = MSG_DONTWAIT | MSG_NOSIGNAL; 273 iov.iov_base = drop_buffer; 274 iov.iov_len = PAGE_SIZE; 275 msg.msg_flags = flags; 276 msg.msg_name = NULL; 277 msg.msg_namelen = 0; 278 msg.msg_control = NULL; 279 280 result = kernel_recvmsg(sock, &msg, &iov, 1, rlen, flags); 281 282 VERBOSE("read: %d\n", result); 283 if (result < 0) { 284 VERBOSE("receive error: %d\n", result); 285 goto out; 286 } 287 server->smb_read += result; 288 289 if (server->smb_read >= server->smb_len) 290 server->rstate = SMB_RECV_END; 291 292out: 293 return result; 294} 295 296/* 297 * smb_receive 298 * Only called by the smbiod thread. 299 */ 300int 301smb_receive(struct smb_sb_info *server, struct smb_request *req) 302{ 303 struct socket *sock; 304 unsigned int flags; 305 struct kvec iov[4]; 306 struct kvec *p = req->rq_iov; 307 size_t num = req->rq_iovlen; 308 struct msghdr msg; 309 int rlen; 310 int result = -EIO; 311 312 sock = server_sock(server); 313 if (!sock) 314 goto out; 315 if (sock->sk->sk_state != TCP_ESTABLISHED) 316 goto out; 317 318 flags = MSG_DONTWAIT | MSG_NOSIGNAL; 319 msg.msg_flags = flags; 320 msg.msg_name = NULL; 321 msg.msg_namelen = 0; 322 msg.msg_control = NULL; 323 324 /* Dont repeat bytes and count available bufferspace */ 325 rlen = min_t(int, smb_move_iov(&p, &num, iov, req->rq_bytes_recvd), 326 (req->rq_rlen - req->rq_bytes_recvd)); 327 328 result = kernel_recvmsg(sock, &msg, p, num, rlen, flags); 329 330 VERBOSE("read: %d\n", result); 331 if (result < 0) { 332 VERBOSE("receive error: %d\n", result); 333 goto out; 334 } 335 req->rq_bytes_recvd += result; 336 server->smb_read += result; 337 338out: 339 return result; 340} 341 342/* 343 * Try to send a SMB request. This may return after sending only parts of the 344 * request. SMB_REQ_TRANSMITTED will be set if a request was fully sent. 345 * 346 * Parts of this was taken from xprt_sendmsg from net/sunrpc/xprt.c 347 */ 348int 349smb_send_request(struct smb_request *req) 350{ 351 struct smb_sb_info *server = req->rq_server; 352 struct socket *sock; 353 struct msghdr msg = {.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT}; 354 int slen = req->rq_slen - req->rq_bytes_sent; 355 int result = -EIO; 356 struct kvec iov[4]; 357 struct kvec *p = req->rq_iov; 358 size_t num = req->rq_iovlen; 359 360 sock = server_sock(server); 361 if (!sock) 362 goto out; 363 if (sock->sk->sk_state != TCP_ESTABLISHED) 364 goto out; 365 366 /* Dont repeat bytes */ 367 if (req->rq_bytes_sent) 368 smb_move_iov(&p, &num, iov, req->rq_bytes_sent); 369 370 result = kernel_sendmsg(sock, &msg, p, num, slen); 371 372 if (result >= 0) { 373 req->rq_bytes_sent += result; 374 if (req->rq_bytes_sent >= req->rq_slen) 375 req->rq_flags |= SMB_REQ_TRANSMITTED; 376 } 377out: 378 return result; 379} 380