iw添加wlan0导致crash问题分析

news/2024/11/21 18:51:36/

比如通过日下命令,创建一个wlan0接口

iw phy phy0 interface add wlan0 type managed

会产生如下panic内容

<1> [54245.466372] Unable to handle kernel NULL pointer dereference at virtual address 00000010
<1> [54245.474729] pgd = c1794000
<1> [54245.477443] [00000010] *pgd=01090831, *pte=00000000, *ppte=00000000
<0> [54245.483879] Internal error: Oops: 17 [#1] PREEMPT THUMB2
<4> [54245.638361] CPU: 0 PID: 21542 Comm: iw Not tainted 3.10.33 #2
<4> [54245.644095] task: c1348000 ti: c13e2000 task.ti: c13e2000
<4> [54245.649524] PC is at nl80211_send_iface+0xc/0x160
<4> [54245.654221] LR is at nl80211_new_interface+0x1cf/0x224
<4> [54245.659345] pc : [<c02956ec>]    lr : [<c029a56f>]    psr: 40000033
sp : c13e3c40  ip : 0000005d  fp : 00000000
<4> [54245.670813] r10: 00000014  r9 : c13e3ca0  r8 : c0923100
<4> [54245.676028] r7 : 00000002  r6 : c17b8000  r5 : 00000000  r4 : c0923100
<4> [54245.682555] r3 : 00000000  r2 : 673be4b6  r1 : 00005426  r0 : c0923100
<4> [54245.689082] Flags: nZcv  IRQs on  FIQs on  Mode SVC_32  ISA Thumb  Segment user
<4> [54245.696372] Control: 50c53c7d  Table: 01794059  DAC: 00000015

nl80211_send_iface的wdev这个参数为空指针 ;看看nl80211_new_interface调用nl80211_send_iface之前,是怎么给wdev赋值的,如下述代码是从rdev_add_virtual_intf获取wdev这个wireless_dev结构体;也就是要找到这个函数为什么返回空指针

static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
{struct cfg80211_registered_device *rdev = info->user_ptr[0];struct vif_params params;struct wireless_dev *wdev;struct sk_buff *msg;int err;enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;/* to avoid failing a new interface creation due to pending removal */cfg80211_destroy_ifaces(rdev);memset(&params, 0, sizeof(params));if (!info->attrs[NL80211_ATTR_IFNAME])return -EINVAL;if (info->attrs[NL80211_ATTR_IFTYPE]) {type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);if (type > NL80211_IFTYPE_MAX)return -EINVAL;}if (!rdev->ops->add_virtual_intf ||!(rdev->wiphy.interface_modes & (1 << type)))return -EOPNOTSUPP;if ((type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN ||rdev->wiphy.features & NL80211_FEATURE_MAC_ON_CREATE) &&info->attrs[NL80211_ATTR_MAC]) {nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC],ETH_ALEN);if (!is_valid_ether_addr(params.macaddr))return -EADDRNOTAVAIL;}if (info->attrs[NL80211_ATTR_4ADDR]) {params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);if (err)return err;}err = nl80211_parse_mon_options(rdev, type, info, &params);if (err < 0)return err;msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);if (!msg)return -ENOMEM;wdev = rdev_add_virtual_intf(rdev,nla_data(info->attrs[NL80211_ATTR_IFNAME]),NET_NAME_USER, type, &params);if (WARN_ON(!wdev)) {nlmsg_free(msg);return -EPROTO;} else if (IS_ERR(wdev)) {nlmsg_free(msg);return PTR_ERR(wdev);}if (info->attrs[NL80211_ATTR_SOCKET_OWNER])wdev->owner_nlportid = info->snd_portid;switch (type) {case NL80211_IFTYPE_MESH_POINT:if (!info->attrs[NL80211_ATTR_MESH_ID])break;wdev_lock(wdev);BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=IEEE80211_MAX_MESH_ID_LEN);wdev->mesh_id_up_len =nla_len(info->attrs[NL80211_ATTR_MESH_ID]);memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),wdev->mesh_id_up_len);wdev_unlock(wdev);break;case NL80211_IFTYPE_NAN:case NL80211_IFTYPE_P2P_DEVICE:/** P2P Device and NAN do not have a netdev, so don't go* through the netdev notifier and must be added here*/mutex_init(&wdev->mtx);INIT_LIST_HEAD(&wdev->event_list);spin_lock_init(&wdev->event_lock);INIT_LIST_HEAD(&wdev->mgmt_registrations);spin_lock_init(&wdev->mgmt_registrations_lock);wdev->identifier = ++rdev->wdev_id;list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list);rdev->devlist_generation++;break;default:break;}if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,rdev, wdev, false) < 0) {nlmsg_free(msg);return -ENOBUFS;}/** For wdevs which have no associated netdev object (e.g. of type* NL80211_IFTYPE_P2P_DEVICE), emit the NEW_INTERFACE event here.* For all other types, the event will be generated from the* netdev notifier*/if (!wdev->netdev)nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);return genlmsg_reply(msg, info);
}

rdev_add_virtual_intf调用的是cfg80211_registered_device的ops成员的add_virtual_intf函数指针

