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