Browse Source

[ipv6] Expose NDP-provided settings (including the DNS server)

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 11 years ago
parent
commit
99c679696a
2 changed files with 234 additions and 9 deletions
  1. 37
    0
      src/include/ipxe/ndp.h
  2. 197
    9
      src/net/ndp.c

+ 37
- 0
src/include/ipxe/ndp.h View File

@@ -67,6 +67,36 @@ struct ndp_prefix_information_option {
67 67
 /** NDP autonomous address configuration flag */
68 68
 #define NDP_PREFIX_AUTONOMOUS 0x40
69 69
 
70
+/** NDP recursive DNS server option */
71
+#define NDP_OPT_RDNSS 25
72
+
73
+/** NDP recursive DNS server */
74
+struct ndp_rdnss_option {
75
+	/** NDP option header */
76
+	struct ndp_option_header header;
77
+	/** Reserved */
78
+	uint16_t reserved;
79
+	/** Lifetime */
80
+	uint32_t lifetime;
81
+	/** Addresses */
82
+	struct in6_addr addresses[0];
83
+} __attribute__ (( packed ));
84
+
85
+/** NDP DNS search list option */
86
+#define NDP_OPT_DNSSL 31
87
+
88
+/** NDP DNS search list */
89
+struct ndp_dnssl_option {
90
+	/** NDP option header */
91
+	struct ndp_option_header header;
92
+	/** Reserved */
93
+	uint16_t reserved;
94
+	/** Lifetime */
95
+	uint32_t lifetime;
96
+	/** Domain names */
97
+	uint8_t names[0];
98
+} __attribute__ (( packed ));
99
+
70 100
 /** An NDP option */
71 101
 union ndp_option {
72 102
 	/** Option header */
@@ -75,6 +105,10 @@ union ndp_option {
75 105
 	struct ndp_ll_addr_option ll_addr;
76 106
 	/** Prefix information option */
77 107
 	struct ndp_prefix_information_option prefix;
108
+	/** Recursive DNS server option */
109
+	struct ndp_rdnss_option rdnss;
110
+	/** DNS search list option */
111
+	struct ndp_dnssl_option dnssl;
78 112
 } __attribute__ (( packed ));
79 113
 
80 114
 /** An NDP neighbour solicitation or advertisement header */
@@ -166,4 +200,7 @@ static inline int ndp_tx ( struct io_buffer *iobuf, struct net_device *netdev,
166 200
 			      &ndp_discovery, net_source, ll_source );
167 201
 }
168 202
 
203
+/** NDP settings block name */
204
+#define NDP_SETTINGS_NAME "ndp"
205
+
169 206
 #endif /* _IPXE_NDP_H */

+ 197
- 9
src/net/ndp.c View File

@@ -38,8 +38,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
38 38
  *
39 39
  */
40 40
 
41
-static int ipv6conf_rx_router_advertisement ( struct net_device *netdev,
42
-					      unsigned int flags );
41
+static int
42
+ipv6conf_rx_router_advertisement ( struct net_device *netdev,
43
+				   struct ndp_router_advertisement_header *radv,
44
+				   size_t len );
43 45
 
44 46
 /**
45 47
  * Transmit NDP packet with link-layer address option
@@ -585,8 +587,8 @@ ndp_rx_router_advertisement ( struct io_buffer *iobuf,
585 587
 		goto err_options;
586 588
 
587 589
 	/* Pass to IPv6 autoconfiguration */
588
-	if ( ( rc = ipv6conf_rx_router_advertisement ( netdev,
589
-						       radv->flags ) ) != 0 )
590
+	if ( ( rc = ipv6conf_rx_router_advertisement ( netdev, radv,
591
+						       len ) ) != 0 )
590 592
 		goto err_ipv6conf;
591 593
 
592 594
  err_ipv6conf:
@@ -611,6 +613,179 @@ struct icmpv6_handler ndp_handlers[] __icmpv6_handler = {
611 613
 	},
612 614
 };
613 615
 
