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