CTC++ Coverage Report - Execution Profile    #857/1532

Files Summary | Functions Summary | Execution Profile | Index | No Index
First | Previous | Next | Last


File: fs/cifs/connect.c
Instrumentation mode: function-decision-multicondition
TER: 0 % ( 0/1919)

Start/ End/    
True False - Line Source

  1 /*
  2  *   fs/cifs/connect.c
  3  *
  4  *   Copyright (C) International Business Machines  Corp., 2002,2005
  5  *   Author(s): Steve French (sfrench@us.ibm.com)
  6  *
  7  *   This library is free software; you can redistribute it and/or modify
  8  *   it under the terms of the GNU Lesser General Public License as published
  9  *   by the Free Software Foundation; either version 2.1 of the License, or
  10  *   (at your option) any later version.
  11  *
  12  *   This library is distributed in the hope that it will be useful,
  13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  15  *   the GNU Lesser General Public License for more details.
  16  *
  17  *   You should have received a copy of the GNU Lesser General Public License
  18  *   along with this library; if not, write to the Free Software
  19  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
  20  */
  21 #include <linux/fs.h>
  22 #include <linux/net.h>
  23 #include <linux/string.h>
  24 #include <linux/list.h>
  25 #include <linux/wait.h>
  26 #include <linux/ipv6.h>
  27 #include <linux/pagemap.h>
  28 #include <linux/ctype.h>
  29 #include <linux/utsname.h>
  30 #include <linux/mempool.h>
  31 #include <linux/delay.h>
  32 #include <linux/completion.h>
  33 #include <linux/pagevec.h>
  34 #include <asm/uaccess.h>
  35 #include <asm/processor.h>
  36 #include "cifspdu.h"
  37 #include "cifsglob.h"
  38 #include "cifsproto.h"
  39 #include "cifs_unicode.h"
  40 #include "cifs_debug.h"
  41 #include "cifs_fs_sb.h"
  42 #include "ntlmssp.h"
  43 #include "nterr.h"
  44 #include "rfc1002pdu.h"
  45 #include "cn_cifs.h"
  46 
  47 #define CIFS_PORT 445
  48 #define RFC1001_PORT 139
  49 
  50 static DECLARE_COMPLETION(cifsd_complete);
  51 
  52 extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
  53              unsigned char *p24);
  54 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
  55           unsigned char *p24);
  56 
  57 extern mempool_t *cifs_req_poolp;
  58 
  59 struct smb_vol {
  60    char *username;
  61    char *password;
  62    char *domainname;
  63    char *UNC;
  64    char *UNCip;
  65    char *in6_addr;  /* ipv6 address as human readable form of in6_addr */
  66    char *iocharset;  /* local code page for mapping to and from Unicode */
  67    char source_rfc1001_name[16]; /* netbios name of client */
  68    char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
  69    uid_t linux_uid;
  70    gid_t linux_gid;
  71    mode_t file_mode;
  72    mode_t dir_mode;
  73    unsigned rw:1;
  74    unsigned retry:1;
  75    unsigned intr:1;
  76    unsigned setuids:1;
  77    unsigned noperm:1;
  78    unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
  79    unsigned cifs_acl:1;
  80    unsigned no_xattr:1;   /* set if xattr (EA) support should be disabled*/
  81    unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
  82    unsigned direct_io:1;
  83    unsigned remap:1;   /* set to remap seven reserved chars in filenames */
  84    unsigned posix_paths:1;   /* unset to not ask for posix pathnames. */
  85    unsigned sfu_emul:1;
  86    unsigned krb5:1;
  87    unsigned ntlm:1;
  88    unsigned ntlmv2:1;
  89    unsigned nullauth:1; /* attempt to authenticate with null user */
  90    unsigned sign:1;
  91    unsigned seal:1;     /* encrypt */
  92    unsigned nocase;     /* request case insensitive filenames */
  93    unsigned nobrl;      /* disable sending byte range locks to srv */
  94    unsigned int rsize;
  95    unsigned int wsize;
  96    unsigned int sockopt;
  97    unsigned short int port;
  98 };
  99 
  100 static int ipv4_connect(struct sockaddr_in *psin_server, 
  101          struct socket **csocket,
  102          char * netb_name,
  103          char * server_netb_name);
  104 static int ipv6_connect(struct sockaddr_in6 *psin_server, 
  105          struct socket **csocket);
  106 
  107 
  108    /* 
  109     * cifs tcp session reconnection
  110     * 
  111     * mark tcp session as reconnecting so temporarily locked
  112     * mark all smb sessions as reconnecting for tcp session
  113     * reconnect tcp session
  114     * wake up waiters on reconnection? - (not needed currently)
  115     */
  116 
  117 int
 
