linux-old/fs/smbfs/sock.c
<<
>>
Prefs
   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/sched.h>
  11#include <linux/errno.h>
  12#include <linux/socket.h>
  13#include <linux/fcntl.h>
  14#include <linux/file.h>
  15#include <linux/poll.h>
  16#include <linux/in.h>
  17#include <linux/net.h>
  18#include <linux/mm.h>
  19#include <linux/netdevice.h>
  20#include <linux/smp_lock.h>
  21#include <net/scm.h>
  22#include <net/ip.h>
  23
  24#include <linux/smb_fs.h>
  25#include <linux/smb.h>
  26#include <linux/smbno.h>
  27
  28#include <asm/uaccess.h>
  29
  30#include "smb_debug.h"
  31#include "proto.h"
  32
  33
  34static int
  35_recvfrom(struct socket *socket, unsigned char *ubuf, int size,
  36          unsigned flags)
  37{
  38        struct iovec iov;
  39        struct msghdr msg;
  40        struct scm_cookie scm;
  41
  42        msg.msg_name = NULL;
  43        msg.msg_namelen = 0;
  44        msg.msg_iov = &iov;
  45        msg.msg_iovlen = 1;
  46        msg.msg_control = NULL;
  47        iov.iov_base = ubuf;
  48        iov.iov_len = size;
  49        
  50        memset(&scm, 0,sizeof(scm));
  51        size=socket->ops->recvmsg(socket, &msg, size, flags, &scm);
  52        if(size>=0)
  53                scm_recv(socket,&msg,&scm,flags);
  54        return size;
  55}
  56
  57static int
  58_send(struct socket *socket, const void *buff, int len)
  59{
  60        struct iovec iov;
  61        struct msghdr msg;
  62        struct scm_cookie scm;
  63        int err;
  64
  65        msg.msg_name = NULL;
  66        msg.msg_namelen = 0;
  67        msg.msg_iov = &iov;
  68        msg.msg_iovlen = 1;
  69        msg.msg_control = NULL;
  70        msg.msg_controllen = 0;
  71        
  72        iov.iov_base = (void *)buff;
  73        iov.iov_len = len;
  74
  75        msg.msg_flags = 0;
  76
  77        err = scm_send(socket, &msg, &scm);
  78        if (err >= 0)
  79        {
  80                err = socket->ops->sendmsg(socket, &msg, len, &scm);
  81                scm_destroy(&scm);
  82        }
  83        return err;
  84}
  85
  86struct data_callback {
  87        struct tq_struct cb;
  88        struct sock *sk;
  89};
  90/*
  91 * N.B. What happens if we're in here when the socket closes??
  92 */
  93static void
  94found_data(struct sock *sk)
  95{
  96        /*
  97         * FIXME: copied from sock_def_readable, it should be a call to
  98         * server->data_ready() -- manfreds@colorfullife.com
  99         */
 100        read_lock(&sk->callback_lock);
 101        if(!sk->dead) {
 102                wake_up_interruptible(sk->sleep);
 103                sock_wake_async(sk->socket,1,POLL_IN);
 104        }
 105        read_unlock(&sk->callback_lock);
 106}
 107
 108static void
 109smb_data_callback(void* ptr)
 110{
 111        struct data_callback* job=ptr;
 112        struct socket *socket = job->sk->socket;
 113        unsigned char peek_buf[4];
 114        int result = 0;
 115        mm_segment_t fs;
 116        int count = 100;   /* this is a lot, we should have some data waiting */
 117        int found = 0;
 118
 119        fs = get_fs();
 120        set_fs(get_ds());
 121
 122        lock_kernel();
 123        while (count-- > 0) {
 124                peek_buf[0] = 0;
 125
 126                result = -EIO;
 127                if (job->sk->dead) {
 128                        PARANOIA("sock dead!\n");
 129                        break;
 130                }
 131
 132                result = _recvfrom(socket, (void *) peek_buf, 1,
 133                                   MSG_PEEK | MSG_DONTWAIT);
 134                if (result < 0)
 135                        break;
 136                if (peek_buf[0] != 0x85)
 137                        break;
 138
 139                /* got SESSION KEEP ALIVE */
 140                result = _recvfrom(socket, (void *) peek_buf, 4,
 141                                   MSG_DONTWAIT);
 142
 143                DEBUG1("got SESSION KEEPALIVE\n");
 144
 145                if (result < 0)
 146                        break;
 147                found = 1;
 148        }
 149        unlock_kernel();
 150        set_fs(fs);
 151
 152        DEBUG1("found=%d, count=%d, result=%d\n", found, count, result);
 153        if (found)
 154                found_data(job->sk);
 155        smb_kfree(ptr);
 156}
 157
 158static void
 159smb_data_ready(struct sock *sk, int len)
 160{
 161        struct data_callback* job;
 162        job = smb_kmalloc(sizeof(struct data_callback),GFP_ATOMIC);
 163        if(job == 0) {
 164                printk("smb_data_ready: lost SESSION KEEPALIVE due to OOM.\n");
 165                found_data(sk);
 166                return;
 167        }
 168        INIT_LIST_HEAD(&job->cb.list);
 169        job->cb.sync = 0;
 170        job->cb.routine = smb_data_callback;
 171        job->cb.data = job;
 172        job->sk = sk;
 173        schedule_task(&job->cb);
 174}
 175
 176int
 177smb_valid_socket(struct inode * inode)
 178{
 179        return (inode && S_ISSOCK(inode->i_mode) && 
 180                inode->u.socket_i.type == SOCK_STREAM);
 181}
 182
 183static struct socket *
 184server_sock(struct smb_sb_info *server)
 185{
 186        struct file *file;
 187
 188        if (server && (file = server->sock_file))
 189        {
 190#ifdef SMBFS_PARANOIA
 191                if (!smb_valid_socket(file->f_dentry->d_inode))
 192                        PARANOIA("bad socket!\n");
 193#endif
 194                return &file->f_dentry->d_inode->u.socket_i;
 195        }
 196        return NULL;
 197}
 198
 199int
 200smb_catch_keepalive(struct smb_sb_info *server)
 201{
 202        struct socket *socket;
 203        struct sock *sk;
 204        void *data_ready;
 205        int error;
 206
 207        error = -EINVAL;
 208        socket = server_sock(server);
 209        if (!socket)
 210        {
 211                printk(KERN_DEBUG "smb_catch_keepalive: did not get valid server!\n");
 212                server->data_ready = NULL;
 213                goto out;
 214        }
 215
 216        sk = socket->sk;
 217        if (sk == NULL)
 218        {
 219                DEBUG1("sk == NULL");
 220                server->data_ready = NULL;
 221                goto out;
 222        }
 223        DEBUG1("sk->d_r = %x, server->d_r = %x\n",
 224                 (unsigned int) (sk->data_ready),
 225                 (unsigned int) (server->data_ready));
 226
 227        /*
 228         * Install the callback atomically to avoid races ...
 229         */
 230        data_ready = xchg(&sk->data_ready, smb_data_ready);
 231        if (data_ready != smb_data_ready) {
 232                server->data_ready = data_ready;
 233                error = 0;
 234        } else
 235                printk(KERN_ERR "smb_catch_keepalive: already done\n");
 236out:
 237        return error;
 238}
 239
 240int
 241smb_dont_catch_keepalive(struct smb_sb_info *server)
 242{
 243        struct socket *socket;
 244        struct sock *sk;
 245        void * data_ready;
 246        int error;
 247
 248        error = -EINVAL;
 249        socket = server_sock(server);
 250        if (!socket)
 251        {
 252                printk(KERN_DEBUG "smb_dont_catch_keepalive: did not get valid server!\n");
 253                goto out;
 254        }
 255
 256        sk = socket->sk;
 257        if (sk == NULL)
 258        {
 259                DEBUG1("sk == NULL");
 260                goto out;
 261        }
 262
 263        /* Is this really an error?? */
 264        if (server->data_ready == NULL)
 265        {
 266                printk(KERN_DEBUG "smb_dont_catch_keepalive: "
 267                       "server->data_ready == NULL\n");
 268                goto out;
 269        }
 270        DEBUG1("smb_dont_catch_keepalive: sk->d_r = %x, server->d_r = %x\n",
 271               (unsigned int) (sk->data_ready),
 272               (unsigned int) (server->data_ready));
 273
 274        /*
 275         * Restore the original callback atomically to avoid races ...
 276         */
 277        data_ready = xchg(&sk->data_ready, server->data_ready);
 278        server->data_ready = NULL;
 279        if (data_ready != smb_data_ready)
 280        {
 281                printk(KERN_ERR "smb_dont_catch_keepalive: "
 282                       "sk->data_ready != smb_data_ready\n");
 283        }
 284        error = 0;
 285out:
 286        return error;
 287}
 288
 289/*
 290 * Called with the server locked.
 291 */
 292void
 293smb_close_socket(struct smb_sb_info *server)
 294{
 295        struct file * file = server->sock_file;
 296
 297        if (file)
 298        {
 299                VERBOSE("closing socket %p\n", server_sock(server));
 300#ifdef SMBFS_PARANOIA
 301                if (server_sock(server)->sk->data_ready == smb_data_ready)
 302                        PARANOIA("still catching keepalives!\n");
 303#endif
 304                server->sock_file = NULL;
 305                fput(file);
 306        }
 307}
 308
 309/*
 310 * Poll the server->socket to allow receives to time out.
 311 * returns 0 when ok to continue, <0 on errors.
 312 */
 313static int
 314smb_receive_poll(struct smb_sb_info *server)
 315{
 316        struct file *file = server->sock_file;
 317        poll_table wait_table;
 318        int result = 0;
 319        int timeout = server->mnt->timeo * HZ;
 320        int mask;
 321
 322        for (;;) {
 323                poll_initwait(&wait_table);
 324                set_current_state(TASK_INTERRUPTIBLE);
 325
 326                mask = file->f_op->poll(file, &wait_table);
 327                if (mask & POLLIN) {
 328                        poll_freewait(&wait_table);
 329                        current->state = TASK_RUNNING;
 330                        break;
 331                }
 332
 333                timeout = schedule_timeout(timeout);
 334                poll_freewait(&wait_table);
 335                set_current_state(TASK_RUNNING);
 336
 337                if (wait_table.error) {
 338                        result = wait_table.error;
 339                        break;
 340                }
 341
 342                if (signal_pending(current)) {
 343                        /* we got a signal (which?) tell the caller to
 344                           try again (on all signals?). */
 345                        DEBUG1("got signal_pending()\n");
 346                        result = -ERESTARTSYS;
 347                        break;
 348                }
 349                if (!timeout) {
 350                        printk(KERN_WARNING "SMB server not responding\n");
 351                        result = -EIO;
 352                        break;
 353                }
 354        }
 355        return result;
 356}
 357
 358static int
 359smb_send_raw(struct socket *socket, unsigned char *source, int length)
 360{
 361        int result;
 362        int already_sent = 0;
 363
 364        while (already_sent < length)
 365        {
 366                result = _send(socket,
 367                               (void *) (source + already_sent),
 368                               length - already_sent);
 369
 370                if (result == 0)
 371                {
 372                        return -EIO;
 373                }
 374                if (result < 0)
 375                {
 376                        DEBUG1("smb_send_raw: sendto error = %d\n", -result);
 377                        return result;
 378                }
 379                already_sent += result;
 380        }
 381        return already_sent;
 382}
 383
 384static int
 385smb_receive_raw(struct smb_sb_info *server, unsigned char *target, int length)
 386{
 387        int result;
 388        int already_read = 0;
 389        struct socket *socket = server_sock(server);
 390
 391        while (already_read < length)
 392        {
 393                result = smb_receive_poll(server);
 394                if (result < 0) {
 395                        DEBUG1("poll error = %d\n", -result);
 396                        return result;
 397                }
 398                result = _recvfrom(socket,
 399                                   (void *) (target + already_read),
 400                                   length - already_read, 0);
 401
 402                if (result == 0)
 403                {
 404                        return -EIO;
 405                }
 406                if (result < 0)
 407                {
 408                        DEBUG1("recvfrom error = %d\n", -result);
 409                        return result;
 410                }
 411                already_read += result;
 412        }
 413        return already_read;
 414}
 415
 416static int
 417smb_get_length(struct smb_sb_info *server, unsigned char *header)
 418{
 419        int result;
 420        unsigned char peek_buf[4];
 421        mm_segment_t fs;
 422
 423      re_recv:
 424        fs = get_fs();
 425        set_fs(get_ds());
 426        result = smb_receive_raw(server, peek_buf, 4);
 427        set_fs(fs);
 428
 429        if (result < 0)
 430        {
 431                PARANOIA("recv error = %d\n", -result);
 432                return result;
 433        }
 434        switch (peek_buf[0])
 435        {
 436        case 0x00:
 437        case 0x82:
 438                break;
 439
 440        case 0x85:
 441                DEBUG1("Got SESSION KEEP ALIVE\n");
 442                goto re_recv;
 443
 444        default:
 445                PARANOIA("Invalid NBT packet, code=%x\n", peek_buf[0]);
 446                return -EIO;
 447        }
 448
 449        if (header != NULL)
 450        {
 451                memcpy(header, peek_buf, 4);
 452        }
 453        /* The length in the RFC NB header is the raw data length */
 454        return smb_len(peek_buf);
 455}
 456
 457/*
 458 * Since we allocate memory in increments of PAGE_SIZE,
 459 * round up the packet length to the next multiple.
 460 */
 461int
 462smb_round_length(int len)
 463{
 464        return (len + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
 465}
 466 
 467/*
 468 * smb_receive
 469 * fs points to the correct segment
 470 */
 471static int
 472smb_receive(struct smb_sb_info *server)
 473{
 474        unsigned char * packet = server->packet;
 475        int len, result;
 476        unsigned char peek_buf[4];
 477
 478        result = smb_get_length(server, peek_buf);
 479        if (result < 0)
 480                goto out;
 481        len = result;
 482        /*
 483         * Some servers do not respect our max_xmit and send
 484         * larger packets.  Try to allocate a new packet,
 485         * but don't free the old one unless we succeed.
 486         */
 487        if (len + 4 > server->packet_size)
 488        {
 489                int new_len = smb_round_length(len + 4);
 490
 491                result = -ENOMEM;
 492                packet = smb_vmalloc(new_len);
 493                if (packet == NULL)
 494                        goto out;
 495                smb_vfree(server->packet);
 496                server->packet = packet;
 497                server->packet_size = new_len;
 498        }
 499        memcpy(packet, peek_buf, 4);
 500        result = smb_receive_raw(server, packet + 4, len);
 501        if (result < 0)
 502        {
 503                VERBOSE("receive error: %d\n", result);
 504                goto out;
 505        }
 506        server->rcls = *(packet + smb_rcls);
 507        server->err  = WVAL(packet, smb_err);
 508
 509#ifdef SMBFS_DEBUG_VERBOSE
 510        if (server->rcls != 0)
 511                VERBOSE("rcls=%d, err=%d\n", server->rcls, server->err);
 512#endif
 513out:
 514        return result;
 515}
 516
 517/*
 518 * This routine checks first for "fast track" processing, as most
 519 * packets won't need to be copied. Otherwise, it allocates a new
 520 * packet to hold the incoming data.
 521 *
 522 * Note that the final server packet must be the larger of the two;
 523 * server packets aren't allowed to shrink.
 524 */
 525static int
 526smb_receive_trans2(struct smb_sb_info *server,
 527                   int *ldata, unsigned char **data,
 528                   int *lparm, unsigned char **parm)
 529{
 530        unsigned char *inbuf, *base, *rcv_buf = NULL;
 531        unsigned int parm_disp, parm_offset, parm_count, parm_tot, parm_len = 0;
 532        unsigned int data_disp, data_offset, data_count, data_tot, data_len = 0;
 533        unsigned int total_p = 0, total_d = 0, buf_len = 0;
 534        int result;
 535
 536        while (1) {
 537                result = smb_receive(server);
 538                if (result < 0)
 539                        goto out;
 540                inbuf = server->packet;
 541                if (server->rcls != 0) {
 542                        *parm = *data = inbuf;
 543                        *ldata = *lparm = 0;
 544                        goto out;
 545                }
 546                /*
 547                 * Extract the control data from the packet.
 548                 */
 549                data_tot    = WVAL(inbuf, smb_tdrcnt);
 550                parm_tot    = WVAL(inbuf, smb_tprcnt);
 551                parm_disp   = WVAL(inbuf, smb_prdisp);
 552                parm_offset = WVAL(inbuf, smb_proff);
 553                parm_count  = WVAL(inbuf, smb_prcnt);
 554                data_disp   = WVAL(inbuf, smb_drdisp);
 555                data_offset = WVAL(inbuf, smb_droff);
 556                data_count  = WVAL(inbuf, smb_drcnt);
 557                base = smb_base(inbuf);
 558
 559                /*
 560                 * Assume success and increment lengths.
 561                 */
 562                parm_len += parm_count;
 563                data_len += data_count;
 564
 565                if (!rcv_buf) {
 566                        /*
 567                         * Check for fast track processing ... just this packet.
 568                         */
 569                        if (parm_count == parm_tot && data_count == data_tot) {
 570                                VERBOSE("fast track, parm=%u %u %u, data=%u %u %u\n",
 571                                        parm_disp, parm_offset, parm_count,
 572                                        data_disp, data_offset, data_count);
 573                                *parm  = base + parm_offset;
 574                                if (*parm - inbuf + parm_tot > server->packet_size)
 575                                        goto out_bad_parm;
 576                                *data  = base + data_offset;
 577                                if (*data - inbuf + data_tot > server->packet_size)
 578                                        goto out_bad_data;
 579                                goto success;
 580                        }
 581
 582                        /*
 583                         * Save the total parameter and data length.
 584                         */
 585                        total_d = data_tot;
 586                        total_p = parm_tot;
 587
 588                        buf_len = total_d + total_p;
 589                        if (server->packet_size > buf_len)
 590                                buf_len = server->packet_size;
 591                        buf_len = smb_round_length(buf_len);
 592                        if (buf_len > SMB_MAX_PACKET_SIZE)
 593                                goto out_too_long;
 594
 595                        rcv_buf = smb_vmalloc(buf_len);
 596                        if (!rcv_buf)
 597                                goto out_no_mem;
 598                        memset(rcv_buf, 0, buf_len);
 599                        
 600                        *parm = rcv_buf;
 601                        *data = rcv_buf + total_p;
 602                } else if (data_tot > total_d || parm_tot > total_p)
 603                        goto out_data_grew;
 604
 605                if (parm_disp + parm_count > total_p)
 606                        goto out_bad_parm;
 607                if (parm_offset + parm_count > server->packet_size)     
 608                        goto out_bad_parm;
 609                if (data_disp + data_count > total_d)
 610                        goto out_bad_data;
 611                if (data_offset + data_count > server->packet_size)     
 612                        goto out_bad_data;
 613                memcpy(*parm + parm_disp, base + parm_offset, parm_count);
 614                memcpy(*data + data_disp, base + data_offset, data_count);
 615
 616                PARANOIA("copied, parm=%u of %u, data=%u of %u\n",
 617                         parm_len, parm_tot, data_len, data_tot);
 618
 619                /*
 620                 * Check whether we've received all of the data. Note that
 621                 * we use the packet totals -- total lengths might shrink!
 622                 */
 623                if (data_len >= data_tot && parm_len >= parm_tot) {
 624                        data_len = data_tot;
 625                        parm_len = parm_tot;
 626                        break;
 627                }
 628        }
 629
 630        /*
 631         * Install the new packet.  Note that it's possible, though
 632         * unlikely, that the new packet could be smaller than the
 633         * old one, in which case we just copy the data.
 634         */
 635        inbuf = server->packet;
 636        if (buf_len >= server->packet_size) {
 637                server->packet_size = buf_len;
 638                server->packet = rcv_buf;
 639                rcv_buf = inbuf;
 640        } else {
 641                if (parm_len + data_len > buf_len)
 642                        goto out_data_grew;
 643
 644                PARANOIA("copying data, old size=%d, new size=%u\n",
 645                         server->packet_size, buf_len);
 646                memcpy(inbuf, rcv_buf, parm_len + data_len);
 647        }
 648
 649success:
 650        *ldata = data_len;
 651        *lparm = parm_len;
 652out:
 653        if (rcv_buf)
 654                smb_vfree(rcv_buf);
 655        return result;
 656
 657out_no_mem:
 658        PARANOIA("couldn't allocate data area\n");
 659        result = -ENOMEM;
 660        goto out;
 661out_too_long:
 662        printk(KERN_ERR "smb_receive_trans2: data/param too long, data=%d, parm=%d\n",
 663                data_tot, parm_tot);
 664        goto out_error;
 665out_data_grew:
 666        printk(KERN_ERR "smb_receive_trans2: data/params grew!\n");
 667        goto out_error;
 668out_bad_parm:
 669        printk(KERN_ERR "smb_receive_trans2: invalid parms, disp=%d, cnt=%d, tot=%d\n",
 670                parm_disp, parm_count, parm_tot);
 671        goto out_error;
 672out_bad_data:
 673        printk(KERN_ERR "smb_receive_trans2: invalid data, disp=%d, cnt=%d, tot=%d\n",
 674                data_disp, data_count, data_tot);
 675out_error:
 676        result = -EIO;
 677        goto out;
 678}
 679
 680/*
 681 * Called with the server locked
 682 */
 683int
 684smb_request(struct smb_sb_info *server)
 685{
 686        unsigned long flags, sigpipe;
 687        mm_segment_t fs;
 688        sigset_t old_set;
 689        int len, result;
 690        unsigned char *buffer;
 691
 692        result = -EBADF;
 693        buffer = server->packet;
 694        if (!buffer)
 695                goto bad_no_packet;
 696
 697        result = -EIO;
 698        if (server->state != CONN_VALID)
 699                goto bad_no_conn;
 700
 701        if ((result = smb_dont_catch_keepalive(server)) != 0)
 702                goto bad_conn;
 703
 704        len = smb_len(buffer) + 4;
 705        DEBUG1("len = %d cmd = 0x%X\n", len, buffer[8]);
 706
 707        spin_lock_irqsave(&current->sigmask_lock, flags);
 708        sigpipe = sigismember(&current->pending.signal, SIGPIPE);
 709        old_set = current->blocked;
 710        siginitsetinv(&current->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP));
 711        recalc_sigpending(current);
 712        spin_unlock_irqrestore(&current->sigmask_lock, flags);
 713
 714        fs = get_fs();
 715        set_fs(get_ds());
 716
 717        result = smb_send_raw(server_sock(server), (void *) buffer, len);
 718        if (result > 0)
 719        {
 720                result = smb_receive(server);
 721        }
 722
 723        /* read/write errors are handled by errno */
 724        spin_lock_irqsave(&current->sigmask_lock, flags);
 725        if (result == -EPIPE && !sigpipe)
 726                sigdelset(&current->pending.signal, SIGPIPE);
 727        current->blocked = old_set;
 728        recalc_sigpending(current);
 729        spin_unlock_irqrestore(&current->sigmask_lock, flags);
 730
 731        set_fs(fs);
 732
 733        if (result >= 0)
 734        {
 735                int result2 = smb_catch_keepalive(server);
 736                if (result2 < 0)
 737                {
 738                        printk(KERN_ERR "smb_request: catch keepalive failed\n");
 739                        result = result2;
 740                }
 741        }
 742        if (result < 0)
 743                goto bad_conn;
 744        /*
 745         * Check for fatal server errors ...
 746         */
 747        if (server->rcls) {
 748                int error = smb_errno(server);
 749                if (error == -EBADSLT) {
 750                        printk(KERN_ERR "smb_request: tree ID invalid\n");
 751                        result = error;
 752                        goto bad_conn;
 753                }
 754        }
 755
 756out:
 757        DEBUG1("result = %d\n", result);
 758        return result;
 759        
 760bad_conn:
 761        PARANOIA("result %d, setting invalid\n", result);
 762        server->state = CONN_INVALID;
 763        smb_invalidate_inodes(server);
 764        goto out;               
 765bad_no_packet:
 766        printk(KERN_ERR "smb_request: no packet!\n");
 767        goto out;
 768bad_no_conn:
 769        printk(KERN_ERR "smb_request: connection %d not valid!\n",
 770               server->state);
 771        goto out;
 772}
 773
 774#define ROUND_UP(x) (((x)+3) & ~3)
 775static int
 776smb_send_trans2(struct smb_sb_info *server, __u16 trans2_command,
 777                int ldata, unsigned char *data,
 778                int lparam, unsigned char *param)
 779{
 780        struct socket *sock = server_sock(server);
 781        struct scm_cookie scm;
 782        int err;
 783        int mparam, mdata;
 784
 785        /* I know the following is very ugly, but I want to build the
 786           smb packet as efficiently as possible. */
 787
 788        const int smb_parameters = 15;
 789        const int oparam =
 790                ROUND_UP(SMB_HEADER_LEN + 2 * smb_parameters + 2 + 3);
 791        const int odata =
 792                ROUND_UP(oparam + lparam);
 793        const int bcc =
 794                odata + ldata - (SMB_HEADER_LEN + 2 * smb_parameters + 2);
 795        const int packet_length =
 796                SMB_HEADER_LEN + 2 * smb_parameters + bcc + 2;
 797
 798        unsigned char padding[4] =
 799        {0,};
 800        char *p;
 801
 802        struct iovec iov[4];
 803        struct msghdr msg;
 804
 805        /* FIXME! this test needs to include SMB overhead too, I think ... */
 806        if ((bcc + oparam) > server->opt.max_xmit)
 807                return -ENOMEM;
 808        p = smb_setup_header(server, SMBtrans2, smb_parameters, bcc);
 809
 810        /*
 811         * max parameters + max data + max setup == max_xmit to make NT4 happy
 812         * and not abort the transfer or split into multiple responses.
 813         *
 814         * -100 is to make room for headers, which OS/2 seems to include in the
 815         * size calculation while NT4 does not?
 816         */
 817        mparam = SMB_TRANS2_MAX_PARAM;
 818        mdata = server->opt.max_xmit - mparam - 100;
 819        if (mdata < 1024) {
 820                mdata = 1024;
 821                mparam = 20;
 822        }
 823
 824        WSET(server->packet, smb_tpscnt, lparam);
 825        WSET(server->packet, smb_tdscnt, ldata);
 826        WSET(server->packet, smb_mprcnt, mparam);
 827        WSET(server->packet, smb_mdrcnt, mdata);
 828        WSET(server->packet, smb_msrcnt, 0);    /* max setup always 0 ? */
 829        WSET(server->packet, smb_flags, 0);
 830        DSET(server->packet, smb_timeout, 0);
 831        WSET(server->packet, smb_pscnt, lparam);
 832        WSET(server->packet, smb_psoff, oparam - 4);
 833        WSET(server->packet, smb_dscnt, ldata);
 834        WSET(server->packet, smb_dsoff, odata - 4);
 835        WSET(server->packet, smb_suwcnt, 1);
 836        WSET(server->packet, smb_setup0, trans2_command);
 837        *p++ = 0;               /* null smb_name for trans2 */
 838        *p++ = 'D';             /* this was added because OS/2 does it */
 839        *p++ = ' ';
 840
 841
 842        msg.msg_name = NULL;
 843        msg.msg_namelen = 0;
 844        msg.msg_control = NULL;
 845        msg.msg_controllen = 0;
 846        msg.msg_iov = iov;
 847        msg.msg_iovlen = 4;
 848        msg.msg_flags = 0;
 849        
 850        iov[0].iov_base = (void *) server->packet;
 851        iov[0].iov_len = oparam;
 852        iov[1].iov_base = (param == NULL) ? padding : param;
 853        iov[1].iov_len = lparam;
 854        iov[2].iov_base = padding;
 855        iov[2].iov_len = odata - oparam - lparam;
 856        iov[3].iov_base = (data == NULL) ? padding : data;
 857        iov[3].iov_len = ldata;
 858
 859        err = scm_send(sock, &msg, &scm);
 860        if (err >= 0) {
 861                err = sock->ops->sendmsg(sock, &msg, packet_length, &scm);
 862                scm_destroy(&scm);
 863        }
 864        return err;
 865}
 866
 867/*
 868 * This is not really a trans2 request, we assume that you only have
 869 * one packet to send.
 870 */
 871int
 872smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
 873                   int ldata, unsigned char *data,
 874                   int lparam, unsigned char *param,
 875                   int *lrdata, unsigned char **rdata,
 876                   int *lrparam, unsigned char **rparam)
 877{
 878        sigset_t old_set;
 879        unsigned long flags, sigpipe;
 880        mm_segment_t fs;
 881        int result;
 882
 883        DEBUG1("com=%d, ld=%d, lp=%d\n", trans2_command, ldata, lparam);
 884
 885        /*
 886         * These are initialized in smb_request_ok, but not here??
 887         */
 888        server->rcls = 0;
 889        server->err = 0;
 890
 891        result = -EIO;
 892        if (server->state != CONN_VALID)
 893                goto out;
 894
 895        if ((result = smb_dont_catch_keepalive(server)) != 0)
 896                goto bad_conn;
 897
 898        spin_lock_irqsave(&current->sigmask_lock, flags);
 899        sigpipe = sigismember(&current->pending.signal, SIGPIPE);
 900        old_set = current->blocked;
 901        siginitsetinv(&current->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP));
 902        recalc_sigpending(current);
 903        spin_unlock_irqrestore(&current->sigmask_lock, flags);
 904
 905        fs = get_fs();
 906        set_fs(get_ds());
 907
 908        result = smb_send_trans2(server, trans2_command,
 909                                 ldata, data, lparam, param);
 910        if (result >= 0)
 911        {
 912                result = smb_receive_trans2(server,
 913                                            lrdata, rdata, lrparam, rparam);
 914        }
 915
 916        /* read/write errors are handled by errno */
 917        spin_lock_irqsave(&current->sigmask_lock, flags);
 918        if (result == -EPIPE && !sigpipe)
 919                sigdelset(&current->pending.signal, SIGPIPE);
 920        current->blocked = old_set;
 921        recalc_sigpending(current);
 922        spin_unlock_irqrestore(&current->sigmask_lock, flags);
 923
 924        set_fs(fs);
 925
 926        if (result >= 0)
 927        {
 928                int result2 = smb_catch_keepalive(server);
 929                if (result2 < 0)
 930                {
 931                        result = result2;
 932                }
 933        }
 934        if (result < 0)
 935                goto bad_conn;
 936        /*
 937         * Check for fatal server errors ...
 938         */
 939        if (server->rcls) {
 940                int error = smb_errno(server);
 941                if (error == -EBADSLT) {
 942                        printk(KERN_ERR "smb_request: tree ID invalid\n");
 943                        result = error;
 944                        goto bad_conn;
 945                }
 946        }
 947
 948out:
 949        return result;
 950
 951bad_conn:
 952        PARANOIA("result=%d, setting invalid\n", result);
 953        server->state = CONN_INVALID;
 954        smb_invalidate_inodes(server);
 955        goto out;
 956}
 957
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.