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