]> git.ipfire.org Git - network.git/commitdiff
Enhanced modem support.
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 1 Jul 2012 15:42:31 +0000 (15:42 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 1 Jul 2012 15:42:31 +0000 (15:42 +0000)
This patch adds a very advanced solution for dialup
connection with serial modems (56k, UMTS, LTE and more).

13 files changed:
Makefile
functions.at [new file with mode: 0644]
functions.device
functions.modem [new file with mode: 0644]
functions.ppp
functions.routing
functions.serial [new file with mode: 0644]
hooks/zones/modem
hooks/zones/pppoe
man/network-device.8.in
network
ppp/dialer
ppp/ip-updown

index e118ae86b783dac6ae4fec5513ec4cf2980e8fe2..5cf67f246675291c2ee92b321103a220a5b87729 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -55,7 +55,7 @@ install:
        ln -svf ip-updown $(DESTDIR)$(sysconfdir)/ppp/ip-down
        ln -svf ip-updown $(DESTDIR)$(sysconfdir)/ppp/ipv6-up
        ln -svf ip-updown $(DESTDIR)$(sysconfdir)/ppp/ipv6-down
-       install -m 755 -v ppp/dialer $(DESTDIR)$(sysconfdir)/ppp
+       install -m 755 -v ppp/dialer $(DESTDIR)$(libdir)/network/
 
        # Install pppoe-server wrapper.
        install -m 755 ppp/pppoe-server $(DESTDIR)$(libdir)/network/
diff --git a/functions.at b/functions.at
new file mode 100644 (file)
index 0000000..b30c600
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/bash
+###############################################################################
+#                                                                             #
+# IPFire.org - A linux based firewall                                         #
+# Copyright (C) 2012  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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+# This file defines a bunch of default AT commands.
+
+# Initialize the modem.
+AT_INITIALIZE="+++ATZ"
+
+# Pulse dial.
+AT_PULSE_DIAL="ATDP"
+
+# Tone dial.
+AT_TONE_DIAL="ATDT"
+
+# Speaker settings.
+AT_SPEAKER_OFF="ATM0"
+AT_SPEAKER_ON="ATM1"
+
+# Hangup.
+AT_HANGUP="ATH"
index 29be51c08d66b6b855c0edbc1e6c95f831db75b2..ffff8a75ec8d8529964ae24975ccb7d4cd0b46f6 100644 (file)
@@ -65,7 +65,12 @@ function device_exists() {
        # If device name was not found, exit.
        [ -n "${device}" ] || return ${EXIT_ERROR}
 
-       [ -d "${SYS_CLASS_NET}/${device}" ]
+       # Check for a normal network device.
+       [ -d "${SYS_CLASS_NET}/${device}" ] && return ${EXIT_OK}
+
+       # If the check above, did not find a result,
+       # we check for serial devices.
+       serial_exists ${device}
 }
 
 function device_has_flag() {
@@ -171,6 +176,10 @@ function device_is_wireless() {
        [ -d "${SYS_CLASS_NET}/${device}/phy80211" ]
 }
 
+function device_is_serial() {
+       serial_exists $@
+}
+
 # Check if the device is a physical network interface
 function device_is_ethernet() {
        local device=${1}
@@ -221,6 +230,9 @@ function device_get_type() {
        elif device_is_ethernet ${device}; then
                echo "ethernet"
 
+       elif device_is_serial ${device}; then
+               echo "serial"
+
        else
                echo "unknown"
        fi
diff --git a/functions.modem b/functions.modem
new file mode 100644 (file)
index 0000000..8b78478
--- /dev/null
@@ -0,0 +1,530 @@
+#!/bin/bash
+###############################################################################
+#                                                                             #
+# IPFire.org - A linux based firewall                                         #
+# Copyright (C) 2012  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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+# Exit codes from the chat(8) command:
+CHAT_OK=0
+CHAT_INVALID=1
+CHAT_ERROR=2
+CHAT_TIMEOUT=3
+
+function modem_chat() {
+       local answer="OK"
+       local device
+       local timeout=2
+       local quiet="false"
+
+       while [ $# -gt 0 ]; do
+               case "${1}" in
+                       --timeout=*)
+                               timeout=$(cli_get_val ${1})
+                               ;;
+                       --answer=*)
+                               answer=$(cli_get_val ${1})
+                               ;;
+                       --quiet)
+                               quiet="true"
+                               ;;
+                       *)
+                               device=${1}
+                               shift; break
+                               ;;
+               esac
+               shift
+       done
+
+       assert serial_exists ${device}
+       assert serial_is_unlocked ${device}
+       assert isset answer
+       assert isset timeout
+
+       local command=$@
+
+       log DEBUG "Sending command to ${device}: ${command}"
+
+       (
+               # This cannot be run with -x.
+               set +x 2>/dev/null
+
+               chat -V -s -t ${timeout} "" "${command}" "${answer}" \
+                       < ${device} > ${device} || exit $?
+               print # Print line feed.
+       ) 2>&1 | __modem_chat_process_output "${answer}" ${quiet}
+
+       local ret=${PIPESTATUS[0]}
+
+       # Return the exit code of the chat command.
+       case "${ret}" in
+               ${CHAT_OK})
+                       return ${EXIT_OK}
+                       ;;
+
+               # When the timeout condition hit, the expected string has not
+               # been received in the given amount of time.
+               ${CHAT_TIMEOUT}|${CHAT_ERROR})
+                       return ${EXIT_ERROR}
+                       ;;
+
+               ${CHAT_INVALID})
+                       return ${EXIT_CONF_ERROR}
+                       ;;
+       esac
+
+       log WARNING "Received unknown exit code from chat(8): ${ret}"
+       return ${EXIT_ERROR}
+}
+
+function __modem_chat_process_output() {
+       local answer=${1}
+       local quiet=${2}
+
+       if enabled quiet; then
+               # Just throw everything away.
+               cat >/dev/null
+               return ${EXIT_OK}
+       fi
+
+       local counter=0
+
+       local line
+       while read line; do
+               log DEBUG "Output[${counter}]: ${line}"
+
+               # Also skip empty lines.
+               [ -n "${line}" ] || continue
+
+               # Ignore all volatile messages.
+               [ "${line:0:1}" = "^" ] && continue
+
+               counter=$(( ${counter} + 1 ))
+
+               # Skip the first line, because that's out command.
+               [ ${counter} -eq 1 ] && continue
+
+               # Filter out the expected answer.
+               [ "${line}" = "${answer}" ] && continue
+
+               # Print the rest.
+               print "${line}"
+       done
+}
+
+# Exit codes of the sim_status function.
+EXIT_SIM_READY=0
+EXIT_SIM_PIN=1
+EXIT_SIM_PUK=2
+EXIT_SIM_UNKNOWN=3
+
+function modem_sim_status() {
+       local device=${1}
+       assert isset device
+
+       local output
+       output=$(modem_chat ${device} "AT+CPIN?")
+       assert_check_retval $?
+
+       # Strip leading +CPIN: from the output.
+       output=${output#*: }
+
+       case "${output}" in
+               "READY")
+                       log DEBUG "${device}'s SIM is unlocked or doesn't need a PIN."
+                       return ${EXIT_SIM_READY}
+                       ;;
+               "SIM PIN")
+                       log DEBUG "${device}'s SIM is waiting for a PIN."
+                       return ${EXIT_SIM_PIN}
+                       ;;
+               "SIM PUK")
+                       log DEBUG "${device}'s SIM is PUK locked."
+                       return ${EXIT_SIM_PUK}
+                       ;;
+       esac
+
+       log WARNING "${device}: Invalid output of the AT+CPIN? command."
+       return ${EXIT_SIM_UNKNOWN}
+}
+
+function modem_sim_unlocked() {
+       local device=${1}
+       assert isset device
+
+       modem_sim_status "${device}"
+       local ret=$?
+
+       [ ${ret} -eq ${EXIT_SIM_READY} ] && return ${EXIT_TRUE} || return ${EXIT_FALSE}
+}
+
+function modem_sim_locked() {
+       modem_sim_unlocked $@ && return ${EXIT_FALSE} || return ${EXIT_TRUE}
+}
+
+function modem_sim_unlock() {
+       local device=${1}
+       assert isset device
+
+       local pin=${2}
+       assert isset pin
+
+       local command="AT+CPIN=${pin}"
+
+       local new_pin=${3}
+       if isset new_pin; then
+               command="${command},${new_pin}"
+       fi
+
+       modem_chat --timeout=2 --quiet "${device}" "${command}"
+
+       local ret=$?
+       case "${ret}" in
+               ${EXIT_OK})
+                       log INFO "Successfully unlocked SIM card on ${device}."
+                       ;;
+               *)
+                       log ERROR "Could not unlock SIM card on ${device}."
+                       ret=${EXIT_ERROR}
+                       ;;
+       esac
+
+       return ${ret}
+}
+
+# Returns the vendor of the modem.
+# For example: "huawei"
+function modem_get_manufacturer() {
+       local device=${1}
+       assert isset device
+
+       local output
+       output=$(modem_chat ${device} "AT+GMI")
+       assert_check_retval $?
+
+       [ "${output:0:1}" = "+" ] && output=${output#*: }
+       output=${output//\"/}
+
+       print "${output}"
+}
+
+function modem_get_model() {
+       local device=${1}
+       assert isset device
+
+       local output
+       output=$(modem_chat ${device} "AT+GMM")
+       assert_check_retval $?
+
+       [ "${output:0:1}" = "+" ] && output=${output#*: }
+       output=${output//\"/}
+
+       print "${output}"
+}
+
+function modem_get_software_version() {
+       local device=${1}
+       assert isset device
+
+       local output
+       output=$(modem_chat ${device} "AT+GMR")
+       assert_check_retval $?
+
+       [ "${output:0:1}" = "+" ] && output=${output#*: }
+       output=${output//\"/}
+
+       print "${output}"
+}
+
+function modem_get_sim_imsi() {
+       local device=${1}
+       assert isset device
+
+       # Make sure the SIM card is unlocked for this operation.
+       assert modem_sim_unlocked ${device}
+
+       modem_chat ${device} "AT+CIMI"
+}
+
+function modem_get_device_imei() {
+       local device=${1}
+       assert isset device
+
+       local output
+       output=$(modem_chat --timeout=1 ${device} "AT+CGSN") || assert_check_retval $?
+       local ret=$?
+
+       if [ ${ret} -eq ${EXIT_OK} ]; then
+               print "${output}"
+       fi
+
+       return ${ret}
+}
+
+function modem_is_mobile() {
+       local device=${1}
+       assert isset device
+
+       # Check if the device can return it's IMEI.
+       # If not, it's probably a serial 56k modem or something
+       # in that category.
+
+       modem_get_device_imei ${device} &>/dev/null
+}
+
+# Exit codes of the network registration function.
+EXIT_REG_REGISTERED_TO_HOME_NETWORK=0
+EXIT_REG_NOT_REGISTERED_NOT_SEARCHING=1
+EXIT_REG_NOT_REGISTERED_SEARCHING=2
+EXIT_REG_REGISTRATION_DENIED=3
+EXIT_REG_REGISTERED_ROAMING=4
+EXIT_REG_UNKNOWN=5
+
+function modem_get_network_registration() {
+       local device=${1}
+       assert isset device
+
+       # Make sure the SIM card is unlocked for this operation.
+       assert modem_sim_unlocked ${device}
+
+       local output
+       output=$(modem_chat ${device} "AT+CREG?")
+       assert_check_retval $?
+
+       # Cut out unneeded parts of the message.
+       output=${output#*: }
+
+       case "${output}" in
+               [0-2],[0-5])
+                       local status=${output%,*}
+
+                       # The status variable must be zero.
+                       [ ${status} -ne 0 ] && break
+
+                       local stat=${output#*,}
+                       case "${stat}" in
+                               0)
+                                       return ${EXIT_REG_NOT_REGISTERED_NOT_SEARCHING}
+                                       ;;
+                               1)
+                                       return ${EXIT_REG_REGISTERED_TO_HOME_NETWORK}
+                                       ;;
+                               2)
+                                       return ${EXIT_REG_NOT_REGISTERED_SEARCHING}
+                                       ;;
+                               3)
+                                       return ${EXIT_REG_REGISTRATION_DENIED}
+                                       ;;
+                               5)
+                                       return ${EXIT_REG_REGISTERED_ROAMING}
+                                       ;;
+                               *)
+                                       return ${EXIT_REG_UNKNOWN}
+                                       ;;
+                       esac
+                       ;;
+       esac
+
+       # Apparently the output of the CREG? command was not in
+       # the right format. The modem will be tried to be set to the
+       # right mode.
+
+       modem_set_network_registration ${device} 0
+       modem_get_network_registration ${device}
+}
+
+function modem_set_network_registration() {
+       local device=${1}
+       assert isset device
+
+       # Make sure the SIM card is unlocked for this operation.
+       assert modem_sim_unlocked ${device}
+
+       local mode=${2}
+       assert isset mode
+
+       modem_chat ${device} "AT+CREG=${mode}"
+}
+
+function modem_scan_networks() {
+       local device=${1}
+       assert isset device
+
+       # Make sure the SIM card is unlocked for this operation.
+       assert modem_sim_unlocked ${device}
+
+       local output
+       output=$(modem_chat --timeout=60 ${device} "AT+COPS=?")
+       assert_check_retval $?
+
+       output=${output#*: }
+
+       # XXX the output is not very nice to parse.
+}
+
+function __modem_get_network_operator() {
+       local device=${1}
+       assert isset device
+
+       # Make sure the SIM card is unlocked for this operation.
+       assert modem_sim_unlocked ${device}
+
+       local argument=${2}
+       assert isset argument
+
+       local output
+       output=$(modem_chat ${device} "AT+COPS?")
+       assert_check_retval $?
+
+       output=${output#*: }
+
+       local mode format operator act
+       read mode format operator act <<< "${output//,/ }"
+
+       # Remove all " from the operator string.
+       operator=${operator//\"/}
+
+       print "${!argument}"
+       return ${EXIT_OK}
+}
+
+function modem_get_network_operator() {
+       local device=${1}
+       assert isset device
+
+       __modem_get_network_operator ${device} operator
+}
+
+# Exit codes of the network operator mode function.
+EXIT_OPMODE_GSM=0
+EXIT_OPMODE_COMPACTGSM=1
+EXIT_OPMODE_GSM_WITH_EGPRS=2
+EXIT_OPMODE_UMTS=3
+EXIT_OPMODE_UMTS_WITH_HSDPA=4
+EXIT_OPMODE_UMTS_WITH_HSUPA=5
+EXIT_OPMODE_UMTS_WITH_HSDPA_AND_HSUPA=6
+EXIT_OPMODE_UNKNOWN=7
+
+function modem_get_network_mode() {
+       local device=${1}
+       assert isset device
+
+       local output
+       output=$(__modem_get_network_operator ${device} act)
+       assert_check_retval $?
+
+       case "${output}" in
+               0)
+                       print "GSM"
+                       return ${EXIT_OPMODE_GSM}
+                       ;;
+               1)
+                       print "Compact GSM"
+                       return ${EXIT_OPMODE_COMPACTGSM}
+                       ;;
+               2)
+                       print "UMTS"
+                       return ${EXIT_OPMODE_UMTS}
+                       ;;
+               3)
+                       print "UMTS with HSDPA"
+                       return ${EXIT_OPMODE_UMTS_WITH_HSDPA}
+                       ;;
+               4)
+                       print "UMTS with HSUPA"
+                       return ${EXIT_OPMODE_UMTS_WITH_HSUPA}
+                       ;;
+               5)
+                       print "UMTS with HSDPA and HSUPA"
+                       return ${EXIT_OPMODE_UMTS_WITH_HSDPA_AND_HSUPA}
+                       ;;
+               *)
+                       print "Unknown"
+                       return ${EXIT_OPMODE_UNKNOWN}
+                       ;;
+       esac
+}
+
+function __modem_get_signal_quality() {
+       local device=${1}
+       assert isset device
+
+       # Make sure the SIM card is unlocked for this operation.
+       assert modem_sim_unlocked ${device}
+
+       local argument=${2}
+       assert isset argument
+
+       local output
+       output=$(modem_chat ${device} "AT+CSQ")
+       assert_check_retval $?
+
+       output=${output#*: }
+
+       case "${output}" in
+               *,*)
+                       local rssi=${output%,*}
+                       local ber=${output#*,}
+
+                       print "${!argument}"
+                       return ${EXIT_OK}
+                       ;;
+               *)
+                       log ERROR "Unknown format for AT+CSQ: ${device}: ${output}"
+                       ;;
+       esac
+
+       return ${EXIT_ERROR}
+}
+
+function modem_get_signal_quality() {
+       local device=${1}
+       assert isset device
+
+       local rssi
+       rssi=$(__modem_get_signal_quality ${device} rssi)
+       assert_check_retval $?
+
+       isset rssi || return ${EXIT_ERROR}
+
+       # 99 indicates an unknown signal strength.
+       [ ${rssi} -eq 99 ] && return ${EXIT_UNKNOWN}
+
+       local dbm=$(( ${rssi} * 2 ))
+       dbm=$(( ${dbm} - 113 ))
+
+       print "%d" "${dbm}"
+       return ${EXIT_OK}
+}
+
+function modem_get_bit_error_rate() {
+       local device=${1}
+       assert isset device
+
+       local ber
+       ber=$(__modem_get_signal_quality ${device} ber)
+       assert_check_retval $?
+
+       isset ber || return ${EXIT_ERROR}
+
+       # 99 indicates that the bit error rate could not be detected or
+       # is unknown for some other reason.
+       [ ${ber} -eq 99 ] && return ${EXIT_UNKNOWN}
+
+       print "%d" "${ber}"
+       return ${EXIT_OK}
+}
index 640b0cac830915271a713006e84ad528391750c6..29a4c9658a975d2f5a65d212b303205ebe40c532 100644 (file)
@@ -45,6 +45,9 @@ function pppd_start() {
                5)
                        error "pppd terminated"
                        ;;
