4 * Copyright (C) International Business Machines Corp., 2002,2004
5 * Author(s): Steve French (sfrench@us.ibm.com)
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.
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.
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
22 #include <linux/slab.h>
23 #include <linux/ctype.h>
24 #include <linux/mempool.h>
27 #include "cifsproto.h"
28 #include "cifs_debug.h"
31 #include "cifs_unicode.h"
33 extern mempool_t
*cifs_sm_req_poolp
;
34 extern mempool_t
*cifs_req_poolp
;
35 extern struct task_struct
* oplockThread
;
37 static __u16 GlobalMid
; /* multiplex id - rotating counter */
39 /* The xid serves as a useful identifier for each incoming vfs request,
40 in a similar way to the mid which is useful to track each sent smb,
41 and CurrentXid can also provide a running counter (although it
42 will eventually wrap past zero) of the total vfs operations handled
43 since the cifs fs was mounted */
50 spin_lock(&GlobalMid_Lock
);
51 GlobalTotalActiveXid
++;
52 if (GlobalTotalActiveXid
> GlobalMaxActiveXid
)
53 GlobalMaxActiveXid
= GlobalTotalActiveXid
; /* keep high water mark for number of simultaneous vfs ops in our filesystem */
54 xid
= GlobalCurrentXid
++;
55 spin_unlock(&GlobalMid_Lock
);
60 _FreeXid(unsigned int xid
)
62 spin_lock(&GlobalMid_Lock
);
63 /* if(GlobalTotalActiveXid == 0)
65 GlobalTotalActiveXid
--;
66 spin_unlock(&GlobalMid_Lock
);
72 struct cifsSesInfo
*ret_buf
;
75 (struct cifsSesInfo
*) kmalloc(sizeof (struct cifsSesInfo
),
78 memset(ret_buf
, 0, sizeof (struct cifsSesInfo
));
79 write_lock(&GlobalSMBSeslock
);
80 atomic_inc(&sesInfoAllocCount
);
81 ret_buf
->status
= CifsNew
;
82 list_add(&ret_buf
->cifsSessionList
, &GlobalSMBSessionList
);
83 init_MUTEX(&ret_buf
->sesSem
);
84 write_unlock(&GlobalSMBSeslock
);
90 sesInfoFree(struct cifsSesInfo
*buf_to_free
)
92 if (buf_to_free
== NULL
) {
93 cFYI(1, ("Null buffer passed to sesInfoFree"));
97 write_lock(&GlobalSMBSeslock
);
98 atomic_dec(&sesInfoAllocCount
);
99 list_del(&buf_to_free
->cifsSessionList
);
100 write_unlock(&GlobalSMBSeslock
);
101 if (buf_to_free
->serverOS
)
102 kfree(buf_to_free
->serverOS
);
103 if (buf_to_free
->serverDomain
)
104 kfree(buf_to_free
->serverDomain
);
105 if (buf_to_free
->serverNOS
)
106 kfree(buf_to_free
->serverNOS
);
107 if (buf_to_free
->password
)
108 kfree(buf_to_free
->password
);
112 struct cifsTconInfo
*
115 struct cifsTconInfo
*ret_buf
;
117 (struct cifsTconInfo
*) kmalloc(sizeof (struct cifsTconInfo
),
120 memset(ret_buf
, 0, sizeof (struct cifsTconInfo
));
121 write_lock(&GlobalSMBSeslock
);
122 atomic_inc(&tconInfoAllocCount
);
123 list_add(&ret_buf
->cifsConnectionList
,
124 &GlobalTreeConnectionList
);
125 ret_buf
->tidStatus
= CifsNew
;
126 INIT_LIST_HEAD(&ret_buf
->openFileList
);
127 init_MUTEX(&ret_buf
->tconSem
);
128 #ifdef CONFIG_CIFS_STATS
129 spin_lock_init(&ret_buf
->stat_lock
);
131 write_unlock(&GlobalSMBSeslock
);
137 tconInfoFree(struct cifsTconInfo
*buf_to_free
)
139 if (buf_to_free
== NULL
) {
140 cFYI(1, ("Null buffer passed to tconInfoFree"));
143 write_lock(&GlobalSMBSeslock
);
144 atomic_dec(&tconInfoAllocCount
);
145 list_del(&buf_to_free
->cifsConnectionList
);
146 write_unlock(&GlobalSMBSeslock
);
147 if (buf_to_free
->nativeFileSystem
)
148 kfree(buf_to_free
->nativeFileSystem
);
155 struct smb_hdr
*ret_buf
= NULL
;
157 /* We could use negotiated size instead of max_msgsize -
158 but it may be more efficient to always alloc same size
159 albeit slightly larger than necessary and maxbuffersize
160 defaults to this and can not be bigger */
162 (struct smb_hdr
*) mempool_alloc(cifs_req_poolp
, SLAB_KERNEL
| SLAB_NOFS
);
164 /* clear the first few header bytes */
165 /* for most paths, more is cleared in header_assemble */
167 memset(ret_buf
, 0, sizeof(struct smb_hdr
) + 3);
168 atomic_inc(&bufAllocCount
);
175 cifs_buf_release(void *buf_to_free
)
178 if (buf_to_free
== NULL
) {
179 /* cFYI(1, ("Null buffer passed to cifs_buf_release"));*/
182 mempool_free(buf_to_free
,cifs_req_poolp
);
184 atomic_dec(&bufAllocCount
);
189 cifs_small_buf_get(void)
191 struct smb_hdr
*ret_buf
= NULL
;
193 /* We could use negotiated size instead of max_msgsize -
194 but it may be more efficient to always alloc same size
195 albeit slightly larger than necessary and maxbuffersize
196 defaults to this and can not be bigger */
198 (struct smb_hdr
*) mempool_alloc(cifs_sm_req_poolp
, SLAB_KERNEL
| SLAB_NOFS
);
200 /* No need to clear memory here, cleared in header assemble */
201 /* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/
202 atomic_inc(&smBufAllocCount
);
208 cifs_small_buf_release(void *buf_to_free
)
211 if (buf_to_free
== NULL
) {
212 cFYI(1, ("Null buffer passed to cifs_small_buf_release"));
215 mempool_free(buf_to_free
,cifs_sm_req_poolp
);
217 atomic_dec(&smBufAllocCount
);
222 header_assemble(struct smb_hdr
*buffer
, char smb_command
/* command */ ,
223 const struct cifsTconInfo
*treeCon
, int word_count
224 /* length of fixed section (word count) in two byte units */)
226 struct list_head
* temp_item
;
227 struct cifsSesInfo
* ses
;
228 char *temp
= (char *) buffer
;
230 memset(temp
,0,MAX_CIFS_HDR_SIZE
);
232 buffer
->smb_buf_length
=
233 (2 * word_count
) + sizeof (struct smb_hdr
) -
234 4 /* RFC 1001 length field does not count */ +
235 2 /* for bcc field itself */ ;
236 /* Note that this is the only network field that has to be converted to big endian and it is done just before we send it */
238 buffer
->Protocol
[0] = 0xFF;
239 buffer
->Protocol
[1] = 'S';
240 buffer
->Protocol
[2] = 'M';
241 buffer
->Protocol
[3] = 'B';
242 buffer
->Command
= smb_command
;
243 buffer
->Flags
= 0x00; /* case sensitive */
244 buffer
->Flags2
= SMBFLG2_KNOWS_LONG_NAMES
;
245 buffer
->Pid
= cpu_to_le16((__u16
)current
->tgid
);
246 buffer
->PidHigh
= cpu_to_le16((__u16
)(current
->tgid
>> 16));
247 spin_lock(&GlobalMid_Lock
);
249 buffer
->Mid
= GlobalMid
;
250 spin_unlock(&GlobalMid_Lock
);
252 buffer
->Tid
= treeCon
->tid
;
254 if (treeCon
->ses
->capabilities
& CAP_UNICODE
)
255 buffer
->Flags2
|= SMBFLG2_UNICODE
;
256 if (treeCon
->ses
->capabilities
& CAP_STATUS32
) {
257 buffer
->Flags2
|= SMBFLG2_ERR_STATUS
;
260 buffer
->Uid
= treeCon
->ses
->Suid
; /* always in LE format */
261 if(multiuser_mount
!= 0) {
262 /* For the multiuser case, there are few obvious technically */
263 /* possible mechanisms to match the local linux user (uid) */
264 /* to a valid remote smb user (smb_uid): */
265 /* 1) Query Winbind (or other local pam/nss daemon */
266 /* for userid/password/logon_domain or credential */
267 /* 2) Query Winbind for uid to sid to username mapping */
268 /* and see if we have a matching password for existing*/
269 /* session for that user perhas getting password by */
270 /* adding a new pam_cifs module that stores passwords */
271 /* so that the cifs vfs can get at that for all logged*/
273 /* 3) (Which is the mechanism we have chosen) */
274 /* Search through sessions to the same server for a */
275 /* a match on the uid that was passed in on mount */
276 /* with the current processes uid (or euid?) and use */
277 /* that smb uid. If no existing smb session for */
278 /* that uid found, use the default smb session ie */
279 /* the smb session for the volume mounted which is */
280 /* the same as would be used if the multiuser mount */
281 /* flag were disabled. */
283 /* BB Add support for establishing new tCon and SMB Session */
284 /* with userid/password pairs found on the smb session */
285 /* for other target tcp/ip addresses BB */
286 if(current
->uid
!= treeCon
->ses
->linux_uid
) {
287 cFYI(1,("Multiuser mode and UID did not match tcon uid "));
288 read_lock(&GlobalSMBSeslock
);
289 list_for_each(temp_item
, &GlobalSMBSessionList
) {
290 ses
= list_entry(temp_item
, struct cifsSesInfo
, cifsSessionList
);
291 if(ses
->linux_uid
== current
->uid
) {
292 if(ses
->server
== treeCon
->ses
->server
) {
293 cFYI(1,("found matching uid substitute right smb_uid"));
294 buffer
->Uid
= ses
->Suid
;
297 /* BB eventually call cifs_setup_session here */
298 cFYI(1,("local UID found but smb sess with this server does not exist"));
302 read_unlock(&GlobalSMBSeslock
);
306 if (treeCon
->Flags
& SMB_SHARE_IS_IN_DFS
)
307 buffer
->Flags2
|= SMBFLG2_DFS
;
308 if((treeCon
->ses
) && (treeCon
->ses
->server
))
309 if(treeCon
->ses
->server
->secMode
&
310 (SECMODE_SIGN_REQUIRED
| SECMODE_SIGN_ENABLED
))
311 buffer
->Flags2
|= SMBFLG2_SECURITY_SIGNATURE
;
314 /* endian conversion of flags is now done just before sending */
315 buffer
->WordCount
= (char) word_count
;
320 checkSMBhdr(struct smb_hdr
*smb
, __u16 mid
)
322 /* Make sure that this really is an SMB, that it is a response,
323 and that the message ids match */
324 if ((*(__le32
*) smb
->Protocol
== cpu_to_le32(0x424d53ff)) &&
326 if(smb
->Flags
& SMBFLG_RESPONSE
)
329 /* only one valid case where server sends us request */
330 if(smb
->Command
== SMB_COM_LOCKING_ANDX
)
333 cERROR(1, ("Rcvd Request not response "));
335 } else { /* bad signature or mid */
336 if (*(__le32
*) smb
->Protocol
!= cpu_to_le32(0x424d53ff))
338 ("Bad protocol string signature header %x ",
339 *(unsigned int *) smb
->Protocol
));
341 cERROR(1, ("Mids do not match"));
343 cERROR(1, ("bad smb detected. The Mid=%d", smb
->Mid
));
348 checkSMB(struct smb_hdr
*smb
, __u16 mid
, int length
)
350 __u32 len
= be32_to_cpu(smb
->smb_buf_length
);
352 ("Entering checkSMB with Length: %x, smb_buf_length: %x ",
354 if (((unsigned int)length
< 2 + sizeof (struct smb_hdr
)) ||
355 (len
> CIFSMaxBufSize
+ MAX_CIFS_HDR_SIZE
- 4)) {
356 if ((unsigned int)length
< 2 + sizeof (struct smb_hdr
)) {
357 if (((unsigned int)length
>=
358 sizeof (struct smb_hdr
) - 1)
359 && (smb
->Status
.CifsError
!= 0)) {
361 return 0; /* some error cases do not return wct and bcc */
363 cERROR(1, ("Length less than smb header size"));
367 if (len
> CIFSMaxBufSize
+ MAX_CIFS_HDR_SIZE
- 4)
369 ("smb_buf_length greater than MaxBufSize"));
371 ("bad smb detected. Illegal length. The mid=%d",
376 if (checkSMBhdr(smb
, mid
))
379 if ((4 + len
!= smbCalcSize(smb
))
380 || (4 + len
!= (unsigned int)length
)) {
383 cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb
)));
385 ("bad smb size detected. The Mid=%d", smb
->Mid
));
390 is_valid_oplock_break(struct smb_hdr
*buf
)
392 struct smb_com_lock_req
* pSMB
= (struct smb_com_lock_req
*)buf
;
393 struct list_head
*tmp
;
394 struct list_head
*tmp1
;
395 struct cifsTconInfo
*tcon
;
396 struct cifsFileInfo
*netfile
;
398 cFYI(1,("Checking for oplock break or dnotify response"));
399 if((pSMB
->hdr
.Command
== SMB_COM_NT_TRANSACT
) &&
400 (pSMB
->hdr
.Flags
& SMBFLG_RESPONSE
)) {
401 struct smb_com_transaction_change_notify_rsp
* pSMBr
=
402 (struct smb_com_transaction_change_notify_rsp
*)buf
;
403 struct file_notify_information
* pnotify
;
404 __u32 data_offset
= 0;
405 if(pSMBr
->ByteCount
> sizeof(struct file_notify_information
)) {
406 data_offset
= le32_to_cpu(pSMBr
->DataOffset
);
408 pnotify
= (struct file_notify_information
*)((char *)&pSMBr
->hdr
.Protocol
410 cFYI(1,("dnotify on %s with action: 0x%x",pnotify
->FileName
,
411 pnotify
->Action
)); /* BB removeme BB */
412 /* cifs_dump_mem("Received notify Data is: ",buf,sizeof(struct smb_hdr)+60); */
415 if(pSMBr
->hdr
.Status
.CifsError
) {
416 cFYI(1,("notify err 0x%d",pSMBr
->hdr
.Status
.CifsError
));
421 if(pSMB
->hdr
.Command
!= SMB_COM_LOCKING_ANDX
)
423 if(pSMB
->hdr
.Flags
& SMBFLG_RESPONSE
) {
424 /* no sense logging error on invalid handle on oplock
425 break - harmless race between close request and oplock
426 break response is expected from time to time writing out
427 large dirty files cached on the client */
428 if ((NT_STATUS_INVALID_HANDLE
) ==
429 le32_to_cpu(pSMB
->hdr
.Status
.CifsError
)) {
430 cFYI(1,("invalid handle on oplock break"));
432 } else if (ERRbadfid
==
433 le16_to_cpu(pSMB
->hdr
.Status
.DosError
.Error
)) {
436 return FALSE
; /* on valid oplock brk we get "request" */
439 if(pSMB
->hdr
.WordCount
!= 8)
442 cFYI(1,(" oplock type 0x%d level 0x%d",pSMB
->LockType
,pSMB
->OplockLevel
));
443 if(!(pSMB
->LockType
& LOCKING_ANDX_OPLOCK_RELEASE
))
446 /* look up tcon based on tid & uid */
447 read_lock(&GlobalSMBSeslock
);
448 list_for_each(tmp
, &GlobalTreeConnectionList
) {
449 tcon
= list_entry(tmp
, struct cifsTconInfo
, cifsConnectionList
);
450 if (tcon
->tid
== buf
->Tid
) {
451 #ifdef CONFIG_CIFS_STATS
452 atomic_inc(&tcon
->num_oplock_brks
);
454 list_for_each(tmp1
,&tcon
->openFileList
){
455 netfile
= list_entry(tmp1
,struct cifsFileInfo
,
457 if(pSMB
->Fid
== netfile
->netfid
) {
458 struct cifsInodeInfo
*pCifsInode
;
459 read_unlock(&GlobalSMBSeslock
);
460 cFYI(1,("file id match, oplock break"));
462 CIFS_I(netfile
->pInode
);
463 pCifsInode
->clientCanCacheAll
= FALSE
;
464 if(pSMB
->OplockLevel
== 0)
465 pCifsInode
->clientCanCacheRead
467 pCifsInode
->oplockPending
= TRUE
;
468 AllocOplockQEntry(netfile
->pInode
,
471 cFYI(1,("about to wake up oplock thd"));
473 wake_up_process(oplockThread
);
477 read_unlock(&GlobalSMBSeslock
);
478 cFYI(1,("No matching file for oplock break"));
482 read_unlock(&GlobalSMBSeslock
);
483 cFYI(1,("Can not process oplock break for non-existent connection"));
488 dump_smb(struct smb_hdr
*smb_buf
, int smb_buf_length
)
492 unsigned char *buffer
;
497 buffer
= (unsigned char *) smb_buf
;
498 for (i
= 0, j
= 0; i
< smb_buf_length
; i
++, j
++) {
499 if (i
% 8 == 0) { /* have reached the beginning of line */
500 printk(KERN_DEBUG
"| ");
503 printk("%0#4x ", buffer
[i
]);
504 debug_line
[2 * j
] = ' ';
505 if (isprint(buffer
[i
]))
506 debug_line
[1 + (2 * j
)] = buffer
[i
];
508 debug_line
[1 + (2 * j
)] = '_';
510 if (i
% 8 == 7) { /* reached end of line, time to print ascii */
512 printk(" | %s\n", debug_line
);
517 debug_line
[2 * j
] = ' ';
518 debug_line
[1 + (2 * j
)] = ' ';
520 printk( " | %s\n", debug_line
);
524 /* Windows maps these to the user defined 16 bit Unicode range since they are
525 reserved symbols (along with \ and /), otherwise illegal to store
526 in filenames in NTFS */
527 #define UNI_ASTERIK (__u16) ('*' + 0xF000)
528 #define UNI_QUESTION (__u16) ('?' + 0xF000)
529 #define UNI_COLON (__u16) (':' + 0xF000)
530 #define UNI_GRTRTHAN (__u16) ('>' + 0xF000)
531 #define UNI_LESSTHAN (__u16) ('<' + 0xF000)
532 #define UNI_PIPE (__u16) ('|' + 0xF000)
533 #define UNI_SLASH (__u16) ('\\' + 0xF000)
535 /* Convert 16 bit Unicode pathname from wire format to string in current code
536 page. Conversion may involve remapping up the seven characters that are
537 only legal in POSIX-like OS (if they are present in the string). Path
538 names are little endian 16 bit Unicode on the wire */
540 cifs_convertUCSpath(char *target
, const __le16
* source
, int maxlen
,
541 const struct nls_table
* cp
)
546 for(i
= 0, j
= 0; i
< maxlen
; i
++) {
547 src_char
= le16_to_cpu(source
[i
]);
550 goto cUCS_out
; /* BB check this BB */
560 /* BB We can not handle remapping slash until
561 all the calls to build_path_from_dentry
562 are modified, as they use slash as separator BB */
576 len
= cp
->uni2char(src_char
, &target
[j
],
577 NLS_MAX_CHARSET_SIZE
);
586 /* make sure we do not overrun callers allocated temp buffer */
587 if(j
>= (2 * NAME_MAX
))
595 /* Convert 16 bit Unicode pathname to wire format from string in current code
596 page. Conversion may involve remapping up the seven characters that are
597 only legal in POSIX-like OS (if they are present in the string). Path
598 names are little endian 16 bit Unicode on the wire */
600 cifsConvertToUCS(__le16
* target
, const char *source
, int maxlen
,
601 const struct nls_table
* cp
, int mapChars
)
604 int len_remaining
= maxlen
;
608 return cifs_strtoUCS((wchar_t *) target
, source
, PATH_MAX
, cp
);
610 for(i
= 0, j
= 0; i
< maxlen
; j
++) {
611 src_char
= source
[i
];
617 target
[j
] = cpu_to_le16(UNI_COLON
);
620 target
[j
] = cpu_to_le16(UNI_ASTERIK
);
623 target
[j
] = cpu_to_le16(UNI_QUESTION
);
626 target
[j
] = cpu_to_le16(UNI_LESSTHAN
);
629 target
[j
] = cpu_to_le16(UNI_GRTRTHAN
);
632 target
[j
] = cpu_to_le16(UNI_PIPE
);
634 /* BB We can not handle remapping slash until
635 all the calls to build_path_from_dentry
636 are modified, as they use slash as separator BB */
638 target[j] = cpu_to_le16(UNI_SLASH);
641 charlen
= cp
->char2uni(source
+i
,
642 len_remaining
, target
+j
);
643 /* if no match, use question mark, which
644 at least in some cases servers as wild card */
646 target
[j
] = cpu_to_le16(0x003f);
649 len_remaining
-= charlen
;
650 /* character may take more than one byte in the
651 the source string, but will take exactly two
652 bytes in the target string */
656 i
++; /* move to next char in source string */