summaryrefslogtreecommitdiffstats
path: root/contrib/wpa_supplicant/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/wpa_supplicant/config.c')
-rw-r--r--contrib/wpa_supplicant/config.c1272
1 files changed, 886 insertions, 386 deletions
diff --git a/contrib/wpa_supplicant/config.c b/contrib/wpa_supplicant/config.c
index 26307cf..2bba4ab 100644
--- a/contrib/wpa_supplicant/config.c
+++ b/contrib/wpa_supplicant/config.c
@@ -1,5 +1,5 @@
/*
- * WPA Supplicant / Configuration file parser
+ * WPA Supplicant / Configuration parser and common functions
* Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
@@ -18,63 +18,40 @@
#include "common.h"
#include "wpa.h"
-#include "config.h"
#include "sha1.h"
#include "wpa_supplicant.h"
#include "eapol_sm.h"
#include "eap.h"
+#include "l2_packet.h"
#include "config.h"
+/*
+ * Structure for network configuration parsing. This data is used to implement
+ * a generic parser for each network block variable. The table of configuration
+ * variables is defined below in this file (ssid_fields[]).
+ */
struct parse_data {
+ /* Configuration variable name */
char *name;
- int (*parser)(struct parse_data *data, int line, const char *value);
- void *param1, *param2, *param3, *param4;
- struct wpa_ssid *ssid;
- int key_data;
-};
+ /* Parser function for this variable */
+ int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid,
+ int line, const char *value);
-static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line)
-{
- char *pos, *end, *sstart;
-
- while (fgets(s, size, stream)) {
- (*line)++;
- s[size - 1] = '\0';
- pos = s;
-
- while (*pos == ' ' || *pos == '\t' || *pos == '\r')
- pos++;
- if (*pos == '#' || *pos == '\n' || *pos == '\0' ||
- *pos == '\r')
- continue;
-
- /* Remove # comments unless they are within a double quoted
- * string. Remove trailing white space. */
- sstart = strchr(pos, '"');
- if (sstart)
- sstart = strchr(sstart + 1, '"');
- if (!sstart)
- sstart = pos;
- end = strchr(sstart, '#');
- if (end)
- *end-- = '\0';
- else
- end = pos + strlen(pos) - 1;
- while (end > pos &&
- (*end == '\n' || *end == ' ' || *end == '\t' ||
- *end == '\r')) {
- *end-- = '\0';
- }
- if (*pos == '\0')
- continue;
+ /* Writer function (i.e., to get the variable in text format from
+ * internal presentation). */
+ char * (*writer)(const struct parse_data *data, struct wpa_ssid *ssid);
- return pos;
- }
+ /* Variable specific parameters for the parser. */
+ void *param1, *param2, *param3, *param4;
- return NULL;
-}
+ /* 0 = this variable can be included in debug output
+ * 1 = this variable contains key/private data and it must not be
+ * included in debug output unless explicitly requested
+ */
+ int key_data;
+};
static char * wpa_config_parse_string(const char *value, size_t *len)
@@ -90,7 +67,7 @@ static char * wpa_config_parse_string(const char *value, size_t *len)
return strdup(value);
} else {
u8 *str;
- int hlen = strlen(value);
+ size_t hlen = strlen(value);
if (hlen % 1)
return NULL;
*len = hlen / 2;
@@ -106,14 +83,15 @@ static char * wpa_config_parse_string(const char *value, size_t *len)
}
-static int wpa_config_parse_str(struct parse_data *data,
+static int wpa_config_parse_str(const struct parse_data *data,
+ struct wpa_ssid *ssid,
int line, const char *value)
{
size_t res_len, *dst_len;
char **dst;
- dst = (char **) (((u8 *) data->ssid) + (long) data->param1);
- dst_len = (size_t *) (((u8 *) data->ssid) + (long) data->param2);
+ dst = (char **) (((u8 *) ssid) + (long) data->param1);
+ dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2);
free(*dst);
*dst = wpa_config_parse_string(value, &res_len);
@@ -155,12 +133,91 @@ static int wpa_config_parse_str(struct parse_data *data,
}
-static int wpa_config_parse_int(struct parse_data *data,
+static int is_hex(const u8 *data, size_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (data[i] < 32 || data[i] >= 127)
+ return 1;
+ }
+ return 0;
+}
+
+
+static char * wpa_config_write_string_ascii(const u8 *value, size_t len)
+{
+ int i;
+ char *buf, *pos, *end;
+
+ pos = buf = malloc(len + 3);
+ if (buf == NULL)
+ return NULL;
+ end = buf + len + 3;
+ pos += snprintf(pos, end - pos, "\"");
+ for (i = 0; i < len; i++)
+ pos += snprintf(pos, end - pos, "%c", value[i]);
+ pos += snprintf(pos, end - pos, "\"");
+
+ return buf;
+}
+
+
+static char * wpa_config_write_string_hex(const u8 *value, size_t len)
+{
+ int i;
+ char *buf, *pos, *end;
+
+ pos = buf = malloc(2 * len + 1);
+ if (buf == NULL)
+ return NULL;
+ memset(buf, 0, 2 * len + 1);
+ end = buf + 2 * len + 1;
+ for (i = 0; i < len; i++)
+ pos += snprintf(pos, end - pos, "%02x", value[i]);
+
+ return buf;
+}
+
+
+static char * wpa_config_write_string(const u8 *value, size_t len)
+{
+ if (value == NULL)
+ return NULL;
+
+ if (is_hex(value, len))
+ return wpa_config_write_string_hex(value, len);
+ else
+ return wpa_config_write_string_ascii(value, len);
+}
+
+
+static char * wpa_config_write_str(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ size_t len;
+ char **src;
+
+ src = (char **) (((u8 *) ssid) + (long) data->param1);
+ if (*src == NULL)
+ return NULL;
+
+ if (data->param2)
+ len = *((size_t *) (((u8 *) ssid) + (long) data->param2));
+ else
+ len = strlen(*src);
+
+ return wpa_config_write_string((const u8 *) *src, len);
+}
+
+
+static int wpa_config_parse_int(const struct parse_data *data,
+ struct wpa_ssid *ssid,
int line, const char *value)
{
int *dst;
- dst = (int *) (((u8 *) data->ssid) + (long) data->param1);
+ dst = (int *) (((u8 *) ssid) + (long) data->param1);
*dst = atoi(value);
wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
@@ -184,26 +241,60 @@ static int wpa_config_parse_int(struct parse_data *data,
}
-static int wpa_config_parse_bssid(struct parse_data *data, int line,
+static char * wpa_config_write_int(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ int *src;
+ char *value;
+
+ src = (int *) (((u8 *) ssid) + (long) data->param1);
+
+ value = malloc(20);
+ if (value == NULL)
+ return NULL;
+ snprintf(value, 20, "%d", *src);
+ return value;
+}
+
+
+static int wpa_config_parse_bssid(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
- if (hwaddr_aton(value, data->ssid->bssid)) {
+ if (hwaddr_aton(value, ssid->bssid)) {
wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.",
line, value);
return -1;
}
- data->ssid->bssid_set = 1;
- wpa_hexdump(MSG_MSGDUMP, "BSSID", data->ssid->bssid, ETH_ALEN);
+ ssid->bssid_set = 1;
+ wpa_hexdump(MSG_MSGDUMP, "BSSID", ssid->bssid, ETH_ALEN);
return 0;
}
-static int wpa_config_parse_psk(struct parse_data *data, int line,
+static char * wpa_config_write_bssid(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (!ssid->bssid_set)
+ return NULL;
+
+ value = malloc(20);
+ if (value == NULL)
+ return NULL;
+ snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid));
+ return value;
+}
+
+
+static int wpa_config_parse_psk(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
if (*value == '"') {
char *pos;
- int len;
+ size_t len;
value++;
pos = strrchr(value, '"');
@@ -212,29 +303,45 @@ static int wpa_config_parse_psk(struct parse_data *data, int line,
len = strlen(value);
if (len < 8 || len > 63) {
wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase "
- "length %d (expected: 8..63) '%s'.",
- line, len, value);
+ "length %lu (expected: 8..63) '%s'.",
+ line, (unsigned long) len, value);
return -1;
}
wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
(u8 *) value, len);
- data->ssid->passphrase = strdup(value);
- return data->ssid->passphrase == NULL ? -1 : 0;
+ ssid->passphrase = strdup(value);
+ return ssid->passphrase == NULL ? -1 : 0;
}
- if (hexstr2bin(value, data->ssid->psk, PMK_LEN) ||
+ if (hexstr2bin(value, ssid->psk, PMK_LEN) ||
value[PMK_LEN * 2] != '\0') {
wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
line, value);
return -1;
}
- data->ssid->psk_set = 1;
- wpa_hexdump_key(MSG_MSGDUMP, "PSK", data->ssid->psk, PMK_LEN);
+ ssid->psk_set = 1;
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK", ssid->psk, PMK_LEN);
return 0;
}
-static int wpa_config_parse_proto(struct parse_data *data, int line,
+static char * wpa_config_write_psk(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ if (ssid->passphrase)
+ return wpa_config_write_string_ascii(
+ (const u8 *) ssid->passphrase,
+ strlen(ssid->passphrase));
+
+ if (ssid->psk_set)
+ return wpa_config_write_string_hex(ssid->psk, PMK_LEN);
+
+ return NULL;
+}
+
+
+static int wpa_config_parse_proto(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
int val = 0, last, errors = 0;
@@ -279,12 +386,39 @@ static int wpa_config_parse_proto(struct parse_data *data, int line,
}
wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
- data->ssid->proto = val;
+ ssid->proto = val;
return errors ? -1 : 0;
}
-static int wpa_config_parse_key_mgmt(struct parse_data *data, int line,
+static char * wpa_config_write_proto(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ int first = 1;
+ char *buf, *pos, *end;
+
+ pos = buf = malloc(10);
+ if (buf == NULL)
+ return NULL;
+ memset(buf, 0, 10);
+ end = buf + 10;
+
+ if (ssid->proto & WPA_PROTO_WPA) {
+ pos += snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
+ first = 0;
+ }
+
+ if (ssid->proto & WPA_PROTO_RSN) {
+ pos += snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
+ first = 0;
+ }
+
+ return buf;
+}
+
+
+static int wpa_config_parse_key_mgmt(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
int val = 0, last, errors = 0;
@@ -334,11 +468,54 @@ static int wpa_config_parse_key_mgmt(struct parse_data *data, int line,
}
wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
- data->ssid->key_mgmt = val;
+ ssid->key_mgmt = val;
return errors ? -1 : 0;
}
+static char * wpa_config_write_key_mgmt(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ int first = 1;
+ char *buf, *pos, *end;
+
+ pos = buf = malloc(50);
+ if (buf == NULL)
+ return NULL;
+ memset(buf, 0, 50);
+ end = buf + 50;
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
+ pos += snprintf(pos, end - pos, "%sWPA-PSK", first ? "" : " ");
+ first = 0;
+ }
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+ pos += snprintf(pos, end - pos, "%sWPA-EAP", first ? "" : " ");
+ first = 0;
+ }
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+ pos += snprintf(pos, end - pos, "%sIEEE8021X",
+ first ? "" : " ");
+ first = 0;
+ }
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) {
+ pos += snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
+ first = 0;
+ }
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
+ pos += snprintf(pos, end - pos, "%sWPA-NONE",
+ first ? "" : " ");
+ first = 0;
+ }
+
+ return buf;
+}
+
+
static int wpa_config_parse_cipher(int line, const char *value)
{
int val = 0, last;
@@ -391,7 +568,48 @@ static int wpa_config_parse_cipher(int line, const char *value)
}
-static int wpa_config_parse_pairwise(struct parse_data *data, int line,
+static char * wpa_config_write_cipher(int cipher)
+{
+ int first = 1;
+ char *buf, *pos, *end;
+
+ pos = buf = malloc(50);
+ if (buf == NULL)
+ return NULL;
+ memset(buf, 0, 50);
+ end = buf + 50;
+
+ if (cipher & WPA_CIPHER_CCMP) {
+ pos += snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
+ first = 0;
+ }
+
+ if (cipher & WPA_CIPHER_TKIP) {
+ pos += snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
+ first = 0;
+ }
+
+ if (cipher & WPA_CIPHER_WEP104) {
+ pos += snprintf(pos, end - pos, "%sWEP104", first ? "" : " ");
+ first = 0;
+ }
+
+ if (cipher & WPA_CIPHER_WEP40) {
+ pos += snprintf(pos, end - pos, "%sWEP40", first ? "" : " ");
+ first = 0;
+ }
+
+ if (cipher & WPA_CIPHER_NONE) {
+ pos += snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
+ first = 0;
+ }
+
+ return buf;
+}
+
+
+static int wpa_config_parse_pairwise(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
int val;
@@ -405,12 +623,20 @@ static int wpa_config_parse_pairwise(struct parse_data *data, int line,
}
wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
- data->ssid->pairwise_cipher = val;
+ ssid->pairwise_cipher = val;
return 0;
}
-static int wpa_config_parse_group(struct parse_data *data, int line,
+static char * wpa_config_write_pairwise(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_cipher(ssid->pairwise_cipher);
+}
+
+
+static int wpa_config_parse_group(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
int val;
@@ -425,12 +651,20 @@ static int wpa_config_parse_group(struct parse_data *data, int line,
}
wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
- data->ssid->group_cipher = val;
+ ssid->group_cipher = val;
return 0;
}
-static int wpa_config_parse_auth_alg(struct parse_data *data, int line,
+static char * wpa_config_write_group(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_cipher(ssid->group_cipher);
+}
+
+
+static int wpa_config_parse_auth_alg(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
int val = 0, last, errors = 0;
@@ -476,12 +710,44 @@ static int wpa_config_parse_auth_alg(struct parse_data *data, int line,
}
wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
- data->ssid->auth_alg = val;
+ ssid->auth_alg = val;
return errors ? -1 : 0;
}
-static int wpa_config_parse_eap(struct parse_data *data, int line,
+static char * wpa_config_write_auth_alg(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ int first = 1;
+ char *buf, *pos, *end;
+
+ pos = buf = malloc(30);
+ if (buf == NULL)
+ return NULL;
+ memset(buf, 0, 30);
+ end = buf + 30;
+
+ if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) {
+ pos += snprintf(pos, end - pos, "%sOPEN", first ? "" : " ");
+ first = 0;
+ }
+
+ if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) {
+ pos += snprintf(pos, end - pos, "%sSHARED", first ? "" : " ");
+ first = 0;
+ }
+
+ if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) {
+ pos += snprintf(pos, end - pos, "%sLEAP", first ? "" : " ");
+ first = 0;
+ }
+
+ return buf;
+}
+
+
+static int wpa_config_parse_eap(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
int last, errors = 0;
@@ -520,9 +786,9 @@ static int wpa_config_parse_eap(struct parse_data *data, int line,
"See README for more information.");
errors++;
} else if (methods[num_methods] == EAP_TYPE_LEAP)
- data->ssid->leap++;
+ ssid->leap++;
else
- data->ssid->non_leap++;
+ ssid->non_leap++;
num_methods++;
if (last)
break;
@@ -540,11 +806,41 @@ static int wpa_config_parse_eap(struct parse_data *data, int line,
num_methods++;
wpa_hexdump(MSG_MSGDUMP, "eap methods", methods, num_methods);
- data->ssid->eap_methods = methods;
+ ssid->eap_methods = methods;
return errors ? -1 : 0;
}
+static char * wpa_config_write_eap(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ int first = 1;
+ char *buf, *pos, *end;
+ const u8 *eap_methods = ssid->eap_methods;
+ const char *name;
+
+ if (eap_methods == NULL)
+ return NULL;
+
+ pos = buf = malloc(100);
+ if (buf == NULL)
+ return NULL;
+ memset(buf, 0, 100);
+ end = buf + 100;
+
+ while (*eap_methods != EAP_TYPE_NONE) {
+ name = eap_get_name(*eap_methods);
+ if (name)
+ pos += snprintf(pos, end - pos, "%s%s",
+ first ? "" : " ", name);
+ first = 0;
+ eap_methods++;
+ }
+
+ return buf;
+}
+
+
static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
const char *value, int idx)
{
@@ -570,54 +866,140 @@ static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
}
-static int wpa_config_parse_wep_key0(struct parse_data *data, int line,
+static int wpa_config_parse_wep_key0(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
- return wpa_config_parse_wep_key(data->ssid->wep_key[0],
- &data->ssid->wep_key_len[0], line,
+ return wpa_config_parse_wep_key(ssid->wep_key[0],
+ &ssid->wep_key_len[0], line,
value, 0);
}
-static int wpa_config_parse_wep_key1(struct parse_data *data, int line,
+static int wpa_config_parse_wep_key1(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
- return wpa_config_parse_wep_key(data->ssid->wep_key[1],
- &data->ssid->wep_key_len[1], line,
+ return wpa_config_parse_wep_key(ssid->wep_key[1],
+ &ssid->wep_key_len[1], line,
value, 1);
}
-static int wpa_config_parse_wep_key2(struct parse_data *data, int line,
+static int wpa_config_parse_wep_key2(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
- return wpa_config_parse_wep_key(data->ssid->wep_key[2],
- &data->ssid->wep_key_len[2], line,
+ return wpa_config_parse_wep_key(ssid->wep_key[2],
+ &ssid->wep_key_len[2], line,
value, 2);
}
-static int wpa_config_parse_wep_key3(struct parse_data *data, int line,
+static int wpa_config_parse_wep_key3(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
- return wpa_config_parse_wep_key(data->ssid->wep_key[3],
- &data->ssid->wep_key_len[3], line,
+ return wpa_config_parse_wep_key(ssid->wep_key[3],
+ &ssid->wep_key_len[3], line,
value, 3);
}
+static char * wpa_config_write_wep_key(struct wpa_ssid *ssid, int idx)
+{
+ if (ssid->wep_key_len[idx] == 0)
+ return NULL;
+ return wpa_config_write_string(ssid->wep_key[idx],
+ ssid->wep_key_len[idx]);
+}
+
+
+static char * wpa_config_write_wep_key0(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_wep_key(ssid, 0);
+}
+
+
+static char * wpa_config_write_wep_key1(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_wep_key(ssid, 1);
+}
+
+
+static char * wpa_config_write_wep_key2(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_wep_key(ssid, 2);
+}
+
+
+static char * wpa_config_write_wep_key3(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_wep_key(ssid, 3);
+}
+
+
+/* Helper macros for network block parser */
+
+/* OFFSET: Get offset of a variable within the wpa_ssid structure */
#define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v)
-#define STR(f) .name = #f, .parser = wpa_config_parse_str, .param1 = OFFSET(f)
+
+/* STR: Define a string variable for an ASCII string; f = field name */
+#define STR(f) .name = #f, .parser = wpa_config_parse_str, \
+ .writer = wpa_config_write_str, .param1 = OFFSET(f)
+
+/* STR_LEN: Define a string variable with a separate variable for storing the
+ * data length. Unlike STR(), this can be used to store arbitrary binary data
+ * (i.e., even nul termination character). */
#define STR_LEN(f) STR(f), .param2 = OFFSET(f ## _len)
+
+/* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length
+ * explicitly specified. */
#define STR_RANGE(f, min, max) STR_LEN(f), .param3 = (void *) (min), \
.param4 = (void *) (max)
+
+
+/* INT: Define an integer variable */
#define INT(f) .name = #f, .parser = wpa_config_parse_int, \
+ .writer = wpa_config_write_int, \
.param1 = OFFSET(f), .param2 = (void *) 0
+
+/* INT: Define an integer variable with allowed value range */
#define INT_RANGE(f, min, max) INT(f), .param3 = (void *) (min), \
.param4 = (void *) (max)
-#define FUNC(f) .name = #f, .parser = wpa_config_parse_ ## f
-static struct parse_data ssid_fields[] = {
+/* FUNC: Define a configuration variable that uses a custom function for
+ * parsing and writing the value. */
+#define FUNC(f) .name = #f, .parser = wpa_config_parse_ ## f, \
+ .writer = wpa_config_write_ ## f
+
+/*
+ * Table of network configuration variables. This table is used to parse each
+ * network configuration variable, e.g., each line in wpa_supplicant.conf file
+ * that is insider a network block.
+ *
+ * This table is generated using the helper macros defined above and with
+ * generous help from the C pre-processor. The field name is stored as a string
+ * into .name and for STR and INT types, the offset of the target buffer within
+ * struct wpa_ssid is stored in .param1. .param2 (if not NULL) is similar
+ * offset to the field containing the length of the configuration variable.
+ * .param3 and .param4 can be used to mark the allowed range (length for STR
+ * and value for INT).
+ *
+ * For each configuration line in wpa_supplicant.conf, the parser goes through
+ * this table and select the entry that matches with the field name. The parser
+ * function (.parser) is then called to parse the actual value of the field.
+ *
+ * This kind of mechanism makes it easy to add new configuration parameters,
+ * since only one line needs to be added into this table and in struct wpa_ssid
+ * definitions if the new variable is either a string or integer. More complex
+ * types will need to use their own parser and writer functions.
+ */
+static const struct parse_data ssid_fields[] = {
{ STR_RANGE(ssid, 0, MAX_SSID_LEN) },
{ INT_RANGE(scan_ssid, 0, 1) },
{ FUNC(bssid) },
@@ -632,24 +1014,30 @@ static struct parse_data ssid_fields[] = {
{ STR_LEN(anonymous_identity) },
{ STR_RANGE(eappsk, EAP_PSK_LEN, EAP_PSK_LEN), .key_data = 1 },
{ STR_LEN(nai) },
- { STR_LEN(server_nai) },
{ STR_LEN(password), .key_data = 1 },
{ STR(ca_cert) },
+ { STR(ca_path) },
{ STR(client_cert) },
{ STR(private_key) },
{ STR(private_key_passwd), .key_data = 1 },
{ STR(dh_file) },
{ STR(subject_match) },
+ { STR(altsubject_match) },
{ STR(ca_cert2) },
+ { STR(ca_path2) },
{ STR(client_cert2) },
{ STR(private_key2) },
{ STR(private_key2_passwd), .key_data = 1 },
{ STR(dh_file2) },
{ STR(subject_match2) },
+ { STR(altsubject_match2) },
{ STR(phase1) },
{ STR(phase2) },
{ STR(pcsc) },
{ STR(pin), .key_data = 1 },
+ { STR(engine_id) },
+ { STR(key_id) },
+ { INT(engine) },
{ INT(eapol_flags) },
{ FUNC(wep_key0), .key_data = 1 },
{ FUNC(wep_key1), .key_data = 1 },
@@ -660,6 +1048,8 @@ static struct parse_data ssid_fields[] = {
{ INT(eap_workaround) },
{ STR(pac_file) },
{ INT_RANGE(mode, 0, 1) },
+ { INT_RANGE(proactive_key_caching, 0, 1) },
+ { INT_RANGE(disabled, 0, 1) },
};
#undef OFFSET
@@ -672,119 +1062,18 @@ static struct parse_data ssid_fields[] = {
#define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0]))
-static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
-{
- struct wpa_ssid *ssid;
- int errors = 0, i, end = 0;
- char buf[256], *pos, *pos2;
-
- wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block",
- *line);
- ssid = (struct wpa_ssid *) malloc(sizeof(*ssid));
- if (ssid == NULL)
- return NULL;
- memset(ssid, 0, sizeof(*ssid));
- ssid->id = id;
-
- ssid->proto = WPA_PROTO_WPA | WPA_PROTO_RSN;
- ssid->pairwise_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
- ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP |
- WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40;
- ssid->key_mgmt = WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X;
- ssid->eapol_flags = EAPOL_FLAG_REQUIRE_KEY_UNICAST |
- EAPOL_FLAG_REQUIRE_KEY_BROADCAST;
- ssid->eap_workaround = (unsigned int) -1;
-
- while ((pos = wpa_config_get_line(buf, sizeof(buf), f, line))) {
- if (strcmp(pos, "}") == 0) {
- end = 1;
- break;
- }
-
- pos2 = strchr(pos, '=');
- if (pos2 == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid SSID line "
- "'%s'.", *line, pos);
- errors++;
- continue;
- }
-
- *pos2++ = '\0';
- if (*pos2 == '"') {
- if (strchr(pos2 + 1, '"') == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "quotation '%s'.", *line, pos2);
- errors++;
- continue;
- }
- }
-
- for (i = 0; i < NUM_SSID_FIELDS; i++) {
- struct parse_data *field = &ssid_fields[i];
- if (strcmp(pos, field->name) != 0)
- continue;
-
- field->ssid = ssid;
- if (field->parser(field, *line, pos2)) {
- wpa_printf(MSG_ERROR, "Line %d: failed to "
- "parse %s '%s'.", *line, pos, pos2);
- errors++;
- }
- break;
- }
- if (i == NUM_SSID_FIELDS) {
- wpa_printf(MSG_ERROR, "Line %d: unknown network field "
- "'%s'.", *line, pos);
- errors++;
- }
- }
-
- if (!end) {
- wpa_printf(MSG_ERROR, "Line %d: network block was not "
- "terminated properly.", *line);
- errors++;
- }
-
- if (ssid->passphrase) {
- if (ssid->psk_set) {
- wpa_printf(MSG_ERROR, "Line %d: both PSK and "
- "passphrase configured.", *line);
- errors++;
- }
- pbkdf2_sha1(ssid->passphrase,
- (char *) ssid->ssid, ssid->ssid_len, 4096,
- ssid->psk, PMK_LEN);
- wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
- ssid->psk, PMK_LEN);
- ssid->psk_set = 1;
- }
-
- if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) {
- wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key "
- "management, but no PSK configured.", *line);
- errors++;
- }
-
- if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
- !(ssid->pairwise_cipher & WPA_CIPHER_CCMP)) {
- /* Group cipher cannot be stronger than the pairwise cipher. */
- wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher"
- " list since it was not allowed for pairwise "
- "cipher", *line);
- ssid->group_cipher &= ~WPA_CIPHER_CCMP;
- }
-
- if (errors) {
- free(ssid);
- ssid = NULL;
- }
-
- return ssid;
-}
-
-
-static int wpa_config_add_prio_network(struct wpa_config *config,
- struct wpa_ssid *ssid)
+/**
+ * wpa_config_add_prio_network - Add a network to priority lists
+ * @config: Configuration data from wpa_config_read()
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to add a network block to the priority list of
+ * networks. This must be called for each network when reading in the full
+ * configuration. In addition, this can be used indirectly when updating
+ * priorities by calling wpa_config_update_prio_list().
+ */
+int wpa_config_add_prio_network(struct wpa_config *config,
+ struct wpa_ssid *ssid)
{
int prio;
struct wpa_ssid *prev, **nlist;
@@ -821,181 +1110,125 @@ static int wpa_config_add_prio_network(struct wpa_config *config,
}
-struct wpa_config * wpa_config_read(const char *config_file)
+/**
+ * wpa_config_update_prio_list - Update network priority list
+ * @config: Configuration data from wpa_config_read()
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called to update the priority list of networks in the
+ * configuration when a network is being added or removed. This is also called
+ * if a priority for a network is changed.
+ */
+static int wpa_config_update_prio_list(struct wpa_config *config)
{
- FILE *f;
- char buf[256], *pos;
- int errors = 0, line = 0;
- struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
- struct wpa_config *config;
- int id = 0, prio;
-
- config = malloc(sizeof(*config));
- if (config == NULL)
- return NULL;
- memset(config, 0, sizeof(*config));
- config->eapol_version = 1;
- config->ap_scan = 1;
- config->fast_reauth = 1;
- wpa_printf(MSG_DEBUG, "Reading configuration file '%s'",
- config_file);
- f = fopen(config_file, "r");
- if (f == NULL) {
- free(config);
- return NULL;
- }
+ struct wpa_ssid *ssid;
+ int ret = 0;
- while ((pos = wpa_config_get_line(buf, sizeof(buf), f, &line))) {
- if (strcmp(pos, "network={") == 0) {
- ssid = wpa_config_read_network(f, &line, id++);
- if (ssid == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: failed to "
- "parse network block.", line);
- errors++;
- continue;
- }
- if (head == NULL) {
- head = tail = ssid;
- } else {
- tail->next = ssid;
- tail = ssid;
- }
- if (wpa_config_add_prio_network(config, ssid)) {
- wpa_printf(MSG_ERROR, "Line %d: failed to add "
- "network block to priority list.",
- line);
- errors++;
- continue;
- }
-#ifdef CONFIG_CTRL_IFACE
- } else if (strncmp(pos, "ctrl_interface=", 15) == 0) {
- free(config->ctrl_interface);
- config->ctrl_interface = strdup(pos + 15);
- wpa_printf(MSG_DEBUG, "ctrl_interface='%s'",
- config->ctrl_interface);
-#ifndef CONFIG_CTRL_IFACE_UDP
- } else if (strncmp(pos, "ctrl_interface_group=", 21) == 0) {
- struct group *grp;
- char *endp;
- const char *group = pos + 21;
-
- grp = getgrnam(group);
- if (grp) {
- config->ctrl_interface_gid = grp->gr_gid;
- config->ctrl_interface_gid_set = 1;
- wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
- " (from group name '%s')",
- (int) config->ctrl_interface_gid,
- group);
- continue;
- }
+ free(config->pssid);
+ config->pssid = NULL;
+ config->num_prio = 0;
- /* Group name not found - try to parse this as gid */
- config->ctrl_interface_gid = strtol(group, &endp, 10);
- if (*group == '\0' || *endp != '\0') {
- wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
- "'%s'", line, group);
- errors++;
- continue;
- }
- wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
- (int) config->ctrl_interface_gid);
-#endif /* CONFIG_CTRL_IFACE_UDP */
-#endif /* CONFIG_CTRL_IFACE */
- } else if (strncmp(pos, "eapol_version=", 14) == 0) {
- config->eapol_version = atoi(pos + 14);
- if (config->eapol_version < 1 ||
- config->eapol_version > 2) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid EAPOL "
- "version (%d): '%s'.",
- line, config->eapol_version, pos);
- errors++;
- continue;
- }
- wpa_printf(MSG_DEBUG, "eapol_version=%d",
- config->eapol_version);
- } else if (strncmp(pos, "ap_scan=", 8) == 0) {
- config->ap_scan = atoi(pos + 8);
- wpa_printf(MSG_DEBUG, "ap_scan=%d", config->ap_scan);
- } else if (strncmp(pos, "fast_reauth=", 12) == 0) {
- config->fast_reauth = atoi(pos + 12);
- wpa_printf(MSG_DEBUG, "fast_reauth=%d",
- config->fast_reauth);
- } else {
- wpa_printf(MSG_ERROR, "Line %d: Invalid configuration "
- "line '%s'.", line, pos);
- errors++;
- continue;
- }
+ ssid = config->ssid;
+ while (ssid) {
+ ssid->pnext = NULL;
+ if (wpa_config_add_prio_network(config, ssid) < 0)
+ ret = -1;
+ ssid = ssid->next;
}
- fclose(f);
+ return ret;
+}
- config->ssid = head;
- for (prio = 0; prio < config->num_prio; prio++) {
- ssid = config->pssid[prio];
- wpa_printf(MSG_DEBUG, "Priority group %d",
- ssid->priority);
- while (ssid) {
- wpa_printf(MSG_DEBUG, " id=%d ssid='%s'",
- ssid->id,
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
- ssid = ssid->pnext;
- }
- }
- if (errors) {
- wpa_config_free(config);
- config = NULL;
- head = NULL;
- }
- return config;
+/**
+ * wpa_config_free_ssid - Free network/ssid configuration data
+ * @ssid: Configuration data for the network
+ *
+ * This function frees all resources allocated for the netowkr configuration
+ * data.
+ */
+void wpa_config_free_ssid(struct wpa_ssid *ssid)
+{
+ free(ssid->ssid);
+ free(ssid->passphrase);
+ free(ssid->eap_methods);
+ free(ssid->identity);
+ free(ssid->anonymous_identity);
+ free(ssid->eappsk);
+ free(ssid->nai);
+ free(ssid->password);
+ free(ssid->ca_cert);
+ free(ssid->ca_path);
+ free(ssid->client_cert);
+ free(ssid->private_key);
+ free(ssid->private_key_passwd);
+ free(ssid->dh_file);
+ free(ssid->subject_match);
+ free(ssid->altsubject_match);
+ free(ssid->ca_cert2);
+ free(ssid->ca_path2);
+ free(ssid->client_cert2);
+ free(ssid->private_key2);
+ free(ssid->private_key2_passwd);
+ free(ssid->dh_file2);
+ free(ssid->subject_match2);
+ free(ssid->altsubject_match2);
+ free(ssid->phase1);
+ free(ssid->phase2);
+ free(ssid->pcsc);
+ free(ssid->pin);
+ free(ssid->engine_id);
+ free(ssid->key_id);
+ free(ssid->otp);
+ free(ssid->pending_req_otp);
+ free(ssid->pac_file);
+ free(ssid->new_password);
+ free(ssid);
}
+/**
+ * wpa_config_free - Free configuration data
+ * @config: Configuration data from wpa_config_read()
+ *
+ * This function frees all resources allocated for the configuration data by
+ * wpa_config_read().
+ */
void wpa_config_free(struct wpa_config *config)
{
+ struct wpa_config_blob *blob, *prevblob;
struct wpa_ssid *ssid, *prev = NULL;
ssid = config->ssid;
while (ssid) {
prev = ssid;
ssid = ssid->next;
- free(prev->ssid);
- free(prev->passphrase);
- free(prev->eap_methods);
- free(prev->identity);
- free(prev->anonymous_identity);
- free(prev->eappsk);
- free(prev->nai);
- free(prev->server_nai);
- free(prev->password);
- free(prev->ca_cert);
- free(prev->client_cert);
- free(prev->private_key);
- free(prev->private_key_passwd);
- free(prev->dh_file);
- free(prev->subject_match);
- free(prev->ca_cert2);
- free(prev->client_cert2);
- free(prev->private_key2);
- free(prev->private_key2_passwd);
- free(prev->dh_file2);
- free(prev->subject_match2);
- free(prev->phase1);
- free(prev->phase2);
- free(prev->pcsc);
- free(prev->pin);
- free(prev->otp);
- free(prev->pending_req_otp);
- free(prev->pac_file);
- free(prev);
+ wpa_config_free_ssid(prev);
}
+
+ blob = config->blobs;
+ prevblob = NULL;
+ while (blob) {
+ prevblob = blob;
+ blob = blob->next;
+ wpa_config_free_blob(prevblob);
+ }
+
free(config->ctrl_interface);
+ free(config->opensc_engine_path);
+ free(config->pkcs11_engine_path);
+ free(config->pkcs11_module_path);
+ free(config->driver_param);
free(config->pssid);
free(config);
}
+/**
+ * wpa_config_allowed_eap_method - Check whether EAP method is allowed
+ * @ssid: Pointer to a configuration data
+ * @method: EAP type
+ * Returns: 1 = allowed EAP method, 0 = not allowed
+ */
int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int method)
{
u8 *pos;
@@ -1013,39 +1246,306 @@ int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int method)
}
-const char * wpa_cipher_txt(int cipher)
+/**
+ * wpa_config_get_network - Get configured network based on id
+ * @config: Configuration data from wpa_config_read()
+ * @id: Unique network id to search for
+ * Returns: Network configuration or %NULL if not found
+ */
+struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id)
{
- switch (cipher) {
- case WPA_CIPHER_NONE:
- return "NONE";
- case WPA_CIPHER_WEP40:
- return "WEP-40";
- case WPA_CIPHER_WEP104:
- return "WEP-104";
- case WPA_CIPHER_TKIP:
- return "TKIP";
- case WPA_CIPHER_CCMP:
- return "CCMP";
- default:
- return "UNKNOWN";
+ struct wpa_ssid *ssid;
+
+ ssid = config->ssid;
+ while (ssid) {
+ if (id == ssid->id)
+ break;
+ ssid = ssid->next;
}
+
+ return ssid;
}
-const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
+/**
+ * wpa_config_add_network - Add a new network with empty configuration
+ * @config: Configuration data from wpa_config_read()
+ * Returns: The new network configuration or %NULL if operation failed
+ */
+struct wpa_ssid * wpa_config_add_network(struct wpa_config *config)
{
- switch (key_mgmt) {
- case WPA_KEY_MGMT_IEEE8021X:
- return proto == WPA_PROTO_RSN ?
- "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
- case WPA_KEY_MGMT_PSK:
- return proto == WPA_PROTO_RSN ?
- "WPA2-PSK" : "WPA-PSK";
- case WPA_KEY_MGMT_NONE:
- return "NONE";
- case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
- return "IEEE 802.1X (no WPA)";
- default:
- return "UNKNOWN";
+ int id;
+ struct wpa_ssid *ssid, *last = NULL;
+
+ id = -1;
+ ssid = config->ssid;
+ while (ssid) {
+ if (ssid->id > id)
+ id = ssid->id;
+ last = ssid;
+ ssid = ssid->next;
}
+ id++;
+
+ ssid = malloc(sizeof(*ssid));
+ if (ssid == NULL)
+ return NULL;
+ memset(ssid, 0, sizeof(*ssid));
+ ssid->id = id;
+ if (last)
+ last->next = ssid;
+ else
+ config->ssid = ssid;
+
+ wpa_config_update_prio_list(config);
+
+ return ssid;
+}
+
+
+/**
+ * wpa_config_remove_network - Remove a configured network based on id
+ * @config: Configuration data from wpa_config_read()
+ * @id: Unique network id to search for
+ * Returns: 0 on success, or -1 if the network was not found
+ */
+int wpa_config_remove_network(struct wpa_config *config, int id)
+{
+ struct wpa_ssid *ssid, *prev = NULL;
+
+ ssid = config->ssid;
+ while (ssid) {
+ if (id == ssid->id)
+ break;
+ prev = ssid;
+ ssid = ssid->next;
+ }
+
+ if (ssid == NULL)
+ return -1;
+
+ if (prev)
+ prev->next = ssid->next;
+ else
+ config->ssid = ssid->next;
+
+ wpa_config_update_prio_list(config);
+ wpa_config_free_ssid(ssid);
+ return 0;
+}
+
+
+/**
+ * wpa_config_set_network_defaults - Set network default values
+ * @ssid: Pointer to a network configuration data
+ */
+void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
+{
+ ssid->proto = DEFAULT_PROTO;
+ ssid->pairwise_cipher = DEFAULT_PAIRWISE;
+ ssid->group_cipher = DEFAULT_GROUP;
+ ssid->key_mgmt = DEFAULT_KEY_MGMT;
+ ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
+ ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
+}
+
+
+/**
+ * wpa_config_set - Set a variable in network configuration
+ * @ssid: Pointer to a network configuration data
+ * @var: Variable name, e.g., "ssid"
+ * @value: Variable value
+ * @line: Line number in configuration file or 0 if not used
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to set network configuration variables based on
+ * both the configuration file and management interface input. The value
+ * parameter must be in the same format as the text-based configuration file is
+ * using. For example, strings are using double quotation marks.
+ */
+int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
+ int line)
+{
+ int i, ret = 0;
+
+ if (ssid == NULL || var == NULL || value == NULL)
+ return -1;
+
+ for (i = 0; i < NUM_SSID_FIELDS; i++) {
+ const struct parse_data *field = &ssid_fields[i];
+ if (strcmp(var, field->name) != 0)
+ continue;
+
+ if (field->parser(field, ssid, line, value)) {
+ if (line) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to "
+ "parse %s '%s'.", line, var, value);
+ }
+ ret = -1;
+ }
+ break;
+ }
+ if (i == NUM_SSID_FIELDS) {
+ if (line) {
+ wpa_printf(MSG_ERROR, "Line %d: unknown network field "
+ "'%s'.", line, var);
+ }
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+/**
+ * wpa_config_get - Get a variable in network configuration
+ * @ssid: Pointer to a network configuration data
+ * @var: Variable name, e.g., "ssid"
+ * Returns: Value of the variable or %NULL on failure
+ *
+ * This function can be used to get network configuration variables. The
+ * returned value is a copy of the configuration variable in text format, i.e,.
+ * the same format that the text-based configuration file and wpa_config_set()
+ * are using for the value. The caller is responsible for freeing the returned
+ * value.
+ */
+char * wpa_config_get(struct wpa_ssid *ssid, const char *var)
+{
+ int i;
+
+ if (ssid == NULL || var == NULL)
+ return NULL;
+
+ for (i = 0; i < NUM_SSID_FIELDS; i++) {
+ const struct parse_data *field = &ssid_fields[i];
+ if (strcmp(var, field->name) == 0)
+ return field->writer(field, ssid);
+ }
+
+ return NULL;
+}
+
+
+/**
+ * wpa_config_update_psk - Update WPA PSK based on passphrase and SSID
+ * @ssid: Pointer to a network configuration data
+ *
+ * This function must be called to update WPA PSK when either SSID or the
+ * passphrase has changed for the network configuration.
+ */
+void wpa_config_update_psk(struct wpa_ssid *ssid)
+{
+ pbkdf2_sha1(ssid->passphrase,
+ (char *) ssid->ssid, ssid->ssid_len, 4096,
+ ssid->psk, PMK_LEN);
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
+ ssid->psk, PMK_LEN);
+ ssid->psk_set = 1;
+}
+
+
+/**
+ * wpa_config_get_blob - Get a named configuration blob
+ * @config: Configuration data from wpa_config_read()
+ * @name: Name of the blob
+ * Returns: Pointer to blob data or %NULL if not found
+ */
+const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config,
+ const char *name)
+{
+ struct wpa_config_blob *blob = config->blobs;
+
+ while (blob) {
+ if (strcmp(blob->name, name) == 0)
+ return blob;
+ blob = blob->next;
+ }
+ return NULL;
+}
+
+
+/**
+ * wpa_config_set_blob - Set or add a named configuration blob
+ * @config: Configuration data from wpa_config_read()
+ * @blob: New value for the blob
+ *
+ * Adds a new configuration blob or replaces the current value of an existing
+ * blob.
+ */
+void wpa_config_set_blob(struct wpa_config *config,
+ struct wpa_config_blob *blob)
+{
+ wpa_config_remove_blob(config, blob->name);
+ blob->next = config->blobs;
+ config->blobs = blob;
+}
+
+
+/**
+ * wpa_config_free_blob - Free blob data
+ * @blob: Pointer to blob to be freed
+ */
+void wpa_config_free_blob(struct wpa_config_blob *blob)
+{
+ if (blob) {
+ free(blob->name);
+ free(blob->data);
+ free(blob);
+ }
+}
+
+
+/**
+ * wpa_config_remove_blob - Remove a named configuration blob
+ * @config: Configuration data from wpa_config_read()
+ * @name: Name of the blob to remove
+ * Returns: 0 if blob was removed or -1 if blob was not found
+ */
+int wpa_config_remove_blob(struct wpa_config *config, const char *name)
+{
+ struct wpa_config_blob *pos = config->blobs, *prev = NULL;
+
+ while (pos) {
+ if (strcmp(pos->name, name) == 0) {
+ if (prev)
+ prev->next = pos->next;
+ else
+ config->blobs = pos->next;
+ wpa_config_free_blob(pos);
+ return 0;
+ }
+ prev = pos;
+ pos = pos->next;
+ }
+
+ return -1;
+}
+
+
+/**
+ * wpa_config_alloc_empty - Allocate an empty configuration
+ * @ctrl_interface: Control interface parameters, e.g., path to UNIX domain
+ * socket
+ * @driver_param: Driver parameters
+ * Returns: Pointer to allocated configuration data or %NULL on failure
+ */
+struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
+ const char *driver_param)
+{
+ struct wpa_config *config;
+
+ config = malloc(sizeof(*config));
+ if (config == NULL)
+ return NULL;
+ memset(config, 0, sizeof(*config));
+ config->eapol_version = DEFAULT_EAPOL_VERSION;
+ config->ap_scan = DEFAULT_AP_SCAN;
+ config->fast_reauth = DEFAULT_FAST_REAUTH;
+
+ if (ctrl_interface)
+ config->ctrl_interface = strdup(ctrl_interface);
+ if (driver_param)
+ config->driver_param = strdup(driver_param);
+
+ return config;
}
OpenPOWER on IntegriCloud