linux/drivers/staging/wilc1000/coreconfigurator.c
<<
>>
Prefs
   1#include "coreconfigurator.h"
   2#include "wilc_wlan_if.h"
   3#include "wilc_wlan.h"
   4#include <linux/errno.h>
   5#include <linux/slab.h>
   6#define TAG_PARAM_OFFSET        (MAC_HDR_LEN + TIME_STAMP_LEN + \
   7                                 BEACON_INTERVAL_LEN + CAP_INFO_LEN)
   8
   9enum basic_frame_type {
  10        FRAME_TYPE_CONTROL     = 0x04,
  11        FRAME_TYPE_DATA        = 0x08,
  12        FRAME_TYPE_MANAGEMENT  = 0x00,
  13        FRAME_TYPE_RESERVED    = 0x0C,
  14        FRAME_TYPE_FORCE_32BIT = 0xFFFFFFFF
  15};
  16
  17enum sub_frame_type {
  18        ASSOC_REQ             = 0x00,
  19        ASSOC_RSP             = 0x10,
  20        REASSOC_REQ           = 0x20,
  21        REASSOC_RSP           = 0x30,
  22        PROBE_REQ             = 0x40,
  23        PROBE_RSP             = 0x50,
  24        BEACON                = 0x80,
  25        ATIM                  = 0x90,
  26        DISASOC               = 0xA0,
  27        AUTH                  = 0xB0,
  28        DEAUTH                = 0xC0,
  29        ACTION                = 0xD0,
  30        PS_POLL               = 0xA4,
  31        RTS                   = 0xB4,
  32        CTS                   = 0xC4,
  33        ACK                   = 0xD4,
  34        CFEND                 = 0xE4,
  35        CFEND_ACK             = 0xF4,
  36        DATA                  = 0x08,
  37        DATA_ACK              = 0x18,
  38        DATA_POLL             = 0x28,
  39        DATA_POLL_ACK         = 0x38,
  40        NULL_FRAME            = 0x48,
  41        CFACK                 = 0x58,
  42        CFPOLL                = 0x68,
  43        CFPOLL_ACK            = 0x78,
  44        QOS_DATA              = 0x88,
  45        QOS_DATA_ACK          = 0x98,
  46        QOS_DATA_POLL         = 0xA8,
  47        QOS_DATA_POLL_ACK     = 0xB8,
  48        QOS_NULL_FRAME        = 0xC8,
  49        QOS_CFPOLL            = 0xE8,
  50        QOS_CFPOLL_ACK        = 0xF8,
  51        BLOCKACK_REQ          = 0x84,
  52        BLOCKACK              = 0x94,
  53        FRAME_SUBTYPE_FORCE_32BIT  = 0xFFFFFFFF
  54};
  55
  56enum info_element_id {
  57        ISSID               = 0,   /* Service Set Identifier         */
  58        ISUPRATES           = 1,   /* Supported Rates                */
  59        IFHPARMS            = 2,   /* FH parameter set               */
  60        IDSPARMS            = 3,   /* DS parameter set               */
  61        ICFPARMS            = 4,   /* CF parameter set               */
  62        ITIM                = 5,   /* Traffic Information Map        */
  63        IIBPARMS            = 6,   /* IBSS parameter set             */
  64        ICOUNTRY            = 7,   /* Country element                */
  65        IEDCAPARAMS         = 12,  /* EDCA parameter set             */
  66        ITSPEC              = 13,  /* Traffic Specification          */
  67        ITCLAS              = 14,  /* Traffic Classification         */
  68        ISCHED              = 15,  /* Schedule                       */
  69        ICTEXT              = 16,  /* Challenge Text                 */
  70        IPOWERCONSTRAINT    = 32,  /* Power Constraint               */
  71        IPOWERCAPABILITY    = 33,  /* Power Capability               */
  72        ITPCREQUEST         = 34,  /* TPC Request                    */
  73        ITPCREPORT          = 35,  /* TPC Report                     */
  74        ISUPCHANNEL         = 36,  /* Supported channel list         */
  75        ICHSWANNOUNC        = 37,  /* Channel Switch Announcement    */
  76        IMEASUREMENTREQUEST = 38,  /* Measurement request            */
  77        IMEASUREMENTREPORT  = 39,  /* Measurement report             */
  78        IQUIET              = 40,  /* Quiet element Info             */
  79        IIBSSDFS            = 41,  /* IBSS DFS                       */
  80        IERPINFO            = 42,  /* ERP Information                */
  81        ITSDELAY            = 43,  /* TS Delay                       */
  82        ITCLASPROCESS       = 44,  /* TCLAS Processing               */
  83        IHTCAP              = 45,  /* HT Capabilities                */
  84        IQOSCAP             = 46,  /* QoS Capability                 */
  85        IRSNELEMENT         = 48,  /* RSN Information Element        */
  86        IEXSUPRATES         = 50,  /* Extended Supported Rates       */
  87        IEXCHSWANNOUNC      = 60,  /* Extended Ch Switch Announcement*/
  88        IHTOPERATION        = 61,  /* HT Information                 */
  89        ISECCHOFF           = 62,  /* Secondary Channel Offeset      */
  90        I2040COEX           = 72,  /* 20/40 Coexistence IE           */
  91        I2040INTOLCHREPORT  = 73,  /* 20/40 Intolerant channel report*/
  92        IOBSSSCAN           = 74,  /* OBSS Scan parameters           */
  93        IEXTCAP             = 127, /* Extended capability            */
  94        IWMM                = 221, /* WMM parameters                 */
  95        IWPAELEMENT         = 221, /* WPA Information Element        */
  96        INFOELEM_ID_FORCE_32BIT  = 0xFFFFFFFF
  97};
  98
  99static inline u16 get_beacon_period(u8 *data)
 100{
 101        u16 bcn_per;
 102
 103        bcn_per  = data[0];
 104        bcn_per |= (data[1] << 8);
 105
 106        return bcn_per;
 107}
 108
 109static inline u32 get_beacon_timestamp_lo(u8 *data)
 110{
 111        u32 time_stamp = 0;
 112        u32 index    = MAC_HDR_LEN;
 113
 114        time_stamp |= data[index++];
 115        time_stamp |= (data[index++] << 8);
 116        time_stamp |= (data[index++] << 16);
 117        time_stamp |= (data[index]   << 24);
 118
 119        return time_stamp;
 120}
 121
 122static inline u32 get_beacon_timestamp_hi(u8 *data)
 123{
 124        u32 time_stamp = 0;
 125        u32 index    = (MAC_HDR_LEN + 4);
 126
 127        time_stamp |= data[index++];
 128        time_stamp |= (data[index++] << 8);
 129        time_stamp |= (data[index++] << 16);
 130        time_stamp |= (data[index]   << 24);
 131
 132        return time_stamp;
 133}
 134
 135static inline enum sub_frame_type get_sub_type(u8 *header)
 136{
 137        return ((enum sub_frame_type)(header[0] & 0xFC));
 138}
 139
 140static inline u8 get_to_ds(u8 *header)
 141{
 142        return (header[1] & 0x01);
 143}
 144
 145static inline u8 get_from_ds(u8 *header)
 146{
 147        return ((header[1] & 0x02) >> 1);
 148}
 149
 150static inline void get_address1(u8 *pu8msa, u8 *addr)
 151{
 152        memcpy(addr, pu8msa + 4, 6);
 153}
 154
 155static inline void get_address2(u8 *pu8msa, u8 *addr)
 156{
 157        memcpy(addr, pu8msa + 10, 6);
 158}
 159
 160static inline void get_address3(u8 *pu8msa, u8 *addr)
 161{
 162        memcpy(addr, pu8msa + 16, 6);
 163}
 164
 165static inline void get_BSSID(u8 *data, u8 *bssid)
 166{
 167        if (get_from_ds(data) == 1)
 168                get_address2(data, bssid);
 169        else if (get_to_ds(data) == 1)
 170                get_address1(data, bssid);
 171        else
 172                get_address3(data, bssid);
 173}
 174
 175static inline void get_ssid(u8 *data, u8 *ssid, u8 *p_ssid_len)
 176{
 177        u8 len = 0;
 178        u8 i   = 0;
 179        u8 j   = 0;
 180
 181        len = data[TAG_PARAM_OFFSET + 1];
 182        j   = TAG_PARAM_OFFSET + 2;
 183
 184        if (len >= MAX_SSID_LEN)
 185                len = 0;
 186
 187        for (i = 0; i < len; i++, j++)
 188                ssid[i] = data[j];
 189
 190        ssid[len] = '\0';
 191
 192        *p_ssid_len = len;
 193}
 194
 195static inline u16 get_cap_info(u8 *data)
 196{
 197        u16 cap_info = 0;
 198        u16 index    = MAC_HDR_LEN;
 199        enum sub_frame_type st;
 200
 201        st = get_sub_type(data);
 202
 203        if ((st == BEACON) || (st == PROBE_RSP))
 204                index += TIME_STAMP_LEN + BEACON_INTERVAL_LEN;
 205
 206        cap_info  = data[index];
 207        cap_info |= (data[index + 1] << 8);
 208
 209        return cap_info;
 210}
 211
 212static inline u16 get_assoc_resp_cap_info(u8 *data)
 213{
 214        u16 cap_info;
 215
 216        cap_info  = data[0];
 217        cap_info |= (data[1] << 8);
 218
 219        return cap_info;
 220}
 221
 222static inline u16 get_asoc_status(u8 *data)
 223{
 224        u16 asoc_status;
 225
 226        asoc_status = data[3];
 227        asoc_status = (asoc_status << 8) | data[2];
 228
 229        return asoc_status;
 230}
 231
 232static inline u16 get_asoc_id(u8 *data)
 233{
 234        u16 asoc_id;
 235
 236        asoc_id  = data[4];
 237        asoc_id |= (data[5] << 8);
 238
 239        return asoc_id;
 240}
 241
 242static u8 *get_tim_elm(u8 *pu8msa, u16 rx_len, u16 tag_param_offset)
 243{
 244        u16 index;
 245
 246        index = tag_param_offset;
 247
 248        while (index < (rx_len - FCS_LEN)) {
 249                if (pu8msa[index] == ITIM)
 250                        return &pu8msa[index];
 251                index += (IE_HDR_LEN + pu8msa[index + 1]);
 252        }
 253
 254        return NULL;
 255}
 256
 257static u8 get_current_channel_802_11n(u8 *pu8msa, u16 rx_len)
 258{
 259        u16 index;
 260
 261        index = TAG_PARAM_OFFSET;
 262        while (index < (rx_len - FCS_LEN)) {
 263                if (pu8msa[index] == IDSPARMS)
 264                        return pu8msa[index + 2];
 265                index += pu8msa[index + 1] + IE_HDR_LEN;
 266        }
 267
 268        return 0;
 269}
 270
 271s32 wilc_parse_network_info(u8 *msg_buffer,
 272                            struct network_info **ret_network_info)
 273{
 274        struct network_info *network_info = NULL;
 275        u8 msg_type = 0;
 276        u8 msg_id = 0;
 277        u16 msg_len = 0;
 278
 279        u16 wid_id = (u16)WID_NIL;
 280        u16 wid_len  = 0;
 281        u8 *wid_val = NULL;
 282
 283        msg_type = msg_buffer[0];
 284
 285        if ('N' != msg_type)
 286                return -EFAULT;
 287
 288        msg_id = msg_buffer[1];
 289        msg_len = MAKE_WORD16(msg_buffer[2], msg_buffer[3]);
 290        wid_id = MAKE_WORD16(msg_buffer[4], msg_buffer[5]);
 291        wid_len = MAKE_WORD16(msg_buffer[6], msg_buffer[7]);
 292        wid_val = &msg_buffer[8];
 293
 294        {
 295                u8 *msa = NULL;
 296                u16 rx_len = 0;
 297                u8 *tim_elm = NULL;
 298                u8 *ies = NULL;
 299                u16 ies_len = 0;
 300                u8 index = 0;
 301                u32 tsf_lo;
 302                u32 tsf_hi;
 303
 304                network_info = kzalloc(sizeof(*network_info), GFP_KERNEL);
 305                if (!network_info)
 306                        return -ENOMEM;
 307
 308                network_info->rssi = wid_val[0];
 309
 310                msa = &wid_val[1];
 311
 312                rx_len = wid_len - 1;
 313                network_info->cap_info = get_cap_info(msa);
 314                network_info->tsf_lo = get_beacon_timestamp_lo(msa);
 315
 316                tsf_lo = get_beacon_timestamp_lo(msa);
 317                tsf_hi = get_beacon_timestamp_hi(msa);
 318
 319                network_info->tsf_hi = tsf_lo | ((u64)tsf_hi << 32);
 320
 321                get_ssid(msa, network_info->ssid, &network_info->ssid_len);
 322                get_BSSID(msa, network_info->bssid);
 323
 324                network_info->ch = get_current_channel_802_11n(msa,
 325                                                        rx_len + FCS_LEN);
 326
 327                index = MAC_HDR_LEN + TIME_STAMP_LEN;
 328
 329                network_info->beacon_period = get_beacon_period(msa + index);
 330
 331                index += BEACON_INTERVAL_LEN + CAP_INFO_LEN;
 332
 333                tim_elm = get_tim_elm(msa, rx_len + FCS_LEN, index);
 334                if (tim_elm)
 335                        network_info->dtim_period = tim_elm[3];
 336                ies = &msa[TAG_PARAM_OFFSET];
 337                ies_len = rx_len - TAG_PARAM_OFFSET;
 338
 339                if (ies_len > 0) {
 340                        network_info->ies = kmemdup(ies, ies_len, GFP_KERNEL);
 341                        if (!network_info->ies) {
 342                                kfree(network_info);
 343                                return -ENOMEM;
 344                        }
 345                }
 346                network_info->ies_len = ies_len;
 347        }
 348
 349        *ret_network_info = network_info;
 350
 351        return 0;
 352}
 353
 354s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len,
 355                               struct connect_resp_info **ret_connect_resp_info)
 356{
 357        struct connect_resp_info *connect_resp_info = NULL;
 358        u16 assoc_resp_len = 0;
 359        u8 *ies = NULL;
 360        u16 ies_len = 0;
 361
 362        connect_resp_info = kzalloc(sizeof(*connect_resp_info), GFP_KERNEL);
 363        if (!connect_resp_info)
 364                return -ENOMEM;
 365
 366        assoc_resp_len = (u16)buffer_len;
 367
 368        connect_resp_info->status = get_asoc_status(buffer);
 369        if (connect_resp_info->status == SUCCESSFUL_STATUSCODE) {
 370                connect_resp_info->capability = get_assoc_resp_cap_info(buffer);
 371                connect_resp_info->assoc_id = get_asoc_id(buffer);
 372
 373                ies = &buffer[CAP_INFO_LEN + STATUS_CODE_LEN + AID_LEN];
 374                ies_len = assoc_resp_len - (CAP_INFO_LEN + STATUS_CODE_LEN +
 375                                            AID_LEN);
 376
 377                connect_resp_info->ies = kmemdup(ies, ies_len, GFP_KERNEL);
 378                if (!connect_resp_info->ies) {
 379                        kfree(connect_resp_info);
 380                        return -ENOMEM;
 381                }
 382
 383                connect_resp_info->ies_len = ies_len;
 384        }
 385
 386        *ret_connect_resp_info = connect_resp_info;
 387
 388        return 0;
 389}
 390