OSDN Git Service

wpa_supplicant: Update to 07-Jul-2012 TOT
[android-x86/external-wpa_supplicant_8.git] / wpa_supplicant / config.c
index d36d027..a795c41 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / Configuration parser and common functions
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -13,6 +13,7 @@
 #include "crypto/sha1.h"
 #include "rsn_supp/wpa.h"
 #include "eap_peer/eap.h"
+#include "p2p/p2p.h"
 #include "config.h"
 
 
@@ -1130,6 +1131,7 @@ static int wpa_config_parse_eap(const struct parse_data *data,
 
        wpa_hexdump(MSG_MSGDUMP, "eap methods",
                    (u8 *) methods, num_methods * sizeof(*methods));
+       os_free(ssid->eap.eap_methods);
        ssid->eap.eap_methods = methods;
        return errors ? -1 : 0;
 }
@@ -1277,6 +1279,11 @@ static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
                os_free(buf);
                return -1;
        }
+       if (*len && *len != 5 && *len != 13 && *len != 16) {
+               wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key length %u - "
+                          "this network block will be ignored",
+                          line, (unsigned int) *len);
+       }
        os_memcpy(key, buf, *len);
        os_free(buf);
        res = os_snprintf(title, sizeof(title), "wep_key%d", idx);
@@ -1556,6 +1563,7 @@ static const struct parse_data ssid_fields[] = {
        { FUNC_KEY(psk) },
        { FUNC(proto) },
        { FUNC(key_mgmt) },
+       { INT(bg_scan_period) },
        { FUNC(pairwise) },
        { FUNC(group) },
        { FUNC(auth_alg) },
@@ -1622,6 +1630,7 @@ static const struct parse_data ssid_fields[] = {
        { INT_RANGE(frequency, 0, 10000) },
        { INT(wpa_ptk_rekey) },
        { STR(bgscan) },
+       { INT_RANGE(ignore_broadcast_ssid, 0, 2) },
 #ifdef CONFIG_P2P
        { FUNC(p2p_client_list) },
 #endif /* CONFIG_P2P */
@@ -1633,6 +1642,8 @@ static const struct parse_data ssid_fields[] = {
        { INT_RANGE(ampdu_density, -1, 7) },
        { STR(ht_mcs) },
 #endif /* CONFIG_HT_OVERRIDES */
+       { INT(ap_max_inactivity) },
+       { INT(dtim_period) },
 };
 
 #ifdef WPA_UNICODE_SSID
@@ -1701,13 +1712,14 @@ int wpa_config_add_prio_network(struct wpa_config *config,
                return -1;
 
        for (prio = 0; prio < config->num_prio; prio++) {
-               if (nlist[prio]->priority < ssid->priority)
+               if (nlist[prio]->priority < ssid->priority) {
+                       os_memmove(&nlist[prio + 1], &nlist[prio],
+                                  (config->num_prio - prio) *
+                                  sizeof(struct wpa_ssid *));
                        break;
+               }
        }
 
-       os_memmove(&nlist[prio + 1], &nlist[prio],
-                  (config->num_prio - prio) * sizeof(struct wpa_ssid *));
-
        nlist[prio] = ssid;
        config->num_prio++;
        config->pssid = nlist;
@@ -1816,6 +1828,22 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
 }
 
 
+void wpa_config_free_cred(struct wpa_cred *cred)
+{
+       os_free(cred->realm);
+       os_free(cred->username);
+       os_free(cred->password);
+       os_free(cred->ca_cert);
+       os_free(cred->client_cert);
+       os_free(cred->private_key);
+       os_free(cred->private_key_passwd);
+       os_free(cred->imsi);
+       os_free(cred->milenage);
+       os_free(cred->domain);
+       os_free(cred);
+}
+
+
 /**
  * wpa_config_free - Free configuration data
  * @config: Configuration data from wpa_config_read()
@@ -1829,6 +1857,7 @@ void wpa_config_free(struct wpa_config *config)
        struct wpa_config_blob *blob, *prevblob;
 #endif /* CONFIG_NO_CONFIG_BLOBS */
        struct wpa_ssid *ssid, *prev = NULL;
+       struct wpa_cred *cred, *cprev;
 
        ssid = config->ssid;
        while (ssid) {
@@ -1837,6 +1866,13 @@ void wpa_config_free(struct wpa_config *config)
                wpa_config_free_ssid(prev);
        }
 
+       cred = config->cred;
+       while (cred) {
+               cprev = cred;
+               cred = cred->next;
+               wpa_config_free_cred(cprev);
+       }
+
 #ifndef CONFIG_NO_CONFIG_BLOBS
        blob = config->blobs;
        prevblob = NULL;
@@ -1847,11 +1883,14 @@ void wpa_config_free(struct wpa_config *config)
        }
 #endif /* CONFIG_NO_CONFIG_BLOBS */
 
+       wpabuf_free(config->wps_vendor_ext_m1);
        os_free(config->ctrl_interface);
        os_free(config->ctrl_interface_group);
        os_free(config->opensc_engine_path);
        os_free(config->pkcs11_engine_path);
        os_free(config->pkcs11_module_path);
+       os_free(config->pcsc_reader);
+       os_free(config->pcsc_pin);
        os_free(config->driver_param);
        os_free(config->device_name);
        os_free(config->manufacturer);
@@ -1861,12 +1900,11 @@ void wpa_config_free(struct wpa_config *config)
        os_free(config->config_methods);
        os_free(config->p2p_ssid_postfix);
        os_free(config->pssid);
-       os_free(config->home_realm);
-       os_free(config->home_username);
-       os_free(config->home_password);
-       os_free(config->home_ca_cert);
-       os_free(config->home_imsi);
-       os_free(config->home_milenage);
+       os_free(config->p2p_pref_chan);
+       os_free(config->autoscan);
+       wpabuf_free(config->wps_nfc_dh_pubkey);
+       wpabuf_free(config->wps_nfc_dh_privkey);
+       wpabuf_free(config->wps_nfc_dev_pw);
 #ifdef ANDROID_P2P
        os_free(config->prioritize);
 #endif
@@ -1997,6 +2035,7 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
        ssid->pairwise_cipher = DEFAULT_PAIRWISE;
        ssid->group_cipher = DEFAULT_GROUP;
        ssid->key_mgmt = DEFAULT_KEY_MGMT;
+       ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
 #ifdef IEEE8021X_EAPOL
        ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
        ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
@@ -2241,6 +2280,168 @@ void wpa_config_update_psk(struct wpa_ssid *ssid)
 }
 
 
