PPP/PPPOE源码阅读笔记

一.缘起

       本人工作与网关产品有关,经常会接触到pppoe协议,但对ppp和pppoe是如何实现的不甚了解。在网上查找相关的文章大多是描述ppp/pppoe协议的具体内容和数据流大的流程,而未过多的涉及内核中pppoe驱动和ppp驱动代码实现的细节,正好这段时间在看毛德操和胡希明老师的《Linux内核源代码情景分析》,看了内核中的终端驱动,遂决定仔细学习一下PPP/PPPOE驱动这一块的内容并将这段时间的收获记录下来,以便以后翻阅同时也与大家分享。

二.关于本文

      本文不会涉及ppp协议和pppoe协议本身,即不会讨论如LCP,PAP,CHAP,IPCP,  PADI等这些报文的格式等内容,如果您仅仅想了解的是ppp和pppoe协议本身,那这篇文章并不适合你。

     如果你想了解ppp和pppoe驱动,想了解ppp程序是怎么建立起ppp网络接口的,以及ppp网络接口如何将数据通过具体的网络接口(比如eth0)发送的,具体的网络接口(比如eth0)收到数据后是怎样将数据给ppp网络接口的那这篇文章正好适合你。

    阅读本文时建议将各个部分的流程图先复制下来保存在一个文档中,然后对照着流程图来看代码。

三.代码链接

ppp代码下载链接 http://mirrors.aliyun.com/ubuntu/pool/main/p/ppp/ppp_2.4.7.orig.tar.gz

Linux-2.4.0代码下载链接https://mirrors.edge.kernel.org/pub/linux/kernel/v2.4/linux-2.4.0.tar.gz

四.代码分析

1.内容预览

       pppd命令

       ppp代码创建ppp网络接口

       pppoe驱动建立channel

       ppp驱动建立ppp网络接口并与pppoe建立的channel关联

      ppp网络接口和ppp程序收包过程

      ppp程序和ppp网络接口发包过程

2.pppd命令

pppd plugin /usr/lib/rp-pppoe.so nic-pon0.30 linkname internet nodefaultroute noipdefault noauth default-asyncmap hide-password nodetach usepeerdns mtu 1492 mru 1492 noaccomp nodeflate nopcomp novj novjccomp user aaa lcp-echo-interval 20 lcp-echo-failure 10 nopersist

3.ppp代码创建ppp网络接口

PPP/PPPOE源码阅读笔记_第1张图片

 

[ppp-2.4.7]main.c中

PPP/PPPOE源码阅读笔记_第2张图片

[ppp-2.4.7]options.c

PPP/PPPOE源码阅读笔记_第3张图片

PPP/PPPOE源码阅读笔记_第4张图片

[ppp-2.4.7]options.c 中general_options

PPP/PPPOE源码阅读笔记_第5张图片

PPP/PPPOE源码阅读笔记_第6张图片

 

PPP/PPPOE源码阅读笔记_第7张图片

PPP/PPPOE源码阅读笔记_第8张图片

PPP/PPPOE源码阅读笔记_第9张图片

 PPP/PPPOE源码阅读笔记_第10张图片

PPP/PPPOE源码阅读笔记_第11张图片

4.pppoe驱动建立channel

PPP/PPPOE源码阅读笔记_第12张图片

 

the_channel->connect()为PPPOEConnectDevice,这个函数比较长我们分段来看

PPP/PPPOE源码阅读笔记_第13张图片

 Linux代码

 PPP/PPPOE源码阅读笔记_第14张图片

上图中proto[protocol]->create即为pppoe_create,因为协议为PX_PROTO_OE,在pppoe_init中注册

 PPP/PPPOE源码阅读笔记_第15张图片

 PPP/PPPOE源码阅读笔记_第16张图片

回到PPPOEConnectDevice函数(续1)

PPP/PPPOE源码阅读笔记_第17张图片

 在openInterface中会创建socket并绑定接口,如下两图所示

 PPP/PPPOE源码阅读笔记_第18张图片

 PPP/PPPOE源码阅读笔记_第19张图片

 创建socket成功后回到PPPOEConnectDevice函数会调用discovery()函数进行pppoe协议的交互

PPP/PPPOE源码阅读笔记_第20张图片

接着看PPPOEConnectDevice函数(续2),会调用connect函数

PPP/PPPOE源码阅读笔记_第21张图片

connect函数会调用内核中的pppoe_connect,这个函数包含在pppoe_ops中,在pppoe_create中设置到sock->ops,即与我们conn->sessionSocket相关的参数中,这一过程可回看上面。

