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