【MTK平台】【wpa_supplicant】关于wpa_supplicant_8/src/p2p/p2p.c文件的介绍
本文主要介绍external/wpa_supplicant_8/src/p2p/p2p.c文件
先看下p2p_find 这个方法
P2P_find 主要用于 P2P(点对点)网络中查找其他对等方的功能。另外可以看到设置P2P模块的状态为 P2P_SEARCH
int p2p_find(struct p2p_data *p2p, unsigned int timeout,enum p2p_discovery_type type,unsigned int num_req_dev_types, const u8 *req_dev_types,const u8 *dev_id, unsigned int search_delay,u8 seek_count, const char **seek, int freq, bool include_6ghz)
{int res;struct os_reltime start;p2p_dbg(p2p, "Starting find (type=%d)", type);//确认P2P扫描已经可以使用if (p2p->p2p_scan_running) {p2p_dbg(p2p, "p2p_scan is already running");}p2p_free_req_dev_types(p2p);if (req_dev_types && num_req_dev_types) {p2p->req_dev_types = os_memdup(req_dev_types,num_req_dev_types *WPS_DEV_TYPE_LEN);if (p2p->req_dev_types == NULL)return -1;p2p->num_req_dev_types = num_req_dev_types;}if (dev_id) {os_memcpy(p2p->find_dev_id_buf, dev_id, ETH_ALEN);p2p->find_dev_id = p2p->find_dev_id_buf;} elsep2p->find_dev_id = NULL;p2p->include_6ghz = p2p_wfd_enabled(p2p) && include_6ghz;if (seek_count == 0 || !seek) {/* Not an ASP search */p2p->p2ps_seek = 0;} else if (seek_count == 1 && seek && (!seek[0] || !seek[0][0])) {/** An empty seek string means no hash values, but still an ASP* search.*/p2p_dbg(p2p, "ASP search");p2p->p2ps_seek_count = 0;p2p->p2ps_seek = 1;} else if (seek && seek_count <= P2P_MAX_QUERY_HASH) {u8 buf[P2PS_HASH_LEN];int i, count = 0;for (i = 0; i < seek_count; i++) {if (!p2ps_gen_hash(p2p, seek[i], buf))continue;p2p_dbg(p2p, "Seek service %s hash " MACSTR,seek[i], MAC2STR(buf));os_memcpy(&p2p->p2ps_seek_hash[count * P2PS_HASH_LEN],buf, P2PS_HASH_LEN);count++;}p2p->p2ps_seek_count = count;p2p->p2ps_seek = 1;} else {p2p->p2ps_seek_count = 0;p2p->p2ps_seek = 1;}/* Special case to perform wildcard search */if (p2p->p2ps_seek_count == 0 && p2p->p2ps_seek) {p2p->p2ps_seek_count = 1;os_memcpy(&p2p->p2ps_seek_hash, p2p->wild_card_hash,P2PS_HASH_LEN);}//P2P_AFTER_SCAN_NOTHING表示P2P设备完成scan动作后,无需做其他动作p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;p2p_clear_timeout(p2p);if (p2p->pending_listen_freq) {p2p_dbg(p2p, "Clear pending_listen_freq for p2p_find");p2p->pending_listen_freq = 0;}//停止监听p2p->cfg->stop_listen(p2p->cfg->cb_ctx);p2p->find_pending_full = 0;p2p->find_type = type;if (freq != 2412 && freq != 2437 && freq != 2462 && freq != 60480)p2p->find_specified_freq = freq;elsep2p->find_specified_freq = 0;p2p_device_clear_reported(p2p);os_memset(p2p->sd_query_no_ack, 0, ETH_ALEN);//设置P2P模块的状态为 P2P_SEARCHp2p_set_state(p2p, P2P_SEARCH);p2p->search_delay = search_delay;p2p->in_search_delay = 0;eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);p2p->last_p2p_find_timeout = timeout;if (timeout)//注册一个扫描超时处理任务eloop_register_timeout(timeout, 0, p2p_find_timeout,p2p, NULL);os_get_reltime(&start);switch (type) {case P2P_FIND_START_WITH_FULL:if (freq > 0) {/** Start with the specified channel and then move to* scans for social channels and this specific channel.*/res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx,P2P_SCAN_SPECIFIC, freq,p2p->num_req_dev_types,p2p->req_dev_types, dev_id,DEV_PW_DEFAULT,p2p->include_6ghz);break;}/* fall through */case P2P_FIND_PROGRESSIVE: //p2p_scan指向函数 wpas_p2p_scanres = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0,p2p->num_req_dev_types,p2p->req_dev_types, dev_id,DEV_PW_DEFAULT, p2p->include_6ghz);break;case P2P_FIND_ONLY_SOCIAL:res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_SOCIAL, 0,p2p->num_req_dev_types,p2p->req_dev_types, dev_id,DEV_PW_DEFAULT, p2p->include_6ghz);break;default:return -1;}if (!res)p2p->find_start = start;if (res != 0 && p2p->p2p_scan_running) {p2p_dbg(p2p, "Failed to start p2p_scan - another p2p_scan was already running");/* wait for the previous p2p_scan to complete */if (type == P2P_FIND_PROGRESSIVE ||(type == P2P_FIND_START_WITH_FULL && freq == 0))p2p->find_pending_full = 1;res = 0; /* do not report failure */} else if (res != 0) {p2p_dbg(p2p, "Failed to start p2p_scan");p2p_set_state(p2p, P2P_IDLE);eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);}return res;
}
接着看下P2P模块的状态为 P2P_SEARCH后如何进行进入listen状态
也就是p2p_listen_in_find这个方法
static void p2p_listen_in_find(struct p2p_data *p2p, int dev_disc)
{unsigned int r, tu;int freq;struct wpabuf *ies;p2p_dbg(p2p, "Starting short listen state (state=%s)",p2p_state_txt(p2p->state));if (p2p->pending_listen_freq) {/* We have a pending p2p_listen request */p2p_dbg(p2p, "p2p_listen command pending already");return;}//根据 p2p_supplicant.conf中listen_channel等配置参数获取对应的频段freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel);if (freq < 0) {p2p_dbg(p2p, "Unknown regulatory class/channel");return;}//计算需要在listen state 等待的时间if (os_get_random((u8 *) &r, sizeof(r)) < 0)r = 0;tu = (r % ((p2p->max_disc_int - p2p->min_disc_int) + 1) +p2p->min_disc_int) * 100;if (p2p->max_disc_tu >= 0 && tu > (unsigned int) p2p->max_disc_tu)tu = p2p->max_disc_tu;if (!dev_disc && tu < 100)tu = 100; /* Need to wait in non-device discovery use cases */if (p2p->cfg->max_listen && 1024 * tu / 1000 > p2p->cfg->max_listen)tu = p2p->cfg->max_listen * 1000 / 1024;if (tu == 0) {p2p_dbg(p2p, "Skip listen state since duration was 0 TU");p2p_set_timeout(p2p, 0, 0);return;}//构造P2P Probe Response帧,当我们在Listen state收到其他设备发来的Probe Request帧后,wifi驱动将直接回复此处设置的 P2P Probe Response帧。ies = p2p_build_probe_resp_ies(p2p, NULL, 0);if (ies == NULL)return;p2p->pending_listen_freq = freq;p2p->pending_listen_sec = 0;p2p->pending_listen_usec = 1024 * tu;//start_listen指向 wpas_start_listen 函数if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, freq, 1024 * tu / 1000,ies) < 0) {p2p_dbg(p2p, "Failed to start listen mode");p2p->pending_listen_freq = 0;}wpabuf_free(ies);
}
在来看p2p_connect函数,其代码如下所示
这里面有3个重要的知识点
1、是 breaker值在每次发起P2P_CONNECT时都取反一次,这样做的目的是在双方的Intent值相同的情况下,多次协商时,双方都有机会做GO。并且在发送Request时才填入自己的breaker值,在回应Response时,是把对方的breaker值取反后作为breaker值发送。
2. 如果当前P2P还在扫描过程中,则设置start_after_scan为P2P_AFTER_SCAN_CONNECT标志,当scan结束后,在扫描结果处理流程中,该标志将通知P2P进入connect处理流程
3. p2p_connect_send发送GON Request帧
int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,enum p2p_wps_method wps_method,int go_intent, const u8 *own_interface_addr,unsigned int force_freq, int persistent_group,const u8 *force_ssid, size_t force_ssid_len,int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id)
{struct p2p_device *dev;p2p_dbg(p2p, "Request to start group negotiation - peer=" MACSTR" GO Intent=%d Intended Interface Address=" MACSTR" wps_method=%d persistent_group=%d pd_before_go_neg=%d ""oob_pw_id=%u allow_6ghz=%d",MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),wps_method, persistent_group, pd_before_go_neg, oob_pw_id,p2p->allow_6ghz);//获取当前设备p2p dev设备的信息dev = p2p_get_device(p2p, peer_addr);if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {p2p_dbg(p2p, "Cannot connect to unknown P2P Device " MACSTR,MAC2STR(peer_addr));return -1;}// 如果指定了工作频段,则需要判断是否支持该工作频段,否则return -1if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq,go_intent == 15) < 0)return -1;if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {if (!(dev->info.dev_capab &P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {p2p_dbg(p2p, "Cannot connect to P2P Device " MACSTR" that is in a group and is not discoverable",MAC2STR(peer_addr));return -1;}if (dev->oper_freq <= 0) {p2p_dbg(p2p, "Cannot connect to P2P Device " MACSTR" with incomplete information",MAC2STR(peer_addr));return -1;}/** First, try to connect directly. If the peer does not* acknowledge frames, assume it is sleeping and use device* discoverability via the GO at that point.*/}p2p->ssid_set = 0;if (force_ssid) {wpa_hexdump_ascii(MSG_DEBUG, "P2P: Forced SSID",force_ssid, force_ssid_len);os_memcpy(p2p->ssid, force_ssid, force_ssid_len);p2p->ssid_len = force_ssid_len;p2p->ssid_set = 1;}dev->flags &= ~P2P_DEV_NOT_YET_READY;dev->flags &= ~P2P_DEV_USER_REJECTED;dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;if (pd_before_go_neg)dev->flags |= P2P_DEV_PD_BEFORE_GO_NEG;else {dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;/** Assign dialog token and tie breaker here to use the same* values in each retry within the same GO Negotiation exchange.*/dev->dialog_token++;if (dev->dialog_token == 0)dev->dialog_token = 1;dev->tie_breaker = p2p->next_tie_breaker;p2p->next_tie_breaker = !p2p->next_tie_breaker;//这里是对intent的值取反}dev->connect_reqs = 0;dev->go_neg_req_sent = 0;dev->go_state = UNKNOWN_GO;p2p_set_dev_persistent(dev, persistent_group);p2p->go_intent = go_intent;os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);if (p2p->state != P2P_IDLE)p2p_stop_find(p2p);dev->wps_method = wps_method;dev->oob_pw_id = oob_pw_id;dev->status = P2P_SC_SUCCESS;if (p2p->p2p_scan_running) {p2p_dbg(p2p, "p2p_scan running - delay connect send");
/*
如果当前P2P还在扫描过程中,则设置start_after_scan为P2P_AFTER_SCAN_CONNECT标志,
当scan结束后,在扫描结果处理流程中,该标志将通知P2P进入connect处理流程。
*/p2p->start_after_scan = P2P_AFTER_SCAN_CONNECT;os_memcpy(p2p->after_scan_peer, peer_addr, ETH_ALEN);return 0;}// 下面这个函数将发送GON Request帧return p2p_connect_send(p2p, dev);
}
p2p_set_state和p2p_set_timeout记录了P2P: State和Timeout
void p2p_set_state(struct p2p_data *p2p, int new_state)
{p2p_dbg(p2p, "State %s -> %s",p2p_state_txt(p2p->state), p2p_state_txt(new_state));p2p->state = new_state;if (new_state == P2P_IDLE && p2p->pending_channel) {p2p_dbg(p2p, "Apply change in listen channel");p2p->cfg->reg_class = p2p->pending_reg_class;p2p->cfg->channel = p2p->pending_channel;p2p->pending_reg_class = 0;p2p->pending_channel = 0;}
}void p2p_set_timeout(struct p2p_data *p2p, unsigned int sec, unsigned int usec)
{p2p_dbg(p2p, "Set timeout (state=%s): %u.%06u sec",p2p_state_txt(p2p->state), sec, usec);eloop_cancel_timeout(p2p_state_timeout, p2p, NULL);eloop_register_timeout(sec, usec, p2p_state_timeout, p2p, NULL);
}
相关文章:
【MTK平台】【wpa_supplicant】关于wpa_supplicant_8/src/p2p/p2p.c文件的介绍
本文主要介绍external/wpa_supplicant_8/src/p2p/p2p.c文件 先看下p2p_find 这个方法 P2P_find 主要用于 P2P(点对点)网络中查找其他对等方的功能。另外可以看到设置P2P模块的状态为 P2P_SEARCH int p2p_find(struct p2p_data *p2p, unsigned int tim…...
华为数通HCIP-流量过滤与转发路径控制
流量控制 分类:流量过滤、流量转发路径控制; 特点:1、作用于数据层面/转发层面; 2、不会影响路由表,针对转发流量生效; 实现步骤: 1、通过流量匹配工具匹配流量(ACL…...
SpringBoot中定时任务开启多线程避免多任务堵塞
场景 SpringBoot中定时任务与异步定时任务的实现: SpringBoot中定时任务与异步定时任务的实现_霸道流氓气质的博客-CSDN博客 使用SpringBoot原生方式实现定时任务,已经开启多线程支持,以上是方式之一。 除此之外还可通过如下方式。 为什…...
回归预测 | MATLAB实现SO-CNN-BiLSTM蛇群算法优化卷积双向长短期记忆神经网络多输入单输出回归预测
回归预测 | MATLAB实现SO-CNN-BiLSTM蛇群算法优化卷积双向长短期记忆神经网络多输入单输出回归预测 目录 回归预测 | MATLAB实现SO-CNN-BiLSTM蛇群算法优化卷积双向长短期记忆神经网络多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 Matlab实…...
入侵检测——IDS概述、签名技术
1. 什么是IDS? IDS(intrusion detection system)入侵检测系统,是一种对网络传输进行即时监视,在发现可疑传输时发出警报或者采取主动反应措施的网络安全设备。它会对系统的运行状态进行监视,发现各种攻击企…...
golang 标准库json Marshal 序列化与反序列化
标准库代码 func Marshal(v any) ([]byte, error) {e : newEncodeState()defer encodeStatePool.Put(e)err : e.marshal(v, encOpts{escapeHTML: true})if err ! nil {return nil, err}buf : append([]byte(nil), e.Bytes()...)return buf, nil }func Unmarshal(data []byte, …...
【【51单片机AD/DA的分析】】
51单片机AD/DA的分析 看似单片机实验,其实是要学好数电 模数转换 与 数模转换 运算放大器 DA的转换就是利用运算放大器实现的 输出电压v0-(D7~D0)/256 x (VrefxRfb)/R D7~D0 就是我们控制的按键看输入多少 然后再划分256份 Vref是我们设置的一个基准电压 PWM 这种…...
在docker中安装使用达梦数据库
关于在docker中安装达梦数据库,达梦官方网站其实是有提供安装使用方法的,但可能还是有朋友不会,这里将在原文基础上简单扩充下。 注意:docker容器中,数据库安装后没有创建服务的脚本,只有bin、bin2、conf、…...
Leetcode-每日一题【剑指 Offer II 010. 和为 k 的子数组】
题目 给定一个整数数组和一个整数 k ,请找到该数组中和为 k 的连续子数组的个数。 示例 1: 输入:nums [1,1,1], k 2输出: 2解释: 此题 [1,1] 与 [1,1] 为两种不同的情况 示例 2: 输入:nums [1,2,3], k 3输出: 2 提示: 1 < nums.leng…...
【JavaScript】使用Promise来处理异步调用,方法传入参数为接口,并回调接口的方法
例如我们在下面这个方法传入一个接口,并将方法的执行过程用传入的接口进行回调 connect() {wx.connectSocket({url: this.url,success: () > {console.log(WebSocket 连接创建成功);},fail: (err) > {console.error(WebSocket 连接创建失败, err);}});wx.onS…...
grid map学习笔记1之Ubuntu18.04+ROS-melodic编译安装grid_map栅格地图及示例运行
文章目录 0 引言1 安装依赖和编译1.1 安装依赖1.2 下载编译 2 运行示例2.1 simple_demo2.2 tutorial_demo2.3 iterators_demo2.4 image_to_gridmap_demo2.5 grid_map_to_image_demo2.6 opencv_demo2.7 resolution_change_demo2.8 filters_demo2.9 interpolation_demo 0 引言 苏…...
postgres wal2json插件jsonb字段数据丢失问题解决
使用pgwal2jsondebezium进行数据同步时,发现偶尔会有jsonb字段数据丢失的问题 进行测试时发现: 1、发生数据丢失的jsonb字段长度都比较大(超过toast阈值,使用toast表存储) 2、针对发生jsonb字段丢失的数据,jsonb字段本身未发生修…...
华为eNSP:路由引入
一、拓扑图 二、路由器的配置 1、配置路由器的IP AR1: [Huawei]int g0/0/0 [Huawei-GigabitEthernet0/0/0]ip add 1.1.1.1 24 [Huawei-GigabitEthernet0/0/0]qu AR2: [Huawei]int g0/0/0 [Huawei-GigabitEthernet0/0/0]ip add 1.1.1.2 24 [Huaw…...
Retrospectives on the Embodied AI Workshop(嵌入式人工智能研讨会回顾) 论文阅读
论文信息 题目:Retrospectives on the Embodied AI Workshop 作者:Matt Deitke, Dhruv Batra, Yonatan Bisk 来源:arXiv 论文地址:https://arxiv.org/pdf/2210.06849 Abstract 我们的分析重点关注 CVPR Embodied AI Workshop 上…...
「JVM」Full GC和Minor GC、Major GC
Full GC和Minor GC、Major GC 一、Full GC1、什么是Full GC?2、什么情况下会触发full gc? 二、Minor GC1、什么是Minor GC?2、什么情况下会触发Minor GC? 三、Major GC1、什么是Major GC?2、什么情况下会触发Major GC?…...
Asp.Net MVC 使用Log4Net
Asp.Net MVC 使用Log4Net 在 ASP.NET MVC 中使用 Log4net 需要进行一些配置和代码集成。下面是在 ASP.NET MVC 中使用 Log4net 的步骤: 1. 安装 Log4net NuGet 包 打开 NuGet 包管理器控制台,并运行以下命令来安装 Log4net: Install-Pack…...
[元带你学: eMMC协议 29] eMMC 断电通知(PON) | 手机平板电脑断电通知
依JEDEC eMMC及经验辛苦整理,原创保护,禁止转载。 专栏 《元带你学:eMMC协议》 内容摘要 全文 2000 字, 主要内容 前言 断电通知是什么? 断电通知过程...
vue使用recorder-core.js实现录音功能
下载组件 npm install recorder-core封装方法 record.ts //必须引入的核心 import Recorder from recorder-core;//引入mp3格式支持文件;如果需要多个格式支持,把这些格式的编码引擎js文件放到后面统统引入进来即可 import recorder-core/src/engine/…...
ThinkPHP8知识详解:给PHP8和MySQL8添加到环境变量
在PHPenv安装的时候,环境变量默认的PHP版本是7.4的,MySQL的版本是5.7的,要想使用ThinkPHP8来开发,就必须修改环境变量,本文就详细讲解了如果修改PHP和MySQL的环境变量。 1、添加网站 启动phpenv,网站&…...
UE使用UnLua(二)
1.前言 最近也是比较忙,忘了来更新了,好多都是开了头断更的(狗头),今天抽空再更一篇!! 这篇讲一下在UnLua中覆盖蓝图事件(函数),及按钮、文本控件的一些使用…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式
简介 在我的 QT/C 开发工作中,合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式:工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...
热烈祝贺埃文科技正式加入可信数据空间发展联盟
2025年4月29日,在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上,可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞,强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...