- 118 cifs_reconnect(struct TCP_Server_Info *server)
  119 {
  120    int rc = 0;
  121    struct list_head *tmp;
  122    struct cifsSesInfo *ses;
  123    struct cifsTconInfo *tcon;
  124    struct mid_q_entry * mid_entry;
  125    
    126    spin_lock(&GlobalMid_Lock);
    126   do
- 126   do-while (0)
- 126 do-while (0)
- 127    if(server->tcpStatus == CifsExiting) {
  128       /* the demux thread will exit normally 
  129       next time through the loop */
    130       spin_unlock(&GlobalMid_Lock);
    130     do
- 130     do-while (0)
- 130   do-while (0)
 - 131       return rc;
    132    } else
  133       server->tcpStatus = CifsNeedReconnect;
    134    spin_unlock(&GlobalMid_Lock);
    134   do
- 134   do-while (0)
- 134 do-while (0)
  135    server->maxBuf = 0;
  136 
- 137    cFYI(1, ("Reconnecting tcp session"));
- 137   if (cifsFYI & 0x01)
  138 
  139    /* before reconnecting the tcp session, mark the smb session (uid)
  140       and the tid bad so they are not used until reconnected */
    141    read_lock(&GlobalSMBSeslock);
    141   do
- 141   do-while (0)
- 141 do-while (0)
- 142    list_for_each(tmp, &GlobalSMBSessionList) {
  143       ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
- 144       if (ses->server) {
- 145          if (ses->server == server) {
  146             ses->status = CifsNeedReconnect;
  147             ses->ipc_tid = 0;
  148          }
  149       }
  150       /* else tcp and smb sessions need reconnection */
  151    }
- 152    list_for_each(tmp, &GlobalTreeConnectionList) {
  153       tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
- 154       if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
 - 154     (T) && (T) && (T)
 - 154     (T) && (T) && (F)
 - 154     (T) && (F) && (_)
 - 154     (F) && (_) && (_)
  155          tcon->tidStatus = CifsNeedReconnect;
  156       }
  157    }
    158    read_unlock(&GlobalSMBSeslock);
    158   do
- 158   do-while (0)
- 158 do-while (0)
  159    /* do not want to be sending data on a socket we are freeing */
  160    down(&server->tcpSem); 
- 161    if(server->ssocket) {
- 162       cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
- 162     if (cifsFYI & 0x01)
  163          server->ssocket->flags));
  164       server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
- 165       cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
- 165     if (cifsFYI & 0x01)
  166          server->ssocket->flags));
  167       sock_release(server->ssocket);
  168       server->ssocket = NULL;
  169    }
  170 
    171    spin_lock(&GlobalMid_Lock);
    171   do
- 171   do-while (0)
- 171 do-while (0)
- 172    list_for_each(tmp, &server->pending_mid_q) {
  173       mid_entry = list_entry(tmp, struct
  174                mid_q_entry,
  175                qhead);
- 176       if(mid_entry) {
- 177          if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
  178             /* Mark other intransit requests as needing
  179                retry so we do not immediately mark the
  180                session bad again (ie after we reconnect
  181                below) as they timeout too */
  182             mid_entry->midState = MID_RETRY_NEEDED;
  183          }
  184       }
  185    }
    186    spin_unlock(&GlobalMid_Lock);
    186   do
- 186   do-while (0)
- 186 do-while (0)
  187    up(&server->tcpSem); 
  188 
- 189    while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
 - 189   (T) && (T)
 - 189   (T) && (F)
 - 189   (F) && (_)
  190    {
- 191       if(server->protocolType == IPV6) {
  192          rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
    193       } else {
  194          rc = ipv4_connect(&server->addr.sockAddr, 
  195                &server->ssocket,
  196                server->workstation_RFC1001_name,
  197                server->server_RFC1001_name);
  198       }
- 199       if(rc) {
- 200          cFYI(1,("reconnect error %d",rc));
- 200       if (cifsFYI & 0x01)
  201          msleep(3000);
    202       } else {
  203          atomic_inc(&tcpSesReconnectCount);
    204          spin_lock(&GlobalMid_Lock);
    204       do
- 204       do-while (0)
- 204     do-while (0)
- 205          if(server->tcpStatus != CifsExiting)
  206             server->tcpStatus = CifsGood;
  207          server->sequence_number = 0;
    208          spin_unlock(&GlobalMid_Lock);         
    208       do
- 208       do-while (0)
- 208     do-while (0)
  209    /*      atomic_set(&server->inFlight,0);*/
  210          wake_up(&server->response_q);
  211       }
  212    }
 - 213    return rc;
  214 }
  215 
  216 /* 
  217    return codes:
  218       0    not a transact2, or all data present
  219       >0    transact2 with that much data missing
  220       -EINVAL = invalid transact2
  221 
  222  */
 
