modemmanager: moving the openwrt related files to subdirectories
authorFlorian Eckert <fe@dev.tdt.de>
Tue, 5 Mar 2024 11:59:23 +0000 (12:59 +0100)
committerFlorian Eckert <fe@dev.tdt.de>
Tue, 5 Mar 2024 12:04:59 +0000 (13:04 +0100)
Moving the openwrt related files to subdirectories as they are installed
on the system. This change makes it immediately apparent during development
where the file is to be installed in the running system.

Signed-off-by: Florian Eckert <fe@dev.tdt.de>
15 files changed:
net/modemmanager/Makefile
net/modemmanager/files/10-report-down [deleted file]
net/modemmanager/files/25-modemmanager-net [deleted file]
net/modemmanager/files/25-modemmanager-tty [deleted file]
net/modemmanager/files/25-modemmanager-wwan [deleted file]
net/modemmanager/files/etc/hotplug.d/net/25-modemmanager-net [new file with mode: 0644]
net/modemmanager/files/etc/hotplug.d/tty/25-modemmanager-tty [new file with mode: 0644]
net/modemmanager/files/etc/hotplug.d/wwan/25-modemmanager-wwan [new file with mode: 0644]
net/modemmanager/files/etc/init.d/modemmanager [new file with mode: 0644]
net/modemmanager/files/lib/netifd/proto/modemmanager.sh [new file with mode: 0644]
net/modemmanager/files/modemmanager.common [deleted file]
net/modemmanager/files/modemmanager.init [deleted file]
net/modemmanager/files/modemmanager.proto [deleted file]
net/modemmanager/files/usr/lib/ModemManager/connection.d/10-report-down [new file with mode: 0644]
net/modemmanager/files/usr/share/ModemManager/modemmanager.common [new file with mode: 0644]

index c4c9e8af40f8e98dd1be16ec7df7e2299ab8db73..bdd55817af7e7fcde17b8256198049476e688c1c 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=modemmanager
 PKG_SOURCE_VERSION:=1.22.0
-PKG_RELEASE:=9
+PKG_RELEASE:=10
 
 PKG_SOURCE_PROTO:=git
 PKG_SOURCE_URL:=https://gitlab.freedesktop.org/mobile-broadband/ModemManager.git
@@ -101,7 +101,8 @@ define Package/modemmanager/install
        $(CP) $(PKG_INSTALL_DIR)/usr/lib/libmm-glib.so.* $(1)/usr/lib
 
        $(INSTALL_DIR) $(1)/usr/lib/ModemManager/connection.d
-       $(INSTALL_BIN) ./files/10-report-down $(1)/usr/lib/ModemManager/connection.d
+       $(INSTALL_BIN) ./files/usr/lib/ModemManager/connection.d/10-report-down \
+               $(1)/usr/lib/ModemManager/connection.d
 
        $(INSTALL_DIR) $(1)/etc/dbus-1/system.d
        $(INSTALL_CONF) $(PKG_INSTALL_DIR)/etc/dbus-1/system.d/org.freedesktop.ModemManager1.conf $(1)/etc/dbus-1/system.d
