@@ -310,10 +310,12 @@ static int wifi_find_radio_aps(struct lyd_node *cifs, const char *radio_name,
310310}
311311
312312/* Generate BSS section for secondary AP (multi-SSID) */
313- static int wifi_gen_bss_section (FILE * hostapd , struct lyd_node * cifs , const char * ifname , struct lyd_node * config )
313+ static int wifi_gen_bss_section (FILE * hostapd , struct lyd_node * cifs , const char * ifname ,
314+ struct lyd_node * config )
314315{
315316 const char * ssid , * hidden , * security_mode , * secret_name , * secret ;
316- struct lyd_node * cif , * wifi , * ap , * security , * secret_node ;
317+ const char * mobility_domain = NULL ;
318+ struct lyd_node * cif , * wifi , * ap , * security , * secret_node , * roaming ;
317319 char bssid [18 ];
318320
319321 /* Find the interface node for this BSS */
@@ -367,28 +369,43 @@ static int wifi_gen_bss_section(FILE *hostapd, struct lyd_node *cifs, const char
367369 }
368370 }
369371
372+ /* Check roaming configuration */
373+ roaming = lydx_get_child (ap , "roaming" );
374+ if (roaming )
375+ mobility_domain = lydx_get_cattr (roaming , "mobility-domain" );
376+
377+
370378 if (!strcmp (security_mode , "open" )) {
371379 fprintf (hostapd , "# Open network\n" );
372380 fprintf (hostapd , "auth_algs=1\n" );
373381 } else if (!strcmp (security_mode , "wpa2-personal" )) {
374382 fprintf (hostapd , "# WPA2-Personal\n" );
375383 fprintf (hostapd , "wpa=2\n" );
376- fprintf (hostapd , "wpa_key_mgmt=WPA-PSK\n" );
384+ if (roaming )
385+ fprintf (hostapd , "wpa_key_mgmt=FT-PSK WPA-PSK\n" );
386+ else
387+ fprintf (hostapd , "wpa_key_mgmt=WPA-PSK\n" );
377388 fprintf (hostapd , "wpa_pairwise=CCMP\n" );
378389 if (secret )
379390 fprintf (hostapd , "wpa_passphrase=%s\n" , secret );
380391 } else if (!strcmp (security_mode , "wpa3-personal" )) {
381392 fprintf (hostapd , "# WPA3-Personal\n" );
382393 fprintf (hostapd , "wpa=2\n" );
383- fprintf (hostapd , "wpa_key_mgmt=SAE\n" );
394+ if (roaming )
395+ fprintf (hostapd , "wpa_key_mgmt=FT-SAE SAE\n" );
396+ else
397+ fprintf (hostapd , "wpa_key_mgmt=SAE\n" );
384398 fprintf (hostapd , "rsn_pairwise=CCMP\n" );
385399 if (secret )
386400 fprintf (hostapd , "sae_password=%s\n" , secret );
387401 fprintf (hostapd , "ieee80211w=2\n" );
388402 } else if (!strcmp (security_mode , "wpa2-wpa3-personal" )) {
389403 fprintf (hostapd , "# WPA2/WPA3 Mixed\n" );
390404 fprintf (hostapd , "wpa=2\n" );
391- fprintf (hostapd , "wpa_key_mgmt=WPA-PSK SAE\n" );
405+ if (roaming )
406+ fprintf (hostapd , "wpa_key_mgmt=FT-PSK FT-SAE WPA-PSK SAE\n" );
407+ else
408+ fprintf (hostapd , "wpa_key_mgmt=WPA-PSK SAE\n" );
392409 fprintf (hostapd , "rsn_pairwise=CCMP\n" );
393410 if (secret ) {
394411 fprintf (hostapd , "wpa_passphrase=%s\n" , secret );
@@ -397,6 +414,15 @@ static int wifi_gen_bss_section(FILE *hostapd, struct lyd_node *cifs, const char
397414 fprintf (hostapd , "ieee80211w=1\n" );
398415 }
399416
417+ /* Roaming configuration (only if enabled) */
418+ if (roaming ) {
419+ fprintf (hostapd , "# Fast roaming (802.11r)\n" );
420+ fprintf (hostapd , "mobility_domain=%s\n" , mobility_domain );
421+ fprintf (hostapd , "ft_over_ds=1\n" );
422+ fprintf (hostapd , "ft_psk_generate_local=1\n" );
423+ fprintf (hostapd , "nas_identifier=%s.%s\n" , ifname , mobility_domain );
424+ }
425+
400426 return 0 ;
401427}
402428
@@ -405,11 +431,11 @@ static int wifi_gen_aps_on_radio(const char *radio_name, struct lyd_node *cifs,
405431 struct lyd_node * radio_node , struct lyd_node * config )
406432{
407433 const char * ssid , * hidden , * security_mode , * secret_name , * secret ;
434+ const char * country , * channel , * band , * primary_ifname ;
435+ const char * mobility_domain = NULL ;
408436 struct lyd_node * primary_cif , * cif ;
409437 struct lyd_node * primary_wifi , * primary_ap ;
410- struct lyd_node * security , * secret_node ;
411- const char * country , * channel , * band ;
412- const char * primary_ifname ;
438+ struct lyd_node * security , * secret_node , * roaming ;
413439 char hostapd_conf [256 ];
414440 char * * ap_list = NULL ;
415441 FILE * hostapd = NULL ;
@@ -455,6 +481,11 @@ static int wifi_gen_aps_on_radio(const char *radio_name, struct lyd_node *cifs,
455481 secret_name = lydx_get_cattr (security , "secret" );
456482 secret = NULL ;
457483
484+ /* Get roaming configuration */
485+ roaming = lydx_get_child (primary_ap , "roaming" );
486+ if (roaming )
487+ mobility_domain = lydx_get_cattr (roaming , "mobility-domain" );
488+
458489 /* Get radio configuration */
459490 country = lydx_get_cattr (radio_node , "country-code" );
460491 band = lydx_get_cattr (radio_node , "band" );
@@ -572,26 +603,51 @@ static int wifi_gen_aps_on_radio(const char *radio_name, struct lyd_node *cifs,
572603 } else if (!strcmp (security_mode , "wpa2-personal" )) {
573604 fprintf (hostapd , "# WPA2-Personal\n" );
574605 fprintf (hostapd , "wpa=2\n" );
575- fprintf (hostapd , "wpa_key_mgmt=WPA-PSK\n" );
606+ if (roaming )
607+ fprintf (hostapd , "wpa_key_mgmt=FT-PSK WPA-PSK\n" );
608+ else
609+ fprintf (hostapd , "wpa_key_mgmt=WPA-PSK\n" );
576610 fprintf (hostapd , "wpa_pairwise=CCMP\n" );
577611 fprintf (hostapd , "wpa_passphrase=%s\n" , secret );
578612 } else if (!strcmp (security_mode , "wpa3-personal" )) {
579613 fprintf (hostapd , "# WPA3-Personal\n" );
580614 fprintf (hostapd , "wpa=2\n" );
581- fprintf (hostapd , "wpa_key_mgmt=SAE\n" );
615+ if (roaming )
616+ fprintf (hostapd , "wpa_key_mgmt=FT-SAE SAE\n" );
617+ else
618+ fprintf (hostapd , "wpa_key_mgmt=SAE\n" );
582619 fprintf (hostapd , "rsn_pairwise=CCMP\n" );
583620 fprintf (hostapd , "sae_password=%s\n" , secret );
584621 fprintf (hostapd , "ieee80211w=2\n" );
585622 } else if (!strcmp (security_mode , "wpa2-wpa3-personal" )) {
586623 fprintf (hostapd , "# WPA2/WPA3 Mixed Mode\n" );
587624 fprintf (hostapd , "wpa=2\n" );
588- fprintf (hostapd , "wpa_key_mgmt=WPA-PSK SAE\n" );
625+ if (roaming )
626+ fprintf (hostapd , "wpa_key_mgmt=FT-PSK FT-SAE WPA-PSK SAE\n" );
627+ else
628+ fprintf (hostapd , "wpa_key_mgmt=WPA-PSK SAE\n" );
589629 fprintf (hostapd , "rsn_pairwise=CCMP\n" );
590630 fprintf (hostapd , "wpa_passphrase=%s\n" , secret );
591631 fprintf (hostapd , "sae_password=%s\n" , secret );
592632 fprintf (hostapd , "ieee80211w=1\n" );
593633 }
594634
635+ /* Roaming configuration (802.11k/r/v) */
636+ if (roaming ) {
637+ fprintf (hostapd , "\n# Fast roaming and seamless handoff (802.11k/r/v)\n" );
638+ fprintf (hostapd , "# 802.11r: Fast BSS Transition\n" );
639+ fprintf (hostapd , "mobility_domain=%s\n" , mobility_domain );
640+ fprintf (hostapd , "ft_over_ds=1\n" );
641+ fprintf (hostapd , "ft_psk_generate_local=1\n" );
642+ fprintf (hostapd , "nas_identifier=%s.%s\n" , primary_ifname , mobility_domain );
643+ fprintf (hostapd , "# 802.11k: Radio Resource Management\n" );
644+ fprintf (hostapd , "rrm_neighbor_report=1\n" );
645+ fprintf (hostapd , "rrm_beacon_report=1\n" );
646+ fprintf (hostapd , "# 802.11v: BSS Transition Management\n" );
647+ fprintf (hostapd , "bss_transition=1\n" );
648+ fprintf (hostapd , "\n" );
649+ }
650+
595651 /* Add BSS sections for secondary APs (multi-SSID) */
596652 for (i = 1 ; i < ap_count ; i ++ ) {
597653 DEBUG ("Adding BSS section for secondary AP %s" , ap_list [i ]);
0 commit comments