static inline struct wireless_dev
*rdev_add_virtual_intf(struct cfg80211_registered_device *rdev, char *name,unsigned char name_assign_type,enum nl80211_iftype type,struct vif_params *params)
{struct wireless_dev *ret;trace_rdev_add_virtual_intf(&rdev->wiphy, name, type);ret = rdev->ops->add_virtual_intf(&rdev->wiphy, name, name_assign_type,type, params);trace_rdev_return_wdev(&rdev->wiphy, ret);return ret;
}

wifi驱动会调用wiphy_new来分配一个cfg80211_registered_device,并且将cfg80211_ops赋值给这个cfg80211_registered_device的ops成员

struct cfg80211_ops wifi_cfg80211_ops = {.add_virtual_intf = wifi_interface_add,.del_virtual_intf = wifi_interface_del.....
}
wiphy_new(&ssv_cfg80211_ops, sizeof(struct ssv_softc));

wiphy_new的实现如下:主要是申请一块cfg80211_registered_device的内存,并将第一个ops参数赋值给ops成员

struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,const char *requested_name)
{....struct cfg80211_registered_device *rdev;rdev = kzalloc(alloc_size, GFP_KERNEL);rdev->ops = ops;wiphy_net_set(&rdev->wiphy, &init_net);....
}

解决办法如下:通过__dev_get_by_name从网络命令空间init_net查找wlan0这个net_device是否已经被注册到系统,检测到直接返回wireless_dev;不然直接再通过register_netdevice注册一个wlan0,就返回NULL了

--- a/package/kernel/wifi/src/fmac/netdev_ops.c
+++ b/package/kernel/wifi/src/fmac/netdev_ops.c
@@ -498,6 +498,10 @@ struct wireless_dev *wifi_interface_add(struct ssv_softc *sc,struct net_device *ndev;int min_idx, max_idx;int vif_idx = -1;int i;
+
+       ndev = __dev_get_by_name(&init_net, "wlan0");
+       if (ndev)
+               return ndev->ieee80211_ptr;ndev = alloc_netdev(sizeof(*vif), name, ssv_netdev_setup);if (!ndev)return NULL;....if (register_netdevice(ndev))return NULL;


http://www.ppmy.cn/news/1548827.html

相关文章

【传知代码】VRT_ 关于视频修复的模型

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀ VRT_ 关于视频修复的模型 背景介绍&#xff1a;重要性&#xff1a; VRT的重要性和研究背景VRT的背景&#xff1a;VRT的重要性&#xff1a; 视…

LabVIEW中的UDP与TCP比较

在LabVIEW中&#xff0c;UDP和TCP可以用于不同的网络通信场景&#xff0c;开发者可以根据需求选择合适的协议。以下是结合LabVIEW开发时的一些比较和应用场景&#xff1a; 1.TCP在LabVIEW中的应用&#xff1a; 可靠性高的场景&#xff1a;当开发一个对数据传输的准确性和完整…

用Python“拍立淘”:在1688的海洋里寻找宝藏

想象一下&#xff0c;你是一名勇敢的探险家&#xff0c;手持一张神秘的藏宝图&#xff0c;准备在阿里巴巴的1688海洋中寻找那些隐藏的宝贝。但这次&#xff0c;你的武器不是传统的铲子和罗盘&#xff0c;而是Python爬虫。我们将一起编写一段代码&#xff0c;让它成为我们的“拍…

【AI系统】核心计算之矩阵乘

核心计算之矩阵乘 AI 模型中往往包含大量的矩阵乘运算&#xff0c;该算子的计算过程表现为较高的内存搬移和计算密度需求&#xff0c;所以矩阵乘的效率是 AI 芯片设计时性能评估的主要参考依据。本文我们一起来看一下矩阵乘运算在 AI 芯片的具体过程&#xff0c;了解它的执行性…

java基础概念31:常见API-Runtime

一、Runtime类常用方法 Runtime&#xff1a;表示当前虚拟机JVM的运行环境&#xff0c;只能有一个。 【注意】&#xff1a; 获取Runtime对象&#xff0c;只能通过getRuntime静态方法。 好处&#xff1a;不管在哪个类中调用Runtime方法&#xff0c;获取的都是同一个对象。即&…

Node.js windows版本 下载和安装(详细步骤)

Node.js发布于2009年5月&#xff0c;由Ryan Dahl开发&#xff0c;是一个基于Chrome V8引擎的JavaScript运行环境&#xff0c;使用了一个事件驱动、非阻塞式I/O模型&#xff0c;让JavaScript 运行在服务端的开发平台&#xff0c;它让JavaScript成为与PHP、Python、Perl、Ruby等服…

MySQL扩展varchar字段长度能否Online DDL

目录 问题场景 Online DDL 简介 场景复现 DBdoctor快速识别 Online DDL 总结 问题场景 在MySQL数据库中&#xff0c;DDL变更可以通过两种算法实现&#xff1a;Copy算法和In-Place算法。Copy算法会复制整个表&#xff0c;这可能导致长时间的写入阻塞&#xff0c;从而严重影…

WPF下 DataGrid加入序号列

先上代码&#xff1a; <DataGrid Name"DGV" AutoGenerateColumns"False" Grid.Row"0" Grid.Column"0" HorizontalGridLinesBrush"RoyalBlue" VerticalGridLinesBrush"Tomato" CanUserAddRows"False&qu…