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