]>
Commit | Line | Data |
---|---|---|
ecdfa446 | 1 | /* IEEE 802.11 SoftMAC layer |
93ba2a85 | 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 GKH |
37 | |
38 | down(&ieee->wx_sem); | |
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: | |
84 | up(&ieee->wx_sem); | |
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 | ||
123 | memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); | |
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 GKH |
148 | |
149 | down(&ieee->wx_sem); | |
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 LF |
162 | spin_lock_irqsave(&ieee->lock, flags); |
163 | memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN); | |
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; |
ecdfa446 | 180 | memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN); |
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 GKH |
187 | out: |
188 | up(&ieee->wx_sem); | |
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 | { | |
94a79942 | 246 | u32 tmp_rate = 0; |
a44be772 LF |
247 | tmp_rate = TxCountToDataRate(ieee, |
248 | ieee->softmac_stats.CurrentShowTxate); | |
ecdfa446 GKH |
249 | wrqu->bitrate.value = tmp_rate * 500000; |
250 | ||
251 | return 0; | |
252 | } | |
3b28499c | 253 | EXPORT_SYMBOL(rtllib_wx_get_rate); |
ecdfa446 GKH |
254 | |
255 | ||
94a79942 | 256 | int rtllib_wx_set_rts(struct rtllib_device *ieee, |
ecdfa446 GKH |
257 | struct iw_request_info *info, |
258 | union iwreq_data *wrqu, char *extra) | |
259 | { | |
260 | if (wrqu->rts.disabled || !wrqu->rts.fixed) | |
261 | ieee->rts = DEFAULT_RTS_THRESHOLD; | |
a44be772 | 262 | else { |
ecdfa446 GKH |
263 | if (wrqu->rts.value < MIN_RTS_THRESHOLD || |
264 | wrqu->rts.value > MAX_RTS_THRESHOLD) | |
265 | return -EINVAL; | |
266 | ieee->rts = wrqu->rts.value; | |
267 | } | |
268 | return 0; | |
269 | } | |
3b28499c | 270 | EXPORT_SYMBOL(rtllib_wx_set_rts); |
ecdfa446 | 271 | |
94a79942 | 272 | int rtllib_wx_get_rts(struct rtllib_device *ieee, |
ecdfa446 GKH |
273 | struct iw_request_info *info, |
274 | union iwreq_data *wrqu, char *extra) | |
275 | { | |
276 | wrqu->rts.value = ieee->rts; | |
277 | wrqu->rts.fixed = 0; /* no auto select */ | |
278 | wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); | |
279 | return 0; | |
280 | } | |
3b28499c | 281 | EXPORT_SYMBOL(rtllib_wx_get_rts); |
94a79942 LF |
282 | |
283 | int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a, | |
ecdfa446 GKH |
284 | union iwreq_data *wrqu, char *b) |
285 | { | |
94a79942 | 286 | int set_mode_status = 0; |
ecdfa446 | 287 | |
94a79942 | 288 | rtllib_stop_scan_syncro(ieee); |
ecdfa446 | 289 | down(&ieee->wx_sem); |
94a79942 LF |
290 | switch (wrqu->mode) { |
291 | case IW_MODE_MONITOR: | |
292 | case IW_MODE_ADHOC: | |
293 | case IW_MODE_INFRA: | |
294 | break; | |
295 | case IW_MODE_AUTO: | |
296 | wrqu->mode = IW_MODE_INFRA; | |
297 | break; | |
298 | default: | |
299 | set_mode_status = -EINVAL; | |
300 | goto out; | |
301 | } | |
ecdfa446 GKH |
302 | |
303 | if (wrqu->mode == ieee->iw_mode) | |
304 | goto out; | |
305 | ||
94a79942 | 306 | if (wrqu->mode == IW_MODE_MONITOR) { |
ecdfa446 | 307 | ieee->dev->type = ARPHRD_IEEE80211; |
a44be772 | 308 | rtllib_EnableNetMonitorMode(ieee->dev, false); |
94a79942 | 309 | } else { |
ecdfa446 | 310 | ieee->dev->type = ARPHRD_ETHER; |
94a79942 | 311 | if (ieee->iw_mode == IW_MODE_MONITOR) |
a44be772 | 312 | rtllib_DisableNetMonitorMode(ieee->dev, false); |
ecdfa446 GKH |
313 | } |
314 | ||
94a79942 | 315 | if (!ieee->proto_started) { |
ecdfa446 | 316 | ieee->iw_mode = wrqu->mode; |
94a79942 | 317 | } else { |
a44be772 | 318 | rtllib_stop_protocol(ieee, true); |
ecdfa446 | 319 | ieee->iw_mode = wrqu->mode; |
94a79942 | 320 | rtllib_start_protocol(ieee); |
ecdfa446 GKH |
321 | } |
322 | ||
323 | out: | |
324 | up(&ieee->wx_sem); | |
94a79942 | 325 | return set_mode_status; |
ecdfa446 | 326 | } |
3b28499c | 327 | EXPORT_SYMBOL(rtllib_wx_set_mode); |
ecdfa446 | 328 | |
94a79942 | 329 | void rtllib_wx_sync_scan_wq(void *data) |
ecdfa446 | 330 | { |
a44be772 LF |
331 | struct rtllib_device *ieee = container_of_work_rsl(data, |
332 | struct rtllib_device, wx_sync_scan_wq); | |
ecdfa446 | 333 | short chan; |
a44be772 LF |
334 | enum ht_extchnl_offset chan_offset = 0; |
335 | enum ht_channel_width bandwidth = 0; | |
ecdfa446 | 336 | int b40M = 0; |
a44be772 | 337 | static int count; |
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 | |
ecdfa446 | 414 | count = 0; |
94a79942 | 415 | out: |
ecdfa446 GKH |
416 | up(&ieee->wx_sem); |
417 | ||
418 | } | |
419 | ||
94a79942 | 420 | int rtllib_wx_set_scan(struct rtllib_device *ieee, struct iw_request_info *a, |
ecdfa446 GKH |
421 | union iwreq_data *wrqu, char *b) |
422 | { | |
423 | int ret = 0; | |
424 | ||
425 | down(&ieee->wx_sem); | |
426 | ||
a44be772 | 427 | if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)) { |
ecdfa446 GKH |
428 | ret = -1; |
429 | goto out; | |
430 | } | |
431 | ||
a44be772 | 432 | if (ieee->state == RTLLIB_LINKED) { |
94a79942 | 433 | queue_work_rsl(ieee->wq, &ieee->wx_sync_scan_wq); |
ecdfa446 GKH |
434 | /* intentionally forget to up sem */ |
435 | return 0; | |
436 | } | |
437 | ||
438 | out: | |
439 | up(&ieee->wx_sem); | |
440 | return ret; | |
441 | } | |
3b28499c | 442 | EXPORT_SYMBOL(rtllib_wx_set_scan); |
ecdfa446 | 443 | |
94a79942 | 444 | int rtllib_wx_set_essid(struct rtllib_device *ieee, |
a44be772 LF |
445 | struct iw_request_info *a, |
446 | union iwreq_data *wrqu, char *extra) | |
ecdfa446 GKH |
447 | { |
448 | ||
a44be772 | 449 | int ret = 0, len, i; |
ecdfa446 GKH |
450 | short proto_started; |
451 | unsigned long flags; | |
452 | ||
94a79942 | 453 | rtllib_stop_scan_syncro(ieee); |
ecdfa446 GKH |
454 | down(&ieee->wx_sem); |
455 | ||
456 | proto_started = ieee->proto_started; | |
457 | ||
a44be772 LF |
458 | len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? wrqu->essid.length : |
459 | IW_ESSID_MAX_SIZE; | |
94a79942 | 460 | |
a44be772 LF |
461 | if (len > IW_ESSID_MAX_SIZE) { |
462 | ret = -E2BIG; | |
ecdfa446 GKH |
463 | goto out; |
464 | } | |
465 | ||
a44be772 LF |
466 | if (ieee->iw_mode == IW_MODE_MONITOR) { |
467 | ret = -1; | |
ecdfa446 GKH |
468 | goto out; |
469 | } | |
470 | ||
a44be772 LF |
471 | for (i = 0; i < len; i++) { |
472 | if (extra[i] < 0) { | |
473 | ret = -1; | |
94a79942 LF |
474 | goto out; |
475 | } | |
65a43784 | 476 | } |
ecdfa446 | 477 | |
94a79942 | 478 | if (proto_started) |
a44be772 | 479 | rtllib_stop_protocol(ieee, true); |
94a79942 | 480 | |
ecdfa446 GKH |
481 | |
482 | /* this is just to be sure that the GET wx callback | |
cd017123 | 483 | * has consistent infos. not needed otherwise |
ecdfa446 GKH |
484 | */ |
485 | spin_lock_irqsave(&ieee->lock, flags); | |
486 | ||
487 | if (wrqu->essid.flags && wrqu->essid.length) { | |
94a79942 LF |
488 | strncpy(ieee->current_network.ssid, extra, len); |
489 | ieee->current_network.ssid_len = len; | |
490 | ieee->cannot_notify = false; | |
ecdfa446 | 491 | ieee->ssid_set = 1; |
a44be772 | 492 | } else { |
ecdfa446 GKH |
493 | ieee->ssid_set = 0; |
494 | ieee->current_network.ssid[0] = '\0'; | |
495 | ieee->current_network.ssid_len = 0; | |
496 | } | |
497 | spin_unlock_irqrestore(&ieee->lock, flags); | |
498 | ||
499 | if (proto_started) | |
94a79942 | 500 | rtllib_start_protocol(ieee); |
ecdfa446 GKH |
501 | out: |
502 | up(&ieee->wx_sem); | |
503 | return ret; | |
504 | } | |
3b28499c | 505 | EXPORT_SYMBOL(rtllib_wx_set_essid); |
ecdfa446 | 506 | |
a44be772 LF |
507 | int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a, |
508 | union iwreq_data *wrqu, char *b) | |
ecdfa446 | 509 | { |
ecdfa446 GKH |
510 | wrqu->mode = ieee->iw_mode; |
511 | return 0; | |
512 | } | |
3b28499c | 513 | EXPORT_SYMBOL(rtllib_wx_get_mode); |
ecdfa446 | 514 | |
a44be772 LF |
515 | int rtllib_wx_set_rawtx(struct rtllib_device *ieee, |
516 | struct iw_request_info *info, | |
517 | union iwreq_data *wrqu, char *extra) | |
ecdfa446 GKH |
518 | { |
519 | ||
520 | int *parms = (int *)extra; | |
521 | int enable = (parms[0] > 0); | |
522 | short prev = ieee->raw_tx; | |
523 | ||
524 | down(&ieee->wx_sem); | |
525 | ||
94a79942 | 526 | if (enable) |
ecdfa446 GKH |
527 | ieee->raw_tx = 1; |
528 | else | |
529 | ieee->raw_tx = 0; | |
530 | ||
531 | printk(KERN_INFO"raw TX is %s\n", | |
532 | ieee->raw_tx ? "enabled" : "disabled"); | |
533 | ||
a44be772 LF |
534 | if (ieee->iw_mode == IW_MODE_MONITOR) { |
535 | if (prev == 0 && ieee->raw_tx) { | |
ecdfa446 | 536 | if (ieee->data_hard_resume) |
94a79942 | 537 | ieee->data_hard_resume(ieee->dev); |
ecdfa446 GKH |
538 | |
539 | netif_carrier_on(ieee->dev); | |
540 | } | |
541 | ||
94a79942 | 542 | if (prev && ieee->raw_tx == 1) |
ecdfa446 GKH |
543 | netif_carrier_off(ieee->dev); |
544 | } | |
545 | ||
546 | up(&ieee->wx_sem); | |
547 | ||
548 | return 0; | |
549 | } | |
3b28499c | 550 | EXPORT_SYMBOL(rtllib_wx_set_rawtx); |
ecdfa446 | 551 | |
94a79942 | 552 | int rtllib_wx_get_name(struct rtllib_device *ieee, |
ecdfa446 GKH |
553 | struct iw_request_info *info, |
554 | union iwreq_data *wrqu, char *extra) | |
555 | { | |
556 | strcpy(wrqu->name, "802.11"); | |
94a79942 LF |
557 | |
558 | if (ieee->modulation & RTLLIB_CCK_MODULATION) | |
ecdfa446 | 559 | strcat(wrqu->name, "b"); |
94a79942 | 560 | if (ieee->modulation & RTLLIB_OFDM_MODULATION) |
ecdfa446 GKH |
561 | strcat(wrqu->name, "g"); |
562 | if (ieee->mode & (IEEE_N_24G | IEEE_N_5G)) | |
3ef5a262 | 563 | strcat(wrqu->name, "n"); |
ecdfa446 GKH |
564 | return 0; |
565 | } | |
3b28499c | 566 | EXPORT_SYMBOL(rtllib_wx_get_name); |
ecdfa446 GKH |
567 | |
568 | ||
569 | /* this is mostly stolen from hostap */ | |
94a79942 | 570 | int rtllib_wx_set_power(struct rtllib_device *ieee, |
ecdfa446 GKH |
571 | struct iw_request_info *info, |
572 | union iwreq_data *wrqu, char *extra) | |
573 | { | |
574 | int ret = 0; | |
4f6807e8 | 575 | |
a44be772 LF |
576 | if ((!ieee->sta_wake_up) || |
577 | (!ieee->enter_sleep_state) || | |
578 | (!ieee->ps_is_queue_empty)) { | |
cd017123 | 579 | RTLLIB_DEBUG(RTLLIB_DL_ERR, "%s(): PS mode is tried to be use " |
a44be772 | 580 | "but driver missed a callback\n\n", __func__); |
ecdfa446 GKH |
581 | return -1; |
582 | } | |
4f6807e8 | 583 | |
ecdfa446 GKH |
584 | down(&ieee->wx_sem); |
585 | ||
a44be772 LF |
586 | if (wrqu->power.disabled) { |
587 | RT_TRACE(COMP_DBG, "===>%s(): power disable\n", __func__); | |
94a79942 | 588 | ieee->ps = RTLLIB_PS_DISABLED; |
ecdfa446 GKH |
589 | goto exit; |
590 | } | |
591 | if (wrqu->power.flags & IW_POWER_TIMEOUT) { | |
ecdfa446 | 592 | ieee->ps_timeout = wrqu->power.value / 1000; |
a44be772 LF |
593 | RT_TRACE(COMP_DBG, "===>%s():ps_timeout is %d\n", __func__, |
594 | ieee->ps_timeout); | |
ecdfa446 GKH |
595 | } |
596 | ||
a44be772 | 597 | if (wrqu->power.flags & IW_POWER_PERIOD) |
ecdfa446 | 598 | ieee->ps_period = wrqu->power.value / 1000; |
94a79942 | 599 | |
ecdfa446 GKH |
600 | switch (wrqu->power.flags & IW_POWER_MODE) { |
601 | case IW_POWER_UNICAST_R: | |
94a79942 | 602 | ieee->ps = RTLLIB_PS_UNICAST; |
ecdfa446 GKH |
603 | break; |
604 | case IW_POWER_MULTICAST_R: | |
94a79942 | 605 | ieee->ps = RTLLIB_PS_MBCAST; |
ecdfa446 GKH |
606 | break; |
607 | case IW_POWER_ALL_R: | |
94a79942 | 608 | ieee->ps = RTLLIB_PS_UNICAST | RTLLIB_PS_MBCAST; |
ecdfa446 GKH |
609 | break; |
610 | ||
611 | case IW_POWER_ON: | |
ecdfa446 GKH |
612 | break; |
613 | ||
614 | default: | |
615 | ret = -EINVAL; | |
616 | goto exit; | |
617 | ||
618 | } | |
619 | exit: | |
620 | up(&ieee->wx_sem); | |
621 | return ret; | |
622 | ||
623 | } | |
3b28499c | 624 | EXPORT_SYMBOL(rtllib_wx_set_power); |
ecdfa446 GKH |
625 | |
626 | /* this is stolen from hostap */ | |
94a79942 | 627 | int rtllib_wx_get_power(struct rtllib_device *ieee, |
ecdfa446 GKH |
628 | struct iw_request_info *info, |
629 | union iwreq_data *wrqu, char *extra) | |
630 | { | |
a44be772 | 631 | int ret = 0; |
ecdfa446 GKH |
632 | |
633 | down(&ieee->wx_sem); | |
634 | ||
94a79942 | 635 | if (ieee->ps == RTLLIB_PS_DISABLED) { |
ecdfa446 GKH |
636 | wrqu->power.disabled = 1; |
637 | goto exit; | |
638 | } | |
639 | ||
640 | wrqu->power.disabled = 0; | |
641 | ||
642 | if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { | |
643 | wrqu->power.flags = IW_POWER_TIMEOUT; | |
644 | wrqu->power.value = ieee->ps_timeout * 1000; | |
645 | } else { | |
ecdfa446 GKH |
646 | wrqu->power.flags = IW_POWER_PERIOD; |
647 | wrqu->power.value = ieee->ps_period * 1000; | |
ecdfa446 GKH |
648 | } |
649 | ||
a44be772 LF |
650 | if ((ieee->ps & (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) == |
651 | (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) | |
94a79942 LF |
652 | wrqu->power.flags |= IW_POWER_ALL_R; |
653 | else if (ieee->ps & RTLLIB_PS_MBCAST) | |
ecdfa446 GKH |
654 | wrqu->power.flags |= IW_POWER_MULTICAST_R; |
655 | else | |
656 | wrqu->power.flags |= IW_POWER_UNICAST_R; | |
657 | ||
658 | exit: | |
659 | up(&ieee->wx_sem); | |
660 | return ret; | |
661 | ||
662 | } | |
3b28499c | 663 | EXPORT_SYMBOL(rtllib_wx_get_power); |