Welcome to Libmac
Summary
The libmac library is designed for the NSF ORBIT Testbed Project. it is a user-space C library that provides applications with an API for,
- Injection and capture of MAC layer frames.
- Manipulation of a subset of wireless interface parameters at both aggregate and per-frame granularity levels.
- Communication of a subset of wireless interface parameters from one end of a network connection to the other, on a per-frame granularity level.
Manipulation and communication of wireless interface parameters, was achieved by modifying open-source Linux device drivers for Atheros and Intel a/b/g 802.11 cards.
Introduction
Network simulation tools, like ns-2 and OPNET have contributed substantially to the development of networking protocols over a number of years in both academia and industry. The validity of results from these tools is such that they are still the preferred way to determine a first approximation to the actual results. There are numerous publications and doctorate dissertations where simulation results, obtained using these tools, form the principal basis for the proposed solution. However, these tools were mainly developed for wired network scenarios where the physical layer is much more predictable and uncomplicated as compared to wireless networks. The use of these tools for such networks demands accurate physical-layer models and their subsequent integration. Although accurate mathematical models exist, it is very difficult to implement these in a simulator given the inherent random nature of every aspect of this physical layer. Implementation is further complicated by the additional facet of mobility of nodes, in such a network, and the random manner in which it occurs.
The OPNET simulator has an implementation of the wireless physical layer that has appreciable support for some aspects but is quite simplistic in other aspects. Additionally, being a commercial product, the complete source code is not available for modification or incremental addition, which is a fundamental requirement in this kind of research. For ns-2, the source code is freely available but the physical layer models are mostly deterministic, which in turn produce incomplete and biased results.
Emulation is seen as an alternative technique to study these networks, where the physical layer characteristics remain the same as in real-world wireless networks, except for mobility, which is the emulated feature. This is the approach adopted by the proposed ORBIT (Open Access Research Testbed for Next-Generation Wireless Networks) testbed. As the name suggests, this will be an open-access multi-user experimental (MXF) facility to support research on next-generation wireless networks.
As part of this effort, open-source software tools need to be developed to perform the fundamental functions of (a) setting up and conducting an experiment and (b) collecting and storing the results. In order to conduct an experiment, the basic functionalities, such as (a) transmission and reception of frames, (b) the ability to tune interface parameters and © the ability to control MAC level mechanisms, are required. Libmac, a user-level C library attempts to provide these features.
Design
Motivation
Currently, protocol development is a two-stage process where specific ideas for the modification of an existing protocol, or the development of a new one, are first implemented in a simulator and then, based on the results, implemented in an open-source kernel. This two-stage process is justified when the first stage provides results with an acceptable loss of accuracy, in a time frame which is smaller than what would be available if the first stage itself was kernel implementation. Simulator designers have to make this tradeoff so that implementors have a first approximation to the actual results as fast as possible, using which, they can decide whether or not they want to invest their time and effort in the second stage. In addition, protocol implementations in a simulator have the advantages of development ease and flexibility.
However, as discussed earlier, the loss of accuracy for wireless network scenarios, in the simulators that are currently available, is not acceptable. Therefore, we have to look at:
- either using just a single-stage protocol development process where we directly modify or implement the protocol in the kernel or
- replacing the first stage with a process that is more accurate than the existing one.
The advantages of the first approach are:
- kernel-level implementations of the protocol provide complete and accurate information about the performance,
- are efficient and
- take into account the interworking between the protocol and all the other system components.
The disadvantages are:
- the requirement of a high level of programming expertise,
- the lack of debugging tools,
- the presence of protection mechanisms,
- the requirement of low-level languages, like C and assembly,
- the high risk involved ('buggy' kernel code can bring down the entire system) and
- the strict layering approach of wired network protocols and their subsequent implementation, which implies that newer philosophies of cross-layer design will prove difficult, if not impossible, to implement in existing stable versions.
Thus, kernel-level implementations provide the real-basis for performance analysis but they are time-consuming and difficult. Additionally, the existing two-stage philosophy will be hard to replace by this single-stage approach because of the widespread acceptance and use of the former approach.
In keeping with the spirit of the two-stage philosophy, emulation is seen as acceptable replacement for the first-stage. It can be designed to provide the same advantages of simulators, namely,
- development ease and flexibility and
- speed of execution.
In addition, accuracy levels will be much more closer to real-world experiments.
Design Goals
Thus, our design goal can be stated as,
Design an emulator framework which will
- provide the development ease and flexibility of a simulator,
- provide more accurate results than those currently obtained and
- serve as common ground where results can be compared. \end{enumerate}}
Design choice I: Implement the emulator in user-space, in a modular manner
Keeping these requirements in mind, a decision was made to implement this emulator framework in user-space, in a modular fashion, built from the ground up so that the lowest module of the framework will communicate with the network device drivers. The figure below gives the general idea behind the framework. Protocol Modules (PM) at each level will provide implementations of the existing protocol stack (for e.g. TCP/IP). The framework will also allow a plug-and-play feature so that newer protocols can be tested and compared with existing ones
The goal is to provide implementations of existing protocol stacks (for e.g. TCP/IP), together with their source code, and allow for newer protocols to be developed and integrated into this framework in a plug-and-play manner (we are in fact, replicating the design of simulators here, which also provide implementations and source code of existing protocol stacks). This should allow protocol developers, at any layer, to concentrate on the performance of their protocol rather than the performance of particular lower or higher layer protocol implementations, since the same implementations will be used by all users.
Design choice II: Use publicly available source code in order to speed up implementation
To speed up the implementation and not rewrite software that already exists, an implicit design choice made was to re-use as much of the public domain source code as possible in order to speed up implementation of this framework.
Design choice III: Implement all modules in the framework as shared libraries that provide APIs
Given the plug-and-play requirement of the framework, in addition to the modularity requirement, a decision was made to implement each module as a shared library. Since shared libraries are linked at run-time instead of compile-time, they have the following advantages:
- All programs using the library need not be recompiled whenever a change is made.
- Each task shares the same memory space for the shared library. Thus, even if there are N programs using the library, there needs to be only one copy in main memory. In other words, not linking in the code into every task can save a lot of disk space.
- Less pages need to be in the main memory, cutting down paging and reducing the overall memory footprint.
Design choice IV: Using public-domain frame injection (libnet) and capture libraries (libpcap)
Quite obviously, the first stage of development of this framework is for the lowest module that needs to be able to transmit and capture raw MAC frames, in addition to providing APIs for interface parameter tuning. An additional requirement of the lowest module is that of appending parameter information to outgoing or incoming frames. The motivation for this requirement stems from the experimental nature of this work and from the interest shown by the research community in cross-layer protocol design. Within the framework, the following figure gives an idea of how the lowest module of the framework can capture raw MAC frames using the packet sockets API.
Though the packet sockets API provides a mechanism using which we can develop this module, it has the following drawbacks:
- Type demultiplexing is the only filtering function provided by the sockets API whereas our requirements are for a much wider variety of filters.
- It is comparatively much less portable across architectures.
- It forces the application developer to deal with system-specific details.
- It is time-consuming considering the amount of functionality that needs to be added.
Design choice II and the drawbacks of the packet sockets API lead us to the choice of using public-domain shared libraries that provide APIs for frame injection and capture.
The choice of using these particular libraries was motivated by the stable nature of the executables, the open-source nature of the source code, their active maintenance and the presence of mailing lists and tutorials. In addition, these libraries have been thoroughly tested by a wide variety of open-source and commercial products. They were written primarily because of the drawbacks of the packet sockets API and their advantages include:
- Providing the user with high-level and simplified interface and hiding the complexity of underlying system from application programmer.
- Portability across multiple architectures.
The figure below shows how the framework will be built on top of the libnet and libpcap libraries, which in turn will be used in the lowest module. This diagram also shows how the envisioned framework will co-exist in parallel with the TCP/UDP sockets API, which uses the networking protocols implemented in the kernel.
The rest of this page will discuss the lowest module, implemented as the shared library, Libmac.
Libmac API
List of features implemented
Features provided by this library include:
- Ethernet frame injection and capture.
- Manipulation of a subset of wireless interface parameters at both aggregate and per-packet levels of granularity.
- Communication of a subset of wireless interface parameters from the sending end of a network connection to the receiving end, on a per-packet granularity level.
- Reception of the entire 802.11 frame, when the receiver is in RFMON mode.
- Appending parameters to all incoming frames and using the pcap filters to receive only those frames that the user of the library is interested in.
Driver-level support is required for features 2, 3 and 5. This support has been provided by modifying the Atheros and Intel drivers for wireless LAN cards. Details of these modifications can be found in the documentation that comes with the library.
Ethernet frame injection and capture
The usage paradigm, for sending or receiving frames using this library, is as follows:
- Obtain parameter information using the mac\_get\_ifinfo function. The argument should be the address of a {NULL} pointer.
- {OPTIONAL:} Allocate memory for, and initialize, the mac_params and the mac_params_flags structures in case you are going to use the mac_get_params or mac_set_params function. Use the mac_init_params function for the same. Again, the arguments {SHOULD BE} addresses of {NULL} pointers.
- {OPTIONAL:} Call any one of the parameter functions, mac\_get\_params or mac_set_params or mac_append_params.
- For each frame that you want to send and depending on the destination address, either call mac_send_broadcast or mac_send_unicast. For each frame that you want to recv, call mac_recv. The double pointers, header, payload, send_parameter_info and recv_parameter_info SHOULD BE addresses of {NULL} pointers. The pointer len, should be the address of an unsigned short.
- {OPTIONAL:} Free memory, if allocated, for the mac_params and the mac_params_flags structures using the mac_free_params function.
- Free interface information using the mac_free_ifinfo before exiting.
The function, int mac_get_ifinfo (struct mac_ifinfo mac_ptr), is used to obtain information on all existing interfaces. It has one argument, which is a pointer to a linked list of structures. Each structure in the list contains members which can store the name of interface, hardware address, ip address, whether the interface is wireless or not and other relevant information. The information stored in these structures is used by the rest of the functions in the library. Likewise, the function, int mac_free_ifinfo (struct mac_ifinfo mac_ptr), is used to free the memory allocated for interface information. It also has one argument, which is the pointer to the linked list of structures. The function, int mac_send_broadcast (u_char *payload, short len, struct mac_ifinfo_list *q), is used to assemble an ethernet frame with the specified payload and broadcast (MAC-level) this frame. The first argument is the pointer to the payload, the second one is the length of the payload and the third one is the structure containing the name of the interface on which this frame needs to be sent.
The function, int mac_send_unicast (u_char *payload, short len, struct mac_ifinfo_list *q, unsigned char *ucast_mac), is used to assemble an ethernet frame with the specified payload and send this frame to a unicast MAC address. The first argument is the pointer to the payload, the second one is the length of the payload, the third one is the structure containing the name of the interface on which this frame needs to be sent and the fourth argument is a pointer to the MAC address of the destination.
The function, int mac_recv (struct ether_header header, char payload, unsigned short *len, unsigned char send_params, unsigned char recv_params, struct mac_ifinfo_list *q, char *filter), is used to receive an ethernet frame. Its arguments include pointers to store ethernet header information, payload, length of the payload, sending side parameters that have been appended, receiving side parameters that have been appended and the pcap filter that is to applied.
Note that parameters are appended to all incoming frames and the pcap filters can be used to receive only those frames that the user of the library is interested in.
Manipulation of a subset of wireless interface parameters at both aggregate and per-packet levels of granularity
The function, int mac_get_params (struct mac_params *h, struct mac_ifinfo_list *if_ptr, int argc, …), is used to request the driver to return information on interface parameters, specified by the fourth argument onwards. The first argument is the pointer to the mac_params structure, where information, on retrieved parameter values, is to be stored. The second one is a pointer to the struct mac_ifinfo_list that specifies the interface to which, a call to this function, applies. The parameter settings on the specified interface will be returned. The third argument is the number of arguments that follow after this one. Each argument that follows corresponds to the key of a parameter.
The function, int mac_set_params (struct mac_params *h, struct mac_ifinfo_list *if_ptr, int argc, …), is used to request the driver to operate on interface parameter settings, specified by the fourth argument onwards. The first argument is the pointer to the mac_params structure, where information, on parameter settings, is stored. The second one is a pointer to the struct mac_ifinfo_list that specifies the interface to which, a call to this function, applies. The parameter values on the specified interface will be set. The third argument is the number of (key,value) pairs that follow after this one.
Communication of a subset of wireless interface parameters from the sending end of a network connection to the receiving end, on a per-packet granularity level
The function, int mac_append_params (struct mac_ifinfo_list *if_ptr, unsigned char direction, int argc, …), is used to request the driver to append interface parameter information, specified by the fourth argument onwards. The first argument is the pointer to the struct mac_ifinfo_list that specifies the interface to which, a call to this function, applies. All outgoing/incoming frames on the specified interface will have the specified parameters appended to them. The appending of parameters can also be turned off. The second argument is a variable, direction, that indicates whether parameters should be appended on outgoing and/or incoming frames. The third argument is the number of arguments that follow after this one. Each argument that follows corresponds to the key of a parameter that needs to be appended.
Reception of the entire 802.11 frame, when the receiver is in RFMON mode
The function, int mac_promisc_recv (unsigned char frame, unsigned short *frame_len, unsigned char send_params, unsigned char recv_params, struct mac_ifinfo_list *q)}, is used to receive an 802.11 frame, in RFMON mode, on an interface specified by the user, and retrieve pointers to the frame, length and parameters. Its arguments include pointers to store the entire frame, length of the frame, sending side parameters that have been appended, receiving side parameters that have been appended and the structure that specifies the interface to which a call to this function applies. Note that parameters are appended to all incoming 802.11 frames and current version of the library does not parse the received frame to extract send-side parameter information that is appended. Detailed documentation on all these functions and their implementation details are included in every release, which can be downloaded from the ORBIT SVN repository. The interested reader is directed to these for more information.
The architecture diagram is shown below - Libmac uses open-source libraries libpcap, for frame capture and libnet, for frame injection.
Starting Points
For Experimenters
Currently supported linux device drivers in the libmac package include ipw2200(version 1.0.8) and madwifi(old version-approx June 2005, NOT madwifi-ng). Supported parameters include RSSI, 802.11 PHY Bit-rate, MAC timestamp (all on the receive side).
For Developers
- Sample code and function specifications are available here
- Check out source using subversion at http://svn.orbit-lab.org/svn/orbit/libmac/trunk.
Attachments (6)
- libmac_layering.jpg (25.2 KB ) - added by 19 years ago.
- p1.jpg (24.9 KB ) - added by 19 years ago.
- p3.png (475.6 KB ) - added by 18 years ago.
- p2.png (595.2 KB ) - added by 18 years ago.
- madwifi-0.9.1-libmac.diff (24.4 KB ) - added by 18 years ago.
- madwifi-0.9.2-libmac.diff (25.1 KB ) - added by 18 years ago.
Download all attachments as: .zip