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        netif_carrier_off(ieee->dev);
 281
 282        if (ieee->data_hard_stop)
 283                ieee->data_hard_stop(ieee->dev);
 284
 285        ieee80211_stop_send_beacons(ieee);
 286
 287        ieee->state = IEEE80211_LINKED_SCANNING;
 288        ieee->link_change(ieee->dev);
 289
 290        ieee80211_start_scan_syncro(ieee);
 291
 292        ieee->set_chan(ieee->dev, chan);
 293
 294        ieee->state = IEEE80211_LINKED;
 295        ieee->link_change(ieee->dev);
 296
 297        if (ieee->data_hard_resume)
 298                ieee->data_hard_resume(ieee->dev);
 299
 300        if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
 301                ieee80211_start_send_beacons(ieee);
 302
 303        netif_carrier_on(ieee->dev);
 304
 305        //YJ,add,080828, In prevent of lossing ping packet during scanning
 306        //ieee80211_sta_ps_send_null_frame(ieee, false);
 307        //YJ,add,080828,end
 308
 309        up(&ieee->wx_sem);
 310
 311}
 312
 313int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a,
 314                             union iwreq_data *wrqu, char *b)
 315{
 316        int ret = 0;
 317
 318        down(&ieee->wx_sem);
 319
 320        if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)){
 321                ret = -1;
 322                goto out;
 323        }
 324        //YJ,add,080828
 325        //In prevent of lossing ping packet during scanning
 326        //ieee80211_sta_ps_send_null_frame(ieee, true);
 327        //YJ,add,080828,end
 328
 329        if ( ieee->state == IEEE80211_LINKED){
 330                queue_work(ieee->wq, &ieee->wx_sync_scan_wq);
 331                /* intentionally forget to up sem */
 332                return 0;
 333        }
 334
 335out:
 336        up(&ieee->wx_sem);
 337        return ret;
 338}
 339
 340int ieee80211_wx_set_essid(struct ieee80211_device *ieee,
 341                              struct iw_request_info *a,
 342                              union iwreq_data *wrqu, char *extra)
 343{
 344
 345        int ret=0,len;
 346        short proto_started;
 347        unsigned long flags;
 348
 349        ieee->sync_scan_hurryup = 1;
 350
 351        down(&ieee->wx_sem);
 352
 353        proto_started = ieee->proto_started;
 354
 355        if (wrqu->essid.length > IW_ESSID_MAX_SIZE){
 356                ret= -E2BIG;
 357                goto out;
 358        }
 359
 360        if (ieee->iw_mode == IW_MODE_MONITOR){
 361                ret= -1;
 362                goto out;
 363        }
 364
 365        if(proto_started)
 366                ieee80211_stop_protocol(ieee);
 367
 368        /* this is just to be sure that the GET wx callback
 369         * has consisten infos. not needed otherwise
 370         */
 371        spin_lock_irqsave(&ieee->lock, flags);
 372
 373        if (wrqu->essid.flags && wrqu->essid.length) {
 374//YJ,modified,080819
 375                len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length) : IW_ESSID_MAX_SIZE;
 376                memset(ieee->current_network.ssid, 0, ieee->current_network.ssid_len); //YJ,add,080819
 377                strncpy(ieee->current_network.ssid, extra, len);
 378                ieee->current_network.ssid_len = len;
 379                ieee->ssid_set = 1;
 380//YJ,modified,080819,end
 381
 382                //YJ,add,080819,for hidden ap
 383                if(len == 0){
 384                        memset(ieee->current_network.bssid, 0, ETH_ALEN);
 385                        ieee->current_network.capability = 0;
 386                }
 387                //YJ,add,080819,for hidden ap,end
 388        }
 389        else{
 390                ieee->ssid_set = 0;
 391                ieee->current_network.ssid[0] = '\0';
 392                ieee->current_network.ssid_len = 0;
 393        }
 394        //printk("==========set essid %s!\n",ieee->current_network.ssid);
 395        spin_unlock_irqrestore(&ieee->lock, flags);
 396
 397        if (proto_started)
 398                ieee80211_start_protocol(ieee);
 399out:
 400        up(&ieee->wx_sem);
 401        return ret;
 402}
 403
 404 int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a,
 405                             union iwreq_data *wrqu, char *b)
 406{
 407
 408        wrqu->mode = ieee->iw_mode;
 409        return 0;
 410}
 411
 412 int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee,
 413                               struct iw_request_info *info,
 414                               union iwreq_data *wrqu, char *extra)
 415{
 416
 417        int *parms = (int *)extra;
 418        int enable = (parms[0] > 0);
 419        short prev = ieee->raw_tx;
 420
 421        down(&ieee->wx_sem);
 422
 423        if(enable)
 424                ieee->raw_tx = 1;
 425        else
 426                ieee->raw_tx = 0;
 427
 428        printk(KERN_INFO"raw TX is %s\n",
 429              ieee->raw_tx ? "enabled" : "disabled");
 430
 431        if(ieee->iw_mode == IW_MODE_MONITOR)
 432        {
 433                if(prev == 0 && ieee->raw_tx){
 434                        if (ieee->data_hard_resume)
 435                                ieee->data_hard_resume(ieee->dev);
 436
 437                        netif_carrier_on(ieee->dev);
 438                }
 439
 440                if(prev && ieee->raw_tx == 1)
 441                        netif_carrier_off(ieee->dev);
 442        }
 443
 444        up(&ieee->wx_sem);
 445
 446        return 0;
 447}
 448
 449int ieee80211_wx_get_name(struct ieee80211_device *ieee,
 450                             struct iw_request_info *info,
 451                             union iwreq_data *wrqu, char *extra)
 452{
 453        strlcpy(wrqu->name, "802.11", IFNAMSIZ);
 454        if(ieee->modulation & IEEE80211_CCK_MODULATION){
 455                strlcat(wrqu->name, "b", IFNAMSIZ);
 456                if(ieee->modulation & IEEE80211_OFDM_MODULATION)
 457                        strlcat(wrqu->name, "/g", IFNAMSIZ);
 458        }else if(ieee->modulation & IEEE80211_OFDM_MODULATION)
 459                strlcat(wrqu->name, "g", IFNAMSIZ);
 460
 461        if((ieee->state == IEEE80211_LINKED) ||
 462                (ieee->state == IEEE80211_LINKED_SCANNING))
 463                strlcat(wrqu->name,"  link", IFNAMSIZ);
 464        else if(ieee->state != IEEE80211_NOLINK)
 465                strlcat(wrqu->name," .....", IFNAMSIZ);
 466
 467
 468        return 0;
 469}
 470
 471
 472/* this is mostly stolen from hostap */
 473int ieee80211_wx_set_power(struct ieee80211_device *ieee,
 474                                 struct iw_request_info *info,
 475                                 union iwreq_data *wrqu, char *extra)
 476{
 477        int ret = 0;
 478
 479        if(
 480                (!ieee->sta_wake_up) ||
 481                (!ieee->ps_request_tx_ack) ||
 482                (!ieee->enter_sleep_state) ||
 483                (!ieee->ps_is_queue_empty)){
 484
 485                printk("ERROR. PS mode is tryied to be use but\
 486driver missed a callback\n\n");
 487
 488                return -1;
 489        }
 490
 491        down(&ieee->wx_sem);
 492
 493        if (wrqu->power.disabled){
 494                ieee->ps = IEEE80211_PS_DISABLED;
 495
 496                goto exit;
 497        }
 498        switch (wrqu->power.flags & IW_POWER_MODE) {
 499        case IW_POWER_UNICAST_R:
 500                ieee->ps = IEEE80211_PS_UNICAST;
 501
 502                break;
 503        case IW_POWER_ALL_R:
 504                ieee->ps = IEEE80211_PS_UNICAST | IEEE80211_PS_MBCAST;
 505                break;
 506
 507        case IW_POWER_ON:
 508                ieee->ps = IEEE80211_PS_DISABLED;
 509                break;
 510
 511        default:
 512                ret = -EINVAL;
 513                goto exit;
 514        }
 515
 516        if (wrqu->power.flags & IW_POWER_TIMEOUT) {
 517
 518                ieee->ps_timeout = wrqu->power.value / 1000;
 519                printk("Timeout %d\n",ieee->ps_timeout);
 520        }
 521
 522        if (wrqu->power.flags & IW_POWER_PERIOD) {
 523
 524                ret = -EOPNOTSUPP;
 525                goto exit;
 526                //wrq->value / 1024;
 527
 528        }
 529exit:
 530        up(&ieee->wx_sem);
 531        return ret;
 532
 533}
 534
 535/* this is stolen from hostap */
 536int ieee80211_wx_get_power(struct ieee80211_device *ieee,
 537                                 struct iw_request_info *info,
 538                                 union iwreq_data *wrqu, char *extra)
 539{
 540        int ret =0;
 541
 542        down(&ieee->wx_sem);
 543
 544        if(ieee->ps == IEEE80211_PS_DISABLED){
 545                wrqu->power.disabled = 1;
 546                goto exit;
 547        }
 548
 549        wrqu->power.disabled = 0;
 550
 551//      if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
 552                wrqu->power.flags = IW_POWER_TIMEOUT;
 553                wrqu->power.value = ieee->ps_timeout * 1000;
 554//      } else {
 555//              ret = -EOPNOTSUPP;
 556//              goto exit;
 557                //wrqu->power.flags = IW_POWER_PERIOD;
 558                //wrqu->power.value = ieee->current_network.dtim_period *
 559                //      ieee->current_network.beacon_interval * 1024;
 560//      }
 561
 562
 563        if (ieee->ps & IEEE80211_PS_MBCAST)
 564                wrqu->power.flags |= IW_POWER_ALL_R;
 565        else
 566                wrqu->power.flags |= IW_POWER_UNICAST_R;
 567
 568exit:
 569        up(&ieee->wx_sem);
 570        return ret;
 571
 572}
 573