servations for Forbidden Zones paper @ RTAS'20
aboutsummaryrefslogblamecommitdiffstats
path: root/fs/cifs/smb2pdu.c
blob: 0f48741a0130d35286fec1e031b5eea45e367699 (plain) (tree)
1
2
3
4


                      
                                                                     




























                                                                                
                                         
                          
                       
                          









                         
                     
                    
                        
                      





























                                                                              

                                                            

                         


                                                                          


                                                                           

                 

           
                                                              

                                               


                                              




                                                                          
                                                           
                                                             
                    
                                                          
                                                                


                                                                     
                                                     
         
                                                            



                         

                                                                        
                                                 
                                                                          
                                                    

                                   
                                 

                                  
                                                  











                                                                               
                                                            
 

                                                                        
                                                 
    






                                                           























                                                                   

                                                                              










































                                                                              
                                                                                    













                                                                              











                                                                         









                                                                    

                                               
 

                                                                         
 
                                                      


                                                                                
                         
         



                                                                      
                                            


















                                                                               
                             

                                 


                  



















                                                                          


                                                                      
                                                    

          

                                                                
 
               











                                                                          


                                                              


                           

                                                                                






                                                     
                         

                                                                           



















                                                                     



                                                                                


           

                                                     
 
                                                              


                                                                         
 



                                                                            


                                                                 
 





































                                                                                
                                                           





























                                                                              

                                                                          























                                                                                
     

                                                                 




                   




















                                                                               
                            

                         
                                                     


                                     
                               
 
                                              
 


                                                           

         
                                                                                   


                          
                                    



                                                                    
 




                                                               
                               





                                                               
                               



                                                                               
                               
         

                                                                       
                      
                                                                                 
                                                    
                                                                                

                                      
 
                                                                             
 


                                                                  
              

                                                            
                                                                     
                                                               
         
                                      
                                   
 
                                                                              

                                                            



                                                                          

                                                                          
                                                                                


                                            

                              




















                                                                                

                                                                 

                                                                                 
                                                           


                            
                                                        
 
                                                               
                                                             
                                                                    
                                                             
                                                                    
                                                             

                                                                     



                                                                     
              
                                                                          
                                                            




                                                            

                                                                                








                                                                   

                                                    


                                                                               

                                                           
                                                          


                                                                                
                                                              

                                                                


                                                                          






                                                                               
                               
                                                                    

                                           
 
                                                    

                              
                          
                                                                             



                                  
         








                                                                               



                                        
 

                                                                           

                                                       
                                                            
                   
                                             


                                              



                                                                        

                                                                          

                                                                               
                                                                             
                                                                            
           
                                                                  

                                                           







                                                                                             




                                                            
                                                                               
                                                                
                                                               

                            
                                          

                                                                     
                                          

                                                                    
                                             
 


                                                           


                                                                      
                                                                            

                                                                

                                                                  



                                                                      
                                                            
                                               

                                                              
                                         
                                                                          
                                                          
                                                                            

                                                                    
         


                                                                   
                                                                           


                                                                              

                                    

         

                                          



                                                                                

                                                                          


                                                                                
                                                                         











                                                                               
               
                                                              
                          


                                                                              
             
                        


                          

 





















                                                                                

























                                                        
                               
 

                                                                          


                          
                                                 
                                    





                                                                               
                                                     












                                                                                

                                                  




















                                                                        
                                          


                                                                               
                                                                              

                                                                           

                                                   



                                                                    

                                                                  










                                                             
                                                    
                                                                



                                                                        
                                  












                                                                   























































                                                                        
                                                

                                                            



















                                                                            




                                                                         
 

                                              
                                               
                                  
                                                           
                            

          



                                                                        



                             
                                                 
 
                                               
               
                             
 





                                                                 
 











                                                                     
 

                                                                       
 

                                                           
                                                                            
                       
 

                         
 
                                                                                                     


                                                                    
                          
                         
         



                                                                     
 
                                                                    
 
 
                                                
                                                            














                                                                         
 









                                                                        
 


                                               
 
                                                                        
                                            





                                                                         

         







                                                                     
 





                                                                       
                                                
                                                            
 








                                                    
 


                                                                       








                                                                               
 
                       






                                                                      
                                                                   
                                   

         















                                                             
         
 











                                                                       







                                                                    


                                           

                                                                                
                               
    

                         







                                                                          
                      



                               
 
                                                      





                                     



                                                                               
                                                                                



                                                                   
                                            



                                                                





                                                         
 
                                                                               
                                    



                                                                          

                          

                  


                                                                             
                                                                      



                                                                               







                                                                   






                                                                         
                                          


                         
                                
                      
                               
 
                                
 
                                    

                            










                                                                             
                                                                       
                      
 

                                                                         




                                
                                      
                                            

                                      

                                       


                                                                               
                                       



                                                        




                                                                                  
                                                                              

                                                               








                                                                        

                                  
                                                            

                                  
                                  
                                                            

                                   
                                   
                                                         

                      
                                                                         




                                                         
                                                                                


                                                               
                                             
                                                              


                                                           
                                                                       




                                                                             
                                       

                                                                           





                                        
                                                                         
                                                              








                                                                       
                                         
                      



                               
 
                                           
 
                                   




                                                                  

                                                                            


                          


                                            





                                                                               
                                    




                                                                   
 
 









                                                                 
                                                                       



                                                               
                                                          






                           
















                                                                       
                                                            






                           
           

                                                                              

                          
                                  

                               
                   
 
                                                                                                                
                                                           
                                                  
                                                            
                                                                









                                                                       
 
                 

 
          

                                                                   



                                                      
                                                                             

                                      
                                                           


                                                            
                                                                
                                                      

                                                      



                             

















                                                                                  
                                                       










































                                                                               
          











                                                                 
                                                                    

                                                                                   





                                                                           
                                                   



                                                      








                                                                             
                                                                    


                                                                                


















                                                                               





                                                                              




                                                         
                                                                    
                                                                                
                                                                                



                             












































                                                                              
   
                                                                               
                                                       
                               



                                       
                                              
                                         
                           
                                        

                         

                                 
                   
                               
                                  
                                             
                      
                               
 
                                       





                                     

                                                                                


                          


                                            
                                                            
                                                 

                                                           
 
                                                   
                                                                 


                                                                     

                                                                                       

                                      
                                                                     
                                       
 
                                                                      











                                                                     
                                                                 


                                                                        

                                                    
                                  
                 
                                                            

                                         






                                                                               

                                                            
                                               
                         




                                                                     

         

                                      
 


                                                 
                                                                


                                                    
                                                                    
                         

                                                    
                                  
                 
                                               

         

                                                                              
                                                                     
                                                         
                                                                           
                                        
                                                                             
                 
 
                                                             
                                                              


                                                    
                                      

                                  
                                                

         

                                                                       

                                                         


                                                          




                                                      


                                

                                                            








                                                          
 
                                                        
                                                                              

                                           
           
                         

                       



                                        




                                                                              
                                                       

                                                              


                                   
                                   
                             
                           
                            
                         
                  
                   
                      
                               


                                      


                                 



                                                          




                                
                                   

                            
                                                                               


                          


                                            







                                                             
                                                                            

                                           
                          
              
                          








                                                                             



                                                                          
           
                                                             






                                                                
 





                                                             
                                    


                        
                                               
              
                                           
 

                                                                             
                                                         
 

                                                                       

                                                        
 
                                           
                                                         
                                


                                                            
                                                                 

                                        































                                                                                

                                                                                




                                        








                                                                    



                                           
                                                                






                                                                             



                  





                                                          

                                         
                            

                         
                      
                               
 
                                 
 
                                   

                            
                                                                               


                          


                                            



                                               
                                   
 
                                                                              

                                                        

                      
                                                         


                                





                                                                        

          


                                                             
 


                                                                                                 



                                                        

                                                                                




                                                                 

                                                                              



                                                                       
                                                                               










                                                                             


                                                                      
                                 
 
                                                                                                   




                               
                                                                          







                                                  

                                                          


                                                                               



                                               
                            

                         
                                         
                      
                               
 
                                      
 
                                   

                            

                                                                       


                          


                                            
                                  
                                        

                                               
                                                                  




                                                                  
 
                                                          

                                      

                                       
 
                                                                              

                                                             
 




                                                              













                                                                               

                                                                        
                                                                        
                                                             




                                        
 
                                                                  

                                                                        


                                                                        
                                      




                                                                









                                                                              
   
                                                              
                                                     
                                       
 


                                                                             
                                                                  


                                                                         






                                                                        

                                                                         
                                                                 
                                                    

 










                                                                           
                                                                          


                                                    
                                                                                




                                                            







                                                                                


                            









                                                                               
                                                                              




                                                                       



                                                                        










                                                                              

                                                             
                                                             

                                       




                                                       

                                                                           






                                                  




                                         


                                                

                               
 
                                           
 
                                                     


                                                                           

         
                                                                             


                          
                                                     
 
                           



                                                
 

                                                                           
               
                                                               



                                    





                                                                              

                                         
                            

                         
                      
                               
 
                                 
 
                                   

                            
                                                                               


                          


                                            



                                               
                                   
 
                                                                              
                                    
 
                    

                                                         
                                                     

                  





                                                                             
                                                      

                                                                    

                         
                                               
                                   
                                       
 

                                                                           

                          


                                             

                                     
                              
                                                     








                                                         




                                                               
                                                     
















                                                                              
                                                                                  
                                            
                                                                              
                                                                          


                                                                



                                              

                                                     


                                                                     
                                         
                                              
                                                     
                                                                     



                                                                               

                                                     








                                                                   
                   








                                                                 

                                                                               
                                          

                                                      



                                                              
 


                                                                   


                                   
                                                                    
                                                         
                                                      

                               
                                                                  
                               

                                                                                                 
                 
                                                                               

                                                              



                                        





                                                                               




                                              










                                                                           







                                                        
                                                                            


                                             
                          

                                   
                                      

                                                      
                                       
                               
                       
 

                                                        






                                                                   


                                            

                                                                    








                                                                                
                          
         
 


                                               







                                               
 
                             
                                                                           
                                                                       
                                                         

                                                   
                                                                                

                                               
                                          

         
                                   
                                                               
                                                                     
                                                                  
                 
                                                                  

                                                                 



                                    
 




                                                                 
                                               
                                         
                                   
                           
                            
                               

                                                   

                    
                                                                                


                          


                                                

                                      
 
                                                                              
                                    
 
                                                       
 




                                                                          
                                                             
                                               

         






                                                             

         

                                 
                   
                                                                      
                                                             
                                                    
                                        







                                                           














                                                                               
                                                                                


























                                                                              












                                                                            









                                                                              

                                                     
 
                                    
                                          
                                   
                                                                 
                                                           

                                   

                               
 
                                                                               








                                                                                
                                      
         
 


                                            
                                           
                                                         






                                                                 
                                      
                                                                         
                                




                                                                  
                                                            















                                                                        
                                                                                   



                                                               
                                                                             
                                             
                                                                              
                                                                          


                                                                

         
                                                         
                           



                                                                   
 

                          



                                         





                                                                           

                                                       
 




                                                                        
                                                
      
 
                             
                                                                           
                                                                           
                                                         

                                                   
                                                                                

                                               
                                          

         
                                   

                                                                             
 
                 
                                                    

                                                         
 

                                    

                  














                                                                              
                            
                      
                               
 




                          

                                                                            





                                                


                                                
                                                             







                                                         
                                      
                                                                         


                                      

                                       
 

                                                                     

                                                        


                                                                   
                                                                
              
                                                       

                                        

                  
 

















                                                                            
                                                                                 




                                                                 

                                                                                                  
























                                                                     
                            

                   
                                          






                                                  
                      
                               





                                     

                                                                            


                          


                                            









                                                                              

                                                                












                                               
                                                                         









                                                                       

                                       



                                                
                                                                              

                                                                  
 
                 

                                                                       


                                                     


                                                                   
 


                                                                         




















                                                                              


                                                                                   




                                                   
                                                              
 






                                        

                                                             


                                                                            



                                             
                            


                         
                                         
                      
                               
 
                                   








                                                             
                                                                                  




                           


                                            
                                                   
 
                                  


                                               
                                                                  
 
                           
                                                                          

                                               
                                          
                           

                                      

                                       

                                   




                                                          

                                                                     

                                                           
 
                    
                                                            
 






























                                                                               

                                                                         


                    

   










                                                                     

                                                                              


   
























                                                                               

                                                                               


                    


                                                                                
                                                                    









                                                 

                                                                             

                                                                           

                                                                             

                                                                            
 







                                                                         











                                                                        
 

   









                                                                          




                                                                   

                                                 
                                   



                               
 
                                             

                                                                         


                          


                                            


                                            
                                                     
 





                                                                               
                                    


                                                                
                                                                       



                  







                                                                         

                                                                             






                                                                        
                                       

                                        
                               
 
                                                        



                                                               

                                   

                                                                       






                                               
                       
                                
                                                                            
                                              
                                                                                                          

                                    
                                 








                                                                           
                            


                                         
                                                     
                                                   
                      






                                                                      


                                            
                                                                               
                                             

                                                              
                                 
         
                                                             
 
                                                                                     
                                                                          


                                                                         



                                                                 
            
                                                     




                                                             
                                                              


                                               
                            
                   
                                           
                                         
                                                     
                                     
                      
 





                                                             


                                                         
                
                                                                   



                                                           



                                                              


                                            
                                                                               
                                             



                                                              
                                                             


                                                       
                                                                      



                                              
                                                                                     
                                                                

                                                
                                                                                    
                                                                              

                                                                            
                                                                                          



                                                                            

             
                                                     

                  








                                                                              
                            

                           
                                 
                               
 
                                                            
 
                                                                              


                          


                                            
                                                   





                                                            

                                      
                                                                      



                                                          

                                                                          
                                    
                 
                                                                     





















                                                                               






                                                                
                                         
                                   



                               
 
                                            

                                                                         


                          


                                            
                                                     
                                             
                        



                                             





                                                                               
                                    


                                                                
                                                                      



                  
/*
 *   fs/cifs/smb2pdu.c
 *
 *   Copyright (C) International Business Machines  Corp., 2009, 2013
 *                 Etersoft, 2012
 *   Author(s): Steve French (sfrench@us.ibm.com)
 *              Pavel Shilovsky (pshilovsky@samba.org) 2012
 *
 *   Contains the routines for constructing the SMB2 PDUs themselves
 *
 *   This library is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with this library; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

 /* SMB2 PDU handling routines here - except for leftovers (eg session setup) */
 /* Note that there are handle based routines which must be		      */
 /* treated slightly differently for reconnection purposes since we never     */
 /* want to reuse a stale file handle and only the caller knows the file info */

