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