2016年10月4日 星期二

TDI Operations - XII

Closing a Transport Address or Control Channel

在關閉任何關聯的連接以後,一個TDI客戶準備好去關閉一個開啟的傳輸位址。

當一個客戶對於開啟的傳輸位址或是控制通道不在使用,它必須如下釋放這些物件:

以相同的方式,一個TDI客戶也可以關閉任何的控制通道。如果客戶端開啟一個表示為控制通道的檔案物件(藉由調用 IoGetDeviceObjectPointer 得到),則它必須將這個檔案物件作為參數,然後調用 ObDereferenceObject 來釋放這個物件。接下來,I/O管理員會向傳輸端的TdiDispatchCleanup以及TdiDispatchClose 例程提交IRPs

這些傳輸端的例程(routines)會立即的關閉傳輸位址或是控制通道,並且釋放所有有關客戶指定的傳輸驅動資源。例如,TdiDispatchCleanup取消所有在傳輸位址上等待處理(pending)請求,解除所有在此位址上註冊過的ClientEventXxx處理函式,並且清除此位上的客戶狀態。如果這個客戶已經釋放了傳輸位址上最後的file handle傳輸也會為此傳輸位址釋放內部的狀態。

在客戶端收到ZwClose的回傳以後,它就不能再向這個傳輸位址或是控制通道提交一個請求。這意味著這個表示為傳輸位址或是控制通道的檔案物件不復存在。

TDI Operations - XI

Closing a Connection Endpoint

下圖示範一個核心模式客戶如何關閉一個連接端點。









在一個點對點連線已經斷線以後,一個客戶可以關閉連接端點。當一個客戶不在需要使用一個開啟的連接端點(connection endpoint),它必須如下關閉連接端點:

接者,I/O管理員提交 IRPs 到傳輸端的 TdiDispatchCleanup,以及之後的 TdiDispatchClose 例程。

這些傳輸例程立即的關閉連接端點並且釋放所有相關的傳輸驅動資源。TdiDispatchCleanup 也透過發送一個斷線通知給對應的遠端節點傳輸終止所有的連線活動。


如前述, 在建立一個關閉連線端點請求之前,TDI客戶不需要撇清(disassociate)連接端點與它所關聯的傳輸位址。如有需要,底層傳輸會模擬一個撇清的影響。

然而,一個客戶可以在關閉連線端點之前,明確的透過 TDI_DISSOCIATE_ADDRESS 請求來撇清(disassociate)一個連接端點與一個開的傳輸位址,這可以使用 TdiBuildDisassociateAddress 來封裝這個請求。

TDI Operations - X

Disconnecting an Endpoint-to-Endpoint Connection

下圖示範一個TDI客戶如何釋放一個點對點連接。

斷線行為是傳輸特的性質。當一個連導向TDI客戶發起一個斷線,兩個節點會進行斷線操作。也就是說,當一個客戶發起一個斷線,則遠端節點客戶必須回應這個請求。

在一個斷線操作期間,TDI傳輸驅動在開啟的連接端點通常會拒絕進入的請求,並且在指定的連接端點停止所有的活動。

如上圖所示,一個客戶在一個點對點連線上可以透過提交一個 TDI_DISCONNECT 請求來發起一個斷線操作。客戶可以透過 TdiBuildDisconnect 來封裝並交給底層傳輸。當傳輸結束了客戶端的請求,它會通知遠端節點傳輸驅動一個斷線正在進行,並且這個傳輸在點對點連線上為了客戶提交的I/O請求開始回傳一個適合的狀態碼。

如果回應的客戶註冊它的 ClientEventDisconnect 處理函式,當斷線發生的時候TDI傳輸會通知客戶。接者,ClientEventDisconnect 建立一個 TDI_DISCONNECT 來對底層的傳輸確認這個斷線。這個通知允許回應的客戶立即的清除客戶為了點對點連線所配置的狀態。

然而,一個斷線操作並不會關閉客戶端所開的連接端點或是傳輸位址。在 TDI_DISCONNECT 完成以後,客戶還是可以重新使用這些檔案物件。例如,客戶在稍後建立網路連線,這在Making an Endpoint-to-Endpoint Connection有介紹過。一直到每個客戶關閉它的連接端點以及關聯的傳輸位址前,這些資源都會保留給客戶提交的IOCTL請求使用。這在稍後Closing a Connection Endpoint以及Closing a Transport Address or Control Channel分別的會被介紹。

TDI Operations - IX

Requesting Transport-Specific Actions

