2 # Copyright (C) 2016 Velocloud Inc
3 # Copyright (C) 2016 Aleksander Morgado <aleksander@aleksander.es>
5 ################################################################################
8 .
/lib
/netifd
/netifd-proto.sh
10 ################################################################################
13 MODEMMANAGER_RUNDIR
="/var/run/modemmanager"
14 MODEMMANAGER_PID_FILE
="${MODEMMANAGER_RUNDIR}/modemmanager.pid"
15 MODEMMANAGER_CDCWDM_CACHE
="${MODEMMANAGER_RUNDIR}/cdcwdm.cache"
16 MODEMMANAGER_MONITOR_CACHE
="${MODEMMANAGER_RUNDIR}/monitor.cache"
17 MODEMMANAGER_EVENTS_CACHE
="${MODEMMANAGER_RUNDIR}/events.cache"
19 ################################################################################
23 local level
="$1"; shift
25 [ "${level}" = "debug" ] && return
26 logger
-p "daemon.${level}" -t "ModemManager[$$]" "hotplug: $*"
29 ################################################################################
30 # Receives as input argument the full sysfs path of the device
31 # Returns the physical device sysfs path
33 # NOTE: this method only works when the device exists, i.e. it cannot be used
34 # on removal hotplug events
36 mm_find_physdev_sysfs_path
() {
40 tmp_path
=$
(dirname "${tmp_path}")
42 # avoid infinite loops iterating
43 [ -z "${tmp_path}" ] ||
[ "${tmp_path}" = "/" ] && return
45 # For USB devices, the physical device will be that with a idVendor
46 # and idProduct pair of files
47 [ -f "${tmp_path}"/idVendor
] && [ -f "${tmp_path}"/idProduct
] && {
48 tmp_path
=$
(readlink
-f "$tmp_path")
53 # For PCI devices, the physical device will be that with a vendor
54 # and device pair of files
55 [ -f "${tmp_path}"/vendor
] && [ -f "${tmp_path}"/device
] && {
56 tmp_path
=$
(readlink
-f "$tmp_path")
63 ################################################################################
65 # Returns the cdc-wdm name retrieved from sysfs
70 cdcwdm
=$
(ls "/sys/class/net/${wwan}/device/usbmisc/")
71 [ -n "${cdcwdm}" ] ||
return
73 # We have to cache it for later, as we won't be able to get the
74 # associated cdc-wdm device on a remove event
75 echo "${wwan} ${cdcwdm}" >> "${MODEMMANAGER_CDCWDM_CACHE}"
80 # Returns the cdc-wdm name retrieved from the cache
85 # Look for the cached associated cdc-wdm device
86 [ -f "${MODEMMANAGER_CDCWDM_CACHE}" ] ||
return
88 cdcwdm
=$
(awk -v wwan
="${wwan}" '!/^#/ && $0 ~ wwan { print $2 }' "${MODEMMANAGER_CDCWDM_CACHE}")
89 [ -n "${cdcwdm}" ] ||
return
92 sed -i "/${wwan} ${cdcwdm}/d" "${MODEMMANAGER_CDCWDM_CACHE}"
97 # Callback for config_foreach()
98 mm_get_modem_config_foreach_cb
() {
103 dev
=$
(uci_get network
"${cfg}" device
)
104 [ "${dev}" = "${sysfspath}" ] ||
return 0
109 # Returns the name of the interface configured for this device
110 mm_get_modem_config
() {
113 # Look for configuration for the given sysfs path
115 config_foreach mm_get_modem_config_foreach_cb interface
"${sysfspath}"
118 ################################################################################
121 # Receives as input the action, the device name and the subsystem
128 # Do not save virtual devices
130 virtual
="$(echo "$sysfspath" | cut -d'/' -f4)"
131 [ "$virtual" = "virtual" ] && {
132 mm_log
"debug" "sysfspath is a virtual device ($sysfspath)"
136 # Track/untrack events in cache
139 # On add events, store event details in cache (if not exists yet)
140 grep -qs "${name},${subsystem}" "${MODEMMANAGER_EVENTS_CACHE}" || \
141 echo "${action},${name},${subsystem},${sysfspath}" >> "${MODEMMANAGER_EVENTS_CACHE}"
144 # On remove events, remove old events from cache (match by subsystem+name)
145 sed -i "/${name},${subsystem}/d" "${MODEMMANAGER_EVENTS_CACHE}"
150 mm_log
"debug" "Report event: action=${action}, name=${name}, subsystem=${subsystem}"
151 result
=$
(mmcli
--report-kernel-event="action=${action},name=${name},subsystem=${subsystem}" 2>&1)
152 if [ "$?" -ne "0" ]; then
153 mm_log
"error" "Couldn't report kernel event: ${result}"
157 mm_report_event_from_cache_line
() {
158 local event_line
="$1"
160 local action name subsystem sysfspath
161 action
=$
(echo "${event_line}" |
awk -F ',' '{ print $1 }')
162 name
=$
(echo "${event_line}" |
awk -F ',' '{ print $2 }')
163 subsystem
=$
(echo "${event_line}" |
awk -F ',' '{ print $3 }')
164 sysfspath
=$
(echo "${event_line}" |
awk -F ',' '{ print $4 }')
166 mm_log
"debug" "cached event found: action=${action}, name=${name}, subsystem=${subsystem}, sysfspath=${sysfspath}"
167 mm_report_event
"${action}" "${name}" "${subsystem}" "${sysfspath}"
170 mm_report_events_from_cache
() {
175 # Wait for ModemManager to be available in the bus
176 while [ $n -ge 0 ]; do
178 mm_log
"info" "checking if ModemManager is available..."
180 if ! mmcli
-L >/dev
/null
2>&1
182 mm_log
"info" "ModemManager not yet available"
190 [ ${mmrunning} -eq 1 ] ||
{
191 mm_log
"error" "couldn't report initial kernel events: ModemManager not running"
195 # Remove the sysfs cache
196 rm -f "${MODEMMANAGER_SYSFS_CACHE}"
198 # Report cached kernel events
199 while IFS
= read -r event_line
; do
200 mm_report_event_from_cache_line
"${event_line}"
201 done < ${MODEMMANAGER_EVENTS_CACHE}
204 # This method expects as first argument a list of key-value pairs, as returned by mmcli --output-keyvalue
205 # The second argument must be exactly the name of the field to read
209 # modem.dbus-path : /org/freedesktop/ModemManager1/Modem/0
210 # modem.generic.device-identifier : ed6eff2e3e0f90463da1c2a755b2acacd1335752
211 # modem.generic.manufacturer : Dell Inc.
212 # modem.generic.model : DW5821e Snapdragon X20 LTE
213 # modem.generic.revision : T77W968.F1.0.0.4.0.GC.009\n026
214 # modem.generic.carrier-configuration : GCF
215 # modem.generic.carrier-configuration-revision : 08E00009
216 # modem.generic.hardware-revision : DW5821e Snapdragon X20 LTE
218 modemmanager_get_field
() {
223 [ -z "${list}" ] ||
[ -z "${field}" ] && return
225 # there is always at least a whitespace after each key, and we use that as part of the
226 # key matching we do (e.g. to avoid getting 'modem.generic.state-failed-reason' as a result
227 # when grepping for 'modem.generic.state'.
228 line
=$
(echo "${list}" |
grep "${field} ")
229 value
=$
(echo ${line#*:})
232 [ -n "${value}" ] ||
return 2
234 # only print value if set
235 [ "${value}" != "--" ] && echo "${value}"
239 # build a comma-separated list of values from the list
240 modemmanager_get_multivalue_field
() {
244 local length idx item
246 [ -z "${list}" ] ||
[ -z "${field}" ] && return
248 length
=$
(modemmanager_get_field
"${list}" "${field}.length")
249 [ -n "${length}" ] ||
return 0
250 [ "$length" -ge 1 ] ||
return 0
253 while [ $idx -le "$length" ]; do
254 item
=$
(modemmanager_get_field
"${list}" "${field}.value\[$idx\]")
255 [ -n "${item}" ] && [ "${item}" != "--" ] && {
256 [ -n "${value}" ] && value
="${value}, "
257 value
="${value}${item}"
263 [ -n "${value}" ] ||
return 2
265 # only print value if set