@@ -313,7 +313,9 @@ static int wifi_find_radio_aps(struct lyd_node *cifs, const char *radio_name,
313313static int wifi_gen_bss_section (FILE * hostapd , struct lyd_node * cifs , const char * ifname , struct lyd_node * config )
314314{
315315 const char * ssid , * hidden , * security_mode , * secret_name , * secret ;
316- struct lyd_node * cif , * wifi , * ap , * security , * secret_node ;
316+ const char * mobility_domain = NULL ;
317+ struct lyd_node * cif , * wifi , * ap , * security , * secret_node , * roaming ;
318+ bool enable_80211k , enable_80211r , enable_80211v ;
317319 char bssid [18 ];
318320
319321 /* Find the interface node for this BSS */
@@ -367,28 +369,46 @@ static int wifi_gen_bss_section(FILE *hostapd, struct lyd_node *cifs, const char
367369 }
368370 }
369371
372+ /* Check 802.11k/r/v configuration */
373+ roaming = lydx_get_child (ap , "roaming" );
374+ enable_80211k = roaming && lydx_get_bool (roaming , "enable-80211k" );
375+ enable_80211r = roaming && lydx_get_bool (roaming , "enable-80211r" );
376+ enable_80211v = roaming && lydx_get_bool (roaming , "enable-80211v" );
377+
378+ if (enable_80211r )
379+ mobility_domain = lydx_get_cattr (roaming , "mobility-domain" );
380+
370381 if (!strcmp (security_mode , "open" )) {
371382 fprintf (hostapd , "# Open network\n" );
372383 fprintf (hostapd , "auth_algs=1\n" );
373384 } else if (!strcmp (security_mode , "wpa2-personal" )) {
374385 fprintf (hostapd , "# WPA2-Personal\n" );
375386 fprintf (hostapd , "wpa=2\n" );
376- fprintf (hostapd , "wpa_key_mgmt=WPA-PSK\n" );
387+ if (enable_80211r )
388+ fprintf (hostapd , "wpa_key_mgmt=FT-PSK WPA-PSK\n" );
389+ else
390+ fprintf (hostapd , "wpa_key_mgmt=WPA-PSK\n" );
377391 fprintf (hostapd , "wpa_pairwise=CCMP\n" );
378392 if (secret )
379393 fprintf (hostapd , "wpa_passphrase=%s\n" , secret );
380394 } else if (!strcmp (security_mode , "wpa3-personal" )) {
381395 fprintf (hostapd , "# WPA3-Personal\n" );
382396 fprintf (hostapd , "wpa=2\n" );
383- fprintf (hostapd , "wpa_key_mgmt=SAE\n" );
397+ if (enable_80211r )
398+ fprintf (hostapd , "wpa_key_mgmt=FT-SAE SAE\n" );
399+ else
400+ fprintf (hostapd , "wpa_key_mgmt=SAE\n" );
384401 fprintf (hostapd , "rsn_pairwise=CCMP\n" );
385402 if (secret )
386403 fprintf (hostapd , "sae_password=%s\n" , secret );
387404 fprintf (hostapd , "ieee80211w=2\n" );
388405 } else if (!strcmp (security_mode , "wpa2-wpa3-personal" )) {
389406 fprintf (hostapd , "# WPA2/WPA3 Mixed\n" );
390407 fprintf (hostapd , "wpa=2\n" );
391- fprintf (hostapd , "wpa_key_mgmt=WPA-PSK SAE\n" );
408+ if (enable_80211r )
409+ fprintf (hostapd , "wpa_key_mgmt=FT-PSK FT-SAE WPA-PSK SAE\n" );
410+ else
411+ fprintf (hostapd , "wpa_key_mgmt=WPA-PSK SAE\n" );
392412 fprintf (hostapd , "rsn_pairwise=CCMP\n" );
393413 if (secret ) {
394414 fprintf (hostapd , "wpa_passphrase=%s\n" , secret );
@@ -397,6 +417,28 @@ static int wifi_gen_bss_section(FILE *hostapd, struct lyd_node *cifs, const char
397417 fprintf (hostapd , "ieee80211w=1\n" );
398418 }
399419
420+ /* 802.11r: Fast BSS Transition */
421+ if (enable_80211r ) {
422+ fprintf (hostapd , "# Fast BSS Transition (802.11r)\n" );
423+ fprintf (hostapd , "mobility_domain=%s\n" , mobility_domain );
424+ fprintf (hostapd , "ft_over_ds=1\n" );
425+ fprintf (hostapd , "ft_psk_generate_local=1\n" );
426+ fprintf (hostapd , "nas_identifier=%s.%s\n" , ifname , mobility_domain );
427+ }
428+
429+ /* 802.11k: Radio Resource Management */
430+ if (enable_80211k ) {
431+ fprintf (hostapd , "# Radio Resource Management (802.11k)\n" );
432+ fprintf (hostapd , "rrm_neighbor_report=1\n" );
433+ fprintf (hostapd , "rrm_beacon_report=1\n" );
434+ }
435+
436+ /* 802.11v: BSS Transition Management */
437+ if (enable_80211v ) {
438+ fprintf (hostapd , "# BSS Transition Management (802.11v)\n" );
439+ fprintf (hostapd , "bss_transition=1\n" );
440+ }
441+
400442 return 0 ;
401443}
402444
@@ -405,11 +447,13 @@ static int wifi_gen_aps_on_radio(const char *radio_name, struct lyd_node *cifs,
405447 struct lyd_node * radio_node , struct lyd_node * config )
406448{
407449 const char * ssid , * hidden , * security_mode , * secret_name , * secret ;
450+ const char * mobility_domain = NULL ;
408451 struct lyd_node * primary_cif , * cif ;
409452 struct lyd_node * primary_wifi , * primary_ap ;
410- struct lyd_node * security , * secret_node ;
453+ struct lyd_node * security , * secret_node , * roaming ;
411454 const char * country , * channel , * band ;
412455 const char * primary_ifname ;
456+ bool enable_80211k , enable_80211r , enable_80211v ;
413457 char hostapd_conf [256 ];
414458 char * * ap_list = NULL ;
415459 FILE * hostapd = NULL ;
@@ -472,6 +516,15 @@ static int wifi_gen_aps_on_radio(const char *radio_name, struct lyd_node *cifs,
472516 }
473517 }
474518
519+ /* Check 802.11k/r/v configuration */
520+ roaming = lydx_get_child (primary_ap , "roaming" );
521+ enable_80211k = roaming && lydx_get_bool (roaming , "enable-80211k" );
522+ enable_80211r = roaming && lydx_get_bool (roaming , "enable-80211r" );
523+ enable_80211v = roaming && lydx_get_bool (roaming , "enable-80211v" );
524+
525+ if (enable_80211r )
526+ mobility_domain = lydx_get_cattr (roaming , "mobility-domain" );
527+
475528 snprintf (hostapd_conf , sizeof (hostapd_conf ), HOSTAPD_CONF_NEXT , radio_name );
476529
477530 hostapd = fopen (hostapd_conf , "w" );
@@ -572,26 +625,60 @@ static int wifi_gen_aps_on_radio(const char *radio_name, struct lyd_node *cifs,
572625 } else if (!strcmp (security_mode , "wpa2-personal" )) {
573626 fprintf (hostapd , "# WPA2-Personal\n" );
574627 fprintf (hostapd , "wpa=2\n" );
575- fprintf (hostapd , "wpa_key_mgmt=WPA-PSK\n" );
628+ if (enable_80211r )
629+ fprintf (hostapd , "wpa_key_mgmt=FT-PSK WPA-PSK\n" );
630+ else
631+ fprintf (hostapd , "wpa_key_mgmt=WPA-PSK\n" );
576632 fprintf (hostapd , "wpa_pairwise=CCMP\n" );
577633 fprintf (hostapd , "wpa_passphrase=%s\n" , secret );
578634 } else if (!strcmp (security_mode , "wpa3-personal" )) {
579635 fprintf (hostapd , "# WPA3-Personal\n" );
580636 fprintf (hostapd , "wpa=2\n" );
581- fprintf (hostapd , "wpa_key_mgmt=SAE\n" );
637+ if (enable_80211r )
638+ fprintf (hostapd , "wpa_key_mgmt=FT-SAE SAE\n" );
639+ else
640+ fprintf (hostapd , "wpa_key_mgmt=SAE\n" );
582641 fprintf (hostapd , "rsn_pairwise=CCMP\n" );
583642 fprintf (hostapd , "sae_password=%s\n" , secret );
584643 fprintf (hostapd , "ieee80211w=2\n" );
585644 } else if (!strcmp (security_mode , "wpa2-wpa3-personal" )) {
586645 fprintf (hostapd , "# WPA2/WPA3 Mixed Mode\n" );
587646 fprintf (hostapd , "wpa=2\n" );
588- fprintf (hostapd , "wpa_key_mgmt=WPA-PSK SAE\n" );
647+ if (enable_80211r )
648+ fprintf (hostapd , "wpa_key_mgmt=FT-PSK FT-SAE WPA-PSK SAE\n" );
649+ else
650+ fprintf (hostapd , "wpa_key_mgmt=WPA-PSK SAE\n" );
589651 fprintf (hostapd , "rsn_pairwise=CCMP\n" );
590652 fprintf (hostapd , "wpa_passphrase=%s\n" , secret );
591653 fprintf (hostapd , "sae_password=%s\n" , secret );
592654 fprintf (hostapd , "ieee80211w=1\n" );
593655 }
594656
657+ /* 802.11r: Fast BSS Transition */
658+ if (enable_80211r ) {
659+ fprintf (hostapd , "\n# Fast BSS Transition (802.11r)\n" );
660+ fprintf (hostapd , "mobility_domain=%s\n" , mobility_domain );
661+ fprintf (hostapd , "ft_over_ds=1\n" );
662+ fprintf (hostapd , "ft_psk_generate_local=1\n" );
663+ fprintf (hostapd , "nas_identifier=%s.%s\n" , primary_ifname , mobility_domain );
664+ }
665+
666+ /* 802.11k: Radio Resource Management */
667+ if (enable_80211k ) {
668+ fprintf (hostapd , "\n# Radio Resource Management (802.11k)\n" );
669+ fprintf (hostapd , "rrm_neighbor_report=1\n" );
670+ fprintf (hostapd , "rrm_beacon_report=1\n" );
671+ }
672+
673+ /* 802.11v: BSS Transition Management */
674+ if (enable_80211v ) {
675+ fprintf (hostapd , "\n# BSS Transition Management (802.11v)\n" );
676+ fprintf (hostapd , "bss_transition=1\n" );
677+ }
678+
679+ if (enable_80211k || enable_80211r || enable_80211v )
680+ fprintf (hostapd , "\n" );
681+
595682 /* Add BSS sections for secondary APs (multi-SSID) */
596683 for (i = 1 ; i < ap_count ; i ++ ) {
597684 DEBUG ("Adding BSS section for secondary AP %s" , ap_list [i ]);
0 commit comments