Browse Source

[ipv6] Expose IPv6 settings acquired through NDP

Expose the IPv6 address (or prefix) as ${ip6}, the prefix length as
${len6}, and the router address as ${gateway6}.

Originally-implemented-by: Hannes Reinecke <hare@suse.de>
Originally-implemented-by: Marin Hannache <git@mareo.fr>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 8 years ago
parent
commit
3b783d7fd2
3 changed files with 282 additions and 5 deletions
  1. 9
    0
      src/include/ipxe/settings.h
  2. 27
    0
      src/net/ipv6.c
  3. 246
    5
      src/net/ndp.c

+ 9
- 0
src/include/ipxe/settings.h View File

@@ -284,6 +284,9 @@ struct builtin_setting {
284 284
 extern const struct settings_scope builtin_scope;
285 285
 
286 286
 /** IPv6 setting scope */
287
+extern const struct settings_scope ipv6_scope;
288
+
289
+/** DHCPv6 setting scope */
287 290
 extern const struct settings_scope dhcpv6_scope;
288 291
 
289 292
 /**
@@ -433,6 +436,12 @@ gateway_setting __setting ( SETTING_IP4, gateway );
433 436
 extern const struct setting
434 437
 dns_setting __setting ( SETTING_IP4_EXTRA, dns );
435 438
 extern const struct setting
439
+ip6_setting __setting ( SETTING_IP6, ip6 );
440
+extern const struct setting
441
+len6_setting __setting ( SETTING_IP6, len6 );
442
+extern const struct setting
443
+gateway6_setting __setting ( SETTING_IP6, gateway6 );
444
+extern const struct setting
436 445
 hostname_setting __setting ( SETTING_HOST, hostname );
437 446
 extern const struct setting
438 447
 domain_setting __setting ( SETTING_IP_EXTRA, domain );

+ 27
- 0
src/net/ipv6.c View File

@@ -1061,6 +1061,33 @@ int format_ipv6_setting ( const struct setting_type *type __unused,
1061 1061
 	return snprintf ( buf, len, "%s", inet6_ntoa ( ipv6 ) );
1062 1062
 }
1063 1063
 
1064
+/** IPv6 settings scope */
1065
+const struct settings_scope ipv6_scope;
1066
+
1067
+/** IPv6 address setting */
1068
+const struct setting ip6_setting __setting ( SETTING_IP6, ip6 ) = {
1069
+	.name = "ip6",
1070
+	.description = "IPv6 address",
1071
+	.type = &setting_type_ipv6,
1072
+	.scope = &ipv6_scope,
1073
+};
1074
+
1075
+/** IPv6 prefix length setting */
1076
+const struct setting len6_setting __setting ( SETTING_IP6, len6 ) = {
1077
+	.name = "len6",
1078
+	.description = "IPv6 prefix length",
1079
+	.type = &setting_type_int8,
1080
+	.scope = &ipv6_scope,
1081
+};
1082
+
1083
+/** Default gateway setting */
1084
+const struct setting gateway6_setting __setting ( SETTING_IP6, gateway6 ) = {
1085
+	.name = "gateway6",
1086
+	.description = "IPv6 gateway",
1087
+	.type = &setting_type_ipv6,
1088
+	.scope = &ipv6_scope,
1089
+};
1090
+
1064 1091
 /**
1065 1092
  * Create IPv6 network device
1066 1093
  *

+ 246
- 5
src/net/ndp.c View File

@@ -20,6 +20,7 @@
20 20
 FILE_LICENCE ( GPL2_OR_LATER );
21 21
 
22 22
 #include <stdlib.h>
23
+#include <stdio.h>
23 24
 #include <string.h>
24 25
 #include <errno.h>
25 26
 #include <byteswap.h>
@@ -41,6 +42,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
41 42
 static struct ipv6conf * ipv6conf_demux ( struct net_device *netdev );
42 43
 static int
43 44
 ipv6conf_rx_router_advertisement ( struct net_device *netdev,
45
+				   struct in6_addr *router,
44 46
 				   struct ndp_router_advertisement_header *radv,
45 47
 				   size_t len );
46 48
 
@@ -585,6 +587,7 @@ ndp_rx_router_advertisement ( struct io_buffer *iobuf,
585 587
 			      struct sockaddr_in6 *sin6_dest __unused ) {
586 588
 	union ndp_header *ndp = iobuf->data;
587 589
 	struct ndp_router_advertisement_header *radv = &ndp->radv;
590
+	struct in6_addr *router = &sin6_src->sin6_addr;
588 591
 	size_t len = iob_len ( iobuf );
589 592
 	int rc;
590 593
 
@@ -595,8 +598,8 @@ ndp_rx_router_advertisement ( struct io_buffer *iobuf,
595 598
 		goto err_options;
596 599
 
597 600
 	/* Pass to IPv6 autoconfiguration */
598
-	if ( ( rc = ipv6conf_rx_router_advertisement ( netdev, radv,
599
-						       len ) ) != 0 )
601
+	if ( ( rc = ipv6conf_rx_router_advertisement ( netdev, router,
602
+						       radv, len ) ) != 0 )
600 603
 		goto err_ipv6conf;
601 604
 
602 605
  err_ipv6conf:
@@ -627,12 +630,26 @@ struct icmpv6_handler ndp_handlers[] __icmpv6_handler = {
627 630
  *
628 631
  */
629 632
 
633
+/** An NDP prefix settings block */
634
+struct ndp_prefix_settings {
635
+	/** Settings interface */
636
+	struct settings settings;
637
+	/** Name */
638
+	char name[4];
639
+	/** Prefix information option */
640
+	struct ndp_prefix_information_option *prefix;
641
+};
642
+
630 643
 /** An NDP settings block */
631 644
 struct ndp_settings {
632 645
 	/** Reference counter */
633 646
 	struct refcnt refcnt;
634 647
 	/** Settings interface */
635 648
 	struct settings settings;
649
+	/** Router address */
650
+	struct in6_addr router;
651
+	/** Router lifetime */
652
+	unsigned int lifetime;
636 653
 	/** Length of NDP options */
637 654
 	size_t len;
638 655
 	/** NDP options */
@@ -779,22 +796,207 @@ static struct settings_operations ndp_settings_operations = {
779 796
 	.fetch = ndp_fetch,
780 797
 };
781 798
 
799
+/**
800
+ * Check applicability of NDP per-prefix setting
801
+ *
802
+ * @v settings		Settings block
803
+ * @v setting		Setting to fetch
804
+ * @ret applies		Setting applies within this settings block
805
+ */
806
+static int ndp_prefix_applies ( struct settings *settings __unused,
807
+				const struct setting *setting ) {
808
+
809
+	return ( setting->scope == &ipv6_scope );
810
+}
811
+
812
+/**
813
+ * Fetch value of NDP IPv6 address setting
814
+ *
815
+ * @v settings		Settings block
816
+ * @v data		Buffer to fill with setting data
817
+ * @v len		Length of buffer
818
+ * @ret len		Length of setting data, or negative error
819
+ */
820
+static int ndp_prefix_fetch_ip6 ( struct settings *settings, void *data,
821
+				  size_t len ) {
822
+	struct ndp_prefix_settings *prefset =
823
+		container_of ( settings, struct ndp_prefix_settings, settings );
824
+	struct ndp_settings *ndpset =
825
+		container_of ( settings->parent, struct ndp_settings, settings);
826
+	struct net_device *netdev =
827
+		container_of ( ndpset->settings.parent, struct net_device,
828
+			       settings.settings );
829
+	struct ndp_prefix_information_option *prefix = prefset->prefix;
830
+	struct in6_addr ip6;
831
+	int prefix_len;
832
+
833
+	/* Skip dead prefixes */
834
+	if ( ! prefix->valid )
835
+		return -ENOENT;
836
+
837
+	/* Construct IPv6 address via SLAAC, if applicable */
838
+	memcpy ( &ip6, &prefix->prefix, sizeof ( ip6 ) );
839
+	if ( prefix->flags & NDP_PREFIX_AUTONOMOUS ) {
840
+		prefix_len = ipv6_eui64 ( &ip6, netdev );
841
+		if ( prefix_len < 0 )
842
+			return prefix_len;
843
+		if ( prefix_len != prefix->prefix_len )
844
+			return -EINVAL;
845
+	}
846
+
847
+	/* Fill in IPv6 address */
848
+	if ( len > sizeof ( ip6 ) )
849
+		len = sizeof ( ip6 );
850
+	memcpy ( data, &ip6, len );
851
+
852
+	return sizeof ( ip6 );
853
+}
854
+
855
+/**
856
+ * Fetch value of NDP prefix length setting
857
+ *
858
+ * @v settings		Settings block
859
+ * @v data		Buffer to fill with setting data
860
+ * @v len		Length of buffer
861
+ * @ret len		Length of setting data, or negative error
862
+ */
863
+static int ndp_prefix_fetch_len6 ( struct settings *settings, void *data,
864
+				   size_t len ) {
865
+	struct ndp_prefix_settings *prefset =
866
+		container_of ( settings, struct ndp_prefix_settings, settings );
867
+	struct ndp_prefix_information_option *prefix = prefset->prefix;
868
+	uint8_t *len6;
869
+
870
+	/* Fill in prefix length */
871
+	if ( len >= sizeof ( *len6 ) ) {
872
+		/* We treat an off-link prefix as having a prefix
873
+		 * length covering the entire IPv6 address.
874
+		 */
875
+		len6 = data;
876
+		*len6 = ( ( prefix->flags & NDP_PREFIX_ON_LINK ) ?
877
+			  prefix->prefix_len : -1UL );
878
+	}
879
+
880
+	return sizeof ( *len6 );
881
+}
882
+
883
+/**
884
+ * Fetch value of NDP router address setting
885
+ *
886
+ * @v settings		Settings block
887
+ * @v data		Buffer to fill with setting data
888
+ * @v len		Length of buffer
889
+ * @ret len		Length of setting data, or negative error
890
+ */
891
+static int ndp_prefix_fetch_gateway6 ( struct settings *settings,
892
+				       void *data, size_t len ) {
893
+	struct ndp_settings *ndpset =
894
+		container_of ( settings->parent, struct ndp_settings, settings);
895
+
896
+	/* Treat non-routing router as non-existent */
897
+	if ( ! ndpset->lifetime )
898
+		return -ENOENT;
899
+
900
+	/* Fill in router address */
901
+	if ( len > sizeof ( ndpset->router ) )
902
+		len = sizeof ( ndpset->router );
903
+	memcpy ( data, &ndpset->router, len );
904
+
905
+	return sizeof ( ndpset->router );
906
+}
907
+
908
+/** An NDP per-prefix setting operation */
909
+struct ndp_prefix_operation {
910
+	/** Generic setting */
911
+	const struct setting *setting;
912
+	/**
913
+	 * Fetch value of setting
914
+	 *
915
+	 * @v settings		Settings block
916
+	 * @v data		Buffer to fill with setting data
917
+	 * @v len		Length of buffer
918
+	 * @ret len		Length of setting data, or negative error
919
+	 */
920
+	int ( * fetch ) ( struct settings *settings, void *data, size_t len );
921
+};
922
+
923
+/** NDP per-prefix settings operations */
924
+static struct ndp_prefix_operation ndp_prefix_operations[] = {
925
+	{ &ip6_setting, ndp_prefix_fetch_ip6 },
926
+	{ &len6_setting, ndp_prefix_fetch_len6 },
927
+	{ &gateway6_setting, ndp_prefix_fetch_gateway6 },
928
+};
929
+
930
+/**
931
+ * Fetch value of NDP pre-prefix setting
932
+ *
933
+ * @v settings		Settings block
934
+ * @v setting		Setting to fetch
935
+ * @v data		Buffer to fill with setting data
936
+ * @v len		Length of buffer
937
+ * @ret len		Length of setting data, or negative error
938
+ */
939
+static int ndp_prefix_fetch ( struct settings *settings,
940
+			      struct setting *setting,
941
+			      void *data, size_t len ) {
942
+	struct ndp_prefix_operation *op;
943
+	unsigned int i;
944
+
945
+	/* Handle per-prefix settings */
946
+	for ( i = 0 ; i < ( sizeof ( ndp_prefix_operations ) /
947
+			    sizeof ( ndp_prefix_operations[0] ) ) ; i++ ) {
948
+		op = &ndp_prefix_operations[i];
949
+		if ( setting_cmp ( setting, op->setting ) == 0 )
950
+			return op->fetch ( settings, data, len );
951
+	}
952
+
953
+	return -ENOENT;
954
+}
955
+
956
+/** NDP per-prefix settings operations */
957
+static struct settings_operations ndp_prefix_settings_operations = {
958
+	.applies = ndp_prefix_applies,
959
+	.fetch = ndp_prefix_fetch,
960
+};
961
+
782 962
 /**
783 963
  * Register NDP settings
784 964
  *
785 965
  * @v netdev		Network device
966
+ * @v router		Router address
967
+ * @v lifetime		Router lifetime
786 968
  * @v options		NDP options
787 969
  * @v len		Length of options
788 970
  * @ret rc		Return status code
789 971
  */
790 972
 static int ndp_register_settings ( struct net_device *netdev,
973
+				   struct in6_addr *router,
974
+				   unsigned int lifetime,
791 975
 				   union ndp_option *options, size_t len ) {
792 976
 	struct settings *parent = netdev_settings ( netdev );
977
+	union ndp_option *option;
793 978
 	struct ndp_settings *ndpset;
979
+	struct ndp_prefix_settings *prefset;
980
+	size_t offset;
981
+	size_t option_len;
982
+	unsigned int prefixes;
983
+	unsigned int instance;
794 984
 	int rc;
795 985
 
986
+	/* Count number of prefix options.  We can assume that the
987
+	 * options are well-formed, otherwise they would have been
988
+	 * rejected prior to being stored.
989
+	 */
990
+	for ( prefixes = 0, offset = 0 ; offset < len ; offset += option_len ) {
991
+		option = ( ( ( void * ) options ) + offset );
992
+		option_len = ( option->header.blocks * NDP_OPTION_BLKSZ );
993
+		if ( option->header.type == NDP_OPT_PREFIX )
994
+			prefixes++;
995
+	}
996
+
796 997
 	/* Allocate and initialise structure */
797
-	ndpset = zalloc ( sizeof ( *ndpset ) + len );
998
+	ndpset = zalloc ( sizeof ( *ndpset ) + len +
999
+			  ( prefixes * sizeof ( *prefset ) ) );
798 1000
 	if ( ! ndpset ) {
799 1001
 		rc = -ENOMEM;
800 1002
 		goto err_alloc;
@@ -802,14 +1004,50 @@ static int ndp_register_settings ( struct net_device *netdev,
802 1004
 	ref_init ( &ndpset->refcnt, NULL );
803 1005
 	settings_init ( &ndpset->settings, &ndp_settings_operations,
804 1006
 			&ndpset->refcnt, &ndp_settings_scope );
1007
+	memcpy ( &ndpset->router, router, sizeof ( ndpset->router ) );
1008
+	ndpset->lifetime = lifetime;
805 1009
 	ndpset->len = len;
806 1010
 	memcpy ( ndpset->options, options, len );
1011
+	prefset = ( ( ( void * ) ndpset->options ) + len );
807 1012
 
808 1013
 	/* Register settings */
809 1014
 	if ( ( rc = register_settings ( &ndpset->settings, parent,
810 1015
 					NDP_SETTINGS_NAME ) ) != 0 )
811 1016
 		goto err_register;
812 1017
 
1018
+	/* Construct and register per-prefix settings */
1019
+	for ( instance = 0, offset = 0 ; offset < len ; offset += option_len ) {
1020
+
1021
+		/* Skip non-prefix options */
1022
+		option = ( ( ( void * ) ndpset->options ) + offset );
1023
+		option_len = ( option->header.blocks * NDP_OPTION_BLKSZ );
1024
+		if ( option->header.type != NDP_OPT_PREFIX )
1025
+			continue;
1026
+
1027
+		/* Initialise structure */
1028
+		settings_init ( &prefset->settings,
1029
+				&ndp_prefix_settings_operations,
1030
+				&ndpset->refcnt, &ndp_settings_scope );
1031
+		prefset->prefix = &option->prefix;
1032
+		snprintf ( prefset->name, sizeof ( prefset->name ), "%d",
1033
+			   instance++ );
1034
+
1035
+		/* Register settings */
1036
+		if ( ( rc = register_settings ( &prefset->settings,
1037
+						&ndpset->settings,
1038
+						prefset->name ) ) != 0 )
1039
+			goto err_register_prefix;
1040
+
1041
+		/* Move to next per-prefix settings */
1042
+		prefset++;
1043
+	}
1044
+	assert ( instance == prefixes );
1045
+
1046
+	ref_put ( &ndpset->refcnt );
1047
+	return 0;
1048
+
1049
+ err_register_prefix:
1050
+	unregister_settings ( &ndpset->settings );
813 1051
  err_register:
814 1052
 	ref_put ( &ndpset->refcnt );
815 1053
  err_alloc:
@@ -938,6 +1176,7 @@ static void ipv6conf_expired ( struct retry_timer *timer, int fail ) {
938 1176
  * Handle router advertisement during IPv6 autoconfiguration
939 1177
  *
940 1178
  * @v netdev		Network device
1179
+ * @v router		Router address
941 1180
  * @v radv		Router advertisement
942 1181
  * @v len		Length of router advertisement
943 1182
  * @ret rc		Return status code
@@ -947,6 +1186,7 @@ static void ipv6conf_expired ( struct retry_timer *timer, int fail ) {
947 1186
  */
948 1187
 static int
949 1188
 ipv6conf_rx_router_advertisement ( struct net_device *netdev,
1189
+				   struct in6_addr *router,
950 1190
 				   struct ndp_router_advertisement_header *radv,
951 1191
 				   size_t len ) {
952 1192
 	struct ipv6conf *ipv6conf;
@@ -970,8 +1210,9 @@ ipv6conf_rx_router_advertisement ( struct net_device *netdev,
970 1210
 
971 1211
 	/* Register NDP settings */
972 1212
 	option_len = ( len - offsetof ( typeof ( *radv ), option ) );
973
-	if ( ( rc = ndp_register_settings ( netdev, radv->option,
974
-					    option_len ) ) != 0 )
1213
+	if ( ( rc = ndp_register_settings ( netdev, router,
1214
+					    ntohl ( radv->lifetime ),
1215
+					    radv->option, option_len ) ) != 0 )
975 1216
 		return rc;
976 1217
 
977 1218
 	/* Start DHCPv6 if required */

Loading…
Cancel
Save