From 5101a0f32017c23707ea0b3aa2f650803b11a644 Mon Sep 17 00:00:00 2001 From: John Klug Date: Mon, 17 Aug 2020 18:08:50 -0500 Subject: Fix chat_wrapper to handle COPS=2, CFUN=0 state --- recipes-core/multitech/config/chat_wrapper | 182 +++++++++++++++++++++++++---- 1 file changed, 158 insertions(+), 24 deletions(-) (limited to 'recipes-core/multitech/config/chat_wrapper') diff --git a/recipes-core/multitech/config/chat_wrapper b/recipes-core/multitech/config/chat_wrapper index f1fd30c..b0bf9e5 100755 --- a/recipes-core/multitech/config/chat_wrapper +++ b/recipes-core/multitech/config/chat_wrapper @@ -18,30 +18,117 @@ # If there are not #MT AT+CGDCONT= lines, then any line without # a comment chararacter before AT+CGDONT= is accepted, but only the # last one in the file. +# +# On entry to this script, file descriptor 0 is the modem. +# For ppp to work, stty must work on file descriptor 0. +# If stty fails, so will ppp. NAME=chat_wrapper CONFIG=/etc/default/${NAME} +CHAT_WRAPPER_RECURSION=/run/chat_wrapper_recursion + function finish { ${LOG} "Launch:" "$@" - exec "$@" + exec "$@" # NOTREACHED } +# This function is used to determine if the modem and serial driver +# are working. In testing, the driver has gotten into states where +# stty fails. Before the chat script is started, the ioctl TCGETS is +# performed, and will fail if the driver is hung. This same function +# is called by stty. The modem port used by pppd is STDIN. Cases +# have been observed on the H5 where radio-cmd works, but stty does +# not, resulting in pppd failing. When this happens, radio-reset is +# the best thing to try. +function sanity +{ + if ! log=$(stty 2>&1) || ! [[ $(radio-cmd -t10000 'AT') =~ ^OK ]]; then + ${LOG} "Modem has issues, so see if we can try again" + ${LOG} "stty error: $(log)" + array=( ) + # our parent is PPID, which is pppd. Get the pppd + # parameter list. + while IFS= read -r -d '' eparm; do + execarg+=( "$eparm" ) + done < <(cat /proc/$PPID/cmdline) + i=0 + ${LOG} "List parameters" + while ((i < ${#execarg[@]})) ; do + ${LOG} "$i: ${execarg[$i]}" + ((i++)) + done + if [[ ${execarg[0]} == "pppd" ]] ; then + execarg[0]=/usr/sbin/pppd + fi + + # Break any recursion loop. + if [[ -f ${CHAT_WRAPPER_RECURSION} ]] ; then + ${LOG} "Failure: modem is still unresponsive after reset" + rm -f ${CHAT_WRAPPER_RECURSION} + exit 1 + fi + touch ${CHAT_WRAPPER_RECURSION} + ${LOG} "Bad TTY, possibly due to modem in bad state" + ${LOG} "Reset modem, and we relaunch pppd" + # Our terminal is the modem. When we reset the modem, + # we will be sent a SIGHUP. Ignore it (:). + trap : SIGHUP + /usr/sbin/mts-io-sysfs store radio-reset 0 + sleep 5 + count=0 + while ((count < 60)) ; do + # Wait for radio-reset to get the modem responding + if [[ $(radio-cmd -t10000 'AT') =~ ^OK ]]; then + # parent is dying, so remove the pppd locks for the new pppd. + for f in /run/lock/LCK..modem_at0 /run/lock/LCK..modem_at1 ; do + if [[ -f $f ]] ; then + mypid=$(cat $f) + ${LOG} "PPID is $PPID, pid is $mypid" + # Remove the lock, if it belongs to our parent, pppd + if [ $mypid = $PPID ] ; then + ${LOG} "match $mypid $PPID" + sleep 60 + rm -f $f + else + ${LOG} "mismatch |$mypid| |$PPID|" + fi + fi + done + # Locks gone, so start new pppd + nohup "${execarg[@]}" >/dev/null 2>&1 & + # Tell our parent we failed, which causes our pppd to terminate. + exit 1 + else + sleep 5 + fi + done + ${LOG} "ERROR: After five minutes the modem is still not ready" + exit 1 + fi + return 0 +} # End of sanity function + +# If > 0, need to wait because we were not registered. +WAITREG=0 + [[ -f $CONFIG ]] || exit 1 . ${CONFIG} : ${REGWAITTIME:=300} : ${FINALWAIT:=5} +: ${COPSWAIT:=10} +: ${CFUNWAIT:=10} : ${LOG:="/usr/bin/logger -t ${NAME} -p daemon.notice"} ${LOG} Timeout is $REGWAITTIME, execute "$@" ((i=$#)) chatscript="${!i}" -${LOG} Parsing chat script "$chatscript" +${LOG} Parsing chat script "$chatscript" # CONTEXT is last context string in chat script CONTEXT=$(egrep "^#MT[[:space:]]+(AT\+CGDCONT=.*)" ${chatscript} | tail -1) if ((${#CONTEXT} == 0)) ; then @@ -60,9 +147,25 @@ if ((${#CONTEXT} == 0)) ; then fi ((CONTEXTNUM=${BASH_REMATCH[2]})) +# Make sure CFUN=1, in case the last pppd was aborted with it set to 0. +${LOG} "Verify CFUN=1" +cfun=$(/usr/bin/radio-cmd ${RADIOOPTION} -t10000 'AT+CFUN?') +result1=$? +if ((result1 != 0)) || ((${#cfun} == 0)) ; then + ${LOG} "Is modem in bad state -- \"CFUN?\" is broken?" + sanity + ((WAITREG++)) +fi +if ! [[ $cfun =~ ^\+CFUN:\ 1[,[:space:]] ]] ; then + /usr/bin/radio-cmd ${RADIOOPTION} -t10000 'AT+CFUN=1' + ${LOG} "Just set CFUN=1 so wait ${CFUNWAIT} seconds" + sleep ${CFUNWAIT} + ((WAITREG++)) +fi ${LOG} "Using Context ${CONTEXTNUM} based on chat script: ${CONTEXT}" + # At this point if there is no context number, we can skip everything else. # Get Modem's context settings @@ -137,7 +240,15 @@ if [[ $MPDP != $PDP ]] || [[ $MAPN != $APN ]] || \ ${LOG} "$MCONTEXT" ${LOG} "Dropping registration with carrier to set context" # Need to deregister + ((WAITREG++)) /usr/bin/radio-cmd ${RADIOOPTION} -t10000 'AT+COPS=2' + + count=10 + while ((count > 0)) && ! [[ $(/usr/bin/radio-query ${RADIOOPTION} --netreg) =~ ^NOT\ REGISTERED$ ]] ; do + sleep 2 + ((count--)) + done + # H5 radios do not like addresses that are empty with "" if ((${#ADDR} == 0)) ; then CMDSTR="AT+CGDCONT=${CONTEXTNUM},\"${PDP}\",\"${APN}\",,$DCOMP,${HCOMP}${FULLBOAT}" @@ -154,7 +265,7 @@ if [[ $MPDP != $PDP ]] || [[ $MAPN != $APN ]] || \ ((count--)) || true LOGMSG=$(/usr/bin/radio-cmd ${RADIOOPTION} -t10000 "${CMDSTR}" 2>&1) result=$? - ${LOG} "Result ${result}, Got response ${LOGMSG}" + ${LOG} "Setting context: Result ${result}, Got response ${LOGMSG}" if [[ $LOGMSG =~ ERROR ]] ; then result=1 fi @@ -163,13 +274,16 @@ if [[ $MPDP != $PDP ]] || [[ $MAPN != $APN ]] || \ # re-enable the modem to defaults. /usr/bin/radio-cmd ${RADIOOPTION} -t10000 'AT+COPS=0' - sleep 1 # Some older modems will not re-register after the COPS # command if you do not reset them using CFUN. /usr/bin/radio-cmd ${RADIOOPTION} -t10000 'AT+CFUN=0' + ${LOG} "Set COPS=0, CFUN=1, so wait ${CFUNWAIT} seconds" + sleep ${CFUNWAIT} /usr/bin/radio-cmd ${RADIOOPTION} -t10000 'AT+CFUN=1' + sleep ${CFUNWAIT} + # Abort PPP if the Context is not correct. We don't want # to cause the carrier to disable the account by dialing # out with a bad APN. @@ -179,27 +293,47 @@ if [[ $MPDP != $PDP ]] || [[ $MAPN != $APN ]] || \ fi sleep 1 ${LOG} "New context is set. Wait up to $REGWAITTIME seconds to register" - # Wait for registration - uptime=$(cat /proc/uptime) - [[ $uptime =~ ^([^\.]*) ]] - t0=${BASH_REMATCH[1]} - while ! [[ $(/usr/bin/radio-query ${RADIOOPTION} --netreg) =~ ^REGISTERED$ ]] ; do - sleep 5 - uptime=$(cat /proc/uptime) - [[ $uptime =~ ^([^\.]*) ]] - t1=${BASH_REMATCH[1]} - if ((t1-t0 > REGWAITTIME)) ; then - ${LOG} "$((t1-t0)) seconds has expired" - exit 1 - fi - done - uptime=$(cat /proc/uptime) - [[ $uptime =~ ^([^\.]*) ]] - t1=${BASH_REMATCH[1]} - ${LOG} "Re-registered in $((t1-t0)) seconds -- wait ${FINALWAIT} more seconds" - sleep $FINALWAIT else - ${LOG} "Context $CONTEXTNUM matches and nothing to do." + ${LOG} "Context $CONTEXTNUM matches verify COPS, then wait for registration." + # Check and set COPS and CFUN to be sure we were not interrupted at some point + # in the past. + cops=$(/usr/bin/radio-cmd ${RADIOOPTION} -t10000 'AT+COPS?') + result0=$? + + if ((result0 != 0)) || ! [[ $cops =~ ^\+COPS:\ 0, ]] ; then + /usr/bin/radio-cmd ${RADIOOPTION} -t10000 'AT+COPS=0' + ((WAITREG++)) + ${LOG} "Just set COPS=0 so wait ${COPSWAIT} seconds" + sleep ${COPSWAIT} + fi + +fi +# Wait for registration +uptime=$(cat /proc/uptime) +[[ $uptime =~ ^([^\.]*) ]] +t0=${BASH_REMATCH[1]} +while ! [[ $(/usr/bin/radio-query ${RADIOOPTION} --netreg) =~ ^REGISTERED$ ]] ; do + sleep 5 + ((WAITREG++)) + uptime=$(cat /proc/uptime) + [[ $uptime =~ ^([^\.]*) ]] + t1=${BASH_REMATCH[1]} + if ((t1-t0 > REGWAITTIME)) ; then + ${LOG} "$((t1-t0)) seconds has expired without registration" + sanity + fi +done +uptime=$(cat /proc/uptime) +[[ $uptime =~ ^([^\.]*) ]] +t1=${BASH_REMATCH[1]} +${LOG} "Re-registered in $((t1-t0)) seconds" +if ((WAITREG > 0)) ; then + ${LOG} "Wait ${FINALWAIT} more seconds" + sleep $FINALWAIT fi +sanity + +rm -f ${CHAT_WRAPPER_RECURSION} finish "$@" + # NOTREACHED -- cgit v1.2.3