IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 螃蟹wifi驱动在AP模式下存在挂死系统的问题 -> 正文阅读

[移动开发]螃蟹wifi驱动在AP模式下存在挂死系统的问题

欢迎大家测试并反馈结果

/*
Realtek Wifi module AP 功能压力测试工具
mengxp work & test 2022/01

Bug 描述
当满足如下 3 个条件时,若有大流量从 AP 发往 iPhone
有概率导致内核线程 ksoftirqd & RTWHALXT 占满 CPU,并有可能导致系统停止响应
1.realtek wifi 工作在 AP 模式
2.iPhone 作为 STA 接入
3.iPhone wifi 进入 SLEEP 状态(POWERSAVE)

Buf 复现步骤
1.realtek 板端建立 wifi AP,并建立 DHCP 服务器(可选,可使用静态IP)
2.iphone 连接该 AP(如果没有 DHCP 需要手动配置 IP)
3.iphone 进入到 设置-蓝牙 界面 (由于 2.4G 天线复用冲突,蓝牙 scan 会导致 Wifi 频繁进入 SLEEP)
4.realtek 板端运行该工具持续向 iPhone 发送 UDP 报文,间隔可修改
  例: udpflood 192.168.20.100 1234 5
  其中 192.168.20.100 是 iphone 的 IP,1234是端口号,可任意输入,5 是间隔 5 毫秒发一次报文
5.观察板端是否有卡住的情况。
  或可将 udpflood 置于后台运行,然后使用命令 top 观察 CPU 占用率

Bug 分析
当 STA 进入 SLEEP 模式时,realtek 不能正确处理发包队列,导致发包线程占满 CPU

目前我在 rtl8723ds 上测试,bug 复现率 100%,我使用的 wifi 驱动版本有
1.R328 SDK中的 v5.6.5_31752.20181221_COEX20181130-2e2e
2.R329 SDK中的 v5.10.1-26-ga10bc0b8b.20200617_COEX20200103-3535
3.rtl8723DS_WiFi_linux_v5.13.5-29-g0dbf6713f.20210604_COEX20210106-3b3b.tar.gz
上述3个版本全部存在该问题。

bug 日志摘抄
sending 1440 bytes every 5 ms via 2 threads
thread bind to cpu 0
thread bind to cpu 1
send iter 100
send iter 200
send iter 300
[  314.114167] INFO: rcu_preempt self-detected stall on CPU
[  314.120151]  1-...: (3000 ticks this GP) idle=551/140000000000001/0 softirq=1858/1858 fqs=0
[  314.129626]   (t=60000 jiffies g=280 c=279 q=1)
[  314.134720] rcu_preempt kthread starved for 60000 jiffies! g280 c279 f0x0 RCU_GP_WAIT_FQS(3) ->state=0x1
[  397.830251] INFO: rcu_preempt detected stalls on CPUs/tasks:
[  397.838564]  0-...: (1 GPs behind) idle=7db/140000000000000/0 softirq=1396/1397 fqs=23
[  397.838577]  (detected by 1, t=60002 jiffies, g=281, c=280, q=3)
[  397.838623] rcu_preempt kthread starved for 2006 jiffies! g281 c280 f0x0 RCU_GP_WAIT_FQS(3) ->state=0x1

Mem: 22104K used, 97400K free, 16K shrd, 3668K buff, 6316K cached
CPU:  0.0% usr 95.2% sys  0.0% nic  0.0% idle  0.0% io  0.0% irq  4.7% sirq
Load average: 8.85 6.44 2.98 5/63 899
  PID  PPID USER     STAT   VSZ %VSZ CPU %CPU COMMAND
   15     2 root     RW       0  0.0   1 50.0 [ksoftirqd/1]
  861     2 root     RW       0  0.0   0 49.9 [RTWHALXT]

*/

#define _GNU_SOURCE     //for pthread CPU_ZERO
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <poll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <sched.h>

typedef int32_t atomic32_t;
static __inline atomic32_t atomic32_init(int v) { return v; }
static __inline int atomic32_add(atomic32_t *p, int v) { return __sync_add_and_fetch(p, v); }
static __inline int atomic32_sub(atomic32_t *p, int v) { return __sync_sub_and_fetch(p, v); }
static __inline int atomic32_get(atomic32_t *p) { return *p; }

int sock, interval;
struct sockaddr_in sin;
atomic32_t iter, cpuid;
char buf[1440];

static int ThreadSetPriority(int priority)
{
    int ret, policy;
    struct sched_param param;

    ret = pthread_getschedparam(pthread_self(), &policy, &param);
    if (ret)
        return ret;

    param.sched_priority = priority;
    return pthread_setschedparam(pthread_self(), SCHED_RR, &param);
}

static int ThreadSetCpuAffinity(int cpuId)
{
    cpu_set_t mask;

    CPU_ZERO(&mask);
    CPU_SET(cpuId, &mask);
    return pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask);
}

static void *SendThread(void *ctx)
{
    int cpu_num = atomic32_add(&cpuid, 1) - 1;

    printf("thread bind to cpu %d\n", cpu_num);
    ThreadSetPriority(62);
    ThreadSetCpuAffinity(cpu_num);

    while (1)
    {
        int n = atomic32_add(&iter, 1);

        if (!(n % 100))
        {
            printf("send iter %d\n", iter);
        }

        sendto(sock, buf, sizeof(buf), 0, (struct sockaddr *)&sin, sizeof(sin));
        poll(NULL, 0, interval);
    }
}

static void UdpFloodTest(char *ipStr, char *portStr, char *intervalStr)
{
    int i, threads = 2;
    pthread_t tid;
    void *tr;

    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = inet_addr(ipStr);
    sin.sin_port = htons(strtol(portStr, NULL, 10));

    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        printf("socket failed with %d\n", errno);
        return;
    }

    interval = strtoul(intervalStr, NULL, 10);
    printf("sending %d bytes every %d ms, %d threads\n", sizeof(buf), interval, threads);

    for (i = 0; i < threads; i++)
    {
        pthread_create(&tid, NULL, SendThread, NULL);
    }
    pthread_join(tid, &tr);
}

static void Usage(int argc, char *argv[])
{
    if (argc == 4)
        return;

    printf("Usage: %s [ip] [port] [interval]\n", argv[0]);
    printf("Exam:  %s 192.168.20.100 1234 5\n", argv[0]);
    printf("\n");
    exit(0);
}

int main(int argc, char *argv[])
{
    char *dstIp = argv[1];
    char *dstPort = argv[2];
    char *interval = argv[3];

    Usage(argc, argv);
    UdpFloodTest(dstIp, dstPort, interval);

    return 0;
}

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-01-29 23:11:58  更:2022-01-29 23:12:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 12:54:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码