+               16)
+                       error "pppd: Link terminated by modem"
+                       ;;
                19)
                        error "pppd: Authentication failed"
                        ;;
@@ -214,14 +217,18 @@ function pppd_write_config() {
        assert isset file
 
        local auth
+       local baudrate
+       local connect_cmd
        local default_asyncmap="true"
        local interface
        local lcp_echo_failure=3
        local lcp_echo_interval=20
        local linkname
        local mtu mru
+       local password
        local plugin plugin_options
-       local user
+       local serial="false"
+       local username
        local value
 
        while [ $# -gt 0 ]; do
@@ -229,6 +236,13 @@ function pppd_write_config() {
                        --auth=*)
                                auth=$(cli_get_val ${1})
                                ;;
+                       --baudrate=*)
+                               baudrate=$(cli_get_val ${1})
+                               assert isoneof baudrate ${SERIAL_BAUDRATES}
+                               ;;
+                       --connect-command=*)
+                               connect_cmd=$(cli_get_val ${1})
+                               ;;
                        # Enable or disable the use of the default asyncmap.
                        --default-asyncmap=*)
                                value=$(cli_get_val ${1})
@@ -268,14 +282,24 @@ function pppd_write_config() {
                        --mru=*)
                                mru=$(cli_get_val ${1})
                                ;;
