Cover image for Linux Network Devices

Linux Network Devices


Timeline

Timeline

2026-01-13

init

This article introduces the basics of Linux network devices, discusses in detail the development history of network communication, the characteristics and functions of common network protocols such as TCP/IP and UDP, and explains network transmission media such as twisted pair cables, coaxial cables, and optical fibers.

Linux Driver Notes

Table of ContentsLinks
1. Linux Driver Framework
2. Linux Driver Loading Logic
3. Character Device Basics
4. Concurrency and Competition
5. Advanced Character Device Progression
6. Interrupts
7. Platform Bus
8. Device Tree
9. Device Model
10. Hot Plug
11. pinctrl Subsystem
12. GPIO Subsystem
13. Input Subsystem
14. Single Bus
15. I2C
16. SPI
17. UART
18. PWM
19. RTC
20. Watchdog
21. CAN
22. Network Device
23. ADC
24. IIO
25. USB
26. LCD

Basics of Network Communication

Development History

In 1969, ARPAnet initially connected computers from four American universities, using packet-switching technology to achieve data transmission between computers.

In 1972, the first transatlantic connection was achieved with computers in the United Kingdom and Norway.

In 1973, research began on the Transmission Control Protocol (TCP) and Internet Protocol (IP).

In 1984, the TCP/IP protocol became the standard for computer network communication.

In 1986, the U.S. National Science Foundation (NSF) established a wide area network (the predecessor of the Internet).

In 1994, China’s NCFC network officially connected to NSFnet, marking China’s entry into the Internet.

Network Protocol

A network protocol is a set of rules and conventions for communication between devices on a network. Common network protocols include:

TCP/IP Protocol

TCP/IP (Transmission Control Protocol/Internet Protocol) is the fundamental protocol suite for internet communication.

Features

  • Connection-oriented: Before transmitting data, the TCP protocol establishes a connection through a ‘three-way handshake’ to ensure the reliability of both communicating parties and the orderly transmission of data.
  • High reliability: TCP ensures data reliability and integrity through mechanisms such as sequence numbers, acknowledgment responses, retransmission, and flow control. If a data packet is lost or corrupted during transmission, TCP will request retransmission until the data arrives accurately.
  • Byte-stream oriented: TCP treats application layer data as an unstructured byte stream, without preserving message boundaries. This means TCP does not concern itself with the specific content of the application layer data, but merely transmits it as a series of bytes.

Function

  • The TCP/IP protocol operates in a layered manner, with each layer performing specific functions, providing a complete communication solution from network hardware to applications. It enables data exchange between different computers and networks.

UDP Protocol

UDP (User Datagram Protocol) is a connectionless protocol. Unlike TCP, UDP does not provide connection-oriented communication, nor does it guarantee data reliability and integrity.

Features

  • Connectionless: UDP does not require establishing a connection before sending data. Each packet is sent independently, and the receiver does not need to send acknowledgment responses. This characteristic gives UDP low latency and high transmission efficiency.

  • Unreliability: UDP cannot guarantee the order, integrity, or reliability of data packets. If packets are lost or corrupted during transmission, UDP does not request retransmission.

  • Datagram-based: UDP encapsulates application layer data into independent datagrams for transmission, each containing complete destination and source address information.

Function

UDP is suitable for scenarios with high real-time requirements, such as video streaming, audio streaming, and online gaming. In these applications, even if a small number of packets are lost, it does not significantly impact the overall experience.

DNS Protocol

DNS (Domain Name System) is a distributed database system whose main function is to convert domain names into corresponding IP addresses (e.g., 192.0.2.1). With DNS, users can access websites using easy-to-remember domain names without having to memorize complex IP addresses.

DHCP Protocol

DHCP (Dynamic Host Configuration Protocol) is a network protocol that automatically assigns network parameters such as IP addresses, subnet masks, default gateways, and DNS server addresses to client devices within a local area network.

FTP Protocol

FTP (File Transfer Protocol) is a protocol for transferring files over a network, enabling file sharing between different computers, and is one of the important tools for file transmission on the internet.

HTTP/HTTPS Protocol

HTTP (HyperText Transfer Protocol) is an application-layer protocol for distributed, collaborative, hypermedia information systems, and is the foundation of data communication on the World Wide Web (WWW).

HTTPS (HyperText Transfer Protocol Secure) is the secure version of HTTP, which encrypts data using the SSL/TLS protocol to ensure the security of data transmission.

Function

The HTTP protocol allows users to access various resources on the internet, such as web pages, images, and videos, through a browser. The HTTPS protocol is dedicated to protecting user data security, preventing data from being stolen or tampered with during transmission, and is widely used in scenarios with high data security requirements, such as online banking, online payments, and e-commerce.

Transmission Medium

Including twisted pair cables, coaxial cables, and optical fibers

  • Twisted Pair Cable

A twisted pair cable is generally composed of several wires, commonly 8 copper wires twisted together in pairs to form 4 twisted pairs. The exterior is wrapped with an insulating layer and a sheath to protect the internal wires, prevent information leakage, and resist external electromagnetic interference.

  • Coaxial Cable

A coaxial cable is a device for transmitting electrical energy or signals, typically composed of several wires or groups of wires. It consists of a conductor, an insulating layer, and a sheath layer.

  • Optical Fiber

An optical fiber is a cable that uses light as an information carrier and transmits data through the principle of total internal reflection in fibers made of glass or plastic. It is mainly divided into single-mode fiber and multi-mode fiber.

Types of Twisted Pair Cables

Category 1 and Category 2 cables

Category 1 and Category 2 cables were mainly used in early telephone communication systems and did not support data transmission or modern network applications. With the continuous advancement of network technology, these two cable categories have been phased out and are no longer used for network cabling.

Category 3 (Cat 3) cable

Category 3 cable is one of the early Ethernet cable standards, mainly used for traditional Ethernet with a transmission rate of 10Mbps. In modern network environments, Cat 3 cables are rarely used.

Category 4 (Cat 4) cable

Compared to Category 3 cables, Category 4 cables showed some improvement, but in practical applications, due to their low cost-effectiveness, they were not widely adopted and were soon replaced by the more advanced Category 5 cables.

Category 5 (Cat 5) cable

5 Category 5 cable is a twisted-pair cable commonly used in computer networks,supports up to 100Mbps data transmission rate(FastEthernet)。

Enhanced Category 5 (Cat 5e) cable

Enhanced 5 Category 5e cable is 5 an enhanced version of Category 5 cable,mainly used for Gigabit Ethernet(1000Mbps),Also backward compatible with 100 Mbps Ethernet。

Category 6 cable (Cat 6)

Compared to previous cables,6 Category cables have improvements in internal structure、material, and external protection,to ensure higher transmission quality and stability。6 Category cables are also used for Gigabit Ethernet(1000Mbps)as the transmission medium

Augmented Category 6 cable (Category 6A, Cat 6a)

Augmented 6 Category cable is 6 a further upgraded version of Category cable,supports 10Gbps transmission rate of(10 Gigabit Ethernet)。

Category 7 cable (Cat 7)

7 Category 7 cable is a type of shielded twisted pair(STP),supports 10Gbps transmission rate,has higher bandwidth and lower signal attenuation。

Ethernet cable wiring standards

There are two standards for Ethernet cable wiring: T568A and T568B.

If both ends of the cable use the same wiring standard, it is called a straight-through cable, used to connect different types of devices, such as a computer to a router;

If the wiring standards differ, such as one end using T568A and the other T568B, it is called a crossover cable, commonly used to connect similar devices, such as computer to computer or switch to switch.

T568A

T568A standard wiring order: white-green, green, white-orange, blue, white-blue, orange, white-brown, brown.

T568A
T568A

T568B

T568B standard wiring order: white-orange, orange, white-green, blue, white-blue, green, white-brown, brown

T568B
T568B

Network model

OSI seven-layer model

The OSI seven-layer network model is a network architecture standard developed by the International Organization for Standardization (ISO) specifically to achieve interconnection and interoperability between different systems.

The OSI seven-layer model, from bottom to top, consists of: Physical Layer, Data Link Layer, Network Layer, Transport Layer, Session Layer, Presentation Layer, and Application Layer, as detailed below:

OSI Seven-Layer Network Model
OSI Seven-Layer Network Model

  • Physical Layer

The physical layer only needs to consider how to send 0s and 1s, and how the receiving end recognizes them to complete the transmission of the bit stream, without caring about the specific meaning of the bit stream. Additionally, it also specifies some electrical characteristics in the network.

  • Data Link Layer

Simple 0s and 1s are meaningless; the data link layer converts the raw bit stream from the physical layer into independent frames. It is also responsible for the establishment, maintenance, and termination of link connections, as well as functions such as frame synchronization, error control, and flow control.

  • Network Layer

The network layer mainly handles the transmission and routing of data packets from the source node to the destination node, i.e., establishing host-to-host communication.

  • Transport Layer

The transport layer is responsible for providing reliable port-to-port data transmission services, ensuring that data can be accurately and error-free transmitted from the sender to the receiver.

  • Session Layer

