prima: TDLS Off Channel ioctl support

TDLS Off Channel ioctl support host side implementation.
This ioctl will provide the parameters to f/w for switching
to target channel as needed by certification test.

Change-Id: Iebff803bec5fd56acc0272cb1d1c1b7f1c77c0a8
CRs-Fixed: 703740
diff --git a/CORE/HDD/inc/wlan_hdd_tdls.h b/CORE/HDD/inc/wlan_hdd_tdls.h
index ec38dfc..d402d50 100644
--- a/CORE/HDD/inc/wlan_hdd_tdls.h
+++ b/CORE/HDD/inc/wlan_hdd_tdls.h
@@ -341,4 +341,6 @@
 int wlan_hdd_set_callback(hddTdlsPeer_t *curr_peer,
                           cfg80211_exttdls_callback callback);
 
+// tdlsoffchan
+hddTdlsPeer_t *wlan_hdd_tdls_get_first_connected_peer(hdd_adapter_t *pAdapter);
 #endif // __HDD_TDSL_H
diff --git a/CORE/HDD/src/wlan_hdd_wext.c b/CORE/HDD/src/wlan_hdd_wext.c
index e9728e6..0fb765b 100644
--- a/CORE/HDD/src/wlan_hdd_wext.c
+++ b/CORE/HDD/src/wlan_hdd_wext.c
@@ -121,6 +121,14 @@
 
 extern int wlan_hdd_cfg80211_update_band(struct wiphy *wiphy, eCsrBand eBand);
 
+// tdlsoffchan
+#ifdef FEATURE_WLAN_TDLS
+static int iw_set_tdlsoffchannel(hdd_context_t *pHddCtx, int offchannel);
+static int iw_set_tdlssecoffchanneloffset(hdd_context_t *pHddCtx, int offchanoffset);
+static int iw_set_tdlsoffchannelmode(hdd_adapter_t *pAdapter, int offchanmode);
+static int tdlsOffCh = 1;
+static int tdlsOffChBwOffset = 0;
+#endif
 static int ioctl_debug;
 module_param(ioctl_debug, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 
@@ -154,6 +162,12 @@
 #define WE_SET_MAX_TX_POWER_5_0   12
 /* Private IOCTL for debug connection issues */
 #define WE_SET_DEBUG_LOG     13
+// tdlsoffchan
+#ifdef FEATURE_WLAN_TDLS
+#define WE_SET_TDLS_OFF_CHAN             14
+#define WE_SET_TDLS_SEC_OFF_CHAN_OFFSET  15
+#define WE_SET_TDLS_OFF_CHAN_MODE        16
+#endif
 
 /* Private ioctls and their sub-ioctls */
 #define WLAN_PRIV_SET_NONE_GET_INT    (SIOCIWFIRSTPRIV + 1)
@@ -246,7 +260,6 @@
 #define MAX_VAR_ARGS         7
 #endif
 
-
 /* Private ioctls (with no sub-ioctls) */
 /* note that they must be odd so that they have "get" semantics */
 #define WLAN_PRIV_ADD_TSPEC (SIOCIWFIRSTPRIV +  9)
@@ -4421,6 +4434,31 @@
            sme_UpdateConnectDebug(pHddCtx->hHal, set_value);
            break;
         }
+#ifdef FEATURE_WLAN_TDLS
+        case WE_SET_TDLS_OFF_CHAN:
+        {
+           hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
+           VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Tdls offchannel num %d",
+                     __func__, set_value);
+           ret = iw_set_tdlsoffchannel(pHddCtx, set_value);
+           break;
+        }
+        case WE_SET_TDLS_SEC_OFF_CHAN_OFFSET:
+        {
+           hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
+           VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Tdls sec offchan offset %d",
+                     __func__, set_value);
+           ret = iw_set_tdlssecoffchanneloffset(pHddCtx, set_value);
+           break;
+        }
+        case WE_SET_TDLS_OFF_CHAN_MODE:
+        {
+           VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Tdls offchannel mode %d",
+                     __func__, set_value);
+           ret = iw_set_tdlsoffchannelmode(pAdapter, set_value);
+           break;
+        }
+#endif
 
         default:
         {
@@ -7440,6 +7478,161 @@
   return VOS_STATUS_SUCCESS;
 }/*iw_set_power_params*/
 
+// tdlsoffchan
+#ifdef FEATURE_WLAN_TDLS
+
+static int iw_set_tdlsoffchannel(hdd_context_t *pHddCtx, int offchannel)
+{
+    if (offchannel < 0 || offchannel > 165)
+    {
+        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: Invalid tdls off channel %u",
+                  __func__, offchannel);
+        return -1;
+
+    }
+
+    VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: change tdls off channel from %d to %d",
+              __func__, tdlsOffCh, offchannel);
+
+    tdlsOffCh = offchannel;
+    return 0;
+}
+
+static int iw_set_tdlssecoffchanneloffset(hdd_context_t *pHddCtx, int offchanoffset)
+{
+    if (offchanoffset ==  0)
+    {
+       tdlsOffChBwOffset = 0;
+       VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: change tdls secondary off channel offset to %u",
+                 __func__, tdlsOffChBwOffset);
+
+       return 0;
+
+    }
+
+    if ( offchanoffset == 40 )
+    {
+       tdlsOffChBwOffset = 1;
+       VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: change tdls secondary off channel offset to %u",
+                 __func__, tdlsOffChBwOffset);
+
+       return 0;
+
+    }
+    if (offchanoffset == -40)
+    {
+       tdlsOffChBwOffset = 3;
+       VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: change tdls secondary off channel offset to %u",
+                 __func__, tdlsOffChBwOffset);
+
+       return 0;
+
+    }
+    VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: Invalid tdls secondary off channel offset %d",
+              __func__, offchanoffset);
+    return -1;
+}
+
+static int iw_set_tdlsoffchannelmode(hdd_adapter_t *pAdapter, int offchanmode)
+{
+    hddTdlsPeer_t *connPeer = NULL;
+    hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
+    hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
+
+    if (offchanmode < 0 || offchanmode > 4)
+    {
+        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                  "%s: Invalid tdls off channel mode %d",
+                  __func__, offchanmode);
+        return -1;
+    }
+
+    if (eConnectionState_Associated != pHddStaCtx->conn_info.connState)
+    {
+        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                  "%s: tdls off channel mode req in not associated state %d",
+                  __func__, offchanmode);
+        return -1;
+    }
+
+    if (eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode ||
+        eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == pHddCtx->tdls_mode)
+    {
+       /* Send TDLS Channel Switch Request to connected peer */
+       connPeer = wlan_hdd_tdls_get_first_connected_peer(pAdapter);
+       if (NULL == connPeer) {
+           VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
+                     "%s: No TDLS Connected Peer", __func__);
+           return -1;
+       }
+    }
+    else
+    {
+       VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
+                 "%s: TDLS Connection not supported", __func__);
+       return -1;
+    }
+
+    VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+              ("%s: TDLS Channel Switch in swmode=%d"),
+               __func__, offchanmode);
+
+    switch (offchanmode)
+    {
+       case 1:/*Enable*/
+       case 2:/*Disable*/
+       {
+           VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+                     "%s: change tdls off channel mode %d tdls_off_channel %d offchanoffset %d ",
+                     __func__, offchanmode, tdlsOffCh, tdlsOffChBwOffset);
+           if (TRUE == pHddCtx->cfg_ini->fEnableTDLSOffChannel)
+           {
+
+               sme_SendTdlsChanSwitchReq(WLAN_HDD_GET_HAL_CTX(pAdapter),
+                                       pAdapter->sessionId, connPeer->peerMac,
+                                       tdlsOffCh, tdlsOffChBwOffset,
+                                       offchanmode);
+           }
+           else
+           {
+               VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                         "%s: TDLS Off Channel not supported", __func__);
+               return -1;
+           }
+           break;
+       }
+       case 3:
+       {
+           VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+                     "%s: change tdls off channel mode %d REJREQ 3 tdls_off_channel %d offchanoffset %d ",
+                     __func__, offchanmode, tdlsOffCh, tdlsOffChBwOffset);
+
+           break;
+       }
+       case 4:
+       {
+           VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+                     "%s: change tdls off channel mode %d UNSOLRESP 4 tdls_off_channel %d offchanoffset %d ",
+                     __func__, offchanmode, tdlsOffCh, tdlsOffChBwOffset);
+           break;
+       }
+       default:
+       {
+           VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                     "%s: change tdls off channel mode %d Not SET 0 tdls_off_channel %d offchanoffset %d ",
+                     __func__, offchanmode, tdlsOffCh, tdlsOffChBwOffset);
+           break;
+       }
+
+    }
+
+    VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: change tdls off channel mode to %u",
+                __func__, offchanmode);
+    return 0;
+}
+
+#endif
+
 
 // Define the Wireless Extensions to the Linux Network Device structure
 // A number of these routines are NULL (meaning they are not implemented.)
