From: root Date: Sun, 19 May 2013 08:56:32 +0000 (+0200) Subject: Handle hotplugging of serial devices. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8fc530804121c2e895812f86f1c67b48f644e3a1;p=network.git Handle hotplugging of serial devices. --- diff --git a/functions.modem b/functions.modem index 1960ee64..b23d68b5 100644 --- a/functions.modem +++ b/functions.modem @@ -126,6 +126,16 @@ function __modem_chat_process_output() { done } +function modem_initialize() { + local device="${1}" + assert isset device + + log INFO "Initializing modem ${device}" + + # Reset the modem. + modem_chat "${device}" "${AT_INITIALIZE}" +} + # Exit codes of the sim_status function. EXIT_SIM_READY=0 EXIT_SIM_PIN=1 @@ -206,6 +216,40 @@ function modem_sim_unlock() { return ${ret} } +function modem_sim_auto_unlock() { + local device="${1}" + assert isset device + + local pin="${2}" + assert isset pin + + # Get the current state the SIM card is in. + modem_sim_status "${device}" &>/dev/null + local sim_status_code=$? + + case "${sim_status_code}" in + ${EXIT_SIM_READY}) + # Everything's fine. The SIM card is + # already unlocked. + return ${EXIT_OK} + ;; + ${EXIT_SIM_PIN}) + # Try to unlock the device. + if modem_sim_unlock ${device} ${pin}; then + return ${EXIT_OK} + else + return ${EXIT_ERROR} + fi + ;; + ${EXIT_SIM_PUK}) + log ERROR "SIM card is PUK locked. Please unlock manually." + return ${EXIT_ERROR} + ;; + esac + + return ${EXIT_ERROR} +} + # Returns the vendor of the modem. # For example: "huawei" function modem_get_manufacturer() { diff --git a/functions.serial b/functions.serial index 8540e293..aaa3e4ea 100644 --- a/functions.serial +++ b/functions.serial @@ -67,3 +67,18 @@ function serial_is_modem() { ;; esac } + +function serial_get_bus_type() { + local device="${1}" + assert isset device + + case "${device}" in + /dev/ttyUSB*) + print "usb" + return ${EXIT_OK} + ;; + esac + + print "unknown" + return ${EXIT_ERROR} +} diff --git a/functions.usb b/functions.usb new file mode 100644 index 00000000..2c6cc00e --- /dev/null +++ b/functions.usb @@ -0,0 +1,70 @@ +#!/bin/bash +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2013 IPFire Network Development Team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +function usb_device_find_by_tty() { + local tty="${1}" + assert isset tty + + # Strip /dev. + tty="$(basename "${tty}")" + + local path="/sys/bus/usb-serial/devices/${tty}" + + # Resolve symlink + path="$(readlink -m "${path}")" + + print "$(dirname "${path}")" + return ${EXIT_OK} +} + +function usb_device_list_interfaces() { + local path="${1}" + assert [ -d "${path}" ] + + local interface + for interface in ${path}/ep_*; do + [ -d "${interface}" ] || continue + print "${interface}" + done + + return ${EXIT_OK} +} + +function usb_device_get_interface_type() { + local interface="${1}" + assert isset interface + + fread "${interface}/type" +} + +function usb_device_has_interface_type_interrupt() { + local device="${1}" + assert isset device + + local interface type + while read -r interface; do + type="$(usb_device_get_interface_type "${interface}")" + + [ "${type}" = "Interrupt" ] && return ${EXIT_TRUE} + done <<< "$(usb_device_list_interfaces "${device}")" + + return ${EXIT_FALSE} +} diff --git a/udev/network-hotplug-serial b/udev/network-hotplug-serial new file mode 100755 index 00000000..ead51af6 --- /dev/null +++ b/udev/network-hotplug-serial @@ -0,0 +1,120 @@ +#!/bin/bash +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2011 Michael Tremer & Christian Schmidt # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +. /usr/lib/network/functions + +# Setup logging. +LOG_FACILITY="network-hotplug-serial" + +# Associated hooks. +ASSOCIATED_HOOKS="modem" + +# Read network configuration. +network_config_read + +log DEBUG "Called with ACTION='${ACTION}', DEVNAME='${DEVNAME}'." + +# If DEVNAME is not set, we cannot handle anything here and will +# exit silently. +isset DEVNAME || exit ${EXIT_OK} + +# Check if the udev environment variables are properly set. +assert isset ACTION + +case "${ACTION}" in + add|register) + # Check if the device node already exists. + if ! serial_exists ${DEVNAME}; then + log DEBUG "Device node ${DEVNAME} does not exist" + exit ${EXIT_ERROR} + fi + + # USB modems often register multiple serial interfaces. + # Some of them allow to send AT commands, some don't know. + # However, there is only one interface that can actually be used + # to connect to somewhere. This interface always runs in + # interrupt mode. Exit for all interfaces, not in this mode. + bus_type="$(serial_get_bus_type "${DEVNAME}")" + if [ "${bus_type}" = "usb" ]; then + # Find USB device. + usb_device="$(usb_device_find_by_tty "${DEVNAME}")" + + # Find an interface in interrupt mode. + if ! usb_device_has_interface_type_interrupt "${usb_device}"; then + log DEBUG "USB device has no interface in interrupt mode: ${DEVNAME}" + exit ${EXIT_OK} + fi + fi + + # Check if the device is actually a modem. + if ! serial_is_modem ${DEVNAME}; then + log DEBUG "${DEVNAME} does not look like a modem" + exit ${EXIT_OK} + fi + + # When we get here, the modem is alive and responds to + # AT commands. + log DEBUG "${DEVNAME} looks like a modem" + + # Initialize the modem here. Resets all established connections + # and so on. + modem_initialize "${DEVNAME}" + + # Unlock the SIM card if it has one. + if modem_sim_locked "${DEVNAME}"; then + log ERROR "SIM card is locked. Needs unlocking." + exit ${EXIT_OK} + fi + + # Try to find the zone configuration by the IMSI of the + # SIM card. + sim_imsi="$(modem_get_sim_imsi "${DEVNAME}")" + isset sim_imsi || exit ${EXIT_OK} + + for zone in $(zones_get_all); do + # XXX Check if the zone is enabled. + + # Skip unsupported hook types. + hook="$(zone_get_hook "${zone}")" + list_match "${hook}" ${ASSOCIATED_HOOKS} || continue + + # Read IMSI from zone configuration. + zone_imsi="$(zone_config_option "${zone}" IMSI)" + + # If IMSIs match, we start that zone. + if [ "${zone_imsi}" = "${sim_imsi}" ]; then + # Start the matching zone. + zone_up "${zone}" + break + fi + done + + exit ${EXIT_OK} + ;; + + remove|unregister) + # After the interface has been removed/unplugged, + # there are often daemons (like pppd) which need + # to be stopped. + ;; +esac + +exit ${EXIT_OK} diff --git a/udev/rules.d/60-net.rules b/udev/rules.d/60-net.rules index ab1779b3..e5d24b9b 100644 --- a/udev/rules.d/60-net.rules +++ b/udev/rules.d/60-net.rules @@ -6,3 +6,6 @@ ACTION=="add", SUBSYSTEM=="net", PROGRAM="/usr/lib/udev/network-hotplug-rename", # Handle all plugged-in devices. SUBSYSTEM=="net", RUN+="/usr/lib/udev/network-hotplug" + +# Handle all serial devices (like modems and so on...). +KERNEL=="ttyUSB*", RUN+="/usr/lib/udev/network-hotplug-serial"