Changeset 1dcc0b9 in mainline for uspace/lib/ieee80211/src


Ignore:
Timestamp:
2015-04-06T10:47:51Z (10 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/lib/ieee80211/src
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • 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.