June 12, 2009

The 802.11 protocol is a distributed one; it gives chance to all the players without first deciding on who transmits when. For this to work, it is necessary that all devices follow the backoff protocol–waits for DIFS before transmission when no one else is transmitting, backoff a random amount when other transmissions are detected. Changing the backoff is not a good idea because doing so is being unfair to all the other participants in the network.

However, for a large number of experiments and many other purposes such as automatic prioritization of some devices, it might be necessary to modify the backoff mechanism. The madwifi truck version has a function called txcont_configure_radio(). This function allows continuous tranmission of scrambled packets through the iwpriv athx txcont 1 command. Even if one does not want continuous transmission of packets, the working of this function is very beneficial for any control on tranmission timing and the backoff mechanism. The function is so well commented, that I do not think it worth to mention any of those things here. A glance through the code will make it clear how to disable backoff. However, if you wish to space packets by exactly some time interval, you may want to consider changing the AIFS time. We have observed that the aifs values (with cwmin, cwmax set to zero) can cause tranmission to be interspaced by (10 + (aifs *20)) microseconds. We have checked this on a spectrum analyzer for madwifi 0.9.4, so if you are experimenting with this, I would advice you to check again.

If you are curious, search for cwmin in the if_ath.c file. You will see how the random backoff is set in the 802.11 code. While you are at it, also examine how adding qi.tqi_qflags |= HAL_TXQ_BACKOFF_DISABLE; in ath_txq_setup() works. It may also interest you that newer devices support modes known as burst and fast frames. These modes can wreak havoc if you do not check their working properly. Basically, multiple packets are sent together in a transmission opportunity (burst) without waiting for DIFS time and this burst length may be as large as 8ms. Both these modes are surely present if you device advertises that it can transmit at 108Mbps. They can be turned off using the iwpriv athx burst 0 and iwpriv athx ff 0 commands. A suggestion is to keep a power meter / spectrum analyzer / CRO alongside when you experiment with backoff. It is the best way of validating if you are really getting what you want. Don’t rely on only receive timestamps.

TX RX Path

April 16, 2009

As we described in the hello world post, the madwifi driver sits between the kernel’s network layer and the physical hardware abstraction layer (HAL). When a user sends packets from his computer, using a socket connection, for example, the network layer invokes certain predefined functions of the MAC layer. The driver implements these entry points and processes the packets, adding MAC headers, deciding transmit rate and so on, and then calls the HAL code to physically transmit the packet. It is the HAL’s responsibility to enable the required registers on the hardware for sending the packet at the appropriate rate and timing.

When a packet is received by the hardware, it causes an interrupt at the driver level. The driver processes the interrupt and effectively receives the packet in software. The MAC header is stripped off the packet, and the packet is sent over to the network layer for further processing.

The Linux network layer calls the function pointed to by the function pointer hard_start_xmit in the net_device structure. One of the first things the madwifi driver does (in ath_attach()) is to initialize this function pointer to point to ath_hardstart(). The parameters to ath_hardstart() are the sk_buff structure and the net_device structure. This simplicity is an artifact of the layering structure that networking follows. The layer above passes to the lower layer only the cooked packet. The lower layer further cooks the packet and passes it to the next layer. The contents of the packet handed over by the network layer are accessible from the skb->data pointer. From this point forward, the packet is prepared for transmission on the wifi interface. It must be given a valid 802.11 header and the driver must decide the various values in this header. All this is done if the wifi device is in ap, sta, adhoc or ahdemo mode. If the device is in the monitor mode, no 802.11 header is attached to the packet and the packet is sent raw on air. Therefore, when in the monitor mode, ath_hardstart() quickly calls the ath_tx_startraw() function, whereas in other modes, the ath_tx_start() function is called. The monitor mode in madwifi thus actually allows one to transmit raw packets. A very important step performed by both the ath_start and ath_startraw functions is the call to ath_hal_setuptxdesc() HAL function. This call hands over the buffer to the hardware and sets up the parameters essential to send the packet on air. It sets the transmit power, the transmit rate, the antenna to use (most Atheros cards have more than one antenna), the type of packet and a host of other parameters through the flags. A lot of variations in the standard packet transmission style can be achieved by varying some of these parameters. For example, if you write some new auto-rate algorithm, you may just change the value of the txrate parameter to force the hardware to send packets at that rate. However, note that not all packets go through this function call. Some packets such as acknowledgments are produced by the hardware and are sent only at predefined rates. But all packets that are generated by the network layer go through this call, and therefore, it can be a good place to hack in. Another feature that we found useful, and had a very hard time figuring out, is to get all packets timestamped by the hardware while transmission. We were operating in the monitor mode and had our own MAC header attached to the network layer packet instead of the standard 802.11 header. Now, we wanted all our packets to be timestamped by the hardware to facilitate synchronization between nodes. The hardware always timestamps beacons, hence, if we can fool the hardware into believing that the packet being sent is a beacon, we can achieve timestamping. This fooling can be done by changing the packet type (atype) parameter to HAL_PKT_TYPE_BEACON in the call to ath_hal_setuptxdesc().

