Commit 7a5cfb1965854132f2f382eade8c6ce2eeb6f692
Committed by
Steve French
1 parent
1d8c4c0009
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
CIFS: Add SMB2 support for flush
Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org> Signed-off-by: Steve French <smfrench@gmail.com>
Showing 4 changed files with 63 additions and 0 deletions Inline Diff
fs/cifs/smb2ops.c
1 | /* | 1 | /* |
2 | * SMB2 version specific operations | 2 | * SMB2 version specific operations |
3 | * | 3 | * |
4 | * Copyright (c) 2012, Jeff Layton <jlayton@redhat.com> | 4 | * Copyright (c) 2012, Jeff Layton <jlayton@redhat.com> |
5 | * | 5 | * |
6 | * This library is free software; you can redistribute it and/or modify | 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 | 7 | * it under the terms of the GNU General Public License v2 as published |
8 | * by the Free Software Foundation. | 8 | * by the Free Software Foundation. |
9 | * | 9 | * |
10 | * This library is distributed in the hope that it will be useful, | 10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
13 | * the GNU Lesser General Public License for more details. | 13 | * the GNU Lesser General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU Lesser General Public License | 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 | 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 | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include "cifsglob.h" | 20 | #include "cifsglob.h" |
21 | #include "smb2pdu.h" | 21 | #include "smb2pdu.h" |
22 | #include "smb2proto.h" | 22 | #include "smb2proto.h" |
23 | #include "cifsproto.h" | 23 | #include "cifsproto.h" |
24 | #include "cifs_debug.h" | 24 | #include "cifs_debug.h" |
25 | 25 | ||
26 | static int | 26 | static int |
27 | change_conf(struct TCP_Server_Info *server) | 27 | change_conf(struct TCP_Server_Info *server) |
28 | { | 28 | { |
29 | server->credits += server->echo_credits + server->oplock_credits; | 29 | server->credits += server->echo_credits + server->oplock_credits; |
30 | server->oplock_credits = server->echo_credits = 0; | 30 | server->oplock_credits = server->echo_credits = 0; |
31 | switch (server->credits) { | 31 | switch (server->credits) { |
32 | case 0: | 32 | case 0: |
33 | return -1; | 33 | return -1; |
34 | case 1: | 34 | case 1: |
35 | server->echoes = false; | 35 | server->echoes = false; |
36 | server->oplocks = false; | 36 | server->oplocks = false; |
37 | cERROR(1, "disabling echoes and oplocks"); | 37 | cERROR(1, "disabling echoes and oplocks"); |
38 | break; | 38 | break; |
39 | case 2: | 39 | case 2: |
40 | server->echoes = true; | 40 | server->echoes = true; |
41 | server->oplocks = false; | 41 | server->oplocks = false; |
42 | server->echo_credits = 1; | 42 | server->echo_credits = 1; |
43 | cFYI(1, "disabling oplocks"); | 43 | cFYI(1, "disabling oplocks"); |
44 | break; | 44 | break; |
45 | default: | 45 | default: |
46 | server->echoes = true; | 46 | server->echoes = true; |
47 | server->oplocks = true; | 47 | server->oplocks = true; |
48 | server->echo_credits = 1; | 48 | server->echo_credits = 1; |
49 | server->oplock_credits = 1; | 49 | server->oplock_credits = 1; |
50 | } | 50 | } |
51 | server->credits -= server->echo_credits + server->oplock_credits; | 51 | server->credits -= server->echo_credits + server->oplock_credits; |
52 | return 0; | 52 | return 0; |
53 | } | 53 | } |
54 | 54 | ||
55 | static void | 55 | static void |
56 | smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add, | 56 | smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add, |
57 | const int optype) | 57 | const int optype) |
58 | { | 58 | { |
59 | int *val, rc = 0; | 59 | int *val, rc = 0; |
60 | spin_lock(&server->req_lock); | 60 | spin_lock(&server->req_lock); |
61 | val = server->ops->get_credits_field(server, optype); | 61 | val = server->ops->get_credits_field(server, optype); |
62 | *val += add; | 62 | *val += add; |
63 | server->in_flight--; | 63 | server->in_flight--; |
64 | if (server->in_flight == 0 && (optype & CIFS_OP_MASK) != CIFS_NEG_OP) | 64 | if (server->in_flight == 0 && (optype & CIFS_OP_MASK) != CIFS_NEG_OP) |
65 | rc = change_conf(server); | 65 | rc = change_conf(server); |
66 | spin_unlock(&server->req_lock); | 66 | spin_unlock(&server->req_lock); |
67 | wake_up(&server->request_q); | 67 | wake_up(&server->request_q); |
68 | if (rc) | 68 | if (rc) |
69 | cifs_reconnect(server); | 69 | cifs_reconnect(server); |
70 | } | 70 | } |
71 | 71 | ||
72 | static void | 72 | static void |
73 | smb2_set_credits(struct TCP_Server_Info *server, const int val) | 73 | smb2_set_credits(struct TCP_Server_Info *server, const int val) |
74 | { | 74 | { |
75 | spin_lock(&server->req_lock); | 75 | spin_lock(&server->req_lock); |
76 | server->credits = val; | 76 | server->credits = val; |
77 | spin_unlock(&server->req_lock); | 77 | spin_unlock(&server->req_lock); |
78 | } | 78 | } |
79 | 79 | ||
80 | static int * | 80 | static int * |
81 | smb2_get_credits_field(struct TCP_Server_Info *server, const int optype) | 81 | smb2_get_credits_field(struct TCP_Server_Info *server, const int optype) |
82 | { | 82 | { |
83 | switch (optype) { | 83 | switch (optype) { |
84 | case CIFS_ECHO_OP: | 84 | case CIFS_ECHO_OP: |
85 | return &server->echo_credits; | 85 | return &server->echo_credits; |
86 | case CIFS_OBREAK_OP: | 86 | case CIFS_OBREAK_OP: |
87 | return &server->oplock_credits; | 87 | return &server->oplock_credits; |
88 | default: | 88 | default: |
89 | return &server->credits; | 89 | return &server->credits; |
90 | } | 90 | } |
91 | } | 91 | } |
92 | 92 | ||
93 | static unsigned int | 93 | static unsigned int |
94 | smb2_get_credits(struct mid_q_entry *mid) | 94 | smb2_get_credits(struct mid_q_entry *mid) |
95 | { | 95 | { |
96 | return le16_to_cpu(((struct smb2_hdr *)mid->resp_buf)->CreditRequest); | 96 | return le16_to_cpu(((struct smb2_hdr *)mid->resp_buf)->CreditRequest); |
97 | } | 97 | } |
98 | 98 | ||
99 | static __u64 | 99 | static __u64 |
100 | smb2_get_next_mid(struct TCP_Server_Info *server) | 100 | smb2_get_next_mid(struct TCP_Server_Info *server) |
101 | { | 101 | { |
102 | __u64 mid; | 102 | __u64 mid; |
103 | /* for SMB2 we need the current value */ | 103 | /* for SMB2 we need the current value */ |
104 | spin_lock(&GlobalMid_Lock); | 104 | spin_lock(&GlobalMid_Lock); |
105 | mid = server->CurrentMid++; | 105 | mid = server->CurrentMid++; |
106 | spin_unlock(&GlobalMid_Lock); | 106 | spin_unlock(&GlobalMid_Lock); |
107 | return mid; | 107 | return mid; |
108 | } | 108 | } |
109 | 109 | ||
110 | static struct mid_q_entry * | 110 | static struct mid_q_entry * |
111 | smb2_find_mid(struct TCP_Server_Info *server, char *buf) | 111 | smb2_find_mid(struct TCP_Server_Info *server, char *buf) |
112 | { | 112 | { |
113 | struct mid_q_entry *mid; | 113 | struct mid_q_entry *mid; |
114 | struct smb2_hdr *hdr = (struct smb2_hdr *)buf; | 114 | struct smb2_hdr *hdr = (struct smb2_hdr *)buf; |
115 | 115 | ||
116 | spin_lock(&GlobalMid_Lock); | 116 | spin_lock(&GlobalMid_Lock); |
117 | list_for_each_entry(mid, &server->pending_mid_q, qhead) { | 117 | list_for_each_entry(mid, &server->pending_mid_q, qhead) { |
118 | if ((mid->mid == hdr->MessageId) && | 118 | if ((mid->mid == hdr->MessageId) && |
119 | (mid->mid_state == MID_REQUEST_SUBMITTED) && | 119 | (mid->mid_state == MID_REQUEST_SUBMITTED) && |
120 | (mid->command == hdr->Command)) { | 120 | (mid->command == hdr->Command)) { |
121 | spin_unlock(&GlobalMid_Lock); | 121 | spin_unlock(&GlobalMid_Lock); |
122 | return mid; | 122 | return mid; |
123 | } | 123 | } |
124 | } | 124 | } |
125 | spin_unlock(&GlobalMid_Lock); | 125 | spin_unlock(&GlobalMid_Lock); |
126 | return NULL; | 126 | return NULL; |
127 | } | 127 | } |
128 | 128 | ||
129 | static void | 129 | static void |
130 | smb2_dump_detail(void *buf) | 130 | smb2_dump_detail(void *buf) |
131 | { | 131 | { |
132 | #ifdef CONFIG_CIFS_DEBUG2 | 132 | #ifdef CONFIG_CIFS_DEBUG2 |
133 | struct smb2_hdr *smb = (struct smb2_hdr *)buf; | 133 | struct smb2_hdr *smb = (struct smb2_hdr *)buf; |
134 | 134 | ||
135 | cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d", | 135 | cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d", |
136 | smb->Command, smb->Status, smb->Flags, smb->MessageId, | 136 | smb->Command, smb->Status, smb->Flags, smb->MessageId, |
137 | smb->ProcessId); | 137 | smb->ProcessId); |
138 | cERROR(1, "smb buf %p len %u", smb, smb2_calc_size(smb)); | 138 | cERROR(1, "smb buf %p len %u", smb, smb2_calc_size(smb)); |
139 | #endif | 139 | #endif |
140 | } | 140 | } |
141 | 141 | ||
142 | static bool | 142 | static bool |
143 | smb2_need_neg(struct TCP_Server_Info *server) | 143 | smb2_need_neg(struct TCP_Server_Info *server) |
144 | { | 144 | { |
145 | return server->max_read == 0; | 145 | return server->max_read == 0; |
146 | } | 146 | } |
147 | 147 | ||
148 | static int | 148 | static int |
149 | smb2_negotiate(const unsigned int xid, struct cifs_ses *ses) | 149 | smb2_negotiate(const unsigned int xid, struct cifs_ses *ses) |
150 | { | 150 | { |
151 | int rc; | 151 | int rc; |
152 | ses->server->CurrentMid = 0; | 152 | ses->server->CurrentMid = 0; |
153 | rc = SMB2_negotiate(xid, ses); | 153 | rc = SMB2_negotiate(xid, ses); |
154 | /* BB we probably don't need to retry with modern servers */ | 154 | /* BB we probably don't need to retry with modern servers */ |
155 | if (rc == -EAGAIN) | 155 | if (rc == -EAGAIN) |
156 | rc = -EHOSTDOWN; | 156 | rc = -EHOSTDOWN; |
157 | return rc; | 157 | return rc; |
158 | } | 158 | } |
159 | 159 | ||
160 | static int | 160 | static int |
161 | smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, | 161 | smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, |
162 | struct cifs_sb_info *cifs_sb, const char *full_path) | 162 | struct cifs_sb_info *cifs_sb, const char *full_path) |
163 | { | 163 | { |
164 | int rc; | 164 | int rc; |
165 | __u64 persistent_fid, volatile_fid; | 165 | __u64 persistent_fid, volatile_fid; |
166 | __le16 *utf16_path; | 166 | __le16 *utf16_path; |
167 | 167 | ||
168 | utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); | 168 | utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); |
169 | if (!utf16_path) | 169 | if (!utf16_path) |
170 | return -ENOMEM; | 170 | return -ENOMEM; |
171 | 171 | ||
172 | rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid, | 172 | rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid, |
173 | FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, NULL); | 173 | FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, NULL); |
174 | if (rc) { | 174 | if (rc) { |
175 | kfree(utf16_path); | 175 | kfree(utf16_path); |
176 | return rc; | 176 | return rc; |
177 | } | 177 | } |
178 | 178 | ||
179 | rc = SMB2_close(xid, tcon, persistent_fid, volatile_fid); | 179 | rc = SMB2_close(xid, tcon, persistent_fid, volatile_fid); |
180 | kfree(utf16_path); | 180 | kfree(utf16_path); |
181 | return rc; | 181 | return rc; |
182 | } | 182 | } |
183 | 183 | ||
184 | static int | 184 | static int |
185 | smb2_get_srv_inum(const unsigned int xid, struct cifs_tcon *tcon, | 185 | smb2_get_srv_inum(const unsigned int xid, struct cifs_tcon *tcon, |
186 | struct cifs_sb_info *cifs_sb, const char *full_path, | 186 | struct cifs_sb_info *cifs_sb, const char *full_path, |
187 | u64 *uniqueid, FILE_ALL_INFO *data) | 187 | u64 *uniqueid, FILE_ALL_INFO *data) |
188 | { | 188 | { |
189 | *uniqueid = le64_to_cpu(data->IndexNumber); | 189 | *uniqueid = le64_to_cpu(data->IndexNumber); |
190 | return 0; | 190 | return 0; |
191 | } | 191 | } |
192 | 192 | ||
193 | static int | 193 | static int |
194 | smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon, | 194 | smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon, |
195 | struct cifs_fid *fid, FILE_ALL_INFO *data) | 195 | struct cifs_fid *fid, FILE_ALL_INFO *data) |
196 | { | 196 | { |
197 | int rc; | 197 | int rc; |
198 | struct smb2_file_all_info *smb2_data; | 198 | struct smb2_file_all_info *smb2_data; |
199 | 199 | ||
200 | smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2, | 200 | smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2, |
201 | GFP_KERNEL); | 201 | GFP_KERNEL); |
202 | if (smb2_data == NULL) | 202 | if (smb2_data == NULL) |
203 | return -ENOMEM; | 203 | return -ENOMEM; |
204 | 204 | ||
205 | rc = SMB2_query_info(xid, tcon, fid->persistent_fid, fid->volatile_fid, | 205 | rc = SMB2_query_info(xid, tcon, fid->persistent_fid, fid->volatile_fid, |
206 | smb2_data); | 206 | smb2_data); |
207 | if (!rc) | 207 | if (!rc) |
208 | move_smb2_info_to_cifs(data, smb2_data); | 208 | move_smb2_info_to_cifs(data, smb2_data); |
209 | kfree(smb2_data); | 209 | kfree(smb2_data); |
210 | return rc; | 210 | return rc; |
211 | } | 211 | } |
212 | 212 | ||
213 | static char * | 213 | static char * |
214 | smb2_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, | 214 | smb2_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, |
215 | struct cifs_tcon *tcon) | 215 | struct cifs_tcon *tcon) |
216 | { | 216 | { |
217 | int pplen = vol->prepath ? strlen(vol->prepath) : 0; | 217 | int pplen = vol->prepath ? strlen(vol->prepath) : 0; |
218 | char *full_path = NULL; | 218 | char *full_path = NULL; |
219 | 219 | ||
220 | /* if no prefix path, simply set path to the root of share to "" */ | 220 | /* if no prefix path, simply set path to the root of share to "" */ |
221 | if (pplen == 0) { | 221 | if (pplen == 0) { |
222 | full_path = kzalloc(2, GFP_KERNEL); | 222 | full_path = kzalloc(2, GFP_KERNEL); |
223 | return full_path; | 223 | return full_path; |
224 | } | 224 | } |
225 | 225 | ||
226 | cERROR(1, "prefixpath is not supported for SMB2 now"); | 226 | cERROR(1, "prefixpath is not supported for SMB2 now"); |
227 | return NULL; | 227 | return NULL; |
228 | } | 228 | } |
229 | 229 | ||
230 | static bool | 230 | static bool |
231 | smb2_can_echo(struct TCP_Server_Info *server) | 231 | smb2_can_echo(struct TCP_Server_Info *server) |
232 | { | 232 | { |
233 | return server->echoes; | 233 | return server->echoes; |
234 | } | 234 | } |
235 | 235 | ||
236 | static void | 236 | static void |
237 | smb2_clear_stats(struct cifs_tcon *tcon) | 237 | smb2_clear_stats(struct cifs_tcon *tcon) |
238 | { | 238 | { |
239 | #ifdef CONFIG_CIFS_STATS | 239 | #ifdef CONFIG_CIFS_STATS |
240 | int i; | 240 | int i; |
241 | for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) { | 241 | for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) { |
242 | atomic_set(&tcon->stats.smb2_stats.smb2_com_sent[i], 0); | 242 | atomic_set(&tcon->stats.smb2_stats.smb2_com_sent[i], 0); |
243 | atomic_set(&tcon->stats.smb2_stats.smb2_com_failed[i], 0); | 243 | atomic_set(&tcon->stats.smb2_stats.smb2_com_failed[i], 0); |
244 | } | 244 | } |
245 | #endif | 245 | #endif |
246 | } | 246 | } |
247 | 247 | ||
248 | static void | 248 | static void |
249 | smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon) | 249 | smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon) |
250 | { | 250 | { |
251 | #ifdef CONFIG_CIFS_STATS | 251 | #ifdef CONFIG_CIFS_STATS |
252 | atomic_t *sent = tcon->stats.smb2_stats.smb2_com_sent; | 252 | atomic_t *sent = tcon->stats.smb2_stats.smb2_com_sent; |
253 | atomic_t *failed = tcon->stats.smb2_stats.smb2_com_failed; | 253 | atomic_t *failed = tcon->stats.smb2_stats.smb2_com_failed; |
254 | seq_printf(m, "\nNegotiates: %d sent %d failed", | 254 | seq_printf(m, "\nNegotiates: %d sent %d failed", |
255 | atomic_read(&sent[SMB2_NEGOTIATE_HE]), | 255 | atomic_read(&sent[SMB2_NEGOTIATE_HE]), |
256 | atomic_read(&failed[SMB2_NEGOTIATE_HE])); | 256 | atomic_read(&failed[SMB2_NEGOTIATE_HE])); |
257 | seq_printf(m, "\nSessionSetups: %d sent %d failed", | 257 | seq_printf(m, "\nSessionSetups: %d sent %d failed", |
258 | atomic_read(&sent[SMB2_SESSION_SETUP_HE]), | 258 | atomic_read(&sent[SMB2_SESSION_SETUP_HE]), |
259 | atomic_read(&failed[SMB2_SESSION_SETUP_HE])); | 259 | atomic_read(&failed[SMB2_SESSION_SETUP_HE])); |
260 | #define SMB2LOGOFF 0x0002 /* trivial request/resp */ | 260 | #define SMB2LOGOFF 0x0002 /* trivial request/resp */ |
261 | seq_printf(m, "\nLogoffs: %d sent %d failed", | 261 | seq_printf(m, "\nLogoffs: %d sent %d failed", |
262 | atomic_read(&sent[SMB2_LOGOFF_HE]), | 262 | atomic_read(&sent[SMB2_LOGOFF_HE]), |
263 | atomic_read(&failed[SMB2_LOGOFF_HE])); | 263 | atomic_read(&failed[SMB2_LOGOFF_HE])); |
264 | seq_printf(m, "\nTreeConnects: %d sent %d failed", | 264 | seq_printf(m, "\nTreeConnects: %d sent %d failed", |
265 | atomic_read(&sent[SMB2_TREE_CONNECT_HE]), | 265 | atomic_read(&sent[SMB2_TREE_CONNECT_HE]), |
266 | atomic_read(&failed[SMB2_TREE_CONNECT_HE])); | 266 | atomic_read(&failed[SMB2_TREE_CONNECT_HE])); |
267 | seq_printf(m, "\nTreeDisconnects: %d sent %d failed", | 267 | seq_printf(m, "\nTreeDisconnects: %d sent %d failed", |
268 | atomic_read(&sent[SMB2_TREE_DISCONNECT_HE]), | 268 | atomic_read(&sent[SMB2_TREE_DISCONNECT_HE]), |
269 | atomic_read(&failed[SMB2_TREE_DISCONNECT_HE])); | 269 | atomic_read(&failed[SMB2_TREE_DISCONNECT_HE])); |
270 | seq_printf(m, "\nCreates: %d sent %d failed", | 270 | seq_printf(m, "\nCreates: %d sent %d failed", |
271 | atomic_read(&sent[SMB2_CREATE_HE]), | 271 | atomic_read(&sent[SMB2_CREATE_HE]), |
272 | atomic_read(&failed[SMB2_CREATE_HE])); | 272 | atomic_read(&failed[SMB2_CREATE_HE])); |
273 | seq_printf(m, "\nCloses: %d sent %d failed", | 273 | seq_printf(m, "\nCloses: %d sent %d failed", |
274 | atomic_read(&sent[SMB2_CLOSE_HE]), | 274 | atomic_read(&sent[SMB2_CLOSE_HE]), |
275 | atomic_read(&failed[SMB2_CLOSE_HE])); | 275 | atomic_read(&failed[SMB2_CLOSE_HE])); |
276 | seq_printf(m, "\nFlushes: %d sent %d failed", | 276 | seq_printf(m, "\nFlushes: %d sent %d failed", |
277 | atomic_read(&sent[SMB2_FLUSH_HE]), | 277 | atomic_read(&sent[SMB2_FLUSH_HE]), |
278 | atomic_read(&failed[SMB2_FLUSH_HE])); | 278 | atomic_read(&failed[SMB2_FLUSH_HE])); |
279 | seq_printf(m, "\nReads: %d sent %d failed", | 279 | seq_printf(m, "\nReads: %d sent %d failed", |
280 | atomic_read(&sent[SMB2_READ_HE]), | 280 | atomic_read(&sent[SMB2_READ_HE]), |
281 | atomic_read(&failed[SMB2_READ_HE])); | 281 | atomic_read(&failed[SMB2_READ_HE])); |
282 | seq_printf(m, "\nWrites: %d sent %d failed", | 282 | seq_printf(m, "\nWrites: %d sent %d failed", |
283 | atomic_read(&sent[SMB2_WRITE_HE]), | 283 | atomic_read(&sent[SMB2_WRITE_HE]), |
284 | atomic_read(&failed[SMB2_WRITE_HE])); | 284 | atomic_read(&failed[SMB2_WRITE_HE])); |
285 | seq_printf(m, "\nLocks: %d sent %d failed", | 285 | seq_printf(m, "\nLocks: %d sent %d failed", |
286 | atomic_read(&sent[SMB2_LOCK_HE]), | 286 | atomic_read(&sent[SMB2_LOCK_HE]), |
287 | atomic_read(&failed[SMB2_LOCK_HE])); | 287 | atomic_read(&failed[SMB2_LOCK_HE])); |
288 | seq_printf(m, "\nIOCTLs: %d sent %d failed", | 288 | seq_printf(m, "\nIOCTLs: %d sent %d failed", |
289 | atomic_read(&sent[SMB2_IOCTL_HE]), | 289 | atomic_read(&sent[SMB2_IOCTL_HE]), |
290 | atomic_read(&failed[SMB2_IOCTL_HE])); | 290 | atomic_read(&failed[SMB2_IOCTL_HE])); |
291 | seq_printf(m, "\nCancels: %d sent %d failed", | 291 | seq_printf(m, "\nCancels: %d sent %d failed", |
292 | atomic_read(&sent[SMB2_CANCEL_HE]), | 292 | atomic_read(&sent[SMB2_CANCEL_HE]), |
293 | atomic_read(&failed[SMB2_CANCEL_HE])); | 293 | atomic_read(&failed[SMB2_CANCEL_HE])); |
294 | seq_printf(m, "\nEchos: %d sent %d failed", | 294 | seq_printf(m, "\nEchos: %d sent %d failed", |
295 | atomic_read(&sent[SMB2_ECHO_HE]), | 295 | atomic_read(&sent[SMB2_ECHO_HE]), |
296 | atomic_read(&failed[SMB2_ECHO_HE])); | 296 | atomic_read(&failed[SMB2_ECHO_HE])); |
297 | seq_printf(m, "\nQueryDirectories: %d sent %d failed", | 297 | seq_printf(m, "\nQueryDirectories: %d sent %d failed", |
298 | atomic_read(&sent[SMB2_QUERY_DIRECTORY_HE]), | 298 | atomic_read(&sent[SMB2_QUERY_DIRECTORY_HE]), |
299 | atomic_read(&failed[SMB2_QUERY_DIRECTORY_HE])); | 299 | atomic_read(&failed[SMB2_QUERY_DIRECTORY_HE])); |
300 | seq_printf(m, "\nChangeNotifies: %d sent %d failed", | 300 | seq_printf(m, "\nChangeNotifies: %d sent %d failed", |
301 | atomic_read(&sent[SMB2_CHANGE_NOTIFY_HE]), | 301 | atomic_read(&sent[SMB2_CHANGE_NOTIFY_HE]), |
302 | atomic_read(&failed[SMB2_CHANGE_NOTIFY_HE])); | 302 | atomic_read(&failed[SMB2_CHANGE_NOTIFY_HE])); |
303 | seq_printf(m, "\nQueryInfos: %d sent %d failed", | 303 | seq_printf(m, "\nQueryInfos: %d sent %d failed", |
304 | atomic_read(&sent[SMB2_QUERY_INFO_HE]), | 304 | atomic_read(&sent[SMB2_QUERY_INFO_HE]), |
305 | atomic_read(&failed[SMB2_QUERY_INFO_HE])); | 305 | atomic_read(&failed[SMB2_QUERY_INFO_HE])); |
306 | seq_printf(m, "\nSetInfos: %d sent %d failed", | 306 | seq_printf(m, "\nSetInfos: %d sent %d failed", |
307 | atomic_read(&sent[SMB2_SET_INFO_HE]), | 307 | atomic_read(&sent[SMB2_SET_INFO_HE]), |
308 | atomic_read(&failed[SMB2_SET_INFO_HE])); | 308 | atomic_read(&failed[SMB2_SET_INFO_HE])); |
309 | seq_printf(m, "\nOplockBreaks: %d sent %d failed", | 309 | seq_printf(m, "\nOplockBreaks: %d sent %d failed", |
310 | atomic_read(&sent[SMB2_OPLOCK_BREAK_HE]), | 310 | atomic_read(&sent[SMB2_OPLOCK_BREAK_HE]), |
311 | atomic_read(&failed[SMB2_OPLOCK_BREAK_HE])); | 311 | atomic_read(&failed[SMB2_OPLOCK_BREAK_HE])); |
312 | #endif | 312 | #endif |
313 | } | 313 | } |
314 | 314 | ||
315 | static void | 315 | static void |
316 | smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock) | 316 | smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock) |
317 | { | 317 | { |
318 | /* struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); */ | 318 | /* struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); */ |
319 | cfile->fid.persistent_fid = fid->persistent_fid; | 319 | cfile->fid.persistent_fid = fid->persistent_fid; |
320 | cfile->fid.volatile_fid = fid->volatile_fid; | 320 | cfile->fid.volatile_fid = fid->volatile_fid; |
321 | /* cifs_set_oplock_level(cinode, oplock); */ | 321 | /* cifs_set_oplock_level(cinode, oplock); */ |
322 | /* cinode->can_cache_brlcks = cinode->clientCanCacheAll; */ | 322 | /* cinode->can_cache_brlcks = cinode->clientCanCacheAll; */ |
323 | } | 323 | } |
324 | 324 | ||
325 | static int | 325 | static int |
326 | smb2_close_file(const unsigned int xid, struct cifs_tcon *tcon, | 326 | smb2_close_file(const unsigned int xid, struct cifs_tcon *tcon, |
327 | struct cifs_fid *fid) | 327 | struct cifs_fid *fid) |
328 | { | 328 | { |
329 | return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid); | 329 | return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid); |
330 | } | 330 | } |
331 | 331 | ||
332 | static int | ||
333 | smb2_flush_file(const unsigned int xid, struct cifs_tcon *tcon, | ||
334 | struct cifs_fid *fid) | ||
335 | { | ||
336 | return SMB2_flush(xid, tcon, fid->persistent_fid, fid->volatile_fid); | ||
337 | } | ||
338 | |||
332 | struct smb_version_operations smb21_operations = { | 339 | struct smb_version_operations smb21_operations = { |
333 | .setup_request = smb2_setup_request, | 340 | .setup_request = smb2_setup_request, |
334 | .setup_async_request = smb2_setup_async_request, | 341 | .setup_async_request = smb2_setup_async_request, |
335 | .check_receive = smb2_check_receive, | 342 | .check_receive = smb2_check_receive, |
336 | .add_credits = smb2_add_credits, | 343 | .add_credits = smb2_add_credits, |
337 | .set_credits = smb2_set_credits, | 344 | .set_credits = smb2_set_credits, |
338 | .get_credits_field = smb2_get_credits_field, | 345 | .get_credits_field = smb2_get_credits_field, |
339 | .get_credits = smb2_get_credits, | 346 | .get_credits = smb2_get_credits, |
340 | .get_next_mid = smb2_get_next_mid, | 347 | .get_next_mid = smb2_get_next_mid, |
341 | .find_mid = smb2_find_mid, | 348 | .find_mid = smb2_find_mid, |
342 | .check_message = smb2_check_message, | 349 | .check_message = smb2_check_message, |
343 | .dump_detail = smb2_dump_detail, | 350 | .dump_detail = smb2_dump_detail, |
344 | .clear_stats = smb2_clear_stats, | 351 | .clear_stats = smb2_clear_stats, |
345 | .print_stats = smb2_print_stats, | 352 | .print_stats = smb2_print_stats, |
346 | .need_neg = smb2_need_neg, | 353 | .need_neg = smb2_need_neg, |
347 | .negotiate = smb2_negotiate, | 354 | .negotiate = smb2_negotiate, |
348 | .sess_setup = SMB2_sess_setup, | 355 | .sess_setup = SMB2_sess_setup, |
349 | .logoff = SMB2_logoff, | 356 | .logoff = SMB2_logoff, |
350 | .tree_connect = SMB2_tcon, | 357 | .tree_connect = SMB2_tcon, |
351 | .tree_disconnect = SMB2_tdis, | 358 | .tree_disconnect = SMB2_tdis, |
352 | .is_path_accessible = smb2_is_path_accessible, | 359 | .is_path_accessible = smb2_is_path_accessible, |
353 | .can_echo = smb2_can_echo, | 360 | .can_echo = smb2_can_echo, |
354 | .echo = SMB2_echo, | 361 | .echo = SMB2_echo, |
355 | .query_path_info = smb2_query_path_info, | 362 | .query_path_info = smb2_query_path_info, |
356 | .get_srv_inum = smb2_get_srv_inum, | 363 | .get_srv_inum = smb2_get_srv_inum, |
357 | .query_file_info = smb2_query_file_info, | 364 | .query_file_info = smb2_query_file_info, |
358 | .build_path_to_root = smb2_build_path_to_root, | 365 | .build_path_to_root = smb2_build_path_to_root, |
359 | .mkdir = smb2_mkdir, | 366 | .mkdir = smb2_mkdir, |
360 | .mkdir_setinfo = smb2_mkdir_setinfo, | 367 | .mkdir_setinfo = smb2_mkdir_setinfo, |
361 | .rmdir = smb2_rmdir, | 368 | .rmdir = smb2_rmdir, |
362 | .unlink = smb2_unlink, | 369 | .unlink = smb2_unlink, |
363 | .open = smb2_open_file, | 370 | .open = smb2_open_file, |
364 | .set_fid = smb2_set_fid, | 371 | .set_fid = smb2_set_fid, |
365 | .close = smb2_close_file, | 372 | .close = smb2_close_file, |
373 | .flush = smb2_flush_file, | ||
366 | }; | 374 | }; |
367 | 375 | ||
368 | struct smb_version_values smb21_values = { | 376 | struct smb_version_values smb21_values = { |
369 | .version_string = SMB21_VERSION_STRING, | 377 | .version_string = SMB21_VERSION_STRING, |
370 | .header_size = sizeof(struct smb2_hdr), | 378 | .header_size = sizeof(struct smb2_hdr), |
371 | .max_header_size = MAX_SMB2_HDR_SIZE, | 379 | .max_header_size = MAX_SMB2_HDR_SIZE, |
372 | .lock_cmd = SMB2_LOCK, | 380 | .lock_cmd = SMB2_LOCK, |
373 | .cap_unix = 0, | 381 | .cap_unix = 0, |
374 | .cap_nt_find = SMB2_NT_FIND, | 382 | .cap_nt_find = SMB2_NT_FIND, |
375 | .cap_large_files = SMB2_LARGE_FILES, | 383 | .cap_large_files = SMB2_LARGE_FILES, |
376 | }; | 384 | }; |
377 | 385 |
fs/cifs/smb2pdu.c
1 | /* | 1 | /* |
2 | * fs/cifs/smb2pdu.c | 2 | * fs/cifs/smb2pdu.c |
3 | * | 3 | * |
4 | * Copyright (C) International Business Machines Corp., 2009, 2011 | 4 | * Copyright (C) International Business Machines Corp., 2009, 2011 |
5 | * Etersoft, 2012 | 5 | * Etersoft, 2012 |
6 | * Author(s): Steve French (sfrench@us.ibm.com) | 6 | * Author(s): Steve French (sfrench@us.ibm.com) |
7 | * Pavel Shilovsky (pshilovsky@samba.org) 2012 | 7 | * Pavel Shilovsky (pshilovsky@samba.org) 2012 |
8 | * | 8 | * |
9 | * Contains the routines for constructing the SMB2 PDUs themselves | 9 | * Contains the routines for constructing the SMB2 PDUs themselves |
10 | * | 10 | * |
11 | * This library is free software; you can redistribute it and/or modify | 11 | * This library is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU Lesser General Public License as published | 12 | * it under the terms of the GNU Lesser General Public License as published |
13 | * by the Free Software Foundation; either version 2.1 of the License, or | 13 | * by the Free Software Foundation; either version 2.1 of the License, or |
14 | * (at your option) any later version. | 14 | * (at your option) any later version. |
15 | * | 15 | * |
16 | * This library is distributed in the hope that it will be useful, | 16 | * This library is distributed in the hope that it will be useful, |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
19 | * the GNU Lesser General Public License for more details. | 19 | * the GNU Lesser General Public License for more details. |
20 | * | 20 | * |
21 | * You should have received a copy of the GNU Lesser General Public License | 21 | * You should have received a copy of the GNU Lesser General Public License |
22 | * along with this library; if not, write to the Free Software | 22 | * along with this library; if not, write to the Free Software |
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
24 | */ | 24 | */ |
25 | 25 | ||
26 | /* SMB2 PDU handling routines here - except for leftovers (eg session setup) */ | 26 | /* SMB2 PDU handling routines here - except for leftovers (eg session setup) */ |
27 | /* Note that there are handle based routines which must be */ | 27 | /* Note that there are handle based routines which must be */ |
28 | /* treated slightly differently for reconnection purposes since we never */ | 28 | /* treated slightly differently for reconnection purposes since we never */ |
29 | /* want to reuse a stale file handle and only the caller knows the file info */ | 29 | /* want to reuse a stale file handle and only the caller knows the file info */ |
30 | 30 | ||
31 | #include <linux/fs.h> | 31 | #include <linux/fs.h> |
32 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
33 | #include <linux/vfs.h> | 33 | #include <linux/vfs.h> |
34 | #include <linux/uaccess.h> | 34 | #include <linux/uaccess.h> |
35 | #include <linux/xattr.h> | 35 | #include <linux/xattr.h> |
36 | #include "smb2pdu.h" | 36 | #include "smb2pdu.h" |
37 | #include "cifsglob.h" | 37 | #include "cifsglob.h" |
38 | #include "cifsacl.h" | 38 | #include "cifsacl.h" |
39 | #include "cifsproto.h" | 39 | #include "cifsproto.h" |
40 | #include "smb2proto.h" | 40 | #include "smb2proto.h" |
41 | #include "cifs_unicode.h" | 41 | #include "cifs_unicode.h" |
42 | #include "cifs_debug.h" | 42 | #include "cifs_debug.h" |
43 | #include "ntlmssp.h" | 43 | #include "ntlmssp.h" |
44 | #include "smb2status.h" | 44 | #include "smb2status.h" |
45 | 45 | ||
46 | /* | 46 | /* |
47 | * The following table defines the expected "StructureSize" of SMB2 requests | 47 | * The following table defines the expected "StructureSize" of SMB2 requests |
48 | * in order by SMB2 command. This is similar to "wct" in SMB/CIFS requests. | 48 | * in order by SMB2 command. This is similar to "wct" in SMB/CIFS requests. |
49 | * | 49 | * |
50 | * Note that commands are defined in smb2pdu.h in le16 but the array below is | 50 | * Note that commands are defined in smb2pdu.h in le16 but the array below is |
51 | * indexed by command in host byte order. | 51 | * indexed by command in host byte order. |
52 | */ | 52 | */ |
53 | static const int smb2_req_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = { | 53 | static const int smb2_req_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = { |
54 | /* SMB2_NEGOTIATE */ 36, | 54 | /* SMB2_NEGOTIATE */ 36, |
55 | /* SMB2_SESSION_SETUP */ 25, | 55 | /* SMB2_SESSION_SETUP */ 25, |
56 | /* SMB2_LOGOFF */ 4, | 56 | /* SMB2_LOGOFF */ 4, |
57 | /* SMB2_TREE_CONNECT */ 9, | 57 | /* SMB2_TREE_CONNECT */ 9, |
58 | /* SMB2_TREE_DISCONNECT */ 4, | 58 | /* SMB2_TREE_DISCONNECT */ 4, |
59 | /* SMB2_CREATE */ 57, | 59 | /* SMB2_CREATE */ 57, |
60 | /* SMB2_CLOSE */ 24, | 60 | /* SMB2_CLOSE */ 24, |
61 | /* SMB2_FLUSH */ 24, | 61 | /* SMB2_FLUSH */ 24, |
62 | /* SMB2_READ */ 49, | 62 | /* SMB2_READ */ 49, |
63 | /* SMB2_WRITE */ 49, | 63 | /* SMB2_WRITE */ 49, |
64 | /* SMB2_LOCK */ 48, | 64 | /* SMB2_LOCK */ 48, |
65 | /* SMB2_IOCTL */ 57, | 65 | /* SMB2_IOCTL */ 57, |
66 | /* SMB2_CANCEL */ 4, | 66 | /* SMB2_CANCEL */ 4, |
67 | /* SMB2_ECHO */ 4, | 67 | /* SMB2_ECHO */ 4, |
68 | /* SMB2_QUERY_DIRECTORY */ 33, | 68 | /* SMB2_QUERY_DIRECTORY */ 33, |
69 | /* SMB2_CHANGE_NOTIFY */ 32, | 69 | /* SMB2_CHANGE_NOTIFY */ 32, |
70 | /* SMB2_QUERY_INFO */ 41, | 70 | /* SMB2_QUERY_INFO */ 41, |
71 | /* SMB2_SET_INFO */ 33, | 71 | /* SMB2_SET_INFO */ 33, |
72 | /* SMB2_OPLOCK_BREAK */ 24 /* BB this is 36 for LEASE_BREAK variant */ | 72 | /* SMB2_OPLOCK_BREAK */ 24 /* BB this is 36 for LEASE_BREAK variant */ |
73 | }; | 73 | }; |
74 | 74 | ||
75 | 75 | ||
76 | static void | 76 | static void |
77 | smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ , | 77 | smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ , |
78 | const struct cifs_tcon *tcon) | 78 | const struct cifs_tcon *tcon) |
79 | { | 79 | { |
80 | struct smb2_pdu *pdu = (struct smb2_pdu *)hdr; | 80 | struct smb2_pdu *pdu = (struct smb2_pdu *)hdr; |
81 | char *temp = (char *)hdr; | 81 | char *temp = (char *)hdr; |
82 | /* lookup word count ie StructureSize from table */ | 82 | /* lookup word count ie StructureSize from table */ |
83 | __u16 parmsize = smb2_req_struct_sizes[le16_to_cpu(smb2_cmd)]; | 83 | __u16 parmsize = smb2_req_struct_sizes[le16_to_cpu(smb2_cmd)]; |
84 | 84 | ||
85 | /* | 85 | /* |
86 | * smaller than SMALL_BUFFER_SIZE but bigger than fixed area of | 86 | * smaller than SMALL_BUFFER_SIZE but bigger than fixed area of |
87 | * largest operations (Create) | 87 | * largest operations (Create) |
88 | */ | 88 | */ |
89 | memset(temp, 0, 256); | 89 | memset(temp, 0, 256); |
90 | 90 | ||
91 | /* Note this is only network field converted to big endian */ | 91 | /* Note this is only network field converted to big endian */ |
92 | hdr->smb2_buf_length = cpu_to_be32(parmsize + sizeof(struct smb2_hdr) | 92 | hdr->smb2_buf_length = cpu_to_be32(parmsize + sizeof(struct smb2_hdr) |
93 | - 4 /* RFC 1001 length field itself not counted */); | 93 | - 4 /* RFC 1001 length field itself not counted */); |
94 | 94 | ||
95 | hdr->ProtocolId[0] = 0xFE; | 95 | hdr->ProtocolId[0] = 0xFE; |
96 | hdr->ProtocolId[1] = 'S'; | 96 | hdr->ProtocolId[1] = 'S'; |
97 | hdr->ProtocolId[2] = 'M'; | 97 | hdr->ProtocolId[2] = 'M'; |
98 | hdr->ProtocolId[3] = 'B'; | 98 | hdr->ProtocolId[3] = 'B'; |
99 | hdr->StructureSize = cpu_to_le16(64); | 99 | hdr->StructureSize = cpu_to_le16(64); |
100 | hdr->Command = smb2_cmd; | 100 | hdr->Command = smb2_cmd; |
101 | hdr->CreditRequest = cpu_to_le16(2); /* BB make this dynamic */ | 101 | hdr->CreditRequest = cpu_to_le16(2); /* BB make this dynamic */ |
102 | hdr->ProcessId = cpu_to_le32((__u16)current->tgid); | 102 | hdr->ProcessId = cpu_to_le32((__u16)current->tgid); |
103 | 103 | ||
104 | if (!tcon) | 104 | if (!tcon) |
105 | goto out; | 105 | goto out; |
106 | 106 | ||
107 | hdr->TreeId = tcon->tid; | 107 | hdr->TreeId = tcon->tid; |
108 | /* Uid is not converted */ | 108 | /* Uid is not converted */ |
109 | if (tcon->ses) | 109 | if (tcon->ses) |
110 | hdr->SessionId = tcon->ses->Suid; | 110 | hdr->SessionId = tcon->ses->Suid; |
111 | /* BB check following DFS flags BB */ | 111 | /* BB check following DFS flags BB */ |
112 | /* BB do we have to add check for SHI1005_FLAGS_DFS_ROOT too? */ | 112 | /* BB do we have to add check for SHI1005_FLAGS_DFS_ROOT too? */ |
113 | if (tcon->share_flags & SHI1005_FLAGS_DFS) | 113 | if (tcon->share_flags & SHI1005_FLAGS_DFS) |
114 | hdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; | 114 | hdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; |
115 | /* BB how does SMB2 do case sensitive? */ | 115 | /* BB how does SMB2 do case sensitive? */ |
116 | /* if (tcon->nocase) | 116 | /* if (tcon->nocase) |
117 | hdr->Flags |= SMBFLG_CASELESS; */ | 117 | hdr->Flags |= SMBFLG_CASELESS; */ |
118 | /* if (tcon->ses && tcon->ses->server && | 118 | /* if (tcon->ses && tcon->ses->server && |
119 | (tcon->ses->server->sec_mode & SECMODE_SIGN_REQUIRED)) | 119 | (tcon->ses->server->sec_mode & SECMODE_SIGN_REQUIRED)) |
120 | hdr->Flags |= SMB2_FLAGS_SIGNED; */ | 120 | hdr->Flags |= SMB2_FLAGS_SIGNED; */ |
121 | out: | 121 | out: |
122 | pdu->StructureSize2 = cpu_to_le16(parmsize); | 122 | pdu->StructureSize2 = cpu_to_le16(parmsize); |
123 | return; | 123 | return; |
124 | } | 124 | } |
125 | 125 | ||
126 | static int | 126 | static int |
127 | smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) | 127 | smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) |
128 | { | 128 | { |
129 | int rc = 0; | 129 | int rc = 0; |
130 | struct nls_table *nls_codepage; | 130 | struct nls_table *nls_codepage; |
131 | struct cifs_ses *ses; | 131 | struct cifs_ses *ses; |
132 | struct TCP_Server_Info *server; | 132 | struct TCP_Server_Info *server; |
133 | 133 | ||
134 | /* | 134 | /* |
135 | * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so | 135 | * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so |
136 | * check for tcp and smb session status done differently | 136 | * check for tcp and smb session status done differently |
137 | * for those three - in the calling routine. | 137 | * for those three - in the calling routine. |
138 | */ | 138 | */ |
139 | if (tcon == NULL) | 139 | if (tcon == NULL) |
140 | return rc; | 140 | return rc; |
141 | 141 | ||
142 | if (smb2_command == SMB2_TREE_CONNECT) | 142 | if (smb2_command == SMB2_TREE_CONNECT) |
143 | return rc; | 143 | return rc; |
144 | 144 | ||
145 | if (tcon->tidStatus == CifsExiting) { | 145 | if (tcon->tidStatus == CifsExiting) { |
146 | /* | 146 | /* |
147 | * only tree disconnect, open, and write, | 147 | * only tree disconnect, open, and write, |
148 | * (and ulogoff which does not have tcon) | 148 | * (and ulogoff which does not have tcon) |
149 | * are allowed as we start force umount. | 149 | * are allowed as we start force umount. |
150 | */ | 150 | */ |
151 | if ((smb2_command != SMB2_WRITE) && | 151 | if ((smb2_command != SMB2_WRITE) && |
152 | (smb2_command != SMB2_CREATE) && | 152 | (smb2_command != SMB2_CREATE) && |
153 | (smb2_command != SMB2_TREE_DISCONNECT)) { | 153 | (smb2_command != SMB2_TREE_DISCONNECT)) { |
154 | cFYI(1, "can not send cmd %d while umounting", | 154 | cFYI(1, "can not send cmd %d while umounting", |
155 | smb2_command); | 155 | smb2_command); |
156 | return -ENODEV; | 156 | return -ENODEV; |
157 | } | 157 | } |
158 | } | 158 | } |
159 | if ((!tcon->ses) || (tcon->ses->status == CifsExiting) || | 159 | if ((!tcon->ses) || (tcon->ses->status == CifsExiting) || |
160 | (!tcon->ses->server)) | 160 | (!tcon->ses->server)) |
161 | return -EIO; | 161 | return -EIO; |
162 | 162 | ||
163 | ses = tcon->ses; | 163 | ses = tcon->ses; |
164 | server = ses->server; | 164 | server = ses->server; |
165 | 165 | ||
166 | /* | 166 | /* |
167 | * Give demultiplex thread up to 10 seconds to reconnect, should be | 167 | * Give demultiplex thread up to 10 seconds to reconnect, should be |
168 | * greater than cifs socket timeout which is 7 seconds | 168 | * greater than cifs socket timeout which is 7 seconds |
169 | */ | 169 | */ |
170 | while (server->tcpStatus == CifsNeedReconnect) { | 170 | while (server->tcpStatus == CifsNeedReconnect) { |
171 | /* | 171 | /* |
172 | * Return to caller for TREE_DISCONNECT and LOGOFF and CLOSE | 172 | * Return to caller for TREE_DISCONNECT and LOGOFF and CLOSE |
173 | * here since they are implicitly done when session drops. | 173 | * here since they are implicitly done when session drops. |
174 | */ | 174 | */ |
175 | switch (smb2_command) { | 175 | switch (smb2_command) { |
176 | /* | 176 | /* |
177 | * BB Should we keep oplock break and add flush to exceptions? | 177 | * BB Should we keep oplock break and add flush to exceptions? |
178 | */ | 178 | */ |
179 | case SMB2_TREE_DISCONNECT: | 179 | case SMB2_TREE_DISCONNECT: |
180 | case SMB2_CANCEL: | 180 | case SMB2_CANCEL: |
181 | case SMB2_CLOSE: | 181 | case SMB2_CLOSE: |
182 | case SMB2_OPLOCK_BREAK: | 182 | case SMB2_OPLOCK_BREAK: |
183 | return -EAGAIN; | 183 | return -EAGAIN; |
184 | } | 184 | } |
185 | 185 | ||
186 | wait_event_interruptible_timeout(server->response_q, | 186 | wait_event_interruptible_timeout(server->response_q, |
187 | (server->tcpStatus != CifsNeedReconnect), 10 * HZ); | 187 | (server->tcpStatus != CifsNeedReconnect), 10 * HZ); |
188 | 188 | ||
189 | /* are we still trying to reconnect? */ | 189 | /* are we still trying to reconnect? */ |
190 | if (server->tcpStatus != CifsNeedReconnect) | 190 | if (server->tcpStatus != CifsNeedReconnect) |
191 | break; | 191 | break; |
192 | 192 | ||
193 | /* | 193 | /* |
194 | * on "soft" mounts we wait once. Hard mounts keep | 194 | * on "soft" mounts we wait once. Hard mounts keep |
195 | * retrying until process is killed or server comes | 195 | * retrying until process is killed or server comes |
196 | * back on-line | 196 | * back on-line |
197 | */ | 197 | */ |
198 | if (!tcon->retry) { | 198 | if (!tcon->retry) { |
199 | cFYI(1, "gave up waiting on reconnect in smb_init"); | 199 | cFYI(1, "gave up waiting on reconnect in smb_init"); |
200 | return -EHOSTDOWN; | 200 | return -EHOSTDOWN; |
201 | } | 201 | } |
202 | } | 202 | } |
203 | 203 | ||
204 | if (!tcon->ses->need_reconnect && !tcon->need_reconnect) | 204 | if (!tcon->ses->need_reconnect && !tcon->need_reconnect) |
205 | return rc; | 205 | return rc; |
206 | 206 | ||
207 | nls_codepage = load_nls_default(); | 207 | nls_codepage = load_nls_default(); |
208 | 208 | ||
209 | /* | 209 | /* |
210 | * need to prevent multiple threads trying to simultaneously reconnect | 210 | * need to prevent multiple threads trying to simultaneously reconnect |
211 | * the same SMB session | 211 | * the same SMB session |
212 | */ | 212 | */ |
213 | mutex_lock(&tcon->ses->session_mutex); | 213 | mutex_lock(&tcon->ses->session_mutex); |
214 | rc = cifs_negotiate_protocol(0, tcon->ses); | 214 | rc = cifs_negotiate_protocol(0, tcon->ses); |
215 | if (!rc && tcon->ses->need_reconnect) | 215 | if (!rc && tcon->ses->need_reconnect) |
216 | rc = cifs_setup_session(0, tcon->ses, nls_codepage); | 216 | rc = cifs_setup_session(0, tcon->ses, nls_codepage); |
217 | 217 | ||
218 | if (rc || !tcon->need_reconnect) { | 218 | if (rc || !tcon->need_reconnect) { |
219 | mutex_unlock(&tcon->ses->session_mutex); | 219 | mutex_unlock(&tcon->ses->session_mutex); |
220 | goto out; | 220 | goto out; |
221 | } | 221 | } |
222 | 222 | ||
223 | cifs_mark_open_files_invalid(tcon); | 223 | cifs_mark_open_files_invalid(tcon); |
224 | rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage); | 224 | rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage); |
225 | mutex_unlock(&tcon->ses->session_mutex); | 225 | mutex_unlock(&tcon->ses->session_mutex); |
226 | cFYI(1, "reconnect tcon rc = %d", rc); | 226 | cFYI(1, "reconnect tcon rc = %d", rc); |
227 | if (rc) | 227 | if (rc) |
228 | goto out; | 228 | goto out; |
229 | atomic_inc(&tconInfoReconnectCount); | 229 | atomic_inc(&tconInfoReconnectCount); |
230 | /* | 230 | /* |
231 | * BB FIXME add code to check if wsize needs update due to negotiated | 231 | * BB FIXME add code to check if wsize needs update due to negotiated |
232 | * smb buffer size shrinking. | 232 | * smb buffer size shrinking. |
233 | */ | 233 | */ |
234 | out: | 234 | out: |
235 | /* | 235 | /* |
236 | * Check if handle based operation so we know whether we can continue | 236 | * Check if handle based operation so we know whether we can continue |
237 | * or not without returning to caller to reset file handle. | 237 | * or not without returning to caller to reset file handle. |
238 | */ | 238 | */ |
239 | /* | 239 | /* |
240 | * BB Is flush done by server on drop of tcp session? Should we special | 240 | * BB Is flush done by server on drop of tcp session? Should we special |
241 | * case it and skip above? | 241 | * case it and skip above? |
242 | */ | 242 | */ |
243 | switch (smb2_command) { | 243 | switch (smb2_command) { |
244 | case SMB2_FLUSH: | 244 | case SMB2_FLUSH: |
245 | case SMB2_READ: | 245 | case SMB2_READ: |
246 | case SMB2_WRITE: | 246 | case SMB2_WRITE: |
247 | case SMB2_LOCK: | 247 | case SMB2_LOCK: |
248 | case SMB2_IOCTL: | 248 | case SMB2_IOCTL: |
249 | case SMB2_QUERY_DIRECTORY: | 249 | case SMB2_QUERY_DIRECTORY: |
250 | case SMB2_CHANGE_NOTIFY: | 250 | case SMB2_CHANGE_NOTIFY: |
251 | case SMB2_QUERY_INFO: | 251 | case SMB2_QUERY_INFO: |
252 | case SMB2_SET_INFO: | 252 | case SMB2_SET_INFO: |
253 | return -EAGAIN; | 253 | return -EAGAIN; |
254 | } | 254 | } |
255 | unload_nls(nls_codepage); | 255 | unload_nls(nls_codepage); |
256 | return rc; | 256 | return rc; |
257 | } | 257 | } |
258 | 258 | ||
259 | /* | 259 | /* |
260 | * Allocate and return pointer to an SMB request hdr, and set basic | 260 | * Allocate and return pointer to an SMB request hdr, and set basic |
261 | * SMB information in the SMB header. If the return code is zero, this | 261 | * SMB information in the SMB header. If the return code is zero, this |
262 | * function must have filled in request_buf pointer. | 262 | * function must have filled in request_buf pointer. |
263 | */ | 263 | */ |
264 | static int | 264 | static int |
265 | small_smb2_init(__le16 smb2_command, struct cifs_tcon *tcon, | 265 | small_smb2_init(__le16 smb2_command, struct cifs_tcon *tcon, |
266 | void **request_buf) | 266 | void **request_buf) |
267 | { | 267 | { |
268 | int rc = 0; | 268 | int rc = 0; |
269 | 269 | ||
270 | rc = smb2_reconnect(smb2_command, tcon); | 270 | rc = smb2_reconnect(smb2_command, tcon); |
271 | if (rc) | 271 | if (rc) |
272 | return rc; | 272 | return rc; |
273 | 273 | ||
274 | /* BB eventually switch this to SMB2 specific small buf size */ | 274 | /* BB eventually switch this to SMB2 specific small buf size */ |
275 | *request_buf = cifs_small_buf_get(); | 275 | *request_buf = cifs_small_buf_get(); |
276 | if (*request_buf == NULL) { | 276 | if (*request_buf == NULL) { |
277 | /* BB should we add a retry in here if not a writepage? */ | 277 | /* BB should we add a retry in here if not a writepage? */ |
278 | return -ENOMEM; | 278 | return -ENOMEM; |
279 | } | 279 | } |
280 | 280 | ||
281 | smb2_hdr_assemble((struct smb2_hdr *) *request_buf, smb2_command, tcon); | 281 | smb2_hdr_assemble((struct smb2_hdr *) *request_buf, smb2_command, tcon); |
282 | 282 | ||
283 | if (tcon != NULL) { | 283 | if (tcon != NULL) { |
284 | #ifdef CONFIG_CIFS_STATS2 | 284 | #ifdef CONFIG_CIFS_STATS2 |
285 | uint16_t com_code = le16_to_cpu(smb2_command); | 285 | uint16_t com_code = le16_to_cpu(smb2_command); |
286 | cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_sent[com_code]); | 286 | cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_sent[com_code]); |
287 | #endif | 287 | #endif |
288 | cifs_stats_inc(&tcon->num_smbs_sent); | 288 | cifs_stats_inc(&tcon->num_smbs_sent); |
289 | } | 289 | } |
290 | 290 | ||
291 | return rc; | 291 | return rc; |
292 | } | 292 | } |
293 | 293 | ||
294 | static void | 294 | static void |
295 | free_rsp_buf(int resp_buftype, void *rsp) | 295 | free_rsp_buf(int resp_buftype, void *rsp) |
296 | { | 296 | { |
297 | if (resp_buftype == CIFS_SMALL_BUFFER) | 297 | if (resp_buftype == CIFS_SMALL_BUFFER) |
298 | cifs_small_buf_release(rsp); | 298 | cifs_small_buf_release(rsp); |
299 | else if (resp_buftype == CIFS_LARGE_BUFFER) | 299 | else if (resp_buftype == CIFS_LARGE_BUFFER) |
300 | cifs_buf_release(rsp); | 300 | cifs_buf_release(rsp); |
301 | } | 301 | } |
302 | 302 | ||
303 | #define SMB2_NUM_PROT 1 | 303 | #define SMB2_NUM_PROT 1 |
304 | 304 | ||
305 | #define SMB2_PROT 0 | 305 | #define SMB2_PROT 0 |
306 | #define SMB21_PROT 1 | 306 | #define SMB21_PROT 1 |
307 | #define BAD_PROT 0xFFFF | 307 | #define BAD_PROT 0xFFFF |
308 | 308 | ||
309 | #define SMB2_PROT_ID 0x0202 | 309 | #define SMB2_PROT_ID 0x0202 |
310 | #define SMB21_PROT_ID 0x0210 | 310 | #define SMB21_PROT_ID 0x0210 |
311 | #define BAD_PROT_ID 0xFFFF | 311 | #define BAD_PROT_ID 0xFFFF |
312 | 312 | ||
313 | static struct { | 313 | static struct { |
314 | int index; | 314 | int index; |
315 | __le16 name; | 315 | __le16 name; |
316 | } smb2protocols[] = { | 316 | } smb2protocols[] = { |
317 | {SMB2_PROT, cpu_to_le16(SMB2_PROT_ID)}, | 317 | {SMB2_PROT, cpu_to_le16(SMB2_PROT_ID)}, |
318 | {SMB21_PROT, cpu_to_le16(SMB21_PROT_ID)}, | 318 | {SMB21_PROT, cpu_to_le16(SMB21_PROT_ID)}, |
319 | {BAD_PROT, cpu_to_le16(BAD_PROT_ID)} | 319 | {BAD_PROT, cpu_to_le16(BAD_PROT_ID)} |
320 | }; | 320 | }; |
321 | 321 | ||
322 | /* | 322 | /* |
323 | * | 323 | * |
324 | * SMB2 Worker functions follow: | 324 | * SMB2 Worker functions follow: |
325 | * | 325 | * |
326 | * The general structure of the worker functions is: | 326 | * The general structure of the worker functions is: |
327 | * 1) Call smb2_init (assembles SMB2 header) | 327 | * 1) Call smb2_init (assembles SMB2 header) |
328 | * 2) Initialize SMB2 command specific fields in fixed length area of SMB | 328 | * 2) Initialize SMB2 command specific fields in fixed length area of SMB |
329 | * 3) Call smb_sendrcv2 (sends request on socket and waits for response) | 329 | * 3) Call smb_sendrcv2 (sends request on socket and waits for response) |
330 | * 4) Decode SMB2 command specific fields in the fixed length area | 330 | * 4) Decode SMB2 command specific fields in the fixed length area |
331 | * 5) Decode variable length data area (if any for this SMB2 command type) | 331 | * 5) Decode variable length data area (if any for this SMB2 command type) |
332 | * 6) Call free smb buffer | 332 | * 6) Call free smb buffer |
333 | * 7) return | 333 | * 7) return |
334 | * | 334 | * |
335 | */ | 335 | */ |
336 | 336 | ||
337 | int | 337 | int |
338 | SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) | 338 | SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) |
339 | { | 339 | { |
340 | struct smb2_negotiate_req *req; | 340 | struct smb2_negotiate_req *req; |
341 | struct smb2_negotiate_rsp *rsp; | 341 | struct smb2_negotiate_rsp *rsp; |
342 | struct kvec iov[1]; | 342 | struct kvec iov[1]; |
343 | int rc = 0; | 343 | int rc = 0; |
344 | int resp_buftype; | 344 | int resp_buftype; |
345 | struct TCP_Server_Info *server; | 345 | struct TCP_Server_Info *server; |
346 | unsigned int sec_flags; | 346 | unsigned int sec_flags; |
347 | u16 i; | 347 | u16 i; |
348 | u16 temp = 0; | 348 | u16 temp = 0; |
349 | int blob_offset, blob_length; | 349 | int blob_offset, blob_length; |
350 | char *security_blob; | 350 | char *security_blob; |
351 | int flags = CIFS_NEG_OP; | 351 | int flags = CIFS_NEG_OP; |
352 | 352 | ||
353 | cFYI(1, "Negotiate protocol"); | 353 | cFYI(1, "Negotiate protocol"); |
354 | 354 | ||
355 | if (ses->server) | 355 | if (ses->server) |
356 | server = ses->server; | 356 | server = ses->server; |
357 | else { | 357 | else { |
358 | rc = -EIO; | 358 | rc = -EIO; |
359 | return rc; | 359 | return rc; |
360 | } | 360 | } |
361 | 361 | ||
362 | rc = small_smb2_init(SMB2_NEGOTIATE, NULL, (void **) &req); | 362 | rc = small_smb2_init(SMB2_NEGOTIATE, NULL, (void **) &req); |
363 | if (rc) | 363 | if (rc) |
364 | return rc; | 364 | return rc; |
365 | 365 | ||
366 | /* if any of auth flags (ie not sign or seal) are overriden use them */ | 366 | /* if any of auth flags (ie not sign or seal) are overriden use them */ |
367 | if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL))) | 367 | if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL))) |
368 | sec_flags = ses->overrideSecFlg; /* BB FIXME fix sign flags?*/ | 368 | sec_flags = ses->overrideSecFlg; /* BB FIXME fix sign flags?*/ |
369 | else /* if override flags set only sign/seal OR them with global auth */ | 369 | else /* if override flags set only sign/seal OR them with global auth */ |
370 | sec_flags = global_secflags | ses->overrideSecFlg; | 370 | sec_flags = global_secflags | ses->overrideSecFlg; |
371 | 371 | ||
372 | cFYI(1, "sec_flags 0x%x", sec_flags); | 372 | cFYI(1, "sec_flags 0x%x", sec_flags); |
373 | 373 | ||
374 | req->hdr.SessionId = 0; | 374 | req->hdr.SessionId = 0; |
375 | 375 | ||
376 | for (i = 0; i < SMB2_NUM_PROT; i++) | 376 | for (i = 0; i < SMB2_NUM_PROT; i++) |
377 | req->Dialects[i] = smb2protocols[i].name; | 377 | req->Dialects[i] = smb2protocols[i].name; |
378 | 378 | ||
379 | req->DialectCount = cpu_to_le16(i); | 379 | req->DialectCount = cpu_to_le16(i); |
380 | inc_rfc1001_len(req, i * 2); | 380 | inc_rfc1001_len(req, i * 2); |
381 | 381 | ||
382 | /* only one of SMB2 signing flags may be set in SMB2 request */ | 382 | /* only one of SMB2 signing flags may be set in SMB2 request */ |
383 | if ((sec_flags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) | 383 | if ((sec_flags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) |
384 | temp = SMB2_NEGOTIATE_SIGNING_REQUIRED; | 384 | temp = SMB2_NEGOTIATE_SIGNING_REQUIRED; |
385 | else if (sec_flags & CIFSSEC_MAY_SIGN) /* MAY_SIGN is a single flag */ | 385 | else if (sec_flags & CIFSSEC_MAY_SIGN) /* MAY_SIGN is a single flag */ |
386 | temp = SMB2_NEGOTIATE_SIGNING_ENABLED; | 386 | temp = SMB2_NEGOTIATE_SIGNING_ENABLED; |
387 | 387 | ||
388 | req->SecurityMode = cpu_to_le16(temp); | 388 | req->SecurityMode = cpu_to_le16(temp); |
389 | 389 | ||
390 | req->Capabilities = cpu_to_le32(SMB2_GLOBAL_CAP_DFS); | 390 | req->Capabilities = cpu_to_le32(SMB2_GLOBAL_CAP_DFS); |
391 | 391 | ||
392 | iov[0].iov_base = (char *)req; | 392 | iov[0].iov_base = (char *)req; |
393 | /* 4 for rfc1002 length field */ | 393 | /* 4 for rfc1002 length field */ |
394 | iov[0].iov_len = get_rfc1002_length(req) + 4; | 394 | iov[0].iov_len = get_rfc1002_length(req) + 4; |
395 | 395 | ||
396 | rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, flags); | 396 | rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, flags); |
397 | 397 | ||
398 | rsp = (struct smb2_negotiate_rsp *)iov[0].iov_base; | 398 | rsp = (struct smb2_negotiate_rsp *)iov[0].iov_base; |
399 | /* | 399 | /* |
400 | * No tcon so can't do | 400 | * No tcon so can't do |
401 | * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]); | 401 | * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]); |
402 | */ | 402 | */ |
403 | if (rc != 0) | 403 | if (rc != 0) |
404 | goto neg_exit; | 404 | goto neg_exit; |
405 | 405 | ||
406 | if (rsp == NULL) { | 406 | if (rsp == NULL) { |
407 | rc = -EIO; | 407 | rc = -EIO; |
408 | goto neg_exit; | 408 | goto neg_exit; |
409 | } | 409 | } |
410 | 410 | ||
411 | cFYI(1, "mode 0x%x", rsp->SecurityMode); | 411 | cFYI(1, "mode 0x%x", rsp->SecurityMode); |
412 | 412 | ||
413 | if (rsp->DialectRevision == smb2protocols[SMB21_PROT].name) | 413 | if (rsp->DialectRevision == smb2protocols[SMB21_PROT].name) |
414 | cFYI(1, "negotiated smb2.1 dialect"); | 414 | cFYI(1, "negotiated smb2.1 dialect"); |
415 | else if (rsp->DialectRevision == smb2protocols[SMB2_PROT].name) | 415 | else if (rsp->DialectRevision == smb2protocols[SMB2_PROT].name) |
416 | cFYI(1, "negotiated smb2 dialect"); | 416 | cFYI(1, "negotiated smb2 dialect"); |
417 | else { | 417 | else { |
418 | cERROR(1, "Illegal dialect returned by server %d", | 418 | cERROR(1, "Illegal dialect returned by server %d", |
419 | le16_to_cpu(rsp->DialectRevision)); | 419 | le16_to_cpu(rsp->DialectRevision)); |
420 | rc = -EIO; | 420 | rc = -EIO; |
421 | goto neg_exit; | 421 | goto neg_exit; |
422 | } | 422 | } |
423 | server->dialect = le16_to_cpu(rsp->DialectRevision); | 423 | server->dialect = le16_to_cpu(rsp->DialectRevision); |
424 | 424 | ||
425 | server->maxBuf = le32_to_cpu(rsp->MaxTransactSize); | 425 | server->maxBuf = le32_to_cpu(rsp->MaxTransactSize); |
426 | server->max_read = le32_to_cpu(rsp->MaxReadSize); | 426 | server->max_read = le32_to_cpu(rsp->MaxReadSize); |
427 | server->max_write = le32_to_cpu(rsp->MaxWriteSize); | 427 | server->max_write = le32_to_cpu(rsp->MaxWriteSize); |
428 | /* BB Do we need to validate the SecurityMode? */ | 428 | /* BB Do we need to validate the SecurityMode? */ |
429 | server->sec_mode = le16_to_cpu(rsp->SecurityMode); | 429 | server->sec_mode = le16_to_cpu(rsp->SecurityMode); |
430 | server->capabilities = le32_to_cpu(rsp->Capabilities); | 430 | server->capabilities = le32_to_cpu(rsp->Capabilities); |
431 | /* Internal types */ | 431 | /* Internal types */ |
432 | server->capabilities |= SMB2_NT_FIND | SMB2_LARGE_FILES; | 432 | server->capabilities |= SMB2_NT_FIND | SMB2_LARGE_FILES; |
433 | 433 | ||
434 | security_blob = smb2_get_data_area_len(&blob_offset, &blob_length, | 434 | security_blob = smb2_get_data_area_len(&blob_offset, &blob_length, |
435 | &rsp->hdr); | 435 | &rsp->hdr); |
436 | if (blob_length == 0) { | 436 | if (blob_length == 0) { |
437 | cERROR(1, "missing security blob on negprot"); | 437 | cERROR(1, "missing security blob on negprot"); |
438 | rc = -EIO; | 438 | rc = -EIO; |
439 | goto neg_exit; | 439 | goto neg_exit; |
440 | } | 440 | } |
441 | #ifdef CONFIG_SMB2_ASN1 /* BB REMOVEME when updated asn1.c ready */ | 441 | #ifdef CONFIG_SMB2_ASN1 /* BB REMOVEME when updated asn1.c ready */ |
442 | rc = decode_neg_token_init(security_blob, blob_length, | 442 | rc = decode_neg_token_init(security_blob, blob_length, |
443 | &server->sec_type); | 443 | &server->sec_type); |
444 | if (rc == 1) | 444 | if (rc == 1) |
445 | rc = 0; | 445 | rc = 0; |
446 | else if (rc == 0) { | 446 | else if (rc == 0) { |
447 | rc = -EIO; | 447 | rc = -EIO; |
448 | goto neg_exit; | 448 | goto neg_exit; |
449 | } | 449 | } |
450 | #endif | 450 | #endif |
451 | 451 | ||
452 | neg_exit: | 452 | neg_exit: |
453 | free_rsp_buf(resp_buftype, rsp); | 453 | free_rsp_buf(resp_buftype, rsp); |
454 | return rc; | 454 | return rc; |
455 | } | 455 | } |
456 | 456 | ||
457 | int | 457 | int |
458 | SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, | 458 | SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, |
459 | const struct nls_table *nls_cp) | 459 | const struct nls_table *nls_cp) |
460 | { | 460 | { |
461 | struct smb2_sess_setup_req *req; | 461 | struct smb2_sess_setup_req *req; |
462 | struct smb2_sess_setup_rsp *rsp = NULL; | 462 | struct smb2_sess_setup_rsp *rsp = NULL; |
463 | struct kvec iov[2]; | 463 | struct kvec iov[2]; |
464 | int rc = 0; | 464 | int rc = 0; |
465 | int resp_buftype; | 465 | int resp_buftype; |
466 | __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ | 466 | __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ |
467 | struct TCP_Server_Info *server; | 467 | struct TCP_Server_Info *server; |
468 | unsigned int sec_flags; | 468 | unsigned int sec_flags; |
469 | u8 temp = 0; | 469 | u8 temp = 0; |
470 | u16 blob_length = 0; | 470 | u16 blob_length = 0; |
471 | char *security_blob; | 471 | char *security_blob; |
472 | char *ntlmssp_blob = NULL; | 472 | char *ntlmssp_blob = NULL; |
473 | bool use_spnego = false; /* else use raw ntlmssp */ | 473 | bool use_spnego = false; /* else use raw ntlmssp */ |
474 | 474 | ||
475 | cFYI(1, "Session Setup"); | 475 | cFYI(1, "Session Setup"); |
476 | 476 | ||
477 | if (ses->server) | 477 | if (ses->server) |
478 | server = ses->server; | 478 | server = ses->server; |
479 | else { | 479 | else { |
480 | rc = -EIO; | 480 | rc = -EIO; |
481 | return rc; | 481 | return rc; |
482 | } | 482 | } |
483 | 483 | ||
484 | /* | 484 | /* |
485 | * If memory allocation is successful, caller of this function | 485 | * If memory allocation is successful, caller of this function |
486 | * frees it. | 486 | * frees it. |
487 | */ | 487 | */ |
488 | ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL); | 488 | ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL); |
489 | if (!ses->ntlmssp) | 489 | if (!ses->ntlmssp) |
490 | return -ENOMEM; | 490 | return -ENOMEM; |
491 | 491 | ||
492 | ses->server->secType = RawNTLMSSP; | 492 | ses->server->secType = RawNTLMSSP; |
493 | 493 | ||
494 | ssetup_ntlmssp_authenticate: | 494 | ssetup_ntlmssp_authenticate: |
495 | if (phase == NtLmChallenge) | 495 | if (phase == NtLmChallenge) |
496 | phase = NtLmAuthenticate; /* if ntlmssp, now final phase */ | 496 | phase = NtLmAuthenticate; /* if ntlmssp, now final phase */ |
497 | 497 | ||
498 | rc = small_smb2_init(SMB2_SESSION_SETUP, NULL, (void **) &req); | 498 | rc = small_smb2_init(SMB2_SESSION_SETUP, NULL, (void **) &req); |
499 | if (rc) | 499 | if (rc) |
500 | return rc; | 500 | return rc; |
501 | 501 | ||
502 | /* if any of auth flags (ie not sign or seal) are overriden use them */ | 502 | /* if any of auth flags (ie not sign or seal) are overriden use them */ |
503 | if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL))) | 503 | if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL))) |
504 | sec_flags = ses->overrideSecFlg; /* BB FIXME fix sign flags?*/ | 504 | sec_flags = ses->overrideSecFlg; /* BB FIXME fix sign flags?*/ |
505 | else /* if override flags set only sign/seal OR them with global auth */ | 505 | else /* if override flags set only sign/seal OR them with global auth */ |
506 | sec_flags = global_secflags | ses->overrideSecFlg; | 506 | sec_flags = global_secflags | ses->overrideSecFlg; |
507 | 507 | ||
508 | cFYI(1, "sec_flags 0x%x", sec_flags); | 508 | cFYI(1, "sec_flags 0x%x", sec_flags); |
509 | 509 | ||
510 | req->hdr.SessionId = 0; /* First session, not a reauthenticate */ | 510 | req->hdr.SessionId = 0; /* First session, not a reauthenticate */ |
511 | req->VcNumber = 0; /* MBZ */ | 511 | req->VcNumber = 0; /* MBZ */ |
512 | /* to enable echos and oplocks */ | 512 | /* to enable echos and oplocks */ |
513 | req->hdr.CreditRequest = cpu_to_le16(3); | 513 | req->hdr.CreditRequest = cpu_to_le16(3); |
514 | 514 | ||
515 | /* only one of SMB2 signing flags may be set in SMB2 request */ | 515 | /* only one of SMB2 signing flags may be set in SMB2 request */ |
516 | if ((sec_flags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) | 516 | if ((sec_flags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) |
517 | temp = SMB2_NEGOTIATE_SIGNING_REQUIRED; | 517 | temp = SMB2_NEGOTIATE_SIGNING_REQUIRED; |
518 | else if (ses->server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) | 518 | else if (ses->server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) |
519 | temp = SMB2_NEGOTIATE_SIGNING_REQUIRED; | 519 | temp = SMB2_NEGOTIATE_SIGNING_REQUIRED; |
520 | else if (sec_flags & CIFSSEC_MAY_SIGN) /* MAY_SIGN is a single flag */ | 520 | else if (sec_flags & CIFSSEC_MAY_SIGN) /* MAY_SIGN is a single flag */ |
521 | temp = SMB2_NEGOTIATE_SIGNING_ENABLED; | 521 | temp = SMB2_NEGOTIATE_SIGNING_ENABLED; |
522 | 522 | ||
523 | req->SecurityMode = temp; | 523 | req->SecurityMode = temp; |
524 | req->Capabilities = 0; | 524 | req->Capabilities = 0; |
525 | req->Channel = 0; /* MBZ */ | 525 | req->Channel = 0; /* MBZ */ |
526 | 526 | ||
527 | iov[0].iov_base = (char *)req; | 527 | iov[0].iov_base = (char *)req; |
528 | /* 4 for rfc1002 length field and 1 for pad */ | 528 | /* 4 for rfc1002 length field and 1 for pad */ |
529 | iov[0].iov_len = get_rfc1002_length(req) + 4 - 1; | 529 | iov[0].iov_len = get_rfc1002_length(req) + 4 - 1; |
530 | if (phase == NtLmNegotiate) { | 530 | if (phase == NtLmNegotiate) { |
531 | ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE), | 531 | ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE), |
532 | GFP_KERNEL); | 532 | GFP_KERNEL); |
533 | if (ntlmssp_blob == NULL) { | 533 | if (ntlmssp_blob == NULL) { |
534 | rc = -ENOMEM; | 534 | rc = -ENOMEM; |
535 | goto ssetup_exit; | 535 | goto ssetup_exit; |
536 | } | 536 | } |
537 | build_ntlmssp_negotiate_blob(ntlmssp_blob, ses); | 537 | build_ntlmssp_negotiate_blob(ntlmssp_blob, ses); |
538 | if (use_spnego) { | 538 | if (use_spnego) { |
539 | /* blob_length = build_spnego_ntlmssp_blob( | 539 | /* blob_length = build_spnego_ntlmssp_blob( |
540 | &security_blob, | 540 | &security_blob, |
541 | sizeof(struct _NEGOTIATE_MESSAGE), | 541 | sizeof(struct _NEGOTIATE_MESSAGE), |
542 | ntlmssp_blob); */ | 542 | ntlmssp_blob); */ |
543 | /* BB eventually need to add this */ | 543 | /* BB eventually need to add this */ |
544 | cERROR(1, "spnego not supported for SMB2 yet"); | 544 | cERROR(1, "spnego not supported for SMB2 yet"); |
545 | rc = -EOPNOTSUPP; | 545 | rc = -EOPNOTSUPP; |
546 | kfree(ntlmssp_blob); | 546 | kfree(ntlmssp_blob); |
547 | goto ssetup_exit; | 547 | goto ssetup_exit; |
548 | } else { | 548 | } else { |
549 | blob_length = sizeof(struct _NEGOTIATE_MESSAGE); | 549 | blob_length = sizeof(struct _NEGOTIATE_MESSAGE); |
550 | /* with raw NTLMSSP we don't encapsulate in SPNEGO */ | 550 | /* with raw NTLMSSP we don't encapsulate in SPNEGO */ |
551 | security_blob = ntlmssp_blob; | 551 | security_blob = ntlmssp_blob; |
552 | } | 552 | } |
553 | } else if (phase == NtLmAuthenticate) { | 553 | } else if (phase == NtLmAuthenticate) { |
554 | req->hdr.SessionId = ses->Suid; | 554 | req->hdr.SessionId = ses->Suid; |
555 | ntlmssp_blob = kzalloc(sizeof(struct _NEGOTIATE_MESSAGE) + 500, | 555 | ntlmssp_blob = kzalloc(sizeof(struct _NEGOTIATE_MESSAGE) + 500, |
556 | GFP_KERNEL); | 556 | GFP_KERNEL); |
557 | if (ntlmssp_blob == NULL) { | 557 | if (ntlmssp_blob == NULL) { |
558 | cERROR(1, "failed to malloc ntlmssp blob"); | 558 | cERROR(1, "failed to malloc ntlmssp blob"); |
559 | rc = -ENOMEM; | 559 | rc = -ENOMEM; |
560 | goto ssetup_exit; | 560 | goto ssetup_exit; |
561 | } | 561 | } |
562 | rc = build_ntlmssp_auth_blob(ntlmssp_blob, &blob_length, ses, | 562 | rc = build_ntlmssp_auth_blob(ntlmssp_blob, &blob_length, ses, |
563 | nls_cp); | 563 | nls_cp); |
564 | if (rc) { | 564 | if (rc) { |
565 | cFYI(1, "build_ntlmssp_auth_blob failed %d", rc); | 565 | cFYI(1, "build_ntlmssp_auth_blob failed %d", rc); |
566 | goto ssetup_exit; /* BB double check error handling */ | 566 | goto ssetup_exit; /* BB double check error handling */ |
567 | } | 567 | } |
568 | if (use_spnego) { | 568 | if (use_spnego) { |
569 | /* blob_length = build_spnego_ntlmssp_blob( | 569 | /* blob_length = build_spnego_ntlmssp_blob( |
570 | &security_blob, | 570 | &security_blob, |
571 | blob_length, | 571 | blob_length, |
572 | ntlmssp_blob); */ | 572 | ntlmssp_blob); */ |
573 | cERROR(1, "spnego not supported for SMB2 yet"); | 573 | cERROR(1, "spnego not supported for SMB2 yet"); |
574 | rc = -EOPNOTSUPP; | 574 | rc = -EOPNOTSUPP; |
575 | kfree(ntlmssp_blob); | 575 | kfree(ntlmssp_blob); |
576 | goto ssetup_exit; | 576 | goto ssetup_exit; |
577 | } else { | 577 | } else { |
578 | security_blob = ntlmssp_blob; | 578 | security_blob = ntlmssp_blob; |
579 | } | 579 | } |
580 | } else { | 580 | } else { |
581 | cERROR(1, "illegal ntlmssp phase"); | 581 | cERROR(1, "illegal ntlmssp phase"); |
582 | rc = -EIO; | 582 | rc = -EIO; |
583 | goto ssetup_exit; | 583 | goto ssetup_exit; |
584 | } | 584 | } |
585 | 585 | ||
586 | /* Testing shows that buffer offset must be at location of Buffer[0] */ | 586 | /* Testing shows that buffer offset must be at location of Buffer[0] */ |
587 | req->SecurityBufferOffset = | 587 | req->SecurityBufferOffset = |
588 | cpu_to_le16(sizeof(struct smb2_sess_setup_req) - | 588 | cpu_to_le16(sizeof(struct smb2_sess_setup_req) - |
589 | 1 /* pad */ - 4 /* rfc1001 len */); | 589 | 1 /* pad */ - 4 /* rfc1001 len */); |
590 | req->SecurityBufferLength = cpu_to_le16(blob_length); | 590 | req->SecurityBufferLength = cpu_to_le16(blob_length); |
591 | iov[1].iov_base = security_blob; | 591 | iov[1].iov_base = security_blob; |
592 | iov[1].iov_len = blob_length; | 592 | iov[1].iov_len = blob_length; |
593 | 593 | ||
594 | inc_rfc1001_len(req, blob_length - 1 /* pad */); | 594 | inc_rfc1001_len(req, blob_length - 1 /* pad */); |
595 | 595 | ||
596 | /* BB add code to build os and lm fields */ | 596 | /* BB add code to build os and lm fields */ |
597 | 597 | ||
598 | rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, CIFS_LOG_ERROR); | 598 | rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, CIFS_LOG_ERROR); |
599 | 599 | ||
600 | kfree(security_blob); | 600 | kfree(security_blob); |
601 | rsp = (struct smb2_sess_setup_rsp *)iov[0].iov_base; | 601 | rsp = (struct smb2_sess_setup_rsp *)iov[0].iov_base; |
602 | if (rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED) { | 602 | if (rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED) { |
603 | if (phase != NtLmNegotiate) { | 603 | if (phase != NtLmNegotiate) { |
604 | cERROR(1, "Unexpected more processing error"); | 604 | cERROR(1, "Unexpected more processing error"); |
605 | goto ssetup_exit; | 605 | goto ssetup_exit; |
606 | } | 606 | } |
607 | if (offsetof(struct smb2_sess_setup_rsp, Buffer) - 4 != | 607 | if (offsetof(struct smb2_sess_setup_rsp, Buffer) - 4 != |
608 | le16_to_cpu(rsp->SecurityBufferOffset)) { | 608 | le16_to_cpu(rsp->SecurityBufferOffset)) { |
609 | cERROR(1, "Invalid security buffer offset %d", | 609 | cERROR(1, "Invalid security buffer offset %d", |
610 | le16_to_cpu(rsp->SecurityBufferOffset)); | 610 | le16_to_cpu(rsp->SecurityBufferOffset)); |
611 | rc = -EIO; | 611 | rc = -EIO; |
612 | goto ssetup_exit; | 612 | goto ssetup_exit; |
613 | } | 613 | } |
614 | 614 | ||
615 | /* NTLMSSP Negotiate sent now processing challenge (response) */ | 615 | /* NTLMSSP Negotiate sent now processing challenge (response) */ |
616 | phase = NtLmChallenge; /* process ntlmssp challenge */ | 616 | phase = NtLmChallenge; /* process ntlmssp challenge */ |
617 | rc = 0; /* MORE_PROCESSING is not an error here but expected */ | 617 | rc = 0; /* MORE_PROCESSING is not an error here but expected */ |
618 | ses->Suid = rsp->hdr.SessionId; | 618 | ses->Suid = rsp->hdr.SessionId; |
619 | rc = decode_ntlmssp_challenge(rsp->Buffer, | 619 | rc = decode_ntlmssp_challenge(rsp->Buffer, |
620 | le16_to_cpu(rsp->SecurityBufferLength), ses); | 620 | le16_to_cpu(rsp->SecurityBufferLength), ses); |
621 | } | 621 | } |
622 | 622 | ||
623 | /* | 623 | /* |
624 | * BB eventually add code for SPNEGO decoding of NtlmChallenge blob, | 624 | * BB eventually add code for SPNEGO decoding of NtlmChallenge blob, |
625 | * but at least the raw NTLMSSP case works. | 625 | * but at least the raw NTLMSSP case works. |
626 | */ | 626 | */ |
627 | /* | 627 | /* |
628 | * No tcon so can't do | 628 | * No tcon so can't do |
629 | * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]); | 629 | * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]); |
630 | */ | 630 | */ |
631 | if (rc != 0) | 631 | if (rc != 0) |
632 | goto ssetup_exit; | 632 | goto ssetup_exit; |
633 | 633 | ||
634 | if (rsp == NULL) { | 634 | if (rsp == NULL) { |
635 | rc = -EIO; | 635 | rc = -EIO; |
636 | goto ssetup_exit; | 636 | goto ssetup_exit; |
637 | } | 637 | } |
638 | 638 | ||
639 | ses->session_flags = le16_to_cpu(rsp->SessionFlags); | 639 | ses->session_flags = le16_to_cpu(rsp->SessionFlags); |
640 | ssetup_exit: | 640 | ssetup_exit: |
641 | free_rsp_buf(resp_buftype, rsp); | 641 | free_rsp_buf(resp_buftype, rsp); |
642 | 642 | ||
643 | /* if ntlmssp, and negotiate succeeded, proceed to authenticate phase */ | 643 | /* if ntlmssp, and negotiate succeeded, proceed to authenticate phase */ |
644 | if ((phase == NtLmChallenge) && (rc == 0)) | 644 | if ((phase == NtLmChallenge) && (rc == 0)) |
645 | goto ssetup_ntlmssp_authenticate; | 645 | goto ssetup_ntlmssp_authenticate; |
646 | return rc; | 646 | return rc; |
647 | } | 647 | } |
648 | 648 | ||
649 | int | 649 | int |
650 | SMB2_logoff(const unsigned int xid, struct cifs_ses *ses) | 650 | SMB2_logoff(const unsigned int xid, struct cifs_ses *ses) |
651 | { | 651 | { |
652 | struct smb2_logoff_req *req; /* response is also trivial struct */ | 652 | struct smb2_logoff_req *req; /* response is also trivial struct */ |
653 | int rc = 0; | 653 | int rc = 0; |
654 | struct TCP_Server_Info *server; | 654 | struct TCP_Server_Info *server; |
655 | 655 | ||
656 | cFYI(1, "disconnect session %p", ses); | 656 | cFYI(1, "disconnect session %p", ses); |
657 | 657 | ||
658 | if (ses && (ses->server)) | 658 | if (ses && (ses->server)) |
659 | server = ses->server; | 659 | server = ses->server; |
660 | else | 660 | else |
661 | return -EIO; | 661 | return -EIO; |
662 | 662 | ||
663 | rc = small_smb2_init(SMB2_LOGOFF, NULL, (void **) &req); | 663 | rc = small_smb2_init(SMB2_LOGOFF, NULL, (void **) &req); |
664 | if (rc) | 664 | if (rc) |
665 | return rc; | 665 | return rc; |
666 | 666 | ||
667 | /* since no tcon, smb2_init can not do this, so do here */ | 667 | /* since no tcon, smb2_init can not do this, so do here */ |
668 | req->hdr.SessionId = ses->Suid; | 668 | req->hdr.SessionId = ses->Suid; |
669 | 669 | ||
670 | rc = SendReceiveNoRsp(xid, ses, (char *) &req->hdr, 0); | 670 | rc = SendReceiveNoRsp(xid, ses, (char *) &req->hdr, 0); |
671 | /* | 671 | /* |
672 | * No tcon so can't do | 672 | * No tcon so can't do |
673 | * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]); | 673 | * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]); |
674 | */ | 674 | */ |
675 | return rc; | 675 | return rc; |
676 | } | 676 | } |
677 | 677 | ||
678 | static inline void cifs_stats_fail_inc(struct cifs_tcon *tcon, uint16_t code) | 678 | static inline void cifs_stats_fail_inc(struct cifs_tcon *tcon, uint16_t code) |
679 | { | 679 | { |
680 | cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_failed[code]); | 680 | cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_failed[code]); |
681 | } | 681 | } |
682 | 682 | ||
683 | #define MAX_SHARENAME_LENGTH (255 /* server */ + 80 /* share */ + 1 /* NULL */) | 683 | #define MAX_SHARENAME_LENGTH (255 /* server */ + 80 /* share */ + 1 /* NULL */) |
684 | 684 | ||
685 | int | 685 | int |
686 | SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, | 686 | SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, |
687 | struct cifs_tcon *tcon, const struct nls_table *cp) | 687 | struct cifs_tcon *tcon, const struct nls_table *cp) |
688 | { | 688 | { |
689 | struct smb2_tree_connect_req *req; | 689 | struct smb2_tree_connect_req *req; |
690 | struct smb2_tree_connect_rsp *rsp = NULL; | 690 | struct smb2_tree_connect_rsp *rsp = NULL; |
691 | struct kvec iov[2]; | 691 | struct kvec iov[2]; |
692 | int rc = 0; | 692 | int rc = 0; |
693 | int resp_buftype; | 693 | int resp_buftype; |
694 | int unc_path_len; | 694 | int unc_path_len; |
695 | struct TCP_Server_Info *server; | 695 | struct TCP_Server_Info *server; |
696 | __le16 *unc_path = NULL; | 696 | __le16 *unc_path = NULL; |
697 | 697 | ||
698 | cFYI(1, "TCON"); | 698 | cFYI(1, "TCON"); |
699 | 699 | ||
700 | if ((ses->server) && tree) | 700 | if ((ses->server) && tree) |
701 | server = ses->server; | 701 | server = ses->server; |
702 | else | 702 | else |
703 | return -EIO; | 703 | return -EIO; |
704 | 704 | ||
705 | if (tcon && tcon->bad_network_name) | 705 | if (tcon && tcon->bad_network_name) |
706 | return -ENOENT; | 706 | return -ENOENT; |
707 | 707 | ||
708 | unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL); | 708 | unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL); |
709 | if (unc_path == NULL) | 709 | if (unc_path == NULL) |
710 | return -ENOMEM; | 710 | return -ENOMEM; |
711 | 711 | ||
712 | unc_path_len = cifs_strtoUTF16(unc_path, tree, strlen(tree), cp) + 1; | 712 | unc_path_len = cifs_strtoUTF16(unc_path, tree, strlen(tree), cp) + 1; |
713 | unc_path_len *= 2; | 713 | unc_path_len *= 2; |
714 | if (unc_path_len < 2) { | 714 | if (unc_path_len < 2) { |
715 | kfree(unc_path); | 715 | kfree(unc_path); |
716 | return -EINVAL; | 716 | return -EINVAL; |
717 | } | 717 | } |
718 | 718 | ||
719 | rc = small_smb2_init(SMB2_TREE_CONNECT, tcon, (void **) &req); | 719 | rc = small_smb2_init(SMB2_TREE_CONNECT, tcon, (void **) &req); |
720 | if (rc) { | 720 | if (rc) { |
721 | kfree(unc_path); | 721 | kfree(unc_path); |
722 | return rc; | 722 | return rc; |
723 | } | 723 | } |
724 | 724 | ||
725 | if (tcon == NULL) { | 725 | if (tcon == NULL) { |
726 | /* since no tcon, smb2_init can not do this, so do here */ | 726 | /* since no tcon, smb2_init can not do this, so do here */ |
727 | req->hdr.SessionId = ses->Suid; | 727 | req->hdr.SessionId = ses->Suid; |
728 | /* if (ses->server->sec_mode & SECMODE_SIGN_REQUIRED) | 728 | /* if (ses->server->sec_mode & SECMODE_SIGN_REQUIRED) |
729 | req->hdr.Flags |= SMB2_FLAGS_SIGNED; */ | 729 | req->hdr.Flags |= SMB2_FLAGS_SIGNED; */ |
730 | } | 730 | } |
731 | 731 | ||
732 | iov[0].iov_base = (char *)req; | 732 | iov[0].iov_base = (char *)req; |
733 | /* 4 for rfc1002 length field and 1 for pad */ | 733 | /* 4 for rfc1002 length field and 1 for pad */ |
734 | iov[0].iov_len = get_rfc1002_length(req) + 4 - 1; | 734 | iov[0].iov_len = get_rfc1002_length(req) + 4 - 1; |
735 | 735 | ||
736 | /* Testing shows that buffer offset must be at location of Buffer[0] */ | 736 | /* Testing shows that buffer offset must be at location of Buffer[0] */ |
737 | req->PathOffset = cpu_to_le16(sizeof(struct smb2_tree_connect_req) | 737 | req->PathOffset = cpu_to_le16(sizeof(struct smb2_tree_connect_req) |
738 | - 1 /* pad */ - 4 /* do not count rfc1001 len field */); | 738 | - 1 /* pad */ - 4 /* do not count rfc1001 len field */); |
739 | req->PathLength = cpu_to_le16(unc_path_len - 2); | 739 | req->PathLength = cpu_to_le16(unc_path_len - 2); |
740 | iov[1].iov_base = unc_path; | 740 | iov[1].iov_base = unc_path; |
741 | iov[1].iov_len = unc_path_len; | 741 | iov[1].iov_len = unc_path_len; |
742 | 742 | ||
743 | inc_rfc1001_len(req, unc_path_len - 1 /* pad */); | 743 | inc_rfc1001_len(req, unc_path_len - 1 /* pad */); |
744 | 744 | ||
745 | rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, 0); | 745 | rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, 0); |
746 | rsp = (struct smb2_tree_connect_rsp *)iov[0].iov_base; | 746 | rsp = (struct smb2_tree_connect_rsp *)iov[0].iov_base; |
747 | 747 | ||
748 | if (rc != 0) { | 748 | if (rc != 0) { |
749 | if (tcon) { | 749 | if (tcon) { |
750 | cifs_stats_fail_inc(tcon, SMB2_TREE_CONNECT_HE); | 750 | cifs_stats_fail_inc(tcon, SMB2_TREE_CONNECT_HE); |
751 | tcon->need_reconnect = true; | 751 | tcon->need_reconnect = true; |
752 | } | 752 | } |
753 | goto tcon_error_exit; | 753 | goto tcon_error_exit; |
754 | } | 754 | } |
755 | 755 | ||
756 | if (rsp == NULL) { | 756 | if (rsp == NULL) { |
757 | rc = -EIO; | 757 | rc = -EIO; |
758 | goto tcon_exit; | 758 | goto tcon_exit; |
759 | } | 759 | } |
760 | 760 | ||
761 | if (tcon == NULL) { | 761 | if (tcon == NULL) { |
762 | ses->ipc_tid = rsp->hdr.TreeId; | 762 | ses->ipc_tid = rsp->hdr.TreeId; |
763 | goto tcon_exit; | 763 | goto tcon_exit; |
764 | } | 764 | } |
765 | 765 | ||
766 | if (rsp->ShareType & SMB2_SHARE_TYPE_DISK) | 766 | if (rsp->ShareType & SMB2_SHARE_TYPE_DISK) |
767 | cFYI(1, "connection to disk share"); | 767 | cFYI(1, "connection to disk share"); |
768 | else if (rsp->ShareType & SMB2_SHARE_TYPE_PIPE) { | 768 | else if (rsp->ShareType & SMB2_SHARE_TYPE_PIPE) { |
769 | tcon->ipc = true; | 769 | tcon->ipc = true; |
770 | cFYI(1, "connection to pipe share"); | 770 | cFYI(1, "connection to pipe share"); |
771 | } else if (rsp->ShareType & SMB2_SHARE_TYPE_PRINT) { | 771 | } else if (rsp->ShareType & SMB2_SHARE_TYPE_PRINT) { |
772 | tcon->print = true; | 772 | tcon->print = true; |
773 | cFYI(1, "connection to printer"); | 773 | cFYI(1, "connection to printer"); |
774 | } else { | 774 | } else { |
775 | cERROR(1, "unknown share type %d", rsp->ShareType); | 775 | cERROR(1, "unknown share type %d", rsp->ShareType); |
776 | rc = -EOPNOTSUPP; | 776 | rc = -EOPNOTSUPP; |
777 | goto tcon_error_exit; | 777 | goto tcon_error_exit; |
778 | } | 778 | } |
779 | 779 | ||
780 | tcon->share_flags = le32_to_cpu(rsp->ShareFlags); | 780 | tcon->share_flags = le32_to_cpu(rsp->ShareFlags); |
781 | tcon->maximal_access = le32_to_cpu(rsp->MaximalAccess); | 781 | tcon->maximal_access = le32_to_cpu(rsp->MaximalAccess); |
782 | tcon->tidStatus = CifsGood; | 782 | tcon->tidStatus = CifsGood; |
783 | tcon->need_reconnect = false; | 783 | tcon->need_reconnect = false; |
784 | tcon->tid = rsp->hdr.TreeId; | 784 | tcon->tid = rsp->hdr.TreeId; |
785 | strncpy(tcon->treeName, tree, MAX_TREE_SIZE); | 785 | strncpy(tcon->treeName, tree, MAX_TREE_SIZE); |
786 | 786 | ||
787 | if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) && | 787 | if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) && |
788 | ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0)) | 788 | ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0)) |
789 | cERROR(1, "DFS capability contradicts DFS flag"); | 789 | cERROR(1, "DFS capability contradicts DFS flag"); |
790 | 790 | ||
791 | tcon_exit: | 791 | tcon_exit: |
792 | free_rsp_buf(resp_buftype, rsp); | 792 | free_rsp_buf(resp_buftype, rsp); |
793 | kfree(unc_path); | 793 | kfree(unc_path); |
794 | return rc; | 794 | return rc; |
795 | 795 | ||
796 | tcon_error_exit: | 796 | tcon_error_exit: |
797 | if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) { | 797 | if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) { |
798 | cERROR(1, "BAD_NETWORK_NAME: %s", tree); | 798 | cERROR(1, "BAD_NETWORK_NAME: %s", tree); |
799 | tcon->bad_network_name = true; | 799 | tcon->bad_network_name = true; |
800 | } | 800 | } |
801 | goto tcon_exit; | 801 | goto tcon_exit; |
802 | } | 802 | } |
803 | 803 | ||
804 | int | 804 | int |
805 | SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon) | 805 | SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon) |
806 | { | 806 | { |
807 | struct smb2_tree_disconnect_req *req; /* response is trivial */ | 807 | struct smb2_tree_disconnect_req *req; /* response is trivial */ |
808 | int rc = 0; | 808 | int rc = 0; |
809 | struct TCP_Server_Info *server; | 809 | struct TCP_Server_Info *server; |
810 | struct cifs_ses *ses = tcon->ses; | 810 | struct cifs_ses *ses = tcon->ses; |
811 | 811 | ||
812 | cFYI(1, "Tree Disconnect"); | 812 | cFYI(1, "Tree Disconnect"); |
813 | 813 | ||
814 | if (ses && (ses->server)) | 814 | if (ses && (ses->server)) |
815 | server = ses->server; | 815 | server = ses->server; |
816 | else | 816 | else |
817 | return -EIO; | 817 | return -EIO; |
818 | 818 | ||
819 | if ((tcon->need_reconnect) || (tcon->ses->need_reconnect)) | 819 | if ((tcon->need_reconnect) || (tcon->ses->need_reconnect)) |
820 | return 0; | 820 | return 0; |
821 | 821 | ||
822 | rc = small_smb2_init(SMB2_TREE_DISCONNECT, tcon, (void **) &req); | 822 | rc = small_smb2_init(SMB2_TREE_DISCONNECT, tcon, (void **) &req); |
823 | if (rc) | 823 | if (rc) |
824 | return rc; | 824 | return rc; |
825 | 825 | ||
826 | rc = SendReceiveNoRsp(xid, ses, (char *)&req->hdr, 0); | 826 | rc = SendReceiveNoRsp(xid, ses, (char *)&req->hdr, 0); |
827 | if (rc) | 827 | if (rc) |
828 | cifs_stats_fail_inc(tcon, SMB2_TREE_DISCONNECT_HE); | 828 | cifs_stats_fail_inc(tcon, SMB2_TREE_DISCONNECT_HE); |
829 | 829 | ||
830 | return rc; | 830 | return rc; |
831 | } | 831 | } |
832 | 832 | ||
833 | int | 833 | int |
834 | SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path, | 834 | SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path, |
835 | u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access, | 835 | u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access, |
836 | __u32 create_disposition, __u32 file_attributes, __u32 create_options, | 836 | __u32 create_disposition, __u32 file_attributes, __u32 create_options, |
837 | struct smb2_file_all_info *buf) | 837 | struct smb2_file_all_info *buf) |
838 | { | 838 | { |
839 | struct smb2_create_req *req; | 839 | struct smb2_create_req *req; |
840 | struct smb2_create_rsp *rsp; | 840 | struct smb2_create_rsp *rsp; |
841 | struct TCP_Server_Info *server; | 841 | struct TCP_Server_Info *server; |
842 | struct cifs_ses *ses = tcon->ses; | 842 | struct cifs_ses *ses = tcon->ses; |
843 | struct kvec iov[2]; | 843 | struct kvec iov[2]; |
844 | int resp_buftype; | 844 | int resp_buftype; |
845 | int uni_path_len; | 845 | int uni_path_len; |
846 | int rc = 0; | 846 | int rc = 0; |
847 | int num_iovecs = 2; | 847 | int num_iovecs = 2; |
848 | 848 | ||
849 | cFYI(1, "create/open"); | 849 | cFYI(1, "create/open"); |
850 | 850 | ||
851 | if (ses && (ses->server)) | 851 | if (ses && (ses->server)) |
852 | server = ses->server; | 852 | server = ses->server; |
853 | else | 853 | else |
854 | return -EIO; | 854 | return -EIO; |
855 | 855 | ||
856 | rc = small_smb2_init(SMB2_CREATE, tcon, (void **) &req); | 856 | rc = small_smb2_init(SMB2_CREATE, tcon, (void **) &req); |
857 | if (rc) | 857 | if (rc) |
858 | return rc; | 858 | return rc; |
859 | 859 | ||
860 | /* if (server->oplocks) | 860 | /* if (server->oplocks) |
861 | req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_BATCH; | 861 | req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_BATCH; |
862 | else */ | 862 | else */ |
863 | req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE; | 863 | req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE; |
864 | req->ImpersonationLevel = IL_IMPERSONATION; | 864 | req->ImpersonationLevel = IL_IMPERSONATION; |
865 | req->DesiredAccess = cpu_to_le32(desired_access); | 865 | req->DesiredAccess = cpu_to_le32(desired_access); |
866 | /* File attributes ignored on open (used in create though) */ | 866 | /* File attributes ignored on open (used in create though) */ |
867 | req->FileAttributes = cpu_to_le32(file_attributes); | 867 | req->FileAttributes = cpu_to_le32(file_attributes); |
868 | req->ShareAccess = FILE_SHARE_ALL_LE; | 868 | req->ShareAccess = FILE_SHARE_ALL_LE; |
869 | req->CreateDisposition = cpu_to_le32(create_disposition); | 869 | req->CreateDisposition = cpu_to_le32(create_disposition); |
870 | req->CreateOptions = cpu_to_le32(create_options); | 870 | req->CreateOptions = cpu_to_le32(create_options); |
871 | uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2; | 871 | uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2; |
872 | req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req) | 872 | req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req) |
873 | - 1 /* pad */ - 4 /* do not count rfc1001 len field */); | 873 | - 1 /* pad */ - 4 /* do not count rfc1001 len field */); |
874 | 874 | ||
875 | iov[0].iov_base = (char *)req; | 875 | iov[0].iov_base = (char *)req; |
876 | /* 4 for rfc1002 length field */ | 876 | /* 4 for rfc1002 length field */ |
877 | iov[0].iov_len = get_rfc1002_length(req) + 4; | 877 | iov[0].iov_len = get_rfc1002_length(req) + 4; |
878 | 878 | ||
879 | /* MUST set path len (NameLength) to 0 opening root of share */ | 879 | /* MUST set path len (NameLength) to 0 opening root of share */ |
880 | if (uni_path_len >= 4) { | 880 | if (uni_path_len >= 4) { |
881 | req->NameLength = cpu_to_le16(uni_path_len - 2); | 881 | req->NameLength = cpu_to_le16(uni_path_len - 2); |
882 | /* -1 since last byte is buf[0] which is sent below (path) */ | 882 | /* -1 since last byte is buf[0] which is sent below (path) */ |
883 | iov[0].iov_len--; | 883 | iov[0].iov_len--; |
884 | iov[1].iov_len = uni_path_len; | 884 | iov[1].iov_len = uni_path_len; |
885 | iov[1].iov_base = path; | 885 | iov[1].iov_base = path; |
886 | /* | 886 | /* |
887 | * -1 since last byte is buf[0] which was counted in | 887 | * -1 since last byte is buf[0] which was counted in |
888 | * smb2_buf_len. | 888 | * smb2_buf_len. |
889 | */ | 889 | */ |
890 | inc_rfc1001_len(req, uni_path_len - 1); | 890 | inc_rfc1001_len(req, uni_path_len - 1); |
891 | } else { | 891 | } else { |
892 | num_iovecs = 1; | 892 | num_iovecs = 1; |
893 | req->NameLength = 0; | 893 | req->NameLength = 0; |
894 | } | 894 | } |
895 | 895 | ||
896 | rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0); | 896 | rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0); |
897 | rsp = (struct smb2_create_rsp *)iov[0].iov_base; | 897 | rsp = (struct smb2_create_rsp *)iov[0].iov_base; |
898 | 898 | ||
899 | if (rc != 0) { | 899 | if (rc != 0) { |
900 | cifs_stats_fail_inc(tcon, SMB2_CREATE_HE); | 900 | cifs_stats_fail_inc(tcon, SMB2_CREATE_HE); |
901 | goto creat_exit; | 901 | goto creat_exit; |
902 | } | 902 | } |
903 | 903 | ||
904 | if (rsp == NULL) { | 904 | if (rsp == NULL) { |
905 | rc = -EIO; | 905 | rc = -EIO; |
906 | goto creat_exit; | 906 | goto creat_exit; |
907 | } | 907 | } |
908 | *persistent_fid = rsp->PersistentFileId; | 908 | *persistent_fid = rsp->PersistentFileId; |
909 | *volatile_fid = rsp->VolatileFileId; | 909 | *volatile_fid = rsp->VolatileFileId; |
910 | 910 | ||
911 | if (buf) { | 911 | if (buf) { |
912 | memcpy(buf, &rsp->CreationTime, 32); | 912 | memcpy(buf, &rsp->CreationTime, 32); |
913 | buf->AllocationSize = rsp->AllocationSize; | 913 | buf->AllocationSize = rsp->AllocationSize; |
914 | buf->EndOfFile = rsp->EndofFile; | 914 | buf->EndOfFile = rsp->EndofFile; |
915 | buf->Attributes = rsp->FileAttributes; | 915 | buf->Attributes = rsp->FileAttributes; |
916 | buf->NumberOfLinks = cpu_to_le32(1); | 916 | buf->NumberOfLinks = cpu_to_le32(1); |
917 | buf->DeletePending = 0; | 917 | buf->DeletePending = 0; |
918 | } | 918 | } |
919 | creat_exit: | 919 | creat_exit: |
920 | free_rsp_buf(resp_buftype, rsp); | 920 | free_rsp_buf(resp_buftype, rsp); |
921 | return rc; | 921 | return rc; |
922 | } | 922 | } |
923 | 923 | ||
924 | int | 924 | int |
925 | SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, | 925 | SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, |
926 | u64 persistent_fid, u64 volatile_fid) | 926 | u64 persistent_fid, u64 volatile_fid) |
927 | { | 927 | { |
928 | struct smb2_close_req *req; | 928 | struct smb2_close_req *req; |
929 | struct smb2_close_rsp *rsp; | 929 | struct smb2_close_rsp *rsp; |
930 | struct TCP_Server_Info *server; | 930 | struct TCP_Server_Info *server; |
931 | struct cifs_ses *ses = tcon->ses; | 931 | struct cifs_ses *ses = tcon->ses; |
932 | struct kvec iov[1]; | 932 | struct kvec iov[1]; |
933 | int resp_buftype; | 933 | int resp_buftype; |
934 | int rc = 0; | 934 | int rc = 0; |
935 | 935 | ||
936 | cFYI(1, "Close"); | 936 | cFYI(1, "Close"); |
937 | 937 | ||
938 | if (ses && (ses->server)) | 938 | if (ses && (ses->server)) |
939 | server = ses->server; | 939 | server = ses->server; |
940 | else | 940 | else |
941 | return -EIO; | 941 | return -EIO; |
942 | 942 | ||
943 | rc = small_smb2_init(SMB2_CLOSE, tcon, (void **) &req); | 943 | rc = small_smb2_init(SMB2_CLOSE, tcon, (void **) &req); |
944 | if (rc) | 944 | if (rc) |
945 | return rc; | 945 | return rc; |
946 | 946 | ||
947 | req->PersistentFileId = persistent_fid; | 947 | req->PersistentFileId = persistent_fid; |
948 | req->VolatileFileId = volatile_fid; | 948 | req->VolatileFileId = volatile_fid; |
949 | 949 | ||
950 | iov[0].iov_base = (char *)req; | 950 | iov[0].iov_base = (char *)req; |
951 | /* 4 for rfc1002 length field */ | 951 | /* 4 for rfc1002 length field */ |
952 | iov[0].iov_len = get_rfc1002_length(req) + 4; | 952 | iov[0].iov_len = get_rfc1002_length(req) + 4; |
953 | 953 | ||
954 | rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0); | 954 | rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0); |
955 | rsp = (struct smb2_close_rsp *)iov[0].iov_base; | 955 | rsp = (struct smb2_close_rsp *)iov[0].iov_base; |
956 | 956 | ||
957 | if (rc != 0) { | 957 | if (rc != 0) { |
958 | if (tcon) | 958 | if (tcon) |
959 | cifs_stats_fail_inc(tcon, SMB2_CLOSE_HE); | 959 | cifs_stats_fail_inc(tcon, SMB2_CLOSE_HE); |
960 | goto close_exit; | 960 | goto close_exit; |
961 | } | 961 | } |
962 | 962 | ||
963 | if (rsp == NULL) { | 963 | if (rsp == NULL) { |
964 | rc = -EIO; | 964 | rc = -EIO; |
965 | goto close_exit; | 965 | goto close_exit; |
966 | } | 966 | } |
967 | 967 | ||
968 | /* BB FIXME - decode close response, update inode for caching */ | 968 | /* BB FIXME - decode close response, update inode for caching */ |
969 | 969 | ||
970 | close_exit: | 970 | close_exit: |
971 | free_rsp_buf(resp_buftype, rsp); | 971 | free_rsp_buf(resp_buftype, rsp); |
972 | return rc; | 972 | return rc; |
973 | } | 973 | } |
974 | 974 | ||
975 | static int | 975 | static int |
976 | validate_buf(unsigned int offset, unsigned int buffer_length, | 976 | validate_buf(unsigned int offset, unsigned int buffer_length, |
977 | struct smb2_hdr *hdr, unsigned int min_buf_size) | 977 | struct smb2_hdr *hdr, unsigned int min_buf_size) |
978 | 978 | ||
979 | { | 979 | { |
980 | unsigned int smb_len = be32_to_cpu(hdr->smb2_buf_length); | 980 | unsigned int smb_len = be32_to_cpu(hdr->smb2_buf_length); |
981 | char *end_of_smb = smb_len + 4 /* RFC1001 length field */ + (char *)hdr; | 981 | char *end_of_smb = smb_len + 4 /* RFC1001 length field */ + (char *)hdr; |
982 | char *begin_of_buf = 4 /* RFC1001 len field */ + offset + (char *)hdr; | 982 | char *begin_of_buf = 4 /* RFC1001 len field */ + offset + (char *)hdr; |
983 | char *end_of_buf = begin_of_buf + buffer_length; | 983 | char *end_of_buf = begin_of_buf + buffer_length; |
984 | 984 | ||
985 | 985 | ||
986 | if (buffer_length < min_buf_size) { | 986 | if (buffer_length < min_buf_size) { |
987 | cERROR(1, "buffer length %d smaller than minimum size %d", | 987 | cERROR(1, "buffer length %d smaller than minimum size %d", |
988 | buffer_length, min_buf_size); | 988 | buffer_length, min_buf_size); |
989 | return -EINVAL; | 989 | return -EINVAL; |
990 | } | 990 | } |
991 | 991 | ||
992 | /* check if beyond RFC1001 maximum length */ | 992 | /* check if beyond RFC1001 maximum length */ |
993 | if ((smb_len > 0x7FFFFF) || (buffer_length > 0x7FFFFF)) { | 993 | if ((smb_len > 0x7FFFFF) || (buffer_length > 0x7FFFFF)) { |
994 | cERROR(1, "buffer length %d or smb length %d too large", | 994 | cERROR(1, "buffer length %d or smb length %d too large", |
995 | buffer_length, smb_len); | 995 | buffer_length, smb_len); |
996 | return -EINVAL; | 996 | return -EINVAL; |
997 | } | 997 | } |
998 | 998 | ||
999 | if ((begin_of_buf > end_of_smb) || (end_of_buf > end_of_smb)) { | 999 | if ((begin_of_buf > end_of_smb) || (end_of_buf > end_of_smb)) { |
1000 | cERROR(1, "illegal server response, bad offset to data"); | 1000 | cERROR(1, "illegal server response, bad offset to data"); |
1001 | return -EINVAL; | 1001 | return -EINVAL; |
1002 | } | 1002 | } |
1003 | 1003 | ||
1004 | return 0; | 1004 | return 0; |
1005 | } | 1005 | } |
1006 | 1006 | ||
1007 | /* | 1007 | /* |
1008 | * If SMB buffer fields are valid, copy into temporary buffer to hold result. | 1008 | * If SMB buffer fields are valid, copy into temporary buffer to hold result. |
1009 | * Caller must free buffer. | 1009 | * Caller must free buffer. |
1010 | */ | 1010 | */ |
1011 | static int | 1011 | static int |
1012 | validate_and_copy_buf(unsigned int offset, unsigned int buffer_length, | 1012 | validate_and_copy_buf(unsigned int offset, unsigned int buffer_length, |
1013 | struct smb2_hdr *hdr, unsigned int minbufsize, | 1013 | struct smb2_hdr *hdr, unsigned int minbufsize, |
1014 | char *data) | 1014 | char *data) |
1015 | 1015 | ||
1016 | { | 1016 | { |
1017 | char *begin_of_buf = 4 /* RFC1001 len field */ + offset + (char *)hdr; | 1017 | char *begin_of_buf = 4 /* RFC1001 len field */ + offset + (char *)hdr; |
1018 | int rc; | 1018 | int rc; |
1019 | 1019 | ||
1020 | if (!data) | 1020 | if (!data) |
1021 | return -EINVAL; | 1021 | return -EINVAL; |
1022 | 1022 | ||
1023 | rc = validate_buf(offset, buffer_length, hdr, minbufsize); | 1023 | rc = validate_buf(offset, buffer_length, hdr, minbufsize); |
1024 | if (rc) | 1024 | if (rc) |
1025 | return rc; | 1025 | return rc; |
1026 | 1026 | ||
1027 | memcpy(data, begin_of_buf, buffer_length); | 1027 | memcpy(data, begin_of_buf, buffer_length); |
1028 | 1028 | ||
1029 | return 0; | 1029 | return 0; |
1030 | } | 1030 | } |
1031 | 1031 | ||
1032 | static int | 1032 | static int |
1033 | query_info(const unsigned int xid, struct cifs_tcon *tcon, | 1033 | query_info(const unsigned int xid, struct cifs_tcon *tcon, |
1034 | u64 persistent_fid, u64 volatile_fid, u8 info_class, | 1034 | u64 persistent_fid, u64 volatile_fid, u8 info_class, |
1035 | size_t output_len, size_t min_len, void *data) | 1035 | size_t output_len, size_t min_len, void *data) |
1036 | { | 1036 | { |
1037 | struct smb2_query_info_req *req; | 1037 | struct smb2_query_info_req *req; |
1038 | struct smb2_query_info_rsp *rsp = NULL; | 1038 | struct smb2_query_info_rsp *rsp = NULL; |
1039 | struct kvec iov[2]; | 1039 | struct kvec iov[2]; |
1040 | int rc = 0; | 1040 | int rc = 0; |
1041 | int resp_buftype; | 1041 | int resp_buftype; |
1042 | struct TCP_Server_Info *server; | 1042 | struct TCP_Server_Info *server; |
1043 | struct cifs_ses *ses = tcon->ses; | 1043 | struct cifs_ses *ses = tcon->ses; |
1044 | 1044 | ||
1045 | cFYI(1, "Query Info"); | 1045 | cFYI(1, "Query Info"); |
1046 | 1046 | ||
1047 | if (ses && (ses->server)) | 1047 | if (ses && (ses->server)) |
1048 | server = ses->server; | 1048 | server = ses->server; |
1049 | else | 1049 | else |
1050 | return -EIO; | 1050 | return -EIO; |
1051 | 1051 | ||
1052 | rc = small_smb2_init(SMB2_QUERY_INFO, tcon, (void **) &req); | 1052 | rc = small_smb2_init(SMB2_QUERY_INFO, tcon, (void **) &req); |
1053 | if (rc) | 1053 | if (rc) |
1054 | return rc; | 1054 | return rc; |
1055 | 1055 | ||
1056 | req->InfoType = SMB2_O_INFO_FILE; | 1056 | req->InfoType = SMB2_O_INFO_FILE; |
1057 | req->FileInfoClass = info_class; | 1057 | req->FileInfoClass = info_class; |
1058 | req->PersistentFileId = persistent_fid; | 1058 | req->PersistentFileId = persistent_fid; |
1059 | req->VolatileFileId = volatile_fid; | 1059 | req->VolatileFileId = volatile_fid; |
1060 | /* 4 for rfc1002 length field and 1 for Buffer */ | 1060 | /* 4 for rfc1002 length field and 1 for Buffer */ |
1061 | req->InputBufferOffset = | 1061 | req->InputBufferOffset = |
1062 | cpu_to_le16(sizeof(struct smb2_query_info_req) - 1 - 4); | 1062 | cpu_to_le16(sizeof(struct smb2_query_info_req) - 1 - 4); |
1063 | req->OutputBufferLength = cpu_to_le32(output_len); | 1063 | req->OutputBufferLength = cpu_to_le32(output_len); |
1064 | 1064 | ||
1065 | iov[0].iov_base = (char *)req; | 1065 | iov[0].iov_base = (char *)req; |
1066 | /* 4 for rfc1002 length field */ | 1066 | /* 4 for rfc1002 length field */ |
1067 | iov[0].iov_len = get_rfc1002_length(req) + 4; | 1067 | iov[0].iov_len = get_rfc1002_length(req) + 4; |
1068 | 1068 | ||
1069 | rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0); | 1069 | rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0); |
1070 | if (rc) { | 1070 | if (rc) { |
1071 | cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE); | 1071 | cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE); |
1072 | goto qinf_exit; | 1072 | goto qinf_exit; |
1073 | } | 1073 | } |
1074 | 1074 | ||
1075 | rsp = (struct smb2_query_info_rsp *)iov[0].iov_base; | 1075 | rsp = (struct smb2_query_info_rsp *)iov[0].iov_base; |
1076 | 1076 | ||
1077 | rc = validate_and_copy_buf(le16_to_cpu(rsp->OutputBufferOffset), | 1077 | rc = validate_and_copy_buf(le16_to_cpu(rsp->OutputBufferOffset), |
1078 | le32_to_cpu(rsp->OutputBufferLength), | 1078 | le32_to_cpu(rsp->OutputBufferLength), |
1079 | &rsp->hdr, min_len, data); | 1079 | &rsp->hdr, min_len, data); |
1080 | 1080 | ||
1081 | qinf_exit: | 1081 | qinf_exit: |
1082 | free_rsp_buf(resp_buftype, rsp); | 1082 | free_rsp_buf(resp_buftype, rsp); |
1083 | return rc; | 1083 | return rc; |
1084 | } | 1084 | } |
1085 | 1085 | ||
1086 | int | 1086 | int |
1087 | SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, | 1087 | SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, |
1088 | u64 persistent_fid, u64 volatile_fid, | 1088 | u64 persistent_fid, u64 volatile_fid, |
1089 | struct smb2_file_all_info *data) | 1089 | struct smb2_file_all_info *data) |
1090 | { | 1090 | { |
1091 | return query_info(xid, tcon, persistent_fid, volatile_fid, | 1091 | return query_info(xid, tcon, persistent_fid, volatile_fid, |
1092 | FILE_ALL_INFORMATION, | 1092 | FILE_ALL_INFORMATION, |
1093 | sizeof(struct smb2_file_all_info) + MAX_NAME * 2, | 1093 | sizeof(struct smb2_file_all_info) + MAX_NAME * 2, |
1094 | sizeof(struct smb2_file_all_info), data); | 1094 | sizeof(struct smb2_file_all_info), data); |
1095 | } | 1095 | } |
1096 | 1096 | ||
1097 | int | 1097 | int |
1098 | SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon, | 1098 | SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon, |
1099 | u64 persistent_fid, u64 volatile_fid, __le64 *uniqueid) | 1099 | u64 persistent_fid, u64 volatile_fid, __le64 *uniqueid) |
1100 | { | 1100 | { |
1101 | return query_info(xid, tcon, persistent_fid, volatile_fid, | 1101 | return query_info(xid, tcon, persistent_fid, volatile_fid, |
1102 | FILE_INTERNAL_INFORMATION, | 1102 | FILE_INTERNAL_INFORMATION, |
1103 | sizeof(struct smb2_file_internal_info), | 1103 | sizeof(struct smb2_file_internal_info), |
1104 | sizeof(struct smb2_file_internal_info), uniqueid); | 1104 | sizeof(struct smb2_file_internal_info), uniqueid); |
1105 | } | 1105 | } |
1106 | 1106 | ||
1107 | /* | 1107 | /* |
1108 | * This is a no-op for now. We're not really interested in the reply, but | 1108 | * This is a no-op for now. We're not really interested in the reply, but |
1109 | * rather in the fact that the server sent one and that server->lstrp | 1109 | * rather in the fact that the server sent one and that server->lstrp |
1110 | * gets updated. | 1110 | * gets updated. |
1111 | * | 1111 | * |
1112 | * FIXME: maybe we should consider checking that the reply matches request? | 1112 | * FIXME: maybe we should consider checking that the reply matches request? |
1113 | */ | 1113 | */ |
1114 | static void | 1114 | static void |
1115 | smb2_echo_callback(struct mid_q_entry *mid) | 1115 | smb2_echo_callback(struct mid_q_entry *mid) |
1116 | { | 1116 | { |
1117 | struct TCP_Server_Info *server = mid->callback_data; | 1117 | struct TCP_Server_Info *server = mid->callback_data; |
1118 | struct smb2_echo_rsp *smb2 = (struct smb2_echo_rsp *)mid->resp_buf; | 1118 | struct smb2_echo_rsp *smb2 = (struct smb2_echo_rsp *)mid->resp_buf; |
1119 | unsigned int credits_received = 1; | 1119 | unsigned int credits_received = 1; |
1120 | 1120 | ||
1121 | if (mid->mid_state == MID_RESPONSE_RECEIVED) | 1121 | if (mid->mid_state == MID_RESPONSE_RECEIVED) |
1122 | credits_received = le16_to_cpu(smb2->hdr.CreditRequest); | 1122 | credits_received = le16_to_cpu(smb2->hdr.CreditRequest); |
1123 | 1123 | ||
1124 | DeleteMidQEntry(mid); | 1124 | DeleteMidQEntry(mid); |
1125 | add_credits(server, credits_received, CIFS_ECHO_OP); | 1125 | add_credits(server, credits_received, CIFS_ECHO_OP); |
1126 | } | 1126 | } |
1127 | 1127 | ||
1128 | int | 1128 | int |
1129 | SMB2_echo(struct TCP_Server_Info *server) | 1129 | SMB2_echo(struct TCP_Server_Info *server) |
1130 | { | 1130 | { |
1131 | struct smb2_echo_req *req; | 1131 | struct smb2_echo_req *req; |
1132 | int rc = 0; | 1132 | int rc = 0; |
1133 | struct kvec iov; | 1133 | struct kvec iov; |
1134 | 1134 | ||
1135 | cFYI(1, "In echo request"); | 1135 | cFYI(1, "In echo request"); |
1136 | 1136 | ||
1137 | rc = small_smb2_init(SMB2_ECHO, NULL, (void **)&req); | 1137 | rc = small_smb2_init(SMB2_ECHO, NULL, (void **)&req); |
1138 | if (rc) | 1138 | if (rc) |
1139 | return rc; | 1139 | return rc; |
1140 | 1140 | ||
1141 | req->hdr.CreditRequest = cpu_to_le16(1); | 1141 | req->hdr.CreditRequest = cpu_to_le16(1); |
1142 | 1142 | ||
1143 | iov.iov_base = (char *)req; | 1143 | iov.iov_base = (char *)req; |
1144 | /* 4 for rfc1002 length field */ | 1144 | /* 4 for rfc1002 length field */ |
1145 | iov.iov_len = get_rfc1002_length(req) + 4; | 1145 | iov.iov_len = get_rfc1002_length(req) + 4; |
1146 | 1146 | ||
1147 | rc = cifs_call_async(server, &iov, 1, NULL, smb2_echo_callback, server, | 1147 | rc = cifs_call_async(server, &iov, 1, NULL, smb2_echo_callback, server, |
1148 | CIFS_ECHO_OP); | 1148 | CIFS_ECHO_OP); |
1149 | if (rc) | 1149 | if (rc) |
1150 | cFYI(1, "Echo request failed: %d", rc); | 1150 | cFYI(1, "Echo request failed: %d", rc); |
1151 | 1151 | ||
1152 | cifs_small_buf_release(req); | 1152 | cifs_small_buf_release(req); |
1153 | return rc; | 1153 | return rc; |
1154 | } | 1154 | } |
1155 | |||
1156 | int | ||
1157 | SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, | ||
1158 | u64 volatile_fid) | ||
1159 | { | ||
1160 | struct smb2_flush_req *req; | ||
1161 | struct TCP_Server_Info *server; | ||
1162 | struct cifs_ses *ses = tcon->ses; | ||
1163 | struct kvec iov[1]; | ||
1164 | int resp_buftype; | ||
1165 | int rc = 0; | ||
1166 | |||
1167 | cFYI(1, "Flush"); | ||
1168 | |||
1169 | if (ses && (ses->server)) | ||
1170 | server = ses->server; | ||
1171 | else | ||
1172 | return -EIO; | ||
1173 | |||
1174 | rc = small_smb2_init(SMB2_FLUSH, tcon, (void **) &req); | ||
1175 | if (rc) | ||
1176 | return rc; | ||
1177 | |||
1178 | req->PersistentFileId = persistent_fid; | ||
1179 | req->VolatileFileId = volatile_fid; | ||
1180 | |||
1181 | iov[0].iov_base = (char *)req; | ||
1182 | /* 4 for rfc1002 length field */ | ||
1183 | iov[0].iov_len = get_rfc1002_length(req) + 4; | ||
1184 | |||
1185 | rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0); | ||
1186 | |||
1187 | if ((rc != 0) && tcon) | ||
1188 | cifs_stats_fail_inc(tcon, SMB2_FLUSH_HE); | ||
1189 | |||
1190 | free_rsp_buf(resp_buftype, iov[0].iov_base); | ||
1191 | return rc; | ||
1192 | } | ||
1155 | 1193 |
fs/cifs/smb2pdu.h
1 | /* | 1 | /* |
2 | * fs/cifs/smb2pdu.h | 2 | * fs/cifs/smb2pdu.h |
3 | * | 3 | * |
4 | * Copyright (c) International Business Machines Corp., 2009, 2010 | 4 | * Copyright (c) International Business Machines Corp., 2009, 2010 |
5 | * Etersoft, 2012 | 5 | * Etersoft, 2012 |
6 | * Author(s): Steve French (sfrench@us.ibm.com) | 6 | * Author(s): Steve French (sfrench@us.ibm.com) |
7 | * Pavel Shilovsky (pshilovsky@samba.org) 2012 | 7 | * Pavel Shilovsky (pshilovsky@samba.org) 2012 |
8 | * | 8 | * |
9 | * This library is free software; you can redistribute it and/or modify | 9 | * This library is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU Lesser General Public License as published | 10 | * it under the terms of the GNU Lesser General Public License as published |
11 | * by the Free Software Foundation; either version 2.1 of the License, or | 11 | * by the Free Software Foundation; either version 2.1 of the License, or |
12 | * (at your option) any later version. | 12 | * (at your option) any later version. |
13 | * | 13 | * |
14 | * This library is distributed in the hope that it will be useful, | 14 | * This library is distributed in the hope that it will be useful, |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
17 | * the GNU Lesser General Public License for more details. | 17 | * the GNU Lesser General Public License for more details. |
18 | * | 18 | * |
19 | * You should have received a copy of the GNU Lesser General Public License | 19 | * You should have received a copy of the GNU Lesser General Public License |
20 | * along with this library; if not, write to the Free Software | 20 | * along with this library; if not, write to the Free Software |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #ifndef _SMB2PDU_H | 24 | #ifndef _SMB2PDU_H |
25 | #define _SMB2PDU_H | 25 | #define _SMB2PDU_H |
26 | 26 | ||
27 | #include <net/sock.h> | 27 | #include <net/sock.h> |
28 | 28 | ||
29 | /* | 29 | /* |
30 | * Note that, due to trying to use names similar to the protocol specifications, | 30 | * Note that, due to trying to use names similar to the protocol specifications, |
31 | * there are many mixed case field names in the structures below. Although | 31 | * there are many mixed case field names in the structures below. Although |
32 | * this does not match typical Linux kernel style, it is necessary to be | 32 | * this does not match typical Linux kernel style, it is necessary to be |
33 | * be able to match against the protocol specfication. | 33 | * be able to match against the protocol specfication. |
34 | * | 34 | * |
35 | * SMB2 commands | 35 | * SMB2 commands |
36 | * Some commands have minimal (wct=0,bcc=0), or uninteresting, responses | 36 | * Some commands have minimal (wct=0,bcc=0), or uninteresting, responses |
37 | * (ie no useful data other than the SMB error code itself) and are marked such. | 37 | * (ie no useful data other than the SMB error code itself) and are marked such. |
38 | * Knowing this helps avoid response buffer allocations and copy in some cases. | 38 | * Knowing this helps avoid response buffer allocations and copy in some cases. |
39 | */ | 39 | */ |
40 | 40 | ||
41 | /* List of commands in host endian */ | 41 | /* List of commands in host endian */ |
42 | #define SMB2_NEGOTIATE_HE 0x0000 | 42 | #define SMB2_NEGOTIATE_HE 0x0000 |
43 | #define SMB2_SESSION_SETUP_HE 0x0001 | 43 | #define SMB2_SESSION_SETUP_HE 0x0001 |
44 | #define SMB2_LOGOFF_HE 0x0002 /* trivial request/resp */ | 44 | #define SMB2_LOGOFF_HE 0x0002 /* trivial request/resp */ |
45 | #define SMB2_TREE_CONNECT_HE 0x0003 | 45 | #define SMB2_TREE_CONNECT_HE 0x0003 |
46 | #define SMB2_TREE_DISCONNECT_HE 0x0004 /* trivial req/resp */ | 46 | #define SMB2_TREE_DISCONNECT_HE 0x0004 /* trivial req/resp */ |
47 | #define SMB2_CREATE_HE 0x0005 | 47 | #define SMB2_CREATE_HE 0x0005 |
48 | #define SMB2_CLOSE_HE 0x0006 | 48 | #define SMB2_CLOSE_HE 0x0006 |
49 | #define SMB2_FLUSH_HE 0x0007 /* trivial resp */ | 49 | #define SMB2_FLUSH_HE 0x0007 /* trivial resp */ |
50 | #define SMB2_READ_HE 0x0008 | 50 | #define SMB2_READ_HE 0x0008 |
51 | #define SMB2_WRITE_HE 0x0009 | 51 | #define SMB2_WRITE_HE 0x0009 |
52 | #define SMB2_LOCK_HE 0x000A | 52 | #define SMB2_LOCK_HE 0x000A |
53 | #define SMB2_IOCTL_HE 0x000B | 53 | #define SMB2_IOCTL_HE 0x000B |
54 | #define SMB2_CANCEL_HE 0x000C | 54 | #define SMB2_CANCEL_HE 0x000C |
55 | #define SMB2_ECHO_HE 0x000D | 55 | #define SMB2_ECHO_HE 0x000D |
56 | #define SMB2_QUERY_DIRECTORY_HE 0x000E | 56 | #define SMB2_QUERY_DIRECTORY_HE 0x000E |
57 | #define SMB2_CHANGE_NOTIFY_HE 0x000F | 57 | #define SMB2_CHANGE_NOTIFY_HE 0x000F |
58 | #define SMB2_QUERY_INFO_HE 0x0010 | 58 | #define SMB2_QUERY_INFO_HE 0x0010 |
59 | #define SMB2_SET_INFO_HE 0x0011 | 59 | #define SMB2_SET_INFO_HE 0x0011 |
60 | #define SMB2_OPLOCK_BREAK_HE 0x0012 | 60 | #define SMB2_OPLOCK_BREAK_HE 0x0012 |
61 | 61 | ||
62 | /* The same list in little endian */ | 62 | /* The same list in little endian */ |
63 | #define SMB2_NEGOTIATE cpu_to_le16(SMB2_NEGOTIATE_HE) | 63 | #define SMB2_NEGOTIATE cpu_to_le16(SMB2_NEGOTIATE_HE) |
64 | #define SMB2_SESSION_SETUP cpu_to_le16(SMB2_SESSION_SETUP_HE) | 64 | #define SMB2_SESSION_SETUP cpu_to_le16(SMB2_SESSION_SETUP_HE) |
65 | #define SMB2_LOGOFF cpu_to_le16(SMB2_LOGOFF_HE) | 65 | #define SMB2_LOGOFF cpu_to_le16(SMB2_LOGOFF_HE) |
66 | #define SMB2_TREE_CONNECT cpu_to_le16(SMB2_TREE_CONNECT_HE) | 66 | #define SMB2_TREE_CONNECT cpu_to_le16(SMB2_TREE_CONNECT_HE) |
67 | #define SMB2_TREE_DISCONNECT cpu_to_le16(SMB2_TREE_DISCONNECT_HE) | 67 | #define SMB2_TREE_DISCONNECT cpu_to_le16(SMB2_TREE_DISCONNECT_HE) |
68 | #define SMB2_CREATE cpu_to_le16(SMB2_CREATE_HE) | 68 | #define SMB2_CREATE cpu_to_le16(SMB2_CREATE_HE) |
69 | #define SMB2_CLOSE cpu_to_le16(SMB2_CLOSE_HE) | 69 | #define SMB2_CLOSE cpu_to_le16(SMB2_CLOSE_HE) |
70 | #define SMB2_FLUSH cpu_to_le16(SMB2_FLUSH_HE) | 70 | #define SMB2_FLUSH cpu_to_le16(SMB2_FLUSH_HE) |
71 | #define SMB2_READ cpu_to_le16(SMB2_READ_HE) | 71 | #define SMB2_READ cpu_to_le16(SMB2_READ_HE) |
72 | #define SMB2_WRITE cpu_to_le16(SMB2_WRITE_HE) | 72 | #define SMB2_WRITE cpu_to_le16(SMB2_WRITE_HE) |
73 | #define SMB2_LOCK cpu_to_le16(SMB2_LOCK_HE) | 73 | #define SMB2_LOCK cpu_to_le16(SMB2_LOCK_HE) |
74 | #define SMB2_IOCTL cpu_to_le16(SMB2_IOCTL_HE) | 74 | #define SMB2_IOCTL cpu_to_le16(SMB2_IOCTL_HE) |
75 | #define SMB2_CANCEL cpu_to_le16(SMB2_CANCEL_HE) | 75 | #define SMB2_CANCEL cpu_to_le16(SMB2_CANCEL_HE) |
76 | #define SMB2_ECHO cpu_to_le16(SMB2_ECHO_HE) | 76 | #define SMB2_ECHO cpu_to_le16(SMB2_ECHO_HE) |
77 | #define SMB2_QUERY_DIRECTORY cpu_to_le16(SMB2_QUERY_DIRECTORY_HE) | 77 | #define SMB2_QUERY_DIRECTORY cpu_to_le16(SMB2_QUERY_DIRECTORY_HE) |
78 | #define SMB2_CHANGE_NOTIFY cpu_to_le16(SMB2_CHANGE_NOTIFY_HE) | 78 | #define SMB2_CHANGE_NOTIFY cpu_to_le16(SMB2_CHANGE_NOTIFY_HE) |
79 | #define SMB2_QUERY_INFO cpu_to_le16(SMB2_QUERY_INFO_HE) | 79 | #define SMB2_QUERY_INFO cpu_to_le16(SMB2_QUERY_INFO_HE) |
80 | #define SMB2_SET_INFO cpu_to_le16(SMB2_SET_INFO_HE) | 80 | #define SMB2_SET_INFO cpu_to_le16(SMB2_SET_INFO_HE) |
81 | #define SMB2_OPLOCK_BREAK cpu_to_le16(SMB2_OPLOCK_BREAK_HE) | 81 | #define SMB2_OPLOCK_BREAK cpu_to_le16(SMB2_OPLOCK_BREAK_HE) |
82 | 82 | ||
83 | #define NUMBER_OF_SMB2_COMMANDS 0x0013 | 83 | #define NUMBER_OF_SMB2_COMMANDS 0x0013 |
84 | 84 | ||
85 | /* BB FIXME - analyze following length BB */ | 85 | /* BB FIXME - analyze following length BB */ |
86 | #define MAX_SMB2_HDR_SIZE 0x78 /* 4 len + 64 hdr + (2*24 wct) + 2 bct + 2 pad */ | 86 | #define MAX_SMB2_HDR_SIZE 0x78 /* 4 len + 64 hdr + (2*24 wct) + 2 bct + 2 pad */ |
87 | 87 | ||
88 | #define SMB2_PROTO_NUMBER __constant_cpu_to_le32(0x424d53fe) | 88 | #define SMB2_PROTO_NUMBER __constant_cpu_to_le32(0x424d53fe) |
89 | 89 | ||
90 | /* | 90 | /* |
91 | * SMB2 Header Definition | 91 | * SMB2 Header Definition |
92 | * | 92 | * |
93 | * "MBZ" : Must be Zero | 93 | * "MBZ" : Must be Zero |
94 | * "BB" : BugBug, Something to check/review/analyze later | 94 | * "BB" : BugBug, Something to check/review/analyze later |
95 | * "PDU" : "Protocol Data Unit" (ie a network "frame") | 95 | * "PDU" : "Protocol Data Unit" (ie a network "frame") |
96 | * | 96 | * |
97 | */ | 97 | */ |
98 | 98 | ||
99 | #define SMB2_HEADER_STRUCTURE_SIZE __constant_cpu_to_le16(64) | 99 | #define SMB2_HEADER_STRUCTURE_SIZE __constant_cpu_to_le16(64) |
100 | 100 | ||
101 | struct smb2_hdr { | 101 | struct smb2_hdr { |
102 | __be32 smb2_buf_length; /* big endian on wire */ | 102 | __be32 smb2_buf_length; /* big endian on wire */ |
103 | /* length is only two or three bytes - with | 103 | /* length is only two or three bytes - with |
104 | one or two byte type preceding it that MBZ */ | 104 | one or two byte type preceding it that MBZ */ |
105 | __u8 ProtocolId[4]; /* 0xFE 'S' 'M' 'B' */ | 105 | __u8 ProtocolId[4]; /* 0xFE 'S' 'M' 'B' */ |
106 | __le16 StructureSize; /* 64 */ | 106 | __le16 StructureSize; /* 64 */ |
107 | __le16 CreditCharge; /* MBZ */ | 107 | __le16 CreditCharge; /* MBZ */ |
108 | __le32 Status; /* Error from server */ | 108 | __le32 Status; /* Error from server */ |
109 | __le16 Command; | 109 | __le16 Command; |
110 | __le16 CreditRequest; /* CreditResponse */ | 110 | __le16 CreditRequest; /* CreditResponse */ |
111 | __le32 Flags; | 111 | __le32 Flags; |
112 | __le32 NextCommand; | 112 | __le32 NextCommand; |
113 | __u64 MessageId; /* opaque - so can stay little endian */ | 113 | __u64 MessageId; /* opaque - so can stay little endian */ |
114 | __le32 ProcessId; | 114 | __le32 ProcessId; |
115 | __u32 TreeId; /* opaque - so do not make little endian */ | 115 | __u32 TreeId; /* opaque - so do not make little endian */ |
116 | __u64 SessionId; /* opaque - so do not make little endian */ | 116 | __u64 SessionId; /* opaque - so do not make little endian */ |
117 | __u8 Signature[16]; | 117 | __u8 Signature[16]; |
118 | } __packed; | 118 | } __packed; |
119 | 119 | ||
120 | struct smb2_pdu { | 120 | struct smb2_pdu { |
121 | struct smb2_hdr hdr; | 121 | struct smb2_hdr hdr; |
122 | __le16 StructureSize2; /* size of wct area (varies, request specific) */ | 122 | __le16 StructureSize2; /* size of wct area (varies, request specific) */ |
123 | } __packed; | 123 | } __packed; |
124 | 124 | ||
125 | /* | 125 | /* |
126 | * SMB2 flag definitions | 126 | * SMB2 flag definitions |
127 | */ | 127 | */ |
128 | #define SMB2_FLAGS_SERVER_TO_REDIR __constant_cpu_to_le32(0x00000001) | 128 | #define SMB2_FLAGS_SERVER_TO_REDIR __constant_cpu_to_le32(0x00000001) |
129 | #define SMB2_FLAGS_ASYNC_COMMAND __constant_cpu_to_le32(0x00000002) | 129 | #define SMB2_FLAGS_ASYNC_COMMAND __constant_cpu_to_le32(0x00000002) |
130 | #define SMB2_FLAGS_RELATED_OPERATIONS __constant_cpu_to_le32(0x00000004) | 130 | #define SMB2_FLAGS_RELATED_OPERATIONS __constant_cpu_to_le32(0x00000004) |
131 | #define SMB2_FLAGS_SIGNED __constant_cpu_to_le32(0x00000008) | 131 | #define SMB2_FLAGS_SIGNED __constant_cpu_to_le32(0x00000008) |
132 | #define SMB2_FLAGS_DFS_OPERATIONS __constant_cpu_to_le32(0x10000000) | 132 | #define SMB2_FLAGS_DFS_OPERATIONS __constant_cpu_to_le32(0x10000000) |
133 | 133 | ||
134 | /* | 134 | /* |
135 | * Definitions for SMB2 Protocol Data Units (network frames) | 135 | * Definitions for SMB2 Protocol Data Units (network frames) |
136 | * | 136 | * |
137 | * See MS-SMB2.PDF specification for protocol details. | 137 | * See MS-SMB2.PDF specification for protocol details. |
138 | * The Naming convention is the lower case version of the SMB2 | 138 | * The Naming convention is the lower case version of the SMB2 |
139 | * command code name for the struct. Note that structures must be packed. | 139 | * command code name for the struct. Note that structures must be packed. |
140 | * | 140 | * |
141 | */ | 141 | */ |
142 | 142 | ||
143 | #define SMB2_ERROR_STRUCTURE_SIZE2 __constant_cpu_to_le16(9) | 143 | #define SMB2_ERROR_STRUCTURE_SIZE2 __constant_cpu_to_le16(9) |
144 | 144 | ||
145 | struct smb2_err_rsp { | 145 | struct smb2_err_rsp { |
146 | struct smb2_hdr hdr; | 146 | struct smb2_hdr hdr; |
147 | __le16 StructureSize; | 147 | __le16 StructureSize; |
148 | __le16 Reserved; /* MBZ */ | 148 | __le16 Reserved; /* MBZ */ |
149 | __le32 ByteCount; /* even if zero, at least one byte follows */ | 149 | __le32 ByteCount; /* even if zero, at least one byte follows */ |
150 | __u8 ErrorData[1]; /* variable length */ | 150 | __u8 ErrorData[1]; /* variable length */ |
151 | } __packed; | 151 | } __packed; |
152 | 152 | ||
153 | struct smb2_negotiate_req { | 153 | struct smb2_negotiate_req { |
154 | struct smb2_hdr hdr; | 154 | struct smb2_hdr hdr; |
155 | __le16 StructureSize; /* Must be 36 */ | 155 | __le16 StructureSize; /* Must be 36 */ |
156 | __le16 DialectCount; | 156 | __le16 DialectCount; |
157 | __le16 SecurityMode; | 157 | __le16 SecurityMode; |
158 | __le16 Reserved; /* MBZ */ | 158 | __le16 Reserved; /* MBZ */ |
159 | __le32 Capabilities; | 159 | __le32 Capabilities; |
160 | __u8 ClientGUID[16]; /* MBZ */ | 160 | __u8 ClientGUID[16]; /* MBZ */ |
161 | __le64 ClientStartTime; /* MBZ */ | 161 | __le64 ClientStartTime; /* MBZ */ |
162 | __le16 Dialects[2]; /* variable length */ | 162 | __le16 Dialects[2]; /* variable length */ |
163 | } __packed; | 163 | } __packed; |
164 | 164 | ||
165 | /* SecurityMode flags */ | 165 | /* SecurityMode flags */ |
166 | #define SMB2_NEGOTIATE_SIGNING_ENABLED 0x0001 | 166 | #define SMB2_NEGOTIATE_SIGNING_ENABLED 0x0001 |
167 | #define SMB2_NEGOTIATE_SIGNING_REQUIRED 0x0002 | 167 | #define SMB2_NEGOTIATE_SIGNING_REQUIRED 0x0002 |
168 | /* Capabilities flags */ | 168 | /* Capabilities flags */ |
169 | #define SMB2_GLOBAL_CAP_DFS 0x00000001 | 169 | #define SMB2_GLOBAL_CAP_DFS 0x00000001 |
170 | #define SMB2_GLOBAL_CAP_LEASING 0x00000002 /* Resp only New to SMB2.1 */ | 170 | #define SMB2_GLOBAL_CAP_LEASING 0x00000002 /* Resp only New to SMB2.1 */ |
171 | #define SMB2_GLOBAL_CAP_LARGE_MTU 0X00000004 /* Resp only New to SMB2.1 */ | 171 | #define SMB2_GLOBAL_CAP_LARGE_MTU 0X00000004 /* Resp only New to SMB2.1 */ |
172 | /* Internal types */ | 172 | /* Internal types */ |
173 | #define SMB2_NT_FIND 0x00100000 | 173 | #define SMB2_NT_FIND 0x00100000 |
174 | #define SMB2_LARGE_FILES 0x00200000 | 174 | #define SMB2_LARGE_FILES 0x00200000 |
175 | 175 | ||
176 | struct smb2_negotiate_rsp { | 176 | struct smb2_negotiate_rsp { |
177 | struct smb2_hdr hdr; | 177 | struct smb2_hdr hdr; |
178 | __le16 StructureSize; /* Must be 65 */ | 178 | __le16 StructureSize; /* Must be 65 */ |
179 | __le16 SecurityMode; | 179 | __le16 SecurityMode; |
180 | __le16 DialectRevision; | 180 | __le16 DialectRevision; |
181 | __le16 Reserved; /* MBZ */ | 181 | __le16 Reserved; /* MBZ */ |
182 | __u8 ServerGUID[16]; | 182 | __u8 ServerGUID[16]; |
183 | __le32 Capabilities; | 183 | __le32 Capabilities; |
184 | __le32 MaxTransactSize; | 184 | __le32 MaxTransactSize; |
185 | __le32 MaxReadSize; | 185 | __le32 MaxReadSize; |
186 | __le32 MaxWriteSize; | 186 | __le32 MaxWriteSize; |
187 | __le64 SystemTime; /* MBZ */ | 187 | __le64 SystemTime; /* MBZ */ |
188 | __le64 ServerStartTime; | 188 | __le64 ServerStartTime; |
189 | __le16 SecurityBufferOffset; | 189 | __le16 SecurityBufferOffset; |
190 | __le16 SecurityBufferLength; | 190 | __le16 SecurityBufferLength; |
191 | __le32 Reserved2; /* may be any value, ignore */ | 191 | __le32 Reserved2; /* may be any value, ignore */ |
192 | __u8 Buffer[1]; /* variable length GSS security buffer */ | 192 | __u8 Buffer[1]; /* variable length GSS security buffer */ |
193 | } __packed; | 193 | } __packed; |
194 | 194 | ||
195 | struct smb2_sess_setup_req { | 195 | struct smb2_sess_setup_req { |
196 | struct smb2_hdr hdr; | 196 | struct smb2_hdr hdr; |
197 | __le16 StructureSize; /* Must be 25 */ | 197 | __le16 StructureSize; /* Must be 25 */ |
198 | __u8 VcNumber; | 198 | __u8 VcNumber; |
199 | __u8 SecurityMode; | 199 | __u8 SecurityMode; |
200 | __le32 Capabilities; | 200 | __le32 Capabilities; |
201 | __le32 Channel; | 201 | __le32 Channel; |
202 | __le16 SecurityBufferOffset; | 202 | __le16 SecurityBufferOffset; |
203 | __le16 SecurityBufferLength; | 203 | __le16 SecurityBufferLength; |
204 | __le64 PreviousSessionId; | 204 | __le64 PreviousSessionId; |
205 | __u8 Buffer[1]; /* variable length GSS security buffer */ | 205 | __u8 Buffer[1]; /* variable length GSS security buffer */ |
206 | } __packed; | 206 | } __packed; |
207 | 207 | ||
208 | /* Currently defined SessionFlags */ | 208 | /* Currently defined SessionFlags */ |
209 | #define SMB2_SESSION_FLAG_IS_GUEST 0x0001 | 209 | #define SMB2_SESSION_FLAG_IS_GUEST 0x0001 |
210 | #define SMB2_SESSION_FLAG_IS_NULL 0x0002 | 210 | #define SMB2_SESSION_FLAG_IS_NULL 0x0002 |
211 | struct smb2_sess_setup_rsp { | 211 | struct smb2_sess_setup_rsp { |
212 | struct smb2_hdr hdr; | 212 | struct smb2_hdr hdr; |
213 | __le16 StructureSize; /* Must be 9 */ | 213 | __le16 StructureSize; /* Must be 9 */ |
214 | __le16 SessionFlags; | 214 | __le16 SessionFlags; |
215 | __le16 SecurityBufferOffset; | 215 | __le16 SecurityBufferOffset; |
216 | __le16 SecurityBufferLength; | 216 | __le16 SecurityBufferLength; |
217 | __u8 Buffer[1]; /* variable length GSS security buffer */ | 217 | __u8 Buffer[1]; /* variable length GSS security buffer */ |
218 | } __packed; | 218 | } __packed; |
219 | 219 | ||
220 | struct smb2_logoff_req { | 220 | struct smb2_logoff_req { |
221 | struct smb2_hdr hdr; | 221 | struct smb2_hdr hdr; |
222 | __le16 StructureSize; /* Must be 4 */ | 222 | __le16 StructureSize; /* Must be 4 */ |
223 | __le16 Reserved; | 223 | __le16 Reserved; |
224 | } __packed; | 224 | } __packed; |
225 | 225 | ||
226 | struct smb2_logoff_rsp { | 226 | struct smb2_logoff_rsp { |
227 | struct smb2_hdr hdr; | 227 | struct smb2_hdr hdr; |
228 | __le16 StructureSize; /* Must be 4 */ | 228 | __le16 StructureSize; /* Must be 4 */ |
229 | __le16 Reserved; | 229 | __le16 Reserved; |
230 | } __packed; | 230 | } __packed; |
231 | 231 | ||
232 | struct smb2_tree_connect_req { | 232 | struct smb2_tree_connect_req { |
233 | struct smb2_hdr hdr; | 233 | struct smb2_hdr hdr; |
234 | __le16 StructureSize; /* Must be 9 */ | 234 | __le16 StructureSize; /* Must be 9 */ |
235 | __le16 Reserved; | 235 | __le16 Reserved; |
236 | __le16 PathOffset; | 236 | __le16 PathOffset; |
237 | __le16 PathLength; | 237 | __le16 PathLength; |
238 | __u8 Buffer[1]; /* variable length */ | 238 | __u8 Buffer[1]; /* variable length */ |
239 | } __packed; | 239 | } __packed; |
240 | 240 | ||
241 | struct smb2_tree_connect_rsp { | 241 | struct smb2_tree_connect_rsp { |
242 | struct smb2_hdr hdr; | 242 | struct smb2_hdr hdr; |
243 | __le16 StructureSize; /* Must be 16 */ | 243 | __le16 StructureSize; /* Must be 16 */ |
244 | __u8 ShareType; /* see below */ | 244 | __u8 ShareType; /* see below */ |
245 | __u8 Reserved; | 245 | __u8 Reserved; |
246 | __le32 ShareFlags; /* see below */ | 246 | __le32 ShareFlags; /* see below */ |
247 | __le32 Capabilities; /* see below */ | 247 | __le32 Capabilities; /* see below */ |
248 | __le32 MaximalAccess; | 248 | __le32 MaximalAccess; |
249 | } __packed; | 249 | } __packed; |
250 | 250 | ||
251 | /* Possible ShareType values */ | 251 | /* Possible ShareType values */ |
252 | #define SMB2_SHARE_TYPE_DISK 0x01 | 252 | #define SMB2_SHARE_TYPE_DISK 0x01 |
253 | #define SMB2_SHARE_TYPE_PIPE 0x02 | 253 | #define SMB2_SHARE_TYPE_PIPE 0x02 |
254 | #define SMB2_SHARE_TYPE_PRINT 0x03 | 254 | #define SMB2_SHARE_TYPE_PRINT 0x03 |
255 | 255 | ||
256 | /* | 256 | /* |
257 | * Possible ShareFlags - exactly one and only one of the first 4 caching flags | 257 | * Possible ShareFlags - exactly one and only one of the first 4 caching flags |
258 | * must be set (any of the remaining, SHI1005, flags may be set individually | 258 | * must be set (any of the remaining, SHI1005, flags may be set individually |
259 | * or in combination. | 259 | * or in combination. |
260 | */ | 260 | */ |
261 | #define SMB2_SHAREFLAG_MANUAL_CACHING 0x00000000 | 261 | #define SMB2_SHAREFLAG_MANUAL_CACHING 0x00000000 |
262 | #define SMB2_SHAREFLAG_AUTO_CACHING 0x00000010 | 262 | #define SMB2_SHAREFLAG_AUTO_CACHING 0x00000010 |
263 | #define SMB2_SHAREFLAG_VDO_CACHING 0x00000020 | 263 | #define SMB2_SHAREFLAG_VDO_CACHING 0x00000020 |
264 | #define SMB2_SHAREFLAG_NO_CACHING 0x00000030 | 264 | #define SMB2_SHAREFLAG_NO_CACHING 0x00000030 |
265 | #define SHI1005_FLAGS_DFS 0x00000001 | 265 | #define SHI1005_FLAGS_DFS 0x00000001 |
266 | #define SHI1005_FLAGS_DFS_ROOT 0x00000002 | 266 | #define SHI1005_FLAGS_DFS_ROOT 0x00000002 |
267 | #define SHI1005_FLAGS_RESTRICT_EXCLUSIVE_OPENS 0x00000100 | 267 | #define SHI1005_FLAGS_RESTRICT_EXCLUSIVE_OPENS 0x00000100 |
268 | #define SHI1005_FLAGS_FORCE_SHARED_DELETE 0x00000200 | 268 | #define SHI1005_FLAGS_FORCE_SHARED_DELETE 0x00000200 |
269 | #define SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING 0x00000400 | 269 | #define SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING 0x00000400 |
270 | #define SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM 0x00000800 | 270 | #define SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM 0x00000800 |
271 | #define SHI1005_FLAGS_FORCE_LEVELII_OPLOCK 0x00001000 | 271 | #define SHI1005_FLAGS_FORCE_LEVELII_OPLOCK 0x00001000 |
272 | #define SHI1005_FLAGS_ENABLE_HASH 0x00002000 | 272 | #define SHI1005_FLAGS_ENABLE_HASH 0x00002000 |
273 | 273 | ||
274 | /* Possible share capabilities */ | 274 | /* Possible share capabilities */ |
275 | #define SMB2_SHARE_CAP_DFS cpu_to_le32(0x00000008) | 275 | #define SMB2_SHARE_CAP_DFS cpu_to_le32(0x00000008) |
276 | 276 | ||
277 | struct smb2_tree_disconnect_req { | 277 | struct smb2_tree_disconnect_req { |
278 | struct smb2_hdr hdr; | 278 | struct smb2_hdr hdr; |
279 | __le16 StructureSize; /* Must be 4 */ | 279 | __le16 StructureSize; /* Must be 4 */ |
280 | __le16 Reserved; | 280 | __le16 Reserved; |
281 | } __packed; | 281 | } __packed; |
282 | 282 | ||
283 | struct smb2_tree_disconnect_rsp { | 283 | struct smb2_tree_disconnect_rsp { |
284 | struct smb2_hdr hdr; | 284 | struct smb2_hdr hdr; |
285 | __le16 StructureSize; /* Must be 4 */ | 285 | __le16 StructureSize; /* Must be 4 */ |
286 | __le16 Reserved; | 286 | __le16 Reserved; |
287 | } __packed; | 287 | } __packed; |
288 | 288 | ||
289 | /* File Attrubutes */ | 289 | /* File Attrubutes */ |
290 | #define FILE_ATTRIBUTE_READONLY 0x00000001 | 290 | #define FILE_ATTRIBUTE_READONLY 0x00000001 |
291 | #define FILE_ATTRIBUTE_HIDDEN 0x00000002 | 291 | #define FILE_ATTRIBUTE_HIDDEN 0x00000002 |
292 | #define FILE_ATTRIBUTE_SYSTEM 0x00000004 | 292 | #define FILE_ATTRIBUTE_SYSTEM 0x00000004 |
293 | #define FILE_ATTRIBUTE_DIRECTORY 0x00000010 | 293 | #define FILE_ATTRIBUTE_DIRECTORY 0x00000010 |
294 | #define FILE_ATTRIBUTE_ARCHIVE 0x00000020 | 294 | #define FILE_ATTRIBUTE_ARCHIVE 0x00000020 |
295 | #define FILE_ATTRIBUTE_NORMAL 0x00000080 | 295 | #define FILE_ATTRIBUTE_NORMAL 0x00000080 |
296 | #define FILE_ATTRIBUTE_TEMPORARY 0x00000100 | 296 | #define FILE_ATTRIBUTE_TEMPORARY 0x00000100 |
297 | #define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200 | 297 | #define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200 |
298 | #define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 | 298 | #define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 |
299 | #define FILE_ATTRIBUTE_COMPRESSED 0x00000800 | 299 | #define FILE_ATTRIBUTE_COMPRESSED 0x00000800 |
300 | #define FILE_ATTRIBUTE_OFFLINE 0x00001000 | 300 | #define FILE_ATTRIBUTE_OFFLINE 0x00001000 |
301 | #define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 | 301 | #define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 |
302 | #define FILE_ATTRIBUTE_ENCRYPTED 0x00004000 | 302 | #define FILE_ATTRIBUTE_ENCRYPTED 0x00004000 |
303 | 303 | ||
304 | /* Oplock levels */ | 304 | /* Oplock levels */ |
305 | #define SMB2_OPLOCK_LEVEL_NONE 0x00 | 305 | #define SMB2_OPLOCK_LEVEL_NONE 0x00 |
306 | #define SMB2_OPLOCK_LEVEL_II 0x01 | 306 | #define SMB2_OPLOCK_LEVEL_II 0x01 |
307 | #define SMB2_OPLOCK_LEVEL_EXCLUSIVE 0x08 | 307 | #define SMB2_OPLOCK_LEVEL_EXCLUSIVE 0x08 |
308 | #define SMB2_OPLOCK_LEVEL_BATCH 0x09 | 308 | #define SMB2_OPLOCK_LEVEL_BATCH 0x09 |
309 | #define SMB2_OPLOCK_LEVEL_LEASE 0xFF | 309 | #define SMB2_OPLOCK_LEVEL_LEASE 0xFF |
310 | 310 | ||
311 | /* Desired Access Flags */ | 311 | /* Desired Access Flags */ |
312 | #define FILE_READ_DATA_LE cpu_to_le32(0x00000001) | 312 | #define FILE_READ_DATA_LE cpu_to_le32(0x00000001) |
313 | #define FILE_WRITE_DATA_LE cpu_to_le32(0x00000002) | 313 | #define FILE_WRITE_DATA_LE cpu_to_le32(0x00000002) |
314 | #define FILE_APPEND_DATA_LE cpu_to_le32(0x00000004) | 314 | #define FILE_APPEND_DATA_LE cpu_to_le32(0x00000004) |
315 | #define FILE_READ_EA_LE cpu_to_le32(0x00000008) | 315 | #define FILE_READ_EA_LE cpu_to_le32(0x00000008) |
316 | #define FILE_WRITE_EA_LE cpu_to_le32(0x00000010) | 316 | #define FILE_WRITE_EA_LE cpu_to_le32(0x00000010) |
317 | #define FILE_EXECUTE_LE cpu_to_le32(0x00000020) | 317 | #define FILE_EXECUTE_LE cpu_to_le32(0x00000020) |
318 | #define FILE_READ_ATTRIBUTES_LE cpu_to_le32(0x00000080) | 318 | #define FILE_READ_ATTRIBUTES_LE cpu_to_le32(0x00000080) |
319 | #define FILE_WRITE_ATTRIBUTES_LE cpu_to_le32(0x00000100) | 319 | #define FILE_WRITE_ATTRIBUTES_LE cpu_to_le32(0x00000100) |
320 | #define FILE_DELETE_LE cpu_to_le32(0x00010000) | 320 | #define FILE_DELETE_LE cpu_to_le32(0x00010000) |
321 | #define FILE_READ_CONTROL_LE cpu_to_le32(0x00020000) | 321 | #define FILE_READ_CONTROL_LE cpu_to_le32(0x00020000) |
322 | #define FILE_WRITE_DAC_LE cpu_to_le32(0x00040000) | 322 | #define FILE_WRITE_DAC_LE cpu_to_le32(0x00040000) |
323 | #define FILE_WRITE_OWNER_LE cpu_to_le32(0x00080000) | 323 | #define FILE_WRITE_OWNER_LE cpu_to_le32(0x00080000) |
324 | #define FILE_SYNCHRONIZE_LE cpu_to_le32(0x00100000) | 324 | #define FILE_SYNCHRONIZE_LE cpu_to_le32(0x00100000) |
325 | #define FILE_ACCESS_SYSTEM_SECURITY_LE cpu_to_le32(0x01000000) | 325 | #define FILE_ACCESS_SYSTEM_SECURITY_LE cpu_to_le32(0x01000000) |
326 | #define FILE_MAXIMAL_ACCESS_LE cpu_to_le32(0x02000000) | 326 | #define FILE_MAXIMAL_ACCESS_LE cpu_to_le32(0x02000000) |
327 | #define FILE_GENERIC_ALL_LE cpu_to_le32(0x10000000) | 327 | #define FILE_GENERIC_ALL_LE cpu_to_le32(0x10000000) |
328 | #define FILE_GENERIC_EXECUTE_LE cpu_to_le32(0x20000000) | 328 | #define FILE_GENERIC_EXECUTE_LE cpu_to_le32(0x20000000) |
329 | #define FILE_GENERIC_WRITE_LE cpu_to_le32(0x40000000) | 329 | #define FILE_GENERIC_WRITE_LE cpu_to_le32(0x40000000) |
330 | #define FILE_GENERIC_READ_LE cpu_to_le32(0x80000000) | 330 | #define FILE_GENERIC_READ_LE cpu_to_le32(0x80000000) |
331 | 331 | ||
332 | /* ShareAccess Flags */ | 332 | /* ShareAccess Flags */ |
333 | #define FILE_SHARE_READ_LE cpu_to_le32(0x00000001) | 333 | #define FILE_SHARE_READ_LE cpu_to_le32(0x00000001) |
334 | #define FILE_SHARE_WRITE_LE cpu_to_le32(0x00000002) | 334 | #define FILE_SHARE_WRITE_LE cpu_to_le32(0x00000002) |
335 | #define FILE_SHARE_DELETE_LE cpu_to_le32(0x00000004) | 335 | #define FILE_SHARE_DELETE_LE cpu_to_le32(0x00000004) |
336 | #define FILE_SHARE_ALL_LE cpu_to_le32(0x00000007) | 336 | #define FILE_SHARE_ALL_LE cpu_to_le32(0x00000007) |
337 | 337 | ||
338 | /* CreateDisposition Flags */ | 338 | /* CreateDisposition Flags */ |
339 | #define FILE_SUPERSEDE_LE cpu_to_le32(0x00000000) | 339 | #define FILE_SUPERSEDE_LE cpu_to_le32(0x00000000) |
340 | #define FILE_OPEN_LE cpu_to_le32(0x00000001) | 340 | #define FILE_OPEN_LE cpu_to_le32(0x00000001) |
341 | #define FILE_CREATE_LE cpu_to_le32(0x00000002) | 341 | #define FILE_CREATE_LE cpu_to_le32(0x00000002) |
342 | #define FILE_OPEN_IF_LE cpu_to_le32(0x00000003) | 342 | #define FILE_OPEN_IF_LE cpu_to_le32(0x00000003) |
343 | #define FILE_OVERWRITE_LE cpu_to_le32(0x00000004) | 343 | #define FILE_OVERWRITE_LE cpu_to_le32(0x00000004) |
344 | #define FILE_OVERWRITE_IF_LE cpu_to_le32(0x00000005) | 344 | #define FILE_OVERWRITE_IF_LE cpu_to_le32(0x00000005) |
345 | 345 | ||
346 | /* CreateOptions Flags */ | 346 | /* CreateOptions Flags */ |
347 | #define FILE_DIRECTORY_FILE_LE cpu_to_le32(0x00000001) | 347 | #define FILE_DIRECTORY_FILE_LE cpu_to_le32(0x00000001) |
348 | /* same as #define CREATE_NOT_FILE_LE cpu_to_le32(0x00000001) */ | 348 | /* same as #define CREATE_NOT_FILE_LE cpu_to_le32(0x00000001) */ |
349 | #define FILE_WRITE_THROUGH_LE cpu_to_le32(0x00000002) | 349 | #define FILE_WRITE_THROUGH_LE cpu_to_le32(0x00000002) |
350 | #define FILE_SEQUENTIAL_ONLY_LE cpu_to_le32(0x00000004) | 350 | #define FILE_SEQUENTIAL_ONLY_LE cpu_to_le32(0x00000004) |
351 | #define FILE_NO_INTERMEDIATE_BUFFERRING_LE cpu_to_le32(0x00000008) | 351 | #define FILE_NO_INTERMEDIATE_BUFFERRING_LE cpu_to_le32(0x00000008) |
352 | #define FILE_SYNCHRONOUS_IO_ALERT_LE cpu_to_le32(0x00000010) | 352 | #define FILE_SYNCHRONOUS_IO_ALERT_LE cpu_to_le32(0x00000010) |
353 | #define FILE_SYNCHRONOUS_IO_NON_ALERT_LE cpu_to_le32(0x00000020) | 353 | #define FILE_SYNCHRONOUS_IO_NON_ALERT_LE cpu_to_le32(0x00000020) |
354 | #define FILE_NON_DIRECTORY_FILE_LE cpu_to_le32(0x00000040) | 354 | #define FILE_NON_DIRECTORY_FILE_LE cpu_to_le32(0x00000040) |
355 | #define FILE_COMPLETE_IF_OPLOCKED_LE cpu_to_le32(0x00000100) | 355 | #define FILE_COMPLETE_IF_OPLOCKED_LE cpu_to_le32(0x00000100) |
356 | #define FILE_NO_EA_KNOWLEDGE_LE cpu_to_le32(0x00000200) | 356 | #define FILE_NO_EA_KNOWLEDGE_LE cpu_to_le32(0x00000200) |
357 | #define FILE_RANDOM_ACCESS_LE cpu_to_le32(0x00000800) | 357 | #define FILE_RANDOM_ACCESS_LE cpu_to_le32(0x00000800) |
358 | #define FILE_DELETE_ON_CLOSE_LE cpu_to_le32(0x00001000) | 358 | #define FILE_DELETE_ON_CLOSE_LE cpu_to_le32(0x00001000) |
359 | #define FILE_OPEN_BY_FILE_ID_LE cpu_to_le32(0x00002000) | 359 | #define FILE_OPEN_BY_FILE_ID_LE cpu_to_le32(0x00002000) |
360 | #define FILE_OPEN_FOR_BACKUP_INTENT_LE cpu_to_le32(0x00004000) | 360 | #define FILE_OPEN_FOR_BACKUP_INTENT_LE cpu_to_le32(0x00004000) |
361 | #define FILE_NO_COMPRESSION_LE cpu_to_le32(0x00008000) | 361 | #define FILE_NO_COMPRESSION_LE cpu_to_le32(0x00008000) |
362 | #define FILE_RESERVE_OPFILTER_LE cpu_to_le32(0x00100000) | 362 | #define FILE_RESERVE_OPFILTER_LE cpu_to_le32(0x00100000) |
363 | #define FILE_OPEN_REPARSE_POINT_LE cpu_to_le32(0x00200000) | 363 | #define FILE_OPEN_REPARSE_POINT_LE cpu_to_le32(0x00200000) |
364 | #define FILE_OPEN_NO_RECALL_LE cpu_to_le32(0x00400000) | 364 | #define FILE_OPEN_NO_RECALL_LE cpu_to_le32(0x00400000) |
365 | #define FILE_OPEN_FOR_FREE_SPACE_QUERY_LE cpu_to_le32(0x00800000) | 365 | #define FILE_OPEN_FOR_FREE_SPACE_QUERY_LE cpu_to_le32(0x00800000) |
366 | 366 | ||
367 | #define FILE_READ_RIGHTS_LE (FILE_READ_DATA_LE | FILE_READ_EA_LE \ | 367 | #define FILE_READ_RIGHTS_LE (FILE_READ_DATA_LE | FILE_READ_EA_LE \ |
368 | | FILE_READ_ATTRIBUTES_LE) | 368 | | FILE_READ_ATTRIBUTES_LE) |
369 | #define FILE_WRITE_RIGHTS_LE (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE \ | 369 | #define FILE_WRITE_RIGHTS_LE (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE \ |
370 | | FILE_WRITE_EA_LE | FILE_WRITE_ATTRIBUTES_LE) | 370 | | FILE_WRITE_EA_LE | FILE_WRITE_ATTRIBUTES_LE) |
371 | #define FILE_EXEC_RIGHTS_LE (FILE_EXECUTE_LE) | 371 | #define FILE_EXEC_RIGHTS_LE (FILE_EXECUTE_LE) |
372 | 372 | ||
373 | /* Impersonation Levels */ | 373 | /* Impersonation Levels */ |
374 | #define IL_ANONYMOUS cpu_to_le32(0x00000000) | 374 | #define IL_ANONYMOUS cpu_to_le32(0x00000000) |
375 | #define IL_IDENTIFICATION cpu_to_le32(0x00000001) | 375 | #define IL_IDENTIFICATION cpu_to_le32(0x00000001) |
376 | #define IL_IMPERSONATION cpu_to_le32(0x00000002) | 376 | #define IL_IMPERSONATION cpu_to_le32(0x00000002) |
377 | #define IL_DELEGATE cpu_to_le32(0x00000003) | 377 | #define IL_DELEGATE cpu_to_le32(0x00000003) |
378 | 378 | ||
379 | /* Create Context Values */ | 379 | /* Create Context Values */ |
380 | #define SMB2_CREATE_EA_BUFFER "ExtA" /* extended attributes */ | 380 | #define SMB2_CREATE_EA_BUFFER "ExtA" /* extended attributes */ |
381 | #define SMB2_CREATE_SD_BUFFER "SecD" /* security descriptor */ | 381 | #define SMB2_CREATE_SD_BUFFER "SecD" /* security descriptor */ |
382 | #define SMB2_CREATE_DURABLE_HANDLE_REQUEST "DHnQ" | 382 | #define SMB2_CREATE_DURABLE_HANDLE_REQUEST "DHnQ" |
383 | #define SMB2_CREATE_DURABLE_HANDLE_RECONNECT "DHnC" | 383 | #define SMB2_CREATE_DURABLE_HANDLE_RECONNECT "DHnC" |
384 | #define SMB2_CREATE_ALLOCATION_SIZE "AlSi" | 384 | #define SMB2_CREATE_ALLOCATION_SIZE "AlSi" |
385 | #define SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST "MxAc" | 385 | #define SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST "MxAc" |
386 | #define SMB2_CREATE_TIMEWARP_REQUEST "TWrp" | 386 | #define SMB2_CREATE_TIMEWARP_REQUEST "TWrp" |
387 | #define SMB2_CREATE_QUERY_ON_DISK_ID "QFid" | 387 | #define SMB2_CREATE_QUERY_ON_DISK_ID "QFid" |
388 | #define SMB2_CREATE_REQUEST_LEASE "RqLs" | 388 | #define SMB2_CREATE_REQUEST_LEASE "RqLs" |
389 | 389 | ||
390 | struct smb2_create_req { | 390 | struct smb2_create_req { |
391 | struct smb2_hdr hdr; | 391 | struct smb2_hdr hdr; |
392 | __le16 StructureSize; /* Must be 57 */ | 392 | __le16 StructureSize; /* Must be 57 */ |
393 | __u8 SecurityFlags; | 393 | __u8 SecurityFlags; |
394 | __u8 RequestedOplockLevel; | 394 | __u8 RequestedOplockLevel; |
395 | __le32 ImpersonationLevel; | 395 | __le32 ImpersonationLevel; |
396 | __le64 SmbCreateFlags; | 396 | __le64 SmbCreateFlags; |
397 | __le64 Reserved; | 397 | __le64 Reserved; |
398 | __le32 DesiredAccess; | 398 | __le32 DesiredAccess; |
399 | __le32 FileAttributes; | 399 | __le32 FileAttributes; |
400 | __le32 ShareAccess; | 400 | __le32 ShareAccess; |
401 | __le32 CreateDisposition; | 401 | __le32 CreateDisposition; |
402 | __le32 CreateOptions; | 402 | __le32 CreateOptions; |
403 | __le16 NameOffset; | 403 | __le16 NameOffset; |
404 | __le16 NameLength; | 404 | __le16 NameLength; |
405 | __le32 CreateContextsOffset; | 405 | __le32 CreateContextsOffset; |
406 | __le32 CreateContextsLength; | 406 | __le32 CreateContextsLength; |
407 | __u8 Buffer[1]; | 407 | __u8 Buffer[1]; |
408 | } __packed; | 408 | } __packed; |
409 | 409 | ||
410 | struct smb2_create_rsp { | 410 | struct smb2_create_rsp { |
411 | struct smb2_hdr hdr; | 411 | struct smb2_hdr hdr; |
412 | __le16 StructureSize; /* Must be 89 */ | 412 | __le16 StructureSize; /* Must be 89 */ |
413 | __u8 OplockLevel; | 413 | __u8 OplockLevel; |
414 | __u8 Reserved; | 414 | __u8 Reserved; |
415 | __le32 CreateAction; | 415 | __le32 CreateAction; |
416 | __le64 CreationTime; | 416 | __le64 CreationTime; |
417 | __le64 LastAccessTime; | 417 | __le64 LastAccessTime; |
418 | __le64 LastWriteTime; | 418 | __le64 LastWriteTime; |
419 | __le64 ChangeTime; | 419 | __le64 ChangeTime; |
420 | __le64 AllocationSize; | 420 | __le64 AllocationSize; |
421 | __le64 EndofFile; | 421 | __le64 EndofFile; |
422 | __le32 FileAttributes; | 422 | __le32 FileAttributes; |
423 | __le32 Reserved2; | 423 | __le32 Reserved2; |
424 | __u64 PersistentFileId; /* opaque endianness */ | 424 | __u64 PersistentFileId; /* opaque endianness */ |
425 | __u64 VolatileFileId; /* opaque endianness */ | 425 | __u64 VolatileFileId; /* opaque endianness */ |
426 | __le32 CreateContextsOffset; | 426 | __le32 CreateContextsOffset; |
427 | __le32 CreateContextsLength; | 427 | __le32 CreateContextsLength; |
428 | __u8 Buffer[1]; | 428 | __u8 Buffer[1]; |
429 | } __packed; | 429 | } __packed; |
430 | 430 | ||
431 | /* Currently defined values for close flags */ | 431 | /* Currently defined values for close flags */ |
432 | #define SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB cpu_to_le16(0x0001) | 432 | #define SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB cpu_to_le16(0x0001) |
433 | struct smb2_close_req { | 433 | struct smb2_close_req { |
434 | struct smb2_hdr hdr; | 434 | struct smb2_hdr hdr; |
435 | __le16 StructureSize; /* Must be 24 */ | 435 | __le16 StructureSize; /* Must be 24 */ |
436 | __le16 Flags; | 436 | __le16 Flags; |
437 | __le32 Reserved; | 437 | __le32 Reserved; |
438 | __u64 PersistentFileId; /* opaque endianness */ | 438 | __u64 PersistentFileId; /* opaque endianness */ |
439 | __u64 VolatileFileId; /* opaque endianness */ | 439 | __u64 VolatileFileId; /* opaque endianness */ |
440 | } __packed; | 440 | } __packed; |
441 | 441 | ||
442 | struct smb2_close_rsp { | 442 | struct smb2_close_rsp { |
443 | struct smb2_hdr hdr; | 443 | struct smb2_hdr hdr; |
444 | __le16 StructureSize; /* 60 */ | 444 | __le16 StructureSize; /* 60 */ |
445 | __le16 Flags; | 445 | __le16 Flags; |
446 | __le32 Reserved; | 446 | __le32 Reserved; |
447 | __le64 CreationTime; | 447 | __le64 CreationTime; |
448 | __le64 LastAccessTime; | 448 | __le64 LastAccessTime; |
449 | __le64 LastWriteTime; | 449 | __le64 LastWriteTime; |
450 | __le64 ChangeTime; | 450 | __le64 ChangeTime; |
451 | __le64 AllocationSize; /* Beginning of FILE_STANDARD_INFO equivalent */ | 451 | __le64 AllocationSize; /* Beginning of FILE_STANDARD_INFO equivalent */ |
452 | __le64 EndOfFile; | 452 | __le64 EndOfFile; |
453 | __le32 Attributes; | 453 | __le32 Attributes; |
454 | } __packed; | 454 | } __packed; |
455 | 455 | ||
456 | struct smb2_flush_req { | ||
457 | struct smb2_hdr hdr; | ||
458 | __le16 StructureSize; /* Must be 24 */ | ||
459 | __le16 Reserved1; | ||
460 | __le32 Reserved2; | ||
461 | __u64 PersistentFileId; /* opaque endianness */ | ||
462 | __u64 VolatileFileId; /* opaque endianness */ | ||
463 | } __packed; | ||
464 | |||
465 | struct smb2_flush_rsp { | ||
466 | struct smb2_hdr hdr; | ||
467 | __le16 StructureSize; | ||
468 | __le16 Reserved; | ||
469 | } __packed; | ||
470 | |||
456 | struct smb2_echo_req { | 471 | struct smb2_echo_req { |
457 | struct smb2_hdr hdr; | 472 | struct smb2_hdr hdr; |
458 | __le16 StructureSize; /* Must be 4 */ | 473 | __le16 StructureSize; /* Must be 4 */ |
459 | __u16 Reserved; | 474 | __u16 Reserved; |
460 | } __packed; | 475 | } __packed; |
461 | 476 | ||
462 | struct smb2_echo_rsp { | 477 | struct smb2_echo_rsp { |
463 | struct smb2_hdr hdr; | 478 | struct smb2_hdr hdr; |
464 | __le16 StructureSize; /* Must be 4 */ | 479 | __le16 StructureSize; /* Must be 4 */ |
465 | __u16 Reserved; | 480 | __u16 Reserved; |
466 | } __packed; | 481 | } __packed; |
467 | 482 | ||
468 | /* Possible InfoType values */ | 483 | /* Possible InfoType values */ |
469 | #define SMB2_O_INFO_FILE 0x01 | 484 | #define SMB2_O_INFO_FILE 0x01 |
470 | #define SMB2_O_INFO_FILESYSTEM 0x02 | 485 | #define SMB2_O_INFO_FILESYSTEM 0x02 |
471 | #define SMB2_O_INFO_SECURITY 0x03 | 486 | #define SMB2_O_INFO_SECURITY 0x03 |
472 | #define SMB2_O_INFO_QUOTA 0x04 | 487 | #define SMB2_O_INFO_QUOTA 0x04 |
473 | 488 | ||
474 | struct smb2_query_info_req { | 489 | struct smb2_query_info_req { |
475 | struct smb2_hdr hdr; | 490 | struct smb2_hdr hdr; |
476 | __le16 StructureSize; /* Must be 41 */ | 491 | __le16 StructureSize; /* Must be 41 */ |
477 | __u8 InfoType; | 492 | __u8 InfoType; |
478 | __u8 FileInfoClass; | 493 | __u8 FileInfoClass; |
479 | __le32 OutputBufferLength; | 494 | __le32 OutputBufferLength; |
480 | __le16 InputBufferOffset; | 495 | __le16 InputBufferOffset; |
481 | __u16 Reserved; | 496 | __u16 Reserved; |
482 | __le32 InputBufferLength; | 497 | __le32 InputBufferLength; |
483 | __le32 AdditionalInformation; | 498 | __le32 AdditionalInformation; |
484 | __le32 Flags; | 499 | __le32 Flags; |
485 | __u64 PersistentFileId; /* opaque endianness */ | 500 | __u64 PersistentFileId; /* opaque endianness */ |
486 | __u64 VolatileFileId; /* opaque endianness */ | 501 | __u64 VolatileFileId; /* opaque endianness */ |
487 | __u8 Buffer[1]; | 502 | __u8 Buffer[1]; |
488 | } __packed; | 503 | } __packed; |
489 | 504 | ||
490 | struct smb2_query_info_rsp { | 505 | struct smb2_query_info_rsp { |
491 | struct smb2_hdr hdr; | 506 | struct smb2_hdr hdr; |
492 | __le16 StructureSize; /* Must be 9 */ | 507 | __le16 StructureSize; /* Must be 9 */ |
493 | __le16 OutputBufferOffset; | 508 | __le16 OutputBufferOffset; |
494 | __le32 OutputBufferLength; | 509 | __le32 OutputBufferLength; |
495 | __u8 Buffer[1]; | 510 | __u8 Buffer[1]; |
496 | } __packed; | 511 | } __packed; |
497 | 512 | ||
498 | /* | 513 | /* |
499 | * PDU infolevel structure definitions | 514 | * PDU infolevel structure definitions |
500 | * BB consider moving to a different header | 515 | * BB consider moving to a different header |
501 | */ | 516 | */ |
502 | 517 | ||
503 | /* partial list of QUERY INFO levels */ | 518 | /* partial list of QUERY INFO levels */ |
504 | #define FILE_DIRECTORY_INFORMATION 1 | 519 | #define FILE_DIRECTORY_INFORMATION 1 |
505 | #define FILE_FULL_DIRECTORY_INFORMATION 2 | 520 | #define FILE_FULL_DIRECTORY_INFORMATION 2 |
506 | #define FILE_BOTH_DIRECTORY_INFORMATION 3 | 521 | #define FILE_BOTH_DIRECTORY_INFORMATION 3 |
507 | #define FILE_BASIC_INFORMATION 4 | 522 | #define FILE_BASIC_INFORMATION 4 |
508 | #define FILE_STANDARD_INFORMATION 5 | 523 | #define FILE_STANDARD_INFORMATION 5 |
509 | #define FILE_INTERNAL_INFORMATION 6 | 524 | #define FILE_INTERNAL_INFORMATION 6 |
510 | #define FILE_EA_INFORMATION 7 | 525 | #define FILE_EA_INFORMATION 7 |
511 | #define FILE_ACCESS_INFORMATION 8 | 526 | #define FILE_ACCESS_INFORMATION 8 |
512 | #define FILE_NAME_INFORMATION 9 | 527 | #define FILE_NAME_INFORMATION 9 |
513 | #define FILE_RENAME_INFORMATION 10 | 528 | #define FILE_RENAME_INFORMATION 10 |
514 | #define FILE_LINK_INFORMATION 11 | 529 | #define FILE_LINK_INFORMATION 11 |
515 | #define FILE_NAMES_INFORMATION 12 | 530 | #define FILE_NAMES_INFORMATION 12 |
516 | #define FILE_DISPOSITION_INFORMATION 13 | 531 | #define FILE_DISPOSITION_INFORMATION 13 |
517 | #define FILE_POSITION_INFORMATION 14 | 532 | #define FILE_POSITION_INFORMATION 14 |
518 | #define FILE_FULL_EA_INFORMATION 15 | 533 | #define FILE_FULL_EA_INFORMATION 15 |
519 | #define FILE_MODE_INFORMATION 16 | 534 | #define FILE_MODE_INFORMATION 16 |
520 | #define FILE_ALIGNMENT_INFORMATION 17 | 535 | #define FILE_ALIGNMENT_INFORMATION 17 |
521 | #define FILE_ALL_INFORMATION 18 | 536 | #define FILE_ALL_INFORMATION 18 |
522 | #define FILE_ALLOCATION_INFORMATION 19 | 537 | #define FILE_ALLOCATION_INFORMATION 19 |
523 | #define FILE_END_OF_FILE_INFORMATION 20 | 538 | #define FILE_END_OF_FILE_INFORMATION 20 |
524 | #define FILE_ALTERNATE_NAME_INFORMATION 21 | 539 | #define FILE_ALTERNATE_NAME_INFORMATION 21 |
525 | #define FILE_STREAM_INFORMATION 22 | 540 | #define FILE_STREAM_INFORMATION 22 |
526 | #define FILE_PIPE_INFORMATION 23 | 541 | #define FILE_PIPE_INFORMATION 23 |
527 | #define FILE_PIPE_LOCAL_INFORMATION 24 | 542 | #define FILE_PIPE_LOCAL_INFORMATION 24 |
528 | #define FILE_PIPE_REMOTE_INFORMATION 25 | 543 | #define FILE_PIPE_REMOTE_INFORMATION 25 |
529 | #define FILE_MAILSLOT_QUERY_INFORMATION 26 | 544 | #define FILE_MAILSLOT_QUERY_INFORMATION 26 |
530 | #define FILE_MAILSLOT_SET_INFORMATION 27 | 545 | #define FILE_MAILSLOT_SET_INFORMATION 27 |
531 | #define FILE_COMPRESSION_INFORMATION 28 | 546 | #define FILE_COMPRESSION_INFORMATION 28 |
532 | #define FILE_OBJECT_ID_INFORMATION 29 | 547 | #define FILE_OBJECT_ID_INFORMATION 29 |
533 | /* Number 30 not defined in documents */ | 548 | /* Number 30 not defined in documents */ |
534 | #define FILE_MOVE_CLUSTER_INFORMATION 31 | 549 | #define FILE_MOVE_CLUSTER_INFORMATION 31 |
535 | #define FILE_QUOTA_INFORMATION 32 | 550 | #define FILE_QUOTA_INFORMATION 32 |
536 | #define FILE_REPARSE_POINT_INFORMATION 33 | 551 | #define FILE_REPARSE_POINT_INFORMATION 33 |
537 | #define FILE_NETWORK_OPEN_INFORMATION 34 | 552 | #define FILE_NETWORK_OPEN_INFORMATION 34 |
538 | #define FILE_ATTRIBUTE_TAG_INFORMATION 35 | 553 | #define FILE_ATTRIBUTE_TAG_INFORMATION 35 |
539 | #define FILE_TRACKING_INFORMATION 36 | 554 | #define FILE_TRACKING_INFORMATION 36 |
540 | #define FILEID_BOTH_DIRECTORY_INFORMATION 37 | 555 | #define FILEID_BOTH_DIRECTORY_INFORMATION 37 |
541 | #define FILEID_FULL_DIRECTORY_INFORMATION 38 | 556 | #define FILEID_FULL_DIRECTORY_INFORMATION 38 |
542 | #define FILE_VALID_DATA_LENGTH_INFORMATION 39 | 557 | #define FILE_VALID_DATA_LENGTH_INFORMATION 39 |
543 | #define FILE_SHORT_NAME_INFORMATION 40 | 558 | #define FILE_SHORT_NAME_INFORMATION 40 |
544 | #define FILE_SFIO_RESERVE_INFORMATION 44 | 559 | #define FILE_SFIO_RESERVE_INFORMATION 44 |
545 | #define FILE_SFIO_VOLUME_INFORMATION 45 | 560 | #define FILE_SFIO_VOLUME_INFORMATION 45 |
546 | #define FILE_HARD_LINK_INFORMATION 46 | 561 | #define FILE_HARD_LINK_INFORMATION 46 |
547 | #define FILE_NORMALIZED_NAME_INFORMATION 48 | 562 | #define FILE_NORMALIZED_NAME_INFORMATION 48 |
548 | #define FILEID_GLOBAL_TX_DIRECTORY_INFORMATION 50 | 563 | #define FILEID_GLOBAL_TX_DIRECTORY_INFORMATION 50 |
549 | #define FILE_STANDARD_LINK_INFORMATION 54 | 564 | #define FILE_STANDARD_LINK_INFORMATION 54 |
550 | 565 | ||
551 | struct smb2_file_internal_info { | 566 | struct smb2_file_internal_info { |
552 | __le64 IndexNumber; | 567 | __le64 IndexNumber; |
553 | } __packed; /* level 6 Query */ | 568 | } __packed; /* level 6 Query */ |
554 | 569 | ||
555 | /* | 570 | /* |
556 | * This level 18, although with struct with same name is different from cifs | 571 | * This level 18, although with struct with same name is different from cifs |
557 | * level 0x107. Level 0x107 has an extra u64 between AccessFlags and | 572 | * level 0x107. Level 0x107 has an extra u64 between AccessFlags and |
558 | * CurrentByteOffset. | 573 | * CurrentByteOffset. |
559 | */ | 574 | */ |
560 | struct smb2_file_all_info { /* data block encoding of response to level 18 */ | 575 | struct smb2_file_all_info { /* data block encoding of response to level 18 */ |
561 | __le64 CreationTime; /* Beginning of FILE_BASIC_INFO equivalent */ | 576 | __le64 CreationTime; /* Beginning of FILE_BASIC_INFO equivalent */ |
562 | __le64 LastAccessTime; | 577 | __le64 LastAccessTime; |
563 | __le64 LastWriteTime; | 578 | __le64 LastWriteTime; |
564 | __le64 ChangeTime; | 579 | __le64 ChangeTime; |
565 | __le32 Attributes; | 580 | __le32 Attributes; |
566 | __u32 Pad1; /* End of FILE_BASIC_INFO_INFO equivalent */ | 581 | __u32 Pad1; /* End of FILE_BASIC_INFO_INFO equivalent */ |
567 | __le64 AllocationSize; /* Beginning of FILE_STANDARD_INFO equivalent */ | 582 | __le64 AllocationSize; /* Beginning of FILE_STANDARD_INFO equivalent */ |
568 | __le64 EndOfFile; /* size ie offset to first free byte in file */ | 583 | __le64 EndOfFile; /* size ie offset to first free byte in file */ |
569 | __le32 NumberOfLinks; /* hard links */ | 584 | __le32 NumberOfLinks; /* hard links */ |
570 | __u8 DeletePending; | 585 | __u8 DeletePending; |
571 | __u8 Directory; | 586 | __u8 Directory; |
572 | __u16 Pad2; /* End of FILE_STANDARD_INFO equivalent */ | 587 | __u16 Pad2; /* End of FILE_STANDARD_INFO equivalent */ |
573 | __le64 IndexNumber; | 588 | __le64 IndexNumber; |
574 | __le32 EASize; | 589 | __le32 EASize; |
575 | __le32 AccessFlags; | 590 | __le32 AccessFlags; |
576 | __le64 CurrentByteOffset; | 591 | __le64 CurrentByteOffset; |
577 | __le32 Mode; | 592 | __le32 Mode; |
578 | __le32 AlignmentRequirement; | 593 | __le32 AlignmentRequirement; |
579 | __le32 FileNameLength; | 594 | __le32 FileNameLength; |
580 | char FileName[1]; | 595 | char FileName[1]; |
581 | } __packed; /* level 18 Query */ | 596 | } __packed; /* level 18 Query */ |
582 | 597 | ||
583 | #endif /* _SMB2PDU_H */ | 598 | #endif /* _SMB2PDU_H */ |
584 | 599 |
fs/cifs/smb2proto.h
1 | /* | 1 | /* |
2 | * fs/cifs/smb2proto.h | 2 | * fs/cifs/smb2proto.h |
3 | * | 3 | * |
4 | * Copyright (c) International Business Machines Corp., 2002, 2011 | 4 | * Copyright (c) International Business Machines Corp., 2002, 2011 |
5 | * Etersoft, 2012 | 5 | * Etersoft, 2012 |
6 | * Author(s): Steve French (sfrench@us.ibm.com) | 6 | * Author(s): Steve French (sfrench@us.ibm.com) |
7 | * Pavel Shilovsky (pshilovsky@samba.org) 2012 | 7 | * Pavel Shilovsky (pshilovsky@samba.org) 2012 |
8 | * | 8 | * |
9 | * This library is free software; you can redistribute it and/or modify | 9 | * This library is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU Lesser General Public License as published | 10 | * it under the terms of the GNU Lesser General Public License as published |
11 | * by the Free Software Foundation; either version 2.1 of the License, or | 11 | * by the Free Software Foundation; either version 2.1 of the License, or |
12 | * (at your option) any later version. | 12 | * (at your option) any later version. |
13 | * | 13 | * |
14 | * This library is distributed in the hope that it will be useful, | 14 | * This library is distributed in the hope that it will be useful, |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
17 | * the GNU Lesser General Public License for more details. | 17 | * the GNU Lesser General Public License for more details. |
18 | * | 18 | * |
19 | * You should have received a copy of the GNU Lesser General Public License | 19 | * You should have received a copy of the GNU Lesser General Public License |
20 | * along with this library; if not, write to the Free Software | 20 | * along with this library; if not, write to the Free Software |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | #ifndef _SMB2PROTO_H | 23 | #ifndef _SMB2PROTO_H |
24 | #define _SMB2PROTO_H | 24 | #define _SMB2PROTO_H |
25 | #include <linux/nls.h> | 25 | #include <linux/nls.h> |
26 | #include <linux/key-type.h> | 26 | #include <linux/key-type.h> |
27 | 27 | ||
28 | struct statfs; | 28 | struct statfs; |
29 | 29 | ||
30 | /* | 30 | /* |
31 | ***************************************************************** | 31 | ***************************************************************** |
32 | * All Prototypes | 32 | * All Prototypes |
33 | ***************************************************************** | 33 | ***************************************************************** |
34 | */ | 34 | */ |
35 | extern int map_smb2_to_linux_error(char *buf, bool log_err); | 35 | extern int map_smb2_to_linux_error(char *buf, bool log_err); |
36 | extern int smb2_check_message(char *buf, unsigned int length); | 36 | extern int smb2_check_message(char *buf, unsigned int length); |
37 | extern unsigned int smb2_calc_size(struct smb2_hdr *hdr); | 37 | extern unsigned int smb2_calc_size(struct smb2_hdr *hdr); |
38 | extern char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr); | 38 | extern char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr); |
39 | extern __le16 *cifs_convert_path_to_utf16(const char *from, | 39 | extern __le16 *cifs_convert_path_to_utf16(const char *from, |
40 | struct cifs_sb_info *cifs_sb); | 40 | struct cifs_sb_info *cifs_sb); |
41 | 41 | ||
42 | extern int smb2_check_receive(struct mid_q_entry *mid, | 42 | extern int smb2_check_receive(struct mid_q_entry *mid, |
43 | struct TCP_Server_Info *server, bool log_error); | 43 | struct TCP_Server_Info *server, bool log_error); |
44 | extern int smb2_setup_request(struct cifs_ses *ses, struct kvec *iov, | 44 | extern int smb2_setup_request(struct cifs_ses *ses, struct kvec *iov, |
45 | unsigned int nvec, struct mid_q_entry **ret_mid); | 45 | unsigned int nvec, struct mid_q_entry **ret_mid); |
46 | extern int smb2_setup_async_request(struct TCP_Server_Info *server, | 46 | extern int smb2_setup_async_request(struct TCP_Server_Info *server, |
47 | struct kvec *iov, unsigned int nvec, | 47 | struct kvec *iov, unsigned int nvec, |
48 | struct mid_q_entry **ret_mid); | 48 | struct mid_q_entry **ret_mid); |
49 | extern void smb2_echo_request(struct work_struct *work); | 49 | extern void smb2_echo_request(struct work_struct *work); |
50 | 50 | ||
51 | extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst, | 51 | extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst, |
52 | struct smb2_file_all_info *src); | 52 | struct smb2_file_all_info *src); |
53 | extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, | 53 | extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, |
54 | struct cifs_sb_info *cifs_sb, | 54 | struct cifs_sb_info *cifs_sb, |
55 | const char *full_path, FILE_ALL_INFO *data, | 55 | const char *full_path, FILE_ALL_INFO *data, |
56 | bool *adjust_tz); | 56 | bool *adjust_tz); |
57 | extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, | 57 | extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, |
58 | const char *name, struct cifs_sb_info *cifs_sb); | 58 | const char *name, struct cifs_sb_info *cifs_sb); |
59 | extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path, | 59 | extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path, |
60 | struct cifs_sb_info *cifs_sb, | 60 | struct cifs_sb_info *cifs_sb, |
61 | struct cifs_tcon *tcon, const unsigned int xid); | 61 | struct cifs_tcon *tcon, const unsigned int xid); |
62 | extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, | 62 | extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, |
63 | const char *name, struct cifs_sb_info *cifs_sb); | 63 | const char *name, struct cifs_sb_info *cifs_sb); |
64 | extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, | 64 | extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, |
65 | const char *name, struct cifs_sb_info *cifs_sb); | 65 | const char *name, struct cifs_sb_info *cifs_sb); |
66 | 66 | ||
67 | extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, | 67 | extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, |
68 | const char *full_path, int disposition, | 68 | const char *full_path, int disposition, |
69 | int desired_access, int create_options, | 69 | int desired_access, int create_options, |
70 | struct cifs_fid *fid, __u32 *oplock, | 70 | struct cifs_fid *fid, __u32 *oplock, |
71 | FILE_ALL_INFO *buf, struct cifs_sb_info *cifs_sb); | 71 | FILE_ALL_INFO *buf, struct cifs_sb_info *cifs_sb); |
72 | 72 | ||
73 | /* | 73 | /* |
74 | * SMB2 Worker functions - most of protocol specific implementation details | 74 | * SMB2 Worker functions - most of protocol specific implementation details |
75 | * are contained within these calls. | 75 | * are contained within these calls. |
76 | */ | 76 | */ |
77 | extern int SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses); | 77 | extern int SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses); |
78 | extern int SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, | 78 | extern int SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, |
79 | const struct nls_table *nls_cp); | 79 | const struct nls_table *nls_cp); |
80 | extern int SMB2_logoff(const unsigned int xid, struct cifs_ses *ses); | 80 | extern int SMB2_logoff(const unsigned int xid, struct cifs_ses *ses); |
81 | extern int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, | 81 | extern int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, |
82 | const char *tree, struct cifs_tcon *tcon, | 82 | const char *tree, struct cifs_tcon *tcon, |
83 | const struct nls_table *); | 83 | const struct nls_table *); |
84 | extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon); | 84 | extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon); |
85 | extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, | 85 | extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, |
86 | __le16 *path, u64 *persistent_fid, u64 *volatile_fid, | 86 | __le16 *path, u64 *persistent_fid, u64 *volatile_fid, |
87 | __u32 desired_access, __u32 create_disposition, | 87 | __u32 desired_access, __u32 create_disposition, |
88 | __u32 file_attributes, __u32 create_options, | 88 | __u32 file_attributes, __u32 create_options, |
89 | struct smb2_file_all_info *buf); | 89 | struct smb2_file_all_info *buf); |
90 | extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, | 90 | extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, |
91 | u64 persistent_file_id, u64 volatile_file_id); | 91 | u64 persistent_file_id, u64 volatile_file_id); |
92 | extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, | ||
93 | u64 persistent_file_id, u64 volatile_file_id); | ||
92 | extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, | 94 | extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, |
93 | u64 persistent_file_id, u64 volatile_file_id, | 95 | u64 persistent_file_id, u64 volatile_file_id, |
94 | struct smb2_file_all_info *data); | 96 | struct smb2_file_all_info *data); |
95 | extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon, | 97 | extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon, |
96 | u64 persistent_fid, u64 volatile_fid, | 98 | u64 persistent_fid, u64 volatile_fid, |
97 | __le64 *uniqueid); | 99 | __le64 *uniqueid); |
98 | extern int SMB2_echo(struct TCP_Server_Info *server); | 100 | extern int SMB2_echo(struct TCP_Server_Info *server); |
99 | 101 | ||
100 | #endif /* _SMB2PROTO_H */ | 102 | #endif /* _SMB2PROTO_H */ |
101 | 103 |