From fc423db233e0ba0541b1863ea59212407289de99 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Wed, 25 Oct 2023 16:57:31 +0530 Subject: [PATCH 3/3] hostapd: create link based hapd ctrl sockets Create link based control sockets to access the link based commands through hostapd_cli. This will create the link interfaces in the name of wlan_link Ex: To fetch link 0 status from wlan0, below command can be used - $ hostapd_cli -i wlan0 -l 0 status If link option (-l) is not provided, the first link of the interface will be selected by default $ hostapd_cli -i wlan0 status The above command applies to the first link of wlan0 (could be link 0 or 1 or anything) On failure of link/interface selection, below error will be observed $ hostapd_cli -i wlan0 -l 2 status Failed to connect to hostapd - wpa_ctrl_open: No such file or directory Signed-off-by: Aditya Kumar Singh --- hostapd/ctrl_iface.c | 16 ++++- hostapd/hostapd_cli.c | 149 +++++++++++++++++++++++++++++++++++++++++- src/ap/hostapd.c | 37 +++++++++++ src/ap/hostapd.h | 3 + src/common/wpa_ctrl.h | 4 ++ 5 files changed, 206 insertions(+), 3 deletions(-) --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -4771,18 +4771,26 @@ static char * hostapd_ctrl_iface_path(st { char *buf; size_t len; + char *ctrl_sock_iface; + +#ifdef CONFIG_IEEE80211BE + ctrl_sock_iface = hapd->ctrl_sock_iface; +#else + ctrl_sock_iface = hapd->conf->iface; +#endif /* CONFIG_IEEE80211BE */ if (hapd->conf->ctrl_interface == NULL) return NULL; len = os_strlen(hapd->conf->ctrl_interface) + - os_strlen(hapd->conf->iface) + 2; + os_strlen(ctrl_sock_iface) + 2; + buf = os_malloc(len); if (buf == NULL) return NULL; os_snprintf(buf, len, "%s/%s", - hapd->conf->ctrl_interface, hapd->conf->iface); + hapd->conf->ctrl_interface, ctrl_sock_iface); buf[len - 1] = '\0'; return buf; } @@ -4953,7 +4961,11 @@ fail: #endif /* ANDROID */ if (os_strlen(hapd->conf->ctrl_interface) + 1 + +#ifdef CONFIG_IEEE80211BE + os_strlen(hapd->ctrl_sock_iface) >= sizeof(addr.sun_path)) +#else os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path)) +#endif /* CONFIG_IEEE80211BE */ goto fail; s = socket(PF_UNIX, SOCK_DGRAM, 0); --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -54,7 +54,11 @@ static void usage(void) fprintf(stderr, "%s\n", hostapd_cli_version); fprintf(stderr, "\n" +#ifdef CONFIG_IEEE80211BE + "usage: hostapd_cli [-p] [-i] [-l] [-hvBr] " +#else "usage: hostapd_cli [-p] [-i] [-hvBr] " +#endif /* CONFIG_IEEE80211BE */ "[-a] \\\n" " [-P] [-G] [command..]\n" "\n" @@ -74,7 +78,13 @@ static void usage(void) " -B run a daemon in the background\n" " -i Interface to listen on (default: first " "interface found in the\n" - " socket path)\n\n"); + " socket path)\n" +#ifdef CONFIG_IEEE80211BE + " -l Link ID of the interface in case of Multi-Link\n" + " Operation (default: first link found in the\n" + " interface)\n" +#endif /* CONFIG_IEEE80211BE */ + "\n"); print_help(stderr, NULL); } @@ -2155,6 +2165,97 @@ static void hostapd_cli_action(struct wp eloop_unregister_read_sock(fd); } +#ifdef CONFIG_IEEE80211BE +/* Returns the link id from link socket name */ +static int get_link_id(char *d_name) +{ + char *ptr; + + ptr = os_strstr(d_name, WPA_CTRL_IFACE_LINK_NAME); + if (!ptr) { + /* this should not happen */ + printf("Failed to find the link\n"); + return -1; + } + ptr += os_strlen(WPA_CTRL_IFACE_LINK_NAME); + + return atoi(ptr); +} + +static void find_first_link(char *d_name, char *first_link_name) +{ + int dir_link_id, first_link = -1; + struct dirent *dent; + char *ptr; + + ptr = os_strstr(d_name, WPA_CTRL_IFACE_LINK_NAME); + if (ptr) { + DIR *dir = opendir(ctrl_iface_dir); + /* Clear the link idx from the interface name + * to find the least first idx + */ + *(ptr + os_strlen(WPA_CTRL_IFACE_LINK_NAME)) = '\0'; + + if (dir) { + while ((dent = readdir(dir))) { + /* skip current and parent dir */ + if (os_strcmp(dent->d_name, ".") == 0 || + os_strcmp(dent->d_name, "..") == 0) + continue; + if (!os_strstr(dent->d_name, d_name)) + continue; + + dir_link_id = get_link_id(dent->d_name); + if (dir_link_id == -1) + continue; + + if (first_link == -1) + first_link = dir_link_id; + else + /* keep the least first link id */ + first_link = first_link < dir_link_id ? + first_link : dir_link_id; + } + closedir(dir); + } + os_snprintf(first_link_name, os_strlen(d_name) + 4, "%s%d", + d_name, first_link); + } else + os_snprintf(first_link_name, os_strlen(d_name) + 2, "%s", + d_name); +} + +static bool ctrl_iface_is_mlo(char *d_name, char *ctrl_ifname_sel) +{ + struct dirent *dent; + DIR *dir = opendir(ctrl_iface_dir); + + if (dir) { + while ((dent = readdir(dir))) { + /* skip current and parent dir */ + if (os_strcmp(dent->d_name, ".") == 0 || + os_strcmp(dent->d_name, "..") == 0) + continue; + + /* skip dir which was not selected in caller */ + if (ctrl_ifname_sel && + !os_strstr(dent->d_name, ctrl_ifname)) + continue; + + /* if any one of the selected dir has "*link*" in it + * then we can assume that interface has links + */ + if (ctrl_ifname_sel && + !os_strstr(dent->d_name, WPA_CTRL_IFACE_LINK_NAME)) + continue; + + return true; + } + } + + return false; +} +#endif /* CONFIG_IEEE80211BE */ int main(int argc, char *argv[]) { @@ -2162,12 +2263,20 @@ int main(int argc, char *argv[]) int c; int daemonize = 0; int reconnect = 0; +#ifdef CONFIG_IEEE80211BE + int link_id = -1; + char buf[128]; +#endif /* CONFIG_IEEE80211BE */ if (os_program_init()) return -1; for (;;) { +#ifdef CONFIG_IEEE80211BE + c = getopt(argc, argv, "a:BhG:i:l:p:P:rs:v"); +#else c = getopt(argc, argv, "a:BhG:i:p:P:rs:v"); +#endif /* CONFIG_IEEE80211BE */ if (c < 0) break; switch (c) { @@ -2202,6 +2311,16 @@ int main(int argc, char *argv[]) case 's': client_socket_dir = optarg; break; +#ifdef CONFIG_IEEE80211BE + case 'l': + link_id = atoi(optarg); + os_memset(buf, '\0', sizeof(buf)); + os_snprintf(buf, sizeof(buf), "%s_%s%d", + ctrl_ifname, WPA_CTRL_IFACE_LINK_NAME, link_id); + os_free(ctrl_ifname); + ctrl_ifname = os_strdup(buf); + break; +#endif /* CONFIG_IEEE80211BE */ default: usage(); return -1; @@ -2218,7 +2337,11 @@ int main(int argc, char *argv[]) return -1; for (;;) { +#ifdef CONFIG_IEEE80211BE + if (ctrl_ifname == NULL || link_id == -1) { +#else if (ctrl_ifname == NULL) { +#endif /* CONFIG_IEEE80211BE */ struct dirent *dent; DIR *dir = opendir(ctrl_iface_dir); if (dir) { @@ -2227,9 +2350,33 @@ int main(int argc, char *argv[]) || os_strcmp(dent->d_name, "..") == 0) continue; +#ifdef CONFIG_IEEE80211BE + if (ctrl_ifname && + !os_strstr(dent->d_name, ctrl_ifname)) + continue; + + if (ctrl_ifname && + !ctrl_iface_is_mlo(dent->d_name, + ctrl_ifname)) { + break; + } + + /* this will sort the link ids and return + * the first link of that interface + */ + os_memset(buf, '\0', sizeof(buf)); + find_first_link(dent->d_name, buf); +#endif /* CONFIG_IEEE80211BE */ printf("Selected interface '%s'\n", +#ifdef CONFIG_IEEE80211BE + buf); + if (ctrl_ifname) + os_free(ctrl_ifname); + ctrl_ifname = os_strdup(buf); +#else dent->d_name); ctrl_ifname = os_strdup(dent->d_name); +#endif /* CONFIG_IEEE80211BE */ break; } closedir(dir); --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -1756,6 +1756,24 @@ static int start_ctrl_iface_bss(struct h return 0; if (hapd->iface->interfaces->ctrl_iface_init(hapd)) { +#ifdef CONFIG_IEEE80211BE + os_memset(hapd->ctrl_sock_iface, '\0', + sizeof(hapd->ctrl_sock_iface)); + os_strlcpy(hapd->ctrl_sock_iface, hapd->conf->iface, + sizeof(hapd->ctrl_sock_iface)); + + if (hapd->conf->mld_ap) { + char buf[128]; + + os_memset(buf, '\0', sizeof(buf)); + os_snprintf(buf, sizeof(buf), "%s_%s%d", + hapd->conf->iface, WPA_CTRL_IFACE_LINK_NAME, + hapd->mld_link_id); + os_memset(hapd->ctrl_sock_iface, '\0', + sizeof(hapd->ctrl_sock_iface)); + os_strlcpy(hapd->ctrl_sock_iface, buf, sizeof(buf)); + } +#endif /* CONFIG_IEEE80211BE */ wpa_printf(MSG_ERROR, "Failed to setup control interface for %s", hapd->conf->iface); @@ -1775,6 +1793,25 @@ static int start_ctrl_iface(struct hosta for (i = 0; i < iface->num_bss; i++) { struct hostapd_data *hapd = iface->bss[i]; +#ifdef CONFIG_IEEE80211BE + os_memset(hapd->ctrl_sock_iface, '\0', + sizeof(hapd->ctrl_sock_iface)); + os_strlcpy(hapd->ctrl_sock_iface, hapd->conf->iface, + sizeof(hapd->ctrl_sock_iface)); + + if (hapd->conf->mld_ap) { + char buf[128]; + + os_memset(buf, '\0', sizeof(buf)); + os_snprintf(buf, sizeof(buf), "%s_%s%d", + hapd->conf->iface, WPA_CTRL_IFACE_LINK_NAME, + hapd->mld_link_id); + os_memset(hapd->ctrl_sock_iface, '\0', + sizeof(hapd->ctrl_sock_iface)); + os_strlcpy(hapd->ctrl_sock_iface, buf, sizeof(buf)); + } +#endif /* CONFIG_IEEE80211BE */ + if (iface->interfaces->ctrl_iface_init(hapd)) { wpa_printf(MSG_ERROR, "Failed to setup control interface for %s", --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -500,6 +500,7 @@ struct hostapd_data { struct hostapd_mld *mld; struct dl_list link; u8 mld_link_id; + char ctrl_sock_iface[IFNAMSIZ + 1]; #endif /* CONFIG_IEEE80211BE */ }; --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -664,4 +664,8 @@ char * wpa_ctrl_get_remote_ifname(struct } #endif +#ifdef CONFIG_IEEE80211BE +#define WPA_CTRL_IFACE_LINK_NAME "link" +#endif /* CONFIG_IEEE80211BE */ + #endif /* WPA_CTRL_H */