#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/vfs.h>
#include <linux/task_io_accounting_ops.h>
#include <linux/uaccess.h>
#include <linux/uuid.h>
#include <linux/pagemap.h>
#include <linux/xattr.h>
#include "smb2pdu.h"
#include "cifsglob.h"
#include "cifsacl.h"
#include "cifsproto.h"
#include "smb2proto.h"
#include "cifs_unicode.h"
#include "cifs_debug.h"
#include "ntlmssp.h"
#include "smb2status.h"
#include "smb2glob.h"
#include "cifspdu.h"
#include "cifs_spnego.h"
#include "smbdirect.h"

/*
 *  The following table defines the expected "StructureSize" of SMB2 requests
 *  in order by SMB2 command.  This is similar to "wct" in SMB/CIFS requests.
 *
 *  Note that commands are defined in smb2pdu.h in le16 but the array below is
 *  indexed by command in host byte order.
 */
static const int smb2_req_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = {
	/* SMB2_NEGOTIATE */ 36,
	/* SMB2_SESSION_SETUP */ 25,
	/* SMB2_LOGOFF */ 4,
	/* SMB2_TREE_CONNECT */	9,
	/* SMB2_TREE_DISCONNECT */ 4,
	/* SMB2_CREATE */ 57,
	/* SMB2_CLOSE */ 24,
	/* SMB2_FLUSH */ 24,
	/* SMB2_READ */	49,
	/* SMB2_WRITE */ 49,
	/* SMB2_LOCK */	48,
	/* SMB2_IOCTL */ 57,
	/* SMB2_CANCEL */ 4,
	/* SMB2_ECHO */ 4,
	/* SMB2_QUERY_DIRECTORY */ 33,
	/* SMB2_CHANGE_NOTIFY */ 32,
	/* SMB2_QUERY_INFO */ 41,
	/* SMB2_SET_INFO */ 33,
	/* SMB2_OPLOCK_BREAK */ 24 /* BB this is 36 for LEASE_BREAK variant */
};

static int encryption_required(const struct cifs_tcon *tcon)
{
	if (!tcon)
		return 0;
	if ((tcon->ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA) ||
	    (tcon->share_flags & SHI1005_FLAGS_ENCRYPT_DATA))
		return 1;
	if (tcon->seal &&
	    (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION))
		return 1;
	return 0;
}

static void
smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd,
		  const struct cifs_tcon *tcon)
{
	shdr->ProtocolId = SMB2_PROTO_NUMBER;
	shdr->StructureSize = cpu_to_le16(64);
	shdr->Command = smb2_cmd;
	if (tcon && tcon->ses && tcon->ses->server) {
		struct TCP_Server_Info *server = tcon->ses->server;

		spin_lock(&server->req_lock);
		/* Request up to 2 credits but don't go over the limit. */
		if (server->credits >= server->max_credits)
			shdr->CreditRequest = cpu_to_le16(0);
		else
			shdr->CreditRequest = cpu_to_le16(
				min_t(int, server->max_credits -
						server->credits, 2));
		spin_unlock(&server->req_lock);
	} else {
		shdr->CreditRequest = cpu_to_le16(2);
	}
	shdr->ProcessId = cpu_to_le32((__u16)current->tgid);

	if (!tcon)
		goto out;

	/* GLOBAL_CAP_LARGE_MTU will only be set if dialect > SMB2.02 */
	/* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */
	if ((tcon->ses) && (tcon->ses->server) &&
	    (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
		shdr->CreditCharge = cpu_to_le16(1);
	/* else CreditCharge MBZ */

	shdr->TreeId = tcon->tid;
	/* Uid is not converted */
	if (tcon->ses)
		shdr->SessionId = tcon->ses->Suid;

	/*
	 * If we would set SMB2_FLAGS_DFS_OPERATIONS on open we also would have
	 * to pass the path on the Open SMB prefixed by \\server\share.
	 * Not sure when we would need to do the augmented path (if ever) and
	 * setting this flag breaks the SMB2 open operation since it is
	 * illegal to send an empty path name (without \\server\share prefix)
	 * when the DFS flag is set in the SMB open header. We could
	 * consider setting the flag on all operations other than open
	 * but it is safer to net set it for now.
	 */
/*	if (tcon->share_flags & SHI1005_FLAGS_DFS)
		shdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; */

	if (tcon->ses && tcon->ses->server && tcon->ses->server->sign &&
	    !encryption_required(tcon))
		shdr->Flags |= SMB2_FLAGS_SIGNED;
out:
	return;
}

static int
smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
{
	int rc = 0;
	struct nls_table *nls_codepage;
	struct cifs_ses *ses;
	struct TCP_Server_Info *server;

	/*
	 * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so
	 * check for tcp and smb session status done differently
	 * for those three - in the calling routine.
	 */
	if (tcon == NULL)
		return rc;

	if (smb2_command == SMB2_TREE_CONNECT)
		return rc;

	if (tcon->tidStatus == CifsExiting) {
		/*
		 * only tree disconnect, open, and write,
		 * (and ulogoff which does not have tcon)
		 * are allowed as we start force umount.
		 */
		if ((smb2_command != SMB2_WRITE) &&
		   (smb2_command != SMB2_CREATE) &&
		   (smb2_command != SMB2_TREE_DISCONNECT)) {
			cifs_dbg(FYI, "can not send cmd %d while umounting\n",
				 smb2_command);
			return -ENODEV;
		}
	}
	if ((!tcon->ses) || (tcon->ses->status == CifsExiting) ||
	    (!tcon->ses->server))
		return -EIO;

	ses = tcon->ses;
	server = ses->server;

	/*
	 * Give demultiplex thread up to 10 seconds to reconnect, should be
	 * greater than cifs socket timeout which is 7 seconds
	 */
	while (server->tcpStatus == CifsNeedReconnect) {
		/*
		 * Return to caller for TREE_DISCONNECT and LOGOFF and CLOSE
		 * here since they are implicitly done when session drops.
		 */
		switch (smb2_command) {
		/*
		 * BB Should we keep oplock break and add flush to exceptions?
		 */
		case SMB2_TREE_DISCONNECT:
		case SMB2_CANCEL:
		case SMB2_CLOSE:
		case SMB2_OPLOCK_BREAK:
			return -EAGAIN;
		}

		wait_event_interruptible_timeout(server->response_q,
			(server->tcpStatus != CifsNeedReconnect), 10 * HZ);

		/* are we still trying to reconnect? */
		if (server->tcpStatus != CifsNeedReconnect)
			break;

		/*
		 * on "soft" mounts we wait once. Hard mounts keep
		 * retrying until process is killed or server comes
		 * back on-line
		 */
		if (!tcon->retry) {
			cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
			return -EHOSTDOWN;
		}
	}

	if (!tcon->ses->need_reconnect && !tcon->need_reconnect)
		return rc;

	nls_codepage = load_nls_default();

	/*
	 * need to prevent multiple threads trying to simultaneously reconnect
	 * the same SMB session
	 */
	mutex_lock(&tcon->ses->session_mutex);

	/*
	 * Recheck after acquire mutex. If another thread is negotiating
	 * and the server never sends an answer the socket will be closed
	 * and tcpStatus set to reconnect.
	 */
	if (server->tcpStatus == CifsNeedReconnect) {
		rc = -EHOSTDOWN;
		mutex_unlock(&tcon->ses->session_mutex);
		goto out;
	}

	rc = cifs_negotiate_protocol(0, tcon->ses);
	if (!rc && tcon->ses->need_reconnect)
		rc = cifs_setup_session(0, tcon->ses, nls_codepage);

	if (rc || !tcon->need_reconnect) {
		mutex_unlock(&tcon->ses->session_mutex);
		goto out;
	}

	cifs_mark_open_files_invalid(tcon);
	if (tcon->use_persistent)
		tcon->need_reopen_files = true;

	rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage);
	mutex_unlock(&tcon->ses->session_mutex);

	cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
	if (rc) {
		/* If sess reconnected but tcon didn't, something strange ... */
		printk_once(KERN_WARNING "reconnect tcon failed rc = %d\n", rc);
		goto out;
	}

	if (smb2_command != SMB2_INTERNAL_CMD)
		queue_delayed_work(cifsiod_wq, &server->reconnect, 0);

	atomic_inc(&tconInfoReconnectCount);
out:
	/*
	 * Check if handle based operation so we know whether we can continue
	 * or not without returning to caller to reset file handle.
	 */
	/*
	 * BB Is flush done by server on drop of tcp session? Should we special
	 * case it and skip above?
	 */
	switch (smb2_command) {
	case SMB2_FLUSH:
	case SMB2_READ:
	case SMB2_WRITE:
	case SMB2_LOCK:
	case SMB2_IOCTL:
	case SMB2_QUERY_DIRECTORY:
	case SMB2_CHANGE_NOTIFY:
	case SMB2_QUERY_INFO:
	case SMB2_SET_INFO:
		rc = -EAGAIN;
	}
	unload_nls(nls_codepage);
	return rc;
}

static void
fill_small_buf(__le16 smb2_command, struct cifs_tcon *tcon, void *buf,
	       unsigned int *total_len)
{
	struct smb2_sync_pdu *spdu = (struct smb2_sync_pdu *)buf;
	/* lookup word count ie StructureSize from table */
	__u16 parmsize = smb2_req_struct_sizes[le16_to_cpu(smb2_command)];

	/*
	 * smaller than SMALL_BUFFER_SIZE but bigger than fixed area of
	 * largest operations (Create)
	 */
	memset(buf, 0, 256);

	smb2_hdr_assemble(&spdu->sync_hdr, smb2_command, tcon);
	spdu->StructureSize2 = cpu_to_le16(parmsize);

	*total_len = parmsize + sizeof(struct smb2_sync_hdr);
}

/*
 * Allocate and return pointer to an SMB request hdr, and set basic
 * SMB information in the SMB header. If the return code is zero, this
 * function must have filled in request_buf pointer.
 */
static int
smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
		    void **request_buf, unsigned int *total_len)
{
	int rc;

	rc = smb2_reconnect(smb2_command, tcon);
	if (rc)
		return rc;

	/* BB eventually switch this to SMB2 specific small buf size */
	*request_buf = cifs_small_buf_get();
	if (*request_buf == NULL) {
		/* BB should we add a retry in here if not a writepage? */
		return -ENOMEM;
	}

	fill_small_buf(smb2_command, tcon,
		       (struct smb2_sync_hdr *)(*request_buf),
		       total_len);

	if (tcon != NULL) {
#ifdef CONFIG_CIFS_STATS2
		uint16_t com_code = le16_to_cpu(smb2_command);
		cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_sent[com_code]);
#endif
		cifs_stats_inc(&tcon->num_smbs_sent);
	}

	return rc;
}

