作者:朱克锋
转载请注明出处:http://blog.csdn.net/linux_zkf/article/details/7492391
Android系统硬件抽象层原理与实现之WIFI
本文我将主要分析wifi的硬件抽象层的实现和WPA相关的东西,wifi是一种无线网路通信技术,相关的介绍网络上有很多,介绍的也很全面,这里我就不在过多的介绍了,作为一种无线网络产品,其在android系统中也有其功能体现。
在android系统中wifi系统包括:linux kernel 中的驱动,协议,本地部分,java框架。本文主要介绍的是本地部分也就是HAL层的实现
首先看看wifi在android系统中的结构:
WIFI APP |
FRAMEWORK |
JNI |
WIFI HAL |
WPA |
DRIVER + PROTOCOL |
由上图可以看出wifi本地部分主要是HAL+WPA两部分,其中HAL部分对上层提供接口,并且与WPA交互,最终具体的实现是有WPA层实现的,可以说WIFI HAL是一个适配层更加合适。
Wifi硬件抽象层代码在源码种的位置:
hardware/libhardware_legacy/wifi/wifi.c
hardware/libhardware_legacy/include/libhardware_legacy/wifi.h
wpa在external/wpa_supplicant/
整个WIFIHAL实现都很简单,都是对wpa_supplicant的操作和使用,如果需要自己实现WIFIHAL可以参考wifi.c来实现wifi.h中所定义的接口,并且设置驱动的路径、名称、模块的名称等参数,具体操作都将由wpa_supplicant来完成。
其中wifi.h定义了Android系统中WIFI硬件抽象层接口,wifi.h定义
//装载wifi驱动
int wifi_load_driver();
//缷载wifi驱动
int wifi_unload_driver();
//开始、停止supplicant
int wifi_start_supplicant();
int wifi_stop_supplicant();
//连接supplicant
int wifi_connect_to_supplicant();
//关闭supplicant连接
voidwifi_close_supplicant_connection();
int wifi_wait_for_event(char *buf,size_t len);
int wifi_command(const char *command,char *reply, size_t *reply_len);
// DHCP请求
int do_dhcp_request(int *ipaddr, int*gateway, int *mask, int *dns1, int *dns2, int *server, int *lease);
const char *get_dhcp_error_string();
操作接口都很简单,其中比较重要的是wifi_wait_for_event和wifi_command函数,前者用于接收wpa_supplicant上报的事件,而后者用于向wpa_supplicant进程发送命令.
下面来看看wifi_wait_for_event的实现
int wifi_wait_for_event(char *buf, size_t buflen)
{
size_t nread = buflen - 1;
int fd;
fd_set rfds;
int result;
struct timeval tval;
struct timeval *tptr;
if (monitor_conn == NULL) {
LOGD("Connection closed\n");
strncpy(buf, WPA_EVENT_TERMINATING " - connection closed", buflen-1);
buf[buflen-1] = '\0';
return strlen(buf);
}
result = wifi_ctrl_recv(monitor_conn, buf, &nread);
if (result < 0) {
LOGD("wifi_ctrl_recv failed: %s\n", strerror(errno));
strncpy(buf, WPA_EVENT_TERMINATING " - recv error", buflen-1);
buf[buflen-1] = '\0';
return strlen(buf);
}
buf[nread] = '\0';
/* LOGD("wait_for_event: result=%d nread=%d string=\"%s\"\n", result, nread, buf); */
/* Check for EOF on the socket */
if (result == 0 && nread == 0) {
/* Fabricate an event to pass up */
LOGD("Received EOF on supplicant socket\n");
strncpy(buf, WPA_EVENT_TERMINATING " - signal 0 received", buflen-1);
buf[buflen-1] = '\0';
return strlen(buf);
}
/*
* Events strings are in the format
*
* <N>CTRL-EVENT-XXX
*
* where N is the message level in numerical form (0=VERBOSE, 1=DEBUG,
* etc.) and XXX is the event name. The level information is not useful
* to us, so strip it off.
*/
if (buf[0] == '<') {
char *match = strchr(buf, '>');
if (match != NULL) {
nread -= (match+1-buf);
memmove(buf, match+1, nread+1);
}
}
return nread;
}
int wifi_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
{
int res;
int ctrlfd = wpa_ctrl_get_fd(ctrl);
struct pollfd rfds[2];
memset(rfds, 0, 2 * sizeof(struct pollfd));
rfds[0].fd = ctrlfd;
rfds[0].events |= POLLIN;
rfds[1].fd = exit_sockets[1];
rfds[1].events |= POLLIN;
res = poll(rfds, 2, -1);
if (res < 0) {
LOGE("Error poll = %d", res);
return res;
}
if (rfds[0].revents & POLLIN) {
return wpa_ctrl_recv(ctrl, reply, reply_len);
} else {
LOGD("Received on exit socket, terminate");
return -1;
}
return 0;
}
其中wifi_ctrl_recv中的wpa_ctrl_recv(ctrl, reply, reply_len)是wpa_ctrl提供的wpa_ctrl_recv接口,来接收事件。
wifi_command函数,用于向wpa_supplicant进程发送命令
int wifi_command(const char *command, char *reply, size_t *reply_len)
{
return wifi_send_command(ctrl_conn, command, reply, reply_len);
}
wifi_command函数会调用wifi_send_command来实现命令的发送,发送过程同样使用wpa_ctrl提供的wpa_ctrl_request接口来完成
int wifi_send_command(struct wpa_ctrl *ctrl, const char *cmd, char *reply, size_t *reply_len)
{
int ret;
if (ctrl_conn == NULL) {
LOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
return -1;
}
ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), reply, reply_len, NULL);
if (ret == -2) {
LOGD("'%s' command timed out.\n", cmd);
/* unblocks the monitor receive socket for termination */
write(exit_sockets[0], "T", 1);
return -2;
} else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
return -1;
}
if (strncmp(cmd, "PING", 4) == 0) {
reply[*reply_len] = '\0';
}
return 0;
}
在wifi.c中还有一点很重要,就是在wifi_connect_to_supplicant函数中调用wpa_ctrl_open函数创建两个socket,一个是ctrlinterface,另一个是 monitorinterface。Monitorinterface用于监测从wpa_supplicant发出的event事件,当两个socket创建成功后,monitorinterface会调用wpa_ctrl_attach函数发送ATTACH到wpa_supplicant模块,wpa_supplicant模块收到后,会将该客户端的socket信息记录下来,用于以后发送事件时用。
#define SUPPLICANT_TIMEOUT 3000000 // microseconds
#define SUPPLICANT_TIMEOUT_STEP 100000 // microseconds
int wifi_connect_to_supplicant()
{
char ifname[256];
char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
int supplicant_timeout = SUPPLICANT_TIMEOUT;
/* Make sure supplicant is running */
if (!property_get(SUPP_PROP_NAME, supp_status, NULL)
|| strcmp(supp_status, "running") != 0) {
LOGE("Supplicant not running, cannot connect");
return -1;
}
if (access(IFACE_DIR, F_OK) == 0) {
snprintf(ifname, sizeof(ifname), "%s/%s", IFACE_DIR, iface);
} else {
strlcpy(ifname, iface, sizeof(ifname));
}
ctrl_conn = wpa_ctrl_open(ifname);
while (ctrl_conn == NULL && supplicant_timeout > 0) {
usleep(SUPPLICANT_TIMEOUT_STEP);
supplicant_timeout -= SUPPLICANT_TIMEOUT_STEP;
ctrl_conn = wpa_ctrl_open(ifname);
}
if (ctrl_conn == NULL) {
LOGE("1.Unable to open connection to supplicant on \"%s\": %s",
ifname, strerror(errno));
return -1;
}
monitor_conn = wpa_ctrl_open(ifname);
if (monitor_conn == NULL) {
wpa_ctrl_close(ctrl_conn);
ctrl_conn = NULL;
LOGE("2. Unable to open connection to supplicant on \"%s\": %s",
ifname, strerror(errno));
return -1;
}
if (wpa_ctrl_attach(monitor_conn) != 0) {
wpa_ctrl_close(monitor_conn);
wpa_ctrl_close(ctrl_conn);
ctrl_conn = monitor_conn = NULL;
return -1;
}
if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets) == -1) {
wpa_ctrl_close(monitor_conn);
wpa_ctrl_close(ctrl_conn);
ctrl_conn = monitor_conn = NULL;
return -1;
}
return 0;
}
在android系统中对wifi驱动的加载与卸载有些特殊注意下面两个方法
static int insmod(const char *filename, const char *args)
{
void *module;
unsigned int size;
int ret;
module = load_file(filename, &size);
if (!module)
return -1;
ret = init_module(module, size, args);
free(module);
return ret;
}
static int rmmod(const char *modname)
{
int ret = -1;
int maxtry = 10;
while (maxtry-- > 0) {
ret = delete_module(modname, O_NONBLOCK | O_EXCL);
if (ret < 0 && errno == EAGAIN)
usleep(500000);
else
break;
}
if (ret != 0)
LOGD("Unable to unload driver module \"%s\": %s\n",
modname, strerror(errno));
return ret;
}
一般的驱动都是在系统启动是加在好的而wifi驱动实在使用时加载,不使用时卸载