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 19 20const long ieee80211_wlan_frequencies[] = { 21 2412, 2417, 2422, 2427, 22 2432, 2437, 2442, 2447, 23 2452, 2457, 2462, 2467, 24 2472, 2484 25}; 26 27 28int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a, 29 union iwreq_data *wrqu, char *b) 30{ 31 int ret; 32 struct iw_freq *fwrq = & wrqu->freq; 33// printk("in %s\n",__func__); 34 down(&ieee->wx_sem); 35 36 if(ieee->iw_mode == IW_MODE_INFRA){ 37 ret = -EOPNOTSUPP; 38 goto out; 39 } 40 41 /* if setting by freq convert to channel */ 42 if (fwrq->e == 1) { 43 if ((fwrq->m >= (int) 2.412e8 && 44 fwrq->m <= (int) 2.487e8)) { 45 int f = fwrq->m / 100000; 46 int c = 0; 47 48 while ((c < 14) && (f != ieee80211_wlan_frequencies[c])) 49 c++; 50 51 /* hack to fall through */ 52 fwrq->e = 0; 53 fwrq->m = c + 1; 54 } 55 } 56 57 if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1 ){ 58 ret = -EOPNOTSUPP; 59 goto out; 60 61 }else { /* Set the channel */ 62 63 64 ieee->current_network.channel = fwrq->m; 65 ieee->set_chan(ieee->dev, ieee->current_network.channel); 66 67 if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) 68 if(ieee->state == IEEE80211_LINKED){ 69 70 ieee80211_stop_send_beacons(ieee); 71 ieee80211_start_send_beacons(ieee); 72 } 73 } 74 75 ret = 0; 76out: 77 up(&ieee->wx_sem); 78 return ret; 79} 80 81 82int ieee80211_wx_get_freq(struct ieee80211_device *ieee, 83 struct iw_request_info *a, 84 union iwreq_data *wrqu, char *b) 85{ 86 struct iw_freq *fwrq = & wrqu->freq; 87 88 if (ieee->current_network.channel == 0) 89 return -1; 90 91 fwrq->m = ieee->current_network.channel; 92 fwrq->e = 0; 93 94 return 0; 95} 96 97int ieee80211_wx_get_wap(struct ieee80211_device *ieee, 98 struct iw_request_info *info, 99 union iwreq_data *wrqu, char *extra) 100{ 101 unsigned long flags; 102 103 wrqu->ap_addr.sa_family = ARPHRD_ETHER; 104 105 if (ieee->iw_mode == IW_MODE_MONITOR) 106 return -1; 107 108 /* We want avoid to give to the user inconsistent infos*/ 109 spin_lock_irqsave(&ieee->lock, flags); 110 111 if (ieee->state != IEEE80211_LINKED && 112 ieee->state != IEEE80211_LINKED_SCANNING && 113 ieee->wap_set == 0) 114 115 memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); 116 else 117 memcpy(wrqu->ap_addr.sa_data, 118 ieee->current_network.bssid, ETH_ALEN); 119 120 spin_unlock_irqrestore(&ieee->lock, flags); 121 122 return 0; 123} 124 125 126int ieee80211_wx_set_wap(struct ieee80211_device *ieee, 127 struct iw_request_info *info, 128 union iwreq_data *awrq, 129 char *extra) 130{ 131 132 int ret = 0; 133 u8 zero[] = {0,0,0,0,0,0}; 134 unsigned long flags; 135 136 short ifup = ieee->proto_started;//dev->flags & IFF_UP; 137 struct sockaddr *temp = (struct sockaddr *)awrq; 138 139 //printk("=======Set WAP:"); 140 ieee->sync_scan_hurryup = 1; 141 142 down(&ieee->wx_sem); 143 /* use ifconfig hw ether */ 144 if (ieee->iw_mode == IW_MODE_MASTER){ 145 ret = -1; 146 goto out; 147 } 148 149 if (temp->sa_family != ARPHRD_ETHER){ 150 ret = -EINVAL; 151 goto out; 152 } 153 154 if (ifup) 155 ieee80211_stop_protocol(ieee); 156 157 /* just to avoid to give inconsistent infos in the 158 * get wx method. not really needed otherwise 159 */ 160 spin_lock_irqsave(&ieee->lock, flags); 161 162 memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN); 163 ieee->wap_set = memcmp(temp->sa_data, zero,ETH_ALEN)!=0; 164 //printk(" %x:%x:%x:%x:%x:%x\n", ieee->current_network.bssid[0],ieee->current_network.bssid[1],ieee->current_network.bssid[2],ieee->current_network.bssid[3],ieee->current_network.bssid[4],ieee->current_network.bssid[5]); 165 166 spin_unlock_irqrestore(&ieee->lock, flags); 167 168 if (ifup) 169 ieee80211_start_protocol(ieee); 170 171out: 172 up(&ieee->wx_sem); 173 return ret; 174} 175 176 int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b) 177{ 178 int len,ret = 0; 179 unsigned long flags; 180 181 if (ieee->iw_mode == IW_MODE_MONITOR) 182 return -1; 183 184 /* We want avoid to give to the user inconsistent infos*/ 185 spin_lock_irqsave(&ieee->lock, flags); 186 187 if (ieee->current_network.ssid[0] == '\0' || 188 ieee->current_network.ssid_len == 0){ 189 ret = -1; 190 goto out; 191 } 192 193 if (ieee->state != IEEE80211_LINKED && 194 ieee->state != IEEE80211_LINKED_SCANNING && 195 ieee->ssid_set == 0){ 196 ret = -1; 197 goto out; 198 } 199 len = ieee->current_network.ssid_len; 200 wrqu->essid.length = len; 201 strncpy(b,ieee->current_network.ssid,len); 202 wrqu->essid.flags = 1; 203 204out: 205 spin_unlock_irqrestore(&ieee->lock, flags); 206 207 return ret; 208 209} 210 211int ieee80211_wx_set_rate(struct ieee80211_device *ieee, 212 struct iw_request_info *info, 213 union iwreq_data *wrqu, char *extra) 214{ 215 216 u32 target_rate = wrqu->bitrate.value; 217 218 //added by lizhaoming for auto mode 219 if(target_rate == -1){ 220 ieee->rate = 110; 221 } else { 222 ieee->rate = target_rate/100000; 223 } 224 return 0; 225} 226 227 228 229int ieee80211_wx_get_rate(struct ieee80211_device *ieee, 230 struct iw_request_info *info, 231 union iwreq_data *wrqu, char *extra) 232{ 233 234 wrqu->bitrate.value = ieee->rate * 100000; 235 236 return 0; 237} 238 239int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a, 240 union iwreq_data *wrqu, char *b) 241{ 242 243 ieee->sync_scan_hurryup = 1; 244 245 down(&ieee->wx_sem); 246 247 if (wrqu->mode == ieee->iw_mode) 248 goto out; 249 250 if (wrqu->mode == IW_MODE_MONITOR){ 251 252 ieee->dev->type = ARPHRD_IEEE80211; 253 }else{ 254 ieee->dev->type = ARPHRD_ETHER; 255 } 256 257 if (!ieee->proto_started){ 258 ieee->iw_mode = wrqu->mode; 259 }else{ 260 ieee80211_stop_protocol(ieee); 261 ieee->iw_mode = wrqu->mode; 262 ieee80211_start_protocol(ieee); 263 } 264 265out: 266 up(&ieee->wx_sem); 267 return 0; 268} 269 270 271void ieee80211_wx_sync_scan_wq(struct work_struct *work) 272{ 273 struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq); 274 short chan; 275 276 chan = ieee->current_network.channel; 277 278 if (ieee->data_hard_stop) 279 ieee->data_hard_stop(ieee->dev); 280 281 ieee80211_stop_send_beacons(ieee); 282 283 ieee->state = IEEE80211_LINKED_SCANNING; 284 ieee->link_change(ieee->dev); 285 286 ieee80211_start_scan_syncro(ieee); 287 288 ieee->set_chan(ieee->dev, chan); 289 290 ieee->state = IEEE80211_LINKED; 291 ieee->link_change(ieee->dev); 292 293 if (ieee->data_hard_resume) 294 ieee->data_hard_resume(ieee->dev); 295 296 if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) 297 ieee80211_start_send_beacons(ieee); 298 299 //YJ,add,080828, In prevent of lossing ping packet during scanning 300 //ieee80211_sta_ps_send_null_frame(ieee, false); 301 //YJ,add,080828,end 302 303 up(&ieee->wx_sem); 304 305} 306 307int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a, 308 union iwreq_data *wrqu, char *b) 309{ 310 int ret = 0; 311 312 down(&ieee->wx_sem); 313 314 if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)){ 315 ret = -1; 316 goto out; 317 } 318 //YJ,add,080828 319 //In prevent of lossing ping packet during scanning 320 //ieee80211_sta_ps_send_null_frame(ieee, true); 321 //YJ,add,080828,end 322 323 if ( ieee->state == IEEE80211_LINKED){ 324 queue_work(ieee->wq, &ieee->wx_sync_scan_wq); 325 /* intentionally forget to up sem */ 326 return 0; 327 } 328 329out: 330 up(&ieee->wx_sem); 331 return ret; 332} 333 334int ieee80211_wx_set_essid(struct ieee80211_device *ieee, 335 struct iw_request_info *a, 336 union iwreq_data *wrqu, char *extra) 337{ 338 339 int ret=0,len; 340 short proto_started; 341 unsigned long flags; 342 343 ieee->sync_scan_hurryup = 1; 344 345 down(&ieee->wx_sem); 346 347 proto_started = ieee->proto_started; 348 349 if (wrqu->essid.length > IW_ESSID_MAX_SIZE){ 350 ret= -E2BIG; 351 goto out; 352 } 353 354 if (ieee->iw_mode == IW_MODE_MONITOR){ 355 ret= -1; 356 goto out; 357 } 358 359 if(proto_started) 360 ieee80211_stop_protocol(ieee); 361 362 /* this is just to be sure that the GET wx callback 363 * has consisten infos. not needed otherwise 364 */ 365 spin_lock_irqsave(&ieee->lock, flags); 366 367 if (wrqu->essid.flags && wrqu->essid.length) { 368//YJ,modified,080819 369 len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length) : IW_ESSID_MAX_SIZE; 370 memset(ieee->current_network.ssid, 0, ieee->current_network.ssid_len); //YJ,add,080819 371 strncpy(ieee->current_network.ssid, extra, len); 372 ieee->current_network.ssid_len = len; 373 ieee->ssid_set = 1; 374//YJ,modified,080819,end 375 376 //YJ,add,080819,for hidden ap 377 if(len == 0){ 378 memset(ieee->current_network.bssid, 0, ETH_ALEN); 379 ieee->current_network.capability = 0; 380 } 381 //YJ,add,080819,for hidden ap,end 382 } 383 else{ 384 ieee->ssid_set = 0; 385 ieee->current_network.ssid[0] = '\0'; 386 ieee->current_network.ssid_len = 0; 387 } 388 //printk("==========set essid %s!\n",ieee->current_network.ssid); 389 spin_unlock_irqrestore(&ieee->lock, flags); 390 391 if (proto_started) 392 ieee80211_start_protocol(ieee); 393out: 394 up(&ieee->wx_sem); 395 return ret; 396} 397 398 int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a, 399 union iwreq_data *wrqu, char *b) 400{ 401 402 wrqu->mode = ieee->iw_mode; 403 return 0; 404} 405 406 int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, 407 struct iw_request_info *info, 408 union iwreq_data *wrqu, char *extra) 409{ 410 411 int *parms = (int *)extra; 412 int enable = (parms[0] > 0); 413 short prev = ieee->raw_tx; 414 415 down(&ieee->wx_sem); 416 417 if(enable) 418 ieee->raw_tx = 1; 419 else 420 ieee->raw_tx = 0; 421 422 printk(KERN_INFO"raw TX is %s\n", 423 ieee->raw_tx ? "enabled" : "disabled"); 424 425 if(ieee->iw_mode == IW_MODE_MONITOR) 426 { 427 if(prev == 0 && ieee->raw_tx){ 428 if (ieee->data_hard_resume) 429 ieee->data_hard_resume(ieee->dev); 430 431 netif_carrier_on(ieee->dev); 432 } 433 434 if(prev && ieee->raw_tx == 1) 435 netif_carrier_off(ieee->dev); 436 } 437 438 up(&ieee->wx_sem); 439 440 return 0; 441} 442 443int ieee80211_wx_get_name(struct ieee80211_device *ieee, 444 struct iw_request_info *info, 445 union iwreq_data *wrqu, char *extra) 446{ 447 strlcpy(wrqu->name, "802.11", IFNAMSIZ); 448 if(ieee->modulation & IEEE80211_CCK_MODULATION){ 449 strlcat(wrqu->name, "b", IFNAMSIZ); 450 if(ieee->modulation & IEEE80211_OFDM_MODULATION) 451 strlcat(wrqu->name, "/g", IFNAMSIZ); 452 }else if(ieee->modulation & IEEE80211_OFDM_MODULATION) 453 strlcat(wrqu->name, "g", IFNAMSIZ); 454 455 if((ieee->state == IEEE80211_LINKED) || 456 (ieee->state == IEEE80211_LINKED_SCANNING)) 457 strlcat(wrqu->name," link", IFNAMSIZ); 458 else if(ieee->state != IEEE80211_NOLINK) 459 strlcat(wrqu->name," .....", IFNAMSIZ); 460 461 462 return 0; 463} 464 465 466/* this is mostly stolen from hostap */ 467int ieee80211_wx_set_power(struct ieee80211_device *ieee, 468 struct iw_request_info *info, 469 union iwreq_data *wrqu, char *extra) 470{ 471 int ret = 0; 472 473 if( 474 (!ieee->sta_wake_up) || 475 (!ieee->ps_request_tx_ack) || 476 (!ieee->enter_sleep_state) || 477 (!ieee->ps_is_queue_empty)){ 478 479 printk("ERROR. PS mode tried to be use but driver missed a callback\n\n"); 480 481 return -1; 482 } 483 484 down(&ieee->wx_sem); 485 486 if (wrqu->power.disabled){ 487 ieee->ps = IEEE80211_PS_DISABLED; 488 489 goto exit; 490 } 491 switch (wrqu->power.flags & IW_POWER_MODE) { 492 case IW_POWER_UNICAST_R: 493 ieee->ps = IEEE80211_PS_UNICAST; 494 495 break; 496 case IW_POWER_ALL_R: 497 ieee->ps = IEEE80211_PS_UNICAST | IEEE80211_PS_MBCAST; 498 break; 499 500 case IW_POWER_ON: 501 ieee->ps = IEEE80211_PS_DISABLED; 502 break; 503 504 default: 505 ret = -EINVAL; 506 goto exit; 507 } 508 509 if (wrqu->power.flags & IW_POWER_TIMEOUT) { 510 511 ieee->ps_timeout = wrqu->power.value / 1000; 512 printk("Timeout %d\n",ieee->ps_timeout); 513 } 514 515 if (wrqu->power.flags & IW_POWER_PERIOD) { 516 517 ret = -EOPNOTSUPP; 518 goto exit; 519 //wrq->value / 1024; 520 521 } 522exit: 523 up(&ieee->wx_sem); 524 return ret; 525 526} 527 528/* this is stolen from hostap */ 529int ieee80211_wx_get_power(struct ieee80211_device *ieee, 530 struct iw_request_info *info, 531 union iwreq_data *wrqu, char *extra) 532{ 533 int ret =0; 534 535 down(&ieee->wx_sem); 536 537 if(ieee->ps == IEEE80211_PS_DISABLED){ 538 wrqu->power.disabled = 1; 539 goto exit; 540 } 541 542 wrqu->power.disabled = 0; 543 544// if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { 545 wrqu->power.flags = IW_POWER_TIMEOUT; 546 wrqu->power.value = ieee->ps_timeout * 1000; 547// } else { 548// ret = -EOPNOTSUPP; 549// goto exit; 550 //wrqu->power.flags = IW_POWER_PERIOD; 551 //wrqu->power.value = ieee->current_network.dtim_period * 552 // ieee->current_network.beacon_interval * 1024; 553// } 554 555 556 if (ieee->ps & IEEE80211_PS_MBCAST) 557 wrqu->power.flags |= IW_POWER_ALL_R; 558 else 559 wrqu->power.flags |= IW_POWER_UNICAST_R; 560 561exit: 562 up(&ieee->wx_sem); 563 return ret; 564 565} 566