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 15 16 #include <linux/etherdevice.h> 17 18 #include "ieee80211.h" 19 #include "dot11d.h" 20 /* FIXME: add A freqs */ 21 22 const long ieee80211_wlan_frequencies[] = { 23 2412, 2417, 2422, 2427, 24 2432, 2437, 2442, 2447, 25 2452, 2457, 2462, 2467, 26 2472, 2484 27 }; 28 EXPORT_SYMBOL(ieee80211_wlan_frequencies); 29 30 int 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 mutex_lock(&ieee->wx_mutex); 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 if (!(GET_DOT11D_INFO(ieee)->channel_map)[fwrq->m]) { 66 ret = -EINVAL; 67 goto out; 68 } 69 ieee->current_network.channel = fwrq->m; 70 ieee->set_chan(ieee->dev, ieee->current_network.channel); 71 72 if (ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) 73 if (ieee->state == IEEE80211_LINKED) { 74 ieee80211_stop_send_beacons(ieee); 75 ieee80211_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(ieee80211_wx_set_freq); 85 86 int 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 EXPORT_SYMBOL(ieee80211_wx_get_freq); 103 104 int ieee80211_wx_get_wap(struct ieee80211_device *ieee, 105 struct iw_request_info *info, 106 union iwreq_data *wrqu, char *extra) 107 { 108 unsigned long flags; 109 110 wrqu->ap_addr.sa_family = ARPHRD_ETHER; 111 112 if (ieee->iw_mode == IW_MODE_MONITOR) 113 return -1; 114 115 /* We want avoid to give to the user inconsistent infos*/ 116 spin_lock_irqsave(&ieee->lock, flags); 117 118 if (ieee->state != IEEE80211_LINKED && 119 ieee->state != IEEE80211_LINKED_SCANNING && 120 ieee->wap_set == 0) 121 122 eth_zero_addr(wrqu->ap_addr.sa_data); 123 else 124 memcpy(wrqu->ap_addr.sa_data, 125 ieee->current_network.bssid, ETH_ALEN); 126 127 spin_unlock_irqrestore(&ieee->lock, flags); 128 129 return 0; 130 } 131 EXPORT_SYMBOL(ieee80211_wx_get_wap); 132 133 int ieee80211_wx_set_wap(struct ieee80211_device *ieee, 134 struct iw_request_info *info, 135 union iwreq_data *awrq, 136 char *extra) 137 { 138 139 int ret = 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 mutex_lock(&ieee->wx_mutex); 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 = !is_zero_ether_addr(temp->sa_data); 169 170 spin_unlock_irqrestore(&ieee->lock, flags); 171 172 if (ifup) 173 ieee80211_start_protocol(ieee); 174 out: 175 mutex_unlock(&ieee->wx_mutex); 176 return ret; 177 } 178 EXPORT_SYMBOL(ieee80211_wx_set_wap); 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 EXPORT_SYMBOL(ieee80211_wx_get_essid); 215 216 int 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 /* FIXME: we might want to limit rate also in management protocols. */ 225 return 0; 226 } 227 EXPORT_SYMBOL(ieee80211_wx_set_rate); 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 235 tmp_rate = TxCountToDataRate(ieee, ieee->softmac_stats.CurrentShowTxate); 236 237 wrqu->bitrate.value = tmp_rate * 500000; 238 239 return 0; 240 } 241 EXPORT_SYMBOL(ieee80211_wx_get_rate); 242 243 int ieee80211_wx_set_rts(struct ieee80211_device *ieee, 244 struct iw_request_info *info, 245 union iwreq_data *wrqu, char *extra) 246 { 247 if (wrqu->rts.disabled || !wrqu->rts.fixed) { 248 ieee->rts = DEFAULT_RTS_THRESHOLD; 249 } else { 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 EXPORT_SYMBOL(ieee80211_wx_set_rts); 258 259 int ieee80211_wx_get_rts(struct ieee80211_device *ieee, 260 struct iw_request_info *info, 261 union iwreq_data *wrqu, char *extra) 262 { 263 wrqu->rts.value = ieee->rts; 264 wrqu->rts.fixed = 0; /* no auto select */ 265 wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); 266 return 0; 267 } 268 EXPORT_SYMBOL(ieee80211_wx_get_rts); 269 270 int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a, 271 union iwreq_data *wrqu, char *b) 272 { 273 274 ieee->sync_scan_hurryup = 1; 275 276 mutex_lock(&ieee->wx_mutex); 277 278 if (wrqu->mode == ieee->iw_mode) 279 goto out; 280 281 if (wrqu->mode == IW_MODE_MONITOR) 282 ieee->dev->type = ARPHRD_IEEE80211; 283 else 284 ieee->dev->type = ARPHRD_ETHER; 285 286 if (!ieee->proto_started) { 287 ieee->iw_mode = wrqu->mode; 288 } else { 289 ieee80211_stop_protocol(ieee); 290 ieee->iw_mode = wrqu->mode; 291 ieee80211_start_protocol(ieee); 292 } 293 294 out: 295 mutex_unlock(&ieee->wx_mutex); 296 return 0; 297 } 298 EXPORT_SYMBOL(ieee80211_wx_set_mode); 299 300 void ieee80211_wx_sync_scan_wq(struct work_struct *work) 301 { 302 struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq); 303 short chan; 304 enum ht_extension_chan_offset chan_offset = 0; 305 enum ht_channel_width bandwidth = 0; 306 int b40M = 0; 307 308 chan = ieee->current_network.channel; 309 netif_carrier_off(ieee->dev); 310 311 if (ieee->data_hard_stop) 312 ieee->data_hard_stop(ieee->dev); 313 314 ieee80211_stop_send_beacons(ieee); 315 316 ieee->state = IEEE80211_LINKED_SCANNING; 317 ieee->link_change(ieee->dev); 318 ieee->InitialGainHandler(ieee->dev, IG_Backup); 319 if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT && ieee->pHTInfo->bCurBW40MHz) { 320 b40M = 1; 321 chan_offset = ieee->pHTInfo->CurSTAExtChnlOffset; 322 bandwidth = (enum ht_channel_width)ieee->pHTInfo->bCurBW40MHz; 323 printk("Scan in 40M, force to 20M first:%d, %d\n", chan_offset, bandwidth); 324 ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); 325 } 326 ieee80211_start_scan_syncro(ieee); 327 if (b40M) { 328 printk("Scan in 20M, back to 40M\n"); 329 if (chan_offset == HT_EXTCHNL_OFFSET_UPPER) 330 ieee->set_chan(ieee->dev, chan + 2); 331 else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER) 332 ieee->set_chan(ieee->dev, chan - 2); 333 else 334 ieee->set_chan(ieee->dev, chan); 335 ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset); 336 } else { 337 ieee->set_chan(ieee->dev, chan); 338 } 339 340 ieee->InitialGainHandler(ieee->dev, IG_Restore); 341 ieee->state = IEEE80211_LINKED; 342 ieee->link_change(ieee->dev); 343 /* To prevent the immediately calling watch_dog after scan. */ 344 if (ieee->LinkDetectInfo.NumRecvBcnInPeriod == 0 || ieee->LinkDetectInfo.NumRecvDataInPeriod == 0) { 345 ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1; 346 ieee->LinkDetectInfo.NumRecvDataInPeriod = 1; 347 } 348 if (ieee->data_hard_resume) 349 ieee->data_hard_resume(ieee->dev); 350 351 if (ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) 352 ieee80211_start_send_beacons(ieee); 353 354 netif_carrier_on(ieee->dev); 355 mutex_unlock(&ieee->wx_mutex); 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 mutex_lock(&ieee->wx_mutex); 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 mutex_unlock(&ieee->wx_mutex); 379 return ret; 380 } 381 EXPORT_SYMBOL(ieee80211_wx_set_scan); 382 383 int ieee80211_wx_set_essid(struct ieee80211_device *ieee, 384 struct iw_request_info *a, 385 union iwreq_data *wrqu, char *extra) 386 { 387 388 int ret = 0, len; 389 short proto_started; 390 unsigned long flags; 391 392 ieee->sync_scan_hurryup = 1; 393 mutex_lock(&ieee->wx_mutex); 394 395 proto_started = ieee->proto_started; 396 397 if (wrqu->essid.length > IW_ESSID_MAX_SIZE) { 398 ret = -E2BIG; 399 goto out; 400 } 401 402 if (ieee->iw_mode == IW_MODE_MONITOR) { 403 ret = -1; 404 goto out; 405 } 406 407 if (proto_started) 408 ieee80211_stop_protocol(ieee); 409 410 411 /* this is just to be sure that the GET wx callback 412 * has consisten infos. not needed otherwise 413 */ 414 spin_lock_irqsave(&ieee->lock, flags); 415 416 if (wrqu->essid.flags && wrqu->essid.length) { 417 /* first flush current network.ssid */ 418 len = ((wrqu->essid.length - 1) < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length - 1) : IW_ESSID_MAX_SIZE; 419 strncpy(ieee->current_network.ssid, extra, len + 1); 420 ieee->current_network.ssid_len = len + 1; 421 ieee->ssid_set = 1; 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 mutex_unlock(&ieee->wx_mutex); 433 return ret; 434 } 435 EXPORT_SYMBOL(ieee80211_wx_set_essid); 436 437 int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a, 438 union iwreq_data *wrqu, char *b) 439 { 440 441 wrqu->mode = ieee->iw_mode; 442 return 0; 443 } 444 EXPORT_SYMBOL(ieee80211_wx_get_mode); 445 446 int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, 447 struct iw_request_info *info, 448 union iwreq_data *wrqu, char *extra) 449 { 450 451 int *parms = (int *)extra; 452 int enable = (parms[0] > 0); 453 short prev = ieee->raw_tx; 454 455 mutex_lock(&ieee->wx_mutex); 456 457 if (enable) 458 ieee->raw_tx = 1; 459 else 460 ieee->raw_tx = 0; 461 462 netdev_info(ieee->dev, "raw TX is %s\n", 463 ieee->raw_tx ? "enabled" : "disabled"); 464 465 if (ieee->iw_mode == IW_MODE_MONITOR) { 466 if (prev == 0 && ieee->raw_tx) { 467 if (ieee->data_hard_resume) 468 ieee->data_hard_resume(ieee->dev); 469 470 netif_carrier_on(ieee->dev); 471 } 472 473 if (prev && ieee->raw_tx == 1) 474 netif_carrier_off(ieee->dev); 475 } 476 477 mutex_unlock(&ieee->wx_mutex); 478 479 return 0; 480 } 481 EXPORT_SYMBOL(ieee80211_wx_set_rawtx); 482 483 int ieee80211_wx_get_name(struct ieee80211_device *ieee, 484 struct iw_request_info *info, 485 union iwreq_data *wrqu, char *extra) 486 { 487 strscpy(wrqu->name, "802.11", IFNAMSIZ); 488 if (ieee->modulation & IEEE80211_CCK_MODULATION) { 489 strlcat(wrqu->name, "b", IFNAMSIZ); 490 if (ieee->modulation & IEEE80211_OFDM_MODULATION) 491 strlcat(wrqu->name, "/g", IFNAMSIZ); 492 } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) { 493 strlcat(wrqu->name, "g", IFNAMSIZ); 494 } 495 496 if (ieee->mode & (IEEE_N_24G | IEEE_N_5G)) 497 strlcat(wrqu->name, "/n", IFNAMSIZ); 498 499 if ((ieee->state == IEEE80211_LINKED) || 500 (ieee->state == IEEE80211_LINKED_SCANNING)) 501 strlcat(wrqu->name, " linked", IFNAMSIZ); 502 else if (ieee->state != IEEE80211_NOLINK) 503 strlcat(wrqu->name, " link..", IFNAMSIZ); 504 505 return 0; 506 } 507 EXPORT_SYMBOL(ieee80211_wx_get_name); 508 509 /* this is mostly stolen from hostap */ 510 int ieee80211_wx_set_power(struct ieee80211_device *ieee, 511 struct iw_request_info *info, 512 union iwreq_data *wrqu, char *extra) 513 { 514 int ret = 0; 515 516 mutex_lock(&ieee->wx_mutex); 517 518 if (wrqu->power.disabled) { 519 ieee->ps = IEEE80211_PS_DISABLED; 520 goto exit; 521 } 522 if (wrqu->power.flags & IW_POWER_TIMEOUT) { 523 /* ieee->ps_period = wrqu->power.value / 1000; */ 524 ieee->ps_timeout = wrqu->power.value / 1000; 525 } 526 527 if (wrqu->power.flags & IW_POWER_PERIOD) { 528 529 /* ieee->ps_timeout = wrqu->power.value / 1000; */ 530 ieee->ps_period = wrqu->power.value / 1000; 531 /* wrq->value / 1024; */ 532 533 } 534 switch (wrqu->power.flags & IW_POWER_MODE) { 535 case IW_POWER_UNICAST_R: 536 ieee->ps = IEEE80211_PS_UNICAST; 537 break; 538 case IW_POWER_MULTICAST_R: 539 ieee->ps = IEEE80211_PS_MBCAST; 540 break; 541 case IW_POWER_ALL_R: 542 ieee->ps = IEEE80211_PS_UNICAST | IEEE80211_PS_MBCAST; 543 break; 544 545 case IW_POWER_ON: 546 /* ieee->ps = IEEE80211_PS_DISABLED; */ 547 break; 548 549 default: 550 ret = -EINVAL; 551 goto exit; 552 553 } 554 exit: 555 mutex_unlock(&ieee->wx_mutex); 556 return ret; 557 558 } 559 EXPORT_SYMBOL(ieee80211_wx_set_power); 560 561 /* this is stolen from hostap */ 562 int ieee80211_wx_get_power(struct ieee80211_device *ieee, 563 struct iw_request_info *info, 564 union iwreq_data *wrqu, char *extra) 565 { 566 mutex_lock(&ieee->wx_mutex); 567 568 if (ieee->ps == IEEE80211_PS_DISABLED) { 569 wrqu->power.disabled = 1; 570 goto exit; 571 } 572 573 wrqu->power.disabled = 0; 574 575 if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { 576 wrqu->power.flags = IW_POWER_TIMEOUT; 577 wrqu->power.value = ieee->ps_timeout * 1000; 578 } else { 579 /* ret = -EOPNOTSUPP; */ 580 /* goto exit; */ 581 wrqu->power.flags = IW_POWER_PERIOD; 582 wrqu->power.value = ieee->ps_period * 1000; 583 /* ieee->current_network.dtim_period * ieee->current_network.beacon_interval * 1024; */ 584 } 585 586 if ((ieee->ps & (IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST)) == (IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST)) 587 wrqu->power.flags |= IW_POWER_ALL_R; 588 else if (ieee->ps & IEEE80211_PS_MBCAST) 589 wrqu->power.flags |= IW_POWER_MULTICAST_R; 590 else 591 wrqu->power.flags |= IW_POWER_UNICAST_R; 592 593 exit: 594 mutex_unlock(&ieee->wx_mutex); 595 return 0; 596 597 } 598 EXPORT_SYMBOL(ieee80211_wx_get_power); 599