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