]>
Commit | Line | Data |
---|---|---|
635d2b00 GKH |
1 | /* |
2 | * *************************************************************************** | |
3 | * FILE: unifi_sme.c | |
4 | * | |
5 | * PURPOSE: SME related functions. | |
6 | * | |
7 | * Copyright (C) 2007-2009 by Cambridge Silicon Radio Ltd. | |
8 | * | |
9 | * Refer to LICENSE.txt included with this source code for details on | |
10 | * the license terms. | |
11 | * | |
12 | * *************************************************************************** | |
13 | */ | |
14 | ||
15 | #include "unifi_priv.h" | |
16 | #include "csr_wifi_hip_unifi.h" | |
17 | #include "csr_wifi_hip_conversions.h" | |
8bd75c77 | 18 | #include <linux/sched/rt.h> |
635d2b00 GKH |
19 | |
20 | ||
21 | ||
22 | int | |
23 | convert_sme_error(CsrResult error) | |
24 | { | |
25 | switch (error) { | |
26 | case CSR_RESULT_SUCCESS: | |
27 | return 0; | |
28 | case CSR_RESULT_FAILURE: | |
29 | case CSR_WIFI_RESULT_NOT_FOUND: | |
30 | case CSR_WIFI_RESULT_TIMED_OUT: | |
31 | case CSR_WIFI_RESULT_CANCELLED: | |
32 | case CSR_WIFI_RESULT_UNAVAILABLE: | |
33 | return -EIO; | |
34 | case CSR_WIFI_RESULT_NO_ROOM: | |
35 | return -EBUSY; | |
36 | case CSR_WIFI_RESULT_INVALID_PARAMETER: | |
37 | return -EINVAL; | |
38 | case CSR_WIFI_RESULT_UNSUPPORTED: | |
39 | return -EOPNOTSUPP; | |
40 | default: | |
41 | return -EIO; | |
42 | } | |
43 | } | |
44 | ||
45 | ||
46 | /* | |
47 | * --------------------------------------------------------------------------- | |
48 | * sme_log_event | |
49 | * | |
50 | * Callback function to be registered as the SME event callback. | |
51 | * Copies the signal content into a new udi_log_t struct and adds | |
52 | * it to the read queue for the SME client. | |
53 | * | |
54 | * Arguments: | |
55 | * arg This is the value given to unifi_add_udi_hook, in | |
56 | * this case a pointer to the client instance. | |
57 | * signal Pointer to the received signal. | |
58 | * signal_len Size of the signal structure in bytes. | |
59 | * bulkdata Pointers to any associated bulk data. | |
60 | * dir Direction of the signal. Zero means from host, | |
61 | * non-zero means to host. | |
62 | * | |
63 | * Returns: | |
64 | * None. | |
65 | * --------------------------------------------------------------------------- | |
66 | */ | |
67 | void | |
68 | sme_log_event(ul_client_t *pcli, | |
69 | const u8 *signal, int signal_len, | |
70 | const bulk_data_param_t *bulkdata, | |
71 | int dir) | |
72 | { | |
73 | unifi_priv_t *priv; | |
74 | CSR_SIGNAL unpacked_signal; | |
75 | CsrWifiSmeDataBlock mlmeCommand; | |
76 | CsrWifiSmeDataBlock dataref1; | |
77 | CsrWifiSmeDataBlock dataref2; | |
78 | CsrResult result = CSR_RESULT_SUCCESS; | |
79 | int r; | |
80 | ||
635d2b00 GKH |
81 | /* Just a sanity check */ |
82 | if ((signal == NULL) || (signal_len <= 0)) { | |
635d2b00 GKH |
83 | return; |
84 | } | |
85 | ||
86 | priv = uf_find_instance(pcli->instance); | |
87 | if (!priv) { | |
88 | unifi_error(priv, "sme_log_event: invalid priv\n"); | |
635d2b00 GKH |
89 | return; |
90 | } | |
91 | ||
92 | if (priv->smepriv == NULL) { | |
93 | unifi_error(priv, "sme_log_event: invalid smepriv\n"); | |
635d2b00 GKH |
94 | return; |
95 | } | |
96 | ||
97 | unifi_trace(priv, UDBG3, | |
98 | "sme_log_event: Process signal 0x%.4X\n", | |
99 | CSR_GET_UINT16_FROM_LITTLE_ENDIAN(signal)); | |
100 | ||
101 | ||
102 | /* If the signal is known, then do any filtering required, otherwise it pass it to the SME. */ | |
103 | r = read_unpack_signal(signal, &unpacked_signal); | |
104 | if (r == CSR_RESULT_SUCCESS) { | |
105 | if ((unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_DEBUG_STRING_INDICATION_ID) || | |
106 | (unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_DEBUG_WORD16_INDICATION_ID)) | |
107 | { | |
635d2b00 GKH |
108 | return; |
109 | } | |
110 | if (unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_MA_PACKET_INDICATION_ID) | |
111 | { | |
8c87f69a | 112 | u16 frmCtrl; |
5379b13d | 113 | u8 unicastPdu = TRUE; |
7e6f5794 GKH |
114 | u8 *macHdrLocation; |
115 | u8 *raddr = NULL, *taddr = NULL; | |
635d2b00 GKH |
116 | CsrWifiMacAddress peerMacAddress; |
117 | /* Check if we need to send CsrWifiRouterCtrlMicFailureInd*/ | |
118 | CSR_MA_PACKET_INDICATION *ind = &unpacked_signal.u.MaPacketIndication; | |
119 | ||
7e6f5794 | 120 | macHdrLocation = (u8 *) bulkdata->d[0].os_data_ptr; |
635d2b00 GKH |
121 | /* Fetch the frame control value from mac header */ |
122 | frmCtrl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(macHdrLocation); | |
123 | ||
124 | /* Point to the addresses */ | |
125 | raddr = macHdrLocation + MAC_HEADER_ADDR1_OFFSET; | |
126 | taddr = macHdrLocation + MAC_HEADER_ADDR2_OFFSET; | |
127 | ||
25aebdb1 | 128 | memcpy(peerMacAddress.a, taddr, ETH_ALEN); |
635d2b00 GKH |
129 | |
130 | if(ind->ReceptionStatus == CSR_MICHAEL_MIC_ERROR) | |
131 | { | |
132 | if (*raddr & 0x1) | |
133 | unicastPdu = FALSE; | |
134 | ||
135 | CsrWifiRouterCtrlMicFailureIndSend (priv->CSR_WIFI_SME_IFACEQUEUE, 0, | |
136 | (ind->VirtualInterfaceIdentifier & 0xff),peerMacAddress, | |
137 | unicastPdu); | |
138 | return; | |
139 | } | |
140 | else | |
141 | { | |
142 | if(ind->ReceptionStatus == CSR_RX_SUCCESS) | |
143 | { | |
7e6f5794 | 144 | u8 pmBit = (frmCtrl & 0x1000)?0x01:0x00; |
8c87f69a | 145 | u16 interfaceTag = (ind->VirtualInterfaceIdentifier & 0xff); |
635d2b00 GKH |
146 | CsrWifiRouterCtrlStaInfo_t *srcStaInfo = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(priv,taddr,interfaceTag); |
147 | if((srcStaInfo != NULL) && (uf_check_broadcast_bssid(priv, bulkdata)== FALSE)) | |
148 | { | |
149 | uf_process_pm_bit_for_peer(priv,srcStaInfo,pmBit,interfaceTag); | |
150 | ||
151 | /* Update station last activity flag */ | |
152 | srcStaInfo->activity_flag = TRUE; | |
153 | } | |
154 | } | |
155 | } | |
156 | } | |
157 | ||
158 | if (unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_MA_PACKET_CONFIRM_ID) | |
159 | { | |
160 | CSR_MA_PACKET_CONFIRM *cfm = &unpacked_signal.u.MaPacketConfirm; | |
8c87f69a | 161 | u16 interfaceTag = (cfm->VirtualInterfaceIdentifier & 0xff); |
635d2b00 GKH |
162 | netInterface_priv_t *interfacePriv; |
163 | CSR_MA_PACKET_REQUEST *req; | |
164 | CsrWifiMacAddress peerMacAddress; | |
165 | ||
166 | if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) | |
167 | { | |
168 | unifi_error(priv, "Bad MA_PACKET_CONFIRM interfaceTag %d\n", interfaceTag); | |
635d2b00 GKH |
169 | return; |
170 | } | |
171 | ||
172 | unifi_trace(priv,UDBG1,"MA-PACKET Confirm (%x, %x)\n", cfm->HostTag, cfm->TransmissionStatus); | |
173 | ||
174 | interfacePriv = priv->interfacePriv[interfaceTag]; | |
175 | #ifdef CSR_SUPPORT_SME | |
176 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
177 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
178 | ||
179 | if(cfm->HostTag == interfacePriv->multicastPduHostTag){ | |
180 | uf_process_ma_pkt_cfm_for_ap(priv ,interfaceTag, cfm); | |
181 | } | |
182 | } | |
183 | #endif | |
184 | ||
185 | req = &interfacePriv->m4_signal.u.MaPacketRequest; | |
186 | ||
187 | if(cfm->HostTag & 0x80000000) | |
188 | { | |
189 | if (cfm->TransmissionStatus != CSR_TX_SUCCESSFUL) | |
190 | { | |
191 | result = CSR_RESULT_FAILURE; | |
192 | } | |
193 | #ifdef CSR_SUPPORT_SME | |
194 | memcpy(peerMacAddress.a, req->Ra.x, ETH_ALEN); | |
195 | /* Check if this is a confirm for EAPOL M4 frame and we need to send transmistted ind*/ | |
196 | if (interfacePriv->m4_sent && (cfm->HostTag == interfacePriv->m4_hostTag)) | |
197 | { | |
198 | unifi_trace(priv, UDBG1, "%s: Sending M4 Transmit CFM\n", __FUNCTION__); | |
199 | CsrWifiRouterCtrlM4TransmittedIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0, | |
200 | interfaceTag, | |
201 | peerMacAddress, | |
202 | result); | |
203 | interfacePriv->m4_sent = FALSE; | |
204 | interfacePriv->m4_hostTag = 0xffffffff; | |
205 | } | |
206 | #endif | |
207 | /* If EAPOL was requested via router APIs then send cfm else ignore*/ | |
208 | if((cfm->HostTag & 0x80000000) != CSR_WIFI_EAPOL_M4_HOST_TAG) { | |
8c87f69a | 209 | CsrWifiRouterMaPacketCfmSend((u16)signal[2], |
635d2b00 GKH |
210 | cfm->VirtualInterfaceIdentifier, |
211 | result, | |
212 | (cfm->HostTag & 0x3fffffff), cfm->Rate); | |
213 | } else { | |
214 | unifi_trace(priv, UDBG1, "%s: M4 received from netdevice\n", __FUNCTION__); | |
215 | } | |
635d2b00 GKH |
216 | return; |
217 | } | |
218 | } | |
219 | } | |
220 | ||
221 | mlmeCommand.length = signal_len; | |
7e6f5794 | 222 | mlmeCommand.data = (u8*)signal; |
635d2b00 GKH |
223 | |
224 | dataref1.length = bulkdata->d[0].data_length; | |
225 | if (dataref1.length > 0) { | |
7e6f5794 | 226 | dataref1.data = (u8 *) bulkdata->d[0].os_data_ptr; |
635d2b00 GKH |
227 | } else |
228 | { | |
229 | dataref1.data = NULL; | |
230 | } | |
231 | ||
232 | dataref2.length = bulkdata->d[1].data_length; | |
233 | if (dataref2.length > 0) { | |
7e6f5794 | 234 | dataref2.data = (u8 *) bulkdata->d[1].os_data_ptr; |
635d2b00 GKH |
235 | } else |
236 | { | |
237 | dataref2.data = NULL; | |
238 | } | |
239 | ||
240 | CsrWifiRouterCtrlHipIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, mlmeCommand.length, mlmeCommand.data, | |
241 | dataref1.length, dataref1.data, | |
242 | dataref2.length, dataref2.data); | |
243 | ||
635d2b00 GKH |
244 | } /* sme_log_event() */ |
245 | ||
246 | ||
247 | /* | |
248 | * --------------------------------------------------------------------------- | |
249 | * uf_sme_port_state | |
250 | * | |
251 | * Return the state of the controlled port. | |
252 | * | |
253 | * Arguments: | |
254 | * priv Pointer to device private context struct | |
255 | * address Pointer to the destination for tx or sender for rx address | |
256 | * queue Controlled or uncontrolled queue | |
257 | * | |
258 | * Returns: | |
259 | * An unifi_ControlledPortAction value. | |
260 | * --------------------------------------------------------------------------- | |
261 | */ | |
262 | CsrWifiRouterCtrlPortAction | |
8c87f69a | 263 | uf_sme_port_state(unifi_priv_t *priv, unsigned char *address, int queue, u16 interfaceTag) |
635d2b00 GKH |
264 | { |
265 | int i; | |
266 | unifi_port_config_t *port; | |
267 | netInterface_priv_t *interfacePriv; | |
268 | ||
269 | if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) { | |
270 | unifi_error(priv, "uf_sme_port_state: bad interfaceTag\n"); | |
271 | return CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD; | |
272 | } | |
273 | ||
274 | interfacePriv = priv->interfacePriv[interfaceTag]; | |
275 | ||
276 | if (queue == UF_CONTROLLED_PORT_Q) { | |
277 | port = &interfacePriv->controlled_data_port; | |
278 | } else { | |
279 | port = &interfacePriv->uncontrolled_data_port; | |
280 | } | |
281 | ||
282 | if (!port->entries_in_use) { | |
283 | unifi_trace(priv, UDBG5, "No port configurations, return Discard.\n"); | |
284 | return CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD; | |
285 | } | |
286 | ||
287 | /* If the port configuration is common for all destinations, return it. */ | |
288 | if (port->overide_action == UF_DATA_PORT_OVERIDE) { | |
289 | unifi_trace(priv, UDBG5, "Single port configuration (%d).\n", | |
290 | port->port_cfg[0].port_action); | |
291 | return port->port_cfg[0].port_action; | |
292 | } | |
293 | ||
294 | unifi_trace(priv, UDBG5, "Multiple (%d) port configurations.\n", port->entries_in_use); | |
295 | ||
296 | /* If multiple configurations exist.. */ | |
297 | for (i = 0; i < UNIFI_MAX_CONNECTIONS; i++) { | |
298 | /* .. go through the list and match the destination address. */ | |
299 | if (port->port_cfg[i].in_use && | |
300 | memcmp(address, port->port_cfg[i].mac_address.a, ETH_ALEN) == 0) { | |
301 | /* Return the desired action. */ | |
302 | return port->port_cfg[i].port_action; | |
303 | } | |
304 | } | |
305 | ||
306 | /* Could not find any information, return Open. */ | |
307 | unifi_trace(priv, UDBG5, "port configuration not found, return Open.\n"); | |
308 | return CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN; | |
309 | } /* uf_sme_port_state() */ | |
310 | ||
311 | /* | |
312 | * --------------------------------------------------------------------------- | |
313 | * uf_sme_port_config_handle | |
314 | * | |
315 | * Return the port config handle of the controlled/uncontrolled port. | |
316 | * | |
317 | * Arguments: | |
318 | * priv Pointer to device private context struct | |
319 | * address Pointer to the destination for tx or sender for rx address | |
320 | * queue Controlled or uncontrolled queue | |
321 | * | |
322 | * Returns: | |
323 | * An unifi_port_cfg_t* . | |
324 | * --------------------------------------------------------------------------- | |
325 | */ | |
326 | unifi_port_cfg_t* | |
8c87f69a | 327 | uf_sme_port_config_handle(unifi_priv_t *priv, unsigned char *address, int queue, u16 interfaceTag) |
635d2b00 GKH |
328 | { |
329 | int i; | |
330 | unifi_port_config_t *port; | |
331 | netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag]; | |
332 | ||
333 | if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) { | |
334 | unifi_error(priv, "uf_sme_port_config_handle: bad interfaceTag\n"); | |
335 | return NULL; | |
336 | } | |
337 | ||
338 | if (queue == UF_CONTROLLED_PORT_Q) { | |
339 | port = &interfacePriv->controlled_data_port; | |
340 | } else { | |
341 | port = &interfacePriv->uncontrolled_data_port; | |
342 | } | |
343 | ||
344 | if (!port->entries_in_use) { | |
345 | unifi_trace(priv, UDBG5, "No port configurations, return Discard.\n"); | |
346 | return NULL; | |
347 | } | |
348 | ||
349 | /* If the port configuration is common for all destinations, return it. */ | |
350 | if (port->overide_action == UF_DATA_PORT_OVERIDE) { | |
351 | unifi_trace(priv, UDBG5, "Single port configuration (%d).\n", | |
352 | port->port_cfg[0].port_action); | |
353 | if (address) { | |
354 | unifi_trace(priv, UDBG5, "addr[0] = %x, addr[1] = %x, addr[2] = %x, addr[3] = %x\n", address[0], address[1], address[2], address[3]); | |
355 | } | |
356 | return &port->port_cfg[0]; | |
357 | } | |
358 | ||
359 | unifi_trace(priv, UDBG5, "Multiple port configurations.\n"); | |
360 | ||
361 | /* If multiple configurations exist.. */ | |
362 | for (i = 0; i < UNIFI_MAX_CONNECTIONS; i++) { | |
363 | /* .. go through the list and match the destination address. */ | |
364 | if (port->port_cfg[i].in_use && | |
365 | memcmp(address, port->port_cfg[i].mac_address.a, ETH_ALEN) == 0) { | |
366 | /* Return the desired action. */ | |
367 | return &port->port_cfg[i]; | |
368 | } | |
369 | } | |
370 | ||
371 | /* Could not find any information, return Open. */ | |
372 | unifi_trace(priv, UDBG5, "port configuration not found, returning NULL (debug).\n"); | |
373 | return NULL; | |
374 | } /* uf_sme_port_config_handle */ | |
375 | ||
376 | void | |
377 | uf_multicast_list_wq(struct work_struct *work) | |
378 | { | |
379 | unifi_priv_t *priv = container_of(work, unifi_priv_t, | |
380 | multicast_list_task); | |
381 | int i; | |
8c87f69a | 382 | u16 interfaceTag = 0; |
635d2b00 GKH |
383 | CsrWifiMacAddress* multicast_address_list = NULL; |
384 | int mc_count; | |
385 | u8 *mc_list; | |
386 | netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag]; | |
387 | ||
388 | if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) { | |
389 | unifi_error(priv, "uf_multicast_list_wq: bad interfaceTag\n"); | |
390 | return; | |
391 | } | |
392 | ||
393 | unifi_trace(priv, UDBG5, | |
394 | "uf_multicast_list_wq: list count = %d\n", | |
395 | interfacePriv->mc_list_count); | |
396 | ||
397 | /* Flush the current list */ | |
398 | CsrWifiRouterCtrlMulticastAddressIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, interfaceTag, CSR_WIFI_SME_LIST_ACTION_FLUSH, 0, NULL); | |
399 | ||
400 | mc_count = interfacePriv->mc_list_count; | |
401 | mc_list = interfacePriv->mc_list; | |
402 | /* | |
403 | * Allocate a new list, need to free it later | |
404 | * in unifi_mgt_multicast_address_cfm(). | |
405 | */ | |
786eeeb3 | 406 | multicast_address_list = kmalloc(mc_count * sizeof(CsrWifiMacAddress), GFP_KERNEL); |
635d2b00 GKH |
407 | |
408 | if (multicast_address_list == NULL) { | |
409 | return; | |
410 | } | |
411 | ||
412 | for (i = 0; i < mc_count; i++) { | |
413 | memcpy(multicast_address_list[i].a, mc_list, ETH_ALEN); | |
414 | mc_list += ETH_ALEN; | |
415 | } | |
416 | ||
417 | if (priv->smepriv == NULL) { | |
55a27055 | 418 | kfree(multicast_address_list); |
635d2b00 GKH |
419 | return; |
420 | } | |
421 | ||
422 | CsrWifiRouterCtrlMulticastAddressIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, | |
423 | interfaceTag, | |
424 | CSR_WIFI_SME_LIST_ACTION_ADD, | |
425 | mc_count, multicast_address_list); | |
426 | ||
427 | /* The SME will take a copy of the addreses*/ | |
55a27055 | 428 | kfree(multicast_address_list); |
635d2b00 GKH |
429 | } |
430 | ||
431 | ||
432 | int unifi_cfg_power(unifi_priv_t *priv, unsigned char *arg) | |
433 | { | |
434 | unifi_cfg_power_t cfg_power; | |
435 | int rc; | |
95edd09e | 436 | int wol; |
635d2b00 GKH |
437 | |
438 | if (get_user(cfg_power, (unifi_cfg_power_t*)(((unifi_cfg_command_t*)arg) + 1))) { | |
439 | unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n"); | |
440 | return -EFAULT; | |
441 | } | |
442 | ||
443 | switch (cfg_power) { | |
444 | case UNIFI_CFG_POWER_OFF: | |
95edd09e | 445 | priv->wol_suspend = (enable_wol == UNIFI_WOL_OFF) ? FALSE : TRUE; |
635d2b00 GKH |
446 | rc = sme_sys_suspend(priv); |
447 | if (rc) { | |
448 | return rc; | |
449 | } | |
450 | break; | |
451 | case UNIFI_CFG_POWER_ON: | |
95edd09e | 452 | wol = priv->wol_suspend; |
635d2b00 GKH |
453 | rc = sme_sys_resume(priv); |
454 | if (rc) { | |
455 | return rc; | |
456 | } | |
95edd09e GKH |
457 | if (wol) { |
458 | /* Kick the BH to ensure pending transfers are handled when | |
459 | * a suspend happened with card powered. | |
460 | */ | |
461 | unifi_send_signal(priv->card, NULL, 0, NULL); | |
462 | } | |
635d2b00 GKH |
463 | break; |
464 | default: | |
465 | unifi_error(priv, "WIFI POWER: Unknown value.\n"); | |
466 | return -EINVAL; | |
467 | } | |
468 | ||
469 | return 0; | |
470 | } | |
471 | ||
472 | ||
473 | int unifi_cfg_power_save(unifi_priv_t *priv, unsigned char *arg) | |
474 | { | |
475 | unifi_cfg_powersave_t cfg_power_save; | |
476 | CsrWifiSmePowerConfig powerConfig; | |
477 | int rc; | |
478 | ||
479 | if (get_user(cfg_power_save, (unifi_cfg_powersave_t*)(((unifi_cfg_command_t*)arg) + 1))) { | |
480 | unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n"); | |
481 | return -EFAULT; | |
482 | } | |
483 | ||
484 | /* Get the coex info from the SME */ | |
485 | rc = sme_mgt_power_config_get(priv, &powerConfig); | |
486 | if (rc) { | |
487 | unifi_error(priv, "UNIFI_CFG: Get unifi_PowerConfigValue failed.\n"); | |
488 | return rc; | |
489 | } | |
490 | ||
491 | switch (cfg_power_save) { | |
492 | case UNIFI_CFG_POWERSAVE_NONE: | |
493 | powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_LOW; | |
494 | break; | |
495 | case UNIFI_CFG_POWERSAVE_FAST: | |
496 | powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_MED; | |
497 | break; | |
498 | case UNIFI_CFG_POWERSAVE_FULL: | |
499 | powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_HIGH; | |
500 | break; | |
501 | case UNIFI_CFG_POWERSAVE_AUTO: | |
502 | powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_AUTO; | |
503 | break; | |
504 | default: | |
505 | unifi_error(priv, "POWERSAVE: Unknown value.\n"); | |
506 | return -EINVAL; | |
507 | } | |
508 | ||
509 | rc = sme_mgt_power_config_set(priv, &powerConfig); | |
510 | ||
511 | if (rc) { | |
512 | unifi_error(priv, "UNIFI_CFG: Set unifi_PowerConfigValue failed.\n"); | |
513 | } | |
514 | ||
515 | return rc; | |
516 | } | |
517 | ||
518 | ||
519 | int unifi_cfg_power_supply(unifi_priv_t *priv, unsigned char *arg) | |
520 | { | |
521 | unifi_cfg_powersupply_t cfg_power_supply; | |
522 | CsrWifiSmeHostConfig hostConfig; | |
523 | int rc; | |
524 | ||
525 | if (get_user(cfg_power_supply, (unifi_cfg_powersupply_t*)(((unifi_cfg_command_t*)arg) + 1))) { | |
526 | unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n"); | |
527 | return -EFAULT; | |
528 | } | |
529 | ||
530 | /* Get the coex info from the SME */ | |
531 | rc = sme_mgt_host_config_get(priv, &hostConfig); | |
532 | if (rc) { | |
533 | unifi_error(priv, "UNIFI_CFG: Get unifi_HostConfigValue failed.\n"); | |
534 | return rc; | |
535 | } | |
536 | ||
537 | switch (cfg_power_supply) { | |
538 | case UNIFI_CFG_POWERSUPPLY_MAINS: | |
539 | hostConfig.powerMode = CSR_WIFI_SME_HOST_POWER_MODE_ACTIVE; | |
540 | break; | |
541 | case UNIFI_CFG_POWERSUPPLY_BATTERIES: | |
542 | hostConfig.powerMode = CSR_WIFI_SME_HOST_POWER_MODE_POWER_SAVE; | |
543 | break; | |
544 | default: | |
545 | unifi_error(priv, "POWERSUPPLY: Unknown value.\n"); | |
546 | return -EINVAL; | |
547 | } | |
548 | ||
549 | rc = sme_mgt_host_config_set(priv, &hostConfig); | |
550 | if (rc) { | |
551 | unifi_error(priv, "UNIFI_CFG: Set unifi_HostConfigValue failed.\n"); | |
552 | } | |
553 | ||
554 | return rc; | |
555 | } | |
556 | ||
557 | ||
558 | int unifi_cfg_packet_filters(unifi_priv_t *priv, unsigned char *arg) | |
559 | { | |
560 | unsigned char *tclas_buffer; | |
561 | unsigned int tclas_buffer_length; | |
562 | tclas_t *dhcp_tclas; | |
563 | int rc; | |
564 | ||
565 | /* Free any TCLASs previously allocated */ | |
566 | if (priv->packet_filters.tclas_ies_length) { | |
55a27055 | 567 | kfree(priv->filter_tclas_ies); |
635d2b00 GKH |
568 | priv->filter_tclas_ies = NULL; |
569 | } | |
570 | ||
571 | tclas_buffer = ((unsigned char*)arg) + sizeof(unifi_cfg_command_t) + sizeof(unsigned int); | |
572 | if (copy_from_user(&priv->packet_filters, (void*)tclas_buffer, | |
573 | sizeof(uf_cfg_bcast_packet_filter_t))) { | |
574 | unifi_error(priv, "UNIFI_CFG: Failed to get the filter struct\n"); | |
575 | return -EFAULT; | |
576 | } | |
577 | ||
578 | tclas_buffer_length = priv->packet_filters.tclas_ies_length; | |
579 | ||
580 | /* Allocate TCLASs if necessary */ | |
581 | if (priv->packet_filters.dhcp_filter) { | |
582 | priv->packet_filters.tclas_ies_length += sizeof(tclas_t); | |
583 | } | |
584 | if (priv->packet_filters.tclas_ies_length > 0) { | |
786eeeb3 | 585 | priv->filter_tclas_ies = kmalloc(priv->packet_filters.tclas_ies_length, GFP_KERNEL); |
635d2b00 GKH |
586 | if (priv->filter_tclas_ies == NULL) { |
587 | return -ENOMEM; | |
588 | } | |
589 | if (tclas_buffer_length) { | |
590 | tclas_buffer += sizeof(uf_cfg_bcast_packet_filter_t) - sizeof(unsigned char*); | |
591 | if (copy_from_user(priv->filter_tclas_ies, | |
592 | tclas_buffer, | |
593 | tclas_buffer_length)) { | |
594 | unifi_error(priv, "UNIFI_CFG: Failed to get the TCLAS buffer\n"); | |
595 | return -EFAULT; | |
596 | } | |
597 | } | |
598 | } | |
599 | ||
600 | if(priv->packet_filters.dhcp_filter) | |
601 | { | |
602 | /* Append the DHCP tclas IE */ | |
603 | dhcp_tclas = (tclas_t*)(priv->filter_tclas_ies + tclas_buffer_length); | |
604 | memset(dhcp_tclas, 0, sizeof(tclas_t)); | |
605 | dhcp_tclas->element_id = 14; | |
606 | dhcp_tclas->length = sizeof(tcpip_clsfr_t) + 1; | |
607 | dhcp_tclas->user_priority = 0; | |
608 | dhcp_tclas->tcp_ip_cls_fr.cls_fr_type = 1; | |
609 | dhcp_tclas->tcp_ip_cls_fr.version = 4; | |
7e6f5794 GKH |
610 | ((u8*)(&dhcp_tclas->tcp_ip_cls_fr.source_port))[0] = 0x00; |
611 | ((u8*)(&dhcp_tclas->tcp_ip_cls_fr.source_port))[1] = 0x44; | |
612 | ((u8*)(&dhcp_tclas->tcp_ip_cls_fr.dest_port))[0] = 0x00; | |
613 | ((u8*)(&dhcp_tclas->tcp_ip_cls_fr.dest_port))[1] = 0x43; | |
635d2b00 GKH |
614 | dhcp_tclas->tcp_ip_cls_fr.protocol = 0x11; |
615 | dhcp_tclas->tcp_ip_cls_fr.cls_fr_mask = 0x58; //bits: 3,4,6 | |
616 | } | |
617 | ||
618 | rc = sme_mgt_packet_filter_set(priv); | |
619 | ||
620 | return rc; | |
621 | } | |
622 | ||
623 | ||
624 | int unifi_cfg_wmm_qos_info(unifi_priv_t *priv, unsigned char *arg) | |
625 | { | |
7e6f5794 | 626 | u8 wmm_qos_info; |
635d2b00 GKH |
627 | int rc = 0; |
628 | ||
7e6f5794 | 629 | if (get_user(wmm_qos_info, (u8*)(((unifi_cfg_command_t*)arg) + 1))) { |
635d2b00 GKH |
630 | unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n"); |
631 | return -EFAULT; | |
632 | } | |
633 | ||
634 | /* Store the value in the connection info */ | |
635 | priv->connection_config.wmmQosInfo = wmm_qos_info; | |
636 | ||
637 | return rc; | |
638 | } | |
639 | ||
640 | ||
641 | int unifi_cfg_wmm_addts(unifi_priv_t *priv, unsigned char *arg) | |
642 | { | |
26a6b2e1 | 643 | u32 addts_tid; |
7e6f5794 GKH |
644 | u8 addts_ie_length; |
645 | u8 *addts_ie; | |
646 | u8 *addts_params; | |
635d2b00 GKH |
647 | CsrWifiSmeDataBlock tspec; |
648 | CsrWifiSmeDataBlock tclas; | |
649 | int rc; | |
650 | ||
7e6f5794 | 651 | addts_params = (u8*)(((unifi_cfg_command_t*)arg) + 1); |
26a6b2e1 | 652 | if (get_user(addts_tid, (u32*)addts_params)) { |
635d2b00 GKH |
653 | unifi_error(priv, "unifi_cfg_wmm_addts: Failed to get the argument\n"); |
654 | return -EFAULT; | |
655 | } | |
656 | ||
26a6b2e1 | 657 | addts_params += sizeof(u32); |
7e6f5794 | 658 | if (get_user(addts_ie_length, (u8*)addts_params)) { |
635d2b00 GKH |
659 | unifi_error(priv, "unifi_cfg_wmm_addts: Failed to get the argument\n"); |
660 | return -EFAULT; | |
661 | } | |
662 | ||
663 | unifi_trace(priv, UDBG4, "addts: tid = 0x%x ie_length = %d\n", | |
664 | addts_tid, addts_ie_length); | |
665 | ||
786eeeb3 | 666 | addts_ie = kmalloc(addts_ie_length, GFP_KERNEL); |
635d2b00 GKH |
667 | if (addts_ie == NULL) { |
668 | unifi_error(priv, | |
669 | "unifi_cfg_wmm_addts: Failed to malloc %d bytes for addts_ie buffer\n", | |
670 | addts_ie_length); | |
671 | return -ENOMEM; | |
672 | } | |
673 | ||
7e6f5794 | 674 | addts_params += sizeof(u8); |
635d2b00 GKH |
675 | rc = copy_from_user(addts_ie, addts_params, addts_ie_length); |
676 | if (rc) { | |
677 | unifi_error(priv, "unifi_cfg_wmm_addts: Failed to get the addts buffer\n"); | |
55a27055 | 678 | kfree(addts_ie); |
635d2b00 GKH |
679 | return -EFAULT; |
680 | } | |
681 | ||
682 | tspec.data = addts_ie; | |
683 | tspec.length = addts_ie_length; | |
684 | tclas.data = NULL; | |
685 | tclas.length = 0; | |
686 | ||
687 | rc = sme_mgt_tspec(priv, CSR_WIFI_SME_LIST_ACTION_ADD, addts_tid, | |
688 | &tspec, &tclas); | |
689 | ||
55a27055 | 690 | kfree(addts_ie); |
635d2b00 GKH |
691 | return rc; |
692 | } | |
693 | ||
694 | ||
695 | int unifi_cfg_wmm_delts(unifi_priv_t *priv, unsigned char *arg) | |
696 | { | |
26a6b2e1 | 697 | u32 delts_tid; |
7e6f5794 | 698 | u8 *delts_params; |
635d2b00 GKH |
699 | CsrWifiSmeDataBlock tspec; |
700 | CsrWifiSmeDataBlock tclas; | |
701 | int rc; | |
702 | ||
7e6f5794 | 703 | delts_params = (u8*)(((unifi_cfg_command_t*)arg) + 1); |
26a6b2e1 | 704 | if (get_user(delts_tid, (u32*)delts_params)) { |
635d2b00 GKH |
705 | unifi_error(priv, "unifi_cfg_wmm_delts: Failed to get the argument\n"); |
706 | return -EFAULT; | |
707 | } | |
708 | ||
709 | unifi_trace(priv, UDBG4, "delts: tid = 0x%x\n", delts_tid); | |
710 | ||
711 | tspec.data = tclas.data = NULL; | |
712 | tspec.length = tclas.length = 0; | |
713 | ||
714 | rc = sme_mgt_tspec(priv, CSR_WIFI_SME_LIST_ACTION_REMOVE, delts_tid, | |
715 | &tspec, &tclas); | |
716 | ||
717 | return rc; | |
718 | } | |
719 | ||
720 | int unifi_cfg_strict_draft_n(unifi_priv_t *priv, unsigned char *arg) | |
721 | { | |
5379b13d | 722 | u8 strict_draft_n; |
7e6f5794 | 723 | u8 *strict_draft_n_params; |
635d2b00 GKH |
724 | int rc; |
725 | ||
726 | CsrWifiSmeStaConfig staConfig; | |
727 | CsrWifiSmeDeviceConfig deviceConfig; | |
728 | ||
7e6f5794 | 729 | strict_draft_n_params = (u8*)(((unifi_cfg_command_t*)arg) + 1); |
5379b13d | 730 | if (get_user(strict_draft_n, (u8*)strict_draft_n_params)) { |
635d2b00 GKH |
731 | unifi_error(priv, "unifi_cfg_strict_draft_n: Failed to get the argument\n"); |
732 | return -EFAULT; | |
733 | } | |
734 | ||
735 | unifi_trace(priv, UDBG4, "strict_draft_n: = %s\n", ((strict_draft_n) ? "yes":"no")); | |
736 | ||
737 | rc = sme_mgt_sme_config_get(priv, &staConfig, &deviceConfig); | |
738 | ||
739 | if (rc) { | |
740 | unifi_warning(priv, "unifi_cfg_strict_draft_n: Get unifi_SMEConfigValue failed.\n"); | |
741 | return -EFAULT; | |
742 | } | |
743 | ||
744 | deviceConfig.enableStrictDraftN = strict_draft_n; | |
745 | ||
746 | rc = sme_mgt_sme_config_set(priv, &staConfig, &deviceConfig); | |
747 | if (rc) { | |
748 | unifi_warning(priv, "unifi_cfg_strict_draft_n: Set unifi_SMEConfigValue failed.\n"); | |
749 | rc = -EFAULT; | |
750 | } | |
751 | ||
752 | return rc; | |
753 | } | |
754 | ||
755 | ||
756 | int unifi_cfg_enable_okc(unifi_priv_t *priv, unsigned char *arg) | |
757 | { | |
5379b13d | 758 | u8 enable_okc; |
7e6f5794 | 759 | u8 *enable_okc_params; |
635d2b00 GKH |
760 | int rc; |
761 | ||
762 | CsrWifiSmeStaConfig staConfig; | |
763 | CsrWifiSmeDeviceConfig deviceConfig; | |
764 | ||
7e6f5794 | 765 | enable_okc_params = (u8*)(((unifi_cfg_command_t*)arg) + 1); |
5379b13d | 766 | if (get_user(enable_okc, (u8*)enable_okc_params)) { |
635d2b00 GKH |
767 | unifi_error(priv, "unifi_cfg_enable_okc: Failed to get the argument\n"); |
768 | return -EFAULT; | |
769 | } | |
770 | ||
771 | unifi_trace(priv, UDBG4, "enable_okc: = %s\n", ((enable_okc) ? "yes":"no")); | |
772 | ||
773 | rc = sme_mgt_sme_config_get(priv, &staConfig, &deviceConfig); | |
774 | if (rc) { | |
775 | unifi_warning(priv, "unifi_cfg_enable_okc: Get unifi_SMEConfigValue failed.\n"); | |
776 | return -EFAULT; | |
777 | } | |
778 | ||
779 | staConfig.enableOpportunisticKeyCaching = enable_okc; | |
780 | ||
781 | rc = sme_mgt_sme_config_set(priv, &staConfig, &deviceConfig); | |
782 | if (rc) { | |
783 | unifi_warning(priv, "unifi_cfg_enable_okc: Set unifi_SMEConfigValue failed.\n"); | |
784 | rc = -EFAULT; | |
785 | } | |
786 | ||
787 | return rc; | |
788 | } | |
789 | ||
790 | ||
791 | int unifi_cfg_get_info(unifi_priv_t *priv, unsigned char *arg) | |
792 | { | |
793 | unifi_cfg_get_t get_cmd; | |
794 | char inst_name[IFNAMSIZ]; | |
795 | int rc; | |
796 | ||
797 | if (get_user(get_cmd, (unifi_cfg_get_t*)(((unifi_cfg_command_t*)arg) + 1))) { | |
798 | unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n"); | |
799 | return -EFAULT; | |
800 | } | |
801 | ||
802 | switch (get_cmd) { | |
803 | case UNIFI_CFG_GET_COEX: | |
804 | { | |
805 | CsrWifiSmeCoexInfo coexInfo; | |
806 | /* Get the coex info from the SME */ | |
807 | rc = sme_mgt_coex_info_get(priv, &coexInfo); | |
808 | if (rc) { | |
809 | unifi_error(priv, "UNIFI_CFG: Get unifi_CoexInfoValue failed.\n"); | |
810 | return rc; | |
811 | } | |
812 | ||
813 | /* Copy the info to the out buffer */ | |
814 | if (copy_to_user((void*)arg, | |
815 | &coexInfo, | |
816 | sizeof(CsrWifiSmeCoexInfo))) { | |
817 | unifi_error(priv, "UNIFI_CFG: Failed to copy the coex info\n"); | |
818 | return -EFAULT; | |
819 | } | |
820 | break; | |
821 | } | |
822 | case UNIFI_CFG_GET_POWER_MODE: | |
823 | { | |
824 | CsrWifiSmePowerConfig powerConfig; | |
825 | rc = sme_mgt_power_config_get(priv, &powerConfig); | |
826 | if (rc) { | |
827 | unifi_error(priv, "UNIFI_CFG: Get unifi_PowerConfigValue failed.\n"); | |
828 | return rc; | |
829 | } | |
830 | ||
831 | /* Copy the info to the out buffer */ | |
832 | if (copy_to_user((void*)arg, | |
833 | &powerConfig.powerSaveLevel, | |
834 | sizeof(CsrWifiSmePowerSaveLevel))) { | |
835 | unifi_error(priv, "UNIFI_CFG: Failed to copy the power save info\n"); | |
836 | return -EFAULT; | |
837 | } | |
838 | break; | |
839 | } | |
840 | case UNIFI_CFG_GET_POWER_SUPPLY: | |
841 | { | |
842 | CsrWifiSmeHostConfig hostConfig; | |
843 | rc = sme_mgt_host_config_get(priv, &hostConfig); | |
844 | if (rc) { | |
845 | unifi_error(priv, "UNIFI_CFG: Get unifi_HostConfigValue failed.\n"); | |
846 | return rc; | |
847 | } | |
848 | ||
849 | /* Copy the info to the out buffer */ | |
850 | if (copy_to_user((void*)arg, | |
851 | &hostConfig.powerMode, | |
852 | sizeof(CsrWifiSmeHostPowerMode))) { | |
853 | unifi_error(priv, "UNIFI_CFG: Failed to copy the host power mode\n"); | |
854 | return -EFAULT; | |
855 | } | |
856 | break; | |
857 | } | |
858 | case UNIFI_CFG_GET_VERSIONS: | |
859 | break; | |
860 | case UNIFI_CFG_GET_INSTANCE: | |
861 | { | |
8c87f69a | 862 | u16 InterfaceId=0; |
635d2b00 GKH |
863 | uf_net_get_name(priv->netdev[InterfaceId], &inst_name[0], sizeof(inst_name)); |
864 | ||
865 | /* Copy the info to the out buffer */ | |
866 | if (copy_to_user((void*)arg, | |
867 | &inst_name[0], | |
868 | sizeof(inst_name))) { | |
869 | unifi_error(priv, "UNIFI_CFG: Failed to copy the instance name\n"); | |
870 | return -EFAULT; | |
871 | } | |
872 | } | |
873 | break; | |
874 | ||
875 | case UNIFI_CFG_GET_AP_CONFIG: | |
876 | { | |
877 | #ifdef CSR_SUPPORT_WEXT_AP | |
878 | uf_cfg_ap_config_t cfg_ap_config; | |
879 | cfg_ap_config.channel = priv->ap_config.channel; | |
880 | cfg_ap_config.beaconInterval = priv->ap_mac_config.beaconInterval; | |
881 | cfg_ap_config.wmmEnabled = priv->ap_mac_config.wmmEnabled; | |
882 | cfg_ap_config.dtimPeriod = priv->ap_mac_config.dtimPeriod; | |
883 | cfg_ap_config.phySupportedBitmap = priv->ap_mac_config.phySupportedBitmap; | |
884 | if (copy_to_user((void*)arg, | |
885 | &cfg_ap_config, | |
886 | sizeof(uf_cfg_ap_config_t))) { | |
887 | unifi_error(priv, "UNIFI_CFG: Failed to copy the AP configuration\n"); | |
888 | return -EFAULT; | |
889 | } | |
890 | #else | |
891 | return -EPERM; | |
892 | #endif | |
893 | } | |
894 | break; | |
895 | ||
896 | ||
897 | default: | |
898 | unifi_error(priv, "unifi_cfg_get_info: Unknown value.\n"); | |
899 | return -EINVAL; | |
900 | } | |
901 | ||
902 | return 0; | |
903 | } | |
904 | #ifdef CSR_SUPPORT_WEXT_AP | |
905 | int | |
7e6f5794 | 906 | uf_configure_supported_rates(u8 * supportedRates, u8 phySupportedBitmap) |
635d2b00 GKH |
907 | { |
908 | int i=0; | |
5379b13d | 909 | u8 b=FALSE, g = FALSE, n = FALSE; |
635d2b00 GKH |
910 | b = phySupportedBitmap & CSR_WIFI_SME_AP_PHY_SUPPORT_B; |
911 | n = phySupportedBitmap & CSR_WIFI_SME_AP_PHY_SUPPORT_N; | |
912 | g = phySupportedBitmap & CSR_WIFI_SME_AP_PHY_SUPPORT_G; | |
913 | if(b || g) { | |
914 | supportedRates[i++]=0x82; | |
915 | supportedRates[i++]=0x84; | |
916 | supportedRates[i++]=0x8b; | |
917 | supportedRates[i++]=0x96; | |
918 | } else if(n) { | |
95edd09e | 919 | /* For some strange reasons WiFi stack needs both b and g rates*/ |
635d2b00 GKH |
920 | supportedRates[i++]=0x02; |
921 | supportedRates[i++]=0x04; | |
922 | supportedRates[i++]=0x0b; | |
923 | supportedRates[i++]=0x16; | |
95edd09e GKH |
924 | supportedRates[i++]=0x0c; |
925 | supportedRates[i++]=0x12; | |
926 | supportedRates[i++]=0x18; | |
927 | supportedRates[i++]=0x24; | |
928 | supportedRates[i++]=0x30; | |
929 | supportedRates[i++]=0x48; | |
930 | supportedRates[i++]=0x60; | |
931 | supportedRates[i++]=0x6c; | |
635d2b00 GKH |
932 | } |
933 | if(g) { | |
934 | if(!b) { | |
935 | supportedRates[i++]=0x8c; | |
936 | supportedRates[i++]=0x98; | |
937 | supportedRates[i++]=0xb0; | |
938 | } else { | |
939 | supportedRates[i++]=0x0c; | |
940 | supportedRates[i++]=0x18; | |
941 | supportedRates[i++]=0x30; | |
942 | } | |
943 | supportedRates[i++]=0x48; | |
944 | supportedRates[i++]=0x12; | |
945 | supportedRates[i++]=0x24; | |
946 | supportedRates[i++]=0x60; | |
947 | supportedRates[i++]=0x6c; | |
948 | } | |
949 | return i; | |
950 | } | |
951 | int unifi_cfg_set_ap_config(unifi_priv_t * priv,unsigned char* arg) | |
952 | { | |
953 | uf_cfg_ap_config_t cfg_ap_config; | |
954 | char *buffer; | |
955 | ||
956 | buffer = ((unsigned char*)arg) + sizeof(unifi_cfg_command_t) + sizeof(unsigned int); | |
957 | if (copy_from_user(&cfg_ap_config, (void*)buffer, | |
958 | sizeof(uf_cfg_ap_config_t))) { | |
959 | unifi_error(priv, "UNIFI_CFG: Failed to get the ap config struct\n"); | |
960 | return -EFAULT; | |
961 | } | |
962 | priv->ap_config.channel = cfg_ap_config.channel; | |
963 | priv->ap_mac_config.dtimPeriod = cfg_ap_config.dtimPeriod; | |
964 | priv->ap_mac_config.beaconInterval = cfg_ap_config.beaconInterval; | |
965 | priv->group_sec_config.apGroupkeyTimeout = cfg_ap_config.groupkeyTimeout; | |
966 | priv->group_sec_config.apStrictGtkRekey = cfg_ap_config.strictGtkRekeyEnabled; | |
967 | priv->group_sec_config.apGmkTimeout = cfg_ap_config.gmkTimeout; | |
968 | priv->group_sec_config.apResponseTimeout = cfg_ap_config.responseTimeout; | |
969 | priv->group_sec_config.apRetransLimit = cfg_ap_config.retransLimit; | |
970 | ||
971 | priv->ap_mac_config.shortSlotTimeEnabled = cfg_ap_config.shortSlotTimeEnabled; | |
972 | priv->ap_mac_config.ctsProtectionType=cfg_ap_config.ctsProtectionType; | |
973 | ||
974 | priv->ap_mac_config.wmmEnabled = cfg_ap_config.wmmEnabled; | |
975 | ||
976 | priv->ap_mac_config.apHtParams.rxStbc=cfg_ap_config.rxStbc; | |
977 | priv->ap_mac_config.apHtParams.rifsModeAllowed=cfg_ap_config.rifsModeAllowed; | |
978 | ||
979 | priv->ap_mac_config.phySupportedBitmap = cfg_ap_config.phySupportedBitmap; | |
980 | priv->ap_mac_config.maxListenInterval=cfg_ap_config.maxListenInterval; | |
981 | ||
982 | priv->ap_mac_config.supportedRatesCount= uf_configure_supported_rates(priv->ap_mac_config.supportedRates,priv->ap_mac_config.phySupportedBitmap); | |
983 | ||
984 | return 0; | |
985 | } | |
986 | ||
987 | #endif | |
988 | #ifdef CSR_SUPPORT_WEXT | |
989 | ||
990 | void | |
991 | uf_sme_config_wq(struct work_struct *work) | |
992 | { | |
993 | CsrWifiSmeStaConfig staConfig; | |
994 | CsrWifiSmeDeviceConfig deviceConfig; | |
995 | unifi_priv_t *priv = container_of(work, unifi_priv_t, sme_config_task); | |
996 | ||
997 | /* Register to receive indications from the SME */ | |
998 | CsrWifiSmeEventMaskSetReqSend(0, | |
999 | CSR_WIFI_SME_INDICATIONS_WIFIOFF | CSR_WIFI_SME_INDICATIONS_CONNECTIONQUALITY | | |
1000 | CSR_WIFI_SME_INDICATIONS_MEDIASTATUS | CSR_WIFI_SME_INDICATIONS_MICFAILURE); | |
1001 | ||
1002 | if (sme_mgt_sme_config_get(priv, &staConfig, &deviceConfig)) { | |
1003 | unifi_warning(priv, "uf_sme_config_wq: Get unifi_SMEConfigValue failed.\n"); | |
1004 | return; | |
1005 | } | |
1006 | ||
1007 | if (priv->if_index == CSR_INDEX_5G) { | |
1008 | staConfig.ifIndex = CSR_WIFI_SME_RADIO_IF_GHZ_5_0; | |
1009 | } else { | |
1010 | staConfig.ifIndex = CSR_WIFI_SME_RADIO_IF_GHZ_2_4; | |
1011 | } | |
1012 | ||
1013 | deviceConfig.trustLevel = (CsrWifiSme80211dTrustLevel)tl_80211d; | |
1014 | if (sme_mgt_sme_config_set(priv, &staConfig, &deviceConfig)) { | |
1015 | unifi_warning(priv, | |
1016 | "SME config for 802.11d Trust Level and Radio Band failed.\n"); | |
1017 | return; | |
1018 | } | |
1019 | ||
1020 | } /* uf_sme_config_wq() */ | |
1021 | ||
1022 | #endif /* CSR_SUPPORT_WEXT */ | |
1023 | ||
1024 | ||
1025 | /* | |
1026 | * --------------------------------------------------------------------------- | |
1027 | * uf_ta_ind_wq | |
1028 | * | |
1029 | * Deferred work queue function to send Traffic Analysis protocols | |
1030 | * indications to the SME. | |
1031 | * These are done in a deferred work queue for two reasons: | |
1032 | * - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context | |
1033 | * - we want to load the main driver data path as lightly as possible | |
1034 | * | |
1035 | * The TA classifications already come from a workqueue. | |
1036 | * | |
1037 | * Arguments: | |
1038 | * work Pointer to work queue item. | |
1039 | * | |
1040 | * Returns: | |
1041 | * None. | |
1042 | * --------------------------------------------------------------------------- | |
1043 | */ | |
1044 | void | |
1045 | uf_ta_ind_wq(struct work_struct *work) | |
1046 | { | |
1047 | struct ta_ind *ind = container_of(work, struct ta_ind, task); | |
1048 | unifi_priv_t *priv = container_of(ind, unifi_priv_t, ta_ind_work); | |
8c87f69a | 1049 | u16 interfaceTag = 0; |
635d2b00 GKH |
1050 | |
1051 | ||
1052 | CsrWifiRouterCtrlTrafficProtocolIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, | |
1053 | interfaceTag, | |
1054 | ind->packet_type, | |
1055 | ind->direction, | |
1056 | ind->src_addr); | |
1057 | ind->in_use = 0; | |
1058 | ||
1059 | } /* uf_ta_ind_wq() */ | |
1060 | ||
1061 | ||
1062 | /* | |
1063 | * --------------------------------------------------------------------------- | |
1064 | * uf_ta_sample_ind_wq | |
1065 | * | |
1066 | * Deferred work queue function to send Traffic Analysis sample | |
1067 | * indications to the SME. | |
1068 | * These are done in a deferred work queue for two reasons: | |
1069 | * - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context | |
1070 | * - we want to load the main driver data path as lightly as possible | |
1071 | * | |
1072 | * The TA classifications already come from a workqueue. | |
1073 | * | |
1074 | * Arguments: | |
1075 | * work Pointer to work queue item. | |
1076 | * | |
1077 | * Returns: | |
1078 | * None. | |
1079 | * --------------------------------------------------------------------------- | |
1080 | */ | |
1081 | void | |
1082 | uf_ta_sample_ind_wq(struct work_struct *work) | |
1083 | { | |
1084 | struct ta_sample_ind *ind = container_of(work, struct ta_sample_ind, task); | |
1085 | unifi_priv_t *priv = container_of(ind, unifi_priv_t, ta_sample_ind_work); | |
8c87f69a | 1086 | u16 interfaceTag = 0; |
635d2b00 GKH |
1087 | |
1088 | unifi_trace(priv, UDBG5, "rxtcp %d txtcp %d rxudp %d txudp %d prio %d\n", | |
1089 | priv->rxTcpThroughput, | |
1090 | priv->txTcpThroughput, | |
1091 | priv->rxUdpThroughput, | |
1092 | priv->txUdpThroughput, | |
1093 | priv->bh_thread.prio); | |
1094 | ||
1095 | if(priv->rxTcpThroughput > 1000) | |
1096 | { | |
1097 | if (bh_priority == -1 && priv->bh_thread.prio != 1) | |
1098 | { | |
1099 | struct sched_param param; | |
1100 | priv->bh_thread.prio = 1; | |
1101 | unifi_trace(priv, UDBG1, "%s new thread (RT) priority = %d\n", | |
1102 | priv->bh_thread.name, priv->bh_thread.prio); | |
1103 | param.sched_priority = priv->bh_thread.prio; | |
1104 | sched_setscheduler(priv->bh_thread.thread_task, SCHED_FIFO, ¶m); | |
1105 | } | |
1106 | } else | |
1107 | { | |
1108 | if (bh_priority == -1 && priv->bh_thread.prio != DEFAULT_PRIO) | |
1109 | { | |
1110 | struct sched_param param; | |
1111 | param.sched_priority = 0; | |
1112 | sched_setscheduler(priv->bh_thread.thread_task, SCHED_NORMAL, ¶m); | |
1113 | priv->bh_thread.prio = DEFAULT_PRIO; | |
1114 | unifi_trace(priv, UDBG1, "%s new thread priority = %d\n", | |
1115 | priv->bh_thread.name, priv->bh_thread.prio); | |
1116 | set_user_nice(priv->bh_thread.thread_task, PRIO_TO_NICE(priv->bh_thread.prio)); | |
1117 | } | |
1118 | } | |
1119 | ||
1120 | CsrWifiRouterCtrlTrafficSampleIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, interfaceTag, ind->stats); | |
1121 | ||
1122 | ind->in_use = 0; | |
1123 | ||
1124 | } /* uf_ta_sample_ind_wq() */ | |
1125 | ||
1126 | ||
1127 | /* | |
1128 | * --------------------------------------------------------------------------- | |
1129 | * uf_send_m4_ready_wq | |
1130 | * | |
1131 | * Deferred work queue function to send M4 ReadyToSend inds to the SME. | |
1132 | * These are done in a deferred work queue for two reasons: | |
1133 | * - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context | |
1134 | * - we want to load the main driver data path as lightly as possible | |
1135 | * | |
1136 | * Arguments: | |
1137 | * work Pointer to work queue item. | |
1138 | * | |
1139 | * Returns: | |
1140 | * None. | |
1141 | * --------------------------------------------------------------------------- | |
1142 | */ | |
1143 | void | |
1144 | uf_send_m4_ready_wq(struct work_struct *work) | |
1145 | { | |
1146 | netInterface_priv_t *InterfacePriv = container_of(work, netInterface_priv_t, send_m4_ready_task); | |
8c87f69a | 1147 | u16 iface = InterfacePriv->InterfaceTag; |
635d2b00 GKH |
1148 | unifi_priv_t *priv = InterfacePriv->privPtr; |
1149 | CSR_MA_PACKET_REQUEST *req = &InterfacePriv->m4_signal.u.MaPacketRequest; | |
1150 | CsrWifiMacAddress peer; | |
1151 | unsigned long flags; | |
1152 | ||
635d2b00 GKH |
1153 | /* The peer address was stored in the signal */ |
1154 | spin_lock_irqsave(&priv->m4_lock, flags); | |
1155 | memcpy(peer.a, req->Ra.x, sizeof(peer.a)); | |
1156 | spin_unlock_irqrestore(&priv->m4_lock, flags); | |
1157 | ||
1158 | /* Send a signal to SME */ | |
1159 | CsrWifiRouterCtrlM4ReadyToSendIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0, iface, peer); | |
1160 | ||
a6737c73 AS |
1161 | unifi_trace(priv, UDBG1, "M4ReadyToSendInd sent for peer %pMF\n", |
1162 | peer.a); | |
635d2b00 | 1163 | |
635d2b00 GKH |
1164 | } /* uf_send_m4_ready_wq() */ |
1165 | ||
95edd09e GKH |
1166 | #if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION)) |
1167 | /* | |
1168 | * --------------------------------------------------------------------------- | |
1169 | * uf_send_pkt_to_encrypt | |
1170 | * | |
1171 | * Deferred work queue function to send the WAPI data pkts to SME when unicast KeyId = 1 | |
1172 | * These are done in a deferred work queue for two reasons: | |
1173 | * - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context | |
1174 | * - we want to load the main driver data path as lightly as possible | |
1175 | * | |
1176 | * Arguments: | |
1177 | * work Pointer to work queue item. | |
1178 | * | |
1179 | * Returns: | |
1180 | * None. | |
1181 | * --------------------------------------------------------------------------- | |
1182 | */ | |
1183 | void uf_send_pkt_to_encrypt(struct work_struct *work) | |
1184 | { | |
1185 | netInterface_priv_t *interfacePriv = container_of(work, netInterface_priv_t, send_pkt_to_encrypt); | |
8c87f69a | 1186 | u16 interfaceTag = interfacePriv->InterfaceTag; |
95edd09e GKH |
1187 | unifi_priv_t *priv = interfacePriv->privPtr; |
1188 | ||
26a6b2e1 | 1189 | u32 pktBulkDataLength; |
7e6f5794 | 1190 | u8 *pktBulkData; |
95edd09e GKH |
1191 | unsigned long flags; |
1192 | ||
1193 | if (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_STA) { | |
1194 | ||
95edd09e GKH |
1195 | pktBulkDataLength = interfacePriv->wapi_unicast_bulk_data.data_length; |
1196 | ||
1197 | if (pktBulkDataLength > 0) { | |
786eeeb3 | 1198 | pktBulkData = kmalloc(pktBulkDataLength, GFP_KERNEL); |
b7244a31 | 1199 | memset(pktBulkData, 0, pktBulkDataLength); |
95edd09e GKH |
1200 | } else { |
1201 | unifi_error(priv, "uf_send_pkt_to_encrypt() : invalid buffer\n"); | |
1202 | return; | |
1203 | } | |
1204 | ||
1205 | spin_lock_irqsave(&priv->wapi_lock, flags); | |
1206 | /* Copy over the MA PKT REQ bulk data */ | |
25aebdb1 | 1207 | memcpy(pktBulkData, (u8*)interfacePriv->wapi_unicast_bulk_data.os_data_ptr, pktBulkDataLength); |
95edd09e GKH |
1208 | /* Free any bulk data buffers allocated for the WAPI Data pkt */ |
1209 | unifi_net_data_free(priv, &interfacePriv->wapi_unicast_bulk_data); | |
1210 | interfacePriv->wapi_unicast_bulk_data.net_buf_length = 0; | |
1211 | interfacePriv->wapi_unicast_bulk_data.data_length = 0; | |
1212 | interfacePriv->wapi_unicast_bulk_data.os_data_ptr = interfacePriv->wapi_unicast_bulk_data.os_net_buf_ptr = NULL; | |
1213 | spin_unlock_irqrestore(&priv->wapi_lock, flags); | |
1214 | ||
1215 | CsrWifiRouterCtrlWapiUnicastTxEncryptIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0, interfaceTag, pktBulkDataLength, pktBulkData); | |
1216 | unifi_trace(priv, UDBG1, "WapiUnicastTxEncryptInd sent to SME\n"); | |
1217 | ||
55a27055 | 1218 | kfree(pktBulkData); /* Would have been copied over by the SME Handler */ |
95edd09e | 1219 | |
95edd09e GKH |
1220 | } else { |
1221 | unifi_warning(priv, "uf_send_pkt_to_encrypt() is NOT applicable for interface mode - %d\n",interfacePriv->interfaceMode); | |
1222 | } | |
1223 | }/* uf_send_pkt_to_encrypt() */ | |
1224 | #endif |