wmi_tlv_helper.c 42 KB

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