1 // SPDX-License-Identifier: GPL-2.0 2 /* IEEE 802.11 SoftMAC layer 3 * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com> 4 * 5 * Mostly extracted from the rtl8180-sa2400 driver for the 6 * in-kernel generic ieee802.11 stack. 7 * 8 * Some pieces of code might be stolen from ipw2100 driver 9 * copyright of who own it's copyright ;-) 10 * 11 * PS wx handler mostly stolen from hostap, copyright who 12 * own it's copyright ;-) 13 */ 14 #include <linux/etherdevice.h> 15 16 #include "rtllib.h" 17 #include "dot11d.h" 18 /* FIXME: add A freqs */ 19 20 const long rtllib_wlan_frequencies[] = { 21 2412, 2417, 2422, 2427, 22 2432, 2437, 2442, 2447, 23 2452, 2457, 2462, 2467, 24 2472, 2484 25 }; 26 EXPORT_SYMBOL(rtllib_wlan_frequencies); 27 28 29 int rtllib_wx_set_freq(struct rtllib_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 mutex_lock(&ieee->wx_mutex); 36 37 if (ieee->iw_mode == IW_MODE_INFRA) { 38 ret = 0; 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 != rtllib_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 (ieee->active_channel_map[fwrq->m] != 1) { 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 || 72 ieee->iw_mode == IW_MODE_MASTER) 73 if (ieee->state == RTLLIB_LINKED) { 74 rtllib_stop_send_beacons(ieee); 75 rtllib_start_send_beacons(ieee); 76 } 77 } 78 79 ret = 0; 80 out: 81 mutex_unlock(&ieee->wx_mutex); 82 return ret; 83 } 84 EXPORT_SYMBOL(rtllib_wx_set_freq); 85 86 87 int rtllib_wx_get_freq(struct rtllib_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 fwrq->m = rtllib_wlan_frequencies[ieee->current_network.channel-1] * 96 100000; 97 fwrq->e = 1; 98 return 0; 99 } 100 EXPORT_SYMBOL(rtllib_wx_get_freq); 101 102 int rtllib_wx_get_wap(struct rtllib_device *ieee, 103 struct iw_request_info *info, 104 union iwreq_data *wrqu, char *extra) 105 { 106 unsigned long flags; 107 108 wrqu->ap_addr.sa_family = ARPHRD_ETHER; 109 110 if (ieee->iw_mode == IW_MODE_MONITOR) 111 return -1; 112 113 /* We want avoid to give to the user inconsistent infos*/ 114 spin_lock_irqsave(&ieee->lock, flags); 115 116 if (ieee->state != RTLLIB_LINKED && 117 ieee->state != RTLLIB_LINKED_SCANNING && 118 ieee->wap_set == 0) 119 120 eth_zero_addr(wrqu->ap_addr.sa_data); 121 else 122 memcpy(wrqu->ap_addr.sa_data, 123 ieee->current_network.bssid, ETH_ALEN); 124 125 spin_unlock_irqrestore(&ieee->lock, flags); 126 127 return 0; 128 } 129 EXPORT_SYMBOL(rtllib_wx_get_wap); 130 131 132 int rtllib_wx_set_wap(struct rtllib_device *ieee, 133 struct iw_request_info *info, 134 union iwreq_data *awrq, 135 char *extra) 136 { 137 138 int ret = 0; 139 unsigned long flags; 140 141 short ifup = ieee->proto_started; 142 struct sockaddr *temp = (struct sockaddr *)awrq; 143 144 rtllib_stop_scan_syncro(ieee); 145 146 mutex_lock(&ieee->wx_mutex); 147 /* use ifconfig hw ether */ 148 if (ieee->iw_mode == IW_MODE_MASTER) { 149 ret = -1; 150 goto out; 151 } 152 153 if (temp->sa_family != ARPHRD_ETHER) { 154 ret = -EINVAL; 155 goto out; 156 } 157 158 if (is_zero_ether_addr(temp->sa_data)) { 159 spin_lock_irqsave(&ieee->lock, flags); 160 ether_addr_copy(ieee->current_network.bssid, temp->sa_data); 161 ieee->wap_set = 0; 162 spin_unlock_irqrestore(&ieee->lock, flags); 163 ret = -1; 164 goto out; 165 } 166 167 168 if (ifup) 169 rtllib_stop_protocol(ieee, true); 170 171 /* just to avoid to give inconsistent infos in the 172 * get wx method. not really needed otherwise 173 */ 174 spin_lock_irqsave(&ieee->lock, flags); 175 176 ieee->cannot_notify = false; 177 ether_addr_copy(ieee->current_network.bssid, temp->sa_data); 178 ieee->wap_set = !is_zero_ether_addr(temp->sa_data); 179 180 spin_unlock_irqrestore(&ieee->lock, flags); 181 182 if (ifup) 183 rtllib_start_protocol(ieee); 184 out: 185 mutex_unlock(&ieee->wx_mutex); 186 return ret; 187 } 188 EXPORT_SYMBOL(rtllib_wx_set_wap); 189 190 int rtllib_wx_get_essid(struct rtllib_device *ieee, struct iw_request_info *a, 191 union iwreq_data *wrqu, char *b) 192 { 193 int len, ret = 0; 194 unsigned long flags; 195 196 if (ieee->iw_mode == IW_MODE_MONITOR) 197 return -1; 198 199 /* We want avoid to give to the user inconsistent infos*/ 200 spin_lock_irqsave(&ieee->lock, flags); 201 202 if (ieee->current_network.ssid[0] == '\0' || 203 ieee->current_network.ssid_len == 0) { 204 ret = -1; 205 goto out; 206 } 207 208 if (ieee->state != RTLLIB_LINKED && 209 ieee->state != RTLLIB_LINKED_SCANNING && 210 ieee->ssid_set == 0) { 211 ret = -1; 212 goto out; 213 } 214 len = ieee->current_network.ssid_len; 215 wrqu->essid.length = len; 216 strncpy(b, ieee->current_network.ssid, len); 217 wrqu->essid.flags = 1; 218 219 out: 220 spin_unlock_irqrestore(&ieee->lock, flags); 221 222 return ret; 223 224 } 225 EXPORT_SYMBOL(rtllib_wx_get_essid); 226 227 int rtllib_wx_set_rate(struct rtllib_device *ieee, 228 struct iw_request_info *info, 229 union iwreq_data *wrqu, char *extra) 230 { 231 232 u32 target_rate = wrqu->bitrate.value; 233 234 ieee->rate = target_rate/100000; 235 return 0; 236 } 237 EXPORT_SYMBOL(rtllib_wx_set_rate); 238 239 int rtllib_wx_get_rate(struct rtllib_device *ieee, 240 struct iw_request_info *info, 241 union iwreq_data *wrqu, char *extra) 242 { 243 u32 tmp_rate; 244 245 tmp_rate = TxCountToDataRate(ieee, 246 ieee->softmac_stats.CurrentShowTxate); 247 wrqu->bitrate.value = tmp_rate * 500000; 248 249 return 0; 250 } 251 EXPORT_SYMBOL(rtllib_wx_get_rate); 252 253 254 int rtllib_wx_set_rts(struct rtllib_device *ieee, 255 struct iw_request_info *info, 256 union iwreq_data *wrqu, char *extra) 257 { 258 if (wrqu->rts.disabled || !wrqu->rts.fixed) 259 ieee->rts = DEFAULT_RTS_THRESHOLD; 260 else { 261 if (wrqu->rts.value < MIN_RTS_THRESHOLD || 262 wrqu->rts.value > MAX_RTS_THRESHOLD) 263 return -EINVAL; 264 ieee->rts = wrqu->rts.value; 265 } 266 return 0; 267 } 268 EXPORT_SYMBOL(rtllib_wx_set_rts); 269 270 int rtllib_wx_get_rts(struct rtllib_device *ieee, 271 struct iw_request_info *info, 272 union iwreq_data *wrqu, char *extra) 273 { 274 wrqu->rts.value = ieee->rts; 275 wrqu->rts.fixed = 0; /* no auto select */ 276 wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); 277 return 0; 278 } 279 EXPORT_SYMBOL(rtllib_wx_get_rts); 280 281 int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a, 282 union iwreq_data *wrqu, char *b) 283 { 284 int set_mode_status = 0; 285 286 rtllib_stop_scan_syncro(ieee); 287 mutex_lock(&ieee->wx_mutex); 288 switch (wrqu->mode) { 289 case IW_MODE_MONITOR: 290 case IW_MODE_ADHOC: 291 case IW_MODE_INFRA: 292 break; 293 case IW_MODE_AUTO: 294 wrqu->mode = IW_MODE_INFRA; 295 break; 296 default: 297 set_mode_status = -EINVAL; 298 goto out; 299 } 300 301 if (wrqu->mode == ieee->iw_mode) 302 goto out; 303 304 if (wrqu->mode == IW_MODE_MONITOR) { 305 ieee->dev->type = ARPHRD_IEEE80211; 306 rtllib_EnableNetMonitorMode(ieee->dev, false); 307 } else { 308 ieee->dev->type = ARPHRD_ETHER; 309 if (ieee->iw_mode == IW_MODE_MONITOR) 310 rtllib_DisableNetMonitorMode(ieee->dev, false); 311 } 312 313 if (!ieee->proto_started) { 314 ieee->iw_mode = wrqu->mode; 315 } else { 316 rtllib_stop_protocol(ieee, true); 317 ieee->iw_mode = wrqu->mode; 318 rtllib_start_protocol(ieee); 319 } 320 321 out: 322 mutex_unlock(&ieee->wx_mutex); 323 return set_mode_status; 324 } 325 EXPORT_SYMBOL(rtllib_wx_set_mode); 326 327 void rtllib_wx_sync_scan_wq(void *data) 328 { 329 struct rtllib_device *ieee = container_of_work_rsl(data, 330 struct rtllib_device, wx_sync_scan_wq); 331 short chan; 332 enum ht_extchnl_offset chan_offset = 0; 333 enum ht_channel_width bandwidth = 0; 334 int b40M = 0; 335 336 if (!(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) { 337 rtllib_start_scan_syncro(ieee, 0); 338 goto out; 339 } 340 341 chan = ieee->current_network.channel; 342 343 if (ieee->LeisurePSLeave) 344 ieee->LeisurePSLeave(ieee->dev); 345 /* notify AP to be in PS mode */ 346 rtllib_sta_ps_send_null_frame(ieee, 1); 347 rtllib_sta_ps_send_null_frame(ieee, 1); 348 349 rtllib_stop_all_queues(ieee); 350 351 if (ieee->data_hard_stop) 352 ieee->data_hard_stop(ieee->dev); 353 rtllib_stop_send_beacons(ieee); 354 ieee->state = RTLLIB_LINKED_SCANNING; 355 ieee->link_change(ieee->dev); 356 /* wait for ps packet to be kicked out successfully */ 357 msleep(50); 358 359 if (ieee->ScanOperationBackupHandler) 360 ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_BACKUP); 361 362 if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT && 363 ieee->pHTInfo->bCurBW40MHz) { 364 b40M = 1; 365 chan_offset = ieee->pHTInfo->CurSTAExtChnlOffset; 366 bandwidth = (enum ht_channel_width)ieee->pHTInfo->bCurBW40MHz; 367 RT_TRACE(COMP_DBG, "Scan in 40M, force to 20M first:%d, %d\n", 368 chan_offset, bandwidth); 369 ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20, 370 HT_EXTCHNL_OFFSET_NO_EXT); 371 } 372 373 rtllib_start_scan_syncro(ieee, 0); 374 375 if (b40M) { 376 RT_TRACE(COMP_DBG, "Scan in 20M, back to 40M\n"); 377 if (chan_offset == HT_EXTCHNL_OFFSET_UPPER) 378 ieee->set_chan(ieee->dev, chan + 2); 379 else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER) 380 ieee->set_chan(ieee->dev, chan - 2); 381 else 382 ieee->set_chan(ieee->dev, chan); 383 ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset); 384 } else { 385 ieee->set_chan(ieee->dev, chan); 386 } 387 388 if (ieee->ScanOperationBackupHandler) 389 ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_RESTORE); 390 391 ieee->state = RTLLIB_LINKED; 392 ieee->link_change(ieee->dev); 393 394 /* Notify AP that I wake up again */ 395 rtllib_sta_ps_send_null_frame(ieee, 0); 396 397 if (ieee->LinkDetectInfo.NumRecvBcnInPeriod == 0 || 398 ieee->LinkDetectInfo.NumRecvDataInPeriod == 0) { 399 ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1; 400 ieee->LinkDetectInfo.NumRecvDataInPeriod = 1; 401 } 402 403 if (ieee->data_hard_resume) 404 ieee->data_hard_resume(ieee->dev); 405 406 if (ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) 407 rtllib_start_send_beacons(ieee); 408 409 rtllib_wake_all_queues(ieee); 410 411 out: 412 mutex_unlock(&ieee->wx_mutex); 413 414 } 415 416 int rtllib_wx_set_scan(struct rtllib_device *ieee, struct iw_request_info *a, 417 union iwreq_data *wrqu, char *b) 418 { 419 int ret = 0; 420 421 mutex_lock(&ieee->wx_mutex); 422 423 if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)) { 424 ret = -1; 425 goto out; 426 } 427 428 if (ieee->state == RTLLIB_LINKED) { 429 schedule_work(&ieee->wx_sync_scan_wq); 430 /* intentionally forget to up sem */ 431 return 0; 432 } 433 434 out: 435 mutex_unlock(&ieee->wx_mutex); 436 return ret; 437 } 438 EXPORT_SYMBOL(rtllib_wx_set_scan); 439 440 int rtllib_wx_set_essid(struct rtllib_device *ieee, 441 struct iw_request_info *a, 442 union iwreq_data *wrqu, char *extra) 443 { 444 445 int ret = 0, len, i; 446 short proto_started; 447 unsigned long flags; 448 449 rtllib_stop_scan_syncro(ieee); 450 mutex_lock(&ieee->wx_mutex); 451 452 proto_started = ieee->proto_started; 453 454 len = min_t(__u16, wrqu->essid.length, IW_ESSID_MAX_SIZE); 455 456 if (ieee->iw_mode == IW_MODE_MONITOR) { 457 ret = -1; 458 goto out; 459 } 460 461 for (i = 0; i < len; i++) { 462 if (extra[i] < 0) { 463 ret = -1; 464 goto out; 465 } 466 } 467 468 if (proto_started) 469 rtllib_stop_protocol(ieee, true); 470 471 472 /* this is just to be sure that the GET wx callback 473 * has consistent infos. not needed otherwise 474 */ 475 spin_lock_irqsave(&ieee->lock, flags); 476 477 if (wrqu->essid.flags && wrqu->essid.length) { 478 strncpy(ieee->current_network.ssid, extra, len); 479 ieee->current_network.ssid_len = len; 480 ieee->cannot_notify = false; 481 ieee->ssid_set = 1; 482 } else { 483 ieee->ssid_set = 0; 484 ieee->current_network.ssid[0] = '\0'; 485 ieee->current_network.ssid_len = 0; 486 } 487 spin_unlock_irqrestore(&ieee->lock, flags); 488 489 if (proto_started) 490 rtllib_start_protocol(ieee); 491 out: 492 mutex_unlock(&ieee->wx_mutex); 493 return ret; 494 } 495 EXPORT_SYMBOL(rtllib_wx_set_essid); 496 497 int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a, 498 union iwreq_data *wrqu, char *b) 499 { 500 wrqu->mode = ieee->iw_mode; 501 return 0; 502 } 503 EXPORT_SYMBOL(rtllib_wx_get_mode); 504 505 int rtllib_wx_set_rawtx(struct rtllib_device *ieee, 506 struct iw_request_info *info, 507 union iwreq_data *wrqu, char *extra) 508 { 509 510 int *parms = (int *)extra; 511 int enable = (parms[0] > 0); 512 short prev = ieee->raw_tx; 513 514 mutex_lock(&ieee->wx_mutex); 515 516 if (enable) 517 ieee->raw_tx = 1; 518 else 519 ieee->raw_tx = 0; 520 521 netdev_info(ieee->dev, "raw TX is %s\n", 522 ieee->raw_tx ? "enabled" : "disabled"); 523 524 if (ieee->iw_mode == IW_MODE_MONITOR) { 525 if (prev == 0 && ieee->raw_tx) { 526 if (ieee->data_hard_resume) 527 ieee->data_hard_resume(ieee->dev); 528 529 netif_carrier_on(ieee->dev); 530 } 531 532 if (prev && ieee->raw_tx == 1) 533 netif_carrier_off(ieee->dev); 534 } 535 536 mutex_unlock(&ieee->wx_mutex); 537 538 return 0; 539 } 540 EXPORT_SYMBOL(rtllib_wx_set_rawtx); 541 542 int rtllib_wx_get_name(struct rtllib_device *ieee, struct iw_request_info *info, 543 union iwreq_data *wrqu, char *extra) 544 { 545 const char *b = ieee->modulation & RTLLIB_CCK_MODULATION ? "b" : ""; 546 const char *g = ieee->modulation & RTLLIB_OFDM_MODULATION ? "g" : ""; 547 const char *n = ieee->mode & (IEEE_N_24G | IEEE_N_5G) ? "n" : ""; 548 549 scnprintf(wrqu->name, sizeof(wrqu->name), "802.11%s%s%s", b, g, n); 550 return 0; 551 } 552 EXPORT_SYMBOL(rtllib_wx_get_name); 553 554 555 /* this is mostly stolen from hostap */ 556 int rtllib_wx_set_power(struct rtllib_device *ieee, 557 struct iw_request_info *info, 558 union iwreq_data *wrqu, char *extra) 559 { 560 int ret = 0; 561 562 if ((!ieee->sta_wake_up) || 563 (!ieee->enter_sleep_state) || 564 (!ieee->ps_is_queue_empty)) { 565 netdev_warn(ieee->dev, 566 "%s(): PS mode is tried to be use but driver missed a callback\n", 567 __func__); 568 return -1; 569 } 570 571 mutex_lock(&ieee->wx_mutex); 572 573 if (wrqu->power.disabled) { 574 RT_TRACE(COMP_DBG, "===>%s(): power disable\n", __func__); 575 ieee->ps = RTLLIB_PS_DISABLED; 576 goto exit; 577 } 578 if (wrqu->power.flags & IW_POWER_TIMEOUT) { 579 ieee->ps_timeout = wrqu->power.value / 1000; 580 RT_TRACE(COMP_DBG, "===>%s():ps_timeout is %d\n", __func__, 581 ieee->ps_timeout); 582 } 583 584 if (wrqu->power.flags & IW_POWER_PERIOD) 585 ieee->ps_period = wrqu->power.value / 1000; 586 587 switch (wrqu->power.flags & IW_POWER_MODE) { 588 case IW_POWER_UNICAST_R: 589 ieee->ps = RTLLIB_PS_UNICAST; 590 break; 591 case IW_POWER_MULTICAST_R: 592 ieee->ps = RTLLIB_PS_MBCAST; 593 break; 594 case IW_POWER_ALL_R: 595 ieee->ps = RTLLIB_PS_UNICAST | RTLLIB_PS_MBCAST; 596 break; 597 598 case IW_POWER_ON: 599 break; 600 601 default: 602 ret = -EINVAL; 603 goto exit; 604 605 } 606 exit: 607 mutex_unlock(&ieee->wx_mutex); 608 return ret; 609 610 } 611 EXPORT_SYMBOL(rtllib_wx_set_power); 612 613 /* this is stolen from hostap */ 614 int rtllib_wx_get_power(struct rtllib_device *ieee, 615 struct iw_request_info *info, 616 union iwreq_data *wrqu, char *extra) 617 { 618 mutex_lock(&ieee->wx_mutex); 619 620 if (ieee->ps == RTLLIB_PS_DISABLED) { 621 wrqu->power.disabled = 1; 622 goto exit; 623 } 624 625 wrqu->power.disabled = 0; 626 627 if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { 628 wrqu->power.flags = IW_POWER_TIMEOUT; 629 wrqu->power.value = ieee->ps_timeout * 1000; 630 } else { 631 wrqu->power.flags = IW_POWER_PERIOD; 632 wrqu->power.value = ieee->ps_period * 1000; 633 } 634 635 if ((ieee->ps & (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) == 636 (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) 637 wrqu->power.flags |= IW_POWER_ALL_R; 638 else if (ieee->ps & RTLLIB_PS_MBCAST) 639 wrqu->power.flags |= IW_POWER_MULTICAST_R; 640 else 641 wrqu->power.flags |= IW_POWER_UNICAST_R; 642 643 exit: 644 mutex_unlock(&ieee->wx_mutex); 645 return 0; 646 647 } 648 EXPORT_SYMBOL(rtllib_wx_get_power); 649