+int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
+                       const char *value, int line)
+{
+       char *val;
+       size_t len;
+
+       if (os_strcmp(var, "priority") == 0) {
+               cred->priority = atoi(value);
+               return 0;
+       }
+
+       if (os_strcmp(var, "pcsc") == 0) {
+               cred->pcsc = atoi(value);
+               return 0;
+       }
+
+       val = wpa_config_parse_string(value, &len);
+       if (val == NULL) {
+               wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
+                          "value '%s'.", line, var, value);
+               return -1;
+       }
+
+       if (os_strcmp(var, "realm") == 0) {
+               os_free(cred->realm);
+               cred->realm = val;
+               return 0;
+       }
+
+       if (os_strcmp(var, "username") == 0) {
+               os_free(cred->username);
+               cred->username = val;
+               return 0;
+       }
+
+       if (os_strcmp(var, "password") == 0) {
+               os_free(cred->password);
+               cred->password = val;
+               return 0;
+       }
+
+       if (os_strcmp(var, "ca_cert") == 0) {
+               os_free(cred->ca_cert);
+               cred->ca_cert = val;
+               return 0;
+       }
+
+       if (os_strcmp(var, "client_cert") == 0) {
+               os_free(cred->client_cert);
+               cred->client_cert = val;
+               return 0;
+       }
+
+       if (os_strcmp(var, "private_key") == 0) {
+               os_free(cred->private_key);
+               cred->private_key = val;
+               return 0;
+       }
+
+       if (os_strcmp(var, "private_key_passwd") == 0) {
+               os_free(cred->private_key_passwd);
+               cred->private_key_passwd = val;
+               return 0;
+       }
+
+       if (os_strcmp(var, "imsi") == 0) {
+               os_free(cred->imsi);
+               cred->imsi = val;
+               return 0;
+       }
+
+       if (os_strcmp(var, "milenage") == 0) {
+               os_free(cred->milenage);
+               cred->milenage = val;
+               return 0;
+       }
+
+       if (os_strcmp(var, "domain") == 0) {
+               os_free(cred->domain);
+               cred->domain = val;
+               return 0;
+       }
+
+       if (line) {
+               wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
+                          line, var);
+       }
+
+       os_free(val);
+
+       return -1;
+}
+
+
+struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id)
+{
+       struct wpa_cred *cred;
+
+       cred = config->cred;
+       while (cred) {
+               if (id == cred->id)
+                       break;
+               cred = cred->next;
+       }
+
+       return cred;
+}
+
+
+struct wpa_cred * wpa_config_add_cred(struct wpa_config *config)
+{
+       int id;
+       struct wpa_cred *cred, *last = NULL;
+
+       id = -1;
+       cred = config->cred;
+       while (cred) {
+               if (cred->id > id)
+                       id = cred->id;
+               last = cred;
+               cred = cred->next;
+       }
+       id++;
+
+       cred = os_zalloc(sizeof(*cred));
+       if (cred == NULL)
+               return NULL;
+       cred->id = id;
+       if (last)
+               last->next = cred;
+       else
+               config->cred = cred;
+
+       return cred;
+}
+
+
+int wpa_config_remove_cred(struct wpa_config *config, int id)
+{
+       struct wpa_cred *cred, *prev = NULL;
+
+       cred = config->cred;
+       while (cred) {
+               if (id == cred->id)
+                       break;
+               prev = cred;
+               cred = cred->next;
+       }
+
+       if (cred == NULL)
+               return -1;
+
+       if (prev)
+               prev->next = cred->next;
+       else
+               config->cred = cred->next;
+
+       wpa_config_free_cred(cred);
+       return 0;
+}
+
+
 #ifndef CONFIG_NO_CONFIG_BLOBS
 /**
  * wpa_config_get_blob - Get a named configuration blob
@@ -2454,6 +2655,35 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data,
 }
 
 
+static int wpa_global_config_parse_bin(const struct global_parse_data *data,
+                                      struct wpa_config *config, int line,
+                                      const char *pos)
+{
+       size_t len;
+       struct wpabuf **dst, *tmp;
+
+       len = os_strlen(pos);
+       if (len & 0x01)
+               return -1;
+
+       tmp = wpabuf_alloc(len / 2);
+       if (tmp == NULL)
+               return -1;
+
+       if (hexstr2bin(pos, wpabuf_put(tmp, len / 2), len / 2)) {
+               wpabuf_free(tmp);
+               return -1;
+       }
+
+       dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
+       wpabuf_free(*dst);
+       *dst = tmp;
+       wpa_printf(MSG_DEBUG, "%s", data->name);
+
+       return 0;
+}
+
+
 static int wpa_config_process_country(const struct global_parse_data *data,
                                      struct wpa_config *config, int line,
                                      const char *pos)
@@ -2528,6 +2758,43 @@ static int wpa_config_process_os_version(const struct global_parse_data *data,
        return 0;
 }
 
+
+static int wpa_config_process_wps_vendor_ext_m1(
+       const struct global_parse_data *data,
+       struct wpa_config *config, int line, const char *pos)
+{
+       struct wpabuf *tmp;
+       int len = os_strlen(pos) / 2;
+       u8 *p;
+
+       if (!len) {
+               wpa_printf(MSG_ERROR, "Line %d: "
+                          "invalid wps_vendor_ext_m1", line);
+               return -1;
+       }
+
+       tmp = wpabuf_alloc(len);
+       if (tmp) {
+               p = wpabuf_put(tmp, len);
+
+               if (hexstr2bin(pos, p, len)) {
+                       wpa_printf(MSG_ERROR, "Line %d: "
+                                  "invalid wps_vendor_ext_m1", line);
+                       wpabuf_free(tmp);
+                       return -1;
+               }
+
+               wpabuf_free(config->wps_vendor_ext_m1);
+               config->wps_vendor_ext_m1 = tmp;
+       } else {
+               wpa_printf(MSG_ERROR, "Can not allocate "
+                          "memory for wps_vendor_ext_m1");
+               return -1;
+       }
+
+       return 0;
+}
+
 #endif /* CONFIG_WPS */
 
 #ifdef CONFIG_P2P
