alist: Update to 3.32.0
[feed/packages.git] / net / modemmanager / files / modemmanager.common
1 #!/bin/sh
2 # Copyright (C) 2016 Velocloud Inc
3 # Copyright (C) 2016 Aleksander Morgado <aleksander@aleksander.es>
4
5 ################################################################################
6
7 . /lib/functions.sh
8 . /lib/netifd/netifd-proto.sh
9
10 ################################################################################
11 # Runtime state
12
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"
18
19 ################################################################################
20 # Common logging
21
22 mm_log() {
23 local level="$1"; shift
24
25 [ "${level}" = "debug" ] && return
26 logger -p "daemon.${level}" -t "ModemManager[$$]" "hotplug: $*"
27 }
28
29 ################################################################################
30 # Receives as input argument the full sysfs path of the device
31 # Returns the physical device sysfs path
32 #
33 # NOTE: this method only works when the device exists, i.e. it cannot be used
34 # on removal hotplug events
35
36 mm_find_physdev_sysfs_path() {
37 local tmp_path="$1"
38
39 while true; do
40 tmp_path=$(dirname "${tmp_path}")
41
42 # avoid infinite loops iterating
43 [ -z "${tmp_path}" ] || [ "${tmp_path}" = "/" ] && return
44
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")
49 echo "${tmp_path}"
50 return
51 }
52
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")
57 echo "${tmp_path}"
58 return
59 }
60 done
61 }
62
63 ################################################################################
64
65 # Returns the cdc-wdm name retrieved from sysfs
66 mm_track_cdcwdm() {
67 local wwan="$1"
68 local cdcwdm
69
70 cdcwdm=$(ls "/sys/class/net/${wwan}/device/usbmisc/")
71 [ -n "${cdcwdm}" ] || return
72
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}"
76
77 echo "${cdcwdm}"
78 }
79
80 # Returns the cdc-wdm name retrieved from the cache
81 mm_untrack_cdcwdm() {
82 local wwan="$1"
83 local cdcwdm
84
85 # Look for the cached associated cdc-wdm device
86 [ -f "${MODEMMANAGER_CDCWDM_CACHE}" ] || return
87
88 cdcwdm=$(awk -v wwan="${wwan}" '!/^#/ && $0 ~ wwan { print $2 }' "${MODEMMANAGER_CDCWDM_CACHE}")
89 [ -n "${cdcwdm}" ] || return
90
91 # Remove from cache
92 sed -i "/${wwan} ${cdcwdm}/d" "${MODEMMANAGER_CDCWDM_CACHE}"
93
94 echo "${cdcwdm}"
95 }
96
97 # Callback for config_foreach()
98 mm_get_modem_config_foreach_cb() {
99 local cfg="$1"
100 local sysfspath="$2"
101
102 local dev
103 dev=$(uci_get network "${cfg}" device)
104 [ "${dev}" = "${sysfspath}" ] || return 0
105
106 echo "${cfg}"
107 }
108
109 # Returns the name of the interface configured for this device
110 mm_get_modem_config() {
111 local sysfspath="$1"
112
113 # Look for configuration for the given sysfs path
114 config_load network
115 config_foreach mm_get_modem_config_foreach_cb interface "${sysfspath}"
116 }
117
118 ################################################################################
119 # Event reporting
120
121 # Receives as input the action, the device name and the subsystem
122 mm_report_event() {
123 local action="$1"
124 local name="$2"
125 local subsystem="$3"
126 local sysfspath="$4"
127
128 # Do not save virtual devices
129 local virtual result
130 virtual="$(echo "$sysfspath" | cut -d'/' -f4)"
131 [ "$virtual" = "virtual" ] && {
132 mm_log "debug" "sysfspath is a virtual device ($sysfspath)"
133 return
134 }
135
136 # Track/untrack events in cache
137 case "${action}" in
138 "add")
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}"
142 ;;
143 "remove")
144 # On remove events, remove old events from cache (match by subsystem+name)
145 sed -i "/${name},${subsystem}/d" "${MODEMMANAGER_EVENTS_CACHE}"
146 ;;
147 esac
148
149 # Report the event
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}"
154 fi
155 }
156
157 mm_report_event_from_cache_line() {
158 local event_line="$1"
159
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 }')
165
166 mm_log "debug" "cached event found: action=${action}, name=${name}, subsystem=${subsystem}, sysfspath=${sysfspath}"
167 mm_report_event "${action}" "${name}" "${subsystem}" "${sysfspath}"
168 }
169
170 mm_report_events_from_cache() {
171 local n=60
172 local step=1
173 local mmrunning=0
174
175 # Wait for ModemManager to be available in the bus
176 while [ $n -ge 0 ]; do
177 sleep $step
178 mm_log "info" "checking if ModemManager is available..."
179
180 if ! mmcli -L >/dev/null 2>&1
181 then
182 mm_log "info" "ModemManager not yet available"
183 else
184 mmrunning=1
185 break
186 fi
187 n=$((n-step))
188 done
189
190 [ ${mmrunning} -eq 1 ] || {
191 mm_log "error" "couldn't report initial kernel events: ModemManager not running"
192 return
193 }
194
195 # Remove the sysfs cache
196 rm -f "${MODEMMANAGER_SYSFS_CACHE}"
197
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}
202 }
203
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
206 #
207 # Sample output:
208 # $ mmcli -m 0 -K
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
217 # ....
218 modemmanager_get_field() {
219 local list=$1
220 local field=$2
221 local value=""
222
223 [ -z "${list}" ] || [ -z "${field}" ] && return
224
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#*:})
230
231 # not found?
232 [ -n "${value}" ] || return 2
233
234 # only print value if set
235 [ "${value}" != "--" ] && echo "${value}"
236 return 0
237 }
238
239 # build a comma-separated list of values from the list
240 modemmanager_get_multivalue_field() {
241 local list=$1
242 local field=$2
243 local value=""
244 local length idx item
245
246 [ -z "${list}" ] || [ -z "${field}" ] && return
247
248 length=$(modemmanager_get_field "${list}" "${field}.length")
249 [ -n "${length}" ] || return 0
250 [ "$length" -ge 1 ] || return 0
251
252 idx=1
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}"
258 }
259 idx=$((idx + 1))
260 done
261
262 # nothing built?
263 [ -n "${value}" ] || return 2
264
265 # only print value if set
266 echo "${value}"
267 return 0
268 }