如果傳輸驅動有定義擴展TDI,則在下圖示範了一個TDI客戶如何建立一個傳輸指定動作 (transport-specific action) 請求。

一個TDI客戶端可以對TDI傳輸驅動發送一個特殊或專有的擴展請求(這些操作定義在一個傳輸指定動作碼的集合)。這些擴展可以是關注一個開的位址,一個開的連接端點,或是一個開的控制通道,這僅限定在調用的客戶端而不是其他任何的TDI傳輸客戶或是驅動。

要請求這樣一個傳輸定義動作操作,首先客戶必須開位址,連接端點,或是控制通道,就想之前提到的Opening a Transport Address, Opening a Connection Endpoint, 或是 Setting and Querying Information。接下來,客戶可以使用 TdiBuildAction 來封裝 TDI_ACTION 請求以及客戶提供的緩衝區(內含傳輸定義的動作碼(action code)以及相關的動作參數)


TDI Operations - VIII

Connection-Oriented Versus Connectionless Transfers

TDI提供一個在傳輸層上最小成本最高品質的連線導向服務。根據特定的驅動協定,這可以涉及客戶數據的打包,sequencing, acknowledgment, retransmission, flow-control, 以及 error recovery。 

TDI也提供數據報一個無連線服務。而這些服務都是輕量級的:它不需要提供error-free delivery 或是 flow control。傳輸階層通常不會分割或是重組數據報。在TDI傳輸上,傳遞無連線數據擁有最輕的負擔。

數據報的發送在本質上是一個不可靠的網路通信。發送的客戶無法得知在遠端節點位址上有多少個已經開的客戶,或是遠端節點客戶是否正在接收數據。此外,根據傳輸驅動作者的裁量權,本地節點TDI驅動可能會丟失或是複製一份數據報。相比之下,本地端節點傳輸在一個已經建立的點對點連線之下,在遠端節點傳輸接受數據並且回覆確認(acknowledged)之前,會負責重新嘗試發送數據。

就像一個數據報的發送,接收數據報的操作也是不可靠的。根據傳輸驅動作者的裁量權,本地節點TDI驅動可能會丟失或是複製一份接收到的數據報。相比之下,本地端節點傳輸在一個已經建立的點對點連線之下,在本地客戶接受(否決)數據並且回覆遠端節點確認(acknowledged)之前,會負責接收。

一個點對點連線會一直保持活動,直到一個斷線操作發生(在稍後的Disconnecting an Endpoint-to-Endpoint Connection會有介紹),或者是底層傳輸沒有收到遠端節點的回應的時候(超時以後斷線)

TDI Operations - VII

Sending and Receiving Connectionless Data

一旦核心模式的客戶端成功對底層傳輸開一個傳輸位址(transport address),他就可以在網路上使用無連線通信(connectionless communication)的方式傳輸數據。

要使用這種方式接收數據,客戶端必須向他的底層傳輸註冊它的ClientEventReceiveDatagram或者是明確的對底層傳輸發布一個TDI_RECEIVE_DATAGRAM請求。

更多有關開一個傳輸位址以及對指定的位址註冊一個事件處理函式,可以參考 Opening a Transport Address.

Sending a Datagram

下圖示範一個TDI客戶如何發送一個數據報(datagram)到遠端節點。


如本圖所示,發送一個數據報類似於發送一個連線導向的數據。然而,本地端節點客戶對於一個開的傳輸位址提交一個TDI_SEND_DATAGRAM請求,這取代了一個點對點連線上的發送方式。

一個TDI_SEND_DATAGRAM IRP請求底層傳輸發送一個客戶端提供的數據報到一個特定位址上的一個未知數量的遠端節點客戶。

本地端客戶可以使用TdiBuildSendDatagram來封裝這個請求。隨著目標的遠端節點位址,客戶端可以提供任何大小的緩衝區數據(在傳輸端允許範圍之內)。客戶端可以透過詢底層傳輸來確定這個長度限制,這在 Setting and Querying Information已經有介紹過了。

Receiving a Datagram

下圖示範了一個核心模式的客戶如何從它的底層傳輸接收一個來自於遠端節點的數據報(datagram)

如本圖所示,接收一個數據報類似於接收一個連線導向數據。然而,本地端節點客戶對於一個開啟的傳輸位址提交一個TDI_RECEIVE_DATAGRAM請求,這取代了一個點對點連線上的接收方式。