@@ -7626,6 +7819,23 @@
     {   WE_SET_DEBUG_LOG,
         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
         0, "setDbgLvl" },
+#ifdef FEATURE_WLAN_TDLS
+    {
+        WE_SET_TDLS_OFF_CHAN,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        0,
+        "tdlsoffchan" },
+    {
+        WE_SET_TDLS_SEC_OFF_CHAN_OFFSET,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        0,
+        "tdlsecchnoffst" },
+    {
+        WE_SET_TDLS_OFF_CHAN_MODE,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        0,
+        "tdlsoffchnmode" },
+#endif
 
     /* handlers for main ioctl */
     {   WLAN_PRIV_SET_NONE_GET_INT,
diff --git a/CORE/MAC/inc/sirApi.h b/CORE/MAC/inc/sirApi.h
index 3640bf3..8a32e8c 100644
--- a/CORE/MAC/inc/sirApi.h
+++ b/CORE/MAC/inc/sirApi.h
@@ -4204,6 +4204,22 @@
    tANI_U8                sessionId;     // Session ID
    tANI_U32               txCompleteStatus;
 } tSirMgmtTxCompletionInd, *tpSirMgmtTxCompletionInd;
+
+//tdlsoffchan
+/* TDLS Channel Switch struct SME-->PE */
+typedef struct
+{
+    tANI_U16            messageType;  //eWNI_SME_TDLS_CHANNEL_SWITCH_REQ
+    tANI_U16            length;
+    tANI_U8             sessionId;     // Session ID
+    tANI_U16            transactionId; // Transaction ID for cmd
+    tANI_U8             tdlsOffCh;     // Target Off Channel
+    tANI_U8             tdlsOffChBwOffset;// Target Off Channel Bandwidth offset
+    tANI_U8             tdlsSwMode;     // TDLS Off Channel Mode
+    tSirMacAddr         bssid;         // For multi-session, for PE to locate peSession ID
+    tSirMacAddr         peerMac;
+}tSirTdlsChanSwitch, *tpSirTdlsChanSwitch;
+
 #endif /* FEATURE_WLAN_TDLS */
 
 #ifdef FEATURE_WLAN_TDLS_INTERNAL
diff --git a/CORE/MAC/inc/wniApi.h b/CORE/MAC/inc/wniApi.h
index a588cc3..30441d7 100644
--- a/CORE/MAC/inc/wniApi.h
+++ b/CORE/MAC/inc/wniApi.h
@@ -336,6 +336,8 @@
     eWNI_SME_MGMT_FRM_TX_COMPLETION_IND,
     eWNI_SME_TDLS_LINK_ESTABLISH_REQ,
     eWNI_SME_TDLS_LINK_ESTABLISH_RSP,
+// tdlsoffchan
+    eWNI_SME_TDLS_CHANNEL_SWITCH_REQ,
 #endif
     //NOTE: If you are planning to add more mesages, please make sure that 
     //SIR_LIM_ITC_MSG_TYPES_BEGIN is moved appropriately. It is set as
diff --git a/CORE/MAC/src/include/sirParams.h b/CORE/MAC/src/include/sirParams.h
index d46083e..d396e78 100644
--- a/CORE/MAC/src/include/sirParams.h
+++ b/CORE/MAC/src/include/sirParams.h
@@ -675,6 +675,13 @@
 
 #endif /* WLAN_FEATURE_EXTSCAN */
 
+#ifdef FEATURE_WLAN_TDLS
+/// PE <-> HAL TDLS messages
+// tdlsoffchan
+#define SIR_HAL_TDLS_CHAN_SWITCH_REQ          (SIR_HAL_ITC_MSG_TYPES_BEGIN + 258)
+#define SIR_HAL_TDLS_CHAN_SWITCH_REQ_RSP      (SIR_HAL_ITC_MSG_TYPES_BEGIN + 259)
+#endif
+
 #define SIR_HAL_MSG_TYPES_END              (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF)
 // CFG message types
 #define SIR_CFG_MSG_TYPES_BEGIN        (SIR_CFG_MODULE_ID << 8)
diff --git a/CORE/MAC/src/pe/lim/limProcessMessageQueue.c b/CORE/MAC/src/pe/lim/limProcessMessageQueue.c
index 8eb6250..144c09f 100644
--- a/CORE/MAC/src/pe/lim/limProcessMessageQueue.c
+++ b/CORE/MAC/src/pe/lim/limProcessMessageQueue.c
@@ -1468,6 +1468,8 @@
         case eWNI_SME_TDLS_ADD_STA_REQ:
         case eWNI_SME_TDLS_DEL_STA_REQ:
         case eWNI_SME_TDLS_LINK_ESTABLISH_REQ:
+// tdlsoffchan
+        case eWNI_SME_TDLS_CHANNEL_SWITCH_REQ:
 #endif
 #ifdef FEATURE_WLAN_TDLS_INTERNAL
         case eWNI_SME_TDLS_DISCOVERY_START_REQ:
diff --git a/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c b/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c
index 9b55421..714baf7 100644
--- a/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c
+++ b/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c
@@ -5750,6 +5750,10 @@
         case eWNI_SME_TDLS_LINK_ESTABLISH_REQ:
             limProcesSmeTdlsLinkEstablishReq(pMac, pMsgBuf);
             break;
+// tdlsoffchan
+        case eWNI_SME_TDLS_CHANNEL_SWITCH_REQ:
+            limProcesSmeTdlsChanSwitchReq(pMac, pMsgBuf);
+            break;
 #endif
 #ifdef FEATURE_WLAN_TDLS_INTERNAL
         case eWNI_SME_TDLS_DISCOVERY_START_REQ:
diff --git a/CORE/MAC/src/pe/lim/limProcessTdls.c b/CORE/MAC/src/pe/lim/limProcessTdls.c
index b1bbd57..8a2a5ba 100644
--- a/CORE/MAC/src/pe/lim/limProcessTdls.c
+++ b/CORE/MAC/src/pe/lim/limProcessTdls.c
@@ -5851,3 +5851,118 @@
 }
 
 #endif
