| /* |
| * 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. |
| * |
| * |
| * <<Broadcom-WL-IPTag/Open:>> |
| * |
| * $Id$ |
| */ |
| |
| #include <dhd_bitpack.h> |
| |
| #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<<bit_length) { |
| cropped_data = BIT_PACK_OVERFLOW << (32 - bit_length); |
| cropped_data = cropped_data >> (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; |
| } |