Browse Source

Apply WPA patch from Glenn Saberton

Requires some cleanup to be mainlineable, but you get the idea.
tags/1.66
Matt Palmer 10 years ago
parent
commit
f4272c7fb7
10 changed files with 1042 additions and 28 deletions
  1. +1
    -1
      Makefile
  2. +44
    -0
      debian/netcfg-common.templates
  3. +1
    -1
      debian/netcfg-dhcp.templates
  4. +60
    -18
      dhcp.c
  5. +56
    -4
      netcfg.c
  6. +13
    -3
      netcfg.h
  7. +1
    -1
      wireless.c
  8. +423
    -0
      wpa.c
  9. +256
    -0
      wpa_ctrl.c
  10. +187
    -0
      wpa_ctrl.h

+ 1
- 1
Makefile View File

@@ -30,7 +30,7 @@ endif
all: $(TARGETS)

netcfg-static: netcfg-static.o static.o ethtool-lite.o
netcfg: netcfg.o dhcp.o static.o ethtool-lite.o
netcfg: netcfg.o dhcp.o static.o ethtool-lite.o wpa.o wpa_ctrl.o

ethtool-lite: ethtool-lite-test.o
$(CC) -o $@ $<


+ 44
- 0
debian/netcfg-common.templates View File

@@ -62,6 +62,15 @@ _Description: Wireless ESSID for ${iface}:
of the wireless network you would like ${iface} to use. To skip wireless
configuration and continue, leave this field blank.

Template: netcfg/wireless_security_type
Type: select
Choices-C: wep/open, wpa
__Choices: WEP/Open Network, WPA PSK
# :sl2:
_Description: Wireless Network Type for ${iface}:
Choose WEP/Open if the network is open or secured with WEP.
Choose WPA if the network is a WPA PSK protected network.

Template: netcfg/wireless_wep
Type: string
# :sl1:
@@ -86,6 +95,19 @@ _Description: Invalid WEP key
the next screen carefully on how to enter your WEP key correctly, and try
again.

Template: netcfg/invalid_pass
Type: error
# :sl2:
_Description: Invalid passphrase
The WPA PSK passphrase was either too long (more than 64 characters)
or too short (less than 8 characters).

Template: netcfg/wireless_wpa
Type: string
# :sl1:
_Description: WPA passphrase for wireless device ${iface}:
Enter a passphrase for WPA PSK authentication.

Template: netcfg/invalid_essid
Type: error
# :sl2:
@@ -93,6 +115,28 @@ _Description: Invalid ESSID
The ESSID "${essid}" is invalid. ESSIDs may only be up to 32 characters,
but may contain all kinds of characters.

Template: netcfg/wpa_progress
Type: text
# :sl1:
_Description: Attempting to exchange keys with the access point...

Template: netcfg/wpa_progress_note
Type: text
# :sl1:
_Description: This may take some time.

Template: netcfg/wpa_success_note
Type: text
# :sl1:
_Description: WPA connection succeeded

Template: netcfg/wpa_supplicant_failed
Type: note
# :sl1:
_Description: Failure of key exchange and association
The exchange of keys and association with the access point failed.
Please check the WPA parameters you provided.

Template: netcfg/get_hostname
Type: string
Default: debian


+ 1
- 1
debian/netcfg-dhcp.templates View File

@@ -77,7 +77,7 @@ Template: netcfg/dhcp_timeout
Type: string
Description: for internal use; can be preseeded
Timeout for trying DHCP
Default: 15
Default: 25

Template: netcfg/dhcp_ntp_servers
Type: text


+ 60
- 18
dhcp.c View File

