2 ###############################################################################
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2012 IPFire Network Development Team #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
22 # Exit codes from the chat(8) command:
28 function modem_chat
() {
34 while [ $# -gt 0 ]; do
37 timeout
=$
(cli_get_val
${1})
40 answer
=$
(cli_get_val
${1})
53 assert serial_exists
${device}
54 assert serial_is_unlocked
${device}
60 log DEBUG
"Sending command to ${device}: ${command}"
63 # This cannot be run with -x.
66 chat
-V -s -t ${timeout} "" "${command}" "${answer}" \
67 < ${device} > ${device} || exit $?
68 print # Print line feed.
69 ) 2>&1 | __modem_chat_process_output "${answer}" ${quiet}
71 local ret=${PIPESTATUS[0]}
73 # Return the exit code of the chat command.
79 # When the timeout condition hit, the expected string has not
80 # been received in the given amount of time.
81 ${CHAT_TIMEOUT}|${CHAT_ERROR})
86 return ${EXIT_CONF_ERROR}
90 log WARNING "Received unknown
exit code from chat
(8): ${ret}"
94 function __modem_chat_process_output() {
98 if enabled quiet; then
99 # Just throw everything away.
108 log DEBUG "Output
[${counter}]: ${line}"
110 # Also skip empty lines.
111 [ -n "${line}" ] || continue
113 # Ignore all volatile messages.
114 [ "${line:0:1}" = "^
" ] && continue
116 counter=$(( ${counter} + 1 ))
118 # Skip the first line, because that's out command.
119 [ ${counter} -eq 1 ] && continue
121 # Filter out the expected answer.
122 [ "${line}" = "${answer}" ] && continue
129 function modem_initialize() {
133 log INFO "Initializing modem
${device}"
136 modem_chat "${device}" "${AT_INITIALIZE}"
139 # Exit codes of the sim_status function.
145 function modem_sim_status() {
150 output=$(modem_chat ${device} "AT
+CPIN?
")
151 assert_check_retval $?
153 # Strip leading +CPIN: from the output.
158 log DEBUG "${device}'s SIM is unlocked or doesn't need a PIN.
"
159 return ${EXIT_SIM_READY}
162 log DEBUG "${device}'s SIM is waiting for a PIN."
163 return ${EXIT_SIM_PIN}
166 log DEBUG "${device}'s SIM is PUK locked.
"
167 return ${EXIT_SIM_PUK}
171 log WARNING "${device}: Invalid output of the AT
+CPIN?
command.
"
172 return ${EXIT_SIM_UNKNOWN}
175 function modem_sim_unlocked() {
179 modem_sim_status "${device}"
182 [ ${ret} -eq ${EXIT_SIM_READY} ] && return ${EXIT_TRUE} || return ${EXIT_FALSE}
185 function modem_sim_locked() {
186 modem_sim_unlocked $@ && return ${EXIT_FALSE} || return ${EXIT_TRUE}
189 function modem_sim_unlock() {
196 local command="AT
+CPIN
=${pin}"
199 if isset new_pin; then
200 command="${command},${new_pin}"
203 modem_chat --timeout=2 --quiet "${device}" "${command}"
208 log INFO "Successfully unlocked SIM card on
${device}.
"
211 log ERROR "Could not unlock SIM card on
${device}.
"
219 function modem_sim_auto_unlock() {
226 # Get the current state the SIM card is in.
227 modem_sim_status "${device}" &>/dev/null
228 local sim_status_code=$?
230 case "${sim_status_code}" in
232 # Everything's fine. The SIM card is
237 # Try to unlock the device.
238 if modem_sim_unlock ${device} ${pin}; then
245 log ERROR "SIM card is PUK locked. Please unlock manually.
"
253 # Returns the vendor of the modem.
254 # For example: "huawei
"
255 function modem_get_manufacturer() {
260 output=$(modem_chat ${device} "AT
+GMI
")
261 assert_check_retval $?
263 [ "${output:0:1}" = "+" ] && output=${output#*: }
264 output=${output//\"/}
269 function modem_get_model() {
274 output=$(modem_chat ${device} "AT
+GMM
")
275 assert_check_retval $?
277 [ "${output:0:1}" = "+" ] && output=${output#*: }
278 output=${output//\"/}
283 function modem_get_software_version() {
288 output=$(modem_chat ${device} "AT
+GMR
")
289 assert_check_retval $?
291 [ "${output:0:1}" = "+" ] && output=${output#*: }
292 output=${output//\"/}
297 function modem_get_sim_imsi() {
301 # Make sure the SIM card is unlocked for this operation.
302 assert modem_sim_unlocked ${device}
304 modem_chat ${device} "AT
+CIMI
"
307 function modem_get_device_imei() {
312 output=$(modem_chat --timeout=1 ${device} "AT
+CGSN
") || assert_check_retval $?
315 if [ ${ret} -eq ${EXIT_OK} ]; then
322 function modem_is_mobile() {
326 # Check if the device can return it's IMEI.
327 # If not, it's probably a serial 56k modem or something
330 modem_get_device_imei ${device} &>/dev/null
333 # Exit codes of the network registration function.
334 EXIT_REG_REGISTERED_TO_HOME_NETWORK=0
335 EXIT_REG_NOT_REGISTERED_NOT_SEARCHING=1
336 EXIT_REG_NOT_REGISTERED_SEARCHING=2
337 EXIT_REG_REGISTRATION_DENIED=3
338 EXIT_REG_REGISTERED_ROAMING=4
341 function modem_get_network_registration() {
345 # Make sure the SIM card is unlocked for this operation.
346 assert modem_sim_unlocked ${device}
349 output=$(modem_chat ${device} "AT
+CREG?
")
350 assert_check_retval $?
352 # Cut out unneeded parts of the message.
357 local status=${output%,*}
359 # The status variable must be zero.
360 [ ${status} -ne 0 ] && break
362 local stat=${output#*,}
365 return ${EXIT_REG_NOT_REGISTERED_NOT_SEARCHING}
368 return ${EXIT_REG_REGISTERED_TO_HOME_NETWORK}
371 return ${EXIT_REG_NOT_REGISTERED_SEARCHING}
374 return ${EXIT_REG_REGISTRATION_DENIED}
377 return ${EXIT_REG_REGISTERED_ROAMING}
380 return ${EXIT_REG_UNKNOWN}
386 # Apparently the output of the CREG? command was not in
387 # the right format. The modem will be tried to be set to the
390 modem_set_network_registration ${device} 0
391 modem_get_network_registration ${device}
394 function modem_set_network_registration() {
398 # Make sure the SIM card is unlocked for this operation.
399 assert modem_sim_unlocked ${device}
404 modem_chat ${device} "AT
+CREG
=${mode}"
407 function modem_scan_networks() {
411 # Make sure the SIM card is unlocked for this operation.
412 assert modem_sim_unlocked ${device}
415 output=$(modem_chat --timeout=60 ${device} "AT
+COPS
=?
")
416 assert_check_retval $?
420 # XXX the output is not very nice to parse.
423 function __modem_get_network_operator() {
427 # Make sure the SIM card is unlocked for this operation.
428 assert modem_sim_unlocked ${device}
431 assert isset argument
434 output=$(modem_chat ${device} "AT
+COPS?
")
435 assert_check_retval $?
438 output=${output//,/ }
440 local arg mode format operator act
442 while read -r arg; do
451 operator="$
(strip
${arg})"
461 done <<< "$
(args
${output})"
467 function modem_get_network_operator() {
471 __modem_get_network_operator ${device} operator
474 # Exit codes of the network operator mode function.
476 EXIT_OPMODE_COMPACTGSM=1
477 EXIT_OPMODE_GSM_WITH_EGPRS=2
479 EXIT_OPMODE_UMTS_WITH_HSDPA=4
480 EXIT_OPMODE_UMTS_WITH_HSUPA=5
481 EXIT_OPMODE_UMTS_WITH_HSDPA_AND_HSUPA=6
482 EXIT_OPMODE_UNKNOWN=7
484 function modem_get_network_mode() {
489 output=$(__modem_get_network_operator ${device} act)
490 assert_check_retval $?
495 return ${EXIT_OPMODE_GSM}
499 return ${EXIT_OPMODE_COMPACTGSM}
503 return ${EXIT_OPMODE_UMTS}
506 print "UMTS with HSDPA
"
507 return ${EXIT_OPMODE_UMTS_WITH_HSDPA}
510 print "UMTS with HSUPA
"
511 return ${EXIT_OPMODE_UMTS_WITH_HSUPA}
514 print "UMTS with HSDPA and HSUPA
"
515 return ${EXIT_OPMODE_UMTS_WITH_HSDPA_AND_HSUPA}
519 return ${EXIT_OPMODE_UNKNOWN}
524 function __modem_get_signal_quality() {
528 # Make sure the SIM card is unlocked for this operation.
529 assert modem_sim_unlocked ${device}
532 assert isset argument
535 output=$(modem_chat ${device} "AT
+CSQ
")
536 assert_check_retval $?
542 local rssi=${output%,*}
543 local ber=${output#*,}
549 log ERROR "Unknown format
for AT
+CSQ
: ${device}: ${output}"
556 function modem_get_signal_quality() {
561 rssi=$(__modem_get_signal_quality ${device} rssi)
562 assert_check_retval $?
564 isset rssi || return ${EXIT_ERROR}
566 # 99 indicates an unknown signal strength.
567 [ ${rssi} -eq 99 ] && return ${EXIT_UNKNOWN}
569 local dbm=$(( ${rssi} * 2 ))
570 dbm=$(( ${dbm} - 113 ))
576 function modem_get_bit_error_rate() {
581 ber=$(__modem_get_signal_quality ${device} ber)
582 assert_check_retval $?
584 isset ber || return ${EXIT_ERROR}
586 # 99 indicates that the bit error rate could not be detected or
587 # is unknown for some other reason.
588 [ ${ber} -eq 99 ] && return ${EXIT_UNKNOWN}