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