+                       --password=*)
+                               password=$(cli_get_val ${1})
+                               ;;
                        --plugin=*)
                                plugin=$(cli_get_val ${1})
                                ;;
                        --plugin-options=*)
                                plugin_options=$(cli_get_val ${1})
                                ;;
-                       --user=*)
-                               user=$(cli_get_val ${1})
+                       # Sets if the modem is a serial device.
+                       --serial=*)
+                               serial=$(cli_get_val ${1})
+                               ;;
+                       --serial-device=*)
+                               serial_device=$(cli_get_val ${1})
+                               ;;
+                       --username=*)
+                               username=$(cli_get_val ${1})
                                ;;
                        *)
                                log WARNING "Unhandled argument: ${1}"
@@ -297,6 +321,14 @@ function pppd_write_config() {
                fi
        fi
 
+       if enabled serial; then
+               assert isset serial_device
+               assert [ -c "${serial_device}" ]
+       fi
+
+       # Set the user credentials.
+       ppp_secret "${username}" "${password}"
+
        # Write the configuration header.
        mkdir -p $(dirname ${file}) 2>/dev/null
        config_header "PPP daemon configuration file" > ${file}
@@ -304,8 +336,12 @@ function pppd_write_config() {
        # At first, set the name of the link.
        print "linkname ${linkname}\n" >> ${file}
 
-       # Configure the interface name.
-       print "# Interface name\nifname ${interface}\n" >> ${file}
+       # Configure the interface/zone name.
+       (
+               print "# Interface name"
+               print "ifname ${interface}"
+               print
+       ) >> ${file}
 
        # Plugin settings
        if isset plugin; then
@@ -317,10 +353,10 @@ function pppd_write_config() {
        fi
 
        # User authentication
-       if isset user; then
+       if isset username; then
                (
                        print "# User authentication"
-                       print "user ${user}"
+                       print "user ${username}"
 
                        print "noauth"
                        if isset auth; then
@@ -342,6 +378,26 @@ function pppd_write_config() {
                ) >> ${file}
        fi
 
+       if enabled serial; then
+               (
+                       print "# Serial modem settings"
+                       print "${serial_device} ${baudrate}"
+                       print "crtscts"
+                       print "lock"
+                       print "modem"
+                       print
+               ) >> ${file}
+
+               # Connect command
+               if isset connect_cmd; then
+                       (
+                               print "# Connect command"
+                               print "connect \"${connect_cmd}\""
+                               print
+                       ) >> ${file}
+               fi
+       fi
+
        # Default asyncmap.
        if enabled default_asyncmap; then
                (
index 10e12828ee8ede8a5a97ecf37fa904eaf86b05e0..9f0e013c8b86d73556eac8a70d627ba41fe66b66 100644 (file)
@@ -50,12 +50,13 @@ function routing_default_update() {
                        if [ "$(routing_db_get ${zone} ${proto} active)" = "1" ]; then
                                gateway=$(routing_db_get ${zone} ${proto} remote-ip-address)
 
-                               assert device_exists ${zone}
+                               # Go on if the device is not there anymore.
+                               device_exists ${zone} || continue
 
                                # If we have got a Point-to-Point device, we will directly send all
                                # packets into the pipe.
                                if device_is_ptp ${zone}; then
-                                       routes="${routes} dev ${zone}"
+                                       routes="${routes} nexthop dev ${zone}"
 
                                # On other devices, we will use the gateway if we got one.
                                elif isset gateway; then
diff --git a/functions.serial b/functions.serial
new file mode 100644 (file)
index 0000000..8540e29
--- /dev/null
@@ -0,0 +1,69 @@
+#!/bin/bash
+###############################################################################
+#                                                                             #
+# IPFire.org - A linux based firewall                                         #
+# Copyright (C) 2012  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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+# This is a list of baudrates that are supported.
+SERIAL_BAUDRATES="921600 460800 230400 115200 57600 38400 19200 9600"
+
+function serial_exists() {
+       local device=${1}
+
+       [ -c "${device}" ]
+}
+
+function serial_is_locked() {
+       local device=${1}
+       assert isset device
+
+       device=$(basename ${device})
+
+       local dir
+       for dir in /var/lock /var/lock/ppp; do
+               [ -e "${dir}/LCK..${device}" ] \
+                       && return ${EXIT_TRUE}
+       done
+
+       return ${EXIT_FALSE}
+}
+
+function serial_is_unlocked() {
+       serial_is_locked ${device} \
+               && return ${EXIT_FALSE} || return ${EXIT_TRUE}
+}
+
+function serial_is_modem() {
+       local device=${1}
+       assert isset device
+
+       modem_chat --timeout=2 "${device}" "AT" &>/dev/null
+       local ret=$?
+
+       case "${ret}" in
+               ${EXIT_OK})
+                       return ${EXIT_TRUE}
+                       ;;
+               ${EXIT_ERROR})
+                       return ${EXIT_FALSE}
+                       ;;
+               *)
+                       return ${EXIT_UNKNOWN}
+                       ;;
+       esac
+}
index 472988b68bf90b03639e99ffededfcc0a946c65a..9dc2b64c2d782f713bf5ef24688dc5da0ed2d21e 100755 (executable)
 
 . /lib/network/header-zone
 
-HOOK_SETTINGS="HOOK AUTH DEVICE BAUDRATE LINKNAME USER SECRET PEERDNS DEFAULTROUTE MTU"
+# Modems support all authentication methods, that pppd does support.
+MODEM_ALLOWED_AUTH_METHODS="${PPP_ALLOWED_AUTH_METHODS}"
 
+HOOK_SETTINGS="HOOK"
+
+# Access Point Name.
+APN=
+HOOK_SETTINGS="${HOOK_SETTINGS} APN"
+
+# Sets the authentication algortihm that must be used.
 AUTH=
+HOOK_SETTINGS="${HOOK_SETTINGS} AUTH"
+
+# Baudrate.
 BAUDRATE=921600
-DEFAULTROUTE=1
+HOOK_SETTINGS="${HOOK_SETTINGS} BAUDRATE"
+
+# The device name of the serial device.
+# XXX how can we make sure that this does not change all the time?
 DEVICE=
-LINKNAME="$(uuid)"
+HOOK_SETTINGS="${HOOK_SETTINGS} DEVICE"
+
+# A monitor device.
+# Send AT commands to this device, when the primary device is
+# connected.
+MONITOR_DEVICE=
+HOOK_SETTINGS="${HOOK_SETTINGS} MONITOR_DEVICE"
+
+# Maximum transmission unit.
 MTU=1492
-PEERDNS=1
-SECRET=
-USER=
+HOOK_SETTINGS="${HOOK_SETTINGS} MTU"
 
-MODEM_ALLOWED_AUTHS="chap pap"
+# User credentials.
+USERNAME=
+PASSWORD=
+HOOK_SETTINGS="${HOOK_SETTINGS} USERNAME PASSWORD"
 
-function pppd_pid() {
-       local zone=${1}
-       shift
+# PIN code.
+PIN=
+HOOK_SETTINGS="${HOOK_SETTINGS} PIN"
 
-       cat /var/run/${zone}.pid 2>/dev/null
-}
+# Phone number.
+PHONE_NUMBER=
+HOOK_SETTINGS="${HOOK_SETTINGS} PHONE_NUMBER"
 
 function _check() {
-       assert isset USER
-       assert isset SECRET
-       assert isset LINKNAME
-       assert isset DEFAULTROUTE
-       assert isset PEERDNS
        assert isset DEVICE
+       assert isset PHONE_NUMBER
+
+       # Make sure the PIN code is an integer, when set.
+       if isset PIN; then
+               assert isinteger PIN
+               assert [ ${#PIN} -ge 4 ]
+               assert [ ${#PIN} -le 8 ]
+       fi
 
-       assert isbool DEFAULTROUTE
-       assert isbool PEERDNS
-       assert isinteger BAUDRATE
+       assert isoneof BAUDRATE ${SERIAL_BAUDRATES}
 
-       isset AUTH && assert isoneof AUTH ${MODEM_ALLOWED_AUTHS}
+       isset AUTH && assert isoneof AUTH ${MODEM_ALLOWED_AUTH_METHODS}
 }
 
 function _parse_cmdline() {
        local value
 
        while [ $# -gt 0 ]; do
-               case "$1" in
-                       --user=*)
-                               USER=${1#--user=}
+               case "${1}" in
+                       --apn=*)
+                               APN=$(cli_get_val ${1})
                                ;;
-                       --secret=*)
-                               SECRET=${1#--secret=}
+                       --auth=*)
+                               AUTH=$(cli_get_val ${1})
                                ;;
-                       --linkname=*)
-                               LINKNAME=${1#--name=}
+                       --baudrate=*)
+                               BAUDRATE=$(cli_get_val ${1})
+                               assert isoneif "${BAUDRATE}" ${SERIAL_BAUDRATES}
+                               ;;
+                       --device=*)
+                               DEVICE=$(cli_get_val ${1})
+                               ;;
+                       --monitor-device=*)
+                               MONITOR_DEVICE=$(cli_get_val ${1})
                                ;;
                        --mtu=*)
-                               MTU=${1#--mtu=}
-                               ;;
-                       --defaultroute=*)
-                               value=${1#--defaultroute=}
-                               if enabled value; then
-                                       DEFAULTROUTE=1
-                               else
-                                       DEFAULTROUTE=0
-                               fi
+                               MTU=$(cli_get_val ${1})
+                               assert isinteger ${MTU}
                                ;;
-                       --dns=*)
-                               value=${1#--dns=}
-                               if enabled value; then
-                                       PEERDNS=1
-                               else
-                                       PEERDNS=0
-                               fi
+                       --password=*)
+                               PASSWORD=$(cli_get_val ${1})
                                ;;
-                       --auth=*)
-                               AUTH=${1#--auth=}
+                       --phone-number=*)
+                               PHONE_NUMBER=$(cli_get_val ${1})
                                ;;
-                       --device=*)
-                               DEVICE=${1#--device=}
+                       --pin=*)
+                               PIN=$(cli_get_val ${1})
                                ;;
-                       --baudrate=*)
-                               BAUDRATE=${1#--baudrate=}
+                       --username=*)
+                               USERNAME=$(cli_get_val ${1})
                                ;;
                        *)
