ffd803d1dd
The configfs gadget can provide the actual interface name, which may not be the default "usb0" since another gadget driver might have claimed "usb0". This code is based on the `start_unudhcpd` function in `init_functions.sh` [ci:skip-build] already built successfully in CI
128 lines
4.5 KiB
Bash
128 lines
4.5 KiB
Bash
#!/bin/sh -e
|
|
# shellcheck disable=SC1091
|
|
# Handle USB tethering with unudhcpd and NetworkManager while also
|
|
# keeping SSH login over USB working when tethering is disabled.
|
|
#
|
|
# Copyright (c) 2023 Dylan Van Assche
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
# Must match with the supplied connection profile,
|
|
# using UUID allows the user to change the connection name if they want to.
|
|
con_uuid="83bd1823-feca-4c2b-9205-4b83dc792e1f"
|
|
|
|
. /usr/share/misc/source_deviceinfo
|
|
|
|
usb_network_function="${deviceinfo_usb_network_function:-ncm.usb0}"
|
|
usb_network_function_fallback="rndis.usb0"
|
|
interface="$(
|
|
cat "/sys/kernel/config/usb_gadget/g1/functions/$usb_network_function/ifname" 2>/dev/null ||
|
|
cat "/sys/kernel/config/usb_gadget/g1/functions/$usb_network_function_fallback/ifname" 2>/dev/null ||
|
|
echo 'usb0'
|
|
)"
|
|
|
|
[ -e /etc/unudhcpd.conf ] && . /etc/unudhcpd.conf
|
|
host_ip="${unudhcpd_host_ip:-172.16.42.1}"
|
|
client_ip="${unudhcpd_client_ip:-172.16.42.2}"
|
|
|
|
# Skip if iface does not match
|
|
if [ "$DEVICE_IFACE" != "$interface" ]; then
|
|
exit 0
|
|
fi
|
|
|
|
# Trigger a disconnect/connect event on the client side to request a new DHCP lease.
|
|
reactivate_gadget() {
|
|
# Mount configFS
|
|
mkdir -p /config
|
|
mount -t configfs none /config || true
|
|
|
|
logger -t nm-tethering "configFS mounted"
|
|
|
|
# Reactivate gadget
|
|
udc=$(cat /config/usb_gadget/g1/UDC)
|
|
echo "" > /config/usb_gadget/g1/UDC
|
|
sleep 1
|
|
echo "$udc" > /config/usb_gadget/g1/UDC
|
|
|
|
logger -t nm-tethering "gadget reactivated"
|
|
|
|
# Unmount configFS
|
|
umount /config
|
|
rm -rf /config
|
|
|
|
logger -t nm-tethering "configFS unmounted"
|
|
}
|
|
|
|
# Default static IP for SSH acccess
|
|
# 1. Configure NetworkManager connection to use IP 172.16.42.1, same as initfs.
|
|
# 2. Disable IPv6 as unudhcpd only supplies IPv4 addresses.
|
|
# 3. Start unudhcpd to handle DHCP requests.
|
|
# 4. Reactivate the USB Ethernet gadget to force the clients to reactivate the interface.
|
|
disable_tethering() {
|
|
# Configure static IP and bring up connection automatically
|
|
nmcli connection modify "$con_uuid" ipv4.address "$host_ip/16"
|
|
nmcli connection modify "$con_uuid" ipv4.method "manual"
|
|
nmcli connection modify "$con_uuid" ipv6.method "link-local"
|
|
nmcli connection modify "$con_uuid" connection.autoconnect "true"
|
|
|
|
# Restart unudhpcd and configure it similar to initfs
|
|
killall unudhpcd || true
|
|
(unudhcpd -i "$interface" -s "$host_ip" -c "$client_ip") &
|
|
logger -t nm-tethering "unudhcpd started"
|
|
|
|
# Reactivate gadget to apply changes
|
|
reactivate_gadget
|
|
logger -t nm-tethering "USB tethering disabled"
|
|
}
|
|
|
|
# USB tethering
|
|
# 1. Enforce 172.16.42.1 as host IP even in tethering mode.
|
|
# 2. Stop unudhcpd as NetworkManager will spawn dnsmasq to handle DNS and DHCP requests.
|
|
# 3. Reactivate the USB Ethernet gadget to force the clients to reactivate the interface.
|
|
enable_tethering() {
|
|
# Enforce the same IP range as when tethering is disabled, this will retrigger
|
|
# the script as we have to reapply again, also bring up connection automatically.
|
|
ip=$(nmcli connection show "$con_uuid" --active | grep ipv4.addresses | tr -s " " | cut -d " " -f2)
|
|
if [ "$ip" != "$host_ip/16" ]; then
|
|
logger -t nm-tethering "Enforcing $host_ip/16 as DHCP range"
|
|
nmcli connection modify "$con_uuid" ipv4.address "$host_ip/16"
|
|
nmcli connection modify "$con_uuid" connection.autoconnect "true"
|
|
nmcli device reapply "$interface"
|
|
return
|
|
fi
|
|
|
|
# Kill unudhcpd if needed
|
|
killall unudhcpd || true
|
|
logger -t nm-tethering "unudhcpd stopped"
|
|
|
|
# Reactivate gadget to apply changes
|
|
reactivate_gadget
|
|
logger -t nm-tethering "USB tethering enabled"
|
|
}
|
|
|
|
# Handle dispatcher events for tethering
|
|
method=$(nmcli connection show "$con_uuid" --active | grep ipv4.method | tr -s " " | cut -d " " -f2)
|
|
case $NM_DISPATCHER_ACTION in
|
|
# Always disable tethering on insert or removal for security
|
|
"up"|"down")
|
|
disable_tethering
|
|
|
|
# The connection may have been configured before to tethering which
|
|
# is not desired when iface comes up or is shut down as tethering must be
|
|
# disabled. Enforce this by triggering a reapply after modifying the connection
|
|
# which will cause NetworkManager to trigger the script again.
|
|
# If the iface is already down since dispatcher scripts are executed async,
|
|
# the command will fail which is fine to ignore
|
|
if [ "$method" = "shared" ]; then
|
|
logger -t nm-tethering "Enforcing tethering disabled on iface up/down"
|
|
nmcli device reapply "$interface" || true
|
|
fi
|
|
;;
|
|
# Enable tethering if the user explicitly enabled it
|
|
"reapply")
|
|
if [ "$method" = "shared" ]; then
|
|
enable_tethering
|
|
elif [ "$method" = "manual" ]; then
|
|
disable_tethering
|
|
fi
|
|
;;
|
|
esac
|