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