-                               echo "Unknown option: $1" >&2
+                               echo "Unknown argument: ${1}" >&2
                                exit ${EXIT_ERROR}
                                ;;
                esac
@@ -110,78 +130,56 @@ function _parse_cmdline() {
 
 function _up() {
        local zone=${1}
-       shift
-
        assert isset zone
 
+       # Load configuration file.
        zone_config_read ${zone}
 
-       assert [ -e "/dev/${DEVICE}" ]
-
-       # Creating necessary files
-       # XXX must be PPP_RUN
-       [ -d "${RED_RUN}/${LINKNAME}" ] || mkdir -p ${RED_RUN}/${LINKNAME}
-
-       ppp_secret "${USER}" "${SECRET}"
-
-       cat <<EOF >${RED_RUN}/${LINKNAME}/options
-# Naming options
-ifname ${zone}
-name ${LINKNAME}
-linkname ${LINKNAME}
-
-# Device configuration
-/dev/${DEVICE} ${BAUDRATE}
-connect "/usr/sbin/chat -v -f /etc/ppp/dialer"
-lock
-modem
-crtscts
-
-# User configuration
-user ${USER}
-
-$(enabled PEERDNS && echo "usepeerdns")
-$(enabled DEFAULTROUTE && echo "defaultroute")
+       # If we have got a PIN, we try to unlock the device first.
+       if isset PIN; then
+               modem_sim_status ${DEVICE} &>/dev/null
+               local sim_status_code=$?
 
-noauth
-$(isset AUTH && echo "require-${AUTH}")
-
-noipdefault
-
-# Maximum transmission/receive unit
-mtu ${MTU}
-mru ${MTU}
-
-# Disable the compression
-noccp noaccomp nodeflate nopcomp novj novjccomp nobsdcomp nomppe
-
-updetach debug
-EOF
-
-       pppd_exec file ${RED_RUN}/${LINKNAME}/options
-
-       local ret=$?
+               case "${sim_status_code}" in
+                       ${EXIT_SIM_READY})
+                               # Everything's fine. The SIM card is
+                               # already unlocked.
+                               ;;
+                       ${EXIT_SIM_PIN})
+                               # Try to unlock the device.
+                               if ! modem_sim_unlock ${DEVICE} ${PIN}; then
+                                       # Reset the PIN setting.
+                                       PIN=""
+                                       config_write $(zone_dir ${zone})/settings ${HOOK_SETTINGS}
+
+                                       error "Could not unlock the SIM card. Removing PIN from settings."
+                                       exit ${EXIT_ERROR}
+                               fi
+                               ;;
+                       ${EXIT_SIM_PUK})
+                               error "SIM card is PUK locked. Please unlock manually."
+                               exit ${EXIT_ERROR}
+                               ;;
+               esac
 