@@ -111,25 +112,31 @@ define Package/modemmanager/install
 
        $(INSTALL_DIR) $(1)/usr/share/ModemManager
        $$(if $$(wildcard $(PKG_INSTALL_DIR)/usr/share/ModemManager/*.conf),$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/ModemManager/*.conf $(1)/usr/share/ModemManager,)
-       $(INSTALL_DATA) ./files/modemmanager.common $(1)/usr/share/ModemManager
+       $(INSTALL_DATA) ./files/usr/share/ModemManager/modemmanager.common \
+               $(1)/usr/share/ModemManager
 
        $(INSTALL_DIR) $(1)/usr/share/ModemManager/fcc-unlock.available.d
        $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/ModemManager/fcc-unlock.available.d/* $(1)/usr/share/ModemManager/fcc-unlock.available.d
 
        $(INSTALL_DIR) $(1)/etc/init.d
-       $(INSTALL_BIN) ./files/modemmanager.init $(1)/etc/init.d/modemmanager
+       $(INSTALL_BIN) ./files/etc/init.d/modemmanager \
+               $(1)/etc/init.d/modemmanager
 
        $(INSTALL_DIR) $(1)/etc/hotplug.d/net
-       $(INSTALL_DATA) ./files/25-modemmanager-net $(1)/etc/hotplug.d/net
+       $(INSTALL_DATA) ./files/etc/hotplug.d/net/25-modemmanager-net \
+               $(1)/etc/hotplug.d/net
 
        $(INSTALL_DIR) $(1)/etc/hotplug.d/tty
-       $(INSTALL_DATA) ./files/25-modemmanager-tty $(1)/etc/hotplug.d/tty
+       $(INSTALL_DATA) ./files/etc/hotplug.d/tty/25-modemmanager-tty \
+               $(1)/etc/hotplug.d/tty
 
        $(INSTALL_DIR) $(1)/etc/hotplug.d/wwan
-       $(INSTALL_DATA) ./files/25-modemmanager-wwan $(1)/etc/hotplug.d/wwan
+       $(INSTALL_DATA) ./files/etc/hotplug.d/wwan/25-modemmanager-wwan \
+               $(1)/etc/hotplug.d/wwan
 
        $(INSTALL_DIR) $(1)/lib/netifd/proto
-       $(INSTALL_BIN) ./files/modemmanager.proto $(1)/lib/netifd/proto/modemmanager.sh
+       $(INSTALL_BIN) ./files/lib/netifd/proto/modemmanager.sh \
+               $(1)/lib/netifd/proto
 endef
 
 $(eval $(call BuildPackage,modemmanager))
diff --git a/net/modemmanager/files/10-report-down b/net/modemmanager/files/10-report-down
deleted file mode 100755 (executable)
index 0ebe87d..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/sh
-
-# SPDX-License-Identifier: CC0-1.0
-# 2022 Aleksander Morgado <aleksander@aleksander.es>
-#
-# Automatically report to netifd that the underlying modem
-# is really disconnected
-#
-# require program name and at least 4 arguments
-[ $# -lt 4 ] && exit 1
-
-MODEM_PATH="$1"
-BEARER_PATH="$2"
-INTERFACE="$3"
-STATE="$4"
-
-[ "${STATE}" = "disconnected" ] || exit 0
-
-. /lib/netifd/netifd-proto.sh
-. /usr/share/ModemManager/modemmanager.common
-
-MODEM_STATUS=$(mmcli --modem="${MODEM_PATH}" --output-keyvalue)
-[ -n "${MODEM_STATUS}" ] || exit 1
-
-MODEM_DEVICE=$(modemmanager_get_field "${MODEM_STATUS}" "modem.generic.device")
-[ -n "${MODEM_DEVICE}" ] || exit 2
-
-CFG=$(mm_get_modem_config "${MODEM_DEVICE}")
-[ -n "${CFG}" ] || exit 3
-
-IFUP=$(ifstatus "${CFG}" | jsonfilter -e "@.up")
-
-[ "${IFUP}" = "true" ] && {
-       logger -t "modemmanager" "interface ${CFG} (network device ${INTERFACE}) ${STATE}"
-       proto_init_update $INTERFACE 0
-       proto_send_update $CFG
-}
-
-exit 0
diff --git a/net/modemmanager/files/25-modemmanager-net b/net/modemmanager/files/25-modemmanager-net
deleted file mode 100644 (file)
index ff46420..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2016 Velocloud Inc
-# Copyright (C) 2016 Aleksander Morgado <aleksander@aleksander.es>
-
-# Load common utilities
-. /usr/share/ModemManager/modemmanager.common
-
-# We require a interface name
-[ -n "${INTERFACE}" ] || exit
-
-# Always make sure the rundir exists
-mkdir -m 0755 -p "${MODEMMANAGER_RUNDIR}"
-
-# Report network interface
-mm_log "info" "${ACTION} network interface ${INTERFACE}: event processed"
-mm_report_event "${ACTION}" "${INTERFACE}" "net" "/sys${DEVPATH}"
-
-# Look for an associated cdc-wdm interface
-
-cdcwdm=""
-
-case "${ACTION}" in
-       "add")    cdcwdm=$(mm_track_cdcwdm "${INTERFACE}") ;;
-       "remove") cdcwdm=$(mm_untrack_cdcwdm "${INTERFACE}") ;;
-esac
-
-# Report cdc-wdm device, if any
-[ -n "${cdcwdm}" ] && {
-       mm_log "info" "${ACTION} cdc interface ${cdcwdm}: custom event processed"
-       mm_report_event "${ACTION}" "${cdcwdm}" "usbmisc" "/sys${DEVPATH}"
-}
diff --git a/net/modemmanager/files/25-modemmanager-tty b/net/modemmanager/files/25-modemmanager-tty
deleted file mode 100644 (file)
index 5d1042c..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2016 Velocloud Inc
-# Copyright (C) 2016 Aleksander Morgado <aleksander@aleksander.es>
-
-# Load hotplug common utilities
-. /usr/share/ModemManager/modemmanager.common
-
-# We require a device name
-[ -n "$DEVNAME" ] || exit
-
-# Always make sure the rundir exists
-mkdir -m 0755 -p "${MODEMMANAGER_RUNDIR}"
-
-# Report TTY
-mm_log "info" "${ACTION} serial interface ${DEVNAME}: event processed"
-mm_report_event "${ACTION}" "${DEVNAME}" "tty" "/sys${DEVPATH}"
diff --git a/net/modemmanager/files/25-modemmanager-wwan b/net/modemmanager/files/25-modemmanager-wwan
deleted file mode 100644 (file)
index b36ade4..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2021 Aleksander Morgado <aleksander@aleksander.es>
-
-# Load hotplug common utilities
-. /usr/share/ModemManager/modemmanager.common
-
-# We require a device name
-[ -n "$DEVNAME" ] || exit
-
-# Always make sure the rundir exists
-mkdir -m 0755 -p "${MODEMMANAGER_RUNDIR}"
-
-# Report wwan
-mm_log "info" "${ACTION} wwan control port ${DEVNAME}: event processed"
-mm_report_event "${ACTION}" "${DEVNAME}" "wwan" "/sys${DEVPATH}"
diff --git a/net/modemmanager/files/etc/hotplug.d/net/25-modemmanager-net b/net/modemmanager/files/etc/hotplug.d/net/25-modemmanager-net
new file mode 100644 (file)
index 0000000..ff46420
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Copyright (C) 2016 Velocloud Inc
+# Copyright (C) 2016 Aleksander Morgado <aleksander@aleksander.es>
+
+# Load common utilities
+. /usr/share/ModemManager/modemmanager.common
+
+# We require a interface name
+[ -n "${INTERFACE}" ] || exit
+
+# Always make sure the rundir exists
+mkdir -m 0755 -p "${MODEMMANAGER_RUNDIR}"
+
+# Report network interface
+mm_log "info" "${ACTION} network interface ${INTERFACE}: event processed"
+mm_report_event "${ACTION}" "${INTERFACE}" "net" "/sys${DEVPATH}"
+
+# Look for an associated cdc-wdm interface
+
+cdcwdm=""
+
+case "${ACTION}" in
+       "add")    cdcwdm=$(mm_track_cdcwdm "${INTERFACE}") ;;
+       "remove") cdcwdm=$(mm_untrack_cdcwdm "${INTERFACE}") ;;
+esac
+
+# Report cdc-wdm device, if any
+[ -n "${cdcwdm}" ] && {
+       mm_log "info" "${ACTION} cdc interface ${cdcwdm}: custom event processed"
+       mm_report_event "${ACTION}" "${cdcwdm}" "usbmisc" "/sys${DEVPATH}"
+}
diff --git a/net/modemmanager/files/etc/hotplug.d/tty/25-modemmanager-tty b/net/modemmanager/files/etc/hotplug.d/tty/25-modemmanager-tty
new file mode 100644 (file)
index 0000000..5d1042c
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+# Copyright (C) 2016 Velocloud Inc
+# Copyright (C) 2016 Aleksander Morgado <aleksander@aleksander.es>
+
+# Load hotplug common utilities
+. /usr/share/ModemManager/modemmanager.common
+
+# We require a device name
+[ -n "$DEVNAME" ] || exit
+
+# Always make sure the rundir exists
+mkdir -m 0755 -p "${MODEMMANAGER_RUNDIR}"
+
+# Report TTY
+mm_log "info" "${ACTION} serial interface ${DEVNAME}: event processed"
+mm_report_event "${ACTION}" "${DEVNAME}" "tty" "/sys${DEVPATH}"
diff --git a/net/modemmanager/files/etc/hotplug.d/wwan/25-modemmanager-wwan b/net/modemmanager/files/etc/hotplug.d/wwan/25-modemmanager-wwan
new file mode 100644 (file)
index 0000000..b36ade4
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+# Copyright (C) 2021 Aleksander Morgado <aleksander@aleksander.es>
+
+# Load hotplug common utilities
+. /usr/share/ModemManager/modemmanager.common
+
+# We require a device name
+[ -n "$DEVNAME" ] || exit
+
+# Always make sure the rundir exists
+mkdir -m 0755 -p "${MODEMMANAGER_RUNDIR}"
+
+# Report wwan
+mm_log "info" "${ACTION} wwan control port ${DEVNAME}: event processed"
+mm_report_event "${ACTION}" "${DEVNAME}" "wwan" "/sys${DEVPATH}"
diff --git a/net/modemmanager/files/etc/init.d/modemmanager b/net/modemmanager/files/etc/init.d/modemmanager
new file mode 100644 (file)
index 0000000..ccc1953
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2016 Aleksander Morgado <aleksander@aleksander.es>
+
+USE_PROCD=1
+START=70
+
+LOG_LEVEL="INFO"
+
+start_service() {
+       # Setup ModemManager service
+       #
+       # We will make sure that the rundir always exists, and we initially cleanup
+       # all interfaces flagging them as unavailable.
+       #
+       # The cached events processing will wait for MM to be available in DBus
+       # and will make sure all ports are re-notified to ModemManager every time
+       # it starts.
+       #
+       # All these commands need to be executed on every MM start, even after
+       # procd-triggered respawns, which is why this is wrapped in a startup
+       # wrapper script called '/usr/sbin/ModemManager-wrapper'.
+       #
+       . /usr/share/ModemManager/modemmanager.common
+       procd_open_instance "service"
+       procd_set_param command /usr/sbin/ModemManager-wrapper
+       procd_append_param command --log-level="$LOG_LEVEL"
+       [ "$LOG_LEVEL" = "DEBUG" ] && procd_append_param command --debug
+       procd_set_param respawn "${respawn_threshold:-3600}" "${respawn_timeout:-5}" "${respawn_retry:-5}"
+       procd_set_param pidfile "${MODEMMANAGER_PID_FILE}"
+       procd_close_instance
+       procd_open_instance "monitor"
+       procd_set_param command /usr/sbin/ModemManager-monitor
+       procd_set_param respawn "${respawn_threshold:-3600}" "${respawn_timeout:-5}" "${respawn_retry:-5}"
+       procd_close_instance
+}
diff --git a/net/modemmanager/files/lib/netifd/proto/modemmanager.sh b/net/modemmanager/files/lib/netifd/proto/modemmanager.sh
new file mode 100644 (file)
index 0000000..b059b4c
--- /dev/null
@@ -0,0 +1,712 @@
+#!/bin/sh
+# Copyright (C) 2016-2019 Aleksander Morgado <aleksander@aleksander.es>
+
+[ -x /usr/bin/mmcli ] || exit 0
+[ -x /usr/sbin/pppd ] || exit 0
+
+[ -n "$INCLUDE_ONLY" ] || {
+       . /lib/functions.sh
+       . ../netifd-proto.sh
+       . ./ppp.sh
+       . /usr/share/ModemManager/modemmanager.common
+       init_proto "$@"
+}
+
+cdr2mask ()
+{
+       # Number of args to shift, 255..255, first non-255 byte, zeroes
+       set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0
+       if [ "$1" -gt 1 ]
+       then
+               shift "$1"
+       else
+               shift
+       fi
+       echo "${1-0}"."${2-0}"."${3-0}"."${4-0}"
+}
+
+modemmanager_cleanup_connection() {
+       local modemstatus="$1"
+
+       local bearercount idx bearerpath
+
+       bearercount=$(modemmanager_get_field "${modemstatus}" "modem.generic.bearers.length")
+
+       # do nothing if no bearers reported
+       [ -n "${bearercount}" ] && [ "$bearercount" -ge 1 ] && {
+               # explicitly disconnect just in case
+               mmcli --modem="${device}" --simple-disconnect >/dev/null 2>&1
+               # and remove all bearer objects, if any found
+               idx=1
+               while [ $idx -le "$bearercount" ]; do
+                       bearerpath=$(modemmanager_get_field "${modemstatus}" "modem.generic.bearers.value\[$idx\]")
+                       mmcli --modem "${device}" --delete-bearer="${bearerpath}" >/dev/null 2>&1
+                       idx=$((idx + 1))
+               done
+       }
+}
+
+modemmanager_connected_method_ppp_ipv4() {
+       local interface="$1"
+       local ttyname="$2"
+       local username="$3"
+       local password="$4"
+       local allowedauth="$5"
+
+       # all auth types are allowed unless a user given list is given
+       local authopts
+       local pap=1
+       local chap=1
+       local mschap=1
+       local mschapv2=1
+       local eap=1
+
+       [ -n "$allowedauth" ] && {
+               pap=0 chap=0 mschap=0 mschapv2=0 eap=0
+               for auth in $allowedauth; do
+                       case $auth in
+                               "pap") pap=1 ;;
+                               "chap") chap=1 ;;
+                               "mschap") mschap=1 ;;
+                               "mschapv2") mschapv2=1 ;;
+                               "eap") eap=1 ;;
+                               *) ;;
+                       esac
+               done
+       }
+
+       [ $pap -eq 1 ] || append authopts "refuse-pap"
+       [ $chap -eq 1 ] || append authopts "refuse-chap"
+       [ $mschap -eq 1 ] || append authopts "refuse-mschap"
+       [ $mschapv2 -eq 1 ] || append authopts "refuse-mschap-v2"
+       [ $eap -eq 1 ] || append authopts "refuse-eap"
+
+       proto_run_command "${interface}" /usr/sbin/pppd \
+               "${ttyname}" \
+               115200 \
+               nodetach \
+               noaccomp \
+               nobsdcomp \
+               nopcomp \
+               novj \
+               noauth \
+               $authopts \
+               ${username:+ user "$username"} \
+               ${password:+ password "$password"} \
+               lcp-echo-failure 5 \
+               lcp-echo-interval 15 \
+               lock \
+               crtscts \
+               nodefaultroute \
+               usepeerdns \
+               ipparam "${interface}" \
+               ip-up-script /lib/netifd/ppp-up \
+               ip-down-script /lib/netifd/ppp-down
+}
+
+modemmanager_disconnected_method_ppp_ipv4() {
+       local interface="$1"
+
+       echo "running disconnection (ppp method)"
+
+       [ -n "${ERROR}" ] && {
+               local errorstring
+               errorstring=$(ppp_exitcode_tostring "${ERROR}")
+               case "$ERROR" in
+                       0)
+                               ;;
+                       2)
+                               proto_notify_error "$interface" "$errorstring"
+                               proto_block_restart "$interface"
+                               ;;
+                       *)
+                               proto_notify_error "$interface" "$errorstring"
+                               ;;
+               esac
+       } || echo "pppd result code not given"
+
+       proto_kill_command "$interface"
+}
+
+modemmanager_connected_method_dhcp_ipv4() {
+       local interface="$1"
+       local wwan="$2"
+       local metric="$3"
+
+       proto_init_update "${wwan}" 1
+       proto_set_keep 1
+       proto_send_update "${interface}"
+
+       json_init
+       json_add_string name "${interface}_4"
+       json_add_string ifname "@${interface}"
+       json_add_string proto "dhcp"
+       proto_add_dynamic_defaults
+       [ -n "$metric" ] && json_add_int metric "${metric}"
+       json_close_object
+       ubus call network add_dynamic "$(json_dump)"
+}
+
+modemmanager_connected_method_static_ipv4() {
+       local interface="$1"
+       local wwan="$2"
+       local address="$3"
+       local prefix="$4"
+       local gateway="$5"
+       local mtu="$6"
+       local dns1="$7"
+       local dns2="$8"
+       local metric="$9"
+
+       local mask=""
+
+       [ -n "${address}" ] || {
+               proto_notify_error "${interface}" ADDRESS_MISSING
+               return
+       }
+
+       [ -n "${prefix}" ] || {
+               proto_notify_error "${interface}" PREFIX_MISSING
+               return
+       }
+       mask=$(cdr2mask "${prefix}")
+
+       [ -n "${mtu}" ] && /sbin/ip link set dev "${wwan}" mtu "${mtu}"
+
+       proto_init_update "${wwan}" 1
+       proto_set_keep 1
+       echo "adding IPv4 address ${address}, netmask ${mask}"
+       proto_add_ipv4_address "${address}" "${mask}"
+       [ -n "${gateway}" ] && {
+               echo "adding default IPv4 route via ${gateway}"
+               proto_add_ipv4_route "0.0.0.0" "0" "${gateway}" "${address}"
+       }
+       [ -n "${dns1}" ] && {
+               echo "adding primary DNS at ${dns1}"
+               proto_add_dns_server "${dns1}"
+       }
+       [ -n "${dns2}" ] && {
+               echo "adding secondary DNS at ${dns2}"
+               proto_add_dns_server "${dns2}"
+       }
+       [ -n "$metric" ] && json_add_int metric "${metric}"
+       proto_send_update "${interface}"
+}
+
+modemmanager_connected_method_dhcp_ipv6() {
+       local interface="$1"
+       local wwan="$2"
+       local metric="$3"
+
+       proto_init_update "${wwan}" 1
+       proto_set_keep 1
+       proto_send_update "${interface}"
+
+       json_init
+       json_add_string name "${interface}_6"
+       json_add_string ifname "@${interface}"
+       json_add_string proto "dhcpv6"
+       proto_add_dynamic_defaults
+       json_add_string extendprefix 1 # RFC 7278: Extend an IPv6 /64 Prefix to LAN
+       [ -n "$metric" ] && json_add_int metric "${metric}"
+       json_close_object
+       ubus call network add_dynamic "$(json_dump)"
+}
+
+modemmanager_connected_method_static_ipv6() {
+       local interface="$1"
+       local wwan="$2"
+       local address="$3"
+       local prefix="$4"
+       local gateway="$5"
+       local mtu="$6"
+       local dns1="$7"
+       local dns2="$8"
+       local metric="$9"
+
+       [ -n "${address}" ] || {
+               proto_notify_error "${interface}" ADDRESS_MISSING
+               return
+       }
+
+       [ -n "${prefix}" ] || {
+               proto_notify_error "${interface}" PREFIX_MISSING
+               return
+       }
+
+       [ -n "${mtu}" ] && /sbin/ip link set dev "${wwan}" mtu "${mtu}"
+
+       proto_init_update "${wwan}" 1
+       proto_set_keep 1
+       echo "adding IPv6 address ${address}, prefix ${prefix}"
+       proto_add_ipv6_address "${address}" "128"
+       proto_add_ipv6_prefix "${address}/${prefix}"
+       [ -n "${gateway}" ] && {
+               echo "adding default IPv6 route via ${gateway}"
+               proto_add_ipv6_route "${gateway}" "128"
+               proto_add_ipv6_route "::0" "0" "${gateway}" "" "" "${address}/${prefix}"
+       }
+       [ -n "${dns1}" ] && {
+               echo "adding primary DNS at ${dns1}"
+               proto_add_dns_server "${dns1}"
+       }
+       [ -n "${dns2}" ] && {
+               echo "adding secondary DNS at ${dns2}"
+               proto_add_dns_server "${dns2}"
+       }
+       [ -n "$metric" ] && json_add_int metric "${metric}"
+       proto_send_update "${interface}"
+}
+
+proto_modemmanager_init_config() {
+       available=1
+       no_device=1
+       proto_config_add_string device
+       proto_config_add_string apn
+       proto_config_add_string 'allowedauth:list(string)'
+       proto_config_add_string username
+       proto_config_add_string password
+       proto_config_add_string allowedmode
+       proto_config_add_string preferredmode
+       proto_config_add_string pincode
+       proto_config_add_string iptype
+       proto_config_add_string plmn
+       proto_config_add_int signalrate
+       proto_config_add_boolean lowpower
+       proto_config_add_boolean allow_roaming
+       proto_config_add_string init_epsbearer
+       proto_config_add_string init_iptype
+       proto_config_add_string 'init_allowedauth:list(string)'
+       proto_config_add_string init_password
+       proto_config_add_string init_user
+       proto_config_add_string init_apn
+       proto_config_add_defaults
+}
+
+# Append param to the global 'connectargs' variable.
+append_param() {
+       local param="$1"
+
+       [ -z "$param" ] && return
+       [ -z "$connectargs" ] || connectargs="${connectargs},"
+       connectargs="${connectargs}${param}"
+}
+
+modemmanager_set_allowed_mode() {
+       local device="$1"
+       local interface="$2"
+       local allowedmode="$3"
+
+       echo "setting allowed mode to '${allowedmode}'"
+       mmcli --modem="${device}" --set-allowed-modes="${allowedmode}" || {
+               proto_notify_error "${interface}" MM_INVALID_ALLOWED_MODES_LIST
+               proto_block_restart "${interface}"
+               return 1
+       }
+}
+
+modemmanager_check_state() {
+       local device="$1"
+       local modemstatus="$2"
+       local pincode="$3"
+
+       local state reason
+
+       state="$(modemmanager_get_field "${modemstatus}" "state")"
+       state="${state%% *}"
+       reason="$(modemmanager_get_field "${modemstatus}" "state-failed-reason")"
+
+       case "$state" in
+               "failed")
+                       case "$reason" in
+                               "sim-missing")
+                                       echo "SIM missing"
+                                       proto_notify_error "${interface}" MM_FAILED_REASON_SIM_MISSING
+                                       proto_block_restart "${interface}"
+                                       return 1
+                                       ;;
+                               *)
+                                       proto_notify_error "${interface}" MM_FAILED_REASON_UNKNOWN
+                                       proto_block_restart "${interface}"
+                                       return 1
+                                       ;;
+                       esac
+                       ;;
+               "locked")
+                       if [ -n "$pincode" ]; then
+                               mmcli --modem="${device}" -i any --pin=${pincode} || {
+                                       proto_notify_error "${interface}" MM_PINCODE_WRONG
+                                       proto_block_restart "${interface}"
+                                       return 1
+                               }
+                       else
+                               echo "PIN required"
+                               proto_notify_error "${interface}" MM_PINCODE_REQUIRED
+                               proto_block_restart "${interface}"
+                               return 1
+                       fi
+                       ;;
+       esac
+}
+
+modemmanager_set_preferred_mode() {
+       local device="$1"
+       local interface="$2"
+       local allowedmode="$3"
+       local preferredmode="$4"
+
+       [ -z "${preferredmode}" ] && {
+               echo "no preferred mode configured"
+               proto_notify_error "${interface}" MM_NO_PREFERRED_MODE_CONFIGURED
+               proto_block_restart "${interface}"
+               return 1
+       }
+
+       [ -z "${allowedmode}" ] && {
+               echo "no allowed mode configured"
+               proto_notify_error "${interface}" MM_NO_ALLOWED_MODE_CONFIGURED
+               proto_block_restart "${interface}"
+               return 1
+       }
+
+       echo "setting preferred mode to '${preferredmode}' (${allowedmode})"
+       mmcli --modem="${device}" \
+               --set-preferred-mode="${preferredmode}" \
+               --set-allowed-modes="${allowedmode}" || {
+               proto_notify_error "${interface}" MM_FAILED_SETTING_PREFERRED_MODE
+               proto_block_restart "${interface}"
+               return 1
+       }
+}
+
+modemmanager_init_epsbearer() {
+       local eps="$1"
+       local device="$2"
+       local connectargs="$3"
+       local apn="$4"
+
+       [ "$eps" != 'none' ] && [ -z "${apn}" ] && {
+               echo "No '$eps' init eps bearer apn configured"
+               proto_notify_error "${interface}" MM_INIT_EPS_BEARER_APN_NOT_CONFIGURED
+               proto_block_restart "${interface}"
+               return 1
+       }
+
+       if [ "$eps" = "none" ]; then
+               echo "Deleting inital EPS bearer..."
+       else
+               echo "Setting '$eps' inital EPS bearer apn to '$apn'..."
+       fi
+
+       mmcli --modem="${device}" \
+               --timeout 120 \
+               --3gpp-set-initial-eps-bearer-settings="${connectargs}" || {
+               proto_notify_error "${interface}" MM_INIT_EPS_BEARER_SET_FAILED
+               proto_block_restart "${interface}"
+               return 1
+       }
+
+       # Wait here so that the modem can set the init EPS bearer
+       # for registration
+       sleep 2
+}
+
+proto_modemmanager_setup() {
+       local interface="$1"
+
+       local modempath modemstatus bearercount bearerpath connectargs bearerstatus beareriface
+       local bearermethod_ipv4 bearermethod_ipv6 auth cliauth
+       local operatorname operatorid registration accesstech signalquality
+       local allowedmode preferredmode
+
+       local device apn allowedauth username password pincode
+       local iptype plmn metric signalrate allow_roaming
+
+       local init_epsbearer
+       local init_iptype init_allowedauth
+       local init_password init_user init_apn
+
+       local address prefix gateway mtu dns1 dns2
+
+       json_get_vars device apn allowedauth username password
+       json_get_vars pincode iptype plmn metric signalrate allow_roaming
+       json_get_vars allowedmode preferredmode
+
+       json_get_vars init_epsbearer
+       json_get_vars init_iptype init_allowedauth
+       json_get_vars init_password init_user init_apn
+
+       # validate sysfs path given in config
+       [ -n "${device}" ] || {
+               echo "No device specified"
+               proto_notify_error "${interface}" NO_DEVICE
+               proto_set_available "${interface}" 0
+               return 1
+       }
+
+       # validate that ModemManager is handling the modem at the sysfs path
+       modemstatus=$(mmcli --modem="${device}" --output-keyvalue)
+       modempath=$(modemmanager_get_field "${modemstatus}" "modem.dbus-path")
+       [ -n "${modempath}" ] || {
+               echo "Device not managed by ModemManager"
+               proto_notify_error "${interface}" DEVICE_NOT_MANAGED
+               proto_set_available "${interface}" 0
+               return 1
+       }
+       echo "modem available at ${modempath}"
+
+       modemmanager_check_state "$device" "${modemstatus}" "$pincode"
+       [ "$?" -ne "0" ] && return 1
+
+       if [ -z "${allowedmode}" ]; then
+               modemmanager_set_allowed_mode "$device" "$interface" "any"
+       else
+               case "$allowedmode" in
+                       "2g")
+                               modemmanager_set_allowed_mode "$device" \
+                                       "$interface" "2g"
+                               ;;
+                       "3g")
+                               modemmanager_set_allowed_mode "$device" \
+                                       "$interface" "3g"
+                               ;;
+                       "4g")
+                               modemmanager_set_allowed_mode "$device" \
+                                       "$interface" "4g"
+                               ;;
+                       "5g")
+                               modemmanager_set_allowed_mode "$device" \
+                                       "$interface" "5g"
+                               ;;
+                       *)
+                               modemmanager_set_preferred_mode "$device" \
+                                       "$interface" "${allowedmode}" "${preferredmode}"
+                               ;;
+               esac
+               # check error for allowed_mode and preferred_mode function call
+               [ "$?" -ne "0" ] && return 1
+       fi
+
+       # always cleanup before attempting a new connection, just in case
+       modemmanager_cleanup_connection "${modemstatus}"
+
+       mmcli --modem="${device}" --timeout 120 --enable || {
+               proto_notify_error "${interface}" MM_MODEM_DISABLED
+               return 1
+       }
+
+       # set initial eps bearer settings
+       [ -z "${init_epsbearer}" ] || {
+               case "$init_epsbearer" in
+                       "none")
+                               connectargs=""
+                               modemmanager_init_epsbearer "none" \
+                                       "$device" "${connectargs}" "$apn"
+                               ;;
+                       "default")
+                               cliauth=""
+                               for auth in $allowedauth; do
+                                       cliauth="${cliauth}${cliauth:+|}$auth"
+                               done
+                               connectargs=""
+                               append_param "apn=${apn}"
+                               append_param "${iptype:+ip-type=${iptype}}"
+                               append_param "${cliauth:+allowed-auth=${cliauth}}"
+                               append_param "${username:+user=${username}}"
+                               append_param "${password:+password=${password}}"
+                               modemmanager_init_epsbearer "default" \
+                                       "$device" "${connectargs}" "$apn"
+                               ;;
+                       "custom")
+                               cliauth=""
+                               for auth in $init_allowedauth; do
+                                       cliauth="${cliauth}${cliauth:+|}$auth"
+                               done
+                               connectargs=""
+                               append_param "apn=${init_apn}"
+                               append_param "${init_iptype:+ip-type=${init_iptype}}"
+                               append_param "${cliauth:+allowed-auth=${cliauth}}"
+                               append_param "${init_username:+user=${init_username}}"
+                               append_param "${init_password:+password=${init_password}}"
+                               modemmanager_init_epsbearer "custom" \
+                                       "$device" "${connectargs}" "$init_apn"
+                               ;;
+               esac
+               # check error for init_epsbearer function call
+               [ "$?" -ne "0" ] && return 1
+       }
+
+       # setup connect args; APN mandatory (even if it may be empty)
+       echo "starting connection with apn '${apn}'..."
+       proto_notify_error "${interface}" MM_CONNECT_IN_PROGRESS
+
+       # setup allow-roaming parameter
+       if [ -n "${allow_roaming}" ] && [ "${allow_roaming}" -eq 0 ];then
+               allow_roaming="no"
+       else
+               # allowed unless a user set the opposite
+               allow_roaming="yes"
+       fi
+
+       cliauth=""
+       for auth in $allowedauth; do
+               cliauth="${cliauth}${cliauth:+|}$auth"
+       done
+       # Append options to 'connectargs' variable
+       connectargs=""
+       append_param "apn=${apn}"
+       append_param "allow-roaming=${allow_roaming}"
+       append_param "${iptype:+ip-type=${iptype}}"
+       append_param "${plmn:+operator-id=${plmn}}"
+       append_param "${cliauth:+allowed-auth=${cliauth}}"
+       append_param "${username:+user=${username}}"
+       append_param "${password:+password=${password}}"
+
+       mmcli --modem="${device}" --timeout 120 --simple-connect="${connectargs}" || {
+               proto_notify_error "${interface}" MM_CONNECT_FAILED
+               proto_block_restart "${interface}"
+               return 1
+       }
+
+       # check if Signal refresh rate is set
+       if [ -n "${signalrate}" ] && [ "${signalrate}" -eq "${signalrate}" ] 2>/dev/null; then
+               echo "setting signal refresh rate to ${signalrate} seconds"
+               mmcli --modem="${device}" --signal-setup="${signalrate}"
+       else
+               echo "signal refresh rate is not set"
+       fi
+
+       # log additional useful information
+       modemstatus=$(mmcli --modem="${device}" --output-keyvalue)
+       operatorname=$(modemmanager_get_field "${modemstatus}" "modem.3gpp.operator-name")
+       [ -n "${operatorname}" ] && echo "network operator name: ${operatorname}"
+       operatorid=$(modemmanager_get_field "${modemstatus}" "modem.3gpp.operator-code")
+       [ -n "${operatorid}" ] && echo "network operator MCCMNC: ${operatorid}"
+       registration=$(modemmanager_get_field "${modemstatus}" "modem.3gpp.registration-state")
+       [ -n "${registration}" ] && echo "registration type: ${registration}"
+       accesstech=$(modemmanager_get_multivalue_field "${modemstatus}" "modem.generic.access-technologies")
+       [ -n "${accesstech}" ] && echo "access technology: ${accesstech}"
+       signalquality=$(modemmanager_get_field "${modemstatus}" "modem.generic.signal-quality.value")
+       [ -n "${signalquality}" ] && echo "signal quality: ${signalquality}%"
+
+       # we won't like it if there are more than one bearers, as that would mean the
+       # user manually created them, and that's unsupported by this proto
+       bearercount=$(modemmanager_get_field "${modemstatus}" "modem.generic.bearers.length")
+       [ -n "${bearercount}" ] && [ "$bearercount" -eq 1 ] || {
+               proto_notify_error "${interface}" INVALID_BEARER_LIST
+               return 1
+       }
+
+       # load connected bearer information
+       bearerpath=$(modemmanager_get_field "${modemstatus}" "modem.generic.bearers.value\[1\]")
+       bearerstatus=$(mmcli --bearer "${bearerpath}" --output-keyvalue)
+
+       # load network interface and method information
+       beareriface=$(modemmanager_get_field "${bearerstatus}" "bearer.status.interface")
+       bearermethod_ipv4=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv4-config.method")
+       bearermethod_ipv6=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv6-config.method")
+
+       # setup IPv4
+       [ -n "${bearermethod_ipv4}" ] && {
+               echo "IPv4 connection setup required in interface ${interface}: ${bearermethod_ipv4}"
+               case "${bearermethod_ipv4}" in
+               "dhcp")
+                       modemmanager_connected_method_dhcp_ipv4 "${interface}" "${beareriface}" "${metric}"
+                       ;;
+               "static")
+                       address=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv4-config.address")
+                       prefix=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv4-config.prefix")
+                       gateway=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv4-config.gateway")
+                       mtu=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv4-config.mtu")
+                       dns1=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv4-config.dns.value\[1\]")
+                       dns2=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv4-config.dns.value\[2\]")
+                       modemmanager_connected_method_static_ipv4 "${interface}" "${beareriface}" "${address}" "${prefix}" "${gateway}" "${mtu}" "${dns1}" "${dns2}" "${metric}"
+                       ;;
+               "ppp")
+                       modemmanager_connected_method_ppp_ipv4 "${interface}" "${beareriface}" "${username}" "${password}" "${allowedauth}"
+                       ;;
+               *)
+                       proto_notify_error "${interface}" UNKNOWN_METHOD
+                       return 1
+                       ;;
+               esac
+       }
+
+       # setup IPv6
+       # note: if using ipv4v6, both IPv4 and IPv6 settings will have the same MTU and metric values reported
+       [ -n "${bearermethod_ipv6}" ] && {
+               echo "IPv6 connection setup required in interface ${interface}: ${bearermethod_ipv6}"
+               case "${bearermethod_ipv6}" in
+               "dhcp")
+                       modemmanager_connected_method_dhcp_ipv6 "${interface}" "${beareriface}" "${metric}"
+                       ;;
+               "static")
+                       address=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv6-config.address")
+                       prefix=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv6-config.prefix")
+                       gateway=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv6-config.gateway")
+                       mtu=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv6-config.mtu")
+                       dns1=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv6-config.dns.value\[1\]")
+                       dns2=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv6-config.dns.value\[2\]")
+                       modemmanager_connected_method_static_ipv6 "${interface}" "${beareriface}" "${address}" "${prefix}" "${gateway}" "${mtu}" "${dns1}" "${dns2}" "${metric}"
+                       ;;
+               "ppp")
+                       proto_notify_error "${interface}" "unsupported method"
+                       return 1
+                       ;;
+               *)
+                       proto_notify_error "${interface}" UNKNOWN_METHOD
+                       return 1
+                       ;;
+               esac
+       }
+
+       return 0
+}
+
+proto_modemmanager_teardown() {
+       local interface="$1"
+
+       local modemstatus bearerpath errorstring
+       local bearermethod_ipv4 bearermethod_ipv6
+
+       local device lowpower iptype
+       json_get_vars device lowpower iptype
+
+       echo "stopping network"
+
+       # load connected bearer information, just the first one should be ok
+       modemstatus=$(mmcli --modem="${device}" --output-keyvalue)
+       bearerpath=$(modemmanager_get_field "${modemstatus}" "modem.generic.bearers.value\[1\]")
+       [ -n "${bearerpath}" ] || {
+               echo "couldn't load bearer path: disconnecting anyway"
+               mmcli --modem="${device}" --simple-disconnect >/dev/null 2>&1
+               return
+       }
+
+       # load bearer connection methods
+       bearerstatus=$(mmcli --bearer "${bearerpath}" --output-keyvalue)
+       bearermethod_ipv4=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv4-config.method")
+       [ -n "${bearermethod_ipv4}" ] &&
+               echo "IPv4 connection teardown required in interface ${interface}: ${bearermethod_ipv4}"
+       bearermethod_ipv6=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv6-config.method")
+       [ -n "${bearermethod_ipv6}" ] &&
+               echo "IPv6 connection teardown required in interface ${interface}: ${bearermethod_ipv6}"
+
+       # disconnection handling only requires special treatment in IPv4/PPP
+       [ "${bearermethod_ipv4}" = "ppp" ] && modemmanager_disconnected_method_ppp_ipv4 "${interface}"
+
+       # disconnect
+       mmcli --modem="${device}" --simple-disconnect ||
+               proto_notify_error "${interface}" DISCONNECT_FAILED
+
+       # disable
+       mmcli --modem="${device}" --disable
+
+       # low power, only if requested
+       [ "${lowpower:-0}" -lt 1 ] ||
+               mmcli --modem="${device}" --set-power-state-low
+}
+
+[ -n "$INCLUDE_ONLY" ] || {
+       add_protocol modemmanager
+}
diff --git a/net/modemmanager/files/modemmanager.common b/net/modemmanager/files/modemmanager.common
deleted file mode 100644 (file)
index ab5f92b..0000000
+++ /dev/null
@@ -1,268 +0,0 @@
-#!/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)"
-               return
-       }
-
-       # 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
-}
diff --git a/net/modemmanager/files/modemmanager.init b/net/modemmanager/files/modemmanager.init
deleted file mode 100755 (executable)
index ccc1953..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/sh /etc/rc.common
-# Copyright (C) 2016 Aleksander Morgado <aleksander@aleksander.es>
-
-USE_PROCD=1
-START=70
-
-LOG_LEVEL="INFO"
-
-start_service() {
-       # Setup ModemManager service
-       #
-       # We will make sure that the rundir always exists, and we initially cleanup
-       # all interfaces flagging them as unavailable.
-       #
-       # The cached events processing will wait for MM to be available in DBus
-       # and will make sure all ports are re-notified to ModemManager every time
-       # it starts.
-       #
-       # All these commands need to be executed on every MM start, even after
-       # procd-triggered respawns, which is why this is wrapped in a startup
-       # wrapper script called '/usr/sbin/ModemManager-wrapper'.
-       #
-       . /usr/share/ModemManager/modemmanager.common
-       procd_open_instance "service"
-       procd_set_param command /usr/sbin/ModemManager-wrapper
-       procd_append_param command --log-level="$LOG_LEVEL"
-       [ "$LOG_LEVEL" = "DEBUG" ] && procd_append_param command --debug
-       procd_set_param respawn "${respawn_threshold:-3600}" "${respawn_timeout:-5}" "${respawn_retry:-5}"
-       procd_set_param pidfile "${MODEMMANAGER_PID_FILE}"
-       procd_close_instance
-       procd_open_instance "monitor"
-       procd_set_param command /usr/sbin/ModemManager-monitor
-       procd_set_param respawn "${respawn_threshold:-3600}" "${respawn_timeout:-5}" "${respawn_retry:-5}"
-       procd_close_instance
-}
diff --git a/net/modemmanager/files/modemmanager.proto b/net/modemmanager/files/modemmanager.proto
deleted file mode 100755 (executable)
index b059b4c..0000000
+++ /dev/null
@@ -1,712 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2016-2019 Aleksander Morgado <aleksander@aleksander.es>
-
-[ -x /usr/bin/mmcli ] || exit 0
-[ -x /usr/sbin/pppd ] || exit 0
-
-[ -n "$INCLUDE_ONLY" ] || {
-       . /lib/functions.sh
-       . ../netifd-proto.sh
-       . ./ppp.sh
-       . /usr/share/ModemManager/modemmanager.common
-       init_proto "$@"
-}
-
-cdr2mask ()
-{
-       # Number of args to shift, 255..255, first non-255 byte, zeroes
-       set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0
-       if [ "$1" -gt 1 ]
-       then
-               shift "$1"
-       else
-               shift
-       fi
-       echo "${1-0}"."${2-0}"."${3-0}"."${4-0}"
-}
-
-modemmanager_cleanup_connection() {
-       local modemstatus="$1"
-
-       local bearercount idx bearerpath
-
-       bearercount=$(modemmanager_get_field "${modemstatus}" "modem.generic.bearers.length")
-
-       # do nothing if no bearers reported
-       [ -n "${bearercount}" ] && [ "$bearercount" -ge 1 ] && {
-               # explicitly disconnect just in case
-               mmcli --modem="${device}" --simple-disconnect >/dev/null 2>&1
-               # and remove all bearer objects, if any found
-               idx=1
-               while [ $idx -le "$bearercount" ]; do
-                       bearerpath=$(modemmanager_get_field "${modemstatus}" "modem.generic.bearers.value\[$idx\]")
-                       mmcli --modem "${device}" --delete-bearer="${bearerpath}" >/dev/null 2>&1
-                       idx=$((idx + 1))
-               done
-       }
-}
-
-modemmanager_connected_method_ppp_ipv4() {
-       local interface="$1"
-       local ttyname="$2"
-       local username="$3"
-       local password="$4"
-       local allowedauth="$5"
-
-       # all auth types are allowed unless a user given list is given
-       local authopts
-       local pap=1
-       local chap=1
-       local mschap=1
-       local mschapv2=1
-       local eap=1
-
-       [ -n "$allowedauth" ] && {
-               pap=0 chap=0 mschap=0 mschapv2=0 eap=0
-               for auth in $allowedauth; do
-                       case $auth in
-                               "pap") pap=1 ;;
-                               "chap") chap=1 ;;
-                               "mschap") mschap=1 ;;
-                               "mschapv2") mschapv2=1 ;;
-                               "eap") eap=1 ;;
-                               *) ;;
-                       esac
-               done
-       }
-
-       [ $pap -eq 1 ] || append authopts "refuse-pap"
-       [ $chap -eq 1 ] || append authopts "refuse-chap"
-       [ $mschap -eq 1 ] || append authopts "refuse-mschap"
-       [ $mschapv2 -eq 1 ] || append authopts "refuse-mschap-v2"
-       [ $eap -eq 1 ] || append authopts "refuse-eap"
-
-       proto_run_command "${interface}" /usr/sbin/pppd \
-               "${ttyname}" \
-               115200 \
-               nodetach \
-               noaccomp \
-               nobsdcomp \
-               nopcomp \
-               novj \
-               noauth \
-               $authopts \
-               ${username:+ user "$username"} \
-               ${password:+ password "$password"} \
-               lcp-echo-failure 5 \
-               lcp-echo-interval 15 \
-               lock \
-               crtscts \
-               nodefaultroute \
-               usepeerdns \
-               ipparam "${interface}" \
-               ip-up-script /lib/netifd/ppp-up \
-               ip-down-script /lib/netifd/ppp-down
-}
-
-modemmanager_disconnected_method_ppp_ipv4() {
-       local interface="$1"
-
-       echo "running disconnection (ppp method)"
-
-       [ -n "${ERROR}" ] && {
-               local errorstring
-               errorstring=$(ppp_exitcode_tostring "${ERROR}")
-               case "$ERROR" in
-                       0)
-                               ;;
-                       2)
-                               proto_notify_error "$interface" "$errorstring"
-                               proto_block_restart "$interface"
-                               ;;
-                       *)
-                               proto_notify_error "$interface" "$errorstring"
-                               ;;
-               esac
-       } || echo "pppd result code not given"
-
-       proto_kill_command "$interface"
-}
-
-modemmanager_connected_method_dhcp_ipv4() {
-       local interface="$1"
-       local wwan="$2"
-       local metric="$3"
-
-       proto_init_update "${wwan}" 1
-       proto_set_keep 1
-       proto_send_update "${interface}"
-
-       json_init
-       json_add_string name "${interface}_4"
-       json_add_string ifname "@${interface}"
-       json_add_string proto "dhcp"
-       proto_add_dynamic_defaults
-       [ -n "$metric" ] && json_add_int metric "${metric}"
-       json_close_object
-       ubus call network add_dynamic "$(json_dump)"
-}
-
-modemmanager_connected_method_static_ipv4() {
-       local interface="$1"
-       local wwan="$2"
-       local address="$3"
-       local prefix="$4"
-       local gateway="$5"
-       local mtu="$6"
-       local dns1="$7"
-       local dns2="$8"
-       local metric="$9"
-
-       local mask=""
-
-       [ -n "${address}" ] || {
-               proto_notify_error "${interface}" ADDRESS_MISSING
-               return
-       }
-
-       [ -n "${prefix}" ] || {
-               proto_notify_error "${interface}" PREFIX_MISSING
-               return
-       }
-       mask=$(cdr2mask "${prefix}")
-
-       [ -n "${mtu}" ] && /sbin/ip link set dev "${wwan}" mtu "${mtu}"
-
-       proto_init_update "${wwan}" 1
-       proto_set_keep 1
-       echo "adding IPv4 address ${address}, netmask ${mask}"
-       proto_add_ipv4_address "${address}" "${mask}"
-       [ -n "${gateway}" ] && {
-               echo "adding default IPv4 route via ${gateway}"
-               proto_add_ipv4_route "0.0.0.0" "0" "${gateway}" "${address}"
-       }
-       [ -n "${dns1}" ] && {
-               echo "adding primary DNS at ${dns1}"
-               proto_add_dns_server "${dns1}"
-       }
-       [ -n "${dns2}" ] && {
-               echo "adding secondary DNS at ${dns2}"
-               proto_add_dns_server "${dns2}"
-       }
-       [ -n "$metric" ] && json_add_int metric "${metric}"
-       proto_send_update "${interface}"
-}
-
-modemmanager_connected_method_dhcp_ipv6() {
-       local interface="$1"
-       local wwan="$2"
-       local metric="$3"
-
-       proto_init_update "${wwan}" 1
-       proto_set_keep 1
-       proto_send_update "${interface}"
-
-       json_init
-       json_add_string name "${interface}_6"
-       json_add_string ifname "@${interface}"
-       json_add_string proto "dhcpv6"
-       proto_add_dynamic_defaults
-       json_add_string extendprefix 1 # RFC 7278: Extend an IPv6 /64 Prefix to LAN
-       [ -n "$metric" ] && json_add_int metric "${metric}"
-       json_close_object
-       ubus call network add_dynamic "$(json_dump)"
-}
-
-modemmanager_connected_method_static_ipv6() {
-       local interface="$1"
-       local wwan="$2"
-       local address="$3"
-       local prefix="$4"
-       local gateway="$5"
-       local mtu="$6"
-       local dns1="$7"
-       local dns2="$8"
-       local metric="$9"
-
-       [ -n "${address}" ] || {
-               proto_notify_error "${interface}" ADDRESS_MISSING
-               return
-       }
-
-       [ -n "${prefix}" ] || {
-               proto_notify_error "${interface}" PREFIX_MISSING
-               return
-       }
-
-       [ -n "${mtu}" ] && /sbin/ip link set dev "${wwan}" mtu "${mtu}"
-
-       proto_init_update "${wwan}" 1
-       proto_set_keep 1
-       echo "adding IPv6 address ${address}, prefix ${prefix}"
-       proto_add_ipv6_address "${address}" "128"
-       proto_add_ipv6_prefix "${address}/${prefix}"
-       [ -n "${gateway}" ] && {
-               echo "adding default IPv6 route via ${gateway}"
-               proto_add_ipv6_route "${gateway}" "128"
-               proto_add_ipv6_route "::0" "0" "${gateway}" "" "" "${address}/${prefix}"
-       }
-       [ -n "${dns1}" ] && {
-               echo "adding primary DNS at ${dns1}"
-               proto_add_dns_server "${dns1}"
-       }
-       [ -n "${dns2}" ] && {
-               echo "adding secondary DNS at ${dns2}"
-               proto_add_dns_server "${dns2}"
-       }
-       [ -n "$metric" ] && json_add_int metric "${metric}"
-       proto_send_update "${interface}"
-}
-
-proto_modemmanager_init_config() {
-       available=1
-       no_device=1
-       proto_config_add_string device
-       proto_config_add_string apn
-       proto_config_add_string 'allowedauth:list(string)'
-       proto_config_add_string username
-       proto_config_add_string password
-       proto_config_add_string allowedmode
-       proto_config_add_string preferredmode
-       proto_config_add_string pincode
-       proto_config_add_string iptype
-       proto_config_add_string plmn
-       proto_config_add_int signalrate
-       proto_config_add_boolean lowpower
-       proto_config_add_boolean allow_roaming
-       proto_config_add_string init_epsbearer
-       proto_config_add_string init_iptype
-       proto_config_add_string 'init_allowedauth:list(string)'
-       proto_config_add_string init_password
-       proto_config_add_string init_user
-       proto_config_add_string init_apn
-       proto_config_add_defaults
-}
-
-# Append param to the global 'connectargs' variable.
-append_param() {
-       local param="$1"
-
-       [ -z "$param" ] && return
-       [ -z "$connectargs" ] || connectargs="${connectargs},"
-       connectargs="${connectargs}${param}"
-}
-
-modemmanager_set_allowed_mode() {
-       local device="$1"
-       local interface="$2"
-       local allowedmode="$3"
-
-       echo "setting allowed mode to '${allowedmode}'"
-       mmcli --modem="${device}" --set-allowed-modes="${allowedmode}" || {
-               proto_notify_error "${interface}" MM_INVALID_ALLOWED_MODES_LIST
-               proto_block_restart "${interface}"
-               return 1
-       }
-}
-
-modemmanager_check_state() {
-       local device="$1"
-       local modemstatus="$2"
-       local pincode="$3"
-
-       local state reason
-
-       state="$(modemmanager_get_field "${modemstatus}" "state")"
-       state="${state%% *}"
-       reason="$(modemmanager_get_field "${modemstatus}" "state-failed-reason")"
-
-       case "$state" in
-               "failed")
-                       case "$reason" in
-                               "sim-missing")
-                                       echo "SIM missing"
-                                       proto_notify_error "${interface}" MM_FAILED_REASON_SIM_MISSING
-                                       proto_block_restart "${interface}"
-                                       return 1
-                                       ;;
-                               *)
-                                       proto_notify_error "${interface}" MM_FAILED_REASON_UNKNOWN
-                                       proto_block_restart "${interface}"
-                                       return 1
-                                       ;;
-                       esac
-                       ;;
-               "locked")
-                       if [ -n "$pincode" ]; then
-                               mmcli --modem="${device}" -i any --pin=${pincode} || {
-                                       proto_notify_error "${interface}" MM_PINCODE_WRONG
-                                       proto_block_restart "${interface}"
-                                       return 1
-                               }
-                       else
-                               echo "PIN required"
-                               proto_notify_error "${interface}" MM_PINCODE_REQUIRED
-                               proto_block_restart "${interface}"
-                               return 1
-                       fi
-                       ;;
-       esac
-}
-
-modemmanager_set_preferred_mode() {
-       local device="$1"
-       local interface="$2"
-       local allowedmode="$3"
-       local preferredmode="$4"
-
-       [ -z "${preferredmode}" ] && {
-               echo "no preferred mode configured"
-               proto_notify_error "${interface}" MM_NO_PREFERRED_MODE_CONFIGURED
-               proto_block_restart "${interface}"
-               return 1
-       }
-
-       [ -z "${allowedmode}" ] && {
-               echo "no allowed mode configured"
-               proto_notify_error "${interface}" MM_NO_ALLOWED_MODE_CONFIGURED
-               proto_block_restart "${interface}"
-               return 1
-       }
-
-       echo "setting preferred mode to '${preferredmode}' (${allowedmode})"
-       mmcli --modem="${device}" \
-               --set-preferred-mode="${preferredmode}" \
-               --set-allowed-modes="${allowedmode}" || {
-               proto_notify_error "${interface}" MM_FAILED_SETTING_PREFERRED_MODE
-               proto_block_restart "${interface}"
-               return 1
-       }
-}
-
-modemmanager_init_epsbearer() {
-       local eps="$1"
-       local device="$2"
-       local connectargs="$3"
-       local apn="$4"
-
-       [ "$eps" != 'none' ] && [ -z "${apn}" ] && {
-               echo "No '$eps' init eps bearer apn configured"
-               proto_notify_error "${interface}" MM_INIT_EPS_BEARER_APN_NOT_CONFIGURED
-               proto_block_restart "${interface}"
-               return 1
-       }
-
-       if [ "$eps" = "none" ]; then
-               echo "Deleting inital EPS bearer..."
-       else
-               echo "Setting '$eps' inital EPS bearer apn to '$apn'..."
-       fi
-
-       mmcli --modem="${device}" \
-               --timeout 120 \
-               --3gpp-set-initial-eps-bearer-settings="${connectargs}" || {
-               proto_notify_error "${interface}" MM_INIT_EPS_BEARER_SET_FAILED
-               proto_block_restart "${interface}"
-               return 1
-       }
-
-       # Wait here so that the modem can set the init EPS bearer
-       # for registration
-       sleep 2
-}
-
-proto_modemmanager_setup() {
-       local interface="$1"
-
-       local modempath modemstatus bearercount bearerpath connectargs bearerstatus beareriface
-       local bearermethod_ipv4 bearermethod_ipv6 auth cliauth
-       local operatorname operatorid registration accesstech signalquality
-       local allowedmode preferredmode
-
-       local device apn allowedauth username password pincode
-       local iptype plmn metric signalrate allow_roaming
-
-       local init_epsbearer
-       local init_iptype init_allowedauth
-       local init_password init_user init_apn
-
-       local address prefix gateway mtu dns1 dns2
-
-       json_get_vars device apn allowedauth username password
-       json_get_vars pincode iptype plmn metric signalrate allow_roaming
-       json_get_vars allowedmode preferredmode
-
-       json_get_vars init_epsbearer
-       json_get_vars init_iptype init_allowedauth
-       json_get_vars init_password init_user init_apn
-
-       # validate sysfs path given in config
-       [ -n "${device}" ] || {
-               echo "No device specified"
-               proto_notify_error "${interface}" NO_DEVICE
-               proto_set_available "${interface}" 0
-               return 1
-       }
-
-       # validate that ModemManager is handling the modem at the sysfs path
-       modemstatus=$(mmcli --modem="${device}" --output-keyvalue)
-       modempath=$(modemmanager_get_field "${modemstatus}" "modem.dbus-path")
-       [ -n "${modempath}" ] || {
-               echo "Device not managed by ModemManager"
-               proto_notify_error "${interface}" DEVICE_NOT_MANAGED
-               proto_set_available "${interface}" 0
-               return 1
-       }
-       echo "modem available at ${modempath}"
-
-       modemmanager_check_state "$device" "${modemstatus}" "$pincode"
-       [ "$?" -ne "0" ] && return 1
-
-       if [ -z "${allowedmode}" ]; then
-               modemmanager_set_allowed_mode "$device" "$interface" "any"
-       else
-               case "$allowedmode" in
-                       "2g")
-                               modemmanager_set_allowed_mode "$device" \
-                                       "$interface" "2g"
-                               ;;
-                       "3g")
-                               modemmanager_set_allowed_mode "$device" \
-                                       "$interface" "3g"
-                               ;;
-                       "4g")
-                               modemmanager_set_allowed_mode "$device" \
-                                       "$interface" "4g"
-                               ;;
-                       "5g")
-                               modemmanager_set_allowed_mode "$device" \
-                                       "$interface" "5g"
-                               ;;
-                       *)
-                               modemmanager_set_preferred_mode "$device" \
-                                       "$interface" "${allowedmode}" "${preferredmode}"
-                               ;;
-               esac
-               # check error for allowed_mode and preferred_mode function call
-               [ "$?" -ne "0" ] && return 1
-       fi
-
-       # always cleanup before attempting a new connection, just in case
-       modemmanager_cleanup_connection "${modemstatus}"
-
-       mmcli --modem="${device}" --timeout 120 --enable || {
-               proto_notify_error "${interface}" MM_MODEM_DISABLED
-               return 1
-       }
-
-       # set initial eps bearer settings
-       [ -z "${init_epsbearer}" ] || {
-               case "$init_epsbearer" in
-                       "none")
-                               connectargs=""
-                               modemmanager_init_epsbearer "none" \
-                                       "$device" "${connectargs}" "$apn"
-                               ;;
-                       "default")
-                               cliauth=""
-                               for auth in $allowedauth; do
-                                       cliauth="${cliauth}${cliauth:+|}$auth"
-                               done
-                               connectargs=""
-                               append_param "apn=${apn}"
-                               append_param "${iptype:+ip-type=${iptype}}"
-                               append_param "${cliauth:+allowed-auth=${cliauth}}"
-                               append_param "${username:+user=${username}}"
-                               append_param "${password:+password=${password}}"
-                               modemmanager_init_epsbearer "default" \
-                                       "$device" "${connectargs}" "$apn"
-                               ;;
-                       "custom")
-                               cliauth=""
-                               for auth in $init_allowedauth; do
-                                       cliauth="${cliauth}${cliauth:+|}$auth"
-                               done
-                               connectargs=""
-                               append_param "apn=${init_apn}"
-                               append_param "${init_iptype:+ip-type=${init_iptype}}"
-                               append_param "${cliauth:+allowed-auth=${cliauth}}"
-                               append_param "${init_username:+user=${init_username}}"
-                               append_param "${init_password:+password=${init_password}}"
-                               modemmanager_init_epsbearer "custom" \
-                                       "$device" "${connectargs}" "$init_apn"
-                               ;;
-               esac
-               # check error for init_epsbearer function call
-               [ "$?" -ne "0" ] && return 1
-       }
-
-       # setup connect args; APN mandatory (even if it may be empty)
-       echo "starting connection with apn '${apn}'..."
-       proto_notify_error "${interface}" MM_CONNECT_IN_PROGRESS
-
-       # setup allow-roaming parameter
-       if [ -n "${allow_roaming}" ] && [ "${allow_roaming}" -eq 0 ];then
-               allow_roaming="no"
-       else
-               # allowed unless a user set the opposite
-               allow_roaming="yes"
-       fi
-
-       cliauth=""
-       for auth in $allowedauth; do
-               cliauth="${cliauth}${cliauth:+|}$auth"
-       done
-       # Append options to 'connectargs' variable
-       connectargs=""
-       append_param "apn=${apn}"
-       append_param "allow-roaming=${allow_roaming}"
-       append_param "${iptype:+ip-type=${iptype}}"
-       append_param "${plmn:+operator-id=${plmn}}"
-       append_param "${cliauth:+allowed-auth=${cliauth}}"
-       append_param "${username:+user=${username}}"
-       append_param "${password:+password=${password}}"
-
-       mmcli --modem="${device}" --timeout 120 --simple-connect="${connectargs}" || {
-               proto_notify_error "${interface}" MM_CONNECT_FAILED
-               proto_block_restart "${interface}"
-               return 1
-       }
-
-       # check if Signal refresh rate is set
-       if [ -n "${signalrate}" ] && [ "${signalrate}" -eq "${signalrate}" ] 2>/dev/null; then
-               echo "setting signal refresh rate to ${signalrate} seconds"
-               mmcli --modem="${device}" --signal-setup="${signalrate}"
-       else
-               echo "signal refresh rate is not set"
-       fi
-
-       # log additional useful information
-       modemstatus=$(mmcli --modem="${device}" --output-keyvalue)
-       operatorname=$(modemmanager_get_field "${modemstatus}" "modem.3gpp.operator-name")
-       [ -n "${operatorname}" ] && echo "network operator name: ${operatorname}"
-       operatorid=$(modemmanager_get_field "${modemstatus}" "modem.3gpp.operator-code")
-       [ -n "${operatorid}" ] && echo "network operator MCCMNC: ${operatorid}"
-       registration=$(modemmanager_get_field "${modemstatus}" "modem.3gpp.registration-state")
-       [ -n "${registration}" ] && echo "registration type: ${registration}"
-       accesstech=$(modemmanager_get_multivalue_field "${modemstatus}" "modem.generic.access-technologies")
-       [ -n "${accesstech}" ] && echo "access technology: ${accesstech}"
-       signalquality=$(modemmanager_get_field "${modemstatus}" "modem.generic.signal-quality.value")
-       [ -n "${signalquality}" ] && echo "signal quality: ${signalquality}%"
-
-       # we won't like it if there are more than one bearers, as that would mean the
-       # user manually created them, and that's unsupported by this proto
-       bearercount=$(modemmanager_get_field "${modemstatus}" "modem.generic.bearers.length")
-       [ -n "${bearercount}" ] && [ "$bearercount" -eq 1 ] || {
-               proto_notify_error "${interface}" INVALID_BEARER_LIST
-               return 1
-       }
-
-       # load connected bearer information
-       bearerpath=$(modemmanager_get_field "${modemstatus}" "modem.generic.bearers.value\[1\]")
-       bearerstatus=$(mmcli --bearer "${bearerpath}" --output-keyvalue)
-
-       # load network interface and method information
-       beareriface=$(modemmanager_get_field "${bearerstatus}" "bearer.status.interface")
-       bearermethod_ipv4=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv4-config.method")
-       bearermethod_ipv6=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv6-config.method")
-
-       # setup IPv4
-       [ -n "${bearermethod_ipv4}" ] && {
-               echo "IPv4 connection setup required in interface ${interface}: ${bearermethod_ipv4}"
-               case "${bearermethod_ipv4}" in
-               "dhcp")
-                       modemmanager_connected_method_dhcp_ipv4 "${interface}" "${beareriface}" "${metric}"
-                       ;;
-               "static")
-                       address=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv4-config.address")
-                       prefix=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv4-config.prefix")
-                       gateway=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv4-config.gateway")
-                       mtu=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv4-config.mtu")
-                       dns1=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv4-config.dns.value\[1\]")
-                       dns2=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv4-config.dns.value\[2\]")
-                       modemmanager_connected_method_static_ipv4 "${interface}" "${beareriface}" "${address}" "${prefix}" "${gateway}" "${mtu}" "${dns1}" "${dns2}" "${metric}"
-                       ;;
-               "ppp")
-                       modemmanager_connected_method_ppp_ipv4 "${interface}" "${beareriface}" "${username}" "${password}" "${allowedauth}"
-                       ;;
-               *)
-                       proto_notify_error "${interface}" UNKNOWN_METHOD
-                       return 1
-                       ;;
-               esac
-       }
-
-       # setup IPv6
-       # note: if using ipv4v6, both IPv4 and IPv6 settings will have the same MTU and metric values reported
-       [ -n "${bearermethod_ipv6}" ] && {
-               echo "IPv6 connection setup required in interface ${interface}: ${bearermethod_ipv6}"
-               case "${bearermethod_ipv6}" in
-               "dhcp")
-                       modemmanager_connected_method_dhcp_ipv6 "${interface}" "${beareriface}" "${metric}"
-                       ;;
-               "static")
-                       address=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv6-config.address")
-                       prefix=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv6-config.prefix")
-                       gateway=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv6-config.gateway")
-                       mtu=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv6-config.mtu")
-                       dns1=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv6-config.dns.value\[1\]")
-                       dns2=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv6-config.dns.value\[2\]")
-                       modemmanager_connected_method_static_ipv6 "${interface}" "${beareriface}" "${address}" "${prefix}" "${gateway}" "${mtu}" "${dns1}" "${dns2}" "${metric}"
-                       ;;
-               "ppp")
-                       proto_notify_error "${interface}" "unsupported method"
-                       return 1
-                       ;;
-               *)
-                       proto_notify_error "${interface}" UNKNOWN_METHOD
-                       return 1
-                       ;;
-               esac
-       }
-
-       return 0
-}
-
-proto_modemmanager_teardown() {
-       local interface="$1"
-
-       local modemstatus bearerpath errorstring
-       local bearermethod_ipv4 bearermethod_ipv6
-
-       local device lowpower iptype
-       json_get_vars device lowpower iptype
-
-       echo "stopping network"
-
-       # load connected bearer information, just the first one should be ok
-       modemstatus=$(mmcli --modem="${device}" --output-keyvalue)
-       bearerpath=$(modemmanager_get_field "${modemstatus}" "modem.generic.bearers.value\[1\]")
-       [ -n "${bearerpath}" ] || {
-               echo "couldn't load bearer path: disconnecting anyway"
-               mmcli --modem="${device}" --simple-disconnect >/dev/null 2>&1
-               return
-       }
-
-       # load bearer connection methods
-       bearerstatus=$(mmcli --bearer "${bearerpath}" --output-keyvalue)
-       bearermethod_ipv4=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv4-config.method")
-       [ -n "${bearermethod_ipv4}" ] &&
-               echo "IPv4 connection teardown required in interface ${interface}: ${bearermethod_ipv4}"
-       bearermethod_ipv6=$(modemmanager_get_field "${bearerstatus}" "bearer.ipv6-config.method")
-       [ -n "${bearermethod_ipv6}" ] &&
-               echo "IPv6 connection teardown required in interface ${interface}: ${bearermethod_ipv6}"
-
-       # disconnection handling only requires special treatment in IPv4/PPP
-       [ "${bearermethod_ipv4}" = "ppp" ] && modemmanager_disconnected_method_ppp_ipv4 "${interface}"
-
-       # disconnect
-       mmcli --modem="${device}" --simple-disconnect ||
-               proto_notify_error "${interface}" DISCONNECT_FAILED
-
-       # disable
-       mmcli --modem="${device}" --disable
-
-       # low power, only if requested
-       [ "${lowpower:-0}" -lt 1 ] ||
-               mmcli --modem="${device}" --set-power-state-low
-}
-
-[ -n "$INCLUDE_ONLY" ] || {
-       add_protocol modemmanager
-}
diff --git a/net/modemmanager/files/usr/lib/ModemManager/connection.d/10-report-down b/net/modemmanager/files/usr/lib/ModemManager/connection.d/10-report-down
new file mode 100644 (file)
index 0000000..0ebe87d
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+# SPDX-License-Identifier: CC0-1.0
+# 2022 Aleksander Morgado <aleksander@aleksander.es>
+#
+# Automatically report to netifd that the underlying modem
+# is really disconnected
+#
+# require program name and at least 4 arguments
+[ $# -lt 4 ] && exit 1
+
+MODEM_PATH="$1"
+BEARER_PATH="$2"
+INTERFACE="$3"
+STATE="$4"
+
+[ "${STATE}" = "disconnected" ] || exit 0
+
+. /lib/netifd/netifd-proto.sh
+. /usr/share/ModemManager/modemmanager.common
+
+MODEM_STATUS=$(mmcli --modem="${MODEM_PATH}" --output-keyvalue)
+[ -n "${MODEM_STATUS}" ] || exit 1
+
+MODEM_DEVICE=$(modemmanager_get_field "${MODEM_STATUS}" "modem.generic.device")
+[ -n "${MODEM_DEVICE}" ] || exit 2
+
+CFG=$(mm_get_modem_config "${MODEM_DEVICE}")
+[ -n "${CFG}" ] || exit 3
+
+IFUP=$(ifstatus "${CFG}" | jsonfilter -e "@.up")
+
+[ "${IFUP}" = "true" ] && {
+       logger -t "modemmanager" "interface ${CFG} (network device ${INTERFACE}) ${STATE}"
+       proto_init_update $INTERFACE 0
+       proto_send_update $CFG
+}
+
+exit 0
diff --git a/net/modemmanager/files/usr/share/ModemManager/modemmanager.common b/net/modemmanager/files/usr/share/ModemManager/modemmanager.common
new file mode 100644 (file)
index 0000000..ab5f92b
--- /dev/null
@@ -0,0 +1,268 @@
+#!/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)"
+               return
+       }
+
+       # 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
+}