a: 在纯linux的环境下,该手动连接过程,同样适用b: 在wifi驱动的移植初期,可以通过手动连接来测试该款wifi的基本驱动和wpa_supplicant是否工作正常c: 通过手动连接,你可以很容易了解wifi的工作过程d: 通过手动连接,可以很容易的调试,可以很好的定位问题出现哪里。
a:加载wifi驱动b:给wifi上电(optional)c:此时应该出来了网络接口(譬如wlan0),给网络接口上电(ifconfig wlan0 up)d:对于支持sta/p2p共存的,这个时候可以通过iwpriv命令,生成p2p0网络接口e:设定wpa_supplicant服务所需的配置文件:wpa_supplicant.conff:启动wpa_supplicant,在后台运行g:启动wpa_cli,并且连接到wpa_supplicant,这个时候可以通过wpa_cli来发送命令给wpa_supplicant来执行。
譬如有时,通过android,有些ap连不上,或不能扫描,或是鉴权失败,则这个时候可以试试通过手动操作来验证问题。如果手动测试是ok的,说明问题是出现在android层的(wifi Setting, wifi framework, wifi service等层)
步骤a:加载wifi驱动
通过insmod命令加载wifi驱动模块,由于mt5931在系统启动阶段的init.rc中,就已经被加载了。所以此处不需要手动加载。见下图(高亮部分即为mt5931所需的驱动模块):
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
{
struct wpa_ctrl *ctrl;
static int counter = 0;
int ret;
size_t res;
int tries = 0;
int flags;
ctrl = os_malloc(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
os_memset(ctrl, 0, sizeof(*ctrl));
ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
if (ctrl->s < 0) {
os_free(ctrl);
return NULL;
}
ctrl->local.sun_family = AF_UNIX;
counter++;
try_again: //如下语句指定了客服端的socket节点是在/data/misc/wifi/sockets路径下,并且节点名是有当前线程的ID和一个序号数组成。
ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
CONFIG_CTRL_IFACE_CLIENT_DIR "/"
CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
(int) getpid(), counter);
if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
close(ctrl->s);
os_free(ctrl);
return NULL;
}
tries++;
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local)) < 0) {//指定bind的时候,就会创建该client端的socket节点
if (errno == EADDRINUSE && tries < 2) {
/*
* getpid() returns unique identifier for this instance
* of wpa_ctrl, so the existing socket file must have
* been left by unclean termination of an earlier run.
* Remove the file and try again.
*/
unlink(ctrl->local.sun_path);
goto try_again;
}
close(ctrl->s);
os_free(ctrl);
return NULL;
}
#if defined(ANDROID) && !defined(PURE_LINUX)
chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
/*
* If the ctrl_path isn't an absolute pathname, assume that
* it's the name of a socket in the Android reserved namespace.
* Otherwise, it's a normal UNIX domain socket appearing in the
* filesystem.
*/
if (ctrl_path != NULL && *ctrl_path != '/') {
char buf[21];
os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
if (socket_local_client_connect(
ctrl->s, buf,
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_DGRAM) < 0) {
close(ctrl->s);
unlink(ctrl->local.sun_path);
os_free(ctrl);
return NULL;
}
return ctrl;
}
#endif /* ANDROID */
ctrl->dest.sun_family = AF_UNIX;
res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
sizeof(ctrl->dest.sun_path));
if (res >= sizeof(ctrl->dest.sun_path)) {
close(ctrl->s);
os_free(ctrl);
return NULL;
}//开始发起连接到service端的socket节点
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
sizeof(ctrl->dest)) < 0) {
close(ctrl->s);
unlink(ctrl->local.sun_path);
os_free(ctrl);
return NULL;
}
/*
* Make socket non-blocking so that we don't hang forever if
* target dies unexpectedly.
*/
flags = fcntl(ctrl->s, F_GETFL);
if (flags >= 0) {
flags |= O_NONBLOCK;
if (fcntl(ctrl->s, F_SETFL, flags) < 0) {
perror("fcntl(ctrl->s, O_NONBLOCK)");
/* Not fatal, continue on.*/
}
}
return ctrl;
}
如下你可以看到wpa_cli进程号是1517,而/data/misc/wifi/sockets下的client端socket节点的名字就是以该进程ID和序号组成的。两个节点,一个用来传输控制命令,一个用来接受wpa_supplicant报上来的事件。