@@ -2551,6 +2818,55 @@ static int wpa_config_process_sec_device_type(
        config->num_sec_device_types++;
        return 0;
 }
+
+
+static int wpa_config_process_p2p_pref_chan(
+       const struct global_parse_data *data,
+       struct wpa_config *config, int line, const char *pos)
+{
+       struct p2p_channel *pref = NULL, *n;
+       unsigned int num = 0;
+       const char *pos2;
+       u8 op_class, chan;
+
+       /* format: class:chan,class:chan,... */
+
+       while (*pos) {
+               op_class = atoi(pos);
+               pos2 = os_strchr(pos, ':');
+               if (pos2 == NULL)
+                       goto fail;
+               pos2++;
+               chan = atoi(pos2);
+
+               n = os_realloc(pref, (num + 1) * sizeof(struct p2p_channel));
+               if (n == NULL)
+                       goto fail;
+               pref = n;
+               pref[num].op_class = op_class;
+               pref[num].chan = chan;
+               num++;
+
+               pos = os_strchr(pos2, ',');
+               if (pos == NULL)
+                       break;
+               pos++;
+       }
+
+       os_free(config->p2p_pref_chan);
+       config->p2p_pref_chan = pref;
+       config->num_p2p_pref_chan = num;
+       wpa_hexdump(MSG_DEBUG, "P2P: Preferred class/channel pairs",
+                   (u8 *) config->p2p_pref_chan,
+                   config->num_p2p_pref_chan * sizeof(struct p2p_channel));
+
+       return 0;
+
+fail:
+       os_free(pref);
+       wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_pref_chan list", line);
+       return -1;
+}
 #endif /* CONFIG_P2P */
 
 
