diff --git a/src/initscripts/networking/dhcpcd.exe b/src/initscripts/networking/dhcpcd.exe index 8a409d010..be6d63708 100644 --- a/src/initscripts/networking/dhcpcd.exe +++ b/src/initscripts/networking/dhcpcd.exe @@ -20,6 +20,7 @@ . /etc/sysconfig/rc . $rc_functions +. /etc/init.d/networking/functions.network eval $(/usr/local/bin/readhash /var/ipfire/ethernet/settings) @@ -85,9 +86,70 @@ dhcpcd_down() fi } +# Called when dhcpcd relies on a third party to configure an IP address +dhcpcd_3rdparty() { + local qmi_device="$(qmi_find_device "${interface}")" + + if [ -n "${qmi_device}" ]; then + setup_qmi "${qmi_device}" || return $? + fi + + return 0 +} + +setup_qmi() { + local device="${1}" + + local address + local netmask + local gateway + local mtu=1500 + + local line + while read -r line; do + # Extract the value + value="${line#*: }" + + case "${line}" in + *IPv4\ address:*) + address="${value}" + ;; + *IPv4\ subnet\ mask:*) + netmask="${value}" + ;; + *IPv4\ gateway\ address:*) + gateway="${value}" + ;; + *MTU:*) + mtu="${value}" + ;; + esac + done <<< "$(qmicli --device="${device}" --wds-get-current-settings)" + + if [ -z "${address}" ] || [ -z "${netmask}" ] || [ -z "${gateway}" ]; then + logger -p "local0.info" -t "dhcpcd.exe[$$]" \ + "Could not retrieve all information from the QMI interface" + return 1 + fi + + # Flush any previous configuration + ip addr flush dev "${interface}" + + # Configure the IP address + ip addr add "${address}/${netmask}" dev "${interface}" + + # Configure the default route + ip route add default via "${gateway}" #mtu "${mtu}" + + return 0 +} + case "$reason" in BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT|STATIC) dhcpcd_up;; PREINIT|EXPIRE|FAIL|IPV4LL|NAK|RELEASE|STOP) dhcpcd_down;; +3RDPARTY) + dhcpcd_3rdparty + ;; *) logger -p "local0.info" -t "dhcpcd.exe[$$]" "Unhandled DHCP event: ${reason}" ;; diff --git a/src/initscripts/networking/functions.network b/src/initscripts/networking/functions.network index f246919de..9698424fd 100644 --- a/src/initscripts/networking/functions.network +++ b/src/initscripts/networking/functions.network @@ -169,3 +169,93 @@ dhcpcd_stop() { echo_failure fi } + +# QMI stuff + +qmi_find_device() { + local intf="${1}" + local _intf + + local path + for path in /dev/cdc-*; do + if [ -c "${path}" ]; then + _intf="$(qmicli --device="${path}" --device-open-proxy --get-wwan-iface)" + + # Check if the interface matches + if [ "${intf}" = "${_intf}" ]; then + echo "${path}" + return 0 + fi + fi + done + + # Nothing found + return 1 +} + +qmi_enable_rawip_mode() { + local intf="${1}" + + # Shut down the device first + ip link set "${intf}" down &>/dev/null + + echo "Y" > "/sys/class/net/${intf}/qmi/raw_ip" +} + +qmi_configure_apn() { + local device="${1}" + + # APN settings + local apn="${2}" + local auth="${3}" + local username="${4}" + local password="${5}" + + local args=( + # We only support IPv4 right now + "ip-type=4" + ) + + # Set APN + if [ -n "${apn}" ]; then + args+=( "apn=${apn}" ) + fi + + # Set auth + case "${auth}" in + PAP|CHAP) + args+=( "auth=${auth}" ) + ;; + esac + + # Set username + if [ -n "${username}" ]; then + args+=( "username=${username}" ) + fi + + # Set password + if [ -n "${password}" ]; then + args+=( "password=${password}" ) + fi + + local _args + + local arg + for arg in ${args[@]}; do + if [ -n "${_args}" ]; then + _args="${_args}," + fi + _args="${_args}${arg}" + done + + qmicli --device="${device}" --device-open-proxy \ + --wds-start-network="${_args}" \ + --client-no-release-cid +} + +qmi_reset() { + local device="${1}" + + qmicli --device="${device}" --device-open-proxy \ + --wds-reset +} diff --git a/src/initscripts/networking/red b/src/initscripts/networking/red index fc10e077a..7df61c1cf 100644 --- a/src/initscripts/networking/red +++ b/src/initscripts/networking/red @@ -210,6 +210,27 @@ case "${1}" in if [ "$TYPE" == "pptpatm" ]; then TYPE="pptp" fi + + # QMI + elif [ "$TYPE" = "qmi" ]; then + DEVICE="$(qmi_find_device "${RED_DEV}")" + + boot_mesg "Bringing up QMI on ${RED_DEV} (${DEVICE})..." + + # Enable RAW-IP mode + qmi_enable_rawip_mode "${RED_DEV}" + + # Configure APN + qmi_configure_apn "${DEVICE}" "${APN}" "${AUTH}" "${USERNAME}" "${PASSWORD}" + + # Set up the interface + ip link set "${RED_DEV}" up &>/dev/null + + # Start the DHCP client + dhcpcd_start "${RED_DEV}" --debug + + # Done + exit 0 fi if [ "$TYPE" == "vdsl" ]; then @@ -477,6 +498,21 @@ case "${1}" in run_subdir ${rc_base}/init.d/networking/red.down/ elif [ "$TYPE" == "PPPOE" ]; then + eval $(/usr/local/bin/readhash /var/ipfire/ppp/settings) + + if [ "${TYPE}" = "qmi" ]; then + boot_mesg "Bringing down the QMI interface ${RED_DEV}..." + DEVICE="$(qmi_find_device "${RED_DEV}")" + + # Stop the DHCP client on RED + dhcpcd_stop "${RED_DEV}" + + # Reset any QMI settings + qmi_reset "${DEVICE}" + + exit 0 + fi + boot_mesg "Bringing down the PPP interface ..." rm -f /var/ipfire/red/keepconnected killall -w -s TERM /usr/sbin/pppd 2>/dev/null