#ifdef CONFIG_CIFS_SMB311
/* offset is sizeof smb2_negotiate_req but rounded up to 8 bytes */
#define OFFSET_OF_NEG_CONTEXT 0x68  /* sizeof(struct smb2_negotiate_req) */


#define SMB2_PREAUTH_INTEGRITY_CAPABILITIES	cpu_to_le16(1)
#define SMB2_ENCRYPTION_CAPABILITIES		cpu_to_le16(2)

static void
build_preauth_ctxt(struct smb2_preauth_neg_context *pneg_ctxt)
{
	pneg_ctxt->ContextType = SMB2_PREAUTH_INTEGRITY_CAPABILITIES;
	pneg_ctxt->DataLength = cpu_to_le16(38);
	pneg_ctxt->HashAlgorithmCount = cpu_to_le16(1);
	pneg_ctxt->SaltLength = cpu_to_le16(SMB311_SALT_SIZE);
	get_random_bytes(pneg_ctxt->Salt, SMB311_SALT_SIZE);
	pneg_ctxt->HashAlgorithms = SMB2_PREAUTH_INTEGRITY_SHA512;
}

static void
build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt)
{
	pneg_ctxt->ContextType = SMB2_ENCRYPTION_CAPABILITIES;
	pneg_ctxt->DataLength = cpu_to_le16(4); /* Cipher Count + le16 cipher */
	pneg_ctxt->CipherCount = cpu_to_le16(1);
/* pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_GCM;*/ /* not supported yet */
	pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_CCM;
}