+// tdlsoffchan
+/*
+ * Process Channel Switch from SME.
+ */
+tSirRetStatus limProcesSmeTdlsChanSwitchReq(tpAniSirGlobal pMac,
+                                            tANI_U32 *pMsgBuf)
+{
+    /* get all discovery request parameters */
+    tSirTdlsChanSwitch *pTdlsChanSwitch = (tSirTdlsChanSwitch*) pMsgBuf ;
+    tpPESession            psessionEntry;
+    tANI_U8                sessionId;
+    tpTdlsChanSwitchParams pMsgTdlsChanSwitch;
+    tSirMsgQ               msg;
+    tANI_U16               peerIdx = 0;
+    tpDphHashNode          pStaDs = NULL;
+
+    VOS_TRACE(VOS_MODULE_ID_PE, VOS_TRACE_LEVEL_INFO,
+             ("TDLS Channel Switch Recieved on peer:" MAC_ADDRESS_STR),
+              MAC_ADDR_ARRAY(pTdlsChanSwitch->peerMac));
+
+    psessionEntry = peFindSessionByBssid(pMac,
+                                         pTdlsChanSwitch->bssid,
+                                         &sessionId);
+    if (psessionEntry == NULL)
+    {
+        VOS_TRACE(VOS_MODULE_ID_PE, VOS_TRACE_LEVEL_ERROR,
+                  "PE Session does not exist for given sme sessionId %d",
+                  pTdlsChanSwitch->sessionId);
+        return eSIR_FAILURE;
+    }
+
+    /* check if we are in proper state to work as TDLS client */
+    if (psessionEntry->limSystemRole != eLIM_STA_ROLE)
+    {
+        VOS_TRACE(VOS_MODULE_ID_PE, VOS_TRACE_LEVEL_ERROR,
+                  "TDLS Channel Switch received in wrong system Role %d",
+                  psessionEntry->limSystemRole);
+        goto lim_tdls_chan_switch_error;
+    }
+
+    /*
+     * if we are still good, go ahead and check if we are in proper state to
+     * do TDLS discovery req/rsp/....frames.
+     */
+    if ((psessionEntry->limSmeState != eLIM_SME_ASSOCIATED_STATE) &&
+            (psessionEntry->limSmeState != eLIM_SME_LINK_EST_STATE))
+    {
+
+        limLog(pMac, LOGE, "TDLS Channel Switch received in invalid LIMsme state (%d)",
+               psessionEntry->limSmeState);
+        goto lim_tdls_chan_switch_error;
+    }
+
+    pStaDs = dphLookupHashEntry(pMac, pTdlsChanSwitch->peerMac, &peerIdx,
+                                &psessionEntry->dph.dphHashTable) ;
+    if ( NULL == pStaDs )
+    {
+        limLog( pMac, LOGE, FL( "pStaDs is NULL" ));
+        goto lim_tdls_chan_switch_error;
+
+    }
+    pMsgTdlsChanSwitch = vos_mem_malloc(sizeof( tTdlsChanSwitchParams ));
+    if ( NULL == pMsgTdlsChanSwitch )
+    {
+        limLog( pMac, LOGE,
+                     FL( "Unable to allocate memory TDLS Channel Switch" ));
+        return eSIR_MEM_ALLOC_FAILED;
+    }
+
+    vos_mem_set( (tANI_U8 *)pMsgTdlsChanSwitch, sizeof(tpTdlsChanSwitchParams), 0);
+
+    pMsgTdlsChanSwitch->staIdx = pStaDs->staIndex;
+    pMsgTdlsChanSwitch->tdlsOffCh = pTdlsChanSwitch->tdlsOffCh;
+    pMsgTdlsChanSwitch->tdlsOffChBwOffset = pTdlsChanSwitch->tdlsOffChBwOffset;
+    pMsgTdlsChanSwitch->tdlsSwMode = pTdlsChanSwitch->tdlsSwMode;
+    pMsgTdlsChanSwitch->operClass = limGetOPClassFromChannel(
+                                           pMac->scan.countryCodeCurrent,
+                                           pTdlsChanSwitch->tdlsOffCh,
+                                           pTdlsChanSwitch->tdlsOffChBwOffset);
+    if(pMsgTdlsChanSwitch->operClass == 0)
+    {
+
+        VOS_TRACE(VOS_MODULE_ID_PE, VOS_TRACE_LEVEL_ERROR,
+                                   "Invalid Operating class 0 !!!");
+        goto lim_tdls_chan_switch_error;
+    }
+    else
+    {
+
+        VOS_TRACE(VOS_MODULE_ID_PE, VOS_TRACE_LEVEL_INFO,
+              "%s: TDLS Channel Switch params: staIdx %d class %d ch %d bw %d mode %d",
+               __func__,
+               pMsgTdlsChanSwitch->staIdx,
+               pMsgTdlsChanSwitch->operClass,
+               pMsgTdlsChanSwitch->tdlsOffCh,
+               pMsgTdlsChanSwitch->tdlsOffChBwOffset,
+               pMsgTdlsChanSwitch->tdlsSwMode);
+    }
+
+    msg.type = WDA_SET_TDLS_CHAN_SWITCH_REQ;
+    msg.reserved = 0;
+    msg.bodyptr = pMsgTdlsChanSwitch;
+    msg.bodyval = 0;
+    if(eSIR_SUCCESS != wdaPostCtrlMsg(pMac, &msg))
+    {
+        limLog(pMac, LOGE, FL("halPostMsgApi failed\n"));
+        goto lim_tdls_chan_switch_error;
+    }
+
+    return eSIR_SUCCESS;
+
+lim_tdls_chan_switch_error:
+    return eSIR_FAILURE;
+}
+
diff --git a/CORE/MAC/src/pe/lim/limTypes.h b/CORE/MAC/src/pe/lim/limTypes.h
index 39e76de..e4ae419 100644
--- a/CORE/MAC/src/pe/lim/limTypes.h
+++ b/CORE/MAC/src/pe/lim/limTypes.h
@@ -741,7 +741,10 @@
 eHalStatus limProcessTdlsAddStaRsp(tpAniSirGlobal pMac, void *msg, tpPESession);
 tSirRetStatus limSendTdlsTeardownFrame(tpAniSirGlobal pMac,
            tSirMacAddr peerMac, tANI_U16 reason, tANI_U8 responder, tpPESession psessionEntry,
-           tANI_U8 *addIe, tANI_U16 addIeLen); 
+           tANI_U8 *addIe, tANI_U16 addIeLen);
+// tdlsoffchan
+tSirRetStatus limProcesSmeTdlsChanSwitchReq(tpAniSirGlobal pMac,
+                                            tANI_U32 *pMsgBuf);
 #endif
 
 // Algorithms & Link Monitoring related functions
diff --git a/CORE/SME/inc/smeInside.h b/CORE/SME/inc/smeInside.h
index 839b800..a7115c8 100644
--- a/CORE/SME/inc/smeInside.h
+++ b/CORE/SME/inc/smeInside.h
@@ -154,6 +154,16 @@
 {
   tSirMacAddr peerMac;
 } tTdlsDelStaCmdInfo;
+
+// tdlsoffchan
+typedef struct TdlsChanSwitchInfo
+{
+  tSirMacAddr peerMac;
+  tANI_U8 tdlsOffCh;
+  tANI_U8 tdlsOffChBwOffset;
+  tANI_U8 tdlsSwMode;
+} tTdlsChanSwitchCmdInfo;
+
 #ifdef FEATURE_WLAN_TDLS_INTERNAL
 typedef struct TdlsDisReqCmdinfo
 {
@@ -190,6 +200,7 @@
     tTdlsSendMgmtCmdInfo tdlsSendMgmtCmdInfo;
     tTdlsAddStaCmdInfo   tdlsAddStaCmdInfo;
     tTdlsDelStaCmdInfo   tdlsDelStaCmdInfo;
+    tTdlsChanSwitchCmdInfo tdlsChanSwitchCmdInfo; //tdlsoffchan
   }u;
 } tTdlsCmd;
 #endif  /* FEATURE_WLAN_TDLS */
@@ -306,8 +317,14 @@
 eHalStatus csrTdlsDelPeerSta(tHalHandle hHal, tANI_U8 sessionId, tSirMacAddr peerMac);
 eHalStatus csrTdlsProcessCmd(tpAniSirGlobal pMac,tSmeCmd *pCommand );
 eHalStatus csrTdlsProcessLinkEstablish( tpAniSirGlobal pMac, tSmeCmd *cmd );
