{{{#!comment [[Include(wiki:802.11/beta-note)]] }}} [[TracNav(802.11/TOC)]] = Distributed Coordination Function (DCF) = The 802.11 DCF is responsible for many behaviors. These actions include (but are not limited to): * Acknowledging good receptions * Retransmitting failed transmissions * Carrier Sense Multiple Access with Collision Avoidance (CSMA/CA) * Binary Exponential Backoff (BEB) The purpose of this document is not to explain or defend aspects of the DCF. Instead, this document is to aid in the understanding of how the standard DCF behavior is realized within the Mango 802.11 Reference Design. This document is intended to be read alongside the actual [browser:ReferenceDesigns/w3_802.11/c/wlan_mac_low_dcf/wlan_mac_dcf.c wlan_mac_dcf.c] and [browser:ReferenceDesigns/w3_802.11/c/wlan_mac_low_framework/wlan_mac_low.c wlan_mac_low.c] code themselves. Rather than structure this documentation as a function-by-function pseudocode equivalent to the above-linked codebases, we will instead approach the documentation from the perspective of two different roles: MPDU transmission and MPDU reception. There is overlap between these roles in what functions they execute (e.g., MPDU transmission still has an element of frame reception to deal with acknowledgments). == MPDU Transmission == [[Image(wiki:802.11/files:mpdu_tx.png, width=800)]] From the DCF's perspective, a new MPDU transmission begins when an IPC message arrives from CPU_HIGH with a payload that must be sent. The origin of this payload is irrelevant - it might be an encapsulated Ethernet frame, or it might be a beacon created by the Access Point (AP) project, or it might even be a LTG frame. Those are all concerns of CPU_HIGH. In CPU_LOW, all that matters is that there are bytes that must be sent and certain actions may possibly be required of us to modify those bytes (e.g. timestamp insertion in a beacon transmission). '''IPC Message from CPU_HIGH: MPDU Ready''' When an IPC message arrives, the MAC Low Framework needs to perform a few different actions before passing the frame off to the DCF for transmission. Pseudocode: {{{ convert high-level MCS/rate into PHY-understandable rate parameter if( insert duration ) calculate duration of SIFS and ACK insert duration into MAC header if ( insert timestamp ) tell PHY Tx which bytes to overwrite with usec timestamp call the frame_tx_callback() }}} For the DCF application, the {{{frame_tx_callback()}}} executes the {{{frame_transmit()}}} function in the DCF code. ---- '''frame_transmit()''' The 802.11 DCF Tx state machine is complex. The implementation of frame_transmit() reflects much of this complexity. In no particular order, the function needs to: * draw a random backoff according to the binary exponential backoff * use the [wiki:802.11/MAC/Support_HW MAC Support Core] to transmit a frame that defers to the medium * if needed, send an RTS instead of the data itself to reserve the medium * if needed, look out for a response frame (i.e. a CTS from a transmitted RTS or an ACK from a transmitted data frame) * if needed, handle a timeout and implement the complex [wiki:802.11/MAC/Lower/Retransmissions retransmission behavior] The {{{frame_transmit()}}} context will only exit when an MPDU is "done." Here, "done" can mean multiple things: * a unicast frame that is acknowledged * a unicast frame whose every retransmission attempt has failed * any multicast frame has been transmitted (since multicast frames are, by definition, successful since they cannot be acknowledged) Pseudocode: {{{ continue_retries = True while( continue_retries ) if( mpdu is long ) load MAC support core with RTS else load MAC support core with MPDU draw a random backoff and set MAC support core (will only be used if medium is busy) start MAC support core Tx state machine do if( MAC support core is done ) switch( MAC support core result ) case immediate success (e.g., multicast): reset contention windows and counters start backoff continue_retries = False case Rx has started: call frame_receive() and check return value if( Rx was ACK and we were waiting for ACK ) reset contention windows and counters start backoff continue_retries = True if ( Rx was CTS and we were waiting on CTS ) frame_receive handled the MPDU Tx, so we should set the MAC support core status variable to pending explicitly so we do not fall out of the do-while if ( other Rx ) increment counters and contention window continue_retries = True case Timeout has occurred: increment counters and contention window continue_retries = False while( MAC support core is pending ) }}} '''frame_receive()''' The {{{frame_receive()}}} function, when called from the context of the above {{{frame_transmit()}}} function block), should perform two tasks: * If the received frame is a good FCS ACK that is addressed to this node, it should raise a flag in its return value stating this * If the received frame is a good FCS CTS that is addressed to this node, it should raise a flag in its return value stating this. It should also start the transmission of the MPDU a SIFS interval after the reception is complete. The [wiki:802.11/MAC/Support_HW MAC Support Core] is capable of transmitting a frame an arbitrary interval after the completion of a reception, so we can use this for sending the MPDU after receiving a CTS. Pseudocode: {{{ if( RA address is to me ) switch( packet type ) case ACK: wait for FCS if( FCS good ) raise corresponding return flag case CTS: wait for FCS status if( FCS good ) configure MAC support core to send MPDU after SIFS interval raise corresponding return flag }}} Upon exiting the {{{frame_transmit()}}} context, execution returns to the MAC Low Framework, where an IPC message is sent to CPU_HIGH indicating that the MPDU transmission is done. == MPDU Reception == [[Image(wiki:802.11/files:mpdu_rx.png, width=800)]] MPDU reception is considerably simpler than transmission. The DCF software is responsible for polling the PHY Rx by calling the {{{wlan_mac_low_poll_frame_rx()}}} function in the MAC Low Framework. '''PHY Rx Poll''' The {{{wlan_mac_low_poll_frame_rx()}}} function reads the status registers from the PHY and converts that information into a {{{phy_rx_details}}} structure that contains the following: * the PHY mode that was used (i.e. OFDM or DSSS) * the PHY rate that was used * the frame length decoded from the SIGNAL field If the reception is valid and supported, the framework calls the {{{frame_rx_callback}}} function. Pseudocode: {{{ read the MAC status register if( the Rx PHY is currently active OR the PHY is blocked after a reception ) if( the PHY is using the DSSS subsystem ) update the phy_rx_details struct to reflect the DSSS mode and rate call frame_rx_callback() else wait for valid OFDM Rx params from the PHY if( params indicate a supported mode ) update the phy_rx_details with Rx params call frame_rx_callback() return status_variable the return of the call to frame_rx_callback() }}} ---- In the DCF, the {{{frame_rx_callback()}}} is attached to the {{{frame_receive()}}} function. In the above MPDU transmission state, we have already seen some executions of this function to deal with the receptions of ACK and CTS frames. Independently of these actions, the {{{frame_receive()}}} function needs to pass receptions up to CPU_HIGH and, if needed, generated control frame responses (i.e. ACK and CTS frames). Pseudocode: {{{ if( RA address is to me ) switch( packet type ) case DATA: wait for FCS if( FCS good ) configure MAC support core to send ACK after SIFS interval case ACK: wait for FCS if( FCS good ) configure MAC support core to send CTS after SIFS interval if( frame passes CPU_LOW filter ) call MAC Low Framework function to send IPC message to CPU_HIGH stating that the Rx MPDU is ready to be processed }}}