@@ -66,13 +66,18 @@ static void netcfg_write_dhcp (char *iface, char *dhostname)
fprintf(fp, "\thostname %s\n", dhostname);
}
if (is_wireless_iface(iface)) {
fprintf(fp, "\t# wireless-* options are implemented by the wireless-tools package\n");
fprintf(fp, "\twireless-mode %s\n",
(mode == MANAGED) ? "managed" : "ad-hoc");
fprintf(fp, "\twireless-essid %s\n",
(essid && *essid) ? essid : "any");
if (wepkey != NULL)
fprintf(fp, "\twireless-key1 %s\n", wepkey);
if (wpa_supplicant_status == WPA_QUEUED) {
fprintf(fp, "\twpa-ssid %s\n", essid);
fprintf(fp, "\twpa-psk %s\n", passphrase);
} else {
fprintf(fp, "\t# wireless-* options are implemented by the wireless-tools package\n");
fprintf(fp, "\twireless-mode %s\n",
(mode == MANAGED) ? "managed" : "ad-hoc");
fprintf(fp, "\twireless-essid %s\n",
(essid && *essid) ? essid : "any");
if (wepkey != NULL)
fprintf(fp, "\twireless-key1 %s\n", wepkey);
}
}
fclose(fp);
}
@@ -289,8 +294,10 @@ int poll_dhcp_client (struct debconfclient *client)
/* show progress bar */
debconf_capb(client, "backup progresscancel");
debconf_progress_start(client, 0, dhcp_seconds, "netcfg/dhcp_progress");
if (debconf_progress_info(client, "netcfg/dhcp_progress_note") == 30)
if (debconf_progress_info(client, "netcfg/dhcp_progress_note") == 30) {
kill_dhcp_client();
goto stop;
}
netcfg_progress_displayed = 1;

/* wait between 2 and dhcp_seconds seconds for a DHCP lease */
@@ -374,20 +381,59 @@ int ask_dhcp_options (struct debconfclient *client)