-eHalStatus tdlsMsgProcessor(tpAniSirGlobal pMac,v_U16_t msg_type,
-                                                           void *pMsgBuf);
+eHalStatus csrTdlsProcessChanSwitchReq(tpAniSirGlobal pMac, tSmeCmd *cmd ); //tdlsoffchan
+eHalStatus tdlsMsgProcessor(tpAniSirGlobal pMac,v_U16_t msg_type, void *pMsgBuf);
+VOS_STATUS csrTdlsSendChanSwitchReq(tHalHandle hHal,
+                                    tANI_U8 sessionId,
+                                    tSirMacAddr peerMac,
+                                    tANI_S32 tdlsOffCh,
+                                    tANI_S32 tdlsOffChBwOffset,
+                                    tANI_U8 tdlsSwMode);
 #ifdef FEATURE_WLAN_TDLS_INTERNAL
 eHalStatus csrTdlsDiscoveryReq(tHalHandle hHal, tANI_U8 sessionId,
                                           tCsrTdlsDisRequest *tdlsDisReq);
diff --git a/CORE/SME/inc/smeInternal.h b/CORE/SME/inc/smeInternal.h
index a2c9527..abbefd1 100644
--- a/CORE/SME/inc/smeInternal.h
+++ b/CORE/SME/inc/smeInternal.h
@@ -81,6 +81,7 @@
     eSmeCommandTdlsAddPeer, 
     eSmeCommandTdlsDelPeer, 
     eSmeCommandTdlsLinkEstablish,
+    eSmeCommandTdlsChannelSwitch, // tdlsoffchan
 #ifdef FEATURE_WLAN_TDLS_INTERNAL
     eSmeCommandTdlsDiscovery,
     eSmeCommandTdlsLinkSetup,
diff --git a/CORE/SME/inc/sme_Api.h b/CORE/SME/inc/sme_Api.h
index 798fc4a..353fddb 100644
--- a/CORE/SME/inc/sme_Api.h
+++ b/CORE/SME/inc/sme_Api.h
@@ -3413,4 +3413,13 @@
 eHalStatus sme_getBcnMissRate(tHalHandle, tANI_U8, void *, void *);
 
 tANI_BOOLEAN  sme_Is11dCountrycode(tHalHandle hHal);
+
+// tdlsoffchan
+VOS_STATUS sme_SendTdlsChanSwitchReq(tHalHandle hHal,
+                                     tANI_U8 sessionId,
+                                     tSirMacAddr peerMac,
+                                     tANI_S32 tdlsOffCh,
+                                     tANI_S32 tdlsOffChBwOffset,
+                                     tANI_U8 tdlsSwMode);
+
 #endif //#if !defined( __SME_API_H )
diff --git a/CORE/SME/src/csr/csrTdlsProcess.c b/CORE/SME/src/csr/csrTdlsProcess.c
index 6a52320..bc1be31 100644
--- a/CORE/SME/src/csr/csrTdlsProcess.c
+++ b/CORE/SME/src/csr/csrTdlsProcess.c
@@ -360,6 +360,53 @@
 
     return status ;
 }
+
+//tdlsoffchan
+/*
+ * TDLS request API, called from HDD to Send Channel Switch Parameters
+ */
+VOS_STATUS csrTdlsSendChanSwitchReq(tHalHandle hHal,
+                                    tANI_U8 sessionId,
+                                    tSirMacAddr peerMac,
+                                    tANI_S32 tdlsOffCh,
+                                    tANI_S32 tdlsOffChBwOffset,
+                                    tANI_U8 tdlsSwMode)
+{
+    tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
+    tSmeCmd *tdlsChanSwitchCmd;
+    eHalStatus status = eHAL_STATUS_FAILURE ;
+
+    //If connected and in Infra. Only then allow this
+    if( CSR_IS_SESSION_VALID( pMac, sessionId ) &&
+        csrIsConnStateConnectedInfra( pMac, sessionId ) &&
+        (NULL != peerMac) )
+    {
+        tdlsChanSwitchCmd = csrGetCommandBuffer(pMac) ;
+
+        if(tdlsChanSwitchCmd)
+        {
+            tTdlsChanSwitchCmdInfo *tdlsChanSwitchCmdInfo =
+            &tdlsChanSwitchCmd->u.tdlsCmd.u.tdlsChanSwitchCmdInfo;
+
+            tdlsChanSwitchCmd->sessionId = sessionId;
+
+            vos_mem_copy(tdlsChanSwitchCmdInfo->peerMac,
+                         peerMac, sizeof(tSirMacAddr));
+            tdlsChanSwitchCmdInfo->tdlsOffCh = tdlsOffCh;
+            tdlsChanSwitchCmdInfo->tdlsOffChBwOffset = tdlsOffChBwOffset;
+            tdlsChanSwitchCmdInfo->tdlsSwMode = tdlsSwMode;
+
+            tdlsChanSwitchCmd->command = eSmeCommandTdlsChannelSwitch;
+            tdlsChanSwitchCmd->u.tdlsCmd.size = sizeof(tTdlsChanSwitchCmdInfo) ;
+            smePushCommand(pMac, tdlsChanSwitchCmd, FALSE) ;
+            status = eHAL_STATUS_SUCCESS ;
+        }
+    }
+
+    return status ;
+}
+
+
 #ifdef FEATURE_WLAN_TDLS_INTERNAL
 /*
  * TDLS request API, called from HDD to enable TDLS discovery request
@@ -734,6 +781,16 @@
             }
         }
         break;
+// tdlsoffchan
+        case eSmeCommandTdlsChannelSwitch:
+        {
+             status = csrTdlsProcessChanSwitchReq( pMac, cmd );
+             if(HAL_STATUS_SUCCESS( status ) )
+             {
+               status = eANI_BOOLEAN_FALSE ;
+             }
+        }
+        break;
 #ifdef FEATURE_WLAN_TDLS_INTERNAL
         case eSmeCommandTdlsDiscovery:
         {
@@ -916,6 +973,51 @@
     return status;
 }
 
+// tdlsoffchan
+eHalStatus csrTdlsProcessChanSwitchReq( tpAniSirGlobal pMac, tSmeCmd *cmd )
+{
+    tTdlsChanSwitchCmdInfo *tdlsChanSwitchCmdInfo = &cmd->u.tdlsCmd.u.tdlsChanSwitchCmdInfo ;
+    tSirTdlsChanSwitch *tdlsChanSwitch = NULL ;
+    eHalStatus status = eHAL_STATUS_FAILURE;
+    tCsrRoamSession *pSession = CSR_GET_SESSION( pMac, cmd->sessionId );
+
+    if (NULL == pSession)
+    {
+        smsLog( pMac, LOGE, FL("pSession is NULL"));
+        return eHAL_STATUS_FAILURE;
+    }
+
+    tdlsChanSwitch = vos_mem_malloc(sizeof(tSirTdlsChanSwitch));
+    if (tdlsChanSwitch == NULL)
+    {
+        smsLog( pMac, LOGE, FL("alloc failed \n") );
+        VOS_ASSERT(0) ;
+        return status ;
+    }
+    tdlsChanSwitch->sessionId = cmd->sessionId;
+    //Using dialog as transactionId. This can be used to match response with request
+    tdlsChanSwitch->transactionId = 0;
+    vos_mem_copy( tdlsChanSwitch->peerMac,
+                  tdlsChanSwitchCmdInfo->peerMac, sizeof(tSirMacAddr));
+    vos_mem_copy(tdlsChanSwitch->bssid, pSession->pConnectBssDesc->bssId,
+                 sizeof (tSirMacAddr));
+
+    tdlsChanSwitch->tdlsOffCh = tdlsChanSwitchCmdInfo->tdlsOffCh;
+    tdlsChanSwitch->tdlsOffChBwOffset = tdlsChanSwitchCmdInfo->tdlsOffChBwOffset;
+    tdlsChanSwitch->tdlsSwMode = tdlsChanSwitchCmdInfo->tdlsSwMode;
+
+    // Send the request to PE.
+    smsLog( pMac, LOGE, "sending TDLS Channel Switch to PE \n" );
+    status = tdlsSendMessage(pMac, eWNI_SME_TDLS_CHANNEL_SWITCH_REQ,
+                             (void *)tdlsChanSwitch,
+                             sizeof(tSirTdlsChanSwitch));
+    if (!HAL_STATUS_SUCCESS( status ) )
+    {
+        smsLog( pMac, LOGE, FL("Failed to send request to MAC\n"));
+    }
+    return status;
+}
+
 #ifdef FEATURE_WLAN_TDLS_INTERNAL
 /*
  * Find specific TDLS peer (based on peer MAC address).
@@ -1162,6 +1264,7 @@
             csrTdlsRemoveSmeCmd(pMac, eSmeCommandTdlsLinkEstablish);
             break;
         }
+
 #ifdef FEATURE_WLAN_TDLS_INTERNAL
         case eWNI_SME_TDLS_DISCOVERY_START_RSP:
         {
diff --git a/CORE/SME/src/sme_common/sme_Api.c b/CORE/SME/src/sme_common/sme_Api.c
index 08a93a2..c51ae21 100644
--- a/CORE/SME/src/sme_common/sme_Api.c
+++ b/CORE/SME/src/sme_common/sme_Api.c
@@ -1014,6 +1014,7 @@
                         case eSmeCommandTdlsAddPeer:
                         case eSmeCommandTdlsDelPeer:
                         case eSmeCommandTdlsLinkEstablish:
+                        case eSmeCommandTdlsChannelSwitch: // tdlsoffchan
 #ifdef FEATURE_WLAN_TDLS_INTERNAL
                         case eSmeCommandTdlsDiscovery:
                         case eSmeCommandTdlsLinkSetup:
@@ -9798,6 +9799,38 @@
    return status ;
 }
 
+// tdlsoffchan
+
+/* ---------------------------------------------------------------------------
+    \fn sme_SendTdlsChanSwitchReq
+    \brief  API to send TDLS management frames.
+
+    \param  peerMac - peer's Mac Adress.
+    \param  tdlsLinkEstablishParams - TDLS Peer Link Establishment Parameters
+    \- return VOS_STATUS_SUCCES
+    -------------------------------------------------------------------------*/
+VOS_STATUS sme_SendTdlsChanSwitchReq(tHalHandle hHal,
+                                     tANI_U8 sessionId,
+                                     tSirMacAddr peerMac,
+                                     tANI_S32 tdlsOffCh,
+                                     tANI_S32 tdlsOffChBwOffset,
+                                     tANI_U8 tdlsSwMode)
+{
+    eHalStatus          status    = eHAL_STATUS_SUCCESS;
+    tpAniSirGlobal      pMac      = PMAC_STRUCT(hHal);
+
+    status = sme_AcquireGlobalLock( &pMac->sme );
+
+    if ( HAL_STATUS_SUCCESS( status ) )
+    {
+        status = csrTdlsSendChanSwitchReq(hHal, sessionId, peerMac,
+                                          tdlsOffCh, tdlsOffChBwOffset,
+                                          tdlsSwMode);
+    }
+    sme_ReleaseGlobalLock( &pMac->sme );
+    return status ;
+}
+
 /* ---------------------------------------------------------------------------
     \fn sme_SendTdlsMgmtFrame
     \brief  API to send TDLS management frames.
diff --git a/CORE/WDA/inc/legacy/halMsgApi.h b/CORE/WDA/inc/legacy/halMsgApi.h
index ba0b003..1bcd624 100644
--- a/CORE/WDA/inc/legacy/halMsgApi.h
+++ b/CORE/WDA/inc/legacy/halMsgApi.h
@@ -1353,6 +1353,17 @@
    tANI_U32  status;
 }tTdlsLinkEstablishParams, *tpTdlsLinkEstablishParams;
 
+// tdlsoffchan
+typedef struct sTdlsChanSwitchParams
+{
+   tANI_U16  staIdx;
+   tANI_U8   tdlsOffCh;        // Target Off Channel
+   tANI_U8   tdlsOffChBwOffset;// Target Off Channel Bandwidth offset
+   tANI_U8   tdlsSwMode;     // TDLS Off Channel Mode
+   tANI_U8   operClass;      //Operating class corresponding to target channel
+   tANI_U32  status;
+}tTdlsChanSwitchParams, *tpTdlsChanSwitchParams;
+
 static inline void halGetTxTSFtimer(tpAniSirGlobal pMac, 
                                                 tSirMacTimeStamp *pTime)
 {
diff --git a/CORE/WDA/inc/wlan_qct_wda.h b/CORE/WDA/inc/wlan_qct_wda.h
index ebe8fd1..5878028 100644
--- a/CORE/WDA/inc/wlan_qct_wda.h
+++ b/CORE/WDA/inc/wlan_qct_wda.h
@@ -1213,6 +1213,11 @@
 #define WDA_LINK_LAYER_STATS_RESULTS_RSP       SIR_HAL_LL_STATS_RESULTS_RSP
 #endif /* WLAN_FEATURE_LINK_LAYER_STATS */
 
