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/
--- /dev/null
+#!/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"
# 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() {
[ -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}
elif device_is_ethernet ${device}; then
echo "ethernet"
+ elif device_is_serial ${device}; then
+ echo "serial"
+
else
echo "unknown"
fi
--- /dev/null
+#!/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}
+}
5)
error "pppd terminated"
;;
+ 16)
+ error "pppd: Link terminated by modem"
+ ;;
19)
error "pppd: Authentication failed"
;;
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
--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})
--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}"
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}
# 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
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
) >> ${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
(
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
--- /dev/null
+#!/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
+}
. /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
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}
}
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
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}
}
# 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
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}
}
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
.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)
}
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
status)
cli_device_status ${device}
;;
+ unlock)
+ cli_device_serial_unlock ${device} $@
+ ;;
*)
cli_show_man network-device
;;
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=$?
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() {
[ "${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
-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}
# #
###############################################################################
+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
log DEBUG " $@"
hook_zone_exec ${HOOK} ppp-${PROGNAME} ${ZONE}
- local ret=$?
+ ret=$?
exit ${ret}
fi