Переглянути джерело

[ipv6] Allow settings to comprise arbitrary subsets of NDP options

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 8 роки тому
джерело
коміт
ee54ab5be6
1 змінених файлів з 67 додано та 35 видалено
  1. 67
    35
      src/net/ndp.c

+ 67
- 35
src/net/ndp.c Переглянути файл

@@ -636,7 +636,7 @@ struct ndp_settings {
636 636
 	/** Length of NDP options */
637 637
 	size_t len;
638 638
 	/** NDP options */
639
-	union ndp_option option[0];
639
+	union ndp_option options[0];
640 640
 };
641 641
 
642 642
 /** NDP settings scope */
@@ -647,9 +647,11 @@ static const struct settings_scope ndp_settings_scope;
647 647
  *
648 648
  * @v type		NDP option type
649 649
  * @v offset		Starting offset of data
650
+ * @v len		Length of data (or 0 to use all remaining data)
650 651
  * @ret tag		NDP tag
651 652
  */
652
-#define NDP_TAG( type, offset )	( ( (offset) << 8 ) | (type) )
653
+#define NDP_TAG( type, offset, len ) \
654
+	( ( (len) << 16 ) | ( (offset) << 8 ) | (type) )
653 655
 
654 656
 /**
655 657
  * Extract NDP tag type
@@ -657,7 +659,7 @@ static const struct settings_scope ndp_settings_scope;
657 659
  * @v tag		NDP tag
658 660
  * @ret type		NDP option type
659 661
  */
660
-#define NDP_TAG_TYPE( tag ) ( (tag) & 0xff )
662
+#define NDP_TAG_TYPE( tag ) ( ( (tag) >> 0 ) & 0xff )
661 663
 
662 664
 /**
663 665
  * Extract NDP tag offset
@@ -665,7 +667,23 @@ static const struct settings_scope ndp_settings_scope;
665 667
  * @v tag		NDP tag
666 668
  * @ret offset		Starting offset of data
667 669
  */
668
-#define NDP_TAG_OFFSET( tag ) ( (tag) >> 8 )
670
+#define NDP_TAG_OFFSET( tag ) ( ( (tag) >> 8 ) & 0xff )
671
+
672
+/**
673
+ * Extract NDP tag length
674
+ *
675
+ * @v tag		NDP tag
676
+ * @ret len		Length of data (or 0 to use all remaining data)
677
+ */
678
+#define NDP_TAG_LEN( tag ) ( ( (tag) >> 16 ) & 0xff )
679
+
680
+/**
681
+ * Extract NDP tag instance
682
+ *
683
+ * @v tag		NDP tag
684
+ * @ret instance	Instance
685
+ */
686
+#define NDP_TAG_INSTANCE( tag ) ( ( (tag) >> 24 ) & 0xff )
669 687
 
670 688
 /**
671 689
  * Check applicability of NDP setting
@@ -698,44 +716,58 @@ static int ndp_fetch ( struct settings *settings,
698 716
 		container_of ( settings->parent, struct net_device,
699 717
 			       settings.settings );
700 718
 	union ndp_option *option;
701
-	unsigned int type = NDP_TAG_TYPE ( setting->tag );
702
-	unsigned int offset = NDP_TAG_OFFSET ( setting->tag );
703
-	size_t remaining;
719
+	unsigned int tag_type;
720
+	unsigned int tag_offset;
721
+	unsigned int tag_len;
722
+	unsigned int tag_instance;
723
+	size_t offset;
704 724
 	size_t option_len;
705
-	size_t payload_len;
725
+	void *option_data;
726
+
727
+	/* Parse setting tag */
728
+	tag_type = NDP_TAG_TYPE ( setting->tag );
729
+	tag_offset = NDP_TAG_OFFSET ( setting->tag );
730
+	tag_len = NDP_TAG_LEN ( setting->tag );
731
+	tag_instance = NDP_TAG_INSTANCE ( setting->tag );
706 732
 
707 733
 	/* Scan through NDP options for requested type.  We can assume
708 734
 	 * that the options are well-formed, otherwise they would have
709 735
 	 * been rejected prior to being stored.
710 736
 	 */
