aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/smb1ops.c
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilovsky@samba.org>2012-05-23 06:31:03 -0400
committerSteve French <smfrench@gmail.com>2012-07-24 01:32:25 -0400
commit316cf94a910f6f93d43cc574359d163ccae098a3 (patch)
tree8a3b54eab2154f843a7040ac40920d4c17600415 /fs/cifs/smb1ops.c
parent7659624ffb550d69c87f9af9ae63e717daa874bd (diff)
CIFS: Move trans2 processing to ops struct
Reviewed-by: Jeff Layton <jlayton@samba.org> Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs/smb1ops.c')
-rw-r--r--fs/cifs/smb1ops.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 6dec38f5522d..28359e789fff 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -213,6 +213,175 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
213 return mid; 213 return mid;
214} 214}
215 215
216/*
217 return codes:
218 0 not a transact2, or all data present
219 >0 transact2 with that much data missing
220 -EINVAL invalid transact2
221 */
222static int
223check2ndT2(char *buf)
224{
225 struct smb_hdr *pSMB = (struct smb_hdr *)buf;
226 struct smb_t2_rsp *pSMBt;
227 int remaining;
228 __u16 total_data_size, data_in_this_rsp;
229
230 if (pSMB->Command != SMB_COM_TRANSACTION2)
231 return 0;
232
233 /* check for plausible wct, bcc and t2 data and parm sizes */
234 /* check for parm and data offset going beyond end of smb */
235 if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
236 cFYI(1, "invalid transact2 word count");
237 return -EINVAL;
238 }
239
240 pSMBt = (struct smb_t2_rsp *)pSMB;
241
242 total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
243 data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
244
245 if (total_data_size == data_in_this_rsp)
246 return 0;
247 else if (total_data_size < data_in_this_rsp) {
248 cFYI(1, "total data %d smaller than data in frame %d",
249 total_data_size, data_in_this_rsp);
250 return -EINVAL;
251 }
252
253 remaining = total_data_size - data_in_this_rsp;
254
255 cFYI(1, "missing %d bytes from transact2, check next response",
256 remaining);
257 if (total_data_size > CIFSMaxBufSize) {
258 cERROR(1, "TotalDataSize %d is over maximum buffer %d",
259 total_data_size, CIFSMaxBufSize);
260 return -EINVAL;
261 }
262 return remaining;
263}
264
265static int
266coalesce_t2(char *second_buf, struct smb_hdr *target_hdr)
267{
268 struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)second_buf;
269 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)target_hdr;
270 char *data_area_of_tgt;
271 char *data_area_of_src;
272 int remaining;
273 unsigned int byte_count, total_in_tgt;
274 __u16 tgt_total_cnt, src_total_cnt, total_in_src;
275
276 src_total_cnt = get_unaligned_le16(&pSMBs->t2_rsp.TotalDataCount);
277 tgt_total_cnt = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
278
279 if (tgt_total_cnt != src_total_cnt)
280 cFYI(1, "total data count of primary and secondary t2 differ "
281 "source=%hu target=%hu", src_total_cnt, tgt_total_cnt);
282
283 total_in_tgt = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
284
285 remaining = tgt_total_cnt - total_in_tgt;
286
287 if (remaining < 0) {
288 cFYI(1, "Server sent too much data. tgt_total_cnt=%hu "
289 "total_in_tgt=%hu", tgt_total_cnt, total_in_tgt);
290 return -EPROTO;
291 }
292
293 if (remaining == 0) {
294 /* nothing to do, ignore */
295 cFYI(1, "no more data remains");
296 return 0;
297 }
298
299 total_in_src = get_unaligned_le16(&pSMBs->t2_rsp.DataCount);
300 if (remaining < total_in_src)
301 cFYI(1, "transact2 2nd response contains too much data");
302
303 /* find end of first SMB data area */
304 data_area_of_tgt = (char *)&pSMBt->hdr.Protocol +
305 get_unaligned_le16(&pSMBt->t2_rsp.DataOffset);
306
307 /* validate target area */
308 data_area_of_src = (char *)&pSMBs->hdr.Protocol +
309 get_unaligned_le16(&pSMBs->t2_rsp.DataOffset);
310
311 data_area_of_tgt += total_in_tgt;
312
313 total_in_tgt += total_in_src;
314 /* is the result too big for the field? */
315 if (total_in_tgt > USHRT_MAX) {
316 cFYI(1, "coalesced DataCount too large (%u)", total_in_tgt);
317 return -EPROTO;
318 }
319 put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount);
320
321 /* fix up the BCC */
322 byte_count = get_bcc(target_hdr);
323 byte_count += total_in_src;
324 /* is the result too big for the field? */
325 if (byte_count > USHRT_MAX) {
326 cFYI(1, "coalesced BCC too large (%u)", byte_count);
327 return -EPROTO;
328 }
329 put_bcc(byte_count, target_hdr);
330
331 byte_count = be32_to_cpu(target_hdr->smb_buf_length);
332 byte_count += total_in_src;
333 /* don't allow buffer to overflow */
334 if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
335 cFYI(1, "coalesced BCC exceeds buffer size (%u)", byte_count);
336 return -ENOBUFS;
337 }
338 target_hdr->smb_buf_length = cpu_to_be32(byte_count);
339
340 /* copy second buffer into end of first buffer */
341 memcpy(data_area_of_tgt, data_area_of_src, total_in_src);
342
343 if (remaining != total_in_src) {
344 /* more responses to go */
345 cFYI(1, "waiting for more secondary responses");
346 return 1;
347 }
348
349 /* we are done */
350 cFYI(1, "found the last secondary response");
351 return 0;
352}
353
354static bool
355cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server,
356 char *buf, int malformed)
357{
358 if (malformed)
359 return false;
360 if (check2ndT2(buf) <= 0)
361 return false;
362 mid->multiRsp = true;
363 if (mid->resp_buf) {
364 /* merge response - fix up 1st*/
365 malformed = coalesce_t2(buf, mid->resp_buf);
366 if (malformed > 0)
367 return true;
368 /* All parts received or packet is malformed. */
369 mid->multiEnd = true;
370 dequeue_mid(mid, malformed);
371 return true;
372 }
373 if (!server->large_buf) {
374 /*FIXME: switch to already allocated largebuf?*/
375 cERROR(1, "1st trans2 resp needs bigbuf");
376 } else {
377 /* Have first buffer */
378 mid->resp_buf = buf;
379 mid->large_buf = true;
380 server->bigbuf = NULL;
381 }
382 return true;
383}
384
216struct smb_version_operations smb1_operations = { 385struct smb_version_operations smb1_operations = {
217 .send_cancel = send_nt_cancel, 386 .send_cancel = send_nt_cancel,
218 .compare_fids = cifs_compare_fids, 387 .compare_fids = cifs_compare_fids,
@@ -229,6 +398,7 @@ struct smb_version_operations smb1_operations = {
229 .check_message = checkSMB, 398 .check_message = checkSMB,
230 .dump_detail = cifs_dump_detail, 399 .dump_detail = cifs_dump_detail,
231 .is_oplock_break = is_valid_oplock_break, 400 .is_oplock_break = is_valid_oplock_break,
401 .check_trans2 = cifs_check_trans2,
232}; 402};
233 403
234struct smb_version_values smb1_values = { 404struct smb_version_values smb1_values = {