11f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt/* 21f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * Common driver-related functions 31f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi> 41f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 71f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt */ 81f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 91f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "includes.h" 101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "utils/common.h" 111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "driver.h" 121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtvoid wpa_scan_results_free(struct wpa_scan_results *res) 141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt size_t i; 161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (res == NULL) 181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return; 191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt for (i = 0; i < res->num; i++) 211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(res->res[i]); 221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(res->res); 231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(res); 241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtconst char * event_to_string(enum wpa_event_type event) 281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#define E2S(n) case EVENT_ ## n: return #n 301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt switch (event) { 311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(ASSOC); 321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(DISASSOC); 331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(MICHAEL_MIC_FAILURE); 341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(SCAN_RESULTS); 351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(ASSOCINFO); 361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(INTERFACE_STATUS); 371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(PMKID_CANDIDATE); 381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(STKSTART); 391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(TDLS); 401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(FT_RESPONSE); 411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(IBSS_RSN_START); 421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(AUTH); 431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(DEAUTH); 441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(ASSOC_REJECT); 451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(AUTH_TIMED_OUT); 461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(ASSOC_TIMED_OUT); 471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(WPS_BUTTON_PUSHED); 481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(TX_STATUS); 491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(RX_FROM_UNKNOWN); 501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(RX_MGMT); 511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(REMAIN_ON_CHANNEL); 521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(CANCEL_REMAIN_ON_CHANNEL); 531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(RX_PROBE_REQ); 541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(NEW_STA); 551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(EAPOL_RX); 561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(SIGNAL_CHANGE); 571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(INTERFACE_ENABLED); 581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(INTERFACE_DISABLED); 591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(CHANNEL_LIST_CHANGED); 601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(INTERFACE_UNAVAILABLE); 611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(BEST_CHANNEL); 621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(UNPROT_DEAUTH); 631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(UNPROT_DISASSOC); 641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(STATION_LOW_ACK); 651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(IBSS_PEER_LOST); 661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(DRIVER_GTK_REKEY); 671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(SCHED_SCAN_STOPPED); 681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(DRIVER_CLIENT_POLL_OK); 691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt E2S(EAPOL_TX_STATUS); 7004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt E2S(CH_SWITCH); 7161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt E2S(WNM); 72f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt E2S(CONNECT_FAILED_REASON); 73ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt E2S(DFS_RADAR_DETECTED); 74ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt E2S(DFS_CAC_FINISHED); 75ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt E2S(DFS_CAC_ABORTED); 76ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt E2S(DFS_NOP_FINISHED); 77b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt E2S(SURVEY); 78fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt E2S(SCAN_STARTED); 79cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt E2S(AVOID_FREQUENCIES); 806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt E2S(NEW_PEER_CANDIDATE); 816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt E2S(ACS_CHANNEL_SELECTED); 827f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt E2S(DFS_CAC_STARTED); 831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return "UNKNOWN"; 861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#undef E2S 871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 88661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt 89661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt 90661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidtconst char * channel_width_to_string(enum chan_width width) 91661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt{ 92661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt switch (width) { 93661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt case CHAN_WIDTH_20_NOHT: 94661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt return "20 MHz (no HT)"; 95661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt case CHAN_WIDTH_20: 96661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt return "20 MHz"; 97661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt case CHAN_WIDTH_40: 98661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt return "40 MHz"; 99661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt case CHAN_WIDTH_80: 100661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt return "80 MHz"; 101661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt case CHAN_WIDTH_80P80: 102661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt return "80+80 MHz"; 103661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt case CHAN_WIDTH_160: 104661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt return "160 MHz"; 105661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt default: 106661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt return "unknown"; 107661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt } 108661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt} 1096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint ht_supported(const struct hostapd_hw_modes *mode) 1126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 1136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) { 1146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* 1156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * The driver did not indicate whether it supports HT. Assume 1166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * it does to avoid connection issues. 1176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */ 1186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 1; 1196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 1206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* 1226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * IEEE Std 802.11n-2009 20.1.1: 1236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * An HT non-AP STA shall support all EQM rates for one spatial stream. 1246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */ 1256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return mode->mcs_set[0] == 0xff; 1266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 1276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint vht_supported(const struct hostapd_hw_modes *mode) 1306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 1316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!(mode->flags & HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN)) { 1326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* 1336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * The driver did not indicate whether it supports VHT. Assume 1346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * it does to avoid connection issues. 1356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */ 1366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 1; 1376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 1386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* 1406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * A VHT non-AP STA shall support MCS 0-7 for one spatial stream. 1416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * TODO: Verify if this complies with the standard 1426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */ 1436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return (mode->vht_mcs_set[0] & 0x3) != 3; 1446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 1456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_check_wowlan_trigger(const char *start, const char *trigger, 1486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int capa_trigger, u8 *param_trigger) 1496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 1506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (os_strcmp(start, trigger) != 0) 1516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 0; 1526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!capa_trigger) 1536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 0; 1546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt *param_trigger = 1; 1566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 1; 1576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 1586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstruct wowlan_triggers * 1616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtwpa_get_wowlan_triggers(const char *wowlan_triggers, 1626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt const struct wpa_driver_capa *capa) 1636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 1646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct wowlan_triggers *triggers; 1656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt char *start, *end, *buf; 1666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int last; 1676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!wowlan_triggers) 1696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return NULL; 1706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt buf = os_strdup(wowlan_triggers); 1726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (buf == NULL) 1736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return NULL; 1746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt triggers = os_zalloc(sizeof(*triggers)); 1766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (triggers == NULL) 1776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt goto out; 1786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#define CHECK_TRIGGER(trigger) \ 1806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_check_wowlan_trigger(start, #trigger, \ 1816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->wowlan_triggers.trigger, \ 1826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt &triggers->trigger) 1836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt start = buf; 1856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt while (*start != '\0') { 1866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt while (isblank(*start)) 1876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt start++; 1886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (*start == '\0') 1896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 1906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt end = start; 1916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt while (!isblank(*end) && *end != '\0') 1926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt end++; 1936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt last = *end == '\0'; 1946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt *end = '\0'; 1956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!CHECK_TRIGGER(any) && 1976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt !CHECK_TRIGGER(disconnect) && 1986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt !CHECK_TRIGGER(magic_pkt) && 1996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt !CHECK_TRIGGER(gtk_rekey_failure) && 2006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt !CHECK_TRIGGER(eap_identity_req) && 2016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt !CHECK_TRIGGER(four_way_handshake) && 2026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt !CHECK_TRIGGER(rfkill_release)) { 2036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, 2046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "Unknown/unsupported wowlan trigger '%s'", 2056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt start); 2066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_free(triggers); 2076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt triggers = NULL; 2086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt goto out; 2096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 2106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (last) 2126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 2136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt start = end + 1; 2146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 2156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#undef CHECK_TRIGGER 2166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtout: 2186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_free(buf); 2196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return triggers; 2206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 221