711
-	option = ndpset->option;
712
-	remaining = ndpset->len;
713
-	while ( remaining ) {
737
+	for ( offset = 0 ; offset < ndpset->len ; offset += option_len ) {
714 738
 
715 739
 		/* Calculate option length */
740
+		option = ( ( ( void * ) ndpset->options ) + offset );
716 741
 		option_len = ( option->header.blocks * NDP_OPTION_BLKSZ );
717 742
 
718
-		/* If this is the requested option, return it */
719
-		if ( option->header.type == type ) {
720
-
721
-			/* Sanity check */
722
-			if ( offset > option_len ) {
723
-				DBGC ( netdev, "NDP %s option %d too short\n",
724
-				       netdev->name, type );
725
-				return -EINVAL;
726
-			}
727
-			payload_len = ( option_len - offset );
728
-
729
-			/* Copy data to output buffer */
730
-			if ( len > payload_len )
731
-				len = payload_len;
732
-			memcpy ( data, ( ( ( void * ) option ) + offset ), len);
733
-			return payload_len;
743
+		/* Skip options that do not match this tag */
744
+		if ( option->header.type != tag_type )
745
+			continue;
746
+
747
+		/* Skip previous instances of this option */
748
+		if ( tag_instance-- != 0 )
749
+			continue;
750
+
751
+		/* Sanity check */
752
+		if ( ( tag_offset + tag_len ) > option_len ) {
753
+			DBGC ( netdev, "NDP %s option %d too short\n",
754
+			       netdev->name, tag_type );
755
+			return -EINVAL;
734 756
 		}
757
+		if ( ! tag_len )
758
+			tag_len = ( option_len - tag_offset );
759
+		option_data = ( ( ( void * ) option ) + tag_offset );
735 760
 
736
-		/* Move to next option */
737
-		option = ( ( ( void * ) option ) + option_len );
738
-		remaining -= option_len;
761
+		/* Copy data to output buffer */
762
+		if ( len > tag_len )
763
+			len = tag_len;
764
+		memcpy ( data, option_data, len );
765
+
766
+		/* Default to hex if no type is specified */
767
+		if ( ! setting->type )
768
+			setting->type = &setting_type_hex;
769
+
770
+		return tag_len;
739 771
 	}
740 772
 
741 773
 	return -ENOENT;
@@ -751,12 +783,12 @@ static struct settings_operations ndp_settings_operations = {
751 783
  * Register NDP settings
752 784
  *
753 785
  * @v netdev		Network device
754
- * @v option		NDP options
786
+ * @v options		NDP options
755 787
  * @v len		Length of options
756 788
  * @ret rc		Return status code
757 789
  */
758 790
 static int ndp_register_settings ( struct net_device *netdev,
759
-				   union ndp_option *option, size_t len ) {
791
+				   union ndp_option *options, size_t len ) {
760 792
 	struct settings *parent = netdev_settings ( netdev );
761 793
 	struct ndp_settings *ndpset;
762 794
 	int rc;
@@ -771,7 +803,7 @@ static int ndp_register_settings ( struct net_device *netdev,
771 803
 	settings_init ( &ndpset->settings, &ndp_settings_operations,
772 804
 			&ndpset->refcnt, &ndp_settings_scope );
773 805
 	ndpset->len = len;
774
-	memcpy ( ndpset->option, option, len );
806
+	memcpy ( ndpset->options, options, len );
775 807
 
776 808
 	/* Register settings */
777 809
 	if ( ( rc = register_settings ( &ndpset->settings, parent,
@@ -789,7 +821,7 @@ const struct setting ndp_dns6_setting __setting ( SETTING_IP6_EXTRA, dns6 ) = {
789 821
 	.name = "dns6",
790 822
 	.description = "DNS server",
791 823
 	.tag = NDP_TAG ( NDP_OPT_RDNSS,
792
-			 offsetof ( struct ndp_rdnss_option, addresses ) ),
824
+			 offsetof ( struct ndp_rdnss_option, addresses ), 0 ),
793 825
 	.type = &setting_type_ipv6,
794 826
 	.scope = &ndp_settings_scope,
795 827
 };
@@ -799,7 +831,7 @@ const struct setting ndp_dnssl_setting __setting ( SETTING_IP_EXTRA, dnssl ) = {
799 831
 	.name = "dnssl",
800 832
 	.description = "DNS search list",
801 833
 	.tag = NDP_TAG ( NDP_OPT_DNSSL,
802
-			 offsetof ( struct ndp_dnssl_option, names ) ),
834
+			 offsetof ( struct ndp_dnssl_option, names ), 0 ),
803 835
 	.type = &setting_type_dnssl,
804 836
 	.scope = &ndp_settings_scope,
805 837
 };

Завантаження…
Відмінити
Зберегти