Android连载46-wpa_supplicant中的P2P(1)

一、Wpa_supplicant中的P2P

1.基本概论

  • 由WifiStateMachine启动,wifi有两个服务WifiService和WifiP2pService,他们都和wpa_supplicant进行交互
  • 启动点:在init配置文件中
service p2p supplicant /system/bin/p2p_supplicant

2.运行时的形态

  • 其实就是wpa_supplicant,只不过是打开了P2P的功能

3.P2P 模块初始化代码分析

int wpas_p2p_init(struct wpa_global* global, struct wpa_supplicant *wpa_s)
{
    struct p2p_config p2p; // P2p变量只想了一个p2p_config对象,代表P2p模块的配置信息
    unsigned int r;
    int i;
    // (1)WPA_DRIVER_FLAGS_P2P_CAPABLE代表WIFI驱动对P2P支持的能力
    if (global -> p2p) return 0;
    // 如果wifi驱动能够完成P2p功能,就不用老家WPAS了
    if (wpa_s -> drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {...}
    // (2) 初始化并设置P2p_config对象
    os_memset(&p2p, 0, sizeof(p2p));
    p2p.msg_ctx = wpa_s;
    p2p.cb_ctx = wpa_s;
    p2p.p2p_scan = wpas_p2p_scan; // p2p对应的扫描函数

    .... // 设置一些回调函数
    os_memcpy(wpa_s -> global -> p2p_dev_addr, wpa_s -> own_addr, ETH_ALEN);
    os_memcpy(p2p.dev_addr, wpa_s-> global -> p2p_dev_addr, ETH_ALEN);

    // 设置P2p模块配置信息,包括device name、 model name 、 uuid等
    p2p.dev_name = wpa_s -> conf -> device_name;
    p2p.manufacturer = wpa_s -> conf -> manufacturer;
    p2p.model_name = wpa_s -> conf -> model_name;
    p2p.model_number = wap_s -> conf -> serial_number;
    if (wpa_s -> wps) {
        os_memecp(p2p.uuid, wpa_s -> wps -> uudi, 16);
        p2p.config_methods = wpa_s -> wps -> config_methods;
    }

    // 设置Operation chanel信息和listen channel信息
    if(wpa_s -> conf -> p2p_listen_reg_class &&
        wpa_s -> conf -> p2p_listen_channel) {
        p2p.reg_class = wpa_s -> confg -> p2p_listen_reg_class;
        p2p.channel = wpa_s -> config -> P2p_listen_channel;
    } else {
        // 设置默认值
    }
    // 设置国家码
    if (wpa_s -> conf -> country[0] && wpa_s -> conf -> country[1]) {
        os_memcpy(p2p.country, wpa_s -> conf -> country, 2);
        p2p.country[2] = 0x04;
    } else {
        // 配置文件中没有设置国家,所以取值为"XX\x04"
        os_memcpy(p2p.country, "XX\x04", 3);
    }
    // 判断wifi驱动是否支持配置文件中设置的operation channel 和 listent channel
    if (wpas_p2p_setup_channels(wpa_s, &p2p.channels)){ .... }
    os_memcpy(p2p.pri_dev_type, wpa_s -> conf -> device_type, WPS_DEV_TYPE_LEN);
    p2p.num_sec_dev_typs = wpa_s -> conf -> device_type;
    os_memcpy(p2p.sec_dev_types * WPA_DEV_TYPE_LEN);
    // 是否支持concurrent operation
    p2p.concurrent_operations = !!(wpa_s -> drv_flags & WPA_DRIVER_FLAGS_P2P_CONCURRENT);
    
    p2p.max_peers = 100; // 最多能报错100个对端p2p device信息
    /*
    配置文件中么有设置p2p_ssid_postfix, 但是p2pStateMachine在initializeP2pSettings函数中将设置p2p ssid后缀,
    */
    if (wpa_s -> conf -> p2p_ssid_postfix) {......}
    
    p2p.p2p_intra_bss = wpa_s -> conf -> 2p_intra_bss;
    // (3) global -P2p指向一个p2p_data结构体,它是WPAS中p2p模块的代表
    global -> p2p = p2p_init(&p2p);
    .....
    for(int i = 0; i < MAX_WPS_VENDOR_EXT; i++) {
        // 复制vendor厂商特定的WSC属性信息
        p2p_add_wps_vendor_extension(global -> p2p, wpa_s conf -> wps_vendor_ext[i]);
    }
    
    return 0;
}
  • 上面其实就是初始化了一个p2p_config对象,根据p2p_supplicant.conf文件的信息来设置其中的内容,同时还需要为p2p模块设置一些回调函数
  • p2p_init函数来初始化p2p模块

4.上面涉及到的一些知识

  • 上面drv_flags变量,可以在驱动的头文件中获知一二
  • 主要就是一个配置文件的标志,里面代表着这个设备是不是支持AP,是不是支持P2P,是不是支持共存,比如
#define WPA_DRIVER_FLAGS_AP   0x00000040 // wifi驱动是否支持AP,使得设备能够扮演GO的角色
#define WPA_DRIVER_FLAGS_P2P_CONCURRENT  0x000000200 // wifi驱动支持STA和P2P的并发运行
......
  • 下面看下wps_p2p_init中出现几个重要数据结构
    在这里插入图片描述
  • p2p_config中定义了20个回调函数,这些函数定义了P2P模块和外界交互的接口
  • 在wpas_p2p_init总,这些回调函数均指向了p2p_supplicant.c中的对应的函数,例如:p2p_scan指向了wpas_p2p_scan,dev_lost指向了wpas_dev_lost
  • p2p_data指向了一个p2p_config对象

5.下面展示五种数据结构

在这里插入图片描述

  • p2p_device代表一个p2p设备,其中设备名、Device capabilityBitmap等信息保存在一个类型为p2p_peer_info的对象中
  • p2p_group代表一个P2p Group的信息,其内部包含一个P2p_group_config对象和一个P2p_group_member链表,P2p_gorup_config表示该group的配置信息,p2p_group_member代表Group Member即P2p client的信息

6.下面来看下p2p_init函数

struct p2p_data * p2p_init(const struct p2p_config *cfg)
{
    struct p2p_data *p2p;
    ....
    // 从下面可以看出,一个p2p_data对象的内存分布,该内存将包含一个p2p_data的所有信息以及一个p2p_config对象的所有信息
    p2p = os_zalloc(sizeof(*p2p) + sizeof(*cfg));
    // 将p2p_data的cfg成员变量指向保存p2p_config信息的那块内存地址
    p2p -> cfg = (struct p2p_config*) (p2p + 1);
    os_memcpy(p2p -> cfg, cfg, sizeof(*cfg)); // 复制传入的cfg
    if (cfg -> dev_name) p2p -> cfg -> def_name = os_strdup(cfg -> dev_name);
    ... // 其他信息复制进去

#ifdef ANDROID_P2P
    p2p -> min_disc_int = 2;    // listen state的最小时间为200ms
    p2p -> sd_dev_list = NULL;
#else
    p2p -> min_disc_int = 1;
#endif
    p2p -> max_disc_init = 3;
    // 随机获取next_tie_breaker的初始值
    // 第二个参数1表示next_tie_breaker的字节长度,其类型是u8
    os_get_random(&p2p -> nex_tie_breaker, 1);
    p2p -> next_tie_breaker &= 0x01;
    // 设置本机p2p device的device capability信息
    if (cfg -> sd_request) p2p -> dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
    p2p ->dev_capab |= P2P_DEV_CAPAB_INVITATION_PROCEDURE;

    if (cfg -> concurrent_operations) // 支持concurrent功能
        p2p -> dev_capab |= P2P_DEV_CAPAB_CONCURRENT_OPER;
    p2p -> dev_capab |= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;

    dl_list_init(&p2p -> devices);
    // 注册一个超时时间(如果定义了ANDROID_P2P的宏,该时间为30ms
    // 用来检测是否有不活跃的p2p_device
    eloop_register_timeout(P2P_PEER_EXPIRATION_INTERVAL, 0, p2p_expiration_timeout, p2p, NULL);
    return p2p;
}

后记:毕业已经五年有余,脱离了语数外物理化很多年,如果现在再让我拿起这些东西,可能读起来用晦涩难懂来形容一点不为过,反而研读历史、地理、政治、金融、法律一些书籍更为得心应手或者说孜孜不倦,这就是所谓兴趣驱动吧,不把它作为任务反而更有动力,但是一旦作为考核的对象,也许就兴趣大减。

二、源码

  • gitee路径:https://gitee.com/dongqianrui/AndroidStudioProject/tree/master/Test1
  • CSDN:https://blog.csdn.net/weixin_44630050
  • 博客园:https://www.cnblogs.com/ruigege0000/
  • 欢迎关注微信公众号:傅里叶变换,个人账号,仅用于技术交流
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值