dfltcc_inflate.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // SPDX-License-Identifier: Zlib
  2. #include "../zlib_inflate/inflate.h"
  3. #include "dfltcc_util.h"
  4. #include "dfltcc_inflate.h"
  5. #include <asm/setup.h>
  6. #include <linux/export.h>
  7. #include <linux/zutil.h>
  8. /*
  9. * Expand.
  10. */
  11. int dfltcc_can_inflate(
  12. z_streamp strm
  13. )
  14. {
  15. struct inflate_state *state = (struct inflate_state *)strm->state;
  16. struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
  17. /* Check for kernel dfltcc command line parameter */
  18. if (zlib_dfltcc_support == ZLIB_DFLTCC_DISABLED ||
  19. zlib_dfltcc_support == ZLIB_DFLTCC_DEFLATE_ONLY)
  20. return 0;
  21. /* Unsupported hardware */
  22. return is_bit_set(dfltcc_state->af.fns, DFLTCC_XPND) &&
  23. is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0);
  24. }
  25. EXPORT_SYMBOL(dfltcc_can_inflate);
  26. void dfltcc_reset_inflate_state(z_streamp strm) {
  27. struct inflate_state *state = (struct inflate_state *)strm->state;
  28. struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
  29. dfltcc_reset_state(dfltcc_state);
  30. }
  31. EXPORT_SYMBOL(dfltcc_reset_inflate_state);
  32. static int dfltcc_was_inflate_used(
  33. z_streamp strm
  34. )
  35. {
  36. struct inflate_state *state = (struct inflate_state *)strm->state;
  37. struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
  38. return !param->nt;
  39. }
  40. static int dfltcc_inflate_disable(
  41. z_streamp strm
  42. )
  43. {
  44. struct inflate_state *state = (struct inflate_state *)strm->state;
  45. struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
  46. if (!dfltcc_can_inflate(strm))
  47. return 0;
  48. if (dfltcc_was_inflate_used(strm))
  49. /* DFLTCC has already decompressed some data. Since there is not
  50. * enough information to resume decompression in software, the call
  51. * must fail.
  52. */
  53. return 1;
  54. /* DFLTCC was not used yet - decompress in software */
  55. memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af));
  56. return 0;
  57. }
  58. static dfltcc_cc dfltcc_xpnd(
  59. z_streamp strm
  60. )
  61. {
  62. struct inflate_state *state = (struct inflate_state *)strm->state;
  63. struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
  64. size_t avail_in = strm->avail_in;
  65. size_t avail_out = strm->avail_out;
  66. dfltcc_cc cc;
  67. cc = dfltcc(DFLTCC_XPND | HBT_CIRCULAR,
  68. param, &strm->next_out, &avail_out,
  69. &strm->next_in, &avail_in, state->window);
  70. strm->avail_in = avail_in;
  71. strm->avail_out = avail_out;
  72. return cc;
  73. }
  74. dfltcc_inflate_action dfltcc_inflate(
  75. z_streamp strm,
  76. int flush,
  77. int *ret
  78. )
  79. {
  80. struct inflate_state *state = (struct inflate_state *)strm->state;
  81. struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
  82. struct dfltcc_param_v0 *param = &dfltcc_state->param;
  83. dfltcc_cc cc;
  84. if (flush == Z_BLOCK || flush == Z_PACKET_FLUSH) {
  85. /* DFLTCC does not support stopping on block boundaries (Z_BLOCK flush option)
  86. * as well as the use of Z_PACKET_FLUSH option (used exclusively by PPP driver)
  87. */
  88. if (dfltcc_inflate_disable(strm)) {
  89. *ret = Z_STREAM_ERROR;
  90. return DFLTCC_INFLATE_BREAK;
  91. } else
  92. return DFLTCC_INFLATE_SOFTWARE;
  93. }
  94. if (state->last) {
  95. if (state->bits != 0) {
  96. strm->next_in++;
  97. strm->avail_in--;
  98. state->bits = 0;
  99. }
  100. state->mode = CHECK;
  101. return DFLTCC_INFLATE_CONTINUE;
  102. }
  103. if (strm->avail_in == 0 && !param->cf)
  104. return DFLTCC_INFLATE_BREAK;
  105. if (!state->window || state->wsize == 0) {
  106. state->mode = MEM;
  107. return DFLTCC_INFLATE_CONTINUE;
  108. }
  109. /* Translate stream to parameter block */
  110. param->cvt = CVT_ADLER32;
  111. param->sbb = state->bits;
  112. if (param->hl)
  113. param->nt = 0; /* Honor history for the first block */
  114. param->cv = state->check;
  115. /* Inflate */
  116. do {
  117. cc = dfltcc_xpnd(strm);
  118. } while (cc == DFLTCC_CC_AGAIN);
  119. /* Translate parameter block to stream */
  120. strm->msg = oesc_msg(dfltcc_state->msg, param->oesc);
  121. state->last = cc == DFLTCC_CC_OK;
  122. state->bits = param->sbb;
  123. state->check = param->cv;
  124. if (cc == DFLTCC_CC_OP2_CORRUPT && param->oesc != 0) {
  125. /* Report an error if stream is corrupted */
  126. state->mode = BAD;
  127. return DFLTCC_INFLATE_CONTINUE;
  128. }
  129. state->mode = TYPEDO;
  130. /* Break if operands are exhausted, otherwise continue looping */
  131. return (cc == DFLTCC_CC_OP1_TOO_SHORT || cc == DFLTCC_CC_OP2_TOO_SHORT) ?
  132. DFLTCC_INFLATE_BREAK : DFLTCC_INFLATE_CONTINUE;
  133. }
  134. EXPORT_SYMBOL(dfltcc_inflate);