Both the ath_start() and the ath_startraw() functions call the ath_tx_txqaddbuf() function that actually inserts a buffer on a specific transmit queue (there are multiple hardware queues) and then calls the ath_hal_txstart() function. This function opens up a gate in the hardware that releases all the buffered packets buffered on the particular hardware queue.

When the hardware receives a packet, it causes the HAL_INT_RX interrupt. Interrupts are handled by the ath_intr() function. Since a lot of processing might be required on a received packet, this processing is deferred to a tasklet known as ath_rx_tasklet(). The tasklet is scheduled soon after the interrupt is fired, whenever the OS deems fit. Hence, it is inappropriate to assume the time of call to the rx_tasklet as being equivalent to the time of packet reception. Instead, a variable inside the ath_softc structure can give us the exact time of complete packet reception. The tasklet is a good place to check for physical errors, the reception rate, the per packet reception signal level and noise floor level. We have observed some odd packets that have length=0, frame type and subtype=0 in the ath_rx_tasklet() function. We believe that these frames are an artifact of the devices we used, but nonetheless, such frames must be ignored (all valid packets are received just fine even after ignoring these phantom entries). In ap, sta, adhoc and ahdemo mode, the tasklet goes on to process the packet further. In the monitor mode, the packet must be sent to the higher layer almost raw. A radiotap/prism2 header may be optionally attached to the raw received frame to preserve the PHY information regarding the rate of transmission etc. before passing it to the network layer. Applications such as tcpdump, wireshark and kismet benefit from the radiotap headers. Packets are passed to the ath_rx_capture() function which then calls the ieee80211_input_monitor() function. The ieee80211_input_monitor() function then calls the network layer function netif_rx() to complete its handling of the packet.

As a side note, the MAC layer does not free the skb it receives from the network layer or the hardware (in either direction). The skb is shared between all layers. Also, in the monitor mode the hardware sends all packets to the driver. In other modes, the driver receives only packets destined to it and broadcast packets. This fundamental difference between monitor mode and other modes, may cause a lot more interrupt handling at the driver for nodes in monitor mode than for other nodes. This may affect the performance of other applications if the monitor mode node is also expected to do other (time sensitive) tasks.

Hello world!

April 5, 2009

My friend Nirav Uchat and I have been involved in a project that uses madwifi driver for communication between wireless nodes. This make us no authority on madwifi drivers, but since we have used and tapped into the intricacies of the driver for sometime now, we would like to document what we know.

The madwifi driver sits between the kernel’s network layer and the Atheros hardware abstraction layer (HAL). Above the driver, in the kernel code, nothing is known about the physical interface over which the network packets are to be sent. This changes at the driver, however. The driver is fully aware of the kind of hardware and the physical layer over which the packets are to be delivered. The driver implements most of the components of the MAC standards, but leaves the most time-sensitive functions to the HAL and the hardware chip. Any possible configuration that the hardware offers, must be exposed up to the driver, otherwise, it is almost of no use. The driver exposes some of the functionalities that are available to it through ioctl calls and entries in the /proc system. All users of the madwifi drivers, who wish to turn into developers, must have a good knowledge of the functionalities already exposed by the iwpriv directives and through the /proc entires. It took us some time, and we tried to do all our modifications from inside the driver code, but it is much simpler to do it from the exposed calls. The madwifi project website (userdocs) provides descriptions of many such iwpriv directives.

In this blog, we shall walk you through the transmit and receive path of a packet inside the madwifi code. We shall show you ways to trick the driver into doing what you want it to. Such idiosyncrasies may be needed for your academic project, or you may just want to be playful. Using what is given in this blog, it might be possible to spoof MAC addresses and exhaust all the access points around. However, we caution you from doing any such thing outside of an academic setting since there are stringent laws in most countries about all such things. This blog wants to aid you in your wireless project; not turn you into crooks. Further, we do not claim that all information written here is perfect, and we do not take any responsibility (or credit) of the consequences of using our suggestions.