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