It is mainly responsible for managing user sessions, controlling the dialogue between applications, including the start, end, and data exchange process of the dialogue.

  • Presentation Layer

The presentation layer is responsible for data format conversion, such as conversion between device-specific formats and network standard formats, which can be understood as acting as a ‘translator’.

  • Application Layer

The application layer is the layer directly facing users, completing specific network applications through interaction between application programs.

TCP/IP Four-Layer Model

The TCP/IP four-layer model is a simplification of the OSI seven-layer model, dividing network functions into the network interface layer, internet layer, transport layer, and application layer, as shown in the following diagram:

TCP/IP Four-Layer Model
TCP/IP Four-Layer Model

  • Application Layer

The application layer directly interacts with applications. Common application layer protocols include HTTP, FTP, SMTP, DNS, etc. Different types of applications choose different protocols in the application layer based on their needs, for example, email transmission applications can select the SMTP protocol.

  • Transport Layer

Provides reliable port-to-port data transmission services. The most important protocols in the transport layer are TCP and UDP. TCP provides connection-oriented, reliable services, while UDP provides connectionless, unreliable but fast services.

  • Network Layer

Provides host-to-host communication. The most important protocol in the network layer is the IP protocol, which adds an IP address to each data packet.

  • Network Interface Layer

The network interface layer includes the physical layer and the data link layer, so it encompasses both physical transmission and link establishment.

OSI (Open System Interconnection) is a seven-layer model developed by the International Organization for Standardization (ISO).

The TCP/IP four-layer model references the OSI seven-layer model and simplifies it into four layers, as shown in the diagram below. As a result, it is more efficient and cost-effective in applications, leading to its rapid development and establishment as the de facto standard.

Differences Between the Two Models
Differences Between the Two Models

Encapsulation and Decapsulation of Network Data

In network communication, encapsulation refers to adding the protocol header and trailer of the current layer to the data from the upper layer, forming a new data unit, and then passing it to the next layer for processing.

Decapsulation is the reverse process of encapsulation, where the receiver removes the protocol header and trailer of the current layer from the received data unit, extracts the upper-layer protocol data, and then passes it to the upper layer for processing.

The processes of encapsulation and decapsulation are carried out sequentially across different network layers.

Encapsulation Process
Encapsulation Process

Application Layer Encapsulation: Data generated by applications, such as web page data transmitted via HTTP protocol or email data transmitted via SMTP protocol, is referred to as application data at this stage. Application layer protocols format the data according to their own requirements; for example, HTTP adds request headers or response headers containing information such as request methods, URLs, and response status codes.

Transport Layer Encapsulation: Application data arrives at the transport layer (e.g., TCP or UDP). Taking TCP as an example, TCP adds a TCP header to the data, which includes source port number, destination port number, sequence number, acknowledgment number, control flags, and other information. Port numbers identify applications, allowing the receiver to correctly deliver data to the corresponding application. The UDP header is relatively simpler, also containing source and destination port numbers for multiplexing and demultiplexing. At this point, the data with the TCP or UDP header is called a segment.

Network Layer Encapsulation: The segment from the transport layer arrives at the network layer (e.g., IPv4 or IPv6), which adds an IP header. The IP header contains key information such as source IP address and destination IP address, used for routing between different networks. The data after adding the IP header is called a packet. For example, when you visit a website, your device encapsulates the TCP segment in an IP packet, with the destination IP address being that of the website server.

Data Link Layer Encapsulation: The packet from the network layer arrives at the data link layer (e.g., Ethernet), which adds a frame header and frame trailer. The Ethernet frame header contains source MAC address, destination MAC address, etc., while the frame trailer includes a cyclic redundancy check (CRC) value for error detection. The data at this stage is called a frame. The frame is then converted into electrical or optical signals by the physical layer for transmission over the physical medium.

Decapsulation is the reverse process of encapsulation. At the receiving end, data starts from the physical layer and moves upward through each network layer, with each layer removing the corresponding header information to restore the data into a form that the application layer can process, as shown in the following diagram:

Decapsulation Process
Decapsulation Process

Data Link Layer Decapsulation: The physical layer receives electrical or optical signals, converts them into data frames, and passes them to the data link layer. The data link layer checks the frame header and trailer, uses CRC to ensure error-free data transmission, removes the header and trailer, and passes the data packet to the network layer.

Network layer decapsulation: The network layer receives the data packet, checks the IP header, and determines whether it is destined for the local machine based on the destination IP address. If so, it removes the IP header and passes the segment to the transport layer.

Transport layer decapsulation: The transport layer receives the segment, delivers the data to the corresponding application based on the port number in the TCP or UDP header, and removes the TCP or UDP header. At this point, the data is restored to application layer data, which the application program can process.

Hardware connection

RJ45 interface

RJ45isRegistered Jack 45abbreviation, in computer networks, RJ45 is the short name for the standard 8-pin modular interface. RJ45 consists of a plug and a socket, connected by a network cable. The RJ45 plug is shown in the figure below

RJ45 plug
RJ45 plug

From the appearance,the RJ45 plugis rectangular, with a plastic outer shell,and inside there are 8 metal contacts, which are used for electrical connection with the RJ45 socket

Corresponding to the RJ45 plug, inRJ45 socketalso has8 metal contact blades for connecting with the RJ45 plug. When the RJ45 plug is inserted, its 8 metal contacts at the front make tight contact with the metal blades inside the socket, thereby achieving signal transmission.

RJ45 socket
RJ45 socket

Both 100M and Gigabit Ethernet ports use the RJ45 interface for physical connection. However, although they look identical, their transmission capabilities are vastly different. The corresponding pin usage is also very different.

100M RJ45 interfacehas 8 pins, these 8 pins are

Pin NumberIdentifierChinese NameFunction Description
1TX+Transmit Data +Positive terminal of Ethernet differential transmit signal
2TX-Transmit Data -Negative terminal of Ethernet differential transmit signal
3RX+Receive data +Positive terminal of Ethernet differential receive signal
4NCNo connectionNo electrical connection, unused
5NCNo connectionNo electrical connection, unused
6RX-Receive data -Negative terminal of Ethernet differential receive signal
7NCNo connectionNo electrical connection, unused
8NCNo connectionNo electrical connection, unused

Differential signal: TX+/- and RX+/- are paired differential signal lines. They use differential transmission to resist interference and enhance the stability of Ethernet data transmission. This is the core design of the RJ45 Ethernet port.

Standard Matching: This definition conforms toT568Bthe wiring standard (most commonly used in residential/industrial scenarios). It differs from the T568A standard only in wire sequence arrangement, while the pin functions are identical.

Unused Pin Function: Pins 4, 5, 7, and 8 are reserved pins. Some industrial-grade Ethernet ports may use them for power supply (e.g., PoE), but in conventional Ethernet applications, they are all NC (Not Connected).

Gigabit RJ45 Interfacealso has 8 pins. Compared to Fast Ethernet, the Gigabit Ethernet port utilizes all 8 pins, divided into 4 differential pairs to achieve full-duplex high-speed transmission.

Pin NumberNameFunction DescriptionTransmission DirectionDifferential Pair Group
1TX_D1+Transceive Data1+ (Transmit Signal +)TransmitFirst Pair
2TX_D1-Transceive Data1-(Send Signal -)SendFirst Pair
3RX_D2+Receive Data2+(Receive Signal +)ReceiveSecond Pair
4BI_D3+Bi-directional Data3+(Bidirectional Signal)BidirectionalThird Pair
5BI_D3-Bi-directional Data3-(Bidirectional Signal)BidirectionalThird Pair
6RX_D2-Receive Data2-(Receive Signal -)ReceiveSecond Pair
7BI_D4+Bi-directional Data4+ (bidirectional signal)BidirectionalFourth pair
8BI_D4-Bi-directional Data4- (bidirectional signal)BidirectionalFourth pair

Transmission rate and pin utilization: Fast Ethernet (100BASE-TX) uses only 4 pins: 1/2 (TX) and 3/6 (RX), whileGigabit Ethernet (1000BASE-T) uses all 8 pins, achieving a transmission rate of 1 Gbps by simultaneously transmitting and receiving over 4 differential pairs.

Function of bidirectional pins (BI): Pins 4/5 and 7/8 are designed for bidirectional transmission. In Gigabit mode, these two pairs dynamically switch transmission and reception directions based on communication needs, achieving full-duplex communication with digital signal processing (DSP) technology.

Differential transmission characteristics: Each pair of pins (e.g., TX_D1+/TX_D1-) are differential signal lines, transmitting signals through the voltage difference between the two wires, effectively suppressing common-mode interference and enhancing the stability of high-speed data transmission. This is a core design of the Ethernet physical layer.

Wiring standard compatibility: This pin definition still follows the T568A/T568B wiring standard, and the wire sequence arrangement is consistent with that of a 100M Ethernet port. Therefore, a Gigabit Ethernet cable is backward compatible with a 100M Ethernet port.

MAC controller

The full name of the MAC controller is Media Access Control. It belongs to**the OSI Layer 2 (Data Link Layer)**part.

