qcacld-3.0: IPv6 packets classification support

Enable classification of IPv6 frames based on the
traffic class field in the IPv6 header.

Change-Id: I4114cb972f61b75da35a225c07f7628d748a744c
CRs-Fixed: 921955
This commit is contained in:
Govind Singh 2015-10-08 16:38:37 +05:30 • committed by Prakash Dhavali
commit b7ab577111
3 changed files with 101 additions and 166 deletions

View file

@ -684,11 +684,6 @@ typedef enum {
#define CFG_ROAM_SCAN_OFFLOAD_ENABLED_MAX (1)
#define CFG_ROAM_SCAN_OFFLOAD_ENABLED_DEFAULT (1)
#define CFG_QOS_WMM_PKT_CLASSIFY_BASIS_NAME "PktClassificationBasis" /* DSCP or 802.1Q */
#define CFG_QOS_WMM_PKT_CLASSIFY_BASIS_MIN (0)
#define CFG_QOS_WMM_PKT_CLASSIFY_BASIS_MAX (1)
#define CFG_QOS_WMM_PKT_CLASSIFY_BASIS_DEFAULT (0) /* DSCP */
/* default TSPEC parameters for AC_VO */
#define CFG_QOS_WMM_INFRA_DIR_AC_VO_NAME "InfraDirAcVo"
#define CFG_QOS_WMM_INFRA_DIR_AC_VO_MIN (0)
@ -2918,7 +2913,6 @@ struct hdd_config {
bool isOkcIniFeatureEnabled;
#endif
bool isRoamOffloadScanEnabled;
hdd_wmm_classification_t PktClassificationBasis; /* DSCP or 802.1Q */
bool bImplicitQosEnabled;
/* default TSPEC parameters for AC_VO */

View file

@ -1095,12 +1095,6 @@ REG_TABLE_ENTRY g_registry_table[] = {
CFG_ROAM_SCAN_OFFLOAD_ENABLED_MIN,
CFG_ROAM_SCAN_OFFLOAD_ENABLED_MAX,
cb_notify_update_roam_scan_offload_enabled, 0),
REG_VARIABLE(CFG_QOS_WMM_PKT_CLASSIFY_BASIS_NAME, WLAN_PARAM_Integer,
struct hdd_config, PktClassificationBasis,
VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
CFG_QOS_WMM_PKT_CLASSIFY_BASIS_DEFAULT,
CFG_QOS_WMM_PKT_CLASSIFY_BASIS_MIN,
CFG_QOS_WMM_PKT_CLASSIFY_BASIS_MAX),
REG_VARIABLE(CFG_QOS_WMM_INFRA_DIR_AC_VO_NAME, WLAN_PARAM_Integer,
struct hdd_config, InfraDirAcVo,
@ -4472,9 +4466,6 @@ void hdd_cfg_print(hdd_context_t *pHddCtx)
CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH,
"Name = [UapsdMask] Value = [0x%x] ",
pHddCtx->config->UapsdMask);
CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH,
"Name = [PktClassificationBasis] Value = [%u] ",
pHddCtx->config->PktClassificationBasis);
CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH,
"Name = [ImplicitQosIsEnabled] Value = [%u]",
(int)pHddCtx->config->bImplicitQosEnabled);

View file

