1 /* IEEE 802.11 SoftMAC layer 2 * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com> 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 EXPORT_SYMBOL(ieee80211_wlan_frequencies); 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 mutex_lock(&ieee->wx_mutex); 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 ieee80211_stop_send_beacons(ieee); 76 ieee80211_start_send_beacons(ieee); 77 } 78 } 79 80 ret = 0; 81 out: 82 mutex_unlock(&ieee->wx_mutex); 83 return ret; 84 } 85 EXPORT_SYMBOL(ieee80211_wx_set_freq); 86 87 int ieee80211_wx_get_freq(struct ieee80211_device *ieee, 88 struct iw_request_info *a, 89 union iwreq_data *wrqu, char *b) 90 { 91 struct iw_freq *fwrq = &wrqu->freq; 92 93 if (ieee->current_network.channel == 0) 94 return -1; 95 /* NM 0.7.0 will not accept channel any more. */ 96 fwrq->m = ieee80211_wlan_frequencies[ieee->current_network.channel-1] * 100000; 97 fwrq->e = 1; 98 /* fwrq->m = ieee->current_network.channel; */ 99 /* fwrq->e = 0; */ 100 101 return 0; 102 } 103 EXPORT_SYMBOL(ieee80211_wx_get_freq); 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 eth_zero_addr(wrqu->ap_addr.sa_data); 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 EXPORT_SYMBOL(ieee80211_wx_get_wap); 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 mutex_lock(&ieee->wx_mutex); 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 mutex_unlock(&ieee->wx_mutex); 177 return ret; 178 } 179 EXPORT_SYMBOL(ieee80211_wx_set_wap); 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 209 out: 210 spin_unlock_irqrestore(&ieee->lock, flags); 211 212 return ret; 213 214 } 215 EXPORT_SYMBOL(ieee80211_wx_get_essid); 216 217 int ieee80211_wx_set_rate(struct ieee80211_device *ieee, 218 struct iw_request_info *info, 219 union iwreq_data *wrqu, char *extra) 220 { 221 222 u32 target_rate = wrqu->bitrate.value; 223 224 ieee->rate = target_rate/100000; 225 /* FIXME: we might want to limit rate also in management protocols. */ 226 return 0; 227 } 228 EXPORT_SYMBOL(ieee80211_wx_set_rate); 229 230 int ieee80211_wx_get_rate(struct ieee80211_device *ieee, 231 struct iw_request_info *info, 232 union iwreq_data *wrqu, char *extra) 233 { 234 u32 tmp_rate; 235 236 tmp_rate = TxCountToDataRate(ieee, ieee->softmac_stats.CurrentShowTxate); 237 238 wrqu->bitrate.value = tmp_rate * 500000; 239 240 return 0; 241 } 242 EXPORT_SYMBOL(ieee80211_wx_get_rate); 243 244 int ieee80211_wx_set_rts(struct ieee80211_device *ieee, 245 struct iw_request_info *info, 246 union iwreq_data *wrqu, char *extra) 247 { 248 if (wrqu->rts.disabled || !wrqu->rts.fixed) 249 ieee->rts = DEFAULT_RTS_THRESHOLD; 250 else { 251 if (wrqu->rts.value < MIN_RTS_THRESHOLD || 252 wrqu->rts.value > MAX_RTS_THRESHOLD) 253 return -EINVAL; 254 ieee->rts = wrqu->rts.value; 255 } 256 return 0; 257 } 258 EXPORT_SYMBOL(ieee80211_wx_set_rts); 259 260 int ieee80211_wx_get_rts(struct ieee80211_device *ieee, 261 struct iw_request_info *info, 262 union iwreq_data *wrqu, char *extra) 263 { 264 wrqu->rts.value = ieee->rts; 265 wrqu->rts.fixed = 0; /* no auto select */ 266 wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); 267 return 0; 268 } 269 EXPORT_SYMBOL(ieee80211_wx_get_rts); 270 271 int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a, 272 union iwreq_data *wrqu, char *b) 273 { 274 275 ieee->sync_scan_hurryup = 1; 276 277 mutex_lock(&ieee->wx_mutex); 278 279 if (wrqu->mode == ieee->iw_mode) 280 goto out; 281 282 if (wrqu->mode == IW_MODE_MONITOR) 283 ieee->dev->type = ARPHRD_IEEE80211; 284 else 285 ieee->dev->type = ARPHRD_ETHER; 286 287 if (!ieee->proto_started) { 288 ieee->iw_mode = wrqu->mode; 289 } else { 290 ieee80211_stop_protocol(ieee); 291 ieee->iw_mode = wrqu->mode; 292 ieee80211_start_protocol(ieee); 293 } 294 295 out: 296 mutex_unlock(&ieee->wx_mutex); 297 return 0; 298 } 299 EXPORT_SYMBOL(ieee80211_wx_set_mode); 300 301 void ieee80211_wx_sync_scan_wq(struct work_struct *work) 302 { 303 struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq); 304 short chan; 305 enum ht_extension_chan_offset chan_offset = 0; 306 enum ht_channel_width bandwidth = 0; 307 int b40M = 0; 308 309 chan = ieee->current_network.channel; 310 netif_carrier_off(ieee->dev); 311 312 if (ieee->data_hard_stop) 313 ieee->data_hard_stop(ieee->dev); 314 315 ieee80211_stop_send_beacons(ieee); 316 317 ieee->state = IEEE80211_LINKED_SCANNING; 318 ieee->link_change(ieee->dev); 319 ieee->InitialGainHandler(ieee->dev, IG_Backup); 320 if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT && ieee->pHTInfo->bCurBW40MHz) { 321 b40M = 1; 322 chan_offset = ieee->pHTInfo->CurSTAExtChnlOffset; 323 bandwidth = (enum ht_channel_width)ieee->pHTInfo->bCurBW40MHz; 324 printk("Scan in 40M, force to 20M first:%d, %d\n", chan_offset, bandwidth); 325 ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); 326 } 327 ieee80211_start_scan_syncro(ieee); 328 if (b40M) { 329 printk("Scan in 20M, back to 40M\n"); 330 if (chan_offset == HT_EXTCHNL_OFFSET_UPPER) 331 ieee->set_chan(ieee->dev, chan + 2); 332 else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER) 333 ieee->set_chan(ieee->dev, chan - 2); 334 else 335 ieee->set_chan(ieee->dev, chan); 336 ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset); 337 } else { 338 ieee->set_chan(ieee->dev, chan); 339 } 340 341 ieee->InitialGainHandler(ieee->dev, IG_Restore); 342 ieee->state = IEEE80211_LINKED; 343 ieee->link_change(ieee->dev); 344 /* To prevent the immediately calling watch_dog after scan. */ 345 if (ieee->LinkDetectInfo.NumRecvBcnInPeriod == 0 || ieee->LinkDetectInfo.NumRecvDataInPeriod == 0) { 346 ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1; 347 ieee->LinkDetectInfo.NumRecvDataInPeriod = 1; 348 } 349 if (ieee->data_hard_resume) 350 ieee->data_hard_resume(ieee->dev); 351 352 if (ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) 353 ieee80211_start_send_beacons(ieee); 354 355 netif_carrier_on(ieee->dev); 356 mutex_unlock(&ieee->wx_mutex); 357 358 } 359 360 int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a, 361 union iwreq_data *wrqu, char *b) 362 { 363 int ret = 0; 364 365 mutex_lock(&ieee->wx_mutex); 366 367 if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)) { 368 ret = -1; 369 goto out; 370 } 371 372 if (ieee->state == IEEE80211_LINKED) { 373 queue_work(ieee->wq, &ieee->wx_sync_scan_wq); 374 /* intentionally forget to up sem */ 375 return 0; 376 } 377 378 out: 379 mutex_unlock(&ieee->wx_mutex); 380 return ret; 381 } 382 EXPORT_SYMBOL(ieee80211_wx_set_scan); 383 384 int ieee80211_wx_set_essid(struct ieee80211_device *ieee, 385 struct iw_request_info *a, 386 union iwreq_data *wrqu, char *extra) 387 { 388 389 int ret = 0, len; 390 short proto_started; 391 unsigned long flags; 392 393 ieee->sync_scan_hurryup = 1; 394 mutex_lock(&ieee->wx_mutex); 395 396 proto_started = ieee->proto_started; 397 398 if (wrqu->essid.length > IW_ESSID_MAX_SIZE) { 399 ret = -E2BIG; 400 goto out; 401 } 402 403 if (ieee->iw_mode == IW_MODE_MONITOR) { 404 ret = -1; 405 goto out; 406 } 407 408 if (proto_started) 409 ieee80211_stop_protocol(ieee); 410 411 412 /* this is just to be sure that the GET wx callback 413 * has consisten infos. not needed otherwise 414 */ 415 spin_lock_irqsave(&ieee->lock, flags); 416 417 if (wrqu->essid.flags && wrqu->essid.length) { 418 /* first flush current network.ssid */ 419 len = ((wrqu->essid.length-1) < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length-1) : IW_ESSID_MAX_SIZE; 420 strncpy(ieee->current_network.ssid, extra, len+1); 421 ieee->current_network.ssid_len = len+1; 422 ieee->ssid_set = 1; 423 } else { 424 ieee->ssid_set = 0; 425 ieee->current_network.ssid[0] = '\0'; 426 ieee->current_network.ssid_len = 0; 427 } 428 spin_unlock_irqrestore(&ieee->lock, flags); 429 430 if (proto_started) 431 ieee80211_start_protocol(ieee); 432 out: 433 mutex_unlock(&ieee->wx_mutex); 434 return ret; 435 } 436 EXPORT_SYMBOL(ieee80211_wx_set_essid); 437 438 int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a, 439 union iwreq_data *wrqu, char *b) 440 { 441 442 wrqu->mode = ieee->iw_mode; 443 return 0; 444 } 445 EXPORT_SYMBOL(ieee80211_wx_get_mode); 446 447 int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, 448 struct iw_request_info *info, 449 union iwreq_data *wrqu, char *extra) 450 { 451 452 int *parms = (int *)extra; 453 int enable = (parms[0] > 0); 454 short prev = ieee->raw_tx; 455 456 mutex_lock(&ieee->wx_mutex); 457 458 if (enable) 459 ieee->raw_tx = 1; 460 else 461 ieee->raw_tx = 0; 462 463 printk(KERN_INFO"raw TX is %s\n", 464 ieee->raw_tx ? "enabled" : "disabled"); 465 466 if (ieee->iw_mode == IW_MODE_MONITOR) { 467 if (prev == 0 && ieee->raw_tx) { 468 if (ieee->data_hard_resume) 469 ieee->data_hard_resume(ieee->dev); 470 471 netif_carrier_on(ieee->dev); 472 } 473 474 if (prev && ieee->raw_tx == 1) 475 netif_carrier_off(ieee->dev); 476 } 477 478 mutex_unlock(&ieee->wx_mutex); 479 480 return 0; 481 } 482 EXPORT_SYMBOL(ieee80211_wx_set_rawtx); 483 484 int ieee80211_wx_get_name(struct ieee80211_device *ieee, 485 struct iw_request_info *info, 486 union iwreq_data *wrqu, char *extra) 487 { 488 strlcpy(wrqu->name, "802.11", IFNAMSIZ); 489 if (ieee->modulation & IEEE80211_CCK_MODULATION) { 490 strlcat(wrqu->name, "b", IFNAMSIZ); 491 if (ieee->modulation & IEEE80211_OFDM_MODULATION) 492 strlcat(wrqu->name, "/g", IFNAMSIZ); 493 } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) { 494 strlcat(wrqu->name, "g", IFNAMSIZ); 495 } 496 497 if (ieee->mode & (IEEE_N_24G | IEEE_N_5G)) 498 strlcat(wrqu->name, "/n", IFNAMSIZ); 499 500 if ((ieee->state == IEEE80211_LINKED) || 501 (ieee->state == IEEE80211_LINKED_SCANNING)) 502 strlcat(wrqu->name, " linked", IFNAMSIZ); 503 else if (ieee->state != IEEE80211_NOLINK) 504 strlcat(wrqu->name, " link..", IFNAMSIZ); 505 506 return 0; 507 } 508 EXPORT_SYMBOL(ieee80211_wx_get_name); 509 510 /* this is mostly stolen from hostap */ 511 int 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 517 mutex_lock(&ieee->wx_mutex); 518 519 if (wrqu->power.disabled) { 520 ieee->ps = IEEE80211_PS_DISABLED; 521 goto exit; 522 } 523 if (wrqu->power.flags & IW_POWER_TIMEOUT) { 524 /* ieee->ps_period = wrqu->power.value / 1000; */ 525 ieee->ps_timeout = wrqu->power.value / 1000; 526 } 527 528 if (wrqu->power.flags & IW_POWER_PERIOD) { 529 530 /* ieee->ps_timeout = wrqu->power.value / 1000; */ 531 ieee->ps_period = wrqu->power.value / 1000; 532 /* wrq->value / 1024; */ 533 534 } 535 switch (wrqu->power.flags & IW_POWER_MODE) { 536 case IW_POWER_UNICAST_R: 537 ieee->ps = IEEE80211_PS_UNICAST; 538 break; 539 case IW_POWER_MULTICAST_R: 540 ieee->ps = IEEE80211_PS_MBCAST; 541 break; 542 case IW_POWER_ALL_R: 543 ieee->ps = IEEE80211_PS_UNICAST | IEEE80211_PS_MBCAST; 544 break; 545 546 case IW_POWER_ON: 547 /* ieee->ps = IEEE80211_PS_DISABLED; */ 548 break; 549 550 default: 551 ret = -EINVAL; 552 goto exit; 553 554 } 555 exit: 556 mutex_unlock(&ieee->wx_mutex); 557 return ret; 558 559 } 560 EXPORT_SYMBOL(ieee80211_wx_set_power); 561 562 /* this is stolen from hostap */ 563 int ieee80211_wx_get_power(struct ieee80211_device *ieee, 564 struct iw_request_info *info, 565 union iwreq_data *wrqu, char *extra) 566 { 567 mutex_lock(&ieee->wx_mutex); 568 569 if (ieee->ps == IEEE80211_PS_DISABLED) { 570 wrqu->power.disabled = 1; 571 goto exit; 572 } 573 574 wrqu->power.disabled = 0; 575 576 if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { 577 wrqu->power.flags = IW_POWER_TIMEOUT; 578 wrqu->power.value = ieee->ps_timeout * 1000; 579 } else { 580 /* ret = -EOPNOTSUPP; */ 581 /* goto exit; */ 582 wrqu->power.flags = IW_POWER_PERIOD; 583 wrqu->power.value = ieee->ps_period * 1000; 584 /* ieee->current_network.dtim_period * ieee->current_network.beacon_interval * 1024; */ 585 } 586 587 if ((ieee->ps & (IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST)) == (IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST)) 588 wrqu->power.flags |= IW_POWER_ALL_R; 589 else if (ieee->ps & IEEE80211_PS_MBCAST) 590 wrqu->power.flags |= IW_POWER_MULTICAST_R; 591 else 592 wrqu->power.flags |= IW_POWER_UNICAST_R; 593 594 exit: 595 mutex_unlock(&ieee->wx_mutex); 596 return 0; 597 598 } 599 EXPORT_SYMBOL(ieee80211_wx_get_power); 600