The main function of the MAC controller is to control the connection with the PHY chip. It acts like a “bridge manager,” responsible for managing data transmission between the data link layer and the physical layer, ensuring that data can flow smoothly between the two layers.

The main functions of the MAC controller include:

  1. Ethernet frame encapsulation and parsing
    • Responsible for adding/parsing the Ethernet frame header (destination MAC, source MAC, type field)
    • Check and generate CRC (FCS)
  2. Data transmission and reception control
    • Read data from system memory (DMA), encapsulate it into Ethernet frames, and send
    • Receive data from the PHY and write it to memory
  3. Traffic and buffer management
    • Transmit/Receive FIFO
    • Notify CPU via interrupt or polling
    • DMA descriptor management (driver layer focus)
  4. Link layer control
    • Supports full-duplex / half-duplex
    • Supports flow control (PAUSE frames)
    • Statistics (packet loss, collisions, error counts, etc.)
  5. Interface with PHY
    • ViaMII / RMII / RGMII / SGMIIinterfaces to communicate with PHY
    • ViaMDIO/MDCto configure and manage the PHY chip

PHY chip

PHY chip stands for Physical Layer chip. The main task of the PHY chip is toconvert digital signals into analog signals suitable for transmission over physical media (e.g., Ethernet cables), thenconvert the received analog signal back into a digital signal, so that the computer can recognize and process it.

The core functions of PHY include:

  1. Signal encoding and decoding
    • 100M:MLT-3、4B/5B
    • 1000M:PAM-5
    • Adaptive equalization, echo cancellation
  2. Auto-Negotiation
    • Negotiate speed (10M / 100M / 1000M)
    • Negotiate duplex mode (half-duplex / full-duplex)
  3. Link detection
    • Cable plug/unplug detection
    • Report Link Up / Link Down status to MAC
  4. Clock recovery and synchronization
    • Recover clock from the received signal
    • Ensure accurate data sampling
  5. Management interface with MAC
    • UsingMDIO/MDCregister interface
    • Common in Linux driversphy_read()/phy_write()

Network transformer

Network transformer, also known as network isolation transformer or Ethernet transformer, mainly functions for signal coupling, electrical isolation, and impedance matching. It is located betweenthe PHY and RJ45 interface, and is a passive component.

The main functions of the network transformer include:

  1. Electrical isolation
    • Provides isolation capability above 1500V
    • Prevents surges and potential differences from damaging chips
    • Meets Ethernet safety standards (e.g., IEEE 802.3)
  2. Signal coupling
    • Couples the differential signal output from the PHY to the twisted pair
    • Block DC component, transmit only AC signal
  3. Impedance matching
    • Match PHY output impedance with network cable (100Ω)
    • Reduce reflections, improve signal quality
  4. EMI suppression
    • Work with common-mode choke to reduce electromagnetic interference
    • Enhance anti-interference capability

Many RJ45 connectors internallyintegrate network transformers and common-mode chokes, commonly referred to in engineering as**“LED-equipped Ethernet port”**。

Connection method

Based on the integration of CPU, MAC, and PHY, it can be further subdivided into the following three methods:

Method 1: CPU integrates MAC and PHY internally

In this method, the CPU integrates MAC and PHY internally. While this reduces the number of peripheral components, it significantly increases CPU cost and offers poor flexibility due to full internal integration. Therefore, this method is rarely used in practical applications.

Method 2: CPU integrates MAC internally, PHY uses a separate chip

The CPU only integrates the MAC controller internally, while the PHY uses a separate chip. The advantage of this method is the flexibility to choose the PHY chip based on the application scenario, and it is alsothe current mainstream approach

CPU integrates MAC internally, PHY uses a separate chip
CPU integrates MAC internally, PHY uses a separate chip

The iTOP-RK3568 also uses this method. It should be noted that the RJ45 connector on the iTOP-RK3568 development board integrates a network transformer internally. If the
RJ45 connector does not have an integrated network transformer, a separate network transformer chip is required.

Method 3: CPU does not integrate MAC and PHY, MAC and PHY use separate chips or integrated chips

In this connection method, the CPU lacks MAC and PHY functions, meaning the CPU itself does not support network functionality. To use network functions, it must be adapted through other interfaces. Therefore, this method has higher costs.

CPU does not integrate MAC and PHY, MAC and PHY use separate chips or integrated chips
CPU does not integrate MAC and PHY, MAC and PHY use separate chips or integrated chips

PHY Interface

In embedded network development, the most mainstream solution is shown in the following diagram:

CPU integrates MAC internally, PHY uses a separate chip
CPU integrates MAC internally, PHY uses a separate chip

From the block diagram, it can be seen that the left side of the PHY chip connects to the MAC, and the right side connects to the RJ45 connector. It is particularly evident that the PHY chip serves as a bridge.

The PHY chip can be connected to the MAC controller via MII, RMII, GMII, RGMII, and MIDO interfaces.

MII Interface

The full name of the MII interface isMedia Independent Interface, i.e., “Media Independent Interface”.

The transmission rate of the MII interface is 10Mbps or 100Mbps. At 100Mbps, the clock is 25MHz; at 10Mbps, the clock is 2.5MHz. The hardware connection is shown in the following diagram:

MII Interface
MII Interface

The MII interface requires a total of 16 signal lines, with the following meanings:

Signal Line TypeSignal Line NameQuantityDescriptionDirection (MAC←→PHY)Core Function
Transmit ChannelTX_CLK1Transmit Clock, generated by PHYMAC ← PHYSynchronous clock for transmitting data (25MHz at 100Mbps)
TX_EN1Transmit Enable, active highMAC → PHYIndicates data valid on TXD [3:0]
TXD[3:0]4Transmit data busMAC → PHYParallel transmitted Ethernet data (4-bit wide)
TX_ER1Transmit error, active highMAC → PHYIndicates an error during transmission (e.g., frame format error)
Receive channelRX_CLK1Receive clock, generated by PHYMAC ← PHYSynchronous clock for received data (25 MHz for 100 Mbps)
RX_DV1Receive data valid, active highMAC ← PHYIndicates data valid on RXD [3:0] (replaces RX_EN)
RXD[3:0]4Receive data busMAC ← PHYParallel received Ethernet data (4-bit wide)
RX_ER1Receive error, active highMAC ← PHYIndicates an error during reception (e.g., CRC error, frame too long)
Collision / Carrier detectionCOL1Collision detection, active highMAC ← PHYIn half-duplex mode, indicates a data collision on the bus
CRS1Carrier sense, active highMAC ← PHYIn half-duplex mode, indicates the bus is busy

RMII Interface

The full name of the RMII interface isReduced Media Independent Interface, which stands for “Reduced Media Independent Interface”. It is a simplified version of the MII interface. Therefore, compared to the MII interface, the RMII interface reduces the number of signal lines for data transmission and reception by half. The hardware connection is shown in the following diagram:

RMII Interface
RMII Interface

The RMII interface requires a total of 7 signal lines, with the following meanings:

Signal Line NameQuantityDirection (MAC ↔ PHY)Core Description & Key Development Points
REF_CLK1 lineExternal → MAC + PHY50MHz fixed reference clock,the only synchronous clock for transmitting and receiving data(replaces MII’s TX_CLK/RX_CLK); must be supplied to both MAC and PHY, clock source can be PHY’s internal crystal oscillator or an external crystal oscillator
TX_EN1 lineMAC → PHYTransmit enable, active high; PHY samples TXD [1:0] data only when this signal is high
TXD[1:0]2 linesMAC → PHY2-bit parallel transmit data bus; achieves 100Mbps rate via ‘2-bit width × 50MHz’, a core design of RMII simplification
CRS_DV1 linePHY → MACMultiplexed signal
Full-duplex mode: only serves as ‘RX_DV (Receive Data Valid)’
Half-duplex mode: simultaneously indicates ‘CRS (Carrier Sense)’ and ‘DV (Data Valid)’
RXD[1:0]2 linesPHY → MAC2-bit parallel receive data bus; MAC samples data only when CRS_DV is high

GMII interface

The full name of the GMII interface isGigabit Media Independent Interface, which stands for “Gigabit Media Independent Interface.” It is an interface designed to meet the high-speed data transmission requirements of Gigabit Ethernet. Under 10M/100M/1000M, the clocks are 2.5M, 25M, and 125M respectively. The hardware connection is shown in the following diagram:

GMII
GMII

The GMII interface requires a total of 25 signal lines, with the following meanings:

Signal NameBit Width / QuantityChinese DescriptionSignal DirectionDetailed Function (Development Core)Rate Adaptation Description
GTX_CLK1 lineGigabit Transmit ClockMAC → PHYDedicated transmit synchronous clock for Gigabit mode, fixed125MHz, the MAC sends data based on this clock, and the PHY synchronously samples TXD dataUsed only for Gigabit (1000M), core clock
TX_CLK1 line100M transmit clockMAC → PHYTransmit clock compatible with 10/100M rates, 10M=2.5MHz, 100M=25MHzUsed only in 10/100M mode, invalid in gigabit mode (floating)
TXD[7:0]8 linesTransmit data busMAC → PHY8-bit parallel transmit data, core wide bit-width design of GMIIFully compatible with gigabit/100M/10M, different rates have different clocks
TX_EN1 lineTransmit enableMAC → PHYActive high, indicates data on TXD [7:0] is valid; PHY samples data only at this timeUniversal for all rates
TX_ER1 lineTransmit error indicationMAC → PHYActive high, indicates a format error in the currently transmitted data frameUniversal for all rates
RX_CLK1 lineReceive clockPHY → MACReceive synchronous clock, Gigabit mode = 125MHz, 100Mbps = 25MHz, 10Mbps = 2.5MHz,extracted and provided by PHY from received data, MAC synchronously samples RXD dataFull-rate universal, core receive clock
RXD[7:0]8 linesReceive data busPHY → MAC8-bit parallel receive data, core wide-bit design of GMIIFully compatible with Gigabit/100Mbps/10Mbps
RX_DV1 lineReceive data validPHY → MACActive high, indicates data valid on RXD [7:0], MAC samples data only at this timeFull-rate universal, replaces MII’s RX_EN naming
RX_ER1 lineReceive Error IndicationPHY → MACActive high, indicates that the currently received data frame has errors (CRC/FCS error, frame length error, etc.)Full Rate Universal
CRS1 lineCarrier Sense SignalPHY → MACOnlyHalf-Duplex ModeActive, high level indicates the Ethernet bus is busy, prohibiting MAC from sending dataFull rate universal, this signal is invalid (pulled low) in full-duplex mode
COL1 lineCollision Detection SignalPHY → MACOnlyHalf-Duplex ModeActive, high level indicates a data collision on the bus, triggering frame retransmission by MACFull rate universal, no collision in full-duplex mode, this signal is invalid

RGMII Interface

RGMII is a simplified version of GMII. It reduces the number of pins from 25 in GMII to 14 in RGMII. The clock frequencies are 2.5M, 25M, and 125M for 10M/100M/1000M modes respectively. The hardware connection is shown in the following diagram:

RGMII
RGMII

The RGMII interface requires a total of 14 signal lines, with the following meanings:

Signal NameQuantityDirection (MAC ↔ PHY)Core Description & Key Development PointsRate Adaptation
TXC1 lineMAC → PHYTransmit clock, fixed in gigabit mode125MHzDouble-edge sampling(rising edge + falling edge) is the core of RGMII simplification1000M=125MHz100M=25MHz10M=2.5MHz
TX_CTL1 lineMAC → PHYTransmit control signal,Multiplexing TX_EN (transmit enable) and TX_ER (transmit error); double-edge synchronized with TXCfull-rate universal
TXD[3:0]4MAC → PHYtransmit data bus, 4-bit parallel;double-edge sampling, each clock edge transmits 1 bit of data, equivalent to 8-bit bandwidthfull-rate universal
RXC1PHY → MACreceive clock, fixed in gigabit mode125MHz; provided by PHY, also supportsdouble-edge sampling1000M=125MHz100M=25MHz10M=2.5MHz
RX_CTL1PHY → MACreceive control signal,multiplexed RX_DV (receive valid) and RX_ER (receive error); double-edge synchronized with RXCFull Rate Universal
RXD[3:0]4MAC → PHYReceive data bus, 4-bit parallel;Double-edge sampling, equivalent to 8-bit bandwidthFull Rate Universal

MDIO Interface

The full name of the MDIO interface isManagement Data Input/Output, i.e., Management Data Input/Output Interface.

Its main function isto enable the MAC controller to manage and control the PHY chip, for example, configuring the operating rate by setting PHY registers via the MDIO interface; it can also obtain the status of the Ethernet port by reading the status registers of the PHY chip.

The MDIO interface is asynchronous serial half-duplex interface, consisting of two signal lines, namely:

  • MDIO: Acts as a data line for transmitting configuration and management data between the MAC layer and the PHY layer.
  • MDC: Serves as a clock line, providing clock synchronization for data transmission.

Example

RTL8211 PHY Chip

The iTOP-RK3568 development board uses the RTL8211 PHY chip. The RTL8211 supports transmission rates of 10Mbps, 100Mbps, and 1000Mbps, and features auto-negotiation, allowing it to automatically adjust its working mode based on the network environment.

From the circuit connection diagram in the RTL8211 chip datasheet, it can be seen that the RTL8211 chip connects to the RJ45 interface via the MDI interface. The MAC controller connects to the PHY chip through the RGMII interface and the MDIO interface, as shown in the following figure:

RTL8211
RTL8211

Simplify the block diagram from the datasheet:

RTL8211
RTL8211

The iTOP-RK3568 core board has an exposed RGMII interface, as shown in the following figure:

RK3568 Core Board Exposes RGMII0
RK3568 Core Board Exposes RGMII0

The iTOP-RK3568 core board connects to the RTL8211 chip via the RGMII interface and the MDIO interface. The schematic is as follows:

Connected to the RTL8211 chip via the RGMII interface and the MDIO interface
Connected to the RTL8211 chip via the RGMII interface and the MDIO interface

  • Pins 15, 16, 17, and 18 correspond to TXD3, TXD2, TXD1, and TXD0 respectively. These are transmit pins, with direction from MAC to PHY.
  • Pins 22, 23, 24, 25, and 26 correspond to RXD3, RXD2, RXD1, and RXD0 respectively. These are receive pins, with direction from PHY to MAC.
  • Pin 20 is the TXC pin, the transmit clock signal pin.
  • Pin 27 is the RXC pin, the receive clock signal pin.
  • Pin 26 is the RXCTL pin, used for receiving control signals.
  • Pins 13 and 14 are the MDIO pins.
  • Pin 31 is the INTB/PMEB pin. If these two functions are not used, this pin should be left floating. If Page 0xd40, REG.22 bit[5] is set to 1, it functions as PMEB; if set to 0, it functions as an interrupt.

The RTL8211 is connected to the RJ45 connector via the MDI interface, as shown in the schematic below:

The RTL8211 is connected to the RJ45 connector via the MDI interface.
The RTL8211 is connected to the RJ45 connector via the MDI interface.

Pins 1 to 10 correspond to the MDI interface pins MDIP0, MDIN0, MDIP1, MDIN1, MDIP2, MDIN2, MDIP3, and MDIN3, respectively.

The MDI interface is used to connect the PHY chip to the network transformer or the RJ45 connector.

RJ45 connector
RJ45 connector

PHY registers

In the 802.3 specification, the first 16 registers of the PHY chip are defined, as shown in the figure below:

The first 16 registers of the PHY chip
The first 16 registers of the PHY chip

In development, we most frequently interact with Register 0 and Register 1.

Register 0 is the control register: Used to configure the operating mode and parameters of the PHY chip. The control register can set the chip’s transmission rate (10Mbps, 100Mbps, or 1000Mbps), duplex mode (full-duplex or half-duplex), and enable or disable auto-negotiation, among other settings.

Register 1 is the status register: Used to indicate the current working status of the PHY chip. For example, through the status register, you can check whether the network connection has been successfully established, whether a link fault is detected, the current transmission rate and duplex mode, and other information.

Registers 16 to 31 are extended registers.: Registers 0 to 15 are defined by IEEE 802.3. Regardless of the PHY chip manufacturer, registers 0 to 15 are identical. Therefore, in general, the generic PHY driver in Linux can be used to drive the PHY chip. However, different manufacturers’ PHY chips may have additional features, so the extended registers are left for PHY manufacturers to customize. That is, the extended registers are only involved when these specific features are used.

PHY Address

Each PHY register has a unique address, through which we can accurately access and operate the corresponding register. The address of the RTL8211 PHY chip on the iTOP-RK3568 development board can be set via pins 22, 27, and 26.

PHY Address Config
PHY Address Config

Physical Address (MAC Address)

The physical address, also known as the MAC address, is a unique identifier for network devices. It consists of 48 binary bits and is usually represented as 12 hexadecimal digits, such as 00:11:22:33:44:55.

IP Address

An IP address is a network layer address used to identify the logical location of a device in a network. It comes in two versions: IPv4 and IPv6:

  • An IPv4 address consists of 32 binary bits and is usually represented in dotted decimal notation, such as 192.168.1.1;
  • An IPv6 address consists of 128 binary bits. The main function of an IP address is to enable communication between different networks, allowing data packets to be routed from the source network to the destination network.

PHY Address

A PHY address is used to uniquely identify a PHY chip within a network. In a system, there may be multiple PHY chips present simultaneously. The PHY address allows different PHY chips to be distinguished for individual configuration and management.

Determination of PHY Chip Address

Taking the Xunwei iTOP-RK3568 development board as an example, the address of its RTL8211 PHY chip is determined in the following way.

Open the datasheet of the RTL8211 PHY chip. As shown in the figure below, pins 22, 26, and 27 are used to configure the address of the PHY chip.

RTL8211 PHY
RTL8211 PHY

Furthermore, on the RK3568 baseboard schematic, the three pins of the PHY chip are connected as follows:

