Browse Source

Handle strings as complete units, instead of a byte at a time.

tags/v0.9.3
Michael Brown 17 years ago
parent
commit
67577556a2
2 changed files with 74 additions and 156 deletions
  1. 0
    19
      src/include/gpxe/iscsi.h
  2. 74
    137
      src/net/tcp/iscsi.c

+ 0
- 19
src/include/gpxe/iscsi.h View File

@@ -478,23 +478,6 @@ enum iscsi_rx_state {
478 478
 	ISCSI_RX_DATA_PADDING,
479 479
 };
480 480
 
481
-enum iscsi_string_key_value {
482
-	STRING_KEY = 0,
483
-	STRING_VALUE,
484
-};
485
-
486
-/** iSCSI text string processor state */
487
-struct iscsi_string_state {
488
-	/** Text string key */
489
-	char key[16];
490
-	/** Text string value */
491
-	char value[8];
492
-	/** Key/value flag */
493
-	enum iscsi_string_key_value key_value;
494
-	/** Index into current string */
495
-	unsigned int index;
496
-};
497
-
498 481
 /** An iSCSI session */
499 482
 struct iscsi_session {
500 483
 	/** TCP connection for this session */
@@ -596,8 +579,6 @@ struct iscsi_session {
596 579
 	size_t rx_len;
597 580
 	/** Buffer for received data (not always used) */
598 581
 	void *rx_buffer;
599
-	/** State of strings received during login phase */
600
-	struct iscsi_string_state string;
601 582
 
602 583
 	/** Current SCSI command
603 584
 	 *

+ 74
- 137
src/net/tcp/iscsi.c View File

@@ -509,17 +509,13 @@ static void iscsi_tx_login_request ( struct iscsi_session *iscsi,
509 509
  * Handle iSCSI AuthMethod text value
510 510
  *
511 511
  * @v iscsi		iSCSI session
512
- * @v finished		Value is complete
512
+ * @v value		AuthMethod value
513 513
  */
514 514
 static void iscsi_handle_authmethod_value ( struct iscsi_session *iscsi,
515
-					    int finished ) {
516
-	struct iscsi_string_state *string = &iscsi->string;
517
-
518
-	if ( ! finished )
519
-		return;
515
+					    const char *value ) {
520 516
 
521 517
 	/* If server requests CHAP, send the CHAP_A string */
522
-	if ( strcmp ( string->value, "CHAP" ) == 0 ) {
518
+	if ( strcmp ( value, "CHAP" ) == 0 ) {
523 519
 		DBG ( "iSCSI %p initiating CHAP authentication\n", iscsi );
524 520
 		iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_ALGORITHM;
525 521
 	}
@@ -529,23 +525,19 @@ static void iscsi_handle_authmethod_value ( struct iscsi_session *iscsi,
529 525
  * Handle iSCSI CHAP_A text value
530 526
  *
531 527
  * @v iscsi		iSCSI session
532
- * @v finished		Value is complete
528
+ * @v value		CHAP_A value
533 529
  */
534 530
 static void iscsi_handle_chap_a_value ( struct iscsi_session *iscsi,
535
-					int finished ) {
536
-	struct iscsi_string_state *string = &iscsi->string;
531
+					const char *value ) {
537 532
 	int rc;
538 533
 
539
-	if ( ! finished )
540
-		return;
541
-	
542 534
 	/* We only ever offer "5" (i.e. MD5) as an algorithm, so if
543 535
 	 * the server responds with anything else it is a protocol
544 536
 	 * violation.
545 537
 	 */
546
-	if ( strcmp ( string->value, "5" ) != 0 ) {
538
+	if ( strcmp ( value, "5" ) != 0 ) {
547 539
 		DBG ( "iSCSI %p got invalid CHAP algorithm \"%s\"\n",
548
-		      iscsi, string->value );
540
+		      iscsi, value );
549 541
 	}
550 542
 
551 543
 	/* Prepare for CHAP with MD5 */
@@ -559,22 +551,18 @@ static void iscsi_handle_chap_a_value ( struct iscsi_session *iscsi,
559 551
  * Handle iSCSI CHAP_I text value
560 552
  *
561 553
  * @v iscsi		iSCSI session
562
- * @v finished		Value is complete
554
+ * @v value		CHAP_I value
563 555
  */
564 556
 static void iscsi_handle_chap_i_value ( struct iscsi_session *iscsi,
565
-					int finished ) {
566
-	struct iscsi_string_state *string = &iscsi->string;
557
+					const char *value ) {
567 558
 	unsigned int identifier;
568 559
 	char *endp;
569 560
 
570
-	if ( ! finished )
571
-		return;
572
-
573 561
 	/* The CHAP identifier is an integer value */
574
-	identifier = strtoul ( string->value, &endp, 0 );
562
+	identifier = strtoul ( value, &endp, 0 );
575 563
 	if ( *endp != '\0' ) {
576 564
 		DBG ( "iSCSI %p saw invalid CHAP identifier \"%s\"\n",
577
-		      iscsi, string->value );
565
+		      iscsi, value );
578 566
 	}
579 567
 
580 568
 	/* Identifier and secret are the first two components of the
@@ -589,159 +577,108 @@ static void iscsi_handle_chap_i_value ( struct iscsi_session *iscsi,
589 577
  * Handle iSCSI CHAP_C text value
590 578
  *
591 579
  * @v iscsi		iSCSI session
592
- * @v finished		Value is complete
580
+ * @v value		CHAP_C value
593 581
  */
594 582
 static void iscsi_handle_chap_c_value ( struct iscsi_session *iscsi,
595
-					int finished ) {
596
-	struct iscsi_string_state *string = &iscsi->string;
597
-	uint8_t byte;
583
+					const char *value ) {
584
+	char buf[3];
598 585
 	char *endp;
586
+	uint8_t byte;
599 587
 
600
-	/* Once the whole challenge is received, calculate the response */
601
-	if ( finished ) {
602
-		DBG ( "iSCSI %p sending CHAP response\n", iscsi );
603
-		chap_respond ( &iscsi->chap );
604
-		iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_RESPONSE;
605
-		return;
588
+	/* Check and strip leading "0x" */
589
+	if ( ( value[0] != '0' ) || ( value[1] != 'x' ) ) {
590
+		DBG ( "iSCSI %p saw invalid CHAP challenge \"%s\"\n",
591
+		      iscsi, value );
606 592
 	}
607
-
608
-	/* Wait until a complete octet ("0x??") is received */
609
-	if ( string->index != 4 )
610
-		return;
611
-
612
-	/* Add octet to challenge */
613
-	byte = strtoul ( string->value, &endp, 0 );
614
-	if ( *endp != '\0' ) {
615
-		DBG ( "iSCSI %p saw invalid CHAP challenge portion \"%s\"\n",
616
-		      iscsi, string->value );
593
+	value += 2;
594
+
595
+	/* Process challenge an octet at a time */
596
+	for ( ; ( value[0] && value[1] ) ; value += 2 ) {
597
+		memcpy ( buf, value, 2 );
598
+		buf[3] = 0;
599
+		byte = strtoul ( buf, &endp, 16 );
600
+		if ( *endp != '\0' ) {
601
+			DBG ( "iSCSI %p saw invalid CHAP challenge byte "
602
+			      "\"%s\"\n", iscsi, buf );
603
+		}
604
+		chap_update ( &iscsi->chap, &byte, sizeof ( byte ) );
617 605
 	}
618
-	chap_update ( &iscsi->chap, &byte, sizeof ( byte ) );
619 606
 
620
-	/* Reset value back to "0x" */
621
-	string->index = 2;
607
+	/* Build CHAP response */
608
+	DBG ( "iSCSI %p sending CHAP response\n", iscsi );
609
+	chap_respond ( &iscsi->chap );
610
+	iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_RESPONSE;
622 611
 }
623 612
 
624 613
 /** An iSCSI text string that we want to handle */
625 614
 struct iscsi_string_type {
626
-	/** String name
615
+	/** String key
627 616
 	 *
628
-	 * This is the portion before the "=" sign,
629
-	 * e.g. InitiatorName, CHAP_A, etc.
617
+	 * This is the portion up to and including the "=" sign,
618
+	 * e.g. "InitiatorName=", "CHAP_A=", etc.
630 619
 	 */
631
-	const char *name;
620
+	const char *key;
632 621
 	/** Handle iSCSI string value
633 622
 	 *
634 623
 	 * @v iscsi		iSCSI session
635
-	 * @v finished		Value is complete
636
-	 *
637
-	 * Process the string in @c iscsi->string.  This method will
638
-	 * be called once for each character in the string, and once
639
-	 * again at the end of the string.
624
+	 * @v value		iSCSI string value
640 625
 	 */
641
-	void ( * handle_value ) ( struct iscsi_session *iscsi, int finished );
626
+	void ( * handle_value ) ( struct iscsi_session *iscsi,
627
+				  const char *value );
642 628
 };
643 629
 
644 630
 /** iSCSI text strings that we want to handle */
645 631
 struct iscsi_string_type iscsi_string_types[] = {
646
-	{ "AuthMethod", iscsi_handle_authmethod_value },
647
-	{ "CHAP_A", iscsi_handle_chap_a_value },
648
-	{ "CHAP_I", iscsi_handle_chap_i_value },
649
-	{ "CHAP_C", iscsi_handle_chap_c_value },
632
+	{ "AuthMethod=", iscsi_handle_authmethod_value },
633
+	{ "CHAP_A=", iscsi_handle_chap_a_value },
634
+	{ "CHAP_I=", iscsi_handle_chap_i_value },
635
+	{ "CHAP_C=", iscsi_handle_chap_c_value },
650 636
 	{ NULL, NULL }
651 637
 };
652 638
 
653 639
 /**
654
- * Handle iSCSI string value
640
+ * Handle iSCSI string
655 641
  *
656 642
  * @v iscsi		iSCSI session
657
- * @v finished		Value is complete
658
- *
659
- * Process the string in @c iscsi->string.  This function will be
660
- * called once for each character in the string, and once again at the
661
- * end of the string.
643
+ * @v string		iSCSI string (in "key=value" format)
662 644
  */
663
-static void iscsi_handle_string_value ( struct iscsi_session *iscsi,
664
-					int finished ) {
665
-	struct iscsi_string_state *string = &iscsi->string;
666
-	struct iscsi_string_type *type = iscsi_string_types;
667
-
668
-	assert ( string->key_value == STRING_VALUE );
669
-
670
-	for ( type = iscsi_string_types ; type->name ; type++ ) {
671
-		if ( strcmp ( type->name, string->key ) == 0 ) {
672
-			if ( string->index <= 1 ) {
673
-				DBG ( "iSCSI %p handling key \"%s\"\n",
674
-				      iscsi, string->key );
675
-			}
676
-			type->handle_value ( iscsi, finished );
645
+static void iscsi_handle_string ( struct iscsi_session *iscsi,
646
+				  const char *string ) {
647
+	struct iscsi_string_type *type;
648
+	size_t key_len;
649
+
650
+	for ( type = iscsi_string_types ; type->key ; type++ ) {
651
+		key_len = strlen ( type->key );
652
+		if ( strncmp ( string, type->key, key_len ) == 0 ) {
653
+			DBG ( "iSCSI %p handling %s\n", iscsi, string );
654
+			type->handle_value ( iscsi, ( string + key_len ) );
677 655
 			return;
678 656
 		}
679 657
 	}
680
-	if ( string->index <= 1 )
681
-		DBG ( "iSCSI %p ignoring key \"%s\"\n", iscsi, string->key );
658
+	DBG ( "iSCSI %p ignoring %s\n", iscsi, string );
682 659
 }
683 660
 
684 661
 /**
685
- * Handle byte of an iSCSI string
662
+ * Handle iSCSI strings
686 663
  *
687 664
  * @v iscsi		iSCSI session
688
- * @v byte		Byte of string
689
- *
690
- * Strings are handled a byte at a time in order to simplify the
691
- * logic, and to ensure that we can provably cope with the TCP packet
692
- * boundaries coming at inconvenient points, such as halfway through a
693
- * string.
665
+ * @v string		iSCSI string buffer
666
+ * @v len		Length of string buffer
694 667
  */
695
-static void iscsi_handle_string_byte ( struct iscsi_session *iscsi,
696
-				       uint8_t byte ) {
697
-	struct iscsi_string_state *string = &iscsi->string;
698
-
699
-	if ( string->key_value == STRING_KEY ) {
700
-		switch ( byte ) {
701
-		case '\0':
702
-			/* Premature termination */
703
-			DBG ( "iSCSI %p premature key termination on \"%s\"\n",
704
-			      iscsi, string->key );
705
-			string->index = 0;
706
-			break;
707
-		case '=':
708
-			/* End of key */
709
-			string->key_value = STRING_VALUE;
710
-			string->index = 0;
711
-			break;
712
-		default:
713
-			/* Part of key */
714
-			if ( string->index < ( sizeof ( string->key ) - 1 ) ) {
715
-				string->key[string->index++] = byte;
716
-				string->key[string->index] = '\0';
717
-			}
718
-			break;
719
-		}
720
-	} else {
721
-		switch ( byte ) {
722
-		case '\0':
723
-			/* End of string */
724
-			iscsi_handle_string_value ( iscsi, 1 );
725
-			string->key_value = STRING_KEY;
726
-			string->index = 0;
727
-			break;
728
-		default:
729
-			/* Part of value */
730
-			if ( string->index < ( sizeof ( string->value ) - 1 )){
731
-				string->value[string->index++] = byte;
732
-				string->value[string->index] = '\0';
733
-				iscsi_handle_string_value ( iscsi, 0 );
734
-			}
735
-			break;
736
-		}
737
-	}
738
-}
739
-
740 668
 static void iscsi_handle_strings ( struct iscsi_session *iscsi,
741 669
 				   const char *strings, size_t len ) {
742
-	for ( ; len-- ; strings++ ) {
743
-		iscsi_handle_string_byte ( iscsi,
744
-					   * ( ( uint8_t * ) strings ) );
670
+	size_t string_len;
671
+
672
+	/* Handle each string in turn, taking care not to overrun the
673
+	 * data buffer in case of badly-terminated data.
674
+	 */
675
+	while ( 1 ) {
676
+		string_len = ( strnlen ( strings, len ) + 1 );
677
+		if ( string_len > len )
678
+			break;
679
+		iscsi_handle_string ( iscsi, strings );
680
+		strings += string_len;
681
+		len -= string_len;
745 682
 	}
746 683
 }
747 684
 

Loading…
Cancel
Save