开启内核kmemleak 选项后,捕获如下泄漏
xxxxxxxxxx
unreferenced object 0xc5b7c980 (size 64):
comm "softirq", pid 0, jiffies 293676 (age 1512.970s)
hex dump (first 32 bytes):
24 08 24 04 34 04 95 04 a5 01 00 00 00 00 00 00 $.$.4...........
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
backtrace:
[<bf900554>] ieee80211_parse_beacon+0x192c/0x1948 [umac]
[<bf902cfc>] ieee80211_recv_asreq+0x174c/0x2654 [umac]
[<bf8fd014>] ieee80211_recv_mgmt+0x7c0/0x1778 [umac]
[<bf96ad94>] ieee80211_input+0x330/0x17c8 [umac]
[<bfbfdc9c>] ol_ath_mgmt_null_handler+0x194/0x4e4 [qca_ol]
[<bfbfe094>] ol_ath_mgmt_rx_event_handler+0xa8/0x108 [qca_ol]
[<bfc1bcc4>] __wmi_control_rx+0x1b4/0x2f4 [qca_ol]
[<bfbd7c00>] ol_ath_handle_wmi_message+0x10/0x18 [qca_ol]
[<bfc1ab90>] wmi_control_rx+0xb4/0x360 [qca_ol]
[<bfc2ce28>] ieee80211_ioctl_get_htc_stats+0xa8/0xd0 [qca_ol]
[<bfc2d38c>] htc_rx_completion_handler+0x388/0x6f0 [qca_ol]
[<bfc31cfc>] hif_pci_ce_recv_data+0x80/0x228 [qca_ol]
[<bfc2fca8>] ce_per_engine_service+0x2c0/0x59c [qca_ol]
[<bfc34c5c>] ce_tasklet+0x50/0x154 [qca_ol]
[<c0234f38>] tasklet_action+0x8c/0xe8
[<c0234580>] __do_softirq+0x114/0x280
每个泄漏快大小为64 字节。
在ALPHA环境,一天泄漏可达16M。
创建open-ssid 手机关联后,将手机移动到信号覆盖不到的地方,触发AP 的T下线动作。观察 /sys/kernel/debug/kmemleak,发现 parse_beacon 内核泄露。
在关联的station 离开AP的通信范围,被T下线时未释放 ieee80211_node 节点中的 ni_supp_chan_ie 占用的内存(64字节)
在 qca/src/qca-wifi/umac/base/ieee80211_node.c
node_free() 中添加 free的操作
xxxxxxxxxx
diff --git a/qca/src/qca-wifi/umac/base/ieee80211_node.c b/qca/src/qca-wifi/umac/base/ieee80211_node.c
index 414547b..1c1955f 100644
--- a/qca/src/qca-wifi/umac/base/ieee80211_node.c
+++ b/qca/src/qca-wifi/umac/base/ieee80211_node.c
@@ -616,6 +616,11 @@ node_free(struct ieee80211_node *ni)
ni->ni_wps_ie = NULL;
}
+ if (ni->ni_supp_chan_ie != NULL) {
+ OS_FREE(ni->ni_supp_chan_ie);
+ ni->ni_supp_chan_ie = NULL;
+ }
+
xxxxxxxxxx
backtrace:
[<bf984d48>] ieee80211_parse_beacon+0x1938/0x1954 [umac]
[<bf987b18>] ieee80211_recv_asreq+0x1d50/0x38d8 [umac]
[<bf98184c>] ieee80211_recv_mgmt+0xb50/0x1a70 [umac]
[<bf9f38c0>] ieee80211_input+0x358/0x1b1c [umac]
[<bfc99c00>] ol_ath_mgmt_null_handler+0x194/0x4e4 [qca_ol]
[<bfc99ff8>] ol_ath_mgmt_rx_event_handler+0xa8/0x108 [qca_ol]
[<bfcb0a84>] __wmi_control_rx+0x1b4/0x2f4 [qca_ol]
[<bfc73f50>] ol_ath_handle_wmi_message+0x10/0x18 [qca_ol]
[<bfcaf950>] wmi_control_rx+0xb4/0x360 [qca_ol]
[<bfcc1dbc>] ieee80211_ioctl_get_htc_stats+0xa8/0xd0 [qca_ol]
[<bfcc2320>] htc_rx_completion_handler+0x388/0x6f0 [qca_ol]
[<bfcc6c74>] hif_pci_ce_recv_data+0x80/0x228 [qca_ol]
[<bfcc4c2c>] ce_per_engine_service+0x2b0/0x580 [qca_ol]
[<bfcc9a98>] ce_tasklet+0x50/0x154 [qca_ol]
[<c0235288>] tasklet_action+0x8c/0xe8
[<c02348d0>] __do_softirq+0x114/0x280
xxxxxxxxxx
(gdb) disassemble ieee80211_parse_beacon
Dump of assembler code for function ieee80211_parse_beacon:
0x00050410 <+0>: lock dec %edi
0x00050410 + 0x1938 = 0x51D48
l *0x51D48
(gdb) l *0x51D48
0x51d48 is in ieee80211_saveie (/home/rel/tmp/ac-271/build_dir/target-arm_cortex-a7_uClibc-1.0.14_eabi/linux-ipq806x/qca-wifi-g901a9ee-dirty-ap271-profile/qca-wifi-g901a9ee-dirty/os/linux/../../umac/mlme/ieee80211_mgmt_ap.c:42).
37 if (*iep == NULL || (*iep)[1] != ie[1]) {
38 if (*iep != NULL)
39 OS_FREE(*iep);
40 *iep = OS_MALLOC(osdev,ielen,0);
41 }
42 if (*iep != NULL)
43 OS_MEMCPY(*iep, ie, ielen);
44 }
45
46 int ieee80211_ht_nss_mcs_valid(struct ieee80211_node *ni, u_int8_t *hcap)
(gdb)
(gdb) l *0x54AB4
0x54ab4 is in ieee80211_recv_asreq (/home/rel/tmp/ac-271/build_dir/target-arm_cortex-a7_uClibc-1.0.14_eabi/linux-ipq806x/qca-wifi-g901a9ee-dirty-ap271-profile/qca-wifi-g901a9ee-dirty/os/linux/../../umac/mlme/ieee80211_mgmt_ap.c:1374).
1369 #endif
1370
1371 ieee80211node_clear_supp_chan_info(ni);
1372 if (supp_chan != NULL) {
1373 ieee80211_saveie(ic->ic_osdev,&ni->ni_supp_chan_ie, supp_chan);
1374 ieee80211_process_supp_chan_ie(ni, supp_chan);
1375 }else if (ni->ni_supp_chan_ie != NULL) {
1376 OS_FREE(ni->ni_supp_chan_ie);
1377 ni->ni_supp_chan_ie = NULL;
1378 }
(gdb)
xxxxxxxxxx
diff --git a/qca/src/qca-wifi/umac/mlme/ieee80211_mgmt_ap.c b/qca/src/qca-wifi/umac/mlme/ieee80211_mgmt_ap.c
index 7253ec7..0aa092d 100644
--- a/qca/src/qca-wifi/umac/mlme/ieee80211_mgmt_ap.c
+++ b/qca/src/qca-wifi/umac/mlme/ieee80211_mgmt_ap.c
@@ -38,6 +38,7 @@ ieee80211_saveie(osdev_t osdev, u_int8_t **iep, const u_int8_t *ie)
if (*iep != NULL)
OS_FREE(*iep);
*iep = OS_MALLOC(osdev,ielen,0);
+ qdf_print("%s - iep: %p, ielen: %d\n", __func__, *iep, ielen);
}
编译固件 并 复现,确认泄漏信息地址与打印是否一致
xxxxxxxxxx
unreferenced object 0xce1f7840 (size 64):
comm "softirq", pid 0, jiffies 99346 (age 2710.400s)
hex dump (first 32 bytes):
24 0a 24 04 34 04 64 0c 95 04 a5 01 00 00 00 00 $.$.4.d.........
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
backtrace:
[<bf984d58>] ieee80211_parse_beacon+0x1948/0x1974 [umac]
[<bf987ad0>] ieee80211_recv_asreq+0x1cec/0x3874 [umac]
[<bf98184c>] ieee80211_recv_mgmt+0xb50/0x1a70 [umac]
[<bf9f3878>] ieee80211_input+0x358/0x1b1c [umac]
[<bfc99c00>] ol_ath_mgmt_null_handler+0x194/0x4e4 [qca_ol]
[<bfc99ff8>] ol_ath_mgmt_rx_event_handler+0xa8/0x108 [qca_ol]
[<bfcb0a84>] __wmi_control_rx+0x1b4/0x2f4 [qca_ol]
[<bfc73f50>] ol_ath_handle_wmi_message+0x10/0x18 [qca_ol]
[<bfcaf950>] wmi_control_rx+0xb4/0x360 [qca_ol]
[<bfcc1dbc>] ieee80211_ioctl_get_htc_stats+0xa8/0xd0 [qca_ol]
[<bfcc2320>] htc_rx_completion_handler+0x388/0x6f0 [qca_ol]
[<bfcc6c74>] hif_pci_ce_recv_data+0x80/0x228 [qca_ol]
[<bfcc4c2c>] ce_per_engine_service+0x2b0/0x580 [qca_ol]
[<bfcc9a98>] ce_tasklet+0x50/0x154 [qca_ol]
[<c0235288>] tasklet_action+0x8c/0xe8
[<c02348d0>] __do_softirq+0x114/0x280
root@AP-39:A0:/tmp# dmesg | grep saveie
[ 542.262020] ieee80211_saveie - iep: c5dafdc0
[ 542.265466] ieee80211_saveie - iep: c5dafb40
[ 709.881135] ieee80211_saveie - iep: ce313480
[ 709.892452] ieee80211_saveie - iep: ce313fc0
[ 1252.512099] ieee80211_saveie - iep: ce1f7ec0
[ 1252.512488] ieee80211_saveie - iep: ce1f71c0
[ 1293.470921] ieee80211_saveie - iep: ce1f7540
[ 1293.471019] ieee80211_saveie - iep: ce1f7840
再次添加调试,确认是 station 的ni ie泄漏
xxxxxxxxxx
root@AP-39:A0:~# dmesg | grep ni_macadd
[ 696.199532] ieee80211_recv_asreq - ni->ni_macaddr = f8:87:f1:62:f8:70
[ 925.949159] ieee80211_recv_asreq - ni->ni_macaddr = cc:08:8d:4b:7d:a7
root@AP-39:A0:~# dmesg | grep iep
[ 696.199453] ieee80211_saveie - iep: c5ec7f00
[ 696.199587] ieee80211_saveie - iep: c5ec7cc0
[ 925.949022] ieee80211_saveie - iep: c8e4dc40
[ 925.949235] ieee80211_saveie - iep: c8e4d940
unreferenced object 0xc8e4d940 (size 64):
comm "softirq", pid 0, jiffies 62594 (age 45492.570s)
hex dump (first 32 bytes):
24 08 24 04 34 04 95 04 a5 01 00 00 00 00 00 00 $.$.4...........
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
backtrace:
[<bf984d58>] ieee80211_parse_beacon+0x1948/0x1974 [umac]
[<bf98953c>] ieee80211_recv_asreq+0x3758/0x38f4 [umac]
[<bf98184c>] ieee80211_recv_mgmt+0xb50/0x1a70 [umac]
[<bf9f38f8>] ieee80211_input+0x358/0x1b1c [umac]
[<bfc99c00>] ol_ath_mgmt_null_handler+0x194/0x4e4 [qca_ol]
[<bfc99ff8>] ol_ath_mgmt_rx_event_handler+0xa8/0x108 [qca_ol]
[<bfcb0a84>] __wmi_control_rx+0x1b4/0x2f4 [qca_ol]
[<bfc73f50>] ol_ath_handle_wmi_message+0x10/0x18 [qca_ol]
[<bfcaf950>] wmi_control_rx+0xb4/0x360 [qca_ol]
[<bfcc1dbc>] ieee80211_ioctl_get_htc_stats+0xa8/0xd0 [qca_ol]
[<bfcc2320>] htc_rx_completion_handler+0x388/0x6f0 [qca_ol]
[<bfcc6c74>] hif_pci_ce_recv_data+0x80/0x228 [qca_ol]
[<bfcc4c2c>] ce_per_engine_service+0x2b0/0x580 [qca_ol]
[<bfcc9a98>] ce_tasklet+0x50/0x154 [qca_ol]
[<c0235288>] tasklet_action+0x8c/0xe8
[<c02348d0>] __do_softirq+0x114/0x280
确认泄漏点后,开始分析相关代码
看到有 ni_supp_chan_ie 的free 相关代码
xxxxxxxxxx
ieee80211node_clear_supp_chan_info(ni);
if (supp_chan != NULL) {
qdf_print("%s - ni->ni_macaddr = %s\n", __func__, ether_sprintf(ni->ni_macaddr));
ieee80211_saveie(ic->ic_osdev,&ni->ni_supp_chan_ie, supp_chan);
ieee80211_process_supp_chan_ie(ni, supp_chan);
}else if (ni->ni_supp_chan_ie != NULL) {
OS_FREE(ni->ni_supp_chan_ie);
ni->ni_supp_chan_ie = NULL;
}
那一定是存在 未释放的地方。
查看 SDK11 的引用,发现 当前AC 的代码中在 base/ieee80211_node.c 无 ni_supp_chan_ie 的释放。
xxxxxxxxxx
qcom@galactica:~/2019-spf-11-0/r11.0_00001.4/qca-networking-2019-spf-11-0_qca_oem.git/qsdk_64/qca/src/qca-wifi/umac$ ag "ni->ni_supp_chan_ie"
base/ieee80211_node.c
504: if (ni->ni_supp_chan_ie != NULL) {
505: OS_FREE(ni->ni_supp_chan_ie);
506: ni->ni_supp_chan_ie = NULL;
mlme/ieee80211_mgmt_ap.c
1759: ieee80211_saveie(ic->ic_osdev, &ni->ni_supp_chan_ie, supp_chan);
1761: } else if (ni->ni_supp_chan_ie != NULL) {
1762: OS_FREE(ni->ni_supp_chan_ie);
1763: ni->ni_supp_chan_ie = NULL;
3225: ieee80211_saveie(ic->ic_osdev, &ni->ni_supp_chan_ie, supp_chan);
3227: } else if (ni->ni_supp_chan_ie != NULL) {
3228: OS_FREE(ni->ni_supp_chan_ie);
3229: ni->ni_supp_chan_ie = NULL;
在 AC 仓库中 qca/src/qca-wifi/umac/base/ieee80211_node.c
node_free() 中添加 free的操作
xxxxxxxxxx
diff --git a/qca/src/qca-wifi/umac/base/ieee80211_node.c b/qca/src/qca-wifi/umac/base/ieee80211_node.c
index 414547b..1c1955f 100644
--- a/qca/src/qca-wifi/umac/base/ieee80211_node.c
+++ b/qca/src/qca-wifi/umac/base/ieee80211_node.c
@@ -616,6 +616,11 @@ node_free(struct ieee80211_node *ni)
ni->ni_wps_ie = NULL;
}
+ if (ni->ni_supp_chan_ie != NULL) {
+ OS_FREE(ni->ni_supp_chan_ie);
+ ni->ni_supp_chan_ie = NULL;
+ }
+
验证结果
编译复现,8小时未复现。