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
 extern const struct settings_scope builtin_scope;
284
 extern const struct settings_scope builtin_scope;
285
 
285
 
286
 /** IPv6 setting scope */
286
 /** IPv6 setting scope */
287
+extern const struct settings_scope ipv6_scope;
288
+
289
+/** DHCPv6 setting scope */
287
 extern const struct settings_scope dhcpv6_scope;
290
 extern const struct settings_scope dhcpv6_scope;
288
 
291
 
289
 /**
292
 /**
433
 extern const struct setting
436
 extern const struct setting
434
 dns_setting __setting ( SETTING_IP4_EXTRA, dns );
437
 dns_setting __setting ( SETTING_IP4_EXTRA, dns );
435
 extern const struct setting
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
 hostname_setting __setting ( SETTING_HOST, hostname );
445
 hostname_setting __setting ( SETTING_HOST, hostname );
437
 extern const struct setting
446
 extern const struct setting
438
 domain_setting __setting ( SETTING_IP_EXTRA, domain );
447
 domain_setting __setting ( SETTING_IP_EXTRA, domain );

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

1061
 	return snprintf ( buf, len, "%s", inet6_ntoa ( ipv6 ) );
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
  * Create IPv6 network device
1092
  * Create IPv6 network device
1066
  *
1093
  *

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

20
 FILE_LICENCE ( GPL2_OR_LATER );
20
 FILE_LICENCE ( GPL2_OR_LATER );
21
 
21
 
22
 #include <stdlib.h>
22
 #include <stdlib.h>
23
+#include <stdio.h>
23
 #include <string.h>
24
 #include <string.h>
24
 #include <errno.h>
25
 #include <errno.h>
25
 #include <byteswap.h>
26
 #include <byteswap.h>
41
 static struct ipv6conf * ipv6conf_demux ( struct net_device *netdev );
42
 static struct ipv6conf * ipv6conf_demux ( struct net_device *netdev );
42
 static int
43
 static int
43
 ipv6conf_rx_router_advertisement ( struct net_device *netdev,
44
 ipv6conf_rx_router_advertisement ( struct net_device *netdev,
45
+				   struct in6_addr *router,
44
 				   struct ndp_router_advertisement_header *radv,
46
 				   struct ndp_router_advertisement_header *radv,
45
 				   size_t len );
47
 				   size_t len );
46
 
48
 
585
 			      struct sockaddr_in6 *sin6_dest __unused ) {
587
 			      struct sockaddr_in6 *sin6_dest __unused ) {
586
 	union ndp_header *ndp = iobuf->data;
588
 	union ndp_header *ndp = iobuf->data;
587
 	struct ndp_router_advertisement_header *radv = &ndp->radv;
589
 	struct ndp_router_advertisement_header *radv = &ndp->radv;
590
+	struct in6_addr *router = &sin6_src->sin6_addr;
588
 	size_t len = iob_len ( iobuf );
591
 	size_t len = iob_len ( iobuf );
589
 	int rc;
592
 	int rc;
590
 
593
 
595
 		goto err_options;
598
 		goto err_options;
596
 
599
 
597
 	/* Pass to IPv6 autoconfiguration */
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
 		goto err_ipv6conf;
603
 		goto err_ipv6conf;
601
 
604
 
602
  err_ipv6conf:
605
  err_ipv6conf:
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
 /** An NDP settings block */
643
 /** An NDP settings block */