+#ifdef FEATURE_WLAN_TDLS
+// tdlsoffchan
+#define WDA_SET_TDLS_CHAN_SWITCH_REQ           SIR_HAL_TDLS_CHAN_SWITCH_REQ
+#define WDA_SET_TDLS_CHAN_SWITCH_REQ_RSP       SIR_HAL_TDLS_CHAN_SWITCH_REQ_RSP
+#endif
 tSirRetStatus wdaPostCtrlMsg(tpAniSirGlobal pMac, tSirMsgQ *pMsg);
 
 eHalStatus WDA_SetRegDomain(void * clientCtxt, v_REGDOMAIN_t regId,
diff --git a/CORE/WDA/src/wlan_qct_wda.c b/CORE/WDA/src/wlan_qct_wda.c
index e92cf42..3375449 100644
--- a/CORE/WDA/src/wlan_qct_wda.c
+++ b/CORE/WDA/src/wlan_qct_wda.c
@@ -7525,7 +7525,110 @@
     }
     return CONVERT_WDI2VOS_STATUS(status);
 }
-#endif
+
+// tdlsoffchan
+void WDA_SetTDLSChanSwitchReqParamsCallback(WDI_SetTdlsChanSwitchReqResp *wdiSetTdlsChanSwitchReqRsp,
+                                               void* pUserData)
+{
+   tWDA_ReqParams *pWdaParams = (tWDA_ReqParams *)pUserData;
+   tWDA_CbContext *pWDA = NULL;
+   tTdlsChanSwitchParams *pTdlsChanSwitchParams;
+
+
+   VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO,
+                                          "<------ %s " ,__func__);
+   if(NULL == pWdaParams)
+   {
+      VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+              "%s: pWdaParams received NULL", __func__);
+      vos_mem_free(pWdaParams->wdaWdiApiMsgParam);
+      VOS_ASSERT(0) ;
+      return ;
+   }
+   pWDA = (tWDA_CbContext *) pWdaParams->pWdaContext;
+
+   pTdlsChanSwitchParams = (tTdlsChanSwitchParams *)pWdaParams->wdaMsgParam ;
+   if( NULL == pTdlsChanSwitchParams || pWDA == NULL )
+   {
+      VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                                          "%s: pTdlsChanSwitchParams "
+                                          "received NULL " ,__func__);
+      VOS_ASSERT(0);
+      vos_mem_free(pWdaParams->wdaWdiApiMsgParam);
+      vos_mem_free(pWdaParams);
+      return ;
+   }
+   pTdlsChanSwitchParams->status = CONVERT_WDI2SIR_STATUS(
+                                               wdiSetTdlsChanSwitchReqRsp->wdiStatus);
+   vos_mem_free(pTdlsChanSwitchParams) ;
+   vos_mem_free(pWdaParams->wdaWdiApiMsgParam) ;
+   vos_mem_free(pWdaParams);
+   /* send response to UMAC
+   WDA_SendMsg(pWDA, WDA_SET_TDLS_CHAN_SWITCH_REQ_RSP, pTdlsChanSwitchParams, 0) ;*/
+
+   return ;
+}
+VOS_STATUS WDA_ProcessSetTdlsChanSwitchReq(tWDA_CbContext *pWDA,
+                                           tTdlsChanSwitchParams *pTdlsChanSwitchParams)
+{
+    WDI_Status status = WDI_STATUS_SUCCESS ;
+    WDI_SetTDLSChanSwitchReqParamsType *wdiSetTDLSChanSwitchReqParam =
+                        (WDI_SetTDLSChanSwitchReqParamsType *)vos_mem_malloc(
+                                   sizeof(WDI_SetTDLSChanSwitchReqParamsType));
+    tWDA_ReqParams *pWdaParams = NULL;
+
+    VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO,
+               "Enter: %s ",__func__);
+    if(NULL == wdiSetTDLSChanSwitchReqParam)
+    {
+        VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                   "%s: VOS MEM Alloc Failure", __func__);
+        VOS_ASSERT(0);
+        return VOS_STATUS_E_NOMEM;
+    }
+
+    pWdaParams = (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams)) ;
+    if(NULL == pWdaParams)
+    {
+        VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                   "%s: VOS MEM Alloc Failure", __func__);
+        vos_mem_free(pTdlsChanSwitchParams);
+        vos_mem_free(wdiSetTDLSChanSwitchReqParam);
+        VOS_ASSERT(0);
+        return VOS_STATUS_E_NOMEM;
+    }
+    wdiSetTDLSChanSwitchReqParam->wdiTDLSChanSwitchReqInfo.staIdx =
+                                              pTdlsChanSwitchParams->staIdx;
+    wdiSetTDLSChanSwitchReqParam->wdiTDLSChanSwitchReqInfo.isOffchannelInitiator =
+                                              pTdlsChanSwitchParams->tdlsSwMode;
+    wdiSetTDLSChanSwitchReqParam->wdiTDLSChanSwitchReqInfo.targetOperClass =
+                                              pTdlsChanSwitchParams->operClass;
+    wdiSetTDLSChanSwitchReqParam->wdiTDLSChanSwitchReqInfo.targetChannel =
+                                              pTdlsChanSwitchParams->tdlsOffCh;
+    wdiSetTDLSChanSwitchReqParam->wdiTDLSChanSwitchReqInfo.secondaryChannelOffset =
+                                          pTdlsChanSwitchParams->tdlsOffChBwOffset;
+
+
+    /* Store msg pointer from PE, as this will be used for response */
+    pWdaParams->wdaMsgParam = (void *)pTdlsChanSwitchParams ;
+    /* store Params pass it to WDI */
+    pWdaParams->wdaWdiApiMsgParam = (void *)wdiSetTDLSChanSwitchReqParam ;
+    pWdaParams->pWdaContext = pWDA;
+    status = WDI_SetTDLSChanSwitchReq(wdiSetTDLSChanSwitchReqParam,
+                                      (WDI_SetTDLSChanSwitchReqParamsRspCb)
+                                       WDA_SetTDLSChanSwitchReqParamsCallback,
+                                       pWdaParams);
+    if(IS_WDI_STATUS_FAILURE(status))
+    {
+        VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                   "Failure in TDLS Channel Switch Req WDI API, free all the memory" );
+        vos_mem_free(pWdaParams->wdaWdiApiMsgParam) ;
+        vos_mem_free(pWdaParams->wdaMsgParam);
+        vos_mem_free(pWdaParams);
+    }
+    return CONVERT_WDI2VOS_STATUS(status);
+}
+#endif /*FEATURE_WLAN_TDLS*/
 
 
 #ifdef WLAN_FEATURE_VOWIFI_11R
