[CIFS] Various minor bigendian fixes and sparse level 2 warning message fixes
[firefly-linux-kernel-4.4.55.git] / fs / cifs / connect.c
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 <asm/uaccess.h>
34 #include <asm/processor.h>
35 #include "cifspdu.h"
36 #include "cifsglob.h"
37 #include "cifsproto.h"
38 #include "cifs_unicode.h"
39 #include "cifs_debug.h"
40 #include "cifs_fs_sb.h"
41 #include "ntlmssp.h"
42 #include "nterr.h"
43 #include "rfc1002pdu.h"
44
45 #define CIFS_PORT 445
46 #define RFC1001_PORT 139
47
48 static DECLARE_COMPLETION(cifsd_complete);
49
50 extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
51                        unsigned char *p24);
52 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
53                          unsigned char *p24);
54
55 extern mempool_t *cifs_req_poolp;
56
57 struct smb_vol {
58         char *username;
59         char *password;
60         char *domainname;
61         char *UNC;
62         char *UNCip;
63         char *in6_addr;  /* ipv6 address as human readable form of in6_addr */
64         char *iocharset;  /* local code page for mapping to and from Unicode */
65         char source_rfc1001_name[16]; /* netbios name of client */
66         char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
67         uid_t linux_uid;
68         gid_t linux_gid;
69         mode_t file_mode;
70         mode_t dir_mode;
71         unsigned rw:1;
72         unsigned retry:1;
73         unsigned intr:1;
74         unsigned setuids:1;
75         unsigned noperm:1;
76         unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
77         unsigned no_xattr:1;   /* set if xattr (EA) support should be disabled*/
78         unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
79         unsigned direct_io:1;
80         unsigned remap:1;   /* set to remap seven reserved chars in filenames */
81         unsigned posix_paths:1;   /* unset to not ask for posix pathnames. */
82         unsigned sfu_emul:1;
83         unsigned nocase;     /* request case insensitive filenames */
84         unsigned nobrl;      /* disable sending byte range locks to srv */
85         unsigned int rsize;
86         unsigned int wsize;
87         unsigned int sockopt;
88         unsigned short int port;
89 };
90
91 static int ipv4_connect(struct sockaddr_in *psin_server, 
92                         struct socket **csocket,
93                         char * netb_name,
94                         char * server_netb_name);
95 static int ipv6_connect(struct sockaddr_in6 *psin_server, 
96                         struct socket **csocket);
97
98
99         /* 
100          * cifs tcp session reconnection
101          * 
102          * mark tcp session as reconnecting so temporarily locked
103          * mark all smb sessions as reconnecting for tcp session
104          * reconnect tcp session
105          * wake up waiters on reconnection? - (not needed currently)
106          */
107
108 int
109 cifs_reconnect(struct TCP_Server_Info *server)
110 {
111         int rc = 0;
112         struct list_head *tmp;
113         struct cifsSesInfo *ses;
114         struct cifsTconInfo *tcon;
115         struct mid_q_entry * mid_entry;
116         
117         spin_lock(&GlobalMid_Lock);
118         if(server->tcpStatus == CifsExiting) {
119                 /* the demux thread will exit normally 
120                 next time through the loop */
121                 spin_unlock(&GlobalMid_Lock);
122                 return rc;
123         } else
124                 server->tcpStatus = CifsNeedReconnect;
125         spin_unlock(&GlobalMid_Lock);
126         server->maxBuf = 0;
127
128         cFYI(1, ("Reconnecting tcp session"));
129
130         /* before reconnecting the tcp session, mark the smb session (uid)
131                 and the tid bad so they are not used until reconnected */
132         read_lock(&GlobalSMBSeslock);
133         list_for_each(tmp, &GlobalSMBSessionList) {
134                 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
135                 if (ses->server) {
136                         if (ses->server == server) {
137                                 ses->status = CifsNeedReconnect;
138                                 ses->ipc_tid = 0;
139                         }
140                 }
141                 /* else tcp and smb sessions need reconnection */
142         }
143         list_for_each(tmp, &GlobalTreeConnectionList) {
144                 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
145                 if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
146                         tcon->tidStatus = CifsNeedReconnect;
147                 }
148         }
149         read_unlock(&GlobalSMBSeslock);
150         /* do not want to be sending data on a socket we are freeing */
151         down(&server->tcpSem); 
152         if(server->ssocket) {
153                 cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
154                         server->ssocket->flags));
155                 server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
156                 cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
157                         server->ssocket->flags));
158                 sock_release(server->ssocket);
159                 server->ssocket = NULL;
160         }
161
162         spin_lock(&GlobalMid_Lock);
163         list_for_each(tmp, &server->pending_mid_q) {
164                 mid_entry = list_entry(tmp, struct
165                                         mid_q_entry,
166                                         qhead);
167                 if(mid_entry) {
168                         if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
169                                 /* Mark other intransit requests as needing
170                                    retry so we do not immediately mark the
171                                    session bad again (ie after we reconnect
172                                    below) as they timeout too */
173                                 mid_entry->midState = MID_RETRY_NEEDED;
174                         }
175                 }
176         }
177         spin_unlock(&GlobalMid_Lock);
178         up(&server->tcpSem); 
179
180         while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
181         {
182                 if(server->protocolType == IPV6) {
183                         rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
184                 } else {
185                         rc = ipv4_connect(&server->addr.sockAddr, 
186                                         &server->ssocket,
187                                         server->workstation_RFC1001_name,
188                                         server->server_RFC1001_name);
189                 }
190                 if(rc) {
191                         msleep(3000);
192                 } else {
193                         atomic_inc(&tcpSesReconnectCount);
194                         spin_lock(&GlobalMid_Lock);
195                         if(server->tcpStatus != CifsExiting)
196                                 server->tcpStatus = CifsGood;
197                         server->sequence_number = 0;
198                         spin_unlock(&GlobalMid_Lock);                   
199         /*              atomic_set(&server->inFlight,0);*/
200                         wake_up(&server->response_q);
201                 }
202         }
203         return rc;
204 }
205
206 /* 
207         return codes:
208                 0       not a transact2, or all data present
209                 >0      transact2 with that much data missing
210                 -EINVAL = invalid transact2
211
212  */
213 static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
214 {
215         struct smb_t2_rsp * pSMBt;
216         int total_data_size;
217         int data_in_this_rsp;
218         int remaining;
219
220         if(pSMB->Command != SMB_COM_TRANSACTION2)
221                 return 0;
222
223         /* check for plausible wct, bcc and t2 data and parm sizes */
224         /* check for parm and data offset going beyond end of smb */
225         if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
226                 cFYI(1,("invalid transact2 word count"));
227                 return -EINVAL;
228         }
229
230         pSMBt = (struct smb_t2_rsp *)pSMB;
231
232         total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
233         data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
234
235         remaining = total_data_size - data_in_this_rsp;
236
237         if(remaining == 0)
238                 return 0;
239         else if(remaining < 0) {
240                 cFYI(1,("total data %d smaller than data in frame %d",
241                         total_data_size, data_in_this_rsp));
242                 return -EINVAL;
243         } else {
244                 cFYI(1,("missing %d bytes from transact2, check next response",
245                         remaining));
246                 if(total_data_size > maxBufSize) {
247                         cERROR(1,("TotalDataSize %d is over maximum buffer %d",
248                                 total_data_size,maxBufSize));
249                         return -EINVAL; 
250                 }
251                 return remaining;
252         }
253 }
254
255 static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
256 {
257         struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
258         struct smb_t2_rsp *pSMBt  = (struct smb_t2_rsp *)pTargetSMB;
259         int total_data_size;
260         int total_in_buf;
261         int remaining;
262         int total_in_buf2;
263         char * data_area_of_target;
264         char * data_area_of_buf2;
265         __u16 byte_count;
266
267         total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
268
269         if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
270                 cFYI(1,("total data sizes of primary and secondary t2 differ"));
271         }
272
273         total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
274
275         remaining = total_data_size - total_in_buf;
276         
277         if(remaining < 0)
278                 return -EINVAL;
279
280         if(remaining == 0) /* nothing to do, ignore */
281                 return 0;
282         
283         total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
284         if(remaining < total_in_buf2) {
285                 cFYI(1,("transact2 2nd response contains too much data"));
286         }
287
288         /* find end of first SMB data area */
289         data_area_of_target = (char *)&pSMBt->hdr.Protocol + 
290                                 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
291         /* validate target area */
292
293         data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
294                                         le16_to_cpu(pSMB2->t2_rsp.DataOffset);
295
296         data_area_of_target += total_in_buf;
297
298         /* copy second buffer into end of first buffer */
299         memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
300         total_in_buf += total_in_buf2;
301         pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
302         byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
303         byte_count += total_in_buf2;
304         BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
305
306         byte_count = pTargetSMB->smb_buf_length;
307         byte_count += total_in_buf2;
308
309         /* BB also add check that we are not beyond maximum buffer size */
310                 
311         pTargetSMB->smb_buf_length = byte_count;
312
313         if(remaining == total_in_buf2) {
314                 cFYI(1,("found the last secondary response"));
315                 return 0; /* we are done */
316         } else /* more responses to go */
317                 return 1;
318
319 }
320
321 static int
322 cifs_demultiplex_thread(struct TCP_Server_Info *server)
323 {
324         int length;
325         unsigned int pdu_length, total_read;
326         struct smb_hdr *smb_buffer = NULL;
327         struct smb_hdr *bigbuf = NULL;
328         struct smb_hdr *smallbuf = NULL;
329         struct msghdr smb_msg;
330         struct kvec iov;
331         struct socket *csocket = server->ssocket;
332         struct list_head *tmp;
333         struct cifsSesInfo *ses;
334         struct task_struct *task_to_wake = NULL;
335         struct mid_q_entry *mid_entry;
336         char temp;
337         int isLargeBuf = FALSE;
338         int isMultiRsp;
339         int reconnect;
340
341         daemonize("cifsd");
342         allow_signal(SIGKILL);
343         current->flags |= PF_MEMALLOC;
344         server->tsk = current;  /* save process info to wake at shutdown */
345         cFYI(1, ("Demultiplex PID: %d", current->pid));
346         write_lock(&GlobalSMBSeslock); 
347         atomic_inc(&tcpSesAllocCount);
348         length = tcpSesAllocCount.counter;
349         write_unlock(&GlobalSMBSeslock);
350         complete(&cifsd_complete);
351         if(length  > 1) {
352                 mempool_resize(cifs_req_poolp,
353                         length + cifs_min_rcv,
354                         GFP_KERNEL);
355         }
356
357         while (server->tcpStatus != CifsExiting) {
358                 if(try_to_freeze())
359                         continue;
360                 if (bigbuf == NULL) {
361                         bigbuf = cifs_buf_get();
362                         if(bigbuf == NULL) {
363                                 cERROR(1,("No memory for large SMB response"));
364                                 msleep(3000);
365                                 /* retry will check if exiting */
366                                 continue;
367                         }
368                 } else if(isLargeBuf) {
369                         /* we are reusing a dirtry large buf, clear its start */
370                         memset(bigbuf, 0, sizeof (struct smb_hdr));
371                 }
372
373                 if (smallbuf == NULL) {
374                         smallbuf = cifs_small_buf_get();
375                         if(smallbuf == NULL) {
376                                 cERROR(1,("No memory for SMB response"));
377                                 msleep(1000);
378                                 /* retry will check if exiting */
379                                 continue;
380                         }
381                         /* beginning of smb buffer is cleared in our buf_get */
382                 } else /* if existing small buf clear beginning */
383                         memset(smallbuf, 0, sizeof (struct smb_hdr));
384
385                 isLargeBuf = FALSE;
386                 isMultiRsp = FALSE;
387                 smb_buffer = smallbuf;
388                 iov.iov_base = smb_buffer;
389                 iov.iov_len = 4;
390                 smb_msg.msg_control = NULL;
391                 smb_msg.msg_controllen = 0;
392                 length =
393                     kernel_recvmsg(csocket, &smb_msg,
394                                  &iov, 1, 4, 0 /* BB see socket.h flags */);
395
396                 if(server->tcpStatus == CifsExiting) {
397                         break;
398                 } else if (server->tcpStatus == CifsNeedReconnect) {
399                         cFYI(1,("Reconnect after server stopped responding"));
400                         cifs_reconnect(server);
401                         cFYI(1,("call to reconnect done"));
402                         csocket = server->ssocket;
403                         continue;
404                 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
405                         msleep(1); /* minimum sleep to prevent looping
406                                 allowing socket to clear and app threads to set
407                                 tcpStatus CifsNeedReconnect if server hung */
408                         continue;
409                 } else if (length <= 0) {
410                         if(server->tcpStatus == CifsNew) {
411                                 cFYI(1,("tcp session abend after SMBnegprot"));
412                                 /* some servers kill the TCP session rather than
413                                    returning an SMB negprot error, in which
414                                    case reconnecting here is not going to help,
415                                    and so simply return error to mount */
416                                 break;
417                         }
418                         if(length == -EINTR) { 
419                                 cFYI(1,("cifsd thread killed"));
420                                 break;
421                         }
422                         cFYI(1,("Reconnect after unexpected peek error %d",
423                                 length));
424                         cifs_reconnect(server);
425                         csocket = server->ssocket;
426                         wake_up(&server->response_q);
427                         continue;
428                 } else if (length < 4) {
429                         cFYI(1,
430                             ("Frame under four bytes received (%d bytes long)",
431                               length));
432                         cifs_reconnect(server);
433                         csocket = server->ssocket;
434                         wake_up(&server->response_q);
435                         continue;
436                 }
437
438                 /* The right amount was read from socket - 4 bytes */
439                 /* so we can now interpret the length field */
440
441                 /* the first byte big endian of the length field,
442                 is actually not part of the length but the type
443                 with the most common, zero, as regular data */
444                 temp = *((char *) smb_buffer);
445
446                 /* Note that FC 1001 length is big endian on the wire, 
447                 but we convert it here so it is always manipulated
448                 as host byte order */
449                 pdu_length = ntohl(smb_buffer->smb_buf_length);
450                 smb_buffer->smb_buf_length = pdu_length;
451
452                 cFYI(1,("rfc1002 length 0x%x)", pdu_length+4));
453
454                 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
455                         continue; 
456                 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
457                         cFYI(1,("Good RFC 1002 session rsp"));
458                         continue;
459                 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
460                         /* we get this from Windows 98 instead of 
461                            an error on SMB negprot response */
462                         cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
463                                 pdu_length));
464                         if(server->tcpStatus == CifsNew) {
465                                 /* if nack on negprot (rather than 
466                                 ret of smb negprot error) reconnecting
467                                 not going to help, ret error to mount */
468                                 break;
469                         } else {
470                                 /* give server a second to
471                                 clean up before reconnect attempt */
472                                 msleep(1000);
473                                 /* always try 445 first on reconnect
474                                 since we get NACK on some if we ever
475                                 connected to port 139 (the NACK is 
476                                 since we do not begin with RFC1001
477                                 session initialize frame) */
478                                 server->addr.sockAddr.sin_port = 
479                                         htons(CIFS_PORT);
480                                 cifs_reconnect(server);
481                                 csocket = server->ssocket;
482                                 wake_up(&server->response_q);
483                                 continue;
484                         }
485                 } else if (temp != (char) 0) {
486                         cERROR(1,("Unknown RFC 1002 frame"));
487                         cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
488                                       length);
489                         cifs_reconnect(server);
490                         csocket = server->ssocket;
491                         continue;
492                 }
493
494                 /* else we have an SMB response */
495                 if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
496                             (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
497                         cERROR(1, ("Invalid size SMB length %d pdu_length %d",
498                                         length, pdu_length+4));
499                         cifs_reconnect(server);
500                         csocket = server->ssocket;
501                         wake_up(&server->response_q);
502                         continue;
503                 } 
504
505                 /* else length ok */
506                 reconnect = 0;
507
508                 if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
509                         isLargeBuf = TRUE;
510                         memcpy(bigbuf, smallbuf, 4);
511                         smb_buffer = bigbuf;
512                 }
513                 length = 0;
514                 iov.iov_base = 4 + (char *)smb_buffer;
515                 iov.iov_len = pdu_length;
516                 for (total_read = 0; total_read < pdu_length; 
517                      total_read += length) {
518                         length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
519                                                 pdu_length - total_read, 0);
520                         if((server->tcpStatus == CifsExiting) ||
521                             (length == -EINTR)) {
522                                 /* then will exit */
523                                 reconnect = 2;
524                                 break;
525                         } else if (server->tcpStatus == CifsNeedReconnect) {
526                                 cifs_reconnect(server);
527                                 csocket = server->ssocket;
528                                 /* Reconnect wakes up rspns q */
529                                 /* Now we will reread sock */
530                                 reconnect = 1;
531                                 break;
532                         } else if ((length == -ERESTARTSYS) || 
533                                    (length == -EAGAIN)) {
534                                 msleep(1); /* minimum sleep to prevent looping,
535                                               allowing socket to clear and app 
536                                               threads to set tcpStatus
537                                               CifsNeedReconnect if server hung*/
538                                 continue;
539                         } else if (length <= 0) {
540                                 cERROR(1,("Received no data, expecting %d",
541                                               pdu_length - total_read));
542                                 cifs_reconnect(server);
543                                 csocket = server->ssocket;
544                                 reconnect = 1;
545                                 break;
546                         }
547                 }
548                 if(reconnect == 2)
549                         break;
550                 else if(reconnect == 1)
551                         continue;
552
553                 length += 4; /* account for rfc1002 hdr */
554         
555
556                 dump_smb(smb_buffer, length);
557                 if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
558                         cERROR(1, ("Bad SMB Received "));
559                         continue;
560                 }
561
562
563                 task_to_wake = NULL;
564                 spin_lock(&GlobalMid_Lock);
565                 list_for_each(tmp, &server->pending_mid_q) {
566                         mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
567
568                         if ((mid_entry->mid == smb_buffer->Mid) && 
569                             (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
570                             (mid_entry->command == smb_buffer->Command)) {
571                                 if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
572                                         /* We have a multipart transact2 resp */
573                                         isMultiRsp = TRUE;
574                                         if(mid_entry->resp_buf) {
575                                                 /* merge response - fix up 1st*/
576                                                 if(coalesce_t2(smb_buffer, 
577                                                         mid_entry->resp_buf)) {
578                                                         break;
579                                                 } else {
580                                                         /* all parts received */
581                                                         goto multi_t2_fnd; 
582                                                 }
583                                         } else {
584                                                 if(!isLargeBuf) {
585                                                         cERROR(1,("1st trans2 resp needs bigbuf"));
586                                         /* BB maybe we can fix this up,  switch
587                                            to already allocated large buffer? */
588                                                 } else {
589                                                         /* Have first buffer */
590                                                         mid_entry->resp_buf =
591                                                                  smb_buffer;
592                                                         mid_entry->largeBuf = 1;
593                                                         bigbuf = NULL;
594                                                 }
595                                         }
596                                         break;
597                                 } 
598                                 mid_entry->resp_buf = smb_buffer;
599                                 if(isLargeBuf)
600                                         mid_entry->largeBuf = 1;
601                                 else
602                                         mid_entry->largeBuf = 0;
603 multi_t2_fnd:
604                                 task_to_wake = mid_entry->tsk;
605                                 mid_entry->midState = MID_RESPONSE_RECEIVED;
606                                 break;
607                         }
608                 }
609                 spin_unlock(&GlobalMid_Lock);
610                 if (task_to_wake) {
611                         /* Was previous buf put in mpx struct for multi-rsp? */
612                         if(!isMultiRsp) {
613                                 /* smb buffer will be freed by user thread */
614                                 if(isLargeBuf) {
615                                         bigbuf = NULL;
616                                 } else
617                                         smallbuf = NULL;
618                         }
619                         wake_up_process(task_to_wake);
620                 } else if ((is_valid_oplock_break(smb_buffer) == FALSE)
621                     && (isMultiRsp == FALSE)) {                          
622                         cERROR(1, ("No task to wake, unknown frame rcvd!"));
623                         cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
624                                       sizeof(struct smb_hdr));
625                 }
626         } /* end while !EXITING */
627
628         spin_lock(&GlobalMid_Lock);
629         server->tcpStatus = CifsExiting;
630         server->tsk = NULL;
631         /* check if we have blocked requests that need to free */
632         /* Note that cifs_max_pending is normally 50, but
633         can be set at module install time to as little as two */
634         if(atomic_read(&server->inFlight) >= cifs_max_pending)
635                 atomic_set(&server->inFlight, cifs_max_pending - 1);
636         /* We do not want to set the max_pending too low or we
637         could end up with the counter going negative */
638         spin_unlock(&GlobalMid_Lock);
639         /* Although there should not be any requests blocked on 
640         this queue it can not hurt to be paranoid and try to wake up requests
641         that may haven been blocked when more than 50 at time were on the wire
642         to the same server - they now will see the session is in exit state
643         and get out of SendReceive.  */
644         wake_up_all(&server->request_q);
645         /* give those requests time to exit */
646         msleep(125);
647         
648         if(server->ssocket) {
649                 sock_release(csocket);
650                 server->ssocket = NULL;
651         }
652         /* buffer usuallly freed in free_mid - need to free it here on exit */
653         if (bigbuf != NULL)
654                 cifs_buf_release(bigbuf);
655         if (smallbuf != NULL)
656                 cifs_small_buf_release(smallbuf);
657
658         read_lock(&GlobalSMBSeslock);
659         if (list_empty(&server->pending_mid_q)) {
660                 /* loop through server session structures attached to this and
661                     mark them dead */
662                 list_for_each(tmp, &GlobalSMBSessionList) {
663                         ses =
664                             list_entry(tmp, struct cifsSesInfo,
665                                        cifsSessionList);
666                         if (ses->server == server) {
667                                 ses->status = CifsExiting;
668                                 ses->server = NULL;
669                         }
670                 }
671                 read_unlock(&GlobalSMBSeslock);
672         } else {
673                 /* although we can not zero the server struct pointer yet,
674                 since there are active requests which may depnd on them,
675                 mark the corresponding SMB sessions as exiting too */
676                 list_for_each(tmp, &GlobalSMBSessionList) {
677                         ses = list_entry(tmp, struct cifsSesInfo,
678                                          cifsSessionList);
679                         if (ses->server == server) {
680                                 ses->status = CifsExiting;
681                         }
682                 }
683
684                 spin_lock(&GlobalMid_Lock);
685                 list_for_each(tmp, &server->pending_mid_q) {
686                 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
687                         if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
688                                 cFYI(1,
689                                   ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
690                                 task_to_wake = mid_entry->tsk;
691                                 if(task_to_wake) {
692                                         wake_up_process(task_to_wake);
693                                 }
694                         }
695                 }
696                 spin_unlock(&GlobalMid_Lock);
697                 read_unlock(&GlobalSMBSeslock);
698                 /* 1/8th of sec is more than enough time for them to exit */
699                 msleep(125);
700         }
701
702         if (!list_empty(&server->pending_mid_q)) {
703                 /* mpx threads have not exited yet give them 
704                 at least the smb send timeout time for long ops */
705                 /* due to delays on oplock break requests, we need
706                 to wait at least 45 seconds before giving up
707                 on a request getting a response and going ahead
708                 and killing cifsd */
709                 cFYI(1, ("Wait for exit from demultiplex thread"));
710                 msleep(46000);
711                 /* if threads still have not exited they are probably never
712                 coming home not much else we can do but free the memory */
713         }
714
715         write_lock(&GlobalSMBSeslock);
716         atomic_dec(&tcpSesAllocCount);
717         length = tcpSesAllocCount.counter;
718
719         /* last chance to mark ses pointers invalid
720         if there are any pointing to this (e.g
721         if a crazy root user tried to kill cifsd 
722         kernel thread explicitly this might happen) */
723         list_for_each(tmp, &GlobalSMBSessionList) {
724                 ses = list_entry(tmp, struct cifsSesInfo,
725                                 cifsSessionList);
726                 if (ses->server == server) {
727                         ses->server = NULL;
728                 }
729         }
730         write_unlock(&GlobalSMBSeslock);
731
732         kfree(server);
733         if(length  > 0) {
734                 mempool_resize(cifs_req_poolp,
735                         length + cifs_min_rcv,
736                         GFP_KERNEL);
737         }
738         
739         complete_and_exit(&cifsd_complete, 0);
740         return 0;
741 }
742
743 static int
744 cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
745 {
746         char *value;
747         char *data;
748         unsigned int  temp_len, i, j;
749         char separator[2];
750
751         separator[0] = ',';
752         separator[1] = 0; 
753
754         memset(vol->source_rfc1001_name,0x20,15);
755         for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
756                 /* does not have to be a perfect mapping since the field is
757                 informational, only used for servers that do not support
758                 port 445 and it can be overridden at mount time */
759                 vol->source_rfc1001_name[i] = 
760                         toupper(system_utsname.nodename[i]);
761         }
762         vol->source_rfc1001_name[15] = 0;
763         /* null target name indicates to use *SMBSERVR default called name
764            if we end up sending RFC1001 session initialize */
765         vol->target_rfc1001_name[0] = 0;
766         vol->linux_uid = current->uid;  /* current->euid instead? */
767         vol->linux_gid = current->gid;
768         vol->dir_mode = S_IRWXUGO;
769         /* 2767 perms indicate mandatory locking support */
770         vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
771
772         /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
773         vol->rw = TRUE;
774
775         /* default is always to request posix paths. */
776         vol->posix_paths = 1;
777
778         if (!options)
779                 return 1;
780
781         if(strncmp(options,"sep=",4) == 0) {
782                 if(options[4] != 0) {
783                         separator[0] = options[4];
784                         options += 5;
785                 } else {
786                         cFYI(1,("Null separator not allowed"));
787                 }
788         }
789                 
790         while ((data = strsep(&options, separator)) != NULL) {
791                 if (!*data)
792                         continue;
793                 if ((value = strchr(data, '=')) != NULL)
794                         *value++ = '\0';
795
796                 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
797                         vol->no_xattr = 0;
798                 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
799                         vol->no_xattr = 1;
800                 } else if (strnicmp(data, "user", 4) == 0) {
801                         if (!value || !*value) {
802                                 printk(KERN_WARNING
803                                        "CIFS: invalid or missing username\n");
804                                 return 1;       /* needs_arg; */
805                         }
806                         if (strnlen(value, 200) < 200) {
807                                 vol->username = value;
808                         } else {
809                                 printk(KERN_WARNING "CIFS: username too long\n");
810                                 return 1;
811                         }
812                 } else if (strnicmp(data, "pass", 4) == 0) {
813                         if (!value) {
814                                 vol->password = NULL;
815                                 continue;
816                         } else if(value[0] == 0) {
817                                 /* check if string begins with double comma
818                                    since that would mean the password really
819                                    does start with a comma, and would not
820                                    indicate an empty string */
821                                 if(value[1] != separator[0]) {
822                                         vol->password = NULL;
823                                         continue;
824                                 }
825                         }
826                         temp_len = strlen(value);
827                         /* removed password length check, NTLM passwords
828                                 can be arbitrarily long */
829
830                         /* if comma in password, the string will be 
831                         prematurely null terminated.  Commas in password are
832                         specified across the cifs mount interface by a double
833                         comma ie ,, and a comma used as in other cases ie ','
834                         as a parameter delimiter/separator is single and due
835                         to the strsep above is temporarily zeroed. */
836
837                         /* NB: password legally can have multiple commas and
838                         the only illegal character in a password is null */
839
840                         if ((value[temp_len] == 0) && 
841                             (value[temp_len+1] == separator[0])) {
842                                 /* reinsert comma */
843                                 value[temp_len] = separator[0];
844                                 temp_len+=2;  /* move after the second comma */
845                                 while(value[temp_len] != 0)  {
846                                         if (value[temp_len] == separator[0]) {
847                                                 if (value[temp_len+1] == 
848                                                      separator[0]) {
849                                                 /* skip second comma */
850                                                         temp_len++;
851                                                 } else { 
852                                                 /* single comma indicating start
853                                                          of next parm */
854                                                         break;
855                                                 }
856                                         }
857                                         temp_len++;
858                                 }
859                                 if(value[temp_len] == 0) {
860                                         options = NULL;
861                                 } else {
862                                         value[temp_len] = 0;
863                                         /* point option to start of next parm */
864                                         options = value + temp_len + 1;
865                                 }
866                                 /* go from value to value + temp_len condensing 
867                                 double commas to singles. Note that this ends up
868                                 allocating a few bytes too many, which is ok */
869                                 vol->password = kcalloc(1, temp_len, GFP_KERNEL);
870                                 if(vol->password == NULL) {
871                                         printk("CIFS: no memory for pass\n");
872                                         return 1;
873                                 }
874                                 for(i=0,j=0;i<temp_len;i++,j++) {
875                                         vol->password[j] = value[i];
876                                         if(value[i] == separator[0]
877                                                 && value[i+1] == separator[0]) {
878                                                 /* skip second comma */
879                                                 i++;
880                                         }
881                                 }
882                                 vol->password[j] = 0;
883                         } else {
884                                 vol->password = kcalloc(1, temp_len+1, GFP_KERNEL);
885                                 if(vol->password == NULL) {
886                                         printk("CIFS: no memory for pass\n");
887                                         return 1;
888                                 }
889                                 strcpy(vol->password, value);
890                         }
891                 } else if (strnicmp(data, "ip", 2) == 0) {
892                         if (!value || !*value) {
893                                 vol->UNCip = NULL;
894                         } else if (strnlen(value, 35) < 35) {
895                                 vol->UNCip = value;
896                         } else {
897                                 printk(KERN_WARNING "CIFS: ip address too long\n");
898                                 return 1;
899                         }
900                 } else if ((strnicmp(data, "unc", 3) == 0)
901                            || (strnicmp(data, "target", 6) == 0)
902                            || (strnicmp(data, "path", 4) == 0)) {
903                         if (!value || !*value) {
904                                 printk(KERN_WARNING
905                                        "CIFS: invalid path to network resource\n");
906                                 return 1;       /* needs_arg; */
907                         }
908                         if ((temp_len = strnlen(value, 300)) < 300) {
909                                 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
910                                 if(vol->UNC == NULL)
911                                         return 1;
912                                 strcpy(vol->UNC,value);
913                                 if (strncmp(vol->UNC, "//", 2) == 0) {
914                                         vol->UNC[0] = '\\';
915                                         vol->UNC[1] = '\\';
916                                 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {                    
917                                         printk(KERN_WARNING
918                                                "CIFS: UNC Path does not begin with // or \\\\ \n");
919                                         return 1;
920                                 }
921                         } else {
922                                 printk(KERN_WARNING "CIFS: UNC name too long\n");
923                                 return 1;
924                         }
925                 } else if ((strnicmp(data, "domain", 3) == 0)
926                            || (strnicmp(data, "workgroup", 5) == 0)) {
927                         if (!value || !*value) {
928                                 printk(KERN_WARNING "CIFS: invalid domain name\n");
929                                 return 1;       /* needs_arg; */
930                         }
931                         /* BB are there cases in which a comma can be valid in
932                         a domain name and need special handling? */
933                         if (strnlen(value, 65) < 65) {
934                                 vol->domainname = value;
935                                 cFYI(1, ("Domain name set"));
936                         } else {
937                                 printk(KERN_WARNING "CIFS: domain name too long\n");
938                                 return 1;
939                         }
940                 } else if (strnicmp(data, "iocharset", 9) == 0) {
941                         if (!value || !*value) {
942                                 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
943                                 return 1;       /* needs_arg; */
944                         }
945                         if (strnlen(value, 65) < 65) {
946                                 if(strnicmp(value,"default",7))
947                                         vol->iocharset = value;
948                                 /* if iocharset not set load_nls_default used by caller */
949                                 cFYI(1, ("iocharset set to %s",value));
950                         } else {
951                                 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
952                                 return 1;
953                         }
954                 } else if (strnicmp(data, "uid", 3) == 0) {
955                         if (value && *value) {
956                                 vol->linux_uid =
957                                         simple_strtoul(value, &value, 0);
958                         }
959                 } else if (strnicmp(data, "gid", 3) == 0) {
960                         if (value && *value) {
961                                 vol->linux_gid =
962                                         simple_strtoul(value, &value, 0);
963                         }
964                 } else if (strnicmp(data, "file_mode", 4) == 0) {
965                         if (value && *value) {
966                                 vol->file_mode =
967                                         simple_strtoul(value, &value, 0);
968                         }
969                 } else if (strnicmp(data, "dir_mode", 4) == 0) {
970                         if (value && *value) {
971                                 vol->dir_mode =
972                                         simple_strtoul(value, &value, 0);
973                         }
974                 } else if (strnicmp(data, "dirmode", 4) == 0) {
975                         if (value && *value) {
976                                 vol->dir_mode =
977                                         simple_strtoul(value, &value, 0);
978                         }
979                 } else if (strnicmp(data, "port", 4) == 0) {
980                         if (value && *value) {
981                                 vol->port =
982                                         simple_strtoul(value, &value, 0);
983                         }
984                 } else if (strnicmp(data, "rsize", 5) == 0) {
985                         if (value && *value) {
986                                 vol->rsize =
987                                         simple_strtoul(value, &value, 0);
988                         }
989                 } else if (strnicmp(data, "wsize", 5) == 0) {
990                         if (value && *value) {
991                                 vol->wsize =
992                                         simple_strtoul(value, &value, 0);
993                         }
994                 } else if (strnicmp(data, "sockopt", 5) == 0) {
995                         if (value && *value) {
996                                 vol->sockopt =
997                                         simple_strtoul(value, &value, 0);
998                         }
999                 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1000                         if (!value || !*value || (*value == ' ')) {
1001                                 cFYI(1,("invalid (empty) netbiosname specified"));
1002                         } else {
1003                                 memset(vol->source_rfc1001_name,0x20,15);
1004                                 for(i=0;i<15;i++) {
1005                                 /* BB are there cases in which a comma can be 
1006                                 valid in this workstation netbios name (and need
1007                                 special handling)? */
1008
1009                                 /* We do not uppercase netbiosname for user */
1010                                         if (value[i]==0)
1011                                                 break;
1012                                         else 
1013                                                 vol->source_rfc1001_name[i] = value[i];
1014                                 }
1015                                 /* The string has 16th byte zero still from
1016                                 set at top of the function  */
1017                                 if((i==15) && (value[i] != 0))
1018                                         printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
1019                         }
1020                 } else if (strnicmp(data, "servern", 7) == 0) {
1021                         /* servernetbiosname specified override *SMBSERVER */
1022                         if (!value || !*value || (*value == ' ')) {
1023                                 cFYI(1,("empty server netbiosname specified"));
1024                         } else {
1025                                 /* last byte, type, is 0x20 for servr type */
1026                                 memset(vol->target_rfc1001_name,0x20,16);
1027
1028                                 for(i=0;i<15;i++) {
1029                                 /* BB are there cases in which a comma can be
1030                                    valid in this workstation netbios name (and need
1031                                    special handling)? */
1032
1033                                 /* user or mount helper must uppercase netbiosname */
1034                                         if (value[i]==0)
1035                                                 break;
1036                                         else
1037                                                 vol->target_rfc1001_name[i] = value[i];
1038                                 }
1039                                 /* The string has 16th byte zero still from
1040                                    set at top of the function  */
1041                                 if((i==15) && (value[i] != 0))
1042                                         printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
1043                         }
1044                 } else if (strnicmp(data, "credentials", 4) == 0) {
1045                         /* ignore */
1046                 } else if (strnicmp(data, "version", 3) == 0) {
1047                         /* ignore */
1048                 } else if (strnicmp(data, "guest",5) == 0) {
1049                         /* ignore */
1050                 } else if (strnicmp(data, "rw", 2) == 0) {
1051                         vol->rw = TRUE;
1052                 } else if ((strnicmp(data, "suid", 4) == 0) ||
1053                                    (strnicmp(data, "nosuid", 6) == 0) ||
1054                                    (strnicmp(data, "exec", 4) == 0) ||
1055                                    (strnicmp(data, "noexec", 6) == 0) ||
1056                                    (strnicmp(data, "nodev", 5) == 0) ||
1057                                    (strnicmp(data, "noauto", 6) == 0) ||
1058                                    (strnicmp(data, "dev", 3) == 0)) {
1059                         /*  The mount tool or mount.cifs helper (if present)
1060                                 uses these opts to set flags, and the flags are read
1061                                 by the kernel vfs layer before we get here (ie
1062                                 before read super) so there is no point trying to
1063                                 parse these options again and set anything and it
1064                                 is ok to just ignore them */
1065                         continue;
1066                 } else if (strnicmp(data, "ro", 2) == 0) {
1067                         vol->rw = FALSE;
1068                 } else if (strnicmp(data, "hard", 4) == 0) {
1069                         vol->retry = 1;
1070                 } else if (strnicmp(data, "soft", 4) == 0) {
1071                         vol->retry = 0;
1072                 } else if (strnicmp(data, "perm", 4) == 0) {
1073                         vol->noperm = 0;
1074                 } else if (strnicmp(data, "noperm", 6) == 0) {
1075                         vol->noperm = 1;
1076                 } else if (strnicmp(data, "mapchars", 8) == 0) {
1077                         vol->remap = 1;
1078                 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1079                         vol->remap = 0;
1080                 } else if (strnicmp(data, "sfu", 3) == 0) {
1081                         vol->sfu_emul = 1;
1082                 } else if (strnicmp(data, "nosfu", 5) == 0) {
1083                         vol->sfu_emul = 0;
1084                 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1085                         vol->posix_paths = 1;
1086                 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1087                         vol->posix_paths = 0;
1088                 } else if ((strnicmp(data, "nocase", 6) == 0) ||
1089                            (strnicmp(data, "ignorecase", 10)  == 0)) {
1090                         vol->nocase = 1;
1091                 } else if (strnicmp(data, "brl", 3) == 0) {
1092                         vol->nobrl =  0;
1093                 } else if ((strnicmp(data, "nobrl", 5) == 0) || 
1094                            (strnicmp(data, "nolock", 6) == 0)) {
1095                         vol->nobrl =  1;
1096                         /* turn off mandatory locking in mode
1097                         if remote locking is turned off since the
1098                         local vfs will do advisory */
1099                         if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
1100                                 vol->file_mode = S_IALLUGO;
1101                 } else if (strnicmp(data, "setuids", 7) == 0) {
1102                         vol->setuids = 1;
1103                 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1104                         vol->setuids = 0;
1105                 } else if (strnicmp(data, "nohard", 6) == 0) {
1106                         vol->retry = 0;
1107                 } else if (strnicmp(data, "nosoft", 6) == 0) {
1108                         vol->retry = 1;
1109                 } else if (strnicmp(data, "nointr", 6) == 0) {
1110                         vol->intr = 0;
1111                 } else if (strnicmp(data, "intr", 4) == 0) {
1112                         vol->intr = 1;
1113                 } else if (strnicmp(data, "serverino",7) == 0) {
1114                         vol->server_ino = 1;
1115                 } else if (strnicmp(data, "noserverino",9) == 0) {
1116                         vol->server_ino = 0;
1117                 } else if (strnicmp(data, "acl",3) == 0) {
1118                         vol->no_psx_acl = 0;
1119                 } else if (strnicmp(data, "noacl",5) == 0) {
1120                         vol->no_psx_acl = 1;
1121                 } else if (strnicmp(data, "direct",6) == 0) {
1122                         vol->direct_io = 1;
1123                 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1124                         vol->direct_io = 1;
1125                 } else if (strnicmp(data, "in6_addr",8) == 0) {
1126                         if (!value || !*value) {
1127                                 vol->in6_addr = NULL;
1128                         } else if (strnlen(value, 49) == 48) {
1129                                 vol->in6_addr = value;
1130                         } else {
1131                                 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1132                                 return 1;
1133                         }
1134                 } else if (strnicmp(data, "noac", 4) == 0) {
1135                         printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1136                 } else
1137                         printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1138         }
1139         if (vol->UNC == NULL) {
1140                 if(devname == NULL) {
1141                         printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1142                         return 1;
1143                 }
1144                 if ((temp_len = strnlen(devname, 300)) < 300) {
1145                         vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
1146                         if(vol->UNC == NULL)
1147                                 return 1;
1148                         strcpy(vol->UNC,devname);
1149                         if (strncmp(vol->UNC, "//", 2) == 0) {
1150                                 vol->UNC[0] = '\\';
1151                                 vol->UNC[1] = '\\';
1152                         } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1153                                 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1154                                 return 1;
1155                         }
1156                 } else {
1157                         printk(KERN_WARNING "CIFS: UNC name too long\n");
1158                         return 1;
1159                 }
1160         }
1161         if(vol->UNCip == NULL)
1162                 vol->UNCip = &vol->UNC[2];
1163
1164         return 0;
1165 }
1166
1167 static struct cifsSesInfo *
1168 cifs_find_tcp_session(struct in_addr * target_ip_addr, 
1169                 struct in6_addr *target_ip6_addr,
1170                  char *userName, struct TCP_Server_Info **psrvTcp)
1171 {
1172         struct list_head *tmp;
1173         struct cifsSesInfo *ses;
1174         *psrvTcp = NULL;
1175         read_lock(&GlobalSMBSeslock);
1176
1177         list_for_each(tmp, &GlobalSMBSessionList) {
1178                 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1179                 if (ses->server) {
1180                         if((target_ip_addr && 
1181                                 (ses->server->addr.sockAddr.sin_addr.s_addr
1182                                   == target_ip_addr->s_addr)) || (target_ip6_addr
1183                                 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1184                                         target_ip6_addr,sizeof(*target_ip6_addr)))){
1185                                 /* BB lock server and tcp session and increment use count here?? */
1186                                 *psrvTcp = ses->server; /* found a match on the TCP session */
1187                                 /* BB check if reconnection needed */
1188                                 if (strncmp
1189                                     (ses->userName, userName,
1190                                      MAX_USERNAME_SIZE) == 0){
1191                                         read_unlock(&GlobalSMBSeslock);
1192                                         return ses;     /* found exact match on both tcp and SMB sessions */
1193                                 }
1194                         }
1195                 }
1196                 /* else tcp and smb sessions need reconnection */
1197         }
1198         read_unlock(&GlobalSMBSeslock);
1199         return NULL;
1200 }
1201
1202 static struct cifsTconInfo *
1203 find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1204 {
1205         struct list_head *tmp;
1206         struct cifsTconInfo *tcon;
1207
1208         read_lock(&GlobalSMBSeslock);
1209         list_for_each(tmp, &GlobalTreeConnectionList) {
1210                 cFYI(1, ("Next tcon - "));
1211                 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1212                 if (tcon->ses) {
1213                         if (tcon->ses->server) {
1214                                 cFYI(1,
1215                                      (" old ip addr: %x == new ip %x ?",
1216                                       tcon->ses->server->addr.sockAddr.sin_addr.
1217                                       s_addr, new_target_ip_addr));
1218                                 if (tcon->ses->server->addr.sockAddr.sin_addr.
1219                                     s_addr == new_target_ip_addr) {
1220         /* BB lock tcon and server and tcp session and increment use count here? */
1221                                         /* found a match on the TCP session */
1222                                         /* BB check if reconnection needed */
1223                                         cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
1224                                               tcon->treeName, uncName));
1225                                         if (strncmp
1226                                             (tcon->treeName, uncName,
1227                                              MAX_TREE_SIZE) == 0) {
1228                                                 cFYI(1,
1229                                                      ("Matched UNC, old user: %s == new: %s ?",
1230                                                       tcon->treeName, uncName));
1231                                                 if (strncmp
1232                                                     (tcon->ses->userName,
1233                                                      userName,
1234                                                      MAX_USERNAME_SIZE) == 0) {
1235                                                         read_unlock(&GlobalSMBSeslock);
1236                                                         return tcon;/* also matched user (smb session)*/
1237                                                 }
1238                                         }
1239                                 }
1240                         }
1241                 }
1242         }
1243         read_unlock(&GlobalSMBSeslock);
1244         return NULL;
1245 }
1246
1247 int
1248 connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1249                     const char *old_path, const struct nls_table *nls_codepage,
1250                     int remap)
1251 {
1252         unsigned char *referrals = NULL;
1253         unsigned int num_referrals;
1254         int rc = 0;
1255
1256         rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage, 
1257                         &num_referrals, &referrals, remap);
1258
1259         /* BB Add in code to: if valid refrl, if not ip address contact
1260                 the helper that resolves tcp names, mount to it, try to 
1261                 tcon to it unmount it if fail */
1262
1263         if(referrals)
1264                 kfree(referrals);
1265
1266         return rc;
1267 }
1268
1269 int
1270 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1271                         const char *old_path, const struct nls_table *nls_codepage, 
1272                         unsigned int *pnum_referrals, 
1273                         unsigned char ** preferrals, int remap)
1274 {
1275         char *temp_unc;
1276         int rc = 0;
1277
1278         *pnum_referrals = 0;
1279
1280         if (pSesInfo->ipc_tid == 0) {
1281                 temp_unc = kmalloc(2 /* for slashes */ +
1282                         strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1283                                  + 1 + 4 /* slash IPC$ */  + 2,
1284                                 GFP_KERNEL);
1285                 if (temp_unc == NULL)
1286                         return -ENOMEM;
1287                 temp_unc[0] = '\\';
1288                 temp_unc[1] = '\\';
1289                 strcpy(temp_unc + 2, pSesInfo->serverName);
1290                 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1291                 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1292                 cFYI(1,
1293                      ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1294                 kfree(temp_unc);
1295         }
1296         if (rc == 0)
1297                 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
1298                                      pnum_referrals, nls_codepage, remap);
1299
1300         return rc;
1301 }
1302
1303 /* See RFC1001 section 14 on representation of Netbios names */
1304 static void rfc1002mangle(char * target,char * source, unsigned int length)
1305 {
1306         unsigned int i,j;
1307
1308         for(i=0,j=0;i<(length);i++) {
1309                 /* mask a nibble at a time and encode */
1310                 target[j] = 'A' + (0x0F & (source[i] >> 4));
1311                 target[j+1] = 'A' + (0x0F & source[i]);
1312                 j+=2;
1313         }
1314
1315 }
1316
1317
1318 static int
1319 ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, 
1320              char * netbios_name, char * target_name)
1321 {
1322         int rc = 0;
1323         int connected = 0;
1324         __be16 orig_port = 0;
1325
1326         if(*csocket == NULL) {
1327                 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1328                 if (rc < 0) {
1329                         cERROR(1, ("Error %d creating socket",rc));
1330                         *csocket = NULL;
1331                         return rc;
1332                 } else {
1333                 /* BB other socket options to set KEEPALIVE, NODELAY? */
1334                         cFYI(1,("Socket created"));
1335                         (*csocket)->sk->sk_allocation = GFP_NOFS; 
1336                 }
1337         }
1338
1339         psin_server->sin_family = AF_INET;
1340         if(psin_server->sin_port) { /* user overrode default port */
1341                 rc = (*csocket)->ops->connect(*csocket,
1342                                 (struct sockaddr *) psin_server,
1343                                 sizeof (struct sockaddr_in),0);
1344                 if (rc >= 0)
1345                         connected = 1;
1346         } 
1347
1348         if(!connected) {
1349                 /* save original port so we can retry user specified port  
1350                         later if fall back ports fail this time  */
1351                 orig_port = psin_server->sin_port;
1352
1353                 /* do not retry on the same port we just failed on */
1354                 if(psin_server->sin_port != htons(CIFS_PORT)) {
1355                         psin_server->sin_port = htons(CIFS_PORT);
1356
1357                         rc = (*csocket)->ops->connect(*csocket,
1358                                         (struct sockaddr *) psin_server,
1359                                         sizeof (struct sockaddr_in),0);
1360                         if (rc >= 0)
1361                                 connected = 1;
1362                 }
1363         }
1364         if (!connected) {
1365                 psin_server->sin_port = htons(RFC1001_PORT);
1366                 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1367                                               psin_server, sizeof (struct sockaddr_in),0);
1368                 if (rc >= 0) 
1369                         connected = 1;
1370         }
1371
1372         /* give up here - unless we want to retry on different
1373                 protocol families some day */
1374         if (!connected) {
1375                 if(orig_port)
1376                         psin_server->sin_port = orig_port;
1377                 cFYI(1,("Error %d connecting to server via ipv4",rc));
1378                 sock_release(*csocket);
1379                 *csocket = NULL;
1380                 return rc;
1381         }
1382         /* Eventually check for other socket options to change from 
1383                 the default. sock_setsockopt not used because it expects 
1384                 user space buffer */
1385         (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1386
1387         /* send RFC1001 sessinit */
1388
1389         if(psin_server->sin_port == htons(RFC1001_PORT)) {
1390                 /* some servers require RFC1001 sessinit before sending
1391                 negprot - BB check reconnection in case where second 
1392                 sessinit is sent but no second negprot */
1393                 struct rfc1002_session_packet * ses_init_buf;
1394                 struct smb_hdr * smb_buf;
1395                 ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
1396                 if(ses_init_buf) {
1397                         ses_init_buf->trailer.session_req.called_len = 32;
1398                         if(target_name && (target_name[0] != 0)) {
1399                                 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1400                                         target_name, 16);
1401                         } else {
1402                                 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1403                                         DEFAULT_CIFS_CALLED_NAME,16);
1404                         }
1405
1406                         ses_init_buf->trailer.session_req.calling_len = 32;
1407                         /* calling name ends in null (byte 16) from old smb
1408                         convention. */
1409                         if(netbios_name && (netbios_name[0] !=0)) {
1410                                 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1411                                         netbios_name,16);
1412                         } else {
1413                                 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1414                                         "LINUX_CIFS_CLNT",16);
1415                         }
1416                         ses_init_buf->trailer.session_req.scope1 = 0;
1417                         ses_init_buf->trailer.session_req.scope2 = 0;
1418                         smb_buf = (struct smb_hdr *)ses_init_buf;
1419                         /* sizeof RFC1002_SESSION_REQUEST with no scope */
1420                         smb_buf->smb_buf_length = 0x81000044;
1421                         rc = smb_send(*csocket, smb_buf, 0x44,
1422                                 (struct sockaddr *)psin_server);
1423                         kfree(ses_init_buf);
1424                 }
1425                 /* else the negprot may still work without this 
1426                 even though malloc failed */
1427                 
1428         }
1429                 
1430         return rc;
1431 }
1432
1433 static int
1434 ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1435 {
1436         int rc = 0;
1437         int connected = 0;
1438         __be16 orig_port = 0;
1439
1440         if(*csocket == NULL) {
1441                 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1442                 if (rc < 0) {
1443                         cERROR(1, ("Error %d creating ipv6 socket",rc));
1444                         *csocket = NULL;
1445                         return rc;
1446                 } else {
1447                 /* BB other socket options to set KEEPALIVE, NODELAY? */
1448                          cFYI(1,("ipv6 Socket created"));
1449                         (*csocket)->sk->sk_allocation = GFP_NOFS;
1450                 }
1451         }
1452
1453         psin_server->sin6_family = AF_INET6;
1454
1455         if(psin_server->sin6_port) { /* user overrode default port */
1456                 rc = (*csocket)->ops->connect(*csocket,
1457                                 (struct sockaddr *) psin_server,
1458                                 sizeof (struct sockaddr_in6),0);
1459                 if (rc >= 0)
1460                         connected = 1;
1461         } 
1462
1463         if(!connected) {
1464                 /* save original port so we can retry user specified port  
1465                         later if fall back ports fail this time  */
1466
1467                 orig_port = psin_server->sin6_port;
1468                 /* do not retry on the same port we just failed on */
1469                 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1470                         psin_server->sin6_port = htons(CIFS_PORT);
1471
1472                         rc = (*csocket)->ops->connect(*csocket,
1473                                         (struct sockaddr *) psin_server,
1474                                         sizeof (struct sockaddr_in6),0);
1475                         if (rc >= 0)
1476                                 connected = 1;
1477                 }
1478         }
1479         if (!connected) {
1480                 psin_server->sin6_port = htons(RFC1001_PORT);
1481                 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1482                                          psin_server, sizeof (struct sockaddr_in6),0);
1483                 if (rc >= 0) 
1484                         connected = 1;
1485         }
1486
1487         /* give up here - unless we want to retry on different
1488                 protocol families some day */
1489         if (!connected) {
1490                 if(orig_port)
1491                         psin_server->sin6_port = orig_port;
1492                 cFYI(1,("Error %d connecting to server via ipv6",rc));
1493                 sock_release(*csocket);
1494                 *csocket = NULL;
1495                 return rc;
1496         }
1497         /* Eventually check for other socket options to change from 
1498                 the default. sock_setsockopt not used because it expects 
1499                 user space buffer */
1500         (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1501                 
1502         return rc;
1503 }
1504
1505 int
1506 cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1507            char *mount_data, const char *devname)
1508 {
1509         int rc = 0;
1510         int xid;
1511         int address_type = AF_INET;
1512         struct socket *csocket = NULL;
1513         struct sockaddr_in sin_server;
1514         struct sockaddr_in6 sin_server6;
1515         struct smb_vol volume_info;
1516         struct cifsSesInfo *pSesInfo = NULL;
1517         struct cifsSesInfo *existingCifsSes = NULL;
1518         struct cifsTconInfo *tcon = NULL;
1519         struct TCP_Server_Info *srvTcp = NULL;
1520
1521         xid = GetXid();
1522
1523 /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1524         
1525         memset(&volume_info,0,sizeof(struct smb_vol));
1526         if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1527                 if(volume_info.UNC)
1528                         kfree(volume_info.UNC);
1529                 if(volume_info.password)
1530                         kfree(volume_info.password);
1531                 FreeXid(xid);
1532                 return -EINVAL;
1533         }
1534
1535         if (volume_info.username) {
1536                 /* BB fixme parse for domain name here */
1537                 cFYI(1, ("Username: %s ", volume_info.username));
1538
1539         } else {
1540                 cifserror("No username specified ");
1541         /* In userspace mount helper we can get user name from alternate
1542            locations such as env variables and files on disk */
1543                 if(volume_info.UNC)
1544                         kfree(volume_info.UNC);
1545                 if(volume_info.password)
1546                         kfree(volume_info.password);
1547                 FreeXid(xid);
1548                 return -EINVAL;
1549         }
1550
1551         if (volume_info.UNCip && volume_info.UNC) {
1552                 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1553
1554                 if(rc <= 0) {
1555                         /* not ipv4 address, try ipv6 */
1556                         rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u); 
1557                         if(rc > 0)
1558                                 address_type = AF_INET6;
1559                 } else {
1560                         address_type = AF_INET;
1561                 }
1562        
1563                 if(rc <= 0) {
1564                         /* we failed translating address */
1565                         if(volume_info.UNC)
1566                                 kfree(volume_info.UNC);
1567                         if(volume_info.password)
1568                                 kfree(volume_info.password);
1569                         FreeXid(xid);
1570                         return -EINVAL;
1571                 }
1572
1573                 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1574                 /* success */
1575                 rc = 0;
1576         } else if (volume_info.UNCip){
1577                 /* BB using ip addr as server name connect to the DFS root below */
1578                 cERROR(1,("Connecting to DFS root not implemented yet"));
1579                 if(volume_info.UNC)
1580                         kfree(volume_info.UNC);
1581                 if(volume_info.password)
1582                         kfree(volume_info.password);
1583                 FreeXid(xid);
1584                 return -EINVAL;
1585         } else /* which servers DFS root would we conect to */ {
1586                 cERROR(1,
1587                        ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified  "));
1588                 if(volume_info.UNC)
1589                         kfree(volume_info.UNC);
1590                 if(volume_info.password)
1591                         kfree(volume_info.password);
1592                 FreeXid(xid);
1593                 return -EINVAL;
1594         }
1595
1596         /* this is needed for ASCII cp to Unicode converts */
1597         if(volume_info.iocharset == NULL) {
1598                 cifs_sb->local_nls = load_nls_default();
1599         /* load_nls_default can not return null */
1600         } else {
1601                 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1602                 if(cifs_sb->local_nls == NULL) {
1603                         cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1604                         if(volume_info.UNC)
1605                                 kfree(volume_info.UNC);
1606                         if(volume_info.password)
1607                                 kfree(volume_info.password);
1608                         FreeXid(xid);
1609                         return -ELIBACC;
1610                 }
1611         }
1612
1613         if(address_type == AF_INET)
1614                 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1615                         NULL /* no ipv6 addr */,
1616                         volume_info.username, &srvTcp);
1617         else if(address_type == AF_INET6)
1618                 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1619                         &sin_server6.sin6_addr,
1620                         volume_info.username, &srvTcp);
1621         else {
1622                 if(volume_info.UNC)
1623                         kfree(volume_info.UNC);
1624                 if(volume_info.password)
1625                         kfree(volume_info.password);
1626                 FreeXid(xid);
1627                 return -EINVAL;
1628         }
1629
1630
1631         if (srvTcp) {
1632                 cFYI(1, ("Existing tcp session with server found "));                
1633         } else {        /* create socket */
1634                 if(volume_info.port)
1635                         sin_server.sin_port = htons(volume_info.port);
1636                 else
1637                         sin_server.sin_port = 0;
1638                 rc = ipv4_connect(&sin_server,&csocket,
1639                                   volume_info.source_rfc1001_name,
1640                                   volume_info.target_rfc1001_name);
1641                 if (rc < 0) {
1642                         cERROR(1,
1643                                ("Error connecting to IPv4 socket. Aborting operation"));
1644                         if(csocket != NULL)
1645                                 sock_release(csocket);
1646                         if(volume_info.UNC)
1647                                 kfree(volume_info.UNC);
1648                         if(volume_info.password)
1649                                 kfree(volume_info.password);
1650                         FreeXid(xid);
1651                         return rc;
1652                 }
1653
1654                 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1655                 if (srvTcp == NULL) {
1656                         rc = -ENOMEM;
1657                         sock_release(csocket);
1658                         if(volume_info.UNC)
1659                                 kfree(volume_info.UNC);
1660                         if(volume_info.password)
1661                                 kfree(volume_info.password);
1662                         FreeXid(xid);
1663                         return rc;
1664                 } else {
1665                         memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1666                         memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1667                         atomic_set(&srvTcp->inFlight,0);
1668                         /* BB Add code for ipv6 case too */
1669                         srvTcp->ssocket = csocket;
1670                         srvTcp->protocolType = IPV4;
1671                         init_waitqueue_head(&srvTcp->response_q);
1672                         init_waitqueue_head(&srvTcp->request_q);
1673                         INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1674                         /* at this point we are the only ones with the pointer
1675                         to the struct since the kernel thread not created yet
1676                         so no need to spinlock this init of tcpStatus */
1677                         srvTcp->tcpStatus = CifsNew;
1678                         init_MUTEX(&srvTcp->tcpSem);
1679                         rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1680                                       CLONE_FS | CLONE_FILES | CLONE_VM);
1681                         if(rc < 0) {
1682                                 rc = -ENOMEM;
1683                                 sock_release(csocket);
1684                                 if(volume_info.UNC)
1685                                         kfree(volume_info.UNC);
1686                                 if(volume_info.password)
1687                                         kfree(volume_info.password);
1688                                 FreeXid(xid);
1689                                 return rc;
1690                         }
1691                         wait_for_completion(&cifsd_complete);
1692                         rc = 0;
1693                         memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
1694                         memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
1695                         srvTcp->sequence_number = 0;
1696                 }
1697         }
1698
1699         if (existingCifsSes) {
1700                 pSesInfo = existingCifsSes;
1701                 cFYI(1, ("Existing smb sess found "));
1702                 if(volume_info.password)
1703                         kfree(volume_info.password);
1704                 /* volume_info.UNC freed at end of function */
1705         } else if (!rc) {
1706                 cFYI(1, ("Existing smb sess not found "));
1707                 pSesInfo = sesInfoAlloc();
1708                 if (pSesInfo == NULL)
1709                         rc = -ENOMEM;
1710                 else {
1711                         pSesInfo->server = srvTcp;
1712                         sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1713                                 NIPQUAD(sin_server.sin_addr.s_addr));
1714                 }
1715
1716                 if (!rc){
1717                         /* volume_info.password freed at unmount */   
1718                         if (volume_info.password)
1719                                 pSesInfo->password = volume_info.password;
1720                         if (volume_info.username)
1721                                 strncpy(pSesInfo->userName,
1722                                         volume_info.username,MAX_USERNAME_SIZE);
1723                         if (volume_info.domainname)
1724                                 strncpy(pSesInfo->domainName,
1725                                         volume_info.domainname,MAX_USERNAME_SIZE);
1726                         pSesInfo->linux_uid = volume_info.linux_uid;
1727                         down(&pSesInfo->sesSem);
1728                         rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1729                         up(&pSesInfo->sesSem);
1730                         if(!rc)
1731                                 atomic_inc(&srvTcp->socketUseCount);
1732                 } else
1733                         if(volume_info.password)
1734                                 kfree(volume_info.password);
1735         }
1736     
1737         /* search for existing tcon to this server share */
1738         if (!rc) {
1739                 if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
1740                         cifs_sb->rsize = volume_info.rsize;
1741                 else
1742                         cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1743                 if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
1744                         cifs_sb->wsize = volume_info.wsize;
1745                 else
1746                         cifs_sb->wsize = CIFSMaxBufSize; /* default */
1747                 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
1748                         cifs_sb->rsize = PAGE_CACHE_SIZE; 
1749                         /* Windows ME does this */
1750                         cFYI(1,("Attempt to set readsize for mount to less than one page (4096)"));
1751                 }
1752                 cifs_sb->mnt_uid = volume_info.linux_uid;
1753                 cifs_sb->mnt_gid = volume_info.linux_gid;
1754                 cifs_sb->mnt_file_mode = volume_info.file_mode;
1755                 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1756                 cFYI(1,("file mode: 0x%x  dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1757
1758                 if(volume_info.noperm)
1759                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1760                 if(volume_info.setuids)
1761                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1762                 if(volume_info.server_ino)
1763                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
1764                 if(volume_info.remap)
1765                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
1766                 if(volume_info.no_xattr)
1767                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
1768                 if(volume_info.sfu_emul)
1769                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
1770                 if(volume_info.nobrl)
1771                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
1772
1773                 if(volume_info.direct_io) {
1774                         cFYI(1,("mounting share using direct i/o"));
1775                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1776                 }
1777
1778                 tcon =
1779                     find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1780                              volume_info.username);
1781                 if (tcon) {
1782                         cFYI(1, ("Found match on UNC path "));
1783                         /* we can have only one retry value for a connection
1784                            to a share so for resources mounted more than once
1785                            to the same server share the last value passed in 
1786                            for the retry flag is used */
1787                         tcon->retry = volume_info.retry;
1788                         tcon->nocase = volume_info.nocase;
1789                 } else {
1790                         tcon = tconInfoAlloc();
1791                         if (tcon == NULL)
1792                                 rc = -ENOMEM;
1793                         else {
1794                                 /* check for null share name ie connect to dfs root */
1795
1796                                 /* BB check if this works for exactly length three strings */
1797                                 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1798                                     && (strchr(volume_info.UNC + 3, '/') ==
1799                                         NULL)) {
1800                                         rc = connect_to_dfs_path(xid, pSesInfo,
1801                                                         "", cifs_sb->local_nls,
1802                                                         cifs_sb->mnt_cifs_flags & 
1803                                                           CIFS_MOUNT_MAP_SPECIAL_CHR);
1804                                         if(volume_info.UNC)
1805                                                 kfree(volume_info.UNC);
1806                                         FreeXid(xid);
1807                                         return -ENODEV;
1808                                 } else {
1809                                         rc = CIFSTCon(xid, pSesInfo, 
1810                                                 volume_info.UNC,
1811                                                 tcon, cifs_sb->local_nls);
1812                                         cFYI(1, ("CIFS Tcon rc = %d", rc));
1813                                 }
1814                                 if (!rc) {
1815                                         atomic_inc(&pSesInfo->inUse);
1816                                         tcon->retry = volume_info.retry;
1817                                         tcon->nocase = volume_info.nocase;
1818                                 }
1819                         }
1820                 }
1821         }
1822         if(pSesInfo) {
1823                 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1824                         sb->s_maxbytes = (u64) 1 << 63;
1825                 } else
1826                         sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1827         }
1828
1829         sb->s_time_gran = 100;
1830
1831 /* on error free sesinfo and tcon struct if needed */
1832         if (rc) {
1833                 /* if session setup failed, use count is zero but
1834                 we still need to free cifsd thread */
1835                 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1836                         spin_lock(&GlobalMid_Lock);
1837                         srvTcp->tcpStatus = CifsExiting;
1838                         spin_unlock(&GlobalMid_Lock);
1839                         if(srvTcp->tsk) {
1840                                 send_sig(SIGKILL,srvTcp->tsk,1);
1841                                 wait_for_completion(&cifsd_complete);
1842                         }
1843                 }
1844                  /* If find_unc succeeded then rc == 0 so we can not end */
1845                 if (tcon)  /* up accidently freeing someone elses tcon struct */
1846                         tconInfoFree(tcon);
1847                 if (existingCifsSes == NULL) {
1848                         if (pSesInfo) {
1849                                 if ((pSesInfo->server) && 
1850                                     (pSesInfo->status == CifsGood)) {
1851                                         int temp_rc;
1852                                         temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1853                                         /* if the socketUseCount is now zero */
1854                                         if((temp_rc == -ESHUTDOWN) &&
1855                                            (pSesInfo->server->tsk)) {
1856                                                 send_sig(SIGKILL,pSesInfo->server->tsk,1);
1857                                                 wait_for_completion(&cifsd_complete);
1858                                         }
1859                                 } else
1860                                         cFYI(1, ("No session or bad tcon"));
1861                                 sesInfoFree(pSesInfo);
1862                                 /* pSesInfo = NULL; */
1863                         }
1864                 }
1865         } else {
1866                 atomic_inc(&tcon->useCount);
1867                 cifs_sb->tcon = tcon;
1868                 tcon->ses = pSesInfo;
1869
1870                 /* do not care if following two calls succeed - informational only */
1871                 CIFSSMBQFSDeviceInfo(xid, tcon);
1872                 CIFSSMBQFSAttributeInfo(xid, tcon);
1873                 if (tcon->ses->capabilities & CAP_UNIX) {
1874                         if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
1875                                 if(!volume_info.no_psx_acl) {
1876                                         if(CIFS_UNIX_POSIX_ACL_CAP & 
1877                                            le64_to_cpu(tcon->fsUnixInfo.Capability))
1878                                                 cFYI(1,("server negotiated posix acl support"));
1879                                                 sb->s_flags |= MS_POSIXACL;
1880                                 }
1881
1882                                 /* Try and negotiate POSIX pathnames if we can. */
1883                                 if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
1884                                     le64_to_cpu(tcon->fsUnixInfo.Capability))) {
1885                                         if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP))  {
1886                                                 cFYI(1,("negotiated posix pathnames support"));
1887                                                 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
1888                                         } else {
1889                                                 cFYI(1,("posix pathnames support requested but not supported"));
1890                                         }
1891                                 }
1892                         }
1893                 }
1894         }
1895
1896         /* volume_info.password is freed above when existing session found
1897         (in which case it is not needed anymore) but when new sesion is created
1898         the password ptr is put in the new session structure (in which case the
1899         password will be freed at unmount time) */
1900         if(volume_info.UNC)
1901                 kfree(volume_info.UNC);
1902         FreeXid(xid);
1903         return rc;
1904 }
1905
1906 static int
1907 CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1908               char session_key[CIFS_SESSION_KEY_SIZE],
1909               const struct nls_table *nls_codepage)
1910 {
1911         struct smb_hdr *smb_buffer;
1912         struct smb_hdr *smb_buffer_response;
1913         SESSION_SETUP_ANDX *pSMB;
1914         SESSION_SETUP_ANDX *pSMBr;
1915         char *bcc_ptr;
1916         char *user;
1917         char *domain;
1918         int rc = 0;
1919         int remaining_words = 0;
1920         int bytes_returned = 0;
1921         int len;
1922         __u32 capabilities;
1923         __u16 count;
1924
1925         cFYI(1, ("In sesssetup "));
1926         if(ses == NULL)
1927                 return -EINVAL;
1928         user = ses->userName;
1929         domain = ses->domainName;
1930         smb_buffer = cifs_buf_get();
1931         if (smb_buffer == NULL) {
1932                 return -ENOMEM;
1933         }
1934         smb_buffer_response = smb_buffer;
1935         pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1936
1937         /* send SMBsessionSetup here */
1938         header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1939                         NULL /* no tCon exists yet */ , 13 /* wct */ );
1940
1941         smb_buffer->Mid = GetNextMid(ses->server);
1942         pSMB->req_no_secext.AndXCommand = 0xFF;
1943         pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1944         pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1945
1946         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1947                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1948
1949         capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1950                 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1951         if (ses->capabilities & CAP_UNICODE) {
1952                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1953                 capabilities |= CAP_UNICODE;
1954         }
1955         if (ses->capabilities & CAP_STATUS32) {
1956                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1957                 capabilities |= CAP_STATUS32;
1958         }
1959         if (ses->capabilities & CAP_DFS) {
1960                 smb_buffer->Flags2 |= SMBFLG2_DFS;
1961                 capabilities |= CAP_DFS;
1962         }
1963         pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1964
1965         pSMB->req_no_secext.CaseInsensitivePasswordLength = 
1966                 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1967
1968         pSMB->req_no_secext.CaseSensitivePasswordLength =
1969             cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1970         bcc_ptr = pByteArea(smb_buffer);
1971         memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1972         bcc_ptr += CIFS_SESSION_KEY_SIZE;
1973         memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1974         bcc_ptr += CIFS_SESSION_KEY_SIZE;
1975
1976         if (ses->capabilities & CAP_UNICODE) {
1977                 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1978                         *bcc_ptr = 0;
1979                         bcc_ptr++;
1980                 }
1981                 if(user == NULL)
1982                         bytes_returned = 0; /* skill null user */
1983                 else
1984                         bytes_returned =
1985                                 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1986                                         nls_codepage);
1987                 /* convert number of 16 bit words to bytes */
1988                 bcc_ptr += 2 * bytes_returned;
1989                 bcc_ptr += 2;   /* trailing null */
1990                 if (domain == NULL)
1991                         bytes_returned =
1992                             cifs_strtoUCS((wchar_t *) bcc_ptr,
1993                                           "CIFS_LINUX_DOM", 32, nls_codepage);
1994                 else
1995                         bytes_returned =
1996                             cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1997                                           nls_codepage);
1998                 bcc_ptr += 2 * bytes_returned;
1999                 bcc_ptr += 2;
2000                 bytes_returned =
2001                     cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2002                                   32, nls_codepage);
2003                 bcc_ptr += 2 * bytes_returned;
2004                 bytes_returned =
2005                     cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
2006                                   32, nls_codepage);
2007                 bcc_ptr += 2 * bytes_returned;
2008                 bcc_ptr += 2;
2009                 bytes_returned =
2010                     cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2011                                   64, nls_codepage);
2012                 bcc_ptr += 2 * bytes_returned;
2013                 bcc_ptr += 2;
2014         } else {
2015                 if(user != NULL) {                
2016                     strncpy(bcc_ptr, user, 200);
2017                     bcc_ptr += strnlen(user, 200);
2018                 }
2019                 *bcc_ptr = 0;
2020                 bcc_ptr++;
2021                 if (domain == NULL) {
2022                         strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2023                         bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2024                 } else {
2025                         strncpy(bcc_ptr, domain, 64);
2026                         bcc_ptr += strnlen(domain, 64);
2027                         *bcc_ptr = 0;
2028                         bcc_ptr++;
2029                 }
2030                 strcpy(bcc_ptr, "Linux version ");
2031                 bcc_ptr += strlen("Linux version ");
2032                 strcpy(bcc_ptr, system_utsname.release);
2033                 bcc_ptr += strlen(system_utsname.release) + 1;
2034                 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2035                 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2036         }
2037         count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2038         smb_buffer->smb_buf_length += count;
2039         pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2040
2041         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2042                          &bytes_returned, 1);
2043         if (rc) {
2044 /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2045         } else if ((smb_buffer_response->WordCount == 3)
2046                    || (smb_buffer_response->WordCount == 4)) {
2047                 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2048                 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2049                 if (action & GUEST_LOGIN)
2050                         cFYI(1, (" Guest login"));      /* do we want to mark SesInfo struct ? */
2051                 ses->Suid = smb_buffer_response->Uid;   /* UID left in wire format (le) */
2052                 cFYI(1, ("UID = %d ", ses->Suid));
2053          /* response can have either 3 or 4 word count - Samba sends 3 */
2054                 bcc_ptr = pByteArea(smb_buffer_response);       
2055                 if ((pSMBr->resp.hdr.WordCount == 3)
2056                     || ((pSMBr->resp.hdr.WordCount == 4)
2057                         && (blob_len < pSMBr->resp.ByteCount))) {
2058                         if (pSMBr->resp.hdr.WordCount == 4)
2059                                 bcc_ptr += blob_len;
2060
2061                         if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2062                                 if ((long) (bcc_ptr) % 2) {
2063                                         remaining_words =
2064                                             (BCC(smb_buffer_response) - 1) /2;
2065                                         bcc_ptr++;      /* Unicode strings must be word aligned */
2066                                 } else {
2067                                         remaining_words =
2068                                                 BCC(smb_buffer_response) / 2;
2069                                 }
2070                                 len =
2071                                     UniStrnlen((wchar_t *) bcc_ptr,
2072                                                remaining_words - 1);
2073 /* We look for obvious messed up bcc or strings in response so we do not go off
2074    the end since (at least) WIN2K and Windows XP have a major bug in not null
2075    terminating last Unicode string in response  */
2076                                 ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
2077                                 if(ses->serverOS == NULL)
2078                                         goto sesssetup_nomem;
2079                                 cifs_strfromUCS_le(ses->serverOS,
2080                                            (wchar_t *)bcc_ptr, len,nls_codepage);
2081                                 bcc_ptr += 2 * (len + 1);
2082                                 remaining_words -= len + 1;
2083                                 ses->serverOS[2 * len] = 0;
2084                                 ses->serverOS[1 + (2 * len)] = 0;
2085                                 if (remaining_words > 0) {
2086                                         len = UniStrnlen((wchar_t *)bcc_ptr,
2087                                                          remaining_words-1);
2088                                         ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
2089                                         if(ses->serverNOS == NULL)
2090                                                 goto sesssetup_nomem;
2091                                         cifs_strfromUCS_le(ses->serverNOS,
2092                                                            (wchar_t *)bcc_ptr,len,nls_codepage);
2093                                         bcc_ptr += 2 * (len + 1);
2094                                         ses->serverNOS[2 * len] = 0;
2095                                         ses->serverNOS[1 + (2 * len)] = 0;
2096                                         if(strncmp(ses->serverNOS,
2097                                                 "NT LAN Manager 4",16) == 0) {
2098                                                 cFYI(1,("NT4 server"));
2099                                                 ses->flags |= CIFS_SES_NT4;
2100                                         }
2101                                         remaining_words -= len + 1;
2102                                         if (remaining_words > 0) {
2103                                                 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2104           /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2105                                                 ses->serverDomain =
2106                                                     kcalloc(1, 2*(len+1),GFP_KERNEL);
2107                                                 if(ses->serverDomain == NULL)
2108                                                         goto sesssetup_nomem;
2109                                                 cifs_strfromUCS_le(ses->serverDomain,
2110                                                      (wchar_t *)bcc_ptr,len,nls_codepage);
2111                                                 bcc_ptr += 2 * (len + 1);
2112                                                 ses->serverDomain[2*len] = 0;
2113                                                 ses->serverDomain[1+(2*len)] = 0;
2114                                         } /* else no more room so create dummy domain string */
2115                                         else
2116                                                 ses->serverDomain = 
2117                                                         kcalloc(1, 2, GFP_KERNEL);
2118                                 } else {        /* no room so create dummy domain and NOS string */
2119                                         /* if these kcallocs fail not much we
2120                                            can do, but better to not fail the
2121                                            sesssetup itself */
2122                                         ses->serverDomain =
2123                                             kcalloc(1, 2, GFP_KERNEL);
2124                                         ses->serverNOS =
2125                                             kcalloc(1, 2, GFP_KERNEL);
2126                                 }
2127                         } else {        /* ASCII */
2128                                 len = strnlen(bcc_ptr, 1024);
2129                                 if (((long) bcc_ptr + len) - (long)
2130                                     pByteArea(smb_buffer_response)
2131                                             <= BCC(smb_buffer_response)) {
2132                                         ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
2133                                         if(ses->serverOS == NULL)
2134                                                 goto sesssetup_nomem;
2135                                         strncpy(ses->serverOS,bcc_ptr, len);
2136
2137                                         bcc_ptr += len;
2138                                         bcc_ptr[0] = 0; /* null terminate the string */
2139                                         bcc_ptr++;
2140
2141                                         len = strnlen(bcc_ptr, 1024);
2142                                         ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
2143                                         if(ses->serverNOS == NULL)
2144                                                 goto sesssetup_nomem;
2145                                         strncpy(ses->serverNOS, bcc_ptr, len);
2146                                         bcc_ptr += len;
2147                                         bcc_ptr[0] = 0;
2148                                         bcc_ptr++;
2149
2150                                         len = strnlen(bcc_ptr, 1024);
2151                                         ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
2152                                         if(ses->serverDomain == NULL)
2153                                                 goto sesssetup_nomem;
2154                                         strncpy(ses->serverDomain, bcc_ptr, len);
2155                                         bcc_ptr += len;
2156                                         bcc_ptr[0] = 0;
2157                                         bcc_ptr++;
2158                                 } else
2159                                         cFYI(1,
2160                                              ("Variable field of length %d extends beyond end of smb ",
2161                                               len));
2162                         }
2163                 } else {
2164                         cERROR(1,
2165                                (" Security Blob Length extends beyond end of SMB"));
2166                 }
2167         } else {
2168                 cERROR(1,
2169                        (" Invalid Word count %d: ",
2170                         smb_buffer_response->WordCount));
2171                 rc = -EIO;
2172         }
2173 sesssetup_nomem:        /* do not return an error on nomem for the info strings,
2174                            since that could make reconnection harder, and
2175                            reconnection might be needed to free memory */
2176         if (smb_buffer)
2177                 cifs_buf_release(smb_buffer);
2178
2179         return rc;
2180 }
2181
2182 static int
2183 CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2184                 char *SecurityBlob,int SecurityBlobLength,
2185                 const struct nls_table *nls_codepage)
2186 {
2187         struct smb_hdr *smb_buffer;
2188         struct smb_hdr *smb_buffer_response;
2189         SESSION_SETUP_ANDX *pSMB;
2190         SESSION_SETUP_ANDX *pSMBr;
2191         char *bcc_ptr;
2192         char *user;
2193         char *domain;
2194         int rc = 0;
2195         int remaining_words = 0;
2196         int bytes_returned = 0;
2197         int len;
2198         __u32 capabilities;
2199         __u16 count;
2200
2201         cFYI(1, ("In spnego sesssetup "));
2202         if(ses == NULL)
2203                 return -EINVAL;
2204         user = ses->userName;
2205         domain = ses->domainName;
2206
2207         smb_buffer = cifs_buf_get();
2208         if (smb_buffer == NULL) {
2209                 return -ENOMEM;
2210         }
2211         smb_buffer_response = smb_buffer;
2212         pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2213
2214         /* send SMBsessionSetup here */
2215         header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2216                         NULL /* no tCon exists yet */ , 12 /* wct */ );
2217
2218         smb_buffer->Mid = GetNextMid(ses->server);
2219         pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2220         pSMB->req.AndXCommand = 0xFF;
2221         pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2222         pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2223
2224         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2225                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2226
2227         capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2228             CAP_EXTENDED_SECURITY;
2229         if (ses->capabilities & CAP_UNICODE) {
2230                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2231                 capabilities |= CAP_UNICODE;
2232         }
2233         if (ses->capabilities & CAP_STATUS32) {
2234                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2235                 capabilities |= CAP_STATUS32;
2236         }
2237         if (ses->capabilities & CAP_DFS) {
2238                 smb_buffer->Flags2 |= SMBFLG2_DFS;
2239                 capabilities |= CAP_DFS;
2240         }
2241         pSMB->req.Capabilities = cpu_to_le32(capabilities);
2242
2243         pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2244         bcc_ptr = pByteArea(smb_buffer);
2245         memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
2246         bcc_ptr += SecurityBlobLength;
2247
2248         if (ses->capabilities & CAP_UNICODE) {
2249                 if ((long) bcc_ptr % 2) {       /* must be word aligned for Unicode strings */
2250                         *bcc_ptr = 0;
2251                         bcc_ptr++;
2252                 }
2253                 bytes_returned =
2254                     cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
2255                 bcc_ptr += 2 * bytes_returned;  /* convert num of 16 bit words to bytes */
2256                 bcc_ptr += 2;   /* trailing null */
2257                 if (domain == NULL)
2258                         bytes_returned =
2259                             cifs_strtoUCS((wchar_t *) bcc_ptr,
2260                                           "CIFS_LINUX_DOM", 32, nls_codepage);
2261                 else
2262                         bytes_returned =
2263                             cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2264                                           nls_codepage);
2265                 bcc_ptr += 2 * bytes_returned;
2266                 bcc_ptr += 2;
2267                 bytes_returned =
2268                     cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2269                                   32, nls_codepage);
2270                 bcc_ptr += 2 * bytes_returned;
2271                 bytes_returned =
2272                     cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2273                                   nls_codepage);
2274                 bcc_ptr += 2 * bytes_returned;
2275                 bcc_ptr += 2;
2276                 bytes_returned =
2277                     cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2278                                   64, nls_codepage);
2279                 bcc_ptr += 2 * bytes_returned;
2280                 bcc_ptr += 2;
2281         } else {
2282                 strncpy(bcc_ptr, user, 200);
2283                 bcc_ptr += strnlen(user, 200);
2284                 *bcc_ptr = 0;
2285                 bcc_ptr++;
2286                 if (domain == NULL) {
2287                         strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2288                         bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2289                 } else {
2290                         strncpy(bcc_ptr, domain, 64);
2291                         bcc_ptr += strnlen(domain, 64);
2292                         *bcc_ptr = 0;
2293                         bcc_ptr++;
2294                 }
2295                 strcpy(bcc_ptr, "Linux version ");
2296                 bcc_ptr += strlen("Linux version ");
2297                 strcpy(bcc_ptr, system_utsname.release);
2298                 bcc_ptr += strlen(system_utsname.release) + 1;
2299                 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2300                 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2301         }
2302         count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2303         smb_buffer->smb_buf_length += count;
2304         pSMB->req.ByteCount = cpu_to_le16(count);
2305
2306         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2307                          &bytes_returned, 1);
2308         if (rc) {
2309 /*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
2310         } else if ((smb_buffer_response->WordCount == 3)
2311                    || (smb_buffer_response->WordCount == 4)) {
2312                 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2313                 __u16 blob_len =
2314                     le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2315                 if (action & GUEST_LOGIN)
2316                         cFYI(1, (" Guest login"));      /* BB do we want to set anything in SesInfo struct ? */
2317                 if (ses) {
2318                         ses->Suid = smb_buffer_response->Uid;   /* UID left in wire format (le) */
2319                         cFYI(1, ("UID = %d ", ses->Suid));
2320                         bcc_ptr = pByteArea(smb_buffer_response);       /* response can have either 3 or 4 word count - Samba sends 3 */
2321
2322                         /* BB Fix below to make endian neutral !! */
2323
2324                         if ((pSMBr->resp.hdr.WordCount == 3)
2325                             || ((pSMBr->resp.hdr.WordCount == 4)
2326                                 && (blob_len <
2327                                     pSMBr->resp.ByteCount))) {
2328                                 if (pSMBr->resp.hdr.WordCount == 4) {
2329                                         bcc_ptr +=
2330                                             blob_len;
2331                                         cFYI(1,
2332                                              ("Security Blob Length %d ",
2333                                               blob_len));
2334                                 }
2335
2336                                 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2337                                         if ((long) (bcc_ptr) % 2) {
2338                                                 remaining_words =
2339                                                     (BCC(smb_buffer_response)
2340                                                      - 1) / 2;
2341                                                 bcc_ptr++;      /* Unicode strings must be word aligned */
2342                                         } else {
2343                                                 remaining_words =
2344                                                     BCC
2345                                                     (smb_buffer_response) / 2;
2346                                         }
2347                                         len =
2348                                             UniStrnlen((wchar_t *) bcc_ptr,
2349                                                        remaining_words - 1);
2350 /* We look for obvious messed up bcc or strings in response so we do not go off
2351    the end since (at least) WIN2K and Windows XP have a major bug in not null
2352    terminating last Unicode string in response  */
2353                                         ses->serverOS =
2354                                             kcalloc(1, 2 * (len + 1), GFP_KERNEL);
2355                                         cifs_strfromUCS_le(ses->serverOS,
2356                                                            (wchar_t *)
2357                                                            bcc_ptr, len,
2358                                                            nls_codepage);
2359                                         bcc_ptr += 2 * (len + 1);
2360                                         remaining_words -= len + 1;
2361                                         ses->serverOS[2 * len] = 0;
2362                                         ses->serverOS[1 + (2 * len)] = 0;
2363                                         if (remaining_words > 0) {
2364                                                 len = UniStrnlen((wchar_t *)bcc_ptr,
2365                                                                  remaining_words
2366                                                                  - 1);
2367                                                 ses->serverNOS =
2368                                                     kcalloc(1, 2 * (len + 1),
2369                                                             GFP_KERNEL);
2370                                                 cifs_strfromUCS_le(ses->serverNOS,
2371                                                                    (wchar_t *)bcc_ptr,
2372                                                                    len,
2373                                                                    nls_codepage);
2374                                                 bcc_ptr += 2 * (len + 1);
2375                                                 ses->serverNOS[2 * len] = 0;
2376                                                 ses->serverNOS[1 + (2 * len)] = 0;
2377                                                 remaining_words -= len + 1;
2378                                                 if (remaining_words > 0) {
2379                                                         len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
2380                             /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2381                                                         ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
2382                                                         cifs_strfromUCS_le(ses->serverDomain,
2383                                                              (wchar_t *)bcc_ptr, 
2384                                  len,
2385                                                              nls_codepage);
2386                                                         bcc_ptr += 2*(len+1);
2387                                                         ses->serverDomain[2*len] = 0;
2388                                                         ses->serverDomain[1+(2*len)] = 0;
2389                                                 } /* else no more room so create dummy domain string */
2390                                                 else
2391                                                         ses->serverDomain =
2392                                                             kcalloc(1, 2,GFP_KERNEL);
2393                                         } else {        /* no room so create dummy domain and NOS string */
2394                                                 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2395                                                 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
2396                                         }
2397                                 } else {        /* ASCII */
2398
2399                                         len = strnlen(bcc_ptr, 1024);
2400                                         if (((long) bcc_ptr + len) - (long)
2401                                             pByteArea(smb_buffer_response)
2402                                             <= BCC(smb_buffer_response)) {
2403                                                 ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
2404                                                 strncpy(ses->serverOS, bcc_ptr, len);
2405
2406                                                 bcc_ptr += len;
2407                                                 bcc_ptr[0] = 0; /* null terminate the string */
2408                                                 bcc_ptr++;
2409
2410                                                 len = strnlen(bcc_ptr, 1024);
2411                                                 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
2412                                                 strncpy(ses->serverNOS, bcc_ptr, len);
2413                                                 bcc_ptr += len;
2414                                                 bcc_ptr[0] = 0;
2415                                                 bcc_ptr++;
2416
2417                                                 len = strnlen(bcc_ptr, 1024);
2418                                                 ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
2419                                                 strncpy(ses->serverDomain, bcc_ptr, len);
2420                                                 bcc_ptr += len;
2421                                                 bcc_ptr[0] = 0;
2422                                                 bcc_ptr++;
2423                                         } else
2424                                                 cFYI(1,
2425                                                      ("Variable field of length %d extends beyond end of smb ",
2426                                                       len));
2427                                 }
2428                         } else {
2429                                 cERROR(1,
2430                                        (" Security Blob Length extends beyond end of SMB"));
2431                         }
2432                 } else {
2433                         cERROR(1, ("No session structure passed in."));
2434                 }
2435         } else {
2436                 cERROR(1,
2437                        (" Invalid Word count %d: ",
2438                         smb_buffer_response->WordCount));
2439                 rc = -EIO;
2440         }
2441
2442         if (smb_buffer)
2443                 cifs_buf_release(smb_buffer);
2444
2445         return rc;
2446 }
2447
2448 static int
2449 CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2450                               struct cifsSesInfo *ses, int * pNTLMv2_flag,
2451                               const struct nls_table *nls_codepage)
2452 {
2453         struct smb_hdr *smb_buffer;
2454         struct smb_hdr *smb_buffer_response;
2455         SESSION_SETUP_ANDX *pSMB;
2456         SESSION_SETUP_ANDX *pSMBr;
2457         char *bcc_ptr;
2458         char *domain;
2459         int rc = 0;
2460         int remaining_words = 0;
2461         int bytes_returned = 0;
2462         int len;
2463         int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2464         PNEGOTIATE_MESSAGE SecurityBlob;
2465         PCHALLENGE_MESSAGE SecurityBlob2;
2466         __u32 negotiate_flags, capabilities;
2467         __u16 count;
2468
2469         cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2470         if(ses == NULL)
2471                 return -EINVAL;
2472         domain = ses->domainName;
2473         *pNTLMv2_flag = FALSE;
2474         smb_buffer = cifs_buf_get();
2475         if (smb_buffer == NULL) {
2476                 return -ENOMEM;
2477         }
2478         smb_buffer_response = smb_buffer;
2479         pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2480         pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2481
2482         /* send SMBsessionSetup here */
2483         header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2484                         NULL /* no tCon exists yet */ , 12 /* wct */ );
2485
2486         smb_buffer->Mid = GetNextMid(ses->server);
2487         pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2488         pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2489
2490         pSMB->req.AndXCommand = 0xFF;
2491         pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2492         pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2493
2494         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2495                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2496
2497         capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2498             CAP_EXTENDED_SECURITY;
2499         if (ses->capabilities & CAP_UNICODE) {
2500                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2501                 capabilities |= CAP_UNICODE;
2502         }
2503         if (ses->capabilities & CAP_STATUS32) {
2504                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2505                 capabilities |= CAP_STATUS32;
2506         }
2507         if (ses->capabilities & CAP_DFS) {
2508                 smb_buffer->Flags2 |= SMBFLG2_DFS;
2509                 capabilities |= CAP_DFS;
2510         }
2511         pSMB->req.Capabilities = cpu_to_le32(capabilities);
2512
2513         bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2514         SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2515         strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2516         SecurityBlob->MessageType = NtLmNegotiate;
2517         negotiate_flags =
2518             NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2519             NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2520             /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2521         if(sign_CIFS_PDUs)
2522                 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2523         if(ntlmv2_support)
2524                 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2525         /* setup pointers to domain name and workstation name */
2526         bcc_ptr += SecurityBlobLength;
2527
2528         SecurityBlob->WorkstationName.Buffer = 0;
2529         SecurityBlob->WorkstationName.Length = 0;
2530         SecurityBlob->WorkstationName.MaximumLength = 0;
2531
2532         if (domain == NULL) {
2533                 SecurityBlob->DomainName.Buffer = 0;
2534                 SecurityBlob->DomainName.Length = 0;
2535                 SecurityBlob->DomainName.MaximumLength = 0;
2536         } else {
2537                 __u16 len;
2538                 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2539                 strncpy(bcc_ptr, domain, 63);
2540                 len = strnlen(domain, 64);
2541                 SecurityBlob->DomainName.MaximumLength =
2542                     cpu_to_le16(len);
2543                 SecurityBlob->DomainName.Buffer =
2544                     cpu_to_le32((long) &SecurityBlob->
2545                                 DomainString -
2546                                 (long) &SecurityBlob->Signature);
2547                 bcc_ptr += len;
2548                 SecurityBlobLength += len;
2549                 SecurityBlob->DomainName.Length =
2550                     cpu_to_le16(len);
2551         }
2552         if (ses->capabilities & CAP_UNICODE) {
2553                 if ((long) bcc_ptr % 2) {
2554                         *bcc_ptr = 0;
2555                         bcc_ptr++;
2556                 }
2557
2558                 bytes_returned =
2559                     cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2560                                   32, nls_codepage);
2561                 bcc_ptr += 2 * bytes_returned;
2562                 bytes_returned =
2563                     cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2564                                   nls_codepage);
2565                 bcc_ptr += 2 * bytes_returned;
2566                 bcc_ptr += 2;   /* null terminate Linux version */
2567                 bytes_returned =
2568                     cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2569                                   64, nls_codepage);
2570                 bcc_ptr += 2 * bytes_returned;
2571                 *(bcc_ptr + 1) = 0;
2572                 *(bcc_ptr + 2) = 0;
2573                 bcc_ptr += 2;   /* null terminate network opsys string */
2574                 *(bcc_ptr + 1) = 0;
2575                 *(bcc_ptr + 2) = 0;
2576                 bcc_ptr += 2;   /* null domain */
2577         } else {                /* ASCII */
2578                 strcpy(bcc_ptr, "Linux version ");
2579                 bcc_ptr += strlen("Linux version ");
2580                 strcpy(bcc_ptr, system_utsname.release);
2581                 bcc_ptr += strlen(system_utsname.release) + 1;
2582                 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2583                 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2584                 bcc_ptr++;      /* empty domain field */
2585                 *bcc_ptr = 0;
2586         }
2587         SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2588         pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2589         count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2590         smb_buffer->smb_buf_length += count;
2591         pSMB->req.ByteCount = cpu_to_le16(count);
2592
2593         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2594                          &bytes_returned, 1);
2595
2596         if (smb_buffer_response->Status.CifsError ==
2597             cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2598                 rc = 0;
2599
2600         if (rc) {
2601 /*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
2602         } else if ((smb_buffer_response->WordCount == 3)
2603                    || (smb_buffer_response->WordCount == 4)) {
2604                 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2605                 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2606
2607                 if (action & GUEST_LOGIN)
2608                         cFYI(1, (" Guest login"));      
2609         /* Do we want to set anything in SesInfo struct when guest login? */
2610
2611                 bcc_ptr = pByteArea(smb_buffer_response);       
2612         /* response can have either 3 or 4 word count - Samba sends 3 */
2613
2614                 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2615                 if (SecurityBlob2->MessageType != NtLmChallenge) {
2616                         cFYI(1,
2617                              ("Unexpected NTLMSSP message type received %d",
2618                               SecurityBlob2->MessageType));
2619                 } else if (ses) {
2620                         ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ 
2621                         cFYI(1, ("UID = %d ", ses->Suid));
2622                         if ((pSMBr->resp.hdr.WordCount == 3)
2623                             || ((pSMBr->resp.hdr.WordCount == 4)
2624                                 && (blob_len <
2625                                     pSMBr->resp.ByteCount))) {
2626
2627                                 if (pSMBr->resp.hdr.WordCount == 4) {
2628                                         bcc_ptr += blob_len;
2629                                         cFYI(1,
2630                                              ("Security Blob Length %d ",
2631                                               blob_len));
2632                                 }
2633
2634                                 cFYI(1, ("NTLMSSP Challenge rcvd "));
2635
2636                                 memcpy(ses->server->cryptKey,
2637                                        SecurityBlob2->Challenge,
2638                                        CIFS_CRYPTO_KEY_SIZE);
2639                                 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2640                                         *pNTLMv2_flag = TRUE;
2641
2642                                 if((SecurityBlob2->NegotiateFlags & 
2643                                         cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) 
2644                                         || (sign_CIFS_PDUs > 1))
2645                                                 ses->server->secMode |= 
2646                                                         SECMODE_SIGN_REQUIRED;  
2647                                 if ((SecurityBlob2->NegotiateFlags & 
2648                                         cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2649                                                 ses->server->secMode |= 
2650                                                         SECMODE_SIGN_ENABLED;
2651
2652                                 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2653                                         if ((long) (bcc_ptr) % 2) {
2654                                                 remaining_words =
2655                                                     (BCC(smb_buffer_response)
2656                                                      - 1) / 2;
2657                                                 bcc_ptr++;      /* Unicode strings must be word aligned */
2658                                         } else {
2659                                                 remaining_words =
2660                                                     BCC
2661                                                     (smb_buffer_response) / 2;
2662                                         }
2663                                         len =
2664                                             UniStrnlen((wchar_t *) bcc_ptr,
2665                                                        remaining_words - 1);
2666 /* We look for obvious messed up bcc or strings in response so we do not go off
2667    the end since (at least) WIN2K and Windows XP have a major bug in not null
2668    terminating last Unicode string in response  */
2669                                         ses->serverOS =
2670                                             kcalloc(1, 2 * (len + 1), GFP_KERNEL);
2671                                         cifs_strfromUCS_le(ses->serverOS,
2672                                                            (wchar_t *)
2673                                                            bcc_ptr, len,
2674                                                            nls_codepage);
2675                                         bcc_ptr += 2 * (len + 1);
2676                                         remaining_words -= len + 1;
2677                                         ses->serverOS[2 * len] = 0;
2678                                         ses->serverOS[1 + (2 * len)] = 0;
2679                                         if (remaining_words > 0) {
2680                                                 len = UniStrnlen((wchar_t *)
2681                                                                  bcc_ptr,
2682                                                                  remaining_words
2683                                                                  - 1);
2684                                                 ses->serverNOS =
2685                                                     kcalloc(1, 2 * (len + 1),
2686                                                             GFP_KERNEL);
2687                                                 cifs_strfromUCS_le(ses->
2688                                                                    serverNOS,
2689                                                                    (wchar_t *)
2690                                                                    bcc_ptr,
2691                                                                    len,
2692                                                                    nls_codepage);
2693                                                 bcc_ptr += 2 * (len + 1);
2694                                                 ses->serverNOS[2 * len] = 0;
2695                                                 ses->serverNOS[1 +
2696                                                                (2 * len)] = 0;
2697                                                 remaining_words -= len + 1;
2698                                                 if (remaining_words > 0) {
2699                                                         len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
2700            /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2701                                                         ses->serverDomain =
2702                                                             kcalloc(1, 2 *
2703                                                                     (len +
2704                                                                      1),
2705                                                                     GFP_KERNEL);
2706                                                         cifs_strfromUCS_le
2707                                                             (ses->
2708                                                              serverDomain,
2709                                                              (wchar_t *)
2710                                                              bcc_ptr, len,
2711                                                              nls_codepage);
2712                                                         bcc_ptr +=
2713                                                             2 * (len + 1);
2714                                                         ses->
2715                                                             serverDomain[2
2716                                                                          * len]
2717                                                             = 0;
2718                                                         ses->
2719                                                             serverDomain[1
2720                                                                          +
2721                                                                          (2
2722                                                                           *
2723                                                                           len)]
2724                                                             = 0;
2725                                                 } /* else no more room so create dummy domain string */
2726                                                 else
2727                                                         ses->serverDomain =
2728                                                             kcalloc(1, 2,
2729                                                                     GFP_KERNEL);
2730                                         } else {        /* no room so create dummy domain and NOS string */
2731                                                 ses->serverDomain =
2732                                                     kcalloc(1, 2, GFP_KERNEL);
2733                                                 ses->serverNOS =
2734                                                     kcalloc(1, 2, GFP_KERNEL);
2735                                         }
2736                                 } else {        /* ASCII */
2737                                         len = strnlen(bcc_ptr, 1024);
2738                                         if (((long) bcc_ptr + len) - (long)
2739                                             pByteArea(smb_buffer_response)
2740                                             <= BCC(smb_buffer_response)) {
2741                                                 ses->serverOS =
2742                                                     kcalloc(1, len + 1,
2743                                                             GFP_KERNEL);
2744                                                 strncpy(ses->serverOS,
2745                                                         bcc_ptr, len);
2746
2747                                                 bcc_ptr += len;
2748                                                 bcc_ptr[0] = 0; /* null terminate string */
2749                                                 bcc_ptr++;
2750
2751                                                 len = strnlen(bcc_ptr, 1024);
2752                                                 ses->serverNOS =
2753                                                     kcalloc(1, len + 1,
2754                                                             GFP_KERNEL);
2755                                                 strncpy(ses->serverNOS, bcc_ptr, len);
2756                                                 bcc_ptr += len;
2757                                                 bcc_ptr[0] = 0;
2758                                                 bcc_ptr++;
2759
2760                                                 len = strnlen(bcc_ptr, 1024);
2761                                                 ses->serverDomain =
2762                                                     kcalloc(1, len + 1,
2763                                                             GFP_KERNEL);
2764                                                 strncpy(ses->serverDomain, bcc_ptr, len);       
2765                                                 bcc_ptr += len;
2766                                                 bcc_ptr[0] = 0;
2767                                                 bcc_ptr++;
2768                                         } else
2769                                                 cFYI(1,
2770                                                      ("Variable field of length %d extends beyond end of smb ",
2771                                                       len));
2772                                 }
2773                         } else {
2774                                 cERROR(1,
2775                                        (" Security Blob Length extends beyond end of SMB"));
2776                         }
2777                 } else {
2778                         cERROR(1, ("No session structure passed in."));
2779                 }
2780         } else {
2781                 cERROR(1,
2782                        (" Invalid Word count %d: ",
2783                         smb_buffer_response->WordCount));
2784                 rc = -EIO;
2785         }
2786
2787         if (smb_buffer)
2788                 cifs_buf_release(smb_buffer);
2789
2790         return rc;
2791 }
2792 static int
2793 CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2794                 char *ntlm_session_key, int ntlmv2_flag,
2795                 const struct nls_table *nls_codepage)
2796 {
2797         struct smb_hdr *smb_buffer;
2798         struct smb_hdr *smb_buffer_response;
2799         SESSION_SETUP_ANDX *pSMB;
2800         SESSION_SETUP_ANDX *pSMBr;
2801         char *bcc_ptr;
2802         char *user;
2803         char *domain;
2804         int rc = 0;
2805         int remaining_words = 0;
2806         int bytes_returned = 0;
2807         int len;
2808         int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2809         PAUTHENTICATE_MESSAGE SecurityBlob;
2810         __u32 negotiate_flags, capabilities;
2811         __u16 count;
2812
2813         cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2814         if(ses == NULL)
2815                 return -EINVAL;
2816         user = ses->userName;
2817         domain = ses->domainName;
2818         smb_buffer = cifs_buf_get();
2819         if (smb_buffer == NULL) {
2820                 return -ENOMEM;
2821         }
2822         smb_buffer_response = smb_buffer;
2823         pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2824         pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2825
2826         /* send SMBsessionSetup here */
2827         header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2828                         NULL /* no tCon exists yet */ , 12 /* wct */ );
2829
2830         smb_buffer->Mid = GetNextMid(ses->server);
2831         pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2832         pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2833         pSMB->req.AndXCommand = 0xFF;
2834         pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2835         pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2836
2837         pSMB->req.hdr.Uid = ses->Suid;
2838
2839         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2840                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2841
2842         capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2843             CAP_EXTENDED_SECURITY;
2844         if (ses->capabilities & CAP_UNICODE) {
2845                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2846                 capabilities |= CAP_UNICODE;
2847         }
2848         if (ses->capabilities & CAP_STATUS32) {
2849                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2850                 capabilities |= CAP_STATUS32;
2851         }
2852         if (ses->capabilities & CAP_DFS) {
2853                 smb_buffer->Flags2 |= SMBFLG2_DFS;
2854                 capabilities |= CAP_DFS;
2855         }
2856         pSMB->req.Capabilities = cpu_to_le32(capabilities);
2857
2858         bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2859         SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2860         strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2861         SecurityBlob->MessageType = NtLmAuthenticate;
2862         bcc_ptr += SecurityBlobLength;
2863         negotiate_flags = 
2864             NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2865             NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2866             0x80000000 | NTLMSSP_NEGOTIATE_128;
2867         if(sign_CIFS_PDUs)
2868                 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2869         if(ntlmv2_flag)
2870                 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2871
2872 /* setup pointers to domain name and workstation name */
2873
2874         SecurityBlob->WorkstationName.Buffer = 0;
2875         SecurityBlob->WorkstationName.Length = 0;
2876         SecurityBlob->WorkstationName.MaximumLength = 0;
2877         SecurityBlob->SessionKey.Length = 0;
2878         SecurityBlob->SessionKey.MaximumLength = 0;
2879         SecurityBlob->SessionKey.Buffer = 0;
2880
2881         SecurityBlob->LmChallengeResponse.Length = 0;
2882         SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2883         SecurityBlob->LmChallengeResponse.Buffer = 0;
2884
2885         SecurityBlob->NtChallengeResponse.Length =
2886             cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2887         SecurityBlob->NtChallengeResponse.MaximumLength =
2888             cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2889         memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2890         SecurityBlob->NtChallengeResponse.Buffer =
2891             cpu_to_le32(SecurityBlobLength);
2892         SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2893         bcc_ptr += CIFS_SESSION_KEY_SIZE;
2894
2895         if (ses->capabilities & CAP_UNICODE) {
2896                 if (domain == NULL) {
2897                         SecurityBlob->DomainName.Buffer = 0;
2898                         SecurityBlob->DomainName.Length = 0;
2899                         SecurityBlob->DomainName.MaximumLength = 0;
2900                 } else {
2901                         __u16 len =
2902                             cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2903                                           nls_codepage);
2904                         len *= 2;
2905                         SecurityBlob->DomainName.MaximumLength =
2906                             cpu_to_le16(len);
2907                         SecurityBlob->DomainName.Buffer =
2908                             cpu_to_le32(SecurityBlobLength);
2909                         bcc_ptr += len;
2910                         SecurityBlobLength += len;
2911                         SecurityBlob->DomainName.Length =
2912                             cpu_to_le16(len);
2913                 }
2914                 if (user == NULL) {
2915                         SecurityBlob->UserName.Buffer = 0;
2916                         SecurityBlob->UserName.Length = 0;
2917                         SecurityBlob->UserName.MaximumLength = 0;
2918                 } else {
2919                         __u16 len =
2920                             cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2921                                           nls_codepage);
2922                         len *= 2;
2923                         SecurityBlob->UserName.MaximumLength =
2924                             cpu_to_le16(len);
2925                         SecurityBlob->UserName.Buffer =
2926                             cpu_to_le32(SecurityBlobLength);
2927                         bcc_ptr += len;
2928                         SecurityBlobLength += len;
2929                         SecurityBlob->UserName.Length =
2930                             cpu_to_le16(len);
2931                 }
2932
2933                 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2934                    SecurityBlob->WorkstationName.Length *= 2;
2935                    SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2936                    SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2937                    bcc_ptr += SecurityBlob->WorkstationName.Length;
2938                    SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2939                    SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length);  */
2940
2941                 if ((long) bcc_ptr % 2) {
2942                         *bcc_ptr = 0;
2943                         bcc_ptr++;
2944                 }
2945                 bytes_returned =
2946                     cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2947                                   32, nls_codepage);
2948                 bcc_ptr += 2 * bytes_returned;
2949                 bytes_returned =
2950                     cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2951                                   nls_codepage);
2952                 bcc_ptr += 2 * bytes_returned;
2953                 bcc_ptr += 2;   /* null term version string */
2954                 bytes_returned =
2955                     cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2956                                   64, nls_codepage);
2957                 bcc_ptr += 2 * bytes_returned;
2958                 *(bcc_ptr + 1) = 0;
2959                 *(bcc_ptr + 2) = 0;
2960                 bcc_ptr += 2;   /* null terminate network opsys string */
2961                 *(bcc_ptr + 1) = 0;
2962                 *(bcc_ptr + 2) = 0;
2963                 bcc_ptr += 2;   /* null domain */
2964         } else {                /* ASCII */
2965                 if (domain == NULL) {
2966                         SecurityBlob->DomainName.Buffer = 0;
2967                         SecurityBlob->DomainName.Length = 0;
2968                         SecurityBlob->DomainName.MaximumLength = 0;
2969                 } else {
2970                         __u16 len;
2971                         negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2972                         strncpy(bcc_ptr, domain, 63);
2973                         len = strnlen(domain, 64);
2974                         SecurityBlob->DomainName.MaximumLength =
2975                             cpu_to_le16(len);
2976                         SecurityBlob->DomainName.Buffer =
2977                             cpu_to_le32(SecurityBlobLength);
2978                         bcc_ptr += len;
2979                         SecurityBlobLength += len;
2980                         SecurityBlob->DomainName.Length = cpu_to_le16(len);
2981                 }
2982                 if (user == NULL) {
2983                         SecurityBlob->UserName.Buffer = 0;
2984                         SecurityBlob->UserName.Length = 0;
2985                         SecurityBlob->UserName.MaximumLength = 0;
2986                 } else {
2987                         __u16 len;
2988                         strncpy(bcc_ptr, user, 63);
2989                         len = strnlen(user, 64);
2990                         SecurityBlob->UserName.MaximumLength =
2991                             cpu_to_le16(len);
2992                         SecurityBlob->UserName.Buffer =
2993                             cpu_to_le32(SecurityBlobLength);
2994                         bcc_ptr += len;
2995                         SecurityBlobLength += len;
2996                         SecurityBlob->UserName.Length = cpu_to_le16(len);
2997                 }
2998                 /* BB fill in our workstation name if known BB */
2999
3000                 strcpy(bcc_ptr, "Linux version ");
3001                 bcc_ptr += strlen("Linux version ");
3002                 strcpy(bcc_ptr, system_utsname.release);
3003                 bcc_ptr += strlen(system_utsname.release) + 1;
3004                 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3005                 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3006                 bcc_ptr++;      /* null domain */
3007                 *bcc_ptr = 0;
3008         }
3009         SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3010         pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3011         count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3012         smb_buffer->smb_buf_length += count;
3013         pSMB->req.ByteCount = cpu_to_le16(count);
3014
3015         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3016                          &bytes_returned, 1);
3017         if (rc) {
3018 /*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
3019         } else if ((smb_buffer_response->WordCount == 3)
3020                    || (smb_buffer_response->WordCount == 4)) {
3021                 __u16 action = le16_to_cpu(pSMBr->resp.Action);
3022                 __u16 blob_len =
3023                     le16_to_cpu(pSMBr->resp.SecurityBlobLength);
3024                 if (action & GUEST_LOGIN)
3025                         cFYI(1, (" Guest login"));      /* BB do we want to set anything in SesInfo struct ? */
3026 /*        if(SecurityBlob2->MessageType != NtLm??){                               
3027                  cFYI("Unexpected message type on auth response is %d ")); 
3028         } */
3029                 if (ses) {
3030                         cFYI(1,
3031                              ("Does UID on challenge %d match auth response UID %d ",
3032                               ses->Suid, smb_buffer_response->Uid));
3033                         ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
3034                         bcc_ptr = pByteArea(smb_buffer_response);       
3035             /* response can have either 3 or 4 word count - Samba sends 3 */
3036                         if ((pSMBr->resp.hdr.WordCount == 3)
3037                             || ((pSMBr->resp.hdr.WordCount == 4)
3038                                 && (blob_len <
3039                                     pSMBr->resp.ByteCount))) {
3040                                 if (pSMBr->resp.hdr.WordCount == 4) {
3041                                         bcc_ptr +=
3042                                             blob_len;
3043                                         cFYI(1,
3044                                              ("Security Blob Length %d ",
3045                                               blob_len));
3046                                 }
3047
3048                                 cFYI(1,
3049                                      ("NTLMSSP response to Authenticate "));
3050
3051                                 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3052                                         if ((long) (bcc_ptr) % 2) {
3053                                                 remaining_words =
3054                                                     (BCC(smb_buffer_response)
3055                                                      - 1) / 2;
3056                                                 bcc_ptr++;      /* Unicode strings must be word aligned */
3057                                         } else {
3058                                                 remaining_words = BCC(smb_buffer_response) / 2;
3059                                         }
3060                                         len =
3061                                             UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
3062 /* We look for obvious messed up bcc or strings in response so we do not go off
3063   the end since (at least) WIN2K and Windows XP have a major bug in not null
3064   terminating last Unicode string in response  */
3065                                         ses->serverOS =
3066                                             kcalloc(1, 2 * (len + 1), GFP_KERNEL);
3067                                         cifs_strfromUCS_le(ses->serverOS,
3068                                                            (wchar_t *)
3069                                                            bcc_ptr, len,
3070                                                            nls_codepage);
3071                                         bcc_ptr += 2 * (len + 1);
3072                                         remaining_words -= len + 1;
3073                                         ses->serverOS[2 * len] = 0;
3074                                         ses->serverOS[1 + (2 * len)] = 0;
3075                                         if (remaining_words > 0) {
3076                                                 len = UniStrnlen((wchar_t *)
3077                                                                  bcc_ptr,
3078                                                                  remaining_words
3079                                                                  - 1);
3080                                                 ses->serverNOS =
3081                                                     kcalloc(1, 2 * (len + 1),
3082                                                             GFP_KERNEL);
3083                                                 cifs_strfromUCS_le(ses->
3084                                                                    serverNOS,
3085                                                                    (wchar_t *)
3086                                                                    bcc_ptr,
3087                                                                    len,
3088                                                                    nls_codepage);
3089                                                 bcc_ptr += 2 * (len + 1);
3090                                                 ses->serverNOS[2 * len] = 0;
3091                                                 ses->serverNOS[1+(2*len)] = 0;
3092                                                 remaining_words -= len + 1;
3093                                                 if (remaining_words > 0) {
3094                                                         len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
3095      /* last string not always null terminated (e.g. for Windows XP & 2000) */
3096                                                         ses->serverDomain =
3097                                                             kcalloc(1, 2 *
3098                                                                     (len +
3099                                                                      1),
3100                                                                     GFP_KERNEL);
3101                                                         cifs_strfromUCS_le
3102                                                             (ses->
3103                                                              serverDomain,
3104                                                              (wchar_t *)
3105                                                              bcc_ptr, len,
3106                                                              nls_codepage);
3107                                                         bcc_ptr +=
3108                                                             2 * (len + 1);
3109                                                         ses->
3110                                                             serverDomain[2
3111                                                                          * len]
3112                                                             = 0;
3113                                                         ses->
3114                                                             serverDomain[1
3115                                                                          +
3116                                                                          (2
3117                                                                           *
3118                                                                           len)]
3119                                                             = 0;
3120                                                 } /* else no more room so create dummy domain string */
3121                                                 else
3122                                                         ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
3123                                         } else {  /* no room so create dummy domain and NOS string */
3124                                                 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
3125                                                 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
3126                                         }
3127                                 } else {        /* ASCII */
3128                                         len = strnlen(bcc_ptr, 1024);
3129                                         if (((long) bcc_ptr + len) - 
3130                         (long) pByteArea(smb_buffer_response) 
3131                             <= BCC(smb_buffer_response)) {
3132                                                 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
3133                                                 strncpy(ses->serverOS,bcc_ptr, len);
3134
3135                                                 bcc_ptr += len;
3136                                                 bcc_ptr[0] = 0; /* null terminate the string */
3137                                                 bcc_ptr++;
3138
3139                                                 len = strnlen(bcc_ptr, 1024);
3140                                                 ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
3141                                                 strncpy(ses->serverNOS, bcc_ptr, len);  
3142                                                 bcc_ptr += len;
3143                                                 bcc_ptr[0] = 0;
3144                                                 bcc_ptr++;
3145
3146                                                 len = strnlen(bcc_ptr, 1024);
3147                                                 ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
3148                                                 strncpy(ses->serverDomain, bcc_ptr, len);
3149                                                 bcc_ptr += len;
3150                                                 bcc_ptr[0] = 0;
3151                                                 bcc_ptr++;
3152                                         } else
3153                                                 cFYI(1,
3154                                                      ("Variable field of length %d extends beyond end of smb ",
3155                                                       len));
3156                                 }
3157                         } else {
3158                                 cERROR(1,
3159                                        (" Security Blob Length extends beyond end of SMB"));
3160                         }
3161                 } else {
3162                         cERROR(1, ("No session structure passed in."));
3163                 }
3164         } else {
3165                 cERROR(1,
3166                        (" Invalid Word count %d: ",
3167                         smb_buffer_response->WordCount));
3168                 rc = -EIO;
3169         }
3170
3171         if (smb_buffer)
3172                 cifs_buf_release(smb_buffer);
3173
3174         return rc;
3175 }
3176
3177 int
3178 CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3179          const char *tree, struct cifsTconInfo *tcon,
3180          const struct nls_table *nls_codepage)
3181 {
3182         struct smb_hdr *smb_buffer;
3183         struct smb_hdr *smb_buffer_response;
3184         TCONX_REQ *pSMB;
3185         TCONX_RSP *pSMBr;
3186         unsigned char *bcc_ptr;
3187         int rc = 0;
3188         int length;
3189         __u16 count;
3190
3191         if (ses == NULL)
3192                 return -EIO;
3193
3194         smb_buffer = cifs_buf_get();
3195         if (smb_buffer == NULL) {
3196                 return -ENOMEM;
3197         }
3198         smb_buffer_response = smb_buffer;
3199
3200         header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3201                         NULL /*no tid */ , 4 /*wct */ );
3202
3203         smb_buffer->Mid = GetNextMid(ses->server);
3204         smb_buffer->Uid = ses->Suid;
3205         pSMB = (TCONX_REQ *) smb_buffer;
3206         pSMBr = (TCONX_RSP *) smb_buffer_response;
3207
3208         pSMB->AndXCommand = 0xFF;
3209         pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
3210         pSMB->PasswordLength = cpu_to_le16(1);  /* minimum */
3211         bcc_ptr = &pSMB->Password[0];
3212         bcc_ptr++;              /* skip password */
3213
3214         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3215                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3216
3217         if (ses->capabilities & CAP_STATUS32) {
3218                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3219         }
3220         if (ses->capabilities & CAP_DFS) {
3221                 smb_buffer->Flags2 |= SMBFLG2_DFS;
3222         }
3223         if (ses->capabilities & CAP_UNICODE) {
3224                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3225                 length =
3226                     cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
3227                 bcc_ptr += 2 * length;  /* convert num of 16 bit words to bytes */
3228                 bcc_ptr += 2;   /* skip trailing null */
3229         } else {                /* ASCII */
3230
3231                 strcpy(bcc_ptr, tree);
3232                 bcc_ptr += strlen(tree) + 1;
3233         }
3234         strcpy(bcc_ptr, "?????");
3235         bcc_ptr += strlen("?????");
3236         bcc_ptr += 1;
3237         count = bcc_ptr - &pSMB->Password[0];
3238         pSMB->hdr.smb_buf_length += count;
3239         pSMB->ByteCount = cpu_to_le16(count);
3240
3241         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3242
3243         /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3244         /* above now done in SendReceive */
3245         if ((rc == 0) && (tcon != NULL)) {
3246                 tcon->tidStatus = CifsGood;
3247                 tcon->tid = smb_buffer_response->Tid;
3248                 bcc_ptr = pByteArea(smb_buffer_response);
3249                 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3250         /* skip service field (NB: this field is always ASCII) */
3251                 bcc_ptr += length + 1;  
3252                 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3253                 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3254                         length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3255                         if ((bcc_ptr + (2 * length)) -
3256                              pByteArea(smb_buffer_response) <=
3257                             BCC(smb_buffer_response)) {
3258                                 if(tcon->nativeFileSystem)
3259                                         kfree(tcon->nativeFileSystem);
3260                                 tcon->nativeFileSystem =
3261                                     kcalloc(1, length + 2, GFP_KERNEL);
3262                                 cifs_strfromUCS_le(tcon->nativeFileSystem,
3263                                                    (wchar_t *) bcc_ptr,
3264                                                    length, nls_codepage);
3265                                 bcc_ptr += 2 * length;
3266                                 bcc_ptr[0] = 0; /* null terminate the string */
3267                                 bcc_ptr[1] = 0;
3268                                 bcc_ptr += 2;
3269                         }
3270                         /* else do not bother copying these informational fields */
3271                 } else {
3272                         length = strnlen(bcc_ptr, 1024);
3273                         if ((bcc_ptr + length) -
3274                             pByteArea(smb_buffer_response) <=
3275                             BCC(smb_buffer_response)) {
3276                                 if(tcon->nativeFileSystem)
3277                                         kfree(tcon->nativeFileSystem);
3278                                 tcon->nativeFileSystem =
3279                                     kcalloc(1, length + 1, GFP_KERNEL);
3280                                 strncpy(tcon->nativeFileSystem, bcc_ptr,
3281                                         length);
3282                         }
3283                         /* else do not bother copying these informational fields */
3284                 }
3285                 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3286                 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3287         } else if ((rc == 0) && tcon == NULL) {
3288         /* all we need to save for IPC$ connection */
3289                 ses->ipc_tid = smb_buffer_response->Tid;
3290         }
3291
3292         if (smb_buffer)
3293                 cifs_buf_release(smb_buffer);
3294         return rc;
3295 }
3296
3297 int
3298 cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3299 {
3300         int rc = 0;
3301         int xid;
3302         struct cifsSesInfo *ses = NULL;
3303         struct task_struct *cifsd_task;
3304
3305         xid = GetXid();
3306
3307         if (cifs_sb->tcon) {
3308                 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3309                 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3310                 if (rc == -EBUSY) {
3311                         FreeXid(xid);
3312                         return 0;
3313                 }
3314                 tconInfoFree(cifs_sb->tcon);
3315                 if ((ses) && (ses->server)) {
3316                         /* save off task so we do not refer to ses later */
3317                         cifsd_task = ses->server->tsk;
3318                         cFYI(1, ("About to do SMBLogoff "));
3319                         rc = CIFSSMBLogoff(xid, ses);
3320                         if (rc == -EBUSY) {
3321                                 FreeXid(xid);
3322                                 return 0;
3323                         } else if (rc == -ESHUTDOWN) {
3324                                 cFYI(1,("Waking up socket by sending it signal"));
3325                                 if(cifsd_task) {
3326                                         send_sig(SIGKILL,cifsd_task,1);
3327                                         wait_for_completion(&cifsd_complete);
3328                                 }
3329                                 rc = 0;
3330                         } /* else - we have an smb session
3331                                 left on this socket do not kill cifsd */
3332                 } else
3333                         cFYI(1, ("No session or bad tcon"));
3334         }
3335         
3336         cifs_sb->tcon = NULL;
3337         if (ses) {
3338                 set_current_state(TASK_INTERRUPTIBLE);
3339                 schedule_timeout(HZ / 2);
3340         }
3341         if (ses)
3342                 sesInfoFree(ses);
3343
3344         FreeXid(xid);
3345         return rc;              /* BB check if we should always return zero here */
3346
3347
3348 int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3349                                            struct nls_table * nls_info)
3350 {
3351         int rc = 0;
3352         char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3353         int ntlmv2_flag = FALSE;
3354         int first_time = 0;
3355
3356         /* what if server changes its buffer size after dropping the session? */
3357         if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3358                 rc = CIFSSMBNegotiate(xid, pSesInfo);
3359                 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3360                         rc = CIFSSMBNegotiate(xid, pSesInfo);
3361                         if(rc == -EAGAIN) 
3362                                 rc = -EHOSTDOWN;
3363                 }
3364                 if(rc == 0) {
3365                         spin_lock(&GlobalMid_Lock);
3366                         if(pSesInfo->server->tcpStatus != CifsExiting)
3367                                 pSesInfo->server->tcpStatus = CifsGood;
3368                         else
3369                                 rc = -EHOSTDOWN;
3370                         spin_unlock(&GlobalMid_Lock);
3371
3372                 }
3373                 first_time = 1;
3374         }
3375         if (!rc) {
3376                 pSesInfo->capabilities = pSesInfo->server->capabilities;
3377                 if(linuxExtEnabled == 0)
3378                         pSesInfo->capabilities &= (~CAP_UNIX);
3379         /*      pSesInfo->sequence_number = 0;*/
3380                 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3381                         pSesInfo->server->secMode,
3382                         pSesInfo->server->capabilities,
3383                         pSesInfo->server->timeZone));
3384                 if (extended_security
3385                                 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3386                                 && (pSesInfo->server->secType == NTLMSSP)) {
3387                         cFYI(1, ("New style sesssetup "));
3388                         rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3389                                 NULL /* security blob */, 
3390                                 0 /* blob length */,
3391                                 nls_info);
3392                 } else if (extended_security
3393                            && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3394                            && (pSesInfo->server->secType == RawNTLMSSP)) {
3395                         cFYI(1, ("NTLMSSP sesssetup "));
3396                         rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3397                                                 pSesInfo,
3398                                                 &ntlmv2_flag,
3399                                                 nls_info);
3400                         if (!rc) {
3401                                 if(ntlmv2_flag) {
3402                                         char * v2_response;
3403                                         cFYI(1,("Can use more secure NTLM version 2 password hash"));
3404                                         if(CalcNTLMv2_partial_mac_key(pSesInfo, 
3405                                                 nls_info)) {
3406                                                 rc = -ENOMEM;
3407                                                 goto ss_err_exit;
3408                                         } else
3409                                                 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3410                                         if(v2_response) {
3411                                                 CalcNTLMv2_response(pSesInfo,v2_response);
3412                                 /*              if(first_time)
3413                                                         cifs_calculate_ntlmv2_mac_key(
3414                                                           pSesInfo->server->mac_signing_key, 
3415                                                           response, ntlm_session_key, */
3416                                                 kfree(v2_response);
3417                                         /* BB Put dummy sig in SessSetup PDU? */
3418                                         } else {
3419                                                 rc = -ENOMEM;
3420                                                 goto ss_err_exit;
3421                                         }
3422
3423                                 } else {
3424                                         SMBNTencrypt(pSesInfo->password,
3425                                                 pSesInfo->server->cryptKey,
3426                                                 ntlm_session_key);
3427
3428                                         if(first_time)
3429                                                 cifs_calculate_mac_key(
3430                                                         pSesInfo->server->mac_signing_key,
3431                                                         ntlm_session_key,
3432                                                         pSesInfo->password);
3433                                 }
3434                         /* for better security the weaker lanman hash not sent
3435                            in AuthSessSetup so we no longer calculate it */
3436
3437                                 rc = CIFSNTLMSSPAuthSessSetup(xid,
3438                                         pSesInfo,
3439                                         ntlm_session_key,
3440                                         ntlmv2_flag,
3441                                         nls_info);
3442                         }
3443                 } else { /* old style NTLM 0.12 session setup */
3444                         SMBNTencrypt(pSesInfo->password,
3445                                 pSesInfo->server->cryptKey,
3446                                 ntlm_session_key);
3447
3448                         if(first_time)          
3449                                 cifs_calculate_mac_key(
3450                                         pSesInfo->server->mac_signing_key,
3451                                         ntlm_session_key, pSesInfo->password);
3452
3453                         rc = CIFSSessSetup(xid, pSesInfo,
3454                                 ntlm_session_key, nls_info);
3455                 }
3456                 if (rc) {
3457                         cERROR(1,("Send error in SessSetup = %d",rc));
3458                 } else {
3459                         cFYI(1,("CIFS Session Established successfully"));
3460                         pSesInfo->status = CifsGood;
3461                 }
3462         }
3463 ss_err_exit:
3464         return rc;
3465 }
3466