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()
(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