




已阅读5页,还剩7页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
(一)PPP驱动程序的基本原理PPP 协议之下是以太网和串口等物理层,之上是IP协议等网络层。这里,对于下层,我们只讨论串口的情况,对于上层,我们只讨论TCP/IP的情况。发送时, TCP/IP数据包经过PPP打包之后经过串口发送。接收时,从串口上来的数据经PPP解包之后上报给TCP/IP协议层。pppd是一个后台服务进程(daemon),是一个用户空间的进程,所以把策略性的内容从内核的PPP协议处理模块移到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设备的接口. 根据终端设备的物理传输特性的不同,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传输通道接收到的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)./dev/ppp设备文件/dev/ppp。通过read系统调用,pppd可以读取PPP协议处理模块的数据包,当然,PPP协议处理模块只会把应该由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_filefile;/* stuff for read/write/poll 0 */struct file*owner;/* file that owns this unit 48 */struct list_head channels;/* list of attached channels 4c */intn_channels;/* how many channels are attached 54 */spinlock_trlock;/* lock for receive side 58 */spinlock_twlock;/* lock for transmit side 5c */intmru;/* max receive unit 60 */unsigned intflags;/* control bits 64 */unsigned intxstate;/* transmit state bits 68 */unsigned intrstate;/* receive state bits 6c */intdebug;/* debug flags 70 */struct slcompress *vj;/* state for VJ header compression */enum NPmodenpmodeNUM_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 longlast_xmit;/* jiffies when last pkt sent 9c */unsigned longlast_recv;/* jiffies when last pkt rcvd a0 */struct net_device *dev;/* network interface device a4 */intclosing;/* is device closing down? a8 */#ifdef CONFIG_PPP_MULTILINKintnxchan;/* next channel to send something on */u32nxseq;/* next sequence number to send */intmrru;/* MP: max reconst. receive unit */u32nextseq;/* MP: seq no of next packet */u32minseq;/* MP: min of most recent seqnos */struct sk_buff_head mrq;/* MP: receive reconstruction queue */#endif /* CONFIG_PPP_MULTILINK */#ifdef CONFIG_PPP_FILTERstruct sock_filter *pass_filter;/* filter for packets to pass */struct sock_filter *active_filter;/* filter for pkts to reset idle */unsigned pass_len, active_len;#endif /* CONFIG_PPP_FILTER */struct net*ppp_net;/* the net we belong to */;struct channel struct ppp_filefile;/* stuff for read/write/poll */struct list_head list;/* link in all/new_channels list */struct ppp_channel *chan;/* public channel data structure */struct rw_semaphore chan_sem;/* protects chan during chan ioctl */spinlock_tdownl;/* protects chan, file.xq dequeue */struct ppp*ppp;/* ppp unit were connected to */struct net*chan_net;/* the net channel belongs to */struct list_head clist;/* link in list of channels per unit */rwlock_tupl;/* protects ppp */#ifdef CONFIG_PPP_MULTILINKu8avail;/* flag used in multilink stuff */u8had_frag;/* = 1 fragments have been sent */u32lastseq;/* MP: last sequence # received */int speed;/* speed of the corresponding ppp channel*/#endif /* CONFIG_PPP_MULTILINK */;struct ppp_file enum INTERFACE=1, CHANNELkind;struct sk_buff_head xq;/* pppd transmit queue */ /*传输队列*/struct sk_buff_head rq;/* receive queue for pppd */ /*发送队列*/wait_queue_head_t rwait;/* for poll on reading /dev/ppp */atomic_trefcnt;/* # refs (incl /dev/ppp attached) */inthdrlen;/* space to leave for headers */intindex;/* interface unit / channel number */intdead;/* unit/channel has been shut down */;struct ppp_channel void*private;/* channel private data */struct ppp_channel_ops *ops;/* operations for this channel */intmtu;/* max transmit packet size */inthdrlen;/* amount of headroom channel needs */void*ppp;/* opaque to channel */intspeed;/* transfer rate (bytes/second) */* the following is not used at present */intlatency;/* overhead time in milliseconds */;struct ppp_channel_ops /* Send a packet (or multilink fragment) on this channel. Returns 1 if it was accepted, 0 if not. */int(*start_xmit)(struct ppp_channel *, struct sk_buff *);/* Handle an ioctl call that has come in via /dev/ppp. */int(*ioctl)(struct ppp_channel *, unsigned int, unsigned long);static struct ppp_channel_ops async_ops = ppp_async_send,ppp_async_ioctl;(三)ppp内核发送数据过程应用程序通过socket 接口发送TCP/IP数据包,这些TCP/IP数据包如何流经PPP协议处理模块,然后通过串口发送出去呢?pppd在make_ppp_unit函数调用ioctrl(PPPIOCNEWUNIT)创建一个网络接口(如ppp0),内核中的PPP协议模块在处理PPPIOCNEWUNIT时,调用register_netdev向内核注册ppp的网络接口,该网络接口的传输函数指向ppp_start_xmit。当应用程序发送数据时,内核根据IP地址和路由表,找到ppp网络接口,然后调用ppp_start_xmit函数,此时控制就转移到PPP协议处理模块了。ppp_start_xmit调用函数ppp_xmit_process去发送队列中的所有数据包,ppp_xmit_process又调用ppp_send_frame去发送单个数据包,ppp_send_frame根据设置,调用压缩等扩展处理之后,又经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把数据发送串口。ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)ppp_xmit_process(struct ppp *ppp)ppp_push(struct ppp *ppp)pch-chan-ops-start_xmit(pch-chan, skb)ppp_async_send(struct ppp_channel *chan, struct sk_buff *skb)ppp_async_push(struct asyncppp *ap)tty-ops-write(tty, ap-optr, avail)(四)ppp内核接受数据过程接收数据的情形又是如何的?ppp_async.c在初始化(ppp_async_init),调用tty_register_ldisc向tty注册了行规程处理接口,也就是一组回调函数,当串口tty收到数据时,它就会回调ppp_ldisc的 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提交给上层协议处理,最后经 socket传递到应用程序。ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf, char *cflags, int count)ppp_async_input(ap, buf, cflags, count);ppp_async_process(unsigned long arg)ppp_input(struct ppp_channel *chan, struct sk_buff *skb)if (!pch-ppp | proto = 0xc000 | proto = PPP_CCPFRAG) /* put it on the channel queue */skb_queue_tail(&pch-file.rq, skb); /是控制协议数据包,放入pch-file.rqb队列,交给pppd处理。/* drop old frames if queue too long */while (pch-file.rq.qlen PPP_MAX_RQLEN & (skb = skb_dequeue(&pch-file.rq)kfree_skb(skb);wake_up_interruptible(&pch-file.rwait); else ppp_do_recv(pch-ppp, skb, pch); /进行PPP处理之后,再由netif_rx提交给上层协议处理(五)pppd代码整体框架流程整个程序的主体实现是从主函数的LCP_OPEN()开始的,在这个函数里,调用了有限状态机FSM_OPEN(),而在FSM_OPEN()中,callback指针指向了starting,于是就到了LCP_STARTING()函数来实现一个OPEN事件从而使得PPP状态准备从DEAD到ESTABLISHED的转变。接下来,回到主函数,下面一步是调用START_LINK(),在此函数中会把一个串口设备作为PPP的接口,并把状态转变为ESTABLISHED,然后调用lcp_lowerup()来告诉上层底层已经UP,lcp_lowerup()中调用FSM_LOWERUP()来发送一个configure-request请求,再把当前状态设置为REQSENT状态,至此,第一个LCP协商的报文已经发送出去。接下来的流程实现主要就是在这个while循环中实现了。之前说过了我们已经发送了第一个配置协商报文,所以handle_events()主要就是做等待接收数据包的时间处理了,在handle_events()里主要调用了两个函数一个是wait_input(),他的任务是等待并判断是否超时。还有一个是calltimeout()他主要是做超时的处理。当等待并未超时而且有数据包过来,则调用整个PPPD中最重要的函数get_input()函数。他主要接收过来的数据包并做出相应的动作。接下来就get_input()函数进行详细的说明,首先对包进行判断,丢弃所有不在LCP阶段和没有OPENED状态的包,然后protop指针指向当前协议的input函数。于是就进入了LCP_INPUT(),同理LCP_INPUT()调用了FSM_INPUT()对收到的包进行代码域的判断,判断收到的是什么包。假设比较顺利,我们收到的是CONFACK的包,于是调用fsm_rconack()函数,在此函数中根据当前自身的状态来决定下一步的状态如何改变,这里我们假设也很顺利,已经发送完了configure-ack,因此我们把FSM当前状态变成了OPENED状态,并把callback指针指向UP.所以我们马上就调用LCP_UP()在那里我们又调用了link_established()函数来进入认证的协商,或者如果没有认证则直接进入网络层协议。当然这里我们还是要认证的所有在LINK_ESTABLISHED()里我们选择是利用何种认证方式是PAP,还是EAP,还是CHAP.假设我们这里采用CHAP而且是选择CHAP WITH PEER,意思是等待对端先发送CHALLENGE挑战报文。于是我们又调用了chap_auth_peer()函数,并等待接收挑战报文。于是从新又来到handle_events()等待接收。再利用get_input()来接收包,在get_input()里这次调用chap_input(),再调用FSM_INPUT(),在那里我们再对包的代码域进行判断,这次判断出是CHAP_CHALLENGE包,则我们要调用chap_respond()函数来回应对端,继续等待对方的报文,再次利用CHAP_INPUT(),FSM_INPUT()来判断,如果是SUCCESS,则调用chap_handle_status(),在这个函数里调用auth_withpeer_success函数,从而进入网络层阶段,调用network_phase()函数。网络层的互动是从start_networks()开始的,如果在网络层阶段同时有CCP协议(压缩控制协议)则进行压缩控制协议的协商,然后再进入正式的IPCP的协商,而IPCP的协商主要也是通过protop指针指向IPCP_OPEN()开始的。而IPCP_OPEN()则是调用了FSM_OPEN(),在这里,首先发送一个configure-request包,然后和之前一样等待接收。经过几个交互后最后调用NP_UP()完成网络层的协商,至此PPP链路可以承载网络层的数据包了。(六)pppd程序接受数据过程Example:get_input()read_packet (unsigned char *buf) /get a PPP packet from the serial deviceread(ppp_fd, buf, len);(*protp-input)(0, p, len);-lcp_input(unit, p, len)fsm_input(f, inpacket, l)(七)pppd程序发送数据过程Example:start_link(unit)lcp_lowerup(0);fsm_lowerup(f)fsm_sdata(f, code, id, data, datalen)output (int unit, unsigned char *p, int len)write(fd, p, len)(八)pppoe内核接受数据过程(九)pppoe内核发送数据过程(十)pppoe程序接受数据过程(十一)pppoe程序发送数据过程discovery(conn);sendPADI(conn);waitForPADO(conn, timeout);parsePacket(&packet, parsePADOTags, &pc);sendPADR(conn);waitForPADS(conn, timeout);recei
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025福建泉州发展集团有限公司校园招聘52人笔试参考题库附带答案详解
- 2025年度重型设备运输合同:明确履行地点与规范交付流程
- 2025年高性能航空航天发动机零部件定制加工与销售合作协议
- 2025年城市地下网络基础设施施工与运维管理合同
- 2025年国际旅游服务及多元文化体验合作框架协议
- 2025年绿色养老住宅租赁与物业服务合同
- 2025年绿色建筑项目厂房抵押权登记与环保监测合同
- 2025商业综合体门禁系统风险评估与隐患排查合同
- 2025年金融信息安全评估及整改服务合同
- 2025年高层住宅小区智能消防设备全面检修及保养服务协议
- GB/T 19851.12-2025中小学体育器材和场地第12部分:学生体质健康测试器材
- 留疆战士考试题库及答案
- T∕CITS 146-2024 尿液有形成分名称与结果报告规范化指南
- 金属封闭母线
- 北师大版数学四年级下册全册教案设计
- 汉语拼音发音表(适合初学者和老年人)
- 《土地管理学》教学大纲
- 购物中心商场商户促销活动管理制度
- 中国工商银行个人贷款申请表
- 【教学设计】3《科学探究:物质的密度》01
- 培训体系流程图
评论
0/150
提交评论