int ask_wifi_configuration (struct debconfclient *client)
{
enum { ABORT, DONE, ESSID, WEP } wifistate = ESSID;
enum { ABORT, ESSID, SECURITY_TYPE, WEP, WPA, START, DONE } wifistate = ESSID;

extern enum wpa_t wpa_supplicant_status;
if (wpa_supplicant_status != WPA_UNAVAIL)
kill_wpa_supplicant();

for (;;) {
switch (wifistate) {
case ESSID:
wifistate = (netcfg_wireless_set_essid(client, interface, "high") == GO_BACK) ?
ABORT : WEP;
if (wpa_supplicant_status == WPA_UNAVAIL)
wifistate = (netcfg_wireless_set_essid(client, interface, "high") == GO_BACK) ?
ABORT : WEP;
else
wifistate = (netcfg_wireless_set_essid(client, interface, "high") == GO_BACK) ?
ABORT : SECURITY_TYPE;
break;
case SECURITY_TYPE:
{
int ret;
ret = wireless_security_type(client, interface);
if (ret == GO_BACK)
wifistate = ESSID;
else if (ret == REPLY_WPA)
wifistate = WPA;
else
wifistate = WEP;
break;
}
case WEP:
wifistate = (netcfg_wireless_set_wep(client, interface) == GO_BACK) ?
if (wpa_supplicant_status == WPA_UNAVAIL)
wifistate = (netcfg_wireless_set_wep(client, interface) == GO_BACK) ?
ESSID : DONE;
else
wifistate = (netcfg_wireless_set_wep(client, interface) == GO_BACK) ?
SECURITY_TYPE : DONE;
break;
case WPA:
wifistate = (netcfg_set_passphrase(client, interface) == GO_BACK) ?
SECURITY_TYPE : START;
break;
case START:
wifistate = (wpa_supplicant_start(client, interface, essid, passphrase) == GO_BACK) ?
ESSID : DONE;
break;
case ABORT:
return REPLY_ASK_OPTIONS;
break;
case DONE:
return REPLY_CHECK_DHCP;
break;
@@ -565,12 +611,8 @@ int netcfg_activate_dhcp (struct debconfclient *client)
break;
case REPLY_RECONFIGURE_WIFI:
if (ask_wifi_configuration(client) == REPLY_CHECK_DHCP) {
if (dhcp_pid > 0)
state = POLL;
else {
kill_dhcp_client();
state = START;
}
kill_dhcp_client();
state = START;
}
else
state = ASK_OPTIONS;


+ 56
- 4
netcfg.c View File

@@ -33,6 +33,7 @@
#endif
#include "netcfg.h"

enum wpa_t wpa_supplicant_status;
static method_t netcfg_method = DHCP;

response_t netcfg_get_method(struct debconfclient *client)
@@ -69,11 +70,15 @@ int main(int argc, char *argv[])
GET_STATIC,
WCONFIG,
WCONFIG_ESSID,
WCONFIG_SECURITY_TYPE,
WCONFIG_WEP,
WCONFIG_WPA,
START_WPA,
QUIT } state = GET_INTERFACE;

static struct debconfclient *client;
static int requested_wireless_tools = 0;
extern enum wpa_t wpa_supplicant_status;
char **ifaces;
char *defiface = NULL, *defwireless = NULL;
response_t res;
@@ -118,6 +123,13 @@ int main(int argc, char *argv[])
case BACKUP:
return 10;
case GET_INTERFACE:
/* If we have returned from outside of netcfg and want to
* reconfigure networking, check to see if wpasupplicant is
* running, and kill it if it is. If left running when
* the interfaces are taken up and down, it appears to
* leave it in an inconsistant state */
kill_wpa_supplicant();

/* Choose a default by looking for link */
if (get_all_ifs(1, &ifaces) > 1) {
while (*ifaces) {
@@ -264,17 +276,57 @@ int main(int argc, char *argv[])
case WCONFIG_ESSID:
if (netcfg_wireless_set_essid(client, interface, NULL) == GO_BACK)
state = BACKUP;
else
state = WCONFIG_WEP;
else {
init_wpa_supplicant_support();
if (wpa_supplicant_status == WPA_UNAVAIL)
state = WCONFIG_WEP;
else
state = WCONFIG_SECURITY_TYPE;
}
break;

case WCONFIG_SECURITY_TYPE:
{
int ret;
ret = wireless_security_type(client, interface);
if (ret == GO_BACK)
state = WCONFIG_ESSID;
else if (ret == REPLY_WPA)
state = WCONFIG_WPA;
else
state = WCONFIG_WEP;
break;
}

case WCONFIG_WEP:
if (netcfg_wireless_set_wep(client, interface) == GO_BACK)
state = WCONFIG_ESSID;
if (netcfg_wireless_set_wep(client, interface) == GO_BACK)
if (wpa_supplicant_status == WPA_UNAVAIL)
state = WCONFIG_ESSID;
else
state = WCONFIG_SECURITY_TYPE;
else
state = GET_METHOD;
break;

case WCONFIG_WPA:
if (wpa_supplicant_status == WPA_OK) {
di_exec_shell_log("apt-install wpasupplicant");
wpa_supplicant_status = WPA_QUEUED;
}

if (netcfg_set_passphrase(client, interface) == GO_BACK)
state = WCONFIG_SECURITY_TYPE;
else
state = START_WPA;
break;

case START_WPA:
if (wpa_supplicant_start(client, interface, essid, passphrase) == GO_BACK)
state = WCONFIG_ESSID;
else
state = GET_METHOD;
break;

case QUIT:
netcfg_update_entropy();
return 0;


+ 13
- 3
netcfg.h View File

@@ -9,6 +9,8 @@
#define DHCLIENT_CONF "/etc/dhclient.conf"
#define DOMAIN_FILE "/tmp/domain_name"
#define NTP_SERVER_FILE "/tmp/dhcp-ntp-servers"
#define WPASUPP_CTRL "/var/run/wpa_supplicant"
#define WPAPID "/var/run/wpa_supplicant.pid"

#define DEVNAMES "/etc/network/devnames"
#define DEVHOTPLUG "/etc/network/devhotplug"
@@ -16,6 +18,9 @@
#define STAB "/var/run/stab"
#endif

#define WPA_MIN 8 /* minimum passphrase length */
#define WPA_MAX 64 /* maximum passphrase length */

#define _GNU_SOURCE

#include <sys/types.h>
@@ -51,9 +56,10 @@
#define MAXHOSTNAMELEN 63
#endif

typedef enum { NOT_ASKED = 30, GO_BACK } response_t;
typedef enum { NOT_ASKED = 30, GO_BACK, REPLY_WEP, REPLY_WPA } response_t;
typedef enum { DHCP, STATIC, DUNNO } method_t;
typedef enum { ADHOC = 1, MANAGED = 2 } wifimode_t;
extern enum wpa_t { WPA_OK, WPA_QUEUED, WPA_UNAVAIL } wpa_supplicant_status;

extern int netcfg_progress_displayed;
extern int wfd, skfd;
@@ -74,7 +80,7 @@ extern struct in_addr gateway;
extern struct in_addr pointopoint;

/* wireless */
extern char *essid, *wepkey;
extern char *essid, *wepkey, *passphrase;
extern wifimode_t mode;

/* common functions */
@@ -121,10 +127,14 @@ extern void netcfg_write_common (struct in_addr ipaddress, char *hostname,
void netcfg_nameservers_to_array(char *nameservers, struct in_addr array[]);

extern int is_wireless_iface (const char* iface);

extern int netcfg_wireless_set_essid (struct debconfclient *client, char* iface, char* priority);
extern int netcfg_wireless_set_wep (struct debconfclient *client, char* iface);
extern int wireless_security_type (struct debconfclient *client, char* iface);
extern int netcfg_set_passphrase (struct debconfclient *client, char* iface);
extern int init_wpa_supplicant_support (void);
extern int kill_wpa_supplicant (void);

extern int wpa_supplicant_start (struct debconfclient *client, char *iface, char *ssid, char *passphrase);
extern int iface_is_hotpluggable(const char *iface);
extern short find_in_stab (const char *iface);
extern void deconfigure_network(void);


+ 1
- 1
wireless.c View File

@@ -53,7 +53,7 @@ int netcfg_wireless_set_essid (struct debconfclient * client, char *iface, char*
wconf.has_mode = 1;
wconf.mode = mode;

debconf_input(client, priority ? priority : "low", "netcfg/wireless_essid");
debconf_input(client, priority ? priority : "high", "netcfg/wireless_essid");

if (debconf_go(client) == 30)
return GO_BACK;


+ 423
- 0
wpa.c View File

@@ -0,0 +1,423 @@
/*
* WPA module for netcfg
*
* Copyright (C) 2008 Glenn Saberton <gsaberton@foomagic.org>
*
* Licensed under the terms of the GNU General Public License version 2
*
*/

#include "netcfg.h"
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <debian-installer.h>
#include "wpa_ctrl.h"
#include <iwlib.h>

pid_t wpa_supplicant_pid = -1;
enum wpa_t wpa_supplicant_status;
struct wpa_ctrl *ctrl;
char *passphrase = NULL;
static int wpa_is_running = 0;

int init_wpa_supplicant_support(void)
{
if (access("/sbin/wpa_supplicant", F_OK) == 0)
wpa_supplicant_status = WPA_OK;
else {
wpa_supplicant_status = WPA_UNAVAIL;
di_info("Wpasupplicant not found on the system. Disabling WPA options");
}
return 0;
}

int kill_wpa_supplicant(void)
{
pid_t wpa_pid;
FILE *fp;

fp = (fopen(WPAPID, "r"));
if (fp == NULL) {
di_warning("Couldn't read Wpasupplicant pid file, not trying to kill.");
return 0;
}
else {
fscanf(fp, "%d", &wpa_pid);
fclose(fp);
}
if ((kill(wpa_pid, SIGTERM)) == 0)
return 0;
else {
kill(wpa_pid, SIGKILL);
unlink(WPAPID);
return 0;
}
}

int wireless_security_type (struct debconfclient *client, char *iface)
{
int ret = 0 ;
debconf_subst(client, "netcfg/wireless_security_type", "iface", iface);
debconf_input(client, "high", "netcfg/wireless_security_type");
ret = debconf_go(client);

if (ret == 30)
return GO_BACK;

debconf_get(client, "netcfg/wireless_security_type");

if (!strcmp(client->value, "wep/open"))
return REPLY_WEP;
else
return REPLY_WPA;

}

int netcfg_set_passphrase (struct debconfclient *client, char *iface)
{
int ret;
debconf_subst(client, "netcfg/wireless_wpa", "iface", iface);
debconf_input(client, "high", "netcfg/wireless_wpa");
ret = debconf_go(client);

if (ret == 30)
return GO_BACK;

if (passphrase != NULL)
free(passphrase);
debconf_get(client, "netcfg/wireless_wpa");
passphrase = strdup(client->value);

while (strlen(passphrase) < WPA_MIN || strlen(passphrase) > WPA_MAX) {
debconf_subst(client, "netcfg/invalid_pass", "passphrase", passphrase);
debconf_input(client, "critical", "netcfg/invalid_pass");
debconf_go(client);
free(passphrase);

debconf_input(client, "high", "netcfg/wireless_wpa");
ret = debconf_go(client);

if (ret == 30)
return GO_BACK;

debconf_get(client, "netcfg/wireless_wpa");
passphrase = strdup(client->value);
}
return 0;
}

static int start_wpa_daemon(struct debconfclient *client)
{
wpa_supplicant_pid = fork();

if (wpa_supplicant_pid == 0) {
fclose(client->out);
if (execlp("wpa_supplicant", "wpa_supplicant", "-i", interface, "-C",
WPASUPP_CTRL, "-P", WPAPID, "-B", NULL) == -1) {
di_error("could not exec wpasupplicant: %s", strerror(errno));
return 1;
}
else
return 0;
}
else {
waitpid(wpa_supplicant_pid, NULL, 0);
return 0;
}
}

void wpa_daemon_running(void)
{
FILE *fp = fopen(WPAPID, "r");
if (fp) {
wpa_is_running = 1;
fclose(fp);
}
}

static int wpa_connect(char *iface)
{
char *cfile;
int flen, res;
flen = (strlen(WPASUPP_CTRL) + strlen(iface) + 2);
cfile = malloc(flen);
if (cfile == NULL) {
di_info("Can't allocate memory for WPA control iface.");
return 1;
}
res = snprintf(cfile, flen, "%s/%s", WPASUPP_CTRL, iface);
if ((res < 0) || (res >= flen)) {
free(cfile);
return 1;
}
ctrl = wpa_ctrl_open(cfile);
free(cfile);
if (ctrl == NULL) {
di_info("Couldn't connect to wpasupplicant");
return 1;
}
else
return 0;
}

static int netcfg_wpa_cmd (char *cmd)
{
char buf[256];
size_t len;
int ret;
len = sizeof(buf) -1;
ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, NULL);
if (ret < 0) {
di_info("Sending %s to wpasupplicant failed", cmd);
return 1;
}
return 0;
}

static int wpa_set_ssid (char *ssid)
{
int ret, res;
size_t len;
char cmd[256];
char buf[256];
res = snprintf(cmd, sizeof(cmd), "SET_NETWORK 0 %s \"%s\"", "ssid", ssid);
if (res < 0)
return 1;
len = sizeof(buf) -1;
ret = wpa_ctrl_request(ctrl, cmd, sizeof(cmd), buf, &len, NULL);
if (ret != 0) {
di_info("Failed to set the ssid with wpasupplicant");
return 1;
}
return 0;
}

static int wpa_set_psk(char *passphrase)
{
int ret, res;
size_t len;
char buf[256];
char cmd[256];
res = snprintf(cmd, sizeof(cmd), "SET_NETWORK 0 %s \"%s\"", "psk", passphrase);
if (res < 0)
return 1;
len = sizeof(buf) -1;
ret = wpa_ctrl_request(ctrl, cmd, sizeof(cmd), buf, &len, NULL);
if (ret != 0)
return 1;

return 0;
}

static int wpa_status(void)
{
int ret;
size_t len;
char buf[2048];
const char *success = "wpa_state=COMPLETED";
len = sizeof(buf) -1;
ret = wpa_ctrl_request(ctrl, "STATUS", 7, buf, &len, NULL);

if (ret == 0) {
buf[len] = '\0';
di_info("buf = %s", buf);
}
else
return 1;
if (strstr(buf, success) == NULL)
return 1;
else {
di_info("success");
return 0;
}
}

int poll_wpa_supplicant(struct debconfclient *client)
{
int wpa_timeout = 60;
int seconds_slept = 0;
int state = 1;

debconf_capb(client, "backup progresscancel");
debconf_progress_start(client, 0, wpa_timeout, "netcfg/wpa_progress");

for (seconds_slept = 0; seconds_slept <= wpa_timeout; seconds_slept++) {

if (debconf_progress_info(client, "netcfg/wpa_progress_note") == 30)
goto stop;

if (debconf_progress_step(client, 1) == 30)
goto stop;

sleep(1);

if ((seconds_slept <= wpa_timeout) && (seconds_slept % 5) == 0) {
if (!wpa_status()) {
debconf_progress_set(client, wpa_timeout);
debconf_progress_info(client, "netcfg/wpa_success_note");
state = 0;
sleep(2);
goto stop;
}
}
if (seconds_slept == wpa_timeout) {
debconf_progress_stop(client);
debconf_capb(client, "backup");
debconf_capb(client, "");
debconf_input(client, "critical", "netcfg/wpa_supplicant_failed");
debconf_go(client);
debconf_capb(client, "backup");
return 1;
}
}
stop:
debconf_progress_stop(client);
debconf_capb(client, "backup");
if (!state)
return 0;
else
return 1;

}

int wpa_supplicant_start(struct debconfclient *client, char *iface, char *ssid, char *passphrase)
{
int retry = 0;
enum { CHECK_DAEMON,
START_DAEMON,
CONNECT,
PING,
ADD_NETWORK,
SET_ESSID,
SET_PSK,
SET_SCAN_SSID,
ENABLE_NETWORK,
POLL,
ABORT,
SUCCESS } state = CHECK_DAEMON;
for (;;) {
switch(state) {
case CHECK_DAEMON:
wpa_daemon_running();
if (wpa_is_running)
state = CONNECT;
else
state = START_DAEMON;
break;
case START_DAEMON:
if (!start_wpa_daemon(client))
state = CONNECT;
else
state = ABORT;
break;
case CONNECT:
if (wpa_connect(iface) == 0)
state = PING;
else
state = ABORT;
break;
case PING:
/* if the daemon doesn't respond, try and ping
* it and increment retry. If we have done
* this 4 times, something must be wrong
* so bail out. */
retry++;
if (retry > 4)
state = ABORT;
else if (netcfg_wpa_cmd("PING")) {
kill_wpa_supplicant();
state = START_DAEMON;
break;
}
else
state = ADD_NETWORK;
break;
case ADD_NETWORK:
if (wpa_is_running) {
state = SET_ESSID;
break;
}
if (netcfg_wpa_cmd("ADD_NETWORK"))
state = PING;
else
state = SET_ESSID;
break;
case SET_ESSID:
if (wpa_set_ssid(ssid))
state = PING;
else
state = SET_PSK;
break;
case SET_PSK:
if (wpa_set_psk(passphrase))
state = PING;
else
state = SET_SCAN_SSID;
break;
case SET_SCAN_SSID:
if (netcfg_wpa_cmd("SET_NETWORK 0 scan_ssid 1"))
state = PING;
else
state = ENABLE_NETWORK;
break;
case ENABLE_NETWORK:
if (netcfg_wpa_cmd("ENABLE_NETWORK 0"))
state = PING;
else
state = POLL;
break;
case POLL:
if (poll_wpa_supplicant(client))
state = ABORT;
else
state = SUCCESS;
break;
case ABORT:
if (ctrl == NULL)
return GO_BACK;
else {
wpa_ctrl_close(ctrl);
ctrl = NULL;
return GO_BACK;
}
case SUCCESS:
if (ctrl == NULL)
return 0;
else {
wpa_ctrl_close(ctrl);
ctrl = NULL;
return 0;
}
}
}
}

+ 256
- 0
wpa_ctrl.c View File

@@ -0,0 +1,256 @@
/*
* Modifed version of src/common/wpa_ctrl.c from wpa_supplicant, discarding
* all code paths except for CONFIG_CTRL_IFACE_UNIX. Define strlcpy inline,
* it is not provided by GNU libc.
* Copyright (c) 2008, Kel Modderman <kel@otaku42.de>
*
* wpa_supplicant/hostapd control interface library
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*/

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>

#include "wpa_ctrl.h"

/**
* strlcpy - Copy a string with size bound and NUL-termination
* @dest: Destination
* @src: Source
* @siz: Size of the target buffer
* Returns: Total length of the target string (length of src) (not including
* NUL-termination)
*
* This function matches in behavior with the strlcpy(3) function in OpenBSD.
*/
size_t strlcpy(char *dest, const char *src, size_t siz)
{
const char *s = src;
size_t left = siz;

if (left) {
/* Copy string up to the maximum size of the dest buffer */
while (--left != 0) {
if ((*dest++ = *s++) == '\0')
break;
}
}

if (left == 0) {
/* Not enough room for the string; force NUL-termination */
if (siz != 0)
*dest = '\0';
while (*s++)
; /* determine total src string length */
}

return s - src - 1;
}


/**
* struct wpa_ctrl - Internal structure for control interface library
*
* This structure is used by the wpa_supplicant/hostapd control interface
* library to store internal data. Programs using the library should not touch
* this data directly. They can only use the pointer to the data structure as
* an identifier for the control interface connection and use this as one of
* the arguments for most of the control interface library functions.
*/
struct wpa_ctrl {
int s;
struct sockaddr_un local;
struct sockaddr_un dest;
};


struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
{
struct wpa_ctrl *ctrl;
static int counter = 0;
int ret;
size_t res;

ctrl = malloc(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
memset(ctrl, 0, sizeof(*ctrl));

ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
if (ctrl->s < 0) {
free(ctrl);
return NULL;
}

ctrl->local.sun_family = AF_UNIX;
ret = snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
"/tmp/wpa_ctrl_%d-%d", getpid(), counter++);
if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
close(ctrl->s);
free(ctrl);
return NULL;
}
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local)) < 0) {
close(ctrl->s);
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);
free(ctrl);
return NULL;
}
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
sizeof(ctrl->dest)) < 0) {
close(ctrl->s);
unlink(ctrl->local.sun_path);
free(ctrl);
return NULL;
}

