Commit | Line | Data |
---|---|---|
cb3126e6 KR |
1 | /* cfg80211 Interface for prism2_usb module */ |
2 | ||
3 | ||
d34602de | 4 | /* Prism2 channel/frequency/bitrate declarations */ |
cb3126e6 KR |
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 | { |
5d5d7c3b | 332 | struct net_device *dev; |
cb3126e6 | 333 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); |
5d5d7c3b | 334 | wlandevice_t *wlandev; |
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 | ||
5d5d7c3b EG |
348 | dev = request->wdev->netdev; |
349 | wlandev = dev->ml_priv; | |
350 | ||
cb3126e6 KR |
351 | if (priv->scan_request && priv->scan_request != request) |
352 | return -EBUSY; | |
353 | ||
354 | if (wlandev->macmode == WLAN_MACMODE_ESS_AP) { | |
355 | printk(KERN_ERR "Can't scan in AP mode\n"); | |
356 | return -EOPNOTSUPP; | |
357 | } | |
358 | ||
359 | priv->scan_request = request; | |
360 | ||
b6bb56e6 | 361 | memset(&msg1, 0x00, sizeof(struct p80211msg_dot11req_scan)); |
cb3126e6 KR |
362 | msg1.msgcode = DIDmsg_dot11req_scan; |
363 | msg1.bsstype.data = P80211ENUM_bsstype_any; | |
364 | ||
625aeb3a | 365 | memset(&msg1.bssid.data.data, 0xFF, sizeof(msg1.bssid.data.data)); |
cb3126e6 KR |
366 | msg1.bssid.data.len = 6; |
367 | ||
368 | if (request->n_ssids > 0) { | |
369 | msg1.scantype.data = P80211ENUM_scantype_active; | |
370 | msg1.ssid.data.len = request->ssids->ssid_len; | |
8aac4d44 DN |
371 | memcpy(msg1.ssid.data.data, |
372 | request->ssids->ssid, request->ssids->ssid_len); | |
cb3126e6 KR |
373 | } else { |
374 | msg1.scantype.data = 0; | |
375 | } | |
376 | msg1.probedelay.data = 0; | |
377 | ||
378 | for (i = 0; | |
379 | (i < request->n_channels) && i < ARRAY_SIZE(prism2_channels); | |
380 | i++) | |
381 | msg1.channellist.data.data[i] = | |
382 | ieee80211_frequency_to_channel(request->channels[i]->center_freq); | |
383 | msg1.channellist.data.len = request->n_channels; | |
384 | ||
385 | msg1.maxchanneltime.data = 250; | |
386 | msg1.minchanneltime.data = 200; | |
387 | ||
388 | result = p80211req_dorequest(wlandev, (u8 *) &msg1); | |
389 | if (result) { | |
390 | err = prism2_result2err(msg1.resultcode.data); | |
391 | goto exit; | |
392 | } | |
393 | /* Now retrieve scan results */ | |
394 | numbss = msg1.numbss.data; | |
395 | ||
396 | for (i = 0; i < numbss; i++) { | |
397 | memset(&msg2, 0, sizeof(msg2)); | |
398 | msg2.msgcode = DIDmsg_dot11req_scan_results; | |
399 | msg2.bssindex.data = i; | |
400 | ||
401 | result = p80211req_dorequest(wlandev, (u8 *) &msg2); | |
402 | if ((result != 0) || | |
403 | (msg2.resultcode.data != P80211ENUM_resultcode_success)) { | |
404 | break; | |
405 | } | |
406 | ||
407 | ie_buf[0] = WLAN_EID_SSID; | |
408 | ie_buf[1] = msg2.ssid.data.len; | |
409 | ie_len = ie_buf[1] + 2; | |
410 | memcpy(&ie_buf[2], &(msg2.ssid.data.data), msg2.ssid.data.len); | |
19f798ad | 411 | bss = cfg80211_inform_bss(wiphy, |
cb3126e6 KR |
412 | ieee80211_get_channel(wiphy, ieee80211_dsss_chan_to_freq(msg2.dschannel.data)), |
413 | (const u8 *) &(msg2.bssid.data.data), | |
414 | msg2.timestamp.data, msg2.capinfo.data, | |
415 | msg2.beaconperiod.data, | |
416 | ie_buf, | |
417 | ie_len, | |
418 | (msg2.signal.data - 65536) * 100, /* Conversion to signed type */ | |
419 | GFP_KERNEL | |
420 | ); | |
19f798ad KW |
421 | |
422 | if (!bss) { | |
423 | err = -ENOMEM; | |
424 | goto exit; | |
425 | } | |
426 | ||
5b112d3d | 427 | cfg80211_put_bss(wiphy, bss); |
cb3126e6 KR |
428 | } |
429 | ||
8dd82ebe | 430 | if (result) |
cb3126e6 | 431 | err = prism2_result2err(msg2.resultcode.data); |
cb3126e6 KR |
432 | |
433 | exit: | |
434 | cfg80211_scan_done(request, err ? 1 : 0); | |
435 | priv->scan_request = NULL; | |
436 | return err; | |
437 | } | |
438 | ||
8dd82ebe EH |
439 | int prism2_set_wiphy_params(struct wiphy *wiphy, u32 changed) |
440 | { | |
cb3126e6 KR |
441 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); |
442 | wlandevice_t *wlandev = priv->wlandev; | |
443 | u32 data; | |
444 | int result; | |
445 | int err = 0; | |
446 | ||
447 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) { | |
448 | if (wiphy->rts_threshold == -1) | |
449 | data = 2347; | |
450 | else | |
451 | data = wiphy->rts_threshold; | |
452 | ||
8dd82ebe EH |
453 | result = prism2_domibset_uint32(wlandev, |
454 | DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold, | |
455 | data); | |
cb3126e6 KR |
456 | if (result) { |
457 | err = -EFAULT; | |
458 | goto exit; | |
459 | } | |
460 | } | |
461 | ||
462 | if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { | |
cb3126e6 KR |
463 | if (wiphy->frag_threshold == -1) |
464 | data = 2346; | |
465 | else | |
466 | data = wiphy->frag_threshold; | |
467 | ||
8dd82ebe EH |
468 | result = prism2_domibset_uint32(wlandev, |
469 | DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold, | |
470 | data); | |
cb3126e6 KR |
471 | if (result) { |
472 | err = -EFAULT; | |
473 | goto exit; | |
474 | } | |
475 | } | |
476 | ||
477 | exit: | |
478 | return err; | |
479 | } | |
480 | ||
481 | int prism2_connect(struct wiphy *wiphy, struct net_device *dev, | |
8dd82ebe EH |
482 | struct cfg80211_connect_params *sme) |
483 | { | |
cb3126e6 KR |
484 | wlandevice_t *wlandev = dev->ml_priv; |
485 | struct ieee80211_channel *channel = sme->channel; | |
b6bb56e6 | 486 | struct p80211msg_lnxreq_autojoin msg_join; |
cb3126e6 KR |
487 | u32 did; |
488 | int length = sme->ssid_len; | |
489 | int chan = -1; | |
490 | int is_wep = (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40) || | |
491 | (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104); | |
492 | int result; | |
493 | int err = 0; | |
494 | ||
495 | /* Set the channel */ | |
496 | if (channel) { | |
497 | chan = ieee80211_frequency_to_channel(channel->center_freq); | |
8dd82ebe EH |
498 | result = prism2_domibset_uint32(wlandev, |
499 | DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel, | |
500 | chan); | |
501 | if (result) | |
502 | goto exit; | |
cb3126e6 KR |
503 | } |
504 | ||
d34602de | 505 | /* Set the authorization */ |
cb3126e6 KR |
506 | if ((sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) || |
507 | ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && !is_wep)) | |
508 | msg_join.authtype.data = P80211ENUM_authalg_opensystem; | |
509 | else if ((sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) || | |
510 | ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && is_wep)) | |
511 | msg_join.authtype.data = P80211ENUM_authalg_sharedkey; | |
8dd82ebe EH |
512 | else |
513 | printk(KERN_WARNING | |
514 | "Unhandled authorisation type for connect (%d)\n", | |
515 | sme->auth_type); | |
cb3126e6 KR |
516 | |
517 | /* Set the encryption - we only support wep */ | |
518 | if (is_wep) { | |
cb3126e6 KR |
519 | if (sme->key) { |
520 | result = prism2_domibset_uint32(wlandev, | |
521 | DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, | |
522 | sme->key_idx); | |
8dd82ebe EH |
523 | if (result) |
524 | goto exit; | |
cb3126e6 KR |
525 | |
526 | /* send key to driver */ | |
527 | switch (sme->key_idx) { | |
528 | case 0: | |
8dd82ebe | 529 | did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0; |
cb3126e6 KR |
530 | break; |
531 | ||
532 | case 1: | |
8dd82ebe | 533 | did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1; |
cb3126e6 KR |
534 | break; |
535 | ||
536 | case 2: | |
8dd82ebe | 537 | did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2; |
cb3126e6 KR |
538 | break; |
539 | ||
540 | case 3: | |
8dd82ebe | 541 | did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3; |
cb3126e6 KR |
542 | break; |
543 | ||
544 | default: | |
545 | err = -EINVAL; | |
546 | goto exit; | |
547 | } | |
548 | ||
8aac4d44 DN |
549 | result = prism2_domibset_pstr32(wlandev, |
550 | did, sme->key_len, | |
551 | (u8 *)sme->key); | |
8dd82ebe EH |
552 | if (result) |
553 | goto exit; | |
cb3126e6 KR |
554 | |
555 | } | |
556 | ||
557 | /* Assume we should set privacy invoked and exclude unencrypted | |
558 | We could possibly use sme->privacy here, but the assumption | |
559 | seems reasonable anyway */ | |
8dd82ebe EH |
560 | result = prism2_domibset_uint32(wlandev, |
561 | DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, | |
562 | P80211ENUM_truth_true); | |
563 | if (result) | |
564 | goto exit; | |
565 | ||
566 | result = prism2_domibset_uint32(wlandev, | |
567 | DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, | |
568 | P80211ENUM_truth_true); | |
569 | if (result) | |
570 | goto exit; | |
cb3126e6 KR |
571 | |
572 | } else { | |
8dd82ebe EH |
573 | /* Assume we should unset privacy invoked |
574 | and exclude unencrypted */ | |
575 | result = prism2_domibset_uint32(wlandev, | |
576 | DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, | |
577 | P80211ENUM_truth_false); | |
578 | if (result) | |
579 | goto exit; | |
580 | ||
581 | result = prism2_domibset_uint32(wlandev, | |
582 | DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, | |
583 | P80211ENUM_truth_false); | |
584 | if (result) | |
585 | goto exit; | |
cb3126e6 KR |
586 | |
587 | } | |
588 | ||
589 | /* Now do the actual join. Note there is no way that I can | |
590 | see to request a specific bssid */ | |
591 | msg_join.msgcode = DIDmsg_lnxreq_autojoin; | |
592 | ||
593 | memcpy(msg_join.ssid.data.data, sme->ssid, length); | |
594 | msg_join.ssid.data.len = length; | |
595 | ||
8dd82ebe | 596 | result = p80211req_dorequest(wlandev, (u8 *) &msg_join); |
cb3126e6 KR |
597 | |
598 | exit: | |
8dd82ebe EH |
599 | if (result) |
600 | err = -EFAULT; | |
cb3126e6 KR |
601 | |
602 | return err; | |
603 | } | |
604 | ||
605 | int prism2_disconnect(struct wiphy *wiphy, struct net_device *dev, | |
8dd82ebe EH |
606 | u16 reason_code) |
607 | { | |
cb3126e6 | 608 | wlandevice_t *wlandev = dev->ml_priv; |
b6bb56e6 | 609 | struct p80211msg_lnxreq_autojoin msg_join; |
cb3126e6 KR |
610 | int result; |
611 | int err = 0; | |
612 | ||
613 | ||
614 | /* Do a join, with a bogus ssid. Thats the only way I can think of */ | |
615 | msg_join.msgcode = DIDmsg_lnxreq_autojoin; | |
616 | ||
617 | memcpy(msg_join.ssid.data.data, "---", 3); | |
618 | msg_join.ssid.data.len = 3; | |
619 | ||
8dd82ebe | 620 | result = p80211req_dorequest(wlandev, (u8 *) &msg_join); |
cb3126e6 | 621 | |
8dd82ebe EH |
622 | if (result) |
623 | err = -EFAULT; | |
cb3126e6 KR |
624 | |
625 | return err; | |
626 | } | |
627 | ||
628 | ||
629 | int prism2_join_ibss(struct wiphy *wiphy, struct net_device *dev, | |
8dd82ebe EH |
630 | struct cfg80211_ibss_params *params) |
631 | { | |
cb3126e6 KR |
632 | return -EOPNOTSUPP; |
633 | } | |
634 | ||
8dd82ebe EH |
635 | int prism2_leave_ibss(struct wiphy *wiphy, struct net_device *dev) |
636 | { | |
cb3126e6 KR |
637 | return -EOPNOTSUPP; |
638 | } | |
639 | ||
640 | ||
5f3b361a EG |
641 | int prism2_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, |
642 | enum nl80211_tx_power_setting type, int mbm) | |
8dd82ebe | 643 | { |
cb3126e6 KR |
644 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); |
645 | wlandevice_t *wlandev = priv->wlandev; | |
646 | u32 data; | |
647 | int result; | |
648 | int err = 0; | |
649 | ||
9015e499 | 650 | if (type == NL80211_TX_POWER_AUTOMATIC) |
cb3126e6 KR |
651 | data = 30; |
652 | else | |
9015e499 | 653 | data = MBM_TO_DBM(mbm); |
cb3126e6 KR |
654 | |
655 | result = prism2_domibset_uint32(wlandev, | |
656 | DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel, | |
657 | data); | |
658 | ||
659 | if (result) { | |
660 | err = -EFAULT; | |
661 | goto exit; | |
662 | } | |
663 | ||
664 | exit: | |
665 | return err; | |
666 | } | |
667 | ||
5f3b361a EG |
668 | int prism2_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, |
669 | int *dbm) | |
8dd82ebe | 670 | { |
cb3126e6 KR |
671 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); |
672 | wlandevice_t *wlandev = priv->wlandev; | |
b6bb56e6 | 673 | struct p80211msg_dot11req_mibget msg; |
8aac4d44 | 674 | p80211item_uint32_t *mibitem; |
cb3126e6 KR |
675 | int result; |
676 | int err = 0; | |
677 | ||
8aac4d44 | 678 | mibitem = (p80211item_uint32_t *) &msg.mibattribute.data; |
cb3126e6 KR |
679 | msg.msgcode = DIDmsg_dot11req_mibget; |
680 | mibitem->did = | |
681 | DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel; | |
682 | ||
8dd82ebe | 683 | result = p80211req_dorequest(wlandev, (u8 *) &msg); |
cb3126e6 KR |
684 | |
685 | if (result) { | |
686 | err = -EFAULT; | |
687 | goto exit; | |
688 | } | |
689 | ||
690 | *dbm = mibitem->data; | |
691 | ||
692 | exit: | |
693 | return err; | |
694 | } | |
695 | ||
696 | ||
697 | ||
698 | ||
699 | /* Interface callback functions, passing data back up to the cfg80211 layer */ | |
8dd82ebe EH |
700 | void prism2_connect_result(wlandevice_t *wlandev, u8 failed) |
701 | { | |
8aac4d44 DN |
702 | u16 status = failed ? |
703 | WLAN_STATUS_UNSPECIFIED_FAILURE : WLAN_STATUS_SUCCESS; | |
cb3126e6 KR |
704 | |
705 | cfg80211_connect_result(wlandev->netdev, wlandev->bssid, | |
8dd82ebe | 706 | NULL, 0, NULL, 0, status, GFP_KERNEL); |
cb3126e6 KR |
707 | } |
708 | ||
8dd82ebe EH |
709 | void prism2_disconnected(wlandevice_t *wlandev) |
710 | { | |
cb3126e6 KR |
711 | cfg80211_disconnected(wlandev->netdev, 0, NULL, |
712 | 0, GFP_KERNEL); | |
713 | } | |
714 | ||
8dd82ebe EH |
715 | void prism2_roamed(wlandevice_t *wlandev) |
716 | { | |
ed9d0102 | 717 | cfg80211_roamed(wlandev->netdev, NULL, wlandev->bssid, |
cb3126e6 KR |
718 | NULL, 0, NULL, 0, GFP_KERNEL); |
719 | } | |
720 | ||
721 | ||
722 | /* Structures for declaring wiphy interface */ | |
723 | static const struct cfg80211_ops prism2_usb_cfg_ops = { | |
724 | .change_virtual_intf = prism2_change_virtual_intf, | |
725 | .add_key = prism2_add_key, | |
726 | .get_key = prism2_get_key, | |
727 | .del_key = prism2_del_key, | |
728 | .set_default_key = prism2_set_default_key, | |
729 | .get_station = prism2_get_station, | |
730 | .scan = prism2_scan, | |
731 | .set_wiphy_params = prism2_set_wiphy_params, | |
732 | .connect = prism2_connect, | |
733 | .disconnect = prism2_disconnect, | |
734 | .join_ibss = prism2_join_ibss, | |
735 | .leave_ibss = prism2_leave_ibss, | |
736 | .set_tx_power = prism2_set_tx_power, | |
737 | .get_tx_power = prism2_get_tx_power, | |
738 | }; | |
739 | ||
740 | ||
741 | /* Functions to create/free wiphy interface */ | |
742 | struct wiphy *wlan_create_wiphy(struct device *dev, wlandevice_t *wlandev) | |
743 | { | |
744 | struct wiphy *wiphy; | |
745 | struct prism2_wiphy_private *priv; | |
8aac4d44 DN |
746 | |
747 | wiphy = wiphy_new(&prism2_usb_cfg_ops, sizeof(*priv)); | |
cb3126e6 KR |
748 | if (!wiphy) |
749 | return NULL; | |
750 | ||
751 | priv = wiphy_priv(wiphy); | |
752 | priv->wlandev = wlandev; | |
753 | memcpy(priv->channels, prism2_channels, sizeof(prism2_channels)); | |
754 | memcpy(priv->rates, prism2_rates, sizeof(prism2_rates)); | |
755 | priv->band.channels = priv->channels; | |
756 | priv->band.n_channels = ARRAY_SIZE(prism2_channels); | |
757 | priv->band.bitrates = priv->rates; | |
758 | priv->band.n_bitrates = ARRAY_SIZE(prism2_rates); | |
aff3ea4e KR |
759 | priv->band.band = IEEE80211_BAND_2GHZ; |
760 | priv->band.ht_cap.ht_supported = false; | |
cb3126e6 KR |
761 | wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; |
762 | ||
763 | set_wiphy_dev(wiphy, dev); | |
764 | wiphy->privid = prism2_wiphy_privid; | |
765 | wiphy->max_scan_ssids = 1; | |
8dd82ebe EH |
766 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
767 | | BIT(NL80211_IFTYPE_ADHOC); | |
cb3126e6 KR |
768 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; |
769 | wiphy->n_cipher_suites = PRISM2_NUM_CIPHER_SUITES; | |
770 | wiphy->cipher_suites = prism2_cipher_suites; | |
771 | ||
772 | if (wiphy_register(wiphy) < 0) | |
773 | return NULL; | |
774 | ||
775 | return wiphy; | |
776 | } | |
777 | ||
778 | ||
779 | void wlan_free_wiphy(struct wiphy *wiphy) | |
780 | { | |
781 | wiphy_unregister(wiphy); | |
782 | wiphy_free(wiphy); | |
783 | } |