Linux NFC 子系统剖析

1.总览

linux源码中NFC在net/nfc下,文件结构如下图:

hci:Host Controller Interface

主要是针对NFC的主机-控制器接口协议

 nci:NFC Controller Interface

主要是NFC的控制器接口协议,用于NFCC(NFC Controller)和DH(Device Host)之间

core.c:

NFC子系统的核心,NFC整个协议栈从这里加载到内核中

af_nfc.c:Address Family

注册NFC协议族

digital_core.c、digital_dep.c、digital_technology.c:

NFC数字协议(NFC Digital Protocol)的协议栈实现

llcp_core.c、llcp_sock.c、llcp_commands.c:

NFC的逻辑链路控制协议(Logical Link Control Protocol)实现

netlink.c:

NFC的Generic netlink相关实现

rawsock.c:

NFC的raw sock相关实现

它们分别在NFC系统中实现了哪些功能?请看下图:

NFC驱动开发:

最底层一共三种方式:

1.直接通过NFC核心驱动框架开发

2.通过HCI接口驱动框架开发

3.通过NCI接口驱动框架开发

这三种方式最终还是通过核心驱动框架与应用层通信,通信的方式有generic netlink、rawsock。如果是llcp,那还会通过rawsock_llcp与应用层交互。

其中generic netlink主要是交互一些命令与事件,比如应用层向驱动层发送开始寻卡命令,寻找到卡后,驱动层会发送寻找到目标的事件。而rawsock主要是数据交互,比如向卡内写数据、读取卡内数据等。

NFC的应用开发:

1.通过dbus获取NFC相关事件

2.通过AF_NFC Sockets与内核交互数据

3.通过Neard AL与驱动层交互(本质还是generic netlink)

其实由驱动也可以看出来,Neard作为应用层的一个守护进程并不是必须的。

2.代码分析

nfc_init

nfc协议栈的起点是 nfc_init 函数,它被subsys_initcall调用后加载。

这个函数包含了nfc协议栈的所有初始化:

nfc类的注册不再赘述,注册成功后会有/sys/class/nfc目录。

nfc_genl_init

nfc_genl_init用来注册nfc的netlink接口:

这中间最重要的是变量 nfc_genl_family ,它包含了使用netlink实现的功能。它包含了两个最重要的元素:

其中name是用来匹配此协议簇,当我们在应用层与之匹配时,需要指明name是nfc,这样就能匹配成功。其次就是匹配成功后该协议簇所支持的一系列操作:

这些操作对应了我们驱动需要实现的功能。在内核有关nfc subsystem的说明文档中有提到:

也就是start_poll 、stop_poll 、activate_target 、deactivate_target 、data_exchange 这些操作是nfc子系统必须实现的,它们的含义:

start_poll :启动设备开始轮询目标

stop_poll :停止轮询操作

activate_target :选择和初始化其中一个发现的目标

deactivate_target :取消选择和恢复初始化目标

data_exchange :发送数据和接收应答

而这些我们需要实现的操作都被 nfc_genl_ops 中不同指令所对应的操作调用。比如start_poll:

上图中的info会由应用层指定,主要就是确定是哪个发起者开始轮询,毕竟系统中可能存在多个发起者。真正的启动轮询函数如下:

上图中的ops是重点,我们编写的驱动中实现的start_poll在这里被调用。对ops的赋值在函数 nfc_allocate_device 中,从函数名也可以看出是用来申请nfc device的,我们的驱动中需要使用此函数申请nfc_dev设备,申请的时候必须传入ops操作合集:

根据上述描述我们已经了解了用户层是如何通过generic netlink的CMD来操作不同设备寻卡、激活卡的,那寻找到卡后怎么通知到应用层?该调用哪些API呢?

很简单在include/uapi/linux/nfc.h中有枚举类型 nfc_commands ,里面包含了所有genl的CMD和事件,我们在net/nfc/netlink.c中搜索 NFC_EVENT_ 前缀的宏定义即可找到对应的函数,比如添加了一个device:

可以看到这个函数主要功能就是广播一条内容为 NFC_EVENT_DEVICE_ADDED 的事件,这个函数只在 nfc_register_device 函数中被调用,所以申请完nfc device后,我们还要调用这个函数注册设备。

所以我们只需要关注我们需要发送哪些事件,即可知道需要调用哪几个函数:

Tips--这里解释一些缩写: 

TM:Target mode

LLC:Logic Link Control,逻辑链路控制,用于P2P模式

SE:Secure Element,安全单元,通常用于CE模式

rawsock_init

该函数用于注册新协议注册。

不用关心如何注册,我们只需要关注下面的变量:

这中间最重要的是 rawsock_ops 和 rawsock_raw_ops 操作函数合集。

当应用层使用下面的操作创建sock时:

socket(AF_NFC, SOCK_SEQPACKET, NFC_SOCKPROTO_RAW)

对应的各个操作函数就是 rawsock_ops了。然后通信的时候先connect,再send/recv。在connect的时候,根据传入的addr中的设备ID和目标ID,确定通过哪个发起者和哪张卡通信。

其中发送函数先把需要发送的数据放在队列里,然后使用tx工作队列:

在创建rawsock的时候,指定了tx_work的执行函数:

传输的关键就在于nfc_data_exchange 函数:

上述 im_transceive 函数也是注册nfc_dev的时候传入的操作函数。 

特定名词

NFC(Near Filed Communication) 近场通信

R/W MOD 读写模式

CE MOD(Card Emulation Mod) 卡仿真模式

P2P MOD 点对点模式

PCD(VCD) 近(疏)耦合设备

PICC(VICC) 近(疏)IC卡

LLCP 逻辑链路控制协议

RF 射频

RFID 设备识别

NDEP NFC数据交换协议

NFCIP NFC接口和协议

NDEF NFC数据交换格式

DEP 数据交换协议

SNEP 简单NDEF交换协议

CHP(Connection Handover Protocol) 连接切换协议

WUPA 唤醒A类卡

ATQ 对请求的应答

ATQA 对A型卡请求的应答

ATQB 对B型卡请求的应答

ATR 对重新启动的请求的应答

ATS 对选择请求的应答

ATQ-ID 对ID号请求的应答

CRC 环检验码

RATS 对选择应答请求

REQA 对A型卡的请求

REQB 对B型卡的请求

REQ-ID 请求ID号

RESEL 重新选择的请求

文章推荐:

LINUX NFC SUBSYSTM | SVEN

http://t.csdnimg.cn/zN4a2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/488531.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot网站开发01-如何搭建Maven类型父子嵌套结构项目

springboot网站开发01-如何搭建Maven类型父子嵌套结构项目!众所周知,实际上,在真正的公司项目开发中为了让代码实现更多的复用,提升项目的开发效率,节省开发的成本(人力成本较高,代码可以尽量复…

算法【查找算法的概念】

查找算法概念 1、查找的基本概念2、评价查找算法3、问题: 查找过程中我们要研究什么? 1、查找的基本概念 查找的概念: 根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素或者记录。 查找算法也可以叫搜索算法。查找算法就是从一个有序…

Dynamo批量将房间名称转换为模型文字

今天呢,我们简单聊聊如何把房间名称,变成模型文字,好在三维中能够看到房间名称。 本来吧,我觉得批量创建模型文字应该是个很简单的事,但是我在Dynamo中搜了下ModelText,发现只有一个在族环境中创建模型文字…

【MATLAB源码-第146期】基于matlab的信源编码仿真GUI,对比霍夫曼编码,算术编码和LZ编码。

操作环境: MATLAB 2022a 1、算法描述 霍夫曼编码、算术编码和LZ编码是三种广泛应用于数据压缩领域的编码技术。它们各自拥有独特的设计哲学、实现方式和适用场景,因此在压缩效率、编解码速度和内存使用等方面表现出不同的特点。接下来详细描述这三种编…

T-Dongle-S3开发笔记——分区表

参考: ESP32之 ESP-IDF 教学(十三)—— 分区表_esp32分区表-CSDN博客 分区表 - ESP32 - — ESP-IDF 编程指南 latest 文档 (espressif.com) 分区表是 ESP32 划分内部 flash 闪存的清单,它将 flash 划分为多个不同功能的区域用于…

反序列化字符串逃逸 [安洵杯 2019]easy_serialize_php1

打开题目 $_SESSION是访客与整个网站交互过程中一直存在的公有变量 然后看extract()函数的功能: extract($_POST)就是将post的内容作为这个函数的参数。 extract() 函数从数组中将变量导入到当前的符号表(本题的作用是将_SESSION的两个函数变为post传参) function…

展锐S8000安卓核心板参数_紫光展锐5G核心板模块定制方案

展锐S8000核心板模块是基于八核S8000平台开发设计的,采用了先进的6nm EUV制程技术。搭载了全新的智能Android 13操作系统,展现出超强的画面解析能力和高性能双通道MIPI,拥有120Hz高刷新率,独立NPU和3.2TOPS Al算力,同时…

【leetcode热题】填充每个节点的下一个右侧节点指针

给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下: struct Node {int val;Node *left;Node *right;Node *next; } 填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到…

运维SRE-15 自动化批量管理-ansible1

## 1.什么是自动化批量管理重复性工作与内容: 思考如何自动化完成. 部署环境,批量查看信息,批量检查:自动化 一般步骤:1.如何手动实现2.如何自动化管理工具,批量实现3.注意事项:想要自动化一定要先标准化(所有环境,软件,目录一致)…

.net6 webapi log4net完整配置使用流程

前置&#xff1a;为项目安装如下两个依赖 1.创建文件夹cfgFile 2.创建log4net.Config <?xml version"1.0" encoding"utf-8" ?> <log4net><appender name"ConsoleAppender" type"log4net.Appender.ConsoleAppender"…

猫头虎分享已解决Bug || ReferenceError: process is not defined ‍

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

【操作系统】14.I/O设备怎么分配和回收?

5.2 I/O设备怎么分配和回收&#xff1f; 5.2.1 I/O核心子系统 I/O调度 设备保护 假脱机技术&#xff08;SPOOLing技术&#xff09; ​ 输入井和输出井 ​ 输入进程和输出进程 ​ 输入缓冲区和输出缓冲区 设备分配与回收 ​ 设备分配应考虑的因素 ​ 静态分配与动态分配 ​ 设备…