return ctrl;
}


void wpa_ctrl_close(struct wpa_ctrl *ctrl)
{
unlink(ctrl->local.sun_path);
close(ctrl->s);
free(ctrl);
}


int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
char *reply, size_t *reply_len,
void (*msg_cb)(char *msg, size_t len))
{
struct timeval tv;
int res;
fd_set rfds;
const char *_cmd;
char *cmd_buf = NULL;
size_t _cmd_len;

{
_cmd = cmd;
_cmd_len = cmd_len;
}

if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
free(cmd_buf);
return -1;
}
free(cmd_buf);

for (;;) {
tv.tv_sec = 2;
tv.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(ctrl->s, &rfds);
res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
if (FD_ISSET(ctrl->s, &rfds)) {
res = recv(ctrl->s, reply, *reply_len, 0);
if (res < 0)
return res;
if (res > 0 && reply[0] == '<') {
/* This is an unsolicited message from
* wpa_supplicant, not the reply to the
* request. Use msg_cb to report this to the
* caller. */
if (msg_cb) {
/* Make sure the message is nul
* terminated. */
if ((size_t) res == *reply_len)
res = (*reply_len) - 1;
reply[res] = '\0';
msg_cb(reply, res);
}
continue;
}
*reply_len = res;
break;
} else {
return -2;
}
}
return 0;
}


