linux/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
<<
>>
Prefs
   1/* IEEE 802.11 SoftMAC layer
   2 * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
   3 *
   4 * Mostly extracted from the rtl8180-sa2400 driver for the
   5 * in-kernel generic ieee802.11 stack.
   6 *
   7 * Some pieces of code might be stolen from ipw2100 driver
   8 * copyright of who own it's copyright ;-)
   9 *
  10 * PS wx handler mostly stolen from hostap, copyright who
  11 * own it's copyright ;-)
  12 *
  13 * released under the GPL
  14 */
  15
  16
  17#include "ieee80211.h"
  18
  19/* FIXME: add A freqs */
  20
  21const long ieee80211_wlan_frequencies[] = {
  22        2412, 2417, 2422, 2427,
  23        2432, 2437, 2442, 2447,
  24        2452, 2457, 2462, 2467,
  25        2472, 2484
  26};
  27
  28
  29int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a,
  30                             union iwreq_data *wrqu, char *b)
  31{
  32        int ret;
  33        struct iw_freq *fwrq = & wrqu->freq;
  34//      printk("in %s\n",__func__);
  35        down(&ieee->wx_sem);
  36
  37        if(ieee->iw_mode == IW_MODE_INFRA){
  38                ret = -EOPNOTSUPP;
  39                goto out;
  40        }
  41
  42        /* if setting by freq convert to channel */
  43        if (fwrq->e == 1) {
  44                if ((fwrq->m >= (int) 2.412e8 &&
  45                     fwrq->m <= (int) 2.487e8)) {
  46                        int f = fwrq->m / 100000;
  47                        int c = 0;
  48
  49                        while ((c < 14) && (f != ieee80211_wlan_frequencies[c]))
  50                                c++;
  51
  52                        /* hack to fall through */
  53                        fwrq->e = 0;
  54                        fwrq->m = c + 1;
  55                }
  56        }
  57
  58        if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1 ){
  59                ret = -EOPNOTSUPP;
  60                goto out;
  61
  62        }else { /* Set the channel */
  63
  64
  65                ieee->current_network.channel = fwrq->m;
  66                ieee->set_chan(ieee->dev, ieee->current_network.channel);
  67
  68                if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
  69                        if(ieee->state == IEEE80211_LINKED){
  70
  71                        ieee80211_stop_send_beacons(ieee);
  72                        ieee80211_start_send_beacons(ieee);
  73                        }
  74        }
  75
  76        ret = 0;
  77out:
  78        up(&ieee->wx_sem);
  79        return ret;
  80}
  81
  82
  83int ieee80211_wx_get_freq(struct ieee80211_device *ieee,
  84                             struct iw_request_info *a,
  85                             union iwreq_data *wrqu, char *b)
  86{
  87        struct iw_freq *fwrq = & wrqu->freq;
  88
  89        if (ieee->current_network.channel == 0)
  90                return -1;
  91
  92        fwrq->m = ieee->current_network.channel;
  93        fwrq->e = 0;
  94
  95        return 0;
  96}
  97
  98int ieee80211_wx_get_wap(struct ieee80211_device *ieee,
  99                            struct iw_request_info *info,
 100                            union iwreq_data *wrqu, char *extra)
 101{
 102        unsigned long flags;
 103
 104        wrqu->ap_addr.sa_family = ARPHRD_ETHER;
 105
 106        if (ieee->iw_mode == IW_MODE_MONITOR)
 107                return -1;
 108
 109        /* We want avoid to give to the user inconsistent infos*/
 110        spin_lock_irqsave(&ieee->lock, flags);
 111
 112        if (ieee->state != IEEE80211_LINKED &&
 113                ieee->state != IEEE80211_LINKED_SCANNING &&
 114                ieee->wap_set == 0)
 115
 116                memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
 117        else
 118                memcpy(wrqu->ap_addr.sa_data,
 119                       ieee->current_network.bssid, ETH_ALEN);
 120
 121        spin_unlock_irqrestore(&ieee->lock, flags);
 122
 123        return 0;
 124}
 125
 126
 127int ieee80211_wx_set_wap(struct ieee80211_device *ieee,
 128                         struct iw_request_info *info,
 129                         union iwreq_data *awrq,
 130                         char *extra)
 131{
 132
 133        int ret = 0;
 134        u8 zero[] = {0,0,0,0,0,0};
 135        unsigned long flags;
 136
 137        short ifup = ieee->proto_started;//dev->flags & IFF_UP;
 138        struct sockaddr *temp = (struct sockaddr *)awrq;
 139
 140        //printk("=======Set WAP:");
 141        ieee->sync_scan_hurryup = 1;
 142
 143        down(&ieee->wx_sem);
 144        /* use ifconfig hw ether */
 145        if (ieee->iw_mode == IW_MODE_MASTER){
 146                ret = -1;
 147                goto out;
 148        }
 149
 150        if (temp->sa_family != ARPHRD_ETHER){
 151                ret = -EINVAL;
 152                goto out;
 153        }
 154
 155        if (ifup)
 156                ieee80211_stop_protocol(ieee);
 157
 158        /* just to avoid to give inconsistent infos in the
 159         * get wx method. not really needed otherwise
 160         */
 161        spin_lock_irqsave(&ieee->lock, flags);
 162
 163        memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
 164        ieee->wap_set = memcmp(temp->sa_data, zero,ETH_ALEN)!=0;
 165        //printk(" %x:%x:%x:%x:%x:%x\n", ieee->current_network.bssid[0],ieee->current_network.bssid[1],ieee->current_network.bssid[2],ieee->current_network.bssid[3],ieee->current_network.bssid[4],ieee->current_network.bssid[5]);
 166
 167        spin_unlock_irqrestore(&ieee->lock, flags);
 168
 169        if (ifup)
 170                ieee80211_start_protocol(ieee);
 171
 172out:
 173        up(&ieee->wx_sem);
 174        return ret;
 175}
 176
 177 int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b)
 178{
 179        int len,ret = 0;
 180        unsigned long flags;
 181
 182        if (ieee->iw_mode == IW_MODE_MONITOR)
 183                return -1;
 184
 185        /* We want avoid to give to the user inconsistent infos*/
 186        spin_lock_irqsave(&ieee->lock, flags);
 187
 188        if (ieee->current_network.ssid[0] == '\0' ||
 189                ieee->current_network.ssid_len == 0){
 190                ret = -1;
 191                goto out;
 192        }
 193
 194        if (ieee->state != IEEE80211_LINKED &&
 195                ieee->state != IEEE80211_LINKED_SCANNING &&
 196                ieee->ssid_set == 0){
 197                ret = -1;
 198                goto out;
 199        }
 200        len = ieee->current_network.ssid_len;
 201        wrqu->essid.length = len;
 202        strncpy(b,ieee->current_network.ssid,len);
 203        wrqu->essid.flags = 1;
 204
 205out:
 206        spin_unlock_irqrestore(&ieee->lock, flags);
 207
 208        return ret;
 209
 210}
 211
 212int ieee80211_wx_set_rate(struct ieee80211_device *ieee,
 213                             struct iw_request_info *info,
 214                             union iwreq_data *wrqu, char *extra)
 215{
 216
 217        u32 target_rate = wrqu->bitrate.value;
 218
 219        //added by lizhaoming for auto mode
 220        if(target_rate == -1){
 221        ieee->rate = 110;
 222        } else {
 223        ieee->rate = target_rate/100000;
 224        }
 225        //FIXME: we might want to limit rate also in management protocols.
 226        return 0;
 227}
 228
 229
 230
 231int ieee80211_wx_get_rate(struct ieee80211_device *ieee,
 232                             struct iw_request_info *info,
 233                             union iwreq_data *wrqu, char *extra)
 234{
 235
 236        wrqu->bitrate.value = ieee->rate * 100000;
 237
 238        return 0;
 239}
 240
 241int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a,
 242                             union iwreq_data *wrqu, char *b)
 243{
 244
 245        ieee->sync_scan_hurryup = 1;
 246
 247        down(&ieee->wx_sem);
 248
 249        if (wrqu->mode == ieee->iw_mode)
 250                goto out;
 251
 252        if (wrqu->mode == IW_MODE_MONITOR){
 253
 254                ieee->dev->type = ARPHRD_IEEE80211;
 255        }else{
 256                ieee->dev->type = ARPHRD_ETHER;
 257        }
 258
 259        if (!ieee->proto_started){
 260                ieee->iw_mode = wrqu->mode;
 261        }else{
 262                ieee80211_stop_protocol(ieee);
 263                ieee->iw_mode = wrqu->mode;
 264                ieee80211_start_protocol(ieee);
 265        }
 266
 267out:
 268        up(&ieee->wx_sem);
 269        return 0;
 270}
 271
 272
 273void ieee80211_wx_sync_scan_wq(struct work_struct *work)
 274{
 275        struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq);
 276        short chan;
 277
 278        chan = ieee->current_network.channel;
 279
 280        if (ieee->data_hard_stop)
 281                ieee->data_hard_stop(ieee->dev);
 282
 283        ieee80211_stop_send_beacons(ieee);
 284
 285        ieee->state = IEEE80211_LINKED_SCANNING;
 286        ieee->link_change(ieee->dev);
 287
 288        ieee80211_start_scan_syncro(ieee);
 289
 290        ieee->set_chan(ieee->dev, chan);
 291
 292        ieee->state = IEEE80211_LINKED;
 293        ieee->link_change(ieee->dev);
 294
 295        if (ieee->data_hard_resume)
 296                ieee->data_hard_resume(ieee->dev);
 297
 298        if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
 299                ieee80211_start_send_beacons(ieee);
 300
 301        //YJ,add,080828, In prevent of lossing ping packet during scanning
 302        //ieee80211_sta_ps_send_null_frame(ieee, false);
 303        //YJ,add,080828,end
 304
 305        up(&ieee->wx_sem);
 306
 307}
 308
 309int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a,
 310                             union iwreq_data *wrqu, char *b)
 311{
 312        int ret = 0;
 313
 314        down(&ieee->wx_sem);
 315
 316        if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)){
 317                ret = -1;
 318                goto out;
 319        }
 320        //YJ,add,080828
 321        //In prevent of lossing ping packet during scanning
 322        //ieee80211_sta_ps_send_null_frame(ieee, true);
 323        //YJ,add,080828,end
 324
 325        if ( ieee->state == IEEE80211_LINKED){
 326                queue_work(ieee->wq, &ieee->wx_sync_scan_wq);
 327                /* intentionally forget to up sem */
 328                return 0;
 329        }
 330
 331out:
 332        up(&ieee->wx_sem);
 333        return ret;
 334}
 335
 336int ieee80211_wx_set_essid(struct ieee80211_device *ieee,
 337                              struct iw_request_info *a,
 338                              union iwreq_data *wrqu, char *extra)
 339{
 340
 341        int ret=0,len;
 342        short proto_started;
 343        unsigned long flags;
 344
 345        ieee->sync_scan_hurryup = 1;
 346
 347        down(&ieee->wx_sem);
 348
 349        proto_started = ieee->proto_started;
 350
 351        if (wrqu->essid.length > IW_ESSID_MAX_SIZE){
 352                ret= -E2BIG;
 353                goto out;
 354        }
 355
 356        if (ieee->iw_mode == IW_MODE_MONITOR){
 357                ret= -1;
 358                goto out;
 359        }
 360
 361        if(proto_started)
 362                ieee80211_stop_protocol(ieee);
 363
 364        /* this is just to be sure that the GET wx callback
 365         * has consisten infos. not needed otherwise
 366         */
 367        spin_lock_irqsave(&ieee->lock, flags);
 368
 369        if (wrqu->essid.flags && wrqu->essid.length) {
 370//YJ,modified,080819
 371                len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length) : IW_ESSID_MAX_SIZE;
 372                memset(ieee->current_network.ssid, 0, ieee->current_network.ssid_len); //YJ,add,080819
 373                strncpy(ieee->current_network.ssid, extra, len);
 374                ieee->current_network.ssid_len = len;
 375                ieee->ssid_set = 1;
 376//YJ,modified,080819,end
 377
 378                //YJ,add,080819,for hidden ap
 379                if(len == 0){
 380                        memset(ieee->current_network.bssid, 0, ETH_ALEN);
 381                        ieee->current_network.capability = 0;
 382                }
 383                //YJ,add,080819,for hidden ap,end
 384        }
 385        else{
 386                ieee->ssid_set = 0;
 387                ieee->current_network.ssid[0] = '\0';
 388                ieee->current_network.ssid_len = 0;
 389        }
 390        //printk("==========set essid %s!\n",ieee->current_network.ssid);
 391        spin_unlock_irqrestore(&ieee->lock, flags);
 392
 393        if (proto_started)
 394                ieee80211_start_protocol(ieee);
 395out:
 396        up(&ieee->wx_sem);
 397        return ret;
 398}
 399
 400 int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a,
 401                             union iwreq_data *wrqu, char *b)
 402{
 403
 404        wrqu->mode = ieee->iw_mode;
 405        return 0;
 406}
 407
 408 int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee,
 409                               struct iw_request_info *info,
 410                               union iwreq_data *wrqu, char *extra)
 411{
 412
 413        int *parms = (int *)extra;
 414        int enable = (parms[0] > 0);
 415        short prev = ieee->raw_tx;
 416
 417        down(&ieee->wx_sem);
 418
 419        if(enable)
 420                ieee->raw_tx = 1;
 421        else
 422                ieee->raw_tx = 0;
 423
 424        printk(KERN_INFO"raw TX is %s\n",
 425              ieee->raw_tx ? "enabled" : "disabled");
 426
 427        if(ieee->iw_mode == IW_MODE_MONITOR)
 428        {
 429                if(prev == 0 && ieee->raw_tx){
 430                        if (ieee->data_hard_resume)
 431                                ieee->data_hard_resume(ieee->dev);
 432
 433                        netif_carrier_on(ieee->dev);
 434                }
 435
 436                if(prev && ieee->raw_tx == 1)
 437                        netif_carrier_off(ieee->dev);
 438        }
 439
 440        up(&ieee->wx_sem);
 441
 442        return 0;
 443}
 444
 445int ieee80211_wx_get_name(struct ieee80211_device *ieee,
 446                             struct iw_request_info *info,
 447                             union iwreq_data *wrqu, char *extra)
 448{
 449        strlcpy(wrqu->name, "802.11", IFNAMSIZ);
 450        if(ieee->modulation & IEEE80211_CCK_MODULATION){
 451                strlcat(wrqu->name, "b", IFNAMSIZ);
 452                if(ieee->modulation & IEEE80211_OFDM_MODULATION)
 453                        strlcat(wrqu->name, "/g", IFNAMSIZ);
 454        }else if(ieee->modulation & IEEE80211_OFDM_MODULATION)
 455                strlcat(wrqu->name, "g", IFNAMSIZ);
 456
 457        if((ieee->state == IEEE80211_LINKED) ||
 458                (ieee->state == IEEE80211_LINKED_SCANNING))
 459                strlcat(wrqu->name,"  link", IFNAMSIZ);
 460        else if(ieee->state != IEEE80211_NOLINK)
 461                strlcat(wrqu->name," .....", IFNAMSIZ);
 462
 463
 464        return 0;
 465}
 466
 467
 468/* this is mostly stolen from hostap */
 469int ieee80211_wx_set_power(struct ieee80211_device *ieee,
 470                                 struct iw_request_info *info,
 471                                 union iwreq_data *wrqu, char *extra)
 472{
 473        int ret = 0;
 474
 475        if(
 476                (!ieee->sta_wake_up) ||
 477                (!ieee->ps_request_tx_ack) ||
 478                (!ieee->enter_sleep_state) ||
 479                (!ieee->ps_is_queue_empty)){
 480
 481                printk("ERROR. PS mode tried to be use but driver missed a callback\n\n");
 482
 483                return -1;
 484        }
 485
 486        down(&ieee->wx_sem);
 487
 488        if (wrqu->power.disabled){
 489                ieee->ps = IEEE80211_PS_DISABLED;
 490
 491                goto exit;
 492        }
 493        switch (wrqu->power.flags & IW_POWER_MODE) {
 494        case IW_POWER_UNICAST_R:
 495                ieee->ps = IEEE80211_PS_UNICAST;
 496
 497                break;
 498        case IW_POWER_ALL_R:
 499                ieee->ps = IEEE80211_PS_UNICAST | IEEE80211_PS_MBCAST;
 500                break;
 501
 502        case IW_POWER_ON:
 503                ieee->ps = IEEE80211_PS_DISABLED;
 504                break;
 505
 506        default:
 507                ret = -EINVAL;
 508                goto exit;
 509        }
 510
 511        if (wrqu->power.flags & IW_POWER_TIMEOUT) {
 512
 513                ieee->ps_timeout = wrqu->power.value / 1000;
 514                printk("Timeout %d\n",ieee->ps_timeout);
 515        }
 516
 517        if (wrqu->power.flags & IW_POWER_PERIOD) {
 518
 519                ret = -EOPNOTSUPP;
 520                goto exit;
 521                //wrq->value / 1024;
 522
 523        }
 524exit:
 525        up(&ieee->wx_sem);
 526        return ret;
 527
 528}
 529
 530/* this is stolen from hostap */
 531int ieee80211_wx_get_power(struct ieee80211_device *ieee,
 532                                 struct iw_request_info *info,
 533                                 union iwreq_data *wrqu, char *extra)
 534{
 535        int ret =0;
 536
 537        down(&ieee->wx_sem);
 538
 539        if(ieee->ps == IEEE80211_PS_DISABLED){
 540                wrqu->power.disabled = 1;
 541                goto exit;
 542        }
 543
 544        wrqu->power.disabled = 0;
 545
 546//      if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
 547                wrqu->power.flags = IW_POWER_TIMEOUT;
 548                wrqu->power.value = ieee->ps_timeout * 1000;
 549//      } else {
 550//              ret = -EOPNOTSUPP;
 551//              goto exit;
 552                //wrqu->power.flags = IW_POWER_PERIOD;
 553                //wrqu->power.value = ieee->current_network.dtim_period *
 554                //      ieee->current_network.beacon_interval * 1024;
 555//      }
 556
 557
 558        if (ieee->ps & IEEE80211_PS_MBCAST)
 559                wrqu->power.flags |= IW_POWER_ALL_R;
 560        else
 561                wrqu->power.flags |= IW_POWER_UNICAST_R;
 562
 563exit:
 564        up(&ieee->wx_sem);
 565        return ret;
 566
 567}
 568