qcacmn: Add APIs to defragment elem/subelem fragment sequence
Add APIs to defragment a sequence of 802.11 element/subelement fragments. Add an inline mode to carry out the defragmentation within the source buffer in order to reduce buffer requirements and to eliminate memory copies/moves for the lead element/sublement. Conversely, add a non-inline mode to copy the defragmented payload to a separate buffer. Add common helper functionality shared between these APIs. CRs-Fixed: 3124132 Change-Id: Ia68584e918ddcf626b748f2b0c3a5da6492b40b6
This commit is contained in:

committed by
Gerrit - the friendly Code Review server

orang tua
94df448341
melakukan
3f38db23d4
@@ -414,6 +414,78 @@ QDF_STATUS wlan_get_elem_fragseq_info(uint8_t *elembuff,
|
||||
qdf_size_t *fragseq_totallen,
|
||||
qdf_size_t *fragseq_payloadlen);
|
||||
|
||||
/**
|
||||
* wlan_defrag_elem_fragseq() - Defragment sequence of element fragments
|
||||
*
|
||||
* @inline_defrag: Whether to use inline defragmentation, wherein the
|
||||
* defragmentation is carried out inline within the source buffer and no
|
||||
* memmoves/memcopy would be required for the lead element.
|
||||
* @fragbuff: Source buffer containing the element fragment sequence starting
|
||||
* with the Element ID of the lead element. The buffer should not contain any
|
||||
* material other than elements. If inline defragmentation is enabled, the
|
||||
* corresponding defragmented payload will be generated inline into this buffer
|
||||
* and the defragmented payload will start after the location of the lead
|
||||
* element's element ID, element length, and (if the lead element's element ID
|
||||
* is WLAN_ELEMID_EXTN_ELEM), the element ID extension. This defragmented
|
||||
* payload will not contain the headers of any of the other fragments in the
|
||||
* fragment sequence.
|
||||
* @fragbuff_maxsize: Maximum size of fragbuff. This should be greater than or
|
||||
* equal to the total size of the element fragment sequence, inclusive of the
|
||||
* header and payload of the leading element and the headers and payloads of all
|
||||
* subsequent fragments applicable to that element.
|
||||
* @defragbuff: The destination buffer into which the defragmented payload
|
||||
* should be copied. This is inapplicable and ignored if inline_defrag is true.
|
||||
* The defragmented payload will be copied to the start of the destination
|
||||
* buffer without including the headers of the lead element and the subsequent
|
||||
* fragment elements, and (if the lead element's element ID is
|
||||
* WLAN_ELEMID_EXTN_ELEM), without including the element ID extension.
|
||||
* @defragbuff_maxsize: Maximum size of defragbuff. This is inapplicable and
|
||||
* ignored if inline_defrag is true. The size should be large enough to contain
|
||||
* the entire defragmented payload, otherwise an error will be returned.
|
||||
* @defragpayload_len: Pointer to the location where the length of the
|
||||
* defragmented payload should be updated. Irrespective of whether inline_defrag
|
||||
* is true or false, this will not include the sizes of the headers of the lead
|
||||
* element and subsequent fragments, and (if the lead element's element ID is
|
||||
* WLAN_ELEMID_EXTN_ELEM), it will not include the size of the lead element's
|
||||
* element ID extension. Please note standards related limitation given in
|
||||
* function description below.
|
||||
*
|
||||
* Defragment a sequence of element fragments. If the source buffer does not
|
||||
* contain an element fragment sequence (in the beginning), an error is
|
||||
* returned. An inline mode is available to carry out the defragmentation within
|
||||
* the source buffer in order to reduce buffer requirements and to eliminate
|
||||
* memory copies/moves for the lead element. In the inline mode, the buffer
|
||||
* content (if any) after the fragments is moved as well. The contents of the
|
||||
* defragmented payload are intended for end consumption by control path
|
||||
* protocol processing code within the driver in a manner uniform with other
|
||||
* protocol data in byte buffers, and not for onward forwarding to other
|
||||
* subsystems or for intrusive specialized processing different from other
|
||||
* protocol data. Hence zero copy methods such as network buffer fragment
|
||||
* processing, etc. are not used in this use case. Additionally, this API is
|
||||
* intended for use cases where the nature of the payload is complex and it is
|
||||
* infeasible for the caller to skip the (un-defragmented) fragment boundaries
|
||||
* on its own in a scalable and maintainable manner. Separately, please note a
|
||||
* limitation arising from the standard wherein if the caller passes a truncated
|
||||
* maximum buffer size such that the buffer ends prematurely just at the end of
|
||||
* a fragment element with length 255, the function will have to conclude that
|
||||
* the last successfully parsed fragment element is the final one in the
|
||||
* fragment sequence, and return results accordingly. If another fragment
|
||||
* actually exists beyond the given buffer, this function cannot detect the
|
||||
* condition since there is no provision in the standard to indicate a total
|
||||
* fragment sequence size in one place in the beginning or anywhere else. Hence
|
||||
* the caller should take care to provide the complete buffer with the max size
|
||||
* set accordingly.
|
||||
*
|
||||
* Return: QDF_STATUS_SUCCESS in the case of success, QDF_STATUS value giving
|
||||
* the reason for error in the case of failure
|
||||
*/
|
||||
QDF_STATUS wlan_defrag_elem_fragseq(bool inline_defrag,
|
||||
uint8_t *fragbuff,
|
||||
qdf_size_t fragbuff_maxsize,
|
||||
uint8_t *defragbuff,
|
||||
qdf_size_t defragbuff_maxsize,
|
||||
qdf_size_t *defragpayload_len);
|
||||
|
||||
/**
|
||||
* wlan_get_subelem_fragseq_info() - Get information about subelement fragment
|
||||
* sequence
|
||||
@@ -481,6 +553,78 @@ QDF_STATUS wlan_get_subelem_fragseq_info(uint8_t subelemfragid,
|
||||
qdf_size_t *fragseq_totallen,
|
||||
qdf_size_t *fragseq_payloadlen);
|
||||
|
||||
/**
|
||||
* wlan_defrag_subelem_fragseq() - Defragment sequence of subelement fragments
|
||||
*
|
||||
* @inline_defrag: Whether to use inline defragmentation, wherein the
|
||||
* defragmentation is carried out inline within the source buffer and no
|
||||
* memmoves/memcopy would be required for the lead subelement.
|
||||
* @subelemid: Fragment ID applicable for the subelement (this can potentially
|
||||
* vary across protocol areas)
|
||||
* @fragbuff: Source buffer containing the subelement fragment sequence starting
|
||||
* with the subelement ID of the lead subelement. The containing element is
|
||||
* required to have already been defragmented (if applicable). If inline
|
||||
* defragmentation is enabled, the corresponding defragmented payload will be
|
||||
* generated inline into this buffer and the defragmented payload will start
|
||||
* after the location of the lead subelement's subelement ID and subelement
|
||||
* length. This defragmented payload will not contain the headers of any of the
|
||||
* other fragments in the fragment sequence.
|
||||
* @fragbuff_maxsize: Maximum size of fragbuff. This should be greater than or
|
||||
* equal to the total size of the subelement fragment sequence, inclusive of the
|
||||
* header and payload of the leading subelement and the headers and payloads of
|
||||
* all subsequent fragments applicable to that subelement.
|
||||
* @defragbuff: The destination buffer into which the defragmented payload
|
||||
* should be copied. This is inapplicable and ignored if inline_defrag is true.
|
||||
* The defragmented payload will be copied to the start of the destination
|
||||
* buffer without including the headers of the lead subelement and the
|
||||
* subsequent fragment subelements.
|
||||
* @defragbuff_maxsize: Maximum size of defragbuff. This is inapplicable and
|
||||
* ignored if inline_defrag is true. The size should be large enough to contain
|
||||
* the entire defragmented payload, otherwise an error will be returned.
|
||||
* @defragpayload_len: Pointer to the location where the length of the
|
||||
* defragmented payload should be updated. Irrespective of whether inline_defrag
|
||||
* is true or false, this will not include the sizes of the headers of the lead
|
||||
* subelement and subsequent fragments. Please note standards related limitation
|
||||
* given in function description below.
|
||||
*
|
||||
* Defragment a sequence of subelement fragments. If the source buffer does not
|
||||
* contain a subelement fragment sequence (in the beginning), the function
|
||||
* returns an error. The containing element is required to have already been
|
||||
* defragmented. An inline mode is available to carry out the defragmentation
|
||||
* within the source buffer in order to reduce buffer requirements and to
|
||||
* eliminate memory copies/moves for the lead subelement. In the inline mode,
|
||||
* the buffer content (if any) after the fragments is moved as well. The
|
||||
* contents of the defragmented payload are intended for end consumption by
|
||||
* control path protocol processing code within the driver in a manner uniform
|
||||
* with other protocol data in byte buffers, and not for onward forwarding to
|
||||
* other subsystems or for intrusive specialized processing different from other
|
||||
* protocol data. Hence zero copy methods such as network buffer fragment
|
||||
* processing, etc. are not used in this use case. Additionally, this API is
|
||||
* intended for use cases where the nature of the payload is complex and it is
|
||||
* infeasible for the caller to skip the (un-defragmented) fragment boundaries
|
||||
* on its own in a scalable and maintainable manner. Separately, please note a
|
||||
* limitation arising from the standard wherein if the caller passes a truncated
|
||||
* maximum buffer size such that the buffer ends prematurely just at the end of
|
||||
* a fragment subelement with length 255, the function will have to conclude
|
||||
* that the last successfully parsed fragment subelement is the final one in the
|
||||
* fragment sequence, and return results accordingly. If another fragment
|
||||
* actually exists beyond the given buffer, this function cannot detect the
|
||||
* condition since there is no provision in the standard to indicate a total
|
||||
* fragment sequence size in one place in the beginning or anywhere else. Hence
|
||||
* the caller should take care to provide the complete buffer with the max size
|
||||
* set accordingly.
|
||||
*
|
||||
* Return: QDF_STATUS_SUCCESS in the case of success, QDF_STATUS value giving
|
||||
* the reason for error in the case of failure
|
||||
*/
|
||||
QDF_STATUS wlan_defrag_subelem_fragseq(bool inline_defrag,
|
||||
uint8_t subelemfragid,
|
||||
uint8_t *fragbuff,
|
||||
qdf_size_t fragbuff_maxsize,
|
||||
uint8_t *defragbuff,
|
||||
qdf_size_t defragbuff_maxsize,
|
||||
qdf_size_t *defragpayload_len);
|
||||
|
||||
/**
|
||||
* wlan_is_emulation_platform() - check if platform is emulation based
|
||||
* @phy_version - psoc nif phy_version
|
||||
|
@@ -1123,6 +1123,204 @@ wlan_get_elemsubelem_fragseq_info(bool is_subelem,
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static QDF_STATUS wlan_defrag_elemsubelem_fragseq(bool inline_defrag,
|
||||
bool is_subelem,
|
||||
uint8_t subelemfragid,
|
||||
uint8_t *fragbuff,
|
||||
qdf_size_t fragbuff_maxsize,
|
||||
uint8_t *defragbuff,
|
||||
qdf_size_t defragbuff_maxsize,
|
||||
qdf_size_t *defragpayload_len)
|
||||
{
|
||||
/* elemunit, i.e. 'element unit' here refers to either an 802.11 element
|
||||
* or a 802.11 subelement.
|
||||
*/
|
||||
uint8_t elemunit_fragid;
|
||||
qdf_size_t elemunit_hdrlen;
|
||||
int elemunit_id_pos;
|
||||
int elemunit_len_pos;
|
||||
int elemunit_idext_pos;
|
||||
|
||||
bool is_fragseq;
|
||||
qdf_size_t fragseq_totallen;
|
||||
qdf_size_t fragseq_payloadlen;
|
||||
|
||||
uint8_t *curr_elemunit_ptr;
|
||||
qdf_size_t curr_elemunit_payloadlen;
|
||||
qdf_size_t curr_elemunit_totallen;
|
||||
|
||||
uint8_t *src;
|
||||
uint8_t *dst;
|
||||
|
||||
/* Current length of the defragmented payload */
|
||||
qdf_size_t defragpayload_currlen;
|
||||
|
||||
/* Remaining length available in the source buffer containing the
|
||||
* fragment sequence, after element units processed so far.
|
||||
*/
|
||||
qdf_size_t fragbuff_remlen;
|
||||
|
||||
QDF_STATUS ret;
|
||||
|
||||
/* Helper function to de-fragment element or subelement fragment
|
||||
* sequence. Refer to the documentation of the public APIs which call
|
||||
* this helper, for more information. Those APIs are mainly wrappers
|
||||
* over this helper.
|
||||
*/
|
||||
|
||||
ret = wlan_get_elemunit_info(is_subelem,
|
||||
subelemfragid,
|
||||
&elemunit_fragid,
|
||||
&elemunit_hdrlen,
|
||||
NULL,
|
||||
&elemunit_id_pos,
|
||||
&elemunit_len_pos,
|
||||
&elemunit_idext_pos);
|
||||
if (QDF_IS_STATUS_ERROR(ret)) {
|
||||
qdf_rl_nofl_err("Investigate error %d when trying to get element unit info",
|
||||
ret);
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
||||
|
||||
if (!fragbuff) {
|
||||
qdf_nofl_err("Source buffer for fragment sequence is NULL");
|
||||
return QDF_STATUS_E_NULL_VALUE;
|
||||
}
|
||||
|
||||
if (fragbuff_maxsize == 0) {
|
||||
qdf_nofl_err("Size of source buffer for fragment sequence is 0");
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
|
||||
if (!inline_defrag) {
|
||||
if (!defragbuff) {
|
||||
qdf_nofl_err("Destination buffer for defragmented payload is NULL");
|
||||
return QDF_STATUS_E_NULL_VALUE;
|
||||
}
|
||||
|
||||
if (defragbuff_maxsize == 0) {
|
||||
qdf_nofl_err("Size of destination buffer for defragmented payload is 0");
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!defragpayload_len) {
|
||||
qdf_nofl_err("Pointer to location for length of defragmented payload is NULL");
|
||||
return QDF_STATUS_E_NULL_VALUE;
|
||||
}
|
||||
|
||||
ret = wlan_get_elemsubelem_fragseq_info(is_subelem,
|
||||
subelemfragid,
|
||||
fragbuff,
|
||||
fragbuff_maxsize,
|
||||
&is_fragseq,
|
||||
&fragseq_totallen,
|
||||
&fragseq_payloadlen);
|
||||
if (QDF_IS_STATUS_ERROR(ret))
|
||||
return ret;
|
||||
|
||||
if (!is_fragseq) {
|
||||
/* We treat this as an error since the caller is supposed to
|
||||
* check this.
|
||||
*/
|
||||
qdf_rl_nofl_err("Fragment sequence not found at start of source buffer for fragment sequence");
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
|
||||
/* fragseq_totallen is known to be smaller than or equal to
|
||||
* fragbuff_maxsize since wlan_get_elemsubelem_fragseq_info() is bound
|
||||
* by fragbuff_maxsize in the search for a fragment sequence and it's
|
||||
* total length.
|
||||
*/
|
||||
|
||||
if (!inline_defrag && (defragbuff_maxsize < fragseq_payloadlen)) {
|
||||
qdf_rl_nofl_err("Size of destination buffer for defragmented payload %zu octets is smaller than the size of fragment sequence payload %zu octets",
|
||||
defragbuff_maxsize, fragseq_payloadlen);
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
|
||||
defragpayload_currlen = 0;
|
||||
fragbuff_remlen = fragbuff_maxsize;
|
||||
|
||||
/* We have already validated through wlan_get_elemsubelem_fragseq_info()
|
||||
* that the elements we are about to access below are within the bounds
|
||||
* of fragbuff.
|
||||
*/
|
||||
|
||||
curr_elemunit_ptr = fragbuff;
|
||||
|
||||
if (!is_subelem &&
|
||||
(curr_elemunit_ptr[elemunit_id_pos] == WLAN_ELEMID_EXTN_ELEM)) {
|
||||
curr_elemunit_payloadlen =
|
||||
curr_elemunit_ptr[elemunit_len_pos] - 1;
|
||||
src = curr_elemunit_ptr + elemunit_hdrlen + 1;
|
||||
} else {
|
||||
curr_elemunit_payloadlen = curr_elemunit_ptr[elemunit_len_pos];
|
||||
src = curr_elemunit_ptr + elemunit_hdrlen;
|
||||
}
|
||||
|
||||
curr_elemunit_totallen =
|
||||
elemunit_hdrlen + curr_elemunit_ptr[elemunit_len_pos];
|
||||
|
||||
if (inline_defrag) {
|
||||
/* There is no need to move any bytes in the lead element. Set
|
||||
* dst=src so that the next update for dst can happen in a
|
||||
* manner uniform with the non-inlined defrag case.
|
||||
*/
|
||||
dst = src;
|
||||
} else {
|
||||
dst = defragbuff;
|
||||
qdf_mem_copy(dst, src, curr_elemunit_payloadlen);
|
||||
}
|
||||
|
||||
defragpayload_currlen += curr_elemunit_payloadlen;
|
||||
|
||||
fragbuff_remlen -= curr_elemunit_totallen;
|
||||
|
||||
dst += curr_elemunit_payloadlen;
|
||||
|
||||
curr_elemunit_ptr += curr_elemunit_totallen;
|
||||
|
||||
/* We have already validated through wlan_get_elemsubelem_fragseq_info()
|
||||
* that at least one non-lead fragment element is present as required in
|
||||
* the standard.
|
||||
*/
|
||||
while (curr_elemunit_ptr[elemunit_id_pos] == elemunit_fragid) {
|
||||
curr_elemunit_payloadlen = curr_elemunit_ptr[elemunit_len_pos];
|
||||
curr_elemunit_totallen =
|
||||
elemunit_hdrlen + curr_elemunit_ptr[elemunit_len_pos];
|
||||
src = curr_elemunit_ptr + elemunit_hdrlen;
|
||||
|
||||
if (inline_defrag)
|
||||
qdf_mem_move(dst, src, curr_elemunit_payloadlen);
|
||||
else
|
||||
qdf_mem_copy(dst, src, curr_elemunit_payloadlen);
|
||||
|
||||
defragpayload_currlen += curr_elemunit_payloadlen;
|
||||
|
||||
fragbuff_remlen -= curr_elemunit_totallen;
|
||||
|
||||
if (fragbuff_remlen == 0)
|
||||
break;
|
||||
|
||||
dst += curr_elemunit_payloadlen;
|
||||
|
||||
curr_elemunit_ptr += curr_elemunit_totallen;
|
||||
}
|
||||
|
||||
if (inline_defrag && (fragbuff_remlen != 0)) {
|
||||
/* Move the residual content after the fragments, in the source
|
||||
* buffer.
|
||||
*/
|
||||
src = curr_elemunit_ptr;
|
||||
qdf_mem_move(dst, src, fragbuff_remlen);
|
||||
}
|
||||
|
||||
*defragpayload_len = defragpayload_currlen;
|
||||
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
QDF_STATUS
|
||||
wlan_get_elem_fragseq_requirements(uint8_t elemid,
|
||||
qdf_size_t payloadlen,
|
||||
@@ -1218,6 +1416,23 @@ QDF_STATUS wlan_get_elem_fragseq_info(uint8_t *elembuff,
|
||||
fragseq_payloadlen);
|
||||
}
|
||||
|
||||
QDF_STATUS wlan_defrag_elem_fragseq(bool inline_defrag,
|
||||
uint8_t *fragbuff,
|
||||
qdf_size_t fragbuff_maxsize,
|
||||
uint8_t *defragbuff,
|
||||
qdf_size_t defragbuff_maxsize,
|
||||
qdf_size_t *defragpayload_len)
|
||||
{
|
||||
return wlan_defrag_elemsubelem_fragseq(inline_defrag,
|
||||
false,
|
||||
0,
|
||||
fragbuff,
|
||||
fragbuff_maxsize,
|
||||
defragbuff,
|
||||
defragbuff_maxsize,
|
||||
defragpayload_len);
|
||||
}
|
||||
|
||||
QDF_STATUS wlan_get_subelem_fragseq_info(uint8_t subelemfragid,
|
||||
uint8_t *subelembuff,
|
||||
qdf_size_t subelembuff_maxsize,
|
||||
@@ -1234,6 +1449,24 @@ QDF_STATUS wlan_get_subelem_fragseq_info(uint8_t subelemfragid,
|
||||
fragseq_payloadlen);
|
||||
}
|
||||
|
||||
QDF_STATUS wlan_defrag_subelem_fragseq(bool inline_defrag,
|
||||
uint8_t subelemfragid,
|
||||
uint8_t *fragbuff,
|
||||
qdf_size_t fragbuff_maxsize,
|
||||
uint8_t *defragbuff,
|
||||
qdf_size_t defragbuff_maxsize,
|
||||
qdf_size_t *defragpayload_len)
|
||||
{
|
||||
return wlan_defrag_elemsubelem_fragseq(inline_defrag,
|
||||
true,
|
||||
subelemfragid,
|
||||
fragbuff,
|
||||
fragbuff_maxsize,
|
||||
defragbuff,
|
||||
defragbuff_maxsize,
|
||||
defragpayload_len);
|
||||
}
|
||||
|
||||
bool wlan_is_emulation_platform(uint32_t phy_version)
|
||||
{
|
||||
if ((phy_version == 0xABC0) || (phy_version == 0xABC1) ||
|
||||
|
Reference in New Issue
Block a user