2 * SMB2 version specific operations
4 * Copyright (c) 2012, Jeff Layton <jlayton@redhat.com>
6 * This library is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License v2 as published
8 * by the Free Software Foundation.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "smb2proto.h"
23 #include "cifsproto.h"
24 #include "cifs_debug.h"
27 change_conf(struct TCP_Server_Info
*server
)
29 server
->credits
+= server
->echo_credits
+ server
->oplock_credits
;
30 server
->oplock_credits
= server
->echo_credits
= 0;
31 switch (server
->credits
) {
35 server
->echoes
= false;
36 server
->oplocks
= false;
37 cERROR(1, "disabling echoes and oplocks");
40 server
->echoes
= true;
41 server
->oplocks
= false;
42 server
->echo_credits
= 1;
43 cFYI(1, "disabling oplocks");
46 server
->echoes
= true;
47 server
->oplocks
= true;
48 server
->echo_credits
= 1;
49 server
->oplock_credits
= 1;
51 server
->credits
-= server
->echo_credits
+ server
->oplock_credits
;
56 smb2_add_credits(struct TCP_Server_Info
*server
, const unsigned int add
,
60 spin_lock(&server
->req_lock
);
61 val
= server
->ops
->get_credits_field(server
, optype
);
64 if (server
->in_flight
== 0 && (optype
& CIFS_OP_MASK
) != CIFS_NEG_OP
)
65 rc
= change_conf(server
);
66 spin_unlock(&server
->req_lock
);
67 wake_up(&server
->request_q
);
69 cifs_reconnect(server
);
73 smb2_set_credits(struct TCP_Server_Info
*server
, const int val
)
75 spin_lock(&server
->req_lock
);
76 server
->credits
= val
;
77 spin_unlock(&server
->req_lock
);
81 smb2_get_credits_field(struct TCP_Server_Info
*server
, const int optype
)
85 return &server
->echo_credits
;
87 return &server
->oplock_credits
;
89 return &server
->credits
;
94 smb2_get_credits(struct mid_q_entry
*mid
)
96 return le16_to_cpu(((struct smb2_hdr
*)mid
->resp_buf
)->CreditRequest
);
100 smb2_get_next_mid(struct TCP_Server_Info
*server
)
103 /* for SMB2 we need the current value */
104 spin_lock(&GlobalMid_Lock
);
105 mid
= server
->CurrentMid
++;
106 spin_unlock(&GlobalMid_Lock
);
110 static struct mid_q_entry
*
111 smb2_find_mid(struct TCP_Server_Info
*server
, char *buf
)
113 struct mid_q_entry
*mid
;
114 struct smb2_hdr
*hdr
= (struct smb2_hdr
*)buf
;
116 spin_lock(&GlobalMid_Lock
);
117 list_for_each_entry(mid
, &server
->pending_mid_q
, qhead
) {
118 if ((mid
->mid
== hdr
->MessageId
) &&
119 (mid
->mid_state
== MID_REQUEST_SUBMITTED
) &&
120 (mid
->command
== hdr
->Command
)) {
121 spin_unlock(&GlobalMid_Lock
);
125 spin_unlock(&GlobalMid_Lock
);
130 smb2_dump_detail(void *buf
)
132 #ifdef CONFIG_CIFS_DEBUG2
133 struct smb2_hdr
*smb
= (struct smb2_hdr
*)buf
;
135 cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d",
136 smb
->Command
, smb
->Status
, smb
->Flags
, smb
->MessageId
,
138 cERROR(1, "smb buf %p len %u", smb
, smb2_calc_size(smb
));
143 smb2_need_neg(struct TCP_Server_Info
*server
)
145 return server
->max_read
== 0;
149 smb2_negotiate(const unsigned int xid
, struct cifs_ses
*ses
)
152 ses
->server
->CurrentMid
= 0;
153 rc
= SMB2_negotiate(xid
, ses
);
154 /* BB we probably don't need to retry with modern servers */
161 smb2_is_path_accessible(const unsigned int xid
, struct cifs_tcon
*tcon
,
162 struct cifs_sb_info
*cifs_sb
, const char *full_path
)
165 __u64 persistent_fid
, volatile_fid
;
168 utf16_path
= cifs_convert_path_to_utf16(full_path
, cifs_sb
);
172 rc
= SMB2_open(xid
, tcon
, utf16_path
, &persistent_fid
, &volatile_fid
,
173 FILE_READ_ATTRIBUTES
, FILE_OPEN
, 0, 0);
179 rc
= SMB2_close(xid
, tcon
, persistent_fid
, volatile_fid
);
184 struct smb_version_operations smb21_operations
= {
185 .setup_request
= smb2_setup_request
,
186 .check_receive
= smb2_check_receive
,
187 .add_credits
= smb2_add_credits
,
188 .set_credits
= smb2_set_credits
,
189 .get_credits_field
= smb2_get_credits_field
,
190 .get_credits
= smb2_get_credits
,
191 .get_next_mid
= smb2_get_next_mid
,
192 .find_mid
= smb2_find_mid
,
193 .check_message
= smb2_check_message
,
194 .dump_detail
= smb2_dump_detail
,
195 .need_neg
= smb2_need_neg
,
196 .negotiate
= smb2_negotiate
,
197 .sess_setup
= SMB2_sess_setup
,
198 .logoff
= SMB2_logoff
,
199 .tree_connect
= SMB2_tcon
,
200 .tree_disconnect
= SMB2_tdis
,
201 .is_path_accessible
= smb2_is_path_accessible
,
204 struct smb_version_values smb21_values
= {
205 .version_string
= SMB21_VERSION_STRING
,
206 .header_size
= sizeof(struct smb2_hdr
),
207 .max_header_size
= MAX_SMB2_HDR_SIZE
,
208 .lock_cmd
= SMB2_LOCK
,