static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
{
char buf[10];
int ret;
size_t len = 10;

ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
buf, &len, NULL);
if (ret < 0)
return ret;
if (len == 3 && memcmp(buf, "OK\n", 3) == 0)
return 0;
return -1;
}


int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
{
return wpa_ctrl_attach_helper(ctrl, 1);
}


int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
{
return wpa_ctrl_attach_helper(ctrl, 0);
}


int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
{
int res;

res = recv(ctrl->s, reply, *reply_len, 0);
if (res < 0)
return res;
*reply_len = res;
return 0;
}


int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
{
struct timeval tv;
fd_set rfds;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(ctrl->s, &rfds);
select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
return FD_ISSET(ctrl->s, &rfds);
}


int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
{
return ctrl->s;
}

+ 187
- 0
wpa_ctrl.h View File

@@ -0,0 +1,187 @@
/*
* Unmodifed version of src/common/wpa_ctrl.h from wpa_supplicant.
*
* wpa_supplicant/hostapd control interface library
* Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*/

#ifndef WPA_CTRL_H
#define WPA_CTRL_H

#ifdef __cplusplus
extern "C" {
#endif

/* wpa_supplicant control interface - fixed message prefixes */

/** Interactive request for identity/password/pin */
#define WPA_CTRL_REQ "CTRL-REQ-"

/** Response to identity/password/pin request */
#define WPA_CTRL_RSP "CTRL-RSP-"

/* Event messages with fixed prefix */
/** Authentication completed successfully and data connection enabled */
#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "
/** Disconnected, data connection is not available */
#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED "
/** wpa_supplicant is exiting */
#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
/** Password change was completed successfully */
#define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED "
/** EAP-Request/Notification received */
#define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION "
/** EAP authentication started (EAP-Request/Identity received) */
#define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED "
/** EAP method selected */
#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
/** EAP authentication completed successfully */
#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
/** EAP authentication failed (EAP-Failure received) */
#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
/** New scan results available */
#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "


/* wpa_supplicant/hostapd control interface access */

/**
* wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd
* @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used.
* Returns: Pointer to abstract control interface data or %NULL on failure
*
* This function is used to open a control interface to wpa_supplicant/hostapd.
* ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path
* is configured in wpa_supplicant/hostapd and other programs using the control
* interface need to use matching path configuration.
*/
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);


