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#ifdef ENABLE_DOT11D 19#include "dot11d.h" 20#endif 21 22const long ieee80211_wlan_frequencies[] = { 23 2412, 2417, 2422, 2427, 24 2432, 2437, 2442, 2447, 25 2452, 2457, 2462, 2467, 26 2472, 2484 27}; 28 29 30int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a, 31 union iwreq_data *wrqu, char *b) 32{ 33 int ret; 34 struct iw_freq *fwrq = & wrqu->freq; 35 36 down(&ieee->wx_sem); 37 38 if(ieee->iw_mode == IW_MODE_INFRA){ 39 ret = -EOPNOTSUPP; 40 goto out; 41 } 42 43 /* if setting by freq convert to channel */ 44 if (fwrq->e == 1) { 45 if ((fwrq->m >= (int) 2.412e8 && 46 fwrq->m <= (int) 2.487e8)) { 47 int f = fwrq->m / 100000; 48 int c = 0; 49 50 while ((c < 14) && (f != ieee80211_wlan_frequencies[c])) 51 c++; 52 53 /* hack to fall through */ 54 fwrq->e = 0; 55 fwrq->m = c + 1; 56 } 57 } 58 59 if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1 ){ 60 ret = -EOPNOTSUPP; 61 goto out; 62 63 }else { /* Set the channel */ 64 65#ifdef ENABLE_DOT11D 66 if (!(GET_DOT11D_INFO(ieee)->channel_map)[fwrq->m]) { 67 ret = -EINVAL; 68 goto out; 69 } 70#endif 71 ieee->current_network.channel = fwrq->m; 72 ieee->set_chan(ieee->dev, ieee->current_network.channel); 73 74 if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) 75 if(ieee->state == IEEE80211_LINKED){ 76 77 ieee80211_stop_send_beacons(ieee); 78 ieee80211_start_send_beacons(ieee); 79 } 80 } 81 82 ret = 0; 83out: 84 up(&ieee->wx_sem); 85 return ret; 86} 87 88 89int ieee80211_wx_get_freq(struct ieee80211_device *ieee, 90 struct iw_request_info *a, 91 union iwreq_data *wrqu, char *b) 92{ 93 struct iw_freq *fwrq = & wrqu->freq; 94 95 if (ieee->current_network.channel == 0) 96 return -1; 97 //NM 0.7.0 will not accept channel any more. 98 fwrq->m = ieee80211_wlan_frequencies[ieee->current_network.channel-1] * 100000; 99 fwrq->e = 1; 100// fwrq->m = ieee->current_network.channel; 101// fwrq->e = 0; 102 103 return 0; 104} 105 106int ieee80211_wx_get_wap(struct ieee80211_device *ieee, 107 struct iw_request_info *info, 108 union iwreq_data *wrqu, char *extra) 109{ 110 unsigned long flags; 111 wrqu->ap_addr.sa_family = ARPHRD_ETHER; 112 113 if (ieee->iw_mode == IW_MODE_MONITOR) 114 return -1; 115 116 /* We want avoid to give to the user inconsistent infos*/ 117 spin_lock_irqsave(&ieee->lock, flags); 118 119 if (ieee->state != IEEE80211_LINKED && 120 ieee->state != IEEE80211_LINKED_SCANNING && 121 ieee->wap_set == 0) 122 123 memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); 124 else 125 memcpy(wrqu->ap_addr.sa_data, 126 ieee->current_network.bssid, ETH_ALEN); 127 128 spin_unlock_irqrestore(&ieee->lock, flags); 129 130 return 0; 131} 132 133 134int ieee80211_wx_set_wap(struct ieee80211_device *ieee, 135 struct iw_request_info *info, 136 union iwreq_data *awrq, 137 char *extra) 138{ 139 140 int ret = 0; 141 u8 zero[] = {0,0,0,0,0,0}; 142 unsigned long flags; 143 144 short ifup = ieee->proto_started;//dev->flags & IFF_UP; 145 struct sockaddr *temp = (struct sockaddr *)awrq; 146 147 ieee->sync_scan_hurryup = 1; 148 149 down(&ieee->wx_sem); 150 /* use ifconfig hw ether */ 151 if (ieee->iw_mode == IW_MODE_MASTER){ 152 ret = -1; 153 goto out; 154 } 155 156 if (temp->sa_family != ARPHRD_ETHER){ 157 ret = -EINVAL; 158 goto out; 159 } 160 161 if (ifup) 162 ieee80211_stop_protocol(ieee,true); 163 164 /* just to avoid to give inconsistent infos in the 165 * get wx method. not really needed otherwise 166 */ 167 spin_lock_irqsave(&ieee->lock, flags); 168 169 memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN); 170 ieee->wap_set = memcmp(temp->sa_data, zero,ETH_ALEN)!=0; 171 172 spin_unlock_irqrestore(&ieee->lock, flags); 173 174 if (ifup) 175 ieee80211_start_protocol(ieee); 176out: 177 up(&ieee->wx_sem); 178 return ret; 179} 180 181 int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b) 182{ 183 int len,ret = 0; 184 unsigned long flags; 185 186 if (ieee->iw_mode == IW_MODE_MONITOR) 187 return -1; 188 189 /* We want avoid to give to the user inconsistent infos*/ 190 spin_lock_irqsave(&ieee->lock, flags); 191 192 if (ieee->current_network.ssid[0] == '\0' || 193 ieee->current_network.ssid_len == 0){ 194 ret = -1; 195 goto out; 196 } 197 198 if (ieee->state != IEEE80211_LINKED && 199 ieee->state != IEEE80211_LINKED_SCANNING && 200 ieee->ssid_set == 0){ 201 ret = -1; 202 goto out; 203 } 204 len = ieee->current_network.ssid_len; 205 wrqu->essid.length = len; 206 strncpy(b,ieee->current_network.ssid,len); 207 wrqu->essid.flags = 1; 208 209out: 210 spin_unlock_irqrestore(&ieee->lock, flags); 211 212 return ret; 213 214} 215 216int ieee80211_wx_set_rate(struct ieee80211_device *ieee, 217 struct iw_request_info *info, 218 union iwreq_data *wrqu, char *extra) 219{ 220 221 u32 target_rate = wrqu->bitrate.value; 222 223 ieee->rate = target_rate/100000; 224 return 0; 225} 226 227 228 229int ieee80211_wx_get_rate(struct ieee80211_device *ieee, 230 struct iw_request_info *info, 231 union iwreq_data *wrqu, char *extra) 232{ 233 u32 tmp_rate; 234 tmp_rate = TxCountToDataRate(ieee, ieee->softmac_stats.CurrentShowTxate); 235 wrqu->bitrate.value = tmp_rate * 500000; 236 237 return 0; 238} 239 240 241int ieee80211_wx_set_rts(struct ieee80211_device *ieee, 242 struct iw_request_info *info, 243 union iwreq_data *wrqu, char *extra) 244{ 245 if (wrqu->rts.disabled || !wrqu->rts.fixed) 246 ieee->rts = DEFAULT_RTS_THRESHOLD; 247 else 248 { 249 if (wrqu->rts.value < MIN_RTS_THRESHOLD || 250 wrqu->rts.value > MAX_RTS_THRESHOLD) 251 return -EINVAL; 252 ieee->rts = wrqu->rts.value; 253 } 254 return 0; 255} 256 257int ieee80211_wx_get_rts(struct ieee80211_device *ieee, 258 struct iw_request_info *info, 259 union iwreq_data *wrqu, char *extra) 260{ 261 wrqu->rts.value = ieee->rts; 262 wrqu->rts.fixed = 0; /* no auto select */ 263 wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); 264 return 0; 265} 266int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a, 267 union iwreq_data *wrqu, char *b) 268{ 269 270 ieee->sync_scan_hurryup = 1; 271 272 down(&ieee->wx_sem); 273 274 if (wrqu->mode == ieee->iw_mode) 275 goto out; 276 277 if (wrqu->mode == IW_MODE_MONITOR){ 278 279 ieee->dev->type = ARPHRD_IEEE80211; 280 }else{ 281 ieee->dev->type = ARPHRD_ETHER; 282 } 283 284 if (!ieee->proto_started){ 285 ieee->iw_mode = wrqu->mode; 286 }else{ 287 ieee80211_stop_protocol(ieee,true); 288 ieee->iw_mode = wrqu->mode; 289 ieee80211_start_protocol(ieee); 290 } 291 292out: 293 up(&ieee->wx_sem); 294 return 0; 295} 296 297void ieee80211_wx_sync_scan_wq(struct work_struct *work) 298{ 299 struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq); 300 short chan; 301 HT_EXTCHNL_OFFSET chan_offset=0; 302 HT_CHANNEL_WIDTH bandwidth=0; 303 int b40M = 0; 304 static int count = 0; 305 chan = ieee->current_network.channel; 306 307#ifdef ENABLE_LPS 308 if (ieee->LeisurePSLeave) { 309 ieee->LeisurePSLeave(ieee->dev); 310 } 311 312 /* notify AP to be in PS mode */ 313 ieee80211_sta_ps_send_null_frame(ieee, 1); 314 ieee80211_sta_ps_send_null_frame(ieee, 1); 315#endif 316 317 if (ieee->data_hard_stop) 318 ieee->data_hard_stop(ieee->dev); 319 320 ieee80211_stop_send_beacons(ieee); 321 322 ieee->state = IEEE80211_LINKED_SCANNING; 323 ieee->link_change(ieee->dev); 324 ieee->InitialGainHandler(ieee->dev,IG_Backup); 325 if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT && ieee->pHTInfo->bCurBW40MHz) { 326 b40M = 1; 327 chan_offset = ieee->pHTInfo->CurSTAExtChnlOffset; 328 bandwidth = (HT_CHANNEL_WIDTH)ieee->pHTInfo->bCurBW40MHz; 329 printk("Scan in 40M, force to 20M first:%d, %d\n", chan_offset, bandwidth); 330 ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); 331 } 332 ieee80211_start_scan_syncro(ieee); 333 if (b40M) { 334 printk("Scan in 20M, back to 40M\n"); 335 if (chan_offset == HT_EXTCHNL_OFFSET_UPPER) 336 ieee->set_chan(ieee->dev, chan + 2); 337 else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER) 338 ieee->set_chan(ieee->dev, chan - 2); 339 else 340 ieee->set_chan(ieee->dev, chan); 341 ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset); 342 } else { 343 ieee->set_chan(ieee->dev, chan); 344 } 345 346 ieee->InitialGainHandler(ieee->dev,IG_Restore); 347 ieee->state = IEEE80211_LINKED; 348 ieee->link_change(ieee->dev); 349 350#ifdef ENABLE_LPS 351 /* Notify AP that I wake up again */ 352 ieee80211_sta_ps_send_null_frame(ieee, 0); 353#endif 354 355 // To prevent the immediately calling watch_dog after scan. 356 if(ieee->LinkDetectInfo.NumRecvBcnInPeriod==0||ieee->LinkDetectInfo.NumRecvDataInPeriod==0 ) 357 { 358 ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1; 359 ieee->LinkDetectInfo.NumRecvDataInPeriod= 1; 360 } 361 if (ieee->data_hard_resume) 362 ieee->data_hard_resume(ieee->dev); 363 364 if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) 365 ieee80211_start_send_beacons(ieee); 366 367 count = 0; 368 up(&ieee->wx_sem); 369 370} 371 372int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a, 373 union iwreq_data *wrqu, char *b) 374{ 375 int ret = 0; 376 377 down(&ieee->wx_sem); 378 379 if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)){ 380 ret = -1; 381 goto out; 382 } 383 384 if ( ieee->state == IEEE80211_LINKED){ 385 queue_work(ieee->wq, &ieee->wx_sync_scan_wq); 386 /* intentionally forget to up sem */ 387 return 0; 388 } 389 390out: 391 up(&ieee->wx_sem); 392 return ret; 393} 394 395int ieee80211_wx_set_essid(struct ieee80211_device *ieee, 396 struct iw_request_info *a, 397 union iwreq_data *wrqu, char *extra) 398{ 399 400 int ret=0,len; 401 short proto_started; 402 unsigned long flags; 403 404 ieee->sync_scan_hurryup = 1; 405 down(&ieee->wx_sem); 406 407 proto_started = ieee->proto_started; 408 409 if (wrqu->essid.length > IW_ESSID_MAX_SIZE){ 410 ret= -E2BIG; 411 goto out; 412 } 413 414 if (ieee->iw_mode == IW_MODE_MONITOR){ 415 ret= -1; 416 goto out; 417 } 418 419 if(proto_started){ 420 ieee80211_stop_protocol(ieee,true); 421 } 422 423 424 /* this is just to be sure that the GET wx callback 425 * has consisten infos. not needed otherwise 426 */ 427 spin_lock_irqsave(&ieee->lock, flags); 428 429 if (wrqu->essid.flags && wrqu->essid.length) { 430 //first flush current network.ssid 431 len = ((wrqu->essid.length-1) < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length-1) : IW_ESSID_MAX_SIZE; 432 strncpy(ieee->current_network.ssid, extra, len+1); 433 ieee->current_network.ssid_len = len+1; 434 ieee->ssid_set = 1; 435 } 436 else{ 437 ieee->ssid_set = 0; 438 ieee->current_network.ssid[0] = '\0'; 439 ieee->current_network.ssid_len = 0; 440 } 441 spin_unlock_irqrestore(&ieee->lock, flags); 442 443 if (proto_started) 444 ieee80211_start_protocol(ieee); 445out: 446 up(&ieee->wx_sem); 447 return ret; 448} 449 450 int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a, 451 union iwreq_data *wrqu, char *b) 452{ 453 454 wrqu->mode = ieee->iw_mode; 455 return 0; 456} 457 458 int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, 459 struct iw_request_info *info, 460 union iwreq_data *wrqu, char *extra) 461{ 462 463 int *parms = (int *)extra; 464 int enable = (parms[0] > 0); 465 short prev = ieee->raw_tx; 466 467 down(&ieee->wx_sem); 468 469 if(enable) 470 ieee->raw_tx = 1; 471 else 472 ieee->raw_tx = 0; 473 474 printk(KERN_INFO"raw TX is %s\n", 475 ieee->raw_tx ? "enabled" : "disabled"); 476 477 if(ieee->iw_mode == IW_MODE_MONITOR) 478 { 479 if(prev == 0 && ieee->raw_tx){ 480 if (ieee->data_hard_resume) 481 ieee->data_hard_resume(ieee->dev); 482 483 netif_carrier_on(ieee->dev); 484 } 485 486 if(prev && ieee->raw_tx == 1) 487 netif_carrier_off(ieee->dev); 488 } 489 490 up(&ieee->wx_sem); 491 492 return 0; 493} 494 495int ieee80211_wx_get_name(struct ieee80211_device *ieee, 496 struct iw_request_info *info, 497 union iwreq_data *wrqu, char *extra) 498{ 499 strcpy(wrqu->name, "802.11"); 500 if(ieee->modulation & IEEE80211_CCK_MODULATION) 501 strcat(wrqu->name, "b"); 502 if(ieee->modulation & IEEE80211_OFDM_MODULATION) 503 strcat(wrqu->name, "g"); 504 if (ieee->mode & (IEEE_N_24G | IEEE_N_5G)) 505 strcat(wrqu->name, "n"); 506 return 0; 507} 508 509 510/* this is mostly stolen from hostap */ 511int ieee80211_wx_set_power(struct ieee80211_device *ieee, 512 struct iw_request_info *info, 513 union iwreq_data *wrqu, char *extra) 514{ 515 int ret = 0; 516 if( 517 (!ieee->sta_wake_up) || 518 // (!ieee->ps_request_tx_ack) || 519 (!ieee->enter_sleep_state) || 520 (!ieee->ps_is_queue_empty)){ 521 522 // printk("ERROR. PS mode is tryied to be use but driver missed a callback\n\n"); 523 524 return -1; 525 } 526 down(&ieee->wx_sem); 527 528 if (wrqu->power.disabled){ 529 ieee->ps = IEEE80211_PS_DISABLED; 530 goto exit; 531 } 532 if (wrqu->power.flags & IW_POWER_TIMEOUT) { 533 //ieee->ps_period = wrqu->power.value / 1000; 534 ieee->ps_timeout = wrqu->power.value / 1000; 535 } 536 537 if (wrqu->power.flags & IW_POWER_PERIOD) { 538 539 //ieee->ps_timeout = wrqu->power.value / 1000; 540 ieee->ps_period = wrqu->power.value / 1000; 541 //wrq->value / 1024; 542 543 } 544 switch (wrqu->power.flags & IW_POWER_MODE) { 545 case IW_POWER_UNICAST_R: 546 ieee->ps = IEEE80211_PS_UNICAST; 547 break; 548 case IW_POWER_MULTICAST_R: 549 ieee->ps = IEEE80211_PS_MBCAST; 550 break; 551 case IW_POWER_ALL_R: 552 ieee->ps = IEEE80211_PS_UNICAST | IEEE80211_PS_MBCAST; 553 break; 554 555 case IW_POWER_ON: 556 // ieee->ps = IEEE80211_PS_DISABLED; 557 break; 558 559 default: 560 ret = -EINVAL; 561 goto exit; 562 563 } 564exit: 565 up(&ieee->wx_sem); 566 return ret; 567 568} 569 570/* this is stolen from hostap */ 571int ieee80211_wx_get_power(struct ieee80211_device *ieee, 572 struct iw_request_info *info, 573 union iwreq_data *wrqu, char *extra) 574{ 575 int ret =0; 576 577 down(&ieee->wx_sem); 578 579 if(ieee->ps == IEEE80211_PS_DISABLED){ 580 wrqu->power.disabled = 1; 581 goto exit; 582 } 583 584 wrqu->power.disabled = 0; 585 586 if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { 587 wrqu->power.flags = IW_POWER_TIMEOUT; 588 wrqu->power.value = ieee->ps_timeout * 1000; 589 } else { 590// ret = -EOPNOTSUPP; 591// goto exit; 592 wrqu->power.flags = IW_POWER_PERIOD; 593 wrqu->power.value = ieee->ps_period * 1000; 594//ieee->current_network.dtim_period * ieee->current_network.beacon_interval * 1024; 595 } 596 597 if ((ieee->ps & (IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST)) == (IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST)) 598 wrqu->power.flags |= IW_POWER_ALL_R; 599 else if (ieee->ps & IEEE80211_PS_MBCAST) 600 wrqu->power.flags |= IW_POWER_MULTICAST_R; 601 else 602 wrqu->power.flags |= IW_POWER_UNICAST_R; 603 604exit: 605 up(&ieee->wx_sem); 606 return ret; 607 608} 609