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