然而,客戶端可以接收來自於遠端節點所發送的數據報(此遠端節點位址是由本地客戶所開啟的傳輸位址作為數據報的目的地)。其它本地端客戶只要開啟相同的傳輸位址都可以接收相同的數據報。

一個TDI_RECEIVE_DATAGRAM IRP請求底層傳輸回傳一個來自於遠端節點的數據報。本地節點客戶可以使用TdiBuildReceiveDatagram來封裝這一個請求。隨著一個表示為開啟傳輸位址的檔案物件,客戶提供TDI傳輸驅動一個緩衝區(TDI傳輸所允許接收長度範圍之內)。由於TDI傳輸絕不會分段數據報,所以本地端節點客戶通常會發布一個接收數據報請求(receive-datagram request)來接收一個數據報。

當完成這樣一個請求時,傳輸驅動會複製一份接收的數據報到客戶所提供的緩衝區,並且會回傳遠端節點這個IRP已經完成。如果收到的數據報超出緩衝區大小,則傳輸會切斷超出的數據。

當完成這樣一個請求時,傳輸驅動會複製一份接收的數據報到客戶所提供的緩衝區,並且會回傳遠端節點這個IRP已經完成。如果收到的數據報超出緩衝區大小,則傳輸會切斷超出的數據。

客戶端也可以透過底層TDI傳輸驅動的事件通知來接收遠端的數據報。對於這些通知事件,傳輸驅動會移除TSDU的檔頭(來自遠端節點),並且調用客戶端所註冊的ClientEventReceiveDatagram或是ClientEventChainedReceiveDatagram處理函式。ClientEventReceiveDatagram可以執行下列操作之一:
  • 立即回傳一個未接受(not-accepted)的狀態,並且明確的告知傳輸驅動這個TSDU不是客戶端有興趣的。
  • 如果傳輸僅提供部分的數據,則複製部分數據到內部緩衝區並封裝一個TDI_RECEIVE_DATAGRAM來請求剩餘的TSDU數據,接著回傳控制權。
  • 複製所有的TSDU到內部緩衝區並回傳控制權。

如果客戶端沒有複製數據或是回傳一個IRP,則非緩衝(Nonbuffering)傳輸驅動可以在接收數據報事件指示後丟棄數據。緩衝式的傳輸驅動則會保留一定數量的數據報訊息,讓它的客戶可以在稍後透過明確的TDI_RECEIVE_DATAGRAM請求來重新獲得數據。

透過底層傳輸,ClientEventChainedReceiveDatagram處理函式總是獲得僅讀取(read-only access)完整TSDU的權限。隨後,這個例程不需要發布一個TDI_RECEIVE_DATAGRAM請求到底層傳輸。然而,客戶端負責立即的調用 TdiReturnChainedReceives 來回傳由NDIS微阜驅動所配置的資源。

2016年10月3日 星期一

TDI Operations - VI

Sending and Receiving Connection-Oriented Data

TDI客戶在不同的節點彼此傳送接收連線導向數據必須要建立一個點對點的連接。在傳輸數據之前,每一個客戶必須做以下的事情:
  1. 開啟一個傳輸位址( transport address)。
  2. 開啟一個連接端點(connection endpoint)。
  3. 關聯開啟的傳輸位址與連接端點。
  4. 建立彼此之間的點對點連接,一個負責發起連接請求,其他負責接收這個請求。
實際上,一旦本地節點傳輸對遠端節點傳輸發送一個連結接受偵(connection-acceptance frame),則接收連結請求的客戶就可以接受來自於遠端節點的數據。

在透過底層傳輸完成點對點連線以後,客戶端彼此之間可以跨過網路傳送數據。

Sending Data on an Endpoint-to-Endpoint Connection

下圖示範一個核心模式的客戶如何在一個點對點連接之間發送數據。

本地端節點的TDI客戶發布一個發送(send)請求,要求本地傳輸從連結端點發送一筆數據至遠端的連結端點。要做到這個,本地端節點的客戶會提交一個 TDI_SEND 的控制請求給他的底層傳輸。客戶端可以使用 TdiBuildSend 來包裝這個IRP,並且裡面包含了一個客戶端提供的緩衝區指標,其內容包含一個stream-oriented 或是message-oriented TSDU。這個緩衝區的最大長度只要在TDI傳輸允許的範圍之內就可以。如果傳輸支援快速發送(expedited sends),則客戶可以請求發布一個快速數據,這個請求會排在傳輸驅動佇列(queue)中其他已經在等待傳送的普通發送(normal sends)請求之前優先來處理。如果傳輸驅動支援內部緩衝,則客戶可以發布一個非阻塞(nonblocking)發送請求。