PHY Address Config
PHY Address Config

From the figure above, it can be seen that the address of the PHY chip is 001, which is 1. The PHY chip sets its address through hardware pins.

Operating PHY Registers

First, open the debug serial port of the iTOP-RK3568 development board, then power on the board. After entering the terminal, execute the commandcd /sys/bus/mdio_bus/devices, to enter the development board’smdio_busbus device directory.

Then, execute the commandcd stmmac-0:00/to enter the device for network card 0. The specific operation process is as follows:

1
2
3
4
5
6
7
cd /sys/bus/mdio_bus/devices

cd stmmac-0:00/
# Viewing the Values of Each Register
cat phy_registers
# Modify the value of register 0 and set it to 0x40
echo 0x00 0x40 > phy_registers

Basics of Network Application Programming

Byte Order

Little-endian mode: The low-order byte is stored at the low address, and the high-order byte is stored at the high address.

Big-endian mode: The high-order byte is stored at the low address, and the low-order byte is stored at the high address.

Byte order conversion functions

There are four common byte order conversion functions: htonl, htons, ntohl, and ntohs. A brief introduction to each function is shown in the table below:

Their core function is to resolve the incompatibility of byte order between different hosts and the network.

Function NameFunction DescriptionData TypeConversion Direction
htonlConvert 32-bit host byte order to network byte orderuint32_tHost → Network
htonsConvert 16-bit host byte order to network byte orderuint16_tHost → Network
ntohlConvert 32-bit network byte order to host byte orderuint32_tNetwork → Host
ntohsConvert 16-bit network byte order to host byte orderuint16_tNetwork → Host

uint32_t htonl(uint32_t hostlong)

  • Function: Used to convert a locally stored 32-bit integer into a format suitable for network transmission (big-endian mode).
  • Parameter: A 32-bit integer in host byte order.
  • Return value: Returns a 32-bit integer in network byte order.

uint16_t htons(uint16_t hostshort)

  • Function: Used to convert a locally stored 16-bit integer (such as a port number) into a format suitable for network transmission.
  • Parameter: A 16-bit integer in host byte order.
  • Return value: Returns a 16-bit integer in network byte order.

uint32_t ntohl(uint32_t netlong)

  • Function: Used to convert 32-bit data received from the network (such as an IPv4 address) into a format that the local system can process.
  • Parameter: A 32-bit integer in network byte order.
  • Return value: Returns a 32-bit integer in host byte order.

uint16_t ntohs(uint16_t netshort)

  • Function: Used to convert 16-bit data received from the network (such as a port number) into a format that the local system can process.
  • Parameter: A 16-bit integer in network byte order.
  • Return value: Returns a 16-bit integer in host byte order.

For example, when writing TCP and UDP code, a port number such as 8080 is needed, and byte order conversion is required. The htons function is used to convert 8080 from host byte order to network byte order. A simple example program is as follows:

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include <arpa/inet.h>
int main(void)
{
uint16_t host_port = 8080; // Host port number
uint16_t net_port = htons(host_port); // Convert to network byte order
printf("Host Port: 0x%04X\n", host_port);
printf("Network Port: 0x%04X\n", net_port);
return 0;
}

Address conversion functions

In addition to byte order conversion, IP addresses also need to be converted. IP addresses are typically displayed in a human-readable form such as dotted decimal (e.g., 192.168.1.1), but internally in programs, they need to be stored and processed in binary form.

In network programming, there are two IP address conversion functions, namelyinet_ptonandinet_ntop, which support the conversion of IPv4 and IPv6 addresses. A brief introduction to the two functions is as follows:

This table shows two core functions used for IP address format conversion in network programming, which support the conversion of both IPv4 and IPv6 addresses.

Function NameFunction DescriptionConversion Direction
inet_ptonConverts an IP address in string format (dotted decimal for IPv4 or colon-hexadecimal for IPv6) to binary data in network byte orderString → Binary
inet_ntopConverts a binary IP address in network byte order to string format (dotted decimal for IPv4 or colon-hexadecimal for IPv6)Binary → String

inet_pton()

  • Converts a string address to binary data
  • Converts an IP address string in dotted decimal (IPv4) or colon-hexadecimal (IPv6) format to binary data in network byte order.

inet_ptonThe function prototype is as follows: returns 1 on success, 0 if the src format is invalid, and -1 if af is not supported.

1
int inet_pton(int af, const char *src, void *dst);

The specific parameter descriptions are as follows:

Parameter NameDescriptionData Type / Value RangeExample Value
afSpecifies the address family, used to distinguish between IPv4 or IPv6 addressesAF_INET:IPv4AF_INET6:IPv6AF_INET(IPv4)
srcPointer to the IP address string to be convertedString"192.168.1.1"
dstPointer to the buffer storing the converted binary dataBinary datastruct in_addr

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
#include <arpa/inet.h>
int main()
{
const char *ipv4 = "192.168.1.1";
struct in_addr addr;
if (inet_pton(AF_INET, ipv4, &addr) <= 0)
{
printf("Invalid IPv4 address\n");
}
else
{
printf("Network byte order: 0x%x\n", addr.s_addr);
}
return 0;
}

inet_ntop()

  • Convert binary data to string address
  • inet_ntopThe function is used to convert a binary IP address in network byte order into a human-readable string form (dotted decimal or colon hexadecimal).

inet_ntopThe function prototype is as follows: returns a pointer to dst on success, returns NULL and sets errno on failure.

1
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

The parameters are as follows:

Parameter NameDescriptionData Type / Value RangeExample Value
afSpecifies the address family to distinguish between IPv4 or IPv6 addressesAF_INET:IPv4AF_INET6:IPv6AF_INET(IPv4)
srcPointer to the buffer storing the binary IP addressBinary Datastruct in_addr
dstPointer to the buffer storing the converted string-form IP addressStringchar ip[INET_ADDRSTRLEN]
sizedstSize of the buffer, ensuring it is large enough to hold the resulting stringsocklen_tINET_ADDRSTRLENorINET6_ADDRSTRLEN

Example Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
#include <arpa/inet.h>
int main()
{
struct in_addr addr;
addr.s_addr = 0xC0A80101; // 192.168.1.1 in network byte order
char ip[INET_ADDRSTRLEN];
if (inet_ntop(AF_INET, &addr, ip, sizeof(ip)) == NULL)
{
printf("inet_ntop");
} else
{
printf("Dotted decimal: %s\n", ip);
}
return 0;
}

UDP

The full English name of UDP isUser Datagram Protocol, meaning User Datagram Protocol, it is aconnectionlesstransport layer protocol that is part of the TCP/IP protocol suite. It provides a simple, lightweight method of data transmission, suitable for scenarios that require high speed but have low reliability requirements, such as video conferencing, online gaming, and voice calls, which are sensitive to latency and can tolerate occasional packet loss.

UDP communication framework
UDP communication framework

UDP functions

Function NameFunction DescriptionUsage Scenario
socket()Create a socket as an endpoint for network communication.Both server and client need to call this function to create a handle for subsequent communication.
bind()Bind the socket to a specified IP address and port number, so the system can deliver data sent to that address to this socket.The server must call this to bind a fixed listening port so clients can find it; clients typically do not need to call it explicitly.
sendto()Send a datagram to a specified target IP address and port; it is the core sending interface of the UDP protocol.Clients use it to send requests to the server; servers use it to send responses to clients.
recvfrom()Receive a datagram from the network and obtain the sender’s IP address and port information.The server uses it to receive requests from clients; the client uses it to receive responses from the server.

sendto()

sendto()is a system call used for sending data, primarily for the connectionless UDP protocol. It allows a program to send data to a specified destination address (i.e., destination IP and port). Unlikesend()different,sendto()requires explicitly specifying the destination address, making it ideal for connectionless communication. Its function prototype is as follows:

1
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

Parameters:

Parameter NameTypeDescription
sockfdintSocket file descriptor, created bysocket()function, is the handle for all subsequent network operations.
bufconst void *Pointer to the data buffer to be sent, it isconsttype, indicating that the function will not modify the contents of the buffer.
lensize_tLength of the data buffer in bytes, telling the function how many bytes of data to send.
flagsintSend flags, usually set to0. Special flags can be set (such asMSG_DONTROUTEindicates not to check the routing table,MSG_CONFIRMused for link-layer acknowledgment), but rarely used in regular UDP communication.
dest_addrstruct sockaddr *a pointer to the destination address structure, typicallystruct sockaddr_in(IPv4) orstruct sockaddr_in6(IPv6), containing the destination IP and port information.
addrlensocklen_tthe size of the destination address structure, in bytes, used to tell the functiondest_addrhow large the pointed structure is.

on success, returns the actual number of bytes sent

recvfrom()

recvfrom()is a system call for receiving data, mainly used in connectionless UDP protocol. It allows a program to receive packets from a specified source address (i.e., the sender’s IP and port). Unlikerecv()which differs,recvfrom()it can obtain the sender’s address information, making it very suitable for connectionless communication. Its function prototype is as follows:

1
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

The parameters of this function are described as follows:

