mirror of
https://dev.iopsys.eu/feed/iopsys.git
synced 2025-12-10 07:44:50 +01:00
624 lines
14 KiB
Bash
Executable file
624 lines
14 KiB
Bash
Executable file
#!/bin/sh /etc/rc.common
|
|
|
|
START=99
|
|
STOP=01
|
|
USE_PROCD=1
|
|
|
|
PROG=/usr/sbin/uspc
|
|
CONFIGURATION=uspc
|
|
|
|
RESET_FILE="/tmp/usp/uspc_param_reset.txt"
|
|
SQL_DB_FILE="/tmp/usp/uspc.db"
|
|
|
|
BASEPATH=""
|
|
INSTANCE_COUNT=0
|
|
|
|
. /usr/share/libubox/jshn.sh
|
|
. /lib/functions.sh
|
|
|
|
global_init()
|
|
{
|
|
BASEPATH=""
|
|
INSTANCE_COUNT=0
|
|
}
|
|
|
|
log()
|
|
{
|
|
echo "$*"|logger -t uspc.init -p debug
|
|
}
|
|
|
|
db_set_reset_file()
|
|
{
|
|
local param value
|
|
|
|
param="${1}"
|
|
shift
|
|
value="$*"
|
|
|
|
if [ -n "${param}" ] && [ -n "${value}" ]; then
|
|
echo "${param} \"${value}\"">>${RESET_FILE}
|
|
else
|
|
echo >>${RESET_FILE}
|
|
fi
|
|
}
|
|
|
|
db_set()
|
|
{
|
|
db_set_reset_file "$@"
|
|
}
|
|
|
|
# if db present then check if it matches with existing instances
|
|
# fallback to max instance present + 1
|
|
# In case of no db get the count
|
|
get_base_path()
|
|
{
|
|
local refpath value path count
|
|
|
|
refpath="${1}"
|
|
value="${2}"
|
|
path=""
|
|
count=0
|
|
|
|
if [ -z "${path}" ]; then
|
|
INSTANCE_COUNT=$(( INSTANCE_COUNT + 1 ))
|
|
path="${refpath}${INSTANCE_COUNT}"
|
|
fi
|
|
BASEPATH="${path}"
|
|
}
|
|
|
|
get_refrence_path()
|
|
{
|
|
local dmref value path
|
|
|
|
dmref="${1}"
|
|
value="${2}"
|
|
path=""
|
|
|
|
path=$(grep "${dmref}\d.Alias " ${RESET_FILE}|grep -w "${value}")
|
|
path=${path%.*}
|
|
echo "${path}"
|
|
}
|
|
|
|
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}"
|
|
}
|
|
|
|
check_for_suboptions() {
|
|
new_opt=""
|
|
# Check if option 25 and 29 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 ))
|
|
|
|
opt=${data:0:"${data_len}"}
|
|
if [ -n "${new_opt}" ]; then
|
|
new_opt="${new_opt}:$(echo ${opt} | sed 's/../&:/g;s/:$//')"
|
|
else
|
|
new_opt="$(echo ${opt} | sed 's/../&:/g;s/:$//')"
|
|
fi
|
|
|
|
# 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 "${new_opt}"
|
|
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
|
|
"25") subopt_present=1
|
|
;;
|
|
"26") subopt_present=1
|
|
;;
|
|
"27") subopt_present=1
|
|
;;
|
|
"28") subopt_present=1
|
|
;;
|
|
"29") 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
|
|
# move ahead data to next enterprise id
|
|
rem_len=$(( rem_len - $data_len ))
|
|
data=${data:"${data_len}":"${rem_len}"}
|
|
else
|
|
opt=${data:0:"${data_len}"}
|
|
if [ -n "${new_opt}" ]; then
|
|
new_opt="${new_opt}:$(echo ${opt} | sed 's/../&:/g;s/:$//')"
|
|
else
|
|
new_opt="$(echo ${opt} | sed 's/../&:/g;s/:$//')"
|
|
fi
|
|
|
|
# move ahead data to next enterprise id
|
|
rem_len=$(( rem_len - $data_len ))
|
|
data=${data:"${data_len}":"${rem_len}"}
|
|
fi
|
|
done
|
|
|
|
echo "${new_opt}"
|
|
}
|
|
|
|
configure_dnsmasq_op125() {
|
|
intf="${1}"
|
|
|
|
endpoint=""
|
|
proto=""
|
|
address=""
|
|
port=""
|
|
topic=""
|
|
prov_code="obusp-client"
|
|
interval="5"
|
|
multiplier="2000"
|
|
|
|
config_load ${CONFIGURATION}
|
|
config_get endpoint controller EndpointID
|
|
config_get proto controller Protocol
|
|
if [ -z "${endpoint}" ] || [ -z "${proto}" ]; then
|
|
return 0
|
|
fi
|
|
|
|
if [ "${proto}" = "MQTT" ]; then
|
|
config_get port mqtt BrokerPort "1883"
|
|
config_get topic controller ResponseTopicConfigured
|
|
proto="mqtt://"
|
|
else
|
|
return 0
|
|
fi
|
|
|
|
address=$(ifstatus "${intf}" | jsonfilter -q -e '@["ipv4-address"][0].address')
|
|
if [ -z "${address}" ] || [ -z "${topic}" ]; then
|
|
return 0
|
|
fi
|
|
|
|
subop_present=0
|
|
opt125="125,"
|
|
base_opt=""
|
|
|
|
service="$(uci -q get dhcp."${intf}".dhcpv4)"
|
|
if [ "${service}" = "server" ]; then
|
|
opt_list="$(uci -q get dhcp."${intf}".dhcp_option)"
|
|
for sopt in $opt_list; do
|
|
if [[ "$sopt" == "$opt125"* ]]; then
|
|
base_opt=$(check_for_suboptions "${sopt:4}")
|
|
uci -q del_list dhcp."${intf}".dhcp_option="$sopt"
|
|
uci -q commit dhcp
|
|
break
|
|
fi
|
|
done
|
|
else
|
|
return 0
|
|
fi
|
|
|
|
if [ -z "${base_opt}" ]; then
|
|
opt125="125,00:00:0D:E9"
|
|
else
|
|
opt125="125,${base_opt}:00:00:0D:E9"
|
|
fi
|
|
|
|
url="${proto}${address}:${port}${topic}"
|
|
url_len=$(echo -n "${url}" | wc -m)
|
|
prov_code_len=$(echo -n "${prov_code}" | wc -m)
|
|
endpoint_len=$(echo -n "${endpoint}" | wc -m)
|
|
interval_len=$(echo -n "${interval}" | wc -m)
|
|
multiplier_len=$(echo -n "${multiplier}" | wc -m)
|
|
|
|
([ ${url_len} -gt 255 ] || [ ${prov_code_len} -gt 255 ] || [ ${endpoint_len} -gt 255 ]) && return 0
|
|
([ ${interval_len} -gt 255 ] || [ ${multiplier_len} -gt 255 ]) && return 0
|
|
|
|
opt125_len=$((url_len + prov_code_len + endpoint_len + interval_len + multiplier_len))
|
|
opt125_len=$((opt125_len + 10))
|
|
|
|
[ $opt125_len -gt 255 ] && return 0
|
|
|
|
hex_opt125_len=$(printf "%02X" "${opt125_len}")
|
|
opt125="${opt125}:${hex_opt125_len}"
|
|
hex_url=$(convert_to_hex "${url}")
|
|
if [ -z "${hex_url}" ]; then
|
|
return 0
|
|
fi
|
|
|
|
hex_url_len=$(printf "%02X" "${url_len}")
|
|
opt125="${opt125}:19:${hex_url_len}${hex_url}"
|
|
|
|
hex_prov_code=$(convert_to_hex "${prov_code}")
|
|
if [ -z "${hex_prov_code}" ]; then
|
|
return 0
|
|
fi
|
|
|
|
hex_prov_len=$(printf "%02X" "${prov_code_len}")
|
|
opt125="${opt125}:1A:${hex_prov_len}${hex_prov_code}"
|
|
|
|
hex_interval=$(convert_to_hex "${interval}")
|
|
if [ -z "${hex_interval}" ]; then
|
|
return 0
|
|
fi
|
|
|
|
hex_interval_len=$(printf "%02X" "${interval_len}")
|
|
opt125="${opt125}:1B:${hex_interval_len}${hex_interval}"
|
|
|
|
hex_multiplier=$(convert_to_hex "${multiplier}")
|
|
if [ -z "${hex_multiplier}" ]; then
|
|
return 0
|
|
fi
|
|
|
|
hex_multiplier_len=$(printf "%02X" "${multiplier_len}")
|
|
opt125="${opt125}:1C:${hex_multiplier_len}${hex_multiplier}"
|
|
|
|
hex_endpoint=$(convert_to_hex "${endpoint}")
|
|
if [ -z "${hex_endpoint}" ]; then
|
|
return 0
|
|
fi
|
|
|
|
hex_endpoint_len=$(printf "%02X" "${endpoint_len}")
|
|
opt125="${opt125}:1D:${hex_endpoint_len}${hex_endpoint}"
|
|
|
|
uci -q add_list dhcp."${intf}".dhcp_option="$opt125"
|
|
ubus call uci commit '{"config":"dhcp"}'
|
|
}
|
|
|
|
boot() {
|
|
local enabled
|
|
local interface
|
|
|
|
config_load ${CONFIGURATION}
|
|
config_get_bool enabled global enabled 0
|
|
config_get interface global interface "lan"
|
|
|
|
if [ "${enabled}" -eq 0 ]; then
|
|
return 0;
|
|
fi
|
|
|
|
# Check if device is an extender nothing to do
|
|
lan_proto="$(uci -q get network.lan.proto)"
|
|
if [ "${lan_proto}" == "dhcp" ]; then
|
|
# extender so return
|
|
return 0;
|
|
fi
|
|
|
|
configure_dnsmasq_op125 "${interface}"
|
|
|
|
start
|
|
}
|
|
|
|
validate_global_section()
|
|
{
|
|
uci_validate_section ${CONFIGURATION} uspc "${1}" \
|
|
'enabled:bool:1' \
|
|
'debug:bool:0' \
|
|
'prototrace:bool:0' \
|
|
'log_level:uinteger' \
|
|
'log_dest:string' \
|
|
'db_file:string'
|
|
}
|
|
|
|
validate_mqtt_client_section()
|
|
{
|
|
uci_validate_section ${CONFIGURATION} mqtt "${1}" \
|
|
'Enable:bool:1' \
|
|
'BrokerAddress:string' \
|
|
'BrokerPort:port:1883' \
|
|
'Username:string' \
|
|
'Password:string' \
|
|
'ProtocolVersion:or("3.1", "3.1.1","5.0"):5.0' \
|
|
'TransportProtocol:or("TCP/IP","TLS"):TCP/IP' \
|
|
'ClientID:string'
|
|
}
|
|
|
|
validate_controller_section()
|
|
{
|
|
uci_validate_section ${CONFIGURATION} mtp "${1}" \
|
|
'EndpointID:string' \
|
|
'Protocol:or("MQTT", "WebSocket")' \
|
|
'ResponseTopicConfigured:string' \
|
|
'Destination:string' \
|
|
'Port:port' \
|
|
'Path:string' \
|
|
'mqtt:string' \
|
|
'stomp:string' \
|
|
'Reference:string' \
|
|
'EnableEncryption:bool:0'
|
|
}
|
|
|
|
configure_controller() {
|
|
local EndpointID Protocol ResponseTopicConfigured
|
|
local Destination Path Port EnableEncryption Reference
|
|
local stomp mqtt dm_ref sec
|
|
|
|
sec="${1}"
|
|
validate_controller_section "${1}" || {
|
|
log "Validation of mtp section failed"
|
|
return 1;
|
|
}
|
|
|
|
if [ -z "${EndpointID}" ]; then
|
|
log "EndpointID not defined for controller"
|
|
return 1;
|
|
fi
|
|
|
|
db_set Device.LocalAgent.EndpointID "${EndpointID}"
|
|
|
|
sec="${sec/mtp_/cpe-}"
|
|
get_base_path "Device.LocalAgent.MTP." "${sec}"
|
|
if [ -z "${BASEPATH}" ]; then
|
|
log "Failed to get path [$BASEPATH]"
|
|
return 1;
|
|
fi
|
|
|
|
if [ -z "${Protocol}" ]; then
|
|
log "Protocol not defined for the mtp[${1}] section"
|
|
return 1;
|
|
fi
|
|
|
|
dm_ref=""
|
|
if [ -z "${Reference}" ]; then
|
|
if [ "${Protocol}" = "STOMP" ]; then
|
|
stomp="${stomp/stomp_/cpe-}"
|
|
dm_ref=$(get_refrence_path "Device.STOMP.Connection." "${stomp}")
|
|
elif [ "${Protocol}" = "MQTT" ]; then
|
|
mqtt="${mqtt/mqtt_/cpe-}"
|
|
dm_ref=$(get_refrence_path "Device.MQTT.Client." "${mqtt}")
|
|
fi
|
|
else
|
|
dm_ref="${Reference}"
|
|
fi
|
|
|
|
db_set "${BASEPATH}.Alias" "${sec}"
|
|
db_set "${BASEPATH}.Enable" "1"
|
|
db_set "${BASEPATH}.Protocol" "${Protocol}"
|
|
if [ "${Protocol}" = "MQTT" ]; then
|
|
db_set "${BASEPATH}.MQTT.Reference" "${dm_ref}"
|
|
db_set "${BASEPATH}.MQTT.ResponseTopicConfigured" "${ResponseTopicConfigured}"
|
|
elif [ "${Protocol}" = "STOMP" ]; then
|
|
db_set "${BASEPATH}.STOMP.Reference" "${dm_ref}"
|
|
db_set "${BASEPATH}.STOMP.Destination" "${Destination}"
|
|
elif [ "${Protocol}" = "CoAP" ]; then
|
|
db_set "${BASEPATH}.CoAP.Path" "${Path}"
|
|
db_set "${BASEPATH}.CoAP.Port" "${Port}"
|
|
elif [ "${Protocol}" = "WebSocket" ]; then
|
|
db_set "${BASEPATH}.WebSocket.Path" "${Path}"
|
|
db_set "${BASEPATH}.WebSocket.Port" "${Port}"
|
|
db_set "${BASEPATH}.WebSocket.EnableEncryption" "${EnableEncryption}"
|
|
fi
|
|
db_set
|
|
}
|
|
|
|
validate_agent_section()
|
|
{
|
|
uci_validate_section ${CONFIGURATION} agent "${1}" \
|
|
'name:string' \
|
|
'EndpointID:string' \
|
|
'Topic:string'
|
|
}
|
|
|
|
configure_agent() {
|
|
local EndpointID Topic name
|
|
local stomp mqtt dm_ref sec
|
|
|
|
sec="${1}"
|
|
validate_agent_section "${1}" || {
|
|
log "Validation of agent section failed"
|
|
return 1;
|
|
}
|
|
|
|
if [ -z "${EndpointID}" ]; then
|
|
log "EndpointID not defined for agent"
|
|
return 1;
|
|
fi
|
|
|
|
if [ -z "${Topic}" ]; then
|
|
log "Topic not defined for agent"
|
|
return 1;
|
|
fi
|
|
|
|
|
|
sec="${sec/mtp_/cpe-}"
|
|
get_base_path "Device.LocalAgent.Controller." "${sec}"
|
|
if [ -z "${BASEPATH}" ]; then
|
|
log "Failed to get path [$BASEPATH]"
|
|
return 1;
|
|
fi
|
|
|
|
db_set "${BASEPATH}.Alias" "${sec}"
|
|
db_set "${BASEPATH}.Enable" "1"
|
|
db_set "${BASEPATH}.EndpointID" "${EndpointID}"
|
|
db_set "${BASEPATH}.MTP.1.Enable" "1"
|
|
db_set "${BASEPATH}.MTP.1.Protocol" "MQTT"
|
|
db_set "${BASEPATH}.MTP.1.MQTT.Reference" "Device.MQTT.Client.1"
|
|
db_set "${BASEPATH}.MTP.1.MQTT.Topic" "${Topic}"
|
|
db_set
|
|
}
|
|
|
|
configure_mqtt_client() {
|
|
local BrokerAddress BrokerPort Enable Username Password ProtocolVersion
|
|
local TransportProtocol ClientID
|
|
local sec
|
|
|
|
sec="${1}"
|
|
validate_mqtt_client_section "${1}" || {
|
|
log "Validation of mqtt section failed"
|
|
return 1;
|
|
}
|
|
|
|
sec="${sec/mqtt_/cpe-}"
|
|
get_base_path "Device.MQTT.Client." "${sec}"
|
|
if [ -z "${BASEPATH}" ]; then
|
|
log "Failed to get path [$BASEPATH]"
|
|
return 1;
|
|
fi
|
|
|
|
db_set "${BASEPATH}.Alias" "${sec}"
|
|
db_set "${BASEPATH}.Enable" "${Enable}"
|
|
db_set "${BASEPATH}.BrokerAddress" "${BrokerAddress}"
|
|
db_set "${BASEPATH}.BrokerPort" "${BrokerPort}"
|
|
db_set "${BASEPATH}.Username" "${Username}"
|
|
db_set "${BASEPATH}.Password" "${Password}"
|
|
db_set "${BASEPATH}.ProtocolVersion" "${ProtocolVersion}"
|
|
db_set "${BASEPATH}.TransportProtocol" "${TransportProtocol}"
|
|
db_set "${BASEPATH}.ClientID" "${ClientID}"
|
|
|
|
db_set
|
|
}
|
|
|
|
configure_uspc() {
|
|
local enabled trust_cert ifname interface debug prototrace log_level db_file log_dest
|
|
local client_cert
|
|
|
|
validate_global_section "global"
|
|
|
|
if [ "${debug}" -ne "0" ]; then
|
|
# Forward stdout of the command to logd
|
|
procd_set_param stdout 1
|
|
# Same for stderr
|
|
procd_set_param stderr 1
|
|
fi
|
|
|
|
procd_append_param command -u
|
|
if [ "${prototrace}" -eq 1 ]; then
|
|
procd_append_param command -p
|
|
fi
|
|
|
|
if [ -n "${log_level}" ]; then
|
|
procd_append_param command -v "${log_level}"
|
|
fi
|
|
|
|
if [ -n "${log_dest}" ]; then
|
|
procd_append_param command -l "${log_dest}"
|
|
fi
|
|
|
|
if [ -f "${RESET_FILE}" ]; then
|
|
procd_append_param command -r ${RESET_FILE}
|
|
fi
|
|
}
|
|
|
|
# Create factory reset file
|
|
db_init()
|
|
{
|
|
# Load configuration
|
|
config_load $CONFIGURATION
|
|
config_get SQL_DB_FILE global db_file "/tmp/usp/uspc.db"
|
|
|
|
# Remove DB and generate from uci
|
|
[ -f "${SQL_DB_FILE}" ] && rm -f "${SQL_DB_FILE}"
|
|
|
|
# Remove reset file if present
|
|
[ -f "${RESET_FILE}" ] && rm -f ${RESET_FILE}
|
|
|
|
config_load $CONFIGURATION
|
|
global_init
|
|
config_foreach configure_mqtt_client mqtt
|
|
global_init
|
|
config_foreach configure_controller controller
|
|
global_init
|
|
config_foreach configure_agent agent
|
|
|
|
return 0;
|
|
}
|
|
|
|
register_service()
|
|
{
|
|
procd_open_instance ${CONFIGURATION}
|
|
procd_set_param command ${PROG}
|
|
|
|
configure_uspc
|
|
procd_set_param respawn \
|
|
"${respawn_threshold:-5}" \
|
|
"${respawn_timeout:-10}" "${respawn_retry:-3}"
|
|
|
|
procd_close_instance
|
|
}
|
|
|
|
start_service() {
|
|
local enabled mode
|
|
|
|
config_load ${CONFIGURATION}
|
|
config_get_bool enabled global enabled 0
|
|
|
|
if [ "${enabled}" -eq 0 ]; then
|
|
return 0;
|
|
fi
|
|
|
|
# Check if device is an extender then do not start the service
|
|
lan_proto="$(uci -q get network.lan.proto)"
|
|
if [ "${lan_proto}" == "dhcp" ]; then
|
|
# extender so return
|
|
return 0;
|
|
fi
|
|
|
|
mkdir -p /tmp/usp/
|
|
db_init
|
|
register_service
|
|
}
|
|
|
|
stop_service() {
|
|
${PROG} -c stop >/dev/null 2>&1
|
|
}
|
|
|
|
reload_service() {
|
|
stop
|
|
start
|
|
}
|
|
|
|
service_triggers() {
|
|
procd_add_reload_trigger "uspc"
|
|
}
|