From: Jouni Malinen Date: Mon, 7 Sep 2009 19:09:13 +0000 (+0300) Subject: WPS: Store device info and make it available through AP ctrl_iface X-Git-Tag: hostap_0_7_0~194 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2678509dec305ad1953c3007a888bf098996c42c;p=thirdparty%2Fhostap.git WPS: Store device info and make it available through AP ctrl_iface Store a copy of device attributes during WPS protocol run and make it available for external programs via the control interface STA MIB command for associated stations. This gives access to device name and type which can be useful when showing user information about associated stations. --- diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 6fe401e58..bdc02f062 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -155,6 +155,10 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len); if (res >= 0) len += res; + res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len, + buflen - len); + if (res >= 0) + len += res; return len; } diff --git a/hostapd/eapol_sm.c b/hostapd/eapol_sm.c index 5491fc4d0..ab6598e22 100644 --- a/hostapd/eapol_sm.c +++ b/hostapd/eapol_sm.c @@ -828,6 +828,7 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr, eap_conf.tnc = eapol->conf.tnc; eap_conf.wps = eapol->conf.wps; eap_conf.assoc_wps_ie = sta->wps_ie; + eap_conf.peer_addr = addr; sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf); if (sm->eap == NULL) { eapol_auth_free(sm); diff --git a/hostapd/wps_hostapd.c b/hostapd/wps_hostapd.c index a0c1e3a1d..5ecf3a444 100644 --- a/hostapd/wps_hostapd.c +++ b/hostapd/wps_hostapd.c @@ -1092,3 +1092,10 @@ static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd) } #endif /* CONFIG_WPS_UPNP */ + + +int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr, + char *buf, size_t buflen) +{ + return wps_registrar_get_info(hapd->wps->registrar, addr, buf, buflen); +} diff --git a/hostapd/wps_hostapd.h b/hostapd/wps_hostapd.h index 5f094f587..c4ac246c8 100644 --- a/hostapd/wps_hostapd.h +++ b/hostapd/wps_hostapd.h @@ -25,6 +25,8 @@ int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid, int hostapd_wps_button_pushed(struct hostapd_data *hapd); int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type, char *path, char *method, char *name); +int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr, + char *buf, size_t buflen); #else /* CONFIG_WPS */ @@ -38,6 +40,13 @@ static inline void hostapd_deinit_wps(struct hostapd_data *hapd) { } +static inline int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, + const u8 *addr, + char *buf, size_t buflen) +{ + return 0; +} + #endif /* CONFIG_WPS */ #endif /* WPS_HOSTAPD_H */ diff --git a/src/eap_server/eap.c b/src/eap_server/eap.c index d23ae2f90..abb807b21 100644 --- a/src/eap_server/eap.c +++ b/src/eap_server/eap.c @@ -1238,6 +1238,8 @@ struct eap_sm * eap_server_sm_init(void *eapol_ctx, sm->wps = conf->wps; if (conf->assoc_wps_ie) sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie); + if (conf->peer_addr) + os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN); wpa_printf(MSG_DEBUG, "EAP: Server state machine created"); diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h index 6a20da4f4..dc00c3198 100644 --- a/src/eap_server/eap.h +++ b/src/eap_server/eap.h @@ -105,6 +105,7 @@ struct eap_config { int tnc; struct wps_context *wps; const struct wpabuf *assoc_wps_ie; + const u8 *peer_addr; }; diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h index d52b86f95..4269a8cfd 100644 --- a/src/eap_server/eap_i.h +++ b/src/eap_server/eap_i.h @@ -185,6 +185,8 @@ struct eap_sm { struct wpabuf *assoc_wps_ie; Boolean start_reauth; + + u8 peer_addr[ETH_ALEN]; }; int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len, diff --git a/src/eap_server/eap_wsc.c b/src/eap_server/eap_wsc.c index 3c1757788..9d14d20a4 100644 --- a/src/eap_server/eap_wsc.c +++ b/src/eap_server/eap_wsc.c @@ -126,6 +126,7 @@ static void * eap_wsc_init(struct eap_sm *sm) cfg.pin_len = sm->user->password_len; } cfg.assoc_wps_ie = sm->assoc_wps_ie; + cfg.peer_addr = sm->peer_addr; data->wps = wps_init(&cfg); if (data->wps == NULL) { os_free(data); diff --git a/src/wps/wps.c b/src/wps/wps.c index e0e19c888..cc8a45be2 100644 --- a/src/wps/wps.c +++ b/src/wps/wps.c @@ -100,6 +100,9 @@ struct wps_data * wps_init(const struct wps_config *cfg) sizeof(*data->new_ap_settings)); } + if (cfg->peer_addr) + os_memcpy(data->peer_dev.mac_addr, cfg->peer_addr, ETH_ALEN); + return data; } diff --git a/src/wps/wps.h b/src/wps/wps.h index c33e8013a..446ff4f16 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -142,6 +142,11 @@ struct wps_config { * current AP settings by using AP PIN. */ const struct wps_credential *new_ap_settings; + + /** + * peer_addr: MAC address of the peer in AP; %NULL if not AP + */ + const u8 *peer_addr; }; struct wps_data * wps_init(const struct wps_config *cfg); @@ -571,6 +576,8 @@ void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr, int wps_registrar_update_ie(struct wps_registrar *reg); int wps_registrar_set_selected_registrar(struct wps_registrar *reg, const struct wpabuf *msg); +int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr, + char *buf, size_t buflen); unsigned int wps_pin_checksum(unsigned int pin); unsigned int wps_pin_valid(unsigned int pin); diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c index 8c8d087e1..89d229e51 100644 --- a/src/wps/wps_enrollee.c +++ b/src/wps/wps_enrollee.c @@ -328,6 +328,16 @@ static struct wpabuf * wps_build_m7(struct wps_data *wps) } wpabuf_free(plain); + if (wps->wps->ap && wps->wps->registrar) { + /* + * If the Registrar is only learning our current configuration, + * it may not continue protocol run to successful completion. + * Store information here to make sure it remains available. + */ + wps_device_store(wps->wps->registrar, &wps->peer_dev, + wps->uuid_r); + } + wps->state = RECV_M8; return msg; } @@ -751,7 +761,8 @@ static enum wps_process_res wps_process_m2(struct wps_data *wps, wps_process_enrollee_nonce(wps, attr->enrollee_nonce) || wps_process_uuid_r(wps, attr->uuid_r) || wps_process_pubkey(wps, attr->public_key, attr->public_key_len) || - wps_process_authenticator(wps, attr->authenticator, msg)) { + wps_process_authenticator(wps, attr->authenticator, msg) || + wps_process_device_attrs(&wps->peer_dev, attr)) { wps->state = SEND_WSC_NACK; return WPS_CONTINUE; } diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h index b79c5291f..c5a9d9f91 100644 --- a/src/wps/wps_i.h +++ b/src/wps/wps_i.h @@ -247,6 +247,8 @@ enum wps_process_res wps_registrar_process_msg(struct wps_data *wps, enum wsc_op_code op_code, const struct wpabuf *msg); int wps_build_cred(struct wps_data *wps, struct wpabuf *msg); +int wps_device_store(struct wps_registrar *reg, + struct wps_device_data *dev, const u8 *uuid); /* ndef.c */ struct wpabuf * ndef_parse_wifi(struct wpabuf *buf); diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index b625d21c4..cfe63aeb5 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -23,6 +23,7 @@ #include "wps_dev_attr.h" #include "wps_upnp.h" #include "crypto.h" +#include "uuid.h" #define WPS_WORKAROUNDS @@ -79,6 +80,13 @@ static void wps_free_pbc_sessions(struct wps_pbc_session *pbc) } +struct wps_registrar_device { + struct wps_registrar_device *next; + struct wps_device_data dev; + u8 uuid[WPS_UUID_LEN]; +}; + + struct wps_registrar { struct wps_context *wps; @@ -104,6 +112,8 @@ struct wps_registrar { int sel_reg_dev_password_id_override; int sel_reg_config_methods_override; int static_wep_only; + + struct wps_registrar_device *devices; }; @@ -113,6 +123,74 @@ static void wps_registrar_set_selected_timeout(void *eloop_ctx, void *timeout_ctx); +static void wps_free_devices(struct wps_registrar_device *dev) +{ + struct wps_registrar_device *prev; + + while (dev) { + prev = dev; + dev = dev->next; + wps_device_data_free(&prev->dev); + os_free(prev); + } +} + + +static struct wps_registrar_device * wps_device_get(struct wps_registrar *reg, + const u8 *addr) +{ + struct wps_registrar_device *dev; + + for (dev = reg->devices; dev; dev = dev->next) { + if (os_memcmp(dev->dev.mac_addr, addr, ETH_ALEN) == 0) + return dev; + } + return NULL; +} + + +static void wps_device_clone_data(struct wps_device_data *dst, + struct wps_device_data *src) +{ + os_memcpy(dst->mac_addr, src->mac_addr, ETH_ALEN); + dst->categ = src->categ; + dst->oui = src->oui; + dst->sub_categ = src->sub_categ; + +#define WPS_STRDUP(n) \ + os_free(dst->n); \ + dst->n = src->n ? os_strdup(src->n) : NULL + + WPS_STRDUP(device_name); + WPS_STRDUP(manufacturer); + WPS_STRDUP(model_name); + WPS_STRDUP(model_number); + WPS_STRDUP(serial_number); +#undef WPS_STRDUP +} + + +int wps_device_store(struct wps_registrar *reg, + struct wps_device_data *dev, const u8 *uuid) +{ + struct wps_registrar_device *d; + + d = wps_device_get(reg, dev->mac_addr); + if (d == NULL) { + d = os_zalloc(sizeof(*d)); + if (d == NULL) + return -1; + d->next = reg->devices; + reg->devices = d; + } + + wps_device_clone_data(&d->dev, dev); + os_memcpy(d->uuid, uuid, WPS_UUID_LEN); + + return 0; +} + + static void wps_registrar_add_pbc_session(struct wps_registrar *reg, const u8 *addr, const u8 *uuid_e) { @@ -406,6 +484,7 @@ void wps_registrar_deinit(struct wps_registrar *reg) wps_free_pins(reg->pins); wps_free_pbc_sessions(reg->pbc_sessions); wpabuf_free(reg->extra_cred); + wps_free_devices(reg->devices); os_free(reg); } @@ -2401,6 +2480,8 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps, if (wps->wps->wps_upnp && wps->ext_reg) { wpa_printf(MSG_DEBUG, "WPS: Negotiation using external " "Registrar completed successfully"); + wps_device_store(wps->wps->registrar, &wps->peer_dev, + wps->uuid_e); return WPS_DONE; } #endif /* CONFIG_WPS_UPNP */ @@ -2419,6 +2500,8 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps, } wpa_printf(MSG_DEBUG, "WPS: Negotiation completed successfully"); + wps_device_store(wps->wps->registrar, &wps->peer_dev, + wps->uuid_e); if (wps->wps->wps_state == WPS_STATE_NOT_CONFIGURED && wps->new_psk && wps->wps->ap && !wps->wps->registrar->disable_auto_conf) { @@ -2606,3 +2689,39 @@ int wps_registrar_set_selected_registrar(struct wps_registrar *reg, reg, NULL); return 0; } + + +int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr, + char *buf, size_t buflen) +{ + struct wps_registrar_device *d; + int len = 0, ret; + char uuid[40]; + + d = wps_device_get(reg, addr); + if (d == NULL) + return 0; + if (uuid_bin2str(d->uuid, uuid, sizeof(uuid))) + return 0; + + ret = os_snprintf(buf + len, buflen - len, + "wpsUuid=%s\n" + "wpsPrimaryDeviceType=%u-%08X-%u\n" + "wpsDeviceName=%s\n" + "wpsManufacturer=%s\n" + "wpsModelName=%s\n" + "wpsModelNumber=%s\n" + "wpsSerialNumber=%s\n", + uuid, + d->dev.categ, d->dev.oui, d->dev.sub_categ, + d->dev.device_name ? d->dev.device_name : "", + d->dev.manufacturer ? d->dev.manufacturer : "", + d->dev.model_name ? d->dev.model_name : "", + d->dev.model_number ? d->dev.model_number : "", + d->dev.serial_number ? d->dev.serial_number : ""); + if (ret < 0 || (size_t) ret >= buflen - len) + return len; + len += ret; + + return len; +}