@@ -7,9 +7,13 @@
# keyid=<keyid_string>
# An optional VLAN ID can be specified by prefixing the line with
# vlanid=<VLAN ID>.
+# An optional WPS tag can be added by prefixing the line with
+# wps=[0/1] (default: 0)
00:00:00:00:00:00 secret passphrase
00:11:22:33:44:55 another passphrase
00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
keyid=example_id 00:11:22:33:44:77 passphrase with keyid
vlanid=3 00:00:00:00:00:00 passphrase with vlanid
+wps=1 00:00:00:00:00:00 passphrase for WPS
+wps=1 11:22:33:44:55:00 dev-specific passphrase for WPS
00:00:00:00:00:00 another passphrase for all STAs
@@ -301,6 +301,7 @@ static int hostapd_config_read_wpa_psk(const char *fname,
while (fgets(buf, sizeof(buf), f)) {
int vlan_id = 0;
+ int wps = 0;
line++;
@@ -331,6 +332,8 @@ static int hostapd_config_read_wpa_psk(const char *fname,
value = "";
if (!os_strcmp(name, "keyid")) {
keyid = value;
+ } else if (!os_strcmp(name, "wps")) {
+ wps = atoi(value);
} else if (!os_strcmp(name, "vlanid")) {
vlan_id = atoi(value);
} else {
@@ -404,6 +407,8 @@ static int hostapd_config_read_wpa_psk(const char *fname,
}
}
+ psk->wps = wps;
+
psk->next = ssid->wpa_psk;
ssid->wpa_psk = psk;
}
@@ -152,6 +152,7 @@ struct hostapd_wpa_psk {
struct hostapd_wpa_psk *next;
int group;
char keyid[KEYID_LEN];
+ int wps;
u8 psk[PMK_LEN];
u8 addr[ETH_ALEN];
u8 p2p_dev_addr[ETH_ALEN];
@@ -268,6 +268,44 @@ static void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr,
config_methods, dev_password_id, request_type, dev_name);
}
+static int hostapd_wps_lookup_pskfile_cb(void *ctx, const u8 *mac_addr,
+ const u8 **psk)
+{
+ const struct hostapd_data *hapd = ctx;
+ const struct hostapd_wpa_psk *wpa_psk;
+ const u8 *any_psk = NULL;
+ const u8 *dev_psk = NULL;
+ u8 any_mac_addr[ETH_ALEN];
+
+ os_memset(any_mac_addr, 0, ETH_ALEN);
+
+ for (wpa_psk = hapd->conf->ssid.wpa_psk; wpa_psk->next;
+ wpa_psk = wpa_psk->next)
+ {
+ if (wpa_psk->wps == 0)
+ continue;
+
+ if (!any_psk && os_memcmp(any_mac_addr, wpa_psk->addr, ETH_ALEN) == 0)
+ any_psk = wpa_psk->psk;
+
+ if (mac_addr && !dev_psk &&
+ os_memcmp(mac_addr, wpa_psk->addr, ETH_ALEN) == 0) {
+ dev_psk = wpa_psk->psk;
+ }
+ }
+
+ if (dev_psk)
+ *psk = dev_psk;
+ else if (any_psk)
+ *psk = any_psk;
+ else {
+ *psk = NULL;
+ wpa_printf(MSG_DEBUG,
+ "WPS: Failed to find appropriate PSK in wpa_psk_file");
+ }
+
+ return *psk ? 1 : 0;
+}
static void wps_reload_config(void *eloop_data, void *user_ctx)
{
@@ -1213,6 +1251,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
cfg.pin_needed_cb = hostapd_wps_pin_needed_cb;
cfg.reg_success_cb = hostapd_wps_reg_success_cb;
cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb;
+ cfg.lookup_pskfile_cb = hostapd_wps_lookup_pskfile_cb;
cfg.cb_ctx = hapd;
cfg.skip_cred_build = conf->skip_cred_build;
cfg.extra_cred = conf->extra_cred;
@@ -344,6 +344,14 @@ struct wps_registrar_config {
u16 dev_password_id, u8 request_type,
const char *dev_name);
+ /**
+ * lookup_pskfile_cb - Callback for searching for PSK in wpa_psk_file
+ * @ctx: Higher layer context data (cb_ctx)
+ * @addr: Enrollee's MAC address
+ * @psk: Pointer to found PSK (output arg)
+ */
+ int (*lookup_pskfile_cb)(void *ctx, const u8 *mac_addr, const u8 **psk);
+
/**
* cb_ctx: Higher layer context data for Registrar callbacks
*/
@@ -159,6 +159,9 @@ struct wps_registrar {
const u8 *pri_dev_type, u16 config_methods,
u16 dev_password_id, u8 request_type,
const char *dev_name);
+
+ int (*lookup_pskfile_cb)(void *ctx, const u8 *mac_addr, const u8 **psk);
+
void *cb_ctx;
struct dl_list pins;
@@ -681,6 +684,7 @@ wps_registrar_init(struct wps_context *wps,
reg->reg_success_cb = cfg->reg_success_cb;
reg->set_sel_reg_cb = cfg->set_sel_reg_cb;
reg->enrollee_seen_cb = cfg->enrollee_seen_cb;
+ reg->lookup_pskfile_cb = cfg->lookup_pskfile_cb;
reg->cb_ctx = cfg->cb_ctx;
reg->skip_cred_build = cfg->skip_cred_build;
if (cfg->extra_cred) {
@@ -1289,6 +1293,14 @@ static void wps_cb_set_sel_reg(struct wps_registrar *reg)
methods);
}
+static int wps_cp_lookup_pskfile(struct wps_registrar *reg, const u8 *mac_addr,
+ const u8** psk)
+{
+ if (reg->lookup_pskfile_cb == NULL)
+ return 0;
+
+ return reg->lookup_pskfile_cb(reg->cb_ctx, mac_addr, psk);
+}
static int wps_set_ie(struct wps_registrar *reg)
{
@@ -1644,6 +1656,7 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
{
struct wpabuf *cred;
struct wps_registrar *reg = wps->wps->registrar;
+ const u8 *pskfile_psk;
if (wps->wps->registrar->skip_cred_build)
goto skip_cred_build;
@@ -1759,6 +1772,13 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
wps->new_psk, wps->new_psk_len);
os_memcpy(wps->cred.key, wps->new_psk, wps->new_psk_len);
wps->cred.key_len = wps->new_psk_len;
+ } else if (wps_cp_lookup_pskfile(reg, wps->mac_addr_e, &pskfile_psk)) {
+ char hex[65];
+ wpa_hexdump_key(MSG_DEBUG, "WPS: Use PSK from wpa_psk_file",
+ pskfile_psk, 32);
+ wpa_snprintf_hex(hex, sizeof(hex), pskfile_psk, 32);
+ os_memcpy(wps->cred.key, hex, 32 * 2);
+ wps->cred.key_len = 32 * 2;
} else if (!wps->wps->registrar->force_per_enrollee_psk &&
wps->use_psk_key && wps->wps->psk_set) {
char hex[65];