Skip to content
8 changes: 6 additions & 2 deletions src/hostif/handlers/src/hostIf_DeviceClient_ReqHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,9 +496,13 @@ int DeviceClientReqHandler::handleGetMsg(HOSTIF_MsgData_t *stMsgData)
}

else if(strcasecmp(stMsgData->paramName,"Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RDKRemoteDebugger.getProfileData") == 0)
{
{
ret = pIface->get_Device_DeviceInfo_X_RDKCENTRAL_COM_RDKRemoteDebuggergetProfileData(stMsgData);
}
}
else if (strcasecmp(stMsgData->paramName,"Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RDKRemoteDebugger.setProfileData") == 0)
{
ret = pIface->set_Device_DeviceInfo_X_RDKCENTRAL_COM_RDKRemoteDebuggersetProfileData(stMsgData);
}
Comment on lines +502 to +505

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleGetMsg is dispatching the readWrite parameter ...RDKRemoteDebugger.setProfileData by calling the setter. A GET for this parameter would unexpectedly mutate internal state (e.g., setting the category to an empty string) and bypass the normal SET path. This branch should be removed from handleGetMsg and handled via handleSetMsg (it already routes RFC params through set_xRDKCentralComRFC).

Suggested change
else if (strcasecmp(stMsgData->paramName,"Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RDKRemoteDebugger.setProfileData") == 0)
{
ret = pIface->set_Device_DeviceInfo_X_RDKCENTRAL_COM_RDKRemoteDebuggersetProfileData(stMsgData);
}

Copilot uses AI. Check for mistakes.
else if (strcasecmp(stMsgData->paramName,"Device.DeviceInfo.X_RDKCENTRAL-COM_PreferredGatewayType") == 0)
{
ret = pIface->get_Device_DeviceInfo_X_RDKCENTRAL_COM_PreferredGatewayType(stMsgData);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3611,6 +3611,11 @@
<syntax>
<string/>
</syntax>
</parameter>
<parameter base="setProfileData" access="readWrite" notification="0" maxNotification="2" >
<syntax>
<string/>
</syntax>
</parameter>
<parameter base="IssueType" access="readWrite" notification="0" maxNotification="2" >
<syntax>
Expand Down Expand Up @@ -4662,3 +4667,4 @@
</object>
</model>
</dm:document>

229 changes: 171 additions & 58 deletions src/hostif/profiles/DeviceInfo/Device_DeviceInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,12 @@ XRFCStorage hostIf_DeviceInfo::m_rfcStorage;
#endif
XBSStore* hostIf_DeviceInfo::m_bsStore;
string hostIf_DeviceInfo::m_xrPollingAction = "0";

#ifdef USE_REMOTE_DEBUGGER
string hostIf_DeviceInfo::m_rdkRemoteDebuggerProfileCategory = "all";
string hostIf_DeviceInfo::m_rdkRemoteDebuggerProfileData;
#endif

#ifndef RDKV_TR69
static bool bPowerControllerEnable;
#endif
Expand Down Expand Up @@ -4043,6 +4049,10 @@ int hostIf_DeviceInfo::set_xRDKCentralComRFC(HOSTIF_MsgData_t * stMsgData)
{
ret = set_Device_DeviceInfo_X_RDKCENTRAL_COM_RDKRemoteDebuggerWebCfgData(stMsgData);
}
else if (strcasecmp(stMsgData->paramName,RDK_REMOTE_DEBUGGER_SET_PROFILE_DATA) == 0)
{
ret = set_Device_DeviceInfo_X_RDKCENTRAL_COM_RDKRemoteDebuggersetProfileData(stMsgData);
}
#endif
else if (strcasecmp(stMsgData->paramName,CANARY_START_TIME) == 0)
{
Expand Down Expand Up @@ -4164,6 +4174,32 @@ int hostIf_DeviceInfo::set_xRDKCentralComNewNtpEnable(HOSTIF_MsgData_t *stMsgDat
return ret;
}

#ifdef USE_REMOTE_DEBUGGER
int hostIf_DeviceInfo::set_Device_DeviceInfo_X_RDKCENTRAL_COM_RDKRemoteDebuggersetProfileData(HOSTIF_MsgData_t *stMsgData)
{
int ret = NOK;
LOG_ENTRY_EXIT;

if (stMsgData->paramtype == hostIf_StringType)
{
// Store the category value to decide what to return in getProfileData
m_rdkRemoteDebuggerProfileCategory = stMsgData->paramValue;

RDK_LOG(RDK_LOG_INFO, LOG_TR69HOSTIF, "[%s] Remote Debugger Profile Data category set to: %s\n",
__FUNCTION__, stMsgData->paramValue);

ret = OK;
}
else
{
RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "[%s:%d] Failed due to wrong data type for %s, please use string type.\n",
__FUNCTION__, __LINE__, stMsgData->paramName);
}

return ret;
}
#endif /* USE_REMOTE_DEBUGGER */

int hostIf_DeviceInfo::get_xRDKCentralComBootstrap(HOSTIF_MsgData_t *stMsgData)
{
return m_bsStore->getValue(stMsgData);
Expand Down Expand Up @@ -4196,6 +4232,8 @@ int hostIf_DeviceInfo::get_xRDKCentralComRFC(HOSTIF_MsgData_t *stMsgData)
}
}



