@@ -491,10 +491,25 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
491491
492492 req -> hdr .sync_hdr .SessionId = 0 ;
493493
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+ }
498513
499514 /* only one of SMB2 signing flags may be set in SMB2 request */
500515 if (ses -> sign )
@@ -528,16 +543,42 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
528543 */
529544 if (rc == - EOPNOTSUPP ) {
530545 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"
532547 " older servers\n" );
533548 goto neg_exit ;
534549 } else if (rc != 0 )
535550 goto neg_exit ;
536551
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+
537580 cifs_dbg (FYI , "mode 0x%x\n" , rsp -> SecurityMode );
538581
539- /* BB we may eventually want to match the negotiated vs. requested
540- dialect, even though we are only requesting one at a time */
541582 if (rsp -> DialectRevision == cpu_to_le16 (SMB20_PROT_ID ))
542583 cifs_dbg (FYI , "negotiated smb2.0 dialect\n" );
543584 else if (rsp -> DialectRevision == cpu_to_le16 (SMB21_PROT_ID ))
@@ -558,6 +599,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
558599 }
559600 server -> dialect = le16_to_cpu (rsp -> DialectRevision );
560601
602+ /* BB: add check that dialect was valid given dialect(s) we asked for */
603+
561604 /* SMB2 only has an extended negflavor */
562605 server -> negflavor = CIFS_NEGFLAVOR_EXTENDED ;
563606 /* 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)
606649 struct validate_negotiate_info_req vneg_inbuf ;
607650 struct validate_negotiate_info_rsp * pneg_rsp ;
608651 u32 rsplen ;
652+ u32 inbuflen ; /* max of 4 dialects */
609653
610654 cifs_dbg (FYI , "validate negotiate\n" );
611655
@@ -634,9 +678,30 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
634678 else
635679 vneg_inbuf .SecurityMode = 0 ;
636680
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+ }
640705
641706 rc = SMB2_ioctl (xid , tcon , NO_FILE_ID , NO_FILE_ID ,
642707 FSCTL_VALIDATE_NEGOTIATE_INFO , true /* is_fsctl */ ,
0 commit comments