(一)PPP驱动程序的基本原理
PPP 协议之下是以太网和串口等物理层,之上是IP协议等网络层。这里,对于下层,我们只讨论串口的情况,对于上层,我们只讨论TCP/IP的情况。发送时, TCP/IP数据包经过PPP打包之后经过串口发送。接收时,从串口上来的数据经PPP解包之后上报给TCP/IP协议层。
pppd是一个后台服务进程(daemon),是一个用户空间的进程,所以把策略性的内容从内核的P
pppd是一个后台服务进程(daemon),是一个用户空间的进程,所以把策略性的内容从内核的P
PP协议处理模块移到pppd中是很自然的事了。pppd实现了所有鉴权、压缩/解压和加密/解密等扩展功能的控制协议。
在移动终端向监控中心发送定位信息的过程中,移动终端上的 GPRS 通信程序通过 socket 接口发送 TCP/IP 数据包,内核根据 IP 地址和路由表,到 PPP 网络接口,然后调用函数 ppp_start_xmit( ),此时控制权就转移到了 PPP 协议模块。函数 ppp_start_xmit( ) 调用函数 ppp_xmit_process( ) 去发送队列中的所有数据包,而函数 ppp_xmit_process( ) 会进一步调用函数 ppp_send_frame( ) 去发送单个数据包。函数 ppp_send_frame( ) 根据前面 pppd 对 PPP 协议模块的设置调用压缩等扩展功能之后,又经函数 ppp_push( ) 调用函数 pch->chan->ops->start_xmit( ) 发送数据包。函数 pch->chan->ops->start_xmit( ) 是具体的传输方式,对于串口发送方式,则是 ppp_async.c:ppp_asynctty_open 中注册的函数 ppp_async_send( ),函数 ppp_async_send( ) 经函数 ppp_async_push( ) 调用函数 tty->driver->write( )(定义在低层驱动程序中)把数据发送到串口 2(GPRS 通信模块接在串口 2 上)。
ppp_async.c 在初始化时(ppp_async_init),调用函数 tty_register_ldisc( ) 向 tty 注册了
行规程 N_PPP 的处理接口,也就是一组回调函数。在移动终端接收监控中心指令的过程中,当 GPRS 通信模块收到数据时,就会回调 N_PPP 行规程中的函数 ppp_asynctty_receive( ) 来接收数据。函数 ppp_asynctty_receive( ) 调用函数 ppp_async_input( ) 把数据 buffer 转换成 sk_buff,并放入接收队列 ap->rqueue 中。ppp_async 另外有一个 tasklet(ppp_async_process)专门处理接收队列 ap->rqueue 中的数据包,ppp_async_process 一直挂在接收队列 ap->rqueue 上,一旦被唤醒,它就调用函数 ppp_input( ) 让 PPP 协议模块处理该数据包。在函数 ppp_input( ) 中,数据被分成两路,一路是协议控制数据包,放入队列 pch->file.rqb 中,交给 pppd 处理。另外一路是用户数据包,经函数 ppp_do_recv( )、ppp_receive_frame( ) 进行 PPP 协议相关的处理后,再由函数 netif_rx( ) 提交给上层的 TCP/IP 协议模块进行处理,最后经 socket 接口传递给应用层的 GPRS 通信程序。
=====================
1) ppp设备是指在点对点的物理链路之间使用PPP帧进行分组交换的内核网络接口设备,
由于Linux内核将串行设备作为终端设备来驱动,
于是引入PPP终端规程来实现终端设备与PPP设备的接口. 根据终端设备的物理传输特性的
1) ppp设备是指在点对点的物理链路之间使用PPP帧进行分组交换的内核网络接口设备,
由于Linux内核将串行设备作为终端设备来驱动,
于是引入PPP终端规程来实现终端设备与PPP设备的接口. 根据终端设备的物理传输特性的
不同,
PPP规程分为异步规程(N_PPP)和同步规程(N_SYNC_PPP)两种, 对于普通串口设备使用异步PPP规程.
PPP规程分为异步规程(N_PPP)和同步规程(N_SYNC_PPP)两种, 对于普通串口设备使用异步PPP规程.
2) 在PPP驱动程序中, 每一tty终端设备对应于一条PPP传输通道(chanell),
每一ppp网络设备对应于一个PPP接口单元(unit).
从终端设备上接收到的数据流通过PPP传输通道解码后转换成PPP帧传递到PPP网络接口单元,
PPP接口单元再将PPP帧转换为PPP设备的接收帧.
反之, 当PPP设备发射数据帧时,发射帧通过PPP接口单元转换成PPP帧传递给PPP通道, PPP通道负责将PPP帧编码后写入终端设备.
在配置了多链路PPP时(CONFIG_PPP_MULTILINK), 多个PPP传输通道可连接到同一PPP接口单元.
PPP接口单元将PPP帧分割成若干个片段传递给不同的PPP传输通道, 反之,
在配置了多链路PPP时(CONFIG_PPP_MULTILINK), 多个PPP传输通道可连接到同一PPP接口单元.
PPP接口单元将PPP帧分割成若干个片段传递给不同的PPP传输通道, 反之,
PPP传输通道接收到的PPP帧片段被PPP接口单元重组成完整的PPP帧.
3) 在Linux-2.4中, 应用程序可通过字符设备/dev/ppp监控内核PPP驱动程序.
用户可以用ioctl(PPPIOCATTACH)将文件绑定到PPP接口单元上, 来读写PPP接口单元的输出帧,
也可以用ioctl(PPPIOCATTCHAN)将文件绑定到PPP传输通道上, 来读写PPP传输通道的输入帧.
4) PPP传输通道用channel结构描述, 系统中所有打开的传输通道在all_channels链表中.
PPP接口单元用ppp结构描述, 系统中所有建立的接口单元在all_ppp_units链表中.
当终端设备的物理链路连接成功后, 用户使用ioctl(TIOCSETD)将终端切换到PPP规程.
PPP规程初始化时, 将建立终端设备的传输通道和通道驱动结构. 对于异步PPP规程来说,
通道驱动结构为asyncppp, 它包含通道操作表async_ops.
传输通道和接口单元各自包含自已的设备文件(/dev/ppp)参数结构(ppp_file).
3) 在Linux-2.4中, 应用程序可通过字符设备/dev/ppp监控内核PPP驱动程序.
用户可以用ioctl(PPPIOCATTACH)将文件绑定到PPP接口单元上, 来读写PPP接口单元的输出帧,
也可以用ioctl(PPPIOCATTCHAN)将文件绑定到PPP传输通道上, 来读写PPP传输通道的输入帧.
4) PPP传输通道用channel结构描述, 系统中所有打开的传输通道在all_channels链表中.
PPP接口单元用ppp结构描述, 系统中所有建立的接口单元在all_ppp_units链表中.
当终端设备的物理链路连接成功后, 用户使用ioctl(TIOCSETD)将终端切换到PPP规程.
PPP规程初始化时, 将建立终端设备的传输通道和通道驱动结构. 对于异步PPP规程来说,
通道驱动结构为asyncppp, 它包含通道操作表async_ops.
传输通道和接口单元各自包含自已的设备文件(/dev/ppp)参数结构(ppp_file).
/dev/ppp
设备文件/dev/ppp。通过read系统调用,pppd可以读取PPP协议处理模块的数据包,当然,PPP协议处理模块只会把应该由recv函数pppd处理的数据包发给pppd。通过write系统调用,pppd可以把要发送的数据包传递给PPP协议处理模块。通过ioctrl系统调用,pppd可以设置PPP协议的参数,可以建立/关闭连接。在pppd里,每种协议实现都在独立的C文件中,它们通常要实现protent接口,该接口主要用于处理数据包,和fsm_callbacks接口,该接口主要用于状态机的状态切换。数据包的接收是由main.c: get_input统一处理的,然后根据协议类型分发到具体的协议实现上。而数据包的发送则是协议实现者根据需要调用output函数完成的。
static const struct file_operations ppp_device_fops = {
.owner = THIS_MODULE,
.read = ppp_read,
.write = ppp_write,
.poll = ppp_poll,
.unlocked_ioctl = ppp_ioctl,
.open = ppp_open,
.release = ppp_release
};
()ppp_init(void)
err = register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops);
()ppp_async_init(void)
tty_register_ldisc(N_PPP, &ppp_ldisc);
(二)ppp相关数据结构
struct ppp {
struct ppp_file file; /* stuff for read/write/poll 0 */
struct file *owner; /* file that owns this unit 48 */
struct list_head channels; /* list of attached channels 4c */
int n_channels; /* how many channels are attached 54 */
spinlock_t rlock; /* lock for receive side 58 */
spinlock_t wlock; /* lock for transmit side 5c */
int mru; /* max receive unit 60 */
unsigned int flags; /* control bits 64 */
unsigned int xstate; /* transmit state bits 68 */
unsigned int rstate; /* receive state bits 6c */
int debug; /* debug flags 70 */
struct slcompress *vj; /* state for VJ header compression */
enum NPmode npmode[NUM_NP]; /* what to do with each net proto 78 */
struct sk_buff *xmit_pending; /* a packet ready to go out 88 */
struct compressor *xcomp; /* transmit packet compressor 8c */
void *xc_state; /* its internal state 90 */
struct compressor *rcomp; /* receive decompressor 94 */
void *rc_state; /* its internal state 98 */
unsigned long last_xmit; /* jiffies when last pkt sent 9c */
unsigned long last_recv; /* jiffies when last pkt rcvd a0 */
struct net_device *dev; /* network interface device a4 */
int closing; /* is device closing down? a8 */
#ifdef CONFIG_PPP_MULTILINK
int nxchan; /* next channel to send something on */
u32 nxseq; /* next sequence number to send */
int mrru; /* MP: max reconst. receive unit */
u32 nextseq; /* MP: seq no of next packet */
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论