static void
assemble_neg_contexts(struct smb2_negotiate_req *req,
		      unsigned int *total_len)
{
	char *pneg_ctxt = (char *)req + OFFSET_OF_NEG_CONTEXT;

	build_preauth_ctxt((struct smb2_preauth_neg_context *)pneg_ctxt);
	/* Add 2 to size to round to 8 byte boundary */

	pneg_ctxt += 2 + sizeof(struct smb2_preauth_neg_context);
	build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt);
	req->NegotiateContextOffset = cpu_to_le32(OFFSET_OF_NEG_CONTEXT);
	req->NegotiateContextCount = cpu_to_le16(2);

	*total_len += 4 + sizeof(struct smb2_preauth_neg_context)
		+ sizeof(struct smb2_encryption_neg_context);
}

static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt)
{
	unsigned int len = le16_to_cpu(ctxt->DataLength);

	/* If invalid preauth context warn but use what we requested, SHA-512 */
	if (len < MIN_PREAUTH_CTXT_DATA_LEN) {
		printk_once(KERN_WARNING "server sent bad preauth context\n");
		return;
	}
	if (le16_to_cpu(ctxt->HashAlgorithmCount) != 1)
		printk_once(KERN_WARNING "illegal SMB3 hash algorithm count\n");
	if (ctxt->HashAlgorithms != SMB2_PREAUTH_INTEGRITY_SHA512)
		printk_once(KERN_WARNING "unknown SMB3 hash algorithm\n");
}

