/* * Bit packing and Base64 utils for EWP * * Copyright (C) 2020, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that * you also meet, for each linked independent module, the terms and conditions of * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. * * * <> * * $Id$ */ #include #define BIT_PACK_OVERFLOW 0xFFFFFFFFu const char* base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; #define BASE64_MAX_VALUE 63u #define BASE64_UNIT_LEN 6u #define BASE64_OFFSET0 0u #define BASE64_OFFSET1 6u #define BASE64_OFFSET2 12u #define MASK_UPPER_6BIT 0xfc #define MASK_LOWER_6BIT 0x3f #define MASK_UPPER_4BIT 0xf0 #define MASK_LOWER_4BIT 0x0f #define MASK_UPPER_2BIT 0xc0 #define MASK_LOWER_2BIT 0x03 #define SHIFT_2BIT 2u #define SHIFT_4BIT 4u #define SHIFT_6BIT 6u #define BASE64_PADDING_MARGIN 4u /* * Function: dhd_bit_pack * * Purpose: bit data packing to given buffer * * Input Parameters: * buf buffer to pack bit data * buf_len total buffer length * bit_offset offset in buffer (bitwise) * data data to pack (max 32 bit) * bit_length bit length to pack * * Output: * Updated bit offset in buf */ int32 dhd_bit_pack(char *buf, int buf_len, int bit_offset, uint32 data, int32 bit_length) { int32 byte_shift = (bit_offset / 8); int32 local_bit_offset = bit_offset % 8; int32 available_bit = 8 - local_bit_offset; int32 remain_bit = bit_length; uint32 cropped_data; int32 idx; int32 total_byte = BYTE_SIZE(local_bit_offset + bit_length); if (bit_length > 32) { /* exceeded max bit length, do nothing */ return bit_offset; } if (BYTE_SIZE(bit_offset + bit_length) > buf_len) { /* can't pack more bits if expected offset is * exceeded then buffer size */ return bit_offset; } if (bit_length < 32 && data >= 1<> (32 - bit_length); } else { cropped_data = data << (32 - bit_length); cropped_data = cropped_data >> (32 - bit_length); } buf += byte_shift; remain_bit = bit_length; if (total_byte > 10) { return bit_offset; } for (idx = 0; idx < total_byte; idx++) { char temp_byte = 0x00; if (idx == 0) { local_bit_offset = bit_offset % 8; } else { local_bit_offset = 0; } available_bit = 8 - local_bit_offset; remain_bit -= available_bit; if (remain_bit >= 0) { temp_byte = cropped_data >> remain_bit; } else { temp_byte = cropped_data << (-1*remain_bit); } *buf = *buf | temp_byte; buf ++; } bit_offset += bit_length; return bit_offset; } static char dhd_base64_get_code(char input) { if (input > BASE64_MAX_VALUE) { return '='; } return base64_table[(int)input]; } /* * Function: dhd_base64_encode * * Purpose: base64 encoding module which converts from 8 bits to * 6 bit based, base64 format using base64_table * eg: input: hex-123456 * bin-0001|0010|0011|0100|0101|0110 * encode every 6 bit : * bin-000100|100011|010001|010110 * base64 code : * base64-EjRW * * Input Parameters: * in_buf input buffer * in_buf_len length of input buffer * out_buf output buffer * out_buf_len length_ of output buffer * * Output: * length of encoded base64 string */ int32 dhd_base64_encode(char* in_buf, int32 in_buf_len, char* out_buf, int32 out_buf_len) { char* input_pos; char* input_end; char* base64_out; char* base64_out_pos; char* base64_output_end; char current_byte = 0; char masked_byte = 0; int32 estimated_out_len = 0; int32 offset = 0; if (!in_buf || !out_buf || in_buf_len == 0 || out_buf_len == 0) { /* wrong input parameters */ return 0; } input_pos = in_buf; input_end = in_buf + in_buf_len; base64_out = out_buf; base64_out_pos = base64_out; base64_output_end = out_buf + out_buf_len - BASE64_PADDING_MARGIN; estimated_out_len = in_buf_len / 3 * 4; if (estimated_out_len > out_buf_len) { /* estimated output length is * larger than output buffer size */ return 0; } while (input_pos != input_end) { if (base64_out_pos > base64_output_end) { /* outbuf buffer size exceeded, finish encoding */ break; } if (offset == BASE64_OFFSET0) { current_byte = *input_pos++; masked_byte = (current_byte & MASK_UPPER_6BIT) >> SHIFT_2BIT; *base64_out_pos++ = dhd_base64_get_code(masked_byte); masked_byte = (current_byte & MASK_LOWER_2BIT) << SHIFT_4BIT; offset += BASE64_UNIT_LEN; } else if (offset == BASE64_OFFSET1) { current_byte = *input_pos++; masked_byte |= (current_byte & MASK_UPPER_4BIT) >> SHIFT_4BIT; *base64_out_pos++ = dhd_base64_get_code(masked_byte); masked_byte = (current_byte & MASK_LOWER_4BIT) << SHIFT_2BIT; offset += BASE64_UNIT_LEN; } else if (offset == BASE64_OFFSET2) { current_byte = *input_pos++; masked_byte |= (current_byte & MASK_UPPER_2BIT) >> SHIFT_6BIT; *base64_out_pos++ = dhd_base64_get_code(masked_byte); offset += BASE64_UNIT_LEN; masked_byte = (current_byte & MASK_LOWER_6BIT); *base64_out_pos++ = dhd_base64_get_code(masked_byte); offset = BASE64_OFFSET0; } } if (offset == BASE64_OFFSET1) { *base64_out_pos++ = dhd_base64_get_code(masked_byte); *base64_out_pos++ = '='; *base64_out_pos++ = '='; } else if (offset == BASE64_OFFSET2) { *base64_out_pos++ = dhd_base64_get_code(masked_byte); *base64_out_pos++ = '='; } return base64_out_pos - base64_out; }