wmi_tlv_helper.c 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359
  1. /*
  2. * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
  3. *
  4. * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  5. *
  6. *
  7. * Permission to use, copy, modify, and/or distribute this software for
  8. * any purpose with or without fee is hereby granted, provided that the
  9. * above copyright notice and this permission notice appear in all
  10. * copies.
  11. *
  12. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  13. * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
  14. * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
  15. * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  16. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  17. * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  18. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  19. * PERFORMANCE OF THIS SOFTWARE.
  20. */
  21. /*
  22. * This file was originally distributed by Qualcomm Atheros, Inc.
  23. * under proprietary terms before Copyright ownership was assigned
  24. * to the Linux Foundation.
  25. */
  26. #include "wmi_tlv_platform.c"
  27. #include "wmi_tlv_defs.h"
  28. #include "wmi_version.h"
  29. #include "qdf_module.h"
  30. #define WMITLV_GET_ATTRIB_NUM_TLVS 0xFFFFFFFF
  31. #define WMITLV_GET_CMDID(val) (val & 0x00FFFFFF)
  32. #define WMITLV_GET_NUM_TLVS(val) ((val >> 24) & 0xFF)
  33. #define WMITLV_GET_TAGID(val) (val & 0x00000FFF)
  34. #define WMITLV_GET_TAG_STRUCT_SIZE(val) ((val >> 12) & 0x000001FF)
  35. #define WMITLV_GET_TAG_ARRAY_SIZE(val) ((val >> 21) & 0x000001FF)
  36. #define WMITLV_GET_TAG_VARIED(val) ((val >> 30) & 0x00000001)
  37. #define WMITLV_SET_ATTRB0(id) ((WMITLV_GET_TAG_NUM_TLV_ATTRIB(id) << 24) | \
  38. (id & 0x00FFFFFF))
  39. #define WMITLV_SET_ATTRB1(tagID, tagStructSize, tagArraySize, tagVaried) \
  40. (((tagVaried&0x1)<<30) | ((tagArraySize&0x1FF)<<21) | \
  41. ((tagStructSize&0x1FF)<<12) | (tagID&0xFFF))
  42. #define WMITLV_OP_SET_TLV_ATTRIB_macro(param_ptr, param_len, wmi_cmd_event_id, \
  43. elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \
  44. WMITLV_SET_ATTRB1(elem_tlv_tag, sizeof(elem_struc_type), arr_size, var_len),
  45. #define WMITLV_GET_CMD_EVT_ATTRB_LIST(id) \
  46. WMITLV_SET_ATTRB0(id), \
  47. WMITLV_TABLE(id,SET_TLV_ATTRIB, NULL, 0)
  48. uint32_t cmd_attr_list[] = {
  49. WMITLV_ALL_CMD_LIST(WMITLV_GET_CMD_EVT_ATTRB_LIST)
  50. };
  51. uint32_t evt_attr_list[] = {
  52. WMITLV_ALL_EVT_LIST(WMITLV_GET_CMD_EVT_ATTRB_LIST)
  53. };
  54. #ifdef NO_DYNAMIC_MEM_ALLOC
  55. static wmitlv_cmd_param_info *g_wmi_static_cmd_param_info_buf;
  56. uint32_t g_wmi_static_max_cmd_param_tlvs;
  57. #endif
  58. /**
  59. * wmitlv_set_static_param_tlv_buf() - tlv helper function
  60. * @param_tlv_buf: tlv buffer parameter
  61. * @max_tlvs_accomodated: max no of tlv entries
  62. *
  63. *
  64. * WMI TLV Helper function to set the static cmd_param_tlv structure
  65. * and number of TLVs that can be accomodated in the structure.
  66. * This function should be used when dynamic memory allocation is not
  67. * supported. When dynamic memory allocation is not supported by any
  68. * component then NO_DYNAMIC_MEMALLOC macro has to be defined in respective
  69. * tlv_platform.c file. And respective component has to allocate
  70. * cmd_param_tlv structure buffer to accomodate whatever number of TLV's.
  71. * Both the buffer address and number of TLV's that can be accomodated in
  72. * the buffer should be sent as arguments to this function.
  73. *
  74. * Return None
  75. */
  76. void
  77. wmitlv_set_static_param_tlv_buf(void *param_tlv_buf,
  78. uint32_t max_tlvs_accomodated)
  79. {
  80. #ifdef NO_DYNAMIC_MEM_ALLOC
  81. g_wmi_static_cmd_param_info_buf = param_tlv_buf;
  82. g_wmi_static_max_cmd_param_tlvs = max_tlvs_accomodated;
  83. #endif
  84. }
  85. /**
  86. * wmitlv_get_attributes() - tlv helper function
  87. * @is_cmd_id: boolean for command attribute
  88. * @cmd_event_id: command event id
  89. * @curr_tlv_order: tlv order
  90. * @tlv_attr_ptr: pointer to tlv attribute
  91. *
  92. *
  93. * WMI TLV Helper functions to find the attributes of the
  94. * Command/Event TLVs.
  95. *
  96. * Return: 0 if success. Return >=1 if failure.
  97. */
  98. static
  99. uint32_t wmitlv_get_attributes(uint32_t is_cmd_id, uint32_t cmd_event_id,
  100. uint32_t curr_tlv_order,
  101. wmitlv_attributes_struc *tlv_attr_ptr)
  102. {
  103. uint32_t i, base_index, num_tlvs, num_entries;
  104. uint32_t *pAttrArrayList;
  105. if (is_cmd_id) {
  106. pAttrArrayList = &cmd_attr_list[0];
  107. num_entries = QDF_ARRAY_SIZE(cmd_attr_list);
  108. } else {
  109. pAttrArrayList = &evt_attr_list[0];
  110. num_entries = QDF_ARRAY_SIZE(evt_attr_list);
  111. }
  112. for (i = 0; i < num_entries; i++) {
  113. num_tlvs = WMITLV_GET_NUM_TLVS(pAttrArrayList[i]);
  114. if (WMITLV_GET_CMDID(cmd_event_id) ==
  115. WMITLV_GET_CMDID(pAttrArrayList[i])) {
  116. tlv_attr_ptr->cmd_num_tlv = num_tlvs;
  117. /* Return success from here when only number of TLVS for
  118. * this command/event is required */
  119. if (curr_tlv_order == WMITLV_GET_ATTRIB_NUM_TLVS) {
  120. wmi_tlv_print_verbose
  121. ("%s: WMI TLV attribute definitions for %s:0x%x found; num_of_tlvs:%d\n",
  122. __func__, (is_cmd_id ? "Cmd" : "Evt"),
  123. cmd_event_id, num_tlvs);
  124. return 0;
  125. }
  126. /* Return failure if tlv_order is more than the expected
  127. * number of TLVs */
  128. if (curr_tlv_order >= num_tlvs) {
  129. wmi_tlv_print_error
  130. ("%s: ERROR: TLV order %d greater than num_of_tlvs:%d for %s:0x%x\n",
  131. __func__, curr_tlv_order, num_tlvs,
  132. (is_cmd_id ? "Cmd" : "Evt"), cmd_event_id);
  133. return 1;
  134. }
  135. base_index = i + 1; /* index to first TLV attributes */
  136. wmi_tlv_print_verbose
  137. ("%s: WMI TLV attributes for %s:0x%x tlv[%d]:0x%x\n",
  138. __func__, (is_cmd_id ? "Cmd" : "Evt"),
  139. cmd_event_id, curr_tlv_order,
  140. pAttrArrayList[(base_index + curr_tlv_order)]);
  141. tlv_attr_ptr->tag_order = curr_tlv_order;
  142. tlv_attr_ptr->tag_id =
  143. WMITLV_GET_TAGID(pAttrArrayList
  144. [(base_index + curr_tlv_order)]);
  145. tlv_attr_ptr->tag_struct_size =
  146. WMITLV_GET_TAG_STRUCT_SIZE(pAttrArrayList
  147. [(base_index +
  148. curr_tlv_order)]);
  149. tlv_attr_ptr->tag_varied_size =
  150. WMITLV_GET_TAG_VARIED(pAttrArrayList
  151. [(base_index +
  152. curr_tlv_order)]);
  153. tlv_attr_ptr->tag_array_size =
  154. WMITLV_GET_TAG_ARRAY_SIZE(pAttrArrayList
  155. [(base_index +
  156. curr_tlv_order)]);
  157. return 0;
  158. }
  159. i += num_tlvs;
  160. }
  161. wmi_tlv_print_error
  162. ("%s: ERROR: Didn't found WMI TLV attribute definitions for %s:0x%x\n",
  163. __func__, (is_cmd_id ? "Cmd" : "Evt"), cmd_event_id);
  164. return 1;
  165. }
  166. /**
  167. * wmitlv_check_tlv_params() - tlv helper function
  168. * @os_handle: os context handle
  169. * @param_struc_ptr: pointer to tlv structure
  170. * @is_cmd_id: boolean for command attribute
  171. * @wmi_cmd_event_id: command event id
  172. *
  173. *
  174. * Helper Function to vaidate the prepared TLV's for
  175. * an WMI event/command to be sent.
  176. *
  177. * Return: 0 if success. Return < 0 if failure.
  178. */
  179. static int
  180. wmitlv_check_tlv_params(void *os_handle, void *param_struc_ptr,
  181. uint32_t param_buf_len, uint32_t is_cmd_id,
  182. uint32_t wmi_cmd_event_id)
  183. {
  184. wmitlv_attributes_struc attr_struct_ptr;
  185. uint32_t buf_idx = 0;
  186. uint32_t tlv_index = 0;
  187. uint8_t *buf_ptr = (unsigned char *)param_struc_ptr;
  188. uint32_t expected_num_tlvs, expected_tlv_len;
  189. int32_t error = -1;
  190. /* Get the number of TLVs for this command/event */
  191. if (wmitlv_get_attributes
  192. (is_cmd_id, wmi_cmd_event_id, WMITLV_GET_ATTRIB_NUM_TLVS,
  193. &attr_struct_ptr) != 0) {
  194. wmi_tlv_print_error
  195. ("%s: ERROR: Couldn't get expected number of TLVs for Cmd=%d\n",
  196. __func__, wmi_cmd_event_id);
  197. goto Error_wmitlv_check_tlv_params;
  198. }
  199. /* NOTE: the returned number of TLVs is in "attr_struct_ptr.cmd_num_tlv" */
  200. expected_num_tlvs = attr_struct_ptr.cmd_num_tlv;
  201. while ((buf_idx + WMI_TLV_HDR_SIZE) <= param_buf_len) {
  202. uint32_t curr_tlv_tag =
  203. WMITLV_GET_TLVTAG(WMITLV_GET_HDR(buf_ptr));
  204. uint32_t curr_tlv_len =
  205. WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr));
  206. if ((buf_idx + WMI_TLV_HDR_SIZE + curr_tlv_len) > param_buf_len) {
  207. wmi_tlv_print_error
  208. ("%s: ERROR: Invalid TLV length for Cmd=%d Tag_order=%d buf_idx=%d Tag:%d Len:%d TotalLen:%d\n",
  209. __func__, wmi_cmd_event_id, tlv_index, buf_idx,
  210. curr_tlv_tag, curr_tlv_len, param_buf_len);
  211. goto Error_wmitlv_check_tlv_params;
  212. }
  213. /* Get the attributes of the TLV with the given order in "tlv_index" */
  214. wmi_tlv_OS_MEMZERO(&attr_struct_ptr,
  215. sizeof(wmitlv_attributes_struc));
  216. if (wmitlv_get_attributes
  217. (is_cmd_id, wmi_cmd_event_id, tlv_index,
  218. &attr_struct_ptr) != 0) {
  219. wmi_tlv_print_error
  220. ("%s: ERROR: No TLV attributes found for Cmd=%d Tag_order=%d\n",
  221. __func__, wmi_cmd_event_id, tlv_index);
  222. goto Error_wmitlv_check_tlv_params;
  223. }
  224. /* Found the TLV that we wanted */
  225. wmi_tlv_print_verbose("%s: [tlv %d]: tag=%d, len=%d\n",
  226. __func__, tlv_index, curr_tlv_tag,
  227. curr_tlv_len);
  228. /* Validating Tag ID order */
  229. if (curr_tlv_tag != attr_struct_ptr.tag_id) {
  230. wmi_tlv_print_error
  231. ("%s: ERROR: TLV has wrong tag in order for Cmd=0x%x. Given=%d, Expected=%d.\n",
  232. __func__, wmi_cmd_event_id, curr_tlv_tag,
  233. attr_struct_ptr.tag_id);
  234. goto Error_wmitlv_check_tlv_params;
  235. }
  236. /* Validate Tag length */
  237. /* Array TLVs length checking needs special handling */
  238. if ((curr_tlv_tag >= WMITLV_TAG_FIRST_ARRAY_ENUM)
  239. && (curr_tlv_tag <= WMITLV_TAG_LAST_ARRAY_ENUM)) {
  240. if (attr_struct_ptr.tag_varied_size == WMITLV_SIZE_FIX) {
  241. /* Array size can't be invalid for fixed size Array TLV */
  242. if (WMITLV_ARR_SIZE_INVALID ==
  243. attr_struct_ptr.tag_array_size) {
  244. wmi_tlv_print_error
  245. ("%s: ERROR: array_size can't be invalid for Array TLV Cmd=0x%x Tag=%d\n",
  246. __func__, wmi_cmd_event_id,
  247. curr_tlv_tag);
  248. goto Error_wmitlv_check_tlv_params;
  249. }
  250. expected_tlv_len =
  251. attr_struct_ptr.tag_array_size *
  252. attr_struct_ptr.tag_struct_size;
  253. /* Paddding is only required for Byte array Tlvs all other
  254. * array tlv's should be aligned to 4 bytes during their
  255. * definition */
  256. if (WMITLV_TAG_ARRAY_BYTE ==
  257. attr_struct_ptr.tag_id) {
  258. expected_tlv_len =
  259. roundup(expected_tlv_len,
  260. sizeof(uint32_t));
  261. }
  262. if (curr_tlv_len != expected_tlv_len) {
  263. wmi_tlv_print_error
  264. ("%s: ERROR: TLV has wrong length for Cmd=0x%x. Tag_order=%d Tag=%d, Given_Len:%d Expected_Len=%d.\n",
  265. __func__, wmi_cmd_event_id,
  266. tlv_index, curr_tlv_tag,
  267. curr_tlv_len, expected_tlv_len);
  268. goto Error_wmitlv_check_tlv_params;
  269. }
  270. } else {
  271. /* Array size should be invalid for variable size Array TLV */
  272. if (WMITLV_ARR_SIZE_INVALID !=
  273. attr_struct_ptr.tag_array_size) {
  274. wmi_tlv_print_error
  275. ("%s: ERROR: array_size should be invalid for Array TLV Cmd=0x%x Tag=%d\n",
  276. __func__, wmi_cmd_event_id,
  277. curr_tlv_tag);
  278. goto Error_wmitlv_check_tlv_params;
  279. }
  280. /* Incase of variable length TLV's, there is no expectation
  281. * on the length field so do whatever checking you can
  282. * depending on the TLV tag if TLV length is non-zero */
  283. if (curr_tlv_len != 0) {
  284. /* Verify TLV length is aligned to the size of structure */
  285. if ((curr_tlv_len %
  286. attr_struct_ptr.tag_struct_size) !=
  287. 0) {
  288. wmi_tlv_print_error
  289. ("%s: ERROR: TLV length %d for Cmd=0x%x is not aligned to size of structure(%d bytes)\n",
  290. __func__, curr_tlv_len,
  291. wmi_cmd_event_id,
  292. attr_struct_ptr.
  293. tag_struct_size);
  294. goto Error_wmitlv_check_tlv_params;
  295. }
  296. if (curr_tlv_tag ==
  297. WMITLV_TAG_ARRAY_STRUC) {
  298. uint8_t *tlv_buf_ptr = NULL;
  299. uint32_t in_tlv_len;
  300. uint32_t idx;
  301. uint32_t num_of_elems;
  302. /* Verify length of inner TLVs */
  303. num_of_elems =
  304. curr_tlv_len /
  305. attr_struct_ptr.
  306. tag_struct_size;
  307. /* Set tlv_buf_ptr to the first inner TLV address */
  308. tlv_buf_ptr =
  309. buf_ptr + WMI_TLV_HDR_SIZE;
  310. for (idx = 0;
  311. idx < num_of_elems;
  312. idx++) {
  313. in_tlv_len =
  314. WMITLV_GET_TLVLEN
  315. (WMITLV_GET_HDR
  316. (tlv_buf_ptr));
  317. if ((in_tlv_len +
  318. WMI_TLV_HDR_SIZE)
  319. !=
  320. attr_struct_ptr.
  321. tag_struct_size) {
  322. wmi_tlv_print_error
  323. ("%s: ERROR: TLV has wrong length for Cmd=0x%x. Tag_order=%d Tag=%d, Given_Len:%zu Expected_Len=%d.\n",
  324. __func__,
  325. wmi_cmd_event_id,
  326. tlv_index,
  327. curr_tlv_tag,
  328. (in_tlv_len
  329. +
  330. WMI_TLV_HDR_SIZE),
  331. attr_struct_ptr.
  332. tag_struct_size);
  333. goto Error_wmitlv_check_tlv_params;
  334. }
  335. tlv_buf_ptr +=
  336. in_tlv_len +
  337. WMI_TLV_HDR_SIZE;
  338. }
  339. } else
  340. if ((curr_tlv_tag ==
  341. WMITLV_TAG_ARRAY_UINT32)
  342. || (curr_tlv_tag ==
  343. WMITLV_TAG_ARRAY_BYTE)
  344. || (curr_tlv_tag ==
  345. WMITLV_TAG_ARRAY_FIXED_STRUC)) {
  346. /* Nothing to verify here */
  347. } else {
  348. wmi_tlv_print_error
  349. ("%s ERROR Need to handle the Array tlv %d for variable length for Cmd=0x%x\n",
  350. __func__,
  351. attr_struct_ptr.tag_id,
  352. wmi_cmd_event_id);
  353. goto Error_wmitlv_check_tlv_params;
  354. }
  355. }
  356. }
  357. } else {
  358. /* Non-array TLV. */
  359. if ((curr_tlv_len + WMI_TLV_HDR_SIZE) !=
  360. attr_struct_ptr.tag_struct_size) {
  361. wmi_tlv_print_error
  362. ("%s: ERROR: TLV has wrong length for Cmd=0x%x. Given=%zu, Expected=%d.\n",
  363. __func__, wmi_cmd_event_id,
  364. (curr_tlv_len + WMI_TLV_HDR_SIZE),
  365. attr_struct_ptr.tag_struct_size);
  366. goto Error_wmitlv_check_tlv_params;
  367. }
  368. }
  369. /* Check TLV length is aligned to 4 bytes or not */
  370. if ((curr_tlv_len % sizeof(uint32_t)) != 0) {
  371. wmi_tlv_print_error
  372. ("%s: ERROR: TLV length %d for Cmd=0x%x is not aligned to %zu bytes\n",
  373. __func__, curr_tlv_len, wmi_cmd_event_id,
  374. sizeof(uint32_t));
  375. goto Error_wmitlv_check_tlv_params;
  376. }
  377. tlv_index++;
  378. buf_ptr += curr_tlv_len + WMI_TLV_HDR_SIZE;
  379. buf_idx += curr_tlv_len + WMI_TLV_HDR_SIZE;
  380. }
  381. if (tlv_index != expected_num_tlvs) {
  382. wmi_tlv_print_verbose
  383. ("%s: INFO: Less number of TLVs filled for Cmd=0x%x Filled %d Expected=%d\n",
  384. __func__, wmi_cmd_event_id, tlv_index, expected_num_tlvs);
  385. }
  386. return 0;
  387. Error_wmitlv_check_tlv_params:
  388. return error;
  389. }
  390. /**
  391. * wmitlv_check_event_tlv_params() - tlv helper function
  392. * @os_handle: os context handle
  393. * @param_struc_ptr: pointer to tlv structure
  394. * @is_cmd_id: boolean for command attribute
  395. * @wmi_cmd_event_id: command event id
  396. *
  397. *
  398. * Helper Function to vaidate the prepared TLV's for
  399. * an WMI event/command to be sent.
  400. *
  401. * Return: 0 if success. Return < 0 if failure.
  402. */
  403. int
  404. wmitlv_check_event_tlv_params(void *os_handle, void *param_struc_ptr,
  405. uint32_t param_buf_len, uint32_t wmi_cmd_event_id)
  406. {
  407. uint32_t is_cmd_id = 0;
  408. return wmitlv_check_tlv_params
  409. (os_handle, param_struc_ptr, param_buf_len, is_cmd_id,
  410. wmi_cmd_event_id);
  411. }
  412. /**
  413. * wmitlv_check_command_tlv_params() - tlv helper function
  414. * @os_handle: os context handle
  415. * @param_struc_ptr: pointer to tlv structure
  416. * @is_cmd_id: boolean for command attribute
  417. * @wmi_cmd_event_id: command event id
  418. *
  419. *
  420. * Helper Function to vaidate the prepared TLV's for
  421. * an WMI event/command to be sent.
  422. *
  423. * Return: 0 if success. Return < 0 if failure.
  424. */
  425. int
  426. wmitlv_check_command_tlv_params(void *os_handle, void *param_struc_ptr,
  427. uint32_t param_buf_len,
  428. uint32_t wmi_cmd_event_id)
  429. {
  430. uint32_t is_cmd_id = 1;
  431. return wmitlv_check_tlv_params
  432. (os_handle, param_struc_ptr, param_buf_len, is_cmd_id,
  433. wmi_cmd_event_id);
  434. }
  435. qdf_export_symbol(wmitlv_check_command_tlv_params);
  436. /**
  437. * wmitlv_check_and_pad_tlvs() - tlv helper function
  438. * @os_handle: os context handle
  439. * @param_buf_len: length of tlv parameter
  440. * @param_struc_ptr: pointer to tlv structure
  441. * @is_cmd_id: boolean for command attribute
  442. * @wmi_cmd_event_id: command event id
  443. * @wmi_cmd_struct_ptr: wmi command structure
  444. *
  445. *
  446. * vaidate the TLV's coming for an event/command and
  447. * also pads data to TLV's if necessary
  448. *
  449. * Return: 0 if success. Return < 0 if failure.
  450. */
  451. static int
  452. wmitlv_check_and_pad_tlvs(void *os_handle, void *param_struc_ptr,
  453. uint32_t param_buf_len, uint32_t is_cmd_id,
  454. uint32_t wmi_cmd_event_id, void **wmi_cmd_struct_ptr)
  455. {
  456. wmitlv_attributes_struc attr_struct_ptr;
  457. uint32_t buf_idx = 0;
  458. uint32_t tlv_index = 0;
  459. uint32_t num_of_elems = 0;
  460. int tlv_size_diff = 0;
  461. uint8_t *buf_ptr = (unsigned char *)param_struc_ptr;
  462. wmitlv_cmd_param_info *cmd_param_tlvs_ptr = NULL;
  463. uint32_t remaining_expected_tlvs = 0xFFFFFFFF;
  464. uint32_t len_wmi_cmd_struct_buf;
  465. uint32_t free_buf_len;
  466. int32_t error = -1;
  467. /* Get the number of TLVs for this command/event */
  468. if (wmitlv_get_attributes
  469. (is_cmd_id, wmi_cmd_event_id, WMITLV_GET_ATTRIB_NUM_TLVS,
  470. &attr_struct_ptr) != 0) {
  471. wmi_tlv_print_error
  472. ("%s: ERROR: Couldn't get expected number of TLVs for Cmd=%d\n",
  473. __func__, wmi_cmd_event_id);
  474. return error;
  475. }
  476. /* NOTE: the returned number of TLVs is in "attr_struct_ptr.cmd_num_tlv" */
  477. if (param_buf_len < WMI_TLV_HDR_SIZE) {
  478. wmi_tlv_print_error
  479. ("%s: ERROR: Incorrect param buf length passed\n",
  480. __func__);
  481. return error;
  482. }
  483. /* Create base structure of format wmi_cmd_event_id##_param_tlvs */
  484. len_wmi_cmd_struct_buf =
  485. attr_struct_ptr.cmd_num_tlv * sizeof(wmitlv_cmd_param_info);
  486. #ifndef NO_DYNAMIC_MEM_ALLOC
  487. /* Dynamic memory allocation supported */
  488. wmi_tlv_os_mem_alloc(os_handle, *wmi_cmd_struct_ptr,
  489. len_wmi_cmd_struct_buf);
  490. #else
  491. /* Dynamic memory allocation is not supported. Use the buffer
  492. * g_wmi_static_cmd_param_info_buf, which should be set using
  493. * wmi_tlv_set_static_param_tlv_buf(),
  494. * for base structure of format wmi_cmd_event_id##_param_tlvs */
  495. *wmi_cmd_struct_ptr = g_wmi_static_cmd_param_info_buf;
  496. if (attr_struct_ptr.cmd_num_tlv > g_wmi_static_max_cmd_param_tlvs) {
  497. /* Error: Expecting more TLVs that accomodated for static structure */
  498. wmi_tlv_print_error
  499. ("%s: Error: Expecting more TLVs that accomodated for static structure. Expected:%d Accomodated:%d\n",
  500. __func__, attr_struct_ptr.cmd_num_tlv,
  501. g_wmi_static_max_cmd_param_tlvs);
  502. return error;
  503. }
  504. #endif
  505. if (*wmi_cmd_struct_ptr == NULL) {
  506. /* Error: unable to alloc memory */
  507. wmi_tlv_print_error
  508. ("%s: Error: unable to alloc memory (size=%d) for TLV\n",
  509. __func__, len_wmi_cmd_struct_buf);
  510. return error;
  511. }
  512. cmd_param_tlvs_ptr = (wmitlv_cmd_param_info *) *wmi_cmd_struct_ptr;
  513. wmi_tlv_OS_MEMZERO(cmd_param_tlvs_ptr, len_wmi_cmd_struct_buf);
  514. remaining_expected_tlvs = attr_struct_ptr.cmd_num_tlv;
  515. while (((buf_idx + WMI_TLV_HDR_SIZE) <= param_buf_len)
  516. && (remaining_expected_tlvs)) {
  517. uint32_t curr_tlv_tag =
  518. WMITLV_GET_TLVTAG(WMITLV_GET_HDR(buf_ptr));
  519. uint32_t curr_tlv_len =
  520. WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr));
  521. int num_padding_bytes = 0;
  522. free_buf_len = param_buf_len - (buf_idx + WMI_TLV_HDR_SIZE);
  523. if (curr_tlv_len > free_buf_len) {
  524. wmi_tlv_print_error("%s: TLV length overflow",
  525. __func__);
  526. goto Error_wmitlv_check_and_pad_tlvs;
  527. }
  528. /* Get the attributes of the TLV with the given order in "tlv_index" */
  529. wmi_tlv_OS_MEMZERO(&attr_struct_ptr,
  530. sizeof(wmitlv_attributes_struc));
  531. if (wmitlv_get_attributes
  532. (is_cmd_id, wmi_cmd_event_id, tlv_index,
  533. &attr_struct_ptr) != 0) {
  534. wmi_tlv_print_error
  535. ("%s: ERROR: No TLV attributes found for Cmd=%d Tag_order=%d\n",
  536. __func__, wmi_cmd_event_id, tlv_index);
  537. goto Error_wmitlv_check_and_pad_tlvs;
  538. }
  539. /* Found the TLV that we wanted */
  540. wmi_tlv_print_verbose("%s: [tlv %d]: tag=%d, len=%d\n",
  541. __func__, tlv_index, curr_tlv_tag,
  542. curr_tlv_len);
  543. /* Validating Tag order */
  544. if (curr_tlv_tag != attr_struct_ptr.tag_id) {
  545. wmi_tlv_print_error
  546. ("%s: ERROR: TLV has wrong tag in order for Cmd=0x%x. Given=%d, Expected=%d.\n",
  547. __func__, wmi_cmd_event_id, curr_tlv_tag,
  548. attr_struct_ptr.tag_id);
  549. goto Error_wmitlv_check_and_pad_tlvs;
  550. }
  551. if ((curr_tlv_tag >= WMITLV_TAG_FIRST_ARRAY_ENUM)
  552. && (curr_tlv_tag <= WMITLV_TAG_LAST_ARRAY_ENUM)) {
  553. /* Current Tag is an array of some kind. */
  554. /* Skip the TLV header of this array */
  555. buf_ptr += WMI_TLV_HDR_SIZE;
  556. buf_idx += WMI_TLV_HDR_SIZE;
  557. } else {
  558. /* Non-array TLV. */
  559. curr_tlv_len += WMI_TLV_HDR_SIZE;
  560. }
  561. if (attr_struct_ptr.tag_varied_size == WMITLV_SIZE_FIX) {
  562. /* This TLV is fixed length */
  563. if (WMITLV_ARR_SIZE_INVALID ==
  564. attr_struct_ptr.tag_array_size) {
  565. tlv_size_diff =
  566. curr_tlv_len -
  567. attr_struct_ptr.tag_struct_size;
  568. num_of_elems =
  569. (curr_tlv_len > WMI_TLV_HDR_SIZE) ? 1 : 0;
  570. } else {
  571. tlv_size_diff =
  572. curr_tlv_len -
  573. (attr_struct_ptr.tag_struct_size *
  574. attr_struct_ptr.tag_array_size);
  575. num_of_elems = attr_struct_ptr.tag_array_size;
  576. }
  577. } else {
  578. /* This TLV has a variable number of elements */
  579. if (WMITLV_TAG_ARRAY_STRUC == attr_struct_ptr.tag_id) {
  580. uint32_t in_tlv_len = 0;
  581. if (curr_tlv_len != 0) {
  582. in_tlv_len =
  583. WMITLV_GET_TLVLEN(WMITLV_GET_HDR
  584. (buf_ptr));
  585. in_tlv_len += WMI_TLV_HDR_SIZE;
  586. if (in_tlv_len > curr_tlv_len) {
  587. wmi_tlv_print_error("%s: Invalid in_tlv_len=%d",
  588. __func__,
  589. in_tlv_len);
  590. goto
  591. Error_wmitlv_check_and_pad_tlvs;
  592. }
  593. tlv_size_diff =
  594. in_tlv_len -
  595. attr_struct_ptr.tag_struct_size;
  596. num_of_elems =
  597. curr_tlv_len / in_tlv_len;
  598. wmi_tlv_print_verbose
  599. ("%s: WARN: TLV array of structures in_tlv_len=%d struct_size:%d diff:%d num_of_elems=%d \n",
  600. __func__, in_tlv_len,
  601. attr_struct_ptr.tag_struct_size,
  602. tlv_size_diff, num_of_elems);
  603. } else {
  604. tlv_size_diff = 0;
  605. num_of_elems = 0;
  606. }
  607. } else
  608. if ((WMITLV_TAG_ARRAY_UINT32 ==
  609. attr_struct_ptr.tag_id)
  610. || (WMITLV_TAG_ARRAY_BYTE ==
  611. attr_struct_ptr.tag_id)
  612. || (WMITLV_TAG_ARRAY_FIXED_STRUC ==
  613. attr_struct_ptr.tag_id)) {
  614. tlv_size_diff = 0;
  615. num_of_elems =
  616. curr_tlv_len /
  617. attr_struct_ptr.tag_struct_size;
  618. } else {
  619. wmi_tlv_print_error
  620. ("%s ERROR Need to handle this tag ID for variable length %d\n",
  621. __func__, attr_struct_ptr.tag_id);
  622. goto Error_wmitlv_check_and_pad_tlvs;
  623. }
  624. }
  625. if ((WMITLV_TAG_ARRAY_STRUC == attr_struct_ptr.tag_id) &&
  626. (tlv_size_diff != 0)) {
  627. void *new_tlv_buf = NULL;
  628. uint8_t *tlv_buf_ptr = NULL;
  629. uint32_t in_tlv_len;
  630. uint32_t i;
  631. if (attr_struct_ptr.tag_varied_size == WMITLV_SIZE_FIX) {
  632. /* This is not allowed. The tag WMITLV_TAG_ARRAY_STRUC can
  633. * only be used with variable-length structure array
  634. * should not have a fixed number of elements (contradicting).
  635. * Use WMITLV_TAG_ARRAY_FIXED_STRUC tag for fixed size
  636. * structure array(where structure never change without
  637. * breaking compatibility) */
  638. wmi_tlv_print_error
  639. ("%s: ERROR: TLV (tag=%d) should be variable-length and not fixed length\n",
  640. __func__, curr_tlv_tag);
  641. goto Error_wmitlv_check_and_pad_tlvs;
  642. }
  643. /* Warning: Needs to allocate a larger structure and pad with zeros */
  644. wmi_tlv_print_verbose
  645. ("%s: WARN: TLV array of structures needs padding. tlv_size_diff=%d\n",
  646. __func__, tlv_size_diff);
  647. /* incoming structure length */
  648. in_tlv_len =
  649. WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr)) +
  650. WMI_TLV_HDR_SIZE;
  651. #ifndef NO_DYNAMIC_MEM_ALLOC
  652. wmi_tlv_os_mem_alloc(os_handle, new_tlv_buf,
  653. (num_of_elems *
  654. attr_struct_ptr.tag_struct_size));
  655. if (new_tlv_buf == NULL) {
  656. /* Error: unable to alloc memory */
  657. wmi_tlv_print_error
  658. ("%s: Error: unable to alloc memory (size=%d) for padding the TLV array %d\n",
  659. __func__,
  660. (num_of_elems *
  661. attr_struct_ptr.tag_struct_size),
  662. curr_tlv_tag);
  663. goto Error_wmitlv_check_and_pad_tlvs;
  664. }
  665. wmi_tlv_OS_MEMZERO(new_tlv_buf,
  666. (num_of_elems *
  667. attr_struct_ptr.tag_struct_size));
  668. tlv_buf_ptr = (uint8_t *) new_tlv_buf;
  669. for (i = 0; i < num_of_elems; i++) {
  670. if (tlv_size_diff > 0) {
  671. /* Incoming structure size is greater than expected
  672. * structure size. so copy the number of bytes equal
  673. * to expected structure size */
  674. wmi_tlv_OS_MEMCPY(tlv_buf_ptr,
  675. (void *)(buf_ptr +
  676. i *
  677. in_tlv_len),
  678. attr_struct_ptr.
  679. tag_struct_size);
  680. } else {
  681. /* Incoming structure size is smaller than expected
  682. * structure size. so copy the number of bytes equal
  683. * to incoming structure size */
  684. wmi_tlv_OS_MEMCPY(tlv_buf_ptr,
  685. (void *)(buf_ptr +
  686. i *
  687. in_tlv_len),
  688. in_tlv_len);
  689. }
  690. tlv_buf_ptr += attr_struct_ptr.tag_struct_size;
  691. }
  692. #else
  693. {
  694. uint8_t *src_addr;
  695. uint8_t *dst_addr;
  696. uint32_t buf_mov_len;
  697. if (tlv_size_diff < 0) {
  698. /* Incoming structure size is smaller than expected size
  699. * then this needs padding for each element in the array */
  700. /* Find amount of bytes to be padded for one element */
  701. num_padding_bytes = tlv_size_diff * -1;
  702. /* Move subsequent TLVs by number of bytes to be padded
  703. * for all elements */
  704. if ((free_buf_len <
  705. attr_struct_ptr.tag_struct_size *
  706. num_of_elems) ||
  707. (param_buf_len <
  708. buf_idx + curr_tlv_len +
  709. num_padding_bytes * num_of_elems)) {
  710. wmi_tlv_print_error("%s: Insufficent buffer\n",
  711. __func__);
  712. goto
  713. Error_wmitlv_check_and_pad_tlvs;
  714. } else {
  715. src_addr =
  716. buf_ptr + curr_tlv_len;
  717. dst_addr =
  718. buf_ptr + curr_tlv_len +
  719. (num_padding_bytes *
  720. num_of_elems);
  721. buf_mov_len =
  722. param_buf_len - (buf_idx +
  723. curr_tlv_len);
  724. wmi_tlv_OS_MEMMOVE(dst_addr,
  725. src_addr,
  726. buf_mov_len);
  727. }
  728. /* Move subsequent elements of array down by number of
  729. * bytes to be padded for one element and alse set
  730. * padding bytes to zero */
  731. tlv_buf_ptr = buf_ptr;
  732. for (i = 0; i < num_of_elems - 1; i++) {
  733. src_addr =
  734. tlv_buf_ptr + in_tlv_len;
  735. if (i != (num_of_elems - 1)) {
  736. dst_addr =
  737. tlv_buf_ptr +
  738. in_tlv_len +
  739. num_padding_bytes;
  740. buf_mov_len =
  741. curr_tlv_len -
  742. ((i +
  743. 1) * in_tlv_len);
  744. wmi_tlv_OS_MEMMOVE
  745. (dst_addr, src_addr,
  746. buf_mov_len);
  747. }
  748. /* Set the padding bytes to zeroes */
  749. wmi_tlv_OS_MEMZERO(src_addr,
  750. num_padding_bytes);
  751. tlv_buf_ptr +=
  752. attr_struct_ptr.
  753. tag_struct_size;
  754. }
  755. src_addr = tlv_buf_ptr + in_tlv_len;
  756. wmi_tlv_OS_MEMZERO(src_addr,
  757. num_padding_bytes);
  758. /* Update the number of padding bytes to total number
  759. * of bytes padded for all elements in the array */
  760. num_padding_bytes =
  761. num_padding_bytes * num_of_elems;
  762. new_tlv_buf = buf_ptr;
  763. } else {
  764. /* Incoming structure size is greater than expected size
  765. * then this needs shrinking for each element in the array */
  766. /* Find amount of bytes to be shrinked for one element */
  767. num_padding_bytes = tlv_size_diff * -1;
  768. /* Move subsequent elements of array up by number of bytes
  769. * to be shrinked for one element */
  770. tlv_buf_ptr = buf_ptr;
  771. for (i = 0; i < (num_of_elems - 1); i++) {
  772. src_addr =
  773. tlv_buf_ptr + in_tlv_len;
  774. dst_addr =
  775. tlv_buf_ptr + in_tlv_len +
  776. num_padding_bytes;
  777. buf_mov_len =
  778. curr_tlv_len -
  779. ((i + 1) * in_tlv_len);
  780. wmi_tlv_OS_MEMMOVE(dst_addr,
  781. src_addr,
  782. buf_mov_len);
  783. tlv_buf_ptr +=
  784. attr_struct_ptr.
  785. tag_struct_size;
  786. }
  787. /* Move subsequent TLVs by number of bytes to be shrinked
  788. * for all elements */
  789. if (param_buf_len >
  790. (buf_idx + curr_tlv_len)) {
  791. src_addr =
  792. buf_ptr + curr_tlv_len;
  793. dst_addr =
  794. buf_ptr + curr_tlv_len +
  795. (num_padding_bytes *
  796. num_of_elems);
  797. buf_mov_len =
  798. param_buf_len - (buf_idx +
  799. curr_tlv_len);
  800. wmi_tlv_OS_MEMMOVE(dst_addr,
  801. src_addr,
  802. buf_mov_len);
  803. }
  804. /* Update the number of padding bytes to total number of
  805. * bytes shrinked for all elements in the array */
  806. num_padding_bytes =
  807. num_padding_bytes * num_of_elems;
  808. new_tlv_buf = buf_ptr;
  809. }
  810. }
  811. #endif
  812. cmd_param_tlvs_ptr[tlv_index].tlv_ptr = new_tlv_buf;
  813. cmd_param_tlvs_ptr[tlv_index].num_elements =
  814. num_of_elems;
  815. cmd_param_tlvs_ptr[tlv_index].buf_is_allocated = 1; /* Indicates that buffer is allocated */
  816. } else if (tlv_size_diff >= 0) {
  817. /* Warning: some parameter truncation */
  818. if (tlv_size_diff > 0) {
  819. wmi_tlv_print_verbose
  820. ("%s: WARN: TLV truncated. tlv_size_diff=%d, curr_tlv_len=%d\n",
  821. __func__, tlv_size_diff, curr_tlv_len);
  822. }
  823. /* TODO: this next line needs more comments and explanation */
  824. cmd_param_tlvs_ptr[tlv_index].tlv_ptr =
  825. (attr_struct_ptr.tag_varied_size
  826. && !curr_tlv_len) ? NULL : (void *)buf_ptr;
  827. cmd_param_tlvs_ptr[tlv_index].num_elements =
  828. num_of_elems;
  829. cmd_param_tlvs_ptr[tlv_index].buf_is_allocated = 0; /* Indicates that buffer is not allocated */
  830. } else {
  831. void *new_tlv_buf = NULL;
  832. /* Warning: Needs to allocate a larger structure and pad with zeros */
  833. wmi_tlv_print_verbose
  834. ("%s: WARN: TLV needs padding. tlv_size_diff=%d\n",
  835. __func__, tlv_size_diff);
  836. #ifndef NO_DYNAMIC_MEM_ALLOC
  837. /* Dynamic memory allocation is supported */
  838. wmi_tlv_os_mem_alloc(os_handle, new_tlv_buf,
  839. (curr_tlv_len - tlv_size_diff));
  840. if (new_tlv_buf == NULL) {
  841. /* Error: unable to alloc memory */
  842. wmi_tlv_print_error
  843. ("%s: Error: unable to alloc memory (size=%d) for padding the TLV %d\n",
  844. __func__, (curr_tlv_len - tlv_size_diff),
  845. curr_tlv_tag);
  846. goto Error_wmitlv_check_and_pad_tlvs;
  847. }
  848. wmi_tlv_OS_MEMZERO(new_tlv_buf,
  849. (curr_tlv_len - tlv_size_diff));
  850. wmi_tlv_OS_MEMCPY(new_tlv_buf, (void *)buf_ptr,
  851. curr_tlv_len);
  852. #else
  853. /* Dynamic memory allocation is not supported. Padding has
  854. * to be done with in the existing buffer assuming we have
  855. * enough space to grow */
  856. {
  857. /* Note: tlv_size_diff is a value less than zero */
  858. /* Move the Subsequent TLVs by amount of bytes needs to be padded */
  859. uint8_t *src_addr;
  860. uint8_t *dst_addr;
  861. uint32_t src_len;
  862. num_padding_bytes = (tlv_size_diff * -1);
  863. src_addr = buf_ptr + curr_tlv_len;
  864. dst_addr =
  865. buf_ptr + curr_tlv_len + num_padding_bytes;
  866. src_len =
  867. param_buf_len - (buf_idx + curr_tlv_len);
  868. wmi_tlv_OS_MEMMOVE(dst_addr, src_addr, src_len);
  869. /* Set the padding bytes to zeroes */
  870. wmi_tlv_OS_MEMZERO(src_addr, num_padding_bytes);
  871. new_tlv_buf = buf_ptr;
  872. }
  873. #endif
  874. cmd_param_tlvs_ptr[tlv_index].tlv_ptr = new_tlv_buf;
  875. cmd_param_tlvs_ptr[tlv_index].num_elements =
  876. num_of_elems;
  877. cmd_param_tlvs_ptr[tlv_index].buf_is_allocated = 1; /* Indicates that buffer is allocated */
  878. }
  879. tlv_index++;
  880. remaining_expected_tlvs--;
  881. buf_ptr += curr_tlv_len + num_padding_bytes;
  882. buf_idx += curr_tlv_len + num_padding_bytes;
  883. }
  884. return 0;
  885. Error_wmitlv_check_and_pad_tlvs:
  886. if (is_cmd_id) {
  887. wmitlv_free_allocated_command_tlvs(wmi_cmd_event_id,
  888. wmi_cmd_struct_ptr);
  889. } else {
  890. wmitlv_free_allocated_event_tlvs(wmi_cmd_event_id,
  891. wmi_cmd_struct_ptr);
  892. }
  893. *wmi_cmd_struct_ptr = NULL;
  894. return error;
  895. }
  896. /**
  897. * wmitlv_check_and_pad_event_tlvs() - tlv helper function
  898. * @os_handle: os context handle
  899. * @param_struc_ptr: pointer to tlv structure
  900. * @param_buf_len: length of tlv parameter
  901. * @wmi_cmd_event_id: command event id
  902. * @wmi_cmd_struct_ptr: wmi command structure
  903. *
  904. *
  905. * validate and pad(if necessary) for incoming WMI Event TLVs
  906. *
  907. * Return: 0 if success. Return < 0 if failure.
  908. */
  909. int
  910. wmitlv_check_and_pad_event_tlvs(void *os_handle, void *param_struc_ptr,
  911. uint32_t param_buf_len,
  912. uint32_t wmi_cmd_event_id,
  913. void **wmi_cmd_struct_ptr)
  914. {
  915. uint32_t is_cmd_id = 0;
  916. return wmitlv_check_and_pad_tlvs
  917. (os_handle, param_struc_ptr, param_buf_len, is_cmd_id,
  918. wmi_cmd_event_id, wmi_cmd_struct_ptr);
  919. }
  920. qdf_export_symbol(wmitlv_check_and_pad_event_tlvs);
  921. /**
  922. * wmitlv_check_and_pad_command_tlvs() - tlv helper function
  923. * @os_handle: os context handle
  924. * @param_struc_ptr: pointer to tlv structure
  925. * @param_buf_len: length of tlv parameter
  926. * @wmi_cmd_event_id: command event id
  927. * @wmi_cmd_struct_ptr: wmi command structure
  928. *
  929. *
  930. * validate and pad(if necessary) for incoming WMI Command TLVs
  931. *
  932. * Return: 0 if success. Return < 0 if failure.
  933. */
  934. int
  935. wmitlv_check_and_pad_command_tlvs(void *os_handle, void *param_struc_ptr,
  936. uint32_t param_buf_len,
  937. uint32_t wmi_cmd_event_id,
  938. void **wmi_cmd_struct_ptr)
  939. {
  940. uint32_t is_cmd_id = 1;
  941. return wmitlv_check_and_pad_tlvs
  942. (os_handle, param_struc_ptr, param_buf_len, is_cmd_id,
  943. wmi_cmd_event_id, wmi_cmd_struct_ptr);
  944. }
  945. /**
  946. * wmitlv_free_allocated_tlvs() - tlv helper function
  947. * @is_cmd_id: bollean to check if cmd or event tlv
  948. * @cmd_event_id: command or event id
  949. * @wmi_cmd_struct_ptr: wmi command structure
  950. *
  951. *
  952. * free any allocated buffers for WMI Event/Command TLV processing
  953. *
  954. * Return: none
  955. */
  956. static void wmitlv_free_allocated_tlvs(uint32_t is_cmd_id,
  957. uint32_t cmd_event_id,
  958. void **wmi_cmd_struct_ptr)
  959. {
  960. void *ptr = *wmi_cmd_struct_ptr;
  961. if (!ptr) {
  962. wmi_tlv_print_error("%s: Nothing to free for CMD/Event 0x%x\n",
  963. __func__, cmd_event_id);
  964. return;
  965. }
  966. #ifndef NO_DYNAMIC_MEM_ALLOC
  967. /* macro to free that previously allocated memory for this TLV. When (op==FREE_TLV_ELEM). */
  968. #define WMITLV_OP_FREE_TLV_ELEM_macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \
  969. if ((((WMITLV_TYPEDEF_STRUCT_PARAMS_TLVS(wmi_cmd_event_id) *)ptr)->WMITLV_FIELD_BUF_IS_ALLOCATED(elem_name)) && \
  970. (((WMITLV_TYPEDEF_STRUCT_PARAMS_TLVS(wmi_cmd_event_id) *)ptr)->elem_name != NULL)) \
  971. { \
  972. wmi_tlv_os_mem_free(((WMITLV_TYPEDEF_STRUCT_PARAMS_TLVS(wmi_cmd_event_id) *)ptr)->elem_name); \
  973. }
  974. #define WMITLV_FREE_TLV_ELEMS(id) \
  975. case id: \
  976. { \
  977. WMITLV_TABLE(id, FREE_TLV_ELEM, NULL, 0) \
  978. } \
  979. break;
  980. if (is_cmd_id) {
  981. switch (cmd_event_id) {
  982. WMITLV_ALL_CMD_LIST(WMITLV_FREE_TLV_ELEMS);
  983. default:
  984. wmi_tlv_print_error
  985. ("%s: ERROR: Cannot find the TLVs attributes for Cmd=0x%x, %d\n",
  986. __func__, cmd_event_id, cmd_event_id);
  987. }
  988. } else {
  989. switch (cmd_event_id) {
  990. WMITLV_ALL_EVT_LIST(WMITLV_FREE_TLV_ELEMS);
  991. default:
  992. wmi_tlv_print_error
  993. ("%s: ERROR: Cannot find the TLVs attributes for Cmd=0x%x, %d\n",
  994. __func__, cmd_event_id, cmd_event_id);
  995. }
  996. }
  997. wmi_tlv_os_mem_free(*wmi_cmd_struct_ptr);
  998. *wmi_cmd_struct_ptr = NULL;
  999. #endif
  1000. return;
  1001. }
  1002. /**
  1003. * wmitlv_free_allocated_command_tlvs() - tlv helper function
  1004. * @cmd_event_id: command or event id
  1005. * @wmi_cmd_struct_ptr: wmi command structure
  1006. *
  1007. *
  1008. * free any allocated buffers for WMI Event/Command TLV processing
  1009. *
  1010. * Return: none
  1011. */
  1012. void wmitlv_free_allocated_command_tlvs(uint32_t cmd_event_id,
  1013. void **wmi_cmd_struct_ptr)
  1014. {
  1015. wmitlv_free_allocated_tlvs(1, cmd_event_id, wmi_cmd_struct_ptr);
  1016. }
  1017. /**
  1018. * wmitlv_free_allocated_event_tlvs() - tlv helper function
  1019. * @cmd_event_id: command or event id
  1020. * @wmi_cmd_struct_ptr: wmi command structure
  1021. *
  1022. *
  1023. * free any allocated buffers for WMI Event/Command TLV processing
  1024. *
  1025. * Return: none
  1026. */
  1027. void wmitlv_free_allocated_event_tlvs(uint32_t cmd_event_id,
  1028. void **wmi_cmd_struct_ptr)
  1029. {
  1030. wmitlv_free_allocated_tlvs(0, cmd_event_id, wmi_cmd_struct_ptr);
  1031. }
  1032. qdf_export_symbol(wmitlv_free_allocated_event_tlvs);
  1033. /**
  1034. * wmi_versions_are_compatible() - tlv helper function
  1035. * @vers1: host wmi version
  1036. * @vers2: target wmi version
  1037. *
  1038. *
  1039. * check if two given wmi versions are compatible
  1040. *
  1041. * Return: none
  1042. */
  1043. int
  1044. wmi_versions_are_compatible(wmi_abi_version *vers1, wmi_abi_version *vers2)
  1045. {
  1046. if ((vers1->abi_version_ns_0 != vers2->abi_version_ns_0) ||
  1047. (vers1->abi_version_ns_1 != vers2->abi_version_ns_1) ||
  1048. (vers1->abi_version_ns_2 != vers2->abi_version_ns_2) ||
  1049. (vers1->abi_version_ns_3 != vers2->abi_version_ns_3)) {
  1050. /* The namespaces are different. Incompatible. */
  1051. return 0;
  1052. }
  1053. if (vers1->abi_version_0 != vers2->abi_version_0) {
  1054. /* The major or minor versions are different. Incompatible */
  1055. return 0;
  1056. }
  1057. /* We ignore the build version */
  1058. return 1;
  1059. }
  1060. /**
  1061. * wmi_versions_can_downgrade() - tlv helper function
  1062. * @version_whitelist_table: version table
  1063. * @my_vers: host version
  1064. * @opp_vers: target version
  1065. * @out_vers: downgraded version
  1066. *
  1067. *
  1068. * check if target wmi version can be downgraded
  1069. *
  1070. * Return: 0 if success. Return < 0 if failure.
  1071. */
  1072. static int
  1073. wmi_versions_can_downgrade(int num_whitelist,
  1074. wmi_whitelist_version_info *version_whitelist_table,
  1075. wmi_abi_version *my_vers,
  1076. wmi_abi_version *opp_vers,
  1077. wmi_abi_version *out_vers)
  1078. {
  1079. uint8_t can_try_to_downgrade;
  1080. uint32_t my_major_vers = WMI_VER_GET_MAJOR(my_vers->abi_version_0);
  1081. uint32_t my_minor_vers = WMI_VER_GET_MINOR(my_vers->abi_version_0);
  1082. uint32_t opp_major_vers = WMI_VER_GET_MAJOR(opp_vers->abi_version_0);
  1083. uint32_t opp_minor_vers = WMI_VER_GET_MINOR(opp_vers->abi_version_0);
  1084. uint32_t downgraded_minor_vers;
  1085. if ((my_vers->abi_version_ns_0 != opp_vers->abi_version_ns_0) ||
  1086. (my_vers->abi_version_ns_1 != opp_vers->abi_version_ns_1) ||
  1087. (my_vers->abi_version_ns_2 != opp_vers->abi_version_ns_2) ||
  1088. (my_vers->abi_version_ns_3 != opp_vers->abi_version_ns_3)) {
  1089. /* The namespaces are different. Incompatible. */
  1090. can_try_to_downgrade = false;
  1091. } else if (my_major_vers != opp_major_vers) {
  1092. /* Major version is different. Incompatible and cannot downgrade. */
  1093. can_try_to_downgrade = false;
  1094. } else {
  1095. /* Same major version. */
  1096. if (my_minor_vers < opp_minor_vers) {
  1097. /* Opposite party is newer. Incompatible and cannot downgrade. */
  1098. can_try_to_downgrade = false;
  1099. } else if (my_minor_vers > opp_minor_vers) {
  1100. /* Opposite party is older. Check whitelist if we can downgrade */
  1101. can_try_to_downgrade = true;
  1102. } else {
  1103. /* Same version */
  1104. wmi_tlv_OS_MEMCPY(out_vers, my_vers,
  1105. sizeof(wmi_abi_version));
  1106. return 1;
  1107. }
  1108. }
  1109. if (!can_try_to_downgrade) {
  1110. wmi_tlv_print_error("%s: Warning: incompatible WMI version.\n",
  1111. __func__);
  1112. wmi_tlv_OS_MEMCPY(out_vers, my_vers, sizeof(wmi_abi_version));
  1113. return 0;
  1114. }
  1115. /* Try to see we can downgrade the supported version */
  1116. downgraded_minor_vers = my_minor_vers;
  1117. while (downgraded_minor_vers > opp_minor_vers) {
  1118. uint8_t downgraded = false;
  1119. int i;
  1120. for (i = 0; i < num_whitelist; i++) {
  1121. if (version_whitelist_table[i].major != my_major_vers) {
  1122. continue; /* skip */
  1123. }
  1124. if ((version_whitelist_table[i].namespace_0 !=
  1125. my_vers->abi_version_ns_0)
  1126. || (version_whitelist_table[i].namespace_1 !=
  1127. my_vers->abi_version_ns_1)
  1128. || (version_whitelist_table[i].namespace_2 !=
  1129. my_vers->abi_version_ns_2)
  1130. || (version_whitelist_table[i].namespace_3 !=
  1131. my_vers->abi_version_ns_3)) {
  1132. continue; /* skip */
  1133. }
  1134. if (version_whitelist_table[i].minor ==
  1135. downgraded_minor_vers) {
  1136. /* Found the next version that I can downgrade */
  1137. wmi_tlv_print_error
  1138. ("%s: Note: found a whitelist entry to downgrade. wh. list ver: %d,%d,0x%x 0x%x 0x%x 0x%x\n",
  1139. __func__, version_whitelist_table[i].major,
  1140. version_whitelist_table[i].minor,
  1141. version_whitelist_table[i].namespace_0,
  1142. version_whitelist_table[i].namespace_1,
  1143. version_whitelist_table[i].namespace_2,
  1144. version_whitelist_table[i].namespace_3);
  1145. downgraded_minor_vers--;
  1146. downgraded = true;
  1147. break;
  1148. }
  1149. }
  1150. if (!downgraded) {
  1151. break; /* Done since we did not find any whitelist to downgrade version */
  1152. }
  1153. }
  1154. wmi_tlv_OS_MEMCPY(out_vers, my_vers, sizeof(wmi_abi_version));
  1155. out_vers->abi_version_0 =
  1156. WMI_VER_GET_VERSION_0(my_major_vers, downgraded_minor_vers);
  1157. if (downgraded_minor_vers != opp_minor_vers) {
  1158. wmi_tlv_print_error
  1159. ("%s: Warning: incompatible WMI version and cannot downgrade.\n",
  1160. __func__);
  1161. return 0; /* Incompatible */
  1162. } else {
  1163. return 1; /* Compatible */
  1164. }
  1165. }
  1166. /**
  1167. * wmi_cmp_and_set_abi_version() - tlv helper function
  1168. * @version_whitelist_table: version table
  1169. * @my_vers: host version
  1170. * @opp_vers: target version
  1171. * @out_vers: downgraded version
  1172. *
  1173. * This routine will compare and set the WMI ABI version.
  1174. * First, compare my version with the opposite side's version.
  1175. * If incompatible, then check the whitelist to see if our side can downgrade.
  1176. * Finally, fill in the final ABI version into the output, out_vers.
  1177. * Return 0 if the output version is compatible
  1178. * Else return 1 if the output version is incompatible
  1179. *
  1180. * Return: 0 if the output version is compatible else < 0.
  1181. */
  1182. int
  1183. wmi_cmp_and_set_abi_version(int num_whitelist,
  1184. wmi_whitelist_version_info *
  1185. version_whitelist_table,
  1186. struct _wmi_abi_version *my_vers,
  1187. struct _wmi_abi_version *opp_vers,
  1188. struct _wmi_abi_version *out_vers)
  1189. {
  1190. wmi_tlv_print_verbose
  1191. ("%s: Our WMI Version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n",
  1192. __func__, WMI_VER_GET_MAJOR(my_vers->abi_version_0),
  1193. WMI_VER_GET_MINOR(my_vers->abi_version_0), my_vers->abi_version_1,
  1194. my_vers->abi_version_ns_0, my_vers->abi_version_ns_1,
  1195. my_vers->abi_version_ns_2, my_vers->abi_version_ns_3);
  1196. wmi_tlv_print_verbose
  1197. ("%s: Opposite side WMI Version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n",
  1198. __func__, WMI_VER_GET_MAJOR(opp_vers->abi_version_0),
  1199. WMI_VER_GET_MINOR(opp_vers->abi_version_0),
  1200. opp_vers->abi_version_1, opp_vers->abi_version_ns_0,
  1201. opp_vers->abi_version_ns_1, opp_vers->abi_version_ns_2,
  1202. opp_vers->abi_version_ns_3);
  1203. /* By default, the output version is our version. */
  1204. wmi_tlv_OS_MEMCPY(out_vers, my_vers, sizeof(wmi_abi_version));
  1205. if (!wmi_versions_are_compatible(my_vers, opp_vers)) {
  1206. /* Our host version and the given firmware version are incompatible. */
  1207. if (wmi_versions_can_downgrade
  1208. (num_whitelist, version_whitelist_table, my_vers, opp_vers,
  1209. out_vers)) {
  1210. /* We can downgrade our host versions to match firmware. */
  1211. wmi_tlv_print_error
  1212. ("%s: Host downgraded WMI Versions to match fw. Ret version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n",
  1213. __func__,
  1214. WMI_VER_GET_MAJOR(out_vers->abi_version_0),
  1215. WMI_VER_GET_MINOR(out_vers->abi_version_0),
  1216. out_vers->abi_version_1,
  1217. out_vers->abi_version_ns_0,
  1218. out_vers->abi_version_ns_1,
  1219. out_vers->abi_version_ns_2,
  1220. out_vers->abi_version_ns_3);
  1221. return 0; /* Compatible */
  1222. } else {
  1223. /* Warn: We cannot downgrade our host versions to match firmware. */
  1224. wmi_tlv_print_error
  1225. ("%s: WARN: Host WMI Versions mismatch with fw. Ret version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n",
  1226. __func__,
  1227. WMI_VER_GET_MAJOR(out_vers->abi_version_0),
  1228. WMI_VER_GET_MINOR(out_vers->abi_version_0),
  1229. out_vers->abi_version_1,
  1230. out_vers->abi_version_ns_0,
  1231. out_vers->abi_version_ns_1,
  1232. out_vers->abi_version_ns_2,
  1233. out_vers->abi_version_ns_3);
  1234. return 1; /* Incompatible */
  1235. }
  1236. } else {
  1237. /* We are compatible. Our host version is the output version */
  1238. wmi_tlv_print_verbose
  1239. ("%s: Host and FW Compatible WMI Versions. Ret version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n",
  1240. __func__, WMI_VER_GET_MAJOR(out_vers->abi_version_0),
  1241. WMI_VER_GET_MINOR(out_vers->abi_version_0),
  1242. out_vers->abi_version_1, out_vers->abi_version_ns_0,
  1243. out_vers->abi_version_ns_1, out_vers->abi_version_ns_2,
  1244. out_vers->abi_version_ns_3);
  1245. return 0; /* Compatible */
  1246. }
  1247. }