客戶調用 IoCallDriver 轉發TDI_SENDIRP到底層傳輸的TdiDispatchInternalDeviceControl例程。這個例程會檢MinorFunction  並更進一步地的調用內部的發送函式來處理這個IRP。發送請求,如果客戶已經提交其他的發送請求,並且這些請求還沒被處理,則內部驅動函式會將這個新的發送請求放置佇列當中。傳輸總是將快速請求數據排在正常的TSDUs之前處理。而無論是普通或是快速,都是使用FIFO的順序來發送客戶端要求的命令。在傳輸完成每一個客戶提交的TDI_SEND IRP之前,傳輸也會複製客戶提供的數據到內部緩衝區或是在網路中發送指定的數據。

如果底層傳輸的內部緩衝區不足,導致一個非阻塞(nonblocking)發送請求失敗。則當傳輸驅動有可用的緩衝區位置可以傳輸時,傳輸驅動會調用客戶註冊的 ClientEventSendPossible 處理函式, 通知客戶可以重新提交一個TDI_SEND的請求。

Receiving Data on an Endpoint-to-Endpoint Connection

下圖示範一個核心模式的客戶如何在點對點連接之間接收數據。


無論是普通(normal)或是快速(expedited),在兩端節點連線的情況下,本地端節點可以透過發送 TDI_RECEIVE 請求給底層傳輸來接收一個TSDU。客戶端可以使用 TdiBuildReceive 來封裝這個IRP,其內包含了客戶端提供的緩衝區位址(接收來自於傳輸端複製全部或是部分TSDU的數據)。緩衝區的長度可以是TDI傳輸驅動所允許的範圍之內。

客戶端調用IoCallDriver來轉發TDI_RECEIVE IRP給底層傳輸TdiDispatchInternalDeviceControl例程。此例程會檢MinorFunction 並且更進一步的調用內部函式來處理這個IRP。內部驅動會不間斷地轉移接收到的數據到客戶端所提供的緩衝區直到緩衝區收滿或是接收的TSDU枯竭。

然而,在接收操作期間,快速(expedited)數據的優先權高於普通(normal)數據。如果一個快速TSDU從一個遠端節點進入,而此時傳輸正在處理一個客戶提交的普通數據接收請求。則無論有多少普通的TSDU數據已經轉移到客戶端提供的緩衝區,傳輸端都會完成這個客戶端的IRP請求,接者,傳輸端會處理快速數據接收直到命令完成,而客戶端必須發布其他的TDI_RECEIVE來獲得剩餘的普通TSDU數據。


當一個底層TDI傳輸驅動通知一個事件發生,客戶也可以藉此接收一個來自於遠端節點的數據。對於這些通知事件,傳輸驅動會移除TSDU(從遠端節點所接收)的傳輸層檔頭(transport layer header), 並且調用客戶端所註冊的ClientEventReceive, ClientEventChainedReceive,ClientEventReceiveExpedited, ClientEventChainedReceiveExpedited 處理程序。

客戶端事件處理程序在稍後會複製數據。如果ClientEventReceive或是ClientEventReceiveExpedited沒有接收到所有的數據,他可以做以下的事情:
  • 立即返回未接受(not-accepted)的狀態,清楚的告知底層傳輸這個接收到的TSDU是客戶端不感興趣的。
  • 建立其他的TDI_RECEIVE接收請求來獲得剩餘的TSDU數據。
  • 依靠後續的驅動接收事件通知來獲得剩餘的數據。

底層傳輸驅動程式總是賦予ClientEventChainedReceiveClientEventChainedReceiveExpedited 處理程序僅讀取(read-only)完整TSDU的權限。因此,這些例程不需要發布一個 TDI_RECEIVE 的請求到底層傳輸,或是處理部分接收的TSDUs。然而,TDI客戶端驅動程式負責立即的調TdiReturnChainedReceives來返回相關聯的資源(初始由NDIS微阜驅動所配置)

2016年9月29日 星期四

TDI Operations - V

Making an Endpoint-to-Endpoint Connection

TDI客戶端在不同的網路節點與他各自的傳輸共同合作,在他們彼此之間建立點對點的連接。而在試圖嘗試連接之前,每一個客戶對它的在節點必須做下列的處理:
1.  開啟一個傳輸位址,同Opening a Transport Address
2.  開啟一個連結端點,同Opening a Connection Endpoint
3. 透過TDI_ASSOCIATE_ADDRESS關聯開啟的連與位址。