PPP/PPPOE源码阅读笔记_第22张图片

 ppp_register_channel函数会生成struct channel *pch,把pch->chan 设成 chan,并把pch放到all_channels中

PPP/PPPOE源码阅读笔记_第23张图片

5.ppp驱动建立ppp网络接口并与pppoe建立的channel关联

PPP/PPPOE源码阅读笔记_第24张图片

回到ppp的auth.c的函数start_link中the_channel->establish_ppp()为generic_establish_ppp

PPP/PPPOE源码阅读笔记_第25张图片

需要注意函数中的fd有改变开始时fd为PPPOEConnectDevice函数的返回值conn->sessionSocket,对它调用ioctl 会走到linux的

pppox_ioctl函数,该函数返回PPPOEConnectDevice[ppp代码中的plugin.c]函数调用connect创建的channel的index

PPP/PPPOE源码阅读笔记_第26张图片

接着来看 generic_establish_ppp中对fd为"/dev/ppp"调用PPPIOCATTCHAN,make_ppp_unit和PPPIOCCONNECT的动作

PPP/PPPOE源码阅读笔记_第27张图片 

调用ioctl会调用ppp_ioctl函数

PPP/PPPOE源码阅读笔记_第28张图片

 PPPIOCATTCHAN时回去找channel,很显然就是找到之前pppoe在connect创建的那个channel

PPP/PPPOE源码阅读笔记_第29张图片 

PPP/PPPOE源码阅读笔记_第30张图片

ppp中make_ppp_unit会调用PPPIOCNEWUNIT

PPP/PPPOE源码阅读笔记_第31张图片

PPP/PPPOE源码阅读笔记_第32张图片 

PPP/PPPOE源码阅读笔记_第33张图片 

PPP/PPPOE源码阅读笔记_第34张图片 

通过网络接口ppp0(假设为这个名字)发送数据时就会调用ppp_start_xmit,后面再看这个函数。

generic_establish_ppp函数中接着会调用PPPIOCCONNECT,通过ppp_connect_channel就将pppoe创建的channel和

ppp网络设备联系在一起了

PPP/PPPOE源码阅读笔记_第35张图片

 PPP/PPPOE源码阅读笔记_第36张图片

6.ppp网络接口和ppp程序收包过程

PPP/PPPOE源码阅读笔记_第37张图片

回到ppp的main函数中看ppp程序是如何接收ppp协议的数据的  

 PPP/PPPOE源码阅读笔记_第38张图片

PPP/PPPOE源码阅读笔记_第39张图片 

PPP/PPPOE源码阅读笔记_第40张图片 

内核接收数据过程

PPP/PPPOE源码阅读笔记_第41张图片

 PPP/PPPOE源码阅读笔记_第42张图片

 PPP/PPPOE源码阅读笔记_第43张图片

 PPP/PPPOE源码阅读笔记_第44张图片

 PPP/PPPOE源码阅读笔记_第45张图片

 PPP/PPPOE源码阅读笔记_第46张图片

 PPP/PPPOE源码阅读笔记_第47张图片

PPP/PPPOE源码阅读笔记_第48张图片 

PPP/PPPOE源码阅读笔记_第49张图片 

 PPP/PPPOE源码阅读笔记_第50张图片

PPP/PPPOE源码阅读笔记_第51张图片 通过ppp_receive_nonmp_frame函数大家可以看到根据收到的数据包的协议是ppp控制包还是普通网络包比如ipv4包,走不同的分支,如果是ppp协议控制包就将其放到ppp->file.rq中,我们的ppp程序会收到这个包,如何是普通的网络包就通过netif_rx进入网络协议栈。

7.ppp程序和ppp网络接口发包过程

PPP/PPPOE源码阅读笔记_第52张图片

 

     PPP/PPPOE源码阅读笔记_第53张图片

 

PPP/PPPOE源码阅读笔记_第54张图片

PPP/PPPOE源码阅读笔记_第55张图片

PPP/PPPOE源码阅读笔记_第56张图片

PPP/PPPOE源码阅读笔记_第57张图片

PPP/PPPOE源码阅读笔记_第58张图片

这个pch->chan->ops->start_xmit(pch->chan, skb)调用的是pppoe_xmit,接下来我们看为什么是pppoe_xmit

这个channel是通过pppoe套接字然后调用connect方法创建的,创建时po->chan.ops = &pppoe_chan_ops;所以start_xmit就是pppoe_xmit

PPP/PPPOE源码阅读笔记_第59张图片

PPP/PPPOE源码阅读笔记_第60张图片

 PPP/PPPOE源码阅读笔记_第61张图片

 

你可能感兴趣的:(PPP/PPPOE源码阅读笔记)