@@ -13054,6 +13157,14 @@
             (tANI_U8*)pMsg->bodyptr);
           break;
       }
+// tdlsoffchan
+#ifdef FEATURE_WLAN_TDLS
+      case WDA_SET_TDLS_CHAN_SWITCH_REQ:
+      {
+          WDA_ProcessSetTdlsChanSwitchReq(pWDA, (tTdlsChanSwitchParams *)pMsg->bodyptr);
+          break;
+      }
+#endif
       default:
       {
          VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO,
diff --git a/CORE/WDI/CP/inc/wlan_qct_wdi.h b/CORE/WDI/CP/inc/wlan_qct_wdi.h
index 59a88f2..d1bb97a 100644
--- a/CORE/WDI/CP/inc/wlan_qct_wdi.h
+++ b/CORE/WDI/CP/inc/wlan_qct_wdi.h
@@ -3544,7 +3544,6 @@
   void*             pUserData;
 }WDI_SetTDLSLinkEstablishReqParamsType;
 
-
 typedef struct
 {
   /*Result of the operation*/
@@ -3554,6 +3553,37 @@
   wpt_uint16 uStaIdx;
 }WDI_SetTdlsLinkEstablishReqResp;
 
+
+
+typedef struct
+{
+   /*STA Index*/
+   wpt_uint8  staIdx;
+   /* if this is 1, self is initiator otherwise responder only*/
+   wpt_uint8  isOffchannelInitiator;
+   /*TDLS off channel related params */
+   wpt_uint8  targetOperClass;
+   wpt_uint8  targetChannel;
+   wpt_uint8   secondaryChannelOffset;
+   wpt_uint8  reserved[64];
+}WDI_SetTDLSChanSwitchReqInfoType;
+
+typedef struct
+{
+  WDI_SetTDLSChanSwitchReqInfoType  wdiTDLSChanSwitchReqInfo;
+  WDI_ReqStatusCb   wdiReqStatusCB;
+  void*  pUserData;
+}WDI_SetTDLSChanSwitchReqParamsType;
+
+
+typedef struct
+{
+  /*Result of the operation*/
+  WDI_Status wdiStatus;
+
+  /*STA Idx*/
+  wpt_uint16 uStaIdx;
+}WDI_SetTdlsChanSwitchReqResp;
 /*---------------------------------------------------------------------------
   WDI_SetAddSTASelfParamsType
 ---------------------------------------------------------------------------*/
@@ -6645,6 +6675,28 @@
                                 void*        pUserData);
 
 /*---------------------------------------------------------------------------
+   WDI_SetTDLSChanSwitchReqParamsRspCb
+
+   DESCRIPTION
+
+   This callback is invoked by DAL when it has received a TDLS Link Establish Req response from
+   the underlying device.
+
+   PARAMETERS
+
+    IN
+    wdiStatus:  response status received from HAL
+    pUserData:  user data
+
+
+
+  RETURN VALUE
+    The result code associated with performing the operation
+---------------------------------------------------------------------------*/
+typedef void  (*WDI_SetTDLSChanSwitchReqParamsRspCb)(WDI_SetTdlsChanSwitchReqResp *
+                                wdiSetTdlsChanSwitchReqRsp,
+                                void*        pUserData);
+/*---------------------------------------------------------------------------
    WDI_SetPwrSaveCfgCb
  
    DESCRIPTION   
@@ -8824,6 +8876,13 @@
   void*                            pUserData
 );
 
+WDI_Status
+WDI_SetTDLSChanSwitchReq
+(
+  WDI_SetTDLSChanSwitchReqParamsType*    pwdiTDLSChanSwitchReqParams,
+  WDI_SetTDLSChanSwitchReqParamsRspCb    wdiTDLSChanSwitchRReqRspCb,
+  void*                            pUserData
+);
 /*======================================================================== 
  
                             Power Save APIs
diff --git a/CORE/WDI/CP/inc/wlan_qct_wdi_i.h b/CORE/WDI/CP/inc/wlan_qct_wdi_i.h
index 062217c..eb6ec89 100644
--- a/CORE/WDI/CP/inc/wlan_qct_wdi_i.h
+++ b/CORE/WDI/CP/inc/wlan_qct_wdi_i.h
@@ -462,6 +462,7 @@
   WDI_EXTSCAN_SET_SIGNF_RSSI_CHANGE_REQ          = 99,
   WDI_EXTSCAN_RESET_SIGNF_RSSI_CHANGE_REQ        = 100,
 #endif
+
   WDI_MAX_REQ,
 
   /*Send a suspend Indication down to HAL*/
