diff --git a/components/dp/core/inc/wlan_dp_priv.h b/components/dp/core/inc/wlan_dp_priv.h index d2480e7546..f351961213 100644 --- a/components/dp/core/inc/wlan_dp_priv.h +++ b/components/dp/core/inc/wlan_dp_priv.h @@ -286,6 +286,7 @@ struct link_monitoring { * @conn_info: STA connection information * @bss_state: AP BSS state * @qdf_sta_eap_frm_done_event: EAP frame event management + * @traffic_end_ind: store traffic end indication info */ struct wlan_dp_intf { struct wlan_dp_psoc_context *dp_ctx; @@ -346,6 +347,7 @@ struct wlan_dp_intf { enum bss_intf_state bss_state; qdf_event_t qdf_sta_eap_frm_done_event; + struct dp_traffic_end_indication traffic_end_ind; }; /** diff --git a/components/dp/core/src/wlan_dp_softap_txrx.c b/components/dp/core/src/wlan_dp_softap_txrx.c index 886e18ae38..0817c7cb21 100644 --- a/components/dp/core/src/wlan_dp_softap_txrx.c +++ b/components/dp/core/src/wlan_dp_softap_txrx.c @@ -520,6 +520,94 @@ static void dp_softap_config_tx_pkt_tracing(struct wlan_dp_intf *dp_intf, QDF_TX)); } +#ifdef DP_TRAFFIC_END_INDICATION +/** + * wlan_dp_traffic_end_indication_update_dscp() - Compare dscp derived from + * provided tos value with + * stored value and update if + * it's equal to special dscp + * @dp_intf: pointer to DP interface + * @tos: pointer to tos + * + * Return: True if tos is updated else False + */ +static inline bool +wlan_dp_traffic_end_indication_update_dscp(struct wlan_dp_intf *dp_intf, + uint8_t *tos) +{ + bool update; + uint8_t dscp, ecn; + + ecn = (*tos & ~QDF_NBUF_PKT_IPV4_DSCP_MASK); + dscp = (*tos & QDF_NBUF_PKT_IPV4_DSCP_MASK) >> + QDF_NBUF_PKT_IPV4_DSCP_SHIFT; + update = (dp_intf->traffic_end_ind.spl_dscp == dscp); + if (update) + *tos = ((dp_intf->traffic_end_ind.def_dscp << + QDF_NBUF_PKT_IPV4_DSCP_SHIFT) | ecn); + return update; +} + +/** + * dp_softap_inspect_traffic_end_indication_pkt() - Restore tos field for last + * packet in data stream + * @dp_intf: pointer to DP interface + * @nbuf: pointer to OS packet + * + * Return: None + */ +static inline void +dp_softap_inspect_traffic_end_indication_pkt(struct wlan_dp_intf *dp_intf, + qdf_nbuf_t nbuf) +{ + uint8_t tos, tc; + bool ret; + + if (qdf_nbuf_data_is_ipv4_pkt(qdf_nbuf_data(nbuf))) { + tos = qdf_nbuf_data_get_ipv4_tos(qdf_nbuf_data(nbuf)); + ret = wlan_dp_traffic_end_indication_update_dscp(dp_intf, &tos); + if (ret) { + qdf_nbuf_data_set_ipv4_tos(qdf_nbuf_data(nbuf), tos); + if (qdf_nbuf_is_ipv4_last_fragment(nbuf)) + QDF_NBUF_CB_GET_PACKET_TYPE(nbuf) = + QDF_NBUF_CB_PACKET_TYPE_END_INDICATION; + } + } else if (qdf_nbuf_is_ipv6_pkt(nbuf)) { + tc = qdf_nbuf_data_get_ipv6_tc(qdf_nbuf_data(nbuf)); + ret = wlan_dp_traffic_end_indication_update_dscp(dp_intf, &tc); + if (ret) { + qdf_nbuf_data_set_ipv6_tc(qdf_nbuf_data(nbuf), tc); + QDF_NBUF_CB_GET_PACKET_TYPE(nbuf) = + QDF_NBUF_CB_PACKET_TYPE_END_INDICATION; + } + } +} + +/** + * dp_softap_traffic_end_indication_enabled() - Check if traffic end indication + * is enabled or not + * @dp_intf: pointer to DP interface + * + * Return: True or False + */ +static inline bool +dp_softap_traffic_end_indication_enabled(struct wlan_dp_intf *dp_intf) +{ + return qdf_unlikely(dp_intf->traffic_end_ind.enabled); +} +#else +static inline bool +dp_softap_traffic_end_indication_enabled(struct wlan_dp_intf *dp_intf) +{ + return false; +} + +static inline void +dp_softap_inspect_traffic_end_indication_pkt(struct wlan_dp_intf *dp_intf, + qdf_nbuf_t nbuf) +{} +#endif + /** * dp_softap_start_xmit() - Transmit a frame * @nbuf: pointer to Network buffer @@ -579,6 +667,9 @@ QDF_STATUS dp_softap_start_xmit(qdf_nbuf_t nbuf, struct wlan_dp_intf *dp_intf) dp_event_eapol_log(nbuf, QDF_TX); } + if (dp_softap_traffic_end_indication_enabled(dp_intf)) + dp_softap_inspect_traffic_end_indication_pkt(dp_intf, nbuf); + dp_softap_config_tx_pkt_tracing(dp_intf, nbuf); /* check whether need to linearize skb, like non-linear udp data */ diff --git a/components/dp/dispatcher/inc/wlan_dp_public_struct.h b/components/dp/dispatcher/inc/wlan_dp_public_struct.h index aad68b3113..61f30eb856 100644 --- a/components/dp/dispatcher/inc/wlan_dp_public_struct.h +++ b/components/dp/dispatcher/inc/wlan_dp_public_struct.h @@ -720,4 +720,16 @@ struct wlan_dp_user_config { uint32_t arp_connectivity_map; }; +/** + * struct dp_traffic_end_indication - Trafic end indication + * @enabled: Feature enabled/disabled config + * @def_dscp: Default DSCP value in regular packets in traffic + * @spl_dscp: Special DSCP value to be used by packet to mark + * end of data stream + */ +struct dp_traffic_end_indication { + bool enabled; + uint8_t def_dscp; + uint8_t spl_dscp; +}; #endif /* end of _WLAN_DP_PUBLIC_STRUCT_H_ */ diff --git a/components/dp/dispatcher/inc/wlan_dp_ucfg_api.h b/components/dp/dispatcher/inc/wlan_dp_ucfg_api.h index f29e478555..841a64fa24 100644 --- a/components/dp/dispatcher/inc/wlan_dp_ucfg_api.h +++ b/components/dp/dispatcher/inc/wlan_dp_ucfg_api.h @@ -1231,4 +1231,59 @@ dp_ucfg_enable_link_monitoring(struct wlan_objmgr_psoc *psoc, void dp_ucfg_disable_link_monitoring(struct wlan_objmgr_psoc *psoc, struct wlan_objmgr_vdev *vdev); + +#ifdef DP_TRAFFIC_END_INDICATION +/** + * ucfg_dp_traffic_end_indication_get() - Get data end indication info + * @vdev: vdev handle + * @info: variable to hold stored data end indication info + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_dp_traffic_end_indication_get(struct wlan_objmgr_vdev *vdev, + struct dp_traffic_end_indication *info); +/** + * ucfg_dp_traffic_end_indication_set() - Store data end indication info + * @vdev: vdev handle + * @info: variable holding new data end indication info + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_dp_traffic_end_indication_set(struct wlan_objmgr_vdev *vdev, + struct dp_traffic_end_indication info); +/** + * ucfg_dp_traffic_end_indication_update_dscp() - update dscp value to default + * @psoc: psoc handle + * @vdev_id: vdev id + * @dscp: dscp value to be updated + * + * Return: void + */ +void +ucfg_dp_traffic_end_indication_update_dscp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + unsigned char *dscp); +#else +static inline QDF_STATUS +ucfg_dp_traffic_end_indication_get(struct wlan_objmgr_vdev *vdev, + struct dp_traffic_end_indication *info) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_dp_traffic_end_indication_set(struct wlan_objmgr_vdev *vdev, + struct dp_traffic_end_indication info) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +ucfg_dp_traffic_end_indication_update_dscp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + unsigned char *dscp) +{} +#endif #endif /* _WLAN_DP_UCFG_API_H_ */ diff --git a/components/dp/dispatcher/src/wlan_dp_ucfg_api.c b/components/dp/dispatcher/src/wlan_dp_ucfg_api.c index 6159365c28..3b8e16fb96 100644 --- a/components/dp/dispatcher/src/wlan_dp_ucfg_api.c +++ b/components/dp/dispatcher/src/wlan_dp_ucfg_api.c @@ -35,6 +35,7 @@ #include "wlan_dp_txrx.h" #include "wlan_nlink_common.h" #include "wlan_pkt_capture_ucfg_api.h" +#include void ucfg_dp_update_inf_mac(struct wlan_objmgr_psoc *psoc, struct qdf_mac_addr *cur_mac, @@ -2185,3 +2186,78 @@ dp_ucfg_disable_link_monitoring(struct wlan_objmgr_psoc *psoc, dp_intf->link_monitoring.enabled = false; dp_intf->link_monitoring.rx_linkspeed_threshold = 0; } + +#ifdef DP_TRAFFIC_END_INDICATION +QDF_STATUS +ucfg_dp_traffic_end_indication_get(struct wlan_objmgr_vdev *vdev, + struct dp_traffic_end_indication *info) +{ + struct wlan_dp_intf *dp_intf = dp_get_vdev_priv_obj(vdev); + + if (!dp_intf) { + dp_err("Unable to get DP interface"); + return QDF_STATUS_E_INVAL; + } + + info->enabled = dp_intf->traffic_end_ind.enabled; + info->def_dscp = dp_intf->traffic_end_ind.def_dscp; + info->spl_dscp = dp_intf->traffic_end_ind.spl_dscp; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_dp_traffic_end_indication_set(struct wlan_objmgr_vdev *vdev, + struct dp_traffic_end_indication info) +{ + struct wlan_dp_intf *dp_intf = dp_get_vdev_priv_obj(vdev); + cdp_config_param_type vdev_param; + + if (!dp_intf) { + dp_err("Unable to get DP interface"); + return QDF_STATUS_E_INVAL; + } + + dp_intf->traffic_end_ind = info; + + dp_debug("enabled:%u default dscp:%u special dscp:%u", + dp_intf->traffic_end_ind.enabled, + dp_intf->traffic_end_ind.def_dscp, + dp_intf->traffic_end_ind.spl_dscp); + + vdev_param.cdp_vdev_param_traffic_end_ind = info.enabled; + if (cdp_txrx_set_vdev_param(cds_get_context(QDF_MODULE_ID_SOC), + dp_intf->intf_id, + CDP_ENABLE_TRAFFIC_END_INDICATION, + vdev_param)) + dp_err("Failed to set traffic end indication param on DP vdev"); + + return QDF_STATUS_SUCCESS; +} + +void ucfg_dp_traffic_end_indication_update_dscp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + unsigned char *dscp) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_dp_intf *dp_intf; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_DP_ID); + if (vdev) { + dp_intf = dp_get_vdev_priv_obj(vdev); + + if (!dp_intf) { + dp_err("Unable to get DP interface"); + goto end; + } + + if (!dp_intf->traffic_end_ind.enabled) + goto end; + + if (*dscp == dp_intf->traffic_end_ind.spl_dscp) + *dscp = dp_intf->traffic_end_ind.def_dscp; +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_DP_ID); + } +} +#endif diff --git a/core/hdd/src/wlan_hdd_wmm.c b/core/hdd/src/wlan_hdd_wmm.c index 069e7bc76c..0447b2df36 100644 --- a/core/hdd/src/wlan_hdd_wmm.c +++ b/core/hdd/src/wlan_hdd_wmm.c @@ -60,6 +60,7 @@ #include "cfg_ucfg_api.h" #include "wlan_hdd_object_manager.h" #include "wlan_hdd_cm_api.h" +#include "wlan_dp_ucfg_api.h" #define HDD_WMM_UP_TO_AC_MAP_SIZE 8 #define DSCP(x) x @@ -1855,6 +1856,27 @@ void hdd_wmm_classify_critical_pkt(struct sk_buff *skb, } } +#ifdef DP_TRAFFIC_END_INDICATION +/** + * hdd_wmm_traffic_end_indication_is_enable() - Get feature enable/disable + * status + * @adapter: hdd adapter handle + * + * Return: true if feature is enable else false + */ +static inline bool +hdd_wmm_traffic_end_indication_is_enable(struct hdd_adapter *adapter) +{ + return qdf_unlikely(adapter->traffic_end_ind_en); +} +#else +static inline bool +hdd_wmm_traffic_end_indication_is_enable(struct hdd_adapter *adapter) +{ + return false; +} +#endif + static void hdd_wmm_get_user_priority_from_ip_tos(struct hdd_adapter *adapter, struct sk_buff *skb, @@ -1867,6 +1889,7 @@ void hdd_wmm_get_user_priority_from_ip_tos(struct hdd_adapter *adapter, struct iphdr *ip_hdr; struct ipv6hdr *ipv6hdr; unsigned char *pkt; + struct wlan_objmgr_psoc *psoc; /* this code is executed for every packet therefore * all debug code is kept conditional @@ -1962,6 +1985,12 @@ void hdd_wmm_get_user_priority_from_ip_tos(struct hdd_adapter *adapter, } dscp = (tos >> 2) & 0x3f; + if (hdd_wmm_traffic_end_indication_is_enable(adapter)) { + psoc = adapter->hdd_ctx->psoc; + ucfg_dp_traffic_end_indication_update_dscp(psoc, + adapter->vdev_id, + &dscp); + } *user_pri = adapter->dscp_to_up_map[dscp]; #ifdef HDD_WMM_DEBUG