lineage_kernel_xcoverpro/drivers/net/wireless/scsc/mib_text_convert.c

344 lines
10 KiB
C
Executable File

/******************************************************************************
*
* Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd and its Licensors.
* All rights reserved.
*
*****************************************************************************/
#include "debug.h"
#include "mib_text_convert.h"
#define CSR_TOUPPER(character) (((character) >= 'a') && ((character) <= 'z') ? ((character) - 0x20) : (character))
static inline bool CsrIsSpace(u8 c)
{
switch (c) {
case '\t':
case '\n':
case '\f':
case '\r':
case ' ':
return true;
default:
return false;
}
}
static inline char *CsrStrDup(const char *string)
{
if (string) {
u32 len = strlen(string) + 1;
char *result = kmalloc(len, GFP_KERNEL);
if (result)
return memcpy(result, string, len);
}
return NULL;
}
static int CsrStrNICmp(const char *string1,
const char *string2,
size_t count)
{
u32 index;
int returnValue = 0;
for (index = 0; index < count; index++) {
if (CSR_TOUPPER(string1[index]) != CSR_TOUPPER(string2[index])) {
if (CSR_TOUPPER(string1[index]) > CSR_TOUPPER(string2[index]))
returnValue = 1;
else
returnValue = -1;
break;
}
if (string1[index] == '\0')
break;
}
return returnValue;
}
static bool CsrHexStrToUint8(const char *string, u8 *returnValue)
{
u16 currentIndex = 0;
*returnValue = 0;
if ((string[currentIndex] == '0') && (CSR_TOUPPER(string[currentIndex + 1]) == 'X'))
string += 2;
if (((string[currentIndex] >= '0') && (string[currentIndex] <= '9')) || ((CSR_TOUPPER(string[currentIndex]) >= 'A') && (CSR_TOUPPER(string[currentIndex]) <= 'F'))) {
while (((string[currentIndex] >= '0') && (string[currentIndex] <= '9')) || ((CSR_TOUPPER(string[currentIndex]) >= 'A') && (CSR_TOUPPER(string[currentIndex]) <= 'F'))) {
*returnValue = (u8)(*returnValue * 16 + (((string[currentIndex] >= '0') && (string[currentIndex] <= '9')) ? string[currentIndex] - '0' : CSR_TOUPPER(string[currentIndex]) - 'A' + 10));
currentIndex++;
if (currentIndex >= 2)
break;
}
return true;
}
return false;
}
static bool CsrHexStrToUint16(const char *string, u16 *returnValue)
{
u16 currentIndex = 0;
*returnValue = 0;
if ((string[currentIndex] == '0') && (CSR_TOUPPER(string[currentIndex + 1]) == 'X'))
string += 2;
if (((string[currentIndex] >= '0') && (string[currentIndex] <= '9')) || ((CSR_TOUPPER(string[currentIndex]) >= 'A') && (CSR_TOUPPER(string[currentIndex]) <= 'F'))) {
while (((string[currentIndex] >= '0') && (string[currentIndex] <= '9')) || ((CSR_TOUPPER(string[currentIndex]) >= 'A') && (CSR_TOUPPER(string[currentIndex]) <= 'F'))) {
*returnValue = (u16)(*returnValue * 16 + (((string[currentIndex] >= '0') && (string[currentIndex] <= '9')) ? string[currentIndex] - '0' : CSR_TOUPPER(string[currentIndex]) - 'A' + 10));
currentIndex++;
if (currentIndex >= 4)
break;
}
return true;
}
return false;
}
static bool CsrHexStrToUint32(const char *string, u32 *returnValue)
{
u16 currentIndex = 0;
*returnValue = 0;
if ((string[currentIndex] == '0') && (CSR_TOUPPER(string[currentIndex + 1]) == 'X'))
string += 2;
if (((string[currentIndex] >= '0') && (string[currentIndex] <= '9')) || ((CSR_TOUPPER(string[currentIndex]) >= 'A') && (CSR_TOUPPER(string[currentIndex]) <= 'F'))) {
while (((string[currentIndex] >= '0') && (string[currentIndex] <= '9')) || ((CSR_TOUPPER(string[currentIndex]) >= 'A') && (CSR_TOUPPER(string[currentIndex]) <= 'F'))) {
*returnValue = *returnValue * 16 + (((string[currentIndex] >= '0') && (string[currentIndex] <= '9')) ? string[currentIndex] - '0' : CSR_TOUPPER(string[currentIndex]) - 'A' + 10);
currentIndex++;
if (currentIndex >= 8)
break;
}
return true;
}
return false;
}
static bool CsrWifiMibConvertStrToUint16(const char *str, u16 *returnValue)
{
u16 currentIndex = 0;
if (str[1] == 'x')
return CsrHexStrToUint16(str, returnValue);
*returnValue = 0;
if ((str[currentIndex] >= '0') && (str[currentIndex] <= '9')) {
while (str[currentIndex] >= '0' && str[currentIndex] <= '9') {
*returnValue *= 10;
*returnValue += (u8)str[currentIndex++] - '0';
}
return true;
}
return false;
}
static bool CsrWifiMibConvertStrToUint32(const char *str, u32 *returnValue)
{
u16 currentIndex = 0;
if (str[1] == 'x')
return CsrHexStrToUint32(str, returnValue);
*returnValue = 0;
if ((str[currentIndex] >= '0') && (str[currentIndex] <= '9')) {
while (str[currentIndex] >= '0' && str[currentIndex] <= '9') {
*returnValue *= 10;
*returnValue += (u8)str[currentIndex++] - '0';
}
return true;
}
return false;
}
static bool CsrWifiMibConvertTextParseLine(const char *linestr, struct slsi_mib_data *mibDataSet, struct slsi_mib_data *mibDataGet)
{
struct slsi_mib_entry entry;
bool result = true;
size_t equals = 0;
size_t dot1 = 0;
size_t dot2 = 0;
size_t trimmedIndex = 0;
char *trimmed = kmalloc(strlen(linestr) + 1, GFP_KERNEL);
const char *current_char = linestr;
bool processingStr = false;
if (!trimmed) {
SLSI_ERR_NODEV("Memory allocation failed!\n");
return false;
}
memset(&entry, 0x00, sizeof(entry));
while (current_char[0] != '\0') {
if (current_char[0] == '"')
processingStr = !processingStr;
if (!processingStr) {
if (current_char[0] == '#')
break;
if (CsrIsSpace((u8)current_char[0])) {
current_char++;
continue;
}
if (!equals && (current_char[0] == '.')) {
if (!dot1) {
dot1 = trimmedIndex;
} else if (!dot2) {
dot2 = trimmedIndex;
} else {
SLSI_ERR_NODEV("CsrWifiMibConvertTextParseLine('%s') only 2 indexes supported", trimmed);
result = false;
}
}
if (!equals && (current_char[0] == '='))
equals = trimmedIndex;
}
trimmed[trimmedIndex++] = current_char[0];
current_char++;
}
trimmed[trimmedIndex] = '\0';
if (strlen(trimmed) == 0) {
kfree(trimmed);
return result;
}
if (result) {
char sep = trimmed[dot1 ? dot1 : equals];
if (dot1 || equals)
trimmed[dot1 ? dot1 : equals] = '\0';
trimmed[dot1 ? dot1 : equals] = sep;
if (!CsrWifiMibConvertStrToUint16(trimmed, &entry.psid)) {
SLSI_ERR_NODEV("CsrWifiMibConvertTextParseLine('%s') Convert <psid> failed", trimmed);
result = false;
}
if (dot1 && !CsrWifiMibConvertStrToUint16(&trimmed[dot1 + 1], &entry.index[0])) {
SLSI_ERR_NODEV("CsrWifiMibConvertTextParseLine('%s') Convert <index 1> failed", trimmed);
result = false;
}
if (dot2 && !CsrWifiMibConvertStrToUint16(&trimmed[dot2 + 1], &entry.index[1])) {
SLSI_ERR_NODEV("CsrWifiMibConvertTextParseLine('%s') Convert <index 2> failed", trimmed);
result = false;
}
if (result && !equals && mibDataGet) {
entry.value.type = SLSI_MIB_TYPE_NONE;
(void)slsi_mib_encode(mibDataGet, &entry);
}
if (result && equals && mibDataSet) {
char *data = &trimmed[equals + 1];
/*SLSI_ERR_NODEV("CsrWifiMibConvertTextParseLine('%s') psid:%d, index1:%d, index2:%d, data '%s'", trimmed, entry.psid, entry.index[0], entry.index[1], data); */
if (CsrStrNICmp(data, "true", 4) == 0) {
entry.value.type = SLSI_MIB_TYPE_BOOL;
entry.value.u.boolValue = 1;
} else if (CsrStrNICmp(data, "false", 5) == 0) {
entry.value.type = SLSI_MIB_TYPE_BOOL;
entry.value.u.boolValue = 0;
} else if (data[0] == '"') {
/* Null Terminated String */
entry.value.type = SLSI_MIB_TYPE_OCTET;
entry.value.u.octetValue.dataLength = (u32)strlen(&data[1]);
entry.value.u.octetValue.data = (u8 *)CsrStrDup(&data[1]);
entry.value.u.octetValue.data[entry.value.u.octetValue.dataLength - 1] = '\0';
} else if (data[0] == '[') {
/* Octet String */
size_t i;
u16 octetLen = ((u16)strlen(&data[1]) - 1) / 2;
entry.value.type = SLSI_MIB_TYPE_OCTET;
entry.value.u.octetValue.dataLength = octetLen;
entry.value.u.octetValue.data = kmalloc(entry.value.u.octetValue.dataLength + 1, GFP_KERNEL);
if (!entry.value.u.octetValue.data) {
SLSI_ERR_NODEV("Memory allocation failed!\n");
kfree(trimmed);
return false;
}
for (i = 0; i < octetLen; i++)
if (!CsrHexStrToUint8(&data[1 + (i * 2)], &entry.value.u.octetValue.data[i])) {
SLSI_ERR_NODEV("CsrWifiMibConvertTextParseLine('%s') Convert Hex Bytes <data> failed", trimmed);
result = false;
break;
}
entry.value.u.octetValue.data[octetLen] = '\0'; /* Make sure the Octet Stream is NULL terminated in case it is interpreted as a String */
} else if (data[0] == '-') {
/* Negative Integer Value */
entry.value.type = SLSI_MIB_TYPE_INT;
if (!CsrWifiMibConvertStrToUint32(&data[1], &entry.value.u.uintValue)) {
SLSI_ERR_NODEV("CsrWifiMibConvertTextParseLine('%s') Convert Integer <data> failed", trimmed);
result = false;
} else {
entry.value.u.intValue = (s32)(0 - (u32)entry.value.u.uintValue);
}
} else if (!CsrWifiMibConvertStrToUint32(data, &entry.value.u.uintValue)) {
SLSI_ERR_NODEV("CsrWifiMibConvertTextParseLine('%s') Convert Unsigned Integer <data> failed", trimmed);
result = false;
} else {
entry.value.type = SLSI_MIB_TYPE_UINT;
}
if (result)
(void)slsi_mib_encode(mibDataSet, &entry);
if (entry.value.type == SLSI_MIB_TYPE_OCTET)
kfree(entry.value.u.octetValue.data);
}
}
kfree(trimmed);
return result;
}
static bool CsrWifiMibConvertTextAppend(const char *mibText, struct slsi_mib_data *mibDataSet, struct slsi_mib_data *mibDataGet)
{
bool result = true;
const char *lineStart = mibText;
const char *lineEnd = mibText;
if (!mibText)
return false;
while (lineEnd[0] != '\0') {
if ((lineEnd[0] == '\n') || (lineEnd[0] == '\r') || (lineEnd[1] == '\0')) {
size_t strSize = (size_t)(lineEnd - lineStart);
if ((lineEnd[1] == '\0'))
strSize++;
if (strSize > 2) {
char *line = kmalloc(strSize + 1, GFP_KERNEL);
if (!line) {
SLSI_ERR_NODEV("Memory allocation failed!\n", line);
return false;
}
(void)strncpy(line, lineStart, strSize);
line[strSize] = '\0';
if (!CsrWifiMibConvertTextParseLine(line, mibDataSet, mibDataGet)) {
SLSI_ERR_NODEV("CsrWifiMibConvertTextParseLine() Failed for line '%s'", line);
result = false;
}
kfree(line);
}
lineEnd++;
lineStart = lineEnd;
continue;
}
lineEnd++;
}
return result;
}
bool CsrWifiMibConvertText(const char *mibText, struct slsi_mib_data *mibDataSet, struct slsi_mib_data *mibDataGet)
{
if (mibDataSet) {
mibDataSet->data = NULL;
mibDataSet->dataLength = 0;
}
if (mibDataGet) {
mibDataGet->data = NULL;
mibDataGet->dataLength = 0;
}
return CsrWifiMibConvertTextAppend(mibText, mibDataSet, mibDataGet);
}