631
 struct ndp_settings {
644
 struct ndp_settings {
632
 	/** Reference counter */
645
 	/** Reference counter */
633
 	struct refcnt refcnt;
646
 	struct refcnt refcnt;
634
 	/** Settings interface */
647
 	/** Settings interface */
635
 	struct settings settings;
648
 	struct settings settings;
649
+	/** Router address */
650
+	struct in6_addr router;
651
+	/** Router lifetime */
652
+	unsigned int lifetime;
636
 	/** Length of NDP options */
653
 	/** Length of NDP options */
637
 	size_t len;
654
 	size_t len;
638
 	/** NDP options */
655
 	/** NDP options */
779
 	.fetch = ndp_fetch,
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
  * Register NDP settings
963
  * Register NDP settings
784
  *
964
  *
785
  * @v netdev		Network device
965
  * @v netdev		Network device
966
+ * @v router		Router address
967
+ * @v lifetime		Router lifetime
786
  * @v options		NDP options
968
  * @v options		NDP options
787
  * @v len		Length of options
969
  * @v len		Length of options
788
  * @ret rc		Return status code
970
  * @ret rc		Return status code
789
  */
971
  */
790
 static int ndp_register_settings ( struct net_device *netdev,
972
 static int ndp_register_settings ( struct net_device *netdev,
973
+				   struct in6_addr *router,
974
+				   unsigned int lifetime,
791
 				   union ndp_option *options, size_t len ) {
975
 				   union ndp_option *options, size_t len ) {
792
 	struct settings *parent = netdev_settings ( netdev );
976
 	struct settings *parent = netdev_settings ( netdev );
977
+	union ndp_option *option;
793
 	struct ndp_settings *ndpset;
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
 	int rc;
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
 	/* Allocate and initialise structure */
997
 	/* Allocate and initialise structure */
797
-	ndpset = zalloc ( sizeof ( *ndpset ) + len );
998
+	ndpset = zalloc ( sizeof ( *ndpset ) + len +
999
+			  ( prefixes * sizeof ( *prefset ) ) );
798
 	if ( ! ndpset ) {
1000
 	if ( ! ndpset ) {
799
 		rc = -ENOMEM;
1001
 		rc = -ENOMEM;
800
 		goto err_alloc;
1002
 		goto err_alloc;
802
 	ref_init ( &ndpset->refcnt, NULL );
1004
 	ref_init ( &ndpset->refcnt, NULL );
803
 	settings_init ( &ndpset->settings, &ndp_settings_operations,
1005
 	settings_init ( &ndpset->settings, &ndp_settings_operations,
804
 			&ndpset->refcnt, &ndp_settings_scope );
1006
 			&ndpset->refcnt, &ndp_settings_scope );
1007
+	memcpy ( &ndpset->router, router, sizeof ( ndpset->router ) );
1008
+	ndpset->lifetime = lifetime;
805
 	ndpset->len = len;
1009
 	ndpset->len = len;
806
 	memcpy ( ndpset->options, options, len );
1010
 	memcpy ( ndpset->options, options, len );
1011
+	prefset = ( ( ( void * ) ndpset->options ) + len );
807
 
1012
 
808
 	/* Register settings */
1013
 	/* Register settings */
809
 	if ( ( rc = register_settings ( &ndpset->settings, parent,
1014
 	if ( ( rc = register_settings ( &ndpset->settings, parent,
810
 					NDP_SETTINGS_NAME ) ) != 0 )
1015
 					NDP_SETTINGS_NAME ) ) != 0 )
811
 		goto err_register;
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
  err_register:
1051
  err_register:
814
 	ref_put ( &ndpset->refcnt );
1052
 	ref_put ( &ndpset->refcnt );
815
  err_alloc:
1053
  err_alloc:
938
  * Handle router advertisement during IPv6 autoconfiguration
1176
  * Handle router advertisement during IPv6 autoconfiguration
939
  *
1177
  *
940
  * @v netdev		Network device
1178
  * @v netdev		Network device
1179
+ * @v router		Router address
941
  * @v radv		Router advertisement
1180
  * @v radv		Router advertisement
942
  * @v len		Length of router advertisement
1181
  * @v len		Length of router advertisement
943
  * @ret rc		Return status code
1182
  * @ret rc		Return status code
947
  */
1186
  */
948
 static int
1187
 static int
949
 ipv6conf_rx_router_advertisement ( struct net_device *netdev,
1188
 ipv6conf_rx_router_advertisement ( struct net_device *netdev,
1189
+				   struct in6_addr *router,
950
 				   struct ndp_router_advertisement_header *radv,
1190
 				   struct ndp_router_advertisement_header *radv,
951
 				   size_t len ) {
1191
 				   size_t len ) {
952
 	struct ipv6conf *ipv6conf;
1192
 	struct ipv6conf *ipv6conf;
970
 
1210
 
971
 	/* Register NDP settings */
1211
 	/* Register NDP settings */
972
 	option_len = ( len - offsetof ( typeof ( *radv ), option ) );
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
 		return rc;
1216
 		return rc;
976
 
1217
 
977
 	/* Start DHCPv6 if required */
1218
 	/* Start DHCPv6 if required */

Loading…
Cancel
Save