-       # Get exit code from ppp daemon and handle it:
-       case "${ret}" in
-               0)
-                       log DEBUG "pppd detached successfully"
-                       exit ${EXIT_OK}
-                       ;;
-       esac
+       # For mobile devices, check if a PIN is required although none is set.
+       elif modem_is_mobile ${DEVICE} && modem_sim_locked ${DEVICE}; then
+               error "The SIM card is locked. Please configure the PIN code."
+               exit ${EXIT_ERROR}
+       fi
 
-       error_log "pppd exited with unknown exit code '${ret}'"
+       # Start the PPP daemon.
+       pppd_start ${zone}
 
-       exit ${EXIT_ERROR}
+       exit ${EXIT_OK}
 }
 
 function _down() {
        local zone=${1}
-       shift
+       assert isset zone
 
-       # Kill pppd
-       # XXX very ugly
-       kill $(pppd_pid ${zone}) &>/dev/null
+       # Stop the PPP daemon.
+       pppd_start ${zone}
 
        exit ${EXIT_OK}
 }
@@ -194,19 +192,19 @@ function _status() {
 
        zone_config_read ${zone}
 
-       cli_headline "  Configuration:"
-       printf "${DEVICE_PRINT_LINE1}" "User:" "${USER}"
-       printf "${DEVICE_PRINT_LINE1}" "Secret:" "<hidden>"
-       echo
-       printf "${DEVICE_PRINT_LINE1}" "MTU:" "${MTU}"
-       printf "${DEVICE_PRINT_LINE1}" "Use default route?" "$(enabled DEFAULTROUTE && echo "enabled" || echo "disabled")"
-       printf "${DEVICE_PRINT_LINE1}" "Use peer DNS?" "$(enabled PEERDNS && echo "enabled" || echo "disabled")"
-       echo
-       cli_headline "  Ports:"
-       zone_ports_status ${zone}
-       if [ -z "$(zone_get_ports ${zone})" ]; then
-               echo -e "    ${COLOUR_WARN}No ports attached. Won't be able to start.${COLOUR_NORMAL}"
+       cli_headline 2 "Configuration"
+       cli_print_fmt1 2 "Username" "${USERNAME}"
+       cli_print_fmt1 2 "Password" "<hidden>"
+       cli_space
+
+       cli_headline 2 "Device settings"
+       cli_print_fmt1 2 "Device" "${DEVICE}"
+       if isset MONITOR_DEVICE; then
+               cli_print_fmt1 2 "Monitor device" "${MONITOR_DEVICE}"
        fi
+       cli_print_fmt1 2 "Baudrate" "${BAUDRATE}"
+       cli_print_fmt1 2 "MTU/MRU" "${MTU}"
+       cli_space
 
        # Exit if zone is down
        if ! zone_is_up ${zone}; then
@@ -214,16 +212,90 @@ function _status() {
                exit ${EXIT_ERROR}
        fi
 
+       cli_headline 2 "Carrier network"
+
+       # If the device and the monitor device are both locked,
+       # we cannot show any carrier information.
+       local device dev
+       for dev in ${DEVICE} ${MONITOR_DEVICE}; do
+               if ! serial_exists ${dev}; then
+                       continue
+               fi
+               if serial_is_locked ${dev}; then
+                       continue
+               fi
+
+               device=${dev}
+       done
+
+       if isset device; then
+               cli_print_fmt1 2 "Operator" \
+                       "$(modem_get_network_operator ${device})"
+               cli_print_fmt1 2 "SIM IMSI" \
+                       "$(modem_get_sim_imsi ${device})"
+               cli_print_fmt1 2 "Mode" \
+                       "$(modem_get_network_mode ${device})"
+               cli_print_fmt1 2 "Signal strength" \
+                       "$(modem_get_signal_quality ${device}) dBm"
+               local ber=$(modem_get_bit_error_rate ${device})
+               isset ber || ber="unknown"
+               cli_print_fmt1 2 "Bit error rate" "${ber}"
+       else
+               cli_print 2 "Device is locked."
+       fi
+       cli_space
+
        # XXX display time since connection started
 
-       cli_headline "    Point-to-Point-over-Ethernet protocol:"
-       echo "        IP-Address            : $(routing_db_get ${zone} local-ip-address)"
-       echo "        Gateway               : $(routing_db_get ${zone} remote-ip-address)"
-       echo "        DNS-Server            : $(routing_db_get ${zone} dns)"
-       echo
-       echo "        MAC-Remote            : $(routing_db_get ${zone} remote-address)"
-       echo
-       echo "        MTU                   : $(device_get_mtu ${zone})"
-       echo # Empty line
+       cli_headline 2 "Point-to-Point-over-Ethernet protocol"
+       local proto
+       for proto in ${IP_SUPPORTED_PROTOCOLS}; do
+               routing_db_exists ${zone} ${proto} || continue
+
+               local headline
+               case "${proto}" in
+                       ipv6)
+                               headline="Internet Protocol Version 6"
+                               ;;
+                       ipv4)
+                               headline="Internet Protocol Version 4"
+                               ;;
+                       *)
+                               headline="Unkown protocol"
+                               ;;
+               esac
+               cli_headline 3 "${headline}"
+
+               cli_print_fmt1 3 "IP address"  "$(routing_db_get ${zone} ${proto} local-ip-address)"
+               cli_print_fmt1 3 "Gateway"     "$(routing_db_get ${zone} ${proto} remote-ip-address)"
+               cli_print_fmt1 3 "DNS servers" "$(routing_db_get ${zone} ${proto} dns)"
+               cli_space
+       done
+
+       exit ${EXIT_OK}
+}
+
+function _ppp_write_config() {
+       local zone=${1}
+       assert isset zone
+
+       local file=${2}
+       assert isset file
+
+       # Read in the configuration files.
+       zone_config_read ${zone}
+
+       pppd_write_config ${file} \
+               --interface="${zone}" \
+               --username="${USERNAME}" \
+               --password="${PASSWORD}" \
+               --mtu="${MTU}" \
+               --auth="${AUTH}" \
+               \
+               --serial="true" \
+               --serial-device="${DEVICE}" \
+               --baudrate="${BAUDRATE}" \
+               --connect-command="/usr/lib/network/dialer ${zone}"
+
        exit ${EXIT_OK}
 }
