hostapd 中netlink初始化

1. 从main()中调用hostapd_driver_init() 

  hostapd_driver_init(interfaces.iface[i])

 

 

 

netlink相关结构体

 

驱动结构体struct wpa_driver_ops函数注册

const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
.get_bssid = wpa_driver_nl80211_get_bssid,
.get_ssid = wpa_driver_nl80211_get_ssid,
.set_key = driver_nl80211_set_key,
.scan2 = driver_nl80211_scan2,
.sched_scan = wpa_driver_nl80211_sched_scan,
.stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
.get_scan_results2 = wpa_driver_nl80211_get_scan_results,
.abort_scan = wpa_driver_nl80211_abort_scan,
.deauthenticate = driver_nl80211_deauthenticate,
.authenticate = driver_nl80211_authenticate,
.associate = wpa_driver_nl80211_associate,
.global_init = nl80211_global_init,
.global_deinit = nl80211_global_deinit,
.init2 = wpa_driver_nl80211_init,
.deinit = driver_nl80211_deinit,
.get_capa = wpa_driver_nl80211_get_capa,
.set_operstate = wpa_driver_nl80211_set_operstate,
.set_supp_port = wpa_driver_nl80211_set_supp_port,
.set_country = wpa_driver_nl80211_set_country,
.get_country = wpa_driver_nl80211_get_country,
.set_ap = wpa_driver_nl80211_set_ap,
.set_acl = wpa_driver_nl80211_set_acl,
.if_add = wpa_driver_nl80211_if_add,
.if_remove = driver_nl80211_if_remove,
.send_mlme = driver_nl80211_send_mlme,
.get_hw_feature_data = nl80211_get_hw_feature_data,
.sta_add = wpa_driver_nl80211_sta_add,
.sta_remove = driver_nl80211_sta_remove,
.tx_control_port = nl80211_tx_control_port,
.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
.sta_set_flags = wpa_driver_nl80211_sta_set_flags,
.sta_set_airtime_weight = driver_nl80211_sta_set_airtime_weight,
.hapd_init = i802_init,
.hapd_deinit = i802_deinit,
.set_wds_sta = i802_set_wds_sta,
.get_seqnum = i802_get_seqnum,
.flush = i802_flush,

......//还有很多

};  

 netlink初始化

 

 

   调用netlink_init  进行 netlink初始化  global->netlink = netlink_init(cfg) 

 

 

 

 

 

  1. netlink_init()

  socket()函数参数介绍

  

 

   (1)创建netlink套接字

  协议族为PF_NETLINK

  类型为原始套接字

  协议为:NETLINK_ROUTE ,用户空间的路由守护程序之间的通讯通道,比如BGP,OSPF,RIP以及内核数据转发模块。用户态的路由守护程序通过此类型的协议来更新内核中的路由表。

  (2)bind 将socket与对应的网络地址进行绑定

  local.nl_family = AF_NETLINK;
  local.nl_groups = RTMGRP_LINK;

  Netlink的RTMGRP_LINK多播群组,用户空间程序可以注册netlink的RTMGRP_LINK多播群组,当设备的状态或配置发生变更时,就会用rtmsg_ifinfo把通知信息传送给Link多播群组RTMGRP_LINK。

  (3)eloop_register_read_sock 注册 netlink_receive

  • netlink_receive()这个函数做了什么?
    • 接收来自对方主机传来的数据,在这里,MSG_DONTWAIT为0,也就是参数flags。
    •  

       cb函数的参数是啥呢?

    • cb函数 wpa_driver_nl80211_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, u8 *buf, size_t len)

    • 不知道这里为什么使用send? send是TCP的函数,recvfrom是udp的

       

    •     注册handler处理函数到table表中,type:EVENT_TYPE_READ

  •  

    eloop_sock_table_add_sock函数

   

 

     eloop_sock_queue()函数 ,这里选择梳理epoll事件处理(代码中有epoll和queue两种方式)

    

  2. global->nl 初始化 wpa_driver_nl80211_init_nl_global(global)

    (1)创建回调函数

     

 

     (2)创建netlink套接字,并connect,回调函数是“nl”

    

     (3)genl的概念,向内核查询协议族的标志id

    

    (4)查询内核“nlctrl” family 的id

    对于从user to kernel的通讯,driver必须先向内核注册一个struct genl_family,并且注册一些cmd的处理函数。这些cmd是跟某个family关联起来的。注册family的时候我们可以让内核自动为这个family分配一个ID。每个family都有一个唯一的ID,其中ID号0x10是被内核的nlctrl family所使用。当注册成功以后,如果user program向某个family发送cmd,那么内核就会回调对应cmd的处理函数。对于user program,使用前,除了要创建一个socket并绑定地址以外,还需要先通过family的名字获取family的ID。获取方法,就是向nlctrl这个family查询。详细的方法可以看后面的例子。有了family的ID以后,才能向该family发送cmd。

    nl80211应该就是driver向内核注册的协议族标志。

    

    (5)global->event 创建接收消息的event socket 套接字并connec内核

    

 

    (6)将接收消息的event socket, 并分别加入到组播组scan mlme regulatory vendor 中,这里只列出加入组播scan

    

 

   

      1.nl_get_multicast_id()

      

 

       2. send_and_recv()

       msg发送 

       

 

      回调函数设置

       

 

      阻塞接收消息,接收消息后调用回调函数

        

 

 

    (7)注册handler到eloop表中 ,handler 内容为:res = nl_recvmsgs(handle, cb);

    

总结:

netlink 初始化 就是创建协议族为PF_NETLINK的socket,并将sock及对应的处理函数handle注册到eloop

 

 

  

 

posted @ 2022-04-07 16:48  bug快递员  阅读(704)  评论(0编辑  收藏  举报