当前位置: 首页 > 工具软件 > MADWIFI > 使用案例 >

hostapd wpa_supplicant madwifi详细分析(五)——hostapd_global_run函数

罗昊明
2023-12-01
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/lee244868149/article/details/42078423


   main函数的前面部分做好了传入参数的处理、config文件的读取、初始化等准备工作,这里将进入最主要的部分,hostapd_global_run函数。

   这里就不贴繁琐的代码了,这个函数主要分三步:


1.  调用tncs_global_init完成tnc相关的初始化,这里就不详细说了

2.  调用os_daemonize函数实现将该程序以后台进程运行,它主要实现过程是调用os_daemon将标准输入、标准输出和标准出错都重定向到/dev/null文件下,这样就不能通过

      终端进行交互了,但是交互过程是使用hostapd_cli这个进程实现的,前面章节有介绍;然后检查pid_file文件的合法性。

3.  eloop_run核心函数,这个函数很重要,所以下面将详细介绍。


 
 
  1. void eloop_run(void)
  2. {
  3. #ifdef CONFIG_ELOOP_POLL
  4. int num_poll_fds;
  5. int timeout_ms = 0;
  6. #endif /* CONFIG_ELOOP_POLL */
  7. #ifdef CONFIG_ELOOP_SELECT
  8. fd_set *rfds, *wfds, *efds;
  9. struct timeval _tv;
  10. #endif /* CONFIG_ELOOP_SELECT */
  11. #ifdef CONFIG_ELOOP_EPOLL
  12. int timeout_ms = -1;
  13. #endif /* CONFIG_ELOOP_EPOLL */
  14. int res;
  15. struct os_reltime tv, now;
  16. #ifdef CONFIG_ELOOP_SELECT
  17. rfds = os_malloc( sizeof(*rfds));
  18. wfds = os_malloc( sizeof(*wfds));
  19. efds = os_malloc( sizeof(*efds));
  20. if (rfds == NULL || wfds == NULL || efds == NULL)
  21. goto out;
  22. #endif /* CONFIG_ELOOP_SELECT */
  23. while (!eloop.terminate &&
  24. (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
  25. eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
  26. struct eloop_timeout *timeout;
  27. timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
  28. list);
  29. if (timeout) {
  30. os_get_reltime(&now);
  31. if (os_reltime_before(&now, &timeout->time))
  32. os_reltime_sub(&timeout->time, &now, &tv);
  33. else
  34. tv.sec = tv.usec = 0;
  35. #if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL)
  36. timeout_ms = tv.sec * 1000 + tv.usec / 1000;
  37. #endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */
  38. #ifdef CONFIG_ELOOP_SELECT
  39. _tv.tv_sec = tv.sec;
  40. _tv.tv_usec = tv.usec;
  41. #endif /* CONFIG_ELOOP_SELECT */
  42. }
  43. #ifdef CONFIG_ELOOP_POLL
  44. num_poll_fds = eloop_sock_table_set_fds(
  45. &eloop.readers, &eloop.writers, &eloop.exceptions,
  46. eloop.pollfds, eloop.pollfds_map,
  47. eloop.max_pollfd_map);
  48. res = poll(eloop.pollfds, num_poll_fds,
  49. timeout ? timeout_ms : -1);
  50. #endif /* CONFIG_ELOOP_POLL */
  51. #ifdef CONFIG_ELOOP_SELECT
  52. eloop_sock_table_set_fds(&eloop.readers, rfds);
  53. eloop_sock_table_set_fds(&eloop.writers, wfds);
  54. eloop_sock_table_set_fds(&eloop.exceptions, efds);
  55. res = select(eloop.max_sock + 1, rfds, wfds, efds,
  56. timeout ? &_tv : NULL);
  57. #endif /* CONFIG_ELOOP_SELECT */
  58. #ifdef CONFIG_ELOOP_EPOLL
  59. if (eloop.count == 0) {
  60. res = 0;
  61. } else {
  62. res = epoll_wait(eloop.epollfd, eloop.epoll_events,
  63. eloop.count, timeout_ms);
  64. }
  65. #endif /* CONFIG_ELOOP_EPOLL */
  66. if (res < 0 && errno != EINTR && errno != 0) {
  67. wpa_printf(MSG_ERROR, "eloop: %s: %s",
  68. #ifdef CONFIG_ELOOP_POLL
  69. "poll"
  70. #endif /* CONFIG_ELOOP_POLL */
  71. #ifdef CONFIG_ELOOP_SELECT
  72. "select"
  73. #endif /* CONFIG_ELOOP_SELECT */
  74. #ifdef CONFIG_ELOOP_EPOLL
  75. "epoll"
  76. #endif /* CONFIG_ELOOP_EPOLL */
  77. , strerror(errno));
  78. goto out;
  79. }
  80. eloop_process_pending_signals();
  81. /* check if some registered timeouts have occurred */
  82. timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
  83. list);
  84. if (timeout) {
  85. os_get_reltime(&now);
  86. if (!os_reltime_before(&now, &timeout->time)) {
  87. void *eloop_data = timeout->eloop_data;
  88. void *user_data = timeout->user_data;
  89. eloop_timeout_handler handler =
  90. timeout->handler;
  91. eloop_remove_timeout(timeout);
  92. handler(eloop_data, user_data);
  93. }
  94. }
  95. if (res <= 0)
  96. continue;
  97. #ifdef CONFIG_ELOOP_POLL
  98. eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,
  99. &eloop.exceptions, eloop.pollfds_map,
  100. eloop.max_pollfd_map);
  101. #endif /* CONFIG_ELOOP_POLL */
  102. #ifdef CONFIG_ELOOP_SELECT
  103. eloop_sock_table_dispatch(&eloop.readers, rfds);
  104. eloop_sock_table_dispatch(&eloop.writers, wfds);
  105. eloop_sock_table_dispatch(&eloop.exceptions, efds);
  106. #endif /* CONFIG_ELOOP_SELECT */
  107. #ifdef CONFIG_ELOOP_EPOLL
  108. eloop_sock_table_dispatch(eloop.epoll_events, res);
  109. #endif /* CONFIG_ELOOP_EPOLL */
  110. }
  111. eloop.terminate = 0;
  112. out:
  113. #ifdef CONFIG_ELOOP_SELECT
  114. os_free(rfds);
  115. os_free(wfds);
  116. os_free(efds);
  117. #endif /* CONFIG_ELOOP_SELECT */
  118. return;
  119.  

