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-2.4.7]main.c中

[ppp-2.4.7]options.c

[ppp-2.4.7]options.c 中general_options

 

 

4.pppoe驅動建立channel

 

the_channel->connect()爲PPPOEConnectDevice,這個函數比較長我們分段來看

 Linux代碼

 

上圖中proto[protocol]->create即爲pppoe_create,因爲協議爲PX_PROTO_OE,在pppoe_init中註冊

 

 

回到PPPOEConnectDevice函數(續1)

 在openInterface中會創建socket並綁定接口,如下兩圖所示

 

 

 創建socket成功後回到PPPOEConnectDevice函數會調用discovery()函數進行pppoe協議的交互

接着看PPPOEConnectDevice函數(續2),會調用connect函數

connect函數會調用內核中的pppoe_connect,這個函數包含在pppoe_ops中,在pppoe_create中設置到sock->ops,即與我們conn->sessionSocket相關的參數中,這一過程可回看上面。

 ppp_register_channel函數會生成struct channel *pch,把pch->chan 設成 chan,並把pch放到all_channels中

5.ppp驅動建立ppp網絡接口並與pppoe建立的channel關聯

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

需要注意函數中的fd有改變開始時fd爲PPPOEConnectDevice函數的返回值conn->sessionSocket,對它調用ioctl 會走到linux的

pppox_ioctl函數,該函數返回PPPOEConnectDevice[ppp代碼中的plugin.c]函數調用connect創建的channel的index

接着來看 generic_establish_ppp中對fd爲"/dev/ppp"調用PPPIOCATTCHAN,make_ppp_unit和PPPIOCCONNECT的動作

 

調用ioctl會調用ppp_ioctl函數

 PPPIOCATTCHAN時回去找channel,很顯然就是找到之前pppoe在connect創建的那個channel

 

ppp中make_ppp_unit會調用PPPIOCNEWUNIT

 

 

 

通過網絡接口ppp0(假設爲這個名字)發送數據時就會調用ppp_start_xmit,後面再看這個函數。

generic_establish_ppp函數中接着會調用PPPIOCCONNECT,通過ppp_connect_channel就將pppoe創建的channel和

ppp網絡設備聯繫在一起了

 

6.ppp網絡接口和ppp程序收包過程

回到ppp的main函數中看ppp程序是如何接收ppp協議的數據的  

 

 

 

內核接收數據過程

 

 

 

 

 

 

 

 

 

通過ppp_receive_nonmp_frame函數大家可以看到根據收到的數據包的協議是ppp控制包還是普通網絡包比如ipv4包,走不同的分支,如果是ppp協議控制包就將其放到ppp->file.rq中,我們的ppp程序會收到這個包,如何是普通的網絡包就通過netif_rx進入網絡協議棧。

7.ppp程序和ppp網絡接口發包過程

 

    

 

這個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

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章