index a219bfdcf7ed3438dbc87f3fd29a3a9302268165..dd44fa618e67845c43db2b8ab9003d99c35685b8 100755 (executable)
@@ -215,9 +215,6 @@ function _ppp_write_config() {
        # Read in the configuration files.
        zone_config_read ${zone}
 
-       # Set the user credentials.
-       ppp_secret "${USERNAME}" "${PASSWORD}"
-
        # Prepare the command line options for the pppoe plugin.
        local plugin_options
 
@@ -236,12 +233,13 @@ function _ppp_write_config() {
 
        pppd_write_config ${file} \
                --interface="${zone}" \
-               --user="${USERNAME}" \
+               --username="${USERNAME}" \
+               --password="${PASSWORD}" \
                --mtu="${MTU}" \
                --auth="${AUTH}" \
                \
                --plugin="${PPPOE_PLUGIN}" \
                --plugin-options="${plugin_options}"
 
-       return ${EXIT_OK}
+       exit ${EXIT_OK}
 }
index bb65e00bfb2a791787bcf675ca2f21fdcef094d0..3e0075626f89f0e002b5ceffd90e6f15d7a73fe1 100644 (file)
@@ -4,7 +4,7 @@
 network-device \- Network Configuration Control Program
 
 .SH SYNOPSIS
-\fBnetwork [OPTIONS] device <device> [status|discover] ...\fR
+\fBnetwork [OPTIONS] device <device> [status|discover|unlock] ...\fR
 
 .SH DESCRIPTION
 By the device subcommands, it is very easy to get status information
@@ -30,6 +30,15 @@ for what the device should be used.
 .RE
 .PP
 
+\fB<device> unlock\fR
+.RS 4
+This command will unlock the SIM card in a modem. Only serial devices
+are supported which are the most UMTS or 3G modems.
+.PP
+For the PIN or PUK code, the user will be prompted.
+.RE
+.PP
+
 .SH SEE ALSO
 network(8)
 
diff --git a/network b/network
index 808d2cd6f398f0939abff1eff3d618df84cf5dc4..ef2064e7cbd94ba25b158f0b9140e225f35f72cb 100755 (executable)
--- a/network
+++ b/network
@@ -50,6 +50,11 @@ function cli_config() {
 }
 
 function cli_device() {
+       if cli_help_requested $@; then
+               cli_show_man network-device
+               exit ${EXIT_OK}
+       fi
+
        local device=${1}
        local action=${2}
        shift 2
@@ -68,6 +73,9 @@ function cli_device() {
                status)
                        cli_device_status ${device}
                        ;;
+               unlock)
+                       cli_device_serial_unlock ${device} $@
+                       ;;
                *)
                        cli_show_man network-device
                        ;;
