Linux Kernel wireless subsystem talking about the Linux kernel Wireless subsystem table of Contents
- 1. Global overview
- 2. Inter-module interface
- 3. Data path and Management path
- 4. How is the packet sent?
- 5. Talk about the management path
- 6. How is the packet received?
- 7. Summarize
How does the Linux kernel implement a wireless network interface? How is the packet sent and received in what way?
When I first started working with the Linux wireless network, I was lost in the vast base code, looking for introductory materials to answer the high-level questions mentioned above.
Following the exploration of the source code for a period of time, I wrote this summary, hoping that the reader could get a helpful overview of how the Linux wireless network works in this article.
1 Global Overview
Before you start exploring the specifics of Linux wireless, let's take a look at the overall architecture of the Linux wireless subsystem. 1, the abstract relationship between the various modules of the Linux wireless subsystem is shown.
Figure A Linux wireless network structure
The dotted line in the illustration shows the case of kernel space. User-space programs run at the top, while hardware-related devices are at the bottom. The left side of the illustration is an Ethernet device and a WiFi device on the right.
In the middle of the same, there are two kinds of WiFi devices, in particular, which kind of IEEE802.11 standard to see how to achieve Mlme.
If the hardware is implemented directly, then the device is a hard Mac (full Mac) device, and if it is implemented by software, then the device is a soft Mac (soft Mac) device. At present, most wireless devices are software-implemented soft MAC devices.
Typically we look at the Linux kernel wireless subsystem as two chunks: cfg80211 and mac80211, which connect to other kernel modules and user-space applications.
In particular, CFG80211 provides configuration management services in kernel space, and the kernel and application tiers implement configuration management interfaces through nl80211. It is to be remembered that
Both hard Mac devices and soft Mac devices require cfg80211 to work. And mac80211 is just a driver API, it only supports software implementation of soft MAC devices.
Next, we focused on soft MAC devices.
The Linux kernel wireless subsystem unifies a variety of WiFi devices and handles the lowest-level MAC, PHY two layer in the OSI model.
If further divided, the MAC layer can be divided into Mac upper and Lower Mac. The former is responsible for the management of MAC layer wireless network detection discovery, identity authentication, association and so on;
The latter implements the MAC layer such as ACK and other emergency operations. In most cases, the hardware, such as the wireless adapter, handles most of the PHY layers and the underlying MAC operations. The Linux subsystem implements most of the MAC's top-level callback functions.
2 Module Indirect port
As we can see from figure one, the dividing line between the modules is clear, and the modules are invisible to each other. The modules generally do not affect each other.
For example, we make changes to the WiFi device driver (such as patching, adding new WiFi drivers, etc.), these changes will not affect the mac80211 module,
So we don't have to change the mac80211 code at all. As another example, adding a new network protocol is theoretically not necessary to modify the sockets Layer and the device-independent layer code. In general, the kernel uses a series of function pointers to make each layer transparent to each other.
The following code shows the connection between the Rtl73usb wireless card driver and the mac80211.
static const struct Ieee80211_ops rt73usb_mac80211_ops = {. tx = Rt2x00mac_tx,. Start = Rt2x00mac_start,. Stop = Rt2x00mac_stop,. add_interface = RT 2x00mac_add_interface,. remove_interface = rt2x00mac_remove_interface,. config = Rt2 X00mac_config,. Configure_filter = Rt2x00mac_configure_filter,. Set_tim = rt2x00mac_s Et_tim,. Set_key = Rt2x00mac_set_key,. Sw_scan_start = Rt2x00mac_sw_scan_start, . Sw_scan_complete = Rt2x00mac_sw_scan_complete,. get_stats = Rt2x00mac_get_stats, . bss_info_changed = rt2x00mac_bss_info_changed,. Conf_tx = Rt73usb_conf_tx,. GET_TSF = RT73USB_GET_TSF,. Rfkill_poll = Rt2x00mac_rfkill_poll,. Flush = Rt2x00mac_flush, . Set_antenna = Rt2x00mac_set_antenna,. Get_antenna = Rt2x00mac_get_antenna,. GE T_ringparam = Rt2x00mac_get_ringparam,. tx_frames_pending = rt2x00mac_tx_frames_pending,};
The left side is mac80211 for the WiFi driver module implementation of the IEEE80211_OPS structure of the callback interface, the specific content of the callback function is implemented by the driver layer.
Obviously, the implementation of the corresponding drivers for different devices is different. The struct ieee80211_ops is responsible for binding the callback functions implemented by different device drivers to the API mappings provided by the mac80211.
When the driver module is inserted into the registration, these callback functions are registered in the mac80211 (through the IEEE80211_ALLOC_HW implementation), and then mac80211 bound the corresponding callback function, no need to know the specific name, and implementation details.
A fully defined IEEE80211_OPS structure contains many members, but not all must be driven by a layer implementation. Generally, the first seven member functions implemented are sufficient. However, in order to implement the other functions correctly, some related member functions need to be implemented, as in the example above.
3 data paths and managed paths
As shown in figure A, there are two main paths: Data path and managed path. The data path corresponds to the IEEE802.11 data frame, while the management path corresponds to the control frame.
In IEEE802.11 control frames, most are used for time-critical operations such as ACK, and are generally implemented directly by hardware. One exception may be ps-poll frames (for Power Save control), which can also be implemented by mac80211.
Data and management paths are implemented separately in mac80211.
4 How is a packet sent?
Next, we focus on the sending process for the next data.
First, the data wrap an application originating from user space, and the application first creates a socket and then binds an interface (such as an Ethernet interface, a WiFi interface). The
then writes the data to the socket buffer and finally sends the buffer's data. When the socket is created, we need to indicate which protocol family will be used, which will work in the kernel.
just now in the Data application module in Figure one, the final application is caught in a system call, and then the next work is done in kernel space. The transfer of
data is first passed through the socket layer, and one of the most important data structures in this process is sk_buff, commonly called SKB. A member of a SKB structure contains the address of the buffer and the length of the data.
It also provides good support for the manipulation of data in different layers of the kernel, and implements many interfaces, such as inserting and removing the headers of different network layers. This structure is used for the entire data sending/receiving process.
We skipped the network protocol module, and I don't have much to say about the network protocol, because once the network protocol is involved, I can't say enough. The agreement here is not our main concern.
But what we need to know is that the protocol used for data transfer is bound to the specified protocol when the socket is created, and then the associated protocol is responsible for the data transfer of the relevant layer.
Next, the data falls from the network layer to the device-independent layer. This layer is transparently connected to a wide variety of hardware devices (such as Ethernet devices, WiFi devices, etc.).
Device independent layer An important structure is: Net_device. Let's go back to figure one and look at the next code to explain how the kernel communicates with the Ethernet device driver. The
Concrete interface is implemented through the NET_DEVICE_OPS structure, which corresponds to many operations of the net_device.
The following are some of the members of the NET_DEVICE_OPS structure:
struct Net_device_ops {int (*ndo_init) (struct net_device *dev); void (*ndo_uninit) (struct net_device *dev); Int (*ndo_open) (struct net_device *dev); Int (*ndo_stop) (struct net_device *dev); netdev_tx_t (*ndo_start_xmit) (struct sk_buff *skb, struct net _device *dev); netdev_features_t (*ndo_features_check) (struct Sk_buff *skb, St Ruct Net_device *dev, netdev_features_t features); U16 (*ndo_select_queue) (struct net_device *dev, str UCT Sk_buff *skb, void *accel_priv, select_queue_fallback_t fallback); void (*ndo_change_rx_flags) (struct net_device *dev, int flags); void (*ndo_set_rx_mode) (struct net_device *dev); Int (*ndo_set_mac_address) (struct Net_device *dev, void *addr); Int (*ndo_validate_addr) (struct net_device *dev); Int (*ndo_do_ioctl) (struct net_device *dev, struct IFRE Q *ifr, int cmd); Int (*ndo_set_config) (struct net_device *dev, struct Ifmap *map); Int (*NDO_CHANGE_MTU) (struct net_device *dev, int new _MTU); Int (*ndo_neigh_setup) (struct Net_device *dev, Struc T neigh_parms *); VoiD (*ndo_tx_timeout) (struct net_device *dev); struct rtnl_link_stats64* (*ndo_get_stats64) (struct Net_device *dev, s Truct rtnl_link_stats64 *storage); struct net_device_stats* (*ndo_get_stats) (struct net_device *dev); Int (*ndo_vlan_rx_add_vid) (struct Net_device *dev, __be16 Proto, U16 vid); Int (*ndo_vlan_rx_kill_vid) (struct net_device *dev,......};
When the contract is contracted, SKB is passed in when calling Dev_queue_xmit. After the specific call relationship is tracked, this is ultimately called: Ops->ndo_start_xmit (SKB, Dev).
Note that this function is required for registration to take effect.
For WiFi devices, we usually use mac80211 (instead of the corresponding device driver), because mac80211 has already registered for us.
From net/mac80211/iface.c you can see:
static const struct Net_device_ops ieee80211_dataif_ops = { . ndo_open = Ieee80211_open, . Ndo_stop = Ieee80211_stop, . Ndo_uninit = Ieee80211_uninit, . Ndo_start_xmit = Ieee80211_subif_start_xmit, . Ndo_set_rx_mode = ieee80211_set_multicast_list, . Ndo_change_mtu = Ieee80211_change_mtu, . ndo_set_mac_address = Ieee80211_change_mac, . Ndo_select_queue = ieee80211_netdev_select_ Queue, . Ndo_get_stats64 = Ieee80211_get_stats64,};
So mac80211 can also be seen as a net_device, when a packet is transmitted over WiFi, the associated transfer function Ieee80211_subif_start_xmit will be called.
We enter the MAC80211 internal IEEE80211_SUBIF_START_XMIT implementation can see such a call subsequence: Ieee80211_xmit = Ieee80211_tx = Ieee80211_tx_frags = Drv_tx
At the moment we are at the boundary of the mac80211 and WiFi drive, and Drv_tx is just a random callback function we have defined that is implemented in the WiFi driver layer and registered.
static inline void Drv_tx (struct ieee80211_local *local, struct Ieee80211_tx_control *control, struct Sk_buff *skb) { LOCAL->OPS->TX (&LOCAL->HW, control, SKB);}
Here, mac80211 is over, and device-driven correlation is over for the time being.
As mentioned earlier, the callback function registered to the device driver will be called through LOCAL->OPS->TX in mac80211. Although each driver's implementation of the corresponding callback function is different.
The following example uses the interface between the previous modules. Struct member TX corresponds to the function Rt2x00max_tx first needs to populate the prepare send descriptor (typically including frame length, ACK policy, rts/cts, retransmission time limit, Shard flag, MCS, etc.)
Some of the information is passed down by mac80211 (some of the information in the struct ieee80211_tx_info will be used), and then the driver will convert the data into a form that the underlying hardware can recognize.
Once the send descriptor is in place, the driver adjusts the frame data (for example, adjust byte alignment, etc.), then puts the data frame into the Send queue, and then sends the descriptor of the frame that will be sent to the hardware.
Since we take an example of a USB WiFi adapter based on RT73USB, the data frame is finally sent to the wireless device via the USB interface.
The data is then inserted into the PHY header and other information, and the last packet is sent to the air. The driver also needs feedback sending status to mac80211, and the state information is usually stored in the struct ieee80211_tx_info.
After ieee80211_tx_status a series of calls, or some variant functions are fed back to the upper layer.
Speaking of which, the sending of packets is also temporarily over.
5 talking about management path
Theoretically, we can send control frames through sockets in user space just like a data path. But there are a lot of well-developed user-level management tools that can do the job.
in particular wpa_supplicant and HOST_APD. Wpa_supplicant controls the connection of wireless networks in the client STA mode, such as Scan Discovery Network, identity authentication, association, etc.
and HOST_APD can do the AP. The former is used to connect hot spots, the latter used to launch hot spots. These user-tier tools communicate with the kernel through NetLink sockets. The associated callback interface in the
kernel is nl80211 in cfg80211. The user-level tool sends commands to the kernel through libraries provided by NetLink (e.g., Nl80211_cmd_trigger_scan).
in the kernel, the nl80211 receives the command issued by the application layer. The following code shows the corresponding binding situation.
static const struct Genl_ops nl80211_ops[] = { { . cmd = nl80211_cmd_get_wiphy, . doit = nl80211_get_wiphy,
.dumpit = nl80211_dump_wiphy, . Done = Nl80211_dump_wiphy_done, . Policy = nl80211_policy,/ * can be Retrieved by unprivileged users */ . internal_flags = nl80211_flag_need_wiphy | NL80211_FLAG_NEED_RTNL, },...... { . cmd = Nl80211_cmd_trigger_scan, . doit = Nl80211_trigger_scan, . Policy = Nl80211_policy, . Flags = Genl_admin_perm, . internal_flags = nl80211_flag_need_wdev_up | NL80211_FLAG_NEED_RTNL, },......};
In the case of triggering scan, the scan request is implemented from cfg80211 to mac80211 by a callback function that is registered in the cfg80211 by mac80211.
const struct Cfg80211_ops mac80211_config_ops = {... . Scan = Ieee80211_scan,...};
In mac80211, Ieee80211_scan will specifically implement the details of the scan Discovery network.
=>ieee80211_scan_state_send_probe =>ieee80211_send_probe_req=>ieee80211_tx_skb_tid_band=>ieee80211_ Xmit=>ieee80211_tx=>ieee80211_tx_frags=>drv_txj
How are 6 packets received?
We then turn to the process of receiving data, and now we are no longer comparing the data path to the managed path. I believe the reader can understand the same.
When a packet is captured in the air by a wireless device, the hardware will send an interrupt to the kernel (most of the PCI interface devices do), or a polling mechanism to determine if there is data coming (for example, using a USB interface).
The former, the interrupt will cause the execution of the interrupt handler, which causes the specific receive function to be called.
The callback function of the general device driver does not do much about receiving the packet, just doing the data check, filling the receive descriptor for mac80211, and then pushing the packet to mac80211, which is done by mac80211 (directly or indirectly into the receiving queue).
After the data enters mac80211, IEEE80211_RX or other variant receive functions are called. Here the data path and the management path are also separated.
If the received frame is data, it will be converted to a 802.3 data frame (implemented via __ieee80211_data_to8023) and the data frame will then be delivered to the network stack via NETIF_RECEIVE_SKB. In the protocol stack, each layer network protocol will parse the data and identify the protocol header.
If a control frame is received, the data will be processed by IEEE80211_STA_RX_QUEUED_MGMT. Some control frames are terminated at the mac80211 level, and others will be sent through cfg80211 to the hypervisor under User space.
For example, the authentication control frame is cfg80211_rx_mlme_mgmt processed and then sent to the wpa_supplicant under the user space via Nl80211_send_rx_auth; The corresponding associated response control frame is cfg80211_rx_assoc_resp processed and sent by NL80211_SEND_RX_ASSOC to the user space.
7 Summary
The general WiFi driver consists of the following three parts: configuration, send callback, receive callback. As an example of a USB WiFi adapter, the probe function is called when the kernel detects that the device is plugged in. This can occur when a configured Ieee80211_ops is registered.
First, IEEE80211_ALLOC_HW assigns a IEEE80211_HW structure, which represents the corresponding WiFi device. In addition, the following data structures are assigned:
- Wiphy structure: Mainly used to describe the WiFi hardware parameters (such as MAC address, interface mode and combination, supported baud rate and some other hardware features).
- Ieee80211_local structure: This is a device driver layer visible structure, and is mac80211 used extensively. The mapping bindings for Ieee80211_ops are linked to ieee80211_local. The former as a member of the latter. Ieee80211_local can be obtained by container_of or hw_to_local this dedicated API in IEEE80211_HW.
- The device driver uses a private structure of void *priv in IEEE80211_HW.
Note: The registration of hardware devices is completed by IEEE80211_REGISTER_HW, provided that the mac80211 module has been inserted in advance, as in STA mode, it is necessary to first connect a hotspot with a wpa_supplicant control device to communicate.
Finally, it is hoped that this summary will allow the relevant personnel to explore the source code with a holistic grasp.
Reference Original: Https://www.linux.com/blog/linux-wireless-networking-short-walk
Reference: Https://wireless.wiki.kernel.org/en/developers/documentation/glossary
Linux Kernel Wireless subsystem