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 */
13int 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(bits: dfltcc_state->af.fns, DFLTCC_XPND) &&
27 is_bit_set(bits: dfltcc_state->af.fmts, DFLTCC_FMT0);
28}
29EXPORT_SYMBOL(dfltcc_can_inflate);
30
31void 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}
37EXPORT_SYMBOL(dfltcc_reset_inflate_state);
38
39static 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
49static 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
69static 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, op1: &strm->next_out, len1: &avail_out,
81 op2: &strm->next_in, len2: &avail_in, hist: state->window);
82 strm->avail_in = avail_in;
83 strm->avail_out = avail_out;
84 return cc;
85}
86
87dfltcc_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(buf: dfltcc_state->msg, oesc: 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}
154EXPORT_SYMBOL(dfltcc_inflate);
155

source code of linux/lib/zlib_dfltcc/dfltcc_inflate.c