Changeset 1dcc0b9 in mainline


Ignore:
Timestamp:
2015-04-06T10:47:51Z (9 years ago)
Author:
Jan Kolarik <kolarik@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
d7dadcb4
Parents:
59fa7ab
Message:

Scanning whole 2.4GHz spectrum, created supplicant for managing connection between device STA and AP, finished association process between STA and AP, handling 4way handshake protocol used for key management, written needed cryptographic algorithms (AES, SHA1, HMAC, PBKDF2) for CCMP protocol, data communication on OPEN/CCMP networks.

Location:
uspace
Files:
4 added
25 edited

Legend:

Unmodified
Added
Removed
  • uspace/Makefile

    r59fa7ab r1dcc0b9  
    214214        lib/fs \
    215215        lib/block \
     216        lib/crypto \
    216217        lib/clui \
    217218        lib/fmtutil \
     
    245246        lib/mbr \
    246247        lib/gpt \
    247         lib/ieee80211
     248        lib/ieee80211 \
    248249
    249250LIBC_BUILD = $(addsuffix .build,$(LIBC))
  • uspace/Makefile.common

    r59fa7ab r1dcc0b9  
    120120LIBPOSIX_PREFIX = $(LIB_PREFIX)/posix
    121121
     122LIBCRYPTO_PREFIX = $(LIB_PREFIX)/crypto
    122123LIBBLOCK_PREFIX = $(LIB_PREFIX)/block
    123124LIBFS_PREFIX = $(LIB_PREFIX)/fs
  • uspace/app/wifi_supplicant/wifi_supplicant.c

    r59fa7ab r1dcc0b9  
    3636#include <ieee80211_iface.h>
    3737
    38 #include <malloc.h>
    3938#include <errno.h>
    4039#include <stdio.h>
     
    4241
    4342#define NAME "wifi_supplicant"
     43
     44#define enum_name(name_arr, i) ((i < 0) ? "NA" : name_arr[i])
     45
     46static const char* ieee80211_security_type_strs[] = {
     47        "OPEN", "WEP", "WPA", "WPA2"
     48};
     49
     50static const char* ieee80211_security_alg_strs[] = {
     51        "WEP40", "WEP104", "CCMP", "TKIP"
     52};
     53
     54static const char* ieee80211_security_auth_strs[] = {
     55        "PSK", "8021X"
     56};
    4457
    4558static void print_syntax(void)
     
    4962        printf("\t<cmd> is:\n");
    5063        printf("\tlist - list wifi devices in <index>: <name> format\n");
    51         printf("\tscan <index> - output scan results for given device\n");
     64        printf("\tscan <index> [-n] - output scan results (force scan "
     65                "immediately)\n");
     66        printf("\tconnect <index> <ssid_prefix> [<password>] - connect to "
     67                "network\n");
     68        printf("\tdisconnect <index> - disconnect from network\n");
    5269}
    5370
     
    98115        }
    99116       
    100         if(i > count - 1) {
     117        if(i >= count) {
    101118                printf("Invalid wifi index.\n");
    102119                free(wifis);
     
    104121        }
    105122
    106         async_sess_t *sess = loc_service_connect(EXCHANGE_SERIALIZE, wifis[i], 0);
     123        async_sess_t *sess =
     124                loc_service_connect(EXCHANGE_SERIALIZE, wifis[i], 0);
    107125        if (sess == NULL) {
    108126                printf("Error connecting to service.\n");
     
    144162}
    145163
    146 static int wifi_connect(uint32_t index, char *ssid, char *password)
    147 {
    148         assert(ssid);
     164static int wifi_connect(uint32_t index, char *ssid_start, char *password)
     165{
     166        assert(ssid_start);
    149167       
    150168        async_sess_t *sess = get_wifi_by_index(index);
    151169        if (sess == NULL) {
    152                 printf("Specified WIFI doesn't exist or cannot connect to it.\n");
     170                printf("Specified WIFI doesn't exist or cannot connect to "
     171                        "it.\n");
    153172                return EINVAL;
    154173        }
    155174       
    156         int rc = ieee80211_connect(sess, ssid, password);
     175        int rc = ieee80211_connect(sess, ssid_start, password);
    157176        if(rc != EOK) {
    158                 printf("Failed connecting to network. Error: %d\n", rc);
    159                 return EINVAL;
    160         }
    161        
    162         printf("Successfully connected to %s!\n", ssid);
    163        
    164         return EOK;
    165 }
    166 
    167 static int wifi_scan(uint32_t index)
    168 {
    169         ieee80211_scan_results_t scan_results;
    170        
     177                if(rc == EREFUSED) {
     178                        printf("Device is not ready yet.\n");                   
     179                } else if(rc == ETIMEOUT) {
     180                        printf("Timeout when authenticating to network.\n");
     181                } else if(rc == EPERM) {
     182                        printf("Bad password provided.\n");
     183                } else {
     184                        printf("Error when connecting to network. "
     185                                "Error: %d\n", rc);
     186                }
     187               
     188                return rc;
     189        }
     190       
     191        printf("Successfully connected to network!\n");
     192       
     193        return EOK;
     194}
     195
     196static int wifi_disconnect(uint32_t index)
     197{
    171198        async_sess_t *sess = get_wifi_by_index(index);
    172199        if (sess == NULL) {
    173                 printf("Specified WIFI doesn't exist or cannot connect to it.\n");
     200                printf("Specified WIFI doesn't exist or cannot connect to "
     201                        "it.\n");
    174202                return EINVAL;
    175203        }
    176204       
    177         int rc = ieee80211_get_scan_results(sess, &scan_results);
     205        int rc = ieee80211_disconnect(sess);
    178206        if(rc != EOK) {
    179                 printf("Failed to fetch scan results. Error: %d\n", rc);
     207                if(rc == EREFUSED) {
     208                        printf("Device is not ready yet.\n");
     209                } else if(rc == EINVAL) {
     210                        printf("Not connected to any WiFi network.\n");
     211                } else {
     212                        printf("Error when disconnecting from network. "
     213                                "Error: %d\n", rc);
     214                }
     215                return rc;
     216        }
     217       
     218        printf("Successfully disconnected.\n");
     219       
     220        return EOK;
     221}
     222
     223static int wifi_scan(uint32_t index, bool now)
     224{
     225        ieee80211_scan_results_t scan_results;
     226       
     227        async_sess_t *sess = get_wifi_by_index(index);
     228        if (sess == NULL) {
     229                printf("Specified WIFI doesn't exist or cannot connect to "
     230                        "it.\n");
    180231                return EINVAL;
    181232        }
     233       
     234        int rc = ieee80211_get_scan_results(sess, &scan_results, now);
     235        if(rc != EOK) {
     236                if(rc == EREFUSED) {
     237                        printf("Device is not ready yet.\n");
     238                } else {
     239                        printf("Failed to fetch scan results. Error: %d\n", rc);
     240                }
     241               
     242                return rc;
     243        }
     244       
     245        if(scan_results.length == 0)
     246                return EOK;
     247       
     248        printf("%16.16s %17s %4s %5s %5s %7s %7s\n",
     249                "SSID", "MAC", "CHAN", "TYPE", "AUTH", "UNI-ALG", "GRP-ALG");
    182250       
    183251        for(int i = 0; i < scan_results.length; i++) {
    184252                ieee80211_scan_result_t result = scan_results.results[i];
    185253               
    186                 printf("SSID: %s, MAC addr: %s\n", result.ssid,
    187                         nic_addr_format(&result.bssid));
     254                printf("%16.16s %17s %4d %5s %5s %7s %7s\n",
     255                        result.ssid,
     256                        nic_addr_format(&result.bssid),
     257                        result.channel,
     258                        enum_name(ieee80211_security_type_strs,
     259                                result.security.type),
     260                        enum_name(ieee80211_security_auth_strs,
     261                                result.security.auth),
     262                        enum_name(ieee80211_security_alg_strs,
     263                                result.security.pair_alg),
     264                        enum_name(ieee80211_security_alg_strs,
     265                                result.security.group_alg)
     266                );
    188267        }
    189268       
     
    197276       
    198277        if(argc == 2) {
    199                 if (!str_cmp(argv[1], "list")) {
     278                if(!str_cmp(argv[1], "list")) {
    200279                        return wifi_list();
    201280                }
    202281        } else if(argc > 2) {
    203282                rc = str_uint32_t(argv[2], NULL, 10, false, &index);
    204                 if (rc != EOK) {
     283                if(rc != EOK) {
    205284                        printf(NAME ": Invalid argument.\n");
    206285                        print_syntax();
    207286                        return EINVAL;
    208287                }
    209                 if (!str_cmp(argv[1], "scan")) {
    210                         return wifi_scan(index);
    211                 } else if (!str_cmp(argv[1], "connect")) {
     288                if(!str_cmp(argv[1], "scan")) {
     289                        bool now = false;
     290                        if(argc > 3)
     291                                if(!str_cmp(argv[3], "-n"))
     292                                        now = true;
     293                        return wifi_scan(index, now);
     294                } else if(!str_cmp(argv[1], "connect")) {
    212295                        char *pass = NULL;
    213296                        if(argc > 3) {
     
    216299                                return wifi_connect(index, argv[3], pass);
    217300                        }
     301                } else if(!str_cmp(argv[1], "disconnect")) {
     302                        return wifi_disconnect(index);
    218303                }
    219304        }
  • uspace/drv/nic/ar9271/Makefile

    r59fa7ab r1dcc0b9  
    3434        $(LIBDRV_PREFIX)/libdrv.a \
    3535        $(LIBNIC_PREFIX)/libnic.a \
    36         $(LIBIEEE80211_PREFIX)/libieee80211.a
     36        $(LIBIEEE80211_PREFIX)/libieee80211.a \
     37        $(LIBCRYPTO_PREFIX)/libcrypto.a
    3738       
    3839EXTRA_CFLAGS += \
     
    4344        -I$(LIBNIC_PREFIX)/include \
    4445        -I$(LIBIEEE80211_PREFIX)/include \
     46        -I$(LIBCRYPTO_PREFIX)
    4547       
    4648BINARY = ar9271
  • uspace/drv/nic/ar9271/ar9271.c

    r59fa7ab r1dcc0b9  
    105105static int ar9271_ieee80211_set_freq(ieee80211_dev_t *ieee80211_dev,
    106106        uint16_t freq);
     107static int ar9271_ieee80211_bssid_change(ieee80211_dev_t *ieee80211_dev);
     108static int ar9271_ieee80211_key_config(ieee80211_dev_t *ieee80211_dev,
     109        ieee80211_key_config_t *key_conf, bool insert);
    107110
    108111static driver_ops_t ar9271_driver_ops = {
     
    118121        .start = ar9271_ieee80211_start,
    119122        .tx_handler = ar9271_ieee80211_tx_handler,
    120         .set_freq = ar9271_ieee80211_set_freq
     123        .set_freq = ar9271_ieee80211_set_freq,
     124        .bssid_change = ar9271_ieee80211_bssid_change,
     125        .key_config = ar9271_ieee80211_key_config
    121126};
    122127
     
    186191 *
    187192 */
    188 static int ar9271_on_multicast_mode_change(nic_t *nic, nic_multicast_mode_t mode,
    189     const nic_address_t *addr, size_t addr_cnt)
     193static int ar9271_on_multicast_mode_change(nic_t *nic,
     194        nic_multicast_mode_t mode, const nic_address_t *addr, size_t addr_cnt)
    190195{
    191196        /*
     
    249254 *
    250255 */
    251 static int ar9271_on_broadcast_mode_change(nic_t *nic, nic_broadcast_mode_t mode)
     256static int ar9271_on_broadcast_mode_change(nic_t *nic,
     257        nic_broadcast_mode_t mode)
    252258{
    253259        /*
     
    271277}
    272278
     279static bool ar9271_rx_status_error(uint8_t status)
     280{
     281        return (status & AR9271_RX_ERROR_PHY) || (status & AR9271_RX_ERROR_CRC);
     282}
     283
    273284static int ar9271_data_polling(void *arg)
    274285{
     286        assert(arg);
     287       
    275288        ar9271_t *ar9271 = (ar9271_t *) arg;
    276289       
     
    282295                if(htc_read_data_message(ar9271->htc_device,
    283296                        buffer, buffer_size, &transferred_size) == EOK) {
    284                         ath_usb_data_header_t *data_header =
    285                                 (ath_usb_data_header_t *) buffer;
    286 
    287                         /* Invalid packet. */
    288                         if(data_header->tag != uint16_t_le2host(RX_TAG)) {
    289                                 continue;
    290                         }
    291                        
    292297                        size_t strip_length =
    293298                                sizeof(ath_usb_data_header_t) +
    294299                                sizeof(htc_frame_header_t) +
    295                                 HTC_RX_HEADER_LENGTH;
     300                                sizeof(htc_rx_status_t);
    296301                       
    297                         /* TODO: RX header inspection. */
     302                        if(transferred_size < strip_length)
     303                                continue;
     304
     305                        ath_usb_data_header_t *data_header =
     306                                (ath_usb_data_header_t *) buffer;
     307
     308                        /* Invalid packet. */
     309                        if(data_header->tag != uint16_t_le2host(RX_TAG))
     310                                continue;
     311                       
     312                        htc_rx_status_t *rx_status =
     313                                (htc_rx_status_t *) ((void *) buffer +
     314                                sizeof(ath_usb_data_header_t) +
     315                                sizeof(htc_frame_header_t));
     316                       
     317                        uint16_t data_length =
     318                                uint16_t_be2host(rx_status->data_length);
     319                       
     320                        int16_t payload_length =
     321                                transferred_size - strip_length;
     322                       
     323                        if(payload_length - data_length < 0)
     324                                continue;
     325                       
     326                        if(ar9271_rx_status_error(rx_status->status))
     327                                continue;
     328                       
    298329                        void *strip_buffer = buffer + strip_length;
    299                        
     330
    300331                        ieee80211_rx_handler(ar9271->ieee80211_dev,
    301332                                strip_buffer,
    302                                 transferred_size - strip_length);
     333                                payload_length);
    303334                }
    304335        }
     
    316347        uint16_t freq)
    317348{
     349        assert(ieee80211_dev);
     350       
    318351        ar9271_t *ar9271 = (ar9271_t *) ieee80211_get_specific(ieee80211_dev);
     352       
     353        //hw_wakeup(ar9271);
    319354       
    320355        wmi_send_command(ar9271->htc_device, WMI_DISABLE_INTR, NULL, 0, NULL);
     
    344379}
    345380
     381static int ar9271_ieee80211_bssid_change(ieee80211_dev_t *ieee80211_dev)
     382{
     383        assert(ieee80211_dev);
     384       
     385        ar9271_t *ar9271 = (ar9271_t *) ieee80211_get_specific(ieee80211_dev);
     386
     387        /* Check if we are connected or disconnected. */
     388        if(ieee80211_is_connected(ieee80211_dev)) {
     389                nic_address_t bssid;
     390                ieee80211_query_bssid(ieee80211_dev, &bssid);
     391
     392                htc_sta_msg_t sta_msg;
     393                memset(&sta_msg, 0, sizeof(htc_sta_msg_t));
     394                sta_msg.is_vif_sta = 0;
     395                sta_msg.max_ampdu =
     396                        host2uint16_t_be(1 << IEEE80211_MAX_AMPDU_FACTOR);
     397                sta_msg.sta_index = 1;
     398                sta_msg.vif_index = 0;
     399                memcpy(&sta_msg.addr, bssid.address, ETH_ADDR);
     400
     401                wmi_send_command(ar9271->htc_device, WMI_NODE_CREATE,
     402                        (uint8_t *) &sta_msg, sizeof(sta_msg), NULL);
     403
     404                htc_rate_msg_t rate_msg;
     405                memset(&rate_msg, 0, sizeof(htc_rate_msg_t));
     406                rate_msg.sta_index = 1;
     407                rate_msg.is_new = 1;
     408                rate_msg.legacy_rates_count =
     409                        ARRAY_SIZE(ieee80211bg_data_rates);
     410                memcpy(&rate_msg.legacy_rates,
     411                        ieee80211bg_data_rates,
     412                        ARRAY_SIZE(ieee80211bg_data_rates));
     413
     414                wmi_send_command(ar9271->htc_device, WMI_RC_RATE_UPDATE,
     415                        (uint8_t *) &rate_msg, sizeof(rate_msg), NULL);
     416
     417                hw_set_rx_filter(ar9271, true);
     418        } else {
     419                uint8_t station_id = 1;
     420                wmi_send_command(ar9271->htc_device, WMI_NODE_REMOVE,
     421                        &station_id, sizeof(station_id), NULL);
     422               
     423                hw_set_rx_filter(ar9271, false);
     424        }
     425       
     426        hw_set_bssid(ar9271);
     427       
     428        return EOK;
     429}
     430
     431static int ar9271_ieee80211_key_config(ieee80211_dev_t *ieee80211_dev,
     432        ieee80211_key_config_t *key_conf, bool insert)
     433{
     434        assert(ieee80211_dev);
     435        assert(key_conf);
     436       
     437        ar9271_t *ar9271 = (ar9271_t *) ieee80211_get_specific(ieee80211_dev);
     438       
     439        uint32_t key[5];
     440        uint32_t key_type;
     441        uint32_t reg_ptr;
     442        void *data_start;
     443       
     444        if(insert) {
     445                nic_address_t bssid;
     446                ieee80211_query_bssid(ieee80211_dev, &bssid);
     447               
     448                switch(key_conf->suite) {
     449                        case IEEE80211_SECURITY_SUITE_WEP40:
     450                                key_type = AR9271_KEY_TABLE_TYPE_WEP40;
     451                                break;
     452                        case IEEE80211_SECURITY_SUITE_WEP104:
     453                                key_type = AR9271_KEY_TABLE_TYPE_WEP104;
     454                                break;
     455                        case IEEE80211_SECURITY_SUITE_TKIP:
     456                                key_type = AR9271_KEY_TABLE_TYPE_TKIP;
     457                                break;
     458                        case IEEE80211_SECURITY_SUITE_CCMP:
     459                                key_type = AR9271_KEY_TABLE_TYPE_CCMP;
     460                                break;
     461                        default:
     462                                key_type = -1;
     463                }
     464               
     465                if(key_conf->flags & IEEE80211_KEY_FLAG_TYPE_PAIRWISE) {
     466                        reg_ptr = AR9271_KEY_TABLE_STA;
     467                } else {
     468                        reg_ptr = AR9271_KEY_TABLE_GRP;
     469                }
     470               
     471                if(key_conf->suite == IEEE80211_SECURITY_SUITE_TKIP) {
     472                        // TODO
     473                } else {
     474                        data_start = (void *) key_conf->data;
     475                       
     476                        key[0] = uint32_t_le2host(
     477                                *((uint32_t *) data_start));
     478                        key[1] = uint16_t_le2host(
     479                                *((uint16_t *) (data_start + 4)));
     480                        key[2] = uint32_t_le2host(
     481                                *((uint32_t *) (data_start + 6)));
     482                        key[3] = uint16_t_le2host(
     483                                *((uint16_t *) (data_start + 10)));
     484                        key[4] = uint32_t_le2host(
     485                                *((uint32_t *) (data_start + 12)));
     486                       
     487                        if(key_conf->suite == IEEE80211_SECURITY_SUITE_WEP40 ||
     488                           key_conf->suite == IEEE80211_SECURITY_SUITE_WEP104) {
     489                                key[4] &= 0xFF;
     490                        }
     491                       
     492                        wmi_reg_write(ar9271->htc_device, reg_ptr + 0, key[0]);
     493                        wmi_reg_write(ar9271->htc_device, reg_ptr + 4, key[1]);
     494                        wmi_reg_write(ar9271->htc_device, reg_ptr + 8, key[2]);
     495                        wmi_reg_write(ar9271->htc_device, reg_ptr + 12, key[3]);
     496                        wmi_reg_write(ar9271->htc_device, reg_ptr + 16, key[4]);
     497                        wmi_reg_write(ar9271->htc_device, reg_ptr + 20,
     498                                key_type);
     499                }
     500               
     501                uint32_t macL, macH;
     502                if(key_conf->flags & IEEE80211_KEY_FLAG_TYPE_PAIRWISE) {
     503                        data_start = (void *) bssid.address;
     504                        macL = uint32_t_le2host(*((uint32_t *) data_start));
     505                        macH = uint16_t_le2host(*((uint16_t *)
     506                                (data_start + 4)));
     507                } else {
     508                        macL = macH = 0;
     509                }
     510               
     511                macL >>= 1;
     512                macL |= (macH & 1) << 31;
     513                macH >>= 1;
     514                macH |= 0x8000;
     515               
     516                wmi_reg_write(ar9271->htc_device, reg_ptr + 24, macL);
     517                wmi_reg_write(ar9271->htc_device, reg_ptr + 28, macH);
     518               
     519                if(key_conf->flags & IEEE80211_KEY_FLAG_TYPE_GROUP)
     520                        ieee80211_setup_key_confirm(ieee80211_dev, true);
     521        } else {
     522                // TODO
     523        }
     524       
     525        return EOK;
     526}
     527
    346528static int ar9271_ieee80211_tx_handler(ieee80211_dev_t *ieee80211_dev,
    347529        void *buffer, size_t buffer_size)
    348530{
     531        assert(ieee80211_dev);
     532       
    349533        size_t complete_size, offset;
    350534        void *complete_buffer;
     
    355539        uint16_t frame_ctrl = *((uint16_t *) buffer);
    356540        if(ieee80211_is_data_frame(frame_ctrl)) {
    357                 offset = sizeof(htc_frame_header_t);
     541                offset = sizeof(htc_tx_data_header_t) +
     542                        sizeof(htc_frame_header_t);
    358543                complete_size = buffer_size + offset;
    359544                complete_buffer = malloc(complete_size);
     545                memset(complete_buffer, 0, complete_size);
     546               
     547                /*
     548                 * Because we handle just station mode yet, node ID and VIF ID
     549                 * are fixed.
     550                 */
     551                htc_tx_data_header_t *data_header =
     552                        (htc_tx_data_header_t *)
     553                        (complete_buffer + sizeof(htc_frame_header_t));
     554                /* TODO: Distinguish data type. */
     555                data_header->data_type = HTC_DATA_NORMAL;
     556                data_header->node_idx = 1;
     557                data_header->vif_idx = 0;
     558                /* TODO: There I should probably handle slot number. */
     559                data_header->cookie = 0;
     560               
     561                if(ieee80211_query_using_key(ieee80211_dev)) {
     562                        data_header->keyix = AR9271_STA_KEY_INDEX;
     563                        int sec_suite =
     564                                ieee80211_get_security_suite(ieee80211_dev);
     565                        switch(sec_suite) {
     566                                case IEEE80211_SECURITY_SUITE_WEP40:
     567                                case IEEE80211_SECURITY_SUITE_WEP104:
     568                                        data_header->key_type =
     569                                                AR9271_KEY_TYPE_WEP;
     570                                        break;
     571                                case IEEE80211_SECURITY_SUITE_TKIP:
     572                                        data_header->key_type =
     573                                                AR9271_KEY_TYPE_TKIP;
     574                                        break;
     575                                case IEEE80211_SECURITY_SUITE_CCMP:
     576                                        data_header->key_type =
     577                                                AR9271_KEY_TYPE_AES;
     578                                        break;
     579                        }
     580                } else {
     581                        data_header->key_type = 0;
     582                        data_header->keyix = 0xFF;
     583                }
     584               
    360585                endpoint = ar9271->htc_device->endpoints.data_be_endpoint;
    361586        } else {
     
    366591                memset(complete_buffer, 0, complete_size);
    367592               
     593                /*
     594                 * Because we handle just station mode yet, node ID and VIF ID
     595                 * are fixed.
     596                 */
    368597                htc_tx_management_header_t *mgmt_header =
    369598                        (htc_tx_management_header_t *)
    370599                        (complete_buffer + sizeof(htc_frame_header_t));
     600                mgmt_header->node_idx = 0;
     601                mgmt_header->vif_idx = 0;
     602                /* TODO: There I should probably handle slot number. */
     603                mgmt_header->cookie = 0;
    371604                mgmt_header->keyix = 0xFF;
    372605               
     
    387620static int ar9271_ieee80211_start(ieee80211_dev_t *ieee80211_dev)
    388621{
     622        assert(ieee80211_dev);
     623       
    389624        ar9271_t *ar9271 = (ar9271_t *) ieee80211_get_specific(ieee80211_dev);
    390625       
     
    434669       
    435670        ar9271->starting_up = false;
     671        ieee80211_set_ready(ieee80211_dev, true);
     672       
     673        usb_log_info("Device fully initialized.\n");
    436674       
    437675        return EOK;
  • uspace/drv/nic/ar9271/ar9271.h

    r59fa7ab r1dcc0b9  
    4646#define AR9271_LED_PIN 15
    4747
     48/** Nominal value for AR9271 noise floor calibration. */
     49#define AR9271_CALIB_NOMINAL_VALUE_2GHZ -118
     50
     51/** RX errors values. */
     52#define AR9271_RX_ERROR_CRC 0x01
     53#define AR9271_RX_ERROR_PHY 0x02
     54
     55/** Key index used for device in station mode. */
     56#define AR9271_STA_KEY_INDEX 4
     57
     58/* HW encryption key indicator. */
     59enum ath9k_key_type {
     60        AR9271_KEY_TYPE_CLEAR,
     61        AR9271_KEY_TYPE_WEP,
     62        AR9271_KEY_TYPE_AES,
     63        AR9271_KEY_TYPE_TKIP,
     64};
     65
    4866/** AR9271 Registers */
    4967typedef enum {
     
    7593        AR9271_GPIO_OUT_MUX_AS_OUT = 0x0,       /**< GPIO set mux as output */
    7694   
    77         /* Wakeup related registers */
     95        /* RTC related registers */
    7896        AR9271_RTC_RC = 0x7000,
    7997        AR9271_RTC_RC_MAC_WARM = 0x00000001,
     
    86104        AR9271_RTC_STATUS_SHUTDOWN = 0x00000001,
    87105        AR9271_RTC_STATUS_ON = 0x00000002,
     106        AR9271_RTC_SLEEP_CLOCK = 0x7048,
     107        AR9271_RTC_SLEEP_CLOCK_FORCE_DERIVED = 0x2,
    88108        AR9271_RTC_FORCE_WAKE = 0x704C,
    89109        AR9271_RTC_FORCE_WAKE_ENABLE = 0x00000001,
     
    93113        AR9271_STATION_ID0 = 0x8000,    /**< STA Address Lower 32 Bits */
    94114        AR9271_STATION_ID1 = 0x8004,    /**< STA Address Upper 16 Bits */
    95         AR9271_BSSID0 = 0x8008,                 /**< BSSID Lower 32 Bits */
    96         AR9271_BSSID1 = 0x800C,                 /**< BSSID Upper 16 Bits */
    97         AR9271_BSSID_MASK0 = 0x80E0,            /**< BSSID Mask Lower 32 Bits */
    98         AR9271_BSSID_MASK1 = 0x80E4,            /**< BSSID Mask Upper 16 Bits */
     115        AR9271_BSSID0 = 0x8008,         /**< BSSID Lower 32 Bits */
     116        AR9271_BSSID1 = 0x800C,         /**< BSSID Upper 16 Bits */
     117        AR9271_BSSID_MASK0 = 0x80E0,    /**< BSSID Mask Lower 32 Bits */
     118        AR9271_BSSID_MASK1 = 0x80E4,    /**< BSSID Mask Upper 16 Bits */
    99119        AR9271_STATION_ID1_MASK = 0x0000FFFF,
    100120        AR9271_STATION_ID1_POWER_SAVING = 0x00040000,
     121        AR9271_MULTICAST_FILTER1 = 0x8040,
     122        AR9271_MULTICAST_FILTER2 = 0x8044,     
     123        AR9271_DIAG = 0x8048,
    101124               
    102125        /* RX filtering register */
     
    110133        AR9271_RX_FILTER_PROBEREQ = 0x00000080,
    111134        AR9271_RX_FILTER_MYBEACON = 0x00000200,
    112         AR9271_MULTICAST_FILTER1 = 0x8040,
    113         AR9271_MULTICAST_FILTER2 = 0x8044,     
    114         AR9271_DIAG = 0x8048,
     135        AR9271_RX_FILTER_MCAST_BCAST_ALL = 0x00008000,
     136               
     137        /* Key related registers */
     138        AR9271_KEY_TABLE_GRP = 0x8820,
     139        AR9271_KEY_TABLE_STA = 0x8880,
     140        AR9271_KEY_TABLE_TYPE_WEP40 = 0x0,
     141        AR9271_KEY_TABLE_TYPE_WEP104 = 0x1,
     142        AR9271_KEY_TABLE_TYPE_TKIP = 0x4,
     143        AR9271_KEY_TABLE_TYPE_CCMP = 0x6,
    115144               
    116145        /* Physical layer registers */
     
    118147        AR9271_ADC_CONTROL = 0x982C,
    119148        AR9271_AGC_CONTROL = 0x9860,
     149        AR9271_PHY_CAL = 0x9864,
    120150        AR9271_PHY_SYNTH_CONTROL = 0x9874,
    121151        AR9271_PHY_SPECTRAL_SCAN = 0x9910,
  • uspace/drv/nic/ar9271/ath_usb.h

    r59fa7ab r1dcc0b9  
    5757typedef struct {
    5858        uint16_t length;                /**< Little Endian value! */
    59         uint16_t tag;           /**< Little Endian value! */
     59        uint16_t tag;                   /**< Little Endian value! */
    6060} ath_usb_data_header_t;
    6161
  • uspace/drv/nic/ar9271/htc.c

    r59fa7ab r1dcc0b9  
    7575       
    7676        nic_address_t addr;
    77         nic_t *nic = nic_get_from_ddf_dev(ieee80211_get_ddf_dev(htc_device->ieee80211_dev));
     77        nic_t *nic =
     78                nic_get_from_ddf_dev(
     79                        ieee80211_get_ddf_dev(htc_device->ieee80211_dev)
     80                );
    7881        nic_query_address(nic, &addr);
    7982       
     
    128131        wmi_reg_write(htc_device, AR9271_STATION_ID1, id1);
    129132       
    130         /* TODO: Set BSSID mask for AP mode. */
    131        
    132133        return EOK;
    133134}
  • uspace/drv/nic/ar9271/htc.h

    r59fa7ab r1dcc0b9  
    4545
    4646#define HTC_RTS_THRESHOLD 2304
    47 #define HTC_RX_HEADER_LENGTH 40
    48 
    49 /**
    50  * HTC message IDs
     47#define HTC_RATES_MAX_LENGTH 30
     48
     49/**
     50 * HTC message IDs.
    5151 */
    5252typedef enum {
     
    5959
    6060/**
    61  * HTC response message status codes
     61 * HTC response message status codes.
    6262 */
    6363typedef enum {
     
    7070
    7171/**
    72  * HTC operating mode definition
     72 * HTC operating mode definition.
    7373 */
    7474typedef enum {
     
    8080
    8181/**
    82  * HTC endpoint numbers
     82 * HTC data type indicator.
     83 */
     84typedef enum {
     85        HTC_DATA_AMPDU = 1,
     86        HTC_DATA_NORMAL = 2,
     87        HTC_DATA_BEACON = 3,
     88        HTC_DATA_MGMT = 4
     89} htc_data_type_t;
     90
     91/**
     92 * HTC endpoint numbers.
    8393 */
    8494typedef struct {
     
    96106
    97107/**
    98  * HTC device data
     108 * HTC device data.
    99109 */
    100110typedef struct {
     
    119129
    120130/**
    121  * HTC frame header structure 
     131 * HTC frame header structure.
    122132 */
    123133typedef struct {
     
    126136        uint16_t  payload_length;       /**< Big Endian value! */
    127137        uint8_t   control_bytes[4];
    128    
    129         /* Message payload starts after the header. */
    130138} __attribute__((packed)) htc_frame_header_t;
    131139
    132140/**
    133  * HTC management TX frame header structure 
     141 * HTC management TX frame header structure.
    134142 */
    135143typedef struct {
     
    145153
    146154/**
    147  * HTC ready message structure
     155 * HTC data TX frame header structure.
     156 */
     157typedef struct {
     158        uint8_t data_type;
     159        uint8_t node_idx;
     160        uint8_t vif_idx;
     161        uint8_t tidno;
     162        uint32_t flags;                 /**< Big Endian value! */
     163        uint8_t key_type;
     164        uint8_t keyix;
     165        uint8_t cookie;
     166        uint8_t pad;
     167} __attribute__((packed)) htc_tx_data_header_t;
     168
     169/**
     170 * HTC ready message structure.
    148171 */
    149172typedef struct {
     
    157180
    158181/**
    159  * HTC service message structure 
     182 * HTC service message structure.
    160183 */
    161184typedef struct {
     
    171194
    172195/**
    173  * HTC service response message structure 
     196 * HTC service response message structure.
    174197 */
    175198typedef struct {
     
    184207
    185208/**
    186  * HTC credits config message structure
     209 * HTC credits config message structure.
    187210 */
    188211typedef struct {
     
    193216
    194217/**
    195  * HTC new virtual interface message
     218 * HTC new virtual interface message.
    196219 */
    197220typedef struct {
     
    205228
    206229/**
    207  * HTC new station message
     230 * HTC new station message.
    208231 */
    209232typedef struct {
     
    231254        uint8_t pad;
    232255} __attribute__((packed)) htc_cap_msg_t;
     256
     257typedef struct {
     258        uint8_t sta_index;
     259        uint8_t is_new;
     260        uint32_t cap_flags;     /**< Big Endian value! */
     261        uint8_t legacy_rates_count;
     262        uint8_t legacy_rates[HTC_RATES_MAX_LENGTH];
     263        uint16_t pad;
     264} htc_rate_msg_t;
     265
     266/**
     267 * HTC RX status structure used in incoming HTC data messages.
     268 */
     269typedef struct {
     270        uint64_t timestamp;     /**< Big Endian value! */
     271        uint16_t data_length;   /**< Big Endian value! */
     272        uint8_t status;
     273        uint8_t phy_err;
     274        int8_t rssi;
     275        int8_t rssi_ctl[3];
     276        int8_t rssi_ext[3];
     277        uint8_t keyix;
     278        uint8_t rate;
     279        uint8_t antenna;
     280        uint8_t more;
     281        uint8_t is_aggr;
     282        uint8_t more_aggr;
     283        uint8_t num_delims;
     284        uint8_t flags;
     285        uint8_t dummy;
     286        uint32_t evm0;          /**< Big Endian value! */
     287        uint32_t evm1;          /**< Big Endian value! */
     288        uint32_t evm2;          /**< Big Endian value! */
     289} htc_rx_status_t;
    233290
    234291/**
  • uspace/drv/nic/ar9271/hw.c

    r59fa7ab r1dcc0b9  
    4343
    4444/**
    45  * Try to wait for register value repeatedly until timeout defined by device
    46  * is reached.
     45 * Try to wait for register value repeatedly until timeout is reached.
    4746 *
    4847 * @param ar9271 Device structure.
     
    264263}
    265264
     265static int hw_activate_phy(ar9271_t *ar9271)
     266{
     267        wmi_reg_write(ar9271->htc_device, AR9271_PHY_ACTIVE, 1);
     268        udelay(1000);
     269       
     270        return EOK;
     271}
     272
    266273static int hw_set_operating_mode(ar9271_t *ar9271,
    267274        ieee80211_operating_mode_t op_mode)
     
    305312static int hw_noise_floor_calibration(ar9271_t *ar9271)
    306313{
     314        uint32_t value;
     315        wmi_reg_read(ar9271->htc_device, AR9271_PHY_CAL, &value);
     316        value &= 0xFFFFFE00;
     317        value |= (((uint32_t) AR9271_CALIB_NOMINAL_VALUE_2GHZ << 1) & 0x1FF);
     318        wmi_reg_write(ar9271->htc_device, AR9271_PHY_CAL, value);
     319       
     320        wmi_reg_clear_bit(ar9271->htc_device, AR9271_AGC_CONTROL,
     321                AR9271_AGC_CONTROL_NF_CALIB_EN);
     322       
     323        wmi_reg_clear_bit(ar9271->htc_device, AR9271_AGC_CONTROL,
     324                AR9271_AGC_CONTROL_NF_NOT_UPDATE);
     325       
     326        wmi_reg_set_bit(ar9271->htc_device, AR9271_AGC_CONTROL,
     327                AR9271_AGC_CONTROL_NF_CALIB);
     328       
     329        int rc = hw_read_wait(ar9271, AR9271_AGC_CONTROL,
     330                AR9271_AGC_CONTROL_NF_CALIB, 0);
     331        if(rc != EOK) {
     332                usb_log_error("Failed to wait for NF calibration.\n");
     333                return rc;
     334        }
     335       
    307336        wmi_reg_set_bit(ar9271->htc_device, AR9271_AGC_CONTROL,
    308337                AR9271_AGC_CONTROL_NF_CALIB_EN);
     
    348377}
    349378
     379int hw_wakeup(ar9271_t *ar9271)
     380{
     381        int rc;
     382       
     383        uint32_t rtc_status;
     384        wmi_reg_read(ar9271->htc_device, AR9271_RTC_STATUS, &rtc_status);
     385        if((rtc_status & AR9271_RTC_STATUS_MASK) == AR9271_RTC_STATUS_SHUTDOWN) {
     386                rc = hw_reset_power_on(ar9271);
     387                if(rc != EOK) {
     388                        usb_log_info("Failed to HW reset power on.\n");
     389                        return rc;
     390                }
     391
     392                rc = hw_set_reset(ar9271, false);
     393                if(rc != EOK) {
     394                        usb_log_info("Failed to HW warm reset.\n");
     395                        return rc;
     396                }
     397        }
     398       
     399        wmi_reg_set_bit(ar9271->htc_device, AR9271_RTC_FORCE_WAKE,
     400                AR9271_RTC_FORCE_WAKE_ENABLE);
     401       
     402        size_t i;
     403        for(i = 0; i < HW_WAIT_LOOPS; i++) {
     404                wmi_reg_read(ar9271->htc_device, AR9271_RTC_STATUS,
     405                        &rtc_status);
     406                if((rtc_status & AR9271_RTC_STATUS_MASK) ==
     407                        AR9271_RTC_STATUS_ON) {
     408                        break;
     409                }
     410                wmi_reg_set_bit(ar9271->htc_device, AR9271_RTC_FORCE_WAKE,
     411                        AR9271_RTC_FORCE_WAKE_ENABLE);
     412                udelay(50);
     413        }       
     414       
     415        if(i == HW_WAIT_LOOPS) {
     416                return EINVAL;
     417        } else {
     418                return EOK;
     419        }
     420}
     421
    350422int hw_freq_switch(ar9271_t *ar9271, uint16_t freq)
    351423{
     
    361433        if(rc != EOK) {
    362434                usb_log_error("Failed to HW set frequency.\n");
     435                return rc;
     436        }
     437       
     438        rc = hw_activate_phy(ar9271);
     439        if(rc != EOK) {
     440                usb_log_error("Failed to activate physical layer.\n");
    363441                return rc;
    364442        }
     
    376454}
    377455
    378 static int hw_set_rx_filter(ar9271_t *ar9271)
     456int hw_set_rx_filter(ar9271_t *ar9271, bool assoc)
    379457{
    380458        uint32_t filter_bits;
    381459       
    382         /* TODO: Do proper filtering here. */
     460        uint32_t additional_bits = 0;
     461       
     462        if(assoc) {
     463                additional_bits |= AR9271_RX_FILTER_MYBEACON;
     464        } else {
     465                additional_bits |= AR9271_RX_FILTER_BEACON;
     466        }
    383467       
    384468        filter_bits = AR9271_RX_FILTER_UNI | AR9271_RX_FILTER_MULTI |
    385                 AR9271_RX_FILTER_BROAD | AR9271_RX_FILTER_BEACON;
     469                AR9271_RX_FILTER_BROAD | additional_bits;
    386470       
    387471        wmi_reg_write(ar9271->htc_device, AR9271_RX_FILTER, filter_bits);
     472       
     473        return EOK;
     474}
     475
     476int hw_set_bssid(ar9271_t *ar9271)
     477{
     478        ieee80211_dev_t *ieee80211_dev = ar9271->ieee80211_dev;
     479       
     480        nic_address_t bssid;
     481        ieee80211_query_bssid(ieee80211_dev, &bssid);
     482       
     483        uint32_t *first_4bytes = (uint32_t *) &bssid.address;
     484        uint16_t *last_2bytes = (uint16_t *) &bssid.address[4];
     485       
     486        wmi_reg_write(ar9271->htc_device, AR9271_BSSID0,
     487                uint32_t_le2host(*first_4bytes));
     488       
     489        wmi_reg_write(ar9271->htc_device, AR9271_BSSID1,
     490                uint16_t_le2host(*last_2bytes) |
     491                ((ieee80211_get_aid(ieee80211_dev) & 0x3FFF) << 16));
    388492       
    389493        return EOK;
     
    395499                AR9271_COMMAND_RX_ENABLE);
    396500       
    397         int rc = hw_set_rx_filter(ar9271);
     501        int rc = hw_set_rx_filter(ar9271, false);
    398502        if(rc != EOK) {
    399503                usb_log_error("Failed to set RX filtering.\n");
     
    410514}
    411515
    412 static int hw_activate_phy(ar9271_t *ar9271)
    413 {
    414         wmi_reg_write(ar9271->htc_device, AR9271_PHY_ACTIVE, 1);
    415         udelay(1000);
    416        
    417         return EOK;
    418 }
    419 
    420516static int hw_init_pll(ar9271_t *ar9271)
    421517{
     
    423519       
    424520        /* Some magic here (set for 2GHz channels). But VERY important :-) */
    425         pll = (0x5 << 10) & 0x00003C00;
    426         pll |= 0x2C & 0x000003FF;
     521        pll = (0x5 << 10) | 0x2C;
    427522       
    428523        wmi_reg_write(ar9271->htc_device, AR9271_RTC_PLL_CONTROL, pll);
    429524       
    430         return EOK;
    431 }
    432 
    433 static int hw_set_init_values(ar9271_t *ar9271)
     525        wmi_reg_write(ar9271->htc_device, AR9271_RTC_SLEEP_CLOCK,
     526                AR9271_RTC_SLEEP_CLOCK_FORCE_DERIVED);
     527        wmi_reg_set_bit(ar9271->htc_device, AR9271_RTC_FORCE_WAKE,
     528                AR9271_RTC_FORCE_WAKE_ENABLE);
     529       
     530        return EOK;
     531}
     532
     533static void hw_set_init_values(ar9271_t *ar9271)
    434534{
    435535        uint32_t reg_offset, reg_value;
     
    458558                wmi_reg_write(ar9271->htc_device, reg_offset, reg_value);
    459559        }
    460        
    461         return EOK;
    462560}
    463561
     
    533631        }
    534632       
    535         rc = hw_set_init_values(ar9271);
    536         if(rc != EOK) {
    537                 usb_log_error("Failed to set device init values.\n");
    538                 return rc;
    539         }
     633        hw_set_init_values(ar9271);
    540634       
    541635        /* Set physical layer mode. */
     
    586680        /* Byteswap TX and RX data buffer words. */
    587681        wmi_reg_write(ar9271->htc_device, AR9271_CONFIG, 0xA);
    588        
    589         usb_log_info("HW reset done.\n");
    590682       
    591683        return EOK;
  • uspace/drv/nic/ar9271/hw.h

    r59fa7ab r1dcc0b9  
    4545extern int hw_rx_init(ar9271_t *ar9271);
    4646extern int hw_reset(ar9271_t *ar9271);
     47extern int hw_wakeup(ar9271_t *ar9271);
     48extern int hw_set_bssid(ar9271_t *ar9271);
     49extern int hw_set_rx_filter(ar9271_t *ar9271, bool assoc);
    4750
    4851#endif  /* ATHEROS_HW_H */
  • uspace/drv/nic/ar9271/wmi.c

    r59fa7ab r1dcc0b9  
    231231        size_t buffer_size = header_size + command_length;
    232232        void *buffer = malloc(buffer_size);
    233         memcpy(buffer+header_size, command_buffer, command_length);
     233       
     234        if(command_buffer != NULL) {
     235                memcpy(buffer+header_size, command_buffer, command_length);
     236        }
    234237       
    235238        /* Set up WMI header */
     
    261264       
    262265        /* Read response. */
    263         rc = htc_read_control_message(htc_device, response_buffer,
    264                 response_buffer_size, NULL);
    265         if(rc != EOK) {
    266                 free(buffer);
    267                 usb_log_error("Failed to receive WMI message response. "
    268                     "Error: %d\n", rc);
    269                 return rc;
    270         }
     266        /* TODO: Ignoring WMI management RX messages ~ TX statuses etc. */
     267        uint16_t cmd_id;
     268        do {
     269                rc = htc_read_control_message(htc_device, response_buffer,
     270                        response_buffer_size, NULL);
     271                if(rc != EOK) {
     272                        free(buffer);
     273                        usb_log_error("Failed to receive WMI message response. "
     274                            "Error: %d\n", rc);
     275                        return rc;
     276                }
     277               
     278                if(response_buffer_size < sizeof(htc_frame_header_t) +
     279                        sizeof(wmi_command_header_t)) {
     280                        free(buffer);
     281                        usb_log_error("Corrupted response received.\n");
     282                        return EINVAL;
     283                }
     284               
     285                wmi_command_header_t *wmi_hdr = (wmi_command_header_t *)
     286                        ((void*) response_buffer + sizeof(htc_frame_header_t));
     287                cmd_id = uint16_t_be2host(wmi_hdr->command_id);
     288        } while(cmd_id & WMI_MGMT_CMD_MASK);
    271289       
    272290        if(clean_resp_buffer) {
  • uspace/drv/nic/ar9271/wmi.h

    r59fa7ab r1dcc0b9  
    4242#define WMI_SERVICE_GROUP 1
    4343#define CREATE_SERVICE_ID(group, i) (int) (((int) group << 8) | (int) (i))
     44
     45#define WMI_MGMT_CMD_MASK 0x1000
    4446
    4547/**
     
    117119extern int wmi_reg_write(htc_device_t *htc_device, uint32_t reg_offset,
    118120        uint32_t val);
    119 extern int wmi_reg_set_clear_bit(htc_device_t *htc_device, uint32_t reg_offset,
    120         uint32_t set_bit, uint32_t clear_bit);
     121extern int wmi_reg_set_clear_bit(htc_device_t *htc_device,
     122        uint32_t reg_offset, uint32_t set_bit, uint32_t clear_bit);
    121123extern int wmi_reg_set_bit(htc_device_t *htc_device, uint32_t reg_offset,
    122124        uint32_t set_bit);
  • uspace/lib/c/include/ieee80211/ieee80211.h

    r59fa7ab r1dcc0b9  
    4141#include <adt/list.h>
    4242#include <nic/nic.h>
     43#include <time.h>
    4344
    44 /* Max length of scan results array. */
     45/** Max length of scan results array. */
    4546#define IEEE80211_MAX_RESULTS_LENGTH 32
    4647
    47 /* Max SSID length including null character. */
     48/** Max SSID length including null character. */
    4849#define IEEE80211_MAX_SSID_LENGTH 35
     50
     51/** WiFi security authentication method indicator. */
     52typedef enum {
     53        IEEE80211_SECURITY_OPEN,
     54        IEEE80211_SECURITY_WEP,
     55        IEEE80211_SECURITY_WPA,
     56        IEEE80211_SECURITY_WPA2
     57} ieee80211_security_type_t;
     58
     59/** WiFi security suite indicator. */
     60typedef enum {
     61        IEEE80211_SECURITY_SUITE_WEP40,
     62        IEEE80211_SECURITY_SUITE_WEP104,
     63        IEEE80211_SECURITY_SUITE_CCMP,
     64        IEEE80211_SECURITY_SUITE_TKIP
     65} ieee80211_security_suite_t;
     66
     67/** WiFi security authentication method indicator. */
     68typedef enum {
     69        IEEE80211_SECURITY_AUTH_PSK,
     70        IEEE80211_SECURITY_AUTH_8021X
     71} ieee80211_security_auth_t;
     72
     73/** Structure for indicating security network security settings. */
     74typedef struct {
     75        int type;
     76        int group_alg;
     77        int pair_alg;
     78        int auth;
     79} ieee80211_security_t;
    4980
    5081/** Structure with scan result info. */
     
    5283        nic_address_t bssid;
    5384        char ssid[IEEE80211_MAX_SSID_LENGTH];
     85        uint8_t channel;
     86        ieee80211_security_t security;
    5487} ieee80211_scan_result_t;
    5588
    56 /** List of scan results info. */
     89/** Array of scan results info. */
    5790typedef struct {
    5891        uint8_t length;
  • uspace/lib/drv/generic/remote_ieee80211.c

    r59fa7ab r1dcc0b9  
    4747typedef enum {
    4848        IEEE80211_GET_SCAN_RESULTS,
    49         IEEE80211_CONNECT
     49        IEEE80211_CONNECT,
     50        IEEE80211_DISCONNECT
    5051} ieee80211_funcs_t;
    5152
     
    5960 */
    6061int ieee80211_get_scan_results(async_sess_t *dev_sess,
    61         ieee80211_scan_results_t *results)
     62        ieee80211_scan_results_t *results, bool now)
    6263{
    6364        assert(results);
     
    6566        async_exch_t *exch = async_exchange_begin(dev_sess);
    6667       
    67         aid_t aid = async_send_1(exch, DEV_IFACE_ID(IEEE80211_DEV_IFACE),
    68             IEEE80211_GET_SCAN_RESULTS, NULL);
     68        aid_t aid = async_send_2(exch, DEV_IFACE_ID(IEEE80211_DEV_IFACE),
     69            IEEE80211_GET_SCAN_RESULTS, now, NULL);
    6970        int rc = async_data_read_start(exch, results, sizeof(ieee80211_scan_results_t));
    7071        async_exchange_end(exch);
     
    7374        async_wait_for(aid, &res);
    7475       
    75         if (rc != EOK)
     76        if(res != EOK)
     77                return (int) res;
     78        else
    7679                return rc;
    77        
    78         return (int) res;
    7980}
    8081
     
    8283 *
    8384 * @param[in] dev_sess Device session.
    84  * @param[in] ssid Network SSID.
     85 * @param[in] ssid_start Network SSID prefix.
    8586 * @param[in] password Network password (pass empty string if not needed).
    8687 *
     
    8889 * negative error code otherwise.
    8990 */
    90 int ieee80211_connect(async_sess_t *dev_sess, char *ssid, char *password)
    91 {
    92         assert(ssid);
     91int ieee80211_connect(async_sess_t *dev_sess, char *ssid_start, char *password)
     92{
     93        assert(ssid_start);
    9394       
    9495        sysarg_t rc_orig;
     
    99100            IEEE80211_CONNECT, NULL);
    100101       
    101         sysarg_t rc = async_data_write_start(exch, ssid, str_size(ssid) + 1);
     102        sysarg_t rc = async_data_write_start(exch, ssid_start,
     103                str_size(ssid_start) + 1);
    102104        if (rc != EOK) {
    103105                async_exchange_end(exch);
     
    132134}
    133135
     136/** Disconnect device from network.
     137 *
     138 * @param[in] dev_sess Device session.
     139 *
     140 * @return EOK If the operation was successfully completed,
     141 * negative error code otherwise.
     142 */
     143int ieee80211_disconnect(async_sess_t *dev_sess)
     144{
     145        async_exch_t *exch = async_exchange_begin(dev_sess);
     146        int rc = async_req_1_0(exch, DEV_IFACE_ID(IEEE80211_DEV_IFACE),
     147            IEEE80211_DISCONNECT);
     148        async_exchange_end(exch);
     149       
     150        return rc;
     151}
     152
    134153static void remote_ieee80211_get_scan_results(ddf_fun_t *fun, void *iface,
    135154    ipc_callid_t callid, ipc_call_t *call)
     
    141160        memset(&scan_results, 0, sizeof(ieee80211_scan_results_t));
    142161       
    143         int rc = ieee80211_iface->get_scan_results(fun, &scan_results);
     162        bool now = IPC_GET_ARG2(*call);
     163       
     164        int rc = ieee80211_iface->get_scan_results(fun, &scan_results, now);
    144165        if (rc == EOK) {
    145166                ipc_callid_t data_callid;
     
    170191        assert(ieee80211_iface->connect);
    171192       
    172         char ssid[MAX_STRING_SIZE];
     193        char ssid_start[MAX_STRING_SIZE];
    173194        char password[MAX_STRING_SIZE];
    174195       
     
    187208        }
    188209       
    189         int rc = async_data_write_finalize(data_callid, ssid, len);
     210        int rc = async_data_write_finalize(data_callid, ssid_start, len);
    190211        if (rc != EOK) {
    191212                async_answer_0(data_callid, EINVAL);
     
    213234        }
    214235       
    215         rc = ieee80211_iface->connect(fun, ssid, password);
    216        
     236        rc = ieee80211_iface->connect(fun, ssid_start, password);
     237       
     238        async_answer_0(callid, rc);
     239}
     240
     241static void remote_ieee80211_disconnect(ddf_fun_t *fun, void *iface,
     242    ipc_callid_t callid, ipc_call_t *call)
     243{
     244        ieee80211_iface_t *ieee80211_iface = (ieee80211_iface_t *) iface;
     245        assert(ieee80211_iface->disconnect);
     246        int rc = ieee80211_iface->disconnect(fun);
    217247        async_answer_0(callid, rc);
    218248}
     
    223253static const remote_iface_func_ptr_t remote_ieee80211_iface_ops[] = {
    224254        [IEEE80211_GET_SCAN_RESULTS] = remote_ieee80211_get_scan_results,
    225         [IEEE80211_CONNECT] = remote_ieee80211_connect
     255        [IEEE80211_CONNECT] = remote_ieee80211_connect,
     256        [IEEE80211_DISCONNECT] = remote_ieee80211_disconnect
    226257};
    227258
  • uspace/lib/drv/include/ieee80211_iface.h

    r59fa7ab r1dcc0b9  
    3939#include <async.h>
    4040
    41 extern int ieee80211_get_scan_results(async_sess_t *, ieee80211_scan_results_t *);
     41extern int ieee80211_get_scan_results(async_sess_t *,
     42        ieee80211_scan_results_t *, bool);
    4243extern int ieee80211_connect(async_sess_t *, char *, char *);
     44extern int ieee80211_disconnect(async_sess_t *);
    4345
    4446#endif
  • uspace/lib/drv/include/ops/ieee80211.h

    r59fa7ab r1dcc0b9  
    4747         * @param fun IEEE 802.11 function.
    4848         * @param results Structure where to put scan results.
     49         * @param now Whether to initiate scan immediately.
    4950         *
    5051         * @return EOK if succeed, negative error code otherwise.
    5152         */
    52         int (*get_scan_results)(ddf_fun_t *, ieee80211_scan_results_t *);
     53        int (*get_scan_results)(ddf_fun_t *, ieee80211_scan_results_t *, bool);
    5354       
    5455        /**
    5556         * Connect IEEE 802.11 device to specified network.
     57         *
    5658         * @param fun IEEE 802.11 function.
    5759         * @param ssid Network SSID.
     
    6163         */
    6264        int (*connect)(ddf_fun_t *, char *, char *);
     65       
     66        /**
     67         * Disconnect IEEE 802.11 device from network.
     68         *
     69         * @param fun IEEE 802.11 function.
     70         *
     71         * @return EOK if succeed, negative error code otherwise.
     72         */
     73        int (*disconnect)(ddf_fun_t *);
    6374} ieee80211_iface_t;
    6475
  • uspace/lib/ieee80211/Makefile

    r59fa7ab r1dcc0b9  
    11#
    2 # Copyright (c) 2005 Martin Decky
    3 # Copyright (c) 2007 Jakub Jermar
     2# Copyright (c) 2015 Jan Kolarik
    43# All rights reserved.
    54#
     
    3332LIBS = \
    3433        $(LIBDRV_PREFIX)/libdrv.a \
    35         $(LIBNIC_PREFIX)/libnic.a
     34        $(LIBNIC_PREFIX)/libnic.a \
     35        $(LIBCRYPTO_PREFIX)/libcrypto.a
    3636
    3737EXTRA_CFLAGS += \
    3838        -Iinclude \
    3939        -I$(LIBDRV_PREFIX)/include \
    40         -I$(LIBNIC_PREFIX)/include
     40        -I$(LIBNIC_PREFIX)/include \
     41        -I$(LIBCRYPTO_PREFIX)
    4142
    4243SOURCES = \
  • uspace/lib/ieee80211/include/ieee80211.h

    r59fa7ab r1dcc0b9  
    5757#define IEEE80211_CHANNEL_GAP 5
    5858
     59/* Max AMPDU factor. */
     60#define IEEE80211_MAX_AMPDU_FACTOR 13
     61
     62/* Max passphrase length in WPA/WPA2 protocols. */
     63#define IEEE80211_WPA_MAX_PASSWORD_LENGTH 64
     64
     65/** IEEE 802.11 b/g supported data rates in units of 500 kb/s. */
     66static const uint8_t ieee80211bg_data_rates[] = {
     67        2, 4, 11, 12, 18, 22, 24, 36, 48, 72, 96, 108
     68};
     69
    5970/** Device operating modes. */
    6071typedef enum {
     
    6576} ieee80211_operating_mode_t;
    6677
     78/** Key flags. */
     79typedef enum {
     80        IEEE80211_KEY_FLAG_TYPE_PAIRWISE = 0x01,
     81        IEEE80211_KEY_FLAG_TYPE_GROUP = 0x02
     82} ieee80211_key_flags_t;
     83
     84/** Key config structure. */
     85typedef struct {
     86        uint8_t id;
     87        uint8_t flags;
     88        ieee80211_security_suite_t suite;
     89        uint8_t data[32];
     90} ieee80211_key_config_t;
     91
    6792/** IEEE 802.11 callback functions. */
    6893typedef struct {
     
    109134         */
    110135        int (*set_freq)(struct ieee80211_dev *, uint16_t);
     136       
     137        /**
     138         * Callback to inform device about BSSID change.
     139         *
     140         * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
     141         *
     142         * @return EOK if succeed, negative error code otherwise.
     143         */
     144        int (*bssid_change)(struct ieee80211_dev *);
     145       
     146        /**
     147         * Callback to setup encryption key in IEEE 802.11 device.
     148         *
     149         * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
     150         * @param key_conf Key config structure.
     151         * @param insert True to insert this key to device, false to remove it.
     152         *
     153         * @return EOK if succeed, negative error code otherwise.
     154         */
     155        int (*key_config)(struct ieee80211_dev *,
     156                ieee80211_key_config_t *key_conf, bool);
    111157} ieee80211_ops_t;
    112158
     
    124170        void *specific);
    125171extern ddf_dev_t *ieee80211_get_ddf_dev(ieee80211_dev_t* ieee80211_dev);
    126 extern ieee80211_operating_mode_t ieee80211_query_current_op_mode(ieee80211_dev_t *ieee80211_dev);
     172extern ieee80211_operating_mode_t
     173        ieee80211_query_current_op_mode(ieee80211_dev_t *ieee80211_dev);
    127174extern uint16_t ieee80211_query_current_freq(ieee80211_dev_t *ieee80211_dev);
     175extern void ieee80211_query_bssid(ieee80211_dev_t* ieee80211_dev,
     176        nic_address_t *bssid);
     177extern bool ieee80211_is_connected(ieee80211_dev_t* ieee80211_dev);
    128178extern void ieee80211_report_current_op_mode(ieee80211_dev_t *ieee80211_dev,
    129179        ieee80211_operating_mode_t op_mode);
    130180extern void ieee80211_report_current_freq(ieee80211_dev_t *ieee80211_dev,
    131181        uint16_t freq);
     182extern uint16_t ieee80211_get_aid(ieee80211_dev_t* ieee80211_dev);
     183extern int ieee80211_get_security_suite(ieee80211_dev_t* ieee80211_dev);
     184extern bool ieee80211_is_ready(ieee80211_dev_t* ieee80211_dev);
     185extern void ieee80211_set_ready(ieee80211_dev_t* ieee80211_dev, bool ready);
     186extern bool ieee80211_query_using_key(ieee80211_dev_t* ieee80211_dev);
     187extern void ieee80211_setup_key_confirm(ieee80211_dev_t* ieee80211_dev,
     188        bool using_key);
    132189
    133190extern bool ieee80211_is_data_frame(uint16_t frame_ctrl);
     
    135192extern bool ieee80211_is_beacon_frame(uint16_t frame_ctrl);
    136193extern bool ieee80211_is_probe_response_frame(uint16_t frame_ctrl);
     194extern bool ieee80211_is_auth_frame(uint16_t frame_ctrl);
     195extern bool ieee80211_is_assoc_response_frame(uint16_t frame_ctrl);
    137196
    138197/* Worker functions. */
  • uspace/lib/ieee80211/include/ieee80211_iface_impl.h

    r59fa7ab r1dcc0b9  
    4545
    4646extern int ieee80211_get_scan_results_impl(ddf_fun_t *fun,
    47         ieee80211_scan_results_t *results);
    48 extern int ieee80211_connect_impl(ddf_fun_t *fun, char *ssid, char *password);
     47        ieee80211_scan_results_t *results, bool now);
     48extern int ieee80211_connect_impl(ddf_fun_t *fun, char *ssid_start,
     49        char *password);
     50extern int ieee80211_disconnect_impl(ddf_fun_t *fun);
    4951
    5052#endif  /* LIB_IEEE80211_IFACE_IMPL_H */
  • uspace/lib/ieee80211/include/ieee80211_impl.h

    r59fa7ab r1dcc0b9  
    4343
    4444extern int ieee80211_start_impl(ieee80211_dev_t *ieee80211_dev);
    45 extern int ieee80211_tx_handler_impl(ieee80211_dev_t *ieee80211_dev, void *buffer,
    46         size_t buffer_size);
    47 extern int ieee80211_set_freq_impl(ieee80211_dev_t *ieee80211_dev, uint16_t freq);
     45extern int ieee80211_tx_handler_impl(ieee80211_dev_t *ieee80211_dev,
     46        void *buffer, size_t buffer_size);
     47extern int ieee80211_set_freq_impl(ieee80211_dev_t *ieee80211_dev,
     48        uint16_t freq);
     49extern int ieee80211_bssid_change_impl(ieee80211_dev_t *ieee80211_dev);
     50extern int ieee80211_key_config_impl(ieee80211_dev_t *ieee80211_dev,
     51        ieee80211_key_config_t *key_conf, bool insert);
    4852extern int ieee80211_scan_impl(ieee80211_dev_t *ieee80211_dev);
     53extern int ieee80211_prf(uint8_t *key, uint8_t *data, uint8_t *hash,
     54        hash_func_t hash_sel);
     55extern int ieee80211_aes_key_unwrap(uint8_t *kek, uint8_t *data,
     56        size_t data_size, uint8_t *output);
     57extern int rnd_sequence(uint8_t *sequence, size_t length);
     58extern uint8_t *min_sequence(uint8_t *seq1, uint8_t *seq2, size_t size);
     59extern uint8_t *max_sequence(uint8_t *seq1, uint8_t *seq2, size_t size);
    4960
    5061#endif  /* LIB_IEEE80211_IMPL_H */
  • uspace/lib/ieee80211/include/ieee80211_private.h

    r59fa7ab r1dcc0b9  
    4040#define LIBNET_IEEE80211_PRIVATE_H
    4141
     42#include <fibril_synch.h>
    4243#include <byteorder.h>
    4344#include <ddf/driver.h>
     
    4647#include <ieee80211/ieee80211.h>
    4748#include "ieee80211.h"
     49
     50/* Timeout in us for waiting to authentication/association response. */
     51#define AUTH_TIMEOUT 200000
     52
     53/* Timeout in us for waiting to finish 4-way handshake process. */
     54#define HANDSHAKE_TIMEOUT 3000000
     55
     56/* Max period to rerun scan. */
     57#define MAX_SCAN_SPAN_SEC 30
     58
     59/* Max time to keep scan result. */
     60#define MAX_KEEP_SCAN_SPAN_SEC 120
     61
     62/* Security bit in capability info field. */
     63#define CAP_SECURITY 0x10
     64
     65/* Protocol type used in EAPOL frames. */
     66#define ETH_TYPE_PAE 0x888E
     67
     68/* WPA OUI used in vendor specific IE. */
     69#define WPA_OUI 0x0050F201
     70
     71/* GTK OUI used in vendor specific IE. */
     72#define GTK_OUI 0x000FAC01
     73
     74/* Max PTK key length. */
     75#define MAX_PTK_LENGTH 64
     76
     77/* Max GTK key length. */
     78#define MAX_GTK_LENGTH 64
     79
     80/* KEK offset inside PTK. */
     81#define KEK_OFFSET 16
     82
     83/* TK offset inside PTK. */
     84#define TK_OFFSET 32
     85
     86/* Length of CCMP header we need to reserve. */
     87#define IEEE80211_CCMP_HEADER_LENGTH 8
     88
     89/*
     90 * Length of data to be encrypted by PRF function:
     91 * NONCE + SNONCE (2 * 32) + DEST_MAC + SOURCE_MAC (2 * ETH_ADDR)
     92 */
     93#define PRF_CRYPT_DATA_LENGTH 2*32 + 2*ETH_ADDR
     94
     95/** IEEE 802.11 PTK key length. */
     96typedef enum {
     97        IEEE80211_PTK_CCMP_LENGTH = 48,
     98        IEEE80211_PTK_TKIP_LENGTH = 64
     99} ieee80211_ptk_length_t;
     100
     101/** IEEE 802.11 GTK key length. */
     102typedef enum {
     103        IEEE80211_GTK_CCMP_LENGTH = 16,
     104        IEEE80211_GTK_TKIP_LENGTH = 32
     105} ieee80211_gtk_length_t;
    48106
    49107/** IEEE 802.11 frame types. */
     
    55113} ieee80211_frame_type_t;
    56114
    57 /** IEEE 802.11 frame subtypes. */
     115/** IEEE 802.11 management frame subtypes. */
    58116typedef enum {
    59117        IEEE80211_MGMT_ASSOC_REQ_FRAME = 0x00,
     
    64122        IEEE80211_MGMT_PROBE_RESP_FRAME = 0x50,
    65123        IEEE80211_MGMT_BEACON_FRAME = 0x80,
    66         IEEE80211_MGMT_DIASSOC_FRAME = 0xA0,
     124        IEEE80211_MGMT_DISASSOC_FRAME = 0xA0,
    67125        IEEE80211_MGMT_AUTH_FRAME = 0xB0,
    68126        IEEE80211_MGMT_DEAUTH_FRAME = 0xC0,
    69 } ieee80211_frame_subtype_t;
     127} ieee80211_frame_mgmt_subtype_t;
     128
     129/** IEEE 802.11 data frame subtypes. */
     130typedef enum {
     131        IEEE80211_DATA_DATA_FRAME = 0x0000,
     132        IEEE80211_DATA_QOS_FRAME = 0x0080
     133} ieee80211_frame_data_subtype_t;
    70134
    71135/** IEEE 802.11 frame control value masks. */
     
    73137        IEEE80211_FRAME_CTRL_FRAME_TYPE = 0x000C,
    74138        IEEE80211_FRAME_CTRL_FRAME_SUBTYPE = 0x00F0,
    75 } ieee80211_frame_control_mask_t;
     139        IEEE80211_FRAME_CTRL_PROTECTED = 0x4000
     140} ieee80211_frame_ctrl_mask_t;
     141
     142/** IEEE 802.11 frame control DS field values. */
     143typedef enum {
     144        IEEE80211_FRAME_CTRL_TODS = 0x0100,
     145        IEEE80211_FRAME_CTRL_FROMDS = 0x0200
     146} ieee80211_frame_ctrl_ds_t;
     147
     148/** IEEE 802.11 authentication cipher suites values. */
     149typedef enum {
     150        IEEE80211_AUTH_CIPHER_TKIP = 0x02,
     151        IEEE80211_AUTH_CIPHER_CCMP = 0x04
     152} ieee80211_auth_cipher_type_t;
     153
     154/** IEEE 802.11 AKM suites values. */
     155typedef enum {
     156        IEEE80211_AUTH_AKM_8021X = 0x01,
     157        IEEE80211_AUTH_AKM_PSK = 0x02
     158} ieee80211_auth_akm_type_t;
     159
     160typedef enum {
     161        IEEE80211_EAPOL_START = 0x1,
     162        IEEE80211_EAPOL_KEY = 0x3
     163} ieee80211_eapol_frame_type_t;
     164
     165typedef enum {
     166        IEEE80211_EAPOL_KEY_KEYINFO_KEYTYPE = 0x0008,
     167        IEEE80211_EAPOL_KEY_KEYINFO_INSTALL = 0x0040,
     168        IEEE80211_EAPOL_KEY_KEYINFO_ACK = 0x0080,
     169        IEEE80211_EAPOL_KEY_KEYINFO_MIC = 0x0100,
     170        IEEE80211_EAPOL_KEY_KEYINFO_SECURE = 0x0200,
     171        IEEE80211_EAPOL_KEY_KEYINFO_ENCDATA = 0x1000
     172} ieee80211_eapol_key_keyinfo_t;
    76173
    77174/** IEEE 802.11 information element types. */
     
    80177        IEEE80211_RATES_IE = 1,         /**< Supported data rates. */
    81178        IEEE80211_CHANNEL_IE = 3,       /**< Current channel number. */
    82         IEEE80211_EXT_RATES_IE = 50     /**< Extended data rates. */
     179        IEEE80211_CHALLENGE_IE = 16,    /**< Challenge text. */
     180        IEEE80211_RSN_IE = 48,          /**< RSN. */
     181        IEEE80211_EXT_RATES_IE = 50,    /**< Extended data rates. */
     182        IEEE80211_VENDOR_IE = 221       /**< Vendor specific IE. */
    83183} ieee80211_ie_type_t;
     184
     185/** IEEE 802.11 authentication phases. */
     186typedef enum {
     187        IEEE80211_AUTH_DISCONNECTED,
     188        IEEE80211_AUTH_AUTHENTICATED,
     189        IEEE80211_AUTH_ASSOCIATED
     190} ieee80211_auth_phase_t;
     191
     192/** Link with scan result info. */
     193typedef struct {
     194        link_t link;
     195        time_t last_beacon;
     196        ieee80211_scan_result_t scan_result;
     197        uint8_t rsn_copy[256];
     198        size_t rsn_copy_len;
     199} ieee80211_scan_result_link_t;
     200
     201/** List of scan results info. */
     202typedef struct {
     203        list_t list;
     204        time_t last_scan;
     205        fibril_mutex_t scan_mutex;
     206        size_t size;
     207} ieee80211_scan_result_list_t;
     208
     209/** BSSID info. */
     210typedef struct {
     211        uint16_t aid;
     212        char password[IEEE80211_WPA_MAX_PASSWORD_LENGTH];
     213        uint8_t ptk[MAX_PTK_LENGTH];
     214        uint8_t gtk[MAX_GTK_LENGTH];
     215        ieee80211_scan_result_link_t *res_link;
     216} ieee80211_bssid_info_t;
    84217
    85218/** IEEE 802.11 WiFi device structure. */
     
    103236        ieee80211_operating_mode_t current_op_mode;
    104237       
     238        /** Info about BSSID we are connected to. */
     239        ieee80211_bssid_info_t bssid_info;
     240       
     241        /**
     242         * Flag indicating that data traffic is encrypted by HW key
     243         * that is set up in device.
     244         */
     245        bool using_hw_key;
     246       
    105247        /** BSSIDs we listen to. */
    106248        nic_address_t bssid_mask;
    107249       
    108250        /** List of APs in neighborhood. */
    109         ieee80211_scan_results_t ap_list;
    110        
    111         /* TODO: Probably to be removed later - nic.open function is now
    112          * executed multiple times, have to find out reason and fix it.
    113          */
     251        ieee80211_scan_result_list_t ap_list;
     252       
     253        /** Current sequence number used in data frames. */
     254        uint16_t sequence_number;
     255       
     256        /** Current authentication phase. */
     257        ieee80211_auth_phase_t current_auth_phase;
     258       
     259        /** General purpose guard. */
     260        fibril_mutex_t gen_mutex;
     261       
     262        /** General purpose condition variable. */
     263        fibril_condvar_t gen_cond;
     264       
     265        /** Indicates whether device is fully initialized. */
     266        bool ready;
     267       
    114268        /** Indicates whether driver has already started. */
    115269        bool started;
    116270};
     271
     272/** IEEE 802.3 (ethernet) header. */
     273typedef struct {
     274        uint8_t dest_addr[ETH_ADDR];
     275        uint8_t src_addr[ETH_ADDR];
     276        uint16_t proto;                 /**< Big Endian value! */
     277} __attribute__((packed)) __attribute__ ((aligned(2)))
     278        eth_header_t;
    117279
    118280/** IEEE 802.11 management header structure. */
     
    124286        uint8_t bssid[ETH_ADDR];
    125287        uint16_t seq_ctrl;              /**< Little Endian value! */
    126 } __attribute__((packed)) __attribute__ ((aligned(2))) ieee80211_mgmt_header_t;
     288} __attribute__((packed)) __attribute__ ((aligned(2)))
     289        ieee80211_mgmt_header_t;
    127290
    128291/** IEEE 802.11 data header structure. */
     
    134297        uint8_t address3[ETH_ADDR];
    135298        uint16_t seq_ctrl;              /**< Little Endian value! */
    136         uint8_t address4[ETH_ADDR];
    137         uint16_t qos_ctrl;              /**< Little Endian value! */
    138 } __attribute__((packed)) __attribute__ ((aligned(2))) ieee80211_data_header_t;
     299} __attribute__((packed)) __attribute__ ((aligned(2)))
     300        ieee80211_data_header_t;
    139301
    140302/** IEEE 802.11 information element header. */
     
    142304        uint8_t element_id;
    143305        uint8_t length;
    144 } __attribute__((packed)) __attribute__ ((aligned(2))) ieee80211_ie_header_t;
     306} __attribute__((packed)) __attribute__ ((aligned(2)))
     307        ieee80211_ie_header_t;
    145308
    146309/** IEEE 802.11 authentication frame body. */
     
    149312        uint16_t auth_trans_no;         /**< Little Endian value! */
    150313        uint16_t status;                /**< Little Endian value! */
    151 } __attribute__((packed)) __attribute__ ((aligned(2))) ieee80211_auth_body_t;
     314} __attribute__((packed)) __attribute__ ((aligned(2)))
     315        ieee80211_auth_body_t;
     316
     317/** IEEE 802.11 deauthentication frame body. */
     318typedef struct {
     319        uint16_t reason;                /**< Little Endian value! */
     320} __attribute__((packed)) __attribute__ ((aligned(2)))
     321        ieee80211_deauth_body_t;
     322
     323/** IEEE 802.11 association request frame body. */
     324typedef struct {
     325        uint16_t capability;            /**< Little Endian value! */
     326        uint16_t listen_interval;       /**< Little Endian value! */
     327} __attribute__((packed)) __attribute__ ((aligned(2)))
     328        ieee80211_assoc_req_body_t;
     329
     330/** IEEE 802.11 association response frame body. */
     331typedef struct {
     332        uint16_t capability;            /**< Little Endian value! */
     333        uint16_t status;                /**< Little Endian value! */
     334        uint16_t aid;                   /**< Little Endian value! */
     335} __attribute__((packed)) __attribute__ ((aligned(2)))
     336        ieee80211_assoc_resp_body_t;
    152337
    153338/** IEEE 802.11 beacon frame body start. */
    154339typedef struct {
    155340        uint8_t timestamp[8];
    156         uint16_t beacon_interval;
    157         uint16_t capability;
    158 } __attribute__((packed)) __attribute__ ((aligned(2))) ieee80211_beacon_start_t;
    159 
    160 extern int ieee80211_probe_request(ieee80211_dev_t *ieee80211_dev);
    161 extern int ieee80211_probe_auth(ieee80211_dev_t *ieee80211_dev);
     341        uint16_t beacon_interval;       /**< Little Endian value! */
     342        uint16_t capability;            /**< Little Endian value! */
     343} __attribute__((packed)) __attribute__ ((aligned(2)))
     344        ieee80211_beacon_start_t;
     345
     346/** IEEE 802.11i EAPOL-Key frame format. */
     347typedef struct {
     348        uint8_t proto_version;
     349        uint8_t packet_type;
     350        uint16_t body_length;           /**< Big Endian value! */
     351        uint8_t descriptor_type;
     352        uint16_t key_info;              /**< Big Endian value! */
     353        uint16_t key_length;            /**< Big Endian value! */
     354        uint8_t key_replay_counter[8];
     355        uint8_t key_nonce[32];
     356        uint8_t eapol_key_iv[16];
     357        uint8_t key_rsc[8];
     358        uint8_t reserved[8];
     359        uint8_t key_mic[16];
     360        uint16_t key_data_length;       /**< Big Endian value! */
     361} __attribute__((packed)) ieee80211_eapol_key_frame_t;
     362
     363#define ieee80211_scan_result_list_foreach(results, iter) \
     364    list_foreach((results).list, link, ieee80211_scan_result_link_t, (iter))
     365
     366static inline void ieee80211_scan_result_list_init(
     367        ieee80211_scan_result_list_t *results)
     368{
     369        list_initialize(&results->list);
     370        fibril_mutex_initialize(&results->scan_mutex);
     371}
     372
     373static inline void ieee80211_scan_result_list_remove(
     374        ieee80211_scan_result_list_t *results,
     375        ieee80211_scan_result_link_t *result)
     376{
     377        list_remove(&result->link);
     378        results->size--;
     379}
     380
     381static inline void ieee80211_scan_result_list_append(
     382        ieee80211_scan_result_list_t *results,
     383        ieee80211_scan_result_link_t *result)
     384{
     385        list_append(&result->link, &results->list);
     386        results->size++;
     387}
     388
     389extern int ieee80211_probe_request(ieee80211_dev_t *ieee80211_dev,
     390        char *ssid);
     391extern int ieee80211_authenticate(ieee80211_dev_t *ieee80211_dev);
     392extern int ieee80211_associate(ieee80211_dev_t *ieee80211_dev,
     393        char *password);
     394extern int ieee80211_deauthenticate(ieee80211_dev_t *ieee80211_dev);
    162395
    163396#endif /* LIBN_IEEE80211_H */
  • uspace/lib/ieee80211/src/ieee80211.c

    r59fa7ab r1dcc0b9  
    3636 */
    3737
     38#include <stdio.h>
     39#include <crypto.h>
     40#include <str.h>
    3841#include <macros.h>
    3942#include <errno.h>
     
    4548#include <ops/ieee80211.h>
    4649
     50#define IEEE80211_DATA_RATES_SIZE 8
     51#define IEEE80211_EXT_DATA_RATES_SIZE 4
     52
     53/** Frame encapsulation used in IEEE 802.11. */
     54static const uint8_t rfc1042_header[] = {
     55        0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00
     56};
     57
    4758/** Broadcast MAC address used to spread probe request through channel. */
    4859static const uint8_t ieee80211_broadcast_mac_addr[] = {
     
    5061};
    5162
    52 /** IEEE 802.11 b/g supported data rates in units of 500 kb/s. */
    53 static const uint8_t ieee80211bg_data_rates[] = {
    54         2, 4, 11, 12, 18, 22, 24, 36
    55 };
    56 
    57 /** IEEE 802.11 b/g extended supported data rates in units of 500 kb/s.
    58  *
    59  *  These are defined separately, because probe request message can
    60  *  only handle up to 8 data rates in supported rates IE.
    61  */
    62 static const uint8_t ieee80211bg_ext_data_rates[] = {
    63         48, 72, 96, 108
    64 };
    65 
     63/**
     64 * Check data frame.
     65 *
     66 * @param frame_ctrl Frame control field in little endian (!).
     67 *
     68 * @return True if it is data frame, otherwise false.
     69 */
    6670inline bool ieee80211_is_data_frame(uint16_t frame_ctrl)
    6771{
     
    7276}
    7377
     78/**
     79 * Check management frame.
     80 *
     81 * @param frame_ctrl Frame control field in little endian (!).
     82 *
     83 * @return True if it is management frame, otherwise false.
     84 */
    7485inline bool ieee80211_is_mgmt_frame(uint16_t frame_ctrl)
    7586{
     
    8091}
    8192
     93/**
     94 * Check management beacon frame.
     95 *
     96 * @param frame_ctrl Frame control field in little endian (!).
     97 *
     98 * @return True if it is beacon frame, otherwise false.
     99 */
    82100inline bool ieee80211_is_beacon_frame(uint16_t frame_ctrl)
    83101{
     
    88106}
    89107
     108/**
     109 * Check management probe response frame.
     110 *
     111 * @param frame_ctrl Frame control field in little endian (!).
     112 *
     113 * @return True if it is probe resp frame, otherwise false.
     114 */
    90115inline bool ieee80211_is_probe_response_frame(uint16_t frame_ctrl)
    91116{
     
    97122
    98123/**
     124 * Check management authentication frame.
     125 *
     126 * @param frame_ctrl Frame control field in little endian (!).
     127 *
     128 * @return True if it is auth frame, otherwise false.
     129 */
     130inline bool ieee80211_is_auth_frame(uint16_t frame_ctrl)
     131{
     132        frame_ctrl = uint16_t_le2host(frame_ctrl);
     133       
     134        return (frame_ctrl & IEEE80211_FRAME_CTRL_FRAME_SUBTYPE)
     135                == IEEE80211_MGMT_AUTH_FRAME;
     136}
     137
     138/**
     139 * Check management association response frame.
     140 *
     141 * @param frame_ctrl Frame control field in little endian (!).
     142 *
     143 * @return True if it is assoc resp frame, otherwise false.
     144 */
     145inline bool ieee80211_is_assoc_response_frame(uint16_t frame_ctrl)
     146{
     147        frame_ctrl = uint16_t_le2host(frame_ctrl);
     148       
     149        return (frame_ctrl & IEEE80211_FRAME_CTRL_FRAME_SUBTYPE)
     150                == IEEE80211_MGMT_ASSOC_RESP_FRAME;
     151}
     152
     153/**
     154 * Check data frame "to distribution system" direction.
     155 *
     156 * @param frame_ctrl Frame control field in little endian (!).
     157 *
     158 * @return True if it is TODS frame, otherwise false.
     159 */
     160static inline bool ieee80211_is_tods_frame(uint16_t frame_ctrl)
     161{
     162        frame_ctrl = uint16_t_le2host(frame_ctrl);
     163       
     164        return (frame_ctrl & IEEE80211_FRAME_CTRL_TODS);
     165}
     166
     167/**
     168 * Check data frame "from distribution system" direction.
     169 *
     170 * @param frame_ctrl Frame control field in little endian (!).
     171 *
     172 * @return True if it is FROMDS frame, otherwise false.
     173 */
     174static inline bool ieee80211_is_fromds_frame(uint16_t frame_ctrl)
     175{
     176        frame_ctrl = uint16_t_le2host(frame_ctrl);
     177       
     178        return (frame_ctrl & IEEE80211_FRAME_CTRL_FROMDS);
     179}
     180
     181/**
     182 * Check if it is data frame containing payload data.
     183 *
     184 * @param frame_ctrl Frame control field in little endian (!).
     185 *
     186 * @return True if it has payload data, otherwise false.
     187 */
     188static inline bool ieee80211_has_data_frame(uint16_t frame_ctrl)
     189{
     190        frame_ctrl = uint16_t_le2host(frame_ctrl);
     191       
     192        return (frame_ctrl & (IEEE80211_FRAME_CTRL_FRAME_TYPE | 0x40))
     193                == IEEE80211_DATA_FRAME;
     194}
     195
     196/**
     197 * Check if it is encrypted frame.
     198 *
     199 * @param frame_ctrl Frame control field in little endian (!).
     200 *
     201 * @return True if the frame is encrypted, otherwise false.
     202 */
     203static inline bool ieee80211_is_encrypted_frame(uint16_t frame_ctrl)
     204{
     205        frame_ctrl = uint16_t_le2host(frame_ctrl);
     206       
     207        return (frame_ctrl & IEEE80211_FRAME_CTRL_PROTECTED) != 0;
     208}
     209
     210/**
     211 * Check if PAE packet is EAPOL-Key frame.
     212 *
     213 * @param key_frame Pointer to start of EAPOL frame.
     214 *
     215 * @return True if it is EAPOL-Key frame, otherwise false.
     216 */
     217static inline bool ieee80211_is_eapol_key_frame(ieee80211_eapol_key_frame_t
     218        *key_frame)
     219{
     220        return (key_frame->packet_type == IEEE80211_EAPOL_KEY);
     221}
     222
     223
     224/**
     225 * Generate packet sequence number.
     226 *
     227 * @param ieee80211_dev IEEE 802.11 device.
     228 *
     229 * @return True if it has payload data, otherwise false.
     230 */
     231static uint16_t ieee80211_get_sequence_number(ieee80211_dev_t *ieee80211_dev)
     232{
     233        uint16_t ret_val = ieee80211_dev->sequence_number;
     234        ieee80211_dev->sequence_number += (1 << 4);
     235        return ret_val;
     236}
     237
     238/**
    99239 * Get driver-specific structure for IEEE 802.11 device.
    100240 *
     
    139279 * @return Current IEEE 802.11 operating mode.
    140280 */
    141 ieee80211_operating_mode_t ieee80211_query_current_op_mode(ieee80211_dev_t* ieee80211_dev)
     281ieee80211_operating_mode_t ieee80211_query_current_op_mode(ieee80211_dev_t*
     282        ieee80211_dev)
    142283{
    143284        return ieee80211_dev->current_op_mode;
     
    154295{
    155296        return ieee80211_dev->current_freq;
     297}
     298
     299/**
     300 * Query BSSID the device is connected to.
     301 *
     302 * @param ieee80211_dev IEEE 802.11 device.
     303 * @param bssid Pointer to structure where should be stored BSSID.
     304 */
     305void ieee80211_query_bssid(ieee80211_dev_t* ieee80211_dev,
     306        nic_address_t *bssid)
     307{
     308        if(bssid) {
     309                ieee80211_scan_result_t *auth_data =
     310                        &ieee80211_dev->bssid_info.res_link->scan_result;
     311               
     312                memcpy(bssid, (void *)&auth_data->bssid, sizeof(nic_address_t));
     313        }
     314}
     315
     316/**
     317 * Get AID of network we are connected to.
     318 *
     319 * @param ieee80211_dev IEEE 802.11 device.
     320 *
     321 * @return AID.
     322 */
     323uint16_t ieee80211_get_aid(ieee80211_dev_t* ieee80211_dev)
     324{
     325        return ieee80211_dev->bssid_info.aid;
     326}
     327
     328/**
     329 * Get security suite used for HW encryption.
     330 *
     331 * @param ieee80211_dev IEEE 802.11 device.
     332 *
     333 * @return Security suite indicator.
     334 */
     335int ieee80211_get_security_suite(ieee80211_dev_t* ieee80211_dev)
     336{
     337        ieee80211_scan_result_link_t *auth_link =
     338                ieee80211_dev->bssid_info.res_link;
     339       
     340        return auth_link->scan_result.security.pair_alg;
     341}
     342
     343/**
     344 * Check if IEEE 802.11 device is connected to network.
     345 *
     346 * @param ieee80211_dev IEEE 802.11 device.
     347 *
     348 * @return True if device is connected to network, otherwise false.
     349 */
     350bool ieee80211_is_connected(ieee80211_dev_t* ieee80211_dev)
     351{
     352        return ieee80211_dev->current_auth_phase == IEEE80211_AUTH_ASSOCIATED;
    156353}
    157354
     
    178375{
    179376        ieee80211_dev->current_freq = freq;
     377}
     378
     379/**
     380 * Check if IEEE 802.11 device is ready (fully initialized).
     381 *
     382 * @param ieee80211_dev IEEE 802.11 device.
     383 *
     384 * @return True if device is ready to work, otherwise false.
     385 */
     386bool ieee80211_is_ready(ieee80211_dev_t* ieee80211_dev)
     387{
     388        fibril_mutex_lock(&ieee80211_dev->gen_mutex);
     389        bool ready_state = ieee80211_dev->ready;
     390        fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
     391       
     392        return ready_state;
     393}
     394
     395/**
     396 * Set IEEE 802.11 device to ready state.
     397 *
     398 * @param ieee80211_dev IEEE 802.11 device.
     399 * @param ready Ready state to be set.
     400 */
     401void ieee80211_set_ready(ieee80211_dev_t* ieee80211_dev, bool ready)
     402{
     403        fibril_mutex_lock(&ieee80211_dev->gen_mutex);
     404        ieee80211_dev->ready = ready;
     405        fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
     406}
     407
     408extern bool ieee80211_query_using_key(ieee80211_dev_t* ieee80211_dev)
     409{
     410        return ieee80211_dev->using_hw_key;
     411}
     412
     413void ieee80211_setup_key_confirm(ieee80211_dev_t* ieee80211_dev,
     414        bool using_key)
     415{
     416        ieee80211_dev->using_hw_key = using_key;
    180417}
    181418
     
    209446}
    210447
    211 /** 
     448/**
    212449 * Send frame handler.
     450 *
     451 * @param nic Pointer to NIC device.
     452 * @param data Data buffer.
     453 * @param size Data buffer size.
    213454 */
    214455static void ieee80211_send_frame(nic_t *nic, void *data, size_t size)
     
    217458                nic_get_specific(nic);
    218459       
    219         ieee80211_dev->ops->tx_handler(ieee80211_dev, data, size);
     460        if(!ieee80211_is_connected(ieee80211_dev)) {
     461                return;
     462        }
     463       
     464        ieee80211_scan_result_t *auth_data =
     465                        &ieee80211_dev->bssid_info.res_link->scan_result;
     466       
     467        /* We drop part of IEEE 802.3 ethernet header. */
     468        size_t drop_bytes = sizeof(eth_header_t) - 2;
     469       
     470        size_t complete_size = (size - drop_bytes) +
     471                sizeof(ieee80211_data_header_t) +
     472                ARRAY_SIZE(rfc1042_header);
     473       
     474        /* Init crypto data. */
     475        size_t add_size = 0;
     476        uint16_t crypto = 0;
     477        uint8_t add_data[8];
     478        memset(add_data, 0, 8);
     479       
     480        if(ieee80211_dev->using_hw_key) {
     481                int sec_suite = auth_data->security.pair_alg;
     482                switch(sec_suite) {
     483                        case IEEE80211_SECURITY_SUITE_CCMP:
     484                                add_size = IEEE80211_CCMP_HEADER_LENGTH;
     485                                add_data[3] = 0x20;
     486                                break;
     487                        default:
     488                                break;
     489                }
     490
     491                crypto = uint16_t_le2host(IEEE80211_FRAME_CTRL_PROTECTED);
     492        }
     493       
     494        complete_size += add_size;
     495       
     496        void *complete_buffer = malloc(complete_size);
     497        memset(complete_buffer, 0, complete_size);
     498       
     499        if(add_size) {
     500                memcpy(complete_buffer + sizeof(ieee80211_data_header_t),
     501                        add_data, add_size);
     502        }
     503       
     504        memcpy(complete_buffer + sizeof(ieee80211_data_header_t) + add_size,
     505                rfc1042_header,
     506                ARRAY_SIZE(rfc1042_header));
     507       
     508        memcpy(complete_buffer +
     509                sizeof(ieee80211_data_header_t) +
     510                ARRAY_SIZE(rfc1042_header) + add_size,
     511                data + drop_bytes, size - drop_bytes);
     512       
     513        ieee80211_data_header_t *data_header =
     514                (ieee80211_data_header_t *) complete_buffer;
     515        data_header->frame_ctrl =
     516                uint16_t_le2host(IEEE80211_DATA_FRAME) |
     517                uint16_t_le2host(IEEE80211_DATA_DATA_FRAME) |
     518                uint16_t_le2host(IEEE80211_FRAME_CTRL_TODS) |
     519                crypto;
     520        data_header->seq_ctrl = ieee80211_get_sequence_number(ieee80211_dev);
     521       
     522        /* BSSID, SA, DA. */
     523        memcpy(data_header->address1, auth_data->bssid.address, ETH_ADDR);
     524        memcpy(data_header->address2, data + ETH_ADDR, ETH_ADDR);
     525        memcpy(data_header->address3, data, ETH_ADDR);
     526       
     527        ieee80211_dev->ops->tx_handler(ieee80211_dev,
     528                complete_buffer,
     529                complete_size);
     530       
     531        free(complete_buffer);
    220532}
    221533
     
    246558                        ieee80211_ops->set_freq = ieee80211_set_freq_impl;
    247559               
     560                if(!ieee80211_ops->bssid_change)
     561                        ieee80211_ops->bssid_change =
     562                                ieee80211_bssid_change_impl;
     563               
     564                if(!ieee80211_ops->key_config)
     565                        ieee80211_ops->key_config = ieee80211_key_config_impl;
     566               
    248567                if(!ieee80211_ops->scan)
    249568                        ieee80211_ops->scan = ieee80211_scan_impl;
     
    257576                if(nic_dev_ops)
    258577                        if (!nic_dev_ops->interfaces[IEEE80211_DEV_IFACE])
    259                                 nic_dev_ops->interfaces[IEEE80211_DEV_IFACE] = ieee80211_iface;
     578                                nic_dev_ops->interfaces[IEEE80211_DEV_IFACE] =
     579                                        ieee80211_iface;
    260580               
    261581                if(!ieee80211_iface->get_scan_results)
    262                         ieee80211_iface->get_scan_results = ieee80211_get_scan_results_impl;
     582                        ieee80211_iface->get_scan_results =
     583                                ieee80211_get_scan_results_impl;
    263584               
    264585                if(!ieee80211_iface->connect)
    265586                        ieee80211_iface->connect = ieee80211_connect_impl;
     587               
     588                if(!ieee80211_iface->disconnect)
     589                        ieee80211_iface->disconnect = ieee80211_disconnect_impl;
    266590        } else {
    267591                return EINVAL;
     
    304628        ieee80211_dev->ddf_dev = ddf_dev;
    305629        ieee80211_dev->started = false;
     630        ieee80211_dev->ready = false;
     631        ieee80211_dev->using_hw_key = false;
    306632        ieee80211_dev->current_op_mode = IEEE80211_OPMODE_STATION;
     633        ieee80211_dev->current_auth_phase = IEEE80211_AUTH_DISCONNECTED;
    307634        memcpy(ieee80211_dev->bssid_mask.address, ieee80211_broadcast_mac_addr,
    308635                ETH_ADDR);
     636       
     637        ieee80211_scan_result_list_init(&ieee80211_dev->ap_list);
     638       
     639        fibril_mutex_initialize(&ieee80211_dev->gen_mutex);
     640        fibril_condvar_initialize(&ieee80211_dev->gen_cond);
    309641       
    310642        /* Bind NIC to device */
     
    373705}
    374706
     707/**
     708 * Convert frequency value to channel number.
     709 *
     710 * @param freq IEEE 802.11 operating frequency.
     711 *
     712 * @return Operating channel number.
     713 */
    375714static uint8_t ieee80211_freq_to_channel(uint16_t freq)
    376715{
     
    378717}
    379718
     719static void ieee80211_prepare_ie_header(void **ie_header,
     720        uint8_t id, uint8_t length, void *data)
     721{
     722        ieee80211_ie_header_t *header =
     723                (ieee80211_ie_header_t *) *ie_header;
     724       
     725        header->element_id = id;
     726        header->length = length;
     727       
     728        memcpy(*ie_header + sizeof(ieee80211_ie_header_t), data, length);
     729       
     730        *ie_header = (void *) ((void *) header +
     731                sizeof(ieee80211_ie_header_t) + length);
     732}
     733
    380734/**
    381735 * Probe request implementation.
    382736 *
    383737 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
     738 * @param ssid Probing SSID or NULL if broadcast.
    384739 *
    385740 * @return EOK if succeed, negative error code otherwise.
    386741 */
    387 int ieee80211_probe_request(ieee80211_dev_t *ieee80211_dev)
     742int ieee80211_probe_request(ieee80211_dev_t *ieee80211_dev, char *ssid)
    388743{
    389744        nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
     
    391746        nic_query_address(nic, &nic_address);
    392747       
    393         size_t data_rates_size = ARRAY_SIZE(ieee80211bg_data_rates);
    394         size_t ext_data_rates_size = ARRAY_SIZE(ieee80211bg_ext_data_rates);
    395        
    396         /* 3 headers - (rates, ext rates, current channel) and their data
    397          * lengths + pad.
     748        size_t ssid_data_size = (ssid != NULL) ? str_size(ssid) : 0;
     749        size_t channel_data_size = 1;
     750       
     751        uint8_t channel =
     752                ieee80211_freq_to_channel(ieee80211_dev->current_freq);
     753       
     754        /* 4 headers - (ssid, rates, ext rates, current channel) and their data
     755         * lengths.
    398756         */
    399757        size_t payload_size =
    400                 sizeof(ieee80211_ie_header_t) * 3 +
    401                 data_rates_size + ext_data_rates_size + sizeof(uint8_t) + 2;
     758                sizeof(ieee80211_ie_header_t) * 4 +
     759                ssid_data_size +
     760                IEEE80211_DATA_RATES_SIZE + IEEE80211_EXT_DATA_RATES_SIZE +
     761                channel_data_size;
    402762       
    403763        size_t buffer_size = sizeof(ieee80211_mgmt_header_t) + payload_size;
     
    415775        memcpy(mgmt_header->src_addr, nic_address.address, ETH_ADDR);
    416776        memcpy(mgmt_header->bssid, ieee80211_broadcast_mac_addr, ETH_ADDR);
    417        
    418         /* Jump to payload -> header + padding. */
    419         ieee80211_ie_header_t *rates_ie_header = (ieee80211_ie_header_t *)
    420                 ((void *)buffer + sizeof(ieee80211_mgmt_header_t) + 2);
    421         rates_ie_header->element_id = IEEE80211_RATES_IE;
    422         rates_ie_header->length = data_rates_size;
    423         memcpy(rates_ie_header + sizeof(ieee80211_ie_header_t),
    424                 ieee80211bg_data_rates,
    425                 data_rates_size);
    426        
    427         ieee80211_ie_header_t *ext_rates_ie_header = (ieee80211_ie_header_t *)
    428                 ((void *)rates_ie_header + sizeof(ieee80211_ie_header_t) +
    429                 data_rates_size);
    430         ext_rates_ie_header->element_id = IEEE80211_EXT_RATES_IE;
    431         ext_rates_ie_header->length = ext_data_rates_size;
    432         memcpy(ext_rates_ie_header + sizeof(ieee80211_ie_header_t),
    433                 ieee80211bg_ext_data_rates,
    434                 ext_data_rates_size);
    435        
    436         ieee80211_ie_header_t *chan_ie_header = (ieee80211_ie_header_t *)
    437                 ((void *)ext_rates_ie_header + sizeof(ieee80211_ie_header_t) +
    438                 ext_data_rates_size);
    439         chan_ie_header->element_id = IEEE80211_CHANNEL_IE;
    440         chan_ie_header->length = 1;
    441         uint8_t *it = (uint8_t *) ((void *)chan_ie_header +
    442                 sizeof(ieee80211_ie_header_t));
    443         *it = ieee80211_freq_to_channel(ieee80211_dev->current_freq);
     777        mgmt_header->seq_ctrl =
     778                host2uint16_t_le(ieee80211_get_sequence_number(ieee80211_dev));
     779       
     780        /* Jump to payload. */
     781        void *it = (void *) buffer + sizeof(ieee80211_mgmt_header_t);
     782        ieee80211_prepare_ie_header(&it, IEEE80211_SSID_IE, ssid_data_size,
     783                (void *) ssid);
     784        ieee80211_prepare_ie_header(&it, IEEE80211_RATES_IE,
     785                IEEE80211_DATA_RATES_SIZE,
     786                (void *) &ieee80211bg_data_rates);
     787        ieee80211_prepare_ie_header(&it, IEEE80211_EXT_RATES_IE,
     788                IEEE80211_EXT_DATA_RATES_SIZE,
     789                (void *) &ieee80211bg_data_rates[IEEE80211_DATA_RATES_SIZE]);
     790        ieee80211_prepare_ie_header(&it, IEEE80211_CHANNEL_IE,
     791                channel_data_size, (void *) &channel);
    444792       
    445793        ieee80211_dev->ops->tx_handler(ieee80211_dev, buffer, buffer_size);
     
    451799
    452800/**
    453  * Probe authentication implementation.
     801 * IEEE 802.11 authentication implementation.
    454802 *
    455803 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
     
    457805 * @return EOK if succeed, negative error code otherwise.
    458806 */
    459 int ieee80211_probe_auth(ieee80211_dev_t *ieee80211_dev)
    460 {
    461         uint8_t test_bssid[] = {0x14, 0xF6, 0x5A, 0xAF, 0x5E, 0xB7};
    462        
     807int ieee80211_authenticate(ieee80211_dev_t *ieee80211_dev)
     808{
    463809        nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
    464810        nic_address_t nic_address;
    465811        nic_query_address(nic, &nic_address);
    466812       
     813        ieee80211_scan_result_t *auth_data =
     814                &ieee80211_dev->bssid_info.res_link->scan_result;
     815       
    467816        size_t buffer_size = sizeof(ieee80211_mgmt_header_t) +
    468817                sizeof(ieee80211_auth_body_t);
     818       
    469819        void *buffer = malloc(buffer_size);
    470820        memset(buffer, 0, buffer_size);
     
    477827                IEEE80211_MGMT_AUTH_FRAME
    478828                );
    479         memcpy(mgmt_header->dest_addr, test_bssid, ETH_ADDR);
     829        memcpy(mgmt_header->dest_addr, auth_data->bssid.address, ETH_ADDR);
    480830        memcpy(mgmt_header->src_addr, nic_address.address, ETH_ADDR);
    481         memcpy(mgmt_header->bssid, test_bssid, ETH_ADDR);
     831        memcpy(mgmt_header->bssid, auth_data->bssid.address, ETH_ADDR);
    482832       
    483833        ieee80211_auth_body_t *auth_body =
     
    485835                (buffer + sizeof(ieee80211_mgmt_header_t));
    486836        auth_body->auth_alg = host2uint16_t_le(0);
    487         auth_body->auth_trans_no = host2uint16_t_le(0);
     837        auth_body->auth_trans_no = host2uint16_t_le(1);
    488838       
    489839        ieee80211_dev->ops->tx_handler(ieee80211_dev, buffer, buffer_size);
     
    494844}
    495845
     846/**
     847 * IEEE 802.11 association implementation.
     848 *
     849 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
     850 * @param password Passphrase to be used in encrypted communication or NULL
     851 * for open networks.
     852 *
     853 * @return EOK if succeed, negative error code otherwise.
     854 */
     855int ieee80211_associate(ieee80211_dev_t *ieee80211_dev, char *password)
     856{
     857        nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
     858        nic_address_t nic_address;
     859        nic_query_address(nic, &nic_address);
     860       
     861        ieee80211_scan_result_link_t *auth_link =
     862                ieee80211_dev->bssid_info.res_link;
     863       
     864        ieee80211_scan_result_t *auth_data = &auth_link->scan_result;
     865       
     866        size_t ssid_data_size = str_size(auth_data->ssid);
     867       
     868        size_t payload_size =
     869                sizeof(ieee80211_ie_header_t) * 3 +
     870                ssid_data_size +
     871                IEEE80211_DATA_RATES_SIZE +
     872                IEEE80211_EXT_DATA_RATES_SIZE;
     873       
     874        size_t buffer_size =
     875                sizeof(ieee80211_mgmt_header_t) +
     876                sizeof(ieee80211_assoc_req_body_t) +
     877                payload_size;
     878       
     879        if(auth_data->security.type == IEEE80211_SECURITY_WPA2) {
     880                buffer_size += auth_link->rsn_copy_len;
     881        }
     882       
     883        void *buffer = malloc(buffer_size);
     884        memset(buffer, 0, buffer_size);
     885       
     886        ieee80211_mgmt_header_t *mgmt_header =
     887                (ieee80211_mgmt_header_t *) buffer;
     888       
     889        mgmt_header->frame_ctrl = host2uint16_t_le(
     890                IEEE80211_MGMT_FRAME |
     891                IEEE80211_MGMT_ASSOC_REQ_FRAME
     892                );
     893        memcpy(mgmt_header->dest_addr, auth_data->bssid.address, ETH_ADDR);
     894        memcpy(mgmt_header->src_addr, nic_address.address, ETH_ADDR);
     895        memcpy(mgmt_header->bssid, auth_data->bssid.address, ETH_ADDR);
     896       
     897        ieee80211_assoc_req_body_t *assoc_body =
     898                (ieee80211_assoc_req_body_t *)
     899                (buffer + sizeof(ieee80211_mgmt_header_t));
     900        assoc_body->listen_interval = host2uint16_t_le(1);
     901       
     902        /* Jump to payload. */
     903        void *it = buffer + sizeof(ieee80211_mgmt_header_t) +
     904                sizeof(ieee80211_assoc_req_body_t);
     905        ieee80211_prepare_ie_header(&it, IEEE80211_SSID_IE,
     906                ssid_data_size, (void *) auth_data->ssid);
     907        ieee80211_prepare_ie_header(&it, IEEE80211_RATES_IE,
     908                IEEE80211_DATA_RATES_SIZE,
     909                (void *) &ieee80211bg_data_rates);
     910        ieee80211_prepare_ie_header(&it, IEEE80211_EXT_RATES_IE,
     911                IEEE80211_EXT_DATA_RATES_SIZE,
     912                (void *) &ieee80211bg_data_rates[IEEE80211_DATA_RATES_SIZE]);
     913       
     914        if(auth_data->security.type != IEEE80211_SECURITY_OPEN) {
     915                assoc_body->capability |= host2uint16_t_le(CAP_SECURITY);
     916        }
     917       
     918        if(auth_data->security.type == IEEE80211_SECURITY_WPA2) {
     919                memcpy(it, auth_link->rsn_copy, auth_link->rsn_copy_len);
     920        }
     921       
     922        ieee80211_dev->ops->tx_handler(ieee80211_dev, buffer, buffer_size);
     923       
     924        /*
     925         * Save password and SSID to be used in eventual authentication
     926         * handshake.
     927         */
     928        memcpy(ieee80211_dev->bssid_info.password, password,
     929                str_size(password));
     930       
     931        free(buffer);
     932       
     933        return EOK;
     934}
     935
     936/**
     937 * IEEE 802.11 deauthentication implementation.
     938 *
     939 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
     940 *
     941 * @return EOK if succeed, negative error code otherwise.
     942 */
     943int ieee80211_deauthenticate(ieee80211_dev_t *ieee80211_dev)
     944{
     945        ieee80211_scan_result_t *auth_data =
     946                &ieee80211_dev->bssid_info.res_link->scan_result;
     947       
     948        ieee80211_dev->current_auth_phase = IEEE80211_AUTH_DISCONNECTED;
     949        ieee80211_dev->bssid_info.aid = (uint16_t) -1;
     950        memcpy(auth_data->bssid.address, ieee80211_broadcast_mac_addr,
     951                ETH_ADDR);
     952       
     953        nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
     954        nic_address_t nic_address;
     955        nic_query_address(nic, &nic_address);
     956       
     957        size_t buffer_size = sizeof(ieee80211_mgmt_header_t) +
     958                sizeof(ieee80211_deauth_body_t);
     959        void *buffer = malloc(buffer_size);
     960        memset(buffer, 0, buffer_size);
     961       
     962        ieee80211_mgmt_header_t *mgmt_header =
     963                (ieee80211_mgmt_header_t *) buffer;
     964       
     965        mgmt_header->frame_ctrl = host2uint16_t_le(
     966                IEEE80211_MGMT_FRAME |
     967                IEEE80211_MGMT_DEAUTH_FRAME
     968                );
     969        memcpy(mgmt_header->dest_addr, auth_data->bssid.address, ETH_ADDR);
     970        memcpy(mgmt_header->src_addr, nic_address.address, ETH_ADDR);
     971        memcpy(mgmt_header->bssid, auth_data->bssid.address, ETH_ADDR);
     972       
     973        ieee80211_dev->ops->tx_handler(ieee80211_dev, buffer, buffer_size);
     974       
     975        free(buffer);
     976       
     977        ieee80211_dev->ops->bssid_change(ieee80211_dev);
     978       
     979        return EOK;
     980}
     981
     982static void ieee80211_process_auth_info(ieee80211_scan_result_link_t *ap_data,
     983        void *buffer)
     984{
     985        uint8_t *it = (uint8_t *) buffer;
     986       
     987        uint16_t *version = (uint16_t *) it;
     988        if(uint16_t_le2host(*version) != 0x1) {
     989                ap_data->scan_result.security.type = -1;
     990                return;
     991        }
     992       
     993        it += sizeof(uint16_t);
     994       
     995        uint32_t group_cipher = *(it+3);
     996        switch(group_cipher) {
     997                case IEEE80211_AUTH_CIPHER_TKIP:
     998                        ap_data->scan_result.security.group_alg =
     999                                IEEE80211_SECURITY_SUITE_TKIP;
     1000                        break;
     1001                case IEEE80211_AUTH_CIPHER_CCMP:
     1002                        ap_data->scan_result.security.group_alg =
     1003                                IEEE80211_SECURITY_SUITE_CCMP;
     1004                        break;
     1005                default:
     1006                        ap_data->scan_result.security.group_alg = -1;
     1007        }
     1008       
     1009        it += 4*sizeof(uint8_t);
     1010       
     1011        uint16_t *pairwise_count = (uint16_t *) it;
     1012        uint32_t pairwise_cipher = *(it+sizeof(uint16_t)+3);
     1013        switch(pairwise_cipher) {
     1014                case IEEE80211_AUTH_CIPHER_TKIP:
     1015                        ap_data->scan_result.security.pair_alg =
     1016                                IEEE80211_SECURITY_SUITE_TKIP;
     1017                        break;
     1018                case IEEE80211_AUTH_CIPHER_CCMP:
     1019                        ap_data->scan_result.security.pair_alg =
     1020                                IEEE80211_SECURITY_SUITE_CCMP;
     1021                        break;
     1022                default:
     1023                        ap_data->scan_result.security.pair_alg = -1;
     1024        }
     1025       
     1026        it += 2*sizeof(uint16_t) +
     1027                uint16_t_le2host(*pairwise_count)*sizeof(uint32_t);
     1028       
     1029        uint32_t auth_suite = *(it+3);
     1030        switch(auth_suite) {
     1031                case IEEE80211_AUTH_AKM_PSK:
     1032                        ap_data->scan_result.security.auth =
     1033                                IEEE80211_SECURITY_AUTH_PSK;
     1034                        break;
     1035                case IEEE80211_AUTH_AKM_8021X:
     1036                        ap_data->scan_result.security.auth =
     1037                                IEEE80211_SECURITY_AUTH_8021X;
     1038                        break;
     1039                default:
     1040                        ap_data->scan_result.security.auth = -1;
     1041        }
     1042}
     1043
     1044static uint32_t uint32_from_uint8_seq(uint8_t *seq)
     1045{
     1046        return (*seq << 24) + (*(seq+1) << 16) + (*(seq+2) << 8) + *(seq+3);
     1047}
     1048
     1049static uint8_t *ieee80211_process_ies(ieee80211_dev_t *ieee80211_dev,
     1050        ieee80211_scan_result_link_t *ap_data, void *buffer, size_t buffer_size)
     1051{
     1052        void *it = buffer;
     1053        while((it + sizeof(ieee80211_ie_header_t)) < buffer + buffer_size) {
     1054                ieee80211_ie_header_t *ie_header =
     1055                        (ieee80211_ie_header_t *) it;
     1056                uint8_t *channel;
     1057                switch(ie_header->element_id) {
     1058                        case IEEE80211_CHANNEL_IE:
     1059                                channel = (uint8_t *)
     1060                                        (it + sizeof(ieee80211_ie_header_t));
     1061                                ap_data->scan_result.channel = *channel;
     1062                                break;
     1063                        case IEEE80211_RSN_IE:
     1064                                if(!ap_data)
     1065                                        break;
     1066                                ap_data->scan_result.security.type =
     1067                                        IEEE80211_SECURITY_WPA2;
     1068                                ieee80211_process_auth_info(ap_data,
     1069                                        it + sizeof(ieee80211_ie_header_t));
     1070                                ap_data->rsn_copy_len = ie_header->length +
     1071                                        sizeof(ieee80211_ie_header_t);
     1072                                memcpy(ap_data->rsn_copy,
     1073                                        it,
     1074                                        ap_data->rsn_copy_len);
     1075                                break;
     1076                        case IEEE80211_VENDOR_IE:
     1077                                if(uint32_from_uint8_seq(it +
     1078                                        sizeof(ieee80211_ie_header_t)) ==
     1079                                        WPA_OUI) {
     1080                                        if(ap_data->scan_result.security.type ==
     1081                                                IEEE80211_SECURITY_WPA2) {
     1082                                                break;
     1083                                        }
     1084                                        ap_data->scan_result.security.type =
     1085                                                IEEE80211_SECURITY_WPA;
     1086                                        ieee80211_process_auth_info(ap_data,
     1087                                                it +
     1088                                                sizeof(ieee80211_ie_header_t) +
     1089                                                sizeof(uint32_t));
     1090                                } else if(uint32_from_uint8_seq(it +
     1091                                        sizeof(ieee80211_ie_header_t)) ==
     1092                                        GTK_OUI) {
     1093                                        return it +
     1094                                                sizeof(ieee80211_ie_header_t) +
     1095                                                sizeof(uint32_t) + 2;
     1096                                }
     1097                }
     1098                it += sizeof(ieee80211_ie_header_t) + ie_header->length;
     1099        }
     1100       
     1101        return NULL;
     1102}
     1103
    4961104/**
    4971105 * Process probe response and store results.
    4981106 *
    4991107 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
     1108 * @param mgmt_header Pointer to start of management frame header.
    5001109 *
    5011110 * @return EOK if succeed, negative error code otherwise.
    5021111 */
    5031112static int ieee80211_process_probe_response(ieee80211_dev_t *ieee80211_dev,
     1113        ieee80211_mgmt_header_t *mgmt_header, size_t buffer_size)
     1114{
     1115        ieee80211_beacon_start_t *beacon_body = (ieee80211_beacon_start_t *)
     1116                ((void *)mgmt_header + sizeof(ieee80211_mgmt_header_t));
     1117       
     1118        ieee80211_ie_header_t *ssid_ie_header = (ieee80211_ie_header_t *)
     1119                ((void *)beacon_body + sizeof(ieee80211_beacon_start_t));
     1120       
     1121        /* Not empty SSID. */
     1122        if(ssid_ie_header->length > 0) {
     1123                fibril_mutex_t *scan_mutex = &ieee80211_dev->ap_list.scan_mutex;
     1124               
     1125                fibril_mutex_lock(scan_mutex);
     1126               
     1127                ieee80211_scan_result_list_t *result_list =
     1128                        &ieee80211_dev->ap_list;
     1129               
     1130                uint8_t *ssid_start = (uint8_t *) ((void *)ssid_ie_header +
     1131                        sizeof(ieee80211_ie_header_t));
     1132                char ssid[IEEE80211_MAX_SSID_LENGTH];
     1133                memcpy(ssid, ssid_start, ssid_ie_header->length);
     1134                ssid[ssid_ie_header->length] = '\0';
     1135               
     1136                /* Check whether SSID is already in results. */
     1137                ieee80211_scan_result_list_foreach(*result_list, result) {
     1138                        if(!str_cmp(ssid, result->scan_result.ssid)) {
     1139                                result->last_beacon = time(NULL);
     1140                                fibril_mutex_unlock(scan_mutex);
     1141                                return EOK;
     1142                        }
     1143                }
     1144               
     1145                /* Results are full. */
     1146                if(result_list->size == IEEE80211_MAX_RESULTS_LENGTH - 1) {
     1147                        fibril_mutex_unlock(scan_mutex);
     1148                        return EOK;
     1149                }
     1150               
     1151                ieee80211_scan_result_link_t *ap_data =
     1152                        malloc(sizeof(ieee80211_scan_result_link_t));
     1153                memset(ap_data, 0, sizeof(ieee80211_scan_result_link_t));
     1154                link_initialize(&ap_data->link);
     1155               
     1156                memcpy(ap_data->scan_result.bssid.address,
     1157                        mgmt_header->bssid, ETH_ADDR);
     1158                memcpy(ap_data->scan_result.ssid, ssid,
     1159                        ssid_ie_header->length + 1);
     1160               
     1161                if(uint16_t_le2host(beacon_body->capability) & CAP_SECURITY) {
     1162                        ap_data->scan_result.security.type =
     1163                                IEEE80211_SECURITY_WEP;
     1164                } else {
     1165                        ap_data->scan_result.security.type =
     1166                                IEEE80211_SECURITY_OPEN;
     1167                        ap_data->scan_result.security.auth = -1;
     1168                        ap_data->scan_result.security.pair_alg = -1;
     1169                        ap_data->scan_result.security.group_alg = -1;
     1170                }
     1171               
     1172                void *rest_ies_start = ssid_start + ssid_ie_header->length;
     1173                size_t rest_buffer_size =
     1174                        buffer_size -
     1175                        sizeof(ieee80211_mgmt_header_t) -
     1176                        sizeof(ieee80211_beacon_start_t) -
     1177                        sizeof(ieee80211_ie_header_t) -
     1178                        ssid_ie_header->length;
     1179               
     1180                ieee80211_process_ies(ieee80211_dev, ap_data, rest_ies_start,
     1181                        rest_buffer_size);
     1182               
     1183                ap_data->last_beacon = time(NULL);
     1184               
     1185                ieee80211_scan_result_list_append(result_list, ap_data);
     1186               
     1187                fibril_mutex_unlock(scan_mutex);
     1188        }
     1189       
     1190        return EOK;
     1191}
     1192
     1193/**
     1194 * Process authentication response.
     1195 *
     1196 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
     1197 * @param mgmt_header Pointer to start of management frame header.
     1198 *
     1199 * @return EOK if succeed, negative error code otherwise.
     1200 */
     1201static int ieee80211_process_auth_response(ieee80211_dev_t *ieee80211_dev,
    5041202        ieee80211_mgmt_header_t *mgmt_header)
    5051203{
    506         ieee80211_ie_header_t *ssid_ie_header = (ieee80211_ie_header_t *)
    507                 ((void *)mgmt_header + sizeof(ieee80211_mgmt_header_t) +
    508                 sizeof(ieee80211_beacon_start_t));
    509        
    510         if(ssid_ie_header->length > 0) {
    511                 uint8_t *results_length = &ieee80211_dev->ap_list.length;
    512                
    513                 ieee80211_scan_result_t *ap_data =
    514                         &ieee80211_dev->ap_list.results[(*results_length)++];
    515                
    516                 memset(ap_data, 0, sizeof(ieee80211_scan_result_t));
    517                
    518                 uint8_t *ssid_start = (uint8_t *)
    519                         ((void *)ssid_ie_header +
    520                         sizeof(ieee80211_ie_header_t));
    521 
    522                 memcpy(ap_data->bssid.address, mgmt_header->bssid, ETH_ADDR);
    523                 memcpy(ap_data->ssid, ssid_start, ssid_ie_header->length);
    524                 ap_data->ssid[ssid_ie_header->length] = '\0';
     1204        fibril_mutex_lock(&ieee80211_dev->gen_mutex);
     1205       
     1206        ieee80211_dev->current_auth_phase = IEEE80211_AUTH_AUTHENTICATED;
     1207       
     1208        fibril_condvar_signal(&ieee80211_dev->gen_cond);
     1209        fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
     1210       
     1211        return EOK;
     1212}
     1213
     1214/**
     1215 * Process association response.
     1216 *
     1217 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
     1218 * @param mgmt_header Pointer to start of management frame header.
     1219 *
     1220 * @return EOK if succeed, negative error code otherwise.
     1221 */
     1222static int ieee80211_process_assoc_response(ieee80211_dev_t *ieee80211_dev,
     1223        ieee80211_mgmt_header_t *mgmt_header)
     1224{
     1225        ieee80211_scan_result_t *auth_data =
     1226                &ieee80211_dev->bssid_info.res_link->scan_result;
     1227       
     1228        fibril_mutex_lock(&ieee80211_dev->gen_mutex);
     1229       
     1230        ieee80211_assoc_resp_body_t *assoc_resp =
     1231                (ieee80211_assoc_resp_body_t *) ((void *)mgmt_header +
     1232                sizeof(ieee80211_mgmt_header_t));
     1233       
     1234        ieee80211_dev->bssid_info.aid = uint16_t_le2host(assoc_resp->aid);
     1235        memcpy(auth_data->bssid.address, mgmt_header->bssid, ETH_ADDR);
     1236       
     1237        ieee80211_dev->current_auth_phase = IEEE80211_AUTH_ASSOCIATED;
     1238       
     1239        ieee80211_dev->ops->bssid_change(ieee80211_dev);
     1240       
     1241        fibril_condvar_signal(&ieee80211_dev->gen_cond);
     1242        fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
     1243       
     1244        return EOK;
     1245}
     1246
     1247static int ieee80211_process_4way_handshake(ieee80211_dev_t *ieee80211_dev,
     1248        void *buffer, size_t buffer_size)
     1249{
     1250        ieee80211_eapol_key_frame_t *key_frame =
     1251                (ieee80211_eapol_key_frame_t *) buffer;
     1252       
     1253        bool handshake_done = false;
     1254               
     1255        ieee80211_scan_result_link_t *auth_link =
     1256                ieee80211_dev->bssid_info.res_link;
     1257
     1258        ieee80211_scan_result_t *auth_data = &auth_link->scan_result;
     1259        uint8_t *ptk = ieee80211_dev->bssid_info.ptk;
     1260        uint8_t *gtk = ieee80211_dev->bssid_info.gtk;
     1261
     1262        size_t ptk_key_length, gtk_key_length;
     1263        hash_func_t hash_sel;
     1264        switch(auth_data->security.pair_alg) {
     1265                case IEEE80211_SECURITY_SUITE_CCMP:
     1266                        ptk_key_length = IEEE80211_PTK_CCMP_LENGTH;
     1267                        hash_sel = HASH_SHA1;
     1268                        break;
     1269                default:
     1270                        return ENOTSUP;
     1271        }
     1272
     1273        switch(auth_data->security.group_alg) {
     1274                case IEEE80211_SECURITY_SUITE_CCMP:
     1275                        gtk_key_length = IEEE80211_GTK_CCMP_LENGTH;
     1276                        break;
     1277                default:
     1278                        return ENOTSUP;
     1279        }
     1280
     1281        size_t output_size =
     1282                sizeof(eth_header_t) +
     1283                sizeof(ieee80211_eapol_key_frame_t);
     1284
     1285        if(!(uint16_t_be2host(key_frame->key_info) &
     1286                IEEE80211_EAPOL_KEY_KEYINFO_SECURE)) {
     1287                output_size += auth_link->rsn_copy_len;
     1288        }
     1289
     1290        nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
     1291        nic_address_t nic_address;
     1292        nic_query_address(nic, &nic_address);
     1293
     1294        void *output_buffer = malloc(output_size);
     1295        memset(output_buffer, 0, output_size);
     1296
     1297        /* Setup ethernet header. */
     1298        eth_header_t *eth_header = (eth_header_t *) output_buffer;
     1299        memcpy(eth_header->dest_addr, auth_data->bssid.address, ETH_ADDR);
     1300        memcpy(eth_header->src_addr, nic_address.address, ETH_ADDR);
     1301        eth_header->proto = host2uint16_t_be(ETH_TYPE_PAE);
     1302
     1303        ieee80211_eapol_key_frame_t *output_key_frame =
     1304                (ieee80211_eapol_key_frame_t *)
     1305                (output_buffer + sizeof(eth_header_t));
     1306
     1307        /* Copy content of incoming EAPOL-Key frame. */
     1308        memcpy((void *) output_key_frame, buffer,
     1309                sizeof(ieee80211_eapol_key_frame_t));
     1310
     1311        output_key_frame->proto_version = 0x1;
     1312        output_key_frame->key_length = 0;
     1313        output_key_frame->body_length =
     1314                host2uint16_t_be(output_size - sizeof(eth_header_t)-4);
     1315        output_key_frame->key_info &=
     1316                ~host2uint16_t_be(
     1317                        IEEE80211_EAPOL_KEY_KEYINFO_ACK
     1318                );
     1319
     1320        /*
     1321         * Check if it is last or first incoming message in 4-way
     1322         * handshake.
     1323         */
     1324        if(uint16_t_be2host(key_frame->key_info) &
     1325                IEEE80211_EAPOL_KEY_KEYINFO_SECURE) {
     1326                output_key_frame->key_info &=
     1327                        ~host2uint16_t_be(
     1328                                IEEE80211_EAPOL_KEY_KEYINFO_ENCDATA
     1329                        );
     1330                output_key_frame->key_info &=
     1331                        ~host2uint16_t_be(
     1332                                IEEE80211_EAPOL_KEY_KEYINFO_INSTALL
     1333                        );
     1334                output_key_frame->key_data_length = 0;
     1335                output_key_frame->key_length = 0;
     1336                memset(output_key_frame->key_nonce, 0, 32);
     1337                memset(output_key_frame->key_mic, 0, 16);
     1338                memset(output_key_frame->key_rsc, 0, 8);
     1339                memset(output_key_frame->eapol_key_iv, 0, 16);
     1340
     1341                /* Derive GTK and save it. */
     1342                uint16_t key_data_length =
     1343                        uint16_t_be2host(key_frame->key_data_length);
     1344                uint16_t decrypt_len = key_data_length - 8;
     1345                uint8_t key_data[decrypt_len];
     1346                uint8_t *data_ptr = (uint8_t *) (buffer +
     1347                        sizeof(ieee80211_eapol_key_frame_t));
     1348                if(ieee80211_aes_key_unwrap(ptk + KEK_OFFSET, data_ptr,
     1349                        key_data_length, key_data) == EOK) {
     1350                       
     1351                        uint8_t *key_ptr = ieee80211_process_ies(ieee80211_dev,
     1352                                NULL, key_data, decrypt_len);
     1353
     1354                        if(key_ptr) {
     1355                                memcpy(gtk, key_ptr, gtk_key_length);
     1356                                handshake_done = true;
     1357                        }
     1358                }
     1359        } else {
     1360                output_key_frame->key_info |=
     1361                        host2uint16_t_be(
     1362                                IEEE80211_EAPOL_KEY_KEYINFO_MIC
     1363                        );
     1364                output_key_frame->key_data_length =
     1365                        host2uint16_t_be(auth_link->rsn_copy_len);
     1366                memcpy((void *)output_key_frame +
     1367                        sizeof(ieee80211_eapol_key_frame_t),
     1368                        auth_link->rsn_copy,
     1369                        auth_link->rsn_copy_len);
     1370
     1371                /* Compute PMK. */
     1372                uint8_t pmk[PBKDF2_KEY_LENGTH];
     1373                pbkdf2((uint8_t *) ieee80211_dev->bssid_info.password,
     1374                        str_size(ieee80211_dev->bssid_info.password),
     1375                        (uint8_t *) auth_data->ssid,
     1376                        str_size(auth_data->ssid), pmk, hash_sel);
     1377
     1378                uint8_t *anonce = key_frame->key_nonce;
     1379
     1380                /* Generate SNONCE. */
     1381                uint8_t snonce[32];
     1382                rnd_sequence(snonce, 32);
     1383
     1384                memcpy(output_key_frame->key_nonce, snonce, 32);
     1385
     1386                uint8_t *dest_addr = eth_header->dest_addr;
     1387                uint8_t *src_addr = eth_header->src_addr;
     1388
     1389                /* Derive PTK and save it. */
     1390                uint8_t prf_result[ptk_key_length];
     1391                uint8_t crypt_data[PRF_CRYPT_DATA_LENGTH];
     1392                memcpy(crypt_data,
     1393                        min_sequence(dest_addr, src_addr, ETH_ADDR),
     1394                        ETH_ADDR);
     1395                memcpy(crypt_data + ETH_ADDR,
     1396                        max_sequence(dest_addr, src_addr, ETH_ADDR),
     1397                        ETH_ADDR);
     1398                memcpy(crypt_data + 2*ETH_ADDR,
     1399                        min_sequence(anonce, snonce, 32),
     1400                        32);
     1401                memcpy(crypt_data + 2*ETH_ADDR + 32,
     1402                        max_sequence(anonce, snonce, 32),
     1403                        32);
     1404                ieee80211_prf(pmk, crypt_data, prf_result, hash_sel);
     1405                memcpy(ptk, prf_result, ptk_key_length);
     1406        }
     1407
     1408        /* Compute MIC of key frame data from KCK part of PTK. */
     1409        uint8_t mic[SHA1_HASH_LENGTH];
     1410        hmac(ptk, 16, (uint8_t *) output_key_frame,
     1411                output_size - sizeof(eth_header_t), mic, hash_sel);
     1412
     1413        memcpy(output_key_frame->key_mic, mic, 16);
     1414
     1415        ieee80211_send_frame(nic, output_buffer, output_size);
     1416
     1417        free(output_buffer);
     1418
     1419        if(handshake_done) {
     1420                /* Insert keys into device. */
     1421               
     1422                /* Pairwise key. */
     1423                ieee80211_key_config_t key_config;
     1424                key_config.suite = auth_data->security.pair_alg;
     1425                key_config.flags =
     1426                        IEEE80211_KEY_FLAG_TYPE_PAIRWISE;
     1427                memcpy(key_config.data,
     1428                        ptk + TK_OFFSET,
     1429                        ptk_key_length - TK_OFFSET);
     1430
     1431                ieee80211_dev->ops->key_config(ieee80211_dev,
     1432                        &key_config, true);
     1433               
     1434                /* Group key. */
     1435                key_config.suite = auth_data->security.group_alg;
     1436                key_config.flags =
     1437                        IEEE80211_KEY_FLAG_TYPE_GROUP;
     1438                memcpy(key_config.data, gtk, gtk_key_length);
     1439
     1440                ieee80211_dev->ops->key_config(ieee80211_dev,
     1441                        &key_config, true);
     1442
     1443                /* Signal successful handshake completion. */
     1444                fibril_mutex_lock(&ieee80211_dev->gen_mutex);
     1445                fibril_condvar_signal(&ieee80211_dev->gen_cond);
     1446                fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
     1447        }
     1448       
     1449        return EOK;
     1450}
     1451
     1452static int ieee80211_process_eapol_frame(ieee80211_dev_t *ieee80211_dev,
     1453        void *buffer, size_t buffer_size)
     1454{
     1455        ieee80211_eapol_key_frame_t *key_frame =
     1456                (ieee80211_eapol_key_frame_t *) buffer;
     1457        if(ieee80211_is_eapol_key_frame(key_frame)) {
     1458                return ieee80211_process_4way_handshake(ieee80211_dev, buffer,
     1459                        buffer_size);
     1460        }
     1461       
     1462        return EOK;
     1463}
     1464
     1465/**
     1466 * Process data frame.
     1467 *
     1468 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
     1469 * @param buffer Data buffer starting with IEEE 802.11 data header.
     1470 * @param buffer_size Size of buffer.
     1471 *
     1472 * @return EOK if succeed, negative error code otherwise.
     1473 */
     1474static int ieee80211_process_data(ieee80211_dev_t *ieee80211_dev,
     1475        void *buffer, size_t buffer_size)
     1476{
     1477        ieee80211_data_header_t *data_header =
     1478                (ieee80211_data_header_t *) buffer;
     1479       
     1480        if(ieee80211_has_data_frame(data_header->frame_ctrl)) {
     1481                nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
     1482                size_t strip_length = sizeof(ieee80211_data_header_t) +
     1483                        ARRAY_SIZE(rfc1042_header);
     1484               
     1485                /* TODO: Probably different by used security alg. */
     1486                if(ieee80211_is_encrypted_frame(data_header->frame_ctrl)) {
     1487                        strip_length += 8;
     1488                }
     1489               
     1490                /* Process 4-way authentication handshake. */
     1491                uint16_t *proto = (uint16_t *) (buffer + strip_length);
     1492                if(uint16_t_be2host(*proto) == ETH_TYPE_PAE) {
     1493                        return ieee80211_process_eapol_frame(ieee80211_dev,
     1494                                buffer + strip_length + sizeof(uint16_t),
     1495                                buffer_size - strip_length - sizeof(uint16_t));
     1496                }
     1497               
     1498                /* Note: ETH protocol ID is already there, so we don't create
     1499                 * whole ETH header. */
     1500                size_t frame_size =
     1501                        buffer_size - strip_length + sizeof(eth_header_t)-2;
     1502                nic_frame_t *frame = nic_alloc_frame(nic, frame_size);
     1503
     1504                if(frame == NULL) {
     1505                        return ENOMEM;
     1506                }
     1507
     1508                uint8_t *src_addr =
     1509                        ieee80211_is_fromds_frame(data_header->frame_ctrl) ?
     1510                                data_header->address3 : data_header->address2;
     1511                uint8_t *dest_addr =
     1512                        ieee80211_is_tods_frame(data_header->frame_ctrl) ?
     1513                                data_header->address3 : data_header->address1;
     1514
     1515                eth_header_t *eth_header =
     1516                        (eth_header_t *) frame->data;
     1517                memcpy(eth_header->src_addr, src_addr, ETH_ADDR);
     1518                memcpy(eth_header->dest_addr, dest_addr, ETH_ADDR);
     1519
     1520                memcpy(frame->data + sizeof(eth_header_t)-2,
     1521                        buffer + strip_length,
     1522                        buffer_size - strip_length);
     1523
     1524                nic_received_frame(nic, frame);
    5251525        }
    5261526       
     
    5481548                        ieee80211_is_beacon_frame(mgmt_header->frame_ctrl)) {
    5491549                        return ieee80211_process_probe_response(ieee80211_dev,
     1550                                mgmt_header, buffer_size);
     1551                }
     1552               
     1553                if(ieee80211_is_auth_frame(mgmt_header->frame_ctrl)) {
     1554                        return ieee80211_process_auth_response(ieee80211_dev,
    5501555                                mgmt_header);
    5511556                }
    552                 // TODO
     1557               
     1558                if(ieee80211_is_assoc_response_frame(mgmt_header->frame_ctrl)) {
     1559                        return ieee80211_process_assoc_response(ieee80211_dev,
     1560                                mgmt_header);
     1561                }
    5531562        } else if(ieee80211_is_data_frame(frame_ctrl)) {
    554                 nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
    555                 size_t frame_size = buffer_size - sizeof(ieee80211_data_header_t);
    556                 nic_frame_t *frame = nic_alloc_frame(nic, frame_size);
    557                 if (frame != NULL) {
    558                         memcpy(frame->data,
    559                                 buffer + sizeof(ieee80211_data_header_t),
    560                                 frame_size);
    561                         nic_received_frame(nic, frame);
    562                 }
    563         } else {
    564                 // TODO
     1563                return ieee80211_process_data(ieee80211_dev, buffer,
     1564                        buffer_size);
    5651565        }
    5661566       
  • uspace/lib/ieee80211/src/ieee80211_iface_impl.c

    r59fa7ab r1dcc0b9  
    2727 */
    2828
    29 #include <stdio.h>
     29#include <str.h>
    3030#include <errno.h>
    3131
     
    4242 */
    4343
     44/**
     45 * Implementation of fetching scan results.
     46 *
     47 * @param fun Device function.
     48 * @param results Structure where should be stored scan results.
     49 *
     50 * @return EOK.
     51 */
    4452int ieee80211_get_scan_results_impl(ddf_fun_t *fun,
    45         ieee80211_scan_results_t *results)
     53        ieee80211_scan_results_t *results, bool now)
    4654{
    4755        nic_t *nic_data = nic_get_from_ddf_fun(fun);
    4856        ieee80211_dev_t *ieee80211_dev = nic_get_specific(nic_data);
    4957       
     58        if(!ieee80211_is_ready(ieee80211_dev))
     59                return EREFUSED;
     60       
     61        fibril_mutex_lock(&ieee80211_dev->ap_list.scan_mutex);
     62        time_t scan_span = time(NULL) - ieee80211_dev->ap_list.last_scan;
     63        fibril_mutex_unlock(&ieee80211_dev->ap_list.scan_mutex);
     64       
     65        if(now || scan_span > MAX_SCAN_SPAN_SEC) {
     66                ieee80211_dev->ops->scan(ieee80211_dev);
     67        }
     68       
     69        fibril_mutex_lock(&ieee80211_dev->ap_list.scan_mutex);
    5070        if(results) {
    51                 memcpy(results, &ieee80211_dev->ap_list,
    52                         sizeof(ieee80211_scan_results_t));
    53         }
     71                ieee80211_scan_result_list_t *result_list =
     72                        &ieee80211_dev->ap_list;
     73               
     74                int i = 0;
     75                ieee80211_scan_result_list_foreach(*result_list, result) {
     76                        memcpy(&results->results[i],
     77                                &result->scan_result,
     78                                sizeof(ieee80211_scan_result_t));
     79                        i++;
     80                }
     81               
     82                results->length = i;
     83        }
     84        fibril_mutex_unlock(&ieee80211_dev->ap_list.scan_mutex);
    5485       
    5586        return EOK;
    5687}
    5788
    58 int ieee80211_connect_impl(ddf_fun_t *fun, char *ssid, char *password)
    59 {
    60         assert(ssid);
     89static uint16_t ieee80211_channel_to_freq(uint8_t channel)
     90{
     91        return IEEE80211_CHANNEL_GAP * (channel - 1) + IEEE80211_FIRST_FREQ;
     92}
     93
     94/**
     95 * Working procedure of connect function.
     96 *
     97 * @param ieee80211_dev Pointer to IEEE 802.11 device.
     98 * @param auth_data Selected AP data we want to connect to.
     99 *
     100 * @return EOK if everything OK, ETIMEOUT when timeout during authenticating.
     101 */
     102static int ieee80211_connect_proc(ieee80211_dev_t *ieee80211_dev,
     103        ieee80211_scan_result_link_t *auth_data, char *password)
     104{
     105        int rc;
     106       
     107        ieee80211_dev->bssid_info.res_link = auth_data;
     108       
     109        /* Set channel. */
     110        rc = ieee80211_dev->ops->set_freq(ieee80211_dev,
     111                ieee80211_channel_to_freq(auth_data->scan_result.channel));
     112        if(rc != EOK)
     113                return rc;
     114       
     115        /* Try to authenticate. */
     116        ieee80211_authenticate(ieee80211_dev);
     117        fibril_mutex_lock(&ieee80211_dev->gen_mutex);
     118        rc = fibril_condvar_wait_timeout(&ieee80211_dev->gen_cond,
     119                        &ieee80211_dev->gen_mutex,
     120                        AUTH_TIMEOUT);
     121        fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
     122        if(rc != EOK)
     123                return rc;
     124        if(ieee80211_dev->current_auth_phase != IEEE80211_AUTH_AUTHENTICATED)
     125                return EINVAL;
     126       
     127        /* Try to associate. */
     128        ieee80211_associate(ieee80211_dev, password);
     129        fibril_mutex_lock(&ieee80211_dev->gen_mutex);
     130        rc = fibril_condvar_wait_timeout(&ieee80211_dev->gen_cond,
     131                        &ieee80211_dev->gen_mutex,
     132                        AUTH_TIMEOUT);
     133        fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
     134        if(rc != EOK)
     135                return rc;
     136        if(ieee80211_dev->current_auth_phase != IEEE80211_AUTH_ASSOCIATED)
     137                return EINVAL;
     138       
     139        /* On open network, we are finished. */
     140        if(auth_data->scan_result.security.type == IEEE80211_SECURITY_OPEN)
     141                return EOK;
     142       
     143        /* Otherwise wait for 4-way handshake to complete. */
     144        fibril_mutex_lock(&ieee80211_dev->gen_mutex);
     145        rc = fibril_condvar_wait_timeout(&ieee80211_dev->gen_cond,
     146                        &ieee80211_dev->gen_mutex,
     147                        HANDSHAKE_TIMEOUT);
     148        fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
     149        if(rc != EOK)
     150                return rc;
     151        if(ieee80211_dev->current_auth_phase != IEEE80211_AUTH_ASSOCIATED)
     152                return EINVAL;
     153       
     154        return EOK;
     155}
     156
     157/**
     158 * Implementation of connecting to specified SSID.
     159 *
     160 * @param fun Device function.
     161 * @param ssid_start SSID prefix of access point we want to connect to.
     162 *
     163 * @return EOK if everything OK, ETIMEOUT when timeout during authenticating,
     164 * EINVAL when SSID not in scan results list, EPERM when incorrect password
     165 * passed.
     166 */
     167int ieee80211_connect_impl(ddf_fun_t *fun, char *ssid_start, char *password)
     168{
     169        assert(ssid_start);
    61170        assert(password);
    62171       
    63         /*
    64172        nic_t *nic_data = nic_get_from_ddf_fun(fun);
    65173        ieee80211_dev_t *ieee80211_dev = nic_get_specific(nic_data);
    66          */
    67        
    68         // TODO
    69        
    70         return EOK;
     174       
     175        if(!ieee80211_is_ready(ieee80211_dev))
     176                return EREFUSED;
     177       
     178        if(ieee80211_is_connected(ieee80211_dev)) {
     179                int rc = ieee80211_dev->iface->disconnect(fun);
     180                if(rc != EOK)
     181                        return rc;
     182        }
     183       
     184        fibril_mutex_lock(&ieee80211_dev->ap_list.scan_mutex);
     185
     186        ieee80211_scan_result_list_foreach(ieee80211_dev->ap_list, result) {
     187                if(!str_lcmp(ssid_start,
     188                        result->scan_result.ssid,
     189                        str_size(ssid_start))) {
     190                        fibril_mutex_unlock(&ieee80211_dev->ap_list.scan_mutex);
     191                        return ieee80211_connect_proc(ieee80211_dev, result,
     192                                password);
     193                }
     194        }
     195       
     196        fibril_mutex_unlock(&ieee80211_dev->ap_list.scan_mutex);
     197       
     198        return EINVAL;
     199}
     200
     201/**
     202 * Implementation of disconnecting device from network.
     203 *
     204 * @param fun Device function.
     205 *
     206 * @return EOK if everything OK, EINVAL when not connected to any network.
     207 */
     208int ieee80211_disconnect_impl(ddf_fun_t *fun)
     209{
     210        nic_t *nic_data = nic_get_from_ddf_fun(fun);
     211        ieee80211_dev_t *ieee80211_dev = nic_get_specific(nic_data);
     212       
     213        if(!ieee80211_is_ready(ieee80211_dev))
     214                return EREFUSED;
     215       
     216        if(!ieee80211_is_connected(ieee80211_dev)) {
     217                return EINVAL;
     218        } else {
     219                return ieee80211_deauthenticate(ieee80211_dev);
     220        }
    71221}
    72222
  • uspace/lib/ieee80211/src/ieee80211_impl.c

    r59fa7ab r1dcc0b9  
    3636 */
    3737
     38#include <stdio.h>
     39#include <crypto.h>
     40#include <stdlib.h>
    3841#include <errno.h>
    3942
     
    8184
    8285/**
     86 * Default implementation of IEEE802.11 BSSID change function.
     87 *
     88 * @param ieee80211_dev Structure of IEEE802.11 device.
     89 *
     90 * @return EOK.
     91 */
     92int ieee80211_bssid_change_impl(ieee80211_dev_t *ieee80211_dev)
     93{
     94        return EOK;
     95}
     96
     97/**
     98 * Default implementation of IEEE802.11 key config function.
     99 *
     100 * @param ieee80211_dev Structure of IEEE802.11 device.
     101 *
     102 * @return EOK.
     103 */
     104int ieee80211_key_config_impl(ieee80211_dev_t *ieee80211_dev,
     105        ieee80211_key_config_t *key_conf, bool insert)
     106{
     107        return EOK;
     108}
     109
     110/**
    83111 * Default implementation of IEEE802.11 scan function.
    84112 *
    85113 * @param ieee80211_dev Structure of IEEE802.11 device.
    86  * @param results Pointer to structure where should be scan results stored.
     114 * @param clear Whether to clear current scan results.
    87115 *
    88116 * @return EOK if succeed, negative error code otherwise.
     
    90118int ieee80211_scan_impl(ieee80211_dev_t *ieee80211_dev)
    91119{
     120        if(ieee80211_is_connected(ieee80211_dev))
     121                return EOK;
     122       
     123        fibril_mutex_lock(&ieee80211_dev->ap_list.scan_mutex);
     124       
     125        /* Remove old entries we don't receive beacons from. */
     126        ieee80211_scan_result_list_t *result_list =
     127                &ieee80211_dev->ap_list;
     128        list_foreach_safe(result_list->list, cur_link, next_link) {
     129                ieee80211_scan_result_link_t *cur_result =
     130                        list_get_instance(cur_link,
     131                        ieee80211_scan_result_link_t,
     132                        link);
     133                if((time(NULL) - cur_result->last_beacon) >
     134                        MAX_KEEP_SCAN_SPAN_SEC) {
     135                        ieee80211_scan_result_list_remove(result_list,
     136                                cur_result);
     137                }
     138        }
     139       
     140        fibril_mutex_unlock(&ieee80211_dev->ap_list.scan_mutex);
     141       
    92142        uint16_t orig_freq = ieee80211_dev->current_freq;
    93143       
     
    96146                freq += IEEE80211_CHANNEL_GAP) {
    97147                ieee80211_dev->ops->set_freq(ieee80211_dev, freq);
    98                 ieee80211_probe_request(ieee80211_dev);
     148                ieee80211_probe_request(ieee80211_dev, NULL);
    99149               
    100150                /* Wait for probe responses. */
     
    104154        ieee80211_dev->ops->set_freq(ieee80211_dev, orig_freq);
    105155       
    106         return EOK;
     156        fibril_mutex_lock(&ieee80211_dev->ap_list.scan_mutex);
     157        time(&ieee80211_dev->ap_list.last_scan);
     158        fibril_mutex_unlock(&ieee80211_dev->ap_list.scan_mutex);
     159       
     160        return EOK;
     161}
     162
     163/**
     164 * Pseudorandom function used for IEEE 802.11 pairwise key computation.
     165 *
     166 * @param key Key with PBKDF2 encrypted passphrase.
     167 * @param data Concatenated sequence of both mac addresses and nonces.
     168 * @param hash Output parameter for result hash (48 byte value).
     169 * @param hash_sel Hash function selector.
     170 *
     171 * @return EINVAL when key or data not specified, ENOMEM when pointer for
     172 * output hash result is not allocated, otherwise EOK.
     173 */
     174int ieee80211_prf(uint8_t *key, uint8_t *data, uint8_t *hash,
     175        hash_func_t hash_sel)
     176{
     177        if(!key || !data)
     178                return EINVAL;
     179       
     180        if(!hash)
     181                return ENOMEM;
     182       
     183        size_t hash_length, result_length;
     184        switch(hash_sel) {
     185                case HASH_MD5:
     186                        hash_length = MD5_HASH_LENGTH;
     187                        result_length = IEEE80211_PTK_TKIP_LENGTH;
     188                        break;
     189                case HASH_SHA1:
     190                        hash_length = SHA1_HASH_LENGTH;
     191                        result_length = IEEE80211_PTK_CCMP_LENGTH;
     192                        break;
     193                default:
     194                        hash_length = 0;
     195                        result_length = 0;
     196        }
     197       
     198        size_t iters = ((result_length * 8) + 159) / 160;
     199       
     200        const char *a = "Pairwise key expansion";
     201        uint8_t result[hash_length*iters];
     202        uint8_t temp[hash_length];
     203        size_t data_size = PRF_CRYPT_DATA_LENGTH + str_size(a) + 2;
     204        uint8_t work_arr[data_size];
     205        memset(work_arr, 0, data_size);
     206       
     207        memcpy(work_arr, a, str_size(a));
     208        memcpy(work_arr + str_size(a) + 1, data, PRF_CRYPT_DATA_LENGTH);
     209
     210        for(uint8_t i = 0; i < iters; i++) {
     211                memcpy(work_arr + data_size - 1, &i, 1);
     212                hmac(key, PBKDF2_KEY_LENGTH, work_arr, data_size, temp,
     213                        hash_sel);
     214                memcpy(result + i*hash_length, temp, hash_length);
     215        }
     216       
     217        memcpy(hash, result, result_length);
     218       
     219        return EOK;
     220}
     221
     222int ieee80211_aes_key_unwrap(uint8_t *kek, uint8_t *data, size_t data_size,
     223        uint8_t *output)
     224{
     225        if(!kek || !data)
     226                return EINVAL;
     227       
     228        if(!output)
     229                return ENOMEM;
     230
     231        uint32_t n = data_size/8 - 1;
     232        uint8_t work_data[n*8];
     233        uint8_t work_input[AES_CIPHER_LENGTH];
     234        uint8_t work_output[AES_CIPHER_LENGTH];
     235        uint8_t *work_block;
     236        uint8_t a[8];
     237        memcpy(a, data, 8);
     238        uint64_t mask = 0xFF;
     239        uint8_t shift, shb;
     240       
     241        memcpy(work_data, data + 8, n*8);
     242        for(int j = 5; j >=0; j--) {
     243                for(int i = n; i > 0; i--) {
     244                        for(size_t k = 0; k < 8; k++) {
     245                                shift = 56 - 8*k;
     246                                shb = ((n*j+i) & (mask << shift)) >> shift;
     247                                a[k] ^= shb;
     248                        }
     249                        work_block = work_data + (i-1)*8;
     250                        memcpy(work_input, a, 8);
     251                        memcpy(work_input + 8, work_block, 8);
     252                        aes_decrypt(kek, work_input, work_output);
     253                        memcpy(a, work_output, 8);
     254                        memcpy(work_data + (i-1)*8, work_output + 8, 8);
     255                }
     256        }
     257       
     258        size_t it;
     259        for(it = 0; it < 8; it++) {
     260                if(a[it] != 0xA6)
     261                        break;
     262        }
     263       
     264        if(it == 8) {
     265                memcpy(output, work_data, n*8);
     266                return EOK;
     267        } else {
     268                return EINVAL;
     269        }
     270}
     271
     272int rnd_sequence(uint8_t *sequence, size_t length)
     273{
     274        if(!sequence)
     275                return ENOMEM;
     276       
     277        for(size_t i = 0; i < length; i++) {
     278                sequence[i] = (uint8_t) rand();
     279        }
     280       
     281        return EOK;
     282}
     283
     284uint8_t *min_sequence(uint8_t *seq1, uint8_t *seq2, size_t size)
     285{
     286        if(!seq1 || !seq2)
     287                return NULL;
     288       
     289        for(size_t i = 0; i < size; i++) {
     290                if(seq1[i] < seq2[i]) {
     291                        return seq1;
     292                } else if(seq1[i] > seq2[i]) {
     293                        return seq2;
     294                }
     295        }
     296       
     297        return seq1;
     298}
     299
     300uint8_t *max_sequence(uint8_t *seq1, uint8_t *seq2, size_t size)
     301{
     302        uint8_t *min = min_sequence(seq1, seq2, size);
     303        if(min == seq1) {
     304                return seq2;
     305        } else {
     306                return seq1;
     307        }
    107308}
    108309
Note: See TracChangeset for help on using the changeset viewer.