这个工具的下载和移植都很简单。移植后能得到 wpa_supplicant
和 wpa_cli
。wpa_supplicant
运行在后台,使用socket与前台进行数据通信。wpa_cli
可以用来进行调试和查看 wpa_supplicant
的运行
配置
在文件 wpa_supplicant.conf
中添加
ctrl_interface=DIR=/var/run/wpa_supplicant
如果没有的话,无法使用wpa_cli
wpa_supplicant
执行时会在 /var/run/wpa_supplicant
下创建 socket
文件
执行
wpa_supplicant -d -Dnl80211 -i ra0 -c /etc/wpa_supplicant/wpa_supplicant.conf &
wpa_supplicant -i ra0 -t -f wpa_supplicant_tmp -Dwext -c /etc/wpa_supplicant/wpa_supplicant.conf &
在C代码中集成wpa_cli
wpa_cli
启动之前的必要条件
- 加载好驱动并且开启了网卡
- 建立/var/run/文件夹
- 建立一个或者使用原有的配置文件,这个文件的第一行如下:
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface
指向的是一个目录,在这个目录中默认会生成一个文件 /var/run/wpa_supplicant/wlan0
,这是 local socket address
,用于我们的程序和后台程序 wpa_supplicant
进行通信(我们必须知道 wpa_supplicant
作为后台服务程序是通过本地socket和客户端进行通信的)
wpa_supplicant后台服务程序
wpa_supplicant -i ra0 -t -f wpa_supplicant_tmp -Dwext -c /etc/wpa_supplicant/wpa_supplicant.conf &
wpa_ctrl函数接口
static struct wpa_ctrl *ctrl_conn;
static struct wpa_ctrl *mon_conn;
static int wpa_cli_open_connection(const char *ifname, int attach)
{
#if defined(CONFIG_CTRL_IFACE_UDP) || defined(CONFIG_CTRL_IFACE_NAMED_PIPE)
ctrl_conn = wpa_ctrl_open(ifname);
if (ctrl_conn == NULL)
return -1;
if (attach && interactive)
mon_conn = wpa_ctrl_open(ifname);
else
mon_conn = NULL;
#else /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
char *cfile = NULL;
int flen, res;
if (ifname == NULL)
return -1;
#ifdef ANDROID
if (access(ctrl_iface_dir, F_OK) < 0) {
cfile = os_strdup(ifname);
if (cfile == NULL)
return -1;
}
#endif /* ANDROID */
if (cfile == NULL) {
flen = os_strlen(ctrl_iface_dir) + os_strlen(ifname) + 2;
cfile = os_malloc(flen);
if (cfile == NULL)
return -1;
res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir,
ifname);
if (res < 0 || res >= flen) {
os_free(cfile);
return -1;
}
}
ctrl_conn = wpa_ctrl_open(cfile);
if (ctrl_conn == NULL) {
os_free(cfile);
return -1;
}
if (attach && interactive)
mon_conn = wpa_ctrl_open(cfile);
else
mon_conn = NULL;
os_free(cfile);
#endif /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
if (mon_conn) {
printf("\033[32m%s[%d]\n\033[0m", __func__, __LINE__);
if (wpa_ctrl_attach(mon_conn) == 0) {
wpa_cli_attached = 1;
if (interactive)
eloop_register_read_sock(
wpa_ctrl_get_fd(mon_conn),
wpa_cli_mon_receive, NULL, NULL);
} else {
printf("Warning: Failed to attach to "
"wpa_supplicant.\n");
return -1;
}
}
return 0;
}
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
{
struct wpa_ctrl *ctrl;
static int counter = 0;
int ret;
size_t res;
int tries = 0;
ctrl = os_malloc(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
os_memset(ctrl, 0, sizeof(*ctrl));
ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
if (ctrl->s < 0) {
os_free(ctrl);
return NULL;
}
ctrl->local.sun_family = AF_UNIX;
counter++;
try_again:
ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
CONFIG_CTRL_IFACE_CLIENT_DIR "/"
CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
(int) getpid(), counter);
if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
close(ctrl->s);
os_free(ctrl);
return NULL;
}
tries++;
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local)) < 0) {
if (errno == EADDRINUSE && tries < 2) {
/*
* getpid() returns unique identifier for this instance
* of wpa_ctrl, so the existing socket file must have
* been left by unclean termination of an earlier run.
* Remove the file and try again.
*/
unlink(ctrl->local.sun_path);
goto try_again;
}
close(ctrl->s);
os_free(ctrl);
return NULL;
}
#ifdef ANDROID
chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
/*
* If the ctrl_path isn't an absolute pathname, assume that
* it's the name of a socket in the Android reserved namespace.
* Otherwise, it's a normal UNIX domain socket appearing in the
* filesystem.
*/
if (ctrl_path != NULL && *ctrl_path != '/') {
char buf[21];
os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
if (socket_local_client_connect(
ctrl->s, buf,
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_DGRAM) < 0) {
close(ctrl->s);
unlink(ctrl->local.sun_path);
os_free(ctrl);
return NULL;
}
return ctrl;
}
#endif /* ANDROID */
ctrl->dest.sun_family = AF_UNIX;
res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
sizeof(ctrl->dest.sun_path));
if (res >= sizeof(ctrl->dest.sun_path)) {
close(ctrl->s);
os_free(ctrl);
return NULL;
}
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
sizeof(ctrl->dest)) < 0) {
close(ctrl->s);
unlink(ctrl->local.sun_path);
os_free(ctrl);
return NULL;
}
return ctrl;
}
从函数中可以看出,使用wpa_ctrl_open打开两次,获得两个wpa_ctrl变量。这些变量代表着后台服务程序wpa_supplicant,通过这两个变量可以和wpa_supplicant进行通信。不过他们的分工有点不同,一个变量用于客户端主动给服务程序发起命令,另外一个变量用于监控wpa_supplicant的是否有数据发给客户端程序。
支持的命令
static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "status", wpa_cli_cmd_status,
cli_cmd_flag_none,
"[verbose] = get current WPA/EAPOL/EAP status" },
{ "ping", wpa_cli_cmd_ping,
cli_cmd_flag_none,
"= pings wpa_supplicant" },
{ "relog", wpa_cli_cmd_relog,
cli_cmd_flag_none,
"= re-open log-file (allow rolling logs)" },
{ "note", wpa_cli_cmd_note,
cli_cmd_flag_none,
"<text> = add a note to wpa_supplicant debug log" },
{ "mib", wpa_cli_cmd_mib,
cli_cmd_flag_none,
"= get MIB variables (dot1x, dot11)" },
{ "help", wpa_cli_cmd_help,
cli_cmd_flag_none,
"= show this usage help" },
{ "interface", wpa_cli_cmd_interface,
cli_cmd_flag_none,
"[ifname] = show interfaces/select interface" },
{ "level", wpa_cli_cmd_level,
cli_cmd_flag_none,
"<debug level> = change debug level" },
{ "license", wpa_cli_cmd_license,
cli_cmd_flag_none,
"= show full wpa_cli license" },
{ "quit", wpa_cli_cmd_quit,
cli_cmd_flag_none,
"= exit wpa_cli" },
{ "set", wpa_cli_cmd_set,
cli_cmd_flag_none,
"= set variables (shows list of variables when run without "
"arguments)" },
{ "get", wpa_cli_cmd_get,
cli_cmd_flag_none,
"<name> = get information" },
{ "logon", wpa_cli_cmd_logon,
cli_cmd_flag_none,
"= IEEE 802.1X EAPOL state machine logon" },
{ "logoff", wpa_cli_cmd_logoff,
cli_cmd_flag_none,
"= IEEE 802.1X EAPOL state machine logoff" },
{ "pmksa", wpa_cli_cmd_pmksa,
cli_cmd_flag_none,
"= show PMKSA cache" },
{ "reassociate", wpa_cli_cmd_reassociate,
cli_cmd_flag_none,
"= force reassociation" },
{ "preauthenticate", wpa_cli_cmd_preauthenticate,
cli_cmd_flag_none,
"<BSSID> = force preauthentication" },
{ "identity", wpa_cli_cmd_identity,
cli_cmd_flag_none,
"<network id> <identity> = configure identity for an SSID" },
{ "password", wpa_cli_cmd_password,
cli_cmd_flag_sensitive,
"<network id> <password> = configure password for an SSID" },
{ "new_password", wpa_cli_cmd_new_password,
cli_cmd_flag_sensitive,
"<network id> <password> = change password for an SSID" },
{ "pin", wpa_cli_cmd_pin,
cli_cmd_flag_sensitive,
"<network id> <pin> = configure pin for an SSID" },
{ "otp", wpa_cli_cmd_otp,
cli_cmd_flag_sensitive,
"<network id> <password> = configure one-time-password for an SSID"
},
{ "passphrase", wpa_cli_cmd_passphrase,
cli_cmd_flag_sensitive,
"<network id> <passphrase> = configure private key passphrase\n"
" for an SSID" },
{ "bssid", wpa_cli_cmd_bssid,
cli_cmd_flag_none,
"<network id> <BSSID> = set preferred BSSID for an SSID" },
{ "blacklist", wpa_cli_cmd_blacklist,
cli_cmd_flag_none,
"<BSSID> = add a BSSID to the blacklist\n"
"blacklist clear = clear the blacklist\n"
"blacklist = display the blacklist" },
{ "log_level", wpa_cli_cmd_log_level,
cli_cmd_flag_none,
"<level> [<timestamp>] = update the log level/timestamp\n"
"log_level = display the current log level and log options" },
{ "list_networks", wpa_cli_cmd_list_networks,
cli_cmd_flag_none,
"= list configured networks" },
{ "select_network", wpa_cli_cmd_select_network,
cli_cmd_flag_none,
"<network id> = select a network (disable others)" },
{ "enable_network", wpa_cli_cmd_enable_network,
cli_cmd_flag_none,
"<network id> = enable a network" },
{ "disable_network", wpa_cli_cmd_disable_network,
cli_cmd_flag_none,
"<network id> = disable a network" },
{ "add_network", wpa_cli_cmd_add_network,
cli_cmd_flag_none,
"= add a network" },
{ "remove_network", wpa_cli_cmd_remove_network,
cli_cmd_flag_none,
"<network id> = remove a network" },
{ "set_network", wpa_cli_cmd_set_network,
cli_cmd_flag_sensitive,
"<network id> <variable> <value> = set network variables (shows\n"
" list of variables when run without arguments)" },
{ "get_network", wpa_cli_cmd_get_network,
cli_cmd_flag_none,
"<network id> <variable> = get network variables" },
{ "save_config", wpa_cli_cmd_save_config,
cli_cmd_flag_none,
"= save the current configuration" },
{ "disconnect", wpa_cli_cmd_disconnect,
cli_cmd_flag_none,
"= disconnect and wait for reassociate/reconnect command before\n"
" connecting" },
{ "reconnect", wpa_cli_cmd_reconnect,
cli_cmd_flag_none,
"= like reassociate, but only takes effect if already disconnected"
},
{ "scan", wpa_cli_cmd_scan,
cli_cmd_flag_none,
"= request new BSS scan" },
{ "scan_results", wpa_cli_cmd_scan_results,
cli_cmd_flag_none,
"= get latest scan results" },
{ "bss", wpa_cli_cmd_bss,
cli_cmd_flag_none,
"<<idx> | <bssid>> = get detailed scan result info" },
{ "get_capability", wpa_cli_cmd_get_capability,
cli_cmd_flag_none,
"<eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilies" },
{ "reconfigure", wpa_cli_cmd_reconfigure,
cli_cmd_flag_none,
"= force wpa_supplicant to re-read its configuration file" },
{ "terminate", wpa_cli_cmd_terminate,
cli_cmd_flag_none,
"= terminate wpa_supplicant" },
{ "interface_add", wpa_cli_cmd_interface_add,
cli_cmd_flag_none,
"<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n"
" <bridge_name> = adds new interface, all parameters but <ifname>\n"
" are optional" },
{ "interface_remove", wpa_cli_cmd_interface_remove,
cli_cmd_flag_none,
"<ifname> = removes the interface" },
{ "interface_list", wpa_cli_cmd_interface_list,
cli_cmd_flag_none,
"= list available interfaces" },
{ "ap_scan", wpa_cli_cmd_ap_scan,
cli_cmd_flag_none,
"<value> = set ap_scan parameter" },
{ "scan_interval", wpa_cli_cmd_scan_interval,
cli_cmd_flag_none,
"<value> = set scan_interval parameter (in seconds)" },
{ "bss_expire_age", wpa_cli_cmd_bss_expire_age,
cli_cmd_flag_none,
"<value> = set BSS expiration age parameter" },
{ "bss_expire_count", wpa_cli_cmd_bss_expire_count,
cli_cmd_flag_none,
"<value> = set BSS expiration scan count parameter" },
{ "stkstart", wpa_cli_cmd_stkstart,
cli_cmd_flag_none,
"<addr> = request STK negotiation with <addr>" },
{ "ft_ds", wpa_cli_cmd_ft_ds,
cli_cmd_flag_none,
"<addr> = request over-the-DS FT with <addr>" },
{ "wps_pbc", wpa_cli_cmd_wps_pbc,
cli_cmd_flag_none,
"[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" },
{ "wps_pin", wpa_cli_cmd_wps_pin,
cli_cmd_flag_sensitive,
"<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
"hardcoded)" },
{ "wps_check_pin", wpa_cli_cmd_wps_check_pin,
cli_cmd_flag_sensitive,
"<PIN> = verify PIN checksum" },
{ "wps_cancel", wpa_cli_cmd_wps_cancel, cli_cmd_flag_none,
"Cancels the pending WPS operation" },
#ifdef CONFIG_WPS_OOB
{ "wps_oob", wpa_cli_cmd_wps_oob,
cli_cmd_flag_sensitive,
"<DEV_TYPE> <PATH> <METHOD> [DEV_NAME] = start WPS OOB" },
#endif /* CONFIG_WPS_OOB */
{ "wps_reg", wpa_cli_cmd_wps_reg,
cli_cmd_flag_sensitive,
"<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
{ "wps_ap_pin", wpa_cli_cmd_wps_ap_pin,
cli_cmd_flag_sensitive,
"[params..] = enable/disable AP PIN" },
{ "wps_er_start", wpa_cli_cmd_wps_er_start,
cli_cmd_flag_none,
"[IP address] = start Wi-Fi Protected Setup External Registrar" },
{ "wps_er_stop", wpa_cli_cmd_wps_er_stop,
cli_cmd_flag_none,
"= stop Wi-Fi Protected Setup External Registrar" },
{ "wps_er_pin", wpa_cli_cmd_wps_er_pin,
cli_cmd_flag_sensitive,
"<UUID> <PIN> = add an Enrollee PIN to External Registrar" },
{ "wps_er_pbc", wpa_cli_cmd_wps_er_pbc,
cli_cmd_flag_none,
"<UUID> = accept an Enrollee PBC using External Registrar" },
{ "wps_er_learn", wpa_cli_cmd_wps_er_learn,
cli_cmd_flag_sensitive,
"<UUID> <PIN> = learn AP configuration" },
{ "wps_er_set_config", wpa_cli_cmd_wps_er_set_config,
cli_cmd_flag_none,
"<UUID> <network id> = set AP configuration for enrolling" },
{ "wps_er_config", wpa_cli_cmd_wps_er_config,
cli_cmd_flag_sensitive,
"<UUID> <PIN> <SSID> <auth> <encr> <key> = configure AP" },
{ "ibss_rsn", wpa_cli_cmd_ibss_rsn,
cli_cmd_flag_none,
"<addr> = request RSN authentication with <addr> in IBSS" },
#ifdef CONFIG_AP
{ "sta", wpa_cli_cmd_sta,
cli_cmd_flag_none,
"<addr> = get information about an associated station (AP)" },
{ "all_sta", wpa_cli_cmd_all_sta,
cli_cmd_flag_none,
"= get information about all associated stations (AP)" },
#endif /* CONFIG_AP */
{ "suspend", wpa_cli_cmd_suspend, cli_cmd_flag_none,
"= notification of suspend/hibernate" },
{ "resume", wpa_cli_cmd_resume, cli_cmd_flag_none,
"= notification of resume/thaw" },
{ "drop_sa", wpa_cli_cmd_drop_sa, cli_cmd_flag_none,
"= drop SA without deauth/disassoc (test command)" },
{ "roam", wpa_cli_cmd_roam,
cli_cmd_flag_none,
"<addr> = roam to the specified BSS" },
#ifdef CONFIG_P2P
{ "p2p_find", wpa_cli_cmd_p2p_find, cli_cmd_flag_none,
"[timeout] [type=*] = find P2P Devices for up-to timeout seconds" },
{ "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, cli_cmd_flag_none,
"= stop P2P Devices search" },
{ "p2p_connect", wpa_cli_cmd_p2p_connect, cli_cmd_flag_none,
"<addr> <\"pbc\"|PIN> = connect to a P2P Devices" },
{ "p2p_listen", wpa_cli_cmd_p2p_listen, cli_cmd_flag_none,
"[timeout] = listen for P2P Devices for up-to timeout seconds" },
{ "p2p_group_remove", wpa_cli_cmd_p2p_group_remove, cli_cmd_flag_none,
"<ifname> = remove P2P group interface (terminate group if GO)" },
{ "p2p_group_add", wpa_cli_cmd_p2p_group_add, cli_cmd_flag_none,
"= add a new P2P group (local end as GO)" },
{ "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc, cli_cmd_flag_none,
"<addr> <method> = request provisioning discovery" },
{ "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase,
cli_cmd_flag_none,
"= get the passphrase for a group (GO only)" },
{ "p2p_serv_disc_req", wpa_cli_cmd_p2p_serv_disc_req,
cli_cmd_flag_none,
"<addr> <TLVs> = schedule service discovery request" },
{ "p2p_serv_disc_cancel_req", wpa_cli_cmd_p2p_serv_disc_cancel_req,
cli_cmd_flag_none,
"<id> = cancel pending service discovery request" },
{ "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp,
cli_cmd_flag_none,
"<freq> <addr> <dialog token> <TLVs> = service discovery response" },
{ "p2p_service_update", wpa_cli_cmd_p2p_service_update,
cli_cmd_flag_none,
"= indicate change in local services" },
{ "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external,
cli_cmd_flag_none,
"<external> = set external processing of service discovery" },
{ "p2p_service_flush", wpa_cli_cmd_p2p_service_flush,
cli_cmd_flag_none,
"= remove all stored service entries" },
{ "p2p_service_add", wpa_cli_cmd_p2p_service_add,
cli_cmd_flag_none,
"<bonjour|upnp> <query|version> <response|service> = add a local "
"service" },
{ "p2p_service_del", wpa_cli_cmd_p2p_service_del,
cli_cmd_flag_none,
"<bonjour|upnp> <query|version> [|service] = remove a local "
"service" },
{ "p2p_reject", wpa_cli_cmd_p2p_reject,
cli_cmd_flag_none,
"<addr> = reject connection attempts from a specific peer" },
{ "p2p_invite", wpa_cli_cmd_p2p_invite,
cli_cmd_flag_none,
"<cmd> [peer=addr] = invite peer" },
{ "p2p_peers", wpa_cli_cmd_p2p_peers, cli_cmd_flag_none,
"[discovered] = list known (optionally, only fully discovered) P2P "
"peers" },
{ "p2p_peer", wpa_cli_cmd_p2p_peer, cli_cmd_flag_none,
"<address> = show information about known P2P peer" },
{ "p2p_set", wpa_cli_cmd_p2p_set, cli_cmd_flag_none,
"<field> <value> = set a P2P parameter" },
{ "p2p_flush", wpa_cli_cmd_p2p_flush, cli_cmd_flag_none,
"= flush P2P state" },
{ "p2p_cancel", wpa_cli_cmd_p2p_cancel, cli_cmd_flag_none,
"= cancel P2P group formation" },
{ "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize, cli_cmd_flag_none,
"<address> = unauthorize a peer" },
{ "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, cli_cmd_flag_none,
"[<duration> <interval>] [<duration> <interval>] = request GO "
"presence" },
{ "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, cli_cmd_flag_none,
"[<period> <interval>] = set extended listen timing" },
#endif /* CONFIG_P2P */
#ifdef CONFIG_INTERWORKING
{ "fetch_anqp", wpa_cli_cmd_fetch_anqp, cli_cmd_flag_none,
"= fetch ANQP information for all APs" },
{ "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, cli_cmd_flag_none,
"= stop fetch_anqp operation" },
{ "interworking_select", wpa_cli_cmd_interworking_select,
cli_cmd_flag_none,
"[auto] = perform Interworking network selection" },
{ "interworking_connect", wpa_cli_cmd_interworking_connect,
cli_cmd_flag_none,
"<BSSID> = connect using Interworking credentials" },
{ "anqp_get", wpa_cli_cmd_anqp_get, cli_cmd_flag_none,
"<addr> <info id>[,<info id>]... = request ANQP information" },
#endif /* CONFIG_INTERWORKING */
{ "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, cli_cmd_flag_none,
"<0/1> = disable/enable automatic reconnection" },
{ "tdls_discover", wpa_cli_cmd_tdls_discover,
cli_cmd_flag_none,
"<addr> = request TDLS discovery with <addr>" },
{ "tdls_setup", wpa_cli_cmd_tdls_setup,
cli_cmd_flag_none,
"<addr> = request TDLS setup with <addr>" },
{ "tdls_teardown", wpa_cli_cmd_tdls_teardown,
cli_cmd_flag_none,
"<addr> = tear down TDLS with <addr>" },
{ "signal_poll", wpa_cli_cmd_signal_poll,
cli_cmd_flag_none,
"= get signal parameters" },
{ NULL, NULL, cli_cmd_flag_none, NULL }
};
在C语言中集成wpa_cli
简化不使用监控socket代码如下:
#ifndef CONFIG_CTRL_IFACE_CLIENT_DIR
#define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp"
#endif
#ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX
#define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_"
#endif
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
{
struct wpa_ctrl *ctrl = NULL;
static int counter = 0;
int ret;
size_t res;
int tries = 0;
ctrl = GxCore_Mallocz(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
memset(ctrl, 0, sizeof(*ctrl));
ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
if (ctrl->s < 0) {
GXCORE_FREE(ctrl);
return NULL;
}
ctrl->local.sun_family = AF_UNIX;
counter++;
try_again:
ret = snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
CONFIG_CTRL_IFACE_CLIENT_DIR "/"
CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
(int) getpid(), counter);
if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
close(ctrl->s);
GXCORE_FREE(ctrl);
return NULL;
}
tries++;
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local)) < 0) {
if (errno == EADDRINUSE && tries < 2) {
/*
* getpid() returns unique identifier for this instance
* of wpa_ctrl, so the existing socket file must have
* been left by unclean termination of an earlier run.
* Remove the file and try again.
*/
unlink(ctrl->local.sun_path);
goto try_again;
}
close(ctrl->s);
GXCORE_FREE(ctrl);
return NULL;
}
ctrl->dest.sun_family = AF_UNIX;
res = strlcpy(ctrl->dest.sun_path, ctrl_path,
sizeof(ctrl->dest.sun_path));
if (res >= sizeof(ctrl->dest.sun_path)) {
close(ctrl->s);
GXCORE_FREE(ctrl);
return NULL;
}
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
sizeof(ctrl->dest)) < 0) {
close(ctrl->s);
unlink(ctrl->local.sun_path);
GXCORE_FREE(ctrl);
return NULL;
}
return ctrl;
}
static int wpa_cli_open_connection(const char *ifname, int attach)
{
char *cfile = NULL;
int flen, res;
if (ifname == NULL)
return -1;
if (cfile == NULL) {
flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
cfile = GxCore_Mallocz(flen);
if (cfile == NULL)
return -1;
res = snprintf(cfile, flen, "%s/%s", ctrl_iface_dir,
ifname);
if (res < 0 || res >= flen) {
GXCORE_FREE(cfile);
return -1;
}
}
ctrl_conn = wpa_ctrl_open(cfile);
if (ctrl_conn == NULL) {
GXCORE_FREE(cfile);
return -1;
}
GXCORE_FREE(cfile);
return 0;
}
static void wpa_ctrl_close(struct wpa_ctrl *ctrl)
{
if (ctrl == NULL)
return;
unlink(ctrl->local.sun_path);
if (ctrl->s >= 0)
close(ctrl->s);
GXCORE_FREE(ctrl);
ctrl = NULL;
}
static void wpa_cli_close_connection(void)
{
if (ctrl_conn == NULL)
return;
wpa_ctrl_close(ctrl_conn);
ctrl_conn = NULL;
}
static void wpa_cli_cleanup(void)
{
wpa_cli_close_connection();
}
static int wpa_cli(const char *ifname, char *cmd)
{
int ret = 0;
char *argv[1] = {};
argv[0] = cmd;
GXCORE_FREE(ctrl_ifname);
ctrl_ifname = GxCore_Strdup(ifname);
if (wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
//printf("Failed to connect to wpa_supplicant - wpa_ctrl_open\n");
GXCORE_FREE(ctrl_ifname);
return -1;
}
ret = wpa_request(ctrl_conn, 1, &argv[0]);
GXCORE_FREE(ctrl_ifname);
wpa_cli_cleanup();
return ret;
}