- 223 static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
  224 {
  225    struct smb_t2_rsp * pSMBt;
  226         int total_data_size;
  227    int data_in_this_rsp;
  228    int remaining;
  229 
- 230    if(pSMB->Command != SMB_COM_TRANSACTION2)
 - 231       return 0;
  232 
  233         /* check for plausible wct, bcc and t2 data and parm sizes */
  234         /* check for parm and data offset going beyond end of smb */
- 235    if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
- 236       cFYI(1,("invalid transact2 word count"));
- 236     if (cifsFYI & 0x01)
 - 237       return -EINVAL;
  238    }
  239 
  240    pSMBt = (struct smb_t2_rsp *)pSMB;
  241 
  242    total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
  243    data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
  244 
  245    remaining = total_data_size - data_in_this_rsp;
  246 
- 247    if(remaining == 0)
 - 248       return 0;
- 249    else if(remaining < 0) {
- 250       cFYI(1,("total data %d smaller than data in frame %d",
- 250     if (cifsFYI & 0x01)
  251          total_data_size, data_in_this_rsp));
 - 252       return -EINVAL;
    253    } else {
- 254       cFYI(1,("missing %d bytes from transact2, check next response",
- 254     if (cifsFYI & 0x01)
  255          remaining));
- 256       if(total_data_size > maxBufSize) {
- 257          cERROR(1,("TotalDataSize %d is over maximum buffer %d",
- 257       if (cifsERROR)
  258             total_data_size,maxBufSize));
 - 259          return -EINVAL; 
  260       }
 - 261       return remaining;
  262    }
  263 }
  264 
 
- 265 static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
  266 {
  267    struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
  268    struct smb_t2_rsp *pSMBt  = (struct smb_t2_rsp *)pTargetSMB;
  269    int total_data_size;
  270    int total_in_buf;
  271    int remaining;
  272    int total_in_buf2;
  273    char * data_area_of_target;
  274    char * data_area_of_buf2;
  275    __u16 byte_count;
  276 
  277    total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
  278 
- 279    if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
- 280       cFYI(1,("total data sizes of primary and secondary t2 differ"));
- 280     if (cifsFYI & 0x01)
  281    }
  282 
  283    total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
  284 
  285    remaining = total_data_size - total_in_buf;
  286    
- 287    if(remaining < 0)
 - 288       return -EINVAL;
  289 
- 290    if(remaining == 0) /* nothing to do, ignore */
 - 291       return 0;
  292    
  293    total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
- 294    if(remaining < total_in_buf2) {
- 295       cFYI(1,("transact2 2nd response contains too much data"));
- 295     if (cifsFYI & 0x01)
  296    }
  297 
  298    /* find end of first SMB data area */
  299    data_area_of_target = (char *)&pSMBt->hdr.Protocol + 
  300             le16_to_cpu(pSMBt->t2_rsp.DataOffset);
  301    /* validate target area */
  302 
  303    data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
  304                                         le16_to_cpu(pSMB2->t2_rsp.DataOffset);
  305 
  306    data_area_of_target += total_in_buf;
  307 
  308    /* copy second buffer into end of first buffer */
  309    memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
  310    total_in_buf += total_in_buf2;
  311    pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
  312    byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
  313    byte_count += total_in_buf2;
  314    BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
  315 
  316    byte_count = pTargetSMB->smb_buf_length;
  317    byte_count += total_in_buf2;
  318 
  319    /* BB also add check that we are not beyond maximum buffer size */
  320       
  321    pTargetSMB->smb_buf_length = byte_count;
  322 
- 323    if(remaining == total_in_buf2) {
- 324       cFYI(1,("found the last secondary response"));
- 324     if (cifsFYI & 0x01)
 - 325       return 0; /* we are done */
    326    } else /* more responses to go */
 - 327       return 1;
  328 
  329 }
  330 
  331 static int
 