@@ -499,6 +500,7 @@
 
   /* csa channel switch req*/
   WDI_CH_SWITCH_REQ_V1,
+  WDI_TDLS_CHAN_SWITCH_REQ,
 
   /*Keep adding the indications to the max request
     such that we keep them sepparate */
@@ -861,6 +863,7 @@
   WDI_HAL_EXTSCAN_BSSID_HOTLIST_RESULT_IND    = WDI_HAL_IND_MIN + 24,
   WDI_HAL_EXTSCAN_SIG_RSSI_RESULT_IND         = WDI_HAL_IND_MIN + 25,
 #endif
+  WDI_TDLS_CHAN_SWITCH_REQ_RESP      = WDI_HAL_IND_MIN + 28,
   WDI_MAX_RESP
 }WDI_ResponseEnumType; 
 
@@ -2401,6 +2404,21 @@
 );
 
 /**
+ @brief Process tdls channel switch request
+
+ @param  pWDICtx:         pointer to the WLAN DAL context
+         pEventData:      pointer to the event information structure
+
+ @see
+ @return Result of the function call
+*/
+WDI_Status
+WDI_ProcessTdlsChanSwitchReq
+(
+  WDI_ControlBlockType*  pWDICtx,
+  WDI_EventInfoType*     pEventData
+);
+/**
  @brief Process Enter IMPS Request function (called when 
         Main FSM allows it)
  
@@ -3852,6 +3870,24 @@
   WDI_EventInfoType*             pEventData
 );
 
+
+  /**
+ @brief Process TDLS Chan Switch  Req Rsp function (called when a response
+        is being received over the bus from HAL)
+
+ @param  pWDICtx:         pointer to the WLAN DAL context
+         pEventData:      pointer to the event information structure
+
+ @see
+ @return Result of the function call
+*/
+WDI_Status
+WDI_ProcessChanSwitchReqRsp
+(
+  WDI_ControlBlockType*          pWDICtx,
+  WDI_EventInfoType*             pEventData
+);
+
 /**
  @brief Process Nv download(called when a response
         is being received over the bus from HAL)
diff --git a/CORE/WDI/CP/src/wlan_qct_wdi.c b/CORE/WDI/CP/src/wlan_qct_wdi.c
index f0bc1fe..2ee834a 100644
--- a/CORE/WDI/CP/src/wlan_qct_wdi.c
+++ b/CORE/WDI/CP/src/wlan_qct_wdi.c
@@ -478,6 +478,11 @@
   WDI_ProcessHT40OBSSStopScanInd,    /*WDI_STOP_HT40_OBSS_SCAN_IND */
 
   WDI_ProcessChannelSwitchReq_V1,    /* WDI_CH_SWITCH_REQ_V1*/
+#ifdef FEATURE_WLAN_TDLS
+  WDI_ProcessTdlsChanSwitchReq,       /* WDI_TDLS_CHAN_SWITCH_REQ */
+#else
+  NULL,
+#endif
 
 };
 
@@ -783,6 +788,11 @@
   NULL,
   NULL,
 #endif /* WLAN_FEATURE_EXTSCAN */
+#ifdef FEATURE_WLAN_TDLS
+  WDI_ProcessChanSwitchReqRsp,              /*WDI_TDLS_CHAN_SWITCH_REQ_RESP*/
+#else
+  NULL,
+#endif
 };
 
 
@@ -1040,6 +1050,7 @@
     CASE_RETURN_STRING( WDI_P2P_GO_NOTICE_OF_ABSENCE_REQ );
 #ifdef FEATURE_WLAN_TDLS
     CASE_RETURN_STRING( WDI_TDLS_LINK_ESTABLISH_REQ );
+    CASE_RETURN_STRING( WDI_TDLS_CHAN_SWITCH_REQ );
 #endif
     CASE_RETURN_STRING( WDI_ENTER_IMPS_REQ );
     CASE_RETURN_STRING( WDI_EXIT_IMPS_REQ );
@@ -1171,6 +1182,7 @@
     CASE_RETURN_STRING( WDI_P2P_GO_NOTICE_OF_ABSENCE_RESP );
 #ifdef FEATURE_WLAN_TDLS
     CASE_RETURN_STRING( WDI_TDLS_LINK_ESTABLISH_REQ_RESP );
+    CASE_RETURN_STRING( WDI_TDLS_CHAN_SWITCH_REQ_RESP);
     CASE_RETURN_STRING( WDI_HAL_TDLS_IND );
 #endif
     CASE_RETURN_STRING( WDI_ENTER_IMPS_RESP );
@@ -5899,6 +5911,67 @@
   return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData);
 
 }/*WDI_SetTDLSLinkEstablishReq*/
+
+//tdlsoffchan
+/**
+ @brief WDI_SetTDLSChanSwitchReq will be called when the
+        upper MAC wants to send TDLS Chan Switch Request Parameters
+         Upon the call of this API the WLAN DAL will
+        pack and send the TDLS Link Establish Request  message to the
+        lower RIVA sub-system if DAL is in state STARTED.
+
+        In state BUSY this request will be queued. Request won't
+        be allowed in any other state.
+
+
+ @param pwdiTDLSChanSwitchReqParams: TDLS Peer Parameters
+        for Link Establishment (Used for TDLS Off Channel ...)
+
+        wdiTDLSChanSwitchReqRspCb: callback for passing back the
+        response of the TDLS Chan Switch request received
+        from the device
+
+        pUserData: user data will be passed back with the
+        callback
+
+ @see
+ @return Result of the function call
+*/
+WDI_Status
+WDI_SetTDLSChanSwitchReq
+(
+  WDI_SetTDLSChanSwitchReqParamsType*    pwdiTDLSChanSwitchReqParams,
+  WDI_SetTDLSChanSwitchReqParamsRspCb    wdiTDLSChanSwitchRReqRspCb,
+  void*                            pUserData
+)
+{
+  WDI_EventInfoType      wdiEventData;
+  /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+  /*------------------------------------------------------------------------
+    Sanity Check
+  ------------------------------------------------------------------------*/
+  if ( eWLAN_PAL_FALSE == gWDIInitialized )
+  {
+    WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
+              "WDI API call before module is initialized - Fail request");
+
+    return WDI_STATUS_E_NOT_ALLOWED;
+  }
+
+  /*------------------------------------------------------------------------
+    Fill in Event data and post to the Main FSM
+  ------------------------------------------------------------------------*/
+  wdiEventData.wdiRequest      = WDI_TDLS_CHAN_SWITCH_REQ;
+  wdiEventData.pEventData      = pwdiTDLSChanSwitchReqParams;
+  wdiEventData.uEventDataSize  = sizeof(*pwdiTDLSChanSwitchReqParams);
+  wdiEventData.pCBfnc          = wdiTDLSChanSwitchRReqRspCb;
+  wdiEventData.pUserData       = pUserData;
+
+  return WDI_PostMainEvent(&gWDICb, WDI_REQUEST_EVENT, &wdiEventData);
+
+}/*WDI_SetTDLSChanSwitchReq*/
+
 #endif
 
 /**
@@ -13425,7 +13498,87 @@
 }/*WDI_ProcessTdlsLinkEstablishReq*/
 
 
