diff options
author | Dmitry Shmidt <dimitrysh@google.com> | 2015-12-28 18:17:09 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-12-28 18:17:09 +0000 |
commit | 98409be0d89a8016663687d026cf4393a9639eb7 (patch) | |
tree | 856d772b38ff3e94486b088d8f4ff82d545b08ec | |
parent | 68e0189a45c0e4955a82d58f085d87376aae45b6 (diff) | |
parent | 0e58d9be2680098adccaadeadf31375ca54b7256 (diff) | |
download | wpa_supplicant_8-98409be0d89a8016663687d026cf4393a9639eb7.tar.gz |
Merge "Cumulative patch from commit c24f8e8e75b46f0b191cca788b6f4c10bed81861"
29 files changed, 1485 insertions, 313 deletions
diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c index 84d03082..d88cc562 100644 --- a/hostapd/hlr_auc_gw.c +++ b/hostapd/hlr_auc_gw.c @@ -1,6 +1,6 @@ /* * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator - * Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2005-2007, 2012-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -284,7 +284,7 @@ static int read_gsm_triplets(const char *fname) f = fopen(fname, "r"); if (f == NULL) { - printf("Could not open GSM tripler data file '%s'\n", fname); + printf("Could not open GSM triplet data file '%s'\n", fname); return -1; } @@ -312,66 +312,40 @@ static int read_gsm_triplets(const char *fname) } /* IMSI */ - pos2 = strchr(pos, ':'); - if (pos2 == NULL) { - printf("%s:%d - Invalid IMSI (%s)\n", - fname, line, pos); - ret = -1; - break; - } - *pos2 = '\0'; - if (strlen(pos) >= sizeof(g->imsi)) { - printf("%s:%d - Too long IMSI (%s)\n", - fname, line, pos); + pos2 = NULL; + pos = str_token(buf, ":", &pos2); + if (!pos || os_strlen(pos) >= sizeof(g->imsi)) { + printf("%s:%d - Invalid IMSI\n", fname, line); ret = -1; break; } os_strlcpy(g->imsi, pos, sizeof(g->imsi)); - pos = pos2 + 1; /* Kc */ - pos2 = strchr(pos, ':'); - if (pos2 == NULL) { - printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos); - ret = -1; - break; - } - *pos2 = '\0'; - if (strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) { - printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos); + pos = str_token(buf, ":", &pos2); + if (!pos || os_strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) { + printf("%s:%d - Invalid Kc\n", fname, line); ret = -1; break; } - pos = pos2 + 1; /* SRES */ - pos2 = strchr(pos, ':'); - if (pos2 == NULL) { - printf("%s:%d - Invalid SRES (%s)\n", fname, line, - pos); + pos = str_token(buf, ":", &pos2); + if (!pos || os_strlen(pos) != 8 || + hexstr2bin(pos, g->sres, 4)) { + printf("%s:%d - Invalid SRES\n", fname, line); ret = -1; break; } - *pos2 = '\0'; - if (strlen(pos) != 8 || hexstr2bin(pos, g->sres, 4)) { - printf("%s:%d - Invalid SRES (%s)\n", fname, line, - pos); - ret = -1; - break; - } - pos = pos2 + 1; /* RAND */ - pos2 = strchr(pos, ':'); - if (pos2) - *pos2 = '\0'; - if (strlen(pos) != 32 || hexstr2bin(pos, g->_rand, 16)) { - printf("%s:%d - Invalid RAND (%s)\n", fname, line, - pos); + pos = str_token(buf, ":", &pos2); + if (!pos || os_strlen(pos) != 32 || + hexstr2bin(pos, g->_rand, 16)) { + printf("%s:%d - Invalid RAND\n", fname, line); ret = -1; break; } - pos = pos2 + 1; g->next = gsm_db; gsm_db = g; @@ -450,86 +424,58 @@ static int read_milenage(const char *fname) } /* IMSI */ - pos2 = strchr(pos, ' '); - if (pos2 == NULL) { - printf("%s:%d - Invalid IMSI (%s)\n", - fname, line, pos); - ret = -1; - break; - } - *pos2 = '\0'; - if (strlen(pos) >= sizeof(m->imsi)) { - printf("%s:%d - Too long IMSI (%s)\n", - fname, line, pos); + pos2 = NULL; + pos = str_token(buf, " ", &pos2); + if (!pos || os_strlen(pos) >= sizeof(m->imsi)) { + printf("%s:%d - Invalid IMSI\n", fname, line); ret = -1; break; } os_strlcpy(m->imsi, pos, sizeof(m->imsi)); - pos = pos2 + 1; /* Ki */ - pos2 = strchr(pos, ' '); - if (pos2 == NULL) { - printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos); + pos = str_token(buf, " ", &pos2); + if (!pos || os_strlen(pos) != 32 || + hexstr2bin(pos, m->ki, 16)) { + printf("%s:%d - Invalid Ki\n", fname, line); ret = -1; break; } - *pos2 = '\0'; - if (strlen(pos) != 32 || hexstr2bin(pos, m->ki, 16)) { - printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos); - ret = -1; - break; - } - pos = pos2 + 1; /* OPc */ - pos2 = strchr(pos, ' '); - if (pos2 == NULL) { - printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos); - ret = -1; - break; - } - *pos2 = '\0'; - if (strlen(pos) != 32 || hexstr2bin(pos, m->opc, 16)) { - printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos); + pos = str_token(buf, " ", &pos2); + if (!pos || os_strlen(pos) != 32 || + hexstr2bin(pos, m->opc, 16)) { + printf("%s:%d - Invalid OPc\n", fname, line); ret = -1; break; } - pos = pos2 + 1; /* AMF */ - pos2 = strchr(pos, ' '); - if (pos2 == NULL) { - printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos); - ret = -1; - break; - } - *pos2 = '\0'; - if (strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) { - printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos); + pos = str_token(buf, " ", &pos2); + if (!pos || os_strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) { + printf("%s:%d - Invalid AMF\n", fname, line); ret = -1; break; } - pos = pos2 + 1; /* SQN */ - pos2 = strchr(pos, ' '); - if (pos2) - *pos2 = '\0'; - if (strlen(pos) != 12 || hexstr2bin(pos, m->sqn, 6)) { - printf("%s:%d - Invalid SEQ (%s)\n", fname, line, pos); + pos = str_token(buf, " ", &pos2); + if (!pos || os_strlen(pos) != 12 || + hexstr2bin(pos, m->sqn, 6)) { + printf("%s:%d - Invalid SEQ\n", fname, line); ret = -1; break; } - if (pos2) { - pos = pos2 + 1; + pos = str_token(buf, " ", &pos2); + if (pos) { m->res_len = atoi(pos); if (m->res_len && (m->res_len < EAP_AKA_RES_MIN_LEN || m->res_len > EAP_AKA_RES_MAX_LEN)) { - printf("%s:%d - Invalid RES_len (%s)\n", - fname, line, pos); + printf("%s:%d - Invalid RES_len\n", + fname, line); ret = -1; break; } @@ -1027,7 +973,7 @@ static void usage(void) { printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA " "database/authenticator\n" - "Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>\n" + "Copyright (c) 2005-2007, 2012-2015, Jouni Malinen <j@w1.fi>\n" "\n" "usage:\n" "hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] " diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c index 4bcdf6f9..b9d61762 100644 --- a/src/ap/gas_serv.c +++ b/src/ap/gas_serv.c @@ -101,6 +101,7 @@ gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr, if (sta->gas_dialog[i].dialog_token != dialog_token || !sta->gas_dialog[i].valid) continue; + ap_sta_replenish_timeout(hapd, sta, 5); return &sta->gas_dialog[i]; } wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for " diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c index 1afeeb29..a5a379eb 100644 --- a/src/drivers/driver_atheros.c +++ b/src/drivers/driver_atheros.c @@ -189,13 +189,13 @@ set80211priv(struct atheros_driver_data *drv, int op, void *data, int len) op == IEEE80211_IOCTL_FILTERFRAME) do_inline = 0; - memset(&iwr, 0, sizeof(iwr)); + os_memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); if (do_inline) { /* * Argument data fits inline; put it there. */ - memcpy(iwr.u.name, data, len); + os_memcpy(iwr.u.name, data, len); } else { /* * Argument data too big for inline transfer; setup a @@ -222,10 +222,10 @@ set80211param(struct atheros_driver_data *drv, int op, int arg) { struct iwreq iwr; - memset(&iwr, 0, sizeof(iwr)); + os_memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); iwr.u.mode = op; - memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg)); + os_memcpy(iwr.u.name + sizeof(__u32), &arg, sizeof(arg)); if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) { wpa_printf(MSG_INFO, @@ -244,9 +244,9 @@ ether_sprintf(const u8 *addr) static char buf[sizeof(MACSTR)]; if (addr != NULL) - snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); + os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); else - snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); + os_snprintf(buf, sizeof(buf), MACSTR, 0, 0, 0, 0, 0, 0); return buf; } #endif /* CONFIG_NO_STDOUT_DEBUG */ @@ -422,7 +422,7 @@ atheros_set_sta_authorized(void *priv, const u8 *addr, int authorized) else mlme.im_op = IEEE80211_MLME_UNAUTHORIZE; mlme.im_reason = 0; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); + os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); if (ret < 0) { wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR, @@ -455,9 +455,9 @@ atheros_del_key(void *priv, const u8 *addr, int key_idx) wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d", __func__, ether_sprintf(addr), key_idx); - memset(&wk, 0, sizeof(wk)); + os_memset(&wk, 0, sizeof(wk)); if (addr != NULL) { - memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); + os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE; } else { wk.idk_keyix = key_idx; @@ -538,20 +538,20 @@ atheros_set_key(const char *ifname, void *priv, enum wpa_alg alg, return -3; } - memset(&wk, 0, sizeof(wk)); + os_memset(&wk, 0, sizeof(wk)); wk.ik_type = cipher; wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT; if (addr == NULL || is_broadcast_ether_addr(addr)) { - memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); + os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); wk.ik_keyix = key_idx; if (set_tx) wk.ik_flags |= IEEE80211_KEY_DEFAULT; } else { - memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); + os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); wk.ik_keyix = IEEE80211_KEYIX_NONE; } wk.ik_keylen = key_len; - memcpy(wk.ik_keydata, key, key_len); + os_memcpy(wk.ik_keydata, key, key_len); ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk)); if (ret < 0) { @@ -575,11 +575,11 @@ atheros_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", __func__, ether_sprintf(addr), idx); - memset(&wk, 0, sizeof(wk)); + os_memset(&wk, 0, sizeof(wk)); if (addr == NULL) - memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); + os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); else - memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); + os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); wk.ik_keyix = idx; if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) { @@ -600,13 +600,13 @@ atheros_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, #define WPA_KEY_RSC_LEN 8 #endif u8 tmp[WPA_KEY_RSC_LEN]; - memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); + os_memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); for (i = 0; i < WPA_KEY_RSC_LEN; i++) { seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; } } #else /* WORDS_BIGENDIAN */ - memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); + os_memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); #endif /* WORDS_BIGENDIAN */ return 0; } @@ -616,7 +616,7 @@ static int atheros_flush(void *priv) { u8 allsta[IEEE80211_ADDR_LEN]; - memset(allsta, 0xff, IEEE80211_ADDR_LEN); + os_memset(allsta, 0xff, IEEE80211_ADDR_LEN); return atheros_sta_deauth(priv, NULL, allsta, IEEE80211_REASON_AUTH_LEAVE); } @@ -629,19 +629,19 @@ atheros_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, struct atheros_driver_data *drv = priv; struct ieee80211req_sta_stats stats; - memset(data, 0, sizeof(*data)); + os_memset(data, 0, sizeof(*data)); /* * Fetch statistics for station from the system. */ - memset(&stats, 0, sizeof(stats)); - memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); + os_memset(&stats, 0, sizeof(stats)); + os_memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); if (set80211priv(drv, IEEE80211_IOCTL_STA_STATS, &stats, sizeof(stats))) { wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr " MACSTR ")", __func__, MAC2STR(addr)); - if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { - memcpy(data, &drv->acct_data, sizeof(*data)); + if (os_memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { + os_memcpy(data, &drv->acct_data, sizeof(*data)); return 0; } @@ -668,7 +668,7 @@ atheros_sta_clear_stats(void *priv, const u8 *addr) wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr)); mlme.im_op = IEEE80211_MLME_CLEAR_STATS; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); + os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); if (ret < 0) { @@ -744,7 +744,7 @@ atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, mlme.im_op = IEEE80211_MLME_DEAUTH; mlme.im_reason = reason_code; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); + os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); if (ret < 0) { wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR @@ -768,7 +768,7 @@ atheros_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, mlme.im_op = IEEE80211_MLME_DISASSOC; mlme.im_reason = reason_code; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); + os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); if (ret < 0) { wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr " @@ -794,7 +794,7 @@ static int atheros_set_qos_map(void *ctx, const u8 *qos_map_set, wpa_printf(MSG_ERROR, "Invalid QoS Map"); return -1; } else { - memset(&req, 0, sizeof(struct ieee80211req_athdbg)); + os_memset(&req, 0, sizeof(struct ieee80211req_athdbg)); req.cmd = IEEE80211_DBGREQ_SETQOSMAPCONF; os_memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->iface, sizeof(iwr.ifr_name)); @@ -1120,8 +1120,8 @@ atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) /* * Fetch negotiated WPA/RSN parameters from the system. */ - memset(&ie, 0, sizeof(ie)); - memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); + os_memset(&ie, 0, sizeof(ie)); + os_memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) { /* * See ATH_WPS_IE comment in the beginning of the file for a @@ -1171,10 +1171,10 @@ atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) no_ie: drv_event_assoc(hapd, addr, iebuf, ielen, 0); - if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { + if (os_memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { /* Cached accounting data is not valid anymore. */ - memset(drv->acct_mac, 0, ETH_ALEN); - memset(&drv->acct_data, 0, sizeof(drv->acct_data)); + os_memset(drv->acct_mac, 0, ETH_ALEN); + os_memset(&drv->acct_data, 0, sizeof(drv->acct_data)); } } @@ -1185,10 +1185,10 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv, #define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); - if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { + if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { char *pos; u8 addr[ETH_ALEN]; - pos = strstr(custom, "addr="); + pos = os_strstr(custom, "addr="); if (pos == NULL) { wpa_printf(MSG_DEBUG, "MLME-MICHAELMICFAILURE.indication " @@ -1212,33 +1212,33 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv, char *key, *value; u32 val; key = custom; - while ((key = strchr(key, '\n')) != NULL) { + while ((key = os_strchr(key, '\n')) != NULL) { key++; - value = strchr(key, '='); + value = os_strchr(key, '='); if (value == NULL) continue; *value++ = '\0'; val = strtoul(value, NULL, 10); - if (strcmp(key, "mac") == 0) + if (os_strcmp(key, "mac") == 0) hwaddr_aton(value, drv->acct_mac); - else if (strcmp(key, "rx_packets") == 0) + else if (os_strcmp(key, "rx_packets") == 0) drv->acct_data.rx_packets = val; - else if (strcmp(key, "tx_packets") == 0) + else if (os_strcmp(key, "tx_packets") == 0) drv->acct_data.tx_packets = val; - else if (strcmp(key, "rx_bytes") == 0) + else if (os_strcmp(key, "rx_bytes") == 0) drv->acct_data.rx_bytes = val; - else if (strcmp(key, "tx_bytes") == 0) + else if (os_strcmp(key, "tx_bytes") == 0) drv->acct_data.tx_bytes = val; key = value; } #ifdef CONFIG_WPS - } else if (strncmp(custom, "PUSH-BUTTON.indication", 22) == 0) { + } else if (os_strncmp(custom, "PUSH-BUTTON.indication", 22) == 0) { /* Some atheros kernels send push button as a wireless event */ /* PROBLEM! this event is received for ALL BSSs ... * so all are enabled for WPS... ugh. */ wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL); - } else if (strncmp(custom, "Manage.prob_req ", 16) == 0) { + } else if (os_strncmp(custom, "Manage.prob_req ", 16) == 0) { /* * Atheros driver uses a hack to pass Probe Request frames as a * binary data in the custom wireless event. The old way (using @@ -1255,7 +1255,7 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv, (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); #endif /* CONFIG_WPS */ #if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) - } else if (strncmp(custom, "Manage.assoc_req ", 17) == 0) { + } else if (os_strncmp(custom, "Manage.assoc_req ", 17) == 0) { /* Format: "Manage.assoc_req <frame len>" | zero padding | * frame */ int len = atoi(custom + 17); @@ -1267,7 +1267,7 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv, } atheros_raw_receive(drv, NULL, (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); - } else if (strncmp(custom, "Manage.auth ", 12) == 0) { + } else if (os_strncmp(custom, "Manage.auth ", 12) == 0) { /* Format: "Manage.auth <frame len>" | zero padding | frame */ int len = atoi(custom + 12); if (len < 0 || @@ -1280,7 +1280,7 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv, (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); #endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R */ #ifdef ATHEROS_USE_RAW_RECEIVE - } else if (strncmp(custom, "Manage.action ", 14) == 0) { + } else if (os_strncmp(custom, "Manage.action ", 14) == 0) { /* Format: "Manage.assoc_req <frame len>" | zero padding | frame */ int len = atoi(custom + 14); @@ -1395,7 +1395,7 @@ atheros_wireless_event_wireless(struct atheros_driver_data *drv, while ((size_t) (end - pos) >= IW_EV_LCP_LEN) { /* Event data may be unaligned, so make a local, aligned copy * before processing. */ - memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); + os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); wpa_printf(MSG_MSGDUMP, "Wireless event: cmd=0x%x len=%d", iwe->cmd, iwe->len); if (iwe->len <= IW_EV_LCP_LEN || iwe->len > end - pos) @@ -1409,10 +1409,10 @@ atheros_wireless_event_wireless(struct atheros_driver_data *drv, /* WE-19 removed the pointer from struct iw_point */ char *dpos = (char *) &iwe_buf.u.data.length; int dlen = dpos - (char *) &iwe_buf; - memcpy(dpos, pos + IW_EV_LCP_LEN, - sizeof(struct iw_event) - dlen); + os_memcpy(dpos, pos + IW_EV_LCP_LEN, + sizeof(struct iw_event) - dlen); } else { - memcpy(&iwe_buf, pos, sizeof(struct iw_event)); + os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); custom += IW_EV_POINT_OFF; } @@ -1432,10 +1432,10 @@ atheros_wireless_event_wireless(struct atheros_driver_data *drv, case IWEVCUSTOM: if (iwe->u.data.length > end - custom) return; - buf = malloc(iwe->u.data.length + 1); + buf = os_malloc(iwe->u.data.length + 1); if (buf == NULL) return; /* XXX */ - memcpy(buf, custom, iwe->u.data.length); + os_memcpy(buf, custom, iwe->u.data.length); buf[iwe->u.data.length] = '\0'; if (iwe->u.data.flags != 0) { @@ -1446,7 +1446,7 @@ atheros_wireless_event_wireless(struct atheros_driver_data *drv, atheros_wireless_event_wireless_custom( drv, buf, buf + iwe->u.data.length); } - free(buf); + os_free(buf); break; } @@ -1500,7 +1500,7 @@ atheros_get_we_version(struct atheros_driver_data *drv) if (range == NULL) return -1; - memset(&iwr, 0, sizeof(iwr)); + os_memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); iwr.u.data.pointer = (caddr_t) range; iwr.u.data.length = buflen; @@ -1569,7 +1569,7 @@ atheros_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, */ len = data_len + sizeof(struct l2_ethhdr); if (len > sizeof(buf)) { - bp = malloc(len); + bp = os_malloc(len); if (bp == NULL) { wpa_printf(MSG_INFO, "EAPOL frame discarded, cannot malloc temp buffer of size %lu!", @@ -1578,17 +1578,17 @@ atheros_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, } } eth = (struct l2_ethhdr *) bp; - memcpy(eth->h_dest, addr, ETH_ALEN); - memcpy(eth->h_source, own_addr, ETH_ALEN); + os_memcpy(eth->h_dest, addr, ETH_ALEN); + os_memcpy(eth->h_source, own_addr, ETH_ALEN); eth->h_proto = host_to_be16(ETH_P_EAPOL); - memcpy(eth+1, data, data_len); + os_memcpy(eth + 1, data, data_len); wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len); status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len); if (bp != buf) - free(bp); + os_free(bp); return status; } @@ -1622,9 +1622,9 @@ atheros_init(struct hostapd_data *hapd, struct wpa_init_params *params) strerror(errno)); goto bad; } - memcpy(drv->iface, params->ifname, sizeof(drv->iface)); + os_memcpy(drv->iface, params->ifname, sizeof(drv->iface)); - memset(&ifr, 0, sizeof(ifr)); + os_memset(&ifr, 0, sizeof(ifr)); os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) { wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s", @@ -1658,7 +1658,7 @@ atheros_init(struct hostapd_data *hapd, struct wpa_init_params *params) } else drv->sock_recv = drv->sock_xmit; - memset(&iwr, 0, sizeof(iwr)); + os_memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); iwr.u.mode = IW_MODE_MASTER; @@ -1728,7 +1728,7 @@ atheros_set_ssid(void *priv, const u8 *buf, int len) struct atheros_driver_data *drv = priv; struct iwreq iwr; - memset(&iwr, 0, sizeof(iwr)); + os_memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); iwr.u.essid.flags = 1; /* SSID active */ iwr.u.essid.pointer = (caddr_t) buf; @@ -1749,7 +1749,7 @@ atheros_get_ssid(void *priv, u8 *buf, int len) struct iwreq iwr; int ret = 0; - memset(&iwr, 0, sizeof(iwr)); + os_memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); iwr.u.essid.pointer = (caddr_t) buf; iwr.u.essid.length = (len > IW_ESSID_MAX_SIZE) ? @@ -1860,7 +1860,7 @@ static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len, wpa_printf(MSG_DEBUG, "%s frmlen = %lu " MACSTR, __func__, (unsigned long) data_len, MAC2STR(mgmt->da)); mgmt_frm = (struct ieee80211req_mgmtbuf *) buf; - memcpy(mgmt_frm->macaddr, (u8 *)mgmt->da, IEEE80211_ADDR_LEN); + os_memcpy(mgmt_frm->macaddr, (u8 *)mgmt->da, IEEE80211_ADDR_LEN); mgmt_frm->buflen = data_len; if (&mgmt_frm->buf[0] + data_len > buf + sizeof(buf)) { wpa_printf(MSG_INFO, "atheros: Too long frame for " diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 0fd836ba..ed5e4a8e 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -1520,11 +1520,16 @@ static void nl80211_check_global(struct nl80211_global *global) static void wpa_driver_nl80211_rfkill_blocked(void *ctx) { + struct wpa_driver_nl80211_data *drv = ctx; + wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked"); + /* - * This may be for any interface; use ifdown event to disable - * interface. + * rtnetlink ifdown handler will report interfaces other than the P2P + * Device interface as disabled. */ + if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL); } @@ -1541,7 +1546,12 @@ static void wpa_driver_nl80211_rfkill_unblocked(void *ctx) if (is_p2p_net_interface(drv->nlmode)) nl80211_disable_11b_rates(drv, drv->ifindex, 1); - /* rtnetlink ifup handler will report interface as enabled */ + /* + * rtnetlink ifup handler will report interfaces other than the P2P + * Device interface as enabled. + */ + if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL); } @@ -1626,13 +1636,65 @@ static void nl80211_destroy_bss(struct i802_bss *bss) } +static void +wpa_driver_nl80211_drv_init_rfkill(struct wpa_driver_nl80211_data *drv) +{ + struct rfkill_config *rcfg; + + if (drv->rfkill) + return; + + rcfg = os_zalloc(sizeof(*rcfg)); + if (!rcfg) + return; + + rcfg->ctx = drv; + + /* rfkill uses netdev sysfs for initialization. However, P2P Device is + * not associated with a netdev, so use the name of some other interface + * sharing the same wiphy as the P2P Device interface. + * + * Note: This is valid, as a P2P Device interface is always dynamically + * created and is created only once another wpa_s interface was added. + */ + if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) { + struct nl80211_global *global = drv->global; + struct wpa_driver_nl80211_data *tmp1; + + dl_list_for_each(tmp1, &global->interfaces, + struct wpa_driver_nl80211_data, list) { + if (drv == tmp1 || drv->wiphy_idx != tmp1->wiphy_idx || + !tmp1->rfkill) + continue; + + wpa_printf(MSG_DEBUG, + "nl80211: Use (%s) to initialize P2P Device rfkill", + tmp1->first_bss->ifname); + os_strlcpy(rcfg->ifname, tmp1->first_bss->ifname, + sizeof(rcfg->ifname)); + break; + } + } else { + os_strlcpy(rcfg->ifname, drv->first_bss->ifname, + sizeof(rcfg->ifname)); + } + + rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked; + rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked; + drv->rfkill = rfkill_init(rcfg); + if (!drv->rfkill) { + wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available"); + os_free(rcfg); + } +} + + static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname, void *global_priv, int hostapd, const u8 *set_addr, const char *driver_params) { struct wpa_driver_nl80211_data *drv; - struct rfkill_config *rcfg; struct i802_bss *bss; if (global_priv == NULL) @@ -1673,19 +1735,6 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname, if (nl80211_init_bss(bss)) goto failed; - rcfg = os_zalloc(sizeof(*rcfg)); - if (rcfg == NULL) - goto failed; - rcfg->ctx = drv; - os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname)); - rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked; - rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked; - drv->rfkill = rfkill_init(rcfg); - if (drv->rfkill == NULL) { - wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available"); - os_free(rcfg); - } - if (linux_iface_up(drv->global->ioctl_sock, ifname) > 0) drv->start_iface_up = 1; @@ -2224,6 +2273,8 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv, if (nlmode == NL80211_IFTYPE_P2P_DEVICE) nl80211_get_macaddr(bss); + wpa_driver_nl80211_drv_init_rfkill(drv); + if (!rfkill_is_blocked(drv->rfkill)) { int ret = i802_set_iface_flags(bss, 1); if (ret) { @@ -2241,20 +2292,22 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv, } else { wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable " "interface '%s' due to rfkill", bss->ifname); - if (nlmode == NL80211_IFTYPE_P2P_DEVICE) - return 0; - drv->if_disabled = 1; + if (nlmode != NL80211_IFTYPE_P2P_DEVICE) + drv->if_disabled = 1; + send_rfkill_event = 1; } - if (!drv->hostapd) + if (!drv->hostapd && nlmode != NL80211_IFTYPE_P2P_DEVICE) netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 1, IF_OPER_DORMANT); - if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, - bss->addr)) - return -1; - os_memcpy(drv->perm_addr, bss->addr, ETH_ALEN); + if (nlmode != NL80211_IFTYPE_P2P_DEVICE) { + if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, + bss->addr)) + return -1; + os_memcpy(drv->perm_addr, bss->addr, ETH_ALEN); + } if (send_rfkill_event) { eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill, diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index 21c0b6db..09e03b3d 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -84,6 +84,7 @@ struct wpa_driver_nl80211_data { struct dl_list list; struct dl_list wiphy_list; char phyname[32]; + unsigned int wiphy_idx; u8 perm_addr[ETH_ALEN]; void *ctx; int ifindex; diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index c74ed5ff..8c3ba491 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -487,6 +487,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + if (tb[NL80211_ATTR_WIPHY]) + drv->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]); + if (tb[NL80211_ATTR_WIPHY_NAME]) os_strlcpy(drv->phyname, nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]), diff --git a/src/drivers/rfkill.c b/src/drivers/rfkill.c index 45b26c46..464cf783 100644 --- a/src/drivers/rfkill.c +++ b/src/drivers/rfkill.c @@ -8,6 +8,7 @@ #include "includes.h" #include <fcntl.h> +#include <limits.h> #include "utils/common.h" #include "utils/eloop.h" @@ -47,6 +48,7 @@ struct rfkill_data { struct rfkill_config *cfg; int fd; int blocked; + uint32_t idx; }; @@ -69,12 +71,13 @@ static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx) (int) len, RFKILL_EVENT_SIZE_V1); return; } + if (event.op != RFKILL_OP_CHANGE || event.idx != rfkill->idx) + return; + wpa_printf(MSG_DEBUG, "rfkill: event: idx=%u type=%d " "op=%u soft=%u hard=%u", event.idx, event.type, event.op, event.soft, event.hard); - if (event.op != RFKILL_OP_CHANGE || event.type != RFKILL_TYPE_WLAN) - return; if (event.hard) { wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked"); @@ -102,11 +105,23 @@ struct rfkill_data * rfkill_init(struct rfkill_config *cfg) struct rfkill_data *rfkill; struct rfkill_event event; ssize_t len; + char *phy = NULL, *rfk_phy; + char buf[24 + IFNAMSIZ + 1]; + char buf2[31 + 11 + 1]; + int found = 0; rfkill = os_zalloc(sizeof(*rfkill)); if (rfkill == NULL) return NULL; + os_snprintf(buf, sizeof(buf), "/sys/class/net/%s/phy80211", + cfg->ifname); + phy = realpath(buf, NULL); + if (!phy) { + wpa_printf(MSG_INFO, "rfkill: Cannot get wiphy information"); + goto fail; + } + rfkill->cfg = cfg; rfkill->fd = open("/dev/rfkill", O_RDONLY); if (rfkill->fd < 0) { @@ -136,13 +151,27 @@ struct rfkill_data * rfkill_init(struct rfkill_config *cfg) (int) len, RFKILL_EVENT_SIZE_V1); continue; } + if (event.op != RFKILL_OP_ADD || + event.type != RFKILL_TYPE_WLAN) + continue; + + os_snprintf(buf2, sizeof(buf2), + "/sys/class/rfkill/rfkill%d/device", event.idx); + rfk_phy = realpath(buf2, NULL); + if (!rfk_phy) + goto fail2; + found = os_strcmp(phy, rfk_phy) == 0; + free(rfk_phy); + + if (!found) + continue; + wpa_printf(MSG_DEBUG, "rfkill: initial event: idx=%u type=%d " "op=%u soft=%u hard=%u", event.idx, event.type, event.op, event.soft, event.hard); - if (event.op != RFKILL_OP_ADD || - event.type != RFKILL_TYPE_WLAN) - continue; + + rfkill->idx = event.idx; if (event.hard) { wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked"); rfkill->blocked = 1; @@ -150,8 +179,12 @@ struct rfkill_data * rfkill_init(struct rfkill_config *cfg) wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked"); rfkill->blocked = 1; } + break; } + if (!found) + goto fail2; + eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL); return rfkill; @@ -160,6 +193,8 @@ fail2: close(rfkill->fd); fail: os_free(rfkill); + /* use standard free function to match realpath() */ + free(phy); return NULL; } diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c index 05960989..503d4b02 100644 --- a/src/eap_peer/eap_peap.c +++ b/src/eap_peer/eap_peap.c @@ -70,8 +70,8 @@ struct eap_peap_data { }; -static int eap_peap_parse_phase1(struct eap_peap_data *data, - const char *phase1) +static void eap_peap_parse_phase1(struct eap_peap_data *data, + const char *phase1) { const char *pos; @@ -126,8 +126,6 @@ static int eap_peap_parse_phase1(struct eap_peap_data *data, wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled"); } #endif /* EAP_TNC */ - - return 0; } @@ -145,11 +143,8 @@ static void * eap_peap_init(struct eap_sm *sm) data->peap_outer_success = 2; data->crypto_binding = OPTIONAL_BINDING; - if (config && config->phase1 && - eap_peap_parse_phase1(data, config->phase1) < 0) { - eap_peap_deinit(sm, data); - return NULL; - } + if (config && config->phase1) + eap_peap_parse_phase1(data, config->phase1); if (eap_peer_select_phase2_methods(config, "auth=", &data->phase2_types, @@ -339,7 +334,8 @@ static int eap_tlv_add_cryptobinding(struct eap_sm *sm, addr[0], len[0]); wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2", addr[1], len[1]); - hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac); + if (hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac) < 0) + return -1; wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN); data->crypto_binding_used = 1; @@ -650,6 +646,7 @@ static int eap_peap_phase2_request(struct eap_sm *sm, if (*resp == NULL) { ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; + wpabuf_free(buf); return -1; } wpabuf_put_buf(*resp, buf); diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c index 4b994fd3..c270832b 100644 --- a/src/eap_peer/eap_tls_common.c +++ b/src/eap_peer/eap_tls_common.c @@ -356,10 +356,8 @@ u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm, struct tls_random keys; u8 *out; - if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys)) - return NULL; - - if (keys.client_random == NULL || keys.server_random == NULL) + if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys) || + keys.client_random == NULL || keys.server_random == NULL) return NULL; *len = 1 + keys.client_random_len + keys.server_random_len; @@ -1041,6 +1039,9 @@ int eap_peer_select_phase2_methods(struct eap_peer_config *config, if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE) { wpa_printf(MSG_ERROR, "TLS: Unsupported Phase2 EAP " "method '%s'", start); + os_free(methods); + os_free(buf); + return -1; } else { num_methods++; _methods = os_realloc_array(methods, num_methods, diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c index 9741dede..a4b26971 100644 --- a/src/eap_peer/eap_ttls.c +++ b/src/eap_peer/eap_ttls.c @@ -71,6 +71,7 @@ static void * eap_ttls_init(struct eap_sm *sm) { struct eap_ttls_data *data; struct eap_peer_config *config = eap_get_config(sm); + int selected_non_eap; char *selected; data = os_zalloc(sizeof(*data)); @@ -78,26 +79,67 @@ static void * eap_ttls_init(struct eap_sm *sm) return NULL; data->ttls_version = EAP_TTLS_VERSION; selected = "EAP"; + selected_non_eap = 0; data->phase2_type = EAP_TTLS_PHASE2_EAP; + /* + * Either one auth= type or one or more autheap= methods can be + * specified. + */ if (config && config->phase2) { + const char *token, *last = NULL; + + while ((token = cstr_token(config->phase2, " \t", &last))) { + if (os_strncmp(token, "auth=", 5) != 0) + continue; + token += 5; + + if (last - token == 8 && + os_strncmp(token, "MSCHAPV2", 8) == 0) { + selected = "MSCHAPV2"; + data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2; + } else if (last - token == 6 && + os_strncmp(token, "MSCHAP", 6) == 0) { + selected = "MSCHAP"; + data->phase2_type = EAP_TTLS_PHASE2_MSCHAP; + } else if (last - token == 3 && + os_strncmp(token, "PAP", 3) == 0) { + selected = "PAP"; + data->phase2_type = EAP_TTLS_PHASE2_PAP; + } else if (last - token == 4 && + os_strncmp(token, "CHAP", 4) == 0) { + selected = "CHAP"; + data->phase2_type = EAP_TTLS_PHASE2_CHAP; + } else { + wpa_printf(MSG_ERROR, + "EAP-TTLS: Unsupported Phase2 type '%s'", + token); + eap_ttls_deinit(sm, data); + return NULL; + } + + if (selected_non_eap) { + wpa_printf(MSG_ERROR, + "EAP-TTLS: Only one Phase2 type can be specified"); + eap_ttls_deinit(sm, data); + return NULL; + } + + selected_non_eap = 1; + } + if (os_strstr(config->phase2, "autheap=")) { + if (selected_non_eap) { + wpa_printf(MSG_ERROR, + "EAP-TTLS: Both auth= and autheap= params cannot be specified"); + eap_ttls_deinit(sm, data); + return NULL; + } selected = "EAP"; data->phase2_type = EAP_TTLS_PHASE2_EAP; - } else if (os_strstr(config->phase2, "auth=MSCHAPV2")) { - selected = "MSCHAPV2"; - data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2; - } else if (os_strstr(config->phase2, "auth=MSCHAP")) { - selected = "MSCHAP"; - data->phase2_type = EAP_TTLS_PHASE2_MSCHAP; - } else if (os_strstr(config->phase2, "auth=PAP")) { - selected = "PAP"; - data->phase2_type = EAP_TTLS_PHASE2_PAP; - } else if (os_strstr(config->phase2, "auth=CHAP")) { - selected = "CHAP"; - data->phase2_type = EAP_TTLS_PHASE2_CHAP; } } + wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected); if (data->phase2_type == EAP_TTLS_PHASE2_EAP) { diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c index 51062b09..d424862a 100644 --- a/src/eap_server/eap_server_peap.c +++ b/src/eap_server/eap_server_peap.c @@ -335,6 +335,18 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data) return -1; wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60); + if (tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) { + /* Fast-connect: IPMK|CMK = TK */ + os_memcpy(data->ipmk, tk, 40); + wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK", + data->ipmk, 40); + os_memcpy(data->cmk, tk + 40, 20); + wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK from TK", + data->cmk, 20); + os_free(tk); + return 0; + } + eap_peap_get_isk(data, isk, sizeof(isk)); wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk)); @@ -357,7 +369,6 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data) os_free(tk); - /* TODO: fast-connect: IPMK|CMK = TK */ os_memcpy(data->ipmk, imck, 40); wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40); os_memcpy(data->cmk, imck + 40, 20); @@ -1267,8 +1278,9 @@ static void eap_peap_process(struct eap_sm *sm, void *priv, wpa_printf(MSG_DEBUG, "EAP-PEAP: Resuming previous session - skip Phase2"); - eap_peap_state(data, SUCCESS_REQ); - tls_connection_set_success_data_resumed(data->ssl.conn); + eap_peap_req_success(sm, data); + if (data->state == SUCCESS_REQ) + tls_connection_set_success_data_resumed(data->ssl.conn); } diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c index 48752d72..86e509e2 100644 --- a/src/rsn_supp/tdls.c +++ b/src/rsn_supp/tdls.c @@ -2176,6 +2176,14 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, "ignore TPK M2 from " MACSTR, MAC2STR(src_addr)); return -1; } + + if (peer->tpk_success) { + wpa_printf(MSG_INFO, "TDLS: Ignore incoming TPK M2 retry, from " + MACSTR " as TPK M3 was already sent", + MAC2STR(src_addr)); + return 0; + } + wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_REQUEST); if (len < 3 + 2 + 1) { diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 9bde3c81..669f658c 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -1670,14 +1670,14 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, } if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, *key_data_len / 8, key_data, buf)) { - os_free(buf); + bin_clear_free(buf, *key_data_len); wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: AES unwrap failed - " "could not decrypt EAPOL-Key key data"); return -1; } os_memcpy(key_data, buf, *key_data_len); - os_free(buf); + bin_clear_free(buf, *key_data_len); WPA_PUT_BE16(key->key_data_length, *key_data_len); } else { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, diff --git a/src/tls/tlsv1_client_ocsp.c b/src/tls/tlsv1_client_ocsp.c index bcc7a860..2d5cdb94 100644 --- a/src/tls/tlsv1_client_ocsp.c +++ b/src/tls/tlsv1_client_ocsp.c @@ -10,7 +10,9 @@ #include "common.h" #include "crypto/tls.h" +#include "crypto/sha1.h" #include "asn1.h" +#include "x509v3.h" #include "tlsv1_common.h" #include "tlsv1_record.h" #include "tlsv1_client.h" @@ -45,12 +47,329 @@ static int is_oid_basic_ocsp_resp(struct asn1_oid *oid) } +static int ocsp_responder_id_match(struct x509_certificate *signer, + struct x509_name *name, const u8 *key_hash) +{ + if (key_hash) { + u8 hash[SHA1_MAC_LEN]; + const u8 *addr[1] = { signer->public_key }; + size_t len[1] = { signer->public_key_len }; + + if (sha1_vector(1, addr, len, hash) < 0) + return 0; + return os_memcmp(hash, key_hash, SHA1_MAC_LEN) == 0; + } + + return x509_name_compare(&signer->subject, name) == 0; +} + + +static unsigned int ocsp_hash_data(struct asn1_oid *alg, const u8 *data, + size_t data_len, u8 *hash) +{ + const u8 *addr[1] = { data }; + size_t len[1] = { data_len }; + char buf[100]; + + if (x509_sha1_oid(alg)) { + if (sha1_vector(1, addr, len, hash) < 0) + return 0; + wpa_hexdump(MSG_MSGDUMP, "OCSP: Hash (SHA1)", hash, 20); + return 20; + } + + if (x509_sha256_oid(alg)) { + if (sha256_vector(1, addr, len, hash) < 0) + return 0; + wpa_hexdump(MSG_MSGDUMP, "OCSP: Hash (SHA256)", hash, 32); + return 32; + } + + if (x509_sha384_oid(alg)) { + if (sha384_vector(1, addr, len, hash) < 0) + return 0; + wpa_hexdump(MSG_MSGDUMP, "OCSP: Hash (SHA384)", hash, 48); + return 48; + } + + if (x509_sha512_oid(alg)) { + if (sha512_vector(1, addr, len, hash) < 0) + return 0; + wpa_hexdump(MSG_MSGDUMP, "OCSP: Hash (SHA512)", hash, 64); + return 64; + } + + + asn1_oid_to_str(alg, buf, sizeof(buf)); + wpa_printf(MSG_DEBUG, "OCSP: Could not calculate hash with alg %s", + buf); + return 0; +} + + +static int tls_process_ocsp_single_response(struct tlsv1_client *conn, + struct x509_certificate *cert, + struct x509_certificate *issuer, + const u8 *resp, size_t len, + enum tls_ocsp_result *res) +{ + struct asn1_hdr hdr; + const u8 *pos, *end; + struct x509_algorithm_identifier alg; + const u8 *name_hash, *key_hash; + size_t name_hash_len, key_hash_len; + const u8 *serial_number; + size_t serial_number_len; + u8 hash[64]; + unsigned int hash_len; + unsigned int cert_status; + os_time_t update; + struct os_time now; + + wpa_hexdump(MSG_MSGDUMP, "OCSP: SingleResponse", resp, len); + + /* + * SingleResponse ::= SEQUENCE { + * certID CertID, + * certStatus CertStatus, + * thisUpdate GeneralizedTime, + * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, + * singleExtensions [1] EXPLICIT Extensions OPTIONAL } + */ + + /* CertID ::= SEQUENCE */ + if (asn1_get_next(resp, len, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, + "OCSP: Expected SEQUENCE (CertID) - found class %d tag 0x%x", + hdr.class, hdr.tag); + return -1; + } + pos = hdr.payload; + end = hdr.payload + hdr.length; + + /* + * CertID ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * issuerNameHash OCTET STRING, + * issuerKeyHash OCTET STRING, + * serialNumber CertificateSerialNumber } + */ + + /* hashAlgorithm AlgorithmIdentifier */ + if (x509_parse_algorithm_identifier(pos, end - pos, &alg, &pos)) + return -1; + + /* issuerNameHash OCTET STRING */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_OCTETSTRING) { + wpa_printf(MSG_DEBUG, + "OCSP: Expected OCTET STRING (issuerNameHash) - found class %d tag 0x%x", + hdr.class, hdr.tag); + return -1; + } + name_hash = hdr.payload; + name_hash_len = hdr.length; + wpa_hexdump(MSG_DEBUG, "OCSP: issuerNameHash", + name_hash, name_hash_len); + pos = hdr.payload + hdr.length; + + wpa_hexdump(MSG_DEBUG, "OCSP: Issuer subject DN", + issuer->subject_dn, issuer->subject_dn_len); + hash_len = ocsp_hash_data(&alg.oid, issuer->subject_dn, + issuer->subject_dn_len, hash); + if (hash_len == 0 || name_hash_len != hash_len || + os_memcmp(name_hash, hash, hash_len) != 0) { + wpa_printf(MSG_DEBUG, "OCSP: issuerNameHash mismatch"); + wpa_hexdump(MSG_DEBUG, "OCSP: Calculated issuerNameHash", + hash, hash_len); + return -1; + } + + /* issuerKeyHash OCTET STRING */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_OCTETSTRING) { + wpa_printf(MSG_DEBUG, + "OCSP: Expected OCTET STRING (issuerKeyHash) - found class %d tag 0x%x", + hdr.class, hdr.tag); + return -1; + } + key_hash = hdr.payload; + key_hash_len = hdr.length; + wpa_hexdump(MSG_DEBUG, "OCSP: issuerKeyHash", key_hash, key_hash_len); + pos = hdr.payload + hdr.length; + + hash_len = ocsp_hash_data(&alg.oid, issuer->public_key, + issuer->public_key_len, hash); + if (hash_len == 0 || key_hash_len != hash_len || + os_memcmp(key_hash, hash, hash_len) != 0) { + wpa_printf(MSG_DEBUG, "OCSP: issuerKeyHash mismatch"); + wpa_hexdump(MSG_DEBUG, "OCSP: Calculated issuerKeyHash", + hash, hash_len); + return -1; + } + + /* serialNumber CertificateSerialNumber ::= INTEGER */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_INTEGER || + hdr.length < 1 || hdr.length > X509_MAX_SERIAL_NUM_LEN) { + wpa_printf(MSG_DEBUG, "OCSP: No INTEGER tag found for serialNumber; class=%d tag=0x%x length=%u", + hdr.class, hdr.tag, hdr.length); + return -1; + } + serial_number = hdr.payload; + serial_number_len = hdr.length; + while (serial_number_len > 0 && serial_number[0] == 0) { + serial_number++; + serial_number_len--; + } + wpa_hexdump(MSG_MSGDUMP, "OCSP: serialNumber", serial_number, + serial_number_len); + + if (serial_number_len != cert->serial_number_len || + os_memcmp(serial_number, cert->serial_number, + serial_number_len) != 0) { + wpa_printf(MSG_DEBUG, "OCSP: serialNumber mismatch"); + return -1; + } + + pos = end; + end = resp + len; + + /* certStatus CertStatus ::= CHOICE */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) { + wpa_printf(MSG_DEBUG, + "OCSP: Expected CHOICE (CertStatus) - found class %d tag 0x%x", + hdr.class, hdr.tag); + return -1; + } + cert_status = hdr.tag; + wpa_printf(MSG_DEBUG, "OCSP: certStatus=%u", cert_status); + wpa_hexdump(MSG_DEBUG, "OCSP: CertStatus additional data", + hdr.payload, hdr.length); + pos = hdr.payload + hdr.length; + + os_get_time(&now); + /* thisUpdate GeneralizedTime */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_GENERALIZEDTIME || + x509_parse_time(hdr.payload, hdr.length, hdr.tag, &update) < 0) { + wpa_printf(MSG_DEBUG, "OCSP: Failed to parse thisUpdate"); + return -1; + } + wpa_printf(MSG_DEBUG, "OCSP: thisUpdate %lu", (unsigned long) update); + pos = hdr.payload + hdr.length; + if ((unsigned long) now.sec < (unsigned long) update) { + wpa_printf(MSG_DEBUG, + "OCSP: thisUpdate time in the future (response not yet valid)"); + return -1; + } + + /* nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL */ + if (pos < end) { + if (asn1_get_next(pos, end - pos, &hdr) < 0) + return -1; + if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC && hdr.tag == 0) { + const u8 *next = hdr.payload + hdr.length; + + if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_GENERALIZEDTIME || + x509_parse_time(hdr.payload, hdr.length, hdr.tag, + &update) < 0) { + wpa_printf(MSG_DEBUG, + "OCSP: Failed to parse nextUpdate"); + return -1; + } + wpa_printf(MSG_DEBUG, "OCSP: nextUpdate %lu", + (unsigned long) update); + pos = next; + if ((unsigned long) now.sec > (unsigned long) update) { + wpa_printf(MSG_DEBUG, "OCSP: nextUpdate time in the past (response has expired)"); + return -1; + } + } + } + + /* singleExtensions [1] EXPLICIT Extensions OPTIONAL */ + if (pos < end) { + wpa_hexdump(MSG_MSGDUMP, "OCSP: singleExtensions", + pos, end - pos); + /* Ignore for now */ + } + + if (cert_status == 0 /* good */) + *res = TLS_OCSP_GOOD; + else if (cert_status == 1 /* revoked */) + *res = TLS_OCSP_REVOKED; + else + return -1; + return 0; +} + + +static enum tls_ocsp_result +tls_process_ocsp_responses(struct tlsv1_client *conn, + struct x509_certificate *issuer, const u8 *resp, + size_t len) +{ + struct asn1_hdr hdr; + const u8 *pos, *end; + enum tls_ocsp_result res; + + pos = resp; + end = resp + len; + while (pos < end) { + /* SingleResponse ::= SEQUENCE */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, + "OCSP: Expected SEQUENCE (SingleResponse) - found class %d tag 0x%x", + hdr.class, hdr.tag); + return TLS_OCSP_INVALID; + } + if (tls_process_ocsp_single_response(conn, conn->server_cert, + issuer, + hdr.payload, hdr.length, + &res) == 0) + return res; + pos = hdr.payload + hdr.length; + } + + wpa_printf(MSG_DEBUG, + "OCSP: Did not find a response matching the server certificate"); + return TLS_OCSP_NO_RESPONSE; +} + + static enum tls_ocsp_result tls_process_basic_ocsp_response(struct tlsv1_client *conn, const u8 *resp, size_t len) { + struct asn1_hdr hdr; + const u8 *pos, *end; + const u8 *resp_data, *sign_value, *key_hash = NULL, *responses; + const u8 *resp_data_signed; + size_t resp_data_len, sign_value_len, responses_len; + size_t resp_data_signed_len; + struct x509_algorithm_identifier alg; + struct x509_certificate *certs = NULL, *last_cert = NULL; + struct x509_certificate *issuer, *signer; + struct x509_name name; /* used if key_hash == NULL */ + char buf[100]; + os_time_t produced_at; + wpa_hexdump(MSG_MSGDUMP, "OCSP: BasicOCSPResponse", resp, len); + os_memset(&name, 0, sizeof(name)); + /* * RFC 6960, 4.2.1: * BasicOCSPResponse ::= SEQUENCE { @@ -60,8 +379,293 @@ tls_process_basic_ocsp_response(struct tlsv1_client *conn, const u8 *resp, * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } */ - /* TODO */ + if (asn1_get_next(resp, len, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, + "OCSP: Expected SEQUENCE (BasicOCSPResponse) - found class %d tag 0x%x", + hdr.class, hdr.tag); + return TLS_OCSP_INVALID; + } + pos = hdr.payload; + end = hdr.payload + hdr.length; + + /* ResponseData ::= SEQUENCE */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, + "OCSP: Expected SEQUENCE (ResponseData) - found class %d tag 0x%x", + hdr.class, hdr.tag); + return TLS_OCSP_INVALID; + } + resp_data = hdr.payload; + resp_data_len = hdr.length; + resp_data_signed = pos; + pos = hdr.payload + hdr.length; + resp_data_signed_len = pos - resp_data_signed; + + /* signatureAlgorithm AlgorithmIdentifier */ + if (x509_parse_algorithm_identifier(pos, end - pos, &alg, &pos)) + return TLS_OCSP_INVALID; + + /* signature BIT STRING */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_BITSTRING) { + wpa_printf(MSG_DEBUG, + "OCSP: Expected BITSTRING (signature) - found class %d tag 0x%x", + hdr.class, hdr.tag); + return TLS_OCSP_INVALID; + } + if (hdr.length < 1) + return TLS_OCSP_INVALID; + pos = hdr.payload; + if (*pos) { + wpa_printf(MSG_DEBUG, "OCSP: BITSTRING - %d unused bits", *pos); + /* PKCS #1 v1.5 10.2.1: + * It is an error if the length in bits of the signature S is + * not a multiple of eight. + */ + return TLS_OCSP_INVALID; + } + sign_value = pos + 1; + sign_value_len = hdr.length - 1; + pos += hdr.length; + wpa_hexdump(MSG_MSGDUMP, "OCSP: signature", sign_value, sign_value_len); + + /* certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL */ + if (pos < end) { + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || + hdr.tag != 0) { + wpa_printf(MSG_DEBUG, + "OCSP: Expected [0] EXPLICIT (certs) - found class %d tag 0x%x", + hdr.class, hdr.tag); + return TLS_OCSP_INVALID; + } + wpa_hexdump(MSG_MSGDUMP, "OCSP: certs", + hdr.payload, hdr.length); + pos = hdr.payload; + end = hdr.payload + hdr.length; + while (pos < end) { + struct x509_certificate *cert; + + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, + "OCSP: Expected SEQUENCE (Certificate) - found class %d tag 0x%x", + hdr.class, hdr.tag); + goto fail; + } + + cert = x509_certificate_parse(hdr.payload, hdr.length); + if (!cert) + goto fail; + if (last_cert) { + last_cert->next = cert; + last_cert = cert; + } else { + last_cert = certs = cert; + } + pos = hdr.payload + hdr.length; + } + } + + /* + * ResponseData ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1, + * responderID ResponderID, + * producedAt GeneralizedTime, + * responses SEQUENCE OF SingleResponse, + * responseExtensions [1] EXPLICIT Extensions OPTIONAL } + */ + pos = resp_data; + end = resp_data + resp_data_len; + wpa_hexdump(MSG_MSGDUMP, "OCSP: ResponseData", pos, end - pos); + + /* + * version [0] EXPLICIT Version DEFAULT v1 + * Version ::= INTEGER { v1(0) } + */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 && + hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC && + hdr.tag == 0) { + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_INTEGER || + hdr.length != 1) { + wpa_printf(MSG_DEBUG, + "OCSP: No INTEGER (len=1) tag found for version field - found class %d tag 0x%x length %d", + hdr.class, hdr.tag, hdr.length); + goto fail; + } + wpa_printf(MSG_DEBUG, "OCSP: ResponseData version %u", + hdr.payload[0]); + if (hdr.payload[0] != 0) { + wpa_printf(MSG_DEBUG, + "OCSP: Unsupported ResponseData version %u", + hdr.payload[0]); + goto no_resp; + } + pos = hdr.payload + hdr.length; + } else { + wpa_printf(MSG_DEBUG, + "OCSP: Default ResponseData version (v1)"); + } + + /* + * ResponderID ::= CHOICE { + * byName [1] Name, + * byKey [2] KeyHash } + */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) { + wpa_printf(MSG_DEBUG, + "OCSP: Expected CHOICE (ResponderID) - found class %d tag 0x%x", + hdr.class, hdr.tag); + goto fail; + } + + if (hdr.tag == 1) { + /* Name */ + if (x509_parse_name(hdr.payload, hdr.length, &name, &pos) < 0) + goto fail; + x509_name_string(&name, buf, sizeof(buf)); + wpa_printf(MSG_DEBUG, "OCSP: ResponderID byName Name: %s", buf); + } else if (hdr.tag == 2) { + /* KeyHash ::= OCTET STRING */ + if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_OCTETSTRING) { + wpa_printf(MSG_DEBUG, + "OCSP: Expected OCTET STRING (KeyHash) - found class %d tag 0x%x", + hdr.class, hdr.tag); + goto fail; + } + key_hash = hdr.payload; + wpa_hexdump(MSG_DEBUG, "OCSP: ResponderID byKey KeyHash", + key_hash, hdr.length); + if (hdr.length != SHA1_MAC_LEN) { + wpa_printf(MSG_DEBUG, + "OCSP: Unexpected byKey KeyHash length %u - expected %u for SHA-1", + hdr.length, SHA1_MAC_LEN); + goto fail; + } + pos = hdr.payload + hdr.length; + } else { + wpa_printf(MSG_DEBUG, "OCSP: Unexpected ResponderID CHOICE %u", + hdr.tag); + goto fail; + } + + /* producedAt GeneralizedTime */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_GENERALIZEDTIME || + x509_parse_time(hdr.payload, hdr.length, hdr.tag, + &produced_at) < 0) { + wpa_printf(MSG_DEBUG, "OCSP: Failed to parse producedAt"); + goto fail; + } + wpa_printf(MSG_DEBUG, "OCSP: producedAt %lu", + (unsigned long) produced_at); + pos = hdr.payload + hdr.length; + + /* responses SEQUENCE OF SingleResponse */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, + "OCSP: Expected SEQUENCE (responses) - found class %d tag 0x%x", + hdr.class, hdr.tag); + goto fail; + } + responses = hdr.payload; + responses_len = hdr.length; + wpa_hexdump(MSG_MSGDUMP, "OCSP: responses", responses, responses_len); + pos = hdr.payload + hdr.length; + + if (pos < end) { + /* responseExtensions [1] EXPLICIT Extensions OPTIONAL */ + wpa_hexdump(MSG_MSGDUMP, "OCSP: responseExtensions", + pos, end - pos); + /* Ignore for now. */ + } + + if (!conn->server_cert) { + wpa_printf(MSG_DEBUG, + "OCSP: Server certificate not known - cannot check OCSP response"); + goto no_resp; + } + + if (conn->server_cert->next) { + /* Issuer has already been verified in the chain */ + issuer = conn->server_cert->next; + } else { + /* Find issuer from the set of trusted certificates */ + for (issuer = conn->cred ? conn->cred->trusted_certs : NULL; + issuer; issuer = issuer->next) { + if (x509_name_compare(&conn->server_cert->issuer, + &issuer->subject) == 0) + break; + } + } + if (!issuer) { + wpa_printf(MSG_DEBUG, + "OCSP: Server certificate issuer not known - cannot check OCSP response"); + goto no_resp; + } + + if (ocsp_responder_id_match(issuer, &name, key_hash)) { + wpa_printf(MSG_DEBUG, + "OCSP: Server certificate issuer certificate matches ResponderID"); + signer = issuer; + } else { + for (signer = certs; signer; signer = signer->next) { + if (!ocsp_responder_id_match(signer, &name, key_hash) || + x509_name_compare(&conn->server_cert->issuer, + &issuer->subject) != 0 || + !(signer->ext_key_usage & + X509_EXT_KEY_USAGE_OCSP) || + x509_certificate_check_signature(issuer, signer) < + 0) + continue; + wpa_printf(MSG_DEBUG, + "OCSP: An extra certificate from the response matches ResponderID and is trusted as an OCSP signer"); + break; + } + if (!signer) { + wpa_printf(MSG_DEBUG, + "OCSP: Could not find OCSP signer certificate"); + goto no_resp; + } + } + + x509_free_name(&name); + os_memset(&name, 0, sizeof(name)); + x509_certificate_chain_free(certs); + certs = NULL; + + if (x509_check_signature(signer, &alg, sign_value, sign_value_len, + resp_data_signed, resp_data_signed_len) < 0) { + wpa_printf(MSG_DEBUG, "OCSP: Invalid signature"); + return TLS_OCSP_INVALID; + } + + return tls_process_ocsp_responses(conn, issuer, responses, + responses_len); + +no_resp: + x509_free_name(&name); + x509_certificate_chain_free(certs); return TLS_OCSP_NO_RESPONSE; + +fail: + x509_free_name(&name); + x509_certificate_chain_free(certs); + return TLS_OCSP_INVALID; } diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c index b1fa15f4..ff124520 100644 --- a/src/tls/tlsv1_client_read.c +++ b/src/tls/tlsv1_client_read.c @@ -889,11 +889,21 @@ static int tls_process_certificate_status(struct tlsv1_client *conn, u8 ct, goto skip; tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE); + if (conn->server_cert) + tls_cert_chain_failure_event( + conn, 0, conn->server_cert, + TLS_FAIL_UNSPECIFIED, + "bad certificate status response"); return -1; case TLS_OCSP_INVALID: if (!(conn->flags & TLS_CONN_REQUIRE_OCSP)) goto skip; /* ignore - process as if no response */ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); + if (conn->server_cert) + tls_cert_chain_failure_event( + conn, 0, conn->server_cert, + TLS_FAIL_UNSPECIFIED, + "bad certificate status response"); return -1; case TLS_OCSP_GOOD: wpa_printf(MSG_DEBUG, "TLSv1: OCSP response good"); diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c index 75e32855..5521390a 100644 --- a/src/tls/x509v3.c +++ b/src/tls/x509v3.c @@ -1,6 +1,6 @@ /* * X.509v3 certificate parsing and processing (RFC 3280 profile) - * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi> + * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -14,7 +14,7 @@ #include "x509v3.h" -static void x509_free_name(struct x509_name *name) +void x509_free_name(struct x509_name *name) { size_t i; @@ -55,6 +55,7 @@ void x509_certificate_free(struct x509_certificate *cert) x509_free_name(&cert->subject); os_free(cert->public_key); os_free(cert->sign_value); + os_free(cert->subject_dn); os_free(cert); } @@ -177,9 +178,9 @@ int x509_name_compare(struct x509_name *a, struct x509_name *b) } -static int x509_parse_algorithm_identifier( - const u8 *buf, size_t len, - struct x509_algorithm_identifier *id, const u8 **next) +int x509_parse_algorithm_identifier(const u8 *buf, size_t len, + struct x509_algorithm_identifier *id, + const u8 **next) { struct asn1_hdr hdr; const u8 *pos, *end; @@ -288,8 +289,8 @@ static int x509_parse_public_key(const u8 *buf, size_t len, } -static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name, - const u8 **next) +int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name, + const u8 **next) { struct asn1_hdr hdr; const u8 *pos, *end, *set_pos, *set_end, *seq_pos, *seq_end; @@ -536,8 +537,7 @@ done: } -static int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag, - os_time_t *val) +int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag, os_time_t *val) { const char *pos; int year, month, day, hour, min, sec; @@ -1122,6 +1122,15 @@ static int x509_id_kp_client_auth_oid(struct asn1_oid *oid) } +static int x509_id_kp_ocsp_oid(struct asn1_oid *oid) +{ + /* id-kp */ + return oid->len == 9 && + x509_id_kp_oid(oid) && + oid->oid[8] == 9 /* id-kp-OCSPSigning */; +} + + static int x509_parse_ext_ext_key_usage(struct x509_certificate *cert, const u8 *pos, size_t len) { @@ -1164,6 +1173,9 @@ static int x509_parse_ext_ext_key_usage(struct x509_certificate *cert, } else if (x509_id_kp_client_auth_oid(&oid)) { os_strlcpy(buf, "id-kp-clientAuth", sizeof(buf)); cert->ext_key_usage |= X509_EXT_KEY_USAGE_CLIENT_AUTH; + } else if (x509_id_kp_ocsp_oid(&oid)) { + os_strlcpy(buf, "id-kp-OCSPSigning", sizeof(buf)); + cert->ext_key_usage |= X509_EXT_KEY_USAGE_OCSP; } else { asn1_oid_to_str(&oid, buf, sizeof(buf)); } @@ -1390,21 +1402,23 @@ static int x509_parse_tbs_certificate(const u8 *buf, size_t len, /* serialNumber CertificateSerialNumber ::= INTEGER */ if (hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_INTEGER) { + hdr.tag != ASN1_TAG_INTEGER || + hdr.length < 1 || hdr.length > X509_MAX_SERIAL_NUM_LEN) { wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for " - "serialNumber; class=%d tag=0x%x", - hdr.class, hdr.tag); + "serialNumber; class=%d tag=0x%x length=%u", + hdr.class, hdr.tag, hdr.length); return -1; } - pos = hdr.payload; - left = hdr.length; - while (left) { - cert->serial_number <<= 8; - cert->serial_number |= *pos++; - left--; + pos = hdr.payload + hdr.length; + while (hdr.length > 0 && hdr.payload[0] == 0) { + hdr.payload++; + hdr.length--; } - wpa_printf(MSG_MSGDUMP, "X509: serialNumber %lu", cert->serial_number); + os_memcpy(cert->serial_number, hdr.payload, hdr.length); + cert->serial_number_len = hdr.length; + wpa_hexdump(MSG_MSGDUMP, "X509: serialNumber", cert->serial_number, + cert->serial_number_len); /* signature AlgorithmIdentifier */ if (x509_parse_algorithm_identifier(pos, end - pos, &cert->signature, @@ -1422,8 +1436,15 @@ static int x509_parse_tbs_certificate(const u8 *buf, size_t len, return -1; /* subject Name */ + const u8 *subject_dn; + subject_dn = pos; if (x509_parse_name(pos, end - pos, &cert->subject, &pos)) return -1; + cert->subject_dn = os_malloc(pos - subject_dn); + if (!cert->subject_dn) + return -1; + cert->subject_dn_len = pos - subject_dn; + os_memcpy(cert->subject_dn, subject_dn, cert->subject_dn_len); x509_name_string(&cert->subject, sbuf, sizeof(sbuf)); wpa_printf(MSG_MSGDUMP, "X509: subject %s", sbuf); @@ -1540,7 +1561,7 @@ static int x509_digest_oid(struct asn1_oid *oid) } -static int x509_sha1_oid(struct asn1_oid *oid) +int x509_sha1_oid(struct asn1_oid *oid) { return oid->len == 6 && oid->oid[0] == 1 /* iso */ && @@ -1566,21 +1587,21 @@ static int x509_sha2_oid(struct asn1_oid *oid) } -static int x509_sha256_oid(struct asn1_oid *oid) +int x509_sha256_oid(struct asn1_oid *oid) { return x509_sha2_oid(oid) && oid->oid[8] == 1 /* sha256 */; } -static int x509_sha384_oid(struct asn1_oid *oid) +int x509_sha384_oid(struct asn1_oid *oid) { return x509_sha2_oid(oid) && oid->oid[8] == 2 /* sha384 */; } -static int x509_sha512_oid(struct asn1_oid *oid) +int x509_sha512_oid(struct asn1_oid *oid) { return x509_sha2_oid(oid) && oid->oid[8] == 3 /* sha512 */; @@ -1705,6 +1726,17 @@ struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len) int x509_certificate_check_signature(struct x509_certificate *issuer, struct x509_certificate *cert) { + return x509_check_signature(issuer, &cert->signature, + cert->sign_value, cert->sign_value_len, + cert->tbs_cert_start, cert->tbs_cert_len); +} + + +int x509_check_signature(struct x509_certificate *issuer, + struct x509_algorithm_identifier *signature, + const u8 *sign_value, size_t sign_value_len, + const u8 *signed_data, size_t signed_data_len) +{ struct crypto_public_key *pk; u8 *data; const u8 *pos, *end, *next, *da_end; @@ -1713,10 +1745,12 @@ int x509_certificate_check_signature(struct x509_certificate *issuer, struct asn1_oid oid; u8 hash[64]; size_t hash_len; + const u8 *addr[1] = { signed_data }; + size_t len[1] = { signed_data_len }; - if (!x509_pkcs_oid(&cert->signature.oid) || - cert->signature.oid.len != 7 || - cert->signature.oid.oid[5] != 1 /* pkcs-1 */) { + if (!x509_pkcs_oid(&signature->oid) || + signature->oid.len != 7 || + signature->oid.oid[5] != 1 /* pkcs-1 */) { wpa_printf(MSG_DEBUG, "X509: Unrecognized signature " "algorithm"); return -1; @@ -1727,15 +1761,15 @@ int x509_certificate_check_signature(struct x509_certificate *issuer, if (pk == NULL) return -1; - data_len = cert->sign_value_len; + data_len = sign_value_len; data = os_malloc(data_len); if (data == NULL) { crypto_public_key_free(pk); return -1; } - if (crypto_public_key_decrypt_pkcs1(pk, cert->sign_value, - cert->sign_value_len, data, + if (crypto_public_key_decrypt_pkcs1(pk, sign_value, + sign_value_len, data, &data_len) < 0) { wpa_printf(MSG_DEBUG, "X509: Failed to decrypt signature"); crypto_public_key_free(pk); @@ -1798,12 +1832,11 @@ int x509_certificate_check_signature(struct x509_certificate *issuer, } if (x509_sha1_oid(&oid)) { - if (cert->signature.oid.oid[6] != - 5 /* sha-1WithRSAEncryption */) { + if (signature->oid.oid[6] != 5 /* sha-1WithRSAEncryption */) { wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA1 " "does not match with certificate " "signatureAlgorithm (%lu)", - cert->signature.oid.oid[6]); + signature->oid.oid[6]); os_free(data); return -1; } @@ -1811,12 +1844,12 @@ int x509_certificate_check_signature(struct x509_certificate *issuer, } if (x509_sha256_oid(&oid)) { - if (cert->signature.oid.oid[6] != + if (signature->oid.oid[6] != 11 /* sha2561WithRSAEncryption */) { wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA256 " "does not match with certificate " "signatureAlgorithm (%lu)", - cert->signature.oid.oid[6]); + signature->oid.oid[6]); os_free(data); return -1; } @@ -1824,12 +1857,11 @@ int x509_certificate_check_signature(struct x509_certificate *issuer, } if (x509_sha384_oid(&oid)) { - if (cert->signature.oid.oid[6] != - 12 /* sha384WithRSAEncryption */) { + if (signature->oid.oid[6] != 12 /* sha384WithRSAEncryption */) { wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA384 " "does not match with certificate " "signatureAlgorithm (%lu)", - cert->signature.oid.oid[6]); + signature->oid.oid[6]); os_free(data); return -1; } @@ -1837,12 +1869,11 @@ int x509_certificate_check_signature(struct x509_certificate *issuer, } if (x509_sha512_oid(&oid)) { - if (cert->signature.oid.oid[6] != - 13 /* sha512WithRSAEncryption */) { + if (signature->oid.oid[6] != 13 /* sha512WithRSAEncryption */) { wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA512 " "does not match with certificate " "signatureAlgorithm (%lu)", - cert->signature.oid.oid[6]); + signature->oid.oid[6]); os_free(data); return -1; } @@ -1856,12 +1887,11 @@ int x509_certificate_check_signature(struct x509_certificate *issuer, } switch (oid.oid[5]) { case 5: /* md5 */ - if (cert->signature.oid.oid[6] != 4 /* md5WithRSAEncryption */) - { + if (signature->oid.oid[6] != 4 /* md5WithRSAEncryption */) { wpa_printf(MSG_DEBUG, "X509: digestAlgorithm MD5 does " "not match with certificate " "signatureAlgorithm (%lu)", - cert->signature.oid.oid[6]); + signature->oid.oid[6]); os_free(data); return -1; } @@ -1892,38 +1922,33 @@ skip_digest_oid: wpa_hexdump(MSG_MSGDUMP, "X509: Decrypted Digest", hdr.payload, hdr.length); - switch (cert->signature.oid.oid[6]) { + switch (signature->oid.oid[6]) { case 4: /* md5WithRSAEncryption */ - md5_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, - hash); + md5_vector(1, addr, len, hash); hash_len = 16; wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (MD5)", hash, hash_len); break; case 5: /* sha-1WithRSAEncryption */ - sha1_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, - hash); + sha1_vector(1, addr, len, hash); hash_len = 20; wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA1)", hash, hash_len); break; case 11: /* sha256WithRSAEncryption */ - sha256_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, - hash); + sha256_vector(1, addr, len, hash); hash_len = 32; wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA256)", hash, hash_len); break; case 12: /* sha384WithRSAEncryption */ - sha384_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, - hash); + sha384_vector(1, addr, len, hash); hash_len = 48; wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA384)", hash, hash_len); break; case 13: /* sha512WithRSAEncryption */ - sha512_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, - hash); + sha512_vector(1, addr, len, hash); hash_len = 64; wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA512)", hash, hash_len); @@ -1931,7 +1956,7 @@ skip_digest_oid: case 2: /* md2WithRSAEncryption */ default: wpa_printf(MSG_INFO, "X509: Unsupported certificate signature " - "algorithm (%lu)", cert->signature.oid.oid[6]); + "algorithm (%lu)", signature->oid.oid[6]); os_free(data); return -1; } diff --git a/src/tls/x509v3.h b/src/tls/x509v3.h index 12ef86ee..dcdb4a30 100644 --- a/src/tls/x509v3.h +++ b/src/tls/x509v3.h @@ -45,13 +45,18 @@ struct x509_name { struct asn1_oid rid; /* registeredID */ }; +#define X509_MAX_SERIAL_NUM_LEN 20 + struct x509_certificate { struct x509_certificate *next; enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version; - unsigned long serial_number; + u8 serial_number[X509_MAX_SERIAL_NUM_LEN]; + size_t serial_number_len; struct x509_algorithm_identifier signature; struct x509_name issuer; struct x509_name subject; + u8 *subject_dn; + size_t subject_dn_len; os_time_t not_before; os_time_t not_after; struct x509_algorithm_identifier public_key_alg; @@ -91,6 +96,7 @@ struct x509_certificate { #define X509_EXT_KEY_USAGE_ANY (1 << 0) #define X509_EXT_KEY_USAGE_SERVER_AUTH (1 << 1) #define X509_EXT_KEY_USAGE_CLIENT_AUTH (1 << 2) +#define X509_EXT_KEY_USAGE_OCSP (1 << 3) /* * The DER format certificate follows struct x509_certificate. These @@ -113,10 +119,21 @@ enum { }; void x509_certificate_free(struct x509_certificate *cert); +int x509_parse_algorithm_identifier(const u8 *buf, size_t len, + struct x509_algorithm_identifier *id, + const u8 **next); +int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name, + const u8 **next); +int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag, os_time_t *val); struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len); +void x509_free_name(struct x509_name *name); void x509_name_string(struct x509_name *name, char *buf, size_t len); int x509_name_compare(struct x509_name *a, struct x509_name *b); void x509_certificate_chain_free(struct x509_certificate *cert); +int x509_check_signature(struct x509_certificate *issuer, + struct x509_algorithm_identifier *signature, + const u8 *sign_value, size_t sign_value_len, + const u8 *signed_data, size_t signed_data_len); int x509_certificate_check_signature(struct x509_certificate *issuer, struct x509_certificate *cert); int x509_certificate_chain_validate(struct x509_certificate *trusted, @@ -127,4 +144,9 @@ x509_certificate_get_subject(struct x509_certificate *chain, struct x509_name *name); int x509_certificate_self_signed(struct x509_certificate *cert); +int x509_sha1_oid(struct asn1_oid *oid); +int x509_sha256_oid(struct asn1_oid *oid); +int x509_sha384_oid(struct asn1_oid *oid); +int x509_sha512_oid(struct asn1_oid *oid); + #endif /* X509V3_H */ diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c index 3275524f..f7acf6b9 100644 --- a/src/utils/wpa_debug.c +++ b/src/utils/wpa_debug.c @@ -148,7 +148,7 @@ int wpa_debug_open_linux_tracing(void) strtok_r(line, " ", &tmp2); tmp_path = strtok_r(NULL, " ", &tmp2); fstype = strtok_r(NULL, " ", &tmp2); - if (strcmp(fstype, "debugfs") == 0) { + if (fstype && strcmp(fstype, "debugfs") == 0) { path = tmp_path; break; } diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index a3b587fe..d1274f6d 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -6450,7 +6450,7 @@ static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst) if (subtypes == 0) return -1; - return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0); + return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0, 0); } @@ -6473,7 +6473,7 @@ static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s, ret = hs20_anqp_send_req(wpa_s, addr, BIT(HS20_STYPE_NAI_HOME_REALM_QUERY), - buf, len); + buf, len, 0); os_free(buf); @@ -6519,14 +6519,59 @@ static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s, ret = hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_NAI_HOME_REALM_QUERY), - buf, len); + buf, len, 0); os_free(buf); return ret; } -static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd) +static int get_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd, char *reply, + int buflen) +{ + u8 dst_addr[ETH_ALEN]; + int used; + char *ctx = NULL, *icon, *poffset, *psize; + + used = hwaddr_aton2(cmd, dst_addr); + if (used < 0) + return -1; + cmd += used; + + icon = str_token(cmd, " ", &ctx); + poffset = str_token(cmd, " ", &ctx); + psize = str_token(cmd, " ", &ctx); + if (!icon || !poffset || !psize) + return -1; + + wpa_s->fetch_osu_icon_in_progress = 0; + return hs20_get_icon(wpa_s, dst_addr, icon, atoi(poffset), atoi(psize), + reply, buflen); +} + + +static int del_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd) +{ + u8 dst_addr[ETH_ALEN]; + int used; + char *icon; + + if (!cmd[0]) + return hs20_del_icon(wpa_s, NULL, NULL); + + used = hwaddr_aton2(cmd, dst_addr); + if (used < 0) + return -1; + + while (cmd[used] == ' ') + used++; + icon = cmd[used] ? &cmd[used] : NULL; + + return hs20_del_icon(wpa_s, dst_addr, icon); +} + + +static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd, int inmem) { u8 dst_addr[ETH_ALEN]; int used; @@ -6542,7 +6587,7 @@ static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd) wpa_s->fetch_osu_icon_in_progress = 0; return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST), - (u8 *) icon, os_strlen(icon)); + (u8 *) icon, os_strlen(icon), inmem); } #endif /* CONFIG_HS20 */ @@ -6704,6 +6749,28 @@ static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf, } +static int wpas_ctrl_iface_signal_monitor(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + const char *pos; + int threshold = 0; + int hysteresis = 0; + + if (wpa_s->bgscan && wpa_s->bgscan_priv) { + wpa_printf(MSG_DEBUG, + "Reject SIGNAL_MONITOR command - bgscan is active"); + return -1; + } + pos = os_strstr(cmd, "THRESHOLD="); + if (pos) + threshold = atoi(pos + 10); + pos = os_strstr(cmd, "HYSTERESIS="); + if (pos) + hysteresis = atoi(pos + 11); + return wpa_drv_signal_monitor(wpa_s, threshold, hysteresis); +} + + static int wpas_ctrl_iface_get_pref_freq_list( struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { @@ -6943,6 +7010,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) #ifdef CONFIG_INTERWORKING #ifdef CONFIG_HS20 hs20_cancel_fetch_osu(wpa_s); + hs20_del_icon(wpa_s, NULL, NULL); #endif /* CONFIG_HS20 */ #endif /* CONFIG_INTERWORKING */ @@ -8566,7 +8634,15 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0) reply_len = -1; } else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) { - if (hs20_icon_request(wpa_s, buf + 18) < 0) + if (hs20_icon_request(wpa_s, buf + 18, 0) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "REQ_HS20_ICON ", 14) == 0) { + if (hs20_icon_request(wpa_s, buf + 14, 1) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "GET_HS20_ICON ", 14) == 0) { + reply_len = get_hs20_icon(wpa_s, buf + 14, reply, reply_size); + } else if (os_strncmp(buf, "DEL_HS20_ICON ", 14) == 0) { + if (del_hs20_icon(wpa_s, buf + 14) < 0) reply_len = -1; } else if (os_strcmp(buf, "FETCH_OSU") == 0) { if (hs20_fetch_osu(wpa_s) < 0) @@ -8769,6 +8845,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) { reply_len = wpa_supplicant_signal_poll(wpa_s, reply, reply_size); + } else if (os_strncmp(buf, "SIGNAL_MONITOR", 14) == 0) { + if (wpas_ctrl_iface_signal_monitor(wpa_s, buf + 14)) + reply_len = -1; } else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) { reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply, reply_size); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 2675bed1..1ac177e8 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1518,6 +1518,10 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, wpas_wps_update_ap_info(wpa_s, scan_res); + if (wpa_s->wpa_state >= WPA_AUTHENTICATING && + wpa_s->wpa_state < WPA_COMPLETED) + goto scan_work_done; + wpa_scan_results_free(scan_res); if (own_request && wpa_s->scan_work) { @@ -1570,6 +1574,13 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, return 0; } + if (ssid != wpa_s->current_ssid && + wpa_s->wpa_state >= WPA_AUTHENTICATING) { + wpa_s->own_disconnect_req = 1; + wpa_supplicant_deauthenticate( + wpa_s, WLAN_REASON_DEAUTH_LEAVING); + } + if (wpa_supplicant_connect(wpa_s, selected, ssid) < 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed"); return -1; diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c index 10ecce7b..457f5fb6 100644 --- a/wpa_supplicant/gas_query.c +++ b/wpa_supplicant/gas_query.c @@ -25,6 +25,9 @@ /** GAS query timeout in seconds */ #define GAS_QUERY_TIMEOUT_PERIOD 2 +/* GAS query wait-time / duration in ms */ +#define GAS_QUERY_WAIT_TIME_INITIAL 1000 +#define GAS_QUERY_WAIT_TIME_COMEBACK 150 /** * struct gas_query_pending - Pending GAS query @@ -37,6 +40,7 @@ struct gas_query_pending { u8 next_frag_id; unsigned int wait_comeback:1; unsigned int offchannel_tx_started:1; + unsigned int retry:1; int freq; u16 status_code; struct wpabuf *req; @@ -63,6 +67,10 @@ struct gas_query { static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx); static void gas_query_timeout(void *eloop_data, void *user_ctx); +static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx); +static void gas_query_tx_initial_req(struct gas_query *gas, + struct gas_query_pending *query); +static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst); static int ms_from_time(struct os_reltime *last) @@ -151,6 +159,7 @@ static void gas_query_done(struct gas_query *gas, offchannel_send_action_done(gas->wpa_s); eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query); eloop_cancel_timeout(gas_query_timeout, gas, query); + eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query); dl_list_del(&query->list); query->cb(query->ctx, query->addr, query->dialog_token, result, query->adv_proto, query->resp, query->status_code); @@ -235,6 +244,13 @@ static void gas_query_tx_status(struct wpa_supplicant *wpa_s, eloop_cancel_timeout(gas_query_timeout, gas, query); eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout, gas, query); + if (query->wait_comeback && !query->retry) { + eloop_cancel_timeout(gas_query_rx_comeback_timeout, + gas, query); + eloop_register_timeout( + 0, (GAS_QUERY_WAIT_TIME_COMEBACK + 10) * 1000, + gas_query_rx_comeback_timeout, gas, query); + } } if (result == OFFCHANNEL_SEND_ACTION_FAILED) { eloop_cancel_timeout(gas_query_timeout, gas, query); @@ -254,9 +270,8 @@ static int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr) static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query, - struct wpabuf *req) + struct wpabuf *req, unsigned int wait_time) { - unsigned int wait_time; int res, prot = pmf_in_use(gas->wpa_s, query->addr); wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u " @@ -267,7 +282,6 @@ static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query, *categ = WLAN_ACTION_PROTECTED_DUAL; } os_get_reltime(&query->last_oper); - wait_time = 1000; if (gas->wpa_s->max_remain_on_chan && wait_time > gas->wpa_s->max_remain_on_chan) wait_time = gas->wpa_s->max_remain_on_chan; @@ -285,6 +299,7 @@ static void gas_query_tx_comeback_req(struct gas_query *gas, struct gas_query_pending *query) { struct wpabuf *req; + unsigned int wait_time; req = gas_build_comeback_req(query->dialog_token); if (req == NULL) { @@ -292,7 +307,10 @@ static void gas_query_tx_comeback_req(struct gas_query *gas, return; } - if (gas_query_tx(gas, query, req) < 0) { + wait_time = (query->retry || !query->offchannel_tx_started) ? + GAS_QUERY_WAIT_TIME_INITIAL : GAS_QUERY_WAIT_TIME_COMEBACK; + + if (gas_query_tx(gas, query, req, wait_time) < 0) { wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to " MACSTR, MAC2STR(query->addr)); gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); @@ -302,6 +320,35 @@ static void gas_query_tx_comeback_req(struct gas_query *gas, } +static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx) +{ + struct gas_query *gas = eloop_data; + struct gas_query_pending *query = user_ctx; + int dialog_token; + + wpa_printf(MSG_DEBUG, + "GAS: No response to comeback request received (retry=%u)", + query->retry); + if (gas->current != query || query->retry) + return; + dialog_token = gas_query_new_dialog_token(gas, query->addr); + if (dialog_token < 0) + return; + wpa_printf(MSG_DEBUG, + "GAS: Retry GAS query due to comeback response timeout"); + query->retry = 1; + query->dialog_token = dialog_token; + *(wpabuf_mhead_u8(query->req) + 2) = dialog_token; + query->wait_comeback = 0; + query->next_frag_id = 0; + wpabuf_free(query->adv_proto); + query->adv_proto = NULL; + eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query); + eloop_cancel_timeout(gas_query_timeout, gas, query); + gas_query_tx_initial_req(gas, query); +} + + static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx) { struct gas_query *gas = eloop_data; @@ -319,6 +366,11 @@ static void gas_query_tx_comeback_req_delay(struct gas_query *gas, { unsigned int secs, usecs; + if (comeback_delay > 1 && query->offchannel_tx_started) { + offchannel_send_action_done(gas->wpa_s); + query->offchannel_tx_started = 0; + } + secs = (comeback_delay * 1024) / 1000000; usecs = comeback_delay * 1024 - secs * 1000000; wpa_printf(MSG_DEBUG, "GAS: Send comeback request to " MACSTR @@ -371,6 +423,7 @@ static void gas_query_rx_comeback(struct gas_query *gas, "comeback_delay=%u)", MAC2STR(query->addr), query->dialog_token, frag_id, more_frags, comeback_delay); + eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query); if ((size_t) 2 + adv_proto[1] != wpabuf_len(query->adv_proto) || os_memcmp(adv_proto, wpabuf_head(query->adv_proto), @@ -620,8 +673,15 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit) } gas->work = work; + gas_query_tx_initial_req(gas, query); +} + - if (gas_query_tx(gas, query, query->req) < 0) { +static void gas_query_tx_initial_req(struct gas_query *gas, + struct gas_query_pending *query) +{ + if (gas_query_tx(gas, query, query->req, + GAS_QUERY_WAIT_TIME_INITIAL) < 0) { wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to " MACSTR, MAC2STR(query->addr)); gas_query_free(query, 1); @@ -633,7 +693,24 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit) query->dialog_token); eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout, gas, query); +} + +static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst) +{ + static int next_start = 0; + int dialog_token; + + for (dialog_token = 0; dialog_token < 256; dialog_token++) { + if (gas_query_dialog_token_available( + gas, dst, (next_start + dialog_token) % 256)) + break; + } + if (dialog_token == 256) + return -1; /* Too many pending queries */ + dialog_token = (next_start + dialog_token) % 256; + next_start = (dialog_token + 1) % 256; + return dialog_token; } @@ -658,20 +735,13 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, { struct gas_query_pending *query; int dialog_token; - static int next_start = 0; if (wpabuf_len(req) < 3) return -1; - for (dialog_token = 0; dialog_token < 256; dialog_token++) { - if (gas_query_dialog_token_available( - gas, dst, (next_start + dialog_token) % 256)) - break; - } - if (dialog_token == 256) - return -1; /* Too many pending queries */ - dialog_token = (next_start + dialog_token) % 256; - next_start = (dialog_token + 1) % 256; + dialog_token = gas_query_new_dialog_token(gas, dst); + if (dialog_token < 0) + return -1; query = os_zalloc(sizeof(*query)); if (query == NULL) diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c index e6c564b3..57b99436 100644 --- a/wpa_supplicant/hs20_supplicant.c +++ b/wpa_supplicant/hs20_supplicant.c @@ -25,6 +25,7 @@ #include "gas_query.h" #include "interworking.h" #include "hs20_supplicant.h" +#include "base64.h" #define OSU_MAX_ITEMS 10 @@ -180,13 +181,14 @@ struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload, int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes, - const u8 *payload, size_t payload_len) + const u8 *payload, size_t payload_len, int inmem) { struct wpabuf *buf; int ret = 0; int freq; struct wpa_bss *bss; int res; + struct icon_entry *icon_entry; bss = wpa_bss_get_bssid(wpa_s, dst); if (!bss) { @@ -210,15 +212,127 @@ int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes, if (res < 0) { wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request"); wpabuf_free(buf); - ret = -1; + return -1; } else wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token " "%u", res); + if (inmem) { + icon_entry = os_zalloc(sizeof(struct icon_entry)); + if (!icon_entry) + return -1; + os_memcpy(icon_entry->bssid, dst, ETH_ALEN); + icon_entry->file_name = os_malloc(payload_len + 1); + if (!icon_entry->file_name) { + os_free(icon_entry); + return -1; + } + os_memcpy(icon_entry->file_name, payload, payload_len); + icon_entry->file_name[payload_len] = '\0'; + icon_entry->dialog_token = res; + + dl_list_add(&wpa_s->icon_head, &icon_entry->list); + } + return ret; } +static struct icon_entry * hs20_find_icon(struct wpa_supplicant *wpa_s, + const u8 *bssid, + const char *file_name) +{ + struct icon_entry *icon; + + dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) { + if (os_memcmp(icon->bssid, bssid, ETH_ALEN) == 0 && + os_strcmp(icon->file_name, file_name) == 0 && icon->image) + return icon; + } + + return NULL; +} + + +int hs20_get_icon(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *file_name, size_t offset, size_t size, + char *reply, size_t buf_len) +{ + struct icon_entry *icon; + size_t out_size; + unsigned char *b64; + size_t b64_size; + int reply_size; + + wpa_printf(MSG_DEBUG, "HS20: Get icon " MACSTR " %s @ %u +%u (%u)", + MAC2STR(bssid), file_name, (unsigned int) offset, + (unsigned int) size, (unsigned int) buf_len); + + icon = hs20_find_icon(wpa_s, bssid, file_name); + if (!icon || !icon->image || offset >= icon->image_len) + return -1; + if (size > icon->image_len - offset) + size = icon->image_len - offset; + out_size = buf_len - 3 /* max base64 padding */; + if (size * 4 > out_size * 3) + size = out_size * 3 / 4; + if (size == 0) + return -1; + + b64 = base64_encode(&icon->image[offset], size, &b64_size); + if (buf_len >= b64_size) { + os_memcpy(reply, b64, b64_size); + reply_size = b64_size; + } else { + reply_size = -1; + } + os_free(b64); + return reply_size; +} + + +static void hs20_free_icon_entry(struct icon_entry *icon) +{ + wpa_printf(MSG_DEBUG, "HS20: Free stored icon from " MACSTR + " dialog_token=%u file_name=%s image_len=%u", + MAC2STR(icon->bssid), icon->dialog_token, + icon->file_name ? icon->file_name : "N/A", + (unsigned int) icon->image_len); + os_free(icon->file_name); + os_free(icon->image); + os_free(icon); +} + + +int hs20_del_icon(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *file_name) +{ + struct icon_entry *icon, *tmp; + int count = 0; + + if (!bssid) + wpa_printf(MSG_DEBUG, "HS20: Delete all stored icons"); + else if (!file_name) + wpa_printf(MSG_DEBUG, "HS20: Delete all stored icons for " + MACSTR, MAC2STR(bssid)); + else + wpa_printf(MSG_DEBUG, "HS20: Delete stored icons for " + MACSTR " file name %s", MAC2STR(bssid), file_name); + + dl_list_for_each_safe(icon, tmp, &wpa_s->icon_head, struct icon_entry, + list) { + if ((!bssid || os_memcmp(icon->bssid, bssid, ETH_ALEN) == 0) && + (!file_name || + os_strcmp(icon->file_name, file_name) == 0)) { + dl_list_del(&icon->list); + hs20_free_icon_entry(icon); + count++; + } + } + return count == 0 ? -1 : 0; +} + + static void hs20_set_osu_access_permission(const char *osu_dir, const char *fname) { @@ -243,14 +357,51 @@ static void hs20_set_osu_access_permission(const char *osu_dir, } } + +static void hs20_remove_duplicate_icons(struct wpa_supplicant *wpa_s, + struct icon_entry *new_icon) +{ + struct icon_entry *icon, *tmp; + + dl_list_for_each_safe(icon, tmp, &wpa_s->icon_head, struct icon_entry, + list) { + if (icon == new_icon) + continue; + if (os_memcmp(icon->bssid, new_icon->bssid, ETH_ALEN) == 0 && + os_strcmp(icon->file_name, new_icon->file_name) == 0) { + dl_list_del(&icon->list); + hs20_free_icon_entry(icon); + } + } +} + + static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *pos, - size_t slen) + size_t slen, u8 dialog_token) { char fname[256]; int png; FILE *f; u16 data_len; + struct icon_entry *icon; + + dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) { + if (icon->dialog_token == dialog_token && !icon->image && + os_memcmp(icon->bssid, sa, ETH_ALEN) == 0) { + icon->image = os_malloc(slen); + if (!icon->image) + return -1; + os_memcpy(icon->image, pos, slen); + icon->image_len = slen; + hs20_remove_duplicate_icons(wpa_s, icon); + wpa_msg(wpa_s, MSG_INFO, + "RX-HS20-ICON " MACSTR " %s %u", + MAC2STR(sa), icon->file_name, + (unsigned int) icon->image_len); + return 0; + } + } wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " Icon Binary File", MAC2STR(sa)); @@ -358,7 +509,7 @@ static void hs20_osu_icon_fetch_result(struct wpa_supplicant *wpa_s, int res) void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, const u8 *sa, - const u8 *data, size_t slen) + const u8 *data, size_t slen, u8 dialog_token) { const u8 *pos = data; u8 subtype; @@ -445,7 +596,8 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, } break; case HS20_STYPE_ICON_BINARY_FILE: - ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen); + ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen, + dialog_token); if (wpa_s->fetch_osu_icon_in_progress) { hs20_osu_icon_fetch_result(wpa_s, ret); eloop_cancel_timeout(hs20_continue_icon_fetch, @@ -579,7 +731,8 @@ void hs20_next_osu_icon(struct wpa_supplicant *wpa_s) if (hs20_anqp_send_req(wpa_s, osu->bssid, BIT(HS20_STYPE_ICON_REQUEST), (u8 *) icon->filename, - os_strlen(icon->filename)) < 0) { + os_strlen(icon->filename), + 0) < 0) { icon->failed = 1; continue; } @@ -1002,8 +1155,16 @@ void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code, } +void hs20_init(struct wpa_supplicant *wpa_s) +{ + dl_list_init(&wpa_s->icon_head); +} + + void hs20_deinit(struct wpa_supplicant *wpa_s) { eloop_cancel_timeout(hs20_continue_icon_fetch, wpa_s, NULL); hs20_free_osu_prov(wpa_s); + if (wpa_s->icon_head.next) + hs20_del_icon(wpa_s, NULL, NULL); } diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h index 85b51201..9fc654c9 100644 --- a/wpa_supplicant/hs20_supplicant.h +++ b/wpa_supplicant/hs20_supplicant.h @@ -11,14 +11,14 @@ void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id); int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes, - const u8 *payload, size_t payload_len); + const u8 *payload, size_t payload_len, int inmem); struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload, size_t payload_len); void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len, struct wpabuf *buf); void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, const u8 *sa, - const u8 *data, size_t slen); + const u8 *data, size_t slen, u8 dialog_token); int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_bss *bss); int hs20_get_pps_mo_id(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); @@ -36,6 +36,12 @@ int hs20_fetch_osu(struct wpa_supplicant *wpa_s); void hs20_cancel_fetch_osu(struct wpa_supplicant *wpa_s); void hs20_icon_fetch_failed(struct wpa_supplicant *wpa_s); void hs20_start_osu_scan(struct wpa_supplicant *wpa_s); +void hs20_init(struct wpa_supplicant *wpa_s); void hs20_deinit(struct wpa_supplicant *wpa_s); +int hs20_get_icon(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *file_name, size_t offset, size_t size, + char *reply, size_t buf_len); +int hs20_del_icon(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *file_name); #endif /* HS20_SUPPLICANT_H */ diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index 6a54d1ee..9df1607e 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -2775,7 +2775,8 @@ static void anqp_add_extra(struct wpa_supplicant *wpa_s, static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, const u8 *sa, u16 info_id, - const u8 *data, size_t slen) + const u8 *data, size_t slen, + u8 dialog_token) { const u8 *pos = data; struct wpa_bss_anqp *anqp = NULL; @@ -2885,7 +2886,8 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, switch (type) { case HS20_ANQP_OUI_TYPE: hs20_parse_rx_hs20_anqp_resp(wpa_s, bss, sa, - pos, slen); + pos, slen, + dialog_token); break; default: wpa_msg(wpa_s, MSG_DEBUG, @@ -2988,7 +2990,7 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, goto out_parse_done; } interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos, - slen); + slen, dialog_token); pos += slen; } diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c index 8f74b5d6..7925aa91 100644 --- a/wpa_supplicant/mesh.c +++ b/wpa_supplicant/mesh.c @@ -193,6 +193,29 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s, ssid->frequency); goto out_free; } + if (ssid->ht40) + conf->secondary_channel = ssid->ht40; + if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A && ssid->vht) { + conf->vht_oper_chwidth = ssid->max_oper_chwidth; + switch (conf->vht_oper_chwidth) { + case VHT_CHANWIDTH_80MHZ: + case VHT_CHANWIDTH_80P80MHZ: + ieee80211_freq_to_chan( + ssid->frequency, + &conf->vht_oper_centr_freq_seg0_idx); + conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2; + break; + case VHT_CHANWIDTH_160MHZ: + ieee80211_freq_to_chan( + ssid->frequency, + &conf->vht_oper_centr_freq_seg0_idx); + conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2; + conf->vht_oper_centr_freq_seg0_idx += 40 / 5; + break; + } + ieee80211_freq_to_chan(ssid->vht_center_freq2, + &conf->vht_oper_centr_freq_seg1_idx); + } if (ssid->mesh_basic_rates == NULL) { /* @@ -334,6 +357,28 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s, ibss_mesh_setup_freq(wpa_s, ssid, ¶ms.freq); wpa_s->mesh_ht_enabled = !!params.freq.ht_enabled; wpa_s->mesh_vht_enabled = !!params.freq.vht_enabled; + if (params.freq.ht_enabled && params.freq.sec_channel_offset) + ssid->ht40 = params.freq.sec_channel_offset; + if (wpa_s->mesh_vht_enabled) { + ssid->vht = 1; + switch (params.freq.bandwidth) { + case 80: + if (params.freq.center_freq2) { + ssid->max_oper_chwidth = VHT_CHANWIDTH_80P80MHZ; + ssid->vht_center_freq2 = + params.freq.center_freq2; + } else { + ssid->max_oper_chwidth = VHT_CHANWIDTH_80MHZ; + } + break; + case 160: + ssid->max_oper_chwidth = VHT_CHANWIDTH_160MHZ; + break; + default: + ssid->max_oper_chwidth = VHT_CHANWIDTH_USE_HT; + break; + } + } if (ssid->beacon_int > 0) params.beacon_int = ssid->beacon_int; else if (wpa_s->conf->beacon_int > 0) diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index c7ddc996..45dae509 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -6770,11 +6770,12 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, pref_freq_list, &size); if (res) return res; - p2p_set_own_pref_freq_list(wpa_s->global->p2p, pref_freq_list, size); if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; + p2p_set_own_pref_freq_list(wpa_s->global->p2p, pref_freq_list, size); + if (wpa_s->parent->conf->p2p_ignore_shared_freq && no_pref_freq_given && pref_freq > 0 && wpa_s->num_multichan_concurrent > 1 && diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 275bf392..aedd61aa 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -1927,6 +1927,12 @@ static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd, printf("Not connected to hostapd - command dropped.\n"); return -1; } + if (ifname_prefix) { + os_snprintf(buf, sizeof(buf), "IFNAME=%s %s", + ifname_prefix, cmd); + buf[sizeof(buf) - 1] = '\0'; + cmd = buf; + } len = sizeof(buf) - 1; ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, wpa_cli_msg_cb); @@ -2754,6 +2760,13 @@ static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc, } +static int wpa_cli_cmd_signal_monitor(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "SIGNAL_MONITOR", 0, argc, argv); +} + + static int wpa_cli_cmd_pktcnt_poll(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -3388,6 +3401,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "signal_poll", wpa_cli_cmd_signal_poll, NULL, cli_cmd_flag_none, "= get signal parameters" }, + { "signal_monitor", wpa_cli_cmd_signal_monitor, NULL, + cli_cmd_flag_none, + "= set signal monitor parameters" }, { "pktcnt_poll", wpa_cli_cmd_pktcnt_poll, NULL, cli_cmd_flag_none, "= get TX/RX packet counters" }, diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 6e2d1807..29683bc4 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1602,6 +1602,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, wpa_s->own_disconnect_req = 0; + /* + * If we are starting a new connection, any previously pending EAPOL + * RX cannot be valid anymore. + */ + wpabuf_free(wpa_s->pending_eapol_rx); + wpa_s->pending_eapol_rx = NULL; + if (ssid->mac_addr == -1) rand_style = wpa_s->conf->mac_addr; else @@ -4750,6 +4757,10 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans); +#ifdef CONFIG_HS20 + hs20_init(wpa_s); +#endif /* CONFIG_HS20 */ + return 0; } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 05a1bc66..7b74f383 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -425,6 +425,15 @@ enum wpa_supplicant_test_failure { WPAS_TEST_FAILURE_SCAN_TRIGGER, }; +struct icon_entry { + struct dl_list list; + u8 bssid[ETH_ALEN]; + u8 dialog_token; + char *file_name; + u8 *image; + size_t image_len; +}; + /** * struct wpa_supplicant - Internal data for wpa_supplicant interface * @@ -905,6 +914,7 @@ struct wpa_supplicant { unsigned int fetch_osu_icon_in_progress:1; struct wpa_bss *interworking_gas_bss; unsigned int osu_icon_id; + struct dl_list icon_head; /* struct icon_entry */ struct osu_provider *osu_prov; size_t osu_prov_count; struct os_reltime osu_icon_fetch_start; |