root/fs/smbfs/sock.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. smb_data_callback
  2. smb_catch_keepalive
  3. smb_dont_catch_keepalive
  4. smb_receive
  5. smb_receive_trans2
  6. server_sock
  7. smb_release
  8. smb_connect
  9. smb_request
  10. smb_trans2_request

   1 /*
   2  *  sock.c
   3  *
   4  *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
   5  *
   6  */
   7 
   8 #include <linux/config.h>
   9 #ifdef MODULE
  10 #include <linux/module.h>
  11 #include <linux/version.h>
  12 #endif
  13 
  14 #include <linux/sched.h>
  15 #include <linux/smb_fs.h>
  16 #include <linux/errno.h>
  17 #include <linux/socket.h>
  18 #include <linux/fcntl.h>
  19 #include <linux/stat.h>
  20 #include <asm/segment.h>
  21 #include <linux/in.h>
  22 #include <linux/net.h>
  23 #include <linux/mm.h>
  24 #include <linux/netdevice.h>
  25 #include <net/ip.h>
  26 
  27 #include <linux/smb.h>
  28 #include <linux/smbno.h>
  29 
  30 
  31 #define _S(nr) (1<<((nr)-1))
  32 
  33 static void
  34 smb_data_callback(struct sock *sk,int len)
     /* [previous][next][first][last][top][bottom][index][help] */
  35 {
  36         struct socket *sock = sk->socket;
  37 
  38         if(!sk->dead)
  39         {
  40                 unsigned char peek_buf[4];
  41                 int result;
  42                 unsigned short fs;
  43 
  44                 fs = get_fs();
  45                 set_fs(get_ds());
  46 
  47                 result = sock->ops->recvfrom(sock, (void *)peek_buf, 1, 1,
  48                                              MSG_PEEK, NULL, NULL);
  49 
  50                 while ((result != -EAGAIN) && (peek_buf[0] == 0x85)) {
  51 
  52                         /* got SESSION KEEP ALIVE */
  53                         result = sock->ops->recvfrom(sock, (void *)peek_buf,
  54                                                      4, 1, 0, NULL, NULL);
  55 
  56                         DDPRINTK("smb_data_callback:"
  57                                  " got SESSION KEEP ALIVE\n");
  58 
  59                         if (result == -EAGAIN)
  60                                 break;
  61 
  62                         result = sock->ops->recvfrom(sock, (void *)peek_buf,
  63                                                      1, 1, MSG_PEEK,
  64                                                      NULL, NULL);
  65 
  66                 }
  67 
  68                 set_fs(fs);
  69 
  70                 if (result != -EAGAIN) {
  71                         wake_up_interruptible(sk->sleep);
  72                 }
  73         }
  74 }
  75 
  76 int
  77 smb_catch_keepalive(struct smb_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
  78 {
  79         struct file   *file;
  80         struct inode  *inode;
  81         struct socket *sock;
  82         struct sock   *sk;
  83 
  84         if (   (server == NULL)
  85             || ((file  = server->sock_file) == NULL)
  86             || ((inode = file->f_inode) == NULL)
  87             || (!S_ISSOCK(inode->i_mode))) {
  88 
  89                 printk("smb_catch_keepalive: did not get valid server!\n");
  90                 server->data_ready = NULL;
  91                 return -EINVAL;
  92         }
  93 
  94         sock = &(inode->u.socket_i);
  95 
  96         if (sock->type != SOCK_STREAM) {
  97                 printk("smb_catch_keepalive: did not get SOCK_STREAM\n");
  98                 server->data_ready = NULL;
  99                 return -EINVAL;
 100         }
 101 
 102         sk   = (struct sock *)(sock->data);
 103 
 104         if (sk == NULL) {
 105                 printk("smb_catch_keepalive: sk == NULL");
 106                 server->data_ready = NULL;
 107                 return -EINVAL;
 108         }
 109 
 110         DDPRINTK("smb_catch_keepalive.: sk->d_r = %x, server->d_r = %x\n",
 111                  (unsigned int)(sk->data_ready),
 112                  (unsigned int)(server->data_ready));
 113 
 114         if (sk->data_ready == smb_data_callback) {
 115                 printk("smb_catch_keepalive: already done\n");
 116                 return -EINVAL;
 117         }
 118 
 119         server->data_ready = sk->data_ready;
 120         sk->data_ready = smb_data_callback;
 121         return 0;
 122 }
 123                 
 124 int
 125 smb_dont_catch_keepalive(struct smb_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
 126 {
 127         struct file   *file;
 128         struct inode  *inode;
 129         struct socket *sock;
 130         struct sock   *sk;
 131 
 132         if (   (server == NULL)
 133             || ((file  = server->sock_file) == NULL)
 134             || ((inode = file->f_inode) == NULL)
 135             || (!S_ISSOCK(inode->i_mode))) {
 136 
 137                 printk("smb_dont_catch_keepalive: "
 138                        "did not get valid server!\n");
 139                 return -EINVAL;
 140         }
 141 
 142         sock = &(inode->u.socket_i);
 143 
 144         if (sock->type != SOCK_STREAM) {
 145                 printk("smb_dont_catch_keepalive: did not get SOCK_STREAM\n");
 146                 return -EINVAL;
 147         }
 148 
 149         sk   = (struct sock *)(sock->data);
 150 
 151         if (sk == NULL) {
 152                 printk("smb_dont_catch_keepalive: sk == NULL");
 153                 return -EINVAL;
 154         }
 155 
 156         if (server->data_ready == NULL) {
 157                 printk("smb_dont_catch_keepalive: "
 158                        "server->data_ready == NULL\n");
 159                 return -EINVAL;
 160         }
 161 
 162         if (sk->data_ready != smb_data_callback) {
 163                 printk("smb_dont_catch_keepalive: "
 164                        "sk->data_callback != smb_data_callback\n");
 165                 return -EINVAL;
 166         }
 167 
 168         DDPRINTK("smb_dont_catch_keepalive: sk->d_r = %x, server->d_r = %x\n",
 169                  (unsigned int)(sk->data_ready),
 170                  (unsigned int)(server->data_ready));
 171 
 172         sk->data_ready = server->data_ready;
 173         server->data_ready = NULL;
 174         return 0;
 175 }
 176 
 177 /*
 178  * smb_receive
 179  * fs points to the correct segment, server != NULL, sock!=NULL
 180  */
 181 static int
 182 smb_receive(struct smb_server *server, struct socket *sock)
     /* [previous][next][first][last][top][bottom][index][help] */
 183 {
 184         int len, result;
 185         unsigned char peek_buf[4];
 186 
 187  re_recv:
 188 
 189         result = sock->ops->recvfrom(sock, (void *)peek_buf, 4, 0,
 190                                      MSG_PEEK, NULL, NULL);
 191 
 192         if (result < 0) {
 193                 DPRINTK("smb_receive: recv error = %d\n", -result);
 194                 return result;
 195         }
 196 
 197         if (result == 0) {
 198                 DPRINTK("smb_receive: got 0 bytes\n");
 199                 return -EIO;
 200         }
 201 
 202         switch (peek_buf[0]) {
 203 
 204         case 0x00:
 205         case 0x82:
 206                 break;
 207 
 208         case 0x85:
 209                 DPRINTK("smb_receive: Got SESSION KEEP ALIVE\n");
 210                 sock->ops->recvfrom(sock, (void *)peek_buf, 4, 1,
 211                                     0, NULL, NULL);
 212                 goto re_recv;
 213                 
 214         default:
 215                 printk("smb_receive: Invalid packet\n");
 216                 return -EIO;
 217         }
 218 
 219         /* Length not including first four bytes. */
 220         len = smb_len(peek_buf) + 4; 
 221         if (len > server->max_xmit) { 
 222                 printk("smb_receive: Received length (%d) > max_xmit (%d)!\n", 
 223                        len, server->max_xmit);
 224                 return -EIO;
 225         }
 226         else
 227         {
 228                 int already_read = 0;
 229 
 230                 while (already_read < len) {
 231                 
 232                         result = sock->ops->
 233                                 recvfrom(sock,
 234                                          (void *)(server->packet+already_read),
 235                                          len - already_read, 0, 0,
 236                                          NULL, NULL);
 237    
 238                         if (result < 0) {
 239                                 printk("SMB: notice message: error = %d\n",
 240                                        -result);
 241                                 return result;
 242                         }
 243 
 244                         already_read += result;
 245                 }
 246                 result = already_read;
 247         }
 248 
 249         server->rcls = *((unsigned char *)(server->packet+9));
 250         server->err  = *((unsigned short *)(server->packet+11));
 251 
 252         if (server->rcls != 0) {
 253                 DPRINTK("smb_response: rcls=%d, err=%d\n",
 254                         server->rcls, server->err);
 255         }
 256 
 257         return result;
 258 }
 259 
 260 
 261 /*
 262  * smb_receive's preconditions also apply here.
 263  */
 264 static int
 265 smb_receive_trans2(struct smb_server *server, struct socket *sock,
     /* [previous][next][first][last][top][bottom][index][help] */
 266                    int *data_len, int *param_len,
 267                    char **data, char **param)
 268 {
 269         int total_data=0;
 270         int total_param=0;
 271         int result;
 272         unsigned char *inbuf = server->packet;
 273 
 274         *data_len = *param_len = 0;
 275 
 276         DDPRINTK("smb_receive_trans2: enter\n");
 277         
 278         if ((result = smb_receive(server, sock)) < 0) {
 279                 return result;
 280         }
 281 
 282         if (server->rcls != 0) {
 283                 return result;
 284         }
 285 
 286         /* parse out the lengths */
 287         total_data = WVAL(inbuf,smb_tdrcnt);
 288         total_param = WVAL(inbuf,smb_tprcnt);
 289 
 290         if (   (total_data  > TRANS2_MAX_TRANSFER)
 291             || (total_param > TRANS2_MAX_TRANSFER)) {
 292                 printk("smb_receive_trans2: data/param too long\n");
 293                 return -EIO;
 294         }
 295 
 296         /* allocate it */
 297         if ((*data  = smb_kmalloc(total_data, GFP_KERNEL)) == NULL) {
 298                 printk("smb_receive_trans2: could not alloc data area\n");
 299                 return -ENOMEM;
 300         }
 301 
 302         if ((*param = smb_kmalloc(total_param, GFP_KERNEL)) == NULL) {
 303                 printk("smb_receive_trans2: could not alloc param area\n");
 304                 smb_kfree_s(*data, total_data);
 305                 return -ENOMEM;
 306         }
 307 
 308         DDPRINTK("smb_rec_trans2: total_data/param: %d/%d\n",
 309                  total_data, total_param);
 310 
 311         while (1)
 312         {
 313                 if (WVAL(inbuf,smb_prdisp)+WVAL(inbuf, smb_prcnt)
 314                     > total_param) {
 315                         printk("smb_receive_trans2: invalid parameters\n");
 316                         result = -EIO;
 317                         goto fail;
 318                 }
 319                 memcpy(*param + WVAL(inbuf,smb_prdisp),
 320                        smb_base(inbuf) + WVAL(inbuf,smb_proff),
 321                        WVAL(inbuf,smb_prcnt));
 322                 *param_len += WVAL(inbuf,smb_prcnt);
 323 
 324 
 325                 if (WVAL(inbuf,smb_drdisp)+WVAL(inbuf, smb_drcnt)>total_data) {
 326                         printk("smb_receive_trans2: invalid data block\n");
 327                         result = -EIO;
 328                         goto fail;
 329                 }
 330                 memcpy(*data + WVAL(inbuf,smb_drdisp),
 331                        smb_base(inbuf) + WVAL(inbuf,smb_droff),
 332                        WVAL(inbuf,smb_drcnt));
 333                 *data_len += WVAL(inbuf,smb_drcnt);
 334 
 335                 DDPRINTK("smb_rec_trans2: drcnt/prcnt: %d/%d\n",
 336                          WVAL(inbuf, smb_drcnt), WVAL(inbuf, smb_prcnt));
 337 
 338                 /* parse out the total lengths again - they can shrink! */
 339 
 340                 if (   (WVAL(inbuf,smb_tdrcnt) > total_data)
 341                     || (WVAL(inbuf,smb_tprcnt) > total_param)) {
 342                         printk("smb_receive_trans2: data/params grew!\n");
 343                         result = -EIO;
 344                         goto fail;
 345                 }
 346 
 347                 total_data = WVAL(inbuf,smb_tdrcnt);
 348                 total_param = WVAL(inbuf,smb_tprcnt);
 349 
 350                 if (total_data <= *data_len && total_param <= *param_len)
 351                         break;
 352 
 353                 if ((result = smb_receive(server, sock)) < 0) {
 354                         goto fail;
 355                 }
 356                 if (server->rcls != 0) {
 357                         result = -EIO;
 358                         goto fail;
 359                 }
 360         }
 361 
 362         DDPRINTK("smb_receive_trans2: normal exit\n");
 363 
 364         return 0;
 365 
 366  fail:
 367         DPRINTK("smb_receive_trans2: failed exit\n");
 368 
 369         smb_kfree_s(*param, 0); *param = NULL;
 370         smb_kfree_s(*data, 0);  *data = NULL;
 371         return result;
 372 }
 373 
 374 static inline struct socket *
 375 server_sock(struct smb_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
 376 {
 377         struct file *file;
 378         struct inode *inode;
 379 
 380         if (server == NULL)
 381                 return NULL;
 382         if ((file = server->sock_file) == NULL)
 383                 return NULL;
 384         if ((inode = file->f_inode) == NULL)
 385                 return NULL;
 386         return &(inode->u.socket_i);
 387 }
 388 
 389 int
 390 smb_release(struct smb_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
 391 {
 392         struct socket *sock = server_sock(server);
 393         int result;
 394 
 395         if (sock == NULL)
 396                 return -EINVAL;
 397 
 398         result = sock->ops->release(sock, NULL);
 399         DPRINTK("smb_release: sock->ops->release = %d\n", result);
 400 
 401         /* inet_release does not set sock->state.  Maybe someone is
 402            confused about sock->state being SS_CONNECTED while there
 403            is nothing behind it, so I set it to SS_UNCONNECTED.*/
 404         sock->state = SS_UNCONNECTED;
 405 
 406         result = sock->ops->create(sock, 0);
 407         DPRINTK("smb_release: sock->ops->create = %d\n", result);
 408         return result;
 409 }
 410 
 411 int
 412 smb_connect(struct smb_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
 413 {
 414         struct socket *sock = server_sock(server);
 415         if (sock == NULL)
 416                 return -EINVAL;
 417         if (sock->state != SS_UNCONNECTED) {
 418                 DPRINTK("smb_connect: socket is not unconnected: %d\n",
 419                         sock->state);
 420         }
 421         return sock->ops->connect(sock, (struct sockaddr *)&(server->m.addr),
 422                                   sizeof(struct sockaddr_in), 0);
 423 }
 424         
 425 /*****************************************************************************/
 426 /*                                                                           */
 427 /*  This routine was once taken from nfs, wich is for udp. Here TCP does     */
 428 /*  most of the ugly stuff for us (thanks, Alan!)                            */
 429 /*                                                                           */
 430 /*****************************************************************************/
 431 int
 432 smb_request(struct smb_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
 433 {
 434         unsigned long old_mask;
 435         unsigned short fs;      /* We fool the kernel to believe
 436                                    we call from user space. */
 437         int len, result, result2;
 438 
 439         struct socket *sock = server_sock(server);
 440         unsigned char *buffer = (server == NULL) ? NULL : server->packet;
 441 
 442         if ((sock == NULL) || (buffer == NULL)) {
 443                 printk("smb_request: Bad server!\n");
 444                 return -EBADF;
 445         }
 446 
 447         if (server->state != CONN_VALID)
 448                 return -EIO;
 449                 
 450 #if 0
 451         while (server->lock)
 452                 sleep_on(&server->wait);
 453         server->lock = 1;
 454 #endif
 455 
 456         if ((result = smb_dont_catch_keepalive(server)) != 0) {
 457                 server->state = CONN_INVALID;
 458                 smb_invalidate_all_inodes(server);
 459                 return result;
 460         }
 461 
 462         len = smb_len(buffer) + 4;
 463 
 464         DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
 465 
 466         old_mask = current->blocked;
 467         current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
 468         fs = get_fs();
 469         set_fs(get_ds());
 470 
 471         result = sock->ops->send(sock, (void *)buffer, len, 0, 0);
 472         if (result < 0) {
 473                 printk("smb_request: send error = %d\n", result);
 474         }
 475         else {
 476                 result = smb_receive(server, sock);
 477         }
 478 
 479         /* read/write errors are handled by errno */
 480         current->signal &= ~_S(SIGPIPE);
 481 
 482         current->blocked = old_mask;
 483         set_fs(fs);
 484 
 485         if ((result2 = smb_catch_keepalive(server)) < 0) {
 486                 result = result2;
 487         }
 488 
 489 #if 0
 490         server->lock = 0;
 491         wake_up(&server->wait);
 492 #endif
 493 
 494         if (result < 0) {
 495                 server->state = CONN_INVALID;
 496                 smb_invalidate_all_inodes(server);
 497         }
 498         
 499         DDPRINTK("smb_request: result = %d\n", result);
 500 
 501         return result;
 502 }
 503 
 504 /*
 505  * This is not really a trans2 request, we assume that you only have
 506  * one packet to send.
 507  */ 
 508 int
 509 smb_trans2_request(struct smb_server *server,
     /* [previous][next][first][last][top][bottom][index][help] */
 510                    int *data_len, int *param_len,
 511                    char **data, char **param)
 512 {
 513         unsigned long old_mask;
 514         unsigned short fs;      /* We fool the kernel to believe
 515                                    we call from user space. */
 516         int len, result, result2;
 517 
 518         struct socket *sock = server_sock(server);
 519         unsigned char *buffer = (server == NULL) ? NULL : server->packet;
 520 
 521         if ((sock == NULL) || (buffer == NULL)) {
 522                 printk("smb_trans2_request: Bad server!\n");
 523                 return -EBADF;
 524         }
 525 
 526         if (server->state != CONN_VALID)
 527                 return -EIO;
 528                 
 529 #if 0
 530         while (server->lock)
 531                 sleep_on(&server->wait);
 532         server->lock = 1;
 533 #endif
 534 
 535         if ((result = smb_dont_catch_keepalive(server)) != 0) {
 536                 server->state = CONN_INVALID;
 537                 smb_invalidate_all_inodes(server);
 538                 return result;
 539         }
 540 
 541         len = smb_len(buffer) + 4;
 542 
 543         DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
 544 
 545         old_mask = current->blocked;
 546         current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
 547         fs = get_fs();
 548         set_fs(get_ds());
 549 
 550         result = sock->ops->send(sock, (void *)buffer, len, 0, 0);
 551         if (result < 0) {
 552                 printk("smb_trans2_request: send error = %d\n", result);
 553         }
 554         else {
 555                 result = smb_receive_trans2(server, sock,
 556                                             data_len, param_len,
 557                                             data, param);
 558         }
 559 
 560         /* read/write errors are handled by errno */
 561         current->signal &= ~_S(SIGPIPE);
 562 
 563         current->blocked = old_mask;
 564         set_fs(fs);
 565 
 566         if ((result2 = smb_catch_keepalive(server)) < 0) {
 567                 result = result2;
 568         }
 569 
 570 #if 0
 571         server->lock = 0;
 572         wake_up(&server->wait);
 573 #endif
 574 
 575         if (result < 0) {
 576                 server->state = CONN_INVALID;
 577                 smb_invalidate_all_inodes(server);
 578         }
 579         
 580         DDPRINTK("smb_trans2_request: result = %d\n", result);
 581 
 582         return result;
 583 }
 584 
 585 /*
 586  * Overrides for Emacs so that we follow Linus's tabbing style.
 587  * Emacs will notice this stuff at the end of the file and automatically
 588  * adjust the settings for this buffer only.  This must remain at the end
 589  * of the file.
 590  * ---------------------------------------------------------------------------
 591  * Local variables:
 592  * c-indent-level: 8
 593  * c-brace-imaginary-offset: 0
 594  * c-brace-offset: -8
 595  * c-argdecl-indent: 8
 596  * c-label-offset: -8
 597  * c-continued-statement-offset: 8
 598  * c-continued-brace-offset: 0
 599  * End:
 600  */

/* [previous][next][first][last][top][bottom][index][help] */