1 /*
2 * Bit packing and Base64 utils for EWP
3 *
4 * Copyright (C) 2020, Broadcom.
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 *
21 * <<Broadcom-WL-IPTag/Open:>>
22 *
23 * $Id$
24 */
25
26 #include <dhd_bitpack.h>
27
28 #define BIT_PACK_OVERFLOW 0xFFFFFFFFu
29
30 const char* base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
31
32 #define BASE64_MAX_VALUE 63u
33
34 #define BASE64_UNIT_LEN 6u
35
36 #define BASE64_OFFSET0 0u
37 #define BASE64_OFFSET1 6u
38 #define BASE64_OFFSET2 12u
39
40 #define MASK_UPPER_6BIT 0xfc
41 #define MASK_LOWER_6BIT 0x3f
42
43 #define MASK_UPPER_4BIT 0xf0
44 #define MASK_LOWER_4BIT 0x0f
45
46 #define MASK_UPPER_2BIT 0xc0
47 #define MASK_LOWER_2BIT 0x03
48
49 #define SHIFT_2BIT 2u
50 #define SHIFT_4BIT 4u
51 #define SHIFT_6BIT 6u
52
53 #define BASE64_PADDING_MARGIN 4u
54
55 /*
56 * Function: dhd_bit_pack
57 *
58 * Purpose: bit data packing to given buffer
59 *
60 * Input Parameters:
61 * buf buffer to pack bit data
62 * buf_len total buffer length
63 * bit_offset offset in buffer (bitwise)
64 * data data to pack (max 32 bit)
65 * bit_length bit length to pack
66 *
67 * Output:
68 * Updated bit offset in buf
69 */
70 int32
dhd_bit_pack(char * buf,int buf_len,int bit_offset,uint32 data,int32 bit_length)71 dhd_bit_pack(char *buf, int buf_len, int bit_offset, uint32 data, int32 bit_length)
72 {
73
74 int32 byte_shift = (bit_offset / 8);
75 int32 local_bit_offset = bit_offset % 8;
76 int32 available_bit = 8 - local_bit_offset;
77 int32 remain_bit = bit_length;
78 uint32 cropped_data;
79 int32 idx;
80 int32 total_byte = BYTE_SIZE(local_bit_offset + bit_length);
81
82 if (bit_length > 32) {
83 /* exceeded max bit length, do nothing */
84 return bit_offset;
85 }
86 if (BYTE_SIZE(bit_offset + bit_length) > buf_len) {
87 /* can't pack more bits if expected offset is
88 * exceeded then buffer size
89 */
90 return bit_offset;
91 }
92 if (bit_length < 32 && data >= 1<<bit_length) {
93 cropped_data = BIT_PACK_OVERFLOW << (32 - bit_length);
94 cropped_data = cropped_data >> (32 - bit_length);
95 } else {
96 cropped_data = data << (32 - bit_length);
97 cropped_data = cropped_data >> (32 - bit_length);
98 }
99
100 buf += byte_shift;
101
102 remain_bit = bit_length;
103 if (total_byte > 10) {
104 return bit_offset;
105 }
106 for (idx = 0; idx < total_byte; idx++) {
107 char temp_byte = 0x00;
108 if (idx == 0) {
109 local_bit_offset = bit_offset % 8;
110 } else {
111 local_bit_offset = 0;
112 }
113
114 available_bit = 8 - local_bit_offset;
115 remain_bit -= available_bit;
116 if (remain_bit >= 0) {
117 temp_byte = cropped_data >> remain_bit;
118 } else {
119 temp_byte = cropped_data << (-1*remain_bit);
120 }
121 *buf = *buf | temp_byte;
122 buf ++;
123 }
124 bit_offset += bit_length;
125
126 return bit_offset;
127 }
128
129 static char
dhd_base64_get_code(char input)130 dhd_base64_get_code(char input)
131 {
132 if (input > BASE64_MAX_VALUE) {
133 return '=';
134 }
135 return base64_table[(int)input];
136 }
137
138 /*
139 * Function: dhd_base64_encode
140 *
141 * Purpose: base64 encoding module which converts from 8 bits to
142 * 6 bit based, base64 format using base64_table
143 * eg: input: hex-123456
144 * bin-0001|0010|0011|0100|0101|0110
145 * encode every 6 bit :
146 * bin-000100|100011|010001|010110
147 * base64 code :
148 * base64-EjRW
149 *
150 * Input Parameters:
151 * in_buf input buffer
152 * in_buf_len length of input buffer
153 * out_buf output buffer
154 * out_buf_len length_ of output buffer
155 *
156 * Output:
157 * length of encoded base64 string
158 */
159 int32
dhd_base64_encode(char * in_buf,int32 in_buf_len,char * out_buf,int32 out_buf_len)160 dhd_base64_encode(char* in_buf, int32 in_buf_len, char* out_buf, int32 out_buf_len)
161 {
162 char* input_pos;
163 char* input_end;
164 char* base64_out;
165 char* base64_out_pos;
166 char* base64_output_end;
167 char current_byte = 0;
168 char masked_byte = 0;
169 int32 estimated_out_len = 0;
170 int32 offset = 0;
171
172 if (!in_buf || !out_buf || in_buf_len == 0 || out_buf_len == 0) {
173 /* wrong input parameters */
174 return 0;
175 }
176
177 input_pos = in_buf;
178 input_end = in_buf + in_buf_len;
179 base64_out = out_buf;
180 base64_out_pos = base64_out;
181 base64_output_end = out_buf + out_buf_len - BASE64_PADDING_MARGIN;
182 estimated_out_len = in_buf_len / 3 * 4;
183
184 if (estimated_out_len > out_buf_len) {
185 /* estimated output length is
186 * larger than output buffer size
187 */
188 return 0;
189 }
190
191 while (input_pos != input_end) {
192 if (base64_out_pos > base64_output_end) {
193 /* outbuf buffer size exceeded, finish encoding */
194 break;
195 }
196 if (offset == BASE64_OFFSET0) {
197 current_byte = *input_pos++;
198 masked_byte = (current_byte & MASK_UPPER_6BIT) >> SHIFT_2BIT;
199 *base64_out_pos++ = dhd_base64_get_code(masked_byte);
200 masked_byte = (current_byte & MASK_LOWER_2BIT) << SHIFT_4BIT;
201 offset += BASE64_UNIT_LEN;
202 } else if (offset == BASE64_OFFSET1) {
203 current_byte = *input_pos++;
204 masked_byte |= (current_byte & MASK_UPPER_4BIT) >> SHIFT_4BIT;
205 *base64_out_pos++ = dhd_base64_get_code(masked_byte);
206 masked_byte = (current_byte & MASK_LOWER_4BIT) << SHIFT_2BIT;
207 offset += BASE64_UNIT_LEN;
208 } else if (offset == BASE64_OFFSET2) {
209 current_byte = *input_pos++;
210 masked_byte |= (current_byte & MASK_UPPER_2BIT) >> SHIFT_6BIT;
211 *base64_out_pos++ = dhd_base64_get_code(masked_byte);
212 offset += BASE64_UNIT_LEN;
213 masked_byte = (current_byte & MASK_LOWER_6BIT);
214 *base64_out_pos++ = dhd_base64_get_code(masked_byte);
215 offset = BASE64_OFFSET0;
216 }
217 }
218 if (offset == BASE64_OFFSET1) {
219 *base64_out_pos++ = dhd_base64_get_code(masked_byte);
220 *base64_out_pos++ = '=';
221 *base64_out_pos++ = '=';
222 } else if (offset == BASE64_OFFSET2) {
223 *base64_out_pos++ = dhd_base64_get_code(masked_byte);
224 *base64_out_pos++ = '=';
225 }
226
227 return base64_out_pos - base64_out;
228 }
229