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