Thursday, October 13, 2011

3G/GPRS connection using pppd and chat for M2M communication

In most cases, connecting to the Internet using 3G modem on normal desktop Linux is fairly easy because the networking support framework is quite mature.

However, for small embedded system, having a full blown networking support framework is a luxury. And usually the desktop networking framework is developed for interactive human intervention whereas for some embedded cases the 3G network connection is on demand and automated by other application request.

For M2M cases, usually a data connection is requested on demand. A specific task sometimes requests to transfer data over the Internet to the report server. To ensure the task is completed, the data connection must be established beforehand and terminated right after the task completed.

Now, the challenge is: can we establish data connection on demand through an application?

The answer is YES you can and it can be done fairly simple. I read a great post here (http://freshfoo.com/articles/using_optus3g_with_linux.html) using pppd and chat and I did some experiment with this.

In order to connect to 3G, there are 2 main and 2 additional configuration files required to establish the data connection.
  1. the PPP peers configuration 
  2. the chat negotiation script 
  3. the pap-secret file 
  4. the chap-secret file 
I have tested this on a Telkomsel Flash unlimited package. Since there is no authentication whatsoever required by Telkomsel Flash connection, I will ignore item number 3 and 4.

PPP peers configuration

I named the peer as "internet", so I created a file /etc/ppp/peers/internet with the following entry:

/dev/ttyS1
115200
lock
crtscts
modem
noauth
defaultroute
replacedefaultroute
user guest
password guest
connect "/usr/sbin/chat -V -f /etc/ppp/chat-internet"
noipdefault
usepeerdns 


The above configuration says that ppp will connect through the second serial port with 115200 baudrate and the rest you can check its meaning at pppd manual. Beware on "replacedefaultroute", not all ppp package support this option.

In order to connect to the other end, pppd will call using chat with a script defined on /etc/ppp/chat-internet. The following is the chat script I use (defined at /etc/ppp/chat-internet):

ABORT BUSY 
ABORT 'NO CARRIER' 
ABORT ERROR 
REPORT CONNECT 
TIMEOUT 10 
"" "ATZ" 
OK "AT&F" 
OK 'AT+CGDCONT=1,"IP","internet"' 
SAY "Calling...\n" 
TIMEOUT 120 
OK "ATD*99***1#" 
CONNECT \c

It says that it will dial to APN "internet". In order to test if it is working, I call the pppd manually using the following command:

# pppd call internet nodetach debug dump

It will show the debugging information and all the ppp negotiation. You can terminate this connection using Ctrl+c or by killing pppd process. To establish connection normally, we call pppd without nodetach debug dump option.

# pppd call internet

If it works OK, then we can proceed to the next step which is using this connection on demand.  

Automating connect, transfer and disconnect process

As you have seen above, we can connect to 3G/GPRS via command line, thus we should be able to call it from a shell script.

Now, in order to check if the connection has been established and the default route has been changed to go through ppp link the "netstat -nr" command can be used. If the default route has been changed to go via ppp link, there will be a line which starts with "0.0.0.0" which means default route and ends with "ppp0" which is the network link device it goes through. The following command will check that condition.

# netstat -nr | grep -e ^0.0.0.0.*ppp0$

If it produces a non-empty string, then the link is established. Now we can check this condition within shell script.

The following example script I had written can be used as then skeleton to implement the automation assuming only one ppp network link is used. I put it at /opt/bin/connect-uploaddata-disconnect.sh

#!/bin/bash
echo "Initiating ppp connection"
/usr/sbin/pppd call internet

cnt=0
res=`netstat -nr | grep -e ^0.0.0.0.*ppp0$`
while [ -z "$res" ] && [ $cnt -lt 10 ]; do
    echo "Wait for another 3 second."
    sleep 3
    cnt=$[cnt+1]
    res=`netstat -nr | grep -e ^0.0.0.0.*ppp0$`
done

if [ -n "$res" ]; then

   # data transfer simulation
    echo "Lets fetch from www.google.co.id using curl."
    data=`/usr/bin/curl -s http://www.google.co.id`
    echo $data

    # Do some more network related task here then terminate pppd
    echo "Terminating ppp connection"
    killall -9 pppd
else
    echo "PPP connection is not available within 10 second"
    echo "Cleaning up any stall pppd process"
    killall -9 pppd
fi


Now, we should have a script to perform a complete cycle of a task.

Scheduling the task.

To perform this task periodically, usually we define a cron entry. Let say we would like the M2M agent to execute the task at every hour, all day, at minute 1. Then, we need to add the cron entry using "crontab -e" with the following entry:

1 * * * * /opt/bin/connect-uploaddata-disconnect.sh

And then save it. Now we should have our M2M agent to perform this task automatically. I hope this help anyone who faces similar issue.

No comments: