summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhaoyang Liu <zhaoyang@codeaurora.org>2017-11-15 15:41:09 +0800
committersnandini <snandini@codeaurora.org>2017-12-15 03:27:20 -0800
commitb5620fbe6c675bb540fee7586d689ca14a6f312b (patch)
treedd94e90bbd00f8301c40202683e242d177bd8d59
parentd3adcf575b12462c7ddf8a5c8436cf4c9a9828a9 (diff)
qcacld-2.0: IEEE802.11p IPv4/IPv6 RAW mode support
IEEE802.11P DSRC OCB RAW mode need support Data traffic through IPv4/IPv6 network stack. TX skb packet is started with 802.3 header, It is required to convert header structure to IEEE802.11 data header and EPD header. EPD header is two bytes in length, which indictates to ether type. Vice versa for RX data packets. Change-Id: Id07d2ac94f49a92ca5bd852ea422c627e7ae96da CRs-Fixed: 2143802
-rw-r--r--CORE/CLD_TXRX/TXRX/ol_rx.c61
-rw-r--r--CORE/CLD_TXRX/TXRX/ol_tx.c75
-rw-r--r--CORE/CLD_TXRX/TXRX/ol_txrx_types.h3
-rw-r--r--CORE/HDD/src/wlan_hdd_ocb.c15
-rw-r--r--CORE/MAC/inc/sirApi.h5
-rw-r--r--CORE/SERVICES/COMMON/if_upperproto.h6
-rw-r--r--CORE/SERVICES/WMA/wma_ocb.c2
7 files changed, 165 insertions, 2 deletions
diff --git a/CORE/CLD_TXRX/TXRX/ol_rx.c b/CORE/CLD_TXRX/TXRX/ol_rx.c
index 6e8ced2cd9ac..150c109fa204 100644
--- a/CORE/CLD_TXRX/TXRX/ol_rx.c
+++ b/CORE/CLD_TXRX/TXRX/ol_rx.c
@@ -1023,6 +1023,47 @@ static inline void ol_rx_timestamp(ol_pdev_handle pdev,
}
#endif
+/**
+ * ol_convert_ieee80211_to_8023() - handle data header transition.
+ * @msdu - Received packet.
+ *
+ * This function try to convert the IEEE80211 data frame to 802.3 frame.
+ * When DSRC OCB interface works in RAW mode, driver received data frame
+ * started with IEEE802.11 header, before this packet is delivered to
+ * network stack, it is needed to do transition. But for QCOM specific
+ * frame, this function do nothing change.
+ */
+static A_STATUS ol_convert_ieee80211_to_8023(adf_nbuf_t msdu)
+{
+ int hdr_size;
+ uint16_t epd_hdr_type;
+ struct ether_header eth_hdr;
+ struct ieee80211_frame *wh;
+
+ wh = (struct ieee80211_frame *)adf_nbuf_data(msdu);
+ if (!IEEE80211_IS_DATA(wh))
+ return A_ERROR;
+
+ hdr_size = ol_txrx_ieee80211_hdrsize(wh);
+ if (adf_nbuf_len(msdu) < (hdr_size + sizeof(epd_hdr_type)))
+ return A_ERROR;
+
+ epd_hdr_type = *(uint16_t *)(adf_nbuf_data(msdu) + hdr_size);
+ if (epd_hdr_type == adf_os_htons(ETHERTYPE_WSMP))
+ return A_ENOTSUP;
+
+ adf_os_mem_zero(&eth_hdr, sizeof(struct ether_header));
+ adf_os_mem_copy(eth_hdr.ether_dhost, wh->i_addr1, IEEE80211_ADDR_LEN);
+ adf_os_mem_copy(eth_hdr.ether_shost, wh->i_addr2, IEEE80211_ADDR_LEN);
+ eth_hdr.ether_type = epd_hdr_type;
+
+ adf_nbuf_pull_head(msdu, hdr_size + sizeof(epd_hdr_type));
+ adf_nbuf_push_head(msdu, sizeof(eth_hdr));
+ adf_os_mem_copy(adf_nbuf_data(msdu), &eth_hdr, sizeof(eth_hdr));
+
+ return A_OK;
+}
+
void
ol_rx_deliver(
struct ol_txrx_vdev_t *vdev,
@@ -1111,13 +1152,31 @@ DONE:
int i;
struct ol_txrx_ocb_chan_info *chan_info = 0;
int packet_freq = peer->last_pkt_center_freq;
+ bool need_rx_stats_hdr = false;
+
for (i = 0; i < vdev->ocb_channel_count; i++) {
if (vdev->ocb_channel_info[i].chan_freq == packet_freq) {
chan_info = &vdev->ocb_channel_info[i];
break;
}
}
- if (!chan_info || !chan_info->disable_rx_stats_hdr) {
+
+ if (NULL != chan_info)
+ need_rx_stats_hdr = !chan_info->disable_rx_stats_hdr;
+
+ if (vdev->ocb_config_flags & OCB_CONFIG_FLAG_80211_FRAME_MODE) {
+ /*
+ * When DSRC OCB interface works in raw mode,
+ * and received packets started with 802.11 data header,
+ * it is required to driver convert the header to
+ * 802.3 header, except specific WSMP data frame.
+ */
+ A_STATUS status = ol_convert_ieee80211_to_8023(msdu);
+ if (A_SUCCESS(status))
+ need_rx_stats_hdr = false;
+ }
+
+ if (need_rx_stats_hdr) {
struct ether_header eth_header = { {0} };
struct ocb_rx_stats_hdr_t rx_header = {0};
diff --git a/CORE/CLD_TXRX/TXRX/ol_tx.c b/CORE/CLD_TXRX/TXRX/ol_tx.c
index db91763d7213..b8169c0537b9 100644
--- a/CORE/CLD_TXRX/TXRX/ol_tx.c
+++ b/CORE/CLD_TXRX/TXRX/ol_tx.c
@@ -1111,6 +1111,70 @@ ol_tx_drop_list_add(adf_nbuf_t *list, adf_nbuf_t msdu, adf_nbuf_t *tail)
*tail = msdu;
}
+/**
+ * ol_build_ieee80211_header() - Build IEEE80211 DATA header from 802.3
+ * @msdu: the msdu buffer to be transmitted.
+ *
+ * This function is used to convert MSDU packet from 802.3 Header to
+ * IEEE802.11 Header + EPD Header. Only used in 802.11p DSRC OCB RAW mode.
+ * EPD header is 2 bytes, indicates the ether_type, larger than 0x600.
+ * OCB configuration Command has already indicated current working mode.
+ */
+static A_STATUS ol_build_ieee80211_header(adf_nbuf_t msdu)
+{
+ int need_hdr_len;
+ uint16_t epd_hdr_type;
+ static uint16_t seq_num = 0;
+ struct ether_header *eth_hdr_p;
+ struct ieee80211_qosframe hdr;
+
+ eth_hdr_p = (struct ether_header *)adf_nbuf_data(msdu);
+ epd_hdr_type = eth_hdr_p->ether_type;
+
+ adf_os_mem_zero(&hdr, sizeof(struct ieee80211_qosframe));
+ hdr.i_fc[0] |= IEEE80211_FC0_VERSION_0 |
+ IEEE80211_FC0_TYPE_DATA |
+ IEEE80211_FC0_SUBTYPE_QOS;
+ adf_os_mem_copy(hdr.i_addr1, eth_hdr_p->ether_dhost,
+ IEEE80211_ADDR_LEN);
+ adf_os_mem_copy(hdr.i_addr2, eth_hdr_p->ether_shost,
+ IEEE80211_ADDR_LEN);
+ adf_os_mem_set(hdr.i_addr3, 0xff, IEEE80211_ADDR_LEN);
+
+ *(uint16_t *)hdr.i_seq = htole16(seq_num << IEEE80211_SEQ_SEQ_SHIFT);
+ seq_num++;
+
+ hdr.i_qos[0] |= adf_nbuf_get_tid(msdu);
+ if (IEEE80211_IS_MULTICAST(hdr.i_addr1))
+ hdr.i_qos[0] |= 1 << IEEE80211_QOS_ACKPOLICY_S;
+
+ need_hdr_len = sizeof(hdr) + sizeof(epd_hdr_type) -
+ ETHER_HDR_LEN - adf_nbuf_headroom(msdu);
+
+ /*
+ * So we need to modify the skb buffer header and hence need
+ * a copy of that. For OCB data packets from network stack,
+ * it is impossible happened here, in case of headroom is not
+ * enough.
+ */
+ if (need_hdr_len > 0 || adf_nbuf_is_cloned(msdu)) {
+ need_hdr_len += adf_nbuf_headroom(msdu);
+ if (adf_nbuf_expand(msdu, need_hdr_len, 0) == NULL) {
+ TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
+ "%s: buf expand fail\n", __func__);
+ return A_ERROR;
+ }
+ }
+
+ adf_nbuf_pull_head(msdu, ETHER_HDR_LEN);
+ adf_os_mem_copy(adf_nbuf_push_head(msdu, sizeof(epd_hdr_type)),
+ &epd_hdr_type, sizeof(epd_hdr_type));
+ adf_os_mem_copy(adf_nbuf_push_head(msdu, sizeof(hdr)),
+ &hdr, sizeof(hdr));
+
+ return A_OK;
+}
+
static inline adf_nbuf_t
ol_tx_hl_base(
ol_txrx_vdev_handle vdev,
@@ -1259,6 +1323,17 @@ ol_tx_hl_base(
ol_collect_per_pkt_tx_stats(vdev, &tx_ctrl, tx_desc->id);
} else {
/*
+ * TX ctrl header is filled by specific operation.
+ * Packets from network stack have no ctrl header.
+ * Only convert the packet from network stack.
+ */
+ if (vdev->ocb_config_flags & OCB_CONFIG_FLAG_80211_FRAME_MODE) {
+ A_STATUS status = ol_build_ieee80211_header(msdu);
+ if (A_FAILED(status))
+ goto free_tx_desc;
+ }
+
+ /*
* IEEE 1609.4-2016 5.3.4 mandates that IP datagrams can
* transmit only on SCH (Service Channel) and can't goes on CCH.
* If SCH not exists, then drop the IP datagram.
diff --git a/CORE/CLD_TXRX/TXRX/ol_txrx_types.h b/CORE/CLD_TXRX/TXRX/ol_txrx_types.h
index e4f3f5e7472c..6cd70c138b90 100644
--- a/CORE/CLD_TXRX/TXRX/ol_txrx_types.h
+++ b/CORE/CLD_TXRX/TXRX/ol_txrx_types.h
@@ -1056,6 +1056,9 @@ struct ol_txrx_vdev_t {
struct ol_txrx_ocb_chan_info *ocb_channel_info;
uint32_t ocb_channel_count;
+ /* OCB Configuration flags */
+ uint16_t ocb_config_flags;
+
/* Default OCB TX parameter */
struct ocb_tx_ctrl_hdr_t *ocb_def_tx_param;
diff --git a/CORE/HDD/src/wlan_hdd_ocb.c b/CORE/HDD/src/wlan_hdd_ocb.c
index 44c704e41848..d511f9b097be 100644
--- a/CORE/HDD/src/wlan_hdd_ocb.c
+++ b/CORE/HDD/src/wlan_hdd_ocb.c
@@ -610,6 +610,21 @@ end:
} else {
if (enable_chan_stats)
wlan_hdd_dsrc_config_radio_chan_stats(adapter, true);
+
+ /*
+ * Net device mtu size is 1500 by default, But for OCB RAW mode,
+ * driver need later convert 802.3 data header to IEEE802.11
+ * data header and EPD header, which will increase total frame
+ * length. In such case, long packet length will exceed the
+ * target credit size. It resulted in that the packet is cut
+ * down, data would be missed and the traffic would be broken.
+ * So decrease the netdev mtu size to work around this issue
+ * in IEEE80211p RAW mode.
+ */
+ if (config->flags & OCB_CONFIG_FLAG_80211_FRAME_MODE)
+ adapter->dev->mtu = ETH_DATA_LEN - 8;
+ else
+ adapter->dev->mtu = ETH_DATA_LEN;
}
return rc;
}
diff --git a/CORE/MAC/inc/sirApi.h b/CORE/MAC/inc/sirApi.h
index ecb350006d6e..372ffbbadbe0 100644
--- a/CORE/MAC/inc/sirApi.h
+++ b/CORE/MAC/inc/sirApi.h
@@ -7241,6 +7241,11 @@ struct sir_ocb_config {
uint32_t def_tx_param_size;
};
+/* Flag to indicate expiry time in TSF. */
+#define OCB_CONFIG_FLAG_EXPIRY_TIME_IN_TSF (0x01)
+/* Flag to indicate 802.11 frame mode. */
+#define OCB_CONFIG_FLAG_80211_FRAME_MODE (0x02)
+
/* The size of the utc time in bytes. */
#define SIZE_UTC_TIME (10)
/* The size of the utc time error in bytes. */
diff --git a/CORE/SERVICES/COMMON/if_upperproto.h b/CORE/SERVICES/COMMON/if_upperproto.h
index 1e869ccf4736..00d269901811 100644
--- a/CORE/SERVICES/COMMON/if_upperproto.h
+++ b/CORE/SERVICES/COMMON/if_upperproto.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011, 2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -58,6 +58,10 @@ struct vlan_hdr {
#define VLAN_VID_MASK 0xfff
#endif
+#ifndef ETHERTYPE_WSMP
+#define ETHERTYPE_WSMP 0x88dc /* WSMP protocol */
+#endif
+
#ifndef ETHERTYPE_PAE
#define ETHERTYPE_PAE 0x888e /* EAPOL PAE/802.1x */
#endif
diff --git a/CORE/SERVICES/WMA/wma_ocb.c b/CORE/SERVICES/WMA/wma_ocb.c
index 9ce4727825b9..3b633d08e88f 100644
--- a/CORE/SERVICES/WMA/wma_ocb.c
+++ b/CORE/SERVICES/WMA/wma_ocb.c
@@ -85,6 +85,8 @@ int wma_ocb_set_config_resp(tp_wma_handle wma_handle, uint8_t status)
vdev->ocb_channel_info = 0;
}
+ vdev->ocb_config_flags = req->flags;
+
/* Default TX parameter */
if (!ol_txrx_set_ocb_def_tx_param(vdev,
req->def_tx_param, req->def_tx_param_size)) {