return ret;
}

Expand Down Expand Up @@ -4319,121 +4357,196 @@ int hostIf_DeviceInfo::set_Device_DeviceInfo_X_RDKCENTRAL_COM_RDKRemoteDebuggerI

int hostIf_DeviceInfo::get_Device_DeviceInfo_X_RDKCENTRAL_COM_RDKRemoteDebuggergetProfileData(HOSTIF_MsgData_t *stMsgData)
{
stMsgData->paramtype = hostIf_StringType;
stMsgData->paramtype = hostIf_StringType;
int retStatus = NOK;
const char *filename = "/etc/rrd/remote_debugger.json";
FILE *fp = nullptr;
char *fileBuf = nullptr;
long fileSz = 0;
size_t bytesRead = 0;
cJSON *root = nullptr;
cJSON *filtered = nullptr;
cJSON *response = nullptr;
char *outStr = nullptr;
size_t outLen = 0;

RDK_LOG(RDK_LOG_TRACE1, LOG_TR69HOSTIF, "[%s] Entering …\n", __FUNCTION__);

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The log message contains a Unicode ellipsis character (). Some embedded toolchains/log pipelines assume ASCII and can fail or garble logs; prefer plain ... in source strings for portability.

Suggested change
RDK_LOG(RDK_LOG_TRACE1, LOG_TR69HOSTIF, "[%s] Entering \n", __FUNCTION__);
RDK_LOG(RDK_LOG_TRACE1, LOG_TR69HOSTIF, "[%s] Entering ...\n", __FUNCTION__);

Copilot uses AI. Check for mistakes.

fp = fopen(filename, "rb");
if (!fp)
{
if (!fp) {
RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "[%s] Cannot open %s\n", __FUNCTION__, filename);
RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "[%s] Leaving with NOK\n", __FUNCTION__);
return retStatus;
}
if (fseek(fp, 0L, SEEK_END) != 0)
{

if (fseek(fp, 0L, SEEK_END) != 0) {
RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "[%s] fseek failed\n", __FUNCTION__);
fclose(fp);
RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "[%s] Leaving with NOK\n", __FUNCTION__);
return retStatus;
}

fileSz = ftell(fp);
rewind(fp);
if (fileSz < 0)
{
RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "[%s] fileSz is negative, Returning....\n", __FUNCTION__);
if (fileSz < 0) {
RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "[%s] fileSz is negative\n", __FUNCTION__);
fclose(fp);
RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "[%s] Leaving with NOK\n", __FUNCTION__);
return retStatus;
}

fileBuf = (char*)malloc((size_t)fileSz + 1);
if (!fileBuf)
{
if (!fileBuf) {
RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "[%s] malloc(%ld) failed\n", __FUNCTION__, fileSz + 1);
fclose(fp);
RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "[%s] Leaving with NOK\n", __FUNCTION__);
return retStatus;
}

