在送真的封包之前,先廣播一個 request to send 封包。這個封包不只有目的地會收到,發送者傳輸範圍內的其他裝置也會收到。而目的地如果順利收到這個 RTS 的封包,則必須廣播一個 clear to send (CTS) 封包,代表已經準備好接收封包。舉例來說,假定 要送一個封包給 :
這時, 會廣播一個 RTS 封包:
這個封包送出去之後,如果 有收到這個 RTS 封包,就要也廣播一個 CTS 封包:
並且規定:聽到 CTS 廣播的那些節點,也就是上圖中的紅色節點,在一段足夠向 傳輸完訊息的時間內,都不能向 傳輸訊息(preempt_disable()
跟local_irq_disable()
的既視感)。這個「某段時間」會記錄在 CTS 封包的 duration_id
欄位,所以所有收到 CTS 的那些節點(也就是「離 太近的那些節點」)都會知道在多久的時間之內不能打擾 。這樣就保證「能到達 的那些節點」在 往 傳完封包之前,不會同時往 傳輸。
需要注意的是:雖然禁止這些紅色節點往 傳送訊息,但是這些節點仍然可對 以外的節點通訊。
而這也是 802.11 對 hidden node problem 的解法。因為「能到達 」是 hidden point 的必要條件,所以排除所有這樣的點就排除了所有可能的 hidden point。
節點會維護一個存放不同節點 duration 的資料結構,稱為 Network Allocation Vector。在一個節點閒置時,在其他節點的 NAV 中,該節點所對應的數值預設為 0
。而 RTS/CTS 發生時,陣列中表示該節點的元素就會被設為 duration_id
所對應的數值。
這個作法有另外一個問題:如果兩個 RTS 封包發生碰撞怎麼辦?解法是:因為協定中,傳了一個 RTS,就必須收到一個 CTS 作為回應。因此,若發現傳送了 RTS,但沒有收到 CTS,這就表示 RTS 並沒有成功傳輸,因此需要重送 RTS。而這個「重送」之前,會等待一段隨機時間(即:exponential back-off),之後再重送 RTS。
如果準備傳送的封包太小,那這時候如果傳送 RTS 就顯得多此一舉。因此只有大到一定程度的封包需要使用 RTS/CTS 交握,否則就直接送封包即可。而兩者的長度界線稱為 RTS threshold。而 include/linux/ieee80211.h
中也有定義:
老樣子,都是用對齊好的結構體來表示。
ieee80211_rts
定義在 include/linux/ieee80211.h
中:
ieee80211_cts
一樣定義在 include/linux/ieee80211.h
中:
ieee80211_rts_get
宣告在 include/net/mac80211.h
中:
定義則是在 net/mac80211/tx.c
:
duration_id
欄位 –- ieee80211_rts_duration
定義在 net/mac80211/util.c
中,宣告在 include/net/mac80211.h
:
duration_id
–- ieee80211_generic_frame_duration
定義在 net/mac80211/util.c
中,宣告在 include/net/mac80211.h
中:
ieee80211_frame_duration
上述兩個函式主要的計算工作都是在 net/mac80211/util.c
當中的 ieee80211_frame_duration
: