From 5d0d2b9753f0446a095c0336c45ebb88089083f3 Mon Sep 17 00:00:00 2001 From: sindhu-krishnan <102755514+sindhu-krishnan@users.noreply.github.com> Date: Thu, 6 Aug 2026 06:42:30 +0530 Subject: [PATCH 1/2] RDKB-63950 : Chrony Integration in RDKB (#390) Reason for change: - Integrates **Chrony** as the alternative NTP client in RDK-B. - Retains **ntpd** as the default NTP client. - Introduces **RFC runtime control** to switch between `ntpd` and `chronyd` Test Procedure: Enable the chrony RFC and check if chrony is the active NTP Client Risks: Medium Priority: P1 Signed-off-by: Sindhuja --------- Co-authored-by: smuthu545 Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../scripts/init/c_registration/10_chronyd.c | 75 +++++ .../scripts/init/c_registration/Makefile.am | 2 + .../scripts/init/defaults/system_defaults_arm | 3 + .../scripts/init/service.d/service_chronyd.sh | 262 ++++++++++++++++++ source/scripts/init/service.d/service_ntpd.sh | 9 + 5 files changed, 351 insertions(+) create mode 100644 source/scripts/init/c_registration/10_chronyd.c create mode 100644 source/scripts/init/service.d/service_chronyd.sh diff --git a/source/scripts/init/c_registration/10_chronyd.c b/source/scripts/init/c_registration/10_chronyd.c new file mode 100644 index 00000000..277d91b1 --- /dev/null +++ b/source/scripts/init/c_registration/10_chronyd.c @@ -0,0 +1,75 @@ +/* + * If not stated otherwise in this file or this component's Licenses.txt file the + * following copyright and licenses apply: + * + * Copyright 2015 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#include +#include "srvmgr.h" + +#define SERVICE_NAME "chronyd" +#define SERVICE_DEFAULT_HANDLER "/etc/utopia/service.d/service_chronyd.sh" + +/* + * Listen to the same network events as ntpd so chronyd starts when WAN comes up. + * ipv6_connection_state is registered for HUB4/SKY platforms (guarded in the + * handler script itself — no compile-time flag needed here because the RFC flag + * /nvram/chrony_enabled gates all execution in service_chronyd.sh). + */ +#ifdef _HUB4_PRODUCT_REQ_ +const char* SERVICE_CUSTOM_EVENTS[] = { + "wan-status|/etc/utopia/service.d/service_chronyd.sh", + "current_wan_ifname|/etc/utopia/service.d/service_chronyd.sh|NULL|"TUPLE_FLAG_EVENT, + NULL +}; +#else +const char* SERVICE_CUSTOM_EVENTS[] = { + "wan-status|/etc/utopia/service.d/service_chronyd.sh", + "current_wan_ifname|/etc/utopia/service.d/service_chronyd.sh|NULL|"TUPLE_FLAG_EVENT, + NULL +}; +#endif + +void srv_register(void) { + sm_register(SERVICE_NAME, SERVICE_DEFAULT_HANDLER, SERVICE_CUSTOM_EVENTS); +} + +void srv_unregister(void) { + sm_unregister(SERVICE_NAME); +} + +int main(int argc, char **argv) +{ + cmd_type_t choice = parse_cmd_line(argc, argv); + + switch (choice) { + case(nochoice): + case(start): + srv_register(); + break; + case(stop): + srv_unregister(); + break; + case(restart): + srv_unregister(); + srv_register(); + break; + default: + printf("%s called with invalid parameter (%s)\n", + argv[0], argc == 1 ? "" : argv[1]); + } + return 0; +} diff --git a/source/scripts/init/c_registration/Makefile.am b/source/scripts/init/c_registration/Makefile.am index 946ca302..5253bd5b 100644 --- a/source/scripts/init/c_registration/Makefile.am +++ b/source/scripts/init/c_registration/Makefile.am @@ -51,6 +51,7 @@ bin_PROGRAMS = \ 09_xdns \ 10_firewall \ 10_ntpd \ + 10_chronyd \ 15_ccsphs \ 15_ddnsclient \ 15_dhcp_server \ @@ -103,6 +104,7 @@ endif 10_fpm_SOURCES = 10_fpm.c 10_ntpclient_SOURCES = 10_ntpclient.c 10_ntpd_SOURCES = 10_ntpd.c +10_chronyd_SOURCES = 10_chronyd.c 10_sysevent_proxy_SOURCES = 10_sysevent_proxy.c 10_time_sync_peer_SOURCES = 10_time_sync_peer.c 15_ccsphs_SOURCES = 15_ccsphs.c diff --git a/source/scripts/init/defaults/system_defaults_arm b/source/scripts/init/defaults/system_defaults_arm index 3495a2b1..dfd75978 100755 --- a/source/scripts/init/defaults/system_defaults_arm +++ b/source/scripts/init/defaults/system_defaults_arm @@ -1235,6 +1235,9 @@ $CpuMemFrag_Interval=4 #Partner support for NTP FQDN $new_ntp_enabled=true +#Chrony RFC enable state (false = ntpd active, true = chrony active) +$chrony_enabled=false + #Enable PresenceDetect $PresenceDetectEnabled=false diff --git a/source/scripts/init/service.d/service_chronyd.sh b/source/scripts/init/service.d/service_chronyd.sh new file mode 100644 index 00000000..9cbf8f47 --- /dev/null +++ b/source/scripts/init/service.d/service_chronyd.sh @@ -0,0 +1,262 @@ +#!/bin/sh +########################################################################## +# If not stated otherwise in this file or this component's Licenses.txt +# file the following copyright and licenses apply: +# +# Copyright 2015 RDK Management +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +########################################################################## + +source /etc/utopia/service.d/ulog_functions.sh +source /etc/utopia/service.d/log_capture_path.sh +source /etc/log_timestamp.sh # define 'echo_t' ASAP! +source /etc/waninfo.sh +source /etc/device.properties + +SERVICE_NAME="chronyd" +SELF_NAME="`basename "$0"`" +CHRONY_CONF_TMP=/etc/rdk_chrony.conf +CHRONY_BIN=chronyd +LOCKFILE=/var/tmp/service_chronyd.pid +SYNC_FILE=/tmp/clock-event +NTP_SYNCED_FILE=/tmp/.ntp_time_synced + +# /rdklogs is a tmpfs that starts empty on every boot; the logs/ subdirectory +# may not exist yet when this script fires early in the boot sequence. +# Ensure it exists before any echo_t write so no log lines are silently dropped. +mkdir -p /rdklogs/logs + +# chrony_rfc_enabled: returns 0 (true) when the chrony RFC path is active. +# Single source of the RFC check so all gates stay consistent. +chrony_rfc_enabled() { + [ "$(syscfg get chrony_enabled)" = "true" ] +} + +if [ -z "$NTPD_LOG_NAME" ]; then + NTPD_LOG_NAME=/rdklogs/logs/ntpLog.log +fi + +CONNCHECK_FILE="/tmp/connectivity_check_done" + +LANIPV6Support=$(sysevent get LANIPv6GUASupport) +CURRENT_WAN_STATUS=$(sysevent get wan-status) +WAN_INTERFACE=$(getWanInterfaceName) + +# ────────────────────────────────────────────────────────────────────────────── +# service_init: load syscfg ntp_enabled into environment +# ────────────────────────────────────────────────────────────────────────────── +service_init() { + FOO=$(utctx_cmd get ntp_enabled) + eval "$FOO" +} + +# ────────────────────────────────────────────────────────────────────────────── +# set_chrony_sync_status: background monitor — polls chronyc until Leap=Normal +# ────────────────────────────────────────────────────────────────────────────── +set_chrony_sync_status() { + local retry=1 + local MAX_RETRY=12 # 12 × 10s = 120s max wait + + while true; do + if [ "$retry" -gt "$MAX_RETRY" ]; then + echo_t "SERVICE_CHRONYD : sync not confirmed within 120s — daemon still running" >> $NTPD_LOG_NAME + break + fi + + leap=$(chronyc tracking 2>/dev/null | grep "Leap status" | awk '{print $NF}') + if [ "$leap" = "Normal" ]; then + echo_t "SERVICE_CHRONYD : time sync confirmed (Leap status Normal)" >> $NTPD_LOG_NAME + syscfg set ntp_status 3 + sysevent set ntp_time_sync 1 + touch "$SYNC_FILE" + touch "$NTP_SYNCED_FILE" + DEVICEFIRSTUSEDATE=$(syscfg get device_first_use_date) + if [ -z "$DEVICEFIRSTUSEDATE" ] || [ "0" = "$DEVICEFIRSTUSEDATE" ]; then + syscfg set device_first_use_date "$(date +%Y-%m-%dT%H:%M:%S)" + fi + break + fi + + retry=$((retry + 1)) + sleep 10 + done + exit 0 +} + +waitForConnChkFile() +{ + echo_t "SERVICE_CHRONYD CONNCHK: Waiting for connection check completion..." >> $NTPD_LOG_NAME + TIMEOUT=120 + INTERVAL=1 + + # Get system uptime in seconds at start + START_TIME=$(cut -d. -f1 /proc/uptime) + + echo_t "SERVICE_CHRONYD : Waiting for $CONNCHECK_FILE (max ${TIMEOUT}s)..." >> $NTPD_LOG_NAME + + while true; do + if [ -f "$CONNCHECK_FILE" ]; then + echo_t "SERVICE_CHRONYD : File $CONNCHECK_FILE present" >> $NTPD_LOG_NAME + return 0 + fi + + CURRENT_TIME=$(cut -d. -f1 /proc/uptime) + ELAPSED=$((CURRENT_TIME - START_TIME)) + + if [ "$ELAPSED" -ge "$TIMEOUT" ]; then + echo_t "SERVICE_CHRONYD : Timeout ${TIMEOUT}s expired - file $CONNCHECK_FILE not found" >> $NTPD_LOG_NAME + return 1 + fi + + sleep "$INTERVAL" + done +} +# ────────────────────────────────────────────────────────────────────────────── +# service_start: main start path +# ────────────────────────────────────────────────────────────────────────────── +service_start() { + # RFC guard — only run if flag is present + if ! chrony_rfc_enabled; then + echo_t "SERVICE_CHRONYD : RFC flag absent — chrony path inactive" >> $NTPD_LOG_NAME + return 0 + fi + + # Wait for connectivitycheck to complete + if [ -f $CONNCHECK_FILE ]; then + echo_t "SERVICE_CHRONYD : connectivity success $CONNCHECK_FILE present" >> $NTPD_LOG_NAME + else + # Exclude XLE device from connectivity check. TODO + if [ "$BOX_TYPE" != "WNXL11BWL" ];then + echo_t "SERVICE_CHRONYD : start connectivity check waiting for $CONNCHECK_FILE file" >> $NTPD_LOG_NAME + waitForConnChkFile + fi + fi + + if [ -n "$SYSCFG_ntp_enabled" ] && [ "0" = "$SYSCFG_ntp_enabled" ]; then + syscfg set ntp_status 2 + sysevent set ${SERVICE_NAME}-status "stopped" + return 0 + fi + + # Do not start a second instance if chronyd is already running + if pidof "$CHRONY_BIN" > /dev/null 2>&1; then + echo_t "SERVICE_CHRONYD : already running (pid=$(pidof $CHRONY_BIN)), skipping start" >> $NTPD_LOG_NAME + return 0 + fi + + syscfg set ntp_status 2 + sysevent set ${SERVICE_NAME}-status "starting" + + + if [ "started" != "$CURRENT_WAN_STATUS" ]; then + syscfg set ntp_status 2 + sysevent set ${SERVICE_NAME}-status "wan-down" + return 0 + fi + + + # Stop ntpd if running — mutual exclusivity with chrony + if pidof ntpd > /dev/null 2>&1; then + echo_t "SERVICE_CHRONYD : stopping ntpd for mutual exclusivity" >> $NTPD_LOG_NAME + systemctl stop ntpd 2>/dev/null + killall ntpd 2>/dev/null + sleep 2 + fi + + # Start chronyd — only reaches here when no instance is running + # start chronyd will populate the config based on latest RFC configuration + echo_t "SERVICE_CHRONYD : starting chronyd daemon" >> $NTPD_LOG_NAME + systemctl start chronyd + rc=$? + if [ "$rc" -eq 0 ]; then + if [ -e "/usr/bin/print_uptime" ] && [ ! -f "/tmp/ntp_boot_uptime_logged" ]; then + /usr/bin/print_uptime "boot_to_chrony_uptime" + touch /tmp/ntp_boot_uptime_logged + fi + fi + if [ "$rc" -ne 0 ]; then + echo_t "SERVICE_CHRONYD : systemctl start chronyd failed (rc=$rc)" >> $NTPD_LOG_NAME + sysevent set ${SERVICE_NAME}-status "error" + return 1 + fi + + + sysevent set ${SERVICE_NAME}-status "started" + echo_t "SERVICE_CHRONYD : chronyd started — monitoring sync in background" >> $NTPD_LOG_NAME + + # Background sync monitor + set_chrony_sync_status & +} + +# ────────────────────────────────────────────────────────────────────────────── +# service_stop +# ────────────────────────────────────────────────────────────────────────────── +service_stop() { + + # RFC guard — if chrony is not the active client, nothing to stop + if ! systemctl is-active --quiet chronyd; then + echo_t "SERVICE_CHRONYD : chronyd is not running — skipping chronyd stop" >> $NTPD_LOG_NAME + return 0 + fi + echo_t "SERVICE_CHRONYD : stopping chronyd" >> $NTPD_LOG_NAME + systemctl stop chronyd 2>/dev/null + killall chronyd 2>/dev/null + sysevent set ${SERVICE_NAME}-status "stopped" +} + +# ────────────────────────────────────────────────────────────────────────────── +# Script entry point — serialise concurrent invocations via lockfile +# ────────────────────────────────────────────────────────────────────────────── +while [ -e "$LOCKFILE" ]; do + kill -0 "$(cat "$LOCKFILE")" 2>/dev/null || break + echo_t "SERVICE_CHRONYD : waiting for parallel instance to finish..." >> $NTPD_LOG_NAME + sleep 1 +done + +trap 'rm -f ${LOCKFILE}; exit' INT TERM EXIT +echo $$ > "$LOCKFILE" + +service_init +CURRENT_WAN_STATUS=$(sysevent get wan-status) + +case "$1" in + "${SERVICE_NAME}-start") + echo_t "SERVICE_CHRONYD : ${SERVICE_NAME}-start received" >> $NTPD_LOG_NAME + service_start + ;; + "${SERVICE_NAME}-stop") + echo_t "SERVICE_CHRONYD : ${SERVICE_NAME}-stop received" >> $NTPD_LOG_NAME + service_stop + ;; + "${SERVICE_NAME}-restart") + echo_t "SERVICE_CHRONYD : ${SERVICE_NAME}-restart received" >> $NTPD_LOG_NAME + service_stop + service_start + ;; + wan-status) + if [ "started" = "$CURRENT_WAN_STATUS" ]; then + # First sync this boot — service_start() guards against duplicate instances via pidof + echo_t "SERVICE_CHRONYD : wan-status=started, calling service_start" >> $NTPD_LOG_NAME + service_start + fi + ;; + *) + echo "Usage: $SELF_NAME [ ${SERVICE_NAME}-start | ${SERVICE_NAME}-stop | ${SERVICE_NAME}-restart | wan-status | ipv6_connection_state ]" >&2 + rm -f "$LOCKFILE" + exit 3 + ;; +esac + +echo_t "SERVICE_CHRONYD : end of script" >> $NTPD_LOG_NAME +rm -f "$LOCKFILE" diff --git a/source/scripts/init/service.d/service_ntpd.sh b/source/scripts/init/service.d/service_ntpd.sh index edae1e55..c1ec55eb 100644 --- a/source/scripts/init/service.d/service_ntpd.sh +++ b/source/scripts/init/service.d/service_ntpd.sh @@ -332,6 +332,15 @@ set_ntp_driftsync_status () service_start () { + if [ "$(syscfg get chrony_enabled)" = "true" ]; then + echo_t "SERVICE_NTPD : RFC flag Present — chrony is the active NTP client" >> $NTPD_LOG_NAME + sysevent set ${SERVICE_NAME}-status "stopped" + if pidof "$BIN" > /dev/null 2>&1; then + echo_t "SERVICE_NTPD : stopping ntpd because chrony is enabled" >> $NTPD_LOG_NAME + service_stop + fi + return 0 + fi local NTP_SERVER_URL_RESTORE="false" # Wait for connectivitycheck to complete From a255095fb1d83ceb09338d6621bcbd591a330e96 Mon Sep 17 00:00:00 2001 From: NareshM1702 Date: Mon, 10 Aug 2026 11:43:44 +0530 Subject: [PATCH 2/2] RDKB-65607: Check devicetype RFC for prod images alone (#392) Reason for change: Bind dropbear according to DeviceType RFC for prod images only Test Procedure: build and test ssh Risks: Low Priority: P1 Signed-off by : nareshkumar_m@comcast.com --- source/scripts/init/service.d/service_sshd.sh | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/source/scripts/init/service.d/service_sshd.sh b/source/scripts/init/service.d/service_sshd.sh index b004eade..8006a180 100755 --- a/source/scripts/init/service.d/service_sshd.sh +++ b/source/scripts/init/service.d/service_sshd.sh @@ -48,14 +48,6 @@ WAN_INTERFACE=$(getWanInterfaceName) DEFAULT_WAN_INTERFACE="erouter0" LANIPV6Support=`sysevent get LANIPv6GUASupport` DEVICE_MODE=`deviceinfo.sh -mode` -DEVICETYPE=$(dmcli eRT getv Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Identity.DeviceType | grep value | cut -d ":" -f 3 | tr -d ' ' | tr -s ' ' | tr '[:lower:]' '[:upper:]') -if [ "$DEVICETYPE" = "TEST" ] && [ "$USE_DYNAMICKEYING" = "TRUE" ]; then - USE_DEVKEYS="-f authorized_keys_dev" - echo_t "[utopia]: dropbear using dev authorization keys" -else - USE_DEVKEYS="" - echo_t "[utopia]: dropbear using prod authorization keys" -fi if [ "$BOX_TYPE" = "HUB4" ] || [ "$BOX_TYPE" = "SR300" ] || [ "$BOX_TYPE" = "SE501" ] || [ "$BOX_TYPE" = "WNXL11BWL" ] || [ "$BOX_TYPE" = "SR213" ] || [ "$BOX_TYPE" == "SCER11BEL" ] || [ "$BOX_TYPE" == "SCXF11BFL" ] || [ "$BOX_TYPE" == "XER2" ]; then CMINTERFACE=$WAN_INTERFACE @@ -157,6 +149,12 @@ do_start() { #chgrp admin $DIR_NAME #chmod 755 $DIR_NAME #fi + # Use prod keys only when both the build and deviceType RFC are prod; dev keys otherwise + USE_DEVKEYS="-f authorized_keys_dev" + DEVICETYPE=$(dmcli eRT getv Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Identity.DeviceType | grep value | cut -d ":" -f 3 | tr -d ' ' | tr -s ' ' | tr '[:lower:]' '[:upper:]') + if [ "$BUILD_TYPE" = "prod" -a "$DEVICETYPE" = "PROD" ]; then + USE_DEVKEYS="" + fi if ([ "$BOX_TYPE" = "XB6" -a "$MANUFACTURE" = "Arris" ] || [ "$MODEL_NUM" = "INTEL_PUMA" ] || [ "$BOX_TYPE" = "VNTXER5" ] || [ "$BOX_TYPE" = "SCER11BEL" -a "$LANIPV6Support" != "true" ] || [ "$BOX_TYPE" = "SCXF11BFL" ] || [ "$BOX_TYPE" = "XER2" ]) ;then get_listen_params