616
+/****************************************************************************
617
+ *
618
+ * NDP settings
619
+ *
620
+ */
621
+
622
+/** An NDP settings block */
623
+struct ndp_settings {
624
+	/** Reference counter */
625
+	struct refcnt refcnt;
626
+	/** Settings interface */
627
+	struct settings settings;
628
+	/** Length of NDP options */
629
+	size_t len;
630
+	/** NDP options */
631
+	union ndp_option option[0];
632
+};
633
+
634
+/** NDP settings scope */
635
+static const struct settings_scope ndp_settings_scope;
636
+
637
+/**
638
+ * Construct NDP tag
639
+ *
640
+ * @v type		NDP option type
641
+ * @v offset		Starting offset of data
642
+ * @ret tag		NDP tag
643
+ */
644
+#define NDP_TAG( type, offset )	( ( (offset) << 8 ) | (type) )
645
+
646
+/**
647
+ * Extract NDP tag type
648
+ *
649
+ * @v tag		NDP tag
650
+ * @ret type		NDP option type
651
+ */
652
+#define NDP_TAG_TYPE( tag ) ( (tag) & 0xff )
653
+
654
+/**
655
+ * Extract NDP tag offset
656
+ *
657
+ * @v tag		NDP tag
658
+ * @ret offset		Starting offset of data
659
+ */
660
+#define NDP_TAG_OFFSET( tag ) ( (tag) >> 8 )
661
+
662
+/**
663
+ * Check applicability of NDP setting
664
+ *
665
+ * @v settings		Settings block
666
+ * @v setting		Setting to fetch
667
+ * @ret applies		Setting applies within this settings block
668
+ */
669
+static int ndp_applies ( struct settings *settings __unused,
670
+			 const struct setting *setting ) {
671
+
672
+	return ( setting->scope == &ndp_settings_scope );
673
+}
674
+
675
+/**
676
+ * Fetch value of NDP setting
677
+ *
678
+ * @v settings		Settings block
679
+ * @v setting		Setting to fetch
680
+ * @v data		Buffer to fill with setting data
681
+ * @v len		Length of buffer
682
+ * @ret len		Length of setting data, or negative error
683
+ */
684
+static int ndp_fetch ( struct settings *settings,
685
+		       struct setting *setting,
686
+		       void *data, size_t len ) {
687
+	struct ndp_settings *ndpset =
688
+		container_of ( settings, struct ndp_settings, settings );
689
+	struct net_device *netdev =
690
+		container_of ( settings->parent, struct net_device,
691
+			       settings.settings );
692
+	union ndp_option *option;
693
+	unsigned int type = NDP_TAG_TYPE ( setting->tag );
694
+	unsigned int offset = NDP_TAG_OFFSET ( setting->tag );
695
+	size_t remaining;
696
+	size_t option_len;
697
+	size_t payload_len;
698
+
699
+	/* Scan through NDP options for requested type.  We can assume
700
+	 * that the options are well-formed, otherwise they would have
701
+	 * been rejected prior to being stored.
702
+	 */
703
+	option = ndpset->option;
704
+	remaining = ndpset->len;
705
+	while ( remaining ) {
706
+
707
+		/* Calculate option length */
708
+		option_len = ( option->header.blocks * NDP_OPTION_BLKSZ );
709
+
710
+		/* If this is the requested option, return it */
711
+		if ( option->header.type == type ) {
712
+
713
+			/* Sanity check */
714
+			if ( offset > option_len ) {
715
+				DBGC ( netdev, "NDP %s option %d too short\n",
716
+				       netdev->name, type );
717
+				return -EINVAL;
718
+			}
719
+			payload_len = ( option_len - offset );
720
+
721
+			/* Copy data to output buffer */
722
+			if ( len > payload_len )
723
+				len = payload_len;
724
+			memcpy ( data, ( ( ( void * ) option ) + offset ), len);
725
+			return payload_len;
726
+		}
727
+
728
+		/* Move to next option */
729
+		option = ( ( ( void * ) option ) + option_len );
730
+		remaining -= option_len;
731
+	}
732
+
733
+	return -ENOENT;
734
+}
735
+
736
+/** NDP settings operations */
737
+static struct settings_operations ndp_settings_operations = {
738
+	.applies = ndp_applies,
739
+	.fetch = ndp_fetch,
740
+};
741
+
742
+/**
743
+ * Register NDP settings
744
+ *
745
+ * @v netdev		Network device
746
+ * @v option		NDP options
747
+ * @v len		Length of options
748
+ * @ret rc		Return status code
749
+ */
750
+static int ndp_register_settings ( struct net_device *netdev,
751
+				   union ndp_option *option, size_t len ) {
752
+	struct settings *parent = netdev_settings ( netdev );
753
+	struct ndp_settings *ndpset;
754
+	int rc;
755
+
756
+	/* Allocate and initialise structure */
757
+	ndpset = zalloc ( sizeof ( *ndpset ) + len );
758
+	if ( ! ndpset ) {
759
+		rc = -ENOMEM;
760
+		goto err_alloc;
761
+	}
762
+	ref_init ( &ndpset->refcnt, NULL );
763
+	settings_init ( &ndpset->settings, &ndp_settings_operations,
764
+			&ndpset->refcnt, &ndp_settings_scope );
765
+	ndpset->len = len;
766
+	memcpy ( ndpset->option, option, len );
767
+
768
+	/* Register settings */
769
+	if ( ( rc = register_settings ( &ndpset->settings, parent,
770
+					NDP_SETTINGS_NAME ) ) != 0 )
771
+		goto err_register;
772
+
773
+ err_register:
774
+	ref_put ( &ndpset->refcnt );
775
+ err_alloc:
776
+	return rc;
777
+}
778
+
779
+/** DNS server setting */
780
+const struct setting ndp_dns6_setting __setting ( SETTING_IP_EXTRA, dns6 ) = {
781
+	.name = "dns6",
782
+	.description = "DNS server",
783
+	.tag = NDP_TAG ( NDP_OPT_RDNSS,
784
+			 offsetof ( struct ndp_rdnss_option, addresses ) ),
785
+	.type = &setting_type_ipv6,
786
+	.scope = &ndp_settings_scope,
787
+};
788
+
614 789
 /****************************************************************************
615 790
  *
616 791
  * IPv6 autoconfiguration
@@ -713,12 +888,19 @@ static void ipv6conf_expired ( struct retry_timer *timer, int fail ) {
713 888
  * Handle router advertisement during IPv6 autoconfiguration
714 889
  *
715 890
  * @v netdev		Network device
716
- * @v flags		Router flags
891
+ * @v radv		Router advertisement
892
+ * @v len		Length of router advertisement
717 893
  * @ret rc		Return status code
894
+ *
895
+ * This function assumes that the router advertisement is well-formed,
896
+ * since it must have already passed through option processing.
718 897
  */