/**
* wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd
* @ctrl: Control interface data from wpa_ctrl_open()
*
* This function is used to close a control interface.
*/
void wpa_ctrl_close(struct wpa_ctrl *ctrl);


/**
* wpa_ctrl_request - Send a command to wpa_supplicant/hostapd
* @ctrl: Control interface data from wpa_ctrl_open()
* @cmd: Command; usually, ASCII text, e.g., "PING"
* @cmd_len: Length of the cmd in bytes
* @reply: Buffer for the response
* @reply_len: Reply buffer length
* @msg_cb: Callback function for unsolicited messages or %NULL if not used
* Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout
*
* This function is used to send commands to wpa_supplicant/hostapd. Received
* response will be written to reply and reply_len is set to the actual length
* of the reply. This function will block for up to two seconds while waiting
* for the reply. If unsolicited messages are received, the blocking time may
* be longer.
*
* msg_cb can be used to register a callback function that will be called for
* unsolicited messages received while waiting for the command response. These
* messages may be received if wpa_ctrl_request() is called at the same time as
* wpa_supplicant/hostapd is sending such a message. This can happen only if
* the program has used wpa_ctrl_attach() to register itself as a monitor for
* event messages. Alternatively to msg_cb, programs can register two control
* interface connections and use one of them for commands and the other one for
* receiving event messages, in other words, call wpa_ctrl_attach() only for
* the control interface connection that will be used for event messages.
*/
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
char *reply, size_t *reply_len,
void (*msg_cb)(char *msg, size_t len));


