Android系统硬件抽象层原理与实现之WIFI

作者:朱克锋

转载请注明出处:http://blog.csdn.net/linux_zkf/article/details/7492391

 

Android系统硬件抽象层原理与实现之WIFI

本文我将主要分析wifi的硬件抽象层的实现和WPA相关的东西,wifi是一种无线网路通信技术,相关的介绍网络上有很多,介绍的也很全面,这里我就不在过多的介绍了,作为一种无线网络产品,其在android系统中也有其功能体现。

android系统中wifi系统包括:linux kernel 中的驱动,协议,本地部分,java框架。本文主要介绍的是本地部分也就是HAL层的实现

首先看看wifiandroid系统中的结构:

 

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

wpaexternal/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_eventwifi_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,另一个是 monitorinterfaceMonitorinterface用于监测从wpa_supplicant发出的event事件,当两个socket创建成功后,monitorinterface会调用wpa_ctrl_attach函数发送ATTACHwpa_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驱动实在使用时加载,不使用时卸载

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值