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