/**
* wpa_ctrl_attach - Register as an event monitor for the control interface
* @ctrl: Control interface data from wpa_ctrl_open()
* Returns: 0 on success, -1 on failure, -2 on timeout
*
* This function registers the control interface connection as a monitor for
* wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the
* control interface connection starts receiving event messages that can be
* read with wpa_ctrl_recv().
*/
int wpa_ctrl_attach(struct wpa_ctrl *ctrl);


/**
* wpa_ctrl_detach - Unregister event monitor from the control interface
* @ctrl: Control interface data from wpa_ctrl_open()
* Returns: 0 on success, -1 on failure, -2 on timeout
*
* This function unregisters the control interface connection as a monitor for
* wpa_supplicant/hostapd events, i.e., cancels the registration done with
* wpa_ctrl_attach().
*/
int wpa_ctrl_detach(struct wpa_ctrl *ctrl);


/**
* wpa_ctrl_recv - Receive a pending control interface message
* @ctrl: Control interface data from wpa_ctrl_open()
* @reply: Buffer for the message data
* @reply_len: Length of the reply buffer
* Returns: 0 on success, -1 on failure
*
* This function will receive a pending control interface message. This
* function will block if no messages are available. The received response will
* be written to reply and reply_len is set to the actual length of the reply.
* wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach()
* must have been used to register the control interface as an event monitor.
*/
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len);


