mirror of
https://github.com/openwrt/packages.git
synced 2025-02-07 13:59:51 +00:00
Virtual netdevices created for multiplexing should not be skipped when reporting events, otherwise it is not possible to setup the data connection. Add these exceptions in mm_report_event function. Signed-off-by: Daniele Palmas <dnlplm@gmail.com>
282 lines
7.9 KiB
Bash
282 lines
7.9 KiB
Bash
#!/bin/sh
|
|
# Copyright (C) 2016 Velocloud Inc
|
|
# Copyright (C) 2016 Aleksander Morgado <aleksander@aleksander.es>
|
|
|
|
################################################################################
|
|
|
|
. /lib/functions.sh
|
|
. /lib/netifd/netifd-proto.sh
|
|
|
|
################################################################################
|
|
# Runtime state
|
|
|
|
MODEMMANAGER_RUNDIR="/var/run/modemmanager"
|
|
MODEMMANAGER_PID_FILE="${MODEMMANAGER_RUNDIR}/modemmanager.pid"
|
|
MODEMMANAGER_CDCWDM_CACHE="${MODEMMANAGER_RUNDIR}/cdcwdm.cache"
|
|
MODEMMANAGER_MONITOR_CACHE="${MODEMMANAGER_RUNDIR}/monitor.cache"
|
|
MODEMMANAGER_EVENTS_CACHE="${MODEMMANAGER_RUNDIR}/events.cache"
|
|
|
|
################################################################################
|
|
# Common logging
|
|
|
|
mm_log() {
|
|
local level="$1"; shift
|
|
|
|
[ "${level}" = "debug" ] && return
|
|
logger -p "daemon.${level}" -t "ModemManager[$$]" "hotplug: $*"
|
|
}
|
|
|
|
################################################################################
|
|
# Receives as input argument the full sysfs path of the device
|
|
# Returns the physical device sysfs path
|
|
#
|
|
# NOTE: this method only works when the device exists, i.e. it cannot be used
|
|
# on removal hotplug events
|
|
|
|
mm_find_physdev_sysfs_path() {
|
|
local tmp_path="$1"
|
|
|
|
while true; do
|
|
tmp_path=$(dirname "${tmp_path}")
|
|
|
|
# avoid infinite loops iterating
|
|
[ -z "${tmp_path}" ] || [ "${tmp_path}" = "/" ] && return
|
|
|
|
# For USB devices, the physical device will be that with a idVendor
|
|
# and idProduct pair of files
|
|
[ -f "${tmp_path}"/idVendor ] && [ -f "${tmp_path}"/idProduct ] && {
|
|
tmp_path=$(readlink -f "$tmp_path")
|
|
echo "${tmp_path}"
|
|
return
|
|
}
|
|
|
|
# For PCI devices, the physical device will be that with a vendor
|
|
# and device pair of files
|
|
[ -f "${tmp_path}"/vendor ] && [ -f "${tmp_path}"/device ] && {
|
|
tmp_path=$(readlink -f "$tmp_path")
|
|
echo "${tmp_path}"
|
|
return
|
|
}
|
|
done
|
|
}
|
|
|
|
################################################################################
|
|
|
|
# Returns the cdc-wdm name retrieved from sysfs
|
|
mm_track_cdcwdm() {
|
|
local wwan="$1"
|
|
local cdcwdm
|
|
|
|
cdcwdm=$(ls "/sys/class/net/${wwan}/device/usbmisc/")
|
|
[ -n "${cdcwdm}" ] || return
|
|
|
|
# We have to cache it for later, as we won't be able to get the
|
|
# associated cdc-wdm device on a remove event
|
|
echo "${wwan} ${cdcwdm}" >> "${MODEMMANAGER_CDCWDM_CACHE}"
|
|
|
|
echo "${cdcwdm}"
|
|
}
|
|
|
|
# Returns the cdc-wdm name retrieved from the cache
|
|
mm_untrack_cdcwdm() {
|
|
local wwan="$1"
|
|
local cdcwdm
|
|
|
|
# Look for the cached associated cdc-wdm device
|
|
[ -f "${MODEMMANAGER_CDCWDM_CACHE}" ] || return
|
|
|
|
cdcwdm=$(awk -v wwan="${wwan}" '!/^#/ && $0 ~ wwan { print $2 }' "${MODEMMANAGER_CDCWDM_CACHE}")
|
|
[ -n "${cdcwdm}" ] || return
|
|
|
|
# Remove from cache
|
|
sed -i "/${wwan} ${cdcwdm}/d" "${MODEMMANAGER_CDCWDM_CACHE}"
|
|
|
|
echo "${cdcwdm}"
|
|
}
|
|
|
|
# Callback for config_foreach()
|
|
mm_get_modem_config_foreach_cb() {
|
|
local cfg="$1"
|
|
local sysfspath="$2"
|
|
|
|
local dev
|
|
dev=$(uci_get network "${cfg}" device)
|
|
[ "${dev}" = "${sysfspath}" ] || return 0
|
|
|
|
echo "${cfg}"
|
|
}
|
|
|
|
# Returns the name of the interface configured for this device
|
|
mm_get_modem_config() {
|
|
local sysfspath="$1"
|
|
|
|
# Look for configuration for the given sysfs path
|
|
config_load network
|
|
config_foreach mm_get_modem_config_foreach_cb interface "${sysfspath}"
|
|
}
|
|
|
|
################################################################################
|
|
# Event reporting
|
|
|
|
# Receives as input the action, the device name and the subsystem
|
|
mm_report_event() {
|
|
local action="$1"
|
|
local name="$2"
|
|
local subsystem="$3"
|
|
local sysfspath="$4"
|
|
|
|
# Do not save virtual devices
|
|
local virtual result
|
|
virtual="$(echo "$sysfspath" | cut -d'/' -f4)"
|
|
[ "$virtual" = "virtual" ] && {
|
|
mm_log "debug" "sysfspath is a virtual device ($sysfspath)"
|
|
case "$name" in
|
|
"qmapmux"*)
|
|
mm_log "debug" "rmnet netdevice $name"
|
|
;;
|
|
"qmimux"*)
|
|
mm_log "debug" "qmi_wwan qmap netdevice $name"
|
|
;;
|
|
"mbimmux"*)
|
|
mm_log "debug" "mbim vlan netdevice $name"
|
|
;;
|
|
*)
|
|
return
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Track/untrack events in cache
|
|
case "${action}" in
|
|
"add")
|
|
# On add events, store event details in cache (if not exists yet)
|
|
grep -qs "${name},${subsystem}" "${MODEMMANAGER_EVENTS_CACHE}" || \
|
|
echo "${action},${name},${subsystem},${sysfspath}" >> "${MODEMMANAGER_EVENTS_CACHE}"
|
|
;;
|
|
"remove")
|
|
# On remove events, remove old events from cache (match by subsystem+name)
|
|
sed -i "/${name},${subsystem}/d" "${MODEMMANAGER_EVENTS_CACHE}"
|
|
;;
|
|
esac
|
|
|
|
# Report the event
|
|
mm_log "debug" "Report event: action=${action}, name=${name}, subsystem=${subsystem}"
|
|
result=$(mmcli --report-kernel-event="action=${action},name=${name},subsystem=${subsystem}" 2>&1)
|
|
if [ "$?" -ne "0" ]; then
|
|
mm_log "error" "Couldn't report kernel event: ${result}"
|
|
fi
|
|
}
|
|
|
|
mm_report_event_from_cache_line() {
|
|
local event_line="$1"
|
|
|
|
local action name subsystem sysfspath
|
|
action=$(echo "${event_line}" | awk -F ',' '{ print $1 }')
|
|
name=$(echo "${event_line}" | awk -F ',' '{ print $2 }')
|
|
subsystem=$(echo "${event_line}" | awk -F ',' '{ print $3 }')
|
|
sysfspath=$(echo "${event_line}" | awk -F ',' '{ print $4 }')
|
|
|
|
mm_log "debug" "cached event found: action=${action}, name=${name}, subsystem=${subsystem}, sysfspath=${sysfspath}"
|
|
mm_report_event "${action}" "${name}" "${subsystem}" "${sysfspath}"
|
|
}
|
|
|
|
mm_report_events_from_cache() {
|
|
local n=60
|
|
local step=1
|
|
local mmrunning=0
|
|
|
|
# Wait for ModemManager to be available in the bus
|
|
while [ $n -ge 0 ]; do
|
|
sleep $step
|
|
mm_log "info" "checking if ModemManager is available..."
|
|
|
|
if ! mmcli -L >/dev/null 2>&1
|
|
then
|
|
mm_log "info" "ModemManager not yet available"
|
|
else
|
|
mmrunning=1
|
|
break
|
|
fi
|
|
n=$((n-step))
|
|
done
|
|
|
|
[ ${mmrunning} -eq 1 ] || {
|
|
mm_log "error" "couldn't report initial kernel events: ModemManager not running"
|
|
return
|
|
}
|
|
|
|
# Remove the sysfs cache
|
|
rm -f "${MODEMMANAGER_SYSFS_CACHE}"
|
|
|
|
# Report cached kernel events
|
|
while IFS= read -r event_line; do
|
|
mm_report_event_from_cache_line "${event_line}"
|
|
done < ${MODEMMANAGER_EVENTS_CACHE}
|
|
}
|
|
|
|
# This method expects as first argument a list of key-value pairs, as returned by mmcli --output-keyvalue
|
|
# The second argument must be exactly the name of the field to read
|
|
#
|
|
# Sample output:
|
|
# $ mmcli -m 0 -K
|
|
# modem.dbus-path : /org/freedesktop/ModemManager1/Modem/0
|
|
# modem.generic.device-identifier : ed6eff2e3e0f90463da1c2a755b2acacd1335752
|
|
# modem.generic.manufacturer : Dell Inc.
|
|
# modem.generic.model : DW5821e Snapdragon X20 LTE
|
|
# modem.generic.revision : T77W968.F1.0.0.4.0.GC.009\n026
|
|
# modem.generic.carrier-configuration : GCF
|
|
# modem.generic.carrier-configuration-revision : 08E00009
|
|
# modem.generic.hardware-revision : DW5821e Snapdragon X20 LTE
|
|
# ....
|
|
modemmanager_get_field() {
|
|
local list=$1
|
|
local field=$2
|
|
local value=""
|
|
|
|
[ -z "${list}" ] || [ -z "${field}" ] && return
|
|
|
|
# there is always at least a whitespace after each key, and we use that as part of the
|
|
# key matching we do (e.g. to avoid getting 'modem.generic.state-failed-reason' as a result
|
|
# when grepping for 'modem.generic.state'.
|
|
line=$(echo "${list}" | grep "${field} ")
|
|
value=$(echo ${line#*:})
|
|
|
|
# not found?
|
|
[ -n "${value}" ] || return 2
|
|
|
|
# only print value if set
|
|
[ "${value}" != "--" ] && echo "${value}"
|
|
return 0
|
|
}
|
|
|
|
# build a comma-separated list of values from the list
|
|
modemmanager_get_multivalue_field() {
|
|
local list=$1
|
|
local field=$2
|
|
local value=""
|
|
local length idx item
|
|
|
|
[ -z "${list}" ] || [ -z "${field}" ] && return
|
|
|
|
length=$(modemmanager_get_field "${list}" "${field}.length")
|
|
[ -n "${length}" ] || return 0
|
|
[ "$length" -ge 1 ] || return 0
|
|
|
|
idx=1
|
|
while [ $idx -le "$length" ]; do
|
|
item=$(modemmanager_get_field "${list}" "${field}.value\[$idx\]")
|
|
[ -n "${item}" ] && [ "${item}" != "--" ] && {
|
|
[ -n "${value}" ] && value="${value}, "
|
|
value="${value}${item}"
|
|
}
|
|
idx=$((idx + 1))
|
|
done
|
|
|
|
# nothing built?
|
|
[ -n "${value}" ] || return 2
|
|
|
|
# only print value if set
|
|
echo "${value}"
|
|
return 0
|
|
}
|