Parameter NameTypeDescription
sockfdintSocket file descriptor, created bysocket()function, is a handle for network operations.
bufvoid *Pointer to a buffer that stores received data; the function writes received data into this buffer.
lensize_tMaximum length of the buffer (in bytes). If received data exceeds this length, the excess is truncated.
flagsintReceiving flags, usually set to0. Special flags can be set (e.g.,MSG_PEEKpeek at data without removing,MSG_DONTWAITnon-blocking receive), rarely used in regular UDP communication.
src_addrstruct sockaddr *Pointer to a structure storing the sender’s address, typicallystruct sockaddr_in(IPv4) orstruct sockaddr_in6(IPv6), used to obtain the sender’s IP and port.
addrlensocklen_t *Pointer to the size of the sender’s address structure. Must be initialized to the expected size before the call, and updated to the actual address length after the call.

On success, returns the actual number of bytes received

Example

udp_client.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, char *argv[]) {
// Define variable port to store the port number
int port;
// Define variable fd to store the socket descriptor
int fd;
// Define character array buf as the buffer for sending data
char buf[1024];

// Check if the number of command-line arguments is 3
if (argc != 3) {
// If the number of arguments is incorrect, output usage example prompt
printf("for example: ./app ip port\n");
// Return -1 to indicate abnormal program termination
return -1;
}

// Convert the port number string from command-line arguments to an integer
port = atoi(argv[2]);

// Create a UDP socket
// AF_INET indicates using IPv4 protocol
// SOCK_DGRAM indicates this is a UDP socket
// 0 indicates using the default protocol
fd = socket(AF_INET, SOCK_DGRAM, 0);
// Check if the socket was created successfully
if (fd == -1) {
// If creation fails, output an error message
printf("socket fd error\n");
// Return -1 to indicate abnormal program termination
return -1;
}

// Initialize a sockaddr_in structure to store target server address information
struct sockaddr_in addr = {0};
// Set the address family to IPv4
addr.sin_family = AF_INET;
// Convert the port number from host byte order to network byte order and assign it to addr.sin_port
addr.sin_port = htons(port);
// Convert the IP address string from command line arguments to an IP address in network byte order and assign it to addr.sin_addr.s_addr
// Here, inet can also be used_pton(AF_INET, argv[1], &addr.sin_addr);, but the current code uses inet_addr is also feasible
addr.sin_addr.s_addr = inet_addr(argv[1]);

// Clear the buffer buf to prepare for subsequent data reception
memset(buf, 0, sizeof(buf));
// Enter an infinite loop to continuously send data to the server
while (1) {
// Read a string from standard input into the buf buffer
scanf("%s", buf);
// Send the data in buf to the server via the UDP socket
// fd is the socket descriptor
// buf is the data to be sent
// strlen(buf) is the data length
// 0 indicates the default sending flag
// (struct sockaddr*)&addr is the server address
// sizeof(addr) is the size of the server address structure
sendto(fd, buf, strlen(buf), 0, (struct sockaddr*)&addr, sizeof(addr));
// Clear the buf buffer to prepare for the next data reception
memset(buf, 0, sizeof(buf));
}

return 0;
}

udp_server.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, char *argv[]) {
// Define variable port to store the port number
int port;
// Define variable fd to store the socket descriptor
int fd;
// Define character array buf as the buffer for receiving data
char buf[1024];
// Define variable ret to store the function return value
int ret;
// Define variable len to store the length of the address structure
int len;

// Check if the number of command-line arguments is 3
if (argc != 3) {
// If the number of arguments is incorrect, output a usage example prompt
printf("for example: ./app ip port\n");
// Return -1 to indicate abnormal program termination
return -1;
}

// Convert the port number string from command-line arguments to an integer
port = atoi(argv[2]);

// Create a UDP socket
// AF_INET indicates using the IPv4 protocol
// SOCK_DGRAM indicates this is a UDP socket
// 0 indicates using the default protocol
fd = socket(AF_INET, SOCK_DGRAM, 0);
// Check if the socket was created successfully
if (fd == -1) {
// If creation fails, output error message
printf("socket fd error\n");
// Return -1 indicates abnormal program termination
return -1;
}

// Initialize local address structure local_addr
struct sockaddr_in local_addr = {0};
// Initialize source address structure src_addr
struct sockaddr_in src_addr = {0};
// Set the address family of the local address to IPv4
local_addr.sin_family = AF_INET;
// Convert port number from host byte order to network byte order and assign to local_addr.sin_port
local_addr.sin_port = htons(port);
// Convert the IP address string from command line argument to network byte order IP address and assign to local_addr.sin_addr.s_addr
local_addr.sin_addr.s_addr = inet_addr(argv[1]);

// Bind socket fd to local_addr
ret = bind(fd, (struct sockaddr *)&local_addr, sizeof(local_addr));
// Check if binding is successful
if (ret == -1) {
// If binding fails, output error message
printf("bind error\n");
// Return -1 indicates abnormal program termination
return -1;
}

// Set the length of src_addr structure
len = sizeof(src_addr);
// Clear buffer buf to prepare for receiving data
memset(buf, 0, sizeof(buf));

// Enter infinite loop to continuously receive data
while (1) {
// Receive data from UDP socket fd
// buf is the buffer for receiving data
// sizeof(buf) is the buffer size
// 0 is the receiving flag
// (struct sockaddr *)&src_addr is the pointer to the source address structure
// &len is used to return the actual length of the source address structure
recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&src_addr, &len);
// Convert the IP address of the source address to dotted decimal format and output it
// The inet_ntoa function converts an IP address in network byte order to a dotted decimal string
// The ntohs function converts a port number in network byte order to host byte order
printf("ip:%s port:%d\n", inet_ntoa(src_addr.sin_addr), ntohs(src_addr.sin_port));
// Output the received data
printf("buf is %s\n", buf);
// Clear the buffer buf to prepare for the next reception
memset(buf, 0, sizeof(buf));
}

return 0;
}

TCP

The full English name of TCP isTransmission Control Protocol, which means Transmission Control Protocol, it is aconnection-orientedtransport layer protocol, and like UDP, it is a core part of the TCP/IP protocol stack.

TCP ensures the integrity, order, and losslessness of data during transmission by establishing a reliable end-to-end connection. It uses a three-way handshake to establish a connection and guarantees the reliability of data transmission through mechanisms such as acknowledgment, retransmission, and flow control.

Therefore, TCP is suitable for scenarios that require high data accuracy, such as file transfer, email, web browsing, etc. In these scenarios, data integrity and order are crucial, while tolerance for latency is relatively high.

TCP communication framework diagram
TCP communication framework diagram

  • Compared to a UDP client, a TCP client has an additional step of calling connect to initiate a connection request.
  • Compared to a UDP server, a TCP server has two additional steps: calling listen to start listening mode and calling accept to block and wait for client requests.
    • listen sets the socket to passive mode to wait for client connection requests.
    • When a client initiates a connection, accept blocks and waits until it receives a request, then returns a new socket file descriptor dedicated to communicating with that client.

After the client initiates a connection request via connect, it performs a TCP three-way handshake with the server to establish a connection. Once the connection is established, the client and server can send and receive data using write() and read().

After data transmission is complete, the client and server each close the connection using close().

TCP functions

connect()

connect() is a system call used to establish a connection, primarily on the client side. It initiates a connection request to the server by specifying the server’s address (IP address and port number). For the TCP protocol, connect() triggers the TCP three-way handshake process. Note that for the UDP protocol, connect can also be used, but it does not actually establish a connection; instead, it binds the target address to the socket for subsequent communication. Its function prototype is as follows:

1
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

Returns 0 on success, -1 on failure

Parameter nameTypeDescription
sockfdintSocket file descriptor, created bysocket()The function creates a handle for all subsequent network operations.
addrstruct sockaddr *A pointer to the target address structure, typicallystruct sockaddr_in(IPv4) orstruct sockaddr_in6(IPv6), containing the IP address and port number to bind.
addrlensocklen_tThe size of the target address structure in bytes, e.g.,sizeof(struct sockaddr_in)

listen()

listen()is a system call used to set a socket to listening mode, primarily for TCP servers. It converts the socket from active mode (for initiating connections) to passive mode (for receiving connection requests). Callinglisten()after that, the socket starts listening for connection requests from clients and maintains a waiting queue to manage these requests. Its function prototype is as follows

1
int listen(int sockfd, int backlog);

Function Length

Parameter NameTypeDescription
sockfdintSocket file descriptor, created bysocket()and bound to a specific address and port viabind().
backlogintThe maximum length of the waiting connection queue, representing the number of TCP connection requests that can be queued for processing simultaneously.

Returns 0 on success, -1 on failure,

accept()

accept()is a system call used to accept client connection requests, primarily for TCP servers. It retrieves a connection request from the listening socket’s waiting queue and creates a new socket dedicated to communicating with that client. Throughaccept(), the server can handle connection requests from multiple clients. Its function prototype is as follows:

1
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

The parameters of this function are described as follows:

