WPS NFC: Add AP mode connection handover report
authorJouni Malinen <jouni@qca.qualcomm.com>
Tue, 2 Apr 2013 15:30:58 +0000 (18:30 +0300)
committerJouni Malinen <j@w1.fi>
Mon, 27 Jan 2014 19:10:55 +0000 (21:10 +0200)
The new NFC connection handover design requires the AP/Registrar to
process the connection handover request message received from the
Enrollee. Add control interface commands for handling this.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>

hostapd/ctrl_iface.c
src/ap/wps_hostapd.c
src/ap/wps_hostapd.h

index 72faeae..e5c3022 100644 (file)
@@ -399,13 +399,70 @@ static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd,
 static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd,
                                                  char *cmd)
 {
-       /*
-        * Since NFC connection handover provided full WPS Credential, there is
-        * no need for additional operations within hostapd. Just report this in
-        * debug log.
-        */
-       wpa_printf(MSG_DEBUG, "NFC: Connection handover reported: %s", cmd);
-       return 0;
+       size_t len;
+       struct wpabuf *req, *sel;
+       int ret;
+       char *pos, *role, *type, *pos2;
+
+       role = cmd;
+       pos = os_strchr(role, ' ');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+
+       type = pos;
+       pos = os_strchr(type, ' ');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+
+       pos2 = os_strchr(pos, ' ');
+       if (pos2 == NULL)
+               return -1;
+       *pos2++ = '\0';
+
+       len = os_strlen(pos);
+       if (len & 0x01)
+               return -1;
+       len /= 2;
+
+       req = wpabuf_alloc(len);
+       if (req == NULL)
+               return -1;
+       if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
+               wpabuf_free(req);
+               return -1;
+       }
+
+       len = os_strlen(pos2);
+       if (len & 0x01) {
+               wpabuf_free(req);
+               return -1;
+       }
+       len /= 2;
+
+       sel = wpabuf_alloc(len);
+       if (sel == NULL) {
+               wpabuf_free(req);
+               return -1;
+       }
+       if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
+               wpabuf_free(req);
+               wpabuf_free(sel);
+               return -1;
+       }
+
+       if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0) {
+               ret = hostapd_wps_nfc_report_handover(hapd, req, sel);
+       } else {
+               wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
+                          "reported: role=%s type=%s", role, type);
+               ret = -1;
+       }
+       wpabuf_free(req);
+       wpabuf_free(sel);
+
+       return ret;
 }
 
 #endif /* CONFIG_WPS_NFC */
@@ -1101,7 +1158,7 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
                                       void *sock_ctx)
 {
        struct hostapd_data *hapd = eloop_ctx;
-       char buf[256];
+       char buf[4096];
        int res;
        struct sockaddr_un from;
        socklen_t fromlen = sizeof(from);
index 4c94210..713218c 100644 (file)
@@ -1808,6 +1808,100 @@ struct wpabuf * hostapd_wps_nfc_hs_cr(struct hostapd_data *hapd, int ndef)
 }
 
 
+int hostapd_wps_nfc_report_handover(struct hostapd_data *hapd,
+                                   const struct wpabuf *req,
+                                   const struct wpabuf *sel)
+{
+       struct wpabuf *wps;
+       int ret = -1;
+       u16 wsc_len;
+       const u8 *pos;
+       struct wpabuf msg;
+       struct wps_parse_attr attr;
+       u16 dev_pw_id;
+
+       /*
+        * Enrollee/station is always initiator of the NFC connection handover,
+        * so use the request message here to find Enrollee public key hash.
+        */
+       wps = ndef_parse_wifi(req);
+       if (wps == NULL)
+               return -1;
+       wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
+                  "payload from NFC connection handover");
+       wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps);
+       if (wpabuf_len(wps) < 2) {
+               wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Request "
+                          "Message");
+               goto out;
+       }
+       pos = wpabuf_head(wps);
+       wsc_len = WPA_GET_BE16(pos);
+       if (wsc_len > wpabuf_len(wps) - 2) {
+               wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) "
+                          "in rt Wi-Fi Handover Request Message", wsc_len);
+               goto out;
+       }
+       pos += 2;
+
+       wpa_hexdump(MSG_DEBUG,
+                   "WPS: WSC attributes in Wi-Fi Handover Request Message",
+                   pos, wsc_len);
+       if (wsc_len < wpabuf_len(wps) - 2) {
+               wpa_hexdump(MSG_DEBUG,
+                           "WPS: Ignore extra data after WSC attributes",
+                           pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len);
+       }
+
+       wpabuf_set(&msg, pos, wsc_len);
+       ret = wps_parse_msg(&msg, &attr);
+       if (ret < 0) {
+               wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in "
+                          "Wi-Fi Handover Request Message");
+               goto out;
+       }
+
+       if (attr.oob_dev_password == NULL ||
+           attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
+               wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password "
+                          "included in Wi-Fi Handover Request Message");
+               ret = -1;
+               goto out;
+       }
+
+       if (attr.uuid_e == NULL) {
+               wpa_printf(MSG_DEBUG, "WPS: No UUID-E included in Wi-Fi "
+                          "Handover Request Message");
+               ret = -1;
+               goto out;
+       }
+
+       wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", attr.uuid_e, WPS_UUID_LEN);
+
+       wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password",
+                   attr.oob_dev_password, attr.oob_dev_password_len);
+       dev_pw_id = WPA_GET_BE16(attr.oob_dev_password +
+                                WPS_OOB_PUBKEY_HASH_LEN);
+       if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) {
+               wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID "
+                          "%u in Wi-Fi Handover Request Message", dev_pw_id);
+               ret = -1;
+               goto out;
+       }
+       wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Public Key hash",
+                   attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN);
+
+       ret = wps_registrar_add_nfc_pw_token(hapd->wps->registrar,
+                                            attr.oob_dev_password,
+                                            DEV_PW_NFC_CONNECTION_HANDOVER,
+                                            NULL, 0, 1);
+
+out:
+       wpabuf_free(wps);
+       return ret;
+}
+
+
 struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef)
 {
        if (hapd->conf->wps_nfc_pw_from_config) {
index a292598..204bd82 100644 (file)
@@ -37,6 +37,9 @@ int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd,
 struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
                                             int ndef);
 struct wpabuf * hostapd_wps_nfc_hs_cr(struct hostapd_data *hapd, int ndef);
+int hostapd_wps_nfc_report_handover(struct hostapd_data *hapd,
+                                   const struct wpabuf *req,
+                                   const struct wpabuf *sel);
 struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef);
 int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd);
 void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd);