Android 的 wifi 结构主要可以分为两个部分
- 数据包的收发
- 无线网络的控制
数据传输
在 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 等。