Parameter NameTypeDescription
sockfdintListening socket file descriptor, created bysocket()and set to listening mode vialisten().
addrstruct sockaddr *Pointer to a structure storing the client address (e.g.,struct sockaddr_infor IPv4 addresses). Can beNULL, indicating no need to retrieve the client address.
addrlensocklen_t *Pointer to the size of the client address structure. Must be initialized to the size of the target address structure before the call, and will be updated to the actual address length after the call.

Returns 0 on success, -1 on failure,

Example

tcp_client.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, char *argv[]) {
// Define variable port to store the port number obtained from the command line
int port;
// Define variable fd to store the socket descriptor
int fd;
// Define character array buf as a data buffer to store data read from standard input and received data
char buf[1024];
// Define variable ret to store the return value of the function
int ret;

// Check if the number of command-line arguments is 3
if (argc != 3) {
// If the number of arguments is incorrect, output usage example prompt
printf("for example: ./app ip port\n");
// Return -1, indicating abnormal program termination
return -1;
}

// Convert the port number string from command-line arguments to an integer
port = atoi(argv[2]);

// Create a TCP socket
// AF_INET indicates using IPv4 protocol
// SOCK_STREAM indicates this is a connection-oriented byte stream socket, suitable for TCP protocol
// 0 indicates using the default protocol
fd = socket(AF_INET, SOCK_STREAM, 0);
// Check if the socket was created successfully
if (fd == -1) {
// If creation fails, output an error message
printf("socket fd error\n");
// Return -1, indicating abnormal program termination
return -1;
}

// Initialize a sockaddr_in structure to store the server's address information
struct sockaddr_in addr = {0};
// Set the address family to IPv4
addr.sin_family = AF_INET;
// Convert the port number from host byte order to network byte order and assign it to addr.sin_port
addr.sin_port = htons(port);
// Convert the IP address string from command line arguments to a network byte order IP address and assign it to addr.sin_addr.s_addr
// Here, inet can also be used_pton(AF_INET, argv[1], &addr.sin_addr);, but the current code uses inet_addr is also feasible
addr.sin_addr.s_addr = inet_addr(argv[1]);

// Use the connect function to connect to the server
// fd is the socket descriptor
// (struct sockaddr*)&addr is a pointer to the server address structure
// sizeof(addr) is the size of the server address structure
ret = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
// Check if the connection is successful
if (ret < 0) {
// If the connection fails, output an error message
printf("connect error\n");
// Return -1, indicating abnormal program termination
return -1;
}

// Clear the buffer buf to prepare for subsequent operations.
memset(buf, 0, sizeof(buf));

// Enter an infinite loop to continuously send data to the server.
while (1) {
// Read a string from standard input into the buf buffer.
scanf("%s", buf);
// Send the data in buf to the server via a TCP socket.
// Note: Using the sendto function here is not appropriate for a TCP socket; typically, TCP uses the send function.
// The correct call should be send(fd, buf, strlen(buf), 0);
// However, the original code uses sendto, so this comment follows the original code logic.
sendto(fd, buf, strlen(buf), 0, (struct sockaddr*)&addr, sizeof(addr));
// Clear the buf buffer to prepare for the next data reception.
memset(buf, 0, sizeof(buf));
}

return 0;
}

tcp_server.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
// Define variable port to store the port number obtained from the command line.
int port;
// Define variable fd to store the socket descriptor.
int fd;
// Define a character array buf as the buffer for receiving data.
char buf[1024];
// Define variable ret to store the return value of functions.
int ret;
// Define variable len to store the length of the address structure.
int len;
// Define variable acc_fd to store the new socket descriptor after accepting a connection.
int acc_fd;

// Check whether the number of command-line arguments is 3.
if (argc != 3) {
// If the number of parameters is incorrect, output usage example prompt information
printf("for example: ./app ip port\n");
// Return -1, indicating abnormal program termination
return -1;
}

// Convert the port number string from command line arguments to an integer
port = atoi(argv[2]);

// Create a TCP socket
// AF_INET indicates using IPv4 protocol
// SOCK_STREAM indicates this is a connection-oriented byte stream socket, suitable for TCP protocol
// 0 indicates using the default protocol
fd = socket(AF_INET, SOCK_STREAM, 0);
// Check if the socket was created successfully
if (fd == -1) {
// If creation fails, output error message
printf("socket fd error\n");
// Return -1, indicating abnormal program termination
return -1;
}

// Initialize a sockaddr_in structure to store local address information
struct sockaddr_in local_addr = {0};
// Set the address family to IPv4
local_addr.sin_family = AF_INET;
// Convert the port number from host byte order to network byte order and assign it to local_addr.sin_port
local_addr.sin_port = htons(port);
// Convert the IP address string from command line arguments to an IP address in network byte order and assign it to local_addr.sin_addr.s_addr
// Here, inet can also be used_pton(AF_INET, argv[1], &local_addr.sin_addr);, but the current code using inet_addr is also feasible
local_addr.sin_addr.s_addr = inet_addr(argv[1]);

// Bind the socket fd to local_addr
ret = bind(fd, (struct sockaddr*)&local_addr, sizeof(local_addr));
// Check if the binding is successful
if (ret == -1) {
// If binding fails, output an error message
printf("bind error\n");
// Return -1, indicating abnormal program termination
return -1;
}

// Set the socket to listening state, waiting for client connections
// The second parameter 10 indicates the maximum length of the pending connection queue
listen(fd, 10);

// Initialize a sockaddr_in structure to store client address information
struct sockaddr_in src_addr = {0};
// Define variable src_len to store the length of the client address structure
socklen_t src_len = sizeof(src_addr);
// Accept the client's connection request, returning a new socket descriptor acc_fd for communication with the client
acc_fd = accept(fd, (struct sockaddr*)&src_addr, &src_len);
// Check if the connection acceptance is successful
if (acc_fd < 0) {
// If connection acceptance fails, output an error message
printf("accept error\n");
// Return -1, indicating abnormal program termination
return -1;
}

// Clear the buffer buf to zero, preparing for subsequent data reception
memset(buf, 0, sizeof(buf));

// Enter an infinite loop to continuously receive data sent by the client
while (1) {
// Receive data from the new socket acc_fd into the buf buffer
int byte = recvfrom(acc_fd, buf, sizeof(buf), 0, (struct sockaddr*)&src_addr, &len);
// Check the number of bytes of received data
if (byte > 0) {
// If the number of received data bytes is greater than 0, print the client's IP address, port number, and the received data
printf("ip:%s port:%d\n", inet_ntoa(src_addr.sin_addr), ntohs(src_addr.sin_port));
printf("buf is %s\n", buf);
}
// If the number of received data bytes is 0, it indicates the client has closed the connection
else if (byte == 0) {
printf("close\n");
// Break out of the loop to end data reception
break;
}
// If an error occurs while receiving data
else {
printf("recvfrom error\n");
// Return -1, indicating the program terminated abnormally
return -1;
}
// Clear the buf buffer to prepare for the next data reception
memset(buf, 0, sizeof(buf));
}

// Close the socket acc_fd used for communication with the client
close(acc_fd);
// Close the listening socket fd
close(fd);

// Return 0, indicating the program terminated normally
return 0;
}

Minimal network device driver

You can use an existing driver in the Linux source code as a template, the driver path isdrivers/net/loopback.c. First, back up this file asloopback.c.bak, then create a newloopback.cfile, in which we write our minimal network device driver.

The driver content is as follows; the code implements a simple loopback network device driver.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include <linux/kernel.h>
// Contains basic kernel-related definitions and functions, such as kernel data types, kernel print functions, etc.
#include <linux/jiffies.h>
// Provides system time-related jiffies variables and functions; jiffies records the number of clock ticks since system boot.
#include <linux/module.h>
// Contains definitions and macros for building loadable kernel modules.
#include <linux/interrupt.h>
// Contains functions and data structures related to interrupt handling.
#include <linux/fs.h>
// File system-related definitions and functions, such as definitions of structures like inode and file_operations.
#include <linux/types.h>
// Defines various kernel data types, such as kuid._t、kgid_t, etc.
#include <linux/string.h>
// Provides string handling functions, such as strcpy, strlen, etc.
#include <linux/socket.h>
// Contains socket-related definitions and functions for network programming.
#include <linux/errno.h>
// Defines various error codes for error handling.
#include <linux/fcntl.h>
// Contains file control-related definitions, such as file open flags (O__RDONLY、O_WRONLY, etc.)
#include <linux/in.h>
// Defines data structures and constants related to Internet addresses, such as sockaddr_in, etc.

#include <linux/uaccess.h>
// Provides functions for data interaction between user space and kernel space, such as copy_from_user、copy_to__user, etc.
#include <linux/io.h>
// Used to perform I/O operations, such as ioread, iowrite, etc.

