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