-#endif
+/**
+ @brief sends the channel switch command to f/w (called when Main FSM
+        allows it)
+
+ @param  pWDICtx:         pointer to the WLAN DAL context
+         pEventData:      pointer to the event information structure
+
+ @see
+ @return Result of the function call
+*/
+WDI_Status
+WDI_ProcessTdlsChanSwitchReq
+(
+  WDI_ControlBlockType*  pWDICtx,
+  WDI_EventInfoType*     pEventData
+)
+{
+  WDI_SetTDLSChanSwitchReqParamsType* pwdiTDLSChanSwitchReqParams;
+  WDI_SetTDLSChanSwitchReqParamsRspCb wdiTDLSChanSwitchReqRspCb;
+  wpt_uint8*                             pSendBuffer         = NULL;
+  wpt_uint16                             usDataOffset        = 0;
+  wpt_uint16                             usSendSize          = 0;
+  //WDI_Status                             wdiStatus;
+  tTDLSChanSwitchReqType                  halSetTDLSChanSwitchParams;
+  /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+  /*-------------------------------------------------------------------------
+    Sanity check
+  -------------------------------------------------------------------------*/
+  if (( NULL == pEventData ) ||
+      ( NULL == pEventData->pEventData))
+  {
+     WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN,
+                 "%s: Invalid parameters", __func__);
+     WDI_ASSERT(0);
+     return WDI_STATUS_E_FAILURE;
+  }
+  pwdiTDLSChanSwitchReqParams =
+    (WDI_SetTDLSChanSwitchReqParamsType*)pEventData->pEventData;
+  wdiTDLSChanSwitchReqRspCb =
+    (WDI_SetTDLSChanSwitchReqParamsRspCb)pEventData->pCBfnc;
+
+  /*-----------------------------------------------------------------------
+    Get message buffer
+  -----------------------------------------------------------------------*/
+  if (( WDI_STATUS_SUCCESS != WDI_GetMessageBuffer( pWDICtx,
+                        WDI_TDLS_CHAN_SWITCH_REQ,
+                        sizeof(halSetTDLSChanSwitchParams),
+                        &pSendBuffer, &usDataOffset, &usSendSize))||
+      ( usSendSize < (usDataOffset + sizeof(halSetTDLSChanSwitchParams) )))
+  {
+     WPAL_TRACE( eWLAN_MODULE_DAL_CTRL,  eWLAN_PAL_TRACE_LEVEL_WARN,
+              "Unable to get send buffer in Channel Switch REQ %p %p %p",
+               pEventData, pwdiTDLSChanSwitchReqParams, wdiTDLSChanSwitchReqRspCb);
+     WDI_ASSERT(0);
+     return WDI_STATUS_E_FAILURE;
+  }
+
+  halSetTDLSChanSwitchParams.staIdx =
+    pwdiTDLSChanSwitchReqParams->wdiTDLSChanSwitchReqInfo.staIdx;
+  halSetTDLSChanSwitchParams.isOffchannelInitiator =
+    pwdiTDLSChanSwitchReqParams->wdiTDLSChanSwitchReqInfo.isOffchannelInitiator;
+  halSetTDLSChanSwitchParams.targetOperClass =
+    pwdiTDLSChanSwitchReqParams->wdiTDLSChanSwitchReqInfo.targetOperClass;
+  halSetTDLSChanSwitchParams.targetChannel =
+    pwdiTDLSChanSwitchReqParams->wdiTDLSChanSwitchReqInfo.targetChannel;
+  halSetTDLSChanSwitchParams.secondaryChannelOffset =
+    pwdiTDLSChanSwitchReqParams->wdiTDLSChanSwitchReqInfo.secondaryChannelOffset;
+  wpalMemoryCopy( pSendBuffer+usDataOffset,
+                   &halSetTDLSChanSwitchParams,
+                   sizeof(halSetTDLSChanSwitchParams));
+
+  pWDICtx->wdiReqStatusCB     = NULL;
+  pWDICtx->pReqStatusUserData = NULL;
+
+  return  WDI_SendMsg( pWDICtx, pSendBuffer, usSendSize,
+                       wdiTDLSChanSwitchReqRspCb, pEventData->pUserData,
+                       WDI_TDLS_CHAN_SWITCH_REQ_RESP);
+}/*WDI_ProcessTdlsChanSwitchReq*/
+
+#endif /*FEATURE_WLAN_TDLS*/
 
 
 
@@ -19020,6 +19173,72 @@
 
   return WDI_STATUS_SUCCESS;
 }/*WDI_ProcessLinkEstablishReqRsp*/
+
+
+
+/**
+ @brief Process TDLS Chan switch Rsp function (called
+        when a response is being received over the bus from HAL)
+
+ @param  pWDICtx:         pointer to the WLAN DAL context
+         pEventData:      pointer to the event information structure
+
+ @see
+ @return Result of the function call
+*/
+WDI_Status
+WDI_ProcessChanSwitchReqRsp
+(
+  WDI_ControlBlockType*  pWDICtx,
+  WDI_EventInfoType*     pEventData
+)
+{
+  eHalStatus       halStatus;
+  WDI_SetTDLSChanSwitchReqParamsRspCb   wdiTDLSChanSwitchReqParamsRspCb;
+  tTDLSChanSwitchRespMsg                halTdlsChanSwitchRespMsg;
+  WDI_SetTdlsChanSwitchReqResp          wdiSetTdlsChanSwitchReqResp;
+
+  /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+  /*-------------------------------------------------------------------------
+    Sanity check
+  -------------------------------------------------------------------------*/
+  if (( NULL == pWDICtx ) || ( NULL == pEventData ) ||
+      ( NULL == pEventData->pEventData))
+  {
+     WPAL_TRACE( eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_WARN,
+                 "%s: Invalid parameters", __func__);
+     WDI_ASSERT(0);
+     return WDI_STATUS_E_FAILURE;
+  }
+
+  /*-------------------------------------------------------------------------
+  Extract indication and send it to UMAC
+ -------------------------------------------------------------------------*/
+  wpalMemoryCopy( &halTdlsChanSwitchRespMsg.tdlsChanSwitchRespParams,
+                  pEventData->pEventData,
+                  sizeof(halTdlsChanSwitchRespMsg.tdlsChanSwitchRespParams) );
+
+  wdiTDLSChanSwitchReqParamsRspCb = (WDI_SetTDLSChanSwitchReqParamsRspCb)pWDICtx->pfncRspCB;
+
+  /*-------------------------------------------------------------------------
+    Extract response and send it to UMAC
+  -------------------------------------------------------------------------*/
+  wpalMemoryCopy( &halStatus,
+                  pEventData->pEventData,
+                  sizeof(halStatus));
+
+  wdiSetTdlsChanSwitchReqResp.wdiStatus   =   WDI_HAL_2_WDI_STATUS(halStatus);
+  wdiSetTdlsChanSwitchReqResp.uStaIdx   =  halTdlsChanSwitchRespMsg.tdlsChanSwitchRespParams.staIdx;
+
+  /*Notify UMAC*/
+  wdiTDLSChanSwitchReqParamsRspCb( &wdiSetTdlsChanSwitchReqResp, pWDICtx->pRspCBUserData );
+
+  return WDI_STATUS_SUCCESS;
+}/*WDI_ProcessChanSwitchReqRsp*/
+
+
+
 #endif
 
 /**
@@ -23440,6 +23659,8 @@
 #ifdef FEATURE_WLAN_TDLS
   case WDI_TDLS_LINK_ESTABLISH_REQ:
     return WLAN_HAL_TDLS_LINK_ESTABLISHED_REQ;
+  case WDI_TDLS_CHAN_SWITCH_REQ:
+    return WLAN_HAL_TDLS_CHAN_SWITCH_REQ;
 #endif
   case WDI_ENTER_IMPS_REQ:
     return WLAN_HAL_ENTER_IMPS_REQ;
@@ -23735,6 +23956,8 @@
 #ifdef FEATURE_WLAN_TDLS
   case WLAN_HAL_TDLS_LINK_ESTABLISHED_RSP:
     return WDI_TDLS_LINK_ESTABLISH_REQ_RESP;
+  case WLAN_HAL_TDLS_CHAN_SWITCH_RSP:
+    return WDI_TDLS_CHAN_SWITCH_REQ_RESP;
   case WLAN_HAL_TDLS_IND:
     return WDI_HAL_TDLS_IND;
 #endif
@@ -30301,6 +30524,7 @@
 
   return WDI_STATUS_SUCCESS;
 }
+
 #endif /* FEATURE_WLAN_CH_AVOID */
 
 /**