#include <linux/inet.h>
// Contains functions and data structures related to Internet protocols, such as IP address handling, etc.
#include <linux/netdevice.h>
// Defines structures and functions related to network devices; it is the core header file for network device driver development
#include <linux/etherdevice.h>
// Provides helper functions related to Ethernet devices, such as Ethernet address operations, etc.
#include <linux/skbuff.h>
// Contains definitions and functions related to socket buffers (sk_buff), used for network data processing and transmission
#include <linux/ethtool.h>
// Used to operate the ethtool functionality of network devices, such as getting and setting various parameters of network devices
#include <net/sock.h>
// Defines socket-related data structures and functions; it is the foundation of socket operations in network programming
#include <net/checksum.h>
// Provides functions for calculating checksums, used for verifying network data
#include <linux/if_ether.h> // For the statistics structure.
// Contains Ethernet-related definitions, such as Ethernet frame format, statistics structures, etc.
#include <linux/if_arp.h> // For ARPHRD_ETHER
// Contains definitions related to the Address Resolution Protocol (ARP), such as ARP hardware types
#include <linux/ip.h>
// Defines data structures related to the IP protocol, such as the iphdr structure for representing the IP header
#include <linux/tcp.h>
// Contains data structures and definitions related to the TCP protocol, such as the tcphdr structure for representing the TCP header
#include <linux/percpu.h>
// Provides functionality related to per-CPU variables, allowing independent data allocation for each CPU
#include <linux/net_tstamp.h>
// Definitions and functions related to network timestamps, used to record time information of network packets
#include <net/net_namespace.h>
// Contains definitions and functions related to network namespaces, used to achieve isolation of network resources
#include <linux/u64_stats_sync.h>
// Provides a mechanism for synchronizing 64-bit statistical data

// Defines a global variable pointing to the network device structure, used to represent the loopback network device
struct net_device *virnet_netdevice;
// Defines a global variable for recording the number of transmitted bytes
unsigned long bytes = 0;
// Defines a global variable for recording the number of transmitted packets
unsigned long packets = 0;

// Defines the send function of the network device, responsible for handling data transmission of the network device
netdev_tx_t loopback_netdevice_xmit(struct sk_buff *skb, struct net_device *dev) {
// Stops the transmission queue of the network device to prevent new data from being sent
netif_stop_queue(dev);
// Updates the number of transmitted bytes by adding the length of the current skb
bytes += skb->len;
// Updates the number of transmitted packets by incrementing by 1
packets++;
// Sets the protocol type of the skb based on the device type
skb->protocol = eth_type_trans(skb, dev);
// Passes the received skb to the receive function of the network device for processing
if (netif_rx(skb) == NET_RX_SUCCESS) {
// If reception is successful, prints a success message
printk("NET_RX_SUCCESS\n");
}
// Wakes up the transmission queue of the network device to allow continued data transmission
netif_wake_queue(dev);
// Returns a flag indicating successful transmission
return NETDEV_TX_OK;
}

// Define a function to obtain network device statistics
void loopback_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) {
// Set the statistics for the number of bytes sent
stats->tx_bytes = bytes;
// Set the statistics for the number of bytes received; here, the loopback device has the same number of bytes sent and received
stats->rx_bytes = bytes;
// Set the statistics for the number of packets sent
stats->tx_packets = packets;
// Set the statistics for the number of packets received; here, the loopback device has the same number of packets sent and received
stats->rx_packets = packets;
}

// Define the network device operation set structure, containing function pointers for various network device operations
struct net_device_ops loopback_ops = {
.ndo_start_xmit = loopback_netdevice_xmit,
// Pointer to the data transmission function
.ndo_get_stats64 = loopback_get_stats64,
// Pointer to the function for obtaining statistics
};

// Define the network device header operation set structure, containing function pointers for creating network headers
struct header_ops loopback_header_ops = {
.create = eth_header,
// Pointer to the function for creating an Ethernet header
};

// Define the network device setup function, used to initialize the properties of the network device
void loopback_setup(struct net_device *dev) {
// Set the network device's Maximum Transmission Unit (MTU) to 64KB
dev->mtu = 64 * 1024;
// Set the network device type to loopback device
dev->type = ARPHRD_LOOPBACK;
// Set the network device flags, adding the loopback device flag
dev->flags |= IFF_LOOPBACK;
// Clear some specific private flags
dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM);
// Set the characteristics of the network device, add loopback feature
dev->features = NETIF_F_LOOPBACK;
// Set the header operations set of the network device
dev->header_ops = &loopback_header_ops;
// Set the operations set of the network device
dev->netdev_ops = &loopback_ops;
}

// Define the network device initialization function, called when the network namespace is initialized
int loopback_net_init(struct net *net) {
int ret;
// Allocate a network device structure, specifying the device name format and initialization function
virnet_netdevice = alloc_netdev(0, "loopback%d", NET_NAME_UNKNOWN, loopback_setup);
// Set the allocated network device as the loopback device of the network namespace
net->loopback_dev = virnet_netdevice;
// Register the network device
ret = register_netdev(virnet_netdevice);
// If registration fails
if (ret < 0) {
// Print registration error message
printk("register_netdev error\n");
// Free the allocated network device structure
free_netdev(virnet_netdevice);
// Return error code
return ret;
}
// Initialization successful, return 0
return 0;
}

// Define the network device exit function, called when the network namespace exits
void loopback_net_exit(struct net *net) {
// Get the loopback device in the network namespace
struct net_device *dev = net->loopback_dev;
// Unregister the network device
unregister_netdev(dev);
// Release the allocated network device structure
free_netdev(virnet_netdevice);
}

// Define the network namespace operations structure, containing function pointers for network namespace initialization and exit
struct pernet_operations loopback_net_ops = {
.init = loopback_net_init,
// Pointer to the network namespace initialization function
.exit = loopback_net_exit,
// Pointer to the network namespace exit function
};

Port the RTL8723DU (WiFi) driver

After extracting the vendor-provided code, modify the Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
CONFIG_MULTIDRV = n
CONFIG_RTL8188E = n
CONFIG_RTL8812A = n
CONFIG_RTL8821A = n
CONFIG_RTL8192E = n
CONFIG_RTL8723B = n
CONFIG_RTL8814A = n
CONFIG_RTL8723C = n
CONFIG_RTL8188F = n
CONFIG_RTL8188GTV = n
CONFIG_RTL8822B = n
CONFIG_RTL8723D = y //Since the adapted module is RTL8723du, set this option to y
CONFIG_RTL8821C = n
CONFIG_RTL8710B = n
CONFIG_RTL8192F = n
CONFIG_RTL8822C = n
CONFIG_RTL8814B = n
CONFIG_RTL8723F = n
######################### Interface ###########################
CONFIG_USB_HCI = y//The module uses a USB interface, set to y
CONFIG_PCI_HCI = n
CONFIG_SDIO_HCI = n
CONFIG_GSPI_HCI = n
CONFIG_PLATFORM_I386_PC = n//Change this option to n
CONFIG_PLATFORM_ANDROID_X86 = n
CONFIG_PLATFORM_ANDROID_INTEL_X86 = n
CONFIG_PLATFORM_JB_X86 = n
CONFIG_PLATFORM_ARM_S3C2K4 = n
CONFIG_PLATFORM_ARM_PXA2XX = n
CONFIG_PLATFORM_ARM_S3C6K4 = n
CONFIG_PLATFORM_MIPS_RMI = n
CONFIG_PLATFORM_RTD2880B = n
CONFIG_PLATFORM_MIPS_AR9132 = n
CONFIG_PLATFORM_RTK_DMP = n
CONFIG_PLATFORM_MIPS_PLM = n
CONFIG_PLATFORM_MSTAR389 = n
CONFIG_PLATFORM_MT53XX = n
CONFIG_PLATFORM_ARM_MX51_241H = n
CONFIG_PLATFORM_FS_MX61 = n
CONFIG_PLATFORM_ACTIONS_ATJ227X = n
CONFIG_PLATFORM_TEGRA3_CARDHU = n
CONFIG_PLATFORM_TEGRA4_DALMORE = n
CONFIG_PLATFORM_ARM_TCC8900 = n
CONFIG_PLATFORM_ARM_TCC8920 = n
CONFIG_PLATFORM_ARM_TCC8920_JB42 = n
CONFIG_PLATFORM_ARM_TCC8930_JB42 = n
CONFIG_PLATFORM_ARM_RK2818 = n
CONFIG_PLATFORM_ARM_RK3066 = n
CONFIG_PLATFORM_ARM_RK3568 = y //Add this option and set it to y

//Change the following 3188 to 3568
CONFIG_PLATFORM_ARM_RK3188 = nifeq ($(CONFIG_PLATFORM_ARM_RK3568), y)
EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID
-DCONFIG_PLATFORM_ROCKCHIPS
# default setting for Power control
#EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC
ifeq ($(CONFIG_SDIO_HCI), y)
EXTRA_CFLAGS += -DRTW_SUPPORT_PLATFORM_SHUTDOWN
endif
# default setting for Special function
ARCH := arm64 //Change to arm64
CROSS_COMPILE :=
/home/topeet/rk356x_linux/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-
gnu/bin/aarch64-linux-gnu-
KSRC := /home/topeet/rk356x_linux/kernel
MODULE_NAME := wlan //Module name
endif

makeCommand generationwlan.koFile