diff options
| author | ninadm <ninadm@qti.qualcomm.com> | 2014-11-20 12:02:50 -0800 |
|---|---|---|
| committer | AnjaneeDevi Kapparapu <c_akappa@qti.qualcomm.com> | 2014-12-11 19:39:40 +0530 |
| commit | 6acf251c85ba697b30293e905f5ad23633671b9c (patch) | |
| tree | 8efc793fe4736df9f3785883c20f8b1935ac980d | |
| parent | c47aea74d499dcb8c7f693f857386c3d7c0ff0e2 (diff) | |
qcacld: hdd: Merge DSRC changes
- Add OCB mode of operation
- Add new config parameter to enable OCB mode
- Create new interface for OCB mode
- Add new ioctl for OCB Set Schedule command
Change-Id: I2e09676909780c5a4f52adf6f56c4e24ccc5e919
CRs-Fixed: 754373
| -rw-r--r-- | CORE/HDD/inc/wlan_hdd_cfg.h | 14 | ||||
| -rw-r--r-- | CORE/HDD/inc/wlan_hdd_main.h | 6 | ||||
| -rw-r--r-- | CORE/HDD/inc/wlan_hdd_tx_rx.h | 4 | ||||
| -rw-r--r-- | CORE/HDD/src/wlan_hdd_cfg.c | 11 | ||||
| -rwxr-xr-x | CORE/HDD/src/wlan_hdd_main.c | 112 | ||||
| -rw-r--r-- | CORE/HDD/src/wlan_hdd_tx_rx.c | 38 | ||||
| -rw-r--r-- | CORE/HDD/src/wlan_hdd_wext.c | 397 | ||||
| -rw-r--r-- | CORE/VOSS/inc/vos_types.h | 1 | ||||
| -rw-r--r-- | CORE/VOSS/src/vos_api.c | 3 |
9 files changed, 547 insertions, 39 deletions
diff --git a/CORE/HDD/inc/wlan_hdd_cfg.h b/CORE/HDD/inc/wlan_hdd_cfg.h index 0cb804d64cdf..7cf14541f523 100644 --- a/CORE/HDD/inc/wlan_hdd_cfg.h +++ b/CORE/HDD/inc/wlan_hdd_cfg.h @@ -2703,6 +2703,17 @@ This feature requires the dependent cfg.ini "gRoamPrefer5GHz" set to 1 */ #define CFG_SAP_AUTH_OFL_KEY_DEFAULT "" #endif /* SAP_AUTH_OFFLOAD */ +enum dot11p_mode { + WLAN_HDD_11P_DISABLED = 0, + WLAN_HDD_11P_STANDALONE, + WLAN_HDD_11P_CONCURRENT, +}; + +#define CFG_DOT11P_MODE_NAME "gDot11PMode" +#define CFG_DOT11P_MODE_DEFAULT ( WLAN_HDD_11P_DISABLED ) +#define CFG_DOT11P_MODE_MIN ( WLAN_HDD_11P_DISABLED ) +#define CFG_DOT11P_MODE_MAX ( WLAN_HDD_11P_CONCURRENT ) + /*--------------------------------------------------------------------------- Type declarations -------------------------------------------------------------------------*/ @@ -3260,6 +3271,7 @@ typedef struct uint32_t dhcp_client_start_ip; v_U8_t dhcpServerIP[IPADDR_STRING_LENGTH]; #endif /* DHCP_SERVER_OFFLOAD */ + bool enable_mac_spoofing; #ifdef IPA_UC_STA_OFFLOAD bool ipa_uc_sta_offload; @@ -3289,6 +3301,8 @@ typedef struct uint32_t sap_auth_offload_sec_type; uint8_t sap_auth_offload_key[WLAN_PSK_STRING_LENGTH]; #endif /* SAP_AUTH_OFFLOAD */ + + uint8_t dot11p_mode; } hdd_config_t; #ifdef WLAN_FEATURE_MBSSID diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h index 68ece7964842..955c89abd309 100644 --- a/CORE/HDD/inc/wlan_hdd_main.h +++ b/CORE/HDD/inc/wlan_hdd_main.h @@ -517,7 +517,8 @@ typedef enum device_mode WLAN_HDD_MONITOR, WLAN_HDD_FTM, WLAN_HDD_IBSS, - WLAN_HDD_P2P_DEVICE + WLAN_HDD_P2P_DEVICE, + WLAN_HDD_OCB }device_mode_t; typedef enum rem_on_channel_request_type @@ -1095,6 +1096,9 @@ struct hdd_adapter_s /* variable for temperature in Celsius */ int temperature; + + /* 802.11p */ + struct completion hdd_ocb_set_sched_req_var; }; #define WLAN_HDD_GET_STATION_CTX_PTR(pAdapter) (&(pAdapter)->sessionCtx.station) diff --git a/CORE/HDD/inc/wlan_hdd_tx_rx.h b/CORE/HDD/inc/wlan_hdd_tx_rx.h index ae2a9e8d54cd..7f65dc9851e4 100644 --- a/CORE/HDD/inc/wlan_hdd_tx_rx.h +++ b/CORE/HDD/inc/wlan_hdd_tx_rx.h @@ -75,6 +75,10 @@ #define SME_QOS_UAPSD_CFG_VI_CHANGED_MASK 0xF4 #define SME_QOS_UAPSD_CFG_VO_CHANGED_MASK 0xF8 +#define HDD_ETH_HEADER_LEN 14 +#define HDD_OCB_TX_HEADER_LEN 16 +#define HDD_ETHERTYPE_OCB_TX 0x8151 + /*--------------------------------------------------------------------------- Type declarations -------------------------------------------------------------------------*/ diff --git a/CORE/HDD/src/wlan_hdd_cfg.c b/CORE/HDD/src/wlan_hdd_cfg.c index 680097c1ef4e..5695fddb43a4 100644 --- a/CORE/HDD/src/wlan_hdd_cfg.c +++ b/CORE/HDD/src/wlan_hdd_cfg.c @@ -3515,6 +3515,13 @@ REG_TABLE_ENTRY g_registry_table[] = VAR_FLAGS_OPTIONAL, (void *) CFG_SAP_AUTH_OFL_KEY_DEFAULT ), #endif /* SAP_AUTH_OFFLOAD */ + + REG_VARIABLE(CFG_DOT11P_MODE_NAME, WLAN_PARAM_Integer, + hdd_config_t, dot11p_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DOT11P_MODE_DEFAULT, + CFG_DOT11P_MODE_MIN, + CFG_DOT11P_MODE_MAX), }; #ifdef WLAN_FEATURE_MBSSID @@ -5960,6 +5967,10 @@ VOS_STATUS hdd_set_sme_config( hdd_context_t *pHddCtx ) smeConfig->csrConfig.is_sta_connection_in_5gz_enabled = pHddCtx->cfg_ini->is_sta_connection_in_5gz_enabled; + /* Update 802.11p config */ + smeConfig->csrConfig.enable_dot11p = (pHddCtx->cfg_ini->dot11p_mode != + WLAN_HDD_11P_DISABLED); + halStatus = sme_UpdateConfig( pHddCtx->hHal, smeConfig); if ( !HAL_STATUS_SUCCESS( halStatus ) ) { diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c index 75572214005a..db8ca30f6022 100755 --- a/CORE/HDD/src/wlan_hdd_main.c +++ b/CORE/HDD/src/wlan_hdd_main.c @@ -8980,6 +8980,7 @@ hdd_adapter_t* hdd_open_adapter( hdd_context_t *pHddCtx, tANI_U8 session_type, /* fall through */ case WLAN_HDD_P2P_CLIENT: case WLAN_HDD_P2P_DEVICE: + case WLAN_HDD_OCB: { pAdapter = hdd_alloc_station_adapter( pHddCtx, macAddr, iface_name ); @@ -11424,6 +11425,21 @@ VOS_STATUS hdd_set_sme_chan_list(hdd_context_t *hdd_ctx) hdd_ctx->reg.cc_src); } +/** + * hdd_set_dot11p_config() - Set 802.11p config flag + * @hdd_ctx: HDD Context pointer + * + * TODO-OCB: This has been temporarily added to ensure this paramter + * is set in CSR when we init the channel list. This should be removed + * once the 5.9 GHz channels are added to the regulatory domain. + */ +void hdd_set_dot11p_config(hdd_context_t *hdd_ctx) +{ + sme_set_dot11p_config(hdd_ctx->hHal, + hdd_ctx->cfg_ini->dot11p_mode != + WLAN_HDD_11P_DISABLED); +} + /**--------------------------------------------------------------------------- \brief hdd_is_5g_supported() - HDD function to know if hardware supports 5GHz @@ -11658,6 +11674,7 @@ int hdd_wlan_startup(struct device *dev, v_VOID_t *hif_sc) #endif tANI_U8 rtnl_lock_enable; tANI_U8 reg_netdev_notifier_done = FALSE; + hdd_adapter_t *dot11_adapter = NULL; ENTER(); @@ -11899,6 +11916,13 @@ int hdd_wlan_startup(struct device *dev, v_VOID_t *hif_sc) goto err_vosclose; } + /* Set 802.11p config + * TODO-OCB: This has been temporarily added here to ensure this paramter + * is set in CSR when we init the channel list. This should be removed + * once the 5.9 GHz channels are added to the regulatory domain. + */ + hdd_set_dot11p_config(pHddCtx); + if (0 == enable_dfs_chan_scan || 1 == enable_dfs_chan_scan) { pHddCtx->cfg_ini->enableDFSChnlScan = enable_dfs_chan_scan; @@ -12042,53 +12066,65 @@ int hdd_wlan_startup(struct device *dev, v_VOID_t *hif_sc) rtnl_lock_enable = FALSE; #endif - pAdapter = hdd_open_adapter( pHddCtx, WLAN_HDD_INFRA_STATION, "wlan%d", - wlan_hdd_get_intf_addr(pHddCtx), rtnl_lock_enable ); + if (pHddCtx->cfg_ini->dot11p_mode == WLAN_HDD_11P_STANDALONE) { + /* Create only 802.11p interface */ + pAdapter = hdd_open_adapter(pHddCtx, WLAN_HDD_OCB, + "wlanocb%d", wlan_hdd_get_intf_addr(pHddCtx), rtnl_lock_enable); + } else { + pAdapter = hdd_open_adapter( pHddCtx, WLAN_HDD_INFRA_STATION, "wlan%d", + wlan_hdd_get_intf_addr(pHddCtx), rtnl_lock_enable ); #ifdef WLAN_OPEN_P2P_INTERFACE - /* Open P2P device interface */ - if (pAdapter != NULL) - { - if (pHddCtx->cfg_ini->isP2pDeviceAddrAdministrated) - { - vos_mem_copy( pHddCtx->p2pDeviceAddress.bytes, - pHddCtx->cfg_ini->intfMacAddr[0].bytes, - sizeof(tSirMacAddr)); - - /* Generate the P2P Device Address. This consists of the device's - * primary MAC address with the locally administered bit set. - */ - pHddCtx->p2pDeviceAddress.bytes[0] |= 0x02; - } - else - { - tANI_U8* p2p_dev_addr = wlan_hdd_get_intf_addr(pHddCtx); - if (p2p_dev_addr != NULL) - { - vos_mem_copy(&pHddCtx->p2pDeviceAddress.bytes[0], - p2p_dev_addr, VOS_MAC_ADDR_SIZE); + /* Open P2P device interface */ + if (pAdapter != NULL) { + if (pHddCtx->cfg_ini->isP2pDeviceAddrAdministrated) { + vos_mem_copy( pHddCtx->p2pDeviceAddress.bytes, + pHddCtx->cfg_ini->intfMacAddr[0].bytes, + sizeof(tSirMacAddr)); + + /* Generate the P2P Device Address. This consists of the device's + * primary MAC address with the locally administered bit set. + */ + pHddCtx->p2pDeviceAddress.bytes[0] |= 0x02; + } else { + uint8_t* p2p_dev_addr = wlan_hdd_get_intf_addr(pHddCtx); + if (p2p_dev_addr != NULL) { + vos_mem_copy(&pHddCtx->p2pDeviceAddress.bytes[0], + p2p_dev_addr, VOS_MAC_ADDR_SIZE); + } else { + hddLog(VOS_TRACE_LEVEL_FATAL, + FL("Failed to allocate mac_address for p2p_device")); + goto err_close_adapter; + } } - else - { + + pP2pAdapter = hdd_open_adapter(pHddCtx, WLAN_HDD_P2P_DEVICE, "p2p%d", + &pHddCtx->p2pDeviceAddress.bytes[0], + rtnl_lock_enable); + + if (NULL == pP2pAdapter) { hddLog(VOS_TRACE_LEVEL_FATAL, - "%s: Failed to allocate mac_address for p2p_device", - __func__); + FL("Failed to do hdd_open_adapter for P2P Device Interface")); goto err_close_adapter; } } - - pP2pAdapter = hdd_open_adapter( pHddCtx, WLAN_HDD_P2P_DEVICE, "p2p%d", - &pHddCtx->p2pDeviceAddress.bytes[0], rtnl_lock_enable ); - - if ( NULL == pP2pAdapter ) - { - hddLog(VOS_TRACE_LEVEL_FATAL, - "%s: Failed to do hdd_open_adapter for P2P Device Interface", - __func__); - goto err_close_adapter; +#endif /* WLAN_OPEN_P2P_INTERFACE */ + + /* Open 802.11p Interface */ + if (pAdapter != NULL) { + if (pHddCtx->cfg_ini->dot11p_mode == WLAN_HDD_11P_CONCURRENT) { + dot11_adapter = hdd_open_adapter(pHddCtx, WLAN_HDD_OCB, + "wlanocb%d", wlan_hdd_get_intf_addr(pHddCtx), + rtnl_lock_enable); + + if (dot11_adapter == NULL) { + hddLog(VOS_TRACE_LEVEL_FATAL, + FL("hdd_open_adapter() failed for 802.11p Interface")); + goto err_close_adapter; + } + } } } -#endif if( pAdapter == NULL ) { diff --git a/CORE/HDD/src/wlan_hdd_tx_rx.c b/CORE/HDD/src/wlan_hdd_tx_rx.c index a41dc0147bd1..f07843cd8eaf 100644 --- a/CORE/HDD/src/wlan_hdd_tx_rx.c +++ b/CORE/HDD/src/wlan_hdd_tx_rx.c @@ -713,6 +713,40 @@ void hdd_tx_resume_cb(void *adapter_context, } #endif /* QCA_LL_TX_FLOW_CT */ +/** + * hdd_remove_ocb_tx_header() - Function to check for OCB + * TX control header on a packet and extract it if present + * + * @skb: Pointer to OS packet (sk_buff) + */ +static void hdd_remove_ocb_tx_header(struct sk_buff *skb) +{ + struct ethhdr *eth_hdr_p; + struct ethhdr eth_hdr; + + /* Check if TX control header is present */ + eth_hdr_p = (struct ethhdr *) &skb->data[0]; + if (eth_hdr_p->h_proto != htons(HDD_ETHERTYPE_OCB_TX)) { + /* TX control header is not present. Nothing to do.. */ + return; + } + + /* Copy and remove the ethernet header */ + memcpy(ð_hdr, eth_hdr_p, HDD_ETH_HEADER_LEN); + skb_pull(skb, HDD_ETH_HEADER_LEN); + + /* Remove the TX control header */ + skb_pull(skb, HDD_OCB_TX_HEADER_LEN); + + /* Convert Ethernet header to 802.3 header by changing ethertype + field to length field */ + eth_hdr.h_proto = htons(skb->len); + + /* Push the now 802.3 header back */ + skb_push(skb, HDD_ETH_HEADER_LEN); + memcpy(&skb->data[0], ð_hdr, HDD_ETH_HEADER_LEN); +} + /**============================================================================ @brief hdd_hard_start_xmit() - Function registered with the Linux OS for transmitting packets. This version of the function directly passes the packet @@ -776,6 +810,10 @@ int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) STAId = pHddStaCtx->conn_info.staId[0]; } + if (pAdapter->device_mode == WLAN_HDD_OCB) { + hdd_remove_ocb_tx_header(skb); + } + #ifdef QCA_LL_TX_FLOW_CT if (VOS_FALSE == WLANTL_GetTxResource((WLAN_HDD_GET_CTX(pAdapter))->pvosContext, diff --git a/CORE/HDD/src/wlan_hdd_wext.c b/CORE/HDD/src/wlan_hdd_wext.c index 0e0c0723c16d..5307a165cf5e 100644 --- a/CORE/HDD/src/wlan_hdd_wext.c +++ b/CORE/HDD/src/wlan_hdd_wext.c @@ -433,6 +433,9 @@ static const hdd_freq_chan_map_t freq_chan_map[] = { {2412, 1}, {2417, 2}, #define WLAN_SET_POWER_PARAMS (SIOCIWFIRSTPRIV + 29) +/* 802.11p IOCTL */ +#define WLAN_SET_DOT11P_CHANNEL_SCHED (SIOCIWFIRSTPRIV + 30) + #define WLAN_GET_LINK_SPEED (SIOCIWFIRSTPRIV + 31) /* Private ioctls and their sub-ioctls */ @@ -2997,6 +3000,399 @@ static int iw_get_linkspeed_priv(struct net_device *dev, return 0; } +/* Structure definitions for WLAN_SET_DOT11P_CHANNEL_SCHED */ +#define NUM_AC (4) +#define OCB_CHANNEL_MAX (5) +#define DOT11P_TX_PWR_MAX (23) +#define AIFSN_MIN (2) +#define AIFSN_MAX (15) +#define CW_MIN (1) +#define CW_MAX (10) +#define HDD_OCB_SET_SCHED_TIME_OUT (1500) + +#define NUM_DOT11P_CHANNELS 9 +static const uint32_t valid_dot11p_channels[NUM_DOT11P_CHANNELS] = { + 5860, 5870, 5880, 5890, 5900, 5910, 5920, 5875, 5905, +}; + +/** + * struct ocb_qos_params - QoS Parameters for each AC + * @aifsn: Arbitration Inter-Frame Spacing + * @cwmin: Contention Window (Min) + * @cwmax: Contention Window (Max) + */ +struct ocb_qos_params { + uint8_t aifsn; + uint8_t cwmin; + uint8_t cwmax; +}; + +/** + * struct ocb_channel - Parameters for each OCB channel + * @channel_freq: Channel Frequency (MHz) + * @duration: Channel Duration (ms) + * @start_guard_interval: Start Guard Interval (ms) + * @end_guard_interval: End Guard Interval (ms) + * @tx_power: Transmit Power (dBm) + * @tx_rate: Transmit Data Rate (mbit) + * @qos_params: Array of QoS Parameters + * @per_packet_rx_stats: Enable per packet RX statistics + */ +struct ocb_channel { + uint32_t channel_freq; + uint32_t duration; + uint32_t start_guard_interval; + uint32_t end_guard_interval; + uint32_t tx_power; + uint32_t tx_rate; + struct ocb_qos_params qos_params[NUM_AC]; + uint32_t per_packet_rx_stats; +}; + +/** + * struct dot11p_channel_sched - OCB channel schedule + * @num_channels: Number of channels + * @channels: Array of channel parameters + * @off_channel_tx: Enable off channel TX + */ +struct dot11p_channel_sched { + uint32_t num_channels; + struct ocb_channel channels[OCB_CHANNEL_MAX]; + uint32_t off_channel_tx; +}; + +/** + * dot11p_validate_channel() - Check if specified channel is valid + * @channel: Channel Frequency (MHz) + * + * Return: 0 on success. 1 on failure. + */ +static int dot11p_validate_channel(uint32_t channel) +{ + int i; + + for (i = 0; i < NUM_DOT11P_CHANNELS; i++) { + if (channel == valid_dot11p_channels[i]) { + return 0; + } + } + + return 1; +} + +/** + * dot11p_validate_qos_params() - Check if QoS parameters are valid + * @qos_params: Array of QoS parameters + * + * Return: 0 on success. 1 on failure. + */ +static int dot11p_validate_qos_params(struct ocb_qos_params qos_params[]) +{ + int i; + + for (i = 0; i < NUM_AC; i++) { + if ((!qos_params[i].aifsn) && (!qos_params[i].cwmin) + && (!qos_params[i].cwmax)) { + continue; + } + + /* Validate AIFSN */ + if ((qos_params[i].aifsn < AIFSN_MIN) + || (qos_params[i].aifsn > AIFSN_MAX)) { + return 1; + } + + /* Validate CWMin */ + if ((qos_params[i].cwmin < CW_MIN) + || (qos_params[i].cwmin > CW_MAX)) { + return 1; + } + + /* Validate CWMax */ + if ((qos_params[i].cwmax < CW_MIN) + || (qos_params[i].cwmax > CW_MAX)) { + return 1; + } + } + + return 0; +} + +/** + * dot11p_validate_sched() - Check if schedule is valid + * @sched: OCB channel schedule + * + * Return: 0 on success. 1 on failure. + */ +int dot11p_validate_sched(struct dot11p_channel_sched *sched) +{ + int i; + + if ((sched->num_channels > OCB_CHANNEL_MAX) + || (sched->num_channels == 0)) { + goto error; + } + + for (i = 0; i < sched->num_channels; i++) { + /* Validate channel frequency */ + if (dot11p_validate_channel(sched->channels[i].channel_freq)) { + goto error; + } + + /* Validate TX Power */ + if (sched->channels[i].tx_power > DOT11P_TX_PWR_MAX) { + goto error; + } + + /* Validate TX Rate */ + switch (sched->channels[i].tx_rate) { + case 0: + case 6: + case 9: + case 12: + case 18: + case 24: + case 36: + case 48: + case 54: + break; + default: + goto error; + } + + /* Validate QoS Params */ + if (dot11p_validate_qos_params(sched->channels[i].qos_params)) { + goto error; + } + + if ((sched->channels[i].per_packet_rx_stats != 0) + && (sched->channels[i].per_packet_rx_stats != 1)) { + goto error; + } + } + + return 0; + +error: + return 1; +} + +/** + * hdd_ocb_register_sta() - Register station with Transport Layer + * @adapter: Pointer to HDD Adapter + * + * This function should be invoked in the OCB Set Schedule callback + * to enable the data path in the TL by calling RegisterSTAClient + * + * Return: 0 on success. -1 on failure. + */ +static int hdd_ocb_register_sta(hdd_adapter_t *adapter) +{ + VOS_STATUS vos_status = VOS_STATUS_E_FAILURE; + WLAN_STADescType sta_desc = {0}; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + u_int8_t peer_id; + v_MACADDR_t wildcardBSSID = { + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + }; + + vos_status = WLANTL_RegisterOCBPeer(hdd_ctx->pvosContext, + adapter->macAddressCurrent.bytes, + &peer_id); + if (!VOS_IS_STATUS_SUCCESS(vos_status)) { + hddLog(LOGE, FL("Error registering OCB Self Peer!")); + return -1; + } + + /* Register adapter for STA ID 0 */ + /* TODO-OCB: This is for standalone 802.11p only. We need to change this + * for concurrent mode */ + hdd_ctx->sta_to_adapter[0] = adapter; + + sta_desc.ucSTAId = peer_id; + /* Fill in MAC addresses */ + vos_copy_macaddr(&sta_desc.vSelfMACAddress, &adapter->macAddressCurrent); + vos_copy_macaddr(&sta_desc.vSTAMACAddress, &adapter->macAddressCurrent); + vos_copy_macaddr(&sta_desc.vBSSIDforIBSS, &wildcardBSSID); + + sta_desc.wSTAType = WLAN_STA_OCB; + sta_desc.ucQosEnabled = 1; + sta_desc.ucInitState = WLANTL_STA_AUTHENTICATED; + + vos_status = WLANTL_RegisterSTAClient(hdd_ctx->pvosContext, + hdd_rx_packet_cbk, + hdd_tx_complete_cbk, + hdd_tx_fetch_packet_cbk, &sta_desc, + 0); + if (!VOS_IS_STATUS_SUCCESS(vos_status)) { + hddLog(LOGE, FL("WLANTL_RegisterSTAClient() failed to register. " + "Status= %d [0x%08X]"), vos_status, vos_status); + return -1; + } + + return 0; +} + +/** + * hdd_ocb_set_sched_callback() - OCB Set Schedule callback functions + * @callback_context: Pointer to HDD Adapter + * @rsp: Pointer to response structure + * + * This function is registered as a callback with the lower layers + * and is used to respond with the status of a OCB Set Schedule command. + */ +static void hdd_ocb_set_sched_callback(sir_ocb_set_sched_response_t *resp) +{ + hdd_adapter_t *adapter; + + if (resp == NULL) { + return; + } + + adapter = (hdd_adapter_t *)resp->adapter; + + if (resp->status) { + /* OCB Set Schedule command failed */ + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("OCB set schedule command failed! Status = %d"), + resp->status); + goto exit; + } + + /* OCB Set Schedule command successful. Open TX data path */ + if (hdd_ocb_register_sta(adapter)) { + resp->status = -1; + } else { + netif_carrier_on(adapter->dev); + netif_tx_start_all_queues(adapter->dev); + } + +exit: + complete(&adapter->hdd_ocb_set_sched_req_var); +} + +/** + * iw_set_dot11p_channel_sched() - Handler for WLAN_SET_DOT11P_CHANNEL_SCHED + * ioctl + * @dev: Pointer to net_device structure + * @iw_request_info: IW Request Info + * @wrqu: IW Request Userspace Data Pointer + * @extra: IW Request Kernel Data Pointer + */ +static int iw_set_dot11p_channel_sched(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int rc = 0; + eHalStatus halStatus; + struct dot11p_channel_sched *sched; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + sir_ocb_set_sched_request_t *sched_req = NULL; + sir_ocb_set_sched_response_t *sched_resp = NULL; + sir_ocb_sched_t *sched_ptr; + int i; + + if (wlan_hdd_validate_context(WLAN_HDD_GET_CTX(adapter))) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (adapter->device_mode != WLAN_HDD_OCB) { + hddLog(LOGE, FL("Device not in OCB mode!")); + return -EINVAL; + } + + if (extra == NULL) { + hddLog(LOGE, FL("No data in IOCTL!")); + return -EINVAL; + } + + sched = (struct dot11p_channel_sched *)extra; + if (dot11p_validate_sched(sched)) { + hddLog(LOGE, FL("OCB schedule validation failed!")); + return -EINVAL; + } + + /* + * Currently we support only single channel operation. + * Hence, we will only use the first channel in the schedule regardless + * of the number of channels specified. All duration parameters will also + * be ignored. + */ + sched_req = vos_mem_malloc(sizeof(sir_ocb_set_sched_request_t)); + if (sched_req == NULL) { + hddLog(LOGE, FL("Failed to allocate memory!")); + return -ENOMEM; + } + vos_mem_set(sched_req, sizeof(*sched_req), 0); + + sched_resp = vos_mem_malloc(sizeof(sir_ocb_set_sched_response_t)); + if (sched_resp == NULL) { + hddLog(LOGE, FL("Failed to allocate memory!")); + rc = -ENOMEM; + goto exit; + } + vos_mem_set(sched_resp, sizeof(*sched_resp), 0); + + sched_req->session_id = adapter->sessionId; + + sched_ptr = &sched_req->sched; + sched_ptr->num_channels = 1; + sched_ptr->channels[0].chan_freq = sched->channels[0].channel_freq; + sched_ptr->channels[0].tx_power = sched->channels[0].tx_power; + sched_ptr->channels[0].tx_rate = sched->channels[0].tx_rate; + for (i = 0; i < NUM_AC; i++) { + sched_ptr->channels[0].qos_params[i].aifsn = + sched->channels[0].qos_params[i].aifsn; + sched_ptr->channels[0].qos_params[i].cwmin = + sched->channels[0].qos_params[i].cwmin; + sched_ptr->channels[0].qos_params[i].cwmax = + sched->channels[0].qos_params[i].cwmax; + } + sched_ptr->channels[0].rx_stats = sched->channels[0].per_packet_rx_stats; + + sched_resp->adapter = (void *)adapter; + sched_req->resp = sched_resp; + sched_req->callback = hdd_ocb_set_sched_callback; + + netif_tx_disable(adapter->dev); + netif_carrier_off(adapter->dev); + + init_completion(&adapter->hdd_ocb_set_sched_req_var); + halStatus = sme_ocb_set_sched_req(sched_req); + if (halStatus != eHAL_STATUS_SUCCESS) { + rc = -EINVAL; + goto exit; + } + + rc = wait_for_completion_timeout(&adapter->hdd_ocb_set_sched_req_var, + msecs_to_jiffies(HDD_OCB_SET_SCHED_TIME_OUT)); + if (!rc) { + hddLog(LOGE, FL("Timeout waiting for OCB set sched to complete")); + rc = -EINVAL; + goto exit; + } + + /* Check the status code */ + if (sched_resp->status) { + hddLog(LOGE, FL("Error while setting OCB Schedule")); + rc = -EINVAL; + goto exit; + } + + rc = 0; + +exit: + if (sched_req) { + vos_mem_free(sched_req); + } + if (sched_resp) { + vos_mem_free(sched_resp); + } + return rc; +} + + /* * Support for the RSSI & RSSI-APPROX private commands * Per the WiFi framework the response must be of the form @@ -9778,6 +10174,7 @@ static const iw_handler we_private[] = { [WLAN_SET_POWER_PARAMS - SIOCIWFIRSTPRIV] = iw_set_power_params_priv, [WLAN_GET_LINK_SPEED - SIOCIWFIRSTPRIV] = iw_get_linkspeed_priv, [WLAN_PRIV_SET_TWO_INT_GET_NONE - SIOCIWFIRSTPRIV] = iw_set_two_ints_getnone, + [WLAN_SET_DOT11P_CHANNEL_SCHED - SIOCIWFIRSTPRIV] = iw_set_dot11p_channel_sched, }; /*Maximum command length can be only 15 */ diff --git a/CORE/VOSS/inc/vos_types.h b/CORE/VOSS/inc/vos_types.h index 8082bb09b7b8..69f2abe41f61 100644 --- a/CORE/VOSS/inc/vos_types.h +++ b/CORE/VOSS/inc/vos_types.h @@ -146,6 +146,7 @@ typedef enum VOS_FTM_MODE = 5, VOS_IBSS_MODE, VOS_P2P_DEVICE_MODE, + VOS_OCB_MODE, VOS_MAX_NO_OF_MODE } tVOS_CON_MODE; diff --git a/CORE/VOSS/src/vos_api.c b/CORE/VOSS/src/vos_api.c index da273fbb80c7..725b0eb28207 100644 --- a/CORE/VOSS/src/vos_api.c +++ b/CORE/VOSS/src/vos_api.c @@ -2337,6 +2337,9 @@ VOS_STATUS vos_get_vdev_types(tVOS_CON_MODE mode, tANI_U32 *type, *type = WMI_VDEV_TYPE_AP; *sub_type = WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO; break; + case VOS_OCB_MODE: + *type = WMI_VDEV_TYPE_OCB; + break; default: hddLog(VOS_TRACE_LEVEL_ERROR, "Invalid device mode %d", mode); status = VOS_STATUS_E_INVAL; |
