1. 前言
PPPOE(PPP over Ethernet, RFC2516,值得注意的是此RFC不是Standard而是Information類型的)定義了如何在乙太網上傳輸PPP資料包的方法,目前流行的寬頻類型
ADSL就是通過PPPoE實現的。
2. 通信過程概述
建立PPPOE通道(ADSL撥號)分兩個階段:發現階段和PPP會話階段。
在發現階段,乙太網上的客戶機要找到一個訪問集中器(AC,Access Concentrator),就是ADSL MODEM,一般家用時一般就只有一個AC;但如果是一個乙太網內可能會有多條ADSL,就會有多個AC,這時客戶機就從中選擇一個。發現階段完成後,客戶機和AC都得到要在乙太網上建立PPP通道的相關資訊。
發現階段是無狀態的,也就是兩邊都不用保存以前的狀態資訊;只有PPP會話開始後,雙方就要建立一個虛擬的PPP通信介面,具體在Linux下會有ppp0網卡,在windows下網路連接中增加ADSL的介面。
3. 協議頭格式
3.1 協議值
PPPOE資料是直接在乙太頭資料之上的,其等級和ARP、IP等是相同的,在乙太頭的類型欄位中,用0x8863 表示是PPPOE發現階段資料,用0x8864表示PPP會話階段資料,如下所示。(類比:0x0800表示IP資料,0x0806表示ARP資料)
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| DESTINATION_ADDR |
| (6 octets) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SOURCE_ADDR |
| (6 octets) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ETHER_TYPE (2 octets) |
| 0x8863 or 0x8864 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| PPPOE Header |
| (6 octets) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
~ ~
~ payload ~
~ ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| CHECKSUM |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3.2 PPPOE協議頭
1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| VER | TYPE | CODE | SESSION_ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| LENGTH | payload ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
PPPOE協定頭有6個位元組,正好和14位元組的乙太頭實現了4位元組對齊,包括以下欄位:
VER:版本號,4位,必須為0x01
TYPE:類型,4位,必須是0x01
CODE:8位,在發現階段和PPP會話階段有不同的定義,表示PPPOE資料類型
SESSION_ID:16位,用來定義一個PPP會話,在發現過程中定義。
LENGTH:16位元,表示負載長度,不包括乙太頭和PPPOE頭。
4. 發現階段
PPPOE發現階段資料的乙太類型是0x8863。
4.1 TAG
在發現階段用於交換客戶機和AC的資訊,建立PPPOE通道,負載資訊都是PPPOE資訊,並沒有上層協定資料。
發現階段的負載稱為TAG,一個TAG資訊格式如下,負載資訊中可能會包含多個TAG:
1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| TAG_TYPE | TAG_LENGTH |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| TAG_VALUE ... ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
TAG_TYPE:16位,TAG類型
TAG_LENGTH:16位元,表示TAG_VALUE部分的長度
TAG_VALUE:TAG值
TAG_TYPE可取以下值(注意第一位元組為2表示是錯誤資訊):
0x0000 End-Of-List
0x0101 Service-Name
0x0102 AC-Name
0x0103 Host-Uniq
0x0104 AC-Cookie
0x0105 Vendor-Specific
0x0110 Relay-Session-Id
0x0201 Service-Name-Error
0x0202 AC-System-Error
0x0203 Generic-Error
4.2 PPPOE主動發現初始包
PPPOE主動發現初始包(PPPoE Active Discovery Initiation, PADI)由客戶機發出,乙太頭中的目的地址是乙太廣播位址FF:FF:FF:FF:FF:FF,PPPOE頭中的CODE為 0x09,SESSION_ID值必須為0,負載部分必須只包含一個Service-Name類型的TAG表示請求的服務類型,另外可以包含其他TAG,整個PPPOE包不能超過1484位元組,這樣省出的16位元組可以由ADSL中繼設備添加中繼TAG。
一個PADI包的例子為:
1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0xffffffff |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0xffff | Host_mac_addr |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Host_mac_addr (cont) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ETHER_TYPE = 0x8863 | v = 1 | t = 1 | CODE = 0x09 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SESSION_ID = 0x0000 | LENGTH = 0x0004 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| TAG_TYPE = 0x0101 | TAG_LENGTH = 0x0000 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4.3 PPPOE主動發現提議包
PPPOE主動發現提議包(PPPoE Active Discovery Offer, PADO)由AC發出,用來回應客戶機的PADI包,乙太頭中的目的地址是客戶機的MAC地址,PPPOE頭中的CODE為 0x07,SESSION_ID值必須為0,負載部分必須包含一個AC-Name類型的TAG,用來指示本AC的名稱,一個在PADI包中指定的 Service-Name的TAG,另外可以包含其他Service-Name的TAG。如果AC不對該客戶機提供服務,AC就不回應PADO包。
一個PADO包的例子為:
1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Host_mac_addr |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Host_mac_addr (cont) | Access_Concentrator_mac_addr |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Access_Concentrator_mac_addr (cont) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ETHER_TYPE = 0x8863 | v = 1 | t = 1 | CODE = 0x07 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SESSION_ID = 0x0000 | LENGTH = 0x0020 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| TAG_TYPE = 0x0101 | TAG_LENGTH = 0x0000 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| TAG_TYPE = 0x0102 | TAG_LENGTH = 0x0018 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x47 | 0x6f | 0x20 | 0x52 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x65 | 0x64 | 0x42 | 0x61 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x63 | 0x6b | 0x20 | 0x2d |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x20 | 0x65 | 0x73 | 0x68 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x73 | 0x68 | 0x65 | 0x73 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x68 | 0x6f | 0x6f | 0x74 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4.4 PPPOE主動發現請求包
PPPOE主動發現請求包(PPPoE Active Discovery Request, PADR)由客戶機發出,因為可能會有多個AC對客戶機發出的PADI包回應了PADO包,客戶機從回應的PADO包中選擇一個AC發送PADR包,乙太頭中的目的地址是該AC的MAC地址,PPPOE頭中的CODE為0x19,SESSION_ID值必須為0,負載部分必須只包含一個Service- Name類型的TAG表示請求的服務類型,另外可以包含其他TAG。
4.5 PPPOE主動發現會話確認包
PPPOE主動發現會話確認包(PPPoE Active Discovery Session-confirmation, PADS)由AC發出,收到客戶機的PADR包後,AC將產生一個SEESSION_ID值用來標誌本次PPP會話,以PADR包方式發送給客戶機。乙太頭中的目的地址是客戶機的MAC地址,PPPOE頭中的CODE為0x65,SESSION_ID值必須為所生成的那個SESSION_ID,負載部分必須只包含一個Service-Name類型的TAG,表示該服務類型被AC接受,另外可以包含其他TAG。如果AC不接受PADR中的Server- Name,PADS中則包含一個Service-Name-Error類型的TAG,這時SESSION_ID設置為0。
4.6 PPPOE主動發現停止包
PPPOE主動發現停止包(PPPoE Active Discovery Terminate, PADT)表示PPPOE會話過程的結束,AC和客戶機都可以主動發出。乙太頭中的目的地址是對方的MAC地址,PPPOE頭中的CODE為 0xa7,SESSION_ID值必須為PPPOE會話過程的SESSION_ID,不需要TAG。
5. PPP會話階段
在PPP會話階段,PPP包被封裝在PPPOE乙太幀中,乙太包目的地址都是單一的,乙太協定為0x8864,PPPOE頭的CODE必須為 0,SESSION_ID必須一直為發現階段協商出的SEESION_ID值,PPPOE的負載是整個PPP包,PPP包前是兩位元組的PPP協定ID值。
一個PPPOE會話過程包的例子為:
1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Access_Concentrator_mac_addr |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Access_Concentrator_mac_addr(c)| Host_mac_addr |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Host_mac_addr (cont) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ETHER_TYPE = 0x8864 | v = 1 | t = 1 | CODE = 0x00 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SESSION_ID = 0x1234 | LENGTH = 0x???? |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| PPP PROTOCOL = 0xc021 | PPP payload ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
注意:由於PPPOE頭是6位元組,PPP協定ID號兩個位元組,一共要佔用8個位元組,而乙太網的MTU值為1500,所以上層PPP負載資料不能超過1492位元組,所以PPP協商時協商的最大接收單元值不能超過1492位元組,也就是相當於在PPPOE環境下的MTU是1492位元組。
6. ADSL撥號過程簡述
客戶機啟動撥號程式,發送PADI包,ADSL MODEM回應PADO包,客戶機再發送PADR包,ADSL MODEM回應PADS包後建立PPPOE通道,隨後客戶機進行普通的PPP協議撥號過程,不過PPP資料包都是包裝進乙太幀中的,撥號成功後客戶機和伺服器之間建立了PPP通道,ADSL MODEM起到將乙太幀轉換為PPP包的作用。ADSL雖然是用電話線,但所用頻率不是通話用的頻率,所以ADSL撥號不影響打電話。通信結束後,會發送 PADT斷開PPPOE通道。
7. 結論
由於ADSL的大面積使用,PPPOE也隨之應用,瞭解其通信協定和資料格式對於底層驅動的開發、協定分析、存取控制等是必要的,現在不論在windows還是linux下都可以很好地支援PPPOE。