@@ -2582,6 +2898,7 @@ static int wpa_config_process_hessid(
 #define _STR(f) #f, wpa_global_config_parse_str, OFFSET(f)
 #define STR(f) _STR(f), NULL, NULL
 #define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
+#define BIN(f) #f, wpa_global_config_parse_bin, OFFSET(f), NULL, NULL
 
 static const struct global_parse_data global_fields[] = {
 #ifdef CONFIG_CTRL_IFACE
@@ -2590,10 +2907,13 @@ static const struct global_parse_data global_fields[] = {
 #endif /* CONFIG_CTRL_IFACE */
        { INT_RANGE(eapol_version, 1, 2), 0 },
        { INT(ap_scan), 0 },
+       { INT(disable_scan_offload), 0 },
        { INT(fast_reauth), 0 },
        { STR(opensc_engine_path), 0 },
        { STR(pkcs11_engine_path), 0 },
        { STR(pkcs11_module_path), 0 },
+       { STR(pcsc_reader), 0 },
+       { STR(pcsc_pin), 0 },
        { STR(driver_param), 0 },
        { INT(dot11RSNAConfigPMKLifetime), 0 },
        { INT(dot11RSNAConfigPMKReauthThreshold), 0 },
@@ -2613,6 +2933,7 @@ static const struct global_parse_data global_fields[] = {
        { FUNC(os_version), CFG_CHANGED_OS_VERSION },
        { STR(config_methods), CFG_CHANGED_CONFIG_METHODS },
        { INT_RANGE(wps_cred_processing, 0, 2), 0 },
+       { FUNC(wps_vendor_ext_m1), CFG_CHANGED_VENDOR_EXTENSION },
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_P2P
        { FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE },
@@ -2625,6 +2946,7 @@ static const struct global_parse_data global_fields[] = {
        { INT_RANGE(persistent_reconnect, 0, 1), 0 },
        { INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
        { INT(p2p_group_idle), 0 },
+       { FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
 #endif /* CONFIG_P2P */
 #ifdef ANDROID_P2P
        { STR_RANGE(prioritize, 0, 32), CFG_CHANGED_IFACE_PRIORITY },
@@ -2636,15 +2958,18 @@ static const struct global_parse_data global_fields[] = {
        { INT_RANGE(filter_ssids, 0, 1), 0 },
        { INT(max_num_sta), 0 },
        { INT_RANGE(disassoc_low_ack, 0, 1), 0 },
-       { STR(home_realm), 0 },
-       { STR(home_username), 0 },
-       { STR(home_password), 0 },
-       { STR(home_ca_cert), 0 },
-       { STR(home_imsi), 0 },
-       { STR(home_milenage), 0 },
+#ifdef CONFIG_HS20
+       { INT_RANGE(hs20, 0, 1), 0 },
+#endif /* CONFIG_HS20 */
        { INT_RANGE(interworking, 0, 1), 0 },
        { FUNC(hessid), 0 },
-       { INT_RANGE(access_network_type, 0, 15), 0 }
+       { INT_RANGE(access_network_type, 0, 15), 0 },
+       { INT_RANGE(pbc_in_m1, 0, 1), 0 },
+       { STR(autoscan), 0 },
+       { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), 0 },
+       { BIN(wps_nfc_dh_pubkey), 0 },
+       { BIN(wps_nfc_dh_privkey), 0 },
+       { BIN(wps_nfc_dev_pw), 0 }
 };
 
 #undef FUNC
@@ -2654,6 +2979,7 @@ static const struct global_parse_data global_fields[] = {
 #undef _STR
 #undef STR
 #undef STR_RANGE
+#undef BIN
 #define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))