frag.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /*
  2. * IE/TLV fragmentation/defragmentation support for
  3. * Broadcom 802.11bang Networking Device Driver
  4. *
  5. * Portions of this code are copyright (c) 2020 Cypress Semiconductor Corporation
  6. *
  7. * Copyright (C) 1999-2020, Broadcom Corporation
  8. *
  9. * Unless you and Broadcom execute a separate written software license
  10. * agreement governing use of this software, this software is licensed to you
  11. * under the terms of the GNU General Public License version 2 (the "GPL"),
  12. * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  13. * following added to such license:
  14. *
  15. * As a special exception, the copyright holders of this software give you
  16. * permission to link this software with independent modules, and to copy and
  17. * distribute the resulting executable under terms of your choice, provided that
  18. * you also meet, for each linked independent module, the terms and conditions of
  19. * the license of that module. An independent module is a module which is not
  20. * derived from this software. The special exception does not apply to any
  21. * modifications of the software.
  22. *
  23. * Notwithstanding the above, under no circumstances may you combine this
  24. * software in any way with any other Broadcom software provided under a license
  25. * other than the GPL, without Broadcom's express prior written consent.
  26. * $Id$
  27. *
  28. * <<Broadcom-WL-IPTag/Open:>>
  29. */
  30. #include <bcmutils.h>
  31. #include <frag.h>
  32. #include <802.11.h>
  33. /* defrag a fragmented dot11 ie/tlv. if space does not permit, return the needed
  34. * ie length to contain all the fragments with status BCME_BUFTOOSHORT.
  35. * out_len is in/out parameter, max length on input, used/required length on output
  36. */
  37. int
  38. bcm_tlv_dot11_defrag(const void *buf, uint buf_len, uint8 id, bool id_ext,
  39. uint8 *out, uint *out_len)
  40. {
  41. int err = BCME_OK;
  42. const bcm_tlv_t *ie;
  43. uint tot_len = 0;
  44. uint out_left;
  45. /* find the ie; includes validation */
  46. ie = bcm_parse_tlvs_dot11(buf, buf_len, id, id_ext);
  47. if (!ie) {
  48. err = BCME_IE_NOTFOUND;
  49. goto done;
  50. }
  51. out_left = (out && out_len) ? *out_len : 0;
  52. /* first fragment */
  53. tot_len = id_ext ? ie->len - 1 : ie->len;
  54. /* copy out if output space permits */
  55. if (out_left < tot_len) {
  56. err = BCME_BUFTOOSHORT;
  57. out_left = 0; /* prevent further copy */
  58. } else {
  59. memcpy(out, &ie->data[id_ext ? 1 : 0], tot_len);
  60. out += tot_len;
  61. out_left -= tot_len;
  62. }
  63. /* if not fragmened or not fragmentable per 802.11 table 9-77 11md0.1 bail
  64. * we can introduce the latter check later
  65. */
  66. if (ie->len != BCM_TLV_MAX_DATA_SIZE) {
  67. goto done;
  68. }
  69. /* adjust buf_len to length after ie including it */
  70. buf_len -= (uint)(((const uint8 *)ie - (const uint8 *)buf));
  71. /* update length from fragments, okay if no next ie */
  72. while ((ie = bcm_next_tlv(ie, &buf_len)) &&
  73. (ie->id == DOT11_MNG_FRAGMENT_ID)) {
  74. /* note: buf_len starts at next ie and last frag may be partial */
  75. if (out_left < ie->len) {
  76. err = BCME_BUFTOOSHORT;
  77. out_left = 0;
  78. } else {
  79. memcpy(out, &ie->data[0], ie->len);
  80. out += ie->len;
  81. out_left -= ie->len;
  82. }
  83. tot_len += ie->len + BCM_TLV_HDR_SIZE;
  84. /* all but last should be of max size */
  85. if (ie->len < BCM_TLV_MAX_DATA_SIZE) {
  86. break;
  87. }
  88. }
  89. done:
  90. if (out_len) {
  91. *out_len = tot_len;
  92. }
  93. return err;
  94. }
  95. int
  96. bcm_tlv_dot11_frag_tot_len(const void *buf, uint buf_len,
  97. uint8 id, bool id_ext, uint *ie_len)
  98. {
  99. return bcm_tlv_dot11_defrag(buf, buf_len, id, id_ext, NULL, ie_len);
  100. }