bytesRead = fread(fileBuf, 1U, (size_t)fileSz, fp);

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fread's return value isn’t validated against the expected file size and ferror(fp) isn’t checked. A short read can lead to parsing truncated JSON and returning misleading data. Consider treating bytesRead != (size_t)fileSz as an error (or loop until EOF) and handle ferror explicitly.

Suggested change
bytesRead = fread(fileBuf, 1U, (size_t)fileSz, fp);
bytesRead = fread(fileBuf, 1U, (size_t)fileSz, fp);
if (bytesRead != (size_t)fileSz) {
if (ferror(fp)) {
RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "[%s] fread failed for %s\n", __FUNCTION__, filename);
} else {
RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "[%s] Short read for %s: expected %ld bytes, got %zu bytes\n",
__FUNCTION__, filename, fileSz, bytesRead);
}
fclose(fp);
fp = nullptr;
free(fileBuf);
fileBuf = nullptr;
return retStatus;
}

Copilot uses AI. Check for mistakes.
fileBuf[bytesRead] = '\0';
fclose(fp); fp = nullptr;
fclose(fp);
fp = nullptr;

root = cJSON_Parse(fileBuf);
if (!root)
{
if (!root) {
RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "[%s] JSON parse error: %s\n", __FUNCTION__, cJSON_GetErrorPtr());
free(fileBuf);
RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "[%s] Leaving with NOK\n", __FUNCTION__);
return retStatus;
}
filtered = cJSON_CreateObject();
if (!filtered)
{
free(fileBuf);
cJSON_Delete(root);
RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "[%s] Leaving with NOK\n", __FUNCTION__);
return retStatus;
}

for (cJSON *top = root->child; top; top = top->next)
{
if (top->type != cJSON_Object)
{
continue;

// Check if setProfileData was called to determine response format
if (strcasecmp(m_rdkRemoteDebuggerProfileCategory.c_str(), "all") == 0) {
// Return filtered profile data for all categories - exclude Commands and Timeout fields
response = cJSON_CreateObject();
if (!response) {
free(fileBuf);
cJSON_Delete(root);
return retStatus;
}
cJSON *arr = cJSON_CreateArray();
if (!arr)
{

cJSON *category = NULL;
cJSON_ArrayForEach(category, root) {
if (cJSON_IsObject(category)) {
cJSON *issueTypesArray = cJSON_CreateArray();
if (!issueTypesArray) {
free(fileBuf);
cJSON_Delete(root);
cJSON_Delete(response);
return retStatus;
}

cJSON *issueType = NULL;
cJSON_ArrayForEach(issueType, category) {
// Only add the issue type name, ignore Commands/Timeout/DebugCommands/DebugTimeout
if (cJSON_IsObject(issueType) && issueType->string) {
cJSON_AddItemToArray(issueTypesArray, cJSON_CreateString(issueType->string));
}
}

if (cJSON_GetArraySize(issueTypesArray) > 0) {
cJSON_AddItemToObject(response, category->string, issueTypesArray);
} else {
Comment on lines +4413 to +4444

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When building the JSON response, cJSON_AddItemToObject(response, category->string, ...) assumes category->string is non-null. If /etc/rrd/remote_debugger.json ever contains an array (or any non-object root/child), category->string can be null and this will crash. Please validate root is an object and guard category->string before using it as an object key.

Copilot uses AI. Check for mistakes.
cJSON_Delete(issueTypesArray);
}
}
}
RDK_LOG(RDK_LOG_INFO, LOG_TR69HOSTIF, "[%s] Returning filtered profile data for all categories\n", __FUNCTION__);
} else if (!m_rdkRemoteDebuggerProfileCategory.empty() &&
strcasecmp(m_rdkRemoteDebuggerProfileCategory.c_str(), "all") != 0) {
// Return filtered issue types for specific category
cJSON* category = cJSON_GetObjectItem(root, m_rdkRemoteDebuggerProfileCategory.c_str());
if (category && cJSON_IsObject(category)) {
response = cJSON_CreateObject();
cJSON *issueTypesArray = cJSON_CreateArray();
if (!response || !issueTypesArray) {
free(fileBuf);
cJSON_Delete(root);
if (response) cJSON_Delete(response);
if (issueTypesArray) cJSON_Delete(issueTypesArray);
return retStatus;
}

cJSON *issueType = NULL;
cJSON_ArrayForEach(issueType, category) {
// Only add the issue type name, ignore Commands/Timeout/DebugCommands/DebugTimeout
if (cJSON_IsObject(issueType) && issueType->string) {
cJSON_AddItemToArray(issueTypesArray, cJSON_CreateString(issueType->string));
}
}

if (cJSON_GetArraySize(issueTypesArray) > 0) {
cJSON_AddItemToObject(response, m_rdkRemoteDebuggerProfileCategory.c_str(), issueTypesArray);
} else {
cJSON_Delete(issueTypesArray);
}

RDK_LOG(RDK_LOG_INFO, LOG_TR69HOSTIF, "[%s] Returning filtered profile data for category: %s\n",
__FUNCTION__, m_rdkRemoteDebuggerProfileCategory.c_str());
} else {
RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "[%s] Category '%s' not found\n",
__FUNCTION__, m_rdkRemoteDebuggerProfileCategory.c_str());
free(fileBuf);
cJSON_Delete(root);
cJSON_Delete(filtered);
RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "[%s] Leaving with NOK\n", __FUNCTION__);
return retStatus;
}
for (cJSON *sub = top->child; sub; sub = sub->next)
{
cJSON_AddItemToArray(arr, cJSON_CreateString(sub->string));
} else {
// Default behavior: return category names with issue types only (filtered)
response = cJSON_CreateObject();
if (!response) {
free(fileBuf);
cJSON_Delete(root);
return retStatus;
}
if (cJSON_GetArraySize(arr) > 0)
{
cJSON_AddItemToObject(filtered, top->string, arr);
}
else
{
cJSON_Delete(arr);

cJSON *category = NULL;
cJSON_ArrayForEach(category, root) {
if (cJSON_IsObject(category)) {
cJSON *issueTypesArray = cJSON_CreateArray();
if (!issueTypesArray) {
free(fileBuf);
cJSON_Delete(root);
cJSON_Delete(response);
return retStatus;
}

cJSON *issueType = NULL;
cJSON_ArrayForEach(issueType, category) {
// Only add the issue type name, ignore Commands/Timeout/DebugCommands/DebugTimeout
if (cJSON_IsObject(issueType) && issueType->string) {
cJSON_AddItemToArray(issueTypesArray, cJSON_CreateString(issueType->string));
}
}

if (cJSON_GetArraySize(issueTypesArray) > 0) {
cJSON_AddItemToObject(response, category->string, issueTypesArray);
} else {
cJSON_Delete(issueTypesArray);
}
}
}
RDK_LOG(RDK_LOG_INFO, LOG_TR69HOSTIF, "[%s] Returning filtered category names and issue types (default)\n", __FUNCTION__);
}

outStr = cJSON_PrintUnformatted(filtered);
if (!outStr)
{

outStr = cJSON_PrintUnformatted(response);
if (!outStr) {
free(fileBuf);
cJSON_Delete(root);
cJSON_Delete(filtered);
RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "[%s] Leaving with NOK\n", __FUNCTION__);
cJSON_Delete(response);
return retStatus;
}

outLen = strlen(outStr);
if (outLen >= sizeof(stMsgData->paramValue))
{
if (outLen >= sizeof(stMsgData->paramValue)) {
outLen = sizeof(stMsgData->paramValue) - 1;
}
memcpy(stMsgData->paramValue, outStr, outLen);
stMsgData->paramValue[outLen] = '\0';
stMsgData->paramLen = outLen;
RDK_LOG(RDK_LOG_INFO, LOG_TR69HOSTIF, "[%s] Extracted profile map: %s\n", __FUNCTION__, outStr);

RDK_LOG(RDK_LOG_INFO, LOG_TR69HOSTIF, "[%s] Returning profile data: %s\n", __FUNCTION__, outStr);
retStatus = OK;
Comment on lines +4541 to 4543

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logging the full generated JSON (outStr) at INFO level can be noisy and potentially large, impacting storage/performance on embedded targets. Consider logging only the selected category and output length (or downgrade to DEBUG).

Copilot uses AI. Check for mistakes.

free(fileBuf);
cJSON_Delete(root);
cJSON_Delete(filtered);
cJSON_Delete(response);
free(outStr);

RDK_LOG(RDK_LOG_TRACE1, LOG_TR69HOSTIF, "[%s] Leaving with OK\n", __FUNCTION__);
return retStatus;
}
Expand Down
10 changes: 8 additions & 2 deletions src/hostif/profiles/DeviceInfo/Device_DeviceInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@
#define RDK_REMOTE_DEBUGGER_ENABLE "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RDKRemoteDebugger.Enable"
#define RDK_REMOTE_DEBUGGER_ISSUETYPE "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RDKRemoteDebugger.IssueType"
#define RDK_REMOTE_DEBUGGER_WEBCFGDATA "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RDKRemoteDebugger.WebCfgData"
#define RDK_REMOTE_DEBUGGER_SET_PROFILE_DATA "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RDKRemoteDebugger.setProfileData"
#define RDK_REMOTE_DEBUGGER_GET_PROFILE_DATA "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RDKRemoteDebugger.getProfileData"
#endif

/* Profile: X_RDKCENTRAL-COM_RFC.Feature.RebootStop */
Expand Down Expand Up @@ -274,6 +276,11 @@ class hostIf_DeviceInfo {
static XBSStore *m_bsStore;
static string m_xrPollingAction;

#ifdef USE_REMOTE_DEBUGGER
static string m_rdkRemoteDebuggerProfileCategory;
static string m_rdkRemoteDebuggerProfileData;

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m_rdkRemoteDebuggerProfileData is declared/defined but not referenced anywhere in the codebase. Keeping unused static state increases confusion and maintenance cost; consider removing it or wiring it into the implementation.

Suggested change
static string m_rdkRemoteDebuggerProfileData;

Copilot uses AI. Check for mistakes.
#endif

std::string m_strXOpsDevManageableNotification;
std::string m_strXOpsRPCFwDwldStartedNotification;
bool m_bXOpsRPCFwDwldCompletedNotification;
Expand All @@ -298,14 +305,12 @@ class hostIf_DeviceInfo {
#ifdef ENABLE_VIDEO_TELEMETRY
int set_xRDKCentralComRFCVideoTelFreq(HOSTIF_MsgData_t *);
#endif

/* AutoReboot handlers */
int set_xRDKCentralComRFCAutoRebootUptime(HOSTIF_MsgData_t*);
int set_xRDKCentralComRFCAutoRebootEnable(HOSTIF_MsgData_t*);
int ScheduleAutoReboot(bool);

int set_xRDKCentralComNewNtpEnable(HOSTIF_MsgData_t *);

int get_xRDKCentralComRFCAccountId (HOSTIF_MsgData_t *);
int get_xOpsDeviceMgmtRPCRebootNow (HOSTIF_MsgData_t *);
int get_xOpsRPCDevManageableNotification(HOSTIF_MsgData_t *);
Expand Down Expand Up @@ -1293,6 +1298,7 @@ class hostIf_DeviceInfo {
int set_Device_DeviceInfo_X_RDKCENTRAL_COM_RDKRemoteDebuggerIssueType(HOSTIF_MsgData_t *);
int set_Device_DeviceInfo_X_RDKCENTRAL_COM_RDKRemoteDebuggerWebCfgData(HOSTIF_MsgData_t *);
int get_Device_DeviceInfo_X_RDKCENTRAL_COM_RDKRemoteDebuggergetProfileData(HOSTIF_MsgData_t *);
int set_Device_DeviceInfo_X_RDKCENTRAL_COM_RDKRemoteDebuggersetProfileData(HOSTIF_MsgData_t *);
#endif

/*
Expand Down
Loading