首先为三个文件描述符集申请空间: 

    rfds = os_malloc(sizeof(*rfds));
    wfds = os_malloc(sizeof(*wfds));
    efds = os_malloc(sizeof(*efds));

然后进入while循环:

   while (!eloop.terminate && (eloop.timeout || eloop.readers.count > 0 || eloop.writers.count > 0 || eloop.exceptions.count > 0))

它的循环条件如括号里面描述,正常情况都在这里面循环,除非terminate为1,而这个有信号处理设置,参见
eloop_register_signal_terminate(handle_term, NULL);
static void handle_term(int sig, void *eloop_ctx, void *signal_ctx)
{
    wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig);
    eloop_terminate();
}
void eloop_terminate(void)
{
    eloop.terminate = 1;
}


接下来对超时时间进行设置timeout,主要是为下面调用的select函数会用到超时时间做准备。

        if (timeout) {
            os_get_reltime(&now);
            if (os_reltime_before(&now, &timeout->time))
                os_reltime_sub(&timeout->time, &now, &tv);
            else
                tv.sec = tv.usec = 0;
            _tv.tv_sec = tv.sec;
            _tv.tv_usec = tv.usec;
        }

将申请的文件描述符集与eloop对象相结合,并调用select函数对这些文件发生异常进行监听:

        eloop_sock_table_set_fds(&eloop.readers, rfds);
        eloop_sock_table_set_fds(&eloop.writers, wfds);
        eloop_sock_table_set_fds(&eloop.exceptions, efds);
        res = select(eloop.max_sock + 1, rfds, wfds, efds, timeout ? &_tv : NULL);


最后eloop_process_pending_signals对发生的信号进行处理:


 
 
  1. static void eloop_process_pending_signals(void)
  2. {
  3. int i;
  4. if (eloop.signaled == 0) //有没有信号产生,如果有,那么这个标志位将为1,说明有信号需要处理,如果为0,那么没有信号要处理,函数返回
  5. return;
  6. eloop.signaled = 0; //将信号标示为置0,以便下次有信号产生时,置1
  7. if (eloop.pending_terminate) { //如果不用处理后面将会产生的信号,则立即向进程发送一个SIGALARM信号,然后将这个标志置0
  8. #ifndef CONFIG_NATIVE_WINDOWS
  9. alarm( 0);
  10. #endif /* CONFIG_NATIVE_WINDOWS */
  11. eloop.pending_terminate = 0;
  12. }
  13. for (i = 0; i < eloop.signal_count; i++) { //对信号标示进行处理
  14. if (eloop.signals[i].signaled) {
  15. eloop.signals[i].signaled = 0;
  16. #ifndef CONFIG_NATIVE_WINDOWS
  17. eloop_register_signal(SIGHUP, handle_reload, NULL); //对中断信号和中断处理函数进行注册
  18. eloop_register_signal(SIGUSR1, handle_dump_state, NULL);
  19. #endif /* CONFIG_NATIVE_WINDOWS */
  20. eloop_register_signal_terminate(handle_term, NULL);
  21. eloop.signals[i].handler(eloop.signals[i].sig, //调用处理函数对相应的信号进行处理,那么到底调用的是什么处理函数呢?这些处理函数的注册是在
  22. eloop.user_data, //什么地方呢?这个进程是怎么样对数据包进行处理的呢?在哪里处理呢?
  23. eloop.signals[i].user_data);
  24. }
  25. }
  26. }


到这里,应该对hostapd这个程序的整体有了一定的把握,应该能看懂第一篇中的那张结构图了,但也有局限的地方,比如好多细节的地方没有讲清楚,

比如:数据包是在哪里接收的? 数据包是在哪里发送的? 数据包是这样存放的?这些处理函数是在哪里注册的? 客户选择的加密方式是怎么起作用的?

hostapd怎么将一块网卡切换到了ap模式? 等等。


接下来将尽力弄清楚这些问题。

 类似资料: