+
+
+static void wps_er_ap_settings_cb(void *ctx, const struct wps_credential *cred)
+{
+ struct wps_er_ap *ap = ctx;
+ wpa_printf(MSG_DEBUG, "WPS ER: AP Settings received");
+ os_free(ap->ap_settings);
+ ap->ap_settings = os_malloc(sizeof(*cred));
+ if (ap->ap_settings) {
+ os_memcpy(ap->ap_settings, cred, sizeof(*cred));
+ ap->ap_settings->cred_attr = NULL;
+ }
+
+ /* TODO: send info through ctrl_iface */
+}
+
+
+static void wps_er_http_put_message_cb(void *ctx, struct http_client *c,
+ enum http_client_event event)
+{
+ struct wps_er_ap *ap = ctx;
+ struct wpabuf *reply;
+ char *msg = NULL;
+
+ switch (event) {
+ case HTTP_CLIENT_OK:
+ wpa_printf(MSG_DEBUG, "WPS ER: PutMessage OK");
+ reply = http_client_get_body(c);
+ if (reply == NULL)
+ break;
+ msg = os_zalloc(wpabuf_len(reply) + 1);
+ if (msg == NULL)
+ break;
+ os_memcpy(msg, wpabuf_head(reply), wpabuf_len(reply));
+ break;
+ case HTTP_CLIENT_FAILED:
+ case HTTP_CLIENT_INVALID_REPLY:
+ case HTTP_CLIENT_TIMEOUT:
+ wpa_printf(MSG_DEBUG, "WPS ER: PutMessage failed");
+ break;
+ }
+ http_client_free(ap->http);
+ ap->http = NULL;
+
+ if (msg) {
+ struct wpabuf *buf;
+ enum http_reply_code ret;
+ buf = xml_get_base64_item(msg, "NewOutMessage", &ret);
+ os_free(msg);
+ if (buf == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS ER: Could not extract "
+ "NewOutMessage from PutMessage response");
+ return;
+ }
+ wps_er_ap_process(ap, buf);
+ wpabuf_free(buf);
+ }
+}
+
+
+static void wps_er_ap_put_message(struct wps_er_ap *ap,
+ const struct wpabuf *msg)
+{
+ struct wpabuf *buf;
+ char *len_ptr, *body_ptr;
+ struct sockaddr_in dst;
+ char *url, *path;
+
+ if (ap->http) {
+ wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing "
+ "with the AP - cannot continue learn");
+ return;
+ }
+
+ if (ap->control_url == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
+ return;
+ }
+
+ url = http_client_url_parse(ap->control_url, &dst, &path);
+ if (url == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
+ return;
+ }
+
+ buf = wps_er_soap_hdr(msg, "PutMessage", "NewInMessage", path, &dst,
+ &len_ptr, &body_ptr);
+ os_free(url);
+ if (buf == NULL)
+ return;
+
+ wps_er_soap_end(buf, "PutMessage", len_ptr, body_ptr);
+
+ ap->http = http_client_addr(&dst, buf, 10000,
+ wps_er_http_put_message_cb, ap);
+ if (ap->http == NULL)
+ wpabuf_free(buf);
+}
+
+
+static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg)
+{
+ enum wps_process_res res;
+
+ res = wps_process_msg(ap->wps, WSC_MSG, msg);
+ if (res == WPS_CONTINUE) {
+ enum wsc_op_code op_code;
+ struct wpabuf *next = wps_get_msg(ap->wps, &op_code);
+ if (next) {
+ wps_er_ap_put_message(ap, next);
+ wpabuf_free(next);
+ } else {
+ wpa_printf(MSG_DEBUG, "WPS ER: Failed to build "
+ "message");
+ wps_deinit(ap->wps);
+ ap->wps = NULL;
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "WPS ER: Failed to process message from "
+ "AP (res=%d)", res);
+ wps_deinit(ap->wps);
+ ap->wps = NULL;
+ }
+}
+
+
+static void wps_er_ap_learn(struct wps_er_ap *ap, const char *dev_info)
+{
+ struct wpabuf *info;
+ enum http_reply_code ret;
+ struct wps_config cfg;
+
+ wpa_printf(MSG_DEBUG, "WPS ER: Received GetDeviceInfo response (M1) "
+ "from the AP");
+ info = xml_get_base64_item(dev_info, "NewDeviceInfo", &ret);
+ if (info == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS ER: Could not extract "
+ "NewDeviceInfo from GetDeviceInfo response");
+ return;
+ }
+
+ if (ap->wps) {
+ wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in "
+ "progress with this AP");
+ wpabuf_free(info);
+ return;
+ }
+
+ os_memset(&cfg, 0, sizeof(cfg));
+ cfg.wps = ap->er->wps;
+ cfg.registrar = 1;
+ ap->wps = wps_init(&cfg);
+ if (ap->wps == NULL) {
+ wpabuf_free(info);
+ return;
+ }
+ ap->wps->ap_settings_cb = wps_er_ap_settings_cb;
+ ap->wps->ap_settings_cb_ctx = ap;
+
+ wps_er_ap_process(ap, info);
+ wpabuf_free(info);
+}
+
+
+static void wps_er_http_get_dev_info_cb(void *ctx, struct http_client *c,
+ enum http_client_event event)
+{
+ struct wps_er_ap *ap = ctx;
+ struct wpabuf *reply;
+ char *dev_info = NULL;
+
+ switch (event) {
+ case HTTP_CLIENT_OK:
+ wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo OK");
+ reply = http_client_get_body(c);
+ if (reply == NULL)
+ break;
+ dev_info = os_zalloc(wpabuf_len(reply) + 1);
+ if (dev_info == NULL)
+ break;
+ os_memcpy(dev_info, wpabuf_head(reply), wpabuf_len(reply));
+ break;
+ case HTTP_CLIENT_FAILED:
+ case HTTP_CLIENT_INVALID_REPLY:
+ case HTTP_CLIENT_TIMEOUT:
+ wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo failed");
+ break;
+ }
+ http_client_free(ap->http);
+ ap->http = NULL;
+
+ if (dev_info) {
+ wps_er_ap_learn(ap, dev_info);
+ os_free(dev_info);
+ }
+}
+
+
+int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
+ size_t pin_len)
+{
+ struct wps_er_ap *ap;
+ struct wpabuf *buf;
+ char *len_ptr, *body_ptr;
+ struct sockaddr_in dst;
+ char *url, *path;
+
+ if (er == NULL)
+ return -1;
+
+ ap = wps_er_ap_get_uuid(er, uuid);
+ if (ap == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS ER: AP not found for learn "
+ "request");
+ return -1;
+ }
+ if (ap->wps || ap->http) {
+ wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
+ "with the AP - cannot start learn");
+ return -1;
+ }
+
+ if (ap->control_url == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
+ return -1;
+ }
+
+ url = http_client_url_parse(ap->control_url, &dst, &path);
+ if (url == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
+ return -1;
+ }
+
+ buf = wps_er_soap_hdr(NULL, "GetDeviceInfo", NULL, path, &dst,
+ &len_ptr, &body_ptr);
+ os_free(url);
+ if (buf == NULL)
+ return -1;
+
+ wps_er_soap_end(buf, "GetDeviceInfo", len_ptr, body_ptr);
+
+ ap->http = http_client_addr(&dst, buf, 10000,
+ wps_er_http_get_dev_info_cb, ap);
+ if (ap->http == NULL) {
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ /* TODO: add PIN without SetSelectedRegistrar trigger to all APs */
+ wps_registrar_add_pin(er->wps->registrar, uuid, pin, pin_len, 0);
+
+ return 0;
+}