/* ***************************************************************************** * * FILE : sme_userspace.c * * PURPOSE : Support functions for userspace SME helper application. * * * Copyright (C) 2008-2011 by Cambridge Silicon Radio Ltd. * * Refer to LICENSE.txt included with this source code for details on * the license terms. * ***************************************************************************** */ #include "unifi_priv.h" /* * Fix Me..... These need to be the correct values... * Dynamic from the user space. */ CsrSchedQid CSR_WIFI_ROUTER_IFACEQUEUE = 0xFFFF; CsrSchedQid CSR_WIFI_SME_IFACEQUEUE = 0xFFFF; #ifdef CSR_SUPPORT_WEXT_AP CsrSchedQid CSR_WIFI_NME_IFACEQUEUE = 0xFFFF; #endif int uf_sme_init(unifi_priv_t *priv) { int i, j; CsrWifiRouterTransportInit(priv); priv->smepriv = priv; init_waitqueue_head(&priv->sme_request_wq); priv->filter_tclas_ies = NULL; memset(&priv->packet_filters, 0, sizeof(uf_cfg_bcast_packet_filter_t)); #ifdef CSR_SUPPORT_WEXT priv->ignore_bssid_join = FALSE; priv->mib_data.length = 0; uf_sme_wext_set_defaults(priv); #endif /* CSR_SUPPORT_WEXT*/ priv->sta_ip_address = 0xFFFFFFFF; priv->wifi_on_state = wifi_on_unspecified; sema_init(&priv->sme_sem, 1); memset(&priv->sme_reply, 0, sizeof(sme_reply_t)); priv->ta_ind_work.in_use = 0; priv->ta_sample_ind_work.in_use = 0; priv->CSR_WIFI_SME_IFACEQUEUE = 0xFFFF; for (i = 0; i < MAX_MA_UNIDATA_IND_FILTERS; i++) { priv->sme_unidata_ind_filters[i].in_use = 0; } /* Create a work queue item for Traffic Analysis indications to SME */ INIT_WORK(&priv->ta_ind_work.task, uf_ta_ind_wq); INIT_WORK(&priv->ta_sample_ind_work.task, uf_ta_sample_ind_wq); #ifdef CSR_SUPPORT_WEXT INIT_WORK(&priv->sme_config_task, uf_sme_config_wq); #endif for (i = 0; i < CSR_WIFI_NUM_INTERFACES; i++) { netInterface_priv_t *interfacePriv = priv->interfacePriv[i]; interfacePriv->m4_sent = FALSE; interfacePriv->m4_bulk_data.net_buf_length = 0; interfacePriv->m4_bulk_data.data_length = 0; interfacePriv->m4_bulk_data.os_data_ptr = interfacePriv->m4_bulk_data.os_net_buf_ptr = NULL; memset(&interfacePriv->controlled_data_port, 0, sizeof(unifi_port_config_t)); interfacePriv->controlled_data_port.entries_in_use = 1; interfacePriv->controlled_data_port.port_cfg[0].in_use = TRUE; interfacePriv->controlled_data_port.port_cfg[0].port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD; interfacePriv->controlled_data_port.overide_action = UF_DATA_PORT_OVERIDE; memset(&interfacePriv->uncontrolled_data_port, 0, sizeof(unifi_port_config_t)); interfacePriv->uncontrolled_data_port.entries_in_use = 1; interfacePriv->uncontrolled_data_port.port_cfg[0].in_use = TRUE; interfacePriv->uncontrolled_data_port.port_cfg[0].port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD; interfacePriv->uncontrolled_data_port.overide_action = UF_DATA_PORT_OVERIDE; /* Mark the remainder of the port config table as unallocated */ for(j = 1; j < UNIFI_MAX_CONNECTIONS; j++) { interfacePriv->controlled_data_port.port_cfg[j].in_use = FALSE; interfacePriv->controlled_data_port.port_cfg[j].port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD; interfacePriv->uncontrolled_data_port.port_cfg[j].in_use = FALSE; interfacePriv->uncontrolled_data_port.port_cfg[j].port_action = CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD; } /* intializing the lists */ INIT_LIST_HEAD(&interfacePriv->genericMgtFrames); INIT_LIST_HEAD(&interfacePriv->genericMulticastOrBroadCastMgtFrames); INIT_LIST_HEAD(&interfacePriv->genericMulticastOrBroadCastFrames); for(j = 0; j < UNIFI_MAX_CONNECTIONS; j++) { interfacePriv->staInfo[j] = NULL; } interfacePriv->num_stations_joined = 0; interfacePriv->sta_activity_check_enabled = FALSE; } return 0; } /* uf_sme_init() */ void uf_sme_deinit(unifi_priv_t *priv) { int i,j; u8 ba_session_idx; ba_session_rx_struct *ba_session_rx = NULL; ba_session_tx_struct *ba_session_tx = NULL; CsrWifiRouterCtrlStaInfo_t *staInfo = NULL; netInterface_priv_t *interfacePriv = NULL; /* Free any TCLASs previously allocated */ if (priv->packet_filters.tclas_ies_length) { priv->packet_filters.tclas_ies_length = 0; kfree(priv->filter_tclas_ies); priv->filter_tclas_ies = NULL; } for (i = 0; i < MAX_MA_UNIDATA_IND_FILTERS; i++) { priv->sme_unidata_ind_filters[i].in_use = 0; } /* Remove all the Peer database, before going down */ for (i = 0; i < CSR_WIFI_NUM_INTERFACES; i++) { down(&priv->ba_mutex); for(ba_session_idx=0; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_RX; ba_session_idx++){ ba_session_rx = priv->interfacePriv[i]->ba_session_rx[ba_session_idx]; if(ba_session_rx) { blockack_session_stop(priv, i, CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_RECIPIENT, ba_session_rx->tID, ba_session_rx->macAddress); } } for(ba_session_idx=0; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_TX; ba_session_idx++){ ba_session_tx = priv->interfacePriv[i]->ba_session_tx[ba_session_idx]; if(ba_session_tx) { blockack_session_stop(priv, i, CSR_WIFI_ROUTER_CTRL_BLOCK_ACK_ORIGINATOR, ba_session_tx->tID, ba_session_tx->macAddress); } } up(&priv->ba_mutex); interfacePriv = priv->interfacePriv[i]; if(interfacePriv){ for(j = 0; j < UNIFI_MAX_CONNECTIONS; j++) { if ((staInfo=interfacePriv->staInfo[j]) != NULL) { /* Clear the STA activity parameters before freeing station Record */ unifi_trace(priv, UDBG1, "uf_sme_deinit: Canceling work queue for STA with AID: %d\n", staInfo->aid); cancel_work_sync(&staInfo->send_disconnected_ind_task); staInfo->nullDataHostTag = INVALID_HOST_TAG; } } if (interfacePriv->sta_activity_check_enabled){ interfacePriv->sta_activity_check_enabled = FALSE; del_timer_sync(&interfacePriv->sta_activity_check_timer); } } CsrWifiRouterCtrlInterfaceReset(priv, i); priv->interfacePriv[i]->interfaceMode = CSR_WIFI_ROUTER_CTRL_MODE_NONE; } } /* uf_sme_deinit() */ /* * --------------------------------------------------------------------------- * unifi_ta_indicate_protocol * * Report that a packet of a particular type has been seen * * Arguments: * drv_priv The device context pointer passed to ta_init. * protocol The protocol type enum value. * direction Whether the packet was a tx or rx. * src_addr The source MAC address from the data packet. * * Returns: * None. * * Notes: * We defer the actual sending to a background workqueue, * see uf_ta_ind_wq(). * --------------------------------------------------------------------------- */ void unifi_ta_indicate_protocol(void *ospriv, CsrWifiRouterCtrlTrafficPacketType packet_type, CsrWifiRouterCtrlProtocolDirection direction, const CsrWifiMacAddress *src_addr) { unifi_priv_t *priv = (unifi_priv_t*)ospriv; if (priv->ta_ind_work.in_use) { unifi_warning(priv, "unifi_ta_indicate_protocol: workqueue item still in use, not sending\n"); return; } if (CSR_WIFI_ROUTER_CTRL_PROTOCOL_DIRECTION_RX == direction) { u16 interfaceTag = 0; CsrWifiRouterCtrlTrafficProtocolIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, interfaceTag, packet_type, direction, *src_addr); } else { priv->ta_ind_work.packet_type = packet_type; priv->ta_ind_work.direction = direction; priv->ta_ind_work.src_addr = *src_addr; queue_work(priv->unifi_workqueue, &priv->ta_ind_work.task); } } /* unifi_ta_indicate_protocol() */ /* * --------------------------------------------------------------------------- * unifi_ta_indicate_sampling * * Send the TA sampling information to the SME. * * Arguments: * drv_priv The device context pointer passed to ta_init. * stats The TA sampling data to send. * * Returns: * None. * --------------------------------------------------------------------------- */ void unifi_ta_indicate_sampling(void *ospriv, CsrWifiRouterCtrlTrafficStats *stats) { unifi_priv_t *priv = (unifi_priv_t*)ospriv; if (!priv) { return; } if (priv->ta_sample_ind_work.in_use) { unifi_warning(priv, "unifi_ta_indicate_sampling: workqueue item still in use, not sending\n"); return; } priv->ta_sample_ind_work.stats = *stats; queue_work(priv->unifi_workqueue, &priv->ta_sample_ind_work.task); } /* unifi_ta_indicate_sampling() */ /* * --------------------------------------------------------------------------- * unifi_ta_indicate_l4stats * * Send the TA TCP/UDP throughput information to the driver. * * Arguments: * drv_priv The device context pointer passed to ta_init. * rxTcpThroughput TCP RX throughput in KiloBytes * txTcpThroughput TCP TX throughput in KiloBytes * rxUdpThroughput UDP RX throughput in KiloBytes * txUdpThroughput UDP TX throughput in KiloBytes * * Returns: * None. * --------------------------------------------------------------------------- */ void unifi_ta_indicate_l4stats(void *ospriv, u32 rxTcpThroughput, u32 txTcpThroughput, u32 rxUdpThroughput, u32 txUdpThroughput) { unifi_priv_t *priv = (unifi_priv_t*)ospriv; if (!priv) { return; } /* Save the info. The actual action will be taken in unifi_ta_indicate_sampling() */ priv->rxTcpThroughput = rxTcpThroughput; priv->txTcpThroughput = txTcpThroughput; priv->rxUdpThroughput = rxUdpThroughput; priv->txUdpThroughput = txUdpThroughput; } /* unifi_ta_indicate_l4stats() */