diff --git a/components/nan/core/src/nan_main.c b/components/nan/core/src/nan_main.c index b657f0504f92..4b7a7141d184 100644 --- a/components/nan/core/src/nan_main.c +++ b/components/nan/core/src/nan_main.c @@ -292,8 +292,10 @@ QDF_STATUS nan_scheduled_msg_handler(struct scheduler_msg *msg) return QDF_STATUS_SUCCESS; } -static QDF_STATUS nan_increment_ndp_sessions(struct wlan_objmgr_psoc *psoc, - struct qdf_mac_addr *peer_ndi_mac) +static QDF_STATUS +nan_increment_ndp_sessions(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_ndi_mac, + struct nan_datapath_channel_info *ndp_chan_info) { struct wlan_objmgr_peer *peer; struct nan_peer_priv_obj *peer_nan_obj; @@ -322,6 +324,12 @@ static QDF_STATUS nan_increment_ndp_sessions(struct wlan_objmgr_psoc *psoc, wlan_objmgr_peer_release_ref(peer, WLAN_NAN_ID); return QDF_STATUS_E_FAILURE; } + /* + * Store the first channel info in NDP Confirm as the home channel info + * and store it in the peer private object. + */ + qdf_mem_copy(&peer_nan_obj->home_chan_info, ndp_chan_info, + sizeof(struct nan_datapath_channel_info)); peer_nan_obj->active_ndp_sessions++; qdf_spin_unlock_bh(&peer_nan_obj->lock); wlan_objmgr_peer_release_ref(peer, WLAN_NAN_ID); @@ -365,12 +373,115 @@ static QDF_STATUS nan_decrement_ndp_sessions(struct wlan_objmgr_psoc *psoc, return QDF_STATUS_SUCCESS; } +static QDF_STATUS +ndi_remove_and_update_primary_connection(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + struct nan_vdev_priv_obj *vdev_nan_obj; + struct nan_psoc_priv_obj *psoc_nan_obj; + struct nan_peer_priv_obj *peer_nan_obj = NULL; + struct wlan_objmgr_peer *peer, *peer_next; + qdf_list_t *peer_list; + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + vdev_nan_obj = nan_get_vdev_priv_obj(vdev); + + peer_list = &vdev->vdev_objmgr.wlan_peer_list; + if (!peer_list) { + nan_err("Peer list for vdev obj is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + peer = wlan_vdev_peer_list_peek_active_head(vdev, peer_list, + WLAN_NAN_ID); + + while (peer) { + peer_nan_obj = nan_get_peer_priv_obj(peer); + if (!peer_nan_obj) + nan_err("NAN peer object for Peer " QDF_MAC_ADDR_STR " is NULL", + QDF_MAC_ADDR_ARRAY(wlan_peer_get_macaddr(peer))); + else if (peer_nan_obj->active_ndp_sessions) + break; + + peer_next = wlan_peer_get_next_active_peer_of_vdev(vdev, + peer_list, + peer, + WLAN_NAN_ID); + wlan_objmgr_peer_release_ref(peer, WLAN_NAN_ID); + peer = peer_next; + } + + if (!peer && psoc_nan_obj->nan_caps.ndi_dbs_supported) { + /* TODO: Remove connection from policy manager tables */ + return QDF_STATUS_SUCCESS; + } + + if (peer_nan_obj && psoc_nan_obj->nan_caps.ndi_dbs_supported) { + /* TODO: Update NDI's primary chan info to WMA */ + /* TODO: Update policy mgr with connection info */ + qdf_mem_copy(vdev_nan_obj->primary_peer_mac.bytes, + wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE); + } + + wlan_objmgr_peer_release_ref(peer, WLAN_NAN_ID); + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +ndi_update_ndp_session(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *peer_ndi_mac, + struct nan_datapath_channel_info *ndp_chan_info) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_peer *peer; + struct nan_vdev_priv_obj *vdev_nan_obj; + struct nan_peer_priv_obj *peer_nan_obj; + + psoc = wlan_vdev_get_psoc(vdev); + + vdev_nan_obj = nan_get_vdev_priv_obj(vdev); + if (!vdev_nan_obj) { + nan_err("NAN vdev private object is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + peer = wlan_objmgr_get_peer_by_mac(psoc, + peer_ndi_mac->bytes, + WLAN_NAN_ID); + + if (!peer) { + nan_err("peer object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + peer_nan_obj = nan_get_peer_priv_obj(peer); + if (!peer_nan_obj) { + nan_err("peer_nan_obj is null"); + wlan_objmgr_peer_release_ref(peer, WLAN_NAN_ID); + return QDF_STATUS_E_NULL_VALUE; + } + + qdf_spin_lock_bh(&peer_nan_obj->lock); + qdf_mem_copy(&peer_nan_obj->home_chan_info, ndp_chan_info, + sizeof(*ndp_chan_info)); + /* TODO: Update NDI's primary chan info to WMA */ + qdf_spin_unlock_bh(&peer_nan_obj->lock); + wlan_objmgr_peer_release_ref(peer, WLAN_NAN_ID); + + if (qdf_is_macaddr_equal(&vdev_nan_obj->primary_peer_mac, + peer_ndi_mac)) { + /* TODO: Update policy mgr with connection info */ + } + return QDF_STATUS_SUCCESS; +} + static QDF_STATUS nan_handle_confirm( struct nan_datapath_confirm_event *confirm) { uint8_t vdev_id; struct wlan_objmgr_psoc *psoc; struct nan_psoc_priv_obj *psoc_nan_obj; + struct nan_vdev_priv_obj *vdev_nan_obj; vdev_id = wlan_vdev_get_id(confirm->vdev); psoc = wlan_vdev_get_psoc(confirm->vdev); @@ -385,6 +496,12 @@ static QDF_STATUS nan_handle_confirm( return QDF_STATUS_E_NULL_VALUE; } + vdev_nan_obj = nan_get_vdev_priv_obj(confirm->vdev); + if (!vdev_nan_obj) { + nan_err("vdev_nan_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + if (confirm->rsp_code != NAN_DATAPATH_RESPONSE_ACCEPT && confirm->num_active_ndps_on_peer == 0) { /* @@ -400,11 +517,33 @@ static QDF_STATUS nan_handle_confirm( /* Increment NDP sessions for the Peer */ if (confirm->rsp_code == NAN_DATAPATH_RESPONSE_ACCEPT) - nan_increment_ndp_sessions(psoc, &confirm->peer_ndi_mac_addr); + nan_increment_ndp_sessions(psoc, &confirm->peer_ndi_mac_addr, + &confirm->ch[0]); psoc_nan_obj->cb_obj.os_if_ndp_event_handler(psoc, confirm->vdev, NDP_CONFIRM, confirm); + if (confirm->rsp_code == NAN_DATAPATH_RESPONSE_ACCEPT && + vdev_nan_obj->active_ndp_peers == 1) { + /* + * If this is the NDI's first NDP, store the NDP instance in + * vdev object as its primary connection. If this instance ends + * the second NDP should take its place. + */ + qdf_mem_copy(vdev_nan_obj->primary_peer_mac.bytes, + &confirm->peer_ndi_mac_addr, QDF_MAC_ADDR_SIZE); + + /* TODO: Update primary connection info in the WMA interfaces */ + + if (psoc_nan_obj->nan_caps.ndi_dbs_supported) { + /* + * TODO: Update connection in Policy Manager if NDI + * concurrencies are supported and this is the first + * active NDP for the NDI. + */ + } + } + return QDF_STATUS_SUCCESS; } @@ -547,6 +686,8 @@ static QDF_STATUS nan_handle_end_ind( uint32_t i; struct wlan_objmgr_psoc *psoc; struct nan_psoc_priv_obj *psoc_nan_obj; + struct wlan_objmgr_vdev *vdev_itr; + struct nan_vdev_priv_obj *vdev_nan_obj; psoc = wlan_vdev_get_psoc(ind->vdev); if (!psoc) { @@ -565,6 +706,30 @@ static QDF_STATUS nan_handle_end_ind( nan_decrement_ndp_sessions(psoc, &ind->ndp_map[i].peer_ndi_mac_addr); + for (i = 0; i < ind->num_ndp_ids; i++) { + vdev_itr = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + ind->ndp_map[i].vdev_id, + WLAN_NAN_ID); + if (!vdev_itr) { + nan_err("NAN vdev object is NULL"); + continue; + } + + vdev_nan_obj = nan_get_vdev_priv_obj(vdev_itr); + if (!vdev_nan_obj) { + wlan_objmgr_vdev_release_ref(vdev_itr, WLAN_NAN_ID); + nan_err("NAN vdev private object is NULL"); + continue; + } + + if (qdf_is_macaddr_equal(&vdev_nan_obj->primary_peer_mac, + &ind->ndp_map[i].peer_ndi_mac_addr)) + ndi_remove_and_update_primary_connection(psoc, + vdev_itr); + + wlan_objmgr_vdev_release_ref(vdev_itr, WLAN_NAN_ID); + } + psoc_nan_obj->cb_obj.ndp_delete_peers(ind->ndp_map, ind->num_ndp_ids); psoc_nan_obj->cb_obj.os_if_ndp_event_handler(psoc, ind->vdev, NDP_END_IND, ind); @@ -666,6 +831,7 @@ static QDF_STATUS nan_handle_schedule_update( return QDF_STATUS_E_NULL_VALUE; } + ndi_update_ndp_session(ind->vdev, &ind->peer_addr, &ind->ch[0]); psoc_nan_obj->cb_obj.os_if_ndp_event_handler(psoc, ind->vdev, NDP_SCHEDULE_UPDATE, ind); diff --git a/components/nan/core/src/nan_main_i.h b/components/nan/core/src/nan_main_i.h index a971aa0d8d93..6ff4794ad594 100644 --- a/components/nan/core/src/nan_main_i.h +++ b/components/nan/core/src/nan_main_i.h @@ -125,6 +125,7 @@ struct nan_psoc_priv_obj { * @ndp_delete_transaction_id: transaction id for delete req * @ndi_delete_rsp_reason: reason code for ndi_delete rsp * @ndi_delete_rsp_status: status for ndi_delete rsp + * @primary_peer_mac: Primary NDP Peer mac address for the vdev */ struct nan_vdev_priv_obj { qdf_spinlock_t lock; @@ -134,16 +135,19 @@ struct nan_vdev_priv_obj { uint16_t ndp_delete_transaction_id; uint32_t ndi_delete_rsp_reason; uint32_t ndi_delete_rsp_status; + struct qdf_mac_addr primary_peer_mac; }; /** * struct nan_peer_priv_obj - nan private peer obj * @lock: lock to be acquired before reading or writing to object * @active_ndp_sessions: number of active ndp sessions for this peer + * @home_chan_info: Home channel info for the NDP associated with the Peer */ struct nan_peer_priv_obj { qdf_spinlock_t lock; uint32_t active_ndp_sessions; + struct nan_datapath_channel_info home_chan_info; }; /**