@@ -80,12 +88,22 @@ function cli_device_status() {
        local device=${1}
        assert device_exists ${device}
 
+       # Disable debugging output here.
+       local log_disable_stdout=${LOG_DISABLE_STDOUT}
+       LOG_DISABLE_STDOUT="true"
+
        # Save the type of the device for later.
        local type=$(device_get_type ${device})
 
        cli_headline 1 "Device status: ${device}"
        cli_print_fmt1 1 "Name"         "${device}"
 
+       # Handle serial devices.
+       if [ "${type}" = "serial" ]; then
+               cli_device_status_serial ${device}
+               return $?
+       fi
+
        # Print the device status.
        device_is_up ${device} &>/dev/null
        local status=$?
@@ -138,6 +156,69 @@ function cli_device_status() {
                cli_space
        fi
 
+       # Reset the logging level.
+       LOG_DISABLE_STDOUT=${log_disable_stdout}
+}
+
+function cli_device_status_serial() {
+       local device=${1}
+       assert device_is_serial ${device}
+
+       serial_is_locked ${device} &>/dev/null
+       local locked=$?
+
+       cli_print_fmt1 1 "Locked" "$(cli_print_bool ${locked})"
+       cli_space
+
+       # Cannot go on when the device is locked.
+       [ ${locked} -eq ${EXIT_TRUE} ] && return ${EXIT_OK}
+
+       cli_print_fmt1 1 "Manufacturer" \
+               "$(modem_get_manufacturer ${device})"
+       cli_print_fmt1 1 "Model" \
+               "$(modem_get_model ${device})"
+       cli_print_fmt1 1 "Software version" \
+               "$(modem_get_software_version ${device})"
+
+       if modem_is_mobile ${device}; then
+               cli_print_fmt1 1 "IMEI" \
+                       "$(modem_get_device_imei ${device})"
+               cli_space
+
+               cli_headline 2 "Network status"
+               modem_sim_status ${device} &>/dev/null
+               local sim_status_code=$?
+
+               local sim_status="unknown"
+               case "${sim_status_code}" in
+                       ${EXIT_SIM_READY})
+                               sim_status="SIM ready"
+                               ;;
+                       ${EXIT_SIM_PIN})
+                               sim_status="PIN locked"
+                               ;;
+                       ${EXIT_SIM_PUK})
+                               sim_status="PUK locked"
+                               ;;
+               esac
+               cli_print_fmt1 2 "SIM status" "${sim_status}"
+
+               if [ ${sim_status_code} -eq ${EXIT_SIM_READY} ]; then
+                       cli_print_fmt1 2 "IMSI" \
+                               "$(modem_get_sim_imsi ${device})"
+                       cli_print_fmt1 2 "Operator" \
+                               "$(modem_get_network_operator ${device})"
+                       cli_print_fmt1 2 "Mode" \
+                               "$(modem_get_network_mode ${device})"
+                       cli_print_fmt1 2 "Signal quality" \
+                               "$(modem_get_signal_quality ${device}) dBm"
+
+                       local ber=$(modem_get_bit_error_rate ${device})
+                       isset ber || ber="unknown"
+                       cli_print_fmt1 2 "Bit Error Rate" "${ber}"
+               fi
+       fi
+       cli_space
 }
 
 function cli_device_discover() {
@@ -211,6 +292,92 @@ function cli_device_discover() {
        [ "${up}" = "1" ] || device_set_down ${device}
 }
 
+function cli_device_serial_unlock() {
+       if cli_help_requested $@; then
+               cli_show_man network-device
+               exit ${EXIT_OK}
+       fi
+
+       local device=${1}
+       assert isset device
+
+       if ! device_is_serial ${device}; then
+               error "${device} is not a serial device."
+               error "Unlocking is only supported for serial devices."
+               exit ${EXIT_ERROR}
+       fi
+
+       # Read the current state of the SIM card.
+       modem_sim_status ${device} &>/dev/null
+       local sim_status_code=$?
+
+       # If the SIM card is already unlocked, we don't need to do anything.
+       if [ ${sim_status_code} -eq ${EXIT_SIM_READY} ]; then
+               print "The SIM card is already unlocked."
+               exit ${EXIT_OK}
+
+       # If the SIM card is in an unknown state, we cannot do anything.
+       elif [ ${sim_status_code} -eq ${EXIT_SIM_UNKNOWN} ]; then
+               error "The SIM card is in an unknown state."
+               exit ${EXIT_ERROR}
+       fi
+
+       # Ask for the code.
+       local code=${2}
+       local require_new_pin="false"
+       local new_pin
+
+       while ! isinteger code; do
+               local message
+               case "${sim_status_code}" in
+                       ${EXIT_SIM_PIN})
+                               message="Please enter PIN:"
+                               ;;
+                       ${EXIT_SIM_PUK})
+                               message="Please enter PUK:"
+                               require_new_pin="true"
+                               ;;
+               esac
+               assert isset message
+
+               echo -n "${message} "
+               read -s code
+               echo # Print newline.
+
+               if enabled require_new_pin; then
+                       local i new_pin2
+                       for i in 0 1; do
+                               case "${i}" in
+                                       0)
+                                               message="Please enter a new PIN code:"
+                                               ;;
+                                       1)
+                                               message="Please confirm the new PIN code:"
+                                               ;;
+                               esac
+
+                               echo -n "${message} "
+                               read -s new_pin2
+                               echo # Print newline.
+
+                               if [ -n "${new_pin}" ]; then
+                                       if [ "${new_pin}" != "${new_pin2}" ]; then
+                                               error "The entered PIN codes did not match."
+                                               exit ${EXIT_ERROR}
+                                       fi
+                               else
+                                       new_pin=${new_pin2}
+                               fi
+                       done
+               fi
+       done
+
+       # Trying to unlock the SIM card.
+       modem_sim_unlock ${device} ${code} ${new_pin}
+
+       exit $?
+}
+
 function cli_hostname() {
        if cli_help_requested $@; then
                cli_show_man network
index 1ccd5fb8d2f10f54cba2fc093d5c3b18847fef49..ccec5a272833ad62611ed0740ae590de04f56f55 100644 (file)
-TIMEOUT                5
-REPORT         CONNECT
-''             '+++ATZ'
-''             'AT'
-''             '+++ATZ'
-OK             'ATH'
-''             'AT+CGDCONT=1,"IP","event.vodafone.de"'
-''             'sleep 5'
-TIMEOUT                30
-OK             'ATDT*99#'
-CONNECT                ''
+#!/bin/bash
+###############################################################################
+#                                                                             #
+# IPFire.org - A linux based firewall                                         #
+# Copyright (C) 2012  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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+LOG_FACILITY=$(basename ${0})
+
+# Do not print any log messages because these may be sent to the modem.
+LOG_DISABLE_STDOUT="true"
+
+. /usr/lib/network/functions
+
+log DEBUG "dialer called with arguments: $@"
+
+# The zone is an optional argument.
+ZONE=${1}
+assert isset ZONE
+
+# If we have the zone information, we will
+# load the zone configuration.
+if zone_exists ${ZONE}; then
+       zone_config_read ${ZONE}
+fi
+
+# The default speaker settings is on.
+at_speaker=${AT_SPEAKER_ON}
+
+# The default dial method is tone dial.
+at_dial=${AT_TONE_DIAL}
+
+# Initalize the commandline
+commandline=""
+
+# If we are running in debug mode, we start chat with the
+# verbose flag as well.
+if enabled DEBUG; then
+       commandline="${commandline} -v"
+fi
+
+# Create a temporary chat script file.
+file=$(mktemp)
+commandline="${commandline} -f ${file}"
+
+# Helper function to write beatiful lines to
+# the chat scripts.
+function println() {
+       printf "%-30s %s\n" "$@" >> ${file}
+}
+
+### Write the connect script.
+
+# Set the timeout value for the configuration commands to
+# 3 seconds. This will be increased later.
+println "TIMEOUT" 3
+
+# Let's log everything until we are properly connected.
+println "REPORT" "CONNECT"
+
+# End the connection, when one of the following conditions
+# happens:
+for condition in "BUSY" "NO ANSWER" "NO CARRIER" "NO DIALTONE"; do
+       println "ABORT" "'${condition}'"
+done
+
+# Now, we get to the exciting stuff.
+# Initalize the modem.
+println "''" "${AT_INITIALIZE}"
+println "''" "AT"
+println "''" "${AT_INITIALIZE}"
+
+# End all left over connections by hanging up.
+println "OK" "${AT_HANGUP}"
+
+# Apply the speaker setting.
+println "OK" "${at_speaker}"
+
+# Set the APN if any.
+if isset APN; then
+       println "''" "'AT+CGDCONT=1,\"IP\",\"${APN}\"'"
+fi
+
+# Enter a 5 seconds break so the modem can setup itself
+# to the settings we just transmitted to it.
+for i in $(seq 0 5); do
+       println "''" "\\d"
+done
+
+# Reset the timeout value to 30 seconds.
+println "TIMEOUT" 30
+
+# Actually dial the number.
+println "OK" "${at_dial}${PHONE_NUMBER}"
+
+# Wait for the CONNECT string.
+println "CONNECT" "\\c"
+
+# If login credentials were set, we send them.
+if isset USERNAME && isset PASSWORD; then
+       println "ogin:--ogin:" "${USERNAME}"
+       println "assword:" "${PASSWORD}"
+fi
+
+# Exec the chat command which will start talking to the modem.
+log DEBUG "Exec'ing chat with command line: ${commandline}"
+exec chat ${commandline}
+
+error "Could not execute chat. Exiting."
+exit ${EXIT_ERROR}
index 3d2cfc5b060dfa34ac4f819274502461fe8d07cc..656fa4b0d6ebba8a5bae0dd61578205d0745b6fb 100755 (executable)
 #                                                                             #
 ###############################################################################
 
+LOG_FACILITY=$(basename ${0})
+
 umask 022
 
+PPP_VARIABLES="IFNAME IPLOCAL IPREMOTE DNS1 DNS2 MACREMOTE LLLOCAL LLREMOTE"
+
 # Give the variables we get passed by pppd an own namespace
-for i in IFNAME IPLOCAL IPREMOTE DNS1 DNS2 MACREMOTE LLLOCAL LLREMOTE; do
+for i in ${PPP_VARIABLES}; do
        export PPP_${i}=${!i}
        unset ${i}
 done
 
 . /usr/lib/network/functions
 
+log DEBUG "Called."
+for i in ${PPP_VARIABLES}; do
+       i="PPP_${i}"
+       log DEBUG "  ${i} = ${!i}"
+done
+
 # Zone equals IFNAME
 ZONE=${PPP_IFNAME}
-assert isset ZONE
 
 # If the given device is a known zone, we will call the required
 # hook methods. If we don't know about any zone with name ${ZONE},
 # we do nothing.
 
-if zone_exists ${ZONE}; then
+if isset ZONE && zone_exists ${ZONE}; then
        HOOK=$(zone_get_hook ${ZONE})
 
        assert isset HOOK
@@ -50,7 +59,7 @@ if zone_exists ${ZONE}; then
        log DEBUG "  $@"
 
        hook_zone_exec ${HOOK} ppp-${PROGNAME} ${ZONE}
-       local ret=$?
+       ret=$?
 
        exit ${ret}
 fi