MODEMMANAGER_RUNDIR="/var/run/modemmanager"
MODEMMANAGER_PID_FILE="${MODEMMANAGER_RUNDIR}/modemmanager.pid"
MODEMMANAGER_CDCWDM_CACHE="${MODEMMANAGER_RUNDIR}/cdcwdm.cache"
-MODEMMANAGER_SYSFS_CACHE="${MODEMMANAGER_RUNDIR}/sysfs.cache"
+MODEMMANAGER_MONITOR_CACHE="${MODEMMANAGER_RUNDIR}/monitor.cache"
MODEMMANAGER_EVENTS_CACHE="${MODEMMANAGER_RUNDIR}/events.cache"
################################################################################
echo "${cdcwdm}"
}
-################################################################################
-# ModemManager needs some time from the ports being added until a modem object
-# is exposed in DBus. With the logic here we do an explicit wait of N seconds
-# for ModemManager to expose the new modem object, making sure that the wait is
-# unique per device (i.e. per physical device sysfs path).
-
-# Gets the modem wait status as retrieved from the cache
-mm_get_modem_wait_status() {
- local sysfspath="$1"
-
- # If no sysfs cache file, we're done
- [ -f "${MODEMMANAGER_SYSFS_CACHE}" ] || return
-
- # Get status of the sysfs path
- awk -v sysfspath="${sysfspath}" '!/^#/ && $0 ~ sysfspath { print $2 }' "${MODEMMANAGER_SYSFS_CACHE}"
-}
-
-# Clear the modem wait status from the cache, if any
-mm_clear_modem_wait_status() {
- local sysfspath="$1"
-
- local escaped_sysfspath
-
- [ -f "${MODEMMANAGER_SYSFS_CACHE}" ] && {
- # escape '/', '\' and '&' for sed...
- escaped_sysfspath=$(echo "$sysfspath" | sed -e 's/[\/&]/\\&/g')
- sed -i "/${escaped_sysfspath}/d" "${MODEMMANAGER_SYSFS_CACHE}"
- }
-}
-
-# Sets the modem wait status in the cache
-mm_set_modem_wait_status() {
- local sysfspath="$1"
- local status="$2"
-
- # Remove sysfs line before adding the new one with the new state
- mm_clear_modem_wait_status "${sysfspath}"
-
- # Add the new status
- echo "${sysfspath} ${status}" >> "${MODEMMANAGER_SYSFS_CACHE}"
-}
-
# Callback for config_foreach()
mm_get_modem_config_foreach_cb() {
local cfg="$1"
config_foreach mm_get_modem_config_foreach_cb interface "${sysfspath}"
}
-# Wait for a modem in the specified sysfspath
-mm_wait_for_modem() {
- local cfg="$1"
- local sysfspath="$2"
-
- # TODO: config max wait
- local n=45
- local step=5
-
- while [ $n -ge 0 ]; do
- [ -d "${sysfspath}" ] || {
- mm_log "error" "ignoring modem detection request: no device at ${sysfspath}"
- proto_set_available "${cfg}" 0
- return 1
- }
-
- # Check if the modem exists at the given sysfs path
- if ! mmcli -m "${sysfspath}" > /dev/null 2>&1
- then
- mm_log "error" "modem not detected at sysfs path"
- else
- mm_log "info" "modem exported successfully at ${sysfspath}"
- mm_log "info" "setting interface '${cfg}' as available"
- proto_set_available "${cfg}" 1
- return 0
- fi
-
- sleep $step
- n=$((n-step))
- done
-
- mm_log "error" "timed out waiting for the modem to get exported at ${sysfspath}"
- proto_set_available "${cfg}" 0
- return 2
-}
-
-mm_report_modem_wait() {
- local sysfspath=$1
-
- local parent_sysfspath status
-
- parent_sysfspath=$(mm_find_physdev_sysfs_path "$sysfspath")
- [ -n "${parent_sysfspath}" ] || {
- mm_log "error" "parent device sysfspath not found"
- return
- }
-
- status=$(mm_get_modem_wait_status "${parent_sysfspath}")
- case "${status}" in
- "")
- local cfg
-
- cfg=$(mm_get_modem_config "${parent_sysfspath}")
- if [ -n "${cfg}" ]; then
- mm_log "info" "interface '${cfg}' is set to configure device '${parent_sysfspath}'"
- mm_log "info" "now waiting for modem at sysfs path ${parent_sysfspath}"
- mm_set_modem_wait_status "${parent_sysfspath}" "processed"
- # Launch subshell for the explicit wait
- ( mm_wait_for_modem "${cfg}" "${parent_sysfspath}" ) > /dev/null 2>&1 &
- else
- mm_log "info" "no need to wait for modem at sysfs path ${parent_sysfspath}"
- mm_set_modem_wait_status "${parent_sysfspath}" "ignored"
- fi
- ;;
- "processed")
- mm_log "info" "already waiting for modem at sysfs path ${parent_sysfspath}"
- ;;
- "ignored")
- ;;
- *)
- mm_log "error" "unknown status read for device at sysfs path ${parent_sysfspath}"
- ;;
- esac
-}
-
-################################################################################
-# Cleanup interfaces
-
-mm_cleanup_interfaces() {
- local sysfs_path status
-
- # Do nothing if there is no sysfs cache
- [ -f "${MODEMMANAGER_SYSFS_CACHE}" ] || return
-
- while IFS= read -r sysfs_cache_line; do
- sysfs_path=$(echo "${sysfs_cache_line}" | awk '{print $1}')
- status=$(echo "${sysfs_cache_line}" | awk '{print $2}')
-
- if [ "${status}" = "processed" ]; then
- mm_log "debug" "call cleanup for: ${sysfs_path}"
- mm_cleanup_interface_by_sysfspath "${sysfs_path}"
- fi
- done < ${MODEMMANAGER_SYSFS_CACHE}
-}
-
-mm_cleanup_interface_by_sysfspath() {
- local dev="$1"
-
- local cfg
- cfg=$(mm_get_modem_config "$dev")
- [ -n "${cfg}" ] || return
-
- mm_log "info" "setting interface '$cfg' as unavailable"
- proto_set_available "${cfg}" 0
-}
-
################################################################################
# Event reporting
# 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 [ "$?" -eq "0" ]; then
- # Wait for added modem if a sysfspath is given
- [ -n "${sysfspath}" ] && [ "$action" = "add" ] && mm_report_modem_wait "${sysfspath}"
- else
+ if [ "$?" -ne "0" ]; then
mm_log "error" "Couldn't report kernel event: ${result}"
fi
-
}
mm_report_event_from_cache_line() {
--- /dev/null
+#!/bin/sh
+
+. /lib/functions.sh
+. /lib/netifd/netifd-proto.sh
+. /usr/share/ModemManager/modemmanager.common
+
+trap_with_arg() {
+ func="$1" ; shift
+ for sig ; do
+ # shellcheck disable=SC2064
+ trap "$func $sig" "$sig"
+ done
+}
+
+func_trap() {
+ local monitor_cache_line object
+
+ logger "ModemManager-monitor[$$]" "Sending signal ${1} ..."
+
+ # Set all configured logical interfaces to unavailable
+ while IFS= read -r monitor_cache_line; do
+ object=$(echo "${monitor_cache_line}" | awk '{print $1}')
+ mm_monitor_cache_remove "$object"
+ done < ${MODEMMANAGER_MONITOR_CACHE}
+
+ kill "-${1}" "$CHILD" 2>/dev/null
+}
+
+mm_monitor_get_sysfspath() {
+ local object="$1"
+
+ # If no monitor cache file, we're done
+ [ -f "${MODEMMANAGER_MONITOR_CACHE}" ] || return
+
+ awk -v object="${object}" '!/^#/ && $0 ~ object { print $2 }' "${MODEMMANAGER_MONITOR_CACHE}"
+}
+
+mm_monitor_cache_remove() {
+ local object="$1"
+
+ local device cfg
+
+ device=$(mm_monitor_get_sysfspath "${object}")
+
+ cfg=$(mm_get_modem_config "${device}")
+ if [ -n "${cfg}" ]; then
+ mm_log "debug" "interface '${cfg}' set '${device}' state unavailable"
+ proto_set_available "${cfg}" 0
+ fi
+
+ mm_log "debug" "delete object '$object' from monitore cache"
+
+ # On monitor remove event, remove old events from cache
+ # Also substitute object path '/org/freedesktop/ModemManager1/Modem/<number>'
+ # all '/' with '\/' to make sed happy with shell expansion
+ sed -i "/${object//\//\\/}/d" "${MODEMMANAGER_MONITOR_CACHE}"
+}
+
+mm_monitor_cache_add() {
+ local object="$1"
+ local modemstatus device sysfspath cfg
+
+ modemstatus="$(mmcli --modem="${object}" --output-keyvalue)"
+
+ device=$(modemmanager_get_field "${modemstatus}" "modem.generic.device")
+ [ -n "${device}" ] || {
+ mm_log "err" "No 'device' for object '$object' not found..."
+ return 1
+ }
+
+ sysfspath=$(modemmanager_get_field "${modemstatus}" "modem.generic.physdev")
+ [ -n "${sysfspath}" ] || {
+ mm_log "err" "No 'sysfspath' for object '$object' not found..."
+ return 2
+ }
+
+ mm_log "debug" "add object '$object' to monitore cache (device=${device},sysfspath=${sysfspath})"
+
+ # On monitor add event, store event details in cache (if not exists yet)
+ grep -qs "${sysfspath}" "${MODEMMANAGER_MONITOR_CACHE}" || \
+ echo "${object} ${device} ${sysfspath}" >> "${MODEMMANAGER_MONITOR_CACHE}"
+
+ cfg=$(mm_get_modem_config "${device}")
+ if [ -n "${cfg}" ]; then
+ mm_log "info" "interface '${cfg}' set '${device}' state available"
+ proto_set_available "${cfg}" 1
+ fi
+}
+
+mm_monitor_cache_del() {
+ local object="$1"
+
+ mm_monitor_cache_remove "$object"
+}
+
+mm_monitor_cache() {
+ local line="$1"
+ local event object modemstatus device pyhsdev
+
+ event="$(echo "$line" | cut -d " " -f 1)"
+ object="$(echo "$line" | cut -d " " -f 2)"
+
+ case "$event" in
+ "(+)")
+ mm_monitor_cache_add "$object"
+ ;;
+ "(-)")
+ mm_monitor_cache_del "$object"
+ ;;
+ esac
+}
+
+main() {
+
+ local n=60
+ local step=1
+ local mmrunning=0
+
+ trap_with_arg func_trap INT TERM KILL
+
+ mkdir -p "${MODEMMANAGER_RUNDIR}"
+ chmod 0755 "${MODEMMANAGER_RUNDIR}"
+
+ # 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 ! /usr/bin/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
+ }
+
+ /usr/bin/mmcli -M | {
+ local line
+ while read -r line; do
+ mm_log "debug" "Monitor cache line: ${line}"
+ mm_monitor_cache "$line"
+ done
+ } &
+ CHILD="$!"
+
+ wait $CHILD
+}
+
+main "$@"