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