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