/**
* wpa_ctrl_pending - Check whether there are pending event messages
* @ctrl: Control interface data from wpa_ctrl_open()
* Returns: 1 if there are pending messages, 0 if no, or -1 on error
*
* This function will check whether there are any pending control interface
* message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is
* only used for event messages, i.e., wpa_ctrl_attach() must have been used to
* register the control interface as an event monitor.
*/
int wpa_ctrl_pending(struct wpa_ctrl *ctrl);


/**
* wpa_ctrl_get_fd - Get file descriptor used by the control interface
* @ctrl: Control interface data from wpa_ctrl_open()
* Returns: File descriptor used for the connection
*
* This function can be used to get the file descriptor that is used for the
* control interface connection. The returned value can be used, e.g., with
* select() while waiting for multiple events.
*
* The returned file descriptor must not be used directly for sending or
* receiving packets; instead, the library functions wpa_ctrl_request() and
* wpa_ctrl_recv() must be used for this.
*/
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);

#ifdef CONFIG_CTRL_IFACE_UDP
#define WPA_CTRL_IFACE_PORT 9877
#define WPA_GLOBAL_CTRL_IFACE_PORT 9878
#endif /* CONFIG_CTRL_IFACE_UDP */


#ifdef __cplusplus
}
#endif

#endif /* WPA_CTRL_H */

Loading…
Cancel
Save