|  | @@ -1088,6 +1088,115 @@ const struct setting gateway6_setting __setting ( SETTING_IP6, gateway6 ) = {
 | 
		
	
		
			
			| 1088 | 1088 |  	.scope = &ipv6_scope,
 | 
		
	
		
			
			| 1089 | 1089 |  };
 | 
		
	
		
			
			| 1090 | 1090 |  
 | 
		
	
		
			
			|  | 1091 | +/**
 | 
		
	
		
			
			|  | 1092 | + * Check applicability of IPv6 link-local address setting
 | 
		
	
		
			
			|  | 1093 | + *
 | 
		
	
		
			
			|  | 1094 | + * @v settings		Settings block
 | 
		
	
		
			
			|  | 1095 | + * @v setting		Setting to fetch
 | 
		
	
		
			
			|  | 1096 | + * @ret applies		Setting applies within this settings block
 | 
		
	
		
			
			|  | 1097 | + */
 | 
		
	
		
			
			|  | 1098 | +static int ipv6_applies ( struct settings *settings __unused,
 | 
		
	
		
			
			|  | 1099 | +			  const struct setting *setting ) {
 | 
		
	
		
			
			|  | 1100 | +
 | 
		
	
		
			
			|  | 1101 | +	return ( setting->scope == &ipv6_scope );
 | 
		
	
		
			
			|  | 1102 | +}
 | 
		
	
		
			
			|  | 1103 | +
 | 
		
	
		
			
			|  | 1104 | +/**
 | 
		
	
		
			
			|  | 1105 | + * Fetch IPv6 link-local address setting
 | 
		
	
		
			
			|  | 1106 | + *
 | 
		
	
		
			
			|  | 1107 | + * @v settings		Settings block
 | 
		
	
		
			
			|  | 1108 | + * @v setting		Setting to fetch
 | 
		
	
		
			
			|  | 1109 | + * @v data		Buffer to fill with setting data
 | 
		
	
		
			
			|  | 1110 | + * @v len		Length of buffer
 | 
		
	
		
			
			|  | 1111 | + * @ret len		Length of setting data, or negative error
 | 
		
	
		
			
			|  | 1112 | + */
 | 
		
	
		
			
			|  | 1113 | +static int ipv6_fetch ( struct settings *settings, struct setting *setting,
 | 
		
	
		
			
			|  | 1114 | +			void *data, size_t len ) {
 | 
		
	
		
			
			|  | 1115 | +	struct net_device *netdev =
 | 
		
	
		
			
			|  | 1116 | +		container_of ( settings->parent, struct net_device,
 | 
		
	
		
			
			|  | 1117 | +			       settings.settings );
 | 
		
	
		
			
			|  | 1118 | +	struct in6_addr ip6;
 | 
		
	
		
			
			|  | 1119 | +	uint8_t *len6;
 | 
		
	
		
			
			|  | 1120 | +	int prefix_len;
 | 
		
	
		
			
			|  | 1121 | +	int rc;
 | 
		
	
		
			
			|  | 1122 | +
 | 
		
	
		
			
			|  | 1123 | +	/* Construct link-local address from EUI-64 as per RFC 2464 */
 | 
		
	
		
			
			|  | 1124 | +	memset ( &ip6, 0, sizeof ( ip6 ) );
 | 
		
	
		
			
			|  | 1125 | +	prefix_len = ipv6_link_local ( &ip6, netdev );
 | 
		
	
		
			
			|  | 1126 | +	if ( prefix_len < 0 ) {
 | 
		
	
		
			
			|  | 1127 | +		rc = prefix_len;
 | 
		
	
		
			
			|  | 1128 | +		return rc;
 | 
		
	
		
			
			|  | 1129 | +	}
 | 
		
	
		
			
			|  | 1130 | +
 | 
		
	
		
			
			|  | 1131 | +	/* Handle setting */
 | 
		
	
		
			
			|  | 1132 | +	if ( setting_cmp ( setting, &ip6_setting ) == 0 ) {
 | 
		
	
		
			
			|  | 1133 | +
 | 
		
	
		
			
			|  | 1134 | +		/* Return link-local ip6 */
 | 
		
	
		
			
			|  | 1135 | +		if ( len > sizeof ( ip6 ) )
 | 
		
	
		
			
			|  | 1136 | +			len = sizeof ( ip6 );
 | 
		
	
		
			
			|  | 1137 | +		memcpy ( data, &ip6, len );
 | 
		
	
		
			
			|  | 1138 | +		return sizeof ( ip6 );
 | 
		
	
		
			
			|  | 1139 | +
 | 
		
	
		
			
			|  | 1140 | +	} else if ( setting_cmp ( setting, &len6_setting ) == 0 ) {
 | 
		
	
		
			
			|  | 1141 | +
 | 
		
	
		
			
			|  | 1142 | +		/* Return prefix length */
 | 
		
	
		
			
			|  | 1143 | +		if ( len ) {
 | 
		
	
		
			
			|  | 1144 | +			len6 = data;
 | 
		
	
		
			
			|  | 1145 | +			*len6 = prefix_len;
 | 
		
	
		
			
			|  | 1146 | +		}
 | 
		
	
		
			
			|  | 1147 | +		return sizeof ( *len6 );
 | 
		
	
		
			
			|  | 1148 | +
 | 
		
	
		
			
			|  | 1149 | +	}
 | 
		
	
		
			
			|  | 1150 | +
 | 
		
	
		
			
			|  | 1151 | +	return -ENOENT;
 | 
		
	
		
			
			|  | 1152 | +}
 | 
		
	
		
			
			|  | 1153 | +
 | 
		
	
		
			
			|  | 1154 | +/** IPv6 link-local address settings operations */
 | 
		
	
		
			
			|  | 1155 | +static struct settings_operations ipv6_settings_operations = {
 | 
		
	
		
			
			|  | 1156 | +	.applies = ipv6_applies,
 | 
		
	
		
			
			|  | 1157 | +	.fetch = ipv6_fetch,
 | 
		
	
		
			
			|  | 1158 | +};
 | 
		
	
		
			
			|  | 1159 | +
 | 
		
	
		
			
			|  | 1160 | +/** IPv6 link-local address settings */
 | 
		
	
		
			
			|  | 1161 | +struct ipv6_settings {
 | 
		
	
		
			
			|  | 1162 | +	/** Reference counter */
 | 
		
	
		
			
			|  | 1163 | +	struct refcnt refcnt;
 | 
		
	
		
			
			|  | 1164 | +	/** Settings interface */
 | 
		
	
		
			
			|  | 1165 | +	struct settings settings;
 | 
		
	
		
			
			|  | 1166 | +};
 | 
		
	
		
			
			|  | 1167 | +
 | 
		
	
		
			
			|  | 1168 | +/**
 | 
		
	
		
			
			|  | 1169 | + * Register IPv6 link-local address settings
 | 
		
	
		
			
			|  | 1170 | + *
 | 
		
	
		
			
			|  | 1171 | + * @v netdev		Network device
 | 
		
	
		
			
			|  | 1172 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 1173 | + */
 | 
		
	
		
			
			|  | 1174 | +static int ipv6_register_settings ( struct net_device *netdev ) {
 | 
		
	
		
			
			|  | 1175 | +	struct settings *parent = netdev_settings ( netdev );
 | 
		
	
		
			
			|  | 1176 | +	struct ipv6_settings *ipv6set;
 | 
		
	
		
			
			|  | 1177 | +	int rc;
 | 
		
	
		
			
			|  | 1178 | +
 | 
		
	
		
			
			|  | 1179 | +	/* Allocate and initialise structure */
 | 
		
	
		
			
			|  | 1180 | +	ipv6set = zalloc ( sizeof ( *ipv6set ) );
 | 
		
	
		
			
			|  | 1181 | +	if ( ! ipv6set ) {
 | 
		
	
		
			
			|  | 1182 | +		rc = -ENOMEM;
 | 
		
	
		
			
			|  | 1183 | +		goto err_alloc;
 | 
		
	
		
			
			|  | 1184 | +	}
 | 
		
	
		
			
			|  | 1185 | +	ref_init ( &ipv6set->refcnt, NULL );
 | 
		
	
		
			
			|  | 1186 | +	settings_init ( &ipv6set->settings, &ipv6_settings_operations,
 | 
		
	
		
			
			|  | 1187 | +			&ipv6set->refcnt, &ipv6_scope );
 | 
		
	
		
			
			|  | 1188 | +
 | 
		
	
		
			
			|  | 1189 | +	/* Register settings */
 | 
		
	
		
			
			|  | 1190 | +	if ( ( rc = register_settings ( &ipv6set->settings, parent,
 | 
		
	
		
			
			|  | 1191 | +					IPV6_SETTINGS_NAME ) ) != 0 )
 | 
		
	
		
			
			|  | 1192 | +		goto err_register;
 | 
		
	
		
			
			|  | 1193 | +
 | 
		
	
		
			
			|  | 1194 | + err_register:
 | 
		
	
		
			
			|  | 1195 | +	ref_put ( &ipv6set->refcnt );
 | 
		
	
		
			
			|  | 1196 | + err_alloc:
 | 
		
	
		
			
			|  | 1197 | +	return rc;
 | 
		
	
		
			
			|  | 1198 | +}
 | 
		
	
		
			
			|  | 1199 | +
 | 
		
	
		
			
			| 1091 | 1200 |  /**
 | 
		
	
		
			
			| 1092 | 1201 |   * Create IPv6 network device
 | 
		
	
		
			
			| 1093 | 1202 |   *
 | 
		
	
	
		
			
			|  | @@ -1116,6 +1225,10 @@ static int ipv6_probe ( struct net_device *netdev ) {
 | 
		
	
		
			
			| 1116 | 1225 |  	if ( ! miniroute )
 | 
		
	
		
			
			| 1117 | 1226 |  		return -ENOMEM;
 | 
		
	
		
			
			| 1118 | 1227 |  
 | 
		
	
		
			
			|  | 1228 | +	/* Register link-local address settings */
 | 
		
	
		
			
			|  | 1229 | +	if ( ( rc = ipv6_register_settings ( netdev ) ) != 0 )
 | 
		
	
		
			
			|  | 1230 | +		return rc;
 | 
		
	
		
			
			|  | 1231 | +
 | 
		
	
		
			
			| 1119 | 1232 |  	return 0;
 | 
		
	
		
			
			| 1120 | 1233 |  }
 | 
		
	
		
			
			| 1121 | 1234 |  
 |