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