然後,其中一個客戶端對其他人建立一個連接,通常其他人都處於被動的聆聽(listen)連接到來。

如果客戶端對它底層傳輸註冊了它的ClientEventConnect。則當有任何來自於遠端節點的連接,則傳輸驅動會調用ClientEventConnect

Requesting a Connection to a Remote Node

下圖示範一個本地端節點的TDI客戶如何對遠端節點啟動一個連接處理。


本地端節點客戶透過提交一個TDI_CONNECT請求來對遠端節點建立一個連接處理,客戶可以透過TdiBuildConnect來封裝這個請求。

本地端節點傳輸從它的客戶端那裏確定遠端節點的位址,並且與遠端節點傳輸合作傳輸連結工作。

如果在之前遠端節點的客戶端有提交一個TDI_LISTEN請求或是註冊ClientEventConnect處理程序,則當有一個連接請求進入時,遠端節點傳輸會通知它的客戶。

如果遠端節點客戶沒有聆聽(listen)或是沒有回應,則本地端節點傳輸會得到連接失敗的結果。遠端節點可以接受或是拒絕連結,如果傳輸支援delayed-connection acceptance,在稍後會有描述。

Accepting a Connection Offer from a Remote Node

下圖示範一個本地端節點客戶如何聆聽一個來自於遠端節點的連接處理。

要建立一個點對點連接,一個客戶會提出一個連接請求,然後其他客戶會對它底層傳輸示意等待一個連接請求的來臨。

本地端節點客戶可以透過提交一個TDI_LISTEN請求來被動地聆聽一個正要進入的連結,客戶可以透過TdiBuildListen來封裝這個請求。當客戶在設定聆聽(listen)IRP時,可以指定可以接收請求發生的遠端節點傳輸位址。如果傳輸支援delayed-connection acceptances,則客戶端可以指定傳輸立即的接收來自於遠端節點的連接,或是允許客戶檢這個請求並且決定是否要接收。

當傳輸接收一個TDI_LISTEN請求,它會監視來自於遠端節點的連接。當它接收到一個遠端位址的連接,傳輸會複製交易的訊息到本地客戶端配置的緩衝區,並且會完成IRP給監聽的客戶端。

接收一個連接有更簡單的方式,如果本地端客戶使用事件處理函式。當傳輸接收一個來自遠端節點的連接,則傳輸會調用客戶端註冊的ClientEventConnect處理函式。ClientEventConnect接者會接收或是否決這個請求。

2016年9月26日 星期一

TDI Operations - IV

Setting and Querying Information

下圖示範一個TDI客戶如何詢問底層傳輸的特徵或是對底層傳輸設定狀態數據。

一個TDI客戶可以詢問某些傳輸驅動的資訊,例如連接狀態的訊息,在一個特定傳輸位址的激活,數據報大小與數量的限制,驅動統計,以及內部收發緩衝區的大小。一個客戶也可以對底層傳輸設定一些狀態訊息,雖然這不能透過發送設定請求來覆寫底層傳輸所定義的某些限制大小值。

如果一個客戶希望詢問有關一個開傳輸位址或是一個連接端點的訊息,它可以提交一個TDI_QUERY_INFORMATION請求,客戶可以透過TdiBuildQueryInformation來封裝請求給底層傳輸。當它使用這個巨集,客戶會使用位址或是連接端點的檔案物件指標以及客戶所配置的緩衝區(用於接收底層傳輸回傳資訊)作為參數。

要設定傳輸訊息,客戶端發布一個TDI_SET_INFORMATION請求,並且透過TdiBuildSetInformation來封裝。

對於每一個操作,客戶也通過一個系統定義的TDI_QUERY_XXX作為 TdiBuild..巨集的參數。QType或是SType分別決定可以詢問以及設定的訊息類型。

查詢或是設定訊息並沒有特別關注一個位址或是一個連接端點,客戶在查詢/設定訊息請求前首先必須開啟一個控制通道。舉例來說,一個客戶端為了無連接傳輸詢問有關底層廣播位址的訊息使用一個控制通道。

要開啟一個控制通道,客戶端調用ZwCreateFile 並且帶有一個空的EaBuffer 指標。客戶端調用ZwCreateFile 使得I/O管理員建立一個代表控制通道的檔案物件並且調用底層的TdiDispatchCreate例程TdiDispatchCreate 注意到沒有EA訊息,以及傳輸端為了開啟的控制通道設置內部狀態。