- 332 cifs_demultiplex_thread(struct TCP_Server_Info *server)
  333 {
  334    int length;
  335    unsigned int pdu_length, total_read;
  336    struct smb_hdr *smb_buffer = NULL;
  337    struct smb_hdr *bigbuf = NULL;
  338    struct smb_hdr *smallbuf = NULL;
  339    struct msghdr smb_msg;
  340    struct kvec iov;
  341    struct socket *csocket = server->ssocket;
  342    struct list_head *tmp;
  343    struct cifsSesInfo *ses;
  344    struct task_struct *task_to_wake = NULL;
  345    struct mid_q_entry *mid_entry;
  346    char temp;
  347    int isLargeBuf = FALSE;
  348    int isMultiRsp;
  349    int reconnect;
  350 
  351    daemonize("cifsd");
  352    allow_signal(SIGKILL);
  353    current->flags |= PF_MEMALLOC;
  354    server->tsk = current;   /* save process info to wake at shutdown */
- 355    cFYI(1, ("Demultiplex PID: %d", current->pid));
- 355   if (cifsFYI & 0x01)
    356    write_lock(&GlobalSMBSeslock); 
    356   do
- 356   do-while (0)
- 356 do-while (0)
  357    atomic_inc(&tcpSesAllocCount);
  358    length = tcpSesAllocCount.counter;
    359    write_unlock(&GlobalSMBSeslock);
    359   do
- 359   do-while (0)
- 359 do-while (0)
  360    complete(&cifsd_complete);
- 361    if(length  > 1) {
  362       mempool_resize(cifs_req_poolp,
  363          length + cifs_min_rcv,
  364          GFP_KERNEL);
  365    }
  366 
- 367    while (server->tcpStatus != CifsExiting) {
- 368       if (try_to_freeze())
 - 369          continue;
- 370       if (bigbuf == NULL) {
  371          bigbuf = cifs_buf_get();
- 372          if(bigbuf == NULL) {
- 373             cERROR(1,("No memory for large SMB response"));
- 373         if (cifsERROR)
  374             msleep(3000);
  375             /* retry will check if exiting */
 - 376             continue;
  377          }
- 378       } else if(isLargeBuf) {
  379          /* we are reusing a dirtry large buf, clear its start */
  380          memset(bigbuf, 0, sizeof (struct smb_hdr));
  381       }
  382 
- 383       if (smallbuf == NULL) {
  384          smallbuf = cifs_small_buf_get();
- 385          if(smallbuf == NULL) {
- 386             cERROR(1,("No memory for SMB response"));
- 386         if (cifsERROR)
  387             msleep(1000);
  388             /* retry will check if exiting */
 - 389             continue;
  390          }
  391          /* beginning of smb buffer is cleared in our buf_get */
    392       } else /* if existing small buf clear beginning */
  393          memset(smallbuf, 0, sizeof (struct smb_hdr));
  394 
  395       isLargeBuf = FALSE;
  396       isMultiRsp = FALSE;
  397       smb_buffer = smallbuf;
  398       iov.iov_base = smb_buffer;
  399       iov.iov_len = 4;
  400       smb_msg.msg_control = NULL;
  401       smb_msg.msg_controllen = 0;
  402       length =
  403           kernel_recvmsg(csocket, &smb_msg,
  404              &iov, 1, 4, 0 /* BB see socket.h flags */);
  405 
- 406       if(server->tcpStatus == CifsExiting) {
 - 407          break;
- 408       } else if (server->tcpStatus == CifsNeedReconnect) {
- 409          cFYI(1,("Reconnect after server stopped responding"));
- 409       if (cifsFYI & 0x01)
  410          cifs_reconnect(server);
- 411          cFYI(1,("call to reconnect done"));
- 411       if (cifsFYI & 0x01)
  412          csocket = server->ssocket;
 - 413          continue;
- 414       } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
 - 414     (T) || (_)
 - 414     (F) || (T)
 - 414     (F) || (F)
  415          msleep(1); /* minimum sleep to prevent looping
  416             allowing socket to clear and app threads to set
  417             tcpStatus CifsNeedReconnect if server hung */
 - 418          continue;
- 419       } else if (length <= 0) {
- 420          if(server->tcpStatus == CifsNew) {
- 421             cFYI(1,("tcp session abend after SMBnegprot"));
- 421         if (cifsFYI & 0x01)
  422             /* some servers kill the TCP session rather than
  423                returning an SMB negprot error, in which
  424                case reconnecting here is not going to help,
  425                and so simply return error to mount */
 - 426             break;
  427          }
- 428          if(length == -EINTR) { 
- 429             cFYI(1,("cifsd thread killed"));
- 429         if (cifsFYI & 0x01)
 - 430             break;
  431          }
- 432          cFYI(1,("Reconnect after unexpected peek error %d",
- 432       if (cifsFYI & 0x01)
  433             length));
  434          cifs_reconnect(server);
  435          csocket = server->ssocket;
  436          wake_up(&server->response_q);
 - 437          continue;
- 438       }&