@ -54,6 +54,7 @@
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/semaphore.h>
#include <linux/ipv6.h>
#include <wlan_hdd_tx_rx.h>
#include <wlan_hdd_wmm.h>
#include <wlan_hdd_ether.h>
@ -1548,29 +1549,27 @@ CDF_STATUS hdd_wmm_adapter_close(hdd_adapter_t *pAdapter)
/**
* hdd_wmm_classify_pkt() - Function which will classify an OS packet
* into a WMM AC based on either 802.1Q or DSCP
* into a WMM AC based on DSCP
*
* @pAdapter: [in] adapter upon which the packet is being transmitted
* @skb: [in] the actual OS packet (sk_buff) being transmitted
* @pAcType: [out] WMM AC type of the OS packet
* @pUserPri: [out] User Priority of the OS packet
* @adapter: adapter upon which the packet is being transmitted
* @skb: pointer to network buffer
* @user_pri: user priority of the OS packet
* @is_eapol: eapol packet flag
*
* Return: None
*/
static
void hdd_wmm_classify_pkt(hdd_adapter_t *pAdapter,
void hdd_wmm_classify_pkt(hdd_adapter_t *adapter,
struct sk_buff *skb,
sme_ac_enum_type *pAcType,
sme_QosWmmUpType *pUserPri,
sme_QosWmmUpType *user_pri,
bool *is_eapol)
{
unsigned char *pPkt;
union generic_ethhdr *pHdr;
struct iphdr *pIpHdr;
unsigned char tos;
unsigned char dscp;
sme_QosWmmUpType userPri;
sme_ac_enum_type acType;
unsigned char tos;
union generic_ethhdr *eth_hdr;
struct iphdr *ip_hdr;
struct ipv6hdr *ipv6hdr;
unsigned char *pkt;
/* this code is executed for every packet therefore
* all debug code is kept conditional
@ -1581,158 +1580,118 @@ void hdd_wmm_classify_pkt(hdd_adapter_t *pAdapter,
"%s: Entered", __func__);
#endif /* HDD_WMM_DEBUG */
pPkt = skb->data;
pHdr = (union generic_ethhdr *)pPkt;
pkt = skb->data;
eth_hdr = (union generic_ethhdr *)pkt;
#ifdef HDD_WMM_DEBUG
CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
"%s: proto/length is 0x%04x", __func__, pHdr->eth_II.h_proto);
"%s: proto is 0x%04x", __func__, skb->protocol);
#endif /* HDD_WMM_DEBUG */
if (HDD_WMM_CLASSIFICATION_DSCP ==
(WLAN_HDD_GET_CTX(pAdapter))->config->PktClassificationBasis) {
if (pHdr->eth_II.h_proto == htons(ETH_P_IP)) {
/* case 1: Ethernet II IP packet */
pIpHdr = (struct iphdr *)&pPkt[sizeof(pHdr->eth_II)];
tos = pIpHdr->tos;
if (eth_hdr->eth_II.h_proto == htons(ETH_P_IP)) {
/* case 1: Ethernet II IP packet */
ip_hdr = (struct iphdr *)&pkt[sizeof(eth_hdr->eth_II)];
tos = ip_hdr->tos;
#ifdef HDD_WMM_DEBUG
CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
"%s: Ethernet II IP Packet, tos is %d",
__func__, tos);
CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
"%s: Ethernet II IP Packet, tos is %d",
__func__, tos);
#endif /* HDD_WMM_DEBUG */
} else if ((ntohs(pHdr->eth_II.h_proto) < WLAN_MIN_PROTO) &&
(pHdr->eth_8023.h_snap.dsap == WLAN_SNAP_DSAP) &&
(pHdr->eth_8023.h_snap.ssap == WLAN_SNAP_SSAP) &&
(pHdr->eth_8023.h_snap.ctrl == WLAN_SNAP_CTRL) &&
(pHdr->eth_8023.h_proto == htons(ETH_P_IP))) {
/* case 2: 802.3 LLC/SNAP IP packet */
pIpHdr = (struct iphdr *)&pPkt[sizeof(pHdr->eth_8023)];
tos = pIpHdr->tos;
} else if (eth_hdr->eth_II.h_proto == htons(ETH_P_IPV6)) {
ipv6hdr = ipv6_hdr(skb);
tos = ntohs(*(const __be16 *)ipv6hdr) >> 4;
#ifdef HDD_WMM_DEBUG
CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
"%s: 802.3 LLC/SNAP IP Packet, tos is %d",
__func__, tos);
CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
"%s: Ethernet II IPv6 Packet, tos is %d",
__func__, tos);
#endif /* HDD_WMM_DEBUG */
} else if (pHdr->eth_II.h_proto == htons(ETH_P_8021Q)) {
/* VLAN tagged */
} else if ((ntohs(eth_hdr->eth_II.h_proto) < WLAN_MIN_PROTO) &&
(eth_hdr->eth_8023.h_snap.dsap == WLAN_SNAP_DSAP) &&
(eth_hdr->eth_8023.h_snap.ssap == WLAN_SNAP_SSAP) &&
(eth_hdr->eth_8023.h_snap.ctrl == WLAN_SNAP_CTRL) &&
(eth_hdr->eth_8023.h_proto == htons(ETH_P_IP))) {
/* case 2: 802.3 LLC/SNAP IP packet */
ip_hdr = (struct iphdr *)&pkt[sizeof(eth_hdr->eth_8023)];
tos = ip_hdr->tos;
#ifdef HDD_WMM_DEBUG
CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
"%s: 802.3 LLC/SNAP IP Packet, tos is %d",
__func__, tos);
#endif /* HDD_WMM_DEBUG */
} else if (eth_hdr->eth_II.h_proto == htons(ETH_P_8021Q)) {
/* VLAN tagged */
if (pHdr->eth_IIv.h_vlan_encapsulated_proto ==
htons(ETH_P_IP)) {
/* case 3: Ethernet II vlan-tagged IP packet */
pIpHdr =
(struct iphdr *)
&pPkt[sizeof(pHdr->eth_IIv)];
tos = pIpHdr->tos;
if (eth_hdr->eth_IIv.h_vlan_encapsulated_proto ==
htons(ETH_P_IP)) {
/* case 3: Ethernet II vlan-tagged IP packet */
ip_hdr =
(struct iphdr *)
&pkt[sizeof(eth_hdr->eth_IIv)];
tos = ip_hdr->tos;
#ifdef HDD_WMM_DEBUG
CDF_TRACE(CDF_MODULE_ID_HDD,
WMM_TRACE_LEVEL_INFO_LOW,
"%s: Ethernet II VLAN tagged IP Packet, tos is %d",
__func__, tos);
CDF_TRACE(CDF_MODULE_ID_HDD,
WMM_TRACE_LEVEL_INFO_LOW,
"%s: Ethernet II VLAN tagged IP Packet, tos is %d",
__func__, tos);
#endif /* HDD_WMM_DEBUG */
} else
if ((ntohs(pHdr->eth_IIv.h_vlan_encapsulated_proto)
< WLAN_MIN_PROTO)
&& (pHdr->eth_8023v.h_snap.dsap ==
WLAN_SNAP_DSAP)
&& (pHdr->eth_8023v.h_snap.ssap ==
WLAN_SNAP_SSAP)
&& (pHdr->eth_8023v.h_snap.ctrl ==
WLAN_SNAP_CTRL)
&& (pHdr->eth_8023v.h_proto ==
htons(ETH_P_IP))) {
/* case 4: 802.3 LLC/SNAP vlan-tagged IP packet */
pIpHdr =
(struct iphdr *)
&pPkt[sizeof(pHdr->eth_8023v)];
tos = pIpHdr->tos;
} else
if ((ntohs(eth_hdr->eth_IIv.h_vlan_encapsulated_proto)
< WLAN_MIN_PROTO)
&& (eth_hdr->eth_8023v.h_snap.dsap ==
WLAN_SNAP_DSAP)
&& (eth_hdr->eth_8023v.h_snap.ssap ==
WLAN_SNAP_SSAP)
&& (eth_hdr->eth_8023v.h_snap.ctrl ==
WLAN_SNAP_CTRL)
&& (eth_hdr->eth_8023v.h_proto ==
htons(ETH_P_IP))) {
/* case 4: 802.3 LLC/SNAP vlan-tagged IP packet */
ip_hdr =
(struct iphdr *)
&pkt[sizeof(eth_hdr->eth_8023v)];
tos = ip_hdr->tos;
#ifdef HDD_WMM_DEBUG
CDF_TRACE(CDF_MODULE_ID_HDD,
WMM_TRACE_LEVEL_INFO_LOW,
"%s: 802.3 LLC/SNAP VLAN tagged IP Packet, tos is %d",
__func__, tos);
CDF_TRACE(CDF_MODULE_ID_HDD,
WMM_TRACE_LEVEL_INFO_LOW,
"%s: 802.3 LLC/SNAP VLAN tagged IP Packet, tos is %d",
__func__, tos);
#endif /* HDD_WMM_DEBUG */
} else {
/* default */
#ifdef HDD_WMM_DEBUG
CDF_TRACE(CDF_MODULE_ID_HDD,
WMM_TRACE_LEVEL_WARN,
"%s: VLAN tagged Unhandled Protocol, using default tos",
__func__);
#endif /* HDD_WMM_DEBUG */
tos = 0;
}
} else {
/* default */
#ifdef HDD_WMM_DEBUG
CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_WARN,
"%s: Unhandled Protocol, using default tos",
__func__);
CDF_TRACE(CDF_MODULE_ID_HDD,
WMM_TRACE_LEVEL_WARN,
"%s: VLAN tagged Unhandled Protocol, using default tos",
__func__);
#endif /* HDD_WMM_DEBUG */
/* Give the highest priority to 802.1x packet */
if (pHdr->eth_II.h_proto ==
htons(HDD_ETHERTYPE_802_1_X)) {
tos = 0xC0;
*is_eapol = true;
} else
tos = 0;
}
dscp = (tos >> 2) & 0x3f;
userPri = pAdapter->hddWmmDscpToUpMap[dscp];
#ifdef HDD_WMM_DEBUG
CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
"%s: tos is %d, dscp is %d, up is %d",
__func__, tos, dscp, userPri);
#endif /* HDD_WMM_DEBUG */
} else if (HDD_WMM_CLASSIFICATION_802_1Q ==
(WLAN_HDD_GET_CTX(pAdapter))->config->
PktClassificationBasis) {
if (pHdr->eth_IIv.h_vlan_proto == htons(ETH_P_8021Q)) {
/* VLAN tagged */
userPri = (ntohs(pHdr->eth_IIv.h_vlan_TCI) >> 13) & 0x7;
#ifdef HDD_WMM_DEBUG
CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
"%s: Tagged frame, UP is %d",
__func__, userPri);
#endif /* HDD_WMM_DEBUG */
} else {
/* not VLAN tagged, use default */
#ifdef HDD_WMM_DEBUG
CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_WARN,
"%s: Untagged frame, using default UP",
__func__);
#endif /* HDD_WMM_DEBUG */
/* Give the highest priority to 802.1x packet */
if (pHdr->eth_II.h_proto ==
htons(HDD_ETHERTYPE_802_1_X)) {
userPri = SME_QOS_WMM_UP_VO;
*is_eapol = true;
} else
userPri = SME_QOS_WMM_UP_BE;
tos = 0;
}
} else {
/* default */
#ifdef HDD_WMM_DEBUG
CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
"%s: Unknown classification scheme, using default UP",
__func__);
CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_WARN,
"%s: Unhandled Protocol, using default tos",
__func__);
#endif /* HDD_WMM_DEBUG */
userPri = SME_QOS_WMM_UP_BE;
/* Give the highest priority to 802.1x packet */
if (eth_hdr->eth_II.h_proto ==
htons(HDD_ETHERTYPE_802_1_X)) {
tos = 0xC0;
*is_eapol = true;
} else
tos = 0;
}
acType = hdd_wmm_up_to_ac_map[userPri];
dscp = (tos >> 2) & 0x3f;
*user_pri = adapter->hddWmmDscpToUpMap[dscp];
#ifdef HDD_WMM_DEBUG
CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
"%s: UP is %d, AC is %d", __func__, userPri, acType);
"%s: tos is %d, dscp is %d, up is %d",
__func__, tos, dscp, *user_pri);
#endif /* HDD_WMM_DEBUG */
*pUserPri = userPri;
*pAcType = acType;
return;
}
@ -1780,25 +1739,21 @@ uint16_t hdd_hostapd_select_queue(struct net_device *dev, struct sk_buff *skb
)
{
sme_ac_enum_type ac;
sme_QosWmmUpType up = SME_QOS_WMM_UP_BE;
uint16_t queueIndex;
hdd_adapter_t *pAdapter = (hdd_adapter_t *) netdev_priv(dev);
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
hdd_adapter_t *adapter = (hdd_adapter_t *) netdev_priv(dev);
hdd_context_t *hddctx = WLAN_HDD_GET_CTX(adapter);
bool is_eapol = false;
int status = 0;
status = wlan_hdd_validate_context(pHddCtx);
status = wlan_hdd_validate_context(hddctx);
if (status != 0) {
skb->priority = SME_QOS_WMM_UP_BE;
return HDD_LINUX_AC_BE;
}
if (HDD_WMM_USER_MODE_NO_QOS != pHddCtx->config->WmmMode) {
/* Get the user priority from IP header & corresponding AC */
hdd_wmm_classify_pkt(pAdapter, skb, &ac, &up, &is_eapol);
}
/* Get the user priority from IP header */
hdd_wmm_classify_pkt(adapter, skb, &up, &is_eapol);
skb->priority = up;
queueIndex = hdd_get_queue_index(skb->priority, is_eapol);
@ -1816,7 +1771,6 @@ uint16_t hdd_hostapd_select_queue(struct net_device *dev, struct sk_buff *skb
*/
uint16_t hdd_wmm_select_queue(struct net_device *dev, struct sk_buff *skb)
{
sme_ac_enum_type ac;
sme_QosWmmUpType up = SME_QOS_WMM_UP_BE;
uint16_t queueIndex;
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
@ -1830,15 +1784,11 @@ uint16_t hdd_wmm_select_queue(struct net_device *dev, struct sk_buff *skb)
return HDD_LINUX_AC_BE;
}
/* if we don't want QoS or the AP doesn't support Qos */
/* All traffic will get equal opportuniy to transmit data frames. */
if (hdd_wmm_is_active(pAdapter)) {
/* Get the user priority from IP header & corresponding AC */
hdd_wmm_classify_pkt(pAdapter, skb, &ac, &up, &is_eapol);
}
/* Get the user priority from IP header */
hdd_wmm_classify_pkt(pAdapter, skb, &up, &is_eapol);
skb->priority = up;
queueIndex = hdd_get_queue_index(skb->priority, is_eapol);
return queueIndex;
}