static int decode_encrypt_ctx(struct TCP_Server_Info *server,
			      struct smb2_encryption_neg_context *ctxt)
{
	unsigned int len = le16_to_cpu(ctxt->DataLength);

	cifs_dbg(FYI, "decode SMB3.11 encryption neg context of len %d\n", len);
	if (len < MIN_ENCRYPT_CTXT_DATA_LEN) {
		printk_once(KERN_WARNING "server sent bad crypto ctxt len\n");
		return -EINVAL;
	}

	if (le16_to_cpu(ctxt->CipherCount) != 1) {
		printk_once(KERN_WARNING "illegal SMB3.11 cipher count\n");
		return -EINVAL;
	}
	cifs_dbg(FYI, "SMB311 cipher type:%d\n", le16_to_cpu(ctxt->Ciphers[0]));
	if ((ctxt->Ciphers[0] != SMB2_ENCRYPTION_AES128_CCM) &&
	    (ctxt->Ciphers[0] != SMB2_ENCRYPTION_AES128_GCM)) {
		printk_once(KERN_WARNING "invalid SMB3.11 cipher returned\n");
		return -EINVAL;
	}
	server->cipher_type = ctxt->Ciphers[0];
	server->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION;
	return 0;
}

static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
				     struct TCP_Server_Info *server)
{
	struct smb2_neg_context *pctx;
	unsigned int offset = le32_to_cpu(rsp->NegotiateContextOffset);
	unsigned int ctxt_cnt = le16_to_cpu(rsp->NegotiateContextCount);
	unsigned int len_of_smb = be32_to_cpu(rsp->hdr.smb2_buf_length);
	unsigned int len_of_ctxts, i;
	int rc = 0;

