@@ -18,6 +18,12 @@ LOG_MODULE_REGISTER(net_ipv6, CONFIG_NET_IPV6_LOG_LEVEL);
1818
1919#include <errno.h>
2020#include <stdlib.h>
21+
22+ #if defined(CONFIG_NET_IPV6_IID_STABLE )
23+ #include <zephyr/random/random.h>
24+ #include <mbedtls/md.h>
25+ #endif /* CONFIG_NET_IPV6_IID_STABLE */
26+
2127#include <zephyr/net/net_core.h>
2228#include <zephyr/net/net_pkt.h>
2329#include <zephyr/net/net_stats.h>
@@ -815,6 +821,194 @@ enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback)
815821 return NET_DROP ;
816822}
817823
824+ #if defined(CONFIG_NET_IPV6_IID_STABLE )
825+ static bool check_reserved (const uint8_t * buf , size_t len )
826+ {
827+ /* Subnet-Router Anycast (RFC 4291) */
828+ if (memcmp (buf , (uint8_t * )& (struct in6_addr )IN6ADDR_ANY_INIT , len ) == 0 ) {
829+ return true;
830+ }
831+
832+ /* Reserved Subnet Anycast Addresses (RFC 2526)
833+ * FDFF:FFFF:FFFF:FF80 - FDFF:FFFF:FFFF:FFFF
834+ */
835+ if (buf [0 ] == 0xFD && buf [1 ] == 0xFF && buf [2 ] == 0xFF &&
836+ buf [3 ] == 0xFF && buf [4 ] == 0xFF && buf [5 ] == 0xFF &&
837+ buf [6 ] == 0xFF && buf [7 ] >= 0x80 ) {
838+ return true;
839+ }
840+
841+ return false;
842+ }
843+ #endif /* CONFIG_NET_IPV6_IID_STABLE */
844+
845+ static int gen_stable_iid (uint8_t if_index ,
846+ const struct in6_addr * prefix ,
847+ uint8_t * network_id , size_t network_id_len ,
848+ uint8_t dad_counter ,
849+ uint8_t * stable_iid ,
850+ size_t stable_iid_len )
851+ {
852+ #if defined(CONFIG_NET_IPV6_IID_STABLE )
853+ const mbedtls_md_info_t * md_info = mbedtls_md_info_from_type (MBEDTLS_MD_SHA256 );
854+ mbedtls_md_context_t ctx ;
855+ uint8_t digest [32 ];
856+ int ret ;
857+ static bool once ;
858+ static uint8_t secret_key [16 ]; /* Min 128 bits, RFC 7217 ch 5 */
859+ struct {
860+ struct in6_addr prefix ;
861+ uint8_t if_index ;
862+ uint8_t network_id [16 ];
863+ uint8_t dad_counter ;
864+ } buf = {
865+ .dad_counter = dad_counter ,
866+ };
867+
868+ if (prefix == NULL ) {
869+ NET_ERR ("IPv6 prefix must be set for generating a stable IID" );
870+ return - EINVAL ;
871+ }
872+
873+ memcpy (& buf .prefix , prefix , sizeof (struct in6_addr ));
874+
875+ buf .if_index = if_index ;
876+
877+ if (network_id != NULL && network_id_len > 0 ) {
878+ memcpy (buf .network_id , network_id ,
879+ MIN (network_id_len , sizeof (buf .network_id )));
880+ }
881+
882+ if (!once ) {
883+ sys_rand_get (& secret_key , sizeof (secret_key ));
884+ once = true;
885+ }
886+
887+ mbedtls_md_init (& ctx );
888+ mbedtls_md_setup (& ctx , md_info , true);
889+ ret = mbedtls_md_hmac_starts (& ctx , secret_key , sizeof (secret_key ));
890+ if (ret != 0 ) {
891+ NET_DBG ("Cannot %s hmac (%d)" , "start" , ret );
892+ goto err ;
893+ }
894+
895+ ret = mbedtls_md_hmac_update (& ctx , (uint8_t * )& buf , sizeof (buf ));
896+ if (ret != 0 ) {
897+ NET_DBG ("Cannot %s hmac (%d)" , "update" , ret );
898+ goto err ;
899+ }
900+
901+ ret = mbedtls_md_hmac_finish (& ctx , digest );
902+ if (ret != 0 ) {
903+ NET_DBG ("Cannot %s hmac (%d)" , "finish" , ret );
904+ goto err ;
905+ }
906+
907+ memcpy (stable_iid , digest , MIN (sizeof (digest ), stable_iid_len ));
908+
909+ /* Check reserved addresses, RFC 5453 ch 3 */
910+ if (unlikely (check_reserved (stable_iid , stable_iid_len ))) {
911+ LOG_HEXDUMP_DBG (stable_iid , stable_iid_len ,
912+ "Generated IID is reserved" );
913+ ret = - EINVAL ;
914+ goto err ;
915+ }
916+
917+ err :
918+ mbedtls_md_free (& ctx );
919+
920+ return ret ;
921+ #else
922+ return - ENOTSUP ;
923+ #endif
924+ }
925+
926+ int net_ipv6_addr_generate_iid (struct net_if * iface ,
927+ const struct in6_addr * prefix ,
928+ uint8_t * network_id ,
929+ size_t network_id_len ,
930+ uint8_t dad_counter ,
931+ struct in6_addr * addr ,
932+ struct net_linkaddr * lladdr )
933+ {
934+ struct in6_addr tmp_addr ;
935+ uint8_t if_index ;
936+
937+ if_index = (iface == NULL ) ? net_if_get_by_iface (net_if_get_default ())
938+ : net_if_get_by_iface (iface );
939+
940+ if (IS_ENABLED (CONFIG_NET_IPV6_IID_STABLE )) {
941+ struct in6_addr tmp_prefix = { 0 };
942+ int ret ;
943+
944+ if (prefix == NULL ) {
945+ UNALIGNED_PUT (htonl (0xfe800000 ), & tmp_prefix .s6_addr32 [0 ]);
946+ } else {
947+ UNALIGNED_PUT (prefix -> s6_addr32 [0 ], & tmp_prefix .s6_addr32 [0 ]);
948+ UNALIGNED_PUT (prefix -> s6_addr32 [1 ], & tmp_prefix .s6_addr32 [1 ]);
949+ }
950+
951+ ret = gen_stable_iid (if_index , & tmp_prefix , network_id , network_id_len ,
952+ dad_counter , (uint8_t * )& tmp_addr + 8 ,
953+ sizeof (tmp_addr ) / 2 );
954+ if (ret < 0 ) {
955+ return ret ;
956+ }
957+ }
958+
959+ if (prefix == NULL ) {
960+ UNALIGNED_PUT (htonl (0xfe800000 ), & tmp_addr .s6_addr32 [0 ]);
961+ UNALIGNED_PUT (0 , & tmp_addr .s6_addr32 [1 ]);
962+ } else {
963+ UNALIGNED_PUT (prefix -> s6_addr32 [0 ], & tmp_addr .s6_addr32 [0 ]);
964+ UNALIGNED_PUT (prefix -> s6_addr32 [1 ], & tmp_addr .s6_addr32 [1 ]);
965+ }
966+
967+ if (IS_ENABLED (CONFIG_NET_IPV6_IID_EUI_64 )) {
968+ switch (lladdr -> len ) {
969+ case 2 :
970+ /* The generated IPv6 shall not toggle the
971+ * Universal/Local bit. RFC 6282 ch 3.2.2
972+ */
973+ if (lladdr -> type == NET_LINK_IEEE802154 ) {
974+ UNALIGNED_PUT (0 , & tmp_addr .s6_addr32 [2 ]);
975+ tmp_addr .s6_addr [11 ] = 0xff ;
976+ tmp_addr .s6_addr [12 ] = 0xfe ;
977+ tmp_addr .s6_addr [13 ] = 0U ;
978+ tmp_addr .s6_addr [14 ] = lladdr -> addr [0 ];
979+ tmp_addr .s6_addr [15 ] = lladdr -> addr [1 ];
980+ }
981+
982+ break ;
983+ case 6 :
984+ /* We do not toggle the Universal/Local bit
985+ * in Bluetooth. See RFC 7668 ch 3.2.2
986+ */
987+ memcpy (& tmp_addr .s6_addr [8 ], lladdr -> addr , 3 );
988+ tmp_addr .s6_addr [11 ] = 0xff ;
989+ tmp_addr .s6_addr [12 ] = 0xfe ;
990+ memcpy (& tmp_addr .s6_addr [13 ], lladdr -> addr + 3 , 3 );
991+
992+ if (lladdr -> type == NET_LINK_ETHERNET ) {
993+ tmp_addr .s6_addr [8 ] ^= 0x02 ;
994+ }
995+
996+ break ;
997+ case 8 :
998+ memcpy (& tmp_addr .s6_addr [8 ], lladdr -> addr , lladdr -> len );
999+ tmp_addr .s6_addr [8 ] ^= 0x02 ;
1000+ break ;
1001+ }
1002+ }
1003+
1004+ NET_DBG ("%s IID for iface %d %s" ,
1005+ IS_ENABLED (CONFIG_NET_IPV6_IID_STABLE ) ? "Stable" : "EUI-64" ,
1006+ if_index , net_sprint_ipv6_addr (& tmp_addr ));
1007+
1008+ memcpy (addr , & tmp_addr , sizeof (* addr ));
1009+ return 0 ;
1010+ }
1011+
8181012void net_ipv6_init (void )
8191013{
8201014 net_ipv6_nbr_init ();
0 commit comments