1fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt/* 2fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Driver interaction with Linux nl80211/cfg80211 - Android specific 3fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> 4fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net> 5fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Copyright (c) 2009-2010, Atheros Communications 6fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * 7fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 8fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * See README for more details. 9fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt */ 10fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 11fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "includes.h" 12fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include <sys/ioctl.h> 13fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include <net/if.h> 14fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include <netlink/genl/genl.h> 15fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include <netlink/genl/family.h> 16fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include <netlink/genl/ctrl.h> 17fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include <fcntl.h> 18fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 19fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "utils/common.h" 20fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "driver_nl80211.h" 21fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "android_drv.h" 22fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 23fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 24fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidttypedef struct android_wifi_priv_cmd { 25fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt char *buf; 26fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int used_len; 27fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int total_len; 28fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} android_wifi_priv_cmd; 29fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 30fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic int drv_errors = 0; 31fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 32fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv) 33fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 34fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt drv_errors++; 35fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { 36fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt drv_errors = 0; 37fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); 38fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 39fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 40fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 41fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 42fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic int android_priv_cmd(struct i802_bss *bss, const char *cmd) 43fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 44fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct wpa_driver_nl80211_data *drv = bss->drv; 45fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct ifreq ifr; 46fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt android_wifi_priv_cmd priv_cmd; 47fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt char buf[MAX_DRV_CMD_SIZE]; 48fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int ret; 49fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 50fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memset(&ifr, 0, sizeof(ifr)); 51fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memset(&priv_cmd, 0, sizeof(priv_cmd)); 52fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); 53fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 54fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memset(buf, 0, sizeof(buf)); 55fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_strlcpy(buf, cmd, sizeof(buf)); 56fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 57fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt priv_cmd.buf = buf; 58fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt priv_cmd.used_len = sizeof(buf); 59fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt priv_cmd.total_len = sizeof(buf); 60fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt ifr.ifr_data = &priv_cmd; 61fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 62fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr); 63fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (ret < 0) { 64fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_ERROR, "%s: failed to issue private commands", 65fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt __func__); 66fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_driver_send_hang_msg(drv); 67fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return ret; 68fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 69fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 70fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt drv_errors = 0; 71fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 72fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 73fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 74fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 75fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtint android_pno_start(struct i802_bss *bss, 76fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct wpa_driver_scan_params *params) 77fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 78fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct wpa_driver_nl80211_data *drv = bss->drv; 79fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct ifreq ifr; 80fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt android_wifi_priv_cmd priv_cmd; 81fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int ret = 0, i = 0, bp; 82fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt char buf[WEXT_PNO_MAX_COMMAND_SIZE]; 83fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 84fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt bp = WEXT_PNOSETUP_HEADER_SIZE; 85fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp); 86fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt buf[bp++] = WEXT_PNO_TLV_PREFIX; 87fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt buf[bp++] = WEXT_PNO_TLV_VERSION; 88fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt buf[bp++] = WEXT_PNO_TLV_SUBVERSION; 89fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt buf[bp++] = WEXT_PNO_TLV_RESERVED; 90fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 91fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) { 92fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* Check that there is enough space needed for 1 more SSID, the 93fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * other sections and null termination */ 94fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN + 95fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf)) 96fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt break; 97fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan", 98fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt params->ssids[i].ssid, 99fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt params->ssids[i].ssid_len); 100fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt buf[bp++] = WEXT_PNO_SSID_SECTION; 101fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt buf[bp++] = params->ssids[i].ssid_len; 102fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memcpy(&buf[bp], params->ssids[i].ssid, 103fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt params->ssids[i].ssid_len); 104fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt bp += params->ssids[i].ssid_len; 105fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt i++; 106fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 107fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 108fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION; 109fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x", 110fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt WEXT_PNO_SCAN_INTERVAL); 111fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt bp += WEXT_PNO_SCAN_INTERVAL_LENGTH; 112fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 113fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt buf[bp++] = WEXT_PNO_REPEAT_SECTION; 114fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x", 115fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt WEXT_PNO_REPEAT); 116fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt bp += WEXT_PNO_REPEAT_LENGTH; 117fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 118fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION; 119fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x", 120fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt WEXT_PNO_MAX_REPEAT); 121fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1; 122fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 123fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt memset(&ifr, 0, sizeof(ifr)); 124fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt memset(&priv_cmd, 0, sizeof(priv_cmd)); 125fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); 126fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 127fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt priv_cmd.buf = buf; 128fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt priv_cmd.used_len = bp; 129fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt priv_cmd.total_len = bp; 130fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt ifr.ifr_data = &priv_cmd; 131fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 132fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr); 133fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 134fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (ret < 0) { 135fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d", 136fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt ret); 137fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_driver_send_hang_msg(drv); 138fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return ret; 139fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 140fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 141fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt drv_errors = 0; 142fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 143fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return android_priv_cmd(bss, "PNOFORCE 1"); 144fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 145fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 146fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 147fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtint android_pno_stop(struct i802_bss *bss) 148fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 149fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return android_priv_cmd(bss, "PNOFORCE 0"); 150fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 151fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 152fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 153fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#ifdef ANDROID_P2P 1544171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt#ifdef ANDROID_LIB_STUB 155fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 156fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtint wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration) 157fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 158fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 159fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 160fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 161fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 162fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtint wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len) 163fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 164fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 165fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 166fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 167fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 168fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtint wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow) 169fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 170fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return -1; 171fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 172fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 173fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 174fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtint wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon, 175fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt const struct wpabuf *proberesp, 176fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt const struct wpabuf *assocresp) 177fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 178fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 179fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 180fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1814171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt#endif /* ANDROID_LIB_STUB */ 182fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#endif /* ANDROID_P2P */ 183fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 184fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 185fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtint android_nl_socket_set_nonblocking(struct nl_handle *handle) 186fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 187fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK); 188fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 189fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 190fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 191