1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include <linux/slab.h>
23#include <linux/ctype.h>
24#include <linux/mempool.h>
25#include "cifspdu.h"
26#include "cifsglob.h"
27#include "cifsproto.h"
28#include "cifs_debug.h"
29#include "smberr.h"
30#include "nterr.h"
31#include "cifs_unicode.h"
32
33extern mempool_t *cifs_sm_req_poolp;
34extern mempool_t *cifs_req_poolp;
35
36
37
38
39
40
41
42unsigned int
43_GetXid(void)
44{
45 unsigned int xid;
46
47 spin_lock(&GlobalMid_Lock);
48 GlobalTotalActiveXid++;
49
50
51 if (GlobalTotalActiveXid > GlobalMaxActiveXid)
52 GlobalMaxActiveXid = GlobalTotalActiveXid;
53 if (GlobalTotalActiveXid > 65000)
54 cFYI(1, ("warning: more than 65000 requests active"));
55 xid = GlobalCurrentXid++;
56 spin_unlock(&GlobalMid_Lock);
57 return xid;
58}
59
60void
61_FreeXid(unsigned int xid)
62{
63 spin_lock(&GlobalMid_Lock);
64
65
66 GlobalTotalActiveXid--;
67 spin_unlock(&GlobalMid_Lock);
68}
69
70struct cifsSesInfo *
71sesInfoAlloc(void)
72{
73 struct cifsSesInfo *ret_buf;
74
75 ret_buf = kzalloc(sizeof(struct cifsSesInfo), GFP_KERNEL);
76 if (ret_buf) {
77 atomic_inc(&sesInfoAllocCount);
78 ret_buf->status = CifsNew;
79 ++ret_buf->ses_count;
80 INIT_LIST_HEAD(&ret_buf->smb_ses_list);
81 INIT_LIST_HEAD(&ret_buf->tcon_list);
82 init_MUTEX(&ret_buf->sesSem);
83 }
84 return ret_buf;
85}
86
87void
88sesInfoFree(struct cifsSesInfo *buf_to_free)
89{
90 if (buf_to_free == NULL) {
91 cFYI(1, ("Null buffer passed to sesInfoFree"));
92 return;
93 }
94
95 atomic_dec(&sesInfoAllocCount);
96 kfree(buf_to_free->serverOS);
97 kfree(buf_to_free->serverDomain);
98 kfree(buf_to_free->serverNOS);
99 if (buf_to_free->password) {
100 memset(buf_to_free->password, 0, strlen(buf_to_free->password));
101 kfree(buf_to_free->password);
102 }
103 kfree(buf_to_free->domainName);
104 kfree(buf_to_free);
105}
106
107struct cifsTconInfo *
108tconInfoAlloc(void)
109{
110 struct cifsTconInfo *ret_buf;
111 ret_buf = kzalloc(sizeof(struct cifsTconInfo), GFP_KERNEL);
112 if (ret_buf) {
113 atomic_inc(&tconInfoAllocCount);
114 ret_buf->tidStatus = CifsNew;
115 ++ret_buf->tc_count;
116 INIT_LIST_HEAD(&ret_buf->openFileList);
117 INIT_LIST_HEAD(&ret_buf->tcon_list);
118#ifdef CONFIG_CIFS_STATS
119 spin_lock_init(&ret_buf->stat_lock);
120#endif
121 }
122 return ret_buf;
123}
124
125void
126tconInfoFree(struct cifsTconInfo *buf_to_free)
127{
128 if (buf_to_free == NULL) {
129 cFYI(1, ("Null buffer passed to tconInfoFree"));
130 return;
131 }
132 atomic_dec(&tconInfoAllocCount);
133 kfree(buf_to_free->nativeFileSystem);
134 if (buf_to_free->password) {
135 memset(buf_to_free->password, 0, strlen(buf_to_free->password));
136 kfree(buf_to_free->password);
137 }
138 kfree(buf_to_free);
139}
140
141struct smb_hdr *
142cifs_buf_get(void)
143{
144 struct smb_hdr *ret_buf = NULL;
145
146
147
148
149
150 ret_buf = mempool_alloc(cifs_req_poolp, GFP_NOFS);
151
152
153
154 if (ret_buf) {
155 memset(ret_buf, 0, sizeof(struct smb_hdr) + 3);
156 atomic_inc(&bufAllocCount);
157#ifdef CONFIG_CIFS_STATS2
158 atomic_inc(&totBufAllocCount);
159#endif
160 }
161
162 return ret_buf;
163}
164
165void
166cifs_buf_release(void *buf_to_free)
167{
168 if (buf_to_free == NULL) {
169
170 return;
171 }
172 mempool_free(buf_to_free, cifs_req_poolp);
173
174 atomic_dec(&bufAllocCount);
175 return;
176}
177
178struct smb_hdr *
179cifs_small_buf_get(void)
180{
181 struct smb_hdr *ret_buf = NULL;
182
183
184
185
186
187 ret_buf = mempool_alloc(cifs_sm_req_poolp, GFP_NOFS);
188 if (ret_buf) {
189
190
191 atomic_inc(&smBufAllocCount);
192#ifdef CONFIG_CIFS_STATS2
193 atomic_inc(&totSmBufAllocCount);
194#endif
195
196 }
197 return ret_buf;
198}
199
200void
201cifs_small_buf_release(void *buf_to_free)
202{
203
204 if (buf_to_free == NULL) {
205 cFYI(1, ("Null buffer passed to cifs_small_buf_release"));
206 return;
207 }
208 mempool_free(buf_to_free, cifs_sm_req_poolp);
209
210 atomic_dec(&smBufAllocCount);
211 return;
212}
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235__u16 GetNextMid(struct TCP_Server_Info *server)
236{
237 __u16 mid = 0;
238 __u16 last_mid;
239 int collision;
240
241 if (server == NULL)
242 return mid;
243
244 spin_lock(&GlobalMid_Lock);
245 last_mid = server->CurrentMid;
246 server->CurrentMid++;
247
248
249
250
251
252
253
254 while (server->CurrentMid != last_mid) {
255 struct list_head *tmp;
256 struct mid_q_entry *mid_entry;
257
258 collision = 0;
259 if (server->CurrentMid == 0)
260 server->CurrentMid++;
261
262 list_for_each(tmp, &server->pending_mid_q) {
263 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
264
265 if ((mid_entry->mid == server->CurrentMid) &&
266 (mid_entry->midState == MID_REQUEST_SUBMITTED)) {
267
268 collision = 1;
269 break;
270 }
271 }
272 if (collision == 0) {
273 mid = server->CurrentMid;
274 break;
275 }
276 server->CurrentMid++;
277 }
278 spin_unlock(&GlobalMid_Lock);
279 return mid;
280}
281
282
283
284void
285header_assemble(struct smb_hdr *buffer, char smb_command ,
286 const struct cifsTconInfo *treeCon, int word_count
287 )
288{
289 struct list_head *temp_item;
290 struct cifsSesInfo *ses;
291 char *temp = (char *) buffer;
292
293 memset(temp, 0, 256);
294
295 buffer->smb_buf_length =
296 (2 * word_count) + sizeof(struct smb_hdr) -
297 4 +
298 2 ;
299
300
301
302 buffer->Protocol[0] = 0xFF;
303 buffer->Protocol[1] = 'S';
304 buffer->Protocol[2] = 'M';
305 buffer->Protocol[3] = 'B';
306 buffer->Command = smb_command;
307 buffer->Flags = 0x00;
308 buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES;
309 buffer->Pid = cpu_to_le16((__u16)current->tgid);
310 buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));
311 if (treeCon) {
312 buffer->Tid = treeCon->tid;
313 if (treeCon->ses) {
314 if (treeCon->ses->capabilities & CAP_UNICODE)
315 buffer->Flags2 |= SMBFLG2_UNICODE;
316 if (treeCon->ses->capabilities & CAP_STATUS32)
317 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
318
319
320 buffer->Uid = treeCon->ses->Suid;
321 buffer->Mid = GetNextMid(treeCon->ses->server);
322 if (multiuser_mount != 0) {
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347 if (current_fsuid() != treeCon->ses->linux_uid) {
348 cFYI(1, ("Multiuser mode and UID "
349 "did not match tcon uid"));
350 read_lock(&cifs_tcp_ses_lock);
351 list_for_each(temp_item, &treeCon->ses->server->smb_ses_list) {
352 ses = list_entry(temp_item, struct cifsSesInfo, smb_ses_list);
353 if (ses->linux_uid == current_fsuid()) {
354 if (ses->server == treeCon->ses->server) {
355 cFYI(1, ("found matching uid substitute right smb_uid"));
356 buffer->Uid = ses->Suid;
357 break;
358 } else {
359
360 cFYI(1, ("local UID found but no smb sess with this server exists"));
361 }
362 }
363 }
364 read_unlock(&cifs_tcp_ses_lock);
365 }
366 }
367 }
368 if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
369 buffer->Flags2 |= SMBFLG2_DFS;
370 if (treeCon->nocase)
371 buffer->Flags |= SMBFLG_CASELESS;
372 if ((treeCon->ses) && (treeCon->ses->server))
373 if (treeCon->ses->server->secMode &
374 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
375 buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
376 }
377
378
379 buffer->WordCount = (char) word_count;
380 return;
381}
382
383static int
384checkSMBhdr(struct smb_hdr *smb, __u16 mid)
385{
386
387
388 if ((*(__le32 *) smb->Protocol == cpu_to_le32(0x424d53ff)) &&
389 (mid == smb->Mid)) {
390 if (smb->Flags & SMBFLG_RESPONSE)
391 return 0;
392 else {
393
394 if (smb->Command == SMB_COM_LOCKING_ANDX)
395 return 0;
396 else
397 cERROR(1, ("Received Request not response"));
398 }
399 } else {
400 if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff))
401 cERROR(1,
402 ("Bad protocol string signature header %x",
403 *(unsigned int *) smb->Protocol));
404 if (mid != smb->Mid)
405 cERROR(1, ("Mids do not match"));
406 }
407 cERROR(1, ("bad smb detected. The Mid=%d", smb->Mid));
408 return 1;
409}
410
411int
412checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
413{
414 __u32 len = smb->smb_buf_length;
415 __u32 clc_len;
416 cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len));
417
418 if (length < 2 + sizeof(struct smb_hdr)) {
419 if ((length >= sizeof(struct smb_hdr) - 1)
420 && (smb->Status.CifsError != 0)) {
421 smb->WordCount = 0;
422
423 return 0;
424 } else if ((length == sizeof(struct smb_hdr) + 1) &&
425 (smb->WordCount == 0)) {
426 char *tmp = (char *)smb;
427
428
429 if (tmp[sizeof(struct smb_hdr)] == 0) {
430
431
432
433
434
435
436
437 tmp[sizeof(struct smb_hdr)+1] = 0;
438 return 0;
439 }
440 cERROR(1, ("rcvd invalid byte count (bcc)"));
441 } else {
442 cERROR(1, ("Length less than smb header size"));
443 }
444 return 1;
445 }
446 if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
447 cERROR(1, ("smb length greater than MaxBufSize, mid=%d",
448 smb->Mid));
449 return 1;
450 }
451
452 if (checkSMBhdr(smb, mid))
453 return 1;
454 clc_len = smbCalcSize_LE(smb);
455
456 if (4 + len != length) {
457 cERROR(1, ("Length read does not match RFC1001 length %d",
458 len));
459 return 1;
460 }
461
462 if (4 + len != clc_len) {
463
464 if ((len > 64 * 1024) && (len > clc_len)) {
465
466 if (((4 + len) & 0xFFFF) == (clc_len & 0xFFFF))
467 return 0;
468 }
469 cFYI(1, ("Calculated size %d vs length %d mismatch for mid %d",
470 clc_len, 4 + len, smb->Mid));
471
472
473
474
475
476
477
478
479
480
481
482 if ((4+len > clc_len) && (len <= clc_len + 512))
483 return 0;
484 else {
485 cERROR(1, ("RFC1001 size %d bigger than SMB for Mid=%d",
486 len, smb->Mid));
487 return 1;
488 }
489 }
490 return 0;
491}
492
493bool
494is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
495{
496 struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
497 struct list_head *tmp, *tmp1, *tmp2;
498 struct cifsSesInfo *ses;
499 struct cifsTconInfo *tcon;
500 struct cifsInodeInfo *pCifsInode;
501 struct cifsFileInfo *netfile;
502 int rc;
503
504 cFYI(1, ("Checking for oplock break or dnotify response"));
505 if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
506 (pSMB->hdr.Flags & SMBFLG_RESPONSE)) {
507 struct smb_com_transaction_change_notify_rsp *pSMBr =
508 (struct smb_com_transaction_change_notify_rsp *)buf;
509 struct file_notify_information *pnotify;
510 __u32 data_offset = 0;
511 if (pSMBr->ByteCount > sizeof(struct file_notify_information)) {
512 data_offset = le32_to_cpu(pSMBr->DataOffset);
513
514 pnotify = (struct file_notify_information *)
515 ((char *)&pSMBr->hdr.Protocol + data_offset);
516 cFYI(1, ("dnotify on %s Action: 0x%x",
517 pnotify->FileName, pnotify->Action));
518
519
520 return true;
521 }
522 if (pSMBr->hdr.Status.CifsError) {
523 cFYI(1, ("notify err 0x%d",
524 pSMBr->hdr.Status.CifsError));
525 return true;
526 }
527 return false;
528 }
529 if (pSMB->hdr.Command != SMB_COM_LOCKING_ANDX)
530 return false;
531 if (pSMB->hdr.Flags & SMBFLG_RESPONSE) {
532
533
534
535
536 if ((NT_STATUS_INVALID_HANDLE) ==
537 le32_to_cpu(pSMB->hdr.Status.CifsError)) {
538 cFYI(1, ("invalid handle on oplock break"));
539 return true;
540 } else if (ERRbadfid ==
541 le16_to_cpu(pSMB->hdr.Status.DosError.Error)) {
542 return true;
543 } else {
544 return false;
545 }
546 }
547 if (pSMB->hdr.WordCount != 8)
548 return false;
549
550 cFYI(1, ("oplock type 0x%d level 0x%d",
551 pSMB->LockType, pSMB->OplockLevel));
552 if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
553 return false;
554
555
556 read_lock(&cifs_tcp_ses_lock);
557 list_for_each(tmp, &srv->smb_ses_list) {
558 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
559 list_for_each(tmp1, &ses->tcon_list) {
560 tcon = list_entry(tmp1, struct cifsTconInfo, tcon_list);
561 if (tcon->tid != buf->Tid)
562 continue;
563
564 cifs_stats_inc(&tcon->num_oplock_brks);
565 read_lock(&GlobalSMBSeslock);
566 list_for_each(tmp2, &tcon->openFileList) {
567 netfile = list_entry(tmp2, struct cifsFileInfo,
568 tlist);
569 if (pSMB->Fid != netfile->netfid)
570 continue;
571
572
573
574
575
576 if (netfile->closePend) {
577 read_unlock(&GlobalSMBSeslock);
578 read_unlock(&cifs_tcp_ses_lock);
579 return true;
580 }
581
582 cFYI(1, ("file id match, oplock break"));
583 pCifsInode = CIFS_I(netfile->pInode);
584 pCifsInode->clientCanCacheAll = false;
585 if (pSMB->OplockLevel == 0)
586 pCifsInode->clientCanCacheRead = false;
587 rc = slow_work_enqueue(&netfile->oplock_break);
588 if (rc) {
589 cERROR(1, ("failed to enqueue oplock "
590 "break: %d\n", rc));
591 } else {
592 netfile->oplock_break_cancelled = false;
593 }
594 read_unlock(&GlobalSMBSeslock);
595 read_unlock(&cifs_tcp_ses_lock);
596 return true;
597 }
598 read_unlock(&GlobalSMBSeslock);
599 read_unlock(&cifs_tcp_ses_lock);
600 cFYI(1, ("No matching file for oplock break"));
601 return true;
602 }
603 }
604 read_unlock(&cifs_tcp_ses_lock);
605 cFYI(1, ("Can not process oplock break for non-existent connection"));
606 return true;
607}
608
609void
610dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
611{
612 int i, j;
613 char debug_line[17];
614 unsigned char *buffer;
615
616 if (traceSMB == 0)
617 return;
618
619 buffer = (unsigned char *) smb_buf;
620 for (i = 0, j = 0; i < smb_buf_length; i++, j++) {
621 if (i % 8 == 0) {
622
623 printk(KERN_DEBUG "| ");
624 j = 0;
625 }
626 printk("%0#4x ", buffer[i]);
627 debug_line[2 * j] = ' ';
628 if (isprint(buffer[i]))
629 debug_line[1 + (2 * j)] = buffer[i];
630 else
631 debug_line[1 + (2 * j)] = '_';
632
633 if (i % 8 == 7) {
634
635 debug_line[16] = 0;
636 printk(" | %s\n", debug_line);
637 }
638 }
639 for (; j < 8; j++) {
640 printk(" ");
641 debug_line[2 * j] = ' ';
642 debug_line[1 + (2 * j)] = ' ';
643 }
644 printk(" | %s\n", debug_line);
645 return;
646}
647
648
649
650
651
652int
653cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
654 const struct nls_table *cp, int mapChars)
655{
656 int i, j, charlen;
657 int len_remaining = maxlen;
658 char src_char;
659 __u16 temp;
660
661 if (!mapChars)
662 return cifs_strtoUCS(target, source, PATH_MAX, cp);
663
664 for (i = 0, j = 0; i < maxlen; j++) {
665 src_char = source[i];
666 switch (src_char) {
667 case 0:
668 target[j] = 0;
669 goto ctoUCS_out;
670 case ':':
671 target[j] = cpu_to_le16(UNI_COLON);
672 break;
673 case '*':
674 target[j] = cpu_to_le16(UNI_ASTERIK);
675 break;
676 case '?':
677 target[j] = cpu_to_le16(UNI_QUESTION);
678 break;
679 case '<':
680 target[j] = cpu_to_le16(UNI_LESSTHAN);
681 break;
682 case '>':
683 target[j] = cpu_to_le16(UNI_GRTRTHAN);
684 break;
685 case '|':
686 target[j] = cpu_to_le16(UNI_PIPE);
687 break;
688
689
690
691
692
693
694 default:
695 charlen = cp->char2uni(source+i,
696 len_remaining, &temp);
697
698
699 if (charlen < 1) {
700 target[j] = cpu_to_le16(0x003f);
701 charlen = 1;
702 } else
703 target[j] = cpu_to_le16(temp);
704 len_remaining -= charlen;
705
706
707
708 i += charlen;
709 continue;
710 }
711 i++;
712 len_remaining--;
713 }
714
715ctoUCS_out:
716 return i;
717}
718
719void
720cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
721{
722 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
723 cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
724 cERROR(1, ("Autodisabling the use of server inode numbers on "
725 "%s. This server doesn't seem to support them "
726 "properly. Hardlinks will not be recognized on this "
727 "mount. Consider mounting with the \"noserverino\" "
728 "option to silence this message.",
729 cifs_sb->tcon->treeName));
730 }
731}
732