作為代表一個控制通道的檔案物件,客戶端可以調用 IoGetDeviceObjectPointer 來得到符合的檔案物件的裝置物件指標。

在成功調用ZwCreateFile 後,會得到一個file handle,並且客戶端可以透過ObReferenceObjectByHandle來獲得檔案物件的指標,現在客戶端已經準備好使用TDI_QUERY_INFORMATION或是TDI_SET_INFORMATION IOCTL請求。

當詢問或是設定訊息的操作完成,客戶端必須使用ZwClose 關閉一個開的控制通道,在稍後的Closing a Transport Address or Control Channel會介紹。


2016年9月22日 星期四

TDI Operations - III

Packaging and Submitting IOCTL Requests


下圖示範了TDI客戶如何封裝以及提交TDI_XXX IOCTL要求給他底層的TDI傳輸驅動。


核心模式客戶端會準備他自己的IOCTL IRPs,可以使用TdiBuildXxx 巨集來建立,詳細的介紹在TDI Routines, Macros, and Callbacks。客戶端可以從網路更高層或是調用TdiBuildInternalDeviceControlIrp來為自己配置一個IRP

隨後調用一個TdiBuildXxx 巨集,在IRP內的MinorFunctionCode 欄位設定適當的TDI_ XXX 碼,並且在IRP內設定MajorFunctionCode IRP_MJ_INTERNAL_DEVICE_CONTROL,同時也對每一個IRP設定客戶端支援的IOCTL特定參數。例如,上一節提到的有關如何設定TDI_ASSOCIATE_ADDRESS要求,當使用 TdiBuildAccept,客戶端會提交一個代表連接端點的檔案物件以及代表傳輸位址檔案物件的handle

IRP設定好以後,客戶端可以調用 IoCallDriver 來提交他的IOCTL請求給他的底層傳輸驅動。傳輸驅動的TdiDispatchInternalDeviceControl例程收到來自於客戶端的IRP,並且將命令轉接給內部驅動函式作更進一步的處理。當完成客戶端請求以後,傳輸驅動會對 IRP 設定 I/O statsus block,然後調用TdiCompleteRequest(或 IoCompleteRequest)來返回操作的結果。

如果客戶端在調用 TdiBuildXxx 巨集的時候有設定 IoCompletion,則當傳輸驅動完成操作請求並且調用Io/TdiCompleteRequest 後,會調用客戶端註冊的 IoCompletion 例程。

TDI Operations - II

Opening a Connection Endpoint


下圖示範了一個核心模式客戶端如何對它底層傳輸驅動開一個連接端點(connection endpoint)


如果一個本地端節點客戶需要建立一個連線導向的網路傳輸,則本地端節點客戶首先必須開一個傳輸位址(transport address)並且對它的底層傳輸驅動開一個連接端點(connection endpoint)。客戶端會調用兩次ZwCreateFile,第一次開一個位址,接著再開一個連接端點。

當開一個連接端點時,客戶端在EA(extended attributes)緩衝區內傳送一個客戶-支援內容參數給ZwCreateFile,客戶端設定EaName為系統所定義的TdiConnectionContext 

客戶端調用ZwCreateFile 會讓I/O管理員建立一個客戶端程序指定的檔案物件並且會調用TDI傳輸驅動的TdiDispatchCreate例程。TdiDispatchCreate會解析EA的資訊,並且如果調用成功的時候,傳輸驅動會對開的連接終端設定內部的狀態。

在成功調用 ZwCreateFile 以後,接者傳輸端驅動程式會回傳客戶端一個 file handle,並且客戶端可以透過 ObReferenceObjectByHandle 來獲得檔案物件的指標,此時客戶端已經準備好創建某些 TDI_XXX IOCTL 請求來對遠端節點建立一個點對點的連接。

首先,客戶端必須透過提交一個TDI_ASSOCIATE_ADDRESS請求來關聯這個連接端點與他的傳輸位址,可以使用TdiBuildAssociateAddress來封裝一個IRP

如何封裝設定一個TDI_XXX IOCTL IRPs,可以參考Packaging and Submitting IOCTL Requests。而更多有關如何建立一個點對點的連接,可以參考Making an Endpoint-to-Endpoint Connection.

當點對點連接已經斷線時,並且客戶端不在使用任何的連線導向傳輸,客戶端必須關閉連接端點,透過先前ZwCreateFile 得到的檔案handel作為參數來使用ZwClose,在 Closing a Connection Endpoint有描述這個部分。