本文共 14530 字,大约阅读时间需要 48 分钟。
前言:之前在 梳理了对wpa_supplicant 启动参数的解析以及存储,对整体的初始化未作探究,继续梳理一下。
1.初始化流程梳理
1.1 os_program_init
int main(int argc, char *argv[]){ int c, i; struct wpa_interface *ifaces, *iface; int iface_count, exitcode = -1; struct wpa_params params; struct wpa_global *global; if (os_program_init()) return -1;
这部分声明了一些局部变量,之后调用os_program_init()进行初始化。看下os_program_init()所做工作。
搜索发现有5个文件定义了该方法,看下Android.mk文件
137 ifndef CONFIG_OS 138 ifdef CONFIG_NATIVE_WINDOWS 139 CONFIG_OS=win32 140 else 141 CONFIG_OS=unix 142 endif 143 endif 144 145 ifeq ($(CONFIG_OS), internal) 146 L_CFLAGS += -DOS_NO_C_LIB_DEFINES 147 endif 148 149 OBJS += src/utils/os_$(CONFIG_OS).c 150 OBJS_p += src/utils/os_$(CONFIG_OS).c 151 OBJS_c += src/utils/os_$(CONFIG_OS).c
这里表示如果没有指定CONFIG_OS宏,则看下有没有指定CONFIG_NATIVE_WINDOWS,若指定了那么CONFIG_OS就是win32,否则是unix。
看到这里其实对上OS名称,这里其实是对操作系统进行区分,另一方面表示wpa_s是支持多操作系统的,比如win32和unix。
本文分析的主要还是Android系统,Android系统在如下config文件有定义。
vim +248 ./wpa_supplicant/android.config
244 # Select wrapper for operating system and C library specific functions245 # unix = UNIX/POSIX like systems (default)246 # win32 = Windows systems247 # none = Empty template248 CONFIG_OS=unix
众所周知,Android底层是基于Linux,属于unix。
这里再回头看下os_program_init()这个方法自然是调用的os_unix.c中的方法。
int os_program_init(void){#ifdef ANDROID struct __user_cap_header_struct header; struct __user_cap_data_struct cap; struct group *grp = getgrnam("wifi"); gid_t gid_wifi = grp ? grp->gr_gid : 0; struct passwd *pwd = getpwnam("wifi"); uid_t uid_wifi = pwd ? pwd->pw_uid : 0; /* * We ignore errors here since errors are normal if we * are already running as non-root. */#ifdef ANDROID_SETGROUPS_OVERRIDE gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE }; if (!gid_wifi || !uid_wifi) return -1;#else /* ANDROID_SETGROUPS_OVERRIDE */ gid_t groups[3]; if (!gid_wifi || !uid_wifi) return -1; groups[0] = gid_wifi; grp = getgrnam("inet"); groups[1] = grp ? grp->gr_gid : 0; if (!groups[1]) return -1; grp = getgrnam("keystore"); groups[2] = grp ? grp->gr_gid : 0; if (!groups[2]) return -1;#endif /* ANDROID_SETGROUPS_OVERRIDE */ setgroups(ARRAY_SIZE(groups), groups); prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); setgid(gid_wifi); setuid(uid_wifi); header.version = _LINUX_CAPABILITY_VERSION; header.pid = 0; cap.effective = cap.permitted = (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW); cap.inheritable = 0; capset(&header, &cap);#endif /* ANDROID */ return 0;}
如何初始化简单看起来分为2个部分,group和capset的处理。
1)group(参考)
相关函数:initgroups, getgroup, getgid, setgid头文件:#include定义函数:int setgroups(size_t size, const gid_t * list);函数说明:setgroups()用来将list 数组中所标明的组加入到目前进程的组设置中. 参数size 为list()的gid_t 数目, 最大值为NGROUP(32)。返回值:设置成功则返回0, 如有错误则返回-1.错误代码:EFAULT:参数list 数组地址不合法.EPERM:权限不足, 必须是root 权限EINVAL:参数size 值大于NGROUP(32).
获取了wifi的gid、inet的gid和keystore的gid,然后设置了一下。
2)capset(参考)
capset 设置了进程权限,获取net相关权限?
总体说来是权限相关的设置。
1.2 wpa_supplicant中的log
os_memset(¶ms, 0, sizeof(params)); params.wpa_debug_level = MSG_INFO;
这里定义了wpa_s的初始化log等级为MSG_INFO.
/** * wpa_debug_level - Debugging verbosity level (e.g., MSG_INFO) */ int wpa_debug_level;
在 src/utils/wpa_debug.h 中声明了所有等级
/* Debugging function - conditional printf and hex dump. Driver wrappers can * use these for debugging purposes. */enum { MSG_EXCESSIVE, MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR};
简单看下这个等级的作用,随便打开一个wpa_s中带log的文件
wpa_printf(MSG_DEBUG, "WPS: Own DH private key not available");
该log打印方法是在src/utils/wpa_debug.c中定义的
void wpa_printf(int level, const char *fmt, ...){ va_list ap; va_start(ap, fmt); if (level >= wpa_debug_level) {#ifdef CONFIG_ANDROID_LOG __android_log_vprint(wpa_to_android_level(level), ANDROID_LOG_NAME, fmt, ap);#else /* CONFIG_ANDROID_LOG */#ifdef CONFIG_DEBUG_SYSLOG if (wpa_debug_syslog) { vsyslog(syslog_priority(level), fmt, ap); } else {#endif /* CONFIG_DEBUG_SYSLOG */ wpa_debug_print_timestamp();#ifdef CONFIG_DEBUG_FILE if (out_file) { vfprintf(out_file, fmt, ap); fprintf(out_file, "\n"); } else {#endif /* CONFIG_DEBUG_FILE */ vprintf(fmt, ap); printf("\n");#ifdef CONFIG_DEBUG_FILE }#endif /* CONFIG_DEBUG_FILE */#ifdef CONFIG_DEBUG_SYSLOG }#endif /* CONFIG_DEBUG_SYSLOG */#endif /* CONFIG_ANDROID_LOG */ } va_end(ap);#ifdef CONFIG_DEBUG_LINUX_TRACING if (wpa_debug_tracing_file != NULL) { va_start(ap, fmt); fprintf(wpa_debug_tracing_file, WPAS_TRACE_PFX, level); vfprintf(wpa_debug_tracing_file, fmt, ap); fprintf(wpa_debug_tracing_file, "\n"); fflush(wpa_debug_tracing_file); va_end(ap); }#endif /* CONFIG_DEBUG_LINUX_TRACING */}
简单说来就是和Android一样,MSG_INFO, MSG_WARNING, MSG_ERROR等级的log才能打印出来。
1.3 wpa_supplicant_fd_workaround
static void wpa_supplicant_fd_workaround(int start){#ifdef __linux__ static int fd[3] = { -1, -1, -1 }; int i; /* When started from pcmcia-cs scripts, wpa_supplicant might start with * fd 0, 1, and 2 closed. This will cause some issues because many * places in wpa_supplicant are still printing out to stdout. As a * workaround, make sure that fd's 0, 1, and 2 are not used for other * sockets. */ if (start) { for (i = 0; i < 3; i++) { fd[i] = open("/dev/null", O_RDWR); if (fd[i] > 2) { close(fd[i]); fd[i] = -1; break; } } } else { for (i = 0; i < 3; i++) { if (fd[i] >= 0) { close(fd[i]); fd[i] = -1; } } }#endif /* __linux__ */}
参考
如果使用了pcmcia-cs scripts来启动wpa_supplicant,这个时候fd 0,1,2是关闭的。(注意: 习惯上,标准输入fd为0,标准输出为1,标准错误为2)
由于在wpa_supplicant中会使用stdout来输出,如果不管0,1,2三个文件描述符可能会出现一些错误。 所以,就有了该函数。 下面来分析一下该函数: 如果不使用pcmcia-cs scripts,那么第一次调用fd[i] = open("/dev/null", O_RDWR)时,fd[i]取值就是3(开启应用程序时,会默认启动0,1,2三个文件),第二次就是4... 后面紧跟了一个判断,如果fd[i]大于2,就close(fd[i])。整个函数相当与什么都没有做。 如果使用了pcmcia-cs scripts,依据上面的注释,三次调用fd[i] = open("/dev/null", O_RDWR)时,fd[i]取值就是0,1,2;即相当于,将标准输入、标准输出、标准错误重定向到/dev/null中。避免了其他socket使用0,1,2这三个文件描述符而导致的程序出错。说的很明白了=-=
1.4 wpa_supplicant_init
/** * wpa_supplicant_init - Initialize %wpa_supplicant * @params: Parameters for %wpa_supplicant * Returns: Pointer to global %wpa_supplicant data, or %NULL on failure * * This function is used to initialize %wpa_supplicant. After successful * initialization, the returned data pointer can be used to add and remove * network interfaces, and eventually, to deinitialize %wpa_supplicant. */struct wpa_global * wpa_supplicant_init(struct wpa_params *params){ struct wpa_global *global; int ret, i; if (params == NULL) return NULL;#ifdef CONFIG_DRIVER_NDIS { void driver_ndis_init_ops(void); driver_ndis_init_ops(); }#endif /* CONFIG_DRIVER_NDIS */#ifndef CONFIG_NO_WPA_MSG wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);#endif /* CONFIG_NO_WPA_MSG */ if (params->wpa_debug_file_path) wpa_debug_open_file(params->wpa_debug_file_path); else wpa_debug_setup_stdout(); if (params->wpa_debug_syslog) wpa_debug_open_syslog(); if (params->wpa_debug_tracing) { ret = wpa_debug_open_linux_tracing(); if (ret) { wpa_printf(MSG_ERROR, "Failed to enable trace logging"); return NULL; } } ret = eap_register_methods(); if (ret) { wpa_printf(MSG_ERROR, "Failed to register EAP methods"); if (ret == -2) wpa_printf(MSG_ERROR, "Two or more EAP methods used " "the same EAP type."); return NULL; } global = os_zalloc(sizeof(*global)); if (global == NULL) return NULL; dl_list_init(&global->p2p_srv_bonjour); dl_list_init(&global->p2p_srv_upnp); global->params.daemonize = params->daemonize; global->params.wait_for_monitor = params->wait_for_monitor; global->params.dbus_ctrl_interface = params->dbus_ctrl_interface; if (params->pid_file) global->params.pid_file = os_strdup(params->pid_file); if (params->ctrl_interface) global->params.ctrl_interface = os_strdup(params->ctrl_interface); if (params->ctrl_interface_group) global->params.ctrl_interface_group = os_strdup(params->ctrl_interface_group); if (params->override_driver) global->params.override_driver = os_strdup(params->override_driver); if (params->override_ctrl_interface) global->params.override_ctrl_interface = os_strdup(params->override_ctrl_interface);#ifdef CONFIG_MATCH_IFACE global->params.match_iface_count = params->match_iface_count; if (params->match_iface_count) { global->params.match_ifaces = os_calloc(params->match_iface_count, sizeof(struct wpa_interface)); os_memcpy(global->params.match_ifaces, params->match_ifaces, params->match_iface_count * sizeof(struct wpa_interface)); }#endif /* CONFIG_MATCH_IFACE */#ifdef CONFIG_P2P if (params->conf_p2p_dev) global->params.conf_p2p_dev = os_strdup(params->conf_p2p_dev);#endif /* CONFIG_P2P */ wpa_debug_level = global->params.wpa_debug_level = params->wpa_debug_level; wpa_debug_show_keys = global->params.wpa_debug_show_keys = params->wpa_debug_show_keys; wpa_debug_timestamp = global->params.wpa_debug_timestamp = params->wpa_debug_timestamp; wpa_printf(MSG_DEBUG, "wpa_supplicant v" VERSION_STR); if (eloop_init()) { wpa_printf(MSG_ERROR, "Failed to initialize event loop"); wpa_supplicant_deinit(global); return NULL; } random_init(params->entropy_file); global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global); if (global->ctrl_iface == NULL) { wpa_supplicant_deinit(global); return NULL; } if (wpas_notify_supplicant_initialized(global)) { wpa_supplicant_deinit(global); return NULL; } for (i = 0; wpa_drivers[i]; i++) global->drv_count++; if (global->drv_count == 0) { wpa_printf(MSG_ERROR, "No drivers enabled"); wpa_supplicant_deinit(global); return NULL; } global->drv_priv = os_calloc(global->drv_count, sizeof(void *)); if (global->drv_priv == NULL) { wpa_supplicant_deinit(global); return NULL; }#ifdef CONFIG_WIFI_DISPLAY if (wifi_display_init(global) < 0) { wpa_printf(MSG_ERROR, "Failed to initialize Wi-Fi Display"); wpa_supplicant_deinit(global); return NULL; }#endif /* CONFIG_WIFI_DISPLAY */ eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0, wpas_periodic, global, NULL); return global;}
将之前从配置中读取的参数赋值初始化。
1.5 wpa_supplicant_add_iface
/** * wpa_supplicant_add_iface - Add a new network interface * @global: Pointer to global data from wpa_supplicant_init() * @iface: Interface configuration options * @parent: Parent interface or %NULL to assign new interface as parent * Returns: Pointer to the created interface or %NULL on failure * * This function is used to add new network interfaces for %wpa_supplicant. * This can be called before wpa_supplicant_run() to add interfaces before the * main event loop has been started. In addition, new interfaces can be added * dynamically while %wpa_supplicant is already running. This could happen, * e.g., when a hotplug network adapter is inserted. */struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global, struct wpa_interface *iface, struct wpa_supplicant *parent){ struct wpa_supplicant *wpa_s; struct wpa_interface t_iface; struct wpa_ssid *ssid; if (global == NULL || iface == NULL) return NULL; wpa_s = wpa_supplicant_alloc(parent); if (wpa_s == NULL) return NULL; wpa_s->global = global; t_iface = *iface; if (global->params.override_driver) { wpa_printf(MSG_DEBUG, "Override interface parameter: driver " "('%s' -> '%s')", iface->driver, global->params.override_driver); t_iface.driver = global->params.override_driver; } if (global->params.override_ctrl_interface) { wpa_printf(MSG_DEBUG, "Override interface parameter: " "ctrl_interface ('%s' -> '%s')", iface->ctrl_interface, global->params.override_ctrl_interface); t_iface.ctrl_interface = global->params.override_ctrl_interface; } if (wpa_supplicant_init_iface(wpa_s, &t_iface)) { wpa_printf(MSG_DEBUG, "Failed to add interface %s", iface->ifname); wpa_supplicant_deinit_iface(wpa_s, 0, 0); return NULL; } /* Notify the control interfaces about new iface */ if (wpas_notify_iface_added(wpa_s)) { wpa_supplicant_deinit_iface(wpa_s, 1, 0); return NULL; } /* Notify the control interfaces about new networks for non p2p mgmt * ifaces. */ if (iface->p2p_mgmt == 0) { for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) wpas_notify_network_added(wpa_s, ssid); } wpa_s->next = global->ifaces; global->ifaces = wpa_s; wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);#ifdef CONFIG_P2P if (wpa_s->global->p2p == NULL && !wpa_s->global->p2p_disabled && !wpa_s->conf->p2p_disabled && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) && wpas_p2p_add_p2pdev_interface( wpa_s, wpa_s->global->params.conf_p2p_dev) < 0) { wpa_printf(MSG_INFO, "P2P: Failed to enable P2P Device interface"); /* Try to continue without. P2P will be disabled. */ }#endif /* CONFIG_P2P */ return wpa_s;}
从之前可以看到一共有两个接口,p2p和wifi
vim +699 ./device/google/marlin/init.common.rcservice wpa_supplicant /vendor/bin/hw/wpa_supplicant \ -ip2p0 -Dnl80211 -c/data/misc/wifi/p2p_supplicant.conf \ -I/vendor/etc/wifi/p2p_supplicant_overlay.conf -N \ -iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf \ -I/vendor/etc/wifi/wpa_supplicant_overlay.conf \ -O/data/misc/wifi/sockets -puse_p2p_group_interface=1 \ -e/data/misc/wifi/entropy.bin -g@android:wpa_wlan0# we will start as root and wpa_supplicant will switch to user wifi# after setting up the capabilities required for WEXT# user wifi# group wifi inet keystore class main socket wpa_wlan0 dgram 660 wifi wifi disabled oneshot--------------------- 作者:i加加 来源:CSDN 原文:https://blog.csdn.net/sinat_20059415/article/details/83449860 版权声明:本文为博主原创文章,转载请附上博文链接!
1.6 wpa_supplicant_run
/** * wpa_supplicant_run - Run the %wpa_supplicant main event loop * @global: Pointer to global data from wpa_supplicant_init() * Returns: 0 after successful event loop run, -1 on failure * * This function starts the main event loop and continues running as long as * there are any remaining events. In most cases, this function is running as * long as the %wpa_supplicant process in still in use. */int wpa_supplicant_run(struct wpa_global *global){ struct wpa_supplicant *wpa_s; if (global->params.daemonize && (wpa_supplicant_daemon(global->params.pid_file) || eloop_sock_requeue())) return -1;#ifdef CONFIG_MATCH_IFACE if (wpa_supplicant_match_existing(global)) return -1;#endif if (global->params.wait_for_monitor) { for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) if (wpa_s->ctrl_iface && !wpa_s->p2p_mgmt) wpa_supplicant_ctrl_iface_wait( wpa_s->ctrl_iface); } eloop_register_signal_terminate(wpa_supplicant_terminate, global); eloop_register_signal_reconfig(wpa_supplicant_reconfig, global); eloop_run(); return 0;}
有很多debug的log,后续自己编译下改下log等级再梳理吧,待续。。。
转载地址:https://jiatai.blog.csdn.net/article/details/83684932 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!