	cifs_dbg(FYI, "decoding %d negotiate contexts\n", ctxt_cnt);
	if (len_of_smb <= offset) {
		cifs_dbg(VFS, "Invalid response: negotiate context offset\n");
		return -EINVAL;
	}

	len_of_ctxts = len_of_smb - offset;

	for (i = 0; i < ctxt_cnt; i++) {
		int clen;
		/* check that offset is not beyond end of SMB */
		if (len_of_ctxts == 0)
			break;

		if (len_of_ctxts < sizeof(struct smb2_neg_context))
			break;

		pctx = (struct smb2_neg_context *)(offset +
			server->vals->header_preamble_size + (char *)rsp);
		clen = le16_to_cpu(pctx->DataLength);
		if (clen > len_of_ctxts)
			break;

		if (pctx->ContextType == SMB2_PREAUTH_INTEGRITY_CAPABILITIES)
			decode_preauth_context(
				(struct smb2_preauth_neg_context *)pctx);
		else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES)
			rc = decode_encrypt_ctx(server,
				(struct smb2_encryption_neg_context *)pctx);
		else
			cifs_dbg(VFS, "unknown negcontext of type %d ignored\n",
				le16_to_cpu(pctx->ContextType));

		if (rc)
			break;
		/* offsets must be 8 byte aligned */
		clen = (clen + 7) & ~0x7;
		offset += clen + sizeof(struct smb2_neg_context);
		len_of_ctxts -= clen;
	}
	return rc;
}

#else
static void assemble_neg_contexts(struct smb2_negotiate_req *req,
				  unsigned int *total_len)
{
	return;
}
#endif /* SMB311 */

/*
 *
 *	SMB2 Worker functions follow:
 *
 *	The general structure of the worker functions is:
 *	1) Call smb2_init (assembles SMB2 header)
 *	2) Initialize SMB2 command specific fields in fixed length area of SMB
 *	3) Call smb_sendrcv2 (sends request on socket and waits for response)
 *	4) Decode SMB2 command specific fields in the fixed length area
 *	5) Decode variable length data area (if any for this SMB2 command type)
 *	6) Call free smb buffer
 *	7) return
 *
 */

