diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c index 235071b52..d5145f0f2 100644 --- a/src/ap/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -154,6 +154,29 @@ static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr, } +static void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr, + const u8 *uuid_e, + const u8 *pri_dev_type, + u16 config_methods, + u16 dev_password_id, u8 request_type, + const char *dev_name) +{ + struct hostapd_data *hapd = ctx; + char uuid[40]; + char devtype[WPS_DEV_TYPE_BUFSIZE]; + if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) + return; + if (dev_name == NULL) + dev_name = ""; + wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ENROLLEE_SEEN MACSTR + " %s %s 0x%x %u %u [%s]", + MAC2STR(addr), uuid, + wps_dev_type_bin2str(pri_dev_type, devtype, + sizeof(devtype)), + config_methods, dev_password_id, request_type, dev_name); +} + + static int str_starts(const char *str, const char *start) { return os_strncmp(str, start, os_strlen(start)) == 0; @@ -596,6 +619,7 @@ int hostapd_init_wps(struct hostapd_data *hapd, cfg.set_ie_cb = hostapd_wps_set_ie_cb; cfg.pin_needed_cb = hostapd_wps_pin_needed_cb; cfg.reg_success_cb = hostapd_wps_reg_success_cb; + cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb; cfg.cb_ctx = hapd; cfg.skip_cred_build = conf->skip_cred_build; cfg.extra_cred = conf->extra_cred; diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index d2cf92059..25032d92a 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -73,6 +73,8 @@ extern "C" { /** WPS enrollment attempt timed out and was terminated */ #define WPS_EVENT_TIMEOUT "WPS-TIMEOUT " +#define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN " + /* WPS ER events */ #define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD " #define WPS_EVENT_ER_AP_REMOVE "WPS-ER-AP-REMOVE " diff --git a/src/wps/wps.h b/src/wps/wps.h index 449d1cb7d..350a64062 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -277,6 +277,22 @@ struct wps_registrar_config { void (*set_sel_reg_cb)(void *ctx, int sel_reg, u16 dev_passwd_id, u16 sel_reg_config_methods); + /** + * enrollee_seen_cb - Callback for reporting Enrollee based on ProbeReq + * @ctx: Higher layer context data (cb_ctx) + * @addr: MAC address of the Enrollee + * @uuid_e: UUID of the Enrollee + * @pri_dev_type: Primary device type + * @config_methods: Config Methods + * @dev_password_id: Device Password ID + * @request_type: Request Type + * @dev_name: Device Name (if available) + */ + void (*enrollee_seen_cb)(void *ctx, const u8 *addr, const u8 *uuid_e, + const u8 *pri_dev_type, u16 config_methods, + u16 dev_password_id, u8 request_type, + const char *dev_name); + /** * cb_ctx: Higher layer context data for Registrar callbacks */ diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index 07e65462e..3f5119022 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -107,6 +107,10 @@ struct wps_registrar { const u8 *uuid_e); void (*set_sel_reg_cb)(void *ctx, int sel_reg, u16 dev_passwd_id, u16 sel_reg_config_methods); + void (*enrollee_seen_cb)(void *ctx, const u8 *addr, const u8 *uuid_e, + const u8 *pri_dev_type, u16 config_methods, + u16 dev_password_id, u8 request_type, + const char *dev_name); void *cb_ctx; struct dl_list pins; @@ -456,6 +460,7 @@ wps_registrar_init(struct wps_context *wps, reg->pin_needed_cb = cfg->pin_needed_cb; reg->reg_success_cb = cfg->reg_success_cb; reg->set_sel_reg_cb = cfg->set_sel_reg_cb; + reg->enrollee_seen_cb = cfg->enrollee_seen_cb; reg->cb_ctx = cfg->cb_ctx; reg->skip_cred_build = cfg->skip_cred_build; if (cfg->extra_cred) { @@ -770,6 +775,24 @@ void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr, return; } + if (reg->enrollee_seen_cb && attr.dev_password_id && attr.uuid_e && + attr.primary_dev_type && attr.request_type) { + char *dev_name = NULL; + if (attr.dev_name) { + dev_name = os_zalloc(attr.dev_name_len + 1); + if (dev_name) { + os_memcpy(dev_name, attr.dev_name, + attr.dev_name_len); + } + } + reg->enrollee_seen_cb(reg->cb_ctx, addr, attr.uuid_e, + attr.primary_dev_type, + WPA_GET_BE16(attr.config_methods), + WPA_GET_BE16(attr.dev_password_id), + *attr.request_type, dev_name); + os_free(dev_name); + } + methods = WPA_GET_BE16(attr.config_methods); if (!(methods & WPS_CONFIG_PUSHBUTTON)) return; /* Not PBC */ diff --git a/wpa_supplicant/wpa_gui-qt4/peers.cpp b/wpa_supplicant/wpa_gui-qt4/peers.cpp index d1439e234..195fb8d72 100644 --- a/wpa_supplicant/wpa_gui-qt4/peers.cpp +++ b/wpa_supplicant/wpa_gui-qt4/peers.cpp @@ -45,7 +45,8 @@ enum peer_type { PEER_TYPE_WPS_PIN_NEEDED, PEER_TYPE_WPS_ER_AP, PEER_TYPE_WPS_ER_AP_UNCONFIGURED, - PEER_TYPE_WPS_ER_ENROLLEE + PEER_TYPE_WPS_ER_ENROLLEE, + PEER_TYPE_WPS_ENROLLEE }; @@ -122,6 +123,9 @@ QString Peers::ItemType(int type) case PEER_TYPE_WPS_ER_ENROLLEE: title = tr("ER: WPS Enrollee"); break; + case PEER_TYPE_WPS_ENROLLEE: + title = tr("WPS Enrollee"); + break; } return title; } @@ -148,7 +152,8 @@ void Peers::context_menu(const QPoint &pos) if ((type == PEER_TYPE_ASSOCIATED_STATION || type == PEER_TYPE_AP_WPS || type == PEER_TYPE_WPS_PIN_NEEDED || - type == PEER_TYPE_WPS_ER_ENROLLEE) && + type == PEER_TYPE_WPS_ER_ENROLLEE || + type == PEER_TYPE_WPS_ENROLLEE) && (config_methods == -1 || (config_methods & 0x010c))) { menu->addAction(tr("Enter WPS PIN"), this, SLOT(enter_pin())); @@ -160,7 +165,8 @@ void Peers::context_menu(const QPoint &pos) } if ((type == PEER_TYPE_ASSOCIATED_STATION || - type == PEER_TYPE_WPS_ER_ENROLLEE) && + type == PEER_TYPE_WPS_ER_ENROLLEE || + type == PEER_TYPE_WPS_ENROLLEE) && config_methods >= 0 && (config_methods & 0x0080)) { menu->addAction(tr("Enroll (PBC)"), this, SLOT(connect_pbc())); @@ -644,6 +650,71 @@ void Peers::event_notify(WpaMsg msg) remove_enrollee_uuid(items[1]); return; } + + if (text.startsWith(WPS_EVENT_ENROLLEE_SEEN)) { + /* TODO: need to time out this somehow or remove on successful + * WPS run, etc. */ + /* + * WPS-ENROLLEE-SEEN 02:00:00:00:01:00 + * 572cf82f-c957-5653-9b16-b5cfb298abf1 1-0050F204-1 0x80 4 1 + * [Wireless Client] + * (MAC addr, UUID-E, pri dev type, config methods, + * dev passwd id, request type, [dev name]) + */ + QStringList items = text.split(' '); + if (items.size() < 7) + return; + QString addr = items[1]; + QString uuid = items[2]; + QString pri_dev_type = items[3]; + int config_methods = items[4].toInt(0, 0); + int dev_passwd_id = items[5].toInt(); + QString name; + + int pos = text.indexOf('['); + if (pos >= 0) { + int pos2 = text.lastIndexOf(']'); + if (pos2 >= pos) { + QStringList items2 = + text.mid(pos + 1, pos2 - pos - 1). + split('|'); + name = items2[0]; + } + } + if (name.isEmpty()) + name = addr; + + QStandardItem *item; + + item = find_uuid(uuid); + if (item) { + QVariant var = item->data(peer_role_config_methods); + QVariant var2 = item->data(peer_role_dev_passwd_id); + if ((var.isValid() && config_methods != var.toInt()) || + (var2.isValid() && dev_passwd_id != var2.toInt())) + remove_enrollee_uuid(uuid); + else + return; + } + + item = new QStandardItem(*laptop_icon, name); + if (item) { + item->setData(uuid, peer_role_uuid); + item->setData(addr, peer_role_address); + item->setData(PEER_TYPE_WPS_ENROLLEE, + peer_role_type); + item->setToolTip(ItemType(PEER_TYPE_WPS_ENROLLEE)); + item->setData(items.join(QString("\n")), + peer_role_details); + item->setData(pri_dev_type, peer_role_pri_dev_type); + item->setData(config_methods, + peer_role_config_methods); + item->setData(dev_passwd_id, peer_role_dev_passwd_id); + model.appendRow(item); + } + + return; + } } @@ -673,8 +744,11 @@ void Peers::remove_enrollee_uuid(QString uuid) peer_role_uuid, uuid); for (int i = 0; i < lst.size(); i++) { QStandardItem *item = model.itemFromIndex(lst[i]); - if (item && item->data(peer_role_type).toInt() == - PEER_TYPE_WPS_ER_ENROLLEE) + if (item == NULL) + continue; + int type = item->data(peer_role_type).toInt(); + if (type == PEER_TYPE_WPS_ER_ENROLLEE || + type == PEER_TYPE_WPS_ENROLLEE) model.removeRow(lst[i].row()); } }