Linux PPP 數據收發流程

 

PPP(Point- to-Point)提供了一種標準的方法在點對點的鏈接上傳輸多種協議數據包,它最多見的用途多是傳統的撥號上網了(聽說如今的寬帶接入也有采用 PPPOE方式的)。在Linux Mobile Phone上,網絡應用程序使用PPP做爲與GSM模組之間的通訊協議,最近遇到了一點關於PPP的麻煩,因此花了點時間去研究它。編程

PPP 協議確定不是最複雜的網絡協議,不過pppd、chat、tty、socket、ccp、chap、pap、eap、ecp、ipcp和不少其它概念攪在一塊兒以後,誰都會被搞得暈頭轉向。我關心的實際上是PPP協議中各個實體之間的協做關係,而不是協議的狀態轉換或者服務的配置,因爲沒有找到這方面的資料,只好去讀RFC,內核、pppd和一些網絡工具的代碼。瀏覽器

PPP協議提供兩個實體之間的數據鏈路鏈接的創建、維持和釋放,負責流量和差錯控制等等功能,因此它應該是屬於數據鏈路層協議的。網絡

PPP 協議之下是以太網和串口等物理層,之上是IP協議等網絡層。這裏,對於下層,咱們只討論串口的狀況,對於上層,咱們只討論TCP/IP的狀況。發送時,TCP/IP數據包通過PPP打包以後通過串口發送。接收時,從串口上來的數據經PPP解包以後上報給TCP/IP協議層。socket

網絡協議是分層實現的,上層通常只須要知道其直接下層,只有在極少數據狀況才使用間接下層的接口。好比,彩信、瀏覽器和郵件等應用程序使用socket接口編程,它們只須要知道TCP/IP協議,而無須要知道PPP協議的存在。這種分層設計簡化了協議的實現和應用程序的開發。async

問題來了:PPP 協議不僅是提供了簡單的數據鏈路層功能,它還提供了諸如鑑權(如PAP/CHAP),數據壓縮/解壓(如CCP)和數據加密/解密(如ECP)等擴展功能。應用程序要求使用透明化,不關心這些擴展功能的存在,而反過來,PPP協議處理模塊自己又沒法處理這些策略性的東西,由於它不知道用戶名/密碼,不知道是否要進行壓縮,不知道是否要進行加密。ide

怎麼辦?如何在對應用程序透明的狀況下使用擴展功能呢?上帝說,這個問題必須解決!因而pppd就出現了。pppd是一個後臺服務進程(daemon),是一個用戶空間的進程,因此把策略性的內容從內核的PPP協議處理模塊移到pppd中是很天然的事了。pppd實現了全部鑑權、壓縮/解壓和加密/解密等擴展功能的控制協議。函數

pppd只是一個普通的用戶進程,它如何擴展PPP協議呢?這就是pppd與內核中的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函數完成的。設計

chat是pppd所帶一個輔助工具。呵,它和xchat不是一個類型的,xchat用來與人聊天,而chat用來與GSM模組創建會話。它的實現比較簡單,它向串口發送AT命令,創建與GSM模組的會話,以便讓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把數據發送串口。

用戶數據發送過程以下圖所示:

pppd的控制協議數據發送過程以下圖所示:

反過來,接收數據的情形又是如何的?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協議的流程基本清楚了,不過還有很多細節有待進一步研究。

相關文章
相關標籤/搜索