Browse Source

[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 years ago
parent
commit
ee54ab5be6
1 changed files with 67 additions and 35 deletions
  1. 67
    35
      src/net/ndp.c

+ 67
- 35
src/net/ndp.c View File

636
 	/** Length of NDP options */
636
 	/** Length of NDP options */
637
 	size_t len;
637
 	size_t len;
638
 	/** NDP options */
638
 	/** NDP options */
639
-	union ndp_option option[0];
639
+	union ndp_option options[0];
640
 };
640
 };
641
 
641
 
642
 /** NDP settings scope */
642
 /** NDP settings scope */
647
  *
647
  *
648
  * @v type		NDP option type
648
  * @v type		NDP option type
649
  * @v offset		Starting offset of data
649
  * @v offset		Starting offset of data
650
+ * @v len		Length of data (or 0 to use all remaining data)
650
  * @ret tag		NDP tag
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
  * Extract NDP tag type
657
  * Extract NDP tag type
657
  * @v tag		NDP tag
659
  * @v tag		NDP tag
658
  * @ret type		NDP option type
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
  * Extract NDP tag offset
665
  * Extract NDP tag offset
665
  * @v tag		NDP tag
667
  * @v tag		NDP tag
666
  * @ret offset		Starting offset of data
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
  * Check applicability of NDP setting
689
  * Check applicability of NDP setting
698
 		container_of ( settings->parent, struct net_device,
716
 		container_of ( settings->parent, struct net_device,
699
 			       settings.settings );
717
 			       settings.settings );
700
 	union ndp_option *option;
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
 	size_t option_len;
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
 	/* Scan through NDP options for requested type.  We can assume
733
 	/* Scan through NDP options for requested type.  We can assume
708
 	 * that the options are well-formed, otherwise they would have
734
 	 * that the options are well-formed, otherwise they would have
709
 	 * been rejected prior to being stored.
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
 		/* Calculate option length */
739
 		/* Calculate option length */
740
+		option = ( ( ( void * ) ndpset->options ) + offset );
716
 		option_len = ( option->header.blocks * NDP_OPTION_BLKSZ );
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
 	return -ENOENT;
773
 	return -ENOENT;
751
  * Register NDP settings
783
  * Register NDP settings
752
  *
784
  *
753
  * @v netdev		Network device
785
  * @v netdev		Network device
754
- * @v option		NDP options
786
+ * @v options		NDP options
755
  * @v len		Length of options
787
  * @v len		Length of options
756
  * @ret rc		Return status code
788
  * @ret rc		Return status code
757
  */
789
  */
758
 static int ndp_register_settings ( struct net_device *netdev,
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
 	struct settings *parent = netdev_settings ( netdev );
792
 	struct settings *parent = netdev_settings ( netdev );
761
 	struct ndp_settings *ndpset;
793
 	struct ndp_settings *ndpset;
762
 	int rc;
794
 	int rc;
771
 	settings_init ( &ndpset->settings, &ndp_settings_operations,
803
 	settings_init ( &ndpset->settings, &ndp_settings_operations,
772
 			&ndpset->refcnt, &ndp_settings_scope );
804
 			&ndpset->refcnt, &ndp_settings_scope );
773
 	ndpset->len = len;
805
 	ndpset->len = len;
774
-	memcpy ( ndpset->option, option, len );
806
+	memcpy ( ndpset->options, options, len );
775
 
807
 
776
 	/* Register settings */
808
 	/* Register settings */
777
 	if ( ( rc = register_settings ( &ndpset->settings, parent,
809
 	if ( ( rc = register_settings ( &ndpset->settings, parent,
789
 	.name = "dns6",
821
 	.name = "dns6",
790
 	.description = "DNS server",
822
 	.description = "DNS server",
791
 	.tag = NDP_TAG ( NDP_OPT_RDNSS,
823
 	.tag = NDP_TAG ( NDP_OPT_RDNSS,
792
-			 offsetof ( struct ndp_rdnss_option, addresses ) ),
824
+			 offsetof ( struct ndp_rdnss_option, addresses ), 0 ),
793
 	.type = &setting_type_ipv6,
825
 	.type = &setting_type_ipv6,
794
 	.scope = &ndp_settings_scope,
826
 	.scope = &ndp_settings_scope,
795
 };
827
 };
799
 	.name = "dnssl",
831
 	.name = "dnssl",
800
 	.description = "DNS search list",
832
 	.description = "DNS search list",
801
 	.tag = NDP_TAG ( NDP_OPT_DNSSL,
833
 	.tag = NDP_TAG ( NDP_OPT_DNSSL,
802
-			 offsetof ( struct ndp_dnssl_option, names ) ),
834
+			 offsetof ( struct ndp_dnssl_option, names ), 0 ),
803
 	.type = &setting_type_dnssl,
835
 	.type = &setting_type_dnssl,
804
 	.scope = &ndp_settings_scope,
836
 	.scope = &ndp_settings_scope,
805
 };
837
 };

Loading…
Cancel
Save