wifi architectrue 简介

Posted by Vector Blog on September 7, 2017

Android 的 wifi 结构主要可以分为两个部分

  1. 数据包的收发
  2. 无线网络的控制

数据传输

在 Linux 中网络通信都是通过 socket 来操作 , 其中会经过

系统调用  <=>  协议无关层 <=> 网络协议 <=> 设备无关层 <=> 设备驱动     

从设备无关层是怎样到设备的驱动呢, 这里就涉及到网络设备的注册了。

在linux中使用struct net_device结构体来描述每一个网络设备 , 以下仅列出部分常用的成员变量

struct net_device {
	char			name[IFNAMSIZ];	//设备名
	int			ifindex;	//标识网络设备的唯一索引号
	unsigned char		*dev_addr;	//设备MAC地址
	unsigned int 	flags;	//网络设备接口的标识符
	struct net_device_stats 	stats;	//包含接口的 tx/rx 统计信息
	const struct net_device_ops 	*netdev_ops;	//包含该接口的各种操作函数指针
	.......
}

struct net_device_ops {
	......
	/* 网络设备被激活时被调用(即设备状态由down变成up) */
	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);
	void			(*ndo_change_rx_flags)(struct net_device *dev,
						       int flags);
	int			(*ndo_set_mac_address)(struct net_device *dev,
						       void *addr);
	int			(*ndo_do_ioctl)(struct net_device *dev,
					        struct ifreq *ifr, int cmd);
	void			(*ndo_set_rx_mode)(struct net_device *dev);
	struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
	......
}		

在网络设备驱动中需要先创建一个 net_device , 常用的函数有

/*  sizeof_priv 是私有数据区大小;
     name 是格式化设备名,
     setup 是初始化函数,注册该设备时,该函数被调用。
     txqs 是 tx subqueues 的数目
     rxqs 是 rx subqueues 的数目  */
struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
		unsigned char name_assign_type,
		void (*setup)(struct net_device *),
		unsigned int txqs, unsigned int rxqs)     
     
#define alloc_netdev(sizeof_priv, name, name_assign_type, setup) \
	alloc_netdev_mqs(sizeof_priv, name, name_assign_type, setup, 1, 1)

#define alloc_netdev_mq(sizeof_priv, name, name_assign_type, setup, count) \
	alloc_netdev_mqs(sizeof_priv, name, name_assign_type, setup, count, \
			 count)

/* alloc_netdev_mqs 的封装 , 以太网设备的名称设为eth%d,
   默认初始化函数设为ether_setup,发送和接收队列数目都设为1  */
struct net_device* alloc_etherdev(int sizeof_priv)

在分配好 net_device 结构体之后需要将该结构体注册到内核中

int register_netdev(struct net_device *dev)
void unregister_netdev(struct net_device *dev)

当设备注册好之后 , 如果有数据要通过该设备发送则会直接调用 netdev_ops 中的 ndo_start_xmit , 而设备收到数据会通过 netif_rx 将数据交给设备无关层来处理

无线网络控制

为从用户空间控制无线驱动程序 , 在 Linux 系统中提供了两套配置 802.11 的接口,分别是 wext ( Wireless Extensions 无线扩展接口) 和 nl80211 接口。

wext的接口实现上,应用层采用ioctl方式访问驱动,设置无线参数或者获取无线参数,配置无线驱动进行联网操作。无线驱动事件到应用层的传递采用的netlink socket技术 。但在linux-2.6.25 之后,wext API接口版本停止在V22就不再进行更新了。而替代其的是nl80211接口。

nl80211接口逐渐替代wext接口,nl80211用于配置一个cfg80211设备, 其应用层和内核层数据交换完全采用 netlink 的方式。目前使用 nl80211 接口的工具包括: iw、crda、hostapd 和 wpa_supplicant 等。