Adding support for MOXA ART SoC. Testing port of linux-2.6.32.60-moxart.
[linux-3.6.7-moxart.git] / drivers / staging / csr / unifi_sme.c
blobff639d47d07bf6b12b0cefe98b92139a2d7cceaf
1 /*
2 * ***************************************************************************
3 * FILE: unifi_sme.c
5 * PURPOSE: SME related functions.
7 * Copyright (C) 2007-2009 by Cambridge Silicon Radio Ltd.
9 * Refer to LICENSE.txt included with this source code for details on
10 * the license terms.
12 * ***************************************************************************
15 #include "unifi_priv.h"
16 #include "csr_wifi_hip_unifi.h"
17 #include "csr_wifi_hip_conversions.h"
22 int
23 convert_sme_error(CsrResult error)
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;
47 * ---------------------------------------------------------------------------
48 * sme_log_event
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.
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.
63 * Returns:
64 * None.
65 * ---------------------------------------------------------------------------
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)
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;
81 func_enter();
82 /* Just a sanity check */
83 if ((signal == NULL) || (signal_len <= 0)) {
84 func_exit();
85 return;
88 priv = uf_find_instance(pcli->instance);
89 if (!priv) {
90 unifi_error(priv, "sme_log_event: invalid priv\n");
91 func_exit();
92 return;
95 if (priv->smepriv == NULL) {
96 unifi_error(priv, "sme_log_event: invalid smepriv\n");
97 func_exit();
98 return;
101 unifi_trace(priv, UDBG3,
102 "sme_log_event: Process signal 0x%.4X\n",
103 CSR_GET_UINT16_FROM_LITTLE_ENDIAN(signal));
106 /* If the signal is known, then do any filtering required, otherwise it pass it to the SME. */
107 r = read_unpack_signal(signal, &unpacked_signal);
108 if (r == CSR_RESULT_SUCCESS) {
109 if ((unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_DEBUG_STRING_INDICATION_ID) ||
110 (unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_DEBUG_WORD16_INDICATION_ID))
112 func_exit();
113 return;
115 if (unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_MA_PACKET_INDICATION_ID)
117 u16 frmCtrl;
118 u8 unicastPdu = TRUE;
119 u8 *macHdrLocation;
120 u8 *raddr = NULL, *taddr = NULL;
121 CsrWifiMacAddress peerMacAddress;
122 /* Check if we need to send CsrWifiRouterCtrlMicFailureInd*/
123 CSR_MA_PACKET_INDICATION *ind = &unpacked_signal.u.MaPacketIndication;
125 macHdrLocation = (u8 *) bulkdata->d[0].os_data_ptr;
126 /* Fetch the frame control value from mac header */
127 frmCtrl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(macHdrLocation);
129 /* Point to the addresses */
130 raddr = macHdrLocation + MAC_HEADER_ADDR1_OFFSET;
131 taddr = macHdrLocation + MAC_HEADER_ADDR2_OFFSET;
133 memcpy(peerMacAddress.a, taddr, ETH_ALEN);
135 if(ind->ReceptionStatus == CSR_MICHAEL_MIC_ERROR)
137 if (*raddr & 0x1)
138 unicastPdu = FALSE;
140 CsrWifiRouterCtrlMicFailureIndSend (priv->CSR_WIFI_SME_IFACEQUEUE, 0,
141 (ind->VirtualInterfaceIdentifier & 0xff),peerMacAddress,
142 unicastPdu);
143 return;
145 else
147 if(ind->ReceptionStatus == CSR_RX_SUCCESS)
149 u8 pmBit = (frmCtrl & 0x1000)?0x01:0x00;
150 u16 interfaceTag = (ind->VirtualInterfaceIdentifier & 0xff);
151 CsrWifiRouterCtrlStaInfo_t *srcStaInfo = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(priv,taddr,interfaceTag);
152 if((srcStaInfo != NULL) && (uf_check_broadcast_bssid(priv, bulkdata)== FALSE))
154 uf_process_pm_bit_for_peer(priv,srcStaInfo,pmBit,interfaceTag);
156 /* Update station last activity flag */
157 srcStaInfo->activity_flag = TRUE;
163 if (unpacked_signal.SignalPrimitiveHeader.SignalId == CSR_MA_PACKET_CONFIRM_ID)
165 CSR_MA_PACKET_CONFIRM *cfm = &unpacked_signal.u.MaPacketConfirm;
166 u16 interfaceTag = (cfm->VirtualInterfaceIdentifier & 0xff);
167 netInterface_priv_t *interfacePriv;
168 CSR_MA_PACKET_REQUEST *req;
169 CsrWifiMacAddress peerMacAddress;
171 if (interfaceTag >= CSR_WIFI_NUM_INTERFACES)
173 unifi_error(priv, "Bad MA_PACKET_CONFIRM interfaceTag %d\n", interfaceTag);
174 func_exit();
175 return;
178 unifi_trace(priv,UDBG1,"MA-PACKET Confirm (%x, %x)\n", cfm->HostTag, cfm->TransmissionStatus);
180 interfacePriv = priv->interfacePriv[interfaceTag];
181 #ifdef CSR_SUPPORT_SME
182 if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP ||
183 interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) {
185 if(cfm->HostTag == interfacePriv->multicastPduHostTag){
186 uf_process_ma_pkt_cfm_for_ap(priv ,interfaceTag, cfm);
189 #endif
191 req = &interfacePriv->m4_signal.u.MaPacketRequest;
193 if(cfm->HostTag & 0x80000000)
195 if (cfm->TransmissionStatus != CSR_TX_SUCCESSFUL)
197 result = CSR_RESULT_FAILURE;
199 #ifdef CSR_SUPPORT_SME
200 memcpy(peerMacAddress.a, req->Ra.x, ETH_ALEN);
201 /* Check if this is a confirm for EAPOL M4 frame and we need to send transmistted ind*/
202 if (interfacePriv->m4_sent && (cfm->HostTag == interfacePriv->m4_hostTag))
204 unifi_trace(priv, UDBG1, "%s: Sending M4 Transmit CFM\n", __FUNCTION__);
205 CsrWifiRouterCtrlM4TransmittedIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0,
206 interfaceTag,
207 peerMacAddress,
208 result);
209 interfacePriv->m4_sent = FALSE;
210 interfacePriv->m4_hostTag = 0xffffffff;
212 #endif
213 /* If EAPOL was requested via router APIs then send cfm else ignore*/
214 if((cfm->HostTag & 0x80000000) != CSR_WIFI_EAPOL_M4_HOST_TAG) {
215 CsrWifiRouterMaPacketCfmSend((u16)signal[2],
216 cfm->VirtualInterfaceIdentifier,
217 result,
218 (cfm->HostTag & 0x3fffffff), cfm->Rate);
219 } else {
220 unifi_trace(priv, UDBG1, "%s: M4 received from netdevice\n", __FUNCTION__);
222 func_exit();
223 return;
228 mlmeCommand.length = signal_len;
229 mlmeCommand.data = (u8*)signal;
231 dataref1.length = bulkdata->d[0].data_length;
232 if (dataref1.length > 0) {
233 dataref1.data = (u8 *) bulkdata->d[0].os_data_ptr;
234 } else
236 dataref1.data = NULL;
239 dataref2.length = bulkdata->d[1].data_length;
240 if (dataref2.length > 0) {
241 dataref2.data = (u8 *) bulkdata->d[1].os_data_ptr;
242 } else
244 dataref2.data = NULL;
247 CsrWifiRouterCtrlHipIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, mlmeCommand.length, mlmeCommand.data,
248 dataref1.length, dataref1.data,
249 dataref2.length, dataref2.data);
251 func_exit();
252 } /* sme_log_event() */
256 * ---------------------------------------------------------------------------
257 * uf_sme_port_state
259 * Return the state of the controlled port.
261 * Arguments:
262 * priv Pointer to device private context struct
263 * address Pointer to the destination for tx or sender for rx address
264 * queue Controlled or uncontrolled queue
266 * Returns:
267 * An unifi_ControlledPortAction value.
268 * ---------------------------------------------------------------------------
270 CsrWifiRouterCtrlPortAction
271 uf_sme_port_state(unifi_priv_t *priv, unsigned char *address, int queue, u16 interfaceTag)
273 int i;
274 unifi_port_config_t *port;
275 netInterface_priv_t *interfacePriv;
277 if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
278 unifi_error(priv, "uf_sme_port_state: bad interfaceTag\n");
279 return CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
282 interfacePriv = priv->interfacePriv[interfaceTag];
284 if (queue == UF_CONTROLLED_PORT_Q) {
285 port = &interfacePriv->controlled_data_port;
286 } else {
287 port = &interfacePriv->uncontrolled_data_port;
290 if (!port->entries_in_use) {
291 unifi_trace(priv, UDBG5, "No port configurations, return Discard.\n");
292 return CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD;
295 /* If the port configuration is common for all destinations, return it. */
296 if (port->overide_action == UF_DATA_PORT_OVERIDE) {
297 unifi_trace(priv, UDBG5, "Single port configuration (%d).\n",
298 port->port_cfg[0].port_action);
299 return port->port_cfg[0].port_action;
302 unifi_trace(priv, UDBG5, "Multiple (%d) port configurations.\n", port->entries_in_use);
304 /* If multiple configurations exist.. */
305 for (i = 0; i < UNIFI_MAX_CONNECTIONS; i++) {
306 /* .. go through the list and match the destination address. */
307 if (port->port_cfg[i].in_use &&
308 memcmp(address, port->port_cfg[i].mac_address.a, ETH_ALEN) == 0) {
309 /* Return the desired action. */
310 return port->port_cfg[i].port_action;
314 /* Could not find any information, return Open. */
315 unifi_trace(priv, UDBG5, "port configuration not found, return Open.\n");
316 return CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN;
317 } /* uf_sme_port_state() */
320 * ---------------------------------------------------------------------------
321 * uf_sme_port_config_handle
323 * Return the port config handle of the controlled/uncontrolled port.
325 * Arguments:
326 * priv Pointer to device private context struct
327 * address Pointer to the destination for tx or sender for rx address
328 * queue Controlled or uncontrolled queue
330 * Returns:
331 * An unifi_port_cfg_t* .
332 * ---------------------------------------------------------------------------
334 unifi_port_cfg_t*
335 uf_sme_port_config_handle(unifi_priv_t *priv, unsigned char *address, int queue, u16 interfaceTag)
337 int i;
338 unifi_port_config_t *port;
339 netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
341 if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
342 unifi_error(priv, "uf_sme_port_config_handle: bad interfaceTag\n");
343 return NULL;
346 if (queue == UF_CONTROLLED_PORT_Q) {
347 port = &interfacePriv->controlled_data_port;
348 } else {
349 port = &interfacePriv->uncontrolled_data_port;
352 if (!port->entries_in_use) {
353 unifi_trace(priv, UDBG5, "No port configurations, return Discard.\n");
354 return NULL;
357 /* If the port configuration is common for all destinations, return it. */
358 if (port->overide_action == UF_DATA_PORT_OVERIDE) {
359 unifi_trace(priv, UDBG5, "Single port configuration (%d).\n",
360 port->port_cfg[0].port_action);
361 if (address) {
362 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]);
364 return &port->port_cfg[0];
367 unifi_trace(priv, UDBG5, "Multiple port configurations.\n");
369 /* If multiple configurations exist.. */
370 for (i = 0; i < UNIFI_MAX_CONNECTIONS; i++) {
371 /* .. go through the list and match the destination address. */
372 if (port->port_cfg[i].in_use &&
373 memcmp(address, port->port_cfg[i].mac_address.a, ETH_ALEN) == 0) {
374 /* Return the desired action. */
375 return &port->port_cfg[i];
379 /* Could not find any information, return Open. */
380 unifi_trace(priv, UDBG5, "port configuration not found, returning NULL (debug).\n");
381 return NULL;
382 } /* uf_sme_port_config_handle */
384 void
385 uf_multicast_list_wq(struct work_struct *work)
387 unifi_priv_t *priv = container_of(work, unifi_priv_t,
388 multicast_list_task);
389 int i;
390 u16 interfaceTag = 0;
391 CsrWifiMacAddress* multicast_address_list = NULL;
392 int mc_count;
393 u8 *mc_list;
394 netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
396 if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
397 unifi_error(priv, "uf_multicast_list_wq: bad interfaceTag\n");
398 return;
401 unifi_trace(priv, UDBG5,
402 "uf_multicast_list_wq: list count = %d\n",
403 interfacePriv->mc_list_count);
405 /* Flush the current list */
406 CsrWifiRouterCtrlMulticastAddressIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, interfaceTag, CSR_WIFI_SME_LIST_ACTION_FLUSH, 0, NULL);
408 mc_count = interfacePriv->mc_list_count;
409 mc_list = interfacePriv->mc_list;
411 * Allocate a new list, need to free it later
412 * in unifi_mgt_multicast_address_cfm().
414 multicast_address_list = kmalloc(mc_count * sizeof(CsrWifiMacAddress), GFP_KERNEL);
416 if (multicast_address_list == NULL) {
417 return;
420 for (i = 0; i < mc_count; i++) {
421 memcpy(multicast_address_list[i].a, mc_list, ETH_ALEN);
422 mc_list += ETH_ALEN;
425 if (priv->smepriv == NULL) {
426 kfree(multicast_address_list);
427 return;
430 CsrWifiRouterCtrlMulticastAddressIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0,
431 interfaceTag,
432 CSR_WIFI_SME_LIST_ACTION_ADD,
433 mc_count, multicast_address_list);
435 /* The SME will take a copy of the addreses*/
436 kfree(multicast_address_list);
440 int unifi_cfg_power(unifi_priv_t *priv, unsigned char *arg)
442 unifi_cfg_power_t cfg_power;
443 int rc;
444 int wol;
446 if (get_user(cfg_power, (unifi_cfg_power_t*)(((unifi_cfg_command_t*)arg) + 1))) {
447 unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n");
448 return -EFAULT;
451 switch (cfg_power) {
452 case UNIFI_CFG_POWER_OFF:
453 priv->wol_suspend = (enable_wol == UNIFI_WOL_OFF) ? FALSE : TRUE;
454 rc = sme_sys_suspend(priv);
455 if (rc) {
456 return rc;
458 break;
459 case UNIFI_CFG_POWER_ON:
460 wol = priv->wol_suspend;
461 rc = sme_sys_resume(priv);
462 if (rc) {
463 return rc;
465 if (wol) {
466 /* Kick the BH to ensure pending transfers are handled when
467 * a suspend happened with card powered.
469 unifi_send_signal(priv->card, NULL, 0, NULL);
471 break;
472 default:
473 unifi_error(priv, "WIFI POWER: Unknown value.\n");
474 return -EINVAL;
477 return 0;
481 int unifi_cfg_power_save(unifi_priv_t *priv, unsigned char *arg)
483 unifi_cfg_powersave_t cfg_power_save;
484 CsrWifiSmePowerConfig powerConfig;
485 int rc;
487 if (get_user(cfg_power_save, (unifi_cfg_powersave_t*)(((unifi_cfg_command_t*)arg) + 1))) {
488 unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n");
489 return -EFAULT;
492 /* Get the coex info from the SME */
493 rc = sme_mgt_power_config_get(priv, &powerConfig);
494 if (rc) {
495 unifi_error(priv, "UNIFI_CFG: Get unifi_PowerConfigValue failed.\n");
496 return rc;
499 switch (cfg_power_save) {
500 case UNIFI_CFG_POWERSAVE_NONE:
501 powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_LOW;
502 break;
503 case UNIFI_CFG_POWERSAVE_FAST:
504 powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_MED;
505 break;
506 case UNIFI_CFG_POWERSAVE_FULL:
507 powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_HIGH;
508 break;
509 case UNIFI_CFG_POWERSAVE_AUTO:
510 powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_AUTO;
511 break;
512 default:
513 unifi_error(priv, "POWERSAVE: Unknown value.\n");
514 return -EINVAL;
517 rc = sme_mgt_power_config_set(priv, &powerConfig);
519 if (rc) {
520 unifi_error(priv, "UNIFI_CFG: Set unifi_PowerConfigValue failed.\n");
523 return rc;
527 int unifi_cfg_power_supply(unifi_priv_t *priv, unsigned char *arg)
529 unifi_cfg_powersupply_t cfg_power_supply;
530 CsrWifiSmeHostConfig hostConfig;
531 int rc;
533 if (get_user(cfg_power_supply, (unifi_cfg_powersupply_t*)(((unifi_cfg_command_t*)arg) + 1))) {
534 unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n");
535 return -EFAULT;
538 /* Get the coex info from the SME */
539 rc = sme_mgt_host_config_get(priv, &hostConfig);
540 if (rc) {
541 unifi_error(priv, "UNIFI_CFG: Get unifi_HostConfigValue failed.\n");
542 return rc;
545 switch (cfg_power_supply) {
546 case UNIFI_CFG_POWERSUPPLY_MAINS:
547 hostConfig.powerMode = CSR_WIFI_SME_HOST_POWER_MODE_ACTIVE;
548 break;
549 case UNIFI_CFG_POWERSUPPLY_BATTERIES:
550 hostConfig.powerMode = CSR_WIFI_SME_HOST_POWER_MODE_POWER_SAVE;
551 break;
552 default:
553 unifi_error(priv, "POWERSUPPLY: Unknown value.\n");
554 return -EINVAL;
557 rc = sme_mgt_host_config_set(priv, &hostConfig);
558 if (rc) {
559 unifi_error(priv, "UNIFI_CFG: Set unifi_HostConfigValue failed.\n");
562 return rc;
566 int unifi_cfg_packet_filters(unifi_priv_t *priv, unsigned char *arg)
568 unsigned char *tclas_buffer;
569 unsigned int tclas_buffer_length;
570 tclas_t *dhcp_tclas;
571 int rc;
573 /* Free any TCLASs previously allocated */
574 if (priv->packet_filters.tclas_ies_length) {
575 kfree(priv->filter_tclas_ies);
576 priv->filter_tclas_ies = NULL;
579 tclas_buffer = ((unsigned char*)arg) + sizeof(unifi_cfg_command_t) + sizeof(unsigned int);
580 if (copy_from_user(&priv->packet_filters, (void*)tclas_buffer,
581 sizeof(uf_cfg_bcast_packet_filter_t))) {
582 unifi_error(priv, "UNIFI_CFG: Failed to get the filter struct\n");
583 return -EFAULT;
586 tclas_buffer_length = priv->packet_filters.tclas_ies_length;
588 /* Allocate TCLASs if necessary */
589 if (priv->packet_filters.dhcp_filter) {
590 priv->packet_filters.tclas_ies_length += sizeof(tclas_t);
592 if (priv->packet_filters.tclas_ies_length > 0) {
593 priv->filter_tclas_ies = kmalloc(priv->packet_filters.tclas_ies_length, GFP_KERNEL);
594 if (priv->filter_tclas_ies == NULL) {
595 return -ENOMEM;
597 if (tclas_buffer_length) {
598 tclas_buffer += sizeof(uf_cfg_bcast_packet_filter_t) - sizeof(unsigned char*);
599 if (copy_from_user(priv->filter_tclas_ies,
600 tclas_buffer,
601 tclas_buffer_length)) {
602 unifi_error(priv, "UNIFI_CFG: Failed to get the TCLAS buffer\n");
603 return -EFAULT;
608 if(priv->packet_filters.dhcp_filter)
610 /* Append the DHCP tclas IE */
611 dhcp_tclas = (tclas_t*)(priv->filter_tclas_ies + tclas_buffer_length);
612 memset(dhcp_tclas, 0, sizeof(tclas_t));
613 dhcp_tclas->element_id = 14;
614 dhcp_tclas->length = sizeof(tcpip_clsfr_t) + 1;
615 dhcp_tclas->user_priority = 0;
616 dhcp_tclas->tcp_ip_cls_fr.cls_fr_type = 1;
617 dhcp_tclas->tcp_ip_cls_fr.version = 4;
618 ((u8*)(&dhcp_tclas->tcp_ip_cls_fr.source_port))[0] = 0x00;
619 ((u8*)(&dhcp_tclas->tcp_ip_cls_fr.source_port))[1] = 0x44;
620 ((u8*)(&dhcp_tclas->tcp_ip_cls_fr.dest_port))[0] = 0x00;
621 ((u8*)(&dhcp_tclas->tcp_ip_cls_fr.dest_port))[1] = 0x43;
622 dhcp_tclas->tcp_ip_cls_fr.protocol = 0x11;
623 dhcp_tclas->tcp_ip_cls_fr.cls_fr_mask = 0x58; //bits: 3,4,6
626 rc = sme_mgt_packet_filter_set(priv);
628 return rc;
632 int unifi_cfg_wmm_qos_info(unifi_priv_t *priv, unsigned char *arg)
634 u8 wmm_qos_info;
635 int rc = 0;
637 if (get_user(wmm_qos_info, (u8*)(((unifi_cfg_command_t*)arg) + 1))) {
638 unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n");
639 return -EFAULT;
642 /* Store the value in the connection info */
643 priv->connection_config.wmmQosInfo = wmm_qos_info;
645 return rc;
649 int unifi_cfg_wmm_addts(unifi_priv_t *priv, unsigned char *arg)
651 u32 addts_tid;
652 u8 addts_ie_length;
653 u8 *addts_ie;
654 u8 *addts_params;
655 CsrWifiSmeDataBlock tspec;
656 CsrWifiSmeDataBlock tclas;
657 int rc;
659 addts_params = (u8*)(((unifi_cfg_command_t*)arg) + 1);
660 if (get_user(addts_tid, (u32*)addts_params)) {
661 unifi_error(priv, "unifi_cfg_wmm_addts: Failed to get the argument\n");
662 return -EFAULT;
665 addts_params += sizeof(u32);
666 if (get_user(addts_ie_length, (u8*)addts_params)) {
667 unifi_error(priv, "unifi_cfg_wmm_addts: Failed to get the argument\n");
668 return -EFAULT;
671 unifi_trace(priv, UDBG4, "addts: tid = 0x%x ie_length = %d\n",
672 addts_tid, addts_ie_length);
674 addts_ie = kmalloc(addts_ie_length, GFP_KERNEL);
675 if (addts_ie == NULL) {
676 unifi_error(priv,
677 "unifi_cfg_wmm_addts: Failed to malloc %d bytes for addts_ie buffer\n",
678 addts_ie_length);
679 return -ENOMEM;
682 addts_params += sizeof(u8);
683 rc = copy_from_user(addts_ie, addts_params, addts_ie_length);
684 if (rc) {
685 unifi_error(priv, "unifi_cfg_wmm_addts: Failed to get the addts buffer\n");
686 kfree(addts_ie);
687 return -EFAULT;
690 tspec.data = addts_ie;
691 tspec.length = addts_ie_length;
692 tclas.data = NULL;
693 tclas.length = 0;
695 rc = sme_mgt_tspec(priv, CSR_WIFI_SME_LIST_ACTION_ADD, addts_tid,
696 &tspec, &tclas);
698 kfree(addts_ie);
699 return rc;
703 int unifi_cfg_wmm_delts(unifi_priv_t *priv, unsigned char *arg)
705 u32 delts_tid;
706 u8 *delts_params;
707 CsrWifiSmeDataBlock tspec;
708 CsrWifiSmeDataBlock tclas;
709 int rc;
711 delts_params = (u8*)(((unifi_cfg_command_t*)arg) + 1);
712 if (get_user(delts_tid, (u32*)delts_params)) {
713 unifi_error(priv, "unifi_cfg_wmm_delts: Failed to get the argument\n");
714 return -EFAULT;
717 unifi_trace(priv, UDBG4, "delts: tid = 0x%x\n", delts_tid);
719 tspec.data = tclas.data = NULL;
720 tspec.length = tclas.length = 0;
722 rc = sme_mgt_tspec(priv, CSR_WIFI_SME_LIST_ACTION_REMOVE, delts_tid,
723 &tspec, &tclas);
725 return rc;
728 int unifi_cfg_strict_draft_n(unifi_priv_t *priv, unsigned char *arg)
730 u8 strict_draft_n;
731 u8 *strict_draft_n_params;
732 int rc;
734 CsrWifiSmeStaConfig staConfig;
735 CsrWifiSmeDeviceConfig deviceConfig;
737 strict_draft_n_params = (u8*)(((unifi_cfg_command_t*)arg) + 1);
738 if (get_user(strict_draft_n, (u8*)strict_draft_n_params)) {
739 unifi_error(priv, "unifi_cfg_strict_draft_n: Failed to get the argument\n");
740 return -EFAULT;
743 unifi_trace(priv, UDBG4, "strict_draft_n: = %s\n", ((strict_draft_n) ? "yes":"no"));
745 rc = sme_mgt_sme_config_get(priv, &staConfig, &deviceConfig);
747 if (rc) {
748 unifi_warning(priv, "unifi_cfg_strict_draft_n: Get unifi_SMEConfigValue failed.\n");
749 return -EFAULT;
752 deviceConfig.enableStrictDraftN = strict_draft_n;
754 rc = sme_mgt_sme_config_set(priv, &staConfig, &deviceConfig);
755 if (rc) {
756 unifi_warning(priv, "unifi_cfg_strict_draft_n: Set unifi_SMEConfigValue failed.\n");
757 rc = -EFAULT;
760 return rc;
764 int unifi_cfg_enable_okc(unifi_priv_t *priv, unsigned char *arg)
766 u8 enable_okc;
767 u8 *enable_okc_params;
768 int rc;
770 CsrWifiSmeStaConfig staConfig;
771 CsrWifiSmeDeviceConfig deviceConfig;
773 enable_okc_params = (u8*)(((unifi_cfg_command_t*)arg) + 1);
774 if (get_user(enable_okc, (u8*)enable_okc_params)) {
775 unifi_error(priv, "unifi_cfg_enable_okc: Failed to get the argument\n");
776 return -EFAULT;
779 unifi_trace(priv, UDBG4, "enable_okc: = %s\n", ((enable_okc) ? "yes":"no"));
781 rc = sme_mgt_sme_config_get(priv, &staConfig, &deviceConfig);
782 if (rc) {
783 unifi_warning(priv, "unifi_cfg_enable_okc: Get unifi_SMEConfigValue failed.\n");
784 return -EFAULT;
787 staConfig.enableOpportunisticKeyCaching = enable_okc;
789 rc = sme_mgt_sme_config_set(priv, &staConfig, &deviceConfig);
790 if (rc) {
791 unifi_warning(priv, "unifi_cfg_enable_okc: Set unifi_SMEConfigValue failed.\n");
792 rc = -EFAULT;
795 return rc;
799 int unifi_cfg_get_info(unifi_priv_t *priv, unsigned char *arg)
801 unifi_cfg_get_t get_cmd;
802 char inst_name[IFNAMSIZ];
803 int rc;
805 if (get_user(get_cmd, (unifi_cfg_get_t*)(((unifi_cfg_command_t*)arg) + 1))) {
806 unifi_error(priv, "UNIFI_CFG: Failed to get the argument\n");
807 return -EFAULT;
810 switch (get_cmd) {
811 case UNIFI_CFG_GET_COEX:
813 CsrWifiSmeCoexInfo coexInfo;
814 /* Get the coex info from the SME */
815 rc = sme_mgt_coex_info_get(priv, &coexInfo);
816 if (rc) {
817 unifi_error(priv, "UNIFI_CFG: Get unifi_CoexInfoValue failed.\n");
818 return rc;
821 /* Copy the info to the out buffer */
822 if (copy_to_user((void*)arg,
823 &coexInfo,
824 sizeof(CsrWifiSmeCoexInfo))) {
825 unifi_error(priv, "UNIFI_CFG: Failed to copy the coex info\n");
826 return -EFAULT;
828 break;
830 case UNIFI_CFG_GET_POWER_MODE:
832 CsrWifiSmePowerConfig powerConfig;
833 rc = sme_mgt_power_config_get(priv, &powerConfig);
834 if (rc) {
835 unifi_error(priv, "UNIFI_CFG: Get unifi_PowerConfigValue failed.\n");
836 return rc;
839 /* Copy the info to the out buffer */
840 if (copy_to_user((void*)arg,
841 &powerConfig.powerSaveLevel,
842 sizeof(CsrWifiSmePowerSaveLevel))) {
843 unifi_error(priv, "UNIFI_CFG: Failed to copy the power save info\n");
844 return -EFAULT;
846 break;
848 case UNIFI_CFG_GET_POWER_SUPPLY:
850 CsrWifiSmeHostConfig hostConfig;
851 rc = sme_mgt_host_config_get(priv, &hostConfig);
852 if (rc) {
853 unifi_error(priv, "UNIFI_CFG: Get unifi_HostConfigValue failed.\n");
854 return rc;
857 /* Copy the info to the out buffer */
858 if (copy_to_user((void*)arg,
859 &hostConfig.powerMode,
860 sizeof(CsrWifiSmeHostPowerMode))) {
861 unifi_error(priv, "UNIFI_CFG: Failed to copy the host power mode\n");
862 return -EFAULT;
864 break;
866 case UNIFI_CFG_GET_VERSIONS:
867 break;
868 case UNIFI_CFG_GET_INSTANCE:
870 u16 InterfaceId=0;
871 uf_net_get_name(priv->netdev[InterfaceId], &inst_name[0], sizeof(inst_name));
873 /* Copy the info to the out buffer */
874 if (copy_to_user((void*)arg,
875 &inst_name[0],
876 sizeof(inst_name))) {
877 unifi_error(priv, "UNIFI_CFG: Failed to copy the instance name\n");
878 return -EFAULT;
881 break;
883 case UNIFI_CFG_GET_AP_CONFIG:
885 #ifdef CSR_SUPPORT_WEXT_AP
886 uf_cfg_ap_config_t cfg_ap_config;
887 cfg_ap_config.channel = priv->ap_config.channel;
888 cfg_ap_config.beaconInterval = priv->ap_mac_config.beaconInterval;
889 cfg_ap_config.wmmEnabled = priv->ap_mac_config.wmmEnabled;
890 cfg_ap_config.dtimPeriod = priv->ap_mac_config.dtimPeriod;
891 cfg_ap_config.phySupportedBitmap = priv->ap_mac_config.phySupportedBitmap;
892 if (copy_to_user((void*)arg,
893 &cfg_ap_config,
894 sizeof(uf_cfg_ap_config_t))) {
895 unifi_error(priv, "UNIFI_CFG: Failed to copy the AP configuration\n");
896 return -EFAULT;
898 #else
899 return -EPERM;
900 #endif
902 break;
905 default:
906 unifi_error(priv, "unifi_cfg_get_info: Unknown value.\n");
907 return -EINVAL;
910 return 0;
912 #ifdef CSR_SUPPORT_WEXT_AP
914 uf_configure_supported_rates(u8 * supportedRates, u8 phySupportedBitmap)
916 int i=0;
917 u8 b=FALSE, g = FALSE, n = FALSE;
918 b = phySupportedBitmap & CSR_WIFI_SME_AP_PHY_SUPPORT_B;
919 n = phySupportedBitmap & CSR_WIFI_SME_AP_PHY_SUPPORT_N;
920 g = phySupportedBitmap & CSR_WIFI_SME_AP_PHY_SUPPORT_G;
921 if(b || g) {
922 supportedRates[i++]=0x82;
923 supportedRates[i++]=0x84;
924 supportedRates[i++]=0x8b;
925 supportedRates[i++]=0x96;
926 } else if(n) {
927 /* For some strange reasons WiFi stack needs both b and g rates*/
928 supportedRates[i++]=0x02;
929 supportedRates[i++]=0x04;
930 supportedRates[i++]=0x0b;
931 supportedRates[i++]=0x16;
932 supportedRates[i++]=0x0c;
933 supportedRates[i++]=0x12;
934 supportedRates[i++]=0x18;
935 supportedRates[i++]=0x24;
936 supportedRates[i++]=0x30;
937 supportedRates[i++]=0x48;
938 supportedRates[i++]=0x60;
939 supportedRates[i++]=0x6c;
941 if(g) {
942 if(!b) {
943 supportedRates[i++]=0x8c;
944 supportedRates[i++]=0x98;
945 supportedRates[i++]=0xb0;
946 } else {
947 supportedRates[i++]=0x0c;
948 supportedRates[i++]=0x18;
949 supportedRates[i++]=0x30;
951 supportedRates[i++]=0x48;
952 supportedRates[i++]=0x12;
953 supportedRates[i++]=0x24;
954 supportedRates[i++]=0x60;
955 supportedRates[i++]=0x6c;
957 return i;
959 int unifi_cfg_set_ap_config(unifi_priv_t * priv,unsigned char* arg)
961 uf_cfg_ap_config_t cfg_ap_config;
962 char *buffer;
964 buffer = ((unsigned char*)arg) + sizeof(unifi_cfg_command_t) + sizeof(unsigned int);
965 if (copy_from_user(&cfg_ap_config, (void*)buffer,
966 sizeof(uf_cfg_ap_config_t))) {
967 unifi_error(priv, "UNIFI_CFG: Failed to get the ap config struct\n");
968 return -EFAULT;
970 priv->ap_config.channel = cfg_ap_config.channel;
971 priv->ap_mac_config.dtimPeriod = cfg_ap_config.dtimPeriod;
972 priv->ap_mac_config.beaconInterval = cfg_ap_config.beaconInterval;
973 priv->group_sec_config.apGroupkeyTimeout = cfg_ap_config.groupkeyTimeout;
974 priv->group_sec_config.apStrictGtkRekey = cfg_ap_config.strictGtkRekeyEnabled;
975 priv->group_sec_config.apGmkTimeout = cfg_ap_config.gmkTimeout;
976 priv->group_sec_config.apResponseTimeout = cfg_ap_config.responseTimeout;
977 priv->group_sec_config.apRetransLimit = cfg_ap_config.retransLimit;
979 priv->ap_mac_config.shortSlotTimeEnabled = cfg_ap_config.shortSlotTimeEnabled;
980 priv->ap_mac_config.ctsProtectionType=cfg_ap_config.ctsProtectionType;
982 priv->ap_mac_config.wmmEnabled = cfg_ap_config.wmmEnabled;
984 priv->ap_mac_config.apHtParams.rxStbc=cfg_ap_config.rxStbc;
985 priv->ap_mac_config.apHtParams.rifsModeAllowed=cfg_ap_config.rifsModeAllowed;
987 priv->ap_mac_config.phySupportedBitmap = cfg_ap_config.phySupportedBitmap;
988 priv->ap_mac_config.maxListenInterval=cfg_ap_config.maxListenInterval;
990 priv->ap_mac_config.supportedRatesCount= uf_configure_supported_rates(priv->ap_mac_config.supportedRates,priv->ap_mac_config.phySupportedBitmap);
992 return 0;
995 #endif
996 #ifdef CSR_SUPPORT_WEXT
998 void
999 uf_sme_config_wq(struct work_struct *work)
1001 CsrWifiSmeStaConfig staConfig;
1002 CsrWifiSmeDeviceConfig deviceConfig;
1003 unifi_priv_t *priv = container_of(work, unifi_priv_t, sme_config_task);
1005 /* Register to receive indications from the SME */
1006 CsrWifiSmeEventMaskSetReqSend(0,
1007 CSR_WIFI_SME_INDICATIONS_WIFIOFF | CSR_WIFI_SME_INDICATIONS_CONNECTIONQUALITY |
1008 CSR_WIFI_SME_INDICATIONS_MEDIASTATUS | CSR_WIFI_SME_INDICATIONS_MICFAILURE);
1010 if (sme_mgt_sme_config_get(priv, &staConfig, &deviceConfig)) {
1011 unifi_warning(priv, "uf_sme_config_wq: Get unifi_SMEConfigValue failed.\n");
1012 return;
1015 if (priv->if_index == CSR_INDEX_5G) {
1016 staConfig.ifIndex = CSR_WIFI_SME_RADIO_IF_GHZ_5_0;
1017 } else {
1018 staConfig.ifIndex = CSR_WIFI_SME_RADIO_IF_GHZ_2_4;
1021 deviceConfig.trustLevel = (CsrWifiSme80211dTrustLevel)tl_80211d;
1022 if (sme_mgt_sme_config_set(priv, &staConfig, &deviceConfig)) {
1023 unifi_warning(priv,
1024 "SME config for 802.11d Trust Level and Radio Band failed.\n");
1025 return;
1028 } /* uf_sme_config_wq() */
1030 #endif /* CSR_SUPPORT_WEXT */
1034 * ---------------------------------------------------------------------------
1035 * uf_ta_ind_wq
1037 * Deferred work queue function to send Traffic Analysis protocols
1038 * indications to the SME.
1039 * These are done in a deferred work queue for two reasons:
1040 * - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context
1041 * - we want to load the main driver data path as lightly as possible
1043 * The TA classifications already come from a workqueue.
1045 * Arguments:
1046 * work Pointer to work queue item.
1048 * Returns:
1049 * None.
1050 * ---------------------------------------------------------------------------
1052 void
1053 uf_ta_ind_wq(struct work_struct *work)
1055 struct ta_ind *ind = container_of(work, struct ta_ind, task);
1056 unifi_priv_t *priv = container_of(ind, unifi_priv_t, ta_ind_work);
1057 u16 interfaceTag = 0;
1060 CsrWifiRouterCtrlTrafficProtocolIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0,
1061 interfaceTag,
1062 ind->packet_type,
1063 ind->direction,
1064 ind->src_addr);
1065 ind->in_use = 0;
1067 } /* uf_ta_ind_wq() */
1071 * ---------------------------------------------------------------------------
1072 * uf_ta_sample_ind_wq
1074 * Deferred work queue function to send Traffic Analysis sample
1075 * indications to the SME.
1076 * These are done in a deferred work queue for two reasons:
1077 * - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context
1078 * - we want to load the main driver data path as lightly as possible
1080 * The TA classifications already come from a workqueue.
1082 * Arguments:
1083 * work Pointer to work queue item.
1085 * Returns:
1086 * None.
1087 * ---------------------------------------------------------------------------
1089 void
1090 uf_ta_sample_ind_wq(struct work_struct *work)
1092 struct ta_sample_ind *ind = container_of(work, struct ta_sample_ind, task);
1093 unifi_priv_t *priv = container_of(ind, unifi_priv_t, ta_sample_ind_work);
1094 u16 interfaceTag = 0;
1096 unifi_trace(priv, UDBG5, "rxtcp %d txtcp %d rxudp %d txudp %d prio %d\n",
1097 priv->rxTcpThroughput,
1098 priv->txTcpThroughput,
1099 priv->rxUdpThroughput,
1100 priv->txUdpThroughput,
1101 priv->bh_thread.prio);
1103 if(priv->rxTcpThroughput > 1000)
1105 if (bh_priority == -1 && priv->bh_thread.prio != 1)
1107 struct sched_param param;
1108 priv->bh_thread.prio = 1;
1109 unifi_trace(priv, UDBG1, "%s new thread (RT) priority = %d\n",
1110 priv->bh_thread.name, priv->bh_thread.prio);
1111 param.sched_priority = priv->bh_thread.prio;
1112 sched_setscheduler(priv->bh_thread.thread_task, SCHED_FIFO, &param);
1114 } else
1116 if (bh_priority == -1 && priv->bh_thread.prio != DEFAULT_PRIO)
1118 struct sched_param param;
1119 param.sched_priority = 0;
1120 sched_setscheduler(priv->bh_thread.thread_task, SCHED_NORMAL, &param);
1121 priv->bh_thread.prio = DEFAULT_PRIO;
1122 unifi_trace(priv, UDBG1, "%s new thread priority = %d\n",
1123 priv->bh_thread.name, priv->bh_thread.prio);
1124 set_user_nice(priv->bh_thread.thread_task, PRIO_TO_NICE(priv->bh_thread.prio));
1128 CsrWifiRouterCtrlTrafficSampleIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, interfaceTag, ind->stats);
1130 ind->in_use = 0;
1132 } /* uf_ta_sample_ind_wq() */
1136 * ---------------------------------------------------------------------------
1137 * uf_send_m4_ready_wq
1139 * Deferred work queue function to send M4 ReadyToSend inds to the SME.
1140 * These are done in a deferred work queue for two reasons:
1141 * - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context
1142 * - we want to load the main driver data path as lightly as possible
1144 * Arguments:
1145 * work Pointer to work queue item.
1147 * Returns:
1148 * None.
1149 * ---------------------------------------------------------------------------
1151 void
1152 uf_send_m4_ready_wq(struct work_struct *work)
1154 netInterface_priv_t *InterfacePriv = container_of(work, netInterface_priv_t, send_m4_ready_task);
1155 u16 iface = InterfacePriv->InterfaceTag;
1156 unifi_priv_t *priv = InterfacePriv->privPtr;
1157 CSR_MA_PACKET_REQUEST *req = &InterfacePriv->m4_signal.u.MaPacketRequest;
1158 CsrWifiMacAddress peer;
1159 unsigned long flags;
1161 func_enter();
1163 /* The peer address was stored in the signal */
1164 spin_lock_irqsave(&priv->m4_lock, flags);
1165 memcpy(peer.a, req->Ra.x, sizeof(peer.a));
1166 spin_unlock_irqrestore(&priv->m4_lock, flags);
1168 /* Send a signal to SME */
1169 CsrWifiRouterCtrlM4ReadyToSendIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0, iface, peer);
1171 unifi_trace(priv, UDBG1, "M4ReadyToSendInd sent for peer %pMF\n",
1172 peer.a);
1174 func_exit();
1176 } /* uf_send_m4_ready_wq() */
1178 #if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION))
1180 * ---------------------------------------------------------------------------
1181 * uf_send_pkt_to_encrypt
1183 * Deferred work queue function to send the WAPI data pkts to SME when unicast KeyId = 1
1184 * These are done in a deferred work queue for two reasons:
1185 * - the CsrWifiRouterCtrl...Send() functions are not safe for atomic context
1186 * - we want to load the main driver data path as lightly as possible
1188 * Arguments:
1189 * work Pointer to work queue item.
1191 * Returns:
1192 * None.
1193 * ---------------------------------------------------------------------------
1195 void uf_send_pkt_to_encrypt(struct work_struct *work)
1197 netInterface_priv_t *interfacePriv = container_of(work, netInterface_priv_t, send_pkt_to_encrypt);
1198 u16 interfaceTag = interfacePriv->InterfaceTag;
1199 unifi_priv_t *priv = interfacePriv->privPtr;
1201 u32 pktBulkDataLength;
1202 u8 *pktBulkData;
1203 unsigned long flags;
1205 if (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_STA) {
1207 func_enter();
1209 pktBulkDataLength = interfacePriv->wapi_unicast_bulk_data.data_length;
1211 if (pktBulkDataLength > 0) {
1212 pktBulkData = kmalloc(pktBulkDataLength, GFP_KERNEL);
1213 memset(pktBulkData, 0, pktBulkDataLength);
1214 } else {
1215 unifi_error(priv, "uf_send_pkt_to_encrypt() : invalid buffer\n");
1216 return;
1219 spin_lock_irqsave(&priv->wapi_lock, flags);
1220 /* Copy over the MA PKT REQ bulk data */
1221 memcpy(pktBulkData, (u8*)interfacePriv->wapi_unicast_bulk_data.os_data_ptr, pktBulkDataLength);
1222 /* Free any bulk data buffers allocated for the WAPI Data pkt */
1223 unifi_net_data_free(priv, &interfacePriv->wapi_unicast_bulk_data);
1224 interfacePriv->wapi_unicast_bulk_data.net_buf_length = 0;
1225 interfacePriv->wapi_unicast_bulk_data.data_length = 0;
1226 interfacePriv->wapi_unicast_bulk_data.os_data_ptr = interfacePriv->wapi_unicast_bulk_data.os_net_buf_ptr = NULL;
1227 spin_unlock_irqrestore(&priv->wapi_lock, flags);
1229 CsrWifiRouterCtrlWapiUnicastTxEncryptIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0, interfaceTag, pktBulkDataLength, pktBulkData);
1230 unifi_trace(priv, UDBG1, "WapiUnicastTxEncryptInd sent to SME\n");
1232 kfree(pktBulkData); /* Would have been copied over by the SME Handler */
1234 func_exit();
1235 } else {
1236 unifi_warning(priv, "uf_send_pkt_to_encrypt() is NOT applicable for interface mode - %d\n",interfacePriv->interfaceMode);
1238 }/* uf_send_pkt_to_encrypt() */
1239 #endif