int
SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
{
	struct smb2_negotiate_req *req;
	struct smb2_negotiate_rsp *rsp;
	struct kvec iov[1];
	struct kvec rsp_iov;
	int rc = 0;
	int resp_buftype;
	struct TCP_Server_Info *server = ses->server;
	int blob_offset, blob_length;
	char *security_blob;
	int flags = CIFS_NEG_OP;
	unsigned int total_len;

	cifs_dbg(FYI, "Negotiate protocol\n");

	if (!server) {
		WARN(1, "%s: server is NULL!\n", __func__);
		return -EIO;
	}

	rc = smb2_plain_req_init(SMB2_NEGOTIATE, NULL, (void **) &req, &total_len);
	if (rc)
		return rc;

	req->sync_hdr.SessionId = 0;
#ifdef CONFIG_CIFS_SMB311
	memset(server->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE);
	memset(ses->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE);
#endif

	if (strcmp(ses->server->vals->version_string,
		   SMB3ANY_VERSION_STRING) == 0) {
		req->Dialects[0] = cpu_to_le16(SMB30_PROT_ID);
		req->Dialects[1] = cpu_to_le16(SMB302_PROT_ID);
		req->DialectCount = cpu_to_le16(2);
		total_len += 4;
	} else if (strcmp(ses->server->vals->version_string,
		   SMBDEFAULT_VERSION_STRING) == 0) {
		req->Dialects[0] = cpu_to_le16(SMB21_PROT_ID);
		req->Dialects[1] = cpu_to_le16(SMB30_PROT_ID);
		req->Dialects[2] = cpu_to_le16(SMB302_PROT_ID);
		req->DialectCount = cpu_to_le16(3);
		total_len += 6;
	} else {
		/* otherwise send specific dialect */
		req->Dialects[0] = cpu_to_le16(ses->server->vals->protocol_id);
		req->DialectCount = cpu_to_le16(1);
		total_len += 2;
	}

	/* only one of SMB2 signing flags may be set in SMB2 request */
	if (ses->sign)
		req->SecurityMode = cpu_to_le16(SMB2_NEGOTIATE_SIGNING_REQUIRED);
	else if (global_secflags & CIFSSEC_MAY_SIGN)
		req->SecurityMode = cpu_to_le16(SMB2_NEGOTIATE_SIGNING_ENABLED);
	else
		req->SecurityMode = 0;

	req->Capabilities = cpu_to_le32(ses->server->vals->req_capabilities);

	/* ClientGUID must be zero for SMB2.02 dialect */
	if (ses->server->vals->protocol_id == SMB20_PROT_ID)
		memset(req->ClientGUID, 0, SMB2_CLIENT_GUID_SIZE);
	else {
		memcpy(req->ClientGUID, server->client_guid,
			SMB2_CLIENT_GUID_SIZE);
		if (ses->server->vals->protocol_id == SMB311_PROT_ID)
			assemble_neg_contexts(req, &total_len);
	}
	iov[0].iov_base = (char *)req;
	iov[0].iov_len = total_len;

	rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
	cifs_small_buf_release(req);
	rsp = (struct smb2_negotiate_rsp *)rsp_iov.iov_base;
	/*
	 * No tcon so can't do
	 * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]);
	 */
	if (rc == -EOPNOTSUPP) {
		cifs_dbg(VFS, "Dialect not supported by server. Consider "
			"specifying vers=1.0 or vers=2.0 on mount for accessing"
			" older servers\n");
		goto neg_exit;
	} else if (rc != 0)
		goto neg_exit;

	if (strcmp(ses->server->vals->version_string,
		   SMB3ANY_VERSION_STRING) == 0) {
		if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) {
			cifs_dbg(VFS,
				"SMB2 dialect returned but not requested\n");
			return -EIO;
		} else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) {
			cifs_dbg(VFS,
				"SMB2.1 dialect returned but not requested\n");
			return -EIO;
		}
	} else if (strcmp(ses->server->vals->version_string,
		   SMBDEFAULT_VERSION_STRING) == 0) {
		if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) {
			cifs_dbg(VFS,
				"SMB2 dialect returned but not requested\n");
			return -EIO;
		} else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) {
			/* ops set to 3.0 by default for default so update */
			ses->server->ops = &smb21_operations;
		}
	} else if (le16_to_cpu(rsp->DialectRevision) !=
				ses->server->vals->protocol_id) {
		/* if requested single dialect ensure returned dialect matched */
		cifs_dbg(VFS, "Illegal 0x%x dialect returned: not requested\n",
			le16_to_cpu(rsp->DialectRevision));
		return -EIO;
	}

	cifs_dbg(FYI, "mode 0x%x\n", rsp->SecurityMode);

	if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID))
		cifs_dbg(FYI, "negotiated smb2.0 dialect\n");
	else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID))
		cifs_dbg(FYI, "negotiated smb2.1 dialect\n");
	else if (rsp->DialectRevision == cpu_to_le16(SMB30_PROT_ID))
		cifs_dbg(FYI, "negotiated smb3.0 dialect\n");
	else if (rsp->DialectRevision == cpu_to_le16(SMB302_PROT_ID))
		cifs_dbg(FYI, "negotiated smb3.02 dialect\n");
#ifdef CONFIG_CIFS_SMB311
	else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID))
		cifs_dbg(FYI, "negotiated smb3.1.1 dialect\n");
#endif /* SMB311 */
	else {
		cifs_dbg(VFS, "Illegal dialect returned by server 0x%x\n",
			 le16_to_cpu(rsp->DialectRevision));
		rc = -EIO;
		goto neg_exit;
	}
	server->dialect = le16_to_cpu(rsp->DialectRevision);