kernel driver NUD(network unreachable detection) 设计

NUD 网络地址不可达是kernel检测网络状态的一种机制,通过发送特定个数的ARP REQ 给网络,如果网络不回复APR RSP,触发断开连接或者触发roaming.

在android phone上有2种实现方式,一种是在WIFI 驱动中实现,一种是在framework中实现。

 

Kernel 设计

/net/core/neighbour.c 中,

在neightbl_fill_parms中提供nl80211接口供上层配置ARP UCAST和MCAST的个数,

static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
{

			NEIGH_VAR(parms, UCAST_PROBES)) ||
	    nla_put_u32(skb, NDTPA_MCAST_PROBES,
			NEIGH_VAR(parms, MCAST_PROBES)) ||
	    nla_put_u32(skb, NDTPA_MCAST_REPROBES,
			NEIGH_VAR(parms, MCAST_REPROBES)) ||
	

在如下

neigh_alloc时,注册了一个timer,在neigh_timer_handler中
timer_setup(&n->timer, neigh_timer_handler, 0);
如果probe的次数大于预定的ARP 个数,网络还不回复,
if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
	    atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
		WRITE_ONCE(neigh->nud_state, NUD_FAILED);
		notify = 1;
		neigh_invalidate(neigh);
		goto out;
	}

触发neigh_update_notify,

out:
		write_unlock(&neigh->lock);
	}

	if (notify)
		neigh_update_notify(neigh, 0);

发送NETEVENT_NEIGH_UPDATE给驱动,同时发送NL消息RTM_NEWNEIGH 给上层。

 

static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid)
{
	call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
	__neigh_notify(neigh, RTM_NEWNEIGH, 0, nlmsg_pid);
}

 

驱动实现

注册notifier_call的回调函数,当notifier_call收到NETEVENT_NEIGH_UPDATE时,发送消息 nud_state_osif_to_dp给data path模块,

os_if/dp/src/os_if_dp.c · LA.VENDOR.13.2.2.r1-02100-QCS8250.0 · CodeLinaro / la / platform / vendor / qcom-opensource / wlan / qcacld-3.0 · GitLab

static struct notifier_block wlan_netevent_nb = {
	.notifier_call = os_if_dp_nud_netevent_cb
};

static int os_if_dp_nud_netevent_cb(struct notifier_block *nb,
				    unsigned long event,
				    void *data)
{

	switch (event) {
	case NETEVENT_NEIGH_UPDATE:
		ucfg_dp_nud_event((struct qdf_mac_addr *)netdev->dev_addr,
				  (struct qdf_mac_addr *)&neighbor->ha[0],
				  nud_state_osif_to_dp(neighbor->nud_state));
		break;

WLAN HDD main 中,调用hdd_register_notifiers注册的回调,

static int hdd_register_notifiers(struct hdd_context *hdd_ctx)
{

	ret = osif_dp_nud_register_netevent_notifier(hdd_ctx->psoc);

hdd_wlan_start_modules时,初始化hdd_register_notifiers

回到ucfg_dp_nud_event,它也是一个cb,接收本地地址,网关地址,和nud_state,

static void dp_nud_filter_netevent(struct qdf_mac_addr *netdev_addr,
				   struct qdf_mac_addr *gw_mac_addr,
				   uint8_t nud_state)
case DP_NUD_FAILED:
		dp_info("DP_NUD_FAILED [0x%x]", nud_state);
		/*
		 * This condition is to handle the scenario where NUD_FAILED
		 * events are received without any NUD_PROBE/INCOMPLETE event
		 * post roaming. Nud state is set to NONE as part of roaming.
		 * NUD_FAILED is not honored when the curr state is any state
		 * other than NUD_PROBE/INCOMPLETE so post roaming, nud state
		 * is moved to DP_NUD_PROBE to honor future NUD_FAILED events.
		 */

		if (dp_intf->nud_tracking.curr_state == DP_NUD_NONE) {
			dp_nud_capture_stats(dp_intf, DP_NUD_PROBE);
			dp_nud_set_tracking(dp_intf, DP_NUD_PROBE, true);
		} else {
			dp_nud_process_failure_event(dp_intf);
		}
		break;

发送一个dp_nud_process_failure_event,更新最新的tx_transmitted,acked,gw_rx_pkt,rx_received状态,gateway.

触发nud_event_work
 */
static void dp_nud_process_failure_event(struct wlan_dp_intf *dp_intf)
{
	uint8_t curr_state;

	curr_state = dp_intf->nud_tracking.curr_state;
	if (curr_state == DP_NUD_PROBE || curr_state == DP_NUD_INCOMPLETE) {
		dp_nud_capture_stats(dp_intf, DP_NUD_FAILED);
		if (dp_nud_honour_failure(dp_intf)) {
			dp_intf->nud_tracking.curr_state = DP_NUD_FAILED;
			qdf_sched_work(0, &dp_intf
					->nud_tracking.nud_event_work);

处理dp_nud_failure_work,

dp_ctx->dp_ops.dp_nud_failure_work(dp_ctx->dp_ops.callback_ctx,
					   dp_intf->intf_id);

dp_nud_failure_work=hdd_nud_failure_work

如果注册了data stall event,发送DATA_STALL_LOG_NUD_FAILURE,

如果是roaming offload 功能使能,sta mode,尝试roaming到新的AP

static void __hdd_nud_failure_work(struct hdd_adapter *adapter)
{


	if (soc && ucfg_dp_nud_fail_data_stall_evt_enabled()) {
		hdd_dp_err("Data stall due to NUD failure");
		cdp_post_data_stall_event
			(soc,
			 DATA_STALL_LOG_INDICATOR_HOST_DRIVER,
			 DATA_STALL_LOG_NUD_FAILURE,
			 OL_TXRX_PDEV_ID, 0XFF,
			 DATA_STALL_LOG_RECOVERY_TRIGGER_PDR);
	}

	if (adapter->device_mode == QDF_STA_MODE &&
	    ucfg_dp_is_roam_after_nud_enabled(hdd_ctx->psoc)) {
		hdd_handle_nud_fail_sta(hdd_ctx, adapter);
		return;
	}
	hdd_handle_nud_fail_non_sta(adapter);

同时把目前AP 加入到black list.

 

android 实现

定义参数

config_nud_steadystate_solicit_num 10

config_nud_steadystate_solicit_interval 750

受到RTM_NEWNEIGH 消息,解析消息内容

 case:NetlinkConstants:RTM_NEWNEIGH:

        RtNetlinkNeighborMessage.parse(nlmsghdr,bytebuffer)l

handleNeighborLost(event)

调用callback

onReachabilityLost

发送CMD_IP_REACHABILITY_LOST消息,handle handIpReachabilityLost,

调用disconnect

mWifiNative.disconnect(mInterfaceName)

可以看出,driver部分的NUD feature 多了一次roaming,android 部分是直接断开连接。

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值