|
@@ -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
|
};
|