@@ -491,10 +491,25 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
491
491
492
492
req -> hdr .sync_hdr .SessionId = 0 ;
493
493
494
- req -> Dialects [0 ] = cpu_to_le16 (ses -> server -> vals -> protocol_id );
495
-
496
- req -> DialectCount = cpu_to_le16 (1 ); /* One vers= at a time for now */
497
- inc_rfc1001_len (req , 2 );
494
+ if (strcmp (ses -> server -> vals -> version_string ,
495
+ SMB3ANY_VERSION_STRING ) == 0 ) {
496
+ req -> Dialects [0 ] = cpu_to_le16 (SMB30_PROT_ID );
497
+ req -> Dialects [1 ] = cpu_to_le16 (SMB302_PROT_ID );
498
+ req -> DialectCount = cpu_to_le16 (2 );
499
+ inc_rfc1001_len (req , 4 );
500
+ } else if (strcmp (ses -> server -> vals -> version_string ,
501
+ SMBDEFAULT_VERSION_STRING ) == 0 ) {
502
+ req -> Dialects [0 ] = cpu_to_le16 (SMB21_PROT_ID );
503
+ req -> Dialects [1 ] = cpu_to_le16 (SMB30_PROT_ID );
504
+ req -> Dialects [2 ] = cpu_to_le16 (SMB302_PROT_ID );
505
+ req -> DialectCount = cpu_to_le16 (3 );
506
+ inc_rfc1001_len (req , 6 );
507
+ } else {
508
+ /* otherwise send specific dialect */
509
+ req -> Dialects [0 ] = cpu_to_le16 (ses -> server -> vals -> protocol_id );
510
+ req -> DialectCount = cpu_to_le16 (1 );
511
+ inc_rfc1001_len (req , 2 );
512
+ }
498
513
499
514
/* only one of SMB2 signing flags may be set in SMB2 request */
500
515
if (ses -> sign )
@@ -528,16 +543,42 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
528
543
*/
529
544
if (rc == - EOPNOTSUPP ) {
530
545
cifs_dbg (VFS , "Dialect not supported by server. Consider "
531
- "specifying vers=1.0 or vers=2.1 on mount for accessing"
546
+ "specifying vers=1.0 or vers=2.0 on mount for accessing"
532
547
" older servers\n" );
533
548
goto neg_exit ;
534
549
} else if (rc != 0 )
535
550
goto neg_exit ;
536
551
552
+ if (strcmp (ses -> server -> vals -> version_string ,
553
+ SMB3ANY_VERSION_STRING ) == 0 ) {
554
+ if (rsp -> DialectRevision == cpu_to_le16 (SMB20_PROT_ID )) {
555
+ cifs_dbg (VFS ,
556
+ "SMB2 dialect returned but not requested\n" );
557
+ return - EIO ;
558
+ } else if (rsp -> DialectRevision == cpu_to_le16 (SMB21_PROT_ID )) {
559
+ cifs_dbg (VFS ,
560
+ "SMB2.1 dialect returned but not requested\n" );
561
+ return - EIO ;
562
+ }
563
+ } else if (strcmp (ses -> server -> vals -> version_string ,
564
+ SMBDEFAULT_VERSION_STRING ) == 0 ) {
565
+ if (rsp -> DialectRevision == cpu_to_le16 (SMB20_PROT_ID )) {
566
+ cifs_dbg (VFS ,
567
+ "SMB2 dialect returned but not requested\n" );
568
+ return - EIO ;
569
+ } else if (rsp -> DialectRevision == cpu_to_le16 (SMB21_PROT_ID )) {
570
+ /* ops set to 3.0 by default for default so update */
571
+ ses -> server -> ops = & smb21_operations ;
572
+ }
573
+ } else if (rsp -> DialectRevision != ses -> server -> vals -> protocol_id ) {
574
+ /* if requested single dialect ensure returned dialect matched */
575
+ cifs_dbg (VFS , "Illegal 0x%x dialect returned: not requested\n" ,
576
+ cpu_to_le16 (rsp -> DialectRevision ));
577
+ return - EIO ;
578
+ }
579
+
537
580
cifs_dbg (FYI , "mode 0x%x\n" , rsp -> SecurityMode );
538
581
539
- /* BB we may eventually want to match the negotiated vs. requested
540
- dialect, even though we are only requesting one at a time */
541
582
if (rsp -> DialectRevision == cpu_to_le16 (SMB20_PROT_ID ))
542
583
cifs_dbg (FYI , "negotiated smb2.0 dialect\n" );
543
584
else if (rsp -> DialectRevision == cpu_to_le16 (SMB21_PROT_ID ))
@@ -558,6 +599,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
558
599
}
559
600
server -> dialect = le16_to_cpu (rsp -> DialectRevision );
560
601
602
+ /* BB: add check that dialect was valid given dialect(s) we asked for */
603
+
561
604
/* SMB2 only has an extended negflavor */
562
605
server -> negflavor = CIFS_NEGFLAVOR_EXTENDED ;
563
606
/* set it to the maximum buffer size value we can send with 1 credit */
@@ -606,6 +649,7 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
606
649
struct validate_negotiate_info_req vneg_inbuf ;
607
650
struct validate_negotiate_info_rsp * pneg_rsp ;
608
651
u32 rsplen ;
652
+ u32 inbuflen ; /* max of 4 dialects */
609
653
610
654
cifs_dbg (FYI , "validate negotiate\n" );
611
655
@@ -634,9 +678,30 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
634
678
else
635
679
vneg_inbuf .SecurityMode = 0 ;
636
680
637
- vneg_inbuf .DialectCount = cpu_to_le16 (1 );
638
- vneg_inbuf .Dialects [0 ] =
639
- cpu_to_le16 (tcon -> ses -> server -> vals -> protocol_id );
681
+
682
+ if (strcmp (tcon -> ses -> server -> vals -> version_string ,
683
+ SMB3ANY_VERSION_STRING ) == 0 ) {
684
+ vneg_inbuf .Dialects [0 ] = cpu_to_le16 (SMB30_PROT_ID );
685
+ vneg_inbuf .Dialects [1 ] = cpu_to_le16 (SMB302_PROT_ID );
686
+ vneg_inbuf .DialectCount = cpu_to_le16 (2 );
687
+ /* structure is big enough for 3 dialects, sending only 2 */
688
+ inbuflen = sizeof (struct validate_negotiate_info_req ) - 2 ;
689
+ } else if (strcmp (tcon -> ses -> server -> vals -> version_string ,
690
+ SMBDEFAULT_VERSION_STRING ) == 0 ) {
691
+ vneg_inbuf .Dialects [0 ] = cpu_to_le16 (SMB21_PROT_ID );
692
+ vneg_inbuf .Dialects [1 ] = cpu_to_le16 (SMB30_PROT_ID );
693
+ vneg_inbuf .Dialects [2 ] = cpu_to_le16 (SMB302_PROT_ID );
694
+ vneg_inbuf .DialectCount = cpu_to_le16 (3 );
695
+ /* structure is big enough for 3 dialects */
696
+ inbuflen = sizeof (struct validate_negotiate_info_req );
697
+ } else {
698
+ /* otherwise specific dialect was requested */
699
+ vneg_inbuf .Dialects [0 ] =
700
+ cpu_to_le16 (tcon -> ses -> server -> vals -> protocol_id );
701
+ vneg_inbuf .DialectCount = cpu_to_le16 (1 );
702
+ /* structure is big enough for 3 dialects, sending only 1 */
703
+ inbuflen = sizeof (struct validate_negotiate_info_req ) - 4 ;
704
+ }
640
705
641
706
rc = SMB2_ioctl (xid , tcon , NO_FILE_ID , NO_FILE_ID ,
642
707
FSCTL_VALIDATE_NEGOTIATE_INFO , true /* is_fsctl */ ,
0 commit comments