#define FLAG_CHUNK (1 << 5)
#define FLAG_SHORT_RECORD (1 << 4)
#define FLAG_ID_LENGTH_PRESENT (1 << 3)
+#define FLAG_TNF_NFC_FORUM (0x01)
#define FLAG_TNF_RFC2046 (0x02)
struct ndef_record {
FLAG_TNF_RFC2046, wifi_handover_type,
os_strlen(wifi_handover_type), NULL, 0, buf);
}
+
+
+struct wpabuf * ndef_build_wifi_hr(void)
+{
+ struct wpabuf *rn, *cr, *ac_payload, *ac, *hr_payload, *hr;
+ struct wpabuf *carrier, *hc;
+
+ rn = wpabuf_alloc(2);
+ if (rn == NULL)
+ return NULL;
+ wpabuf_put_be16(rn, os_random() & 0xffff);
+
+ cr = ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_TNF_NFC_FORUM, "cr", 2,
+ NULL, 0, rn);
+ wpabuf_free(rn);
+
+ if (cr == NULL)
+ return NULL;
+
+ ac_payload = wpabuf_alloc(4);
+ if (ac_payload == NULL) {
+ wpabuf_free(cr);
+ return NULL;
+ }
+ wpabuf_put_u8(ac_payload, 0x01); /* Carrier Flags: CRS=1 "active" */
+ wpabuf_put_u8(ac_payload, 0x01); /* Carrier Data Reference Length */
+ wpabuf_put_u8(ac_payload, '0'); /* Carrier Data Reference: "0" */
+ wpabuf_put_u8(ac_payload, 0); /* Aux Data Reference Count */
+
+ ac = ndef_build_record(FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "ac", 2,
+ NULL, 0, ac_payload);
+ wpabuf_free(ac_payload);
+ if (ac == NULL) {
+ wpabuf_free(cr);
+ return NULL;
+ }
+
+ hr_payload = wpabuf_alloc(1 + wpabuf_len(cr) + wpabuf_len(ac));
+ if (hr_payload == NULL) {
+ wpabuf_free(cr);
+ wpabuf_free(ac);
+ return NULL;
+ }
+
+ wpabuf_put_u8(hr_payload, 0x12); /* Connection Handover Version 1.2 */
+ wpabuf_put_buf(hr_payload, cr);
+ wpabuf_put_buf(hr_payload, ac);
+ wpabuf_free(cr);
+ wpabuf_free(ac);
+
+ hr = ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_TNF_NFC_FORUM, "Hr", 2,
+ NULL, 0, hr_payload);
+ wpabuf_free(hr_payload);
+ if (hr == NULL)
+ return NULL;
+
+ carrier = wpabuf_alloc(2 + os_strlen(wifi_handover_type));
+ if (carrier == NULL) {
+ wpabuf_free(hr);
+ return NULL;
+ }
+ wpabuf_put_u8(carrier, 0x02); /* Carrier Type Format */
+ wpabuf_put_u8(carrier, os_strlen(wifi_handover_type));
+ wpabuf_put_str(carrier, wifi_handover_type);
+
+ hc = ndef_build_record(FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "Hc", 2,
+ "0", 1, carrier);
+ wpabuf_free(carrier);
+ if (hc == NULL) {
+ wpabuf_free(hr);
+ return NULL;
+ }
+
+ return wpabuf_concat(hr, hc);
+}
/* ndef.c */
struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf);
struct wpabuf * ndef_build_wifi(const struct wpabuf *buf);
+struct wpabuf * ndef_build_wifi_hr(void);
#ifdef CONFIG_WPS_STRICT
int wps_validate_beacon(const struct wpabuf *wps_ie);
the ER functionality has been started (wps_er_start), the NFC password
token is used to enable enrollment of a new station (that was the source
of the NFC password token).
+
+"nfc_get_handover_req <NDEF> <WPS>" command can be used to build the
+contents of a Handover Request Message for connection handover. The
+first argument selects the format of the output data and the second
+argument selects which type of connection handover is requested (WPS =
+Wi-Fi handover as specified in WSC 2.0).
+
+"nfc_get_handover_sel <NDEF> <WPS>" command can be used to build the
+contents of a Handover Select Message for connection handover when this
+does not depend on the contents of the Handover Request Message. The
+first argument selects the format of the output data and the second
+argument selects which type of connection handover is requested (WPS =
+Wi-Fi handover as specified in WSC 2.0).
+
+"nfc_rx_handover_req <hexdump of payload>" is used to indicate receipt
+of NFC connection handover request. The payload may include multiple
+carriers the the applicable ones are matched based on the media
+type. The reply data is contents for the Handover Select Message
+(hexdump).
+
+"nfc_rx_handover_sel <hexdump of payload>" is used to indicate receipt
+of NFC connection handover select. The payload may include multiple
+carriers the the applicable ones are matched based on the media
+type.
return ret;
}
+
+static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
+ char *reply, size_t max_len)
+{
+ struct wpabuf *buf;
+ int res;
+
+ buf = wpas_wps_nfc_handover_req(wpa_s);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ char *pos;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ if (os_strcmp(cmd, "NDEF") != 0)
+ return -1;
+
+ if (os_strcmp(pos, "WPS") == 0) {
+ return wpas_ctrl_nfc_get_handover_req_wps(wpa_s, reply,
+ max_len);
+ }
+
+ return -1;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
+ char *reply, size_t max_len)
+{
+ struct wpabuf *buf;
+ int res;
+
+ buf = wpas_wps_nfc_handover_sel(wpa_s);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ char *pos;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ if (os_strcmp(cmd, "NDEF") != 0)
+ return -1;
+
+ if (os_strcmp(pos, "WPS") == 0) {
+ return wpas_ctrl_nfc_get_handover_sel_wps(wpa_s, reply,
+ max_len);
+ }
+
+ return -1;
+}
+
+
+static int wpas_ctrl_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ size_t len;
+ struct wpabuf *buf;
+ int ret;
+
+ len = os_strlen(cmd);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+ if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ ret = wpas_wps_nfc_rx_handover_req(wpa_s, buf);
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+
+static int wpas_ctrl_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ size_t len;
+ struct wpabuf *buf;
+ int ret;
+
+ len = os_strlen(cmd);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+ if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ ret = wpas_wps_nfc_rx_handover_sel(wpa_s, buf);
+ wpabuf_free(buf);
+
+ return ret;
+}
+
#endif /* CONFIG_WPS_NFC */
int reply_len;
if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
- os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
+ os_strncmp(buf, "SET_NETWORK ", 12) == 0 ||
+ os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
+ os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) {
wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
(const u8 *) buf, os_strlen(buf));
} else {
if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
buf + 17))
reply_len = -1;
+ } else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) {
+ reply_len = wpas_ctrl_nfc_get_handover_req(
+ wpa_s, buf + 21, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
+ reply_len = wpas_ctrl_nfc_get_handover_sel(
+ wpa_s, buf + 21, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_RX_HANDOVER_REQ ", 20) == 0) {
+ reply_len = wpas_ctrl_nfc_rx_handover_req(
+ wpa_s, buf + 20, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_RX_HANDOVER_SEL ", 20) == 0) {
+ if (wpas_ctrl_nfc_rx_handover_sel(wpa_s, buf + 20))
+ reply_len = -1;
#endif /* CONFIG_WPS_NFC */
} else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
return ret;
}
+
+static int wpa_cli_cmd_nfc_get_handover_req(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_REQ", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_SEL", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_nfc_rx_handover_req(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ int ret;
+ char *buf;
+ size_t buflen;
+
+ if (argc != 1) {
+ printf("Invalid 'nfc_rx_handover_req' command - one argument "
+ "is required.\n");
+ return -1;
+ }
+
+ buflen = 21 + os_strlen(argv[0]);
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return -1;
+ os_snprintf(buf, buflen, "NFC_RX_HANDOVER_REQ %s", argv[0]);
+
+ ret = wpa_ctrl_command(ctrl, buf);
+ os_free(buf);
+
+ return ret;
+}
+
+
+static int wpa_cli_cmd_nfc_rx_handover_sel(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ int ret;
+ char *buf;
+ size_t buflen;
+
+ if (argc != 1) {
+ printf("Invalid 'nfc_rx_handover_sel' command - one argument "
+ "is required.\n");
+ return -1;
+ }
+
+ buflen = 21 + os_strlen(argv[0]);
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return -1;
+ os_snprintf(buf, buflen, "NFC_RX_HANDOVER_SEL %s", argv[0]);
+
+ ret = wpa_ctrl_command(ctrl, buf);
+ os_free(buf);
+
+ return ret;
+}
+
#endif /* CONFIG_WPS_NFC */
{ "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, NULL,
cli_cmd_flag_sensitive,
"<hexdump of payload> = report read NFC tag with WPS data" },
+ { "nfc_get_handover_req", wpa_cli_cmd_nfc_get_handover_req, NULL,
+ cli_cmd_flag_none,
+ "<NDEF> <WPS> = create NFC handover request" },
+ { "nfc_get_handover_sel", wpa_cli_cmd_nfc_get_handover_sel, NULL,
+ cli_cmd_flag_none,
+ "<NDEF> <WPS> = create NFC handover select" },
+ { "nfc_rx_handover_req", wpa_cli_cmd_nfc_rx_handover_req, NULL,
+ cli_cmd_flag_none,
+ "<hexdump of payload> = report received NFC handover request" },
+ { "nfc_rx_handover_sel", wpa_cli_cmd_nfc_rx_handover_sel, NULL,
+ cli_cmd_flag_none,
+ "<hexdump of payload> = report received NFC handover select" },
#endif /* CONFIG_WPS_NFC */
{ "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss,
cli_cmd_flag_sensitive,
return ret;
}
+
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s)
+{
+ return ndef_build_wifi_hr();
+}
+
+
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s)
+{
+ return NULL;
+}
+
+
+int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data)
+{
+ /* TODO */
+ return -1;
+}
+
+
+int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data)
+{
+ struct wpabuf *wps;
+ int ret;
+
+ wps = ndef_parse_wifi(data);
+ if (wps == NULL)
+ return -1;
+ wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
+ "payload from NFC connection handover");
+ wpa_hexdump_buf_key(MSG_DEBUG, "WPS: NFC payload", wps);
+ ret = wpas_wps_nfc_tag_process(wpa_s, wps);
+ wpabuf_free(wps);
+
+ return ret;
+}
+
#endif /* CONFIG_WPS_NFC */
int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid);
int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
const struct wpabuf *data);
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s);
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s);
+int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data);
+int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data);
void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid);