diff --git a/gateway-info/Makefile b/gateway-info/Makefile new file mode 100644 index 000000000..5de1e90ea --- /dev/null +++ b/gateway-info/Makefile @@ -0,0 +1,60 @@ +# +# Copyright (C) 2025 IOPSYS Software Solutions AB +# +# This is free software, licensed under the BSD-3-Clause +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=gateway-info +PKG_VERSION:=1.0.0 + +LOCAL_DEV:=0 +ifneq ($(LOCAL_DEV),1) +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://dev.iopsys.eu/bbf/gateway-info.git +PKG_SOURCE_VERSION:=26e407a25b156da75e3941d54ddd74294cd9eae8 +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz +PKG_MIRROR_HASH:=skip +endif + +PKG_LICENSE:=BSD-3-Clause +PKG_LICENSE_FILES:=LICENSE + +include $(INCLUDE_DIR)/package.mk +include ../bbfdm/bbfdm.mk + +define Package/gateway-info + CATEGORY:=Utilities + TITLE:=GatewayInfo Data Model Support + DEPENDS:=+libuci +libubox +libubus +libblobmsg-json + DEPENDS+=+libbbfdm-api +libbbfdm-ubus +dm-service +endef + +define Package/gateway-info/description + Package to add Device.GatewayInfo. data model support. +endef + +MAKE_PATH:=src + +ifeq ($(LOCAL_DEV),1) +define Build/Prepare + $(CP) ~/git/gateway-info/* $(PKG_BUILD_DIR)/ +endef +endif + +define Package/gateway-info/install + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_DIR) $(1)/etc/uci-defaults + $(INSTALL_DIR) $(1)/etc/udhcpc.user.d + $(INSTALL_DIR) $(1)/etc/bbfdm/services + $(INSTALL_DIR) $(1)/usr/share/bbfdm/micro_services + $(INSTALL_DATA) ./files/etc/config/gateway $(1)/etc/config/gateway + $(INSTALL_BIN) ./files/etc/udhcpc.user.d/udhcpc_gateway_info.user $(1)/etc/udhcpc.user.d/udhcpc_gateway_info.user + $(INSTALL_BIN) ./files/etc/uci-defaults/86-set-gateway-device-info $(1)/etc/uci-defaults/ + $(BBFDM_REGISTER_SERVICES) ./files/bbfdm_service.json $(1) $(PKG_NAME) + $(BBFDM_INSTALL_MS_DM) $(PKG_BUILD_DIR)/src/libgwinfo.so $(1) $(PKG_NAME) +endef + +$(eval $(call BuildPackage,gateway-info)) diff --git a/gateway-info/files/bbfdm_service.json b/gateway-info/files/bbfdm_service.json new file mode 100644 index 000000000..9867c13ba --- /dev/null +++ b/gateway-info/files/bbfdm_service.json @@ -0,0 +1,16 @@ +{ + "daemon": { + "enable": "1", + "service_name": "gateway-info", + "unified_daemon": false, + "services": [ + { + "parent_dm": "Device.", + "object": "GatewayInfo" + } + ], + "config": { + "loglevel": "3" + } + } +} diff --git a/gateway-info/files/etc/config/gateway b/gateway-info/files/etc/config/gateway new file mode 100644 index 000000000..79e61a09a --- /dev/null +++ b/gateway-info/files/etc/config/gateway @@ -0,0 +1,3 @@ +config global 'global' + option wan_interface 'wan' + option lan_interface 'lan' diff --git a/gateway-info/files/etc/uci-defaults/86-set-gateway-device-info b/gateway-info/files/etc/uci-defaults/86-set-gateway-device-info new file mode 100644 index 000000000..31ebe3c6e --- /dev/null +++ b/gateway-info/files/etc/uci-defaults/86-set-gateway-device-info @@ -0,0 +1,291 @@ +#!/bin/sh + +. /lib/functions.sh + +convert_to_hex() { + local val="" + local optval="${1}" + OPTIND=1 + while getopts ":" opt "-$optval" + do + temp=$(printf "%02X" "'${OPTARG:-:}") + val="${val}:${temp}" + done + + echo "${val}" +} + +configure_send_op125() { + local sendopt="${1}" + local intf="${2}" + local uci="${3}" + local hex_oui="" + local hex_serial="" + local hex_class="" + local oui_len=0 + local serial_len=0 + local class_len=0 + + if [ "${uci}" = "network" ]; then + local opt125="125:00:00:0D:E9" + else + if [ -z "${sendopt}" ]; then + local opt125="125,00:00:0D:E9" + else + local opt125=":00:00:0D:E9" + fi + fi + + config_get oui cpe manufacturer_oui "" + if [ -z "${oui}" ]; then + oui=$(db -q get device.deviceinfo.ManufacturerOUI) + fi + + oui=$(echo "${oui}" | tr 'a-f' 'A-F') + + config_get serial cpe serial_number "" + if [ -z "${serial}" ]; then + serial=$(db -q get device.deviceinfo.SerialNumber) + fi + + config_get class cpe product_class "" + if [ -z "${class}" ]; then + class=$(db -q get device.deviceinfo.ProductClass) + fi + + oui_len=$(echo -n "${oui}" | wc -m) + serial_len=$(echo -n "${serial}" | wc -m) + class_len=$(echo -n "${class}" | wc -m) + + if [ "${oui_len}" -eq 0 ] || [ "${serial_len}" -eq 0 ]; then + return 0 + fi + + opt125_len=$((oui_len + serial_len + class_len)) + if [ "${class_len}" -gt 0 ]; then + opt125_len=$((opt125_len + 6)) + else + opt125_len=$((opt125_len + 4)) + fi + + hex_opt125_len=$(printf "%02X" "${opt125_len}") + opt125="${opt125}:${hex_opt125_len}" + hex_oui=$(convert_to_hex "${oui}") + if [ -z "${hex_oui}" ]; then + return 0 + fi + + hex_oui_len=$(printf "%02X" "${oui_len}") + if [ "${uci}" = "network" ]; then + opt125="${opt125}:01:${hex_oui_len}${hex_oui}" + else + opt125="${opt125}:04:${hex_oui_len}${hex_oui}" + fi + + hex_serial=$(convert_to_hex "${serial}") + if [ -z "${hex_serial}" ]; then + return 0 + fi + + hex_serial_len=$(printf "%02X" "${serial_len}") + if [ "${uci}" = "network" ]; then + opt125="${opt125}:02:${hex_serial_len}${hex_serial}" + else + opt125="${opt125}:05:${hex_serial_len}${hex_serial}" + fi + + if [ "${class_len}" -gt 0 ]; then + hex_class=$(convert_to_hex "${class}") + if [ -z "${hex_class}" ]; then + return 0 + fi + + hex_class_len=$(printf "%02X" "${class_len}") + if [ "${uci}" = "network" ]; then + opt125="${opt125}:03:${hex_class_len}${hex_class}" + else + opt125="${opt125}:06:${hex_class_len}${hex_class}" + fi + fi + + + if [ "${uci}" = "network" ]; then + new_send_opt="$sendopt $opt125" + uci -q set network."${intf}".sendopts="$new_send_opt" + else + new_send_opt="$sendopt$opt125" + uci -q add_list dhcp."${intf}".dhcp_option="$new_send_opt" + fi +} + +check_for_suboptions() { + # Check if option 4 and 5 present inside enterprise id 3561 + data=$(echo "${1}" | sed 's/://g') + len=$(printf "${data}"|wc -c) + + rem_len="${len}" + while [ $rem_len -gt 8 ]; do + subopt_present=0 + + ent_id="${data:0:8}" + ent_id=$(printf "%d\n" "0x$ent_id") + if [ $ent_id -ne 3561 ]; then + len_val=${data:8:2} + data_len=$(printf "%d\n" "0x$len_val") + # add 4 byte for ent_id and 1 byte for len + data_len=$(( data_len * 2 + 10 )) + # move ahead data to next enterprise id + data=${data:"${data_len}":"${rem_len}"} + rem_len=$(( rem_len - data_len )) + continue + fi + + # read the length of enterprise data + len_val=${data:8:2} + data_len=$(printf "%d\n" "0x$len_val") + # add 4 byte for ent_id and 1 byte for len + data_len=$(( data_len * 2 + 10 )) + + len_val=${data:8:2} + opt_len=$(printf "%d\n" "0x$len_val") + if [ $opt_len -eq 0 ]; then + echo ${subopt_present} + return 0 + fi + + # populate the option data of enterprise id + sub_data_len=$(( opt_len * 2)) + # starting 10 means ahead of length field + sub_data=${data:10:"${sub_data_len}"} + + # parsing of suboption of option 125 + while [ $sub_data_len -gt 0 ]; do + # get the suboption id + sub_opt_id=${sub_data:0:2} + sub_opt_id=$(printf "%d\n" "0x$sub_opt_id") + case "${sub_opt_id}" in + "4") subopt_present=1 + ;; + "5") subopt_present=1 + ;; + esac + + if [ ${subopt_present} -eq 1 ]; then + break; + fi + + # get the length of suboption + sub_opt_len=${sub_data:2:2} + sub_opt_len=$(printf "%d\n" "0x$sub_opt_len") + sub_opt_len=$(( sub_opt_len * 2 )) + + # add 2 bytes for sub_opt id and sub_opt len field + sub_opt_end=$(( sub_opt_len + 4 )) + + # update the remaining sub option hex string length + sub_data_len=$((sub_data_len - sub_opt_end)) + + # fetch next sub option hex string + sub_data=${sub_data:${sub_opt_end}:${sub_data_len}} + done + + if [ ${subopt_present} -eq 1 ]; then + break; + else + # move ahead data to next enterprise id + rem_len=$(( rem_len - $data_len )) + data=${data:"${data_len}":"${rem_len}"} + fi + done + + echo ${subopt_present} +} + +enable_dhcp_option125() { + local wan="${1}" + local reqopts="$(uci -q get network."${wan}".reqopts)" + local sendopts="$(uci -q get network."${wan}".sendopts)" + local proto="$(uci -q get network."${wan}".proto)" + local newreqopts="" + local newsendopts="" + local req125_present=0 + local send125_present=0 + local network_uci_update=0 + local opt125="125:" + + for ropt in $reqopts; do + case $ropt in + 125) req125_present=1 ;; + *) ;; + esac + done + + for sopt in $sendopts; do + if [[ "$sopt" == "$opt125"* ]]; then + send125_present=1 + break + fi + done + + if [ "${proto}" = "dhcp" ]; then + if [ ${req125_present} -eq 0 ]; then + newreqopts="$reqopts 125" + uci -q set network."${wan}".reqopts="$newreqopts" + network_uci_update=1 + fi + + if [ ${send125_present} -eq 0 ]; then + configure_send_op125 "${sendopts}" "${wan}" "network" + network_uci_update=1 + fi + fi + + if [ ${network_uci_update} -eq 1 ]; then + uci commit network + fi +} + +enable_dnsmasq_option125() { + local lan="${1}" + local send125_present=0 + local opt125="125," + + local proto="$(uci -q get dhcp."${lan}".dhcpv4)" + if [ "${proto}" = "server" ]; then + opt_list="$(uci -q get dhcp."${lan}".dhcp_option)" + base_opt="" + + for sopt in $opt_list; do + if [[ "$sopt" == "$opt125"* ]]; then + send125_present=$(check_for_suboptions "${sopt:4}") + base_opt="${sopt}" + break + fi + done + + if [ ${send125_present} -eq 0 ]; then + uci -q del_list dhcp."${lan}".dhcp_option="${base_opt}" + configure_send_op125 "${base_opt}" "${lan}" "dhcp" + uci commit dhcp + fi + fi +} + +configure_gateway_device_info() { + wan_intf="" + lan_intf="" + + config_load gateway + config_get wan_intf global wan_interface "wan" + config_get lan_intf global lan_interface "lan" + + # Set dhcp_option 125 for device info if not already configured + enable_dhcp_option125 "${wan_intf}" + + if [ "${wan_intf}" != "${lan_intf}" ]; then + # This is extender no need to configure gateway info + enable_dnsmasq_option125 "${lan_intf}" + fi +} + +configure_gateway_device_info diff --git a/gateway-info/files/etc/udhcpc.user.d/udhcpc_gateway_info.user b/gateway-info/files/etc/udhcpc.user.d/udhcpc_gateway_info.user new file mode 100644 index 000000000..50be8f824 --- /dev/null +++ b/gateway-info/files/etc/udhcpc.user.d/udhcpc_gateway_info.user @@ -0,0 +1,134 @@ +#!/bin/sh + +. /lib/functions.sh + +CLASS="" +OUI="" +SERIAL="" + +get_vivsoi() { + # opt125 environment variable has data in below format + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | enterprise-number1 | + # | | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | data-len1 | | + # +-+-+-+-+-+-+-+-+ option-data1 | + # / / + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ----- + # | enterprise-number2 | ^ + # | | | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | + # | data-len2 | | optional + # +-+-+-+-+-+-+-+-+ option-data2 | | + # / / | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | + # ~ ... ~ V + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ----- + + # Enterprise Id Len Sub Op SLen Data Sub Op SLen Data Sub Op SLen Data + # +-------------+-----+------+------+----+------+-----+----+-----+------+-----+----+ + # | id | n | 1 | n1 | D1 | 2 | n2 | D2 | ... | 6 | n6 | D6 | + # +-------------+-----+------+------+----+------+-----+----+-----+------+-----+----+ + + local opt125="$1" + local len="$2" + local ent_id + + #hex-string 2 character=1 Byte + # length in hex string will be twice of actual Byte length + [ "$len" -gt "8" ] || return + + data="${opt125}" + rem_len="${len}" + while [ $rem_len -gt 0 ]; do + ent_id=${data:0:8} + ent_id=$(printf "%d\n" "0x$ent_id") + + if [ $ent_id -ne 3561 ]; then + len_val=${data:8:2} + data_len=$(printf "%d\n" "0x$len_val") + # add 4 byte for ent_id and 1 byte for len + data_len=$(( data_len * 2 + 10 )) + # move ahead data to next enterprise id + data=${data:"${data_len}":"${rem_len}"} + rem_len=$(( rem_len - $data_len )) + continue + fi + + # read the length of enterprise data + len_val=${data:8:2} + data_len=$(printf "%d\n" "0x$len_val") + # add 4 byte for ent_id and 1 byte for len + data_len=$(( data_len * 2 + 10 )) + + opt_len=$(printf "%d\n" "0x$len_val") + [ $opt_len -eq 0 ] && return + + # populate the option data of enterprise id + sub_data_len=$(( opt_len * 2)) + # starting 10 means ahead of length field + sub_data=${data:10:"${sub_data_len}"} + + # parsing of suboption of option 125 + while [ $sub_data_len -gt 0 ]; do + # get the suboption id + sub_opt_id=${sub_data:0:2} + sub_opt_id=$(printf "%d\n" "0x$sub_opt_id") + + # get the length of suboption + sub_opt_len=${sub_data:2:2} + sub_opt_len=$(printf "%d\n" "0x$sub_opt_len") + sub_opt_len=$(( sub_opt_len * 2 )) + + # get the value of sub option starting 4 means starting after length + sub_opt_val=${sub_data:4:${sub_opt_len}} + + # assign the value found in sub option + case "${sub_opt_id}" in + "4") OUI=$(echo -n $sub_opt_val | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf && echo '') + ;; + "5") SERIAL=$(echo -n $sub_opt_val | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf && echo '') + ;; + "6") CLASS=$(echo -n $sub_opt_val | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf && echo '') + ;; + esac + + # add 2 bytes for sub_opt id and sub_opt len field + sub_opt_end=$(( sub_opt_len + 4 )) + + # update the remaining sub option hex string length + sub_data_len=$((sub_data_len - sub_opt_end)) + + # fetch next sub option hex string + sub_data=${sub_data:${sub_opt_end}:${sub_data_len}} + done + + # move ahead data to next enterprise id + data=${data:"${data_len}":"${rem_len}"} + rem_len=$(( rem_len - data_len )) + done +} + +config_load gateway +config_get wan_intf global wan_interface "wan" + +if [ "${wan_intf}" == "${INTERFACE}" ]; then + if [ -n "$opt125" ]; then + len=$(printf "$opt125"|wc -c) + get_vivsoi "$opt125" "$len" + fi + + mkdir -p /var/state + touch /var/state/gwinfo + sec=$(uci -q -c /var/state get gwinfo.gatewayinfo) + if [ -z "${sec}" ]; then + sec=$(uci -q -c /var/state add gwinfo gatewayinfo) + uci -q -c /var/state rename gwinfo."${sec}"="gatewayinfo" + fi + + uci -q -c /var/state set gwinfo.gatewayinfo.class="$CLASS" + uci -q -c /var/state set gwinfo.gatewayinfo.oui="$OUI" + uci -q -c /var/state set gwinfo.gatewayinfo.serial="$SERIAL" + uci -q -c /var/state commit gwinfo +fi diff --git a/netmode/files/etc/uci-defaults/netmode.l2mode b/netmode/files/etc/uci-defaults/62-netmode.l2mode similarity index 96% rename from netmode/files/etc/uci-defaults/netmode.l2mode rename to netmode/files/etc/uci-defaults/62-netmode.l2mode index 82fc21888..3bd7ef326 100644 --- a/netmode/files/etc/uci-defaults/netmode.l2mode +++ b/netmode/files/etc/uci-defaults/62-netmode.l2mode @@ -99,6 +99,10 @@ l2_network_config() { uci -q set cwmp.cpe.default_wan_interface="lan" uci -q commit cwmp + # Update gateway WAN Interface + uci -q set gateway.global.wan_interface="lan" + uci -q commit gateway + # disable firewall uci -q set firewall.globals.enabled="0" uci -q commit firewall