719
-static int ipv6conf_rx_router_advertisement ( struct net_device *netdev,
720
-					      unsigned int flags ) {
898
+static int
899
+ipv6conf_rx_router_advertisement ( struct net_device *netdev,
900
+				   struct ndp_router_advertisement_header *radv,
901
+				   size_t len ) {
721 902
 	struct ipv6conf *ipv6conf;
903
+	size_t option_len;
722 904
 	int stateful;
723 905
 	int rc;
724 906
 
@@ -739,9 +921,15 @@ static int ipv6conf_rx_router_advertisement ( struct net_device *netdev,
739 921
 	/* Stop router solicitation timer */
740 922
 	stop_timer ( &ipv6conf->timer );
741 923
 
924
+	/* Register NDP settings */
925
+	option_len = ( len - offsetof ( typeof ( *radv ), option ) );
926
+	if ( ( rc = ndp_register_settings ( netdev, radv->option,
927
+					    option_len ) ) != 0 )
928
+		return rc;
929
+
742 930
 	/* Start DHCPv6 if required */
743
-	if ( flags & ( NDP_ROUTER_MANAGED | NDP_ROUTER_OTHER ) ) {
744
-		stateful = ( flags & NDP_ROUTER_MANAGED );
931
+	if ( radv->flags & ( NDP_ROUTER_MANAGED | NDP_ROUTER_OTHER ) ) {
932
+		stateful = ( radv->flags & NDP_ROUTER_MANAGED );
745 933
 		if ( ( rc = start_dhcpv6 ( &ipv6conf->dhcp, netdev,
746 934
 					   stateful ) ) != 0 ) {
747 935
 			DBGC ( netdev, "NDP %s could not start state%s DHCPv6: "

Loading…
Cancel
Save