3G模块PPPD拨号流程分析
来源:互联网 发布:ubuntu14.04安装mysql 编辑:程序博客网 时间:2024/04/24 02:38
1 案例描述
现在公司的前端产品很多都使用3G模块来作为网络连接的接口,而3G拨号使用PPPD程序,了解拨号程序的流程对解决3G连接网络的问题会有很大的帮助,鉴于此重要性,对PPPD的拨号流程做一个简要的分析。
因为PPPD程序不依赖与硬件平台,这里没有指定具体应用的场景,目的在于说明这个拨号程序的通用性。
目前公司平台采用的这个程序的版本是ppp-2.4.3。
本文只对PPPD的拨号流程进行说明,对拨号程序所用的详细参数以及所使用协议的不做具体说明。
2 案例分析
总体说明
PPPD 是一个用户空间的后台服务进程(daemon),负责与3G模块进行通信会话来进行必要的初始化设置,然后开始按照协议所要求的步骤进行拨号。初始化设置是由PPPD自带的一个辅助工具CHAT程序来完成的,这个程序利用AT指令和3G模块进行通信,主要是交互一些拨号的参数设置、进行拨号的用户名和密码、是否采用数据加密等连网必不可少的参数;之后PPPD开始正常的拨号工作。下面开始分析这个拨号的流程。
补充说明:AT指令是配置3G模块的通用指令,一般通过RS232等串行线路发送到3G等无线模块,格式以及举例如下:
AT+CGMI? -------给出模块厂商的标识
AT---------是AT指令的开始符号,后面的+号表示后面有具体的配置参数;
CGMI-----这就是具体的配置参数,这个参数后面的?号标示是向3G查询;
关于3G的AT指令,业界推出了一些标准的指令集合,这些指令在任何厂家的任何模块上都可以使用,也有一些是3G模块生产厂家自己规范的一些AT指令,这些指令就只能在特定的模块上才能使用。
2.2 PPPD拨号流程下面结合PPPD程序的代码对拨号流程做一下分析。
主程序是pppd_start,这个函数首先是做一些初始化的工作:
void *pppd_start(void *arg)
{
……………
for (i = 0; (protp = protocols[i]) != NULL; ++i)
(*protp->init)(0);
tty_init();
………
首先是对几个所使用的协议进行初始化,我们这里所用到的分别是lcp_protent、chap_protent、ipcp_protent。初始化的工作基本一致,就是建立各个协议的状态机进行默认设置,为以后网络的维护做好准备;tty_init()是对3G模块所使用串口进行设置,包括所使用的默认拨特率、停止位、是否校验等,在这个函数里还有一个操作就是设置好网络连接所用的通道:
the_channel = &tty_channel(这是在tty_init函数里),这个所谓的连接通道是3G连接的重要函数,后面有这个通道的使用说明;
在完成一些初始化后,正式开始进行协议的协商:
……
pppd_start ->lcp_open();: 打开LCP协议状态机,设置状态为STARTING;
各个协议的状态机分别是-----
STARTING 、INITIAL、CLOSED、CLOSING、STOPPED、OPENED。在上面的初始化时把所有的协议状态机都设置为INITIAL。这里打开LCP协议就是把状态设置为STARTING。接着往下看程序,还是在pppd_start()主函数里:
pppd_start ->start_link();这个函数比较重要,我们把他展开:
void start_link(unit)
{
char *msg;
new_phase(PHASE_SERIALCONN);
devfd = the_channel->connect();
msg = "Connect script failed";
if (devfd < 0)
goto fail;
/* set up the serial device as a ppp interface */
/*
* N.B. we used to do tdb_writelock/tdb_writeunlock around this
* (from establish_ppp to set_ifunit). However, we won't be
* doing the set_ifunit in multilink mode, which is the only time
* we need the atomicity that the tdb_writelock/tdb_writeunlock
* gives us. Thus we don't need the tdb_writelock/tdb_writeunlock.
*/
fd_ppp = the_channel->establish_ppp(devfd);
msg = "ppp establishment failed";
if (fd_ppp < 0) {
status = EXIT_FATAL_ERROR;
goto disconnect;
}
/*
* Start opening the connection and wait for
* incoming events (reply, timeout, etc.).
*/
if (ifunit >= 0)
notice("Connect: %s <--> %s", ifname, ppp_devnam);
else
notice("Starting negotiation on %s", ppp_devnam);
add_fd(fd_ppp);
status = EXIT_NEGOTIATION_FAILED;
new_phase(PHASE_ESTABLISH);
lcp_lowerup(0);
return;
disconnect:
new_phase(PHASE_DISCONNECT);
if (the_channel->disconnect)
the_channel->disconnect();
fail:
new_phase(PHASE_DEAD);
if (the_channel->cleanup)
(*the_channel->cleanup)();
}
首先调用the_channel->connect(),这是个函数指针,实际调用的是connect_tty(),(这个函数在上面pppd_start->tty_init里进行了设置)他设置一些TTY通道的参数,然后开辟一个线程chat_main,发送AT指令对3G进行配置;一切正常后从connect_tty返回到start_link继续往下执行;
start_link->the_channel->establish_ppp(devfd)
下面把establish_ppp()函数展开:
int tty_establish_ppp (int tty_fd)
{
………
ret_fd = generic_establish_ppp(tty_fd);
………
}
一个重要的函数generic_establish_ppp()执行,然后generic_establish_ppp->make_ppp_unit(),在make_ppp_unit()函数里:
……
ppp_dev_fd = open("/dev/ppp", O_RDWR),打开/dev/ppp
ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit)
建立一个网络接口ppp0, 如果网络接口成功建立后会显示:
notice("Connect: %s <--> %s", ifname, ppp_devnam)==Connect: serial0 <--> /dev/ttyUSB0 ,说明网络接口已经建立; (这个时候可以在SHELL下ifconfig看到这个接口);之后再次返回到start_link执行;
接下来开始发起LCP通信:
start_link->lcp_lowerup():
这个函数首先和内核的PPP协议进行协商,主要是MTU等链路参数,协商后设置LCP的DELAYED_UP标志,把lcp_delayed_up函数设置给一个定时器,这个定时器会根据DELAYED_UP标志周期执行之前赋给他的函数,就是这个lcp_delayed_up,在这里函数里将主动发起LCP协议请求,之后等待对端的回应。start_link函数结束返回到 pppd_start()主函数继续执行:
接下来,主函数pppd_start会进入一个无限循环,这个循环主要执行两个函数handle_events()、get_input();
handle_events主要处理接收到的信号,还有一个功能就是执行定时器的函数,前面曾经设置过一个lcp_delayed_up函数,那么建立连接首先执行这个函数;
get_input主要是负责处理接收到的数据包,这个函数下面会介绍。先来看lcp_delayed_up:
调用lcp_delayed_up->fsm_lowerup,在上面的lcp_open()函数里LCP的状态已经是STARTING,所以根据这个状态调用fsm_sconfreq(),发送LCP初始化配置请求,然后LCP状态设置为:REQSENT,函数返回;
fsm_sconfreq先组建一些连接用的参数,然后调用fsm_sdata(f, CONFREQ, f->reqid, outp, cilen),通过/dev/ppp->串口发送请求给3G;然后设置一个超时函数给定时器,一旦发送的这个LCP请求没有回应,则重新发送。
如果没有超时,那么会收到一个LCP请求的回应:rcvd [LCP ConfReq id=0x0,这个时候数据的接收get_input函数来处理的,那么是如何收到对端发来的数据呢?就是这个get_input(),现在来看一下:
首先阻塞的读/dev/ppp,一旦收到一个数据包,检查包里的协议,看是哪种协议数据(在Establishment Phase阶段,只接收LCP的协议包,其他的就丢弃);然后调用lcp_input进行实际的数据接收处理;lcp_input->fsm_input,在这个函数里根据收到包的请求命令进行分别处理:比如:rcvd [LCP ConfReq id=。。。。。。;那么就调用fsm_rconfreq()进一步处理,如果接收正确,则会调用fsm_sdata()发送CONFACK命令;然后设置LCP为ACKSENT
然后等待数据包接收;当接收到一个ConfAck的包后,调用fsm_rconfack时,设置LCP为OPENED,然后lcp_up->lcp_echo_lowerup,注意,此时会调用ipcp_lowerup,设置IPCP为CLOSED!!!之后发送sent [LCP EchoReq id;之后返回到lcp_up,执行link_established,这个函数设置PPP为PHASE_AUTHENTICATE认证阶段,开始加密等认证;之后返回;
当接收到一个rcvd [CHAP Challenge时,调用chap_input-》chap_respond,发送一个CHAP_RESPONSE,sent [CHAP Response id=0x1,然后继续接收数据包;
当收到一个rcvd [CHAP Success后,调用chap_handle_status,这个函数打印CHAP authentication succeeded
然后执行auth_withpeer_success,他继续打印notice("%s authentication succeeded", prot);
执行network_phase,network_phase->start_networks,改变PPP为PHASE_NETWORK状态,依次执行各个协议的open函数:这个时候IPCP已经为CLOSED的,所以会发送sent [IPCP ConfReq,并设置IPCP为REQSENT
当接收到一个rcvd [IPCP ConfNak时,会发送sent [IPCP ConfReq id=0x2,再次请求
当再次收到rcvd [IPCP ConfReq,接着发送sent [IPCP ConfNak id=0x0 <addr 0.0.0.0>]
当接收到rcvd [IPCP ConfAck id=0x4时,调用IPCP_UP,显示
notice("local IP address %I", go->ouraddr);
notice("remote IP address %I", ho->hisaddr);
整个的协议协商过程用图表表示为:
Send lcp confreq
Send lcp ack
Send chap confreq
Send chap ack
Send ipcp confreq
Send chap ack
Send ipcp confreq
Send ipcp ack
3G网络基站
拨号端
图2-1 PPPD协议协商流程图
。说明:箭头表示是数据的发送方向
此时,已经从3G网络获得动态分配的IP地址,表明已经建立连接,可以象使用普通以太网那样使用3G网络的接口。
从上面的代码中看到,网络的连接是PPPD主动发起的,就是函数start_link,之后就是根据所接收的状态是否满足要求进而进行下一阶段的工作。
2.3 PPP链路的工作过程上面的拨号过程中使用到了PPP拨号的几个不同阶段,这里做一个简单的介绍
(1) 链路不可用阶段(Link Dead Phase)在最开始,整条链路处于链路不可用状态,此阶段有时也称为物理不可用阶段,PPP链路都需从这个阶段开始和结束,当通信双方的两端检测到物理线路激活时,就会从当前这个阶段进入到链路建立阶段
(2) 链路建立阶段 (Link Establishment Phase) 在此阶段,PPP链路将进行LCP相关协商,协商内容包括工作方式,认证方式,连路压缩等,LCP在协商成功后进入Opened状态,表示底层链路已经建立,如果链路协商失败,则会返回到第一阶段,在链路建立阶段成功后,如果配置了PPP认证,则会进入认证阶段,如果没有配置PPP认证,则会直接进入网络层协议阶段
(3) 认证阶段 (Authentication Phase) 在此阶段,PPP将进行用户认证工作,PPP支持PAP和CHAP两种认证方式,关于这两种认证方式在后面将会详细介绍,如果认证失败,PPP链路会进入链路终止阶段,拆除链路,LCP状态转为DOWN,如果认证成功就进入网络层协议阶段
(4) 网络层协议阶段 (Network-Layer Protocol Phase) 一旦PPP完成了前面几个阶段,每种网络层协议(IP,IPX等)会通过各自相应网络控制协议进行配置,只有相应的网络层协议协商成功后,该网络层协议才可以通过这条PPP链路发送报文,对于IPCP协议,协商的内容主要包括双方的IP地址等
(5) 链路终止阶段 (Link Termination Phase) PPP能在任何时候终止链路,载波丢失,认证失败后用户人为关闭链路等情况均会导致链路终止,PPP协议通过交换LCP的链路之中报文来关闭链路,当链路关闭时,连路层会通知网络层做相应的操作,而且也会通过物理层强制关断链路
通过学习PPPD拨号过程,可以更好的理解3G的连接情况,为定义拨号过程以及拨号成功后的数据通信可能出现的问题,有比较清晰的解决思路。
- 3G模块PPPD拨号流程分析
- 3G模块PPPD拨号流程分析
- 3G模块PPPD拨号流程分析
- pppd拨号3G设备
- pppd拨号3G设备
- linux pppd 3g 拨号记录
- linux pppd 3g 拨号记录
- 嵌入式 hi3518c平台SIMCOM5360E型号3G模块移植使用PPPD拨号(待续)
- gprs模块下pppd拨号脚本
- PPPD拨号
- 嵌入式 PPPD工具实现3G拨号实践以及工具PPPD和CHAT详解摘录
- Linux下ppp拨号+电信3G模块
- YUGA CWM900 3G模块拨号脚本
- 嵌入式 hi3518c,3g-sincom5360e平台pppd成功拨号联通3G示例
- pppd拨号脚本配置
- pppd拨号脚本配置
- pppd拨号脚本配置
- pppd拨号脚本配置
- c++中函数参数传递(值传递、指针传递,引用传递)进一步认识
- ROWID
- 巧用Graphviz和pvtrace等工具可视化C函数调用
- VC6.0找不到控件工具条
- 查看tomcat为jvm分配的内存大小
- 3G模块PPPD拨号流程分析
- 系统架构师笔记(一)
- 光棍节程序员闯关秀第1关(总共10关)
- CoverFlow
- 设计模式心得(一) 简单工厂模式
- 线段树题集
- iOS开发-push远程通知
- jQuery Form Plugin
- js改变url地址