Skip to main content

14.9 Near Field Communication (NFC)

If you think Bluetooth's range of a few meters still isn't close enough, let's get even closer.

How close? Close enough for physical contact.

That's exactly what NFC (Near Field Communication) is designed for. It's a short-range (typically under 2 inches), low-latency wireless technology built for the sole purpose of exchanging small amounts of data the instant two devices "tap" together. Its speed cap of 424 kb/s might sound like a relic from the Stone Age compared to Gigabit Ethernet, but for its intended use cases, it's more than enough.

NFC typically carries very small payloads—perhaps just a URL, a snippet of text, or pairing information to trigger a Bluetooth/WiFi handover. Its core logic is binding "physical proximity" to "immediate action." Tap your phone against a transit gate, a poster tag, or another phone, and the data exchange is complete—no need to "discover," "pair," and "connect" like with Bluetooth.

NFC operates at 13.65 MHz and is based on the ISO14443 and Sony FeliCa RFID standards at the physical layer. The NFC Forum (http://www.nfc-forum.org/) drives the standardization effort, defining a comprehensive set of specifications covering everything from low-level digital protocols to upper-layer connection handover and medical device communication. The good news is that these specifications are publicly available and free.

NDEF: The Universal "Envelope"

At the heart of the NFC standard ecosystem lies NDEF (NFC Data Exchange Format). You can think of it as the "common language" or "standard envelope" of the NFC world.

Whether reading a tag or engaging in peer-to-peer communication between devices, the data payload is encapsulated in NDEF format. An NDEF record contains two parts:

  1. Header: Metadata telling the receiver "what type of data I am" (e.g., a URL or plain text).
  2. Payload: The actual data.

This design allows applications to ignore the underlying protocol details. By simply parsing the NDEF record, an app knows exactly what action to trigger—whether it's opening a browser or initiating a phone call.


NFC Devices and Tags: Who Powers Up, Who Speaks

In the NFC world, there is a fundamental distinction between devices and tags.

Tags: Silent Stones

NFC tags are extremely simple devices. They usually consist of a tiny flash memory chip and an induction antenna, packaged into a sticker, a keychain, or a card. They have no battery and lack the ability to actively emit a radio field.

So how do they work? By "stealing" power.

When an active NFC device (like your phone) approaches, the phone's radio field induces a current in the tag's antenna. This meager amount of energy wakes up the chip, allowing it to send its stored data back. This mechanism is known as passive communication.

The NFC Forum defines four tag types, each carrying its own historical baggage from RFID and smart card technologies:

  • Type 1: Based on the Innovision/Broadcom Topaz and Jewel specifications. Very small capacity (96 bytes ~ 2KB) and a speed of only 106 kb/s. Cheap.
  • Type 2: Based on the NXP Mifare Ultralight. Similar to Type 1, these are also inexpensive consumer-grade tags.
  • Type 3: Based on Sony FeliCa. This is the Japanese standard (e.g., Suica cards). Larger capacity (up to 1MB) and faster speeds (212 or 424 kb/s), and naturally, more expensive.
  • Type 4: Based on the NXP DESFire. Supports encryption and more complex access control, with capacities up to 32KB and support for all three speeds.

Devices: The Active Party

NFC devices (phones, readers) are the active party. They can generate a magnetic field and read data back. More importantly, they can do three things:

  1. Read/Write Mode: Reading from and writing to tags.
  2. Card Emulation Mode: Pretending to be a tag (e.g., using your phone as a transit card).
  3. Peer-to-Peer Mode (P2P): Two NFC devices talking directly to each other.

Three Operating Modes

Linux kernel NFC support primarily revolves around these three modes, which we need to distinguish clearly:

  1. Read/Write: The simplest mode. A phone reads a tag or writes data to it.
  2. Peer-to-Peer: Unique to NFC. Two devices tap together to establish an LLCP (Logical Link Control Protocol) link. Over this link, various services can run (such as SNEP for transmitting NDEF data, or Connection Handover for switching to a Bluetooth connection).
  3. Card Emulation: The most highly regarded mode by the payment industry. The phone pretends to be a card, and a reader (POS terminal) reads it. For security, this usually involves a "Secure Element," where the payment application on the phone runs inside a trusted environment that directly controls the NFC radio frequency.

The Kernel Perspective: From Hardware to Sockets

Unlike Android, which shoves the entire NFC protocol stack into user space, the standard Linux kernel handles a significant portion of the work. Starting with kernel 3.1, Linux introduced the AF_NFC socket protocol family, along with a set of Generic Netlink interfaces for NFC control.

The design philosophy here is: the kernel abstracts the hardware and provides standard interfaces, while user space handles complex business logic.

Driver Layer: HCI vs NCI

The NFC hardware ecosystem used to be incredibly fragmented. Early controllers mostly relied on the HCI standard defined by ETSI, which was originally designed for communication between SIM cards and contactless front-ends, making it a poor fit for NFC. As a result, various vendors (NXP, Broadcom, etc.) piled on countless proprietary extensions to this standard.

To clean up this mess, the NFC Forum defined a new interface: NCI (NFC Controller Interface). Today, NCI has become the mainstream standard, and nearly all newly released chips support it.

In the kernel, driver developers choose which subsystem to register with based on the interface supported by the chip:

  • NCI-based drivers (like nfcwilink) register with the NCI layer.
  • ETSI HCI-based drivers (like pn544, microread) register with the HCI layer.
  • Drivers based on pure USB proprietary protocols (like pn533) register directly with NFC Core.

Core Registration Flow

Regardless of the path taken, the final destination is always nfc_register_device().

Scenario A: Direct Registration to Core (The Lowest Level) If you are writing a driver for something like pn533 that uses a quirky USB protocol, you need to:

  1. Call nfc_allocate_device() to allocate a nfc_dev structure.
  2. Fill in the nfc_ops callback functions (this is the most tedious part, as you must manually implement low-level logic like polling and target activation).
    • start_poll: Start polling for tags.
    • stop_poll: Stop polling.
    • activate_target: Activate a selected target.
    • deactivate_target: Deactivate a target.
    • im_transceive: Transmit and receive data.
  3. Call nfc_register_device() to register the device with the kernel.

Scenario B: Registration to the HCI Layer (Slightly Easier) If you are using an HCI-supported chip (like pn544), the HCI layer shields you from many details:

  1. Call nfc_hci_allocate_device().
  2. Call nfc_hci_register_device().
    • This automatically calls nfc_register_device() for you.
    • The HCI layer provides a default set of hci_nfc_ops, so you don't need to implement all five callbacks yourself.

Scenario C: Registration to the NCI Layer (The Modern Standard) This is the currently recommended approach, with a flow similar to HCI:

  1. nci_allocate_device().
  2. nci_register_device().
    • This also indirectly calls nfc_register_device().

This layered architecture allows the kernel to flexibly accommodate both legacy chips and modern standard-compliant ones.


With the kernel paving the way, how does user space actually use NFC? There are two main paths: Sockets and Netlink.

1. NFC Sockets (AF_NFC)

This is the "highway" for NFC communication. The kernel implements two types of sockets:

  • Raw Sockets (SOCK_RAW):

    • Purpose: Used for reader/writer mode.
    • Mechanism: You can send tag-specific commands directly to the driver, which forwards them to the tag verbatim. The received data is also returned to you untouched. The kernel does not parse the content.
    • Operations: connect() is used to select and activate a detected tag. send/recv is used to send and receive data.
  • LLCP Sockets (SOCK_STREAM / SOCK_DGRAM):

    • Purpose: Used for peer-to-peer mode.
    • Mechanism: The kernel handles the complex LLCP link-layer protocol for you (connection establishment, fragmentation, reassembly). You simply read and write data streams as if you were writing a standard network program.
    • Operations:
      • connect(): Connect to a specific service on the peer device (e.g., SNEP).
      • bind(): Register a service locally so others can connect to you.

This is the "control panel" for NFC. If you want to control the behavior of the NFC adapter (rather than sending and receiving application data), you use Netlink.

Through Netlink, you can:

  • List all NFC controllers.
  • Power on or power off a controller.
  • Start/stop Polling mode to discover nearby tags or devices.
  • Query what LLCP services a peer device offers.
  • Manage Secure Elements.

Netlink also serves as an event channel. When the kernel detects a new tag, a new device, or a transaction on a Secure Element, it broadcasts events via Netlink to any listening applications.

Initialization Flow: nfc_init()

When the kernel boots, the initialization sequence of the NFC subsystem is highly deliberate—it must proceed layer by layer without skipping steps. The nfc_init() function in net/nfc/core.c demonstrates this assembly process:

static int __init nfc_init(void)
{
int rc;

// 1. 先把 Netlink 这个「控制台」搭起来
rc = nfc_genl_init();
if (rc)
goto err_genl;

// 2. 初始化 Raw Socket 支持(为了读写标签)
rc = rawsock_init();
if (rc)
goto err_rawsock;

// 3. 初始化 LLCP 协议栈(为了点对点通信)
rc = nfc_llcp_init();
if (rc)
goto err_llcp_sock;

// 4. 最后注册整个 AF_NFC 协议族
rc = af_nfc_init();
if (rc)
goto err_af_nfc;

return 0;
// ... 错误处理 ...
}

There is a strict dependency chain here: LLCP depends on the Raw mechanism, and the registration of the AF_NFC protocol family depends on all the preceding infrastructure being ready. If nfc_llcp_init() fails, the entire NFC functionality becomes unavailable, and a rollback must occur.


User Space Daemon: neard

Although the kernel provides low-level Socket and Netlink APIs, writing applications directly against them is painful. You have to handle various protocol details and state machines. To solve this, the Linux community created a user space daemon: neard.

neard plays a role similar to BlueZ in the Bluetooth world. It runs on top of the kernel APIs, exposing a unified and clean interface to upper-layer applications via D-Bus.

It implements:

  • Read/write logic for all four tag types.
  • All NFC Forum-specified P2P protocols (SNEP, Connection Handover, etc.).

The D-Bus API design is highly intuitive:

  • org.neard.Adapter: Represents your NFC adapter (e.g., the chip inside your phone). You can use it to start polling.
  • org.neard.Tag / org.neard.Device: Represents a detected entity. You can call the Push method to send data, or the Write method to write to a tag.
  • org.neard.Record: Represents an NDEF record. Applications can register an Agent to receive raw NDEF data, or directly parse it into readable text/URLs.

Android's Approach

The Linux kernel + neard combination is the standard approach, but Android took a different path.

Android moved the entire NFC protocol stack (including the NCI implementation, LLCP, SNEP, etc.) into user space, placing it in the HAL (Hardware Abstraction Layer). The kernel is left with only a minimal driver stub responsible solely for shuttling data to the hardware via I2C/SPI/UART.

Google provides a reference implementation based on the Broadcom NCI specification. For phone manufacturers, if your chip supports NCI, porting is relatively straightforward; if not, you have to write your own adaptation layer. This is also why some third-party ROMs fail to read cards after porting NFC functionality—the HAL layer wasn't matched correctly.


Chapter Echoes

In this section, we completed the leap from "contact-based" to "near field."

On the surface, we are discussing a "tap-to-connect" technology, but in reality, we are examining how Linux handles an extremely fragmented hardware ecosystem. NFC carries more historical baggage than Bluetooth—RFID standards, ETSI HCI, and vendor-specific proprietary protocols are all mixed together. By introducing NCI, abstracting HCI, and defining unified Socket and Netlink APIs, the Linux kernel managed to build a maintainable architecture right on top of this rubble.

Remember the freight train analogy from the previous section on Bluetooth? If Bluetooth is about laying down a "dedicated freight line," then NFC is about establishing a "handshake protocol." Its focus isn't on moving massive amounts of data, but rather on establishing trust and triggering context. The kernel's role here is to ensure that no matter whether the underlying chip is from NXP or Broadcom, upper-layer applications only need to care about the "I want to tap" action, without worrying about what happens at the RF layer.

In the next section, we will take a step back. Instead of focusing on a specific wireless technology, we will look at the "nervous system" that supports the operation of the entire network subsystem—Notification Chains. They are the fundamental reason why network device state changes (like plugging or unplugging a network cable, or an interface going UP/DOWN) can instantly propagate throughout the entire system.