Commit | Line | Data |
---|---|---|
cb3126e6 | 1 | /* cfg80211 Interface for prism2_usb module */ |
6eaf0788 TR |
2 | #include "hfa384x.h" |
3 | #include "prism2mgmt.h" | |
cb3126e6 | 4 | |
d34602de | 5 | /* Prism2 channel/frequency/bitrate declarations */ |
cb3126e6 KR |
6 | static const struct ieee80211_channel prism2_channels[] = { |
7 | { .center_freq = 2412 }, | |
8 | { .center_freq = 2417 }, | |
9 | { .center_freq = 2422 }, | |
10 | { .center_freq = 2427 }, | |
11 | { .center_freq = 2432 }, | |
12 | { .center_freq = 2437 }, | |
13 | { .center_freq = 2442 }, | |
14 | { .center_freq = 2447 }, | |
15 | { .center_freq = 2452 }, | |
16 | { .center_freq = 2457 }, | |
17 | { .center_freq = 2462 }, | |
18 | { .center_freq = 2467 }, | |
19 | { .center_freq = 2472 }, | |
20 | { .center_freq = 2484 }, | |
21 | }; | |
22 | ||
23 | static const struct ieee80211_rate prism2_rates[] = { | |
24 | { .bitrate = 10 }, | |
25 | { .bitrate = 20 }, | |
26 | { .bitrate = 55 }, | |
27 | { .bitrate = 110 } | |
28 | }; | |
29 | ||
30 | #define PRISM2_NUM_CIPHER_SUITES 2 | |
31 | static const u32 prism2_cipher_suites[PRISM2_NUM_CIPHER_SUITES] = { | |
32 | WLAN_CIPHER_SUITE_WEP40, | |
33 | WLAN_CIPHER_SUITE_WEP104 | |
34 | }; | |
35 | ||
cb3126e6 KR |
36 | /* prism2 device private data */ |
37 | struct prism2_wiphy_private { | |
38 | wlandevice_t *wlandev; | |
39 | ||
40 | struct ieee80211_supported_band band; | |
41 | struct ieee80211_channel channels[ARRAY_SIZE(prism2_channels)]; | |
42 | struct ieee80211_rate rates[ARRAY_SIZE(prism2_rates)]; | |
43 | ||
44 | struct cfg80211_scan_request *scan_request; | |
45 | }; | |
46 | ||
47 | static const void * const prism2_wiphy_privid = &prism2_wiphy_privid; | |
48 | ||
cb3126e6 KR |
49 | /* Helper Functions */ |
50 | static int prism2_result2err(int prism2_result) | |
51 | { | |
52 | int err = 0; | |
53 | ||
54 | switch (prism2_result) { | |
55 | case P80211ENUM_resultcode_invalid_parameters: | |
56 | err = -EINVAL; | |
57 | break; | |
58 | case P80211ENUM_resultcode_implementation_failure: | |
59 | err = -EIO; | |
60 | break; | |
61 | case P80211ENUM_resultcode_not_supported: | |
62 | err = -EOPNOTSUPP; | |
63 | break; | |
64 | default: | |
65 | err = 0; | |
66 | break; | |
67 | } | |
68 | ||
69 | return err; | |
70 | } | |
71 | ||
72 | static int prism2_domibset_uint32(wlandevice_t *wlandev, u32 did, u32 data) | |
73 | { | |
b6bb56e6 | 74 | struct p80211msg_dot11req_mibset msg; |
bb1da756 | 75 | p80211item_uint32_t *mibitem = |
0adf62bf | 76 | (p80211item_uint32_t *)&msg.mibattribute.data; |
cb3126e6 KR |
77 | |
78 | msg.msgcode = DIDmsg_dot11req_mibset; | |
79 | mibitem->did = did; | |
80 | mibitem->data = data; | |
81 | ||
0adf62bf | 82 | return p80211req_dorequest(wlandev, (u8 *)&msg); |
cb3126e6 KR |
83 | } |
84 | ||
85 | static int prism2_domibset_pstr32(wlandevice_t *wlandev, | |
c1e5f471 | 86 | u32 did, u8 len, const u8 *data) |
cb3126e6 | 87 | { |
b6bb56e6 | 88 | struct p80211msg_dot11req_mibset msg; |
bb1da756 | 89 | p80211item_pstr32_t *mibitem = |
0adf62bf | 90 | (p80211item_pstr32_t *)&msg.mibattribute.data; |
cb3126e6 KR |
91 | |
92 | msg.msgcode = DIDmsg_dot11req_mibset; | |
93 | mibitem->did = did; | |
94 | mibitem->data.len = len; | |
95 | memcpy(mibitem->data.data, data, len); | |
96 | ||
0adf62bf | 97 | return p80211req_dorequest(wlandev, (u8 *)&msg); |
cb3126e6 KR |
98 | } |
99 | ||
cb3126e6 | 100 | /* The interface functions, called by the cfg80211 layer */ |
55da06eb TB |
101 | static int prism2_change_virtual_intf(struct wiphy *wiphy, |
102 | struct net_device *dev, | |
103 | enum nl80211_iftype type, u32 *flags, | |
104 | struct vif_params *params) | |
cb3126e6 KR |
105 | { |
106 | wlandevice_t *wlandev = dev->ml_priv; | |
107 | u32 data; | |
108 | int result; | |
109 | int err = 0; | |
110 | ||
111 | switch (type) { | |
112 | case NL80211_IFTYPE_ADHOC: | |
8dd82ebe EH |
113 | if (wlandev->macmode == WLAN_MACMODE_IBSS_STA) |
114 | goto exit; | |
cb3126e6 KR |
115 | wlandev->macmode = WLAN_MACMODE_IBSS_STA; |
116 | data = 0; | |
117 | break; | |
118 | case NL80211_IFTYPE_STATION: | |
8dd82ebe EH |
119 | if (wlandev->macmode == WLAN_MACMODE_ESS_STA) |
120 | goto exit; | |
cb3126e6 KR |
121 | wlandev->macmode = WLAN_MACMODE_ESS_STA; |
122 | data = 1; | |
123 | break; | |
124 | default: | |
eed88971 | 125 | netdev_warn(dev, "Operation mode: %d not support\n", type); |
cb3126e6 KR |
126 | return -EOPNOTSUPP; |
127 | } | |
128 | ||
129 | /* Set Operation mode to the PORT TYPE RID */ | |
8aac4d44 DN |
130 | result = prism2_domibset_uint32(wlandev, |
131 | DIDmib_p2_p2Static_p2CnfPortType, | |
132 | data); | |
cb3126e6 KR |
133 | |
134 | if (result) | |
135 | err = -EFAULT; | |
8dd82ebe | 136 | |
cb3126e6 KR |
137 | dev->ieee80211_ptr->iftype = type; |
138 | ||
139 | exit: | |
140 | return err; | |
141 | } | |
142 | ||
55da06eb TB |
143 | static int prism2_add_key(struct wiphy *wiphy, struct net_device *dev, |
144 | u8 key_index, bool pairwise, const u8 *mac_addr, | |
145 | struct key_params *params) | |
8dd82ebe | 146 | { |
cb3126e6 KR |
147 | wlandevice_t *wlandev = dev->ml_priv; |
148 | u32 did; | |
149 | ||
150 | int err = 0; | |
151 | int result = 0; | |
152 | ||
153 | switch (params->cipher) { | |
154 | case WLAN_CIPHER_SUITE_WEP40: | |
155 | case WLAN_CIPHER_SUITE_WEP104: | |
156 | result = prism2_domibset_uint32(wlandev, | |
8dd82ebe EH |
157 | DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, |
158 | key_index); | |
159 | if (result) | |
160 | goto exit; | |
cb3126e6 KR |
161 | |
162 | /* send key to driver */ | |
163 | switch (key_index) { | |
164 | case 0: | |
8dd82ebe | 165 | did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0; |
cb3126e6 KR |
166 | break; |
167 | ||
168 | case 1: | |
8dd82ebe | 169 | did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1; |
cb3126e6 KR |
170 | break; |
171 | ||
172 | case 2: | |
8dd82ebe | 173 | did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2; |
cb3126e6 KR |
174 | break; |
175 | ||
176 | case 3: | |
8dd82ebe | 177 | did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3; |
cb3126e6 KR |
178 | break; |
179 | ||
180 | default: | |
181 | err = -EINVAL; | |
182 | goto exit; | |
183 | } | |
184 | ||
bb1da756 HS |
185 | result = prism2_domibset_pstr32(wlandev, did, |
186 | params->key_len, params->key); | |
8dd82ebe EH |
187 | if (result) |
188 | goto exit; | |
cb3126e6 KR |
189 | break; |
190 | ||
191 | default: | |
192 | pr_debug("Unsupported cipher suite\n"); | |
193 | result = 1; | |
194 | } | |
195 | ||
196 | exit: | |
8dd82ebe EH |
197 | if (result) |
198 | err = -EFAULT; | |
cb3126e6 KR |
199 | |
200 | return err; | |
201 | } | |
202 | ||
55da06eb TB |
203 | static int prism2_get_key(struct wiphy *wiphy, struct net_device *dev, |
204 | u8 key_index, bool pairwise, | |
205 | const u8 *mac_addr, void *cookie, | |
206 | void (*callback)(void *cookie, struct key_params*)) | |
8dd82ebe | 207 | { |
cb3126e6 KR |
208 | wlandevice_t *wlandev = dev->ml_priv; |
209 | struct key_params params; | |
210 | int len; | |
211 | ||
8dd82ebe EH |
212 | if (key_index >= NUM_WEPKEYS) |
213 | return -EINVAL; | |
cb3126e6 KR |
214 | |
215 | len = wlandev->wep_keylens[key_index]; | |
216 | memset(¶ms, 0, sizeof(params)); | |
217 | ||
8dd82ebe | 218 | if (len == 13) |
cb3126e6 | 219 | params.cipher = WLAN_CIPHER_SUITE_WEP104; |
8dd82ebe | 220 | else if (len == 5) |
cb3126e6 | 221 | params.cipher = WLAN_CIPHER_SUITE_WEP104; |
8dd82ebe EH |
222 | else |
223 | return -ENOENT; | |
cb3126e6 KR |
224 | params.key_len = len; |
225 | params.key = wlandev->wep_keys[key_index]; | |
aff3ea4e | 226 | params.seq_len = 0; |
cb3126e6 KR |
227 | |
228 | callback(cookie, ¶ms); | |
8dd82ebe | 229 | |
cb3126e6 KR |
230 | return 0; |
231 | } | |
232 | ||
55da06eb TB |
233 | static int prism2_del_key(struct wiphy *wiphy, struct net_device *dev, |
234 | u8 key_index, bool pairwise, const u8 *mac_addr) | |
8dd82ebe | 235 | { |
cb3126e6 KR |
236 | wlandevice_t *wlandev = dev->ml_priv; |
237 | u32 did; | |
238 | int err = 0; | |
239 | int result = 0; | |
240 | ||
241 | /* There is no direct way in the hardware (AFAIK) of removing | |
35028fe1 GL |
242 | * a key, so we will cheat by setting the key to a bogus value |
243 | */ | |
244 | ||
cb3126e6 KR |
245 | /* send key to driver */ |
246 | switch (key_index) { | |
247 | case 0: | |
248 | did = | |
249 | DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0; | |
250 | break; | |
251 | ||
252 | case 1: | |
253 | did = | |
254 | DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1; | |
255 | break; | |
256 | ||
257 | case 2: | |
258 | did = | |
259 | DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2; | |
260 | break; | |
261 | ||
262 | case 3: | |
263 | did = | |
264 | DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3; | |
265 | break; | |
266 | ||
267 | default: | |
268 | err = -EINVAL; | |
269 | goto exit; | |
270 | } | |
271 | ||
272 | result = prism2_domibset_pstr32(wlandev, did, 13, "0000000000000"); | |
273 | ||
274 | exit: | |
8dd82ebe EH |
275 | if (result) |
276 | err = -EFAULT; | |
cb3126e6 KR |
277 | |
278 | return err; | |
279 | } | |
280 | ||
55da06eb TB |
281 | static int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev, |
282 | u8 key_index, bool unicast, bool multicast) | |
8dd82ebe | 283 | { |
cb3126e6 KR |
284 | wlandevice_t *wlandev = dev->ml_priv; |
285 | ||
286 | int err = 0; | |
287 | int result = 0; | |
288 | ||
289 | result = prism2_domibset_uint32(wlandev, | |
290 | DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, | |
291 | key_index); | |
292 | ||
8dd82ebe EH |
293 | if (result) |
294 | err = -EFAULT; | |
cb3126e6 KR |
295 | |
296 | return err; | |
297 | } | |
298 | ||
55da06eb | 299 | static int prism2_get_station(struct wiphy *wiphy, struct net_device *dev, |
3b3a0162 | 300 | const u8 *mac, struct station_info *sinfo) |
8dd82ebe | 301 | { |
cb3126e6 | 302 | wlandevice_t *wlandev = dev->ml_priv; |
b6bb56e6 | 303 | struct p80211msg_lnxreq_commsquality quality; |
cb3126e6 KR |
304 | int result; |
305 | ||
306 | memset(sinfo, 0, sizeof(*sinfo)); | |
307 | ||
308 | if ((wlandev == NULL) || (wlandev->msdstate != WLAN_MSD_RUNNING)) | |
309 | return -EOPNOTSUPP; | |
310 | ||
311 | /* build request message */ | |
312 | quality.msgcode = DIDmsg_lnxreq_commsquality; | |
313 | quality.dbm.data = P80211ENUM_truth_true; | |
314 | quality.dbm.status = P80211ENUM_msgitem_status_data_ok; | |
315 | ||
316 | /* send message to nsd */ | |
317 | if (wlandev->mlmerequest == NULL) | |
318 | return -EOPNOTSUPP; | |
319 | ||
0adf62bf | 320 | result = wlandev->mlmerequest(wlandev, (struct p80211msg *)&quality); |
cb3126e6 | 321 | |
cb3126e6 KR |
322 | if (result == 0) { |
323 | sinfo->txrate.legacy = quality.txrate.data; | |
319090bf | 324 | sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); |
cb3126e6 | 325 | sinfo->signal = quality.level.data; |
319090bf | 326 | sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); |
cb3126e6 KR |
327 | } |
328 | ||
329 | return result; | |
330 | } | |
331 | ||
bb1da756 HS |
332 | static int prism2_scan(struct wiphy *wiphy, |
333 | struct cfg80211_scan_request *request) | |
cb3126e6 | 334 | { |
5d5d7c3b | 335 | struct net_device *dev; |
cb3126e6 | 336 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); |
5d5d7c3b | 337 | wlandevice_t *wlandev; |
b6bb56e6 EH |
338 | struct p80211msg_dot11req_scan msg1; |
339 | struct p80211msg_dot11req_scan_results msg2; | |
19f798ad | 340 | struct cfg80211_bss *bss; |
cb3126e6 KR |
341 | int result; |
342 | int err = 0; | |
343 | int numbss = 0; | |
344 | int i = 0; | |
345 | u8 ie_buf[46]; | |
346 | int ie_len; | |
347 | ||
348 | if (!request) | |
349 | return -EINVAL; | |
350 | ||
5d5d7c3b EG |
351 | dev = request->wdev->netdev; |
352 | wlandev = dev->ml_priv; | |
353 | ||
cb3126e6 KR |
354 | if (priv->scan_request && priv->scan_request != request) |
355 | return -EBUSY; | |
356 | ||
357 | if (wlandev->macmode == WLAN_MACMODE_ESS_AP) { | |
eed88971 | 358 | netdev_err(dev, "Can't scan in AP mode\n"); |
cb3126e6 KR |
359 | return -EOPNOTSUPP; |
360 | } | |
361 | ||
362 | priv->scan_request = request; | |
363 | ||
b6bb56e6 | 364 | memset(&msg1, 0x00, sizeof(struct p80211msg_dot11req_scan)); |
cb3126e6 KR |
365 | msg1.msgcode = DIDmsg_dot11req_scan; |
366 | msg1.bsstype.data = P80211ENUM_bsstype_any; | |
367 | ||
625aeb3a | 368 | memset(&msg1.bssid.data.data, 0xFF, sizeof(msg1.bssid.data.data)); |
cb3126e6 KR |
369 | msg1.bssid.data.len = 6; |
370 | ||
371 | if (request->n_ssids > 0) { | |
372 | msg1.scantype.data = P80211ENUM_scantype_active; | |
373 | msg1.ssid.data.len = request->ssids->ssid_len; | |
8aac4d44 DN |
374 | memcpy(msg1.ssid.data.data, |
375 | request->ssids->ssid, request->ssids->ssid_len); | |
cb3126e6 KR |
376 | } else { |
377 | msg1.scantype.data = 0; | |
378 | } | |
379 | msg1.probedelay.data = 0; | |
380 | ||
381 | for (i = 0; | |
382 | (i < request->n_channels) && i < ARRAY_SIZE(prism2_channels); | |
383 | i++) | |
384 | msg1.channellist.data.data[i] = | |
bb1da756 HS |
385 | ieee80211_frequency_to_channel( |
386 | request->channels[i]->center_freq); | |
cb3126e6 KR |
387 | msg1.channellist.data.len = request->n_channels; |
388 | ||
389 | msg1.maxchanneltime.data = 250; | |
390 | msg1.minchanneltime.data = 200; | |
391 | ||
0adf62bf | 392 | result = p80211req_dorequest(wlandev, (u8 *)&msg1); |
cb3126e6 KR |
393 | if (result) { |
394 | err = prism2_result2err(msg1.resultcode.data); | |
395 | goto exit; | |
396 | } | |
397 | /* Now retrieve scan results */ | |
398 | numbss = msg1.numbss.data; | |
399 | ||
400 | for (i = 0; i < numbss; i++) { | |
4e5e9d7c ZG |
401 | int freq; |
402 | ||
cb3126e6 KR |
403 | memset(&msg2, 0, sizeof(msg2)); |
404 | msg2.msgcode = DIDmsg_dot11req_scan_results; | |
405 | msg2.bssindex.data = i; | |
406 | ||
0adf62bf | 407 | result = p80211req_dorequest(wlandev, (u8 *)&msg2); |
cb3126e6 KR |
408 | if ((result != 0) || |
409 | (msg2.resultcode.data != P80211ENUM_resultcode_success)) { | |
410 | break; | |
411 | } | |
412 | ||
413 | ie_buf[0] = WLAN_EID_SSID; | |
414 | ie_buf[1] = msg2.ssid.data.len; | |
415 | ie_len = ie_buf[1] + 2; | |
416 | memcpy(&ie_buf[2], &(msg2.ssid.data.data), msg2.ssid.data.len); | |
4e5e9d7c | 417 | freq = ieee80211_channel_to_frequency(msg2.dschannel.data, |
57fbcce3 | 418 | NL80211_BAND_2GHZ); |
19f798ad | 419 | bss = cfg80211_inform_bss(wiphy, |
4e5e9d7c | 420 | ieee80211_get_channel(wiphy, freq), |
5bc8c1f2 | 421 | CFG80211_BSS_FTYPE_UNKNOWN, |
0adf62bf | 422 | (const u8 *)&(msg2.bssid.data.data), |
cb3126e6 KR |
423 | msg2.timestamp.data, msg2.capinfo.data, |
424 | msg2.beaconperiod.data, | |
425 | ie_buf, | |
426 | ie_len, | |
427 | (msg2.signal.data - 65536) * 100, /* Conversion to signed type */ | |
428 | GFP_KERNEL | |
429 | ); | |
19f798ad KW |
430 | |
431 | if (!bss) { | |
432 | err = -ENOMEM; | |
433 | goto exit; | |
434 | } | |
435 | ||
5b112d3d | 436 | cfg80211_put_bss(wiphy, bss); |
cb3126e6 KR |
437 | } |
438 | ||
8dd82ebe | 439 | if (result) |
cb3126e6 | 440 | err = prism2_result2err(msg2.resultcode.data); |
cb3126e6 KR |
441 | |
442 | exit: | |
443 | cfg80211_scan_done(request, err ? 1 : 0); | |
444 | priv->scan_request = NULL; | |
445 | return err; | |
446 | } | |
447 | ||
55da06eb | 448 | static int prism2_set_wiphy_params(struct wiphy *wiphy, u32 changed) |
8dd82ebe | 449 | { |
cb3126e6 KR |
450 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); |
451 | wlandevice_t *wlandev = priv->wlandev; | |
452 | u32 data; | |
453 | int result; | |
454 | int err = 0; | |
455 | ||
456 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) { | |
457 | if (wiphy->rts_threshold == -1) | |
458 | data = 2347; | |
459 | else | |
460 | data = wiphy->rts_threshold; | |
461 | ||
8dd82ebe EH |
462 | result = prism2_domibset_uint32(wlandev, |
463 | DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold, | |
464 | data); | |
cb3126e6 KR |
465 | if (result) { |
466 | err = -EFAULT; | |
467 | goto exit; | |
468 | } | |
469 | } | |
470 | ||
471 | if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { | |
cb3126e6 KR |
472 | if (wiphy->frag_threshold == -1) |
473 | data = 2346; | |
474 | else | |
475 | data = wiphy->frag_threshold; | |
476 | ||
8dd82ebe EH |
477 | result = prism2_domibset_uint32(wlandev, |
478 | DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold, | |
479 | data); | |
cb3126e6 KR |
480 | if (result) { |
481 | err = -EFAULT; | |
482 | goto exit; | |
483 | } | |
484 | } | |
485 | ||
486 | exit: | |
487 | return err; | |
488 | } | |
489 | ||
55da06eb TB |
490 | static int prism2_connect(struct wiphy *wiphy, struct net_device *dev, |
491 | struct cfg80211_connect_params *sme) | |
8dd82ebe | 492 | { |
cb3126e6 KR |
493 | wlandevice_t *wlandev = dev->ml_priv; |
494 | struct ieee80211_channel *channel = sme->channel; | |
b6bb56e6 | 495 | struct p80211msg_lnxreq_autojoin msg_join; |
cb3126e6 KR |
496 | u32 did; |
497 | int length = sme->ssid_len; | |
498 | int chan = -1; | |
499 | int is_wep = (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40) || | |
500 | (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104); | |
501 | int result; | |
502 | int err = 0; | |
503 | ||
504 | /* Set the channel */ | |
505 | if (channel) { | |
506 | chan = ieee80211_frequency_to_channel(channel->center_freq); | |
8dd82ebe EH |
507 | result = prism2_domibset_uint32(wlandev, |
508 | DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel, | |
509 | chan); | |
510 | if (result) | |
511 | goto exit; | |
cb3126e6 KR |
512 | } |
513 | ||
d34602de | 514 | /* Set the authorization */ |
cb3126e6 KR |
515 | if ((sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) || |
516 | ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && !is_wep)) | |
517 | msg_join.authtype.data = P80211ENUM_authalg_opensystem; | |
518 | else if ((sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) || | |
519 | ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && is_wep)) | |
520 | msg_join.authtype.data = P80211ENUM_authalg_sharedkey; | |
8dd82ebe | 521 | else |
eed88971 | 522 | netdev_warn(dev, |
8dd82ebe EH |
523 | "Unhandled authorisation type for connect (%d)\n", |
524 | sme->auth_type); | |
cb3126e6 KR |
525 | |
526 | /* Set the encryption - we only support wep */ | |
527 | if (is_wep) { | |
cb3126e6 KR |
528 | if (sme->key) { |
529 | result = prism2_domibset_uint32(wlandev, | |
530 | DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, | |
531 | sme->key_idx); | |
8dd82ebe EH |
532 | if (result) |
533 | goto exit; | |
cb3126e6 KR |
534 | |
535 | /* send key to driver */ | |
536 | switch (sme->key_idx) { | |
537 | case 0: | |
8dd82ebe | 538 | did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0; |
cb3126e6 KR |
539 | break; |
540 | ||
541 | case 1: | |
8dd82ebe | 542 | did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1; |
cb3126e6 KR |
543 | break; |
544 | ||
545 | case 2: | |
8dd82ebe | 546 | did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2; |
cb3126e6 KR |
547 | break; |
548 | ||
549 | case 3: | |
8dd82ebe | 550 | did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3; |
cb3126e6 KR |
551 | break; |
552 | ||
553 | default: | |
554 | err = -EINVAL; | |
555 | goto exit; | |
556 | } | |
557 | ||
8aac4d44 DN |
558 | result = prism2_domibset_pstr32(wlandev, |
559 | did, sme->key_len, | |
560 | (u8 *)sme->key); | |
8dd82ebe EH |
561 | if (result) |
562 | goto exit; | |
cb3126e6 KR |
563 | } |
564 | ||
565 | /* Assume we should set privacy invoked and exclude unencrypted | |
35028fe1 GL |
566 | * We could possible use sme->privacy here, but the assumption |
567 | * seems reasonable anyways | |
568 | */ | |
8dd82ebe EH |
569 | result = prism2_domibset_uint32(wlandev, |
570 | DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, | |
571 | P80211ENUM_truth_true); | |
572 | if (result) | |
573 | goto exit; | |
574 | ||
575 | result = prism2_domibset_uint32(wlandev, | |
576 | DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, | |
577 | P80211ENUM_truth_true); | |
578 | if (result) | |
579 | goto exit; | |
cb3126e6 KR |
580 | |
581 | } else { | |
8dd82ebe | 582 | /* Assume we should unset privacy invoked |
35028fe1 GL |
583 | * and exclude unencrypted |
584 | */ | |
8dd82ebe EH |
585 | result = prism2_domibset_uint32(wlandev, |
586 | DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, | |
587 | P80211ENUM_truth_false); | |
588 | if (result) | |
589 | goto exit; | |
590 | ||
591 | result = prism2_domibset_uint32(wlandev, | |
592 | DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, | |
593 | P80211ENUM_truth_false); | |
594 | if (result) | |
595 | goto exit; | |
cb3126e6 KR |
596 | } |
597 | ||
598 | /* Now do the actual join. Note there is no way that I can | |
4f9de774 GL |
599 | * see to request a specific bssid |
600 | */ | |
cb3126e6 KR |
601 | msg_join.msgcode = DIDmsg_lnxreq_autojoin; |
602 | ||
603 | memcpy(msg_join.ssid.data.data, sme->ssid, length); | |
604 | msg_join.ssid.data.len = length; | |
605 | ||
0adf62bf | 606 | result = p80211req_dorequest(wlandev, (u8 *)&msg_join); |
cb3126e6 KR |
607 | |
608 | exit: | |
8dd82ebe EH |
609 | if (result) |
610 | err = -EFAULT; | |
cb3126e6 KR |
611 | |
612 | return err; | |
613 | } | |
614 | ||
55da06eb TB |
615 | static int prism2_disconnect(struct wiphy *wiphy, struct net_device *dev, |
616 | u16 reason_code) | |
8dd82ebe | 617 | { |
cb3126e6 | 618 | wlandevice_t *wlandev = dev->ml_priv; |
b6bb56e6 | 619 | struct p80211msg_lnxreq_autojoin msg_join; |
cb3126e6 KR |
620 | int result; |
621 | int err = 0; | |
622 | ||
cb3126e6 KR |
623 | /* Do a join, with a bogus ssid. Thats the only way I can think of */ |
624 | msg_join.msgcode = DIDmsg_lnxreq_autojoin; | |
625 | ||
626 | memcpy(msg_join.ssid.data.data, "---", 3); | |
627 | msg_join.ssid.data.len = 3; | |
628 | ||
0adf62bf | 629 | result = p80211req_dorequest(wlandev, (u8 *)&msg_join); |
cb3126e6 | 630 | |
8dd82ebe EH |
631 | if (result) |
632 | err = -EFAULT; | |
cb3126e6 KR |
633 | |
634 | return err; | |
635 | } | |
636 | ||
55da06eb TB |
637 | static int prism2_join_ibss(struct wiphy *wiphy, struct net_device *dev, |
638 | struct cfg80211_ibss_params *params) | |
8dd82ebe | 639 | { |
cb3126e6 KR |
640 | return -EOPNOTSUPP; |
641 | } | |
642 | ||
55da06eb | 643 | static int prism2_leave_ibss(struct wiphy *wiphy, struct net_device *dev) |
8dd82ebe | 644 | { |
cb3126e6 KR |
645 | return -EOPNOTSUPP; |
646 | } | |
647 | ||
55da06eb TB |
648 | static int prism2_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, |
649 | enum nl80211_tx_power_setting type, int mbm) | |
8dd82ebe | 650 | { |
cb3126e6 KR |
651 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); |
652 | wlandevice_t *wlandev = priv->wlandev; | |
653 | u32 data; | |
654 | int result; | |
655 | int err = 0; | |
656 | ||
9015e499 | 657 | if (type == NL80211_TX_POWER_AUTOMATIC) |
cb3126e6 KR |
658 | data = 30; |
659 | else | |
9015e499 | 660 | data = MBM_TO_DBM(mbm); |
cb3126e6 KR |
661 | |
662 | result = prism2_domibset_uint32(wlandev, | |
663 | DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel, | |
664 | data); | |
665 | ||
666 | if (result) { | |
667 | err = -EFAULT; | |
668 | goto exit; | |
669 | } | |
670 | ||
671 | exit: | |
672 | return err; | |
673 | } | |
674 | ||
55da06eb TB |
675 | static int prism2_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, |
676 | int *dbm) | |
8dd82ebe | 677 | { |
cb3126e6 KR |
678 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); |
679 | wlandevice_t *wlandev = priv->wlandev; | |
b6bb56e6 | 680 | struct p80211msg_dot11req_mibget msg; |
8aac4d44 | 681 | p80211item_uint32_t *mibitem; |
cb3126e6 KR |
682 | int result; |
683 | int err = 0; | |
684 | ||
0adf62bf | 685 | mibitem = (p80211item_uint32_t *)&msg.mibattribute.data; |
cb3126e6 KR |
686 | msg.msgcode = DIDmsg_dot11req_mibget; |
687 | mibitem->did = | |
688 | DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel; | |
689 | ||
0adf62bf | 690 | result = p80211req_dorequest(wlandev, (u8 *)&msg); |
cb3126e6 KR |
691 | |
692 | if (result) { | |
693 | err = -EFAULT; | |
694 | goto exit; | |
695 | } | |
696 | ||
697 | *dbm = mibitem->data; | |
698 | ||
699 | exit: | |
700 | return err; | |
701 | } | |
702 | ||
cb3126e6 | 703 | /* Interface callback functions, passing data back up to the cfg80211 layer */ |
8dd82ebe EH |
704 | void prism2_connect_result(wlandevice_t *wlandev, u8 failed) |
705 | { | |
8aac4d44 DN |
706 | u16 status = failed ? |
707 | WLAN_STATUS_UNSPECIFIED_FAILURE : WLAN_STATUS_SUCCESS; | |
cb3126e6 KR |
708 | |
709 | cfg80211_connect_result(wlandev->netdev, wlandev->bssid, | |
8dd82ebe | 710 | NULL, 0, NULL, 0, status, GFP_KERNEL); |
cb3126e6 KR |
711 | } |
712 | ||
8dd82ebe EH |
713 | void prism2_disconnected(wlandevice_t *wlandev) |
714 | { | |
cb3126e6 | 715 | cfg80211_disconnected(wlandev->netdev, 0, NULL, |
80279fb7 | 716 | 0, false, GFP_KERNEL); |
cb3126e6 KR |
717 | } |
718 | ||
8dd82ebe EH |
719 | void prism2_roamed(wlandevice_t *wlandev) |
720 | { | |
ed9d0102 | 721 | cfg80211_roamed(wlandev->netdev, NULL, wlandev->bssid, |
cb3126e6 KR |
722 | NULL, 0, NULL, 0, GFP_KERNEL); |
723 | } | |
724 | ||
cb3126e6 KR |
725 | /* Structures for declaring wiphy interface */ |
726 | static const struct cfg80211_ops prism2_usb_cfg_ops = { | |
727 | .change_virtual_intf = prism2_change_virtual_intf, | |
728 | .add_key = prism2_add_key, | |
729 | .get_key = prism2_get_key, | |
730 | .del_key = prism2_del_key, | |
731 | .set_default_key = prism2_set_default_key, | |
732 | .get_station = prism2_get_station, | |
733 | .scan = prism2_scan, | |
734 | .set_wiphy_params = prism2_set_wiphy_params, | |
735 | .connect = prism2_connect, | |
736 | .disconnect = prism2_disconnect, | |
737 | .join_ibss = prism2_join_ibss, | |
738 | .leave_ibss = prism2_leave_ibss, | |
739 | .set_tx_power = prism2_set_tx_power, | |
740 | .get_tx_power = prism2_get_tx_power, | |
741 | }; | |
742 | ||
cb3126e6 | 743 | /* Functions to create/free wiphy interface */ |
36d9c250 | 744 | static struct wiphy *wlan_create_wiphy(struct device *dev, wlandevice_t *wlandev) |
cb3126e6 KR |
745 | { |
746 | struct wiphy *wiphy; | |
747 | struct prism2_wiphy_private *priv; | |
8aac4d44 DN |
748 | |
749 | wiphy = wiphy_new(&prism2_usb_cfg_ops, sizeof(*priv)); | |
cb3126e6 KR |
750 | if (!wiphy) |
751 | return NULL; | |
752 | ||
753 | priv = wiphy_priv(wiphy); | |
754 | priv->wlandev = wlandev; | |
755 | memcpy(priv->channels, prism2_channels, sizeof(prism2_channels)); | |
756 | memcpy(priv->rates, prism2_rates, sizeof(prism2_rates)); | |
757 | priv->band.channels = priv->channels; | |
758 | priv->band.n_channels = ARRAY_SIZE(prism2_channels); | |
759 | priv->band.bitrates = priv->rates; | |
760 | priv->band.n_bitrates = ARRAY_SIZE(prism2_rates); | |
57fbcce3 | 761 | priv->band.band = NL80211_BAND_2GHZ; |
aff3ea4e | 762 | priv->band.ht_cap.ht_supported = false; |
57fbcce3 | 763 | wiphy->bands[NL80211_BAND_2GHZ] = &priv->band; |
cb3126e6 KR |
764 | |
765 | set_wiphy_dev(wiphy, dev); | |
766 | wiphy->privid = prism2_wiphy_privid; | |
767 | wiphy->max_scan_ssids = 1; | |
8dd82ebe EH |
768 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
769 | | BIT(NL80211_IFTYPE_ADHOC); | |
cb3126e6 KR |
770 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; |
771 | wiphy->n_cipher_suites = PRISM2_NUM_CIPHER_SUITES; | |
772 | wiphy->cipher_suites = prism2_cipher_suites; | |
773 | ||
774 | if (wiphy_register(wiphy) < 0) | |
775 | return NULL; | |
776 | ||
777 | return wiphy; | |
778 | } | |
779 | ||
36d9c250 | 780 | static void wlan_free_wiphy(struct wiphy *wiphy) |
cb3126e6 KR |
781 | { |
782 | wiphy_unregister(wiphy); | |
783 | wiphy_free(wiphy); | |
784 | } |