aboutsummaryrefslogtreecommitdiffstats
path: root/fs
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
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')
-rw-r--r--fs/cifs/cifsglob.h3
-rw-r--r--fs/cifs/connect.c161
-rw-r--r--fs/cifs/smb1ops.c170
3 files changed, 175 insertions, 159 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 6df0cbe1cbc9..2aac4e5fb334 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -187,6 +187,9 @@ struct smb_version_operations {
187 /* verify the message */ 187 /* verify the message */
188 int (*check_message)(char *, unsigned int); 188 int (*check_message)(char *, unsigned int);
189 bool (*is_oplock_break)(char *, struct TCP_Server_Info *); 189 bool (*is_oplock_break)(char *, struct TCP_Server_Info *);
190 /* process transaction2 response */
191 bool (*check_trans2)(struct mid_q_entry *, struct TCP_Server_Info *,
192 char *, int);
190}; 193};
191 194
192struct smb_version_values { 195struct smb_version_values {
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index a675b7f47d63..6d846e7624d0 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -395,143 +395,6 @@ cifs_reconnect(struct TCP_Server_Info *server)
395 return rc; 395 return rc;
396} 396}
397 397
398/*
399 return codes:
400 0 not a transact2, or all data present
401 >0 transact2 with that much data missing
402 -EINVAL = invalid transact2
403
404 */
405static int check2ndT2(char *buf)
406{
407 struct smb_hdr *pSMB = (struct smb_hdr *)buf;
408 struct smb_t2_rsp *pSMBt;
409 int remaining;
410 __u16 total_data_size, data_in_this_rsp;
411
412 if (pSMB->Command != SMB_COM_TRANSACTION2)
413 return 0;
414
415 /* check for plausible wct, bcc and t2 data and parm sizes */
416 /* check for parm and data offset going beyond end of smb */
417 if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
418 cFYI(1, "invalid transact2 word count");
419 return -EINVAL;
420 }
421
422 pSMBt = (struct smb_t2_rsp *)pSMB;
423
424 total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
425 data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
426
427 if (total_data_size == data_in_this_rsp)
428 return 0;
429 else if (total_data_size < data_in_this_rsp) {
430 cFYI(1, "total data %d smaller than data in frame %d",
431 total_data_size, data_in_this_rsp);
432 return -EINVAL;
433 }
434
435 remaining = total_data_size - data_in_this_rsp;
436
437 cFYI(1, "missing %d bytes from transact2, check next response",
438 remaining);
439 if (total_data_size > CIFSMaxBufSize) {
440 cERROR(1, "TotalDataSize %d is over maximum buffer %d",
441 total_data_size, CIFSMaxBufSize);
442 return -EINVAL;
443 }
444 return remaining;
445}
446
447static int coalesce_t2(char *second_buf, struct smb_hdr *target_hdr)
448{
449 struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)second_buf;
450 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)target_hdr;
451 char *data_area_of_tgt;
452 char *data_area_of_src;
453 int remaining;
454 unsigned int byte_count, total_in_tgt;
455 __u16 tgt_total_cnt, src_total_cnt, total_in_src;
456
457 src_total_cnt = get_unaligned_le16(&pSMBs->t2_rsp.TotalDataCount);
458 tgt_total_cnt = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
459
460 if (tgt_total_cnt != src_total_cnt)
461 cFYI(1, "total data count of primary and secondary t2 differ "
462 "source=%hu target=%hu", src_total_cnt, tgt_total_cnt);
463
464 total_in_tgt = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
465
466 remaining = tgt_total_cnt - total_in_tgt;
467
468 if (remaining < 0) {
469 cFYI(1, "Server sent too much data. tgt_total_cnt=%hu "
470 "total_in_tgt=%hu", tgt_total_cnt, total_in_tgt);
471 return -EPROTO;
472 }
473
474 if (remaining == 0) {
475 /* nothing to do, ignore */
476 cFYI(1, "no more data remains");
477 return 0;
478 }
479
480 total_in_src = get_unaligned_le16(&pSMBs->t2_rsp.DataCount);
481 if (remaining < total_in_src)
482 cFYI(1, "transact2 2nd response contains too much data");
483
484 /* find end of first SMB data area */
485 data_area_of_tgt = (char *)&pSMBt->hdr.Protocol +
486 get_unaligned_le16(&pSMBt->t2_rsp.DataOffset);
487
488 /* validate target area */
489 data_area_of_src = (char *)&pSMBs->hdr.Protocol +
490 get_unaligned_le16(&pSMBs->t2_rsp.DataOffset);
491
492 data_area_of_tgt += total_in_tgt;
493
494 total_in_tgt += total_in_src;
495 /* is the result too big for the field? */
496 if (total_in_tgt > USHRT_MAX) {
497 cFYI(1, "coalesced DataCount too large (%u)", total_in_tgt);
498 return -EPROTO;
499 }
500 put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount);
501
502 /* fix up the BCC */
503 byte_count = get_bcc(target_hdr);
504 byte_count += total_in_src;
505 /* is the result too big for the field? */
506 if (byte_count > USHRT_MAX) {
507 cFYI(1, "coalesced BCC too large (%u)", byte_count);
508 return -EPROTO;
509 }
510 put_bcc(byte_count, target_hdr);
511
512 byte_count = be32_to_cpu(target_hdr->smb_buf_length);
513 byte_count += total_in_src;
514 /* don't allow buffer to overflow */
515 if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
516 cFYI(1, "coalesced BCC exceeds buffer size (%u)", byte_count);
517 return -ENOBUFS;
518 }
519 target_hdr->smb_buf_length = cpu_to_be32(byte_count);
520
521 /* copy second buffer into end of first buffer */
522 memcpy(data_area_of_tgt, data_area_of_src, total_in_src);
523
524 if (remaining != total_in_src) {
525 /* more responses to go */
526 cFYI(1, "waiting for more secondary responses");
527 return 1;
528 }
529
530 /* we are done */
531 cFYI(1, "found the last secondary response");
532 return 0;
533}
534
535static void 398static void
536cifs_echo_request(struct work_struct *work) 399cifs_echo_request(struct work_struct *work)
537{ 400{
@@ -804,29 +667,9 @@ static void
804handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server, 667handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
805 char *buf, int malformed) 668 char *buf, int malformed)
806{ 669{
807 if (malformed == 0 && check2ndT2(buf) > 0) { 670 if (server->ops->check_trans2 &&
808 mid->multiRsp = true; 671 server->ops->check_trans2(mid, server, buf, malformed))
809 if (mid->resp_buf) {
810 /* merge response - fix up 1st*/
811 malformed = coalesce_t2(buf, mid->resp_buf);
812 if (malformed > 0)
813 return;
814
815 /* All parts received or packet is malformed. */
816 mid->multiEnd = true;
817 return dequeue_mid(mid, malformed);
818 }
819 if (!server->large_buf) {
820 /*FIXME: switch to already allocated largebuf?*/
821 cERROR(1, "1st trans2 resp needs bigbuf");
822 } else {
823 /* Have first buffer */
824 mid->resp_buf = buf;
825 mid->large_buf = true;
826 server->bigbuf = NULL;
827 }
828 return; 672 return;
829 }
830 mid->resp_buf = buf; 673 mid->resp_buf = buf;
831 mid->large_buf = server->large_buf; 674 mid->large_buf = server->large_buf;
832 /* Was previous buf put in mpx struct for multi-rsp? */ 675 /* Was previous buf put in mpx struct for multi-rsp? */
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 = {