emNet
User Guide & Reference Manual
Document: UM07001
Software Version: 3.54.1
Document revision: 0
Introduction to emNet
This chapter provides an introduction to using emNet. It explains the basic concepts behind emNet.
What is emNet
emNet is a CPU-independent TCP/IP stack.
emNet is a high-performance library that has been optimized for speed, versatility and small memory footprint.
Features
emNet is written in ANSI C and can be used on virtually any CPU.
Some features of emNet:
- Standard socket interface.
- High performance.
- Small footprint.
- No configuration required.
- Runs “out-of-the-box”.
- Very simple network interface driver structure.
- Works seamlessly with embOS in multitasking environment.
- Zero data copy for ultra fast performance.
- Non-blocking versions of all functions.
- Connections limited only by memory availability.
- Delayed ACKs.
- Handling gratuitous ARP packets
- Support for VLAN
- BSD style “keep-alive” option.
- Support for messages and warnings in debug build.
- Drivers for most common Ethernet controllers available.
- Support for driver side (hardware) checksum computation.
- Royalty-free.
Basic concepts
emNet structure
emNet is organized in different layers, as shown in the following illustration.
A short description of each layer’s functionality follows below.
Application layer
The application layer is the interface between emNet and the user application. It
uses the emNet API to transmit data over an TCP/IP network. The emNet API
provides functions in BSD (Berkeley Software Distribution) socket style, such as
connect(), bind(), listen(), etc.
Transport layer
The transport layer provides end-to-end communication services for applications. The
two relevant protocols of the Transport layer protocol are the Transmission Control
Protocol (TCP) and the User Datagram Protocol (UDP). TCP is a reliable connection-oriented
transport service. It provides end-to-end reliability, resequencing, and flow
control. UDP is a connectionless transport service.
Internet layer
All protocols of the transport layer use the Internet Protocol (IP) to carry data from
source host to destination host. IP is a connectionless service, providing no end-to-end
delivery guarantees. IP datagrams may arrive at the destination host damaged,
duplicated, out of order, or not at all. The transport layer is responsible for reliable
delivery of the datagrams when it is required. The IP protocol includes provision for
addressing, type-of-service specification, fragmentation and reassembly, and
security information.
Link layer
The link layer provides the implementation of the communication protocol used to
interface to the directly-connected network. A variety of communication protocols
have been developed and standardized. The most commonly used protocol is Ethernet
(IEEE 802.3). In this version of emNet only Ethernet is supported.
Encapsulation
The four layers structure is defined in [RFC 1122]. The data flow starts at the application
layer and goes over the transport layer, the network layer, and the link layer.
Every protocol adds a protocol-specific header and encapsulates the data and header from the
layer above as data. On the receiving side, the data will be extracted in the complementary direction.
The opposed protocols do not know which protocol on the above and below layers are used.
The following illustration shows the encapsulation of data within an UDP datagram
within an IP packet.
Tasks and interrupt usage
emNet can be used in an application in three different ways.
- One task dedicated to the stack (IP_Task)
- Two tasks dedicated to the stack (IP_Task, IP_RxTask)
- Zero tasks dedicated to the stack (Superloop)
The default task structure is one task dedicated to the stack. The priority of the
management task IP_Task should be higher then the priority of all application tasks that
use the stack to allow optimal performance. The IP_RxTask (if available) should
run at the highest single task priority of all IP related task as it is an interrupt moved
into a task.
Task priorities
IP task priorities are independent from other (non IP) task priorities. However as soon as a task
calls an IP API it should follow these priority rules for the best performance of the stack:
- The IP_RxTask (if used at all) should have the highest single priority of all
tasks that make use of the IP API, having a higher priority than the IP_Task .
- The IP_Task should have a higher task priority than any other task that makes
use of the IP API. It should have a lower priority than the IP_RxTask (if used at all).
- All tasks that make use of the IP API should use a task priority below the IP_Task
to allow optimal performance.
Task priorities for tasks not using the IP API can be freely chosen.
One task dedicated to the stack
Using one task dedicated to the stack is the simplest way to use the TCP/IP stack. It
is called IP_Task and handles housekeeping operations, resending and handling of
incoming packets. The “Read packet” operation is performed from within the ISR.
Because the “Read packet” operation is called directly from the ISR, no additional
task is required. The length of the interrupt latency will be extended for the time
period which is required to process the “Read packet” operation. Refer to IP_Task
for more information and an example about how to include the IP_Task
into your project.
Two tasks dedicated to the stack
The first task is called the IP_Task and handles
housekeeping operations, resends, and handling of incoming packets. The second is
called IP_RxTask and handles the “Read packet” operation. IP_RxTask is woken up
from the interrupt service routine if new packets are available. The interrupt latency
is not extended, because the “Read packet” operation has been moved from the
interrupt service routine to IP_RxTask. Refer to IP_Task and
IP_RxTask for more information. IP_RxTask should have a higher priority
than IP_Task as it is treated as interrupt in task form and should not be interrupted
by IP_Task or any other IP task.

Note
Initializing the IP stack with two task concept from main()
Packets might receive as soon as Ethernet is initialized by IP_Init() and the (receive) interrupt
is enabled. The internal switch between the single task and two task concept gets set automatically
upon the first execution of IP_RxTask() . Initializing the stack from main() typically means to
initialize it before a task scheduler is active.
If a packet is received between IP_Init() and the first run of IP_RxTask() the packet will be processed
like in the single task concept. This should typically cause no problem to the application and the mode
is automatically switched to the two task concept as soon as IP_RxTask() has run for the first time.
If it is desired to completely avoid this to happen, the following steps need to be taken care of:
- Call IP_SetUseRxTask() manually (best placed after calling IP_Init() and adding the two tasks)
to switch to the two task concept early.
- The Ethernet interrupt enable (typically in BSP_IP.c) needs to be manually moved to after
calling IP_Init() and IP_SetUseRxTask() .
Zero tasks dedicated to the stack (Superloop)
emNet can also be used without any additional task for the stack if an application
task calls IP_Exec() periodically. The “Read packet” operation is performed from
within the ISR. Because the “Read packet” operation is called directly from the ISR,
no additional task is required. The length of the interrupt latency will be extended for
the time period which is required to process the “Read packet” operation.
Components of an Ethernet system
Main parts of an Ethernet system are the Media Access Controller (MAC) and the
Physical device (PHY). The MAC handles generating and parsing physical frames and
the PHY handles how this data is actually moved to or from the wire.
MCUs with integrated MAC
Some modern MCUs (for example, the ATMEL SAM7X or the ST STR912) include the
MAC and use the internal RAM to store the Ethernet data. The following block
diagram illustrates such a configuration.
External Ethernet controllers with MAC and PHY
Chips without integrated MAC can use fully integrated single chip Ethernet MAC
controller with integrated PHY and a general processor interface. The following
schematic illustrates such a configuration.
MII / RMII: Interface between MAC and PHY
The MAC communicates with the PHY via the Media Independent Interface (MII) or
the Reduced Media Independent Interface (RMII). The MII is defined in IEEE 802.3u.
The RMII is a subset of the MII and is defined in the RMI specification. The MII/RMII
can handle control over the PHY which allows for selection of such transmission criteria
as line speed, duplex mode, etc.
In theory, up to 32 PHYs can be connected to a single MAC. In praxis, this is never
done; only one PHY is connected. In order to allow multiple PHYs to be connected to
a single MAC, individual 5-bit addresses have to be assigned to the different PHYs. If
only one PHY is connected, the emNet driver automatically finds the address of it.
The standard defines 32 16-bit PHY registers. The first 6 are defined by the standard.
Register | Description |
BMCR | Basic Mode Control Register |
BSR | Basic Mode Status Register |
PHYSID1 | PHYS ID 1 |
PHYSID2 | PHYS ID 2 |
ANAR | Auto-Negotiation Advertisement Register |
LPAR | Link Partner Ability register |
The drivers automatically recognize any PHY connected, no manual configuration of
PHY address is required.
The MII and RMII interface are capable of both 10Mb/s and 100Mb/s data rates as
described in the IEEE 802.3u standard.
The intent of the RMII is to provide a reduced pin count alternative to the IEEE
802.3u MII. It uses 2 bits for transmit (TXD0 and TXD1) and two bits for receive
(RXD0 and RXD1). There is a Transmit Enable (TX_EN), a Receive Error (RX_ER), a
Carrier Sense (CRS), and a 50 MHz Reference Clock (TX_CLK) for 100Mb/s data rate.
The pins used by the MII and RMII interfaces are described in the following table.
Signal | MII | RMII |
TX_CLK | Transmit Clock (25 MHz) | Reference Clock (50 MHz) |
TX_EN | Transmit Enable | Transmit Enable |
TXD[0:1] | 4-bit Transmit Data | 2-bit Transmit Data |
TXD[2:3] | 4-bit Transmit Data (cont’d) | N/A |
PHYCLK | PHY Clock Output | PHY Clock Output |
CRS | Carrier Sense | N/A |
COL | Collision Detect | N/A |
MDIO | Management data I/O | Management data I/O |
MDC | Data Transfer Timing Reference Clock | Data Transfer Timing Reference Clock |
RX_CLK | Receive Clock | N/A |
RXD[0:1] | 4-bit Receive Data | 2-bit Receive Data |
RXD[2:3] | 4-bit Receive Data (cont’d) | N/A |
RX_DV | Data Valid | Carrier Sense/Data Valid |
RX_ER | Receive Error | Receive Error |
Further reading
This guide explains the usage of the emNet protocol stack. It describes all
functions which are required to build a network application. For a deeper understanding
about how the protocols of the Internet protocol suite works use the following
references.
The following Request for Comments (RFC) define the relevant protocols of the Internet
protocol suite and have been used to build the protocol stack. They contain all
required technical specifications. The listed books are simpler to read as the RFCs
and give a general survey about the interconnection of the different protocols.
RFC# | Description |
[RFC 768] | UDP - User Datagram Protocol
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc768.txt
|
[RFC 791] | IP - Internet Protocol
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc791.txt
|
[RFC 792] | ICMP - Internet Control Message Protocol
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc792.txt
|
[RFC 793] | TCP - Transmission Control Protocol
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc793.txt
|
[RFC 821] | SMTP - Simple Mail Transfer Protocol
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc826.txt
|
[RFC 826] | ARP - Ethernet Address Resolution Protocol
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc826.txt
|
[RFC 951] | BOOTP - Bootstrap Protocol
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc951.txt
|
[RFC 959] | FTP - File Transfer Protocol
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc959.txt
|
[RFC 1034] | DNS - Domain names - concepts and facilities
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc1034.txt
|
[RFC 1035] | DNS - Domain names - implementation and specification
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc1035.txt
|
[RFC 1042] | IE-EEE - Transmission of IP datagrams over IEEE 802 networks
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc1042.txt
|
[RFC 1122] | Requirements for Internet Hosts - Communication Layers
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc1122.txt
|
[RFC 1123] | Requirements for Internet Hosts - Application and Support
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc1123.txt
|
[RFC 1661] | PPP - Point-to-Point Protocol
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc1661.txt
|
[RFC 1939] | POP3 - Post Office Protocol - Version 3
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc1939.txt
|
[RFC 2131] | DHCP - Dynamic Host Configuration Protocol
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc2131.txt
|
[RFC 2616] | HTTP - Hypertext Transfer Protocol -- HTTP/1.1
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc2616.txt
|
- [Comer] - Computer Networks and Internets, Douglas E Comer and Ralph E.
Droms - ISBN: 978-0131433519
- [Tannenbaum] - Computer Networks, Andrew S. Tannenbaum
ISBN: 978-0130661029
- [StevensV1] - TCP/IP Illustrated, Volume 1, W. Richard Stevens
ISBN: 978-0201633467.
- [StevensV2] - TCP/IP Illustrated, Volume 2, W. Richard Stevens and Gary R.
Wright - ISBN: 978-0201633542.
- [StevensV3] - TCP/IP Illustrated, Volume 3, W. Richard Stevens
ISBN: 978-0201634952.
Development environment (compiler)
The CPU used is of no importance; only an ANSI-compliant C compiler complying with
at least one of the following international standard is required:
- ISO/IEC/ANSI 9899:1990 (C90) with support for C++ style comments (//)
- ISO/IEC 9899:1999 (C99)
- ISO/IEC 14882:1998 (C++)
If your compiler has some limitations, let us know and we will inform you if these will
be a problem when compiling the software. Any compiler for 16/32/64-bit CPUs or
DSPs that we know of can be used; most 8-bit compilers can be used as well.
A C++ compiler is not required, but can be used. The application program can therefore
also be programmed in C++ if desired.
Running emNet on target hardware
This chapter explains how to integrate and run emNet on your target hardware.
It explains this process step-by-step.
Integrating emNet
The emNet default configuration is preconfigured with valid values, which
matches the requirements of the most applications. emNet is designed to be used
with embOS, SEGGER’s real-time operating system. We recommend to start with an
embOS sample project and include emNet into this project.
We assume that you are familiar with the tools you have selected for your project
(compiler, project manager, linker, etc.). You should therefore be able to add files,
add directories to the include search path, and so on. In this document the
SEGGER Embedded Studio
is used for all examples and screenshots, but every other
ANSI C toolchain can also be used. It is also possible to use make files; in this case,
when we say “add to the project”, this translates into “add to the make file”.
Procedure to follow
Integration of emNet is a relatively simple process, which consists of the following steps:
- Step 1: Open an embOS project and compile it.
- Step 2: Add emNet to the start project
- Step 3: Compile the project
Step 1: Open an embOS start project
We recommend that you use one of the supplied embOS start projects for your target
system. Compile the project and run it on your target hardware.
Step 2: Adding emNet to the start project
Add all IP source files as in the IP release delivery to your project.
The Config folder includes all configuration files of emNet. The configuration files
are preconfigured with valid values, which match the requirements of most applications.
Add the hardware configuration IP_Config_<TargetName>.c supplied with the
driver shipment.
If your hardware is currently not supported, use the example configuration file and
the driver template to write your own driver. The example configuration file and the
driver template is located in the Sample folder.
The IP\ASM folder contains files for various CPUs and toolchains with routines optimized
in assembler code. Typically only one of these files needs to be added to your
project and the rest should be excluded. The optimized routines are used by overwriting
a specific macro that typically can be found in Config\IP_Conf.h.
The SEGGER folder is an optional component of the emNet shipment. It contains
optimized MCU and/or compiler specific files, for example a special memcopy function.
BSP support
IP drivers need hardware setting from the BSP file (like port settings for example).
Some older driver are supplied with BSP.c and BSP.h that need to replace the one
supplied with embOS shipment.
Newer and updated drivers have a separate BSP_IP.c file instead.
Depending on your case, either
replace BSP.c and BSP.h of your embOS start project or add BSP_IP.c.
Configuring the include path
The include path is the path in which the compiler looks for include files. In cases
where the included files (typically header files, .h ) do not reside in the same directory
as the C file to compile, an include path needs to be set. In order to build the
project with all added files, you will need to add the IP directories to your
include path.
Select the start application
For quick and easy testing of your emNet integration, start with the code found in
the folder Application. Add one of the applications to your project (for example
IP_SimpleServer.c).
Step 3: Build the project and test it
Build the project. It should compile without errors and warnings. If you encounter
any problem during the build process, check your include path and your project configuration
settings. To test the project, download the output into your target and
start the application.
By default, ICMP is activated. This means that you could ping your target. Open the
command line interface of your operating system and enter ping <TargetAddress>,
to check if the stack runs on your target. The target should answer all pings without
any error.
Example applications
In this chapter, you will find a description of each emNet example application.
Overview
Various example applications for emNet are supplied. These can be used for testing
the correct installation and proper function of the device running emNet.
The following start application files are provided:
File | Description |
IP_DNSClient.c | Demonstrates the use of the integrated DNS client. |
IP_NonBlockingConnect.c | Demonstrates how to connect to a server using non-blocking sockets. |
IP_Ping.c | Demonstrates how to send ICMP echo requests and how to process ICMP
replies in application. |
IP_SHELL_Start.c | Demonstrates using the IP-shell to diagnose the IP stack. |
IP_SimpleServer.c | Demonstrates setup of a simple server which simply sends back the
target system tick for every character received. |
IP_SpeedClient_TCP.c | Demonstrates the TCP send and receive performance of the device
running emNet. |
IP_Start.c | Demonstrates use of the IP stack without any server or client program.
To ping the target, use the command line: ping <target-ip> where
<target-ip> represents the IP address of the target, which depends
on the configuration and is usually 192.168.2.252 if the DHCP client
is not enabled. |
IP_UDPDiscover.c | Demonstrates setup of a simple UDP application which replies to UDP
broadcasts. The application sends an answer for every received discover
packet. The related host application sends discover packets as UDP
broadcasts and waits for the feedback of the targets which are available
in the subnet. |
IP_UDPDiscover_ZeroCopy.c | Demonstrates setup of a simple UDP application which replies to UDP
broadcasts. The application uses the the emNet zero-copy interface. It
sends an answer for every received discover packet. The related host
application sends discover packets as UDP broadcasts and waits for
the feedback of the targets which are available in the subnet. |
The example applications for the target-side are supplied in source code in the
Application directory.
emNet DNS client (IP_DNSClient.c)
The emNet DNS client resolves a hostname (for example, segger.com) to an IP
address and outputs the resolved address via terminal I/O.
emNet non-blocking connect (IP_NonBlockingConnect.c)
The emNet non-blocking connect sample demonstrates how to connect to a
server using non-blocking sockets. The target tries to connect to TCP server with an
non-blocking socket. The sample can be used with any TCP server independent of the
application which is listening on the port. The client only opens a TCP connection to
the server and closes it without any further communication. The terminal I/O output
in your debugger should be similar to the following out:
Connecting using non-blocking socket...
Successfully connected after 2ms!
1 of 1 tries were successful.
Connecting using non-blocking socket...
Successfully connected after 1ms!
2 of 2 tries were successful.
emNet ping (IP_Ping.c)
The emNet ping sample demonstrates how to send ICMP echo requests and how
to process received ICMP packets in your application. A callback function is
implemented which outputs a message if an ICMP echo reply or an ICMP echo request has
been received.
To test the emNet ICMP implementation, you have to perform the following steps:
- Customize the Local defines, configurable section of IP_Ping.c.
Change the macro HOST_TO_PING according to your configuration. For example, if
the Windows host PC which you want to ping use the IP address 192.168.5.15,
change the HOST_TO_PING macro to 0xC0A8050F.
- Open the command line interface and enter:
ping [IP_ADDRESS _OF_YOUR_TARGET_RUNNING_EMNET]
The terminal I/O output in your debugger should be similar to the following out:
ICMP echo reply received!
ICMP echo request received!
ICMP echo reply received!
ICMP echo reply received!
ICMP echo reply received!
ICMP echo reply received!
ICMP echo request received!
ICMP echo reply received!
ICMP echo reply received!
ICMP echo reply received!
emNet shell (IP_SHELL_Start.c)
The emNet shell server is a task which opens TCP-port 23 (telnet) and waits for a
connection. The actual shell server is part of the stack, which keep the application
program nice and small. The shell server task can be added to any application and
should be used to retrieve status information while the target is running. To connect
to the target, use the command line: telnet <target-ip> where <target-ip>
represents the IP address of the target, which depends on the configuration and is
usually 192.168.2.252 if the DHCP client is not enabled.
emNet simple server (IP_SimpleServer.c)
Demonstrates setup of a simple server which simply sends back the target system
tick for every character received. It opens TCP-port 23 (telnet) and waits for a connection.
To connect to the target, use the command line: telnet <target-ip>
where <target-ip> represents the IP address of the target, which depends on the
configuration and is usually 192.168.2.252 if the DHCP client is not enabled.
emNet speed client (IP_SpeedClient_TCP.c)
The emNet speed client is a small application to detect the TCP send and receive
performance of emNet on your hardware.
Running the emNet speed client
To test the emNet performance, you have to perform the following steps:
- Start the Windows speed test server. The example application for the host-side is
supplied as executable and in source code in the Windows\SpeedTestServer\ directory.
To run the speed test server, simply start the executable, for example by double-clicking
it or open the supplied Visual C project and compile and start the application.
- Add IP_SpeedClient.c to your project.
- Customize the Local defines, configurable section of IP_SpeedClient.c.
Change the macro SERVER_IP_ADDR according to your configuration. For example,
if the Windows host PC running the speed test server uses the IP address
192.168.5.15, change the SERVER_IP_ADDR macro to 0xC0A8050F. If you have
changed the port which the Windows host application uses to listen, change the
macro SERVER_PORT accordingly.
- Build and download the speed client into your target. The target connects to the
server and starts the transmission.
emNet start (IP_Start.c)
Demonstrates use of the IP stack without any server or client program. To ping the
target, use the command line: ping <target-ip> where <target-ip> represents the
IP address of the target, which depends on the configuration and is usually
192.168.2.252 if the DHCP client is not enabled.
emNet UDP discover (IP_UDPDiscover.c / IP_UDPDiscover_ZeroCopy.c)
To test the emNet UDP discover example, you have to perform the following
steps:
- Start the Windows UDP discover example application. The example application for the
host-side is supplied as executable and in source code in the Windows\UDPDiscover\
directory. To run the UDP discover example, simply start the executable, for example
by double-clicking it or open the supplied Visual C project and compile and start the
application.
- Add IP_UDPDiscover.c to your project.
- Customize the Local defines, configurable section of IP_UDPDiscover.c.
By default, the example uses port 50020. If you have changed the port that the
Windows host application uses, change the macro PORT accordingly.
- Build and download the UDP discover example into your target. The target sends
an answer for every received discover packet. The related host application sends
discover packets as UDP broadcasts and waits for the feedback of the targets
which are available in the subnet.
Core functions
In this chapter, you will find a description of each emNet core function.
API functions
The table below lists the available API functions within their respective categories.
Configuration functions
IP_AddBuffers()
Description
Adds buffers to the TCP/IP stack. This is a configuration function,
typically called from IP_X_Config(). It needs to be called 2 times,
one per buffer size.
Prototype
void IP_AddBuffers(int NumBuffers,
int BytesPerBuffer);
Parameters
Parameter | Description |
NumBuffers | The number of buffers. |
BytesPerBuffer | Size of buffers in bytes. |
Additional information
The stack requires small and large buffers. We recommend to define
the size of the big buffers to 1536 to allow a full Ethernet packet
to fit. The small buffers are used to store packets which encapsulates
no or few application data like protocol management packets (TCP SYNs,
TCP ACKs, etc.). We recommend to define the size of the small buffers
to 256 bytes.
Example
IP_AddBuffers(20, 256); // 20 small buffers, each 256 bytes.
IP_AddBuffers(12, 1536); // 12 big buffers, each 1536 bytes.
IP_AddEtherInterface()
Description
Adds an Ethernet interface to the stack.
Prototype
int IP_AddEtherInterface(const IP_HW_DRIVER * pDriver);
Parameters
Parameter | Description |
pDriver | Pointer to a network interface driver structure. |
Return value
≥ 0 | Zero-based interface index of the newly created interface. |
< 0 | Error. |
Additional information
Optional configuration of the maximum number of interfaces
that can be added to the system using IP_ConfigMaxIFaces()
needs to be done before adding any interface and must not
be changed later.
While the order in which interfaces are added to the stack does
not matter to the stack itself, it might be important for the
driver to add.
Typically drivers for CPU integrated controllers are expected
to be added first. Next drivers for external controllers can
be added. As external controllers can be used as an extension
to internal controllers they do not rely on a specific interface
order.
To fill in gaps in the order of interfaces added, a dummy driver
IP_Driver_Dummy can be added. A sample of such a configuration
would be an application that relies on the following order:
- IFace0: Internal controller
- IFace1: External WiFi module
The same hardware might be produced with a different configuration
like only providing WiFi but using a cheaper CPU without internal
controller. In this case the dummy driver can be used to keep up
the same order:
- IFace0: Dummy
- IFace1: External WiFi module
For drivers and hardware that supports dual Ethernet the requirement
to add drivers for internal controllers remain. For using both internal
controllers this means:
- IFace0: First internal controller
- IFace1: Second internal controller
- IFace2: External WiFi module
When using only the second internal controller the interface index
needs to be pushed by using the dummy driver again:
- IFace0: Dummy
- IFace1: Second internal controller
- IFace2: External WiFi module
However for using only the first controller of a driver that
supports a dual unit, no dummy needs to be added before adding
additional external drivers:
- IFace0: First internal controller, second is not used.
- IFace1: External WiFi module
Additional information
Refer to Available network interface drivers for a list of available network
interface drivers.
Example
IP_AddEtherInterface(&IP_Driver_SAM7X); // Add Ethernet driver for your hardware
IP_AddVirtEtherInterface()
Description
Adds a virtual interface to the stack that uses a hardware
interface for communication.
Prototype
int IP_AddVirtEtherInterface(unsigned HWIFaceId);
Parameters
Parameter | Description |
HWIFaceId | Zero-based interface index of the hardware interface. |
Return value
≥ 0 | Zero-based interface index of the newly created interface. |
< 0 | Error. |
Additional information
Virtual interfaces can be added to allow configuration of
multiple IP addresses on the same target. One configuration
can be assigned per interface.
Optional configuration of the maximum number of interfaces
that can be added to the system using IP_ConfigMaxIFaces()
needs to be done before adding any interface and must not
be changed later.
Example
int IFaceId;
IFaceId = IP_AddEtherInterface(&IP_Driver_SAM7X); // Add HW Ethernet driver
IP_AddVirtEtherInterface(IFaceId);
IP_AddLoopbackInterface()
Description
Adds a loopback interface to the stack.
Prototype
int IP_AddLoopbackInterface(void);
Return value
≥ 0 | Zero-based interface index of the newly created interface. |
< 0 | Error. |
Additional information
The loopback interface will be added with the pre-configured
static IP addresse of 127.0.0.1/8.
Optional configuration of the maximum number of interfaces
that can be added to the system using IP_ConfigMaxIFaces()
needs to be done before adding any interface and must not
be changed later.
Example
IP_AddLoopbackInterface(); // Add an Ethernet loopback interface.
IP_AddMemory()
Description
This function is called from the application to add additional
memory to the stack. IP_AssignMemory() needs to be called first.
Prototype
void IP_AddMemory(U32 * pMem,
U32 NumBytes);
Parameters
Parameter | Description |
pMem | A pointer to the start of the memory region which should be added. |
NumBytes | Number of bytes which should be added. |
Additional information
This function can be used to add additional memory to the stack
that can then be requested by application level modules such as
Web server or FTP server directly from the stacks memory
management.
For further information about the available
memory management functions, refer to IP_Alloc and IP_Free.
Example
#define MEM_SIZE 0x8000 // Size of memory to add to the stack in bytes.
U32 _aMem[MEM_SIZE / 4]; // Memory area to add to the stack.
IP_AddMemory(_aMem, sizeof(_aMem));
IP_AllowBackPressure()
Description
Allows back pressure if the driver supports this feature.
Prototype
void IP_AllowBackPressure(char v);
Parameters
Parameter | Description |
v | 0 to disable, 1 to enable back pressure. |
IP_AssignMemory()
Description
Assigns memory to the stack.
Prototype
void IP_AssignMemory(U32 * pMem,
U32 NumBytes);
Parameters
Parameter | Description |
pMem | A pointer to the start of the memory region which should be assigned. |
NumBytes | Number of bytes which should be assigned. |
Additional information
IP_AssignMemory() should be the first function which is called
in IP_X_Config(). The amount of RAM required depends on the
configuration and the respective application purpose. The
assigned memory pool is required for the socket buffers, memory
buffers, etc.
Example
#define ALLOC_SIZE 0x8000 // Size of memory dedicated to the stack in bytes
U32 _aPool[ALLOC_SIZE / 4]; // Memory area used by the stack.
IP_AssignMemory(_aPool, sizeof(_aPool));
IP_ARP_ConfigAgeout()
Description
Configures the timeout for cached ARP entries.
The ARP timer removes entries which have not been used for a time
longer than AgeOut.
Prototype
void IP_ARP_ConfigAgeout(U32 Ageout);
Parameters
Parameter | Description |
Ageout | in Timeout in ms after which an entry is deleted from the ARP cache. Default: 30s. |
Additional information
Only effective after adding at least one interface that is
capable of using ARP (all kinds of Ethernet interfaces). Might
be overwritten if set before adding the first Ethernet interface.
IP_ARP_ConfigAgeoutNoReply()
Description
Configures the timeout for an ARP entry that has been added due
to sending an ARP request to the network that has not been answered
yet.
Prototype
void IP_ARP_ConfigAgeoutNoReply(U32 Ageout);
Parameters
Parameter | Description |
Ageout | in Timeout in ms after which an entry is deleted in case we are still waiting for an ARP response. Default: 3s. |
Additional information
Only effective after adding at least one interface that is
capable of using ARP (all kinds of Ethernet interfaces). Might
be overwritten if set before adding the first Ethernet interface.
IP_ARP_ConfigAgeoutSniff()
Description
Configures the age out value for ARP entries, which we have created
by looking up addresses of received IP packets.
The ARP timer removes entries which have not been used for a time
longer than AgeOut.
Prototype
void IP_ARP_ConfigAgeoutSniff(U32 Ageout);
Parameters
Parameter | Description |
Ageout | Timeout in ms after which an entry is deleted from the ARP cache. Default: 500ms. |
Additional information
Only effective after adding at least one interface that is
capable of using ARP (all kinds of Ethernet interfaces). Might
be overwritten if set before adding the first Ethernet interface.
IP_ARP_ConfigAllowGratuitousARP()
Description
Configures if gratuitous ARP packets from other network
members are allowed to update the ARP cache.
Prototype
void IP_ARP_ConfigAllowGratuitousARP(U8 OnOff);
Parameters
Parameter | Description |
OnOff | Default: On. 0: Off. 1: On. |
Additional information
Gratuitous ARP packets allow the network to update itself by
sending out informations about changes regarding IP and hardware
ID assignments. As this behaviour helps the network to become
more stable and helps to manage itself it is on by default.
In case you consider gratuitous ARP packets as a security risk
IP_ARP_ConfigAllowGratuitousARP() can be used to disallow this
behaviour.
IP_ARP_ConfigAnnounceStaticIP()
Description
Configures whether to announce using a static IP in the network
using gratuitous ARP packets.
Prototype
void IP_ARP_ConfigAnnounceStaticIP(unsigned IFaceId,
U8 NumAnnouncements);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
NumAnnouncements | Number of gARPs to send. |
Additional information
Configures the stack to send a number of gARP packets when a
static IP is configured and/or a link-UP for an interface with
a static IP set occurs. The gARPs are typically sent with one
second delay between them.
A race condition exists between setting a static IP and
recognizing a link-UP event that can lead to sending up to
twice as many gARPs as configured. As this is not harmful, only
occuring very rarely and would need a lot of overhead to prevent
this to happen, this should be taken into account when using
this feature.
IP_ARP_ConfigMaxPending()
Description
Configures the maximum number packets that can be queued waiting
for an ARP reply.
Prototype
void IP_ARP_ConfigMaxPending(unsigned NumPackets);
Parameters
Parameter | Description |
NumPackets | Maximum number of packets that can be pending for one ARP entry. Default: 3. |
Additional information
Only effective after adding at least one interface that is
capable of using ARP (all kinds of Ethernet interfaces). Might
be overwritten if set before adding the first Ethernet interface.
IP_ARP_ConfigMaxRetries()
Description
Configures how often an ARP request is resent before considering
the request failed.
Prototype
void IP_ARP_ConfigMaxRetries(unsigned Retries);
Parameters
Parameter | Description |
Retries | Number of retries for sending an ARP request. Default: 8. |
Additional information
Only effective after adding at least one interface that is
capable of using ARP (all kinds of Ethernet interfaces). Might
be overwritten if set before adding the first Ethernet interface.
IP_ARP_ConfigNumEntries()
Description
Configures the maximum number of possible entries in the ARP cache.
Prototype
int IP_ARP_ConfigNumEntries(unsigned MaxNumEntries);
Parameters
Parameter | Description |
MaxNumEntries | New value to use as number of entries. Default: 8. |
Return value
0 | OK, stack will try to allocate the requested number of ARP entries. |
-1 | Error, called after IP_Init(). |
Additional information
Needs to be called early in IP_X_Config(), typically before
adding interfaces.
IP_BSP_SetAPI()
Description
Sets an API to be used for BSP related abstraction like
initializing hardware and installing interrupt handlers.
Prototype
void IP_BSP_SetAPI( unsigned IFaceId,
const BSP_IP_API * pAPI);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pAPI | Pointer to function table to use. For further information regarding BSP_IP_API please refer to Structure BSP_IP_API. |
IP_ConfigDoNotAddLowLevelChecks_ARP()
Description
Tells the stack to not add low level ARP checks when initializing
the stack with IP_Init() .
Prototype
void IP_ConfigDoNotAddLowLevelChecks_ARP(void);
Additional information
Please refer to IP_ConfigDoNotAddLowLevelChecks() for more information.
IP_ConfigDoNotAddLowLevelChecks_UDP()
Description
Tells the stack to not add low level UDP checks when initializing
the stack with IP_Init() .
Prototype
void IP_ConfigDoNotAddLowLevelChecks_UDP(void);
Additional information
Please refer to IP_ConfigDoNotAddLowLevelChecks() for more information.
IP_ConfigMaxIFaces()
Description
Configures the maximum number of interfaces that can be added
to the system.
Prototype
void IP_ConfigMaxIFaces(unsigned NumIFaces);
Parameters
Parameter | Description |
NumIFaces | Number of interfaces to allocate memory for. |
Additional information
The memory for the driver list will be pre-allocated for the
maximum allowed number of interfaces. The system uses the default
value of IP_MAX_IFACES if not configured else with this function.
To save some memory the maximum number of interfaces should be
only the number of interfaces that are really required.
IP_ConfigNumLinkDownProbes()
Description
Configures the number of continuous link down probes to take
before the stack accepts the link down status.
Prototype
void IP_ConfigNumLinkDownProbes(U8 IFaceId,
U8 NumProbes);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
NumProbes | Number of continuous link down probes to take before link down is set in the stack. |
Additional information
On unstable hardware or unstable network hardware like a switch
a link jitter might occur. This jitter might lead to disconnects
on upper protocol layers like TCP that might be disconnected
once a link down is recognized. To prevent this to happen due
to link jitter, multiple samples of a link down state can be
taken before actually accepting the link down.
Typically the link status is checked once per second. Therefore
by default NumProbes = seconds after which the link state in the
stack is allowed to really get down after the first link down
reported by the driver.
This routine is only effective in case the define
IP_NUM_LINK_DOWN_PROBES is not 0.
IP_ConfigNumLinkUpProbes()
Description
Configures the number of continuous link up probes to take before
the stack accepts the link up status.
Prototype
void IP_ConfigNumLinkUpProbes(U8 IFaceId,
U8 NumProbes);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
NumProbes | Number of continuous link up probes to take before link up is set in the stack. |
Additional information
Some switches might already report a link between switch and target
but are not immediately operational resulting in packets getting
lost until fully operational.
Typically the link status is checked once per second. Therefore
by default NumProbes = seconds after which the link state in the
stack is allowed to really get up after the first link up reported
by the driver.
At the moment this only applies to Ethernet interfaces to address
this behavior with some Ethernet switches.
This routine is only effective in case the define
IP_NUM_LINK_UP_PROBES is not 0.
IP_ConfigOffCached2Uncached()
Description
Configures the offset from a cached memory area to its uncached
equivalent for uncached access.
Prototype
void IP_ConfigOffCached2Uncached(I32 Off);
Parameters
Parameter | Description |
Off | Offset from cached to uncached area. Can be negative if uncached area is before cached area. |
Additional information
This function needs to be called in case the microcontroller
is utilizing cache. Typically the data area that is used by
default is accessed cached. In this case the stack needs to
know where it can bypass the cache to write hardware related
data such as driver descriptors that will be accessed by a DMA.
IP_ConfigReportSameMacOnNet()
Description
Configures if the stack warns about receiving an Ethernet
packet from the same HW address as the interface the packet
came in.
Prototype
void IP_ConfigReportSameMacOnNet(unsigned OnOff,
void * p);
Parameters
Parameter | Description |
OnOff | = 0: Disabled. ≠ 0: Enabled, reports a warning if a duplicate MAC is seen on the network. |
p | Reserved for future extensions of this API. |
Additional information
The generated warning uses the filter type IP_MTYPE_APPLICATION .
IP_ConfigTCPSpace()
Description
Configures the size of the TCP send and receive window size.
Prototype
void IP_ConfigTCPSpace(unsigned SendSpace,
unsigned RecvSpace);
Parameters
Parameter | Description |
SendSpace | Transmit window size. |
RecvSpace | Receive window size. |
Additional information
The receive window size is the amount of unacknowledged data a
sender can send to the receiver on a particular TCP connection
before it gets an acknowledgment.
IP_DisableIPRxChecksum()
Description
Disables checksum verification of the checksum in the IP header
for incoming packets.
Prototype
void IP_DisableIPRxChecksum(U8 IFace);
Parameters
Parameter | Description |
IFace | Zero-based interface index. |
Additional information
In a typical network all data contained in a transferred frame
have already been verified by the hardware checking the transmitted
frames checksum and it is unlikely that data within this frame are
corrupted if the frame checksum was verified as being correct.
Therefore for optimization reasons the checksum calculation might
be disabled.
IP_DisableIPv4()
Description
Disables IPv4 in the stack as good as possible.
Prototype
void IP_DisableIPv4(void);
Additional information
Needs to be called before IP_Init() or during IP_X_Config() .
As IPv4 is a base component of the stack, disabling IPv4 will
be done to the best as possible.
Also disables other IPv4 related protocols like ARP and ICMPv4.
IP_CACHE_SetConfig()
Description
Configures cache related functionality that might be required by
the stack for several purposes such as cache handling in drivers.
Prototype
void IP_CACHE_SetConfig(const SEGGER_CACHE_CONFIG * pConfig,
unsigned ConfSize);
Parameters
Parameter | Description |
pConfig | Pointer to an element of SEGGER_CACHE_CONFIG . |
ConfSize | Size of the passed structure in case library and header size of the structure differs. |
Additional information
IP_CACHE_SetConfig() has to be called before IP_Init() or during
IP_X_Config().
Typically used together with IP_ConfigOffCached2Uncached()
IP_DNS_GetServer()
Description
Retrieves the first DNS server configured of the first interface.
Prototype
U32 IP_DNS_GetServer(void);
Return value
IP address of the DNS server in host-byte-order.
IP_DNS_GetServerEx()
Description
Retrieves a DNS server configured for an interface.
Prototype
void IP_DNS_GetServerEx(unsigned IFaceId,
U8 DNSIndex,
U8 * pAddr,
int * pAddrLen);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
DNSIndex | Zero-based index of the server to retrieve from interface. |
pAddr | Pointer to a U32 variable to store the IPv4 DNS address in host-byte-order. |
pAddrLen | Length of DNS addr. in bytes. Typically 4 for IPv4. |
IP_DNS_ResolveHostEx()
Description
Sends a query to the DNS server. The functions blocks
until the reply is received or for a maximum time.
Prototype
int IP_DNS_ResolveHostEx( unsigned IFaceId,
const IP_DNSSD_REQUEST * pRequest,
unsigned ms);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pRequest | Pointer to the request description. |
ms | Maximum time to wait for a reply (around 5s for all attempts). |
Return value
= 0 | Request is valid. |
= 1 | No reply. All attempts not done. |
< 0 | No reply all attempts done or request invalid. |
IP_DNS_SendDynUpdate()
Description
Build a dynamic update request. It could send the IPv4 address
and/or a request to clear all previous records.
Prototype
int IP_DNS_SendDynUpdate( unsigned IFaceId,
const char * sHost,
const char * sDomain,
U32 IPv4Addr,
int ClearPreviousRR,
U32 ms);
Parameters
Parameter | Description |
IFaceId | Index of the interface. |
sHost | Null-terminated string of the host to update. |
sDomain | Null-terminated string of the domain name. |
IPv4Addr | IPv4 address used for the update. Set to 0 to ignore. |
ClearPreviousRR | Sent an update request to remove all previous records. |
ms | Time in ms that the function is waiting for a reply. The reply might still be fulfilled after the timeout. |
Return value
= 1 | Send is pending |
= 0 | Success |
< 0 | Error |
IP_DNS_SetTSIGContext()
Description
Set the TSIG signature context with the parameters needed to
perform Secured Dynamic Updates signed with TSIG.
Prototype
void IP_DNS_SetTSIGContext
(char * KeyName,
char * KeyAlgoName,
int ( *pfSign)(U8 * pData , U16 DataLength , U8 * pDigest , int DigestMaxSize ),
int ( *pfGetTime)(U32 * pSeconds ));
Parameters
Parameter | Description |
KeyName | Pointer to the string containing the key name. Only the pointer is kept so the string must be static. |
KeyAlgoName | Pointer to the string containing the algorithm name. Only the pointer is kept so the string must be static. |
pfSign | Function pointer on the function which is called to do the crypto signature. |
pfGetTime | Function pointer on the function used to get the current time in seconds since 1th January 1970. |
IP_DNS_SetMaxTTL()
Description
Sets the maximum Time To Live (TTL) of a DNS entry in seconds.
Prototype
void IP_DNS_SetMaxTTL(U32 TTL);
Parameters
Parameter | Description |
TTL | Maximum TTL of a DNS entry in seconds. |
Additional information
The real TTL is the minimum of this value and the TTL specified
by the DNS server for the entry. The default for the maximum
TTL of a DNS entry is 600 seconds.
IP_DNS_SetServer()
Description
Sets the DNS server address of the first interface.
Prototype
void IP_DNS_SetServer(U32 DNSServerAddr);
Parameters
Parameter | Description |
DNSServerAddr | IP address of the DNS server. |
Additional information
If a DHCP server is used for configuring your target, IP_DNS_SetServer()
should not be called. The DNS server settings are normally part of the
DHCP configuration setup. The DNS server has to be defined before calling
gethostbyname() to resolve an internet address.
IP_DNS_SetServerEx()
Description
Sets the IP address of the available DNS servers for an interface.
Prototype
int IP_DNS_SetServerEx( unsigned IFaceId,
U8 DNSIndex,
const U8 * pDNSAddr,
int AddrLen);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
DNSIndex | Zero-based index of DNS servers. |
pDNSAddr | Pointer to memory location holding the DNS address to set. Typically a 4-byte IP address. |
AddrLen | Length of IP address of server. Typically 4-bytes. |
Return value
IP_MDNS_ResolveHost()
Description
Sends a query using Multicast DNS. The functions blocks
until the reply is received or for a maximum time.
Prototype
int IP_MDNS_ResolveHost( unsigned IFaceId,
const IP_DNSSD_REQUEST * pRequest,
unsigned ms);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pRequest | Pointer to the request description. |
ms | Maximum time [ms] to wait for a reply (around 5s for all attempts). |
Return value
= 0 | Request is valid. |
= 1 | No reply. All attempts not done. |
< 0 | No reply all attempts done or request invalid. |
Additional information
When the requested type is A (IPv4 address) or AAAA (IPv6 address),
the request is sent for both Apple mDNS and Microsoft LLMNR.
Other DNS-SD request are sent only on mDNS.
IP_MDNS_ResolveHostSingleIP()
Description
Sends a query using Multicast DNS. The functions blocks
until the reply is received or for a maximum time. Only the
first reply is returned, all others will be discarded.
Prototype
int IP_MDNS_ResolveHostSingleIP( unsigned IFaceId,
void * pIP,
const char * sHost,
U16 Type,
unsigned ms);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pIP | Pointer where to store the result. Make sure that enough space is available to store a 4-bytes IPv4 (in host endianness) or 16-bytes IPv6 as requested. |
sHost | Hostname to resolve. |
Type | Type of desired result: IP_DNS_SERVER_TYPE_A IP_DNS_SERVER_TYPE_AAAA |
ms | Maximum time [ms] to wait for a reply (around 5s for all attempts). |
Return value
= 0 | Request is valid. |
= 1 | No reply. All attempts not done. |
< 0 | No reply all attempts done or request invalid. |
Additional information
The requested is sent for both Apple mDNS and Microsoft LLMNR.
IP_EnableIPRxChecksum()
Description
Enables the IP Rx checksum calculation in the IP header for
incoming packets. This is the default behaviour of the stack.
Prototype
void IP_EnableIPRxChecksum(U8 IFace);
Parameters
Parameter | Description |
IFace | Zero-based interface index. |
Additional information
In a typical network all data contained in a transferred frame
have already been verified by the hardware checking the transmitted
frames checksum and it is unlikely that data within this frame are
corrupted if the frame checksum was verified as being correct.
Therefore for optimization reasons the checksum calculation might
be disabled.
IP_GetMaxAvailPacketSize()
Description
Asks the stack for the maximum available free packet size that
can then be allocated. (e.g. with a zero-copy alloc).
Prototype
U32 IP_GetMaxAvailPacketSize(int IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index for which the packet shall be allocated. |
Return value
No free packet is available at all: 0.
Other : Max. packet size that is free.
Additional information
The packet size returned does not contain any protocol headers
other than the transport layer (for Ethernet typically 14
bytes/for PPP typically 6 bytes). Other protocol header such as
IPvX and UDPvX need to be subtracted from the value returned.
IP_GetMemPoolInfo()
Description
Collects data about a memory pool such as its size and free
bytes.
Prototype
int IP_GetMemPoolInfo(void * pPoolAddr,
IP_MEM_POOL_INFO * pInfo);
Parameters
Parameter | Description |
pPoolAddr | Memory pool to retrieve information for. NULL for the main memory pool added with IP_AssignMemory() . |
pInfo | Pointer to structure of IP_MEM_POOL_INFO where to store information about the selected pool. |
Return value
= 0 | O.K. |
≠ 0 | Error, memory pool not found ? |
IP_GetMTU()
Description
Retrieves the configured TCP MTU size for an interface.
Prototype
U32 IP_GetMTU(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
MTU configured for the interface, either set as default when
adding the interface or set via IP_SetMTU().
IP_GetPrimaryIFace()
Description
Retrieves the currently set primary interface index.
Prototype
int IP_GetPrimaryIFace(void);
Return value
Currently set primary interface index. Default is 0.
IP_ICMP_Add()
Description
Adds ICMP Protocol function to the stack.
Prototype
void IP_ICMP_Add(void);
Additional information
IP_ICMP_Add() adds ICMP to the stack. The function should be called
during the initialization of the stack. In the supplied sample
configuration files IP_ICMP_Add() is called from IP_X_Config().
If you remove the call of IP_ICMP_Add(), the ICMP code will not
be available in your application.
IP_ICMP_DisableRxChecksum()
Description
Disables the ICMP Rx checksum calculation. The ICMP checksum
computation can be disabled to improve the performance of the
stack.
Prototype
void IP_ICMP_DisableRxChecksum(U8 IFace);
Parameters
Parameter | Description |
IFace | Interface index. |
Additional information
In a typical network all data contained in a transferred frame
have already been verified by the hardware by checking the
trasmitted frames checksum. It is unlikely that data within
this frame is corrupted if the frame checksum was verified
as being correct. Therefore for optimization reasons the checksum
calculation might be disabled.
IP_ICMP_EnableRxChecksum()
Description
Enables the ICMP Rx checksum calculation. This is the default
behaviour of the stack. The ICMP checksum computation can be
disabled to improve the performance of the stack.
Prototype
void IP_ICMP_EnableRxChecksum(U8 IFace);
Parameters
Parameter | Description |
IFace | Zero-based interface index. |
Additional information
In a typical network all data contained in a transferred frame
have already been verified by the hardware by checking the
trasmitted frames checksum. It is unlikely that data within
this frame is corrupted if the frame checksum was verified
as being correct. Therefore for optimization reasons the checksum
calculation might be disabled.
IP_IGMP_Add()
Description
Adds the IGMP protocol to interface #0.
Prototype
int IP_IGMP_Add(void);
Return value
Additional information
The IGMP (Internet Group Management Protocol) allows a host to
JOIN (or subscribe) to a multicast group and receive messages
for it. If the switch supports “IGMP snooping” it can then
forward multicast packets only to hosts that are subscribed to
a group while saving bandwidth on other ports where no host is
subscribed to that group. A typical usage example is any form
of broadcasting like IPTV where a video feed is sent to a
multicast group but switches/routers will only deliver it to
the hosts actually interested in receiving the content.
IP_IGMP_AddEx()
Description
Adds the IGMP protocol to an interface.
Prototype
int IP_IGMP_AddEx(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
Additional information
The IGMP (Internet Group Management Protocol) allows a host to
JOIN (or subscribe) to a multicast group and receive messages
for it. If the switch supports “IGMP snooping” it can then
forward multicast packets only to hosts that are subscribed to
a group while saving bandwidth on other ports where no host is
subscribed to that group. A typical usage example is any form
of broadcasting like IPTV where a video feed is sent to a
multicast group but switches/routers will only deliver it to
the hosts actually interested in receiving the content.
IP_IGMP_ConfigV2AlwaysReport()
Description
Configures if upon every IGMPv2 QUERY a REPORT shall be sent back.
Prototype
void IP_IGMP_ConfigV2AlwaysReport(unsigned IFaceId,
U8 OnOff);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
OnOff | 0: Default. Do not send a REPORT if another host has already sent a REPORT for a QUERY. 1: Send a REPORT even if a REPORT from another host has been seen. |
Additional information
According to RFC 2236 duplicate REPORTs for the same group shall
be avoided. With IGMP snooping on the switch/router this should
never happen as REPORTs should not be forwarded anyhow.
However there are some faulty switches/routers that forward
REPORTs and in such a case we have to respond with a REPORT even
if it seems like IGMP snooping is not in use and duplicates should
be avoided. Otherwise we might loose our group membership with
IGMP snooping due to this faulty implementation on the switch/router.
This behavior can be configured per interface as it might be the
case that on a multi interface device one interface is part of a
network behaving entirely correct and the other interface being
part of a network with faulty switches/routers.
IP_IGMP_JoinGroup()
Description
Joins an IGMP group.
Prototype
int IP_IGMP_JoinGroup(unsigned IFaceId,
IP_ADDR GroupIP);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
GroupIP | IGMP group IP to join in host endianness. |
Return value
= 0 | O.K. |
< 0 | Error, no memory ? |
Additional information
Multicast is a technique to distribute a packet to multiple receivers
in a network by sending only one packet. Handling of who will receive
the packet is not done by the sender but instead is done by network
hardware such as routers or switches that will duplicate the
packet and send it to everyone that participates the chosen group.
After sending an initial JOIN REPORT the target does not actively
participate by sending more unsolicitied messages. The network
hardware periodically sends a membership QUERY either to all hosts
or specific groups to check that these groups are still in use and
if we still want to be part of it.
The “all-systems”/“all-hosts” group 224.0.0.1 is automatically
“joined” by opening receive filters for it. This group is a special
case as it is a receive only group. In older versions this group
had to be joined manually. When calling JOIN for this group it is
now ignored and returns O.K.
IP_IGMP_JoinGroup_AutoRejoin()
Description
Joins an IGMP group and rejoins when the interface link state
changes. Executed on link DOWN to UP or different in speed/duplex.
Prototype
int IP_IGMP_JoinGroup_AutoRejoin(unsigned IFaceId,
IP_ADDR GroupIP);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
GroupIP | IGMP group IP to join in host endianness. |
Return value
= 0 | O.K. |
< 0 | Error, no memory ? |
Additional information
Multicast is a technique to distribute a packet to multiple receivers
in a network by sending only one packet. Handling of who will receive
the packet is not done by the sender but instead is done by network
hardware such as routers or switches that will duplicate the
packet and send it to everyone that participates the chosen group.
After sending an initial JOIN REPORT the target does not actively
participate by sending more unsolicitied messages. The network
hardware periodically sends a membership QUERY either to all hosts
or specific groups to check that these groups are still in use and
if we still want to be part of it.
The “all-systems”/“all-hosts” group 224.0.0.1 is automatically
“joined” by opening receive filters for it. This group is a special
case as it is a receive only group. In older versions this group
had to be joined manually. When calling JOIN for this group it is
now ignored and returns O.K.
Rejoining groups sends a mesaage immediately after the link change
is reported by the system followed by a randomly delayed second
message in case the first one got lost (same as for a regular join).
To avoid the first message getting lost due to the link change being
reported but not immediately being stable/usable, please configure
a delay using IP_ConfigNumLinkUpProbes() .
Example
/* Excerpt from the UPnP code */
#define SSDP_IP 0xEFFFFFFA // Simple service discovery prot. IP, 239.255.255.250
IP_IGMP_Add(); // IGMP is needed for UPnP
//
// Join the IGMP group for SSDP .
//
IP_IGMP_JoinGroup_AutoRejoin(0, SSDP_IP);
IP_IGMP_LeaveGroup()
Description
Leaves an IGMP group.
Prototype
void IP_IGMP_LeaveGroup(unsigned IFaceId,
IP_ADDR GroupIP);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
GroupIP | IGMP group IP to leave in host endianness. |
Example
/* Excerpt from the UPnP code */
#define SSDP_IP 0xEFFFFFFA // Simple service discovery prot. IP, 239.255.255.250
//
// Leave the IGMP group for SSDP .
//
IP_IGMP_LeaveGroup(0, SSDP_IP);
IP_RAW_Add()
Description
Adds RAW socket function to stack
Prototype
void IP_RAW_Add(void);
Additional information
IP_RAW_Add() adds RAW socket support to the stack. The function
should be called during the initialization of the stack.
IP_SetAddrMask()
Description
Sets the IP address and subnet mask of an interface.
Operates on interface 0.
Prototype
void IP_SetAddrMask(U32 Addr,
U32 Mask);
Parameters
Parameter | Description |
Addr | IP address in host endianness. |
Mask | Subnet mask in host endianness. |
Additional information
The address mask should only be set if no DHCP server is used to
obtain IP address, subnet mask and default gateway.
Refer to chapter DHCP client for
detailed information about the usage of the emNet DHCP client.
Example
IP_SetAddrMask(0xC0A80505, 0xFFFF0000); // IP: 192.168.5.5
// Subnet mask: 255.255.0.0
IP_SetAddrMaskEx()
Description
Sets the IP address and subnet mask of an interface.
Prototype
void IP_SetAddrMaskEx(U8 IFace,
U32 Addr,
U32 Mask);
Parameters
Parameter | Description |
IFace | Interface number. |
Addr | IP address in host endianness. |
Mask | Subnet mask in host endianness. |
Additional information
The address mask should only be set if no DHCP server is used to
obtain IP address, subnet mask and default gateway.
Refer to chapter DHCP client for
detailed information about the usage of the emNet DHCP client.
Example
IP_SetAddrMaskEx(0, 0xC0A80505, 0xFFFF0000); // IP: 192.168.5.5
// Subnet mask: 255.255.0.0
IP_SetGWAddr()
Description
Sets the default gateway address of the selected interface.
Prototype
void IP_SetGWAddr(U8 IFace,
U32 GWAddr);
Parameters
Parameter | Description |
IFace | Zero-based interface index. |
GWAddr | 4-byte gateway address in host endianness. |
Additional information
The address mask should only be set if no DHCP server is used to
obtain IP address, subnet mask and default gateway.
Refer to chapter DHCP client for
detailed information about the usage of the emNet DHCP client.
Example
IP_SetGWAddr(0, 0xC0A80101); // Interface: 0
// IPv4 address of the GW: 192.168.1.1
IP_SetHWAddr()
Description
Sets the Media Access Control address (MAC) of the interface 0.
Prototype
void IP_SetHWAddr(const U8 * pHWAddr);
Parameters
Parameter | Description |
pHWAddr | 6 bytes MAC address. |
Additional information
The MAC address needs to be unique for production units.
Example
IP_SetHWAddr("\x00\x22\x33\x44\x55\x66");
IP_SetHWAddrEx()
Description
Sets the Media Access Control address (MAC) of the selected interface.
Prototype
void IP_SetHWAddrEx( unsigned IFaceId,
const U8 * pHWAddr,
unsigned NumBytes);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pHWAddr | Pointer to the MAC address. |
NumBytes | Number of bytes of the MAC address (typically 6). |
Additional information
The MAC address needs to be unique for production units.
Example
IP_SetHWAddrEx(0, "\x00\x22\x33\x44\x55\x66", 6);
IP_SetMTU()
Description
Allows to set the maximum transmission unit (MTU) of an interface.
Prototype
void IP_SetMTU(unsigned IFaceId,
U32 Mtu);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Mtu | Size of maximum transmission unit in bytes. |
Additional information
The Maximum Transmission Unit is the MTU from an IP standpoint,
so the size of the IP-packet without local net header. A typical
value for ethernet is 1500, since the maximum size of an Ethernet
packet is 1518 bytes. Since Ethernet uses 12 bytes for MAC
addresses, 2 bytes for type and 4 bytes for CRC, 1500 bytes
“payload” remain. The minimum size of the MTU is 576 according
to RFC 879. Refer to [RFC 879] - TCP - The TCP Maximum Segment
Size and Related Topics for more information about the MTU.
All TCP connections are guaranteed to work with any MTU in the
permitted range of 576 - 1500 bytes. The advantage of a smaller
MTU is that smaller packets are sent in TCP communication,
resulting in reduced RAM requirements, especially if the window
size is also reduced. The disadvantage is a loss of communication
speed.
When being called from IP_X_Config() during the configuration phase,
the MTU can only be reduced to avoid configuring an MTU bigger than
what the interface is capable of. The initial MTU for an interface
is set by the stack automatically when an interface is added. After
the configuration phase the MTU can freely be set and the application
is responsible to make sure to read the initially set MTU using
IP_GetMTU() and to not configure an MTU higher than that.
Note:
In the supplied emNet example configurations, the MTU is used
to configure the maximum packet size that the stack can handle.
This means that if you lower the MTU (for example, set it to 576 bytes),
the stack can only handle packets
up to that size. If you plan to use larger UDP packets, change
the configuration according to your requirements. For further
information about the configuration of
the stack, refer to Configuring emNet.
IP_SetRandCallback()
Description
Sets a callback that can provide random data.
Prototype
void IP_SetRandCallback(void ( *pfGetRand)(U8 * pBuffer , unsigned NumBytes ));
Parameters
Parameter | Description |
pfGetRand | Callback function that provides randomized data. |
Example
/********************************************************************
*
* _cbRand()
*
* Function description
* Provides a source of randomness.
*
* Parameters
* pBuffer : Pointer where to store the random data.
* NumBytes: Number of random bytes to store.
*/
static void _cbRand(U8* pBuffer, unsigned NumBytes) {
//
// Generate NumBytes of random data and store it at pBuffer.
//
}
IP_SetRandCallback(_cbRand);
IP_SetOnIFaceSelectCallback()
Description
Sets a callback that gets notified about an internal interface
selection by the stack and allows to override it.
Prototype
void IP_SetOnIFaceSelectCallback(IP_ON_IFACE_SELECT_FUNC * pf);
Parameters
Parameter | Description |
pf | Callback to execute when an interface is selected. Use NULL to remove the callback. |
Example
/*********************************************************************
*
* _OnIFaceSelect()
*
* Function description
* Callback executed for an internal interface selection. The
* proposed interface selected internally can be overridden.
*
* Parameters
* pFamily: Protocol family (at the moment only PF_INET or PF_INET6).
* pInfo : Further information of type IP_ON_IFACE_SELECT_INFO
* about the interface selection parameters as well as
* the proposed interface, selected internally based upon
* these parameters.
*
* Return value
* == -1: No suitable interface.
* >= 0: Interface index to use.
*/
static int _OnIFaceSelect(int PFamily, IP_ON_IFACE_SELECT_INFO* pInfo) {
//
// Example: IPv4 firewall out-filter.
// Blocking communication with a specific foreign host.
// This does not necessarily block communicaton if the
// initial transfer was started by the peer as in this
// case we might get our interface assigned based on the
// interface it came in on. This only causes us to not
// find a suitable interface if we do the initial
// communication like a connect() to a host.
//
if (PFamily == PF_INET) { // We define rules for IPv4 only.
if (pInfo->pFAddrV4 != NULL) {
if (htonl(*pInfo->pFAddrV4) == IP_BYTES2ADDR(192, 168, 2, 3)) {
return -1; // No interface.
}
}
}
//
// Do not care about other cases and accept the proposed
// interface as selected by the stack internally.
//
return pInfo->IFaceId;
}
/*********************************************************************
*
* MainTask()
*
* Function description
* Main task executed by the RTOS to create further resources and
* running the main application.
*/
void MainTask(void) {
IP_Init();
//
// Set callback that gets notified when the stack has internally
// selected an interface.
//
IP_SetOnIFaceSelectCallback(_OnIFaceSelect);
...
}
IP_SetPrimaryIFace()
Description
Sets the primary interface index.
Prototype
int IP_SetPrimaryIFace(int IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index to use as primary interface of the system. Default is 0. |
Return value
Additional information
The primary interface is given priority for several purposes
in multi interface setups. One example would be to use a
preferred interface when looking for a DNS server to use in
case multiple interface have set DNS servers.
IP_SetSupportedDuplexModes()
Description
Sets the supported duplex/speed of the device to be advertised
during Auto-Negotiation.
Prototype
int IP_SetSupportedDuplexModes(unsigned IFaceId,
unsigned DuplexMode);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
DuplexMode | Bitwise-OR combination of the following supported modes: IP_PHY_MODE_10_HALF IP_PHY_MODE_10_FULL IP_PHY_MODE_100_HALF IP_PHY_MODE_100_FULL IP_PHY_MODE_1000_HALF IP_PHY_MODE_1000_FULL |
Return value
= 0 | Success |
< 0 | Not supported. |
Additional information
Combining one of the supported duplex/speed modes with
IP_PHY_MODE_NO_AUTONEG disables the Auto-Negotiation
advertisement and configures a fixed duplex/speed.
IP_SetTTL()
Description
Sets the default value for the Time-To-Live IP header field.
Prototype
void IP_SetTTL(int v);
Parameters
Parameter | Description |
v | Time-To-Live value. |
Additional information
By default, the TTL (Time-To-Live) is 64. The TTL field length
of the IP is 8 bits. The maximum value of the TTL field is
therefore 255.
IP_SetGlobalMcTTL()
Description
Sets the default value for the Time-To-Live IP header field
for global multicast packets.
Prototype
void IP_SetGlobalMcTTL(int v);
Parameters
Parameter | Description |
v | Time-To-Live value. |
Additional information
By default, the TTL (Time-To-Live) is 64. The TTL field length
of the IP is 8 bits. The maximum value of the TTL field is
therefore 255.
Global multicast packets are packets with destinations outside the
following networks:
IP_SetLocalMcTTL()
Description
Sets the default value for the Time-To-Live IP header field
for local multicast packets.
Prototype
void IP_SetLocalMcTTL(int v);
Parameters
Parameter | Description |
v | Time-To-Live value. |
Additional information
By default, the TTL (Time-To-Live) is 1. The TTL field length
of the IP is 8 bits. The maximum value of the TTL field is
therefore 255.
Local multicast packets are packets with destinations inside the
following networks:
IP_SetUseRxTask()
Description
Sets the internal flag for using the IP_RxTask() manually.
Prototype
void IP_SetUseRxTask(void);
Additional information
The IP_RxTask flag has to be set before enabling the interrupt
as otherwise it would still be possible for an Rx interrupt to
fire before the IP_RxTask flag has been set on first execution
of said task. Processing the first interrupt(s) without IP_RxTask
however should not hurt and a device should not be offended by
interrupt delay during or directly after init when the task
scheduler gets started.
IP_SOCKET_ConfigSelectMultiplicator()
Description
Configures the multiplicator for the timeout parameter of select().
Default multiplicator is 1.
Prototype
void IP_SOCKET_ConfigSelectMultiplicator(U32 v);
Parameters
Parameter | Description |
v | Multiplicator to be used. |
Additional information
By default the select() timeout is given in ticks of 1 ms. The
UNIX standard takes the timeout in a structue including seconds.
The multiplicator can be configured but as it is more common for
an embedded system we will stick to units of 1 tick (typically 1
ms) for the default.
IP_SOCKET_SetDefaultOptions()
Description
Sets the socket options enabled by default.
Prototype
void IP_SOCKET_SetDefaultOptions(U16 v);
Parameters
Parameter | Description |
v | Socket options which should be enabled. |
Additional information
By default, keepalive (SO_KEEPALIVE ) socket option is enabled.
Refer to setsockopt() for a list of supported socket options.
IP_SOCKET_SetLimit()
Description
Sets the maximum number of allowed sockets.
Prototype
void IP_SOCKET_SetLimit(unsigned Limit);
Parameters
Parameter | Description |
Limit | Sets a limit on number of sockets which can be created. The default is 0 which means that no limit is set. |
IP_SYSVIEW_Init()
Description
Initializes the profile instrumentation of the stack and
SystemView as profiling implementation.
Prototype
void IP_SYSVIEW_Init(void);
Additional information
For further information regarding the SysView profiling implementation in emNet
please refer to the chapter Profiling with SystemView.
IP_TCP_Add()
Description
Adds TCP Protocol function to the stack.
Prototype
void IP_TCP_Add(void);
Additional information
IP_TCP_Add() adds TCP to the stack. The function should be called
during the initialization of the stack. In the supplied sample
configuration files IP_TCP_Add() is called from IP_X_Config().
If you remove the call of IP_TCP_Add(), the TCP code will not
be available in your application.
IP_TCP_DisableRxChecksum()
Description
Disables the TCP Rx checksum calculation. The TCP checksum
computation can be disabled to improve the performance of the
stack.
Prototype
void IP_TCP_DisableRxChecksum(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Additional information
In a typical network all data contained in a transferred frame
has already been verified by the hardware checking the trasmitted
frames checksum and it is unlikely that data within this frame is
corrupted if the frame checksum was verified as being correct.
Therefore for optimization reasons the checksum calculation might
be disabled.
This only affects the checksum calculation in software. In case
the hardware supports TCP Rx checksum calculation it might still
discard a received frame in which the TCP checksum is invalid.
When supported by hardware, the software calculation is disabled
by default and enabled by default if not supported in hardware.
IP_TCP_EnableRxChecksum()
Description
Enables checksum verification of the checksum in the TCP header
for incoming packets.
Prototype
void IP_TCP_EnableRxChecksum(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Additional information
In a typical network all data contained in a transferred frame
has already been verified by the hardware checking the trasmitted
frames checksum and it is unlikely that data within this frame is
corrupted if the frame checksum was verified as being correct.
Therefore for optimization reasons the checksum calculation might
be disabled.
This only affects the checksum calculation in software. In case
the hardware supports TCP Rx checksum calculation it might still
discard a received frame in which the TCP checksum is invalid.
When supported by hardware, the software calculation is disabled
by default and enabled by default if not supported in hardware.
IP_TCP_Set2MSLDelay()
Description
Sets the maximum segment lifetime (MSL).
Prototype
void IP_TCP_Set2MSLDelay(unsigned v);
Parameters
Parameter | Description |
v | Maximum segment lifetime. The default is 2 seconds. |
Additional information
The maximum segment lifetime is the amount of time any segment
can exist in the network before being discarded. This time limit
is constricted. When TCP performs an active close the connection
must stay in TIME_WAIT (2MSL) state for twice the MSL after
sending the final ACK.
Refer to [RFC 793] - TCP - Transmission Control Protocol for
more information about TCP states.
IP_TCP_SetConnKeepaliveOpt()
Description
Sets the keepalive options.
Prototype
void IP_TCP_SetConnKeepaliveOpt(U32 Init,
U32 Idle,
U32 Period,
U32 MaxRep);
Parameters
Parameter | Description |
Init | Maximum time [ms] after TCP-connection open (response to SYN) in ms in case no data transfer takes place. The default is IP_TCP_KEEPALIVE_INIT . |
Idle | Time [ms] of TCP-inactivity before first keepalive probe is sent. The default is IP_TCP_KEEPALIVE_IDLE . |
Period | Time [ms] of TCP-inactivity between keepalive probes. The default is IP_TCP_KEEPALIVE_PERIOD . |
MaxRep | Number of keepalive probes before we give up and close the connection. The default is IP_TCP_KEEPALIVE_MAX_REPS repetitions. |
Additional information
Keepalives are not part of the TCP specification, since they can
cause good connections to be dropped during transient failures.
For example, if the keepalive probes are sent during the time
that an intermediate router has crashed and is rebooting, TCP
will think that the client’s host has crashed, which is not what
has happened. Nevertheless, the keepalive feature is very useful
for embedded server applications that might tie up resources on
behalf of a client, and want to know if the client host crashes.
Keepalives will be sent if the TCP connection sits idle for Idle
ms and will then start sending a keepalive each Period ms for
MaxRep. Each time a keepalive is ACked by the peer, the next
keepalive will again be sent after Idle ms.
By design keepalives are retransmissions of already sent and
ACKed data. Depending on the used IP stack a retransmit is
typically one byte sent with the current sequence number - 1,
so that the peer will discard the data itself as it has already
been received and ACKed but will send an ACK back to notify the
sender that it has been received and to not send it again.
Other stacks might even send a TCP packet with zero data and the
current sequence number, forcing the other side to practically
answer back to a duplicate ACK. Keepalives might not be displayed
correctly by tools like Wireshark. A zero length keepalive is
typically seen like a duplicate ACK while a one byte keepalive
might actually be a one byte retransmit if sending chunks of one
byte and one of them has not been ACKed.
The Init value configured is the connect timeout that will be
used for connect().
IP_TCP_SetRetransDelayRange()
Description
Sets retransmission delay range.
Prototype
void IP_TCP_SetRetransDelayRange(unsigned RetransDelayMin,
unsigned RetransDelayMax);
Parameters
Parameter | Description |
RetransDelayMin | Minimum time [ms] before first retransmission. The default is IP_TCP_RETRANS_MIN . Please note that setting a minimum value below the minimum value of the peer is not recommended and might break delayed ACKs. The default for many stacks is ~200ms, therefore the minimum should be set slightly higher. |
RetransDelayMax | Maximum time [ms] to wait before a retransmission. The default is IP_TCP_RETRANS_MAX . |
Additional information
TCP is a reliable transport layer. One of the ways it provides
reliability is for each end to acknowledge the data it receives
from the communication partner. But data segments and
acknowledgments can get lost. TCP handles this by setting a
timeout when it sends data, and if the data is not acknowledged
when the timeout expires, it retransmits the data. The timeout
and retransmission is the measurement of the round-trip time (RTT)
experienced on a given connection. The RTT can change over time,
as routes might change and as network traffic changes, and TCP
should track these changes and modify its timeout accordingly.
IP_TCP_SetRetransDelayRange() should be called if the default
limits are not sufficient for your application.
IP_UDP_Add()
Description
Adds UDP Protocol support to the stack.
Prototype
void IP_UDP_Add(void);
Additional information
IP_UDP_Add() adds UDP to the stack. The function should be called
during the initialization of the stack. In the supplied sample
configuration files IP_UDP_Add() is called from IP_X_Config().
If you remove the call of IP_UDP_Add(), the UDP code will not
be available in your application.
IP_UDP_AddEchoServer()
Description
Adds a simple echo server for UDP packets that can be used for
UDP pings and other tests.
Prototype
IP_UDP_CONNECTION *IP_UDP_AddEchoServer(U16 LPort);
Parameters
Parameter | Description |
LPort | Local port on which to listen for incoming packets. |
Return value
≠ NULL | O.K. Pointer to the connection. |
= NULL | Error. |
Additional information
The echo server will simply send back the incoming packet to
the sender.
IP_UDP_DisableRxChecksum()
Description
Disables checksum verification of the checksum in the UDP header
for incoming packets.
Prototype
void IP_UDP_DisableRxChecksum(void);
Additional information
In a typical network all data contained in a transfered frame
have already been verified by the hardware checking the
trasmitted frames checksum and it is unlikely that data within
this frame are corrupted if the frame checksum was verified
as being correct. Therefore for optimization reasons the
checksum calculation might be disabled.
IP_UDP_EnableRxChecksum()
Description
Enables checksum verification of the checksum in the TCP header
for incoming packets.
Prototype
void IP_UDP_EnableRxChecksum(void);
Additional information
In a typical network all data contained in a transfered frame
have already been verified by the hardware checking the
trasmitted frames checksum and it is unlikely that data within
this frame are corrupted if the frame checksum was verified
as being correct. Therefore for optimization reasons the
checksum calculation might be disabled.
Configuration functions (IP fragmentation)
IP_FRAGMENT_ConfigRx()
Description
Modifies the default settings for IPv4 fragmentation.
Prototype
void IP_FRAGMENT_ConfigRx(U16 MaxFragments,
U32 Timeout,
U8 KeepOOO);
Parameters
Parameter | Description |
MaxFragments | Maximum number of fragments which are allowed for a fragmented packet. Currently 0..255 fragments are allowed. |
Timeout | Timeout [ms] before discarding fragment queues. |
KeepOOO | Keep Out Of Order fragments. 0: Discard (default). 1: Keep. |
IP_FRAGMENT_Enable()
Description
Initializes the required variables and adds a timer to the stack
to handle outdated fragment queues.
Prototype
void IP_FRAGMENT_Enable(void);
IP_IPV6_FRAGMENT_ConfigRx()
Description
Modifies the default settings for IPv6 fragmentation.
Prototype
void IP_IPV6_FRAGMENT_ConfigRx(U16 MaxFragments,
U32 Timeout,
U8 KeepOOO);
Parameters
Parameter | Description |
MaxFragments | Maximum number of fragments which are allowed for a fragmented packet. |
Timeout | Timeout [ms] before discarding fragment queues. |
KeepOOO | Keep Out Of Order fragments. 0: Discard (default). 1: Keep. |
IP_IPV6_FRAGMENT_Enable()
Description
Initializes the required variables and adds a timer to the stack
to handle outdated fragment queues.
Prototype
void IP_IPV6_FRAGMENT_Enable(void);
Management functions
IP_DeInit()
Description
Deinitializes the TCP/IP stack.
Prototype
void IP_DeInit(void);
Additional information
IP_DeInit() de-initializes the IP stack. This function should be
the very last function of the stack called by the application
and is typically not needed if you do not need to shutdown your
whole application for a special reason.
De-initialization should be done in the exact reversed order of
initialization. This means terminating any created task that uses
the IP API, terminating the IP_RxTask (if used), terminating the
IP_Task and finally calling IP_DeInit() to close down the stack.
The whole de-initialization should be done with Ethernet interrupts
disabled and task switching disabled to prevent the de-initialization
being interrupted by an Ethernet event.
De-init has to be supported by the driver as well. If your driver
does not yet support IP_DeInit() you will end up in IP_Panic().
Please contact our support address and ask for IP_DeInit() support
to be added to your driver.
Example
#include "IP.h"
void main(void) {
IP_Init();
//
// Create IP tasks and use the stack
//
...
//
// Disable Ethernet interrupt
//
OS_EnterRegion(); // Prevent task switching
//
// Terminate all application tasks that make use of the IP API
//
//
// Terminate IP_RxTask first (if used) and IP_Task
//
IP_DeInit();
OS_LeaveRegion(); // Allow task switching
}
IP_Init()
Description
Initializes the TCP/IP stack.
Prototype
int IP_Init(void);
Return value
Additional information
IP_Init() initializes the IP stack and creates resources required
for an OS integration. This function must be called before any
other function of the stack is called.
Does not detect memory allocation problems during IP_Init() at
this time. A sufficient memory pool size should be checked by
running an IP_DEBUG enabled build with IP_PANIC() checks first
as this will help to discover other problems with the setup as well.
Example
#include "IP.h"
void main(void) {
IP_Init();
/*
* Use the stack
*/
}
IP_Task()
Description
Main task for handling the stack.
Prototype
void IP_Task(void);
Additional information
Implementing this task is the simplest way to include the stack
into your project. An example for typical task stack usage is
defined by TASK_STACK_SIZE_IP_TASK .
For best performance this task should be given a task priority
higher than any other IP stack related application task. It
however must not have a higher or the same priority than the
IP_RxTask() or its API alternatives IP_RXTASK_Init(),
IP_RXTASK_Exec() and IP_RXTASK_WaitForEvent() .
For more information regarding task priorities, please refer to
Tasks and interrupt usage .
After startup, this routine settles into a loop, handling
received packets and executing other jobs. This loop sleeps
until signaled by a driver or a stack internal job being ready
for excution.
In case of de-initializing the stack with IP_DeInit(), it is
possible to leave the loop gracefully by using IP_ShutDown() .
Example
#include <stdio.h>
#include "RTOS.h"
#include "BSP.h"
#include "IP.h"
#include "IP_Int.h"
static OS_STACKPTR int _Stack0[512]; // Task stacks
static OS_TASK _TCB0; // Task-control-blocks
static OS_STACKPTR int _IPStack[1024]; // Task stacks
static OS_TASK _IPTCB; // Task-control-blocks
/*********************************************************************
*
* MainTask
*/
void MainTask(void);
void MainTask(void) {
printf("****************************************\nProgram start\n");
IP_Init();
OS_SetPriority(OS_GetTaskID(), 255); // This task has highest prio!
OS_CREATETASK(&_IPTCB, "IP_Task", IP_Task, 150, _IPStack);
while (1) {
BSP_ToggleLED(1);
OS_Delay (200);
}
}
/**********************************************************
*
* main
*/
void main(void) {
BSP_Init();
BSP_SetLED(0);
OS_IncDI(); /* Initially disable interrupts */
OS_InitKern(); /* initialize OS */
OS_InitHW(); /* initialize Hardware for OS */
OS_CREATETASK(&_TCB0, "MainTask", MainTask, 100, _Stack0);
OS_Start();
}
IP_Exec()
Description
Processes received packets and handles timers and other jobs.
Prototype
U32 IP_Exec(void);
Return value
Value of the next timeout [ms].
Additional information
This function is normally called internally from an endless loop
in IP_Task() . If no dedicated task running IP_Task() is
implemented in your project e.g. when using a superloop,
IP_Exec() should be called regularly.
When being called from a task context, the same task priority
rules as for IP_Task() apply.
IP_TASK_Init()
Description
Initializes the main IP task context when not using IP_Task() .
Prototype
void IP_TASK_Init(void);
Additional information
The IP_TASK_* API is an alternative to using the IP_Task() .
It allows finer control over the internal steps done in
IP_Task() . This can be utilized for example to feed a
watchdog from the same task periodically.
Note
This routine is not intended to be used when using IP_Task()
or IP_Exec() instead. It needs to be called before
IP_TASK_Exec() or IP_TASK_WaitForEvent() is used.
For best performance the IP_TASK_* API should be called with
a task priority higher than any other IP stack related
application task.
Example
/*********************************************************************
*
* _IP_Task()
*
* Function description
* Application specific implementation of IP_Task() .
*
* Additional information
* Allows to insert your own code like feeding a watchdog
* in-between the separate steps that would be executed by the
* original task API provided by the stack.
*/
static void _IP_Task(void) {
unsigned Timeout;
//
// Initialize.
//
IP_TASK_Init();
//
// Task-loop.
//
for (;;) {
//
// Process received packets and execute pending jobs.
// The timeout returned is when the next timer-event is due.
//
Timeout = IP_TASK_Exec();
//
// Sleep until the next timer-event is due or an event like
// new packets have been received is signaled.
//
IP_TASK_WaitForEvent(Timeout);
}
}
IP_TASK_Exec()
Description
Processes received packets and handles timers and other jobs.
Prototype
unsigned IP_TASK_Exec(void);
Return value
Value of the next timeout [ms].
Additional information
The IP_TASK_* API is an alternative to using the IP_Task() . It
allows finer control over the internal steps done in IP_Task() .
This can be utilized for example to feed a watchdog from the
same task periodically.
Note
This routine is not intended to be used when using IP_Task() or
IP_Exec() instead.
For best performance the IP_TASK_* API should be called with a
task priority higher than any other IP stack related application
task.
IP_TASK_WaitForEvent()
Description
Waits for an event for the main IP task to be signaled.
Prototype
unsigned IP_TASK_WaitForEvent(unsigned Timeout);
Parameters
Parameter | Description |
Timeout | Timeout [ms] to wait for an event. 0 for INFINITE is currently not supported (but can be used) and is internally changed to 1 . Typically the timeout value returned by IP_TASK_Exec() should be used. |
Return value
= 0 | An event was signaled. |
≠ 0 | Timeout. |
Additional information
The IP_TASK_* API is an alternative to using the IP_Task() . It
allows finer control over the internal steps done in IP_Task() .
This can be utilized for example to feed a watchdog from the
same task periodically.
Note
This routine is not intended to be used when using IP_Task() or
IP_Exec() instead.
For best performance the IP_TASK_* API should be called with a
task priority higher than any other IP stack related application
task.
IP_RxTask()
Description
Optional task to reduce time spent in receive interrupts.
Prototype
void IP_RxTask(void);
Additional information
This optional task can be implementing into your project to
reduce the time spent in Ethernet receive interrupts. An example
for typical task stack usage is defined by TASK_STACK_SIZE_IP_RX_TASK .
Warning
This task operates as a pseudo-interrupt executed from task
context and is not secured against other API or tasks of the
stack. It therefore needs to be given a task priority above
all tasks that make use of the API of the stack or one of the
other tasks of the stack like the IP_Task() or its API
alternatives like IP_TASK_Init() , IP_TASK_Exec() and
IP_TASK_WaitForEvent() .
For more information regarding task priorities, please refer to
Tasks and interrupt usage .
After startup, this routine settles into a loop, receiving/copying
packets in a task context instead of from the interrupt itself
to reduce interrupt latency. This loop sleeps until signaled
by a driver.
In case of de-initializing the stack with IP_DeInit(), it is
possible to leave the loop gracefully by using IP_ShutDown() .
IP_RXTASK_Init()
Description
Initializes the RxTask context when not using IP_RxTask() .
Prototype
void IP_RXTASK_Init(void);
Additional information
The IP_RXTASK_* API is an alternative to using the IP_RxTask() .
It allows finer control over the internal steps done in
IP_RxTask() . This can be utilized for example to feed a
watchdog from the same task periodically.
Warning
This routine is part of a pseudo-interrupt executed from task
context and is not secured against other API or tasks of the
stack. The task priority from which this routine is executed
has to be above all tasks that make use of the API of the
stack or one of the other tasks of the stack like the IP_Task()
or its API alternatives like IP_TASK_Init(), IP_TASK_Exec()
and IP_TASK_WaitForEvent() .
For more information regarding task priorities, please refer to
Tasks and interrupt usage .
It can however be used from a lower task priority when locking
the API with IP_OS_LOCK() before and unlocking with
IP_OS_UNLOCK() after calling this routine.
Example
/*********************************************************************
*
* _IP_RxTask()
*
* Function description
* Application specific implementation of IP_RxTask() .
*
* Additional information
* Allows to insert your own code like feeding a watchdog
* in-between the separate steps that would be executed by the
* original task API provided by the stack.
*/
static void _IP_RxTask(void) {
//
// Initialize.
//
IP_RXTASK_Init();
//
// Task-loop.
//
for (;;) {
//
// Wait with timeout [ms] (here INFINITE) for the next event to be
// signaled. Typically the signal is triggered by an interrupt
// from the driver when receiving new packets.
//
IP_RXTASK_WaitForEvent(0u);
//
// Handle received packets and copy them into the stack.
//
IP_RXTASK_Exec();
}
}
IP_RXTASK_Exec()
Description
Copies received packets from driver to stack in a task context
instead of from an interrupt.
Prototype
void IP_RXTASK_Exec(void);
Additional information
The IP_RXTASK_* API is an alternative to using the IP_RxTask() .
It allows finer control over the internal steps done in
IP_RxTask() . This can be utilized for example to feed a
watchdog from the same task periodically.
Note
This routine is not intended to be used when using IP_RxTask()
instead.
Warning
This routine is part of a pseudo-interrupt executed from task
context and is not secured against other API or tasks of the
stack. The task priority from which this routine is executed
has to be above all tasks that make use of the API of the
stack or one of the other tasks of the stack like the IP_Task()
or its API alternatives like IP_TASK_Init(), IP_TASK_Exec()
and IP_TASK_WaitForEvent() .
For more information regarding task priorities, please refer to
Tasks and interrupt usage .
It can however be used from a lower task priority when locking
the API with IP_OS_LOCK() before and unlocking with
IP_OS_UNLOCK() after calling this routine. In this case you might
have to manually remove the IP_DEBUG check in the IP_OS layer
that ensures that the task priorities are used correctly.
IP_RXTASK_WaitForEvent()
Description
Waits for an event for the IP_RxTask to be signaled.
Prototype
unsigned IP_RXTASK_WaitForEvent(unsigned Timeout);
Parameters
Parameter | Description |
Timeout | Timeout [ms] to wait for an event. 0 for INFINITE . |
Return value
= 0 | An event was signaled. |
≠ 0 | Timeout. |
Additional information
The IP_RXTASK_* API is an alternative to using the IP_RxTask() .
It allows finer control over the internal steps done in
IP_RxTask() . This can be utilized for example to feed a
watchdog from the same task periodically.
Note
This routine is not intended to be used when using IP_RxTask()
instead.
Warning
This routine is part of a pseudo-interrupt executed from task
context and is not secured against other API or tasks of the
stack. The task priority from which this routine is executed
has to be above all tasks that make use of the API of the
stack or one of the other tasks of the stack like the IP_Task()
or its API alternatives like IP_TASK_Init(), IP_TASK_Exec()
and IP_TASK_WaitForEvent() .
For more information regarding task priorities, please refer to
Tasks and interrupt usage .
It can however be used from a lower task priority when locking
the API with IP_OS_LOCK() before and unlocking with
IP_OS_UNLOCK() after calling this routine. In this case you might
have to manually remove the IP_DEBUG check in the IP_OS layer
that ensures that the task priorities are used correctly.
IP_Shutdown()
Description
Prepare network stack related tasks for a graceful shutdown.
Prototype
unsigned IP_Shutdown(unsigned LeaveTaskLoop,
U32 Timeout);
Parameters
Parameter | Description |
LeaveTaskLoop | Leave the task loop(s) of the stack when shutting down the tasks. |
Timeout | Timeout [ms] after which the routine returns regardless of all tasks being able to shut down or not. A timeout of 0 ms for immediate return can be used but the tasks will only be shut down for sure if all of them have a higher priority than the task calling this routine. A non-zero timeout is therefore advised. |
Return value
= 0 | All tasks have been shut down successfully. |
≠ 0 | Mask of IP_TASK_* bits for the tasks that have not been shut down within the timeout. |
Additional information
Before calling IP_DeInit() all application tasks should stop
calling network API and all tasks that belong directly to the
stack like IP_Task() should be stopped as well. The later of both
is not as easy as the application has no knowledge about the
current execution status of these tasks and it might happen
that for example IP_Task() is currently deep into some protocol
like TCP or even deeper like in a callback back into the
application.
By calling this routine a graceful stop of these tasks can be
requested to prepare them for having their tasks completely
removed in the next step.
Network interface configuration and handling functions
IP_NI_AddPTPDriver()
Description
Adds an NI specific PTP driver for HW timestamp support.
Prototype
int IP_NI_AddPTPDriver( unsigned IFaceId,
const IP_PTP_DRIVER * pPTPDriver,
U32 Clock);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pPTPDriver | PTP driver to add. |
Clock | Clock [Hz] of the PTP timer. Can not be 0. |
Return value
-1 | Error, not supported |
0 | OK |
1 | Error, called after driver initialization has been completed. |
IP_NI_ClrBPressure()
Description
Disables usage of back pressure (sending a jam signal to signal
when we run into a shortage where the hardware can not receive
more data).
Prototype
void IP_NI_ClrBPressure(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
IP_NI_ConfigPoll()
Description
Select polled mode for the network interface.
This should be used only if the NI can not activate an ISR itself.
Prototype
void IP_NI_ConfigPoll(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
IP_NI_ForceCaps()
Description
Allows to force capabilities to be set for an interface. Typically
this is used to allow the checksum calculation capabilities to be
set manually. Typically this is used to give the target a performance
boost in high traffic applications on stable networks, where the
occurence of wrong checksums is unlikely.
Prototype
void IP_NI_ForceCaps(unsigned IFaceId,
U8 CapsForcedMask,
U8 CapsForcedValue);
Parameters
Parameter | Description |
IFaceId | Zero-based index network interfaces. |
CapsForcedMask | Defines which bits in the Caps byte will be modified. A 1 in the mask will allow the Caps to be modified by the corresponding bit in CapsForcedValue. |
CapsForcedValue | Values for the corresponding bits in CapsForcedMask. Usually an OR of the following values: IP_NI_CAPS_WRITE_IP_CHKSUM IP_NI_CAPS_WRITE_UDP_CHKSUM IP_NI_CAPS_WRITE_TCP_CHKSUM IP_NI_CAPS_WRITE_ICMP_CHKSUM IP_NI_CAPS_CHECK_IP_CHKSUM IP_NI_CAPS_CHECK_UDP_CHKSUM IP_NI_CAPS_CHECK_TCP_CHKSUM IP_NI_CAPS_CHECK_ICMP_CHKSUM |
Example
Forcing the capability bits 0 to value ’0’ and bit 2 to value ’1’ for the first interface
can be done as shown in the code example below:
IP_NI_ForceCaps(0, 5, 4);
IP_NI_SetBPressure()
Description
Enables usage of back pressure (sending a jam signal to signal
when we run into a shortage where the hardware can not receive
more data).
Prototype
void IP_NI_SetBPressure(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
IP_NI_SetTxBufferSize()
Description
Sets the size of the Tx buffer of the network interface.
Prototype
int IP_NI_SetTxBufferSize(unsigned IFaceId,
unsigned NumBytes);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
NumBytes | Size of the Tx buffer (at least size of the MTU + 16 bytes for Ethernet). |
Return value
-1 | Error, not supported |
0 | OK |
1 | Error, called after driver initialization has been completed. |
Additional information
The default Tx buffer size is 1536 bytes. It can be useful to
reduce the buffer size on systems with less RAM and an application
that uses a small MTU. According to RFC 576 bytes is the smallest
possible MTU. The size of the Tx buffer should be at least
MTU + 16 bytes for Ethernet header and footer. The
function should be called in IP_X_Config().
Note:
This function is not implemented in all network interface drivers, since not
all Media Access Controllers (MAC) support variable buffer sizes.
PHY configuration functions
IP_NI_ConfigPHYAddr()
Description
Configure the PHY Addr.
Prototype
void IP_NI_ConfigPHYAddr(unsigned IFaceId,
U8 Addr);
Parameters
Parameter | Description |
IFaceId | Zero-based interface number. |
Addr | 5-bit address. |
Additional information
The PHY address is a 5-bit value. The generic PHY driver tries
to detect the PHY address automatically, therefore this should
not be called if not explicitly needed. If you use this function
to set the address explicitly, the function must be called from
within IP_X_Config().
IP_NI_ConfigPHYMode()
Description
Configure the PHY mode.
Prototype
void IP_NI_ConfigPHYMode(unsigned IFaceId,
U8 Mode);
Parameters
Parameter | Description |
IFaceId | Zero-based interface number. |
Mode | The operating mode of the PHY. |
Valid values for parameter Mode
Value | Description |
IP_PHY_MODE_MII | Phy uses the Media Independent Interface (MII). |
IP_PHY_MODE_RMII | Phy uses the Reduced Media Independent Interface (RMII). |
Additional information
The PHY can be connected to the MAC via two different modes, MII or RMII. Refer to
section MII / RMII: Interface between MAC and PHY for detailed information
about the differences of the MII and RMII modes.
The selection which mode is used is normally done correctly by the hardware. The
mode is typically sampled during power-on RESET. If you use this function to set the
mode explicitly, the function must be called from within IP_X_Config().
Refer to IP_X_Config.
IP_PHY_AddDriver()
Description
Adds a PHY driver and assigns it to an interface.
Prototype
void IP_PHY_AddDriver( unsigned IFaceId,
const IP_PHY_HW_DRIVER * pDriver,
const void * pAccess,
IP_PHY_pfConfig pf);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pDriver | Pointer to driver function table. |
pAccess | Pointer to function table containing routines for hardware access, depending on the driver to add. |
pf | Callback to PHY config routine. |
Additional information
If a driver has already been added for the selected interface
the driver will not be overwritten. The same applies for the
hardware access functions and the config callback. This allows
settings different parameters like the driver and access
routines from different places.
Typically the network interface driver will try to add the
generic PHY driver so it is not necessary to update an existing
IP_X_Config() unless new IP_PHY_* functions shall be used or a
driver other than the generic PHY driver shall be used.
Example
The following is an excerpt from an IP_Config_*.c file:
/*********************************************************************
*
* _ConfigPHY()
*
* Function description
* Callback executed during the PHY init of the stack to configure
* PHY settings once the hardware interface has been initialized.
*
* Parameters
* IFaceId: Zero-based interface index.
*/
static void _ConfigPHY(unsigned IFaceId) {
//
// Further PHY configuration can be added here by calling
// IP_PHY_*() functions for generic or specific PHY configuration.
//
}
/*********************************************************************
*
* IP_X_Config()
*
* Function description
* This function is called by the IP stack during IP_Init().
*/
void IP_X_Config(void) {
...
//
// Add the generic PHY driver for interface #0 and register
// a PHY config routine executed when the PHY driver is initialized.
//
IP_PHY_AddDriver(0, &IP_PHY_Driver_Generic, NULL, &_ConfigPHY);
...
}
IP_PHY_AddResetHook()
Description
This function adds a hook function to the IP_HOOK_ON_PHY_RESET
list. Registered hooks will be called after a PHY reset has
been executed and the generic init has been finished. This
allows the user to apply further settings to the PHY if needed.
Prototype
void IP_PHY_AddResetHook(IP_HOOK_ON_PHY_RESET * pHook,
IP_NI_pfOnPhyReset pf);
Parameters
Parameter | Description |
pHook | Pointer to static element of IP_HOOK_ON_PHY_RESET that can be internally used by the stack. |
pf | Function pointer to the callback that will be executed. |
Additional information
In some cases it might be necessary to apply a custom configuration
to the PHY. The generic PHY module used by the stack in most cases
will only apply a minimal configuration. Registering a callback
custom settings can be applied to this configuration.
If you are changing the PHY register page you need to reset it back
to page 0 before returning from the callback.
Example
//
// Excerpt of content of IP_Config_*.c
//
static IP_HOOK_ON_PHY_RESET _Hook;
/*********************************************************************
*
* _OnPhyReset()
*
* Function description
* Callback called after a PHY reset and generic initialization has
* been applied by the stack to allow the user to apply his own
* settings if necessary.
*
* Parameters
* IFaceId : Zero-based interface ID.
* pContext: PHY context.
* pApi : PHY access API.
*/
static void _OnPhyReset(unsigned IFaceId, void *pContext, const IP_PHY_API *pApi) {
U16 v;
v = pApi->pfRead(pContext, 0); // Read PHY register 0.
... // Modify value read.
pApi->pfWrite(pContext, 0, v); // Write modified value back to PHY register 0.
}
void IP_X_Config(void) {
...
IP_PHY_AddResetHook(&_Hook, _OnPhyReset); // Register _OnPhyReset() to
// be executed after a PHY
// software reset.
...
}
IP_PHY_ConfigAddr()
Description
Configures the PHY address to use.
Prototype
void IP_PHY_ConfigAddr(unsigned IFaceId,
unsigned Addr);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Addr | PHY address. |
Additional information
New version of the old function IP_NI_ConfigPHYAddr() that makes
direct use of the PHY module.
IP_PHY_ConfigAfterResetDelay()
Description
Configures the delay between (soft) resetting the PHY and
further communication with it.
Prototype
void IP_PHY_ConfigAfterResetDelay(unsigned IFaceId,
U16 ms);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
ms | Delay between (soft) resetting the PHY and further communication with it. |
IP_PHY_ConfigAltAddr()
Description
Sets a list of PHY addresses that can alternately be checked for
the link state.
Prototype
void IP_PHY_ConfigAltAddr( unsigned IFaceId,
const IP_PHY_ALT_LINK_STATE_ADDR * pAltPhyAddr);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pAltPhyAddr | List of alternate PHY addresses. |
Additional information
A typical setup would be using a switch where the first PHY/port
uses the PHY addr. 0x01 and the second PHY/port uses the addr.
0x02. The PHY driver by default might only support one addr. to
check the link state (e.g. on PHY addr. 0x01) and will ignore
the link state on any other PHY addr. Using this alternate list
of addr. these will be checked as well if supported by the driver.
Example
//
// PHY addresses of switch ports 2 - 4 (port 1 with addr. 0x01 will be
// found automatically).
//
const U8 aAltPhyAddr[] = { 0x02, 0x03, 0x04 };
const IP_PHY_ALT_LINK_STATE_ADDR AltPhyAddr = {
aAltPhyAddr,
SEGGER_COUNTOF(aAltPhyAddr)
};
void IP_X_Config(void) {
...
IFaceId = IP_AddEtherInterface(DRIVER);
IP_PHY_ConfigAltAddr(IFaceId, &AltPhyAddr);
...
}
IP_PHY_ConfigGigabitSupport()
Description
Configures if the MAC supports Gigabit Ethernet. If the MAC does
not support Gigabit Ethernet (default) then the PHY driver does
not have to handle it in case it is not supported anyhow.
Prototype
void IP_PHY_ConfigGigabitSupport(unsigned IFaceId,
unsigned OnOff);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
OnOff | 0: MAC does not support Gigabit Ethernet. 1: MAC supports Gigabit Ethernet. If the PHY is Gigabit capable as well it can be used. |
Additional information
Typically only required if a PHY driver other than the generic
PHY driver is used.
IP_PHY_ConfigSupportedModes()
Description
Configures the supported duplex/speed of the device to be
advertised during Auto-Negotiation.
Prototype
void IP_PHY_ConfigSupportedModes(unsigned IFaceId,
unsigned Modes);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Modes | Bitwise-OR combination of the following supported modes: IP_PHY_MODE_10_HALF IP_PHY_MODE_10_FULL IP_PHY_MODE_100_HALF IP_PHY_MODE_100_FULL IP_PHY_MODE_1000_HALF IP_PHY_MODE_1000_FULL |
Additional information
New version of the old function IP_SetSupportedDuplexModes()
that makes direct use of the PHY module.
Combining one of the supported duplex/speed modes with
IP_PHY_MODE_NO_AUTONEG disables the Auto-Negotiation
advertisement and configures a fixed duplex/speed.
IP_PHY_ConfigUseStaticFilters()
Description
Tells the stack if using PHY static MAC filter is allowed.
Prototype
void IP_PHY_ConfigUseStaticFilters(unsigned IFaceId,
unsigned OnOff);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
OnOff | 0: Do not use the PHY static filters. 1: Use the PHY static filters. |
Additional information
By default the stack is allowed to use PHY filters if available.
Can be disabled using this function if a custom filtering by the
user shall be used.
Needs to be used with a hardware interface (typically #0). Does
have no effect when being used with virtual interfaces like Tail
Tagging interfaces.
IP_PHY_DisableCheck()
Description
Disables PHY checks for all interfaces. This might be necessary
for some PHYs that are not fully IEEE 802.3u compliant.
Prototype
void IP_PHY_DisableCheck(U32 Mask);
Parameters
Parameter | Description |
Mask | Bitwise-OR bit mask of checks to disable: PHY_DISABLE_CHECK_ID PHY_DISABLE_CHECK_LINK_STATE_AFTER_UP PHY_DISABLE_WATCHDOG |
IP_PHY_DisableCheckEx()
Description
Disables PHY checks for one interface. This might be necessary
for some PHYs that are not fully IEEE 802.3u compliant.
Prototype
void IP_PHY_DisableCheckEx(unsigned IFaceId,
U32 Mask);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Mask | Bitwise-OR bit mask of checks to disable: PHY_DISABLE_CHECK_ID PHY_DISABLE_CHECK_LINK_STATE_AFTER_UP PHY_DISABLE_WATCHDOG |
IP_PHY_ReadReg()
Description
Reads a PHY register.
Prototype
int IP_PHY_ReadReg(unsigned IFaceId,
unsigned RegIndex,
unsigned * pData);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
RegIndex | Register index to read. |
pData | Pointer where to store the register value read. |
Return value
Additional information
At the moment PHY access is only implemented as a blocking
operation including actively waiting for the access to finish.
PHY access routines that operate according to the IEEE 802.3
standard have a maximum clock speed of 2.5 MHz. Frequent access
to PHY registers might block other operations in the stack.
Example
static IP_HOOK_ON_LINK_CHANGE _LinkChangeHook;
static void _OnLinkChange(unsigned IFaceId, U32 Duplex, U32 Speed) {
unsigned Reg;
IP_USE_PARA(Duplex);
if (Speed != 0u) { // Only on LINK-UP .
(void)IP_PHY_ReadReg(IFaceId, 0x06u, &Reg);
if (Reg & 1u) {
IP_Logf_Application("AutoNeg advertised by peer.");
} else {
IP_Logf_Application("No AutoNeg advertised by peer.");
}
}
}
/********************************************************************
*
* MainTask()
*/
void MainTask(void) {
IP_Init();
IP_AddLinkChangeHook(&_LinkChangeHook, _OnLinkChange);
...
}
IP_AddLinkChangeHook()
Description
Adds a callback that gets executed each time the link state
changes.
Prototype
void IP_AddLinkChangeHook
(IP_HOOK_ON_LINK_CHANGE * pHook,
void ( *pf)(unsigned IFaceId , U32 Duplex , U32 Speed ));
Parameters
Parameter | Description |
pHook | Management element of type IP_HOOK_ON_LINK_CHANGE. |
pf | Callback to execute on a link state change. |
Example
static IP_HOOK_ON_LINK_CHANGE _Hook;
static void _OnLinkChange(unsigned IFaceId, U32 Duplex, U32 Speed) {
...
}
void main(void) {
...
IP_AddLinkChangeHook(&_Hook, _OnLinkChange); // Register _OnLinkChange() to be
// executed when interface changes.
// Connect dial-up interface.
...
}
IP_AddOnPacketFreeHook()
Description
This function adds a hook function to the IP_HOOK_ON_PACKET_FREE
list. Registered hooks will be called in case a packet gets freed.
Prototype
void IP_AddOnPacketFreeHook(IP_HOOK_ON_PACKET_FREE * pHook,
void ( *pf)(IP_PACKET * pPacket ));
Parameters
Parameter | Description |
pHook | Element of type IP_HOOK_ON_PACKET_FREE to register. |
pf | Callback that is notified on a packet free. |
IP_AddStateChangeHook()
Description
Adds a hook to a callback that is executed when the AdminState or
HWState of an interface changes.
Prototype
void IP_AddStateChangeHook
(IP_HOOK_ON_STATE_CHANGE * pHook,
void ( *pf)(unsigned IFaceId , U8 AdminState , U8 HWState ));
Parameters
Parameter | Description |
pHook | Pointer to static element of IP_HOOK_ON_STATE_CHANGE that can be internally used by the stack. |
pf | Function pointer to the callback that will be executed. |
Additional information
A state change hook can be used to be notified about an interface
disconnect that has not been triggered by the application. Typical
example would be a peer that closes a dial-up connection and the
application needs to get notified of this event to call a
disconnect itself. Examples of this behavior can be found in the
samples shipped with the stack.
Example
static IP_HOOK_ON_STATE_CHANGE _Hook;
static void _OnChange(unsigned IFaceId, U8 AdminState, U8 HWState) {
...
}
void main(void) {
...
IP_AddStateChangeHook(&_Hook, _OnChange); // Register _OnState() to be
// executed when interface changes.
// Connect dial-up interface.
...
}
IP_PHY_ReInit()
Description
Re-initializes the PHY.
Prototype
void IP_PHY_ReInit(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
IP_PHY_SetWdTimeout()
Description
Sets the watchdog timeout for watching if the PHY reached
an unstable state.
Prototype
void IP_PHY_SetWdTimeout(int ShiftCnt);
Parameters
Parameter | Description |
ShiftCnt | Timeout comparison mask is (1 << ShiftCnt) - 1. |
Additional information
For optimization reasons the comparison is done by using a
bitmask instead of a division. The bitmask is not allowed
to contain a zero bit on a lower value position than a one
bit. To reach this we pass a shift count instead of a typical
timeout.
A PHY watchdog timeout might occur due to a link down of the
interface if it had a link up before. In this case the stack
resets the PHY as well to make sure it is not in a bad state
and is kept functional.
IP_PHY_WriteReg()
Description
Writes a PHY register.
Prototype
int IP_PHY_WriteReg(unsigned IFaceId,
unsigned RegIndex,
unsigned Data);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
RegIndex | Register index to write. |
Data | Data to write to the register. |
Return value
Additional information
At the moment PHY access is only implemented as a blocking
operation including actively waiting for the access to finish.
PHY access routines that operate according to the IEEE 802.3
standard have a maximum clock speed of 2.5 MHz. Frequent access
to PHY registers might block other operations in the stack.
Writes to the PHY registers 0-5 might use an internal caching
of the values written. This cache is currently not updated
when using this routine and might therefore result in working
with wrong values and resetting values when these registers
are written by the stack after they have been modified by the
application using this routine.
Statistics functions
IP_STATS_EnableIFaceCounters()
Description
Enables statistic counters for a specific interface.
Prototype
void IP_STATS_EnableIFaceCounters(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Additional information
IP_SUPPORT_STATS_IFACE or IP_SUPPORT_STATS needs to be enabled.
IP_STATS_GetIFaceCounters()
Description
Retrieves a pointer to the statistic counters for a specific interface.
Prototype
IP_STATS_IFACE *IP_STATS_GetIFaceCounters(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
Success: Pointer to structure of type IP_STATS_IFACE.
Error : NULL
Additional information
IP_SUPPORT_STATS_IFACE or IP_SUPPORT_STATS needs to be enabled.
IP_STATS_GetLastLinkStateChange()
Description
Retrieves the tick count when an interface entered its current
state.
Prototype
U32 IP_STATS_GetLastLinkStateChange(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
Timestamp in system ticks (typically 1ms).
Additional information
IP_SUPPORT_STATS_IFACE or IP_SUPPORT_STATS needs to be enabled.
IP_STATS_GetRxBytesCnt()
Description
Retrieves the number of bytes received on an interface.
Prototype
U32 IP_STATS_GetRxBytesCnt(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
Number of bytes received on this interface.
Additional information
IP_SUPPORT_STATS_IFACE or IP_SUPPORT_STATS needs to be enabled.
IP_STATS_GetRxDiscardCnt()
Description
Retrieves the number of packets received but discarded although
they were O.K. .
Prototype
U32 IP_STATS_GetRxDiscardCnt(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
Number of packets received but discarded although they were O.K. .
Additional information
IP_SUPPORT_STATS_IFACE or IP_SUPPORT_STATS needs to be enabled.
IP_STATS_GetRxErrCnt()
Description
Retrieves the number of receive errors.
Prototype
U32 IP_STATS_GetRxErrCnt(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
Number of receive errors.
Additional information
IP_SUPPORT_STATS_IFACE or IP_SUPPORT_STATS needs to be enabled.
IP_STATS_GetRxNotUnicastCnt()
Description
Retrieves the number of packets received on an interface that
were not unicasts.
Prototype
U32 IP_STATS_GetRxNotUnicastCnt(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
Number of packets received on this interface that were not unicasts.
Additional information
IP_SUPPORT_STATS_IFACE or IP_SUPPORT_STATS needs to be enabled.
IP_STATS_GetRxUnicastCnt()
Description
Retrieves the number of unicast packets received on an interface.
Prototype
U32 IP_STATS_GetRxUnicastCnt(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
Number of unicast packets received on this interface.
Additional information
IP_SUPPORT_STATS_IFACE or IP_SUPPORT_STATS needs to be enabled.
IP_STATS_GetRxUnknownProtoCnt()
Description
Retrieves the number of unknown protocols received.
Prototype
U32 IP_STATS_GetRxUnknownProtoCnt(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
Number of unknown protocols received.
Additional information
IP_SUPPORT_STATS_IFACE or IP_SUPPORT_STATS needs to be enabled.
IP_STATS_GetTxBytesCnt()
Description
Retrieves the number of bytes sent on an interface.
Prototype
U32 IP_STATS_GetTxBytesCnt(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
Number of bytes sent on this interface.
Additional information
IP_SUPPORT_STATS_IFACE or IP_SUPPORT_STATS needs to be enabled.
IP_STATS_GetTxDiscardCnt()
Description
Retrieves the number of packets to send but discarded although
they were O.K. .
Prototype
U32 IP_STATS_GetTxDiscardCnt(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
Number of packets to send but discarded although they were O.K. .
Additional information
IP_SUPPORT_STATS_IFACE or IP_SUPPORT_STATS needs to be enabled.
IP_STATS_GetTxErrCnt()
Description
Retrieves the number of send errors on an interface.
Prototype
U32 IP_STATS_GetTxErrCnt(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
Number of send errors.
Additional information
IP_SUPPORT_STATS_IFACE or IP_SUPPORT_STATS needs to be enabled.
IP_STATS_GetTxNotUnicastCnt()
Description
Retrieves the number of packets sent on an interface that were
not unicasts.
Prototype
U32 IP_STATS_GetTxNotUnicastCnt(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
Number of packets sent on this interface that were not unicasts.
Additional information
IP_SUPPORT_STATS_IFACE or IP_SUPPORT_STATS needs to be enabled.
IP_STATS_GetTxUnicastCnt()
Description
Retrieves the number of unicast packets sent on an interface.
Prototype
U32 IP_STATS_GetTxUnicastCnt(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
Number of unicast packets sent on this interface.
Additional information
IP_SUPPORT_STATS_IFACE or IP_SUPPORT_STATS needs to be enabled.
Other IP Stack functions
IP_AddAfterInitHook()
Description
Adds a hook to a callback that is executed at the end of IP_Init()
to allow adding initializations to be executed right after the
stack itself has been initialized and all API can be used.
Prototype
void IP_AddAfterInitHook(IP_HOOK_AFTER_INIT * pHook,
void ( *pf)());
Parameters
Parameter | Description |
pHook | Pointer to static element of IP_HOOK_AFTER_INIT that can be internally used by the stack. |
pf | Function pointer to the callback that will be executed. |
Additional information
Adding a callback to be executed right after IP_Init() can be
helpful for various things. For example this allows using a
centralized initialization that is not located in the main
routine that calls IP_Init() and has to make use of IP API
that is only valid to be used after IP_Init() .
Example
//
// Excerpt of content of IP_Config_*.c
//
static IP_HOOK_AFTER_INIT _Hook;
static void _Connect(void) {
...
}
void IP_X_Config(void) {
...
IP_AddAfterInitHook(&_Hook, _Connect); // Register _Connect() to be
// executed at end of IP_Init()
...
}
//
// Excerpt of content of main.c
//
void main(void) {
...
IP_Init();
...
}
IP_AddEtherTypeHook()
Description
This function registers a callback to be called for received
packets with the registered Ethernet type.
Prototype
void IP_AddEtherTypeHook
(IP_HOOK_ON_ETH_TYPE * pHook,
int ( *pf)(unsigned IFaceId , IP_PACKET * pPacket , void * pBuffer , U32 NumBytes ),
U16 Type);
Parameters
Parameter | Description |
pHook | Hook resource of type IP_HOOK_ON_ETH_TYPE. |
pf | Callback to call for the registered Ethernet type. |
Type | Ethernet type that triggers the callback in host endianness. |
Example
static IP_HOOK_ON_ETH_TYPE _Hook;
/********************************************************************
*
* _OnARP()
*
* Function description
* This function allocates a packet to mirror back a received ARP
* packet to the network. This is of no use but demonstrates how
* to use the API.
* The received packet will be handled regularly by the stack as
* well by returning IP_OK_TRY_OTHER_HANDLER.
*
* Parameters
* IFaceId : Zero-based interface index.
* pPacket : Pointer to received packet.
* pBuffer : Pointer to start of data of the received packet.
* NumBytes: NumBytes data received in the packet.
*
* Return value
* Original packet has not been changed and the stack shall
* process it: IP_OK_TRY_OTHER_HANDLER
* Original packet has been freed or reused by the callback:
* Other like IP_OK or IP_RX_ERROR.
*/
static int _OnARP(unsigned IFaceId,IP_PACKET* pPacket,void* pBuffer,U32 NumBytes) {
IP_PACKET* pPacketOut;
U8* p;
pPacketOut = IP_AllocEtherPacket(IFaceId, NumBytes, &p);
if (pPacketOut != NULL) {
IP_MEMCPY(p, pBuffer, NumBytes);
IP_SendEtherPacket(IFaceId, pPacketOut, NumBytes);
}
return IP_OK_TRY_OTHER_HANDLER;
}
/********************************************************************
*
* MainTask()
*/
void MainTask(void) {
IP_Init();
IP_AddEtherTypeHook(&_Hook, _OnARP, 0x0806);
...
}
IP_AddInterfaceErrorHook()
Description
Adds a hook function which will be called if initialization
fails for an interface.
Prototype
void IP_AddInterfaceErrorHook(IP_HOOK_ON_IF_ERROR * pfOnInterfaceError);
Parameters
Parameter | Description |
pfOnInterfaceError | Pointer to the callback function of type IP_HOOK_ON_IF_ERROR. |
IP_AddLinkChangeHook()
Description
Adds a callback that gets executed each time the link state
changes.
Prototype
void IP_AddLinkChangeHook
(IP_HOOK_ON_LINK_CHANGE * pHook,
void ( *pf)(unsigned IFaceId , U32 Duplex , U32 Speed ));
Parameters
Parameter | Description |
pHook | Management element of type IP_HOOK_ON_LINK_CHANGE. |
pf | Callback to execute on a link state change. |
Example
static IP_HOOK_ON_LINK_CHANGE _Hook;
static void _OnLinkChange(unsigned IFaceId, U32 Duplex, U32 Speed) {
...
}
void main(void) {
...
IP_AddLinkChangeHook(&_Hook, _OnLinkChange); // Register _OnLinkChange() to be
// executed when interface changes.
// Connect dial-up interface.
...
}
IP_AddOnPacketFreeHook()
Description
This function adds a hook function to the IP_HOOK_ON_PACKET_FREE
list. Registered hooks will be called in case a packet gets freed.
Prototype
void IP_AddOnPacketFreeHook(IP_HOOK_ON_PACKET_FREE * pHook,
void ( *pf)(IP_PACKET * pPacket ));
Parameters
Parameter | Description |
pHook | Element of type IP_HOOK_ON_PACKET_FREE to register. |
pf | Callback that is notified on a packet free. |
IP_AddStateChangeHook()
Description
Adds a hook to a callback that is executed when the AdminState or
HWState of an interface changes.
Prototype
void IP_AddStateChangeHook
(IP_HOOK_ON_STATE_CHANGE * pHook,
void ( *pf)(unsigned IFaceId , U8 AdminState , U8 HWState ));
Parameters
Parameter | Description |
pHook | Pointer to static element of IP_HOOK_ON_STATE_CHANGE that can be internally used by the stack. |
pf | Function pointer to the callback that will be executed. |
Additional information
A state change hook can be used to be notified about an interface
disconnect that has not been triggered by the application. Typical
example would be a peer that closes a dial-up connection and the
application needs to get notified of this event to call a
disconnect itself. Examples of this behavior can be found in the
samples shipped with the stack.
Example
static IP_HOOK_ON_STATE_CHANGE _Hook;
static void _OnChange(unsigned IFaceId, U8 AdminState, U8 HWState) {
...
}
void main(void) {
...
IP_AddStateChangeHook(&_Hook, _OnChange); // Register _OnState() to be
// executed when interface changes.
// Connect dial-up interface.
...
}
IP_Alloc()
Description
Thread safe memory allocation from main IP stack memory pool.
Prototype
void *IP_Alloc(U32 NumBytesReq);
Parameters
Parameter | Description |
NumBytesReq | Number of bytes to allocate. |
Return value
= NULL | Error. |
≠ NULL | O.K. Pointer to allocated memory |
Additional information
Memory allocated with this function has to be freed with IP_Free().
IP_AllocEtherPacket()
Description
Allocates a packet to store the raw data of an Ethernet packet
of up to NumBytes at the location returned by ppBuffer.
Prototype
IP_PACKET *IP_AllocEtherPacket(unsigned IFaceId,
U32 NumBytes,
U8 ** ppBuffer);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
NumBytes | Minimum buffer size the packet has to provide. |
ppBuffer | Pointer where to store the pointer to the beginning of the packet buffer. |
Return value
O.K. : Pointer to packet allocated.
Error: NULL.
IP_AllocEx()
Description
Thread safe memory allocation from a specific memory pool
managed by the stack that has been added using IP_AddMemory().
Prototype
void *IP_AllocEx(U32 * pPoolAddr,
U32 NumBytesReq);
Parameters
Parameter | Description |
pPoolAddr | Base address of the memory pool. |
NumBytesReq | Number of bytes to allocate. |
Return value
= NULL | Error. |
≠ NULL | O.K. Pointer to allocated memory |
Additional information
Memory allocated with this function has to be freed with IP_Free().
IP_ARP_CleanCache()
Description
Cleans all ARP entries that are not static entries.
Prototype
void IP_ARP_CleanCache(void);
IP_ARP_CleanCacheByInterface()
Description
Cleans all ARP entries that are known to belong to a specific
interface and are not static entries.
Prototype
void IP_ARP_CleanCacheByInterface(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
IP_Connect()
Description
Calls a previously registered hook for the interface if any was
set using IP_SetIFaceConnectHook() .
Prototype
int IP_Connect(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
= 0 | O.K. or no callback set. |
< 0 | Error. |
IP_Disconnect()
Description
Calls a previously registered hook for the interface if any was
set using IP_SetIFaceDisconnectHook() .
Prototype
int IP_Disconnect(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
= 0 | O.K. or no callback set. |
< 0 | Error. |
IP_Err2Str()
Description
Converts IP stack error code to a readable string by simply using
the defines name.
Prototype
char *IP_Err2Str(int x);
Parameters
Parameter | Description |
x | Error code returned by API of the stack. |
Return value
Pointer to string of the define name.
IP_FindIFaceByIP()
Description
Tries to find out the interface number when only the IP address
is known.
Prototype
int IP_FindIFaceByIP(void * pAddr,
unsigned Len);
Parameters
Parameter | Description |
pAddr | Pointer to a variable holding the address to find in host endianness. |
Len | Length of address at pAddr. |
Return value
= -1 | Interface not found. |
≥ 0 | Interface found. |
Additional information
For the moment only IPv4 is supported.
Example
The following sample tries to find an interface that has previously been configured to
a fixed IP address of 192.168.2.10.
int IFaceId;
U32 IPAddr;
IPAddr = IP_BYTES2ADDR(192, 168, 2, 10);
IFaceId = IP_FindIFaceByIP(&IPAddr, sizeof(IPAddr));
IP_Free()
Description
Thread safe memory free to IP stack memory pools.
Prototype
void IP_Free(void * p);
Parameters
Parameter | Description |
p | Pointer to memory block previously allocated with IP_Alloc(). |
IP_FreePacket()
Description
Frees a packet back to the stack.
Prototype
void IP_FreePacket(IP_PACKET * pPacket);
Parameters
Parameter | Description |
pPacket | Packet to free. |
Additional information
This routine can be used to typically free any allocated packet
regardless of the API used to allocate it.
IP_GetAddrMask()
Description
Retrieves the IP address and subnet mask of an interface.
The values are stored in host bytes order.
(for example, 192.168.1.1 is returned as 0xC0A80101).
Prototype
void IP_GetAddrMask(U8 IFace,
U32 * pAddr,
U32 * pMask);
Parameters
Parameter | Description |
IFace | Zero-based interface index. |
pAddr | Address to store the IP address in host order. Can be NULL. |
pMask | Address to store the subnet mask in host order. Can be NULL. |
IP_GetCurrentLinkSpeed()
Description
Returns the current link speed of the first interface (interface ID 0).
Prototype
int IP_GetCurrentLinkSpeed(void);
Return value
Current link speed in Hertz.
Additional information
The application should check if the link is up before a packet
will be sent. It can take 2-3 seconds till the link is up if
the PHY has been reset.
Example
//
// Wait until link is up.
//
while (IP_GetCurrentLinkSpeed() == 0) {
OS_IP_Delay(100);
}
IP_GetCurrentLinkSpeedEx()
Description
Returns the current link speed of the requested interface.
Prototype
int IP_GetCurrentLinkSpeedEx(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface number. |
Return value
Current link speed in Hertz.
Additional information
The application should check if the link is up before a packet
will be sent. It can take 2-3 seconds till the link is up if
the PHY has been reset.
Example
//
// Wait until link is up.
//
while (IP_GetCurrentLinkSpeedEx(0) == 0) {
OS_IP_Delay(100);
}
IP_GetFreePacketCnt()
Description
Checks how many packets for a specific size or greater are
currently available in the system.
Prototype
U32 IP_GetFreePacketCnt(U32 NumBytes);
Parameters
Parameter | Description |
NumBytes | Minimum size of packets to find. |
Return value
Number of packets available for this size.
Description
Retrieves the size of the header necessary for the transport
medium that is used by a specific interface.
Example: Ethernet: 14 bytes header + 2 bytes padding.
Prototype
U32 IP_GetIFaceHeaderSize(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
Size of header for this interface.
IP_GetGWAddr()
Description
Returns the gateway address of the interface in host endianness.
(for example, 192.168.1.1 is returned as 0xc0a80101).
Prototype
U32 IP_GetGWAddr(U8 IFace);
Parameters
Parameter | Description |
IFace | Zero-based interface index. |
Return value
The gateway address of the interface.
IP_GetHWAddr()
Description
Returns the hardware address (Media Access Control address) of
the interface.
Prototype
void IP_GetHWAddr(unsigned IFaceId,
U8 * pDest,
unsigned Len);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pDest | Address of the buffer to store the 48-bit MAC address. |
Len | Size of the buffer. Should be at least 6-bytes. |
IP_GetIPAddr()
Description
Returns the IP address of the interface in host endianness.
Example:
192.168.0.1 is returned as 0xc0a80001 for a big endian target,
0x0100a8c0 for a little endian target.
Prototype
U32 IP_GetIPAddr(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface number. |
Return value
IP address of the interface in host endianness.
Example
void PrintIFaceIPAddr(void) {
char ac[16];
U32 IPAddr;
IPAddr = IP_GetIPAddr(0);
IP_PrintIPAddr(ac, IPAddr, sizeof(ac));
printf("IP Addr: %s\n", ac);
}
IP_GetIPPacketInfo()
Description
Returns the start address of the data part of an IPv4 packet.
Prototype
U8 *IP_GetIPPacketInfo(IP_PACKET * pPacket);
Parameters
Parameter | Description |
pPacket | Pointer to an IP_PACKET . |
Return value
≠ NULL | Pointer to the data part of the IPv4 packet. |
= NULL | Error. |
Example
/*********************************************************************
*
* _pfOnRxICMP
*/
static int _pfOnRxICMP(IP_PACKET* pPacket) {
const U8* pData;
pData = IP_GetIPPacketInfo(pPacket);
if(*pData == 0x08) {
printf("ICMP echo request received!\n");
}
if(*pData == 0x00) {
printf("ICMP echo reply received!\n");
}
return 0;
}
IP_GetRawPacketInfo()
Description
Returns the start address of the raw data of an IP_PACKET.
Prototype
char *IP_GetRawPacketInfo(const IP_PACKET * pPacket,
U16 * pNumBytes);
Parameters
Parameter | Description |
pPacket | Pointer to an IP_PACKET structure. |
pNumBytes | Output length of the packet. |
Return value
> 0 | Start address of the raw data part of the IP packet. |
= 0 | On failure. |
IP_GetVersion()
Description
Returns the version of the stack.
Prototype
int IP_GetVersion(void);
Return value
Version number.
Additional information
The format of the version number: <Major><Minor><Minor><Revision><Revision> .
For example, the return value 10201 means version 1.02a.
IP_ICMP_AddRxHook()
Description
This function adds a callback that is executed upon receiving
an ICMPv4 packet.
Prototype
void IP_ICMP_AddRxHook(IP_HOOK_ON_ICMPV4 * pHook,
IP_ON_ICMPV4_FUNC * pf,
void * pUserContext);
Parameters
Parameter | Description |
pHook | Pointer to static element of IP_HOOK_ON_ICMPV4 that can be internally used by the stack. |
pf | Function pointer to the callback to execute. |
pUserContext | User defined context top pass to the callback. |
Example
static IP_HOOK_ON_ICMPV4 _Hook;
/*********************************************************************
*
* _cbOnRx()
*
* Function description
* Callback executed when an ICMPv4 packet is received.
*
* Parameters
* IFaceId : Zero-based interface index.
* pPacket : Packet that has been received.
* pUserContext: User context given when adding the hook.
* p : Reserved for future extensions of this API.
*
* Return value
* == IP_OK : Packet has been handled (freed or reused).
* == IP_OK_TRY_OTHER_HANDLER: Packet is untouched and stack shall try another handler.
*
* Additional information
* The callback can remove its own hook using IP_ICMP_RemoveRxHook() .
*/
static int _cbOnRx(unsigned IFaceId,
IP_PACKET* pPacket,
void* pUserContext,
void* p) {
const U8* pData;
IP_USE_PARA(IFaceId);
IP_USE_PARA(pUserContext);
IP_USE_PARA(p);
pData = IP_GetIPPacketInfo(pPacket);
if(*pData == IP_ICMP_TYPE_ECHO_REQUEST) {
IP_Logf_Application("ICMP echo request received!");
}
if(*pData == IP_ICMP_TYPE_ECHO_REPLY) {
IP_Logf_Application("ICMP echo reply received!");
}
//
// Optional: Remove the hook once no longer needed.
//
IP_ICMP_RemoveRxHook(SEGGER_PTR2PTR(IP_HOOK_ON_ICMPV4, pUserContext));
return IP_OK_TRY_OTHER_HANDLER; // Let the stack handle the message.
}
/*********************************************************************
*
* MainTask()
*
* Function description
* Main task executed by the RTOS to create further resources and
* running the main application.
*/
void MainTask(void) {
IP_Init();
//
// Add a hook that gets notified about received ICMP messages.
// In this example the pointer to the hook item itself is passed as
// user context to demonstrate the hook removing itself.
//
IP_ICMP_AddRxHook(&_Hook, _cbOnRx, &_Hook);
...
}
IP_ICMP_SetRxHook()
Description
Sets a hook function which will be called if target receives a
ping packet.
Prototype
void IP_ICMP_SetRxHook(IP_RX_HOOK * pfRxHook);
Parameters
Parameter | Description |
pfRxHook | Pointer to the callback function of type IP_RX_HOOK. |
Additional information
The return value of the callback function is relevant for the
further processing of the ICMP packet. A return value of 0
indicates that the stack has to process the packet after the
callback has returned. A return value of 1 indicates that the
packet will be freed directly after the callback has returned.
The callback is executed AFTER evaluating ICMP replies to our
requests but BEFORE answering to foreign requests.
Example
/*********************************************************************
*
* Local defines, configurable
*
**********************************************************************
*/
#define HOST_TO_PING 0xC0A80101
/*********************************************************************
*
* _pfOnRxICMP
*/
static int _pfOnRxICMP(IP_PACKET * pPacket) {
const char * pData;
pData = IP_GetIPPacketInfo(pPacket);
if(*pData == 0x08) {
printf("ICMP echo request received!\n");
}
if(*pData == 0x00) {
printf("ICMP echo reply received!\n");
}
return 0; // Give packet back to the stack for further processing.
}
/*********************************************************************
*
* PingTask
*/
void PingTask(void) {
int Seq;
char * s = "This is a ICMP echo request!";
while (IP_IFaceIsReady() == 0) {
OS_Delay(50);
}
IP_ICMP_SetRxHook(_pfOnRxICMP);
Seq = 1111;
while (1) {
BSP_ToggleLED(1);
OS_Delay (200);
IP_SendPing(htonl(HOST_TO_PING), s, strlen(s), Seq++);
}
}
IP_ICMP_RemoveRxHook()
Description
This function removes a hook function from the
IP_HOOK_ON_ICMPV4 list.
Prototype
void IP_ICMP_RemoveRxHook(IP_HOOK_ON_ICMPV4 * pHook);
Parameters
Parameter | Description |
pHook | Element of type IP_HOOK_ON_ICMPV4 to remove from list. |
IP_IFaceIsReady()
Description
Checks if the interface is ready for usage. Ready for usage
means that the target has a physical link detected and a valid
IP address.
Operates on interface 0.
Prototype
int IP_IFaceIsReady(void);
Return value
1 | Network interface is ready. |
0 | Network interface is not ready. |
Additional information
The application has to check if the link is up before a packet
will be sent and if the interface is configured. If a DHCP
server is used for configuring your target, this function
has to be called to assure that no application data will be
sent before the target is ready.
Example
//
// Wait until interface is ready.
//
while (IP_IFaceIsReady() == 0) {
OS_Delay(100);
}
IP_IFaceIsReadyEx()
Description
Checks if the specified interface is ready for usage. Ready for
usage means that the target has a physical link detected and a
valid IP address.
Prototype
int IP_IFaceIsReadyEx(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface number. |
Return value
1 | Interface is ready. |
0 | Interface is not ready. |
Additional information
The application has to check if the link is up before a packet
will be sent and if the interface is configured. If a DHCP
server is used for configuring your target, this function has
to be called to assure that no application data will be sent
before the target is ready.
Example
//
// Wait until second interface is ready.
//
while (IP_IFaceIsReadyEx(1) == 0) {
OS_Delay(100);
}
IP_IsAllZero()
Description
Checks if there are zeros at the given pointer.
Prototype
unsigned IP_IsAllZero(const U8 * p,
unsigned NumBytes);
Parameters
Parameter | Description |
p | Pointer to location to check for zeros. |
NumBytes | Number of bytes to check to be zero. |
Return value
0 | NOT all bytes are 0x00 at the pointer. |
1 | All bytes are 0x00 at the pointer. |
IP_IsExpired()
Description
Checks if the given system timestamp has already expired.
Prototype
unsigned IP_IsExpired(U32 Time);
Parameters
Parameter | Description |
Time | System timestamp as used by OS abstraction layer. |
Return value
1 | Time has expired. |
0 | Time has not yet expired. |
Example
U32 Timeout;
//
// Get current system time [ms] and timeout in one second.
//
Timeout = IP_OS_GET_TIME() + 1000;
//
// Wait until timeout expires.
//
do {
OS_Delay(1);
} while (IP_IsExpired(Timeout) == 0);
IP_NI_ConfigLinkCheckMultiplier()
Description
Configures the multiplier of the period between interface link
checks typically executed each second.
Prototype
int IP_NI_ConfigLinkCheckMultiplier(unsigned IFaceId,
unsigned Multiplier);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Multiplier | Multiplier of the link check period (default 1s). |
Return value
= 0 | O.K. |
≠ 0 | Error/Not supported. |
Additional information
The default period between link checks is one second which is
fine for reacting on a link change. For other interfaces like
WiFi it might not be necessary to check for the link status
each second or it might even be worth reducing link checks
to a minimum if this interferes with packet transactions on
the same interface like a single SPI.
IP_NI_ConfigUsePromiscuousMode()
Description
Configures if the driver tries to use its hardware precise and
hash filters as available before switching to promiscuous mode
or if promiscuous mode will be used in any case.
Prototype
void IP_NI_ConfigUsePromiscuousMode(unsigned IFaceId,
unsigned OnOff);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
OnOff | 0: Driver will try to use its hardware filters (default). 1: Driver will be using promiscuous mode. |
IP_NI_GetAdminState()
Description
Retrieves the admin state of the given interface.
Prototype
int IP_NI_GetAdminState(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
0 | Interface disabled. |
1 | Interface enabled. |
-1 | Invalid interface ID. |
IP_NI_GetIFaceType()
Description
Retrieves a short textual description of the interface type.
Prototype
int IP_NI_GetIFaceType(unsigned IFaceId,
char * pBuffer,
U32 * pNumBytes);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pBuffer | Pointer to the buffer where to store the string. |
pNumBytes | Pointer to the size of the buffer at pBuffer and where to store the length of the string (without termination). |
Return value
Additional information
If the buffer is big enough this function will terminate the
string in the buffer as well. The length of the string is
always stored at pNumBytes.
Example
char ac[10]; // Should be big enough to hold all short interface descriptions.
U32 NumBytes;
//
// Get the type of interface #0 .
//
NumBytes = sizeof(ac);
IP_NI_GetIFaceType(0, &ac[0], &NumBytes);
printf("Interface #0 is of type \"%s\"", &ac[0]);
IP_NI_GetState()
Description
Returns the hardware state of the interface.
Prototype
int IP_NI_GetState(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
0 | Interface is down |
1 | Interface is up |
-1 | Invalid interface ID |
IP_NI_SetAdminState()
Description
Sets the AdminState of the interface.
Prototype
void IP_NI_SetAdminState(unsigned IFaceId,
int AdminState);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
AdminState | Admin state to set. 0: DOWN 1: UP |
Additional information
For most interfaces like Ethernet, WiFi and virtual interfaces
like VLAN the state is UP by default. Connection oriented
interfaces like PPP or PPPoE use the state for a connect
request and therefore start with state DOWN.
Setting an interface like Ethernet to DOWN will try to
disable this interface to the best possible. A software filter
for interfaces with state DOWN discards packets that can
not be filtered using other mechanisms.
- Best case: The Rx interrupt of the interface gets disabled, reducing the CPU load for the disabled interface.
- Worst case: Only software filtering is applied. The CPU load for processing incoming packets will remain like for an interface with state UP.
IP_NI_GetTxQueueLen()
Description
Retrieves the current length of the Tx queue of an interface.
Prototype
int IP_NI_GetTxQueueLen(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
≥ 0 | Current Tx queue length. |
< 0 | Error. |
Additional information
IP_SUPPORT_STATS_IFACE or IP_SUPPORT_STATS needs to be enabled.
IP_NI_PauseRx()
Description
Pauses the Rx handling of an interface by disabling it temporary.
The Rx handling will be automatically re-enabled after the
specified pause time.
Prototype
int IP_NI_PauseRx(unsigned IFaceId,
U32 Pause);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Pause | Time to pause the Rx handling [ms]. |
Return value
= 0 | O.K. |
< 0 | Error or disable Rx not supported by driver. |
Additional information
Can be called from an interrupt context!
While most of the API is using an API lock that can not be
used from an interrupt, this API can be called from an interrupt
context as this is the typical case when being flooded with
incoming packets. Calling this API from a task might not succeed
anymore as the CPU is held constantly busy by Rx.
Unlike IP_NI_PauseRxInt() this routine disables the complete Rx
logic of the driver which will also prevent being kept busy
processing received data from any hardware RxFIFO. By disabling
the Rx path completely the RxFIFO no longer is fed.
IP_NI_PauseRxInt()
Description
Pauses the Rx interrupt of an interface by disabling it temporary.
The Rx interrupt will be automatically re-enabled after the
specified pause time.
Prototype
int IP_NI_PauseRxInt(unsigned IFaceId,
U32 Pause);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Pause | Time to pause the Rx interrupt [ms]. |
Return value
= 0 | O.K. |
< 0 | Error or disable Rx interrupt not supported by driver. |
Additional information
Can be called from an interrupt context!
While most of the API is using an API lock that can not be
used from an interrupt, this API can be called from an interrupt
context as this is the typical case when being flooded with
incoming packets. Calling this API from a task might not succeed
anymore as the CPU is held constantly busy by Rx interrupts.
For plain anti-flooding measurements please use IP_NI_PauseRx() .
Pausing the Rx interrupt of an interface can be used as
countermeasure to flood situations. It does not prevent the
flood of packets being received at the interface itself. It
will prevent new Rx interrupts to occur for a certain period
of time but will not abort already started Rx handling from a
previous interrupt. This means that if the flood keeps on feeding
the hardwares RxFIFO for example, it is possible that Rx handling
will continue until the hardware is able to read away all incoming
data and return to an idle state.
Pausing the Rx interrupt alone but keeping the Rx logic in general
enabled can be used to continue receiving incoming data in a flood
situation using the IP_RxTask while making sure to give Rx a pause
once the flooding stops for a moment.
IP_PrintIPAddr()
Description
Convert a 4-byte IP address to a dots-and-number string.
Prototype
int IP_PrintIPAddr(char * pBuffer,
U32 IPAddr,
int BufferSize);
Parameters
Parameter | Description |
pBuffer | Pointer to a buffer where to store the string. |
IPAddr | IPv4 addresse in host byte order. |
BufferSize | Size of buffer at pBuffer. Should be at least 16 bytes to store xxx.xxx.xxx.xxx . |
Return value
> 0 | Length of string stored into the buffer without string termination character. |
= 0 | Buffer is too small. |
Additional information
IPAddr is given in host order.
Example: 192.168.0.1 is 0xC0A80001 for big endian targets
0x0100A8C0 for little endian targets.
Example
void PrintIPAddr(void) {
U32 IPAddr;
char ac[16];
IPAddr = 0xC0A80801; // IP address: 192.168.8.1
IP_PrintIPAddr(ac, IPAddr, sizeof(ac));
printf("IP address: %s\n", ac); // Output: IP address: 192.168.8.1
}
IP_ResolveHost()
Description
Resolve a host name string to its IP address by using a configured
DNS server.
Prototype
int IP_ResolveHost(const char * sHost,
U32 * pIPAddr,
U32 ms);
Parameters
Parameter | Description |
sHost | Host name string to resolve. |
pIPAddr | Pointer to where to store the resolved IP addr. in network order. |
ms | Timeout in ms to wait for the DNS server to answer. |
Return value
= 0 | O.K., host name resolved. |
< 0 | Error: Could not resolve host name. |
Additional information
In contrast to the standard socket function gethostbyname(), this
function allows resolving a host name in a thread safe way and
should therefore be used whenever possible.
The retrieved IP address will be returned in network order so it
can be directly used with the BSD socket API.
IP_RemoveEtherTypeHook()
Description
This function removes a hook function for a previously
registered Ethernet type.
Prototype
void IP_RemoveEtherTypeHook(IP_HOOK_ON_ETH_TYPE * pHook);
Parameters
IP_SendEtherPacket()
Description
Sends a previously allocated Ethernet packet.
Prototype
int IP_SendEtherPacket(unsigned IFaceId,
IP_PACKET * pPacket,
U32 NumBytes);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pPacket | Previously allocated Ethernet packet to send. |
NumBytes | Number of bytes that have been stored in the packet buffer. |
Return value
Additional information
The packet gets freed by the stack whether the return code is
success or error. The packet can not be reused by the application.
IP_SendPacket()
Description
Sends a user defined packet on the interface. The packet will not
be modified by the stack. IP_SendPacket() allocates a packet
control block (IP_PACKET) and adds it to the out queue of the
interface.
Prototype
int IP_SendPacket(unsigned IFace,
void * pData,
unsigned NumBytes);
Parameters
Parameter | Description |
IFace | Zero-based interface index. |
pData | Pointer to user data to send. |
NumBytes | Length of data to send. |
Return value
-1 | Could not allocate a packet for sending. |
0 | Packet in out queue. |
1 | Interface can not send. |
IP_SendPing()
Description
Sends a single ICMP echo request (“ping”) to the specified host.
Function uses always interface 0.
Prototype
int IP_SendPing(U32 FHost,
char * pData,
unsigned NumBytes,
U16 SeqNum);
Parameters
Parameter | Description |
FHost | 4-byte IPv4 address in network endian byte order of the target. |
pData | Pointer to the ping data, NULL if do not care. |
NumBytes | Length of data to attach to ping request. |
SeqNum | Ping sequence number. |
Return value
= 0 | ICMP echo request was successfully sent. |
< 0 | Error |
Additional information
If you call this function with activated logging, the ICMP reply or (in case of an error)
the error message will be sent to stdout. To enable the output of ICMP status messages,
add the message type IP_MTYPE_ICMP to the log filter and the warn filter.
Refer to Debugging for detailed information about logging.
IP_SendPingCheckReply()
Description
Sends a single ICMP echo request (“ping”) to the specified host
using the selected interface and waits for the reply.
Prototype
int IP_SendPingCheckReply(U32 IFaceId,
U32 FHost,
char * pData,
unsigned NumBytes,
unsigned ms);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
FHost | 4-byte IPv4 address in network endian byte order of the target. |
pData | Pointer to the ping data, NULL if do not care. |
NumBytes | Length of data to attach to ping request. |
ms | Number of ms to wait for the reply. |
Return value
= 0 | OK, ping sent and reply received. |
= IP_ERR_TIMEDOUT | Timeout, ping sent but no reply received. |
< 0 | Error. |
Additional information
If you call this function with activated logging, the ICMP reply or (in case of an error)
the error message will be sent to stdout. To enable the output of ICMP status messages,
add the message type IP_MTYPE_ICMP to the log filter and the warn filter.
Refer to Debugging for detailed information about logging.
IP_SendPingEx()
Description
Sends a single ICMP echo request (“ping”) to the specified host
using the selected interface.
Prototype
int IP_SendPingEx(U32 IFaceId,
U32 FHost,
char * pData,
unsigned NumBytes,
U16 SeqNum);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
FHost | 4-byte IPv4 address in network endian byte order of the target. |
pData | Pointer to the ping data, NULL if do not care. |
NumBytes | Length of data to attach to ping request. |
SeqNum | Ping sequence number. |
Return value
Additional information
If you call this function with activated logging, the ICMP reply or (in case of an error)
the error message will be sent to stdout. To enable the output of ICMP status messages,
add the message type IP_MTYPE_ICMP to the log filter and the warn filter.
Refer to Debugging for detailed information about logging.
IP_SetIFaceConnectHook()
Description
Sets a hook for an interface that is executed when
IP_Connect() is called.
Prototype
void IP_SetIFaceConnectHook(unsigned IFaceId,
int ( *pf)(unsigned IFaceId ));
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pf | Hook that is called on IP_Connect(). |
Additional information
Typically for a pure Ethernet interface this functionality is
not needed. Typically it is used with dial-up interfaces or
interfaces that need more configurations to be set by the
application to work.
IP_SetIFaceDisconnectHook()
Description
Sets a hook for an interface that is executed when
IP_Disconnect() is called.
Prototype
void IP_SetIFaceDisconnectHook(unsigned IFaceId,
int ( *pf)(unsigned IFaceId ));
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pf | Hook that is called on IP_Disconnect(). |
Additional information
Typically for a pure Ethernet interface this functionality is
not needed. Typically it is used with dial-up interfaces or
interfaces that need more configurations to be set by the
application to work.
IP_SetOnPacketFreeCallback()
Description
This function sets a callback to be executed once the packet
has been freed.
Prototype
void IP_SetOnPacketFreeCallback
(IP_PACKET * pPacket,
void ( *pfOnFreeCB)(IP_PACKET * pPacketCB , void * pContextCB ),
void * pContext);
Parameters
Parameter | Description |
pPacket | Pointer to the packet. |
pfOnFreeCB | Callback that is notified on a packet free. |
pContext | Application context that will be passed to the callback once the packet gets freed. |
IP_SetPacketToS()
Description
Sets the value of the ToS/DSCP byte in the IP header of a packet
to be sent via the zero-copy API.
Prototype
void IP_SetPacketToS(IP_PACKET * pPacket,
U8 ToS);
Parameters
Parameter | Description |
pPacket | Pointer to packet buffer. |
ToS | ToS byte to use in packet when being sent. |
Additional information
The ToS (Type of Service) byte in the IPv4 header has been
reused as DSCP (Differentiated Services Code Point) byte with
its values remaining somewhat compatible between both use cases.
While the ToS field is only present for IPv4, the DSCP field
is present in the same way for IPv4 and IPv6 . If the user
intends to explicitly set a ToS value, it is the users
responsibility to make sure that he is applying it to an IPv4
packet only.
A good starting point regarding the ToS/DSCP field and its value
can be found at the following location:
IP_SetRxHook()
Description
Sets a hook function which will be called if target receives a packet.
Prototype
void IP_SetRxHook(IP_RX_HOOK * pfRxHook);
Parameters
Parameter | Description |
pfRxHook | Pointer to the callback function of type IP_RX_HOOK. |
Additional information
The return value of the callback function is relevant for the
further processing of the packet. A return value of 0 indicates
that the stack has to process the packet after the callback has
returned. A return value of >0 indicates that the packet will
be freed directly after the callback has returned.
The prototype for the callback function is defined as follows:
typedef int (IP_RX_HOOK)(IP_PACKET * pPacket);
Example
Refer to IP_ICMP_SetRxHook for an example.
IP_SetMicrosecondsCallback()
Description
Sets a callback that is used to get a timestamp in microseconds.
Prototype
void IP_SetMicrosecondsCallback(U64 ( *pfGetTime_us)());
Parameters
Parameter | Description |
pfGetTime_us | The callback to set. |
Additional information
Replaces a previously set IP_SetNanosecondsCallback() with an
internal conversion routine. If your system can provide a
nanosecond precise timestamp use IP_SetNanosecondsCallback()
only.
Example
IP_SetMicrosecondsCallback(OS_GetTime_us64);
IP_SetNanosecondsCallback()
Description
Sets a callback that is used to get a timestamp in nanoseconds.
Prototype
void IP_SetNanosecondsCallback(U64 ( *pfGetTime_ns)());
Parameters
Parameter | Description |
pfGetTime_ns | The callback to set. |
Additional information
Replaces previously set time callbacks of different time bases
with an internal conversion as required.
Stack internal functions, variables and data-structures
emNet internal functions, variables and data-structures are not explained here as
they are in no way required to use emNet. Your application should not rely on any
of the internal elements, as only the documented API functions are guaranteed to
remain unchanged in future versions of emNet.
The following data-structures are meant for public usage together with the documented API.
Structure BSP_IP_INSTALL_ISR_PARA
Description
Used to pass parameters for installing an ISR handler between driver and hardware
specific callback.
Prototype
typedef struct {
void (*pfISR)(void);
int ISRIndex;
int Prio;
} BSP_IP_INSTALL_ISR_PARA;
Member | Description |
pfISR | Interrupt handler to register. |
ISRIndex | Interrupt index given by the driver as reference. The index might
differ from hardware to hardware. |
Prio | Interrupt priority given by the driver as reference. Override this
with a priority that best fits your system. |
Structure BSP_IP_API
Description
Used to set callbacks for a driver to call hardware specific functions that can not be
handled in a generic way by the driver itself.
Prototype
typedef struct {
void (*pfInit) (unsigned IFaceId);
void (*pfDeInit) (unsigned IFaceId);
void (*pfInstallISR) (unsigned IFaceId, BSP_IP_INSTALL_ISR_PARA* pPara);
unsigned (*pfGetMiiMode) (unsigned IFaceId);
unsigned long (*pfGetEthClock)(void);
} BSP_IP_API;
Member | Description |
pfInit | Initializes port pins and clocks for Ethernet. Can be NULL. |
pfDeInit | De-initializes port pins and clocks for Ethernet. Can be NULL. |
pfInstallISR | Installs the driver interrupt handler. Can be NULL.
For further information regarding BSP_IP_INSTALL_ISR_PARA
please refer to Structure BSP_IP_INSTALL_ISR_PARA. |
pfGetMiiMode | Returns the MII mode that the pins have been configured for (0: MII, 1: RMII). Can be NULL. |
pfGetEthClock | Returns the clock frequency [Hz] used by the Ethernet peripheral for auto-configuration of internal parameters. Can be NULL. |
Additional information
For further information about how this structure is used please refer to
IP_BSP_SetAPI.
Structure SEGGER_CACHE_CONFIG
Description
Used to pass cache configuration and callback function pointers to the stack.
Prototype
typedef struct {
int CacheLineSize;
void (*pfDMB) (void);
void (*pfClean) (void *p, unsigned NumBytes);
void (*pfInvalidate)(void *p, unsigned NumBytes);
} SEGGER_CACHE_CONFIG;
Member | Description |
CacheLineSize | Length of one cache line of the CPU.
= 0: No Cache.
> 0: Cache line size in bytes.
Most Systems such as ARM9 use a 32 bytes cache line size. |
pfDMB | Pointer to a callback function that executes a DMB (Data Memory
Barrier) instruction to make sure all memory operations are completed.
Can be NULL. |
pfClean | Pointer to a callback function that executes a clean operation on
cached memory.
Can be NULL. |
pfInvalidate | Pointer to a callback function that executes a clean operation on
cached memory.
Can be NULL. |
Additional information
For further information about how this structure is used please refer to
IP_CACHE_SetConfig.
IP_STATS_IFACE
Description
Used to access the whole structure that can be accessed individually using the
IP_STATS_* functions. Primary usage for these information is utilizing them for SNMP
statistics, therefore their SNMP usage is explained.
Prototype
typedef struct {
U32 LastLinkStateChange;
U32 RxBytesCnt;
U32 RxUnicastCnt;
U32 RxNotUnicastCnt;
U32 RxDiscardCnt;
U32 RxErrCnt;
U32 RxUnknownProtoCnt;
U32 TxBytesCnt;
U32 TxUnicastCnt;
U32 TxNotUnicastCnt;
U32 TxDiscardCnt;
U32 TxErrCnt;
} IP_STATS_IFACE;
Member | Description (SNMP usage) |
LastLinkStateChange | SNMP: ifLastChange [TimeTicks]. Needs to be converted into in 1/100 seconds since SNMP epoch. |
RxBytesCnt | SNMP: ifInOctets [Counter]. |
RxUnicastCnt | SNMP: ifInUcastPkts [Counter]. |
RxNotUnicastCnt | SNMP: ifInNUcastPkts [Counter]. |
RxDiscardCnt | SNMP: ifInDiscards [Counter]. |
RxErrCnt | SNMP: ifInErrors [Counter]. |
RxUnknownProtoCnt | SNMP: ifInUnknownProtos [Counter]. |
TxBytesCnt | SNMP: ifOutOctets [Counter]. |
TxUnicastCnt | SNMP: ifOutUcastPkts [Counter]. |
TxNotUnicastCnt | SNMP: ifOutNUcastPkts [Counter]. |
TxDiscardCnt | SNMP: ifOutDiscards [Counter]. |
TxErrCnt | SNMP: ifOutErrors [Counter]. |
IP_HOOK_ON_IF_ERROR
Description
Callback executed for an error during interface initialization.
Type definition
typedef void (IP_HOOK_ON_IF_ERROR)(IP_DRIVER_INTERFACE_ERROR init,
int IFaceId,
int Errcode);
Parameters
Parameter | Description |
init | Gives information about which init failed. init = IP_DRIVER_INTERFACE_INIT_ERROR: Error during driver init. init = IP_DRIVER_INTERFACE_PHY_ERROR: Error during PHY Init. |
IFaceId | Number of interface that failed. |
ErrCode | Error Code. |
IP_ON_IFACE_SELECT_INFO
Description
Provides information about an internal interface selection for
an operation (typically sending without previous receive), as
well as to propose an interface.
Type definition
typedef struct {
int IFaceId;
const U32 * pLAddrV4;
const U32 * pFAddrV4;
const IPV6_ADDR * pLAddrV6;
const IPV6_ADDR * pFAddrV6;
U8 Flags;
} IP_ON_IFACE_SELECT_INFO;
Structure members
Member | Description |
IFaceId | Interface as proposed by internal selection. -1 if no suitable interface was found. |
pLAddrV4 | Pointer to local IPv4 address. NULL if not used. Value is in network endianness (big endian). |
pFAddrV4 | Pointer to foreign IPv4 address. NULL if not used. Value is in network endianness (big endian). |
pLAddrV6 | Pointer to local IPv6 address. NULL if not used. |
pFAddrV6 | Pointer to foreign IPv6 address. NULL if not used. |
Flags | ORR-ed combination of IP_IFACE_SELECT_FLAG_* : None : Looking for a unicast interface. IP_ON_IFACE_SELECT_FLAG_BROADCAST: Looking for an interface that is capable of broadcasting. IP_ON_IFACE_SELECT_FLAG_MULTICAST: Looking for an interface that is capable of multicast. |
Additional information
Most parameters are presented as pointers to the actual internal
value. If a parameter/pointer is NULL, this means that this
parameter was not involved in selecting the proposed interface.
If IFaceId is -1, this means no interface has been selected
by the internal procedure.
IP_ON_IFACE_SELECT_FUNC
Description
Callback executed for an internal interface selection. The
proposed interface selected internally can be overridden.
Type definition
typedef int (IP_ON_IFACE_SELECT_FUNC)(int PFamily,
IP_ON_IFACE_SELECT_INFO * pInfo);
Parameters
Parameter | Description |
PFamily | Protocol family (at the moment only PF_INET or PF_INET6). |
pInfo | Further information of type IP_ON_IFACE_SELECT_INFO about the interface selection parameters as well as the proposed interface, selected internally based upon these parameters. |
Return value
= -1 | No suitable interface. |
≥ 0 | Interface index to use. |
IP_ON_ICMPV4_FUNC
Description
Callback executed when an ICMPv4 packet is received.
Type definition
typedef int (IP_ON_ICMPV4_FUNC)(unsigned IFaceId,
IP_PACKET * pPacket,
void * pUserContext,
void * p);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pPacket | Packet that has been received. pPacket->pData points to the IPv4 header. |
pUserContext | User context given when adding the hook. |
p | Reserved for future extensions of this API. |
Return value
IP_OK | Packet has been handled (freed or reused). |
IP_OK_TRY_OTHER_HANDLER | Packet is untouched and stack shall try another handler. |
Additional information
The callback can remove its own hook using IP_ICMP_RemoveRxHook() .
IP_MEM_POOL_INFO
Description
Provides information about a memory pool managed by the stack.
Type definition
typedef struct {
PTR_ADDR BaseAddr;
U32 Size;
U32 Free;
U32 MaxFreeChunk;
} IP_MEM_POOL_INFO;
Structure members
Member | Description |
BaseAddr | Base address of the memory pool. |
Size | Total number of bytes managed for this pool. |
Free | Number of bytes available for allocation from this pool. |
MaxFreeChunk | Biggest chunk available for allocation. |
Additional information
Numbers such as free space and maximum chunk size that can be
allocated vary by a couple of bytes with values returned being
higher than what can be successfully allocated. This is due to
internal overhead and alignments that are calculated during
allocation processes that are not calculated when retrieving
this information about a pool and its free resources.
Socket interface
The emNet socket API is almost compatible to the Berkeley socket interface.
The Berkeley socket interface is the de facto standard for socket communication.
emNet specific functions allow an easier or even extended usage of some socket operations.
All API functions are described in this chapter.
API functions
The table below lists the available socket API functions.
accept()
Description
Accepts an incoming attempt on a socket.
Prototype
int accept(int Socket,
sockaddr * pSockAddr,
int * pAddrLen);
Parameters
Parameter | Description |
Socket | Socket handle. |
pSockAddr | An optional pointer to a buffer where the address of the connecting entity is stored. The format of the address depends on the defined address family which was defined when the socket was created. |
pAddrLen | As input an optional pointer to a variable with the maximum length of socket address that can be stored. Aa output an optional pointer to an integer where the length of the received address is stored. Just like the format of the address, the length of the address depends on the defined address family. |
Return value
≥ 0 | Socket handle of the socket on which the actual connection is made. |
= -1 | Error. |
Additional information
This call is used with connection-based socket types, currently with SOCK_STREAM .
Refer to socket() for more information about the different socket types.
Before calling accept() , the used socket Socket has to be bound to an address with
bind() and should be listening for connections after calling listen() . accept()
extracts the first connection on the queue of pending connections, creates a new
socket with the same properties of Socket and allocates a new file descriptor for the
socket. If no pending connections are present on the queue, and the socket is not
marked as non-blocking, accept() blocks the caller until a connection is present. If
the socket is marked non-blocking and no pending connections are present on the
queue, accept() returns and reports an error. The accepted socket is used to read
and write data to and from the socket which is connected to this one; it is not used to
accept more connections. The original socket Socket remains open for accepting further connections.
The argument pSockAddr is a result parameter that is filled in with the address of the
connecting entity as known to the communications layer. The exact format of the
pSockAddr parameter is determined by the domain in which the communication is occurring.
The pAddrLen is a value-result parameter. It should initially contain the amount
of space pointed to by pSockAddr .
Example
The following sample can be used to retrieve information about the accepted client:
struct sockaddr_in Client;
...
struct sockaddr_in Addr;
int AddrLen;
AddrLen = sizeof(Addr);
if ((hSock = accept(hSockListen, (struct sockaddr*)&Addr, &AddrLen)) ==
SOCKET_ERROR) {
continue; // Error
}
...
For example the peer IP address can then be retrieved in network endianness from
Addr.sin_addr.s_addr.
bind()
Description
Assigns a name (port) to an unnamed socket.
Prototype
int bind(int Socket,
sockaddr * pSockAddr,
int AddrLen);
Parameters
Parameter | Description |
Socket | Socket handle. |
pSockAddr | A pointer to a buffer where the address of the connecting entity is stored. The format of the address depends on the defined address family which was defined when the socket was created. |
AddrLen | The length of the address. |
Return value
Additional information
When a socket is created with socket() it exists in a name space (address family)
but has no name assigned. bind() is used on an unconnected socket before subsequent
calls to the connect() or listen() functions. bind() assigns the name
pointed to by pSockAddr to the socket.
closesocket()
Description
Closes a socket.
Prototype
int closesocket(int Socket);
Parameters
Parameter | Description |
Socket | Socket handle. |
Return value
0 | On success. |
-1 | On failure. |
Additional information
closesocket() closes a connection on the socket associated with Socket and the
socket descriptor associated with Socket will be returned to the free socket descriptor pool.
Once a socket is closed, no further socket calls should be made with it.
If the socket promises reliable delivery of data and SO_LINGER is set, the system will
block the caller on the closesocket() attempt until it is able to transmit the data or
until it decides it is unable to deliver the information (a timeout period, termed the
linger interval, is specified in the setsockopt() call when SO_LINGER is requested).
If SO_LINGER is disabled and a closesocket() is issued, the system will process the
close in a manner that allows the caller to continue as quickly as possible. If
SO_LINGER is enabled with a timeout period of ’0’ and a closesocket() is issued, the
system will perform a hard close.
Example
/*********************************************************************
*
* _CloseSocketGracefully()
*
* Function description
* Wrapper for closesocket() with linger enabled to verify a gracefull
* disconnect.
*/
static int _CloseSocketGracefully(long pConnectionInfo) {
struct linger Linger;
Linger.l_onoff = 1; // Enable linger for this socket.
Linger.l_linger = 1; // Linger timeout in seconds
setsockopt(hSocket, SOL_SOCKET, SO_LINGER, &Linger, sizeof(Linger));
return closesocket(hSocket);
}
/*********************************************************************
*
* _CloseSocketHard()
*
* Function description
* Wrapper for closesocket() with linger option enabled to perform a hard close.
*/
static int _CloseSocketHard(long hSocket) {
struct linger Linger;
Linger.l_onoff = 1; // Enable linger for this socket.
Linger.l_linger = 0; // Linger timeout in seconds
setsockopt(hSocket, SOL_SOCKET, SO_LINGER, &Linger, sizeof(Linger));
return closesocket(hSocket);
}
connect()
Description
Establishes a connection to a socket.
Prototype
int connect(int Socket,
sockaddr * pSockAddr,
int AddrLen);
Parameters
Parameter | Description |
Socket | Socket handle. |
pSockAddr | A pointer to a buffer where the address of the connecting entity is stored. The format of the address depends on the defined address family which was defined when the socket was created. |
AddrLen | A pointer to an integer where the length of the received address is stored. Just like the format of the address, the length of the address depends on the defined address family. |
Return value
0 | On success. |
-1 | On failure. |
Additional information
If Socket is of type SOCK_DGRAM or SOCK_RAW, then this call specifies the peer with
which the socket is to be associated. pAddr defines the address to which datagrams
are sent and the only address from which datagrams are received.
To enable RAW socket support in the IP stack it is madatory to call IP_RAW_Add()
during initialization of the stack.
If Socket is of type SOCK_STREAM , then this call attempts to make a connection to
another socket. The other socket is specified by pSockAddr which is an address in the
communications space of the socket. Each communications space interprets the
pSockAddr parameter in its own way.
Generally, stream sockets may successfully connect() only once; datagram sockets
may use connect() multiple times to change their association. Datagram sockets
may dissolve the association by connecting to an invalid address, such as a NULL
address.
If a connect is in progress and the socket is blocking, the connect call waits until connected
or an error to happen. If the socket is non-blocking (refer to setsockopt() for more information), 0 is returned.
You can use the getsockopt() function to determine the status of the connect attempt.
The timeout for a connect attempt can be configured via the Init parameter of
IP_TCP_SetConnKeepaliveOpt().
Example
#define SERVER_PORT 1234
#define SERVER_IP_ADDR 0xC0A80101 // 192.168.1.1
/*********************************************************************
*
* _TCPClientTask
*
* Function description
* Creates a connection to a given IP address, TCP port.
*/
static void _TCPClientTask(void) {
int TCPSockID;
struct sockaddr_in ServerAddr;
int ConnectStatus;
//
// Wait until link is up. This can take 2-3 seconds if PHY has been reset.
//
while (IP_GetCurrentLinkSpeed() == 0) {
OS_Delay(100);
}
while(1) {
TCPSockID = socket(AF_INET, SOCK_STREAM, 0); // Open socket
if (TCPSockID < 0) { // Error, Could not get socket
while (1) {
OS_Delay(20);
}
} else {
//
// Connect to server
//
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(SERVER_PORT);
ServerAddr.sin_addr.s_addr = htonl(SERVER_IP_ADDR);
ConnectStatus = connect(TCPSockID,
(struct sockaddr *)&ServerAddr,
sizeof(struct sockaddr_in));
if (ConnectStatus == 0) {
//
// Do something...
//
}
}
closesocket(TCPSockID);
OS_Delay(50);
}
}
gethostbyname()
Description
Resolve a host name into an IP address.
Prototype
gethostbyname(const char * sName);
Parameters
Parameter | Description |
sName | Host name to resolve. |
Return value
OK: Pointer to a hostent structure
Error: NULL if not successful.
Additional information
The function is called with a string containing the host name
to be resolved as a fully-qualified domain name (for example,
myhost.mydomain.com).
Example
static void _DNSClient() {
struct hostent *pHostEnt;
char **ps;
char **ppAddr;
//
// Wait until link is up.
//
while (IP_IFaceIsReady() == 0) {
OS_Delay(100);
}
while(1) {
pHostEnt = gethostbyname("www.segger.com");
if (pHostEnt == NULL) {
printf("Could not resolve host addr.\n");
break;
}
printf("h_name: %s\n", pHostEnt->h_name);
//
// Show aliases
//
ps = pHostEnt->h_aliases;
for (;;) {
char * s;
s = *ps++;
if (s == NULL) {
break;
}
printf("h_aliases: %s\n", s);
}
//
// Show IP addresses
//
ppAddr = pHostEnt->h_addr_list;
for (;;) {
U32 IPAddr;
char * pAddr;
char ac[16];
pAddr = *ppAddr++;
if (pAddr == NULL) {
break;
}
IPAddr = *(U32*)pAddr;
IP_PrintIPAddr(ac, IPAddr, sizeof(ac));
printf("IP Addr: %s\n", ac);
}
}
}
Warning
gethostbyname() is not thread safe and should therefore only be used where absolutely necessary. If possible use the thread safe function IP_ResolveHost() instead.
getpeername()
Description
Fills the passed structure sockaddr with the IP addressing
information of the connected host.
Prototype
int getpeername(int Socket,
sockaddr * pSockAddr,
int * pAddrLen);
Parameters
Parameter | Description |
Socket | Socket handle. |
pSockAddr | A pointer to a structure of type sockaddr in which the IP address information of the connected host should be stored. |
pAddrLen | Max. size of address to return without exceeding the output buffer. |
Return value
Additional information
Refer to sockaddr for detailed information about the structure sockaddr.
Example
The following sample can be used to retrieve information about the peer host from an
existing connection:
struct sockaddr_in Client;
int i;
...
if ((hSock = accept(hSockListen, &Addr, &AddrLen)) == SOCKET_ERROR) {
continue; // Error
}
i = sizeof(Client);
getpeername(hSock, (struct sockaddr*)&Client, &i);
...
For example the peer IP address can then be retrieved in network endianness from
Client.sin_addr.s_addr.
getsockname()
Description
Returns the current address to which the socket is bound in the
buffer pointed to by pAddr.
Prototype
int getsockname(int Socket,
sockaddr * pSockAddr,
int * pAddrLen);
Parameters
Parameter | Description |
Socket | Socket handle. |
pSockAddr | A pointer to a structure of type sockaddr in which the IP address information of the connected host should be stored. |
pAddrLen | Max. size of address to return without exceeding the output buffer. |
Return value
Additional information
Refer to sockaddr for detailed information about the structure sockaddr.
getsockopt()
Description
Returns the options associated with a socket.
Prototype
int getsockopt(int Socket,
int Level,
int Option,
void * pVal,
int ValLen);
Parameters
Parameter | Description |
Socket | Socket handle. |
Level | Compatibility parameter for setsockopt() and getsockopt(). Use symbol SOL_SOCKET. |
Option | The socket option which should be retrieved. |
pVal | A pointer to the buffer in which the value of the requested option should be stored. |
ValLen | The size of the data buffer. |
Return value
Valid values for parameter Option
Value | Description |
SO_DONTROUTE | Indicates that outgoing messages must bypass
the standard routing facilities. |
SO_KEEPALIVE | Indicates that the periodic transmission of messages
on a connected socket is enabled. If the
connected party fails to respond to these messages,
the connection is considered broken.
For keepalive behavior configuration please refer
to IP_TCP_SetConnKeepaliveOpt(). |
SO_LINGER | Controls the action taken when unsent messages
are queued on a socket and a closesocket() is
performed. Refer to closesocket()
for detailed information about the linger option. |
SO_NOSLOWSTART | Determines if suppressing slow start on this socket
is enabled. This option stores an integer value which will
contain a non-zero value to suppress slow start
or a 0 value to let the socket slow start. |
SO_BROADCAST | Determines if sending broadcasts for UDP communication
is permitted. |
SO_REUSEADDR | Determines if reusing local addresses is allowed
when using bind() on a socket. This option
stores an integer which will contain a non-zero value
to allow reusing addresses or a 0 value to disallow
reusing addresses. |
SO_RCVTIMEO | Determines the timeout for recv() in ms. A return
value of 0 indicates that no timeout is set.
This changes the behavior of recv(). recv() is
by default a blocking function which only returns
if data has been received. If a timeout is set
recv() will return in case of data reception or
timeout. |
SO_SNDTIMEO | Determines the timeout for send() in ms. A return
value of 0 indicates that no timeout is set.
This changes the behavior of send(). send() is
by default a blocking function which only returns
if data has been received. If a timeout is set
send() will return in case of data reception or
timeout. |
SO_NONBLOCK | Determines sockets blocking status. This option stores
an integer which will contain a non-zero value to
set non-blocking IO or a 0 value to reset non-blocking IO. |
SO_SNDBUF | Determines the TX buffer size in bytes. |
SO_RCVBUF | Determines the RX buffer size in bytes. |
SO_MAXMSG | Determines the Maximum TCP segment size. |
IP_HDRINCL | Determines if the IP header has to be included by
the user for a RAW socket or if the IP header is
generated by the stack. |
IP_DONTFRAG | Determines if fragmentation of large packets is permitted.
This option stores an integer value which will
contain a non-zero value to suppress fragmentation
or a 0 value to allow fragmentation. |
IP_TOS | Determines the IPv4 type of service. |
IP_TTL | Determines the IPv4 time to live. |
IP_MULTICAST_TTL | Determines the IPv4 multicast time to live. |
TCP_MAXSEG | Determines the maximum segment size in bytes. |
TCP_ACKDELAYTIME | Determines the time for delayed acks in milliseconds. |
TCP_NOACKDELAY | Determines if delayed ACKs are suppressed. |
TCP_NODELAY | Determines if Nagle’s Algorithm is disabled.
This option stores an integer value which will
contain a non-zero value to disable Nagle’s Algorithm
or a 0 value to enable Nagle’s Algorithm. |
SO_ERROR | Stores the latest socket error in pVal and clears
the error in the socket structure. |
SO_MYADDR | Stores the IP address of the used interface in
pVal. |
SO_TYPE | Determines the socket type. For valid socket types refer to |
SO_TXDATA | Stores the amount of data currently in the TX buffer in bytes. |
SO_RXDATA | Stores the amount of data currently in the RX buffer in bytes. |
SO_NBIO | Sets socket non-blocking status.
The specified value will be ignored. |
SO_BIO | Sets socket blocking status.
The specified value will be ignored. |
SO_CALLBACK | Sets zero-copy callback routine. Refer to
TCP zero-copy interface for detailed information. |
IPV6_UNICAST_HOPS | Set the unicast hop limit for the socket. |
IPV6_JOIN_GROUP | Used to join a multicast group on a specified interface. |
IPV6_LEAVE_GROUP | Used to leave a multicast group on a specified interface. |
Additional information
getsockopt() retrieves the current value for a socket option associated with a
socket of any type, in any state, and stores the result in pVal. Options can exist at
multiple protocol levels, but they are always present at the uppermost “socket” level.
Options affect socket operations, such as the packet routing.
The value associated with the selected option is returned in the buffer pVal. The
integer pointed to by ValLen should originally contain the size of this buffer; on
return, it will be set to the size of the value returned. For SO_LINGER, this will be the
size of a LINGER structure. For most other options, it will be the size of an integer.
The application is responsible for allocating any memory space pointed to directly or
indirectly by any of the parameters it specified. If the option was never set with
setsockopt(), then getsockopt() returns the default value for the option.
The option SO_ERROR returns 0 or the number of the socket error and clears the
socket error. The following table lists the socket errors.
Symbolic name | Value | Description |
IP_ERR_SEND_PENDING | 1 | Packet to send is not sent yet. |
IP_ERR_MISC | -1 | Miscellaneous errors that do not have a
specific error code. |
IP_ERR_TIMEDOUT | -2 | Operation timed out. |
IP_ERR_ISCONN | -3 | Socket is already connected. |
IP_ERR_OP_NOT_SUPP | -4 | Operation not supported for selected socket. |
IP_ERR_CONN_ABORTED | -5 | Connection was aborted. |
IP_ERR_WOULD_BLOCK | -6 | Socket is in non-blocking state and the
current operation would block the socket
if not in non-blocking state. |
IP_ERR_CONN_REFUSED | -7 | Connection refused by peer. |
IP_ERR_CONN_RESET | -8 | Connection has been reset. |
IP_ERR_NOT_CONN | -9 | Socket is not connected. |
IP_ERR_ALREADY | -10 | Socket already is in the requested state. |
IP_ERR_IN_VAL | -11 | Passed value for configuration is not
valid. |
IP_ERR_MSG_SIZE | -12 | Message is too big to send. |
IP_ERR_PIPE | -13 | Socket is not in the correct state for this
operation. |
IP_ERR_DEST_ADDR_REQ | -14 | Destination addr. has not been specified. |
IP_ERR_SHUTDOWN | -15 | Connection has been closed as soon as
all data has been received upon a FIN
request. |
IP_ERR_NO_PROTO_OPT | -16 | Unknown socket option for setsockopt()
or getsockopt(). |
IP_ERR_ADDR_NOT_AVAIL | -19 | No known path to send to the specified
addr. |
IP_ERR_ADDR_IN_USE | -20 | Socket already has a connection to this
addr. and port or is already bound to this
addr. |
IP_ERR_IN_PROGRESS | -22 | Operation is still in progress. |
IP_ERR_NO_BUF | -23 | No internal buffer was available. |
IP_ERR_NOT_SOCK | -24 | Socket has not been opened or has
already been closed |
IP_ERR_FAULT | -25 | Generic error for a failed operation. |
IP_ERR_NET_UNREACH | -26 | No path to the desired network available. |
IP_ERR_PARAM | -27 | Invalid parameter to function. |
IP_ERR_LOGIC | -28 | Logical error that should not have happened. |
IP_ERR_NOMEM | -29 | System error: No memory for requested
operation. |
IP_ERR_NOBUFFER | -30 | System error: No internal buffer available for the requested operation. |
IP_ERR_RESOURCE | -31 | System error: Not enough free resources
available for the requested operation. |
IP_ERR_BAD_STATE | -32 | Socket is in an unexpected state. |
IP_ERR_TIMEOUT | -33 | Requested operation timed out. |
IP_ERR_NO_ROUTE | -36 | Net error: Destination is unreachable. |
IP_ERR_QUEUE_FULL | -37 | No more packets can be queued for sending.
Typically caused by packets waiting
for an ARP response to be fulfilled. |
IP_ERR_USER_ABORT | -38 | When IP_SOCKET_AbortRead() was used on a socket
that is currently waiting blocked in recv() or
other API. |
listen()
Description
Prepares the socket to accept connections.
Prototype
int listen(int Socket,
int Backlog);
Parameters
Parameter | Description |
hSock | Socket handle. |
Backlog | Backlog for incoming connections. Defines the maximum length of the queue of pending connections. |
Return value
Additional information
The Backlog parameter uses a one by one mapping of its values,
meaning the given number means exactly the amount of connections
that can be accepted before being processed by calling accept() .
As the Backlog parameter is not standardized, other stacks might
use different value mappings.
A Backlog parameter of 0 will be increased to 1 as not accepting
any connections does not make sense.
Example
/*********************************************************************
*
* _ListenAtTcpAddr
*
* Function description
* Starts listening at the given TCP port.
*/
static int _ListenAtTcpAddr(U16 Port) {
int Sock;
struct sockaddr_in Addr;
Sock = socket(AF_INET, SOCK_STREAM, 0);
memset(&Addr, 0, sizeof(Addr));
Addr.sin_family = AF_INET;
Addr.sin_port = htons(Port);
Addr.sin_addr.s_addr = INADDR_ANY;
bind(Sock, (struct sockaddr *)&Addr, sizeof(Addr));
listen(Sock, 1);
return Sock;
}
recv()
Description
Receives data from a connected socket.
Prototype
int recv(int Socket,
char * pData,
int NumBytes,
int Flag);
Parameters
Parameter | Description |
Socket | Handle on the socket. |
pData | A pointer to a buffer for incoming data. |
NumBytes | Number of bytes of the buffer. |
Flag | OR-combination of flags (MSG_PEEK). |
Return value
= -1 | Error occurred. |
= 0 | Connection was gracefully closed. |
> 0 | Number of bytes received. |
Additional information
If a message is too long to fit in the supplied buffer, excess bytes may be discarded
depending on the type of socket the message is received from. Refer to socket()
for more information about the different types of sockets.
You can only use the recv() function on a connected socket. To receive data on a
socket, whether it is in a connected state or not refer to recvfrom().
If no messages are available at the socket and the socket is blocking, the receive call
waits for a message to arrive. If the socket is non-blocking (refer to setsockopt()
for more information), -1 is returned.
You can use the select() function to determine when more data arrives.
Valid values for parameter Flag
Value | Description |
MSG_PEEK | “Peek” at the data present on the socket; the data
are returned, but not consumed, so that a subsequent receive operation will see the same data. |
recvfrom()
Description
Receives a datagram and stores the source address.
Prototype
int recvfrom(int Socket,
char * pData,
int NumBytes,
int Flag,
sockaddr * pFrom,
int * pFromLen);
Parameters
Parameter | Description |
Socket | Handle on the socket. |
pData | A pointer to a buffer for incoming data. |
NumBytes | Number of bytes of the buffer pointed by pData. |
Flag | OR-combination of flags (MSG_PEEK). |
pFrom | An optional pointer to a buffer where the address of the connecting entity is stored. The format of the address depends on the defined address family which was defined when the socket was created. Can be NULL. |
pFromLen | An optional pointer to an integer where the length of the received address is stored. Just like the format of the address, the length of the address depends on the defined address family. |
Return value
= -1 | Error occurred. |
≥ 0 | Number of bytes received. |
Additional information
If pFrom is not a NULL pointer, the source address of the message is filled in.
pFromLen is a value-result parameter, initialized to the size of the buffer associated with
pFrom , and modified on return to indicate the actual size of the address stored there.
If a message is too long to fit in the supplied buffer, excess bytes may be discarded
depending on the type of socket the message is received from. Refer to socket()
for more information about the different types of sockets.
If no messages are available at the socket and the socket is blocking, the receive call
waits for a message to arrive. If the socket is non-blocking (refer to setsockopt()
for more information), -1 is returned.
You can use the select() function to determine when more data arrives.
Valid values for parameter Flag
Value | Description |
MSG_PEEK | “Peek” at the data present on the socket; the data
are returned, but not consumed, so that a subsequent receive operation will see the same data. |
select()
Description
Provides a UNIX-like socket select() call.
Prototype
int select(IP_fd_set * readfds,
IP_fd_set * writefds,
IP_fd_set * exceptfds,
I32 timeout);
Parameters
Parameter | Description |
readfds | Read file descriptor set. Can be NULL. |
writefds | Write file descriptor set. Can be NULL. |
exceptfds | Exception file descriptor set. Can be NULL. |
timeout | Maximum timeout [ms] that select() should block, waiting for any file descriptor in any given FD_SET to become ready. timeout of 0 will result in the function retuning immediately. timeout of -1 will cause the function to block indefinitely (until one of the descriptors becomes ready or an error occurs). |
Return value
= < 0 (SOCKET_ERROR) | Error occurred. |
= < 0 (IP_ERR_USER_ABORT) | Only when calling IP_SOCKET_AbortRead() on a socket that is part of the readfds . |
= 0 | Timeout. |
> 0 | Number of ready file descriptors (sockets) returned over all given descriptor sets. |
Additional information
The select() call overwrites the given descriptor sets with
subsets consisting of those file descriptors (sockets) that
are ready. The descriptor sets readfds, writefds and exceptfds
may be omitted using NULL if no file descriptors are of interest
for the specific operation.
In the standard Berkeley UNIX Sockets API, the descriptor sets are stored as bit
fields in arrays of integers. This works in the UNIX environment because under UNIX
socket descriptors are file system descriptors which are guaranteed to be small integers
that can be used as indexes into the bit fields. In emNet, socket descriptors
are pointers and thus a bit field representation of the descriptor sets is not feasible.
Because of this, the emNet API differs from the Berkeley standard in that the
descriptor sets are represented as instances of the following structure:
typedef struct IP_FD_SET { // The select socket array manager
unsigned fd_count; // how many are SET?
long fd_array[FD_SETSIZE]; // an array of SOCKETs
} IP_fd_set;
Instead of a socket descriptor being represented in a descriptor set via an indexed
bit, an emNet socket descriptor is represented in a descriptor set by its presence
in the fd_array field of the associated IP_fd_set structure. Despite this
non-standard representation of the descriptor sets themselves, the following standard entry
points are provided for manipulating such descriptor sets: IP_FD_ZERO(&fdset)
initializes a descriptor set fdset to the null set. IP_FD_SET(fd, &fdset) includes a
particular descriptor, fd , in fdset. IP_FD_CLR(fd, &fdset) removes fd from fdset.
IP_FD_ISSET(fd, &fdset) is nonzero if fd is a member of fdset, zero otherwise.
These entry points behave according to the standard Berkeley semantics.
You should be aware that the value of FD_SETSIZE defines the maximum number of descriptors that can be represented in a single descriptor set.
The default value of FD_SETSIZE is 12. This value can be increased in the source code version of emNet to accommodate a larger maximum number of descriptors at the cost of increased processor stack usage.
Another difference between the Berkeley and emNet select() calls is the
representation of the timeout parameter. Under Berkeley Sockets, the timeout parameter
is represented by a pointer to a structure. Under emNet sockets, a timeout is
specified by the timeout parameter, which defines the maximum number of milliseconds
that should elapse before the call to select() returns. A timeout parameter equal to 0
implies that select() should return immediately (effectively a poll of the sockets in
the descriptor sets). A timeout parameter equal to -1 implies that select() blocks forever
unless one of its descriptors becomes ready.
The final difference between the Berkeley and emNet versions of select() is the
absence in the emNet version of the Berkeley width parameter. The width parameter
is of use only when descriptor sets are represented as bit arrays and was thus
deleted in the emNet implementation.
Note:
Under rare circumstances, select() may indicate that a descriptor is
ready for writing when in fact an attempt to write would block. This can happen if
system resources necessary for a write are exhausted or otherwise unavailable. If an
application deems it critical that writes to a file descriptor not block, it should set the
descriptor for non-blocking I/O. Refer to setsockopt for detailed information.
Example
static void _Client() {
long Socket;
struct sockaddr_in Addr;
IP_fd_set readfds;
char RecvBuffer[1472]
int r;
while (IP_IFaceIsReady() == 0) {
OS_Delay(100);
}
Restart:
Socket = socket(AF_INET, SOCK_DGRAM, 0); // Open socket
Addr.sin_family = AF_INET;
Addr.sin_port = htons(2222);
Addr.sin_addr.s_addr = INADDR_ANY;
r = bind(Socket, (struct sockaddr *)&Addr, sizeof(Addr));
if (r == -1){
socketclose(Socket);
OS_Delay(1000);
goto Restart;
}
while(1) {
IP_FD_ZERO(&readfds); // Clear the set
IP_FD_SET(Socket, &readfds); // Add descriptor to the set
r = select(&readfds, NULL, NULL, 5000); // Check for activity.
if (r <= 0) {
continue; // No socket activity or error detected
}
if (IP_FD_ISSET(Socket, &readfds)) {
IP_FD_CLR(Socket, &readfds); // Remove socket from set
r = recvfrom(Socket, RecvBuffer, sizeof(RecvBuffer), 0, NULL, NULL);
if (r == -1){
socketclose(Socket)
goto Restart;
}
}
OS_Delay(100);
}
}
send()
Description
Hands data to the stack in order to send it to a connected socket.
The stack will copy the data into the socket buffer.
In blocking mode, the function returns when all data have been
accepted by the stack.
If non blocking mode, the function returns immediately.
Prototype
int send( int Socket,
const char * pBuffer,
int NumBytes,
int Flags);
Parameters
Parameter | Description |
Socket | Socket handle to a connected socket |
pBuffer | Pointer to a buffer that contains data to send |
NumBytes | Number of bytes to send from pBuffer |
Flags | OR-combination of one or more of the valid values listed in the table below. |
Return value
< 0 | Error (SOCKET_ERROR). |
≥ 0 | OK, Number of bytes accepted by the stack and ready to be sent. Note: In blocking mode this can only be the full number of bytes, since the function would otherwise block. |
Additional information
send() may be used only when the socket is in a connected state. Refer to sendto()
for information about sending data to a non-connected socket.
If no messages space is available at the socket to hold the message to be transmitted,
then send() normally blocks, unless the socket has been placed in non-blocking
I/O mode.
MSG_DONTROUTE is usually used only by diagnostic or routing programs.
Valid values for parameter Flags
Value | Description |
MSG_DONTROUTE | Specifies that the data should not be subject to routing. |
sendto()
Description
Hands data to the stack in order to send it to a specified
address on a socket.
The stack will copy the data into the socket buffer.
In blocking mode, the function returns when all data have been
accepted by the stack.
If non blocking mode, the function returns immediately.
Prototype
int sendto( int Socket,
const char * pBuffer,
int NumBytes,
int Flags,
sockaddr * pDestAddr,
int NumBytesAddr);
Parameters
Parameter | Description |
Socket | Socket handle |
pBuffer | Pointer to a buffer that contains data to send |
NumBytes | Number of bytes to send from pBuffer |
Flags | Ignored at the moment |
pDestAddr | Pointer to a buffer containing the destination address |
NumBytesAddr | Length of the address stored at pDestAddr in bytes |
Return value
< 0 | Error (SOCKET_ERROR). |
≥ 0 | OK, Number of bytes accepted by the stack and ready to be sent. Note: In blocking mode this can only be the full number of bytes, since the function would otherwise block. |
Additional information
In contrast to send(), sendto() can be used at any time. The connection state is in
which case the address of the target is given by the pDestAddr parameter.
Valid values for parameter Flags
Value | Description |
MSG_DONTROUTE | Specifies that the data should not be subject to routing. |
setsockopt()
Description
Configures some options for the socket.
Prototype
int setsockopt( int Socket,
int Level,
int Name,
const void * pVal,
int ValLen);
Parameters
Parameter | Description |
Socket | Socket handle. |
Level | Level at which the option should be interpreted (SOL_SOCKET for example). |
Name | Option enum. |
pVal | Pointer on the value for the given option. |
ValLen | Length of the data pointed by pVal. |
Return value
Valid values for parameter Option
For valid values and options please refer to getsockopt().
Example
void _EnableKeepAlive(long sock) {
int v = 1;
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &v, sizeof(v));
}
shutdown()
Description
Stops specific activities on a socket.
Prototype
int shutdown(int hSock,
int How);
Parameters
Parameter | Description |
hSock | Socket handle. |
How | One of the following modes: SHUT_RD : No more receive operations. SHUT_WR : No more send operations. SHUT_RDWR: No more receive & send operations. |
Return value
0 | Success. |
-1 | SOCKET_ERROR |
Additional information
A shutdown() call causes all or a part of a full-duplex connection on the socket
associated to be shut down. If How is SHUT_RD, then further receives will be
disallowed. If How is SHUT_WR, then further sends will be disallowed. If How is 2,
then further receives and sends will be disallowed. The shutdown function does not
block regardless of the SO_LINGER setting on the socket.
socket()
Description
Creates a socket.
Prototype
int socket(int Domain,
int Type,
int Proto);
Parameters
Parameter | Description |
Domain | Protocol family which should be used. |
Type | Specifies the type of the socket. |
Proto | Specifies the protocol which should be used with the socket. Must be set to zero except when Type is SOCK_RAW. |
Return value
= -1 | In case of error. |
≥ 0 | Socket handle. |
Valid values for parameter Domain
Value | Description |
AF_INET | IPv4 - Internet protocol version 4 |
AF_INET6 | IPv6 - Internet protocol version 6 |
Valid values for parameter Type
Value | Description |
SOCK_STREAM | Stream socket |
SOCK_DGRAM | Datagram socket |
SOCK_RAW | RAW socket |
Additional information
The Domain parameter specifies a communication domain within which communication
will take place; the communication domain selects the protocol family which
should be used. The protocol family generally is the same as the address family for
the addresses supplied in later operations on the socket.
A SOCK_STREAM socket provides sequenced, reliable, two-way connection based byte
streams. A SOCK_DGRAM socket supports datagrams (connectionless, unreliable
messages of a fixed - typically small - maximum length).
Sockets of type SOCK_STREAM are full-duplex byte streams, similar to UNIX pipes. A
stream socket must be in a connected state before it can send or receive data.
A connection to another socket is created with a connect() call. Once connected,
data can be transferred using send() and recv() calls. When a session has been
completed, a closesocket() should be performed.
The communications protocols used to implement a SOCK_STREAM ensure that data is
not lost or duplicated. If a piece of data (for which the peer protocol has buffer
space) cannot be successfully transmitted within a reasonable length of time, then
the connection is considered broken and calls will return -1 which indicates an error.
The protocols optionally keep sockets “warm” by forcing transmissions roughly every
minute in the absence of other activity. An error is then indicated if no response can
be elicited on an otherwise idle connection for a extended period (such as five minutes).
When receiving data from a socket of type SOCK_STREAM only up to the requested
amount of data is consumed from the socket buffer upon calling a receive routine.
Excess bytes of a message remain in the socket buffer and are available upon further
calls to the receive routine.
When receiving data from a socket that is not of type SOCK_STREAM like a socket of
type SOCK_DGRAM or SOCK_RAW one complete message (in the chunk as it was
received) will be consumed and excess bytes of this message that are not read out of
the buffer will be discarded and are not available for further calls to the receive routine.
SOCK_DGRAM sockets allow sending of datagrams to correspondents named in
sendto() calls. Datagrams are generally received with recvfrom(), which returns
the next datagram with its return address.
SOCK_RAW sockets allow receiving data including network and IP header and allow
sending of data either with or without specifying the IP header yourself. RAW sockets
are operated the same way as SOCK_DGRAM sockets but allow the ability to receive
data including the IP and protocol header and to implement your own protocol.
For using RAW sockets it is mandatory to call IP_RAW_Add during the
initialization of the stack.
More information about RAW sockets can be found below.
The operation of sockets is controlled by socket-level options. The getsockopt() and
setsockopt() functions are used to get and set options. Refer to getsockopt
and setsockopt for detailed information.
RAW sockets (receiving)
For RAW sockets the Proto parameter specifies the IP protocol that will be received
using this socket. Protocols registered to be used with IP_*_Add() will be handled
the stack and can not be used with RAW sockets at the same time. Using
IPPROTO_RAW will receive data for any protocol not handled by the IP stack.
RAW sockets (sending)
For RAW sockets the Proto parameter specifies the IP protocol that will be entered
into the IP header when sending data using this socket. Using IPPROTO_RAW for Proto
for a sending socket results in the same as setting the socket option IP_HDRINCL for
this socket by using setsockopt and requires the user to include his
own IP header in the data to send.
IP_RAW_AddPacketToSocket()
Description
Adds a packet and its data to a RAW socket (buffer).
The current pData pointer and NumBytes of the packet will be
used for the payload that will be added to the RAW socket (buffer).
Prototype
int IP_RAW_AddPacketToSocket(int hSock,
IP_PACKET * pPacket);
Parameters
Parameter | Description |
hSock | Socket handle of a RAW socket. |
pPacket | Packet to add to socket (buffer). |
Return value
≥ 0 | O.K., packet is now handled by the stack. |
< 0 | Error. Packet has to be freed by application. |
Additional information
This function can be used to imitate a packet socket using RAW
socket API. As the new data gets stored into the socket buffer
without traversing all the way through other layers like IPv4,
it is more effective but lacks a proper IP header. Therefore
things like getting the source address using recvfrom() is not
supported and will return invalid data.
IP_SOCKET_AbortRead()
Description
Aborts a blocking recv(), recvfrom() and its variations or
select() call on a socket.
Prototype
int IP_SOCKET_AbortRead(int hSock);
Parameters
Parameter | Description |
hSock | Socket handler. |
Return value
0 | O.K. |
-1 (SOCKET_ERROR) | Error, socket is invalid. |
Additional information
Using this routine on a socket that is currently waited on using
recv() or recvfrom() or one of its variations aborts the blocking
wait process. The waiting API sets IP_ERR_USER_ABORT as socket error.
For select() instead of SOCKET_ERROR , select() directly returns
IP_ERR_USER_ABORT instead of SOCKET_ERROR if the socket aborted
was part of the “read” FD_SET .
IP_SOCKET_AddGetSetOptHook()
Description
This function adds a callback that gets executed when the application
uses getsockopt()/setsockopt() with the registered option.
Prototype
void IP_SOCKET_AddGetSetOptHook(IP_SOCK_HOOK_ON_SETGETOPT * pHook,
IP_SOCK_HOOK_ON_GETSETOPT_FUNC * pf,
int Name);
Parameters
Parameter | Description |
pHook | Management block of type IP_SOCK_HOOK_ON_SETGETOPT . |
pf | Callback to execute on getsockopt()/setsockopt() . |
Name | Option name for which the callback gets executed. To avoid conflicts between newly added and existing option names, the base of IP_SOCK_GETSETOPT_HOOK_NAME_BASE should be used when implementing your own options. |
Example
enum {
APP_SOCK_OPT_VENDOR_NAME = IP_SOCK_GETSETOPT_HOOK_NAME_BASE
};
static char _acVendor[32];
static IP_SOCK_HOOK_ON_SETGETOPT _SockoptHook_VendorName;
static IP_SOCK_HOOK_ON_SETGETOPT _SockoptHook_SO_RXDATA;
static U8 _ShowNoteOnce_SO_RXDATA;
/*********************************************************************
*
* _cbGetSetVendorName()
*
* Function description
* Callback for application specific socket option extension of
* set/get an application specific vendor name.
*
* Parameters
* Type : Source/reason of execution:
* * IP_SOCK_HOOK_GETOPT
* * IP_SOCK_HOOK_SETOPT
* hSock : Socket handle.
* Level : Socket level such as SOL_SOCKET .
* Name : Option name - APP_SOCK_OPT_VENDOR_NAME .
* pVal : Pointer to the string to set or where to read to.
* ValLen: Length of string to set or size of buffer (including
* string termination) where to read to.
*
* Return value
* == IP_SOCK_HOOK_IGNORE_CB: Magic return value used to tell the
* stack that while it ended up in the
* callback it should still execute its
* regular (internal) behavior.
* == 0 : O.K.
* == IP_ERR_LOGIC : Not able to get the string as no buffer
* or a zero buffer has been given.
* == IP_ERR_MSG_SIZE : Unable to get/set a string due to string
* or buffer size.
*
*/
static int _cbGetSetVendorName(unsigned Type, int hSock, int Level, int Name, void* pVal, int ValLen) {
unsigned Len;
int r;
IP_USE_PARA(hSock);
IP_USE_PARA(Level);
IP_USE_PARA(Name);
r = 0; // Assume O.K.
if (Type == IP_SOCK_HOOK_GETOPT) {
//
// Get vendor name.
//
if ((pVal == NULL) || (ValLen == 0)) {
r = IP_ERR_LOGIC;
} else {
Len = strlen(_acVendor) + 1; // Always count the termination char.
if ((unsigned)ValLen < Len) {
r = IP_ERR_MSG_SIZE;
} else {
memcpy(pVal, &_acVendor[0], Len);
}
}
} else {
//
// Set vendor name.
//
if ((pVal == NULL) || (ValLen == 0)) {
_acVendor[0] = '\0'; // Clear vendor name.
} else {
if ((unsigned)ValLen > sizeof(_acVendor)) {
r = IP_ERR_MSG_SIZE;
} else {
memcpy(&_acVendor[0], pVal, ValLen);
}
}
}
return r;
}
/*********************************************************************
*
* _cbOnSockopt_SO_RXDATA()
*
* Function description
* Callback for application specific socket option extension to
* notify in case get SO_RXDATA is used.
*
* Parameters
* Type : Source/reason of execution:
* * IP_SOCK_HOOK_GETOPT
* * IP_SOCK_HOOK_SETOPT
* hSock : Socket handle.
* Level : Socket level such as SOL_SOCKET .
* Name : Option name.
* pVal : Pointer to the option value.
* ValLen: Length of the option at pVal .
*
* Return value
* == IP_SOCK_HOOK_IGNORE_CB: Magic return value used to tell the
* stack that while it ended up in the
* callback it should still execute its
* regular (internal) behavior.
* == 0 : O.K.
* != 0 : Error (typically negative) that will be
* stored as socket error. The API call
* itself will still return SOCKET_ERROR .
* Value is limited to the size of signed char.
*
*/
static int _cbOnSockopt_SO_RXDATA(unsigned Type, int hSock, int Level, int Name, void* pVal, int ValLen) {
IP_USE_PARA(Type);
IP_USE_PARA(hSock);
IP_USE_PARA(Level);
IP_USE_PARA(Name);
IP_USE_PARA(pVal);
IP_USE_PARA(ValLen);
if (_ShowNoteOnce_SO_RXDATA == 0u) {
_ShowNoteOnce_SO_RXDATA = 1u;
printf("NOTE: You can use IP_SOCKET_GetNumRxBytes() for a more direct call.\n");
}
return IP_SOCK_HOOK_IGNORE_CB;
}
/*********************************************************************
*
* _InstallAppSocketCallbacks()
*
* Function description
* Installs a couple of application specific sample callbacks for
* getsockopt()/setsockopt() options.
*/
static void _InstallAppSocketCallbacks(void) {
IP_SOCKET_AddGetSetOptHook(&_SockoptHook_VendorName, _cbGetSetVendorName , APP_SOCK_OPT_VENDOR_NAME);
IP_SOCKET_AddGetSetOptHook(&_SockoptHook_SO_RXDATA , _cbOnSockopt_SO_RXDATA, SO_RXDATA);
}
IP_SOCKET_CloseAll()
Description
Closes all socket handles that are open. Can be used to close
all sockets in case of changing the local IP address or similar
actions that change connection parameters.
Prototype
void IP_SOCKET_CloseAll(U32 ConfMask);
Parameters
Parameter | Description |
ConfMask | Bitwise-OR bit mask of configurations: CLOSE_ALL_KEEP_LISTEN: Keep listening sockets. |
Example: Closing all webserver child tasks
The following code closes all webserver child tasks for example if the target has changed
its IP address. The parent listening socket shall be kept open as it is independent from
the IP address and typically listens to any address of the system.
OS_EnterRegion(); // Avoid being disturbed by disabling task switches.
//
// End all child tasks that might access sockets.
//
for (i = 0; i < MAX_CONNECTIONS; i++) {
r = OS_IsTask(&_aWebTasks[i]);
if (r != 0) {
OS_TerminateTask(&_aWebTasks[i]);
}
}
//
// Close all sockets that might been abandoned but
// leave open listening parent sockets.
//
IP_SOCKET_CloseAll(CLOSE_ALL_KEEP_LISTEN);
OS_LeaveRegion(); // Allow task switches again.
IP_SOCKET_ConfigSelectMultiplicator()
Description
Configures the multiplicator for the timeout parameter of select().
Default multiplicator is 1.
Prototype
void IP_SOCKET_ConfigSelectMultiplicator(U32 v);
Parameters
Parameter | Description |
v | Multiplicator to be used. |
Additional information
By default the select() timeout is given in ticks of 1 ms. The
UNIX standard takes the timeout in a structue including seconds.
The multiplicator can be configured but as it is more common for
an embedded system we will stick to units of 1 tick (typically 1
ms) for the default.
IP_SOCKET_GetAddrFam()
Description
Returns the IP version of a socket (IPv4 or IPv6).
Prototype
U16 IP_SOCKET_GetAddrFam(int hSock);
Parameters
Parameter | Description |
hSock | Socket handle |
Return value
0 | Invalid socket handle |
AF_INET | IPv4 socket. |
AF_INET6 | IPv6 socket. |
IP_SOCKET_GetErrorCode()
Description
Returns the last error reported on a socket. Returns 0 if the
socket has not previously reported an error.
Prototype
int IP_SOCKET_GetErrorCode(int hSock);
Parameters
Parameter | Description |
hSock | Socket handle. |
Return value
Last error of the socket. Please refer to the IP.h IP_ERR_* return
codes for more details.
IP_SOCKET_GetLocalPort()
Description
Returns the local port of a socket.
Prototype
U16 IP_SOCKET_GetLocalPort(int hSock);
Parameters
Parameter | Description |
hSock | Socket handle |
Return value
> 0 | OK. Local port number of the socket in network byte order. |
= 0 | Error. Socket not available or no local port bound to socket. |
IP_SOCKET_GetNumRxBytes()
Description
Returns the number of received bytes
Prototype
int IP_SOCKET_GetNumRxBytes(int hSock);
Parameters
Parameter | Description |
hSock | Socket handler. |
Return value
> 0 | Number of bytes received. |
= -1 (SOCKET_ERROR) | Error, socket is invalid. |
IP_SOCKET_SetDefaultOptions()
Description
Sets the socket options enabled by default.
Prototype
void IP_SOCKET_SetDefaultOptions(U16 v);
Parameters
Parameter | Description |
v | Socket options which should be enabled. |
Additional information
By default, keepalive (SO_KEEPALIVE ) socket option is enabled.
Refer to setsockopt() for a list of supported socket options.
IP_SOCKET_SetLimit()
Description
Sets the maximum number of allowed sockets.
Prototype
void IP_SOCKET_SetLimit(unsigned Limit);
Parameters
Parameter | Description |
Limit | Sets a limit on number of sockets which can be created. The default is 0 which means that no limit is set. |
IP_SOCKET_SetLinger()
Description
Activates linger.
Prototype
int IP_SOCKET_SetLinger(int hSock,
int Linger);
Parameters
Parameter | Description |
hSock | Socket handler. |
Linger | Flag to activate or deactivate linger. |
Return value
0 | O.K. |
-1 (SOCKET_ERROR) | Error, socket is invalid. |
IP_SOCKET_SetRxTimeout()
Description
Sets the rx timeout
Prototype
int IP_SOCKET_SetRxTimeout(int hSock,
int Timeout);
Parameters
Parameter | Description |
hSock | Socket handler. |
Timeout | New timeout value. |
Return value
0 | O.K. |
-1 (SOCKET_ERROR) | Error, socket is invalid. |
IP_SOCK_recvfrom_info()
Description
Receives a datagram and stores the source address and additional
information as requested.
Prototype
int IP_SOCK_recvfrom_info(int hSock,
char * pData,
int NumBytes,
int Flags,
sockaddr * pFrom,
int * pAddrLen,
IP_SOCK_RECVFROM_INFO * pInfo);
Parameters
Parameter | Description |
hSock | Handle on the socket. |
pData | A pointer to a buffer for incoming data. |
NumBytes | Number of bytes of the buffer. |
Flags | OR-combination of flags (MSG_PEEK). |
pFrom | An optional pointer to a buffer where the address of the connecting entity is stored. The format of the address depends on the defined address family which was defined when the socket was created. Can be NULL. |
pAddrLen | An optional pointer to an integer where the length of the received address is stored. Just like the format of the address, the length of the address depends on the defined address family. |
pInfo | Pointer where to store additional requested information about the received data. |
Return value
= -1 | Error occurred. |
≥ 0 | Number of bytes received. |
IP_SOCK_recvfrom_ts()
Description
Receives a datagram and stores the source address and timestamp.
Prototype
int IP_SOCK_recvfrom_ts(int hSock,
char * pData,
int NumBytes,
int Flags,
sockaddr * pFrom,
int * pAddrLen,
IP_PACKET_TIMESTAMP * pTimestamp);
Parameters
Parameter | Description |
hSock | Handle on the socket. |
pData | A pointer to a buffer for incoming data. |
NumBytes | Number of bytes of the buffer. |
Flags | OR-combination of flags (MSG_PEEK). |
pFrom | An optional pointer to a buffer where the address of the connecting entity is stored. The format of the address depends on the defined address family which was defined when the socket was created. Can be NULL. |
pAddrLen | An optional pointer to an integer where the length of the received address is stored. Just like the format of the address, the length of the address depends on the defined address family. |
pTimestamp | Pointer where to store the packet timestamp. Can be NULL. |
Return value
= -1 | Error occurred. |
≥ 0 | Number of bytes received. |
Additional information
Requires IP_SUPPORT_PACKET_TIMESTAMP and/or IP_SUPPORT_PTP to be enabled.
IP_TCP_Accept()
Description
Registers a callback that will be executed upon a new client.
Prototype
int IP_TCP_Accept
(IP_TCP_ACCEPT_HOOK * pHook,
void ( *pfAccept)(int hSock , IP_TCP_ACCEPT_INFO * pInfo , void * pContext ),
int hSock,
void * pContext);
Parameters
Parameter | Description |
pHook | Management element of type IP_TCP_ACCEPT_HOOK. |
pfAccept | Callback to register. |
hSock | Parent socket handle (needs to have bind() and listen() done). |
pContext | Custom context that will be passed to the callback. |
Return value
Additional information
The registered callback has to prevent any blocking situation.
Calling send() for example on a non-blocking socket is fine.
Only clients fitting the registered parent socket will be
reported to the callback like a regular accept() call. Therefore
the usual steps like calling bind() and listen() are still
necessary.
IP_FD_CLR()
Description
Removes a socket from a set.
Prototype
void IP_FD_CLR(int hSock,
IP_fd_set * pSet);
Parameters
Parameter | Description |
hSock | Socket handle. |
pSet | Pointer on a set of type IP_fd_set. |
IP_FD_SET()
Description
Adds a socket to a set.
Prototype
void IP_FD_SET(int hSock,
IP_fd_set * pSet);
Parameters
Parameter | Description |
hSock | Socket handle. |
pSet | Pointer on a set of type IP_fd_set. |
IP_FD_ISSET()
Description
Checks if a socket is part of a set.
Prototype
int IP_FD_ISSET(int hSock,
IP_fd_set * pSet);
Parameters
Parameter | Description |
hSock | Socket handle. |
pSet | Pointer on a set of type IP_fd_set. |
Return value
1 | Socket is part of the set. |
0 | Socket is not part of the set. |
Data structures
sockaddr
Description
This structure holds socket address information for many types of sockets.
Prototype
struct sockaddr {
U16 sa_family;
char sa_data[14];
};
Member | Description |
sa_family | Address family. Normally AF_INET. |
sa_data | The character array sa_data contains the destination address and
port number for the socket. |
Additional information
The structure sockaddr is mostly used as function parameter. To deal with struct
sockaddr, a parallel structure struct sockaddr_in is implemented. The structure
sockaddr_in is the same size as structure sockaddr, so that a pointer can freely be
casted from one type to the other. Refer to sockaddr_in for
more information and an example.
sockaddr_in
Description
Structure for handling Internet addresses.
Prototype
struct sockaddr_in {
short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
Member | Description |
sin_family | Address family. Normally AF_INET. |
sin_port | Port number for the socket. |
sin_addr | Structure of type in_addr. The structure represents a 4-byte
number that represents one digit in an IP address per byte. |
sin_zero | sin_zero member is unused. |
Example
Refer to connect for an example.
in_addr
Description
4-byte number that represents one digit in an IP address per byte.
Prototype
struct in_addr {
unsigned long s_addr;
};
Member | Description |
s_addr | Number that represents one digit in an IP address per byte. |
hostent
Description
The hostent structure is used by functions to store information about a given host,
such as host name, IPv4 address, and so on.
Prototype
struct hostent {
char * h_name;
char ** h_aliases;
int h_addrtype;
int h_length;
char ** h_addr_list;
};
Member | Description |
h_name | Official name of the host. |
h_aliases | Alias list. |
s_addrtype | Host address type. |
h_length | Length of the address. |
s_addr_list | List of addresses from the name server. |
IP_SOCK_HOOK_ON_GETSETOPT_FUNC
Description
Callback for custom implementations with setsockopt()/getsockopt() .
Type definition
typedef int (IP_SOCK_HOOK_ON_GETSETOPT_FUNC)(unsigned Type,
int hSock,
int Level,
int Name,
void * pVal,
int ValLen);
Parameters
Parameter | Description |
Type | Source/reason of execution: IP_SOCK_HOOK_GETOPT IP_SOCK_HOOK_SETOPT |
hSock | Socket handle. |
Level | Socket level such as SOL_SOCKET . |
Name | Option name. |
pVal | Pointer to the option value. |
ValLen | Length of the option at pVal . |
Return value
= IP_SOCK_HOOK_IGNORE_CB | Magic return value used to tell the stack that while it ended up in the callback it should still execute its regular (internal) behavior. |
= 0 | O.K. |
≠ 0 | Error (typically negative) that will be stored as socket error. The API call itself will still return SOCKET_ERROR . Value is limited to the size of signed char. |
IP_SOCK_RECVFROM_INFO
Description
Returns information about the received UDP packet typically
not available with the original BSD compatible call.
Type definition
typedef struct {
IP_PACKET_TIMESTAMP * pTimestamp;
void * pLAddrV6;
unsigned AddrLenV6;
U32 LAddr;
U8 IFaceId;
} IP_SOCK_RECVFROM_INFO;
Structure members
Member | Description |
pTimestamp | Pointer where to store the packet timestamp. Can be NULL. |
pLAddrV6 | Pointer to buffer where to store the local IPv6 address on which the datagram was received. Can be NULL. |
AddrLenV6 | Length of the buffer at pLAddrV6 . |
LAddr | Local IPv4 address on which the datagram was received. |
IFaceId | Zero-based interface index the packet has been received on. |
Error codes
The following table contains a list of generic error codes, generally full success is 0.
Definite errors are negative numbers, and indeterminate conditions are positive
numbers.
Symbolic name | Value | Description |
IP_ERR_PARAM | -10 | Bad parameter. |
IP_ERR_LOGIC | -11 | Sequence of events that shouldn’t happen. |
IP_ERR_NOMEM | -20 | malloc() or calloc() failed. |
IP_ERR_NOBUFFER | -21 | Run out of free packets. |
IP_ERR_RESOURCE | -22 | Run out of other queue-able resource. |
IP_ERR_BAD_STATE | -23 | TCP layer error. |
IP_ERR_TIMEOUT | -24 | Timeout error on TCP layer. |
IP_ERR_BAD_HEADER | -32 | Bad header at upper layer (for upcalls). |
IP_ERR_NO_ROUTE | -33 | Can not find a reasonable next IP hop. |
IP_ERR_SEND_PENDING | 1 | Packet queued pending an ARP reply. |
IP_ERR_NOT_MINE | 2 | Packet was not of interest (upcall reply). |
TCP zero-copy interface
The TCP protocol can be used via socket functions or the TCP zero-copy interface
which is described in this chapter.
TCP zero-copy
This section documents an optional extension to the Sockets layer, the TCP zero-copy
API. The TCP zero-copy API is intended to assist the development of higher-performance
embedded network applications by allowing the application direct access to
the TCP/IP stack packet buffers. This feature can be used to avoid the overhead of
having the stack copy data between application-owned buffers and stack-owned buffers
in send() and recv() , but the application has to fit its data into, and accept its
data from, the stack buffers.
The TCP zero-copy API is small because it is simply an extension to the existing
Sockets API that provides an alternate mechanism for sending and receiving data on
a socket. The Sockets API is used for all other operations on the socket.
Allocating, freeing and sending TCP packet buffers
The two functions for allocating and freeing packet buffers are straightforward
requests:
IP_TCP_Alloc() allocates a packet buffer from the pool of packet buffers on the
stack and IP_TCP_Free() frees a packet buffer. Applications using the TCP zero-copy
API are responsible for allocating packet buffers for use in sending data, as well as
for freeing buffers that have been used to receive data and those that the application
has allocated but decided not to use for sending data. As these packet buffers are a
limited resource, it is important that applications free them promptly when they are
no longer of use.
The functions for sending data, IP_TCP_Send() and IP_TCP_SendAndFree() , send a
packet buffer of data using a socket. The TCP zero-copy interface supports two different
approaches to send and free a packet. One approach is that the stack frees the
packet independent from the success of sending the packet. Therefore,
IP_TCP_SendAndFree() is called to send and free the packet. It frees the packet
independent from the success of the send operation. The other approach is that
IP_TCP_Send() is called. In this case it is the responsibility of the application to free
the packet. Depending on the return value the application can decide if
IP_TCP_Free() should be called to free the packet.
Callback function for TCP zero-copy
Applications that use the TCP Zero-copy API for receiving data must include a callback
function for acceptance of received packets, and must register the callback
function with the socket using the setsockopt() sockets function with the
SO_CALLBACK option name. The callback function, once registered, receives not only
received data packets, but also connection events that result in socket errors.
Sending data with the TCP zero-copy API
To send data with the TCP zero-copy API, you should proceed as follow:
- Allocating a packet buffer
- Filling the allocated buffer
- Sending the packet
The following section describes the procedure for allocating a packet buffer, sending
data, and freeing the packet buffer step by step.
Allocating a packet buffer for TCP zero-copy
The first step in using the TCP zero-copy API to send data is to allocate a packet
buffer from the stack using the IP_TCP_Alloc() function. This function takes the
maximum length of the data you intend to send in the buffer as argument and
returns a pointer to an IP_PACKET structure.
IP_PACKET * pPacket;
U32 DataLen; // Amount of data to send
DataLen = 512; // Should indicate amount of data to send
pPacket = IP_TCP_Alloc(DataLen);
if (pPacket == NULL) {
// Error, could not allocate packet buffer
}
This limits how much data you can send in one call using the TCP zero-copy API, as
the data sent in one call to IP_TCP_Send() must fit in a single packet buffer. The
actual limit is determined by the big packet buffer size, less 68 bytes for protocol
headers. If you try to request a larger buffer than this, IP_TCP_Alloc() returns
NULL to indicate that it cannot allocate a sufficiently large buffer.
Filling the allocated buffer with data for TCP zero-copy
Having allocated the packet buffer, you now fill it with the data to send. The function
IP_TCP_Alloc() has initialized the returned IP_PACKET pPacket and so
pPacket->pData points to where you can start depositing data.
Sending the TCP zero-copy packet
Finally, you send the packet by giving it back to the stack using the function
IP_TCP_Send() .
e = IP_TCP_Send(socket, pPacket);
if (e < 0) {
IP_TCP_Free(pPacket);
}
This function sends the packet over TCP, or returns an error. If its return value is less
than zero, it has not accepted the packet and the application has to decide either to
free the packet or to retain it for sending later. Use IP_TCP_SendAndFree() if the
packet should be freed automatically in any case.
Receiving data with the TCP zero-copy API
To receive data with the TCP zero-copy API, you should proceed as follow:
- Writing a callback function
- Registering the callback function
Writing a callback function for TCP zero-copy
Using the TCP zero-copy API for receiving data requires the application developer to
write a callback function that the stack can use to inform the application of received
data packets and other socket events. This function is expected to conform to the
following prototype:
int rx_callback(long Socket, IP_PACKET * pPacket, int code);
The stack calls this function when it has received a data packet or other event to
report for a socket. The parameter Socket identifies the socket. The parameter
pPacket passes a pointer to the packet buffer (if there is a packet buffer). If pPacket
is not NULL, it is a pointer to a packet buffer containing received data for the socket.
pPacket->pData points to the start of the received data, and pPacket->NumBytes
indicates the number of bytes of received data in this buffer.
The parameter code passes an error event (if there is an error to report). If code is
not 0, it is a socket error indicating that an error or other event has occurred on the
socket. Typical nonzero values are IP_ERR_SHUTDOWN and IP_ERR_CONN_RESET. IP_ERR_SHUTDOWN defines
that the connected peer has closed its end of the connection and sends no more data.
IP_ERR_CONN_RESET defines that the connected peer has abruptly closed its end of the connection
and neither sends nor receives more data.
Returned values
The callback function may return one of the following values:
Symbolic | Numerical | Description |
IP_OK | 0 | Data handled, packet can be freed. |
IP_OK_KEEP_PACKET | 1 | Data will be handled by application later, the
stack should NOT free the packet. This will be
done by the application at a later time when the
data has been handled and the packet is no
longer needed. |
Note: The callback function is called from the stack and is expected to return promptly.
No blocking API shall be called from within the callback.
Registering the TCP zero-copy callback function
The application must also inform the stack of the callback function. setsockopt()
function provides an additional socket option, SO_CALLBACK , which should be used for
this purpose once the socket has been created. The following code fragment
illustrates the use of this option to register a callback function named RxUpcall() on the
socket Socket :
setsockopt(Socket, SOL_SOCKET, SO_CALLBACK, (void *)RxUpcall, 0);
See the function setsockopt for more details.
API functions
IP_TCP_Alloc()
Description
Allocates a packet buffer large enough to hold NumBytes bytes of
TCP data, plus TCP, IP and MAC headers.
Prototype
IP_PACKET *IP_TCP_Alloc(unsigned NumBytes);
Parameters
Parameter | Description |
NumBytes | Length of the data which should be sent. |
Return value
≠ NULL | Success, pointer to the allocated buffer. |
= NULL | Error. |
Additional information
This function must be called to allocate a buffer for sending
data via IP_TCP_Send(). It returns the allocated packet buffer
with its pPacket->pData field set to where the application must
deposit the data to be sent.
This datasize limits how much data that you can send in one call
using the TCP zero-copy API, as the data sent in one call to
IP_TCP_Send() must fit in a single packet buffer, with the TCP,
IP, and lower-layer headers that the stack needs to add in order
to send the packet.
The actual limit is determined by the big packet buffer size
(normally 1516 bytes). Refer to IP_AddBuffers() for more
information about defining buffer sizes. If you try to request
a larger buffer than this, IP_TCP_Alloc() returns NULL to
indicate that it cannot allocate a sufficiently-large buffer.
Example
IP_PACKET * pPacket;
U32 DataLen; // Amount of data to send
DataLen = 1024; // Should indicate amount of data to send
pPacket = IP_TCP_Alloc(DataLen);
if (pPacket == NULL) {
// Error, could not allocate packet buffer
}
IP_TCP_AllocEx()
Description
Allocates a packet buffer large enough to hold NumBytes bytes of
TCP data, plus TCP, IP and MAC headers.
Prototype
IP_PACKET *IP_TCP_AllocEx(unsigned NumBytes,
unsigned NumBytesHeader);
Parameters
Parameter | Description |
NumBytes | Length of the data which should be sent. |
NumBytesHeader | Size of all headers (Ethernet + IPvX + TCPvX). |
Return value
≠ NULL | Success, pointer to the allocated buffer. |
= NULL | Error. |
Additional information
For further information please refer to IP_TCP_Alloc().
IP_TCP_Free()
Description
Free a packet allocated by IP_TCP_Alloc().
Prototype
void IP_TCP_Free(IP_PACKET * p);
Parameters
Parameter | Description |
p | Pointer to the IP_Packet structure. |
IP_TCP_Send()
Description
Sends a packet buffer on a socket.
Prototype
int IP_TCP_Send(int hSock,
IP_PACKET * pPacket);
Parameters
Parameter | Description |
hSock | Socket handle. |
pPacket | Pointer to the IP_PACKET structure. |
Return value
= 0 | The packet was sent successfully. |
< 0 | The packet was not accepted by the stack. The application must re-send the packet using a call to IP_TCP_Send(), or free the packet using IP_TCP_Free(). |
> 0 | The packet has been accepted and queued on the socket but has not yet been transmitted. |
Additional information
Applications using the TCP zero-copy API are responsible for
allocating packet buffers for use in sending data, as well as
for freeing buffers that have been used to receive data and those
that the application has allocated but decided not to use for
sending data. As these packet buffers are a limited resource, it
is important that applications free them promptly when they are
no longer of use.
Packets have to be freed after processing. The TCP zero-copy
interface supports two different approaches to free a packet.
One approach is that the stack frees the packet independent
from the success of sending the packet. Therefore,
IP_TCP_SendAndFree() is called to send the packet and free
the packet. It frees the packet independently from the
success of the send operation. The other approach is that
IP_TCP_Send() is called. In this case it is the responsibility
application programmer to free the packet. Depending on the
return value the application programmer can decide if
IP_TCP_Free() should be called to free the packet.
IP_TCP_SendAndFree()
Description
Sends a packet buffer on a socket.
Prototype
int IP_TCP_SendAndFree(int hSock,
IP_PACKET * pPacket);
Parameters
Parameter | Description |
hSock | Socket handle. |
pPacket | Pointer to the IP_PACKET structure. |
Return value
= 0 | The packet was sent successfully. |
< 0 | The packet was not accepted by the stack. |
> 0 | The packet has been accepted and queued on the socket but has not yet been transmitted. |
Additional information
Applications using the TCP zero-copy API are responsible for
allocating packet buffers for use in sending data, as well as
for freeing buffers that have been used to receive data and
those that the application has allocated but decided not to
use for sending data. As these packet buffers are a limited
resource, it is important that applications free them promptly
when they are no longer of use.
IP_TCP_SendAndFree() frees packet pPacket after processing.
It frees the packet independent from the success of the send
operation.
UDP zero-copy interface
The UDP transfer protocol can be used via socket functions or the zero-copy interface
which is described in this chapter.
UDP zero-copy
The UDP zero-copy API functions are provided for systems that do not need the overhead
of sockets. These routines impose a lower demand on CPU and system memory
requirements than sockets. However, they do not offer the portability of sockets.
UDP zero-copy API functions are intended to assist the development of higher-performance
embedded network applications by allowing the application direct access to
the UDP/IP stack packet buffers. This feature can be used to avoid the overhead of
having the stack copy data between application-owned buffers and stack-owned buffers
in sendto() and recvfrom(), but the application has to fit its data into, and
accept its data from the stack buffers. Refer to
emNet UDP discover (IP_UDPDiscover.c / IP_UDPDiscover_ZeroCopy.c) for detailed
information about the UDP zero-copy example application.
Allocating, freeing and sending UDP packet buffers
The two functions for allocating and freeing packet buffers are straightforward
requests:
IP_UDP_Alloc() allocates a packet buffer from the pool of packet buffers on the
stack and IP_UDP_Free() frees a packet buffer. Applications using the UDP zero-copy
API are responsible for allocating packet buffers for use in sending data, as well as
for freeing buffers that have been used to receive data and those that the application
has allocated but decided not to use for sending data. As these packet buffers are a
limited resource, it is important that applications free them promptly when they are
no longer of use.
The functions for sending data, IP_UDP_Send() and IP_UDP_SendAndFree() , send a
packet buffer of data using a port. The UDP zero-copy interface supports two different
approaches to send and free a packet. One approach is that the stack frees the
packet independent from the success of sending the packet. Therefore,
IP_UDP_SendAndFree() is called to send and free the packet. It frees the packet
independent from the success of the send operation. The other approach is that
IP_UDP_Send() is called. In this case it is the responsibility of the application to free
the packet. Depending on the return value the application can decide if
IP_UDP_Free() should be called to free the packet.
Callback function for UDP zero-copy
Applications that use the UDP zero-copy API for receiving data must include a call-
back function for acceptance of received packets, and must register the callback
function with a port using the IP_UDP_Open() function. The callback function, once
registered, receives all matching data packets.
Sending data with the UDP zero-copy API
To send data with the UDP zero-copy API, you should proceed as follow:
- Allocating a packet buffer
- Filling the allocated buffer
- Sending the packet
The following section describes the procedure for allocating a packet buffer, sending
data, and freeing the packet buffer step by step.
Allocating a packet buffer for UDP zero-copy
The first step in using the UDP zero-copy API to send data is to allocate a packet
buffer from the stack using the IP_UDP_Alloc() function. This function takes the
maximum length of the data you intend to send in the buffer as argument and
returns a pointer to an IP_PACKET structure.
IP_PACKET * pPacket;
U32 DataLen; // Amount of data to send
DataLen = 512; // Should indicate amount of data to send
pPacket = IP_UDP_Alloc(DataLen);
if (pPacket == NULL) {
// Error, could not allocate packet buffer
}
This limits how much data you can send in one call using the UDP zero-copy API, as
the data sent in one call to IP_UDP_Send() must fit in a single packet buffer. The
actual limit is determined by the big packet buffer size, less typically 42 bytes for
protocol headers (14 bytes for Ethernet header, 20 bytes IP header, 8 bytes UDP
header). If you try to request a larger buffer than this, IP_UDP_Alloc() returns NULL
to indicate that it cannot allocate a sufficiently large buffer.
Filling the allocated buffer with data for UDP zero-copy
Having allocated the packet buffer, you now fill it with the data to send. The function
IP_UDP_Alloc() has initialized the returned IP_PACKET pPacket and so
pPacket->pData points to where you can start depositing data.
Sending the UDP zero-copy packet
Finally, you send the packet by giving it back to the stack using the function
IP_UDP_Send() .
#define SRC_PORT 50020
#define DEST_PORT 50020
#define DEST_ADDR 0xC0A80101
e = IP_UDP_Send(0, htonl(DEST_ADDR), SRC_PORT, DEST_PORT, pPacket);
if (e < 0) {
IP_UDP_Free(pPacket);
}
This function sends the packet over UDP, or returns an error. If its return value is less
than zero, it has not accepted the packet and the application has to decide either to
free the packet or to retain it for sending later. Use IP_UDP_SendAndFree() if the
packet should be freed automatically in any case.
Receiving data with the UDP zero-copy API
To receive data with the UDP zero-copy API, you should proceed as follow:
- Writing a callback function
- Registering the callback function
Writing a callback function for UDP zero-copy
Using the UDP zero-copy API for receiving data requires the application developer to
write a callback function that the stack can use to inform the application of received
data packets. This function is expected to conform to the following prototype:
int rx_callback(IP_PACKET * pPacket, void * pContext)
The stack calls this function when it has received a data packet for a port. The
parameter pPacket points to the packet buffer. The packet buffer contains the
received data for the socket. pPacket->pData points to the start of the received
data, and pPacket->NumBytes indicates the number of bytes of received data in this
buffer.
Returned values
The callback function may return one of the following values:
Symbolic | Numerical | Description |
IP_OK | 0 | Data handled. emNet will free the packet. |
IP_OK_KEEP_PACKET | 1 | Data will be handled by application later, the
stack should NOT free the packet. This will be
done by the application at a later time when the
data has been handled and the packet is no
longer needed. |
Note: The callback function is called from the stack and is expected to return promptly.
No blocking API shall be called from within the callback.
Registering the UDP zero-copy callback function
The application must also inform the stack of the callback function. This is done by
calling the IP_UDP_Open() function. The following code fragment illustrates the use
of this option to register a callback function named RxUpcall() on the port 50020:
#define SRC_PORT 50020
#define DEST_PORT 50020
IP_UDP_Open(0L /* any foreign host */, SRC_PORT, DEST_PORT, RxUpCall, 0L /* any tag
*/);
For further information, refer to IP_UDP_Open.
API functions
IP_UDP_Alloc()
Description
Returns a pointer to a packet buffer big enough for the specified
sizes.
Prototype
IP_PACKET *IP_UDP_Alloc(unsigned NumBytesData);
Parameters
Parameter | Description |
NumBytesData | Length of the data which should be sent. |
Return value
≠ NULL | Success, pointer to the allocated buffer. |
= NULL | Error. |
Additional information
Applications using the UDP zero-copy API are responsible for
allocating packet buffers for use in sending data, as well as
for freeing buffers that have been used to receive data and
those that the application has allocated but decided not to use
for sending data. As these packet buffers are a limited resource,
it is important that applications free them promptly when they
are no longer of use.
The UDP zero-copy interface supports two different approaches to
free a packet. One approach is that the stack frees the packet
independent from the success of sending the packet. Therefore,
IP_UDP_SendAndFree() is called to send the packet and free the
packet. It frees the packet independent from the success of the
send operation.
The other approach is that IP_UDP_Send() is called. In this case
it is the responsibility of the application to free the packet.
Depending on the return value the application programmer can
decide if IP_UDP_Free() should be called to free the packet.
IP_UDP_AllocEx()
Description
Allocates a packet for UDP on the given interface.
Prototype
IP_PACKET *IP_UDP_AllocEx(unsigned IFaceId,
unsigned NumBytesData);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
NumBytesData | Length of the data which should be sent. |
Return value
Success: Returns a pointer to the allocated buffer.
Error : NULL.
IP_UDP_Close()
Description
Closes a UDP connection handle and removes the connection from
demux table list of connections and deallocates it.
Prototype
void IP_UDP_Close(IP_UDP_CONNECTION * pCon);
Parameters
Parameter | Description |
pCon | Pointer to the UDP connection. |
IP_UDP_FindFreePort()
Description
Obtains a random port number that is suitable for use as the
LPort parameter in a call to IP_UDP_Open().
Prototype
U16 IP_UDP_FindFreePort(void);
Return value
A usable port number in local endianness.
Additional information
The returned port number is suitable for use as the LPort
parameter in a call to IP_UDP_Open(). Refer to IP_UDP_Open()
for more information.
IP_UDP_FindFreePort() avoids picking port numbers in the
reserved range 0-1024, or in the range 1025-1199, which may
be used for server applications.
IP_UDP_Free()
Description
Frees the buffer which was used for a packet.
Prototype
void IP_UDP_Free(IP_PACKET * pPacket);
Parameters
Parameter | Description |
pPacket | Pointer to a packet structure. |
IP_UDP_GetDataSize()
Description
Returns the size of the data contained in the received UDP packet.
Prototype
U16 IP_UDP_GetDataSize(const IP_PACKET * pPacket);
Parameters
Parameter | Description |
pPacket | Pointer to a packet structure. |
Return value
Size of the data contained in the received UDP packet.
IP_UDP_GetDataPtr()
Description
Returns a pointer to the data contained in the received UDP packet.
Prototype
void *IP_UDP_GetDataPtr(const IP_PACKET * pPacket);
Parameters
Parameter | Description |
pPacket | Pointer to a packet structure. |
Return value
Pointer to the data part of the UDP packet.
IP_UDP_GetDestAddr()
Description
Extracts destination IP address information from a UDP packet.
Prototype
void IP_UDP_GetDestAddr(const IP_PACKET * pPacket,
void * pDestAddr,
int AddrLen);
Parameters
Parameter | Description |
pPacket | Pointer to a packet structure. |
pDestAddr | Pointer to a buffer to store the destination address. |
AddrLen | Size of the buffer used to store the destination address. |
IP_UDP_GetFPort()
Description
Extracts foreign port information from a UDP packet.
Prototype
U16 IP_UDP_GetFPort(const IP_PACKET * pPacket);
Parameters
Parameter | Description |
pPacket | Pointer to a packet structure. |
Return value
Foreign port of the packet.
IP_UDP_GetIFIndex()
Description
Extracts the zero-based interface index of the given UDP Packet.
Prototype
unsigned IP_UDP_GetIFIndex(const IP_PACKET * pPacket);
Parameters
Parameter | Description |
pPacket | Pointer to a packet structure. |
Return value
Zero-based interface index on which the packet was received.
IP_UDP_GetLPort()
Description
Extracts local port information from a UDP packet.
Prototype
U16 IP_UDP_GetLPort(const IP_PACKET * pPacket);
Parameters
Parameter | Description |
pPacket | Pointer to a packet structure. |
Return value
Local port of the packet.
IP_UDP_GetSrcAddr()
Description
Extracts source IP address information from a UDP packet.
Prototype
void IP_UDP_GetSrcAddr(const IP_PACKET * pPacket,
void * pSrcAddr,
int AddrLen);
Parameters
Parameter | Description |
pPacket | Pointer to a packet structure. |
pSrcAddr | Pointer to a buffer to store the source address. |
AddrLen | Size of the buffer used to store the source address. |
IP_UDP_Open()
Description
Creates a UDP connection to receive and pass upwards UDP packets
that match the parameters passed.
Prototype
IP_UDP_CONNECTION *IP_UDP_Open(IP_ADDR FAddr,
U16 FPort,
U16 LPort,
int ( *handler)(IP_PACKET * , void * ),
void * pContext);
Parameters
Parameter | Description |
FAddr | Foreign IP address in network endianness. |
FPort | Foreign port in host endianness. |
LPort | Local port in host endianness. |
handler | Callback function which is called when a UDP packet is received. |
pContext | Application defined context pointer. |
Return value
≠ NULL | Success, pointer to the UDP connection. |
= NULL | Error. |
Additional information
The parameters FAddr, FPort , LPort, can be set to 0
as a wild card, which enables the reception of broadcast datagrams.
The callback handler function is called with a pointer to a
received datagram and a copy of the data pointer which is passed
to IP_UDP_Open(). This can be any data the programmer requires,
such as a pointer to another function, or a control structure to
help in demultiplexing the received UDP packet.
The returned handle is used as parameter for IP_UDP_Close() only.
If IP_UDP_Close() is not called, there is no need to save the
return value.
IP_UDP_OpenEx()
Description
Creates a UDP connection to receive, and pass upwards UDP packets
that match the parameters passed.
Prototype
IP_UDP_CONNECTION *IP_UDP_OpenEx(IP_ADDR FAddr,
U16 FPort,
IP_ADDR LAddr,
U16 LPort,
int ( *handler)(IP_PACKET * , void * ),
void * pContext);
Parameters
Parameter | Description |
FAddr | Foreign IP address in network endianness. |
FPort | Foreign port in host endianness. |
LAddr | Local IP address in network endianness. |
LPort | Local port in host endianness. |
handler | Callback function which is called when a UDP packet is received. |
pContext | Application defined context pointer. |
Return value
≠ NULL | Success, pointer to the UDP connection. |
= NULL | Error. |
Additional information
The parameters FAddr, FPort , LAddr and LPort, can be set to 0
as a wild card, which enables the reception of broadcast datagrams.
The callback handler function is called with a pointer to a
received datagram and a copy of the data pointer which is passed
to IP_UDP_OpenEx(). This can be any data the programmer requires,
such as a pointer to another function, or a control structure to
help in demultiplexing the received UDP packet.
The returned handle is used as parameter for IP_UDP_Close() only.
If IP_UDP_Close() is not called, there is no need to save the
return value.
IP_UDP_Send()
Description
Sends an UDP packet to a specified host.
Contrarily to IP_UDP_SendAndFree(), it does not free the packet
in case of error.
Prototype
int IP_UDP_Send(int IFace,
IP_ADDR FHost,
U16 fport,
U16 lport,
IP_PACKET * pPacket);
Parameters
Parameter | Description |
IFace | Zero-based interface index. |
FHost | IP address of the target host in network endianness. |
fport | Foreign port in host endianness. |
lport | Local port in host endianness. |
pPacket | Data which should be sent to the target host. |
Return value
= 0 | O.K. Packet sent or in a send FIFO, to be on the wire shortly. |
= 1 | IP_ERR_SEND_PENDING. Packet is waiting for address resolution (incoming ARP response). |
< 0 | Error code. |
Additional information
The packet pPacket has to be allocated by calling IP_UDP_Alloc().
Refer to IP_UDP_Alloc() for detailed information.
If you expect to get any response to this packet you should have
opened a UDP connection prior to calling IP_UDP_Send(). Refer
to IP_UDP_Open() for more information about creating a UDP
connection.
IP_UDP_Send() does not free the packet in case of an error. In
this case it is the responsibility of the application to either
free the packet using IP_UDP_Free() or to try sending the packet
again.
IP_UDP_SendAndFree()
Description
Sends an UDP packet to a specified host and frees the packet.
Prototype
int IP_UDP_SendAndFree(int IFace,
IP_ADDR FHost,
U16 fport,
U16 lport,
IP_PACKET * pPacket);
Parameters
Parameter | Description |
IFace | Zero-based interface index. |
FHost | IP address of the target host in network endianness. |
fport | Foreign port in host endianness. |
lport | Local port in host endianness. |
pPacket | Data which should be sent to the target host. |
Return value
= 0 | O.K. Packet sent or in a send FIFO, to be on the wire shortly. |
= 1 | IP_ERR_SEND_PENDING. Packet is waiting for address resolution (incoming ARP response). |
< 0 | Error code. |
Additional information
The packet pPacket has to be allocated by calling IP_UDP_Alloc().
Refer to IP_UDP_Alloc() for detailed information.
If you expect to get any response to this packet you should have
opened a UDP connection prior to calling this. Refer to
IP_UDP_Open() for more information about creating a
UDP connection.
Packets are always freed by calling IP_UDP_SendAndFree().
Therefore no call of IP_UDP_Free() is required.
IP_UDP_ReducePayloadLen()
Description
Reduces the payload length of an allocated packet.
Prototype
int IP_UDP_ReducePayloadLen(IP_PACKET * pPacket,
int NumBytes);
Parameters
Parameter | Description |
pPacket | Pointer to previously allocated packet. |
NumBytes | Reduced payload len. |
Return value
< 0 | Error, NumBytes parameter is bigger than current len. Other: O.K., current payload len. |
Additional information
A previously allocated packet might have been allocated
bigger than necessary to be on the safe side. This function
allows to reduce the number of bytes that will be sent to the
real amount necessary.
The payload len can only be reduced. Trying to increase it
(again) is returned as error.
RAW zero-copy interface
Transferring RAW data can be used via socket functions or the zero-copy interface
which is described in this chapter.
RAW zero-copy
The RAW zero-copy API functions are provided for systems that do not need the
overhead of sockets. These routines impose a lower demand on CPU and system
memory requirements than sockets. However, they do not offer the portability of
sockets.
RAW zero-copy API functions are intended to assist the development of higher-performance
embedded network applications by allowing the application direct access to
the IP stack packet buffers. This feature can be used to avoid the overhead of having
the stack copy data between application-owned buffers and stack-owned buffers in
sendto() and recvfrom() , but the application has to fit its data into, and accept its
data from the stack buffers.
To enable RAW socket support in the IP stack it is mandatory to call IP_RAW_Add()
during initialization of the stack.
Allocating, freeing and sending packet buffers for RAW Zero-Copy
The two functions for allocating and freeing packet buffers are straightforward
requests:
IP_RAW_Alloc() allocates a packet buffer from the pool of packet buffers on the
stack and IP_RAW_Free() frees a packet buffer. Applications using the RAW
zero-copy API are responsible for allocating packet buffers for use in sending data, as well
as for freeing buffers that have been used to receive data and those that the application
has allocated but decided not to use for sending data. As these packet buffers
are a limited resource, it is important that applications free them promptly when they
are no longer of use.
The functions for sending data, IP_RAW_Send() and IP_RAW_SendAndFree(), send a
packet buffer of data using a specific protocol or sending pure data which requires
the user to include his own IP header. The RAW zero-copy interface supports two different
approaches to send and free a packet. One approach is that the stack frees the
packet independent from the success of sending the packet. Therefore,
IP_RAW_SendAndFree() is called to send and free the packet. It frees the packet
independent from the success of the send operation. The other approach is that
IP_RAW_Send() is called. In this case it is the responsibility of the application to free
the packet. Depending on the return value the application can decide if
IP_RAW_Free() should be called to free the packet.
Callback function for RAW Zero-Copy
Applications that use the RAW zero-copy API for receiving data must include a call-
back function for acceptance of received packets, and must register the callback
function with a protocol using the IP_RAW_Open() function. The callback function,
once registered, receives all matching data packets.
Sending data with the RAW zero-copy API
To send data with the RAW zero-copy API, you should proceed as follow:
- Allocating a packet buffer
- Filling the allocated buffer
- Sending the packet
The following section describes the procedure for allocating a packet buffer, sending
data, and freeing the packet buffer step by step.
Allocating a packet buffer for RAW Zero-Copy
The first step in using the RAW zero-copy API to send data is to allocate a packet
buffer from the stack using the IP_RAW_Alloc() function. This function takes the
maximum length of the data you intend to send in the buffer and if the IP header will
be written by the stack or by yourself as arguments and returns a pointer to an
IP_PACKET structure.
IP_PACKET * pPacket;
U32 DataLen; // Amount of data to send
DataLen = 512; // Should indicate amount of data to send
pPacket = IP_RAW_Alloc(0, DataLen, 0); // Stack will write IP header
if (pPacket == NULL) {
// Error, could not allocate packet buffer
}
This limits how much data you can send in one call using the RAW zero-copy API, as
the data sent in one call to IP_RAW_Send() must fit in a single packet buffer. The
actual limit is determined by the big packet buffer size, less typically 34 bytes for
protocol headers (14 bytes for Ethernet header, 20 bytes IP header). If you try to
request a larger buffer than this, IP_RAW_Alloc() returns NULL to indicate that it
cannot allocate a sufficiently large buffer.
If you decide to provide the IP header yourself you can allocate a packet buffer the
following way:
pPacket = IP_RAW_Alloc(0, DataLen, 1);
In this case the packet size allocate limit is determined by the big packet buffer size,
less typically 14 bytes for the Ethernet header.
Filling the allocated buffer with data for RAW Zero-Copy
Having allocated the packet buffer, you now fill it with the data to send. The function
IP_RAW_Alloc() has initialized the returned IP_PACKET pPacket and so
pPacket->pData points to where you can start depositing data.
Depending on if you decided to provide your own IP header you will have to store this
data starting at pPacket->pData as well.
Sending the packet
Finally, you send the packet by giving it back to the stack using the function
IP_RAW_Send().
#define PROTOCOL 1 // ICMP
#define DEST_ADDR 0xC0A80101
e = IP_RAW_Send(0, DEST_ADDR, PROTOCOL, pPacket);
if (e < 0) {
IP_RAW_Free(pPacket);
}
This function sends the packet specifying the ICMP protocol in the IP header, or
returns an error. If its return value is less than zero, it has not accepted the packet
and the application has to decide either to free the packet or to retain it for sending
later. Use IP_RAW_SendAndFree() if the packet should be freed automatically in any
case.
In case you intend to provide your own IP header the protocol passed has to be
IPPROTO_RAW. This prevents the stack to generate and include a header on its own.
Receiving data with the RAW zero-copy API
To receive data with the RAW zero-copy API, you should proceed as follow:
- Writing a callback function
- Registering the callback function
Writing a callback function
Using the RAW zero-copy API for receiving data requires the application developer to
write a callback function that the stack can use to inform the application of received
data packets. This function is expected to conform to the following prototype:
int rx_callback(IP_PACKET * pPacket, void * pContext)
The stack calls this function when it has received a data packet for a protocol. The
parameter pPacket points to the packet buffer. The packet buffer contains the
received data for the socket. pPacket->pData points to the start of the received data
(including network and IP header), and pPacket->NumBytes indicates the number of
bytes of received data in this buffer.
Returned values
The callback function may return one of the following values:
Symbolic | Numerical | Description |
IP_OK | 0 | Data handled. emNet will free the packet. |
IP_OK_KEEP_PACKET | 1 | Data will be handled by application later, the
stack should NOT free the packet. This will be
done by the application at a later time when the
data has been handled and the packet is no
longer needed. |
Note: The callback function is called from the stack and is expected to return promptly.
No blocking API shall be called from within the callback.
Registering the callback function for RAW Zero-Copy
The application must also inform the stack of the callback function. This is done by
calling the IP_RAW_Open() function. The following code fragment illustrates the use
of this option to register a callback function named RxUpcall() for the ICMP protocol:
#define PROTOCOL 1 // ICMP
IP_RAW_Open(0L /* any foreign host */, 0L /* any local host */, PROTOCOL, RxUpCall,
0L /* any tag */);
See function IP_RAW_Open for reference.
To receive ICMP packets the ICMP protocol has not to be added to the stack by calling
IP_ICMP_Add() . Protocols known to the stack and added for handling through the
stack can not be used with the RAW zero-copy API.
API functions
IP_RAW_Alloc()
Description
Returns a pointer to a packet buffer big enough for the specified
sizes.
Prototype
IP_PACKET *IP_RAW_Alloc(unsigned IFaceId,
unsigned NumBytesData,
int IpHdrIncl);
Parameters
Parameter | Description |
IFaceId | Zero-based index of available interfaces. |
NumBytesData | Length of the data which should be sent. |
IpHdrIncl | Specifies if the IP header is generated or has to be provided by the user. 0: Header generated by the stack; 1: Header to be provided in the packet data by the user. |
Return value
≠ NULL | Success, pointer to the allocated buffer. |
= NULL | Error. |
Additional information
Applications using the RAW zero-copy API are responsible for
allocating packet buffers for use in sending data, as well as
for freeing buffers that have been used to receive data and
those that the application has allocated but decided not to
use for sending data. As these packet buffers are a limited
resource, it is important that applications free them promptly
when they are no longer of use.
The RAW zero-copy interface supports two different approaches
to free a packet. One approach is that the stack frees the
packet independent from the success of sending the packet.
Therefore, IP_RAW_SendAndFree() is called to send the packet
and free the packet. It frees the packet independent from the
success of the send operation. The other approach is that
IP_RAW_Send() is called. In this case it is the responsibility
of the application to free the packet. Depending on the return
value the application programmer can decide if IP_RAW_Free()
should be called to free the packet.
IP_RAW_Close()
Description
Closes a RAW connection handle and removes the connection from
demux table list of connections and deallocates it.
Prototype
void IP_RAW_Close(IP_RAW_CONNECTION * pCon);
Parameters
Parameter | Description |
pCon | RAW Connection handle. |
IP_RAW_Free()
Description
Frees the buffer which was used for a packet.
Prototype
void IP_RAW_Free(IP_PACKET * pPacket);
Parameters
Parameter | Description |
pPacket | Pointer to a packet structure. |
IP_RAW_GetDataPtr()
Description
Returns pointer to data contained in the received RAW packet
Prototype
void *IP_RAW_GetDataPtr(const IP_PACKET * pPacket);
Parameters
Parameter | Description |
pPacket | Pointer to a packet structure. |
Return value
Pointer to the data part of the packet.
Additional information
The data pointer returned points to the start of the network
header. Therefore typically 34 bytes header (14 bytes Ethernet
header, 20 bytes IP header) are included.
IP_RAW_GetDataSize()
Description
Returns size of the payload in the received RAW packet.
Prototype
U16 IP_RAW_GetDataSize(const IP_PACKET * pPacket);
Parameters
Parameter | Description |
pPacket | Pointer to a packet structure. |
Return value
Number of data bytes received in the packet.
IP_RAW_GetDestAddr()
Description
Extracts destination IP address information from a RAW packet.
Prototype
void IP_RAW_GetDestAddr(const IP_PACKET * pPacket,
void * pDestAddr,
int AddrLen);
Parameters
Parameter | Description |
pPacket | Pointer to a packet structure. |
pDestAddr | Pointer to a buffer to store the destination address. |
AddrLen | Size of the buffer used to store the destination address. |
IP_RAW_GetIFIndex()
Description
Retrieves the zero-based interface index of the given RAW Packet.
Prototype
unsigned IP_RAW_GetIFIndex(const IP_PACKET * pPacket);
Parameters
Parameter | Description |
pPacket | Pointer to a packet structure. |
Return value
Zero-based interface index on which the packet was received.
IP_RAW_GetSrcAddr()
Description
Extracts source address information from a RAW packet.
Prototype
void IP_RAW_GetSrcAddr(const IP_PACKET * pPacket,
void * pSrcAddr,
int AddrLen);
Parameters
Parameter | Description |
pPacket | Pointer to a packet structure. |
pSrcAddr | Pointer to a buffer to store the source address. |
AddrLen | Size of the buffer used to store the source address. |
IP_RAW_Open()
Description
Creates a RAW connection handle to receive, and pass
upwards RAW packets that match the parameters passed.
Prototype
IP_RAW_CONNECTION *IP_RAW_Open
(IP_ADDR FAddr,
IP_ADDR LAddr,
U8 Protocol,
int ( *handler)(IP_PACKET * pPacket , void * pContext ),
void * pContext);
Parameters
Parameter | Description |
FAddr | Foreign IP address. |
LAddr | Local IP address. |
Protocol | IP protocol. |
handler | Callback function which is called when a packet of protocol “Protocol” is received. |
pContext | in/out Application defined context pointer. |
Return value
≠ NULL | Success, pointer to the RAW connection handle. |
= NULL | Error. |
Additional information
The parameters FAddr and LAddr can be set to 0 as a wild card,
which enables the reception of broadcast packets. To enable
the reception of any protocol use IPPROTO_RAW as Protocol.
The callback handler function is called with a pointer to a
received protocol and a copy of the data pointer which is
passed to IP_RAW_Open(). This can be any data the application
requires, such as a pointer to another function, or a control
structure to aid in demultiplexing the received packet.
The returned handle is used as parameter for IP_RAW_Close()
only. If IP_RAW_Close() is not called, there is no need to
save the return value.
IP_RAW_Send()
Description
Send a RAW packet to a specified host.
Contrarily to IP_RAW_SendAndFree(), it does not free the packet
in case of error.
Prototype
int IP_RAW_Send(int IFace,
IP_ADDR FHost,
U8 Protocol,
IP_PACKET * pPacket);
Parameters
Parameter | Description |
IFace | Zero-based index of available interfaces. |
FHost | IP address of the target host in network endianness. |
Protocol | Protocol that will be used in the IP header generated by the stack. |
pPacket | Packet that should be sent to the target host. |
Return value
= 0 | O.K. Packet sent or in a send FIFO, to be on the wire shortly. |
= 1 | IP_ERR_SEND_PENDING. Packet is waiting for address resolution (incoming ARP response). |
< 0 | Error code. |
Additional information
The packet pPacket has to be allocated by calling IP_RAW_Alloc().
Refer to IP_RAW_Alloc() for detailed information.
If you expect to get any response to this packet you should have
opened a RAW connection prior to calling IP_RAW_Send(). Refer
to IP_RAW_Open() for more information about creating a RAW
connection.
IP_RAW_Send() does not free the packet in case of an error. In
this case it is the responsibility of the application to either
free the packet using IP_RAW_Free() or to try sending the packet
again.
IP_RAW_SendAndFree()
Description
Sends a RAW Packet to a specified host and frees the packet.
Typically called from applications using zero-copy RAW communication.
A packet sent with this function is normally allocated by calling IP_RAW_Alloc()
Prototype
int IP_RAW_SendAndFree(int IFace,
IP_ADDR FHost,
U8 Protocol,
IP_PACKET * pPacket);
Parameters
Parameter | Description |
IFace | Zero-based index of available interfaces. |
FHost | IP address of the target host in network endianness. |
Protocol | Protocol that will be used in the IP header generated by the stack. |
pPacket | Packet that should be sent to the target host. |
Return value
= 0 | O.K. Packet sent or in a send FIFO, to be on the wire shortly. |
= 1 | IP_ERR_SEND_PENDING. Packet is waiting for address resolution (incoming ARP response). |
< 0 | Error code. |
Additional information
The packet pPacket has to be allocated by calling IP_RAW_Alloc().
Refer to IP_RAW_Alloc() for detailed information.
If you expect to get any response to this packet you should have
opened a RAW connection prior to calling this. Refer to
IP_RAW_Open() for more information about creating a
UDP connection.
Packets are always freed by calling IP_RAW_SendAndFree().
Therefore no call of IP_RAW_Free() is required.
IP_RAW_ReducePayloadLen()
Description
Reduces the payload length of an allocated packet.
Prototype
int IP_RAW_ReducePayloadLen(IP_PACKET * pPacket,
int NumBytes);
Parameters
Parameter | Description |
pPacket | Pointer to previously allocated packet. |
NumBytes | Reduced payload len. |
Return value
< 0 | Error, NumBytes parameter is bigger than current len. Other: O.K., current payload len. |
Additional information
A previously allocated packet might have been allocated
bigger than necessary to be on the safe side. This function
allows to reduce the number of bytes that will be sent to the
real amount necessary.
The payload len can only be reduced. Trying to increase it
(again) is returned as error.
DHCP client
This chapter explains the usage of the Dynamic Host Control Protocol (DHCP) with emNet.
All API functions are described in this chapter.
DHCP backgrounds
DHCP stands for Dynamic Host Configuration Protocol. It is designed to ease configuration
management of large networks by allowing the network administrator to collect all the
IP hosts “soft” configuration information into a single computer. This
includes IP address, name, gateway, and default servers. Refer to
[RFC 2131] - DHCP - Dynamic Host Configuration Protocol for detailed information
about all settings which can be assigned with DHCP.
DHCP is a “client/server” protocol, meaning that machine with the DHCP database
“serves” requests from DHCP clients. The clients typically initiate the transaction by
requesting an IP address and perhaps other information from the server. The server
looks up the client in its database, usually by the client’s media address, and assigns
the requested fields. Clients do not always need to be in the server’s database. If an
unknown client submits a request, the server may optionally assign the client a free
IP address from a “pool” of free addresses kept for this purpose. The server may also
assign the client default information of the local network, such as the default gateway,
the DNS server, and routing information.
When the IP addresses is assigned, it is “leased” to the client for a finite amount of
time. The DHCP client needs to keep track of this lease time, and obtain a lease
extension from the server before the lease time runs out. Once the lease has
elapsed, the client should not send any more IP packets (except DHCP requests) until
he get another address. This approach allows computers (such as laptops or factory
floor monitors) which will not be permanently attached to the network to share IP
addresses and not hog them when they are not using the net.
DHCP is just a superset of the Bootstrap Protocol (BOOTP). The main differences
between the two are the lease concept, which was created for DHCP, and the ability
to assign addresses from a pool. Refer to
[RFC 951] - Bootstrap Protocol for detailed information about the Bootstrap Protocol.
Most of the IP_DHCPC_* API also applies to the BOOTP protocol. Therefore no separate
API for BOOTP is available except for IP_BOOTPC_Activate().
API functions
IP_BOOTPC_Activate()
Description
Activates the BOOTP client for the specified interface.
Prototype
int IP_BOOTPC_Activate(int IFaceId);
Parameters
Parameter | Description |
IFaceId | Interface index. |
Return value
= 0 | O.K. |
≠ 0 | Error, no memory ? |
IP_DHCPC_Activate()
Description
Activates the DHCP client for the specified interface.
Prototype
int IP_DHCPC_Activate( int IFaceId,
const char * sHost,
const char * sDomain,
const char * sVendor);
Parameters
Parameter | Description |
IFaceId | Zero based interface index. |
sHost | Pointer to host name to use in negotiation. May be NULL. |
sDomain | Pointer to domain name to use in negotiation. May be NULL. |
sVendor | Pointer to vendor to use in negotiation. May be NULL. |
Return value
= 0 | O.K. |
≠ 0 | Error, no memory ? |
Additional information
This function is typically called from within IP_X_Config().
This function initializes the DHCP client. It attempts to open
a UDP connection to listen for incoming replies and begins the
process of configuring a network interface using DHCP. The
process may take several seconds, and the DHCP client will keep
retrying if the service does not respond.
The parameters sHost, sDomain, sVendor are optional (can be NULL).
If not NULL, must point to a memory area which remains valid after
the call since the string is not copied.
Example
// Correct function call
IP_DHCPC_Activate(0, "Target", NULL, NULL);
// Illegal function call
char ac;
sprintf(ac, "Target%d, Index);
IP_DHCPC_Activate(0, ac, NULL, NULL);
// Correct function call
static char ac;
sprintf(ac, "Target%d, Index);
IP_DHCPC_Activate(0, ac, NULL, NULL);
If you start the DHCP client with activated logging the output on the terminal I/O
should be similar to the listing below:
DHCP: Sending discover!
DHCP: Received packet from 192.168.1.1
DHCP: Packet type is OFFER.
DHCP: Renewal time: 2160 min.
DHCP: Rebinding time: 3780 min.
DHCP: Lease time: 4320 min.
DHCP: Host name received.
DHCP: Sending Request.
DHCP: Received packet from 192.168.1.1
DHCP: Packet type is ACK.
DHCP: Renewal time: 2160 min.
DHCP: Rebinding time: 3780 min.
DHCP: Lease time: 4320 min.
DHCP: Host name received.
DHCP: IFace 0: IP: 192.168.199.20, Mask: 255.255.0.0, GW: 192.168.1.1.
IP_DHCPC_AddStateChangeHook()
Description
This function adds a hook function to the IP_DHCPC_HOOK_ON_STATE_CHANGE
list. Registered hooks will be called with every status change
and reports some DHCP informations about the current status.
Prototype
void IP_DHCPC_AddStateChangeHook
(IP_DHCPC_HOOK_ON_STATE_CHANGE * pHook,
void ( *pf)(unsigned IFaceId , unsigned State , IP_DHCPC_STATE_INFO * pInfo ));
Parameters
Parameter | Description |
pHook | Element of type IP_DHCPC_HOOK_ON_STATE_CHANGE to register. |
pf | Callback that is notified on a state change. IFaceId: Zero-based interface index. State : Current DHCP client state. pInfo : Further information about the current state. |
Additional information
This mechanism is provided so that the caller can do some processing
when the interface is up (like doing initializations or blinking
LEDs, etc.).
The pointer on IP_DHCPC_STATE_INFO structure will not be valid after
the callback is called. If parameters are to be used, they need to
be copied.
IP_DHCPC_AssignCurrentConfig()
Description
Assigns the internally saved configuration received so far to
the interface.
Prototype
int IP_DHCPC_AssignCurrentConfig(int IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
1 | No configuration available (no previous IP address received). |
0 | O.K., configuration previously received assigned. |
-1 | Error, no memory ? |
Additional information
Please refer to IP_DHCPC_ConfigAssignConfigManually() for more information.
IP_DHCPC_ConfigAlwaysStartInit()
Description
Configures if the client always starts with INIT phase, sending
a DISCOVER packet, even if an IP was configured for the interface
before.
Prototype
int IP_DHCPC_ConfigAlwaysStartInit(int IFaceId,
U8 OnOff);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
OnOff | 0: Off. 1: On. |
Return value
= 0 | O.K. |
≠ 0 | Error, no memory ? |
Additional information
This function shall be called before activating the DHCP client
for an interface using IP_DHCPC_Activate() .
IP_DHCPC_ConfigAssignConfigManually()
Description
Configures if the configuration received by a DHCP server is
assigned to the interface as soon as received.
Prototype
int IP_DHCPC_ConfigAssignConfigManually(int IFaceId,
U8 OnOff);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
OnOff | 0: Off (default), configuration is assigned as soon as received. 1: On, configuration is only saved internally and the user needs to manually assign it to an interface. |
Return value
= 0 | O.K. |
≠ 0 | Error, no memory ? |
Additional information
This function shall be called before activating the DHCP client
for an interface using IP_DHCPC_Activate() .
In case the received configuration shall not be used immediately
upon receiving it, it needs to be set manually later on. This can
be done by either using information from the state callback using
IP_DHCPC_AddStateChangeHook() or by simply calling
IP_DHCPC_AssignCurrentConfig() to activate the configuration as
it would have been done automatically.
This configuration does not override assigning a fallback
configuration if this has been configured as well.
IP_DHCPC_ConfigDisableARPCheck()
Description
Configures if the client checks an offered address to be really
free by sending ARP probes before using the IP.
Prototype
int IP_DHCPC_ConfigDisableARPCheck(int IFaceId,
U8 OnOff);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
OnOff | 0: Off, ARP probes are sent (default). 1: On, ARP probes are disabled. |
Return value
= 0 | O.K. |
≠ 0 | Error, no memory ? |
Additional information
This function shall be called before activating the DHCP client
for an interface using IP_DHCPC_Activate() .
This routine is not available when configuring the define
IP_DHCPC_CHECK_IP_BEFORE_BOUND=0 .
IP_DHCPC_ConfigDNSManually()
Description
Configures if the client will request and use a received DNS
server configuration.
Prototype
int IP_DHCPC_ConfigDNSManually(int IFaceId,
U8 OnOff);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
OnOff | 0: Off, DNS configuration from server is used. 1: On, DNS configuration needs to be set manually. |
Return value
= 0 | O.K. |
≠ 0 | Error, no memory ? |
Additional information
This function shall be called before activating the DHCP client
for an interface using IP_DHCPC_Activate() .
IP_DHCPC_ConfigRequestLeaseTime()
Description
Configures the lease time to use in REQUEST messages.
Prototype
int IP_DHCPC_ConfigRequestLeaseTime(int IFaceId,
U32 LeaseTime);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
LeaseTime | Lease time [s] to request from the server. The value 0xFFFFFFFF requests an infinte lease from the server. Which lease time is actually granted is decided by the server. |
Return value
= 0 | O.K. |
≠ 0 | Error, no memory ? |
Additional information
This function shall be called before activating the DHCP client
for an interface using IP_DHCPC_Activate() .
By default the lease time initially granted by the server in
its OFFER message is used when sending REQUEST messages. To
only initially send a custom lease time you should revert back
to a value of 0 (use the previously granted value) or
0xFFFFFFFF (infinity). It is possible to call this routine while
the DHCP client is active to change this behavior on the fly.
IP_DHCPC_ConfigOnActivate()
Description
Configures behavior regarding currently set parameters of an
interface when the DHCP client is activated on this interface.
Prototype
int IP_DHCPC_ConfigOnActivate(int IFaceId,
U8 Mode);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Mode | Mode to configure. |
Return value
= 0 | O.K. |
≠ 0 | Error, no memory ? |
Additional information
This function shall be called before activating the DHCP client
for an interface using IP_DHCPC_Activate() .
Please be aware that activating the DHCP client with a static
configured IP address instructs the DHCP client to try to request
this address from the server. In case IP_DHCPC_ConfigOnFail() is
configured to use DHCP_RESET_CONFIG (default) it might happen that
the static IP will be reset if no server is reachable for the
REQUEST or the IP addr. gets declined by a server.
Possible values for Mode
Mode | Description |
DHCPC_RESET_CONFIG | Reset interface when activating the DHCP client on this
interface to avoid using old settings longer than
necessary. Default. |
DHCPC_USE_STATIC_CONFIG | Keep previous static configuration, if any, as fallback
configuration as long as no new configuration has been
received from a server. |
IP_DHCPC_ConfigOnFail()
Description
Configures behavior regarding currently set parameters of an
interface when the DHCP client fails in communication to negotiate
a previously received configuration with a server (REQUEST message).
Prototype
int IP_DHCPC_ConfigOnFail(int IFaceId,
U8 Mode);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Mode | Mode to configure. |
Return value
= 0 | O.K. |
≠ 0 | Error, no memory ? |
Additional information
This function shall be called before activating the DHCP client
for an interface using IP_DHCPC_Activate() .
To configure a fallback IP in case no DHCP server is available at
all, starting the DHCP client from INIT state, please refer to
IP_DHCPC_ConfigOnActivate() .
When the on-fail configuration is applied this does not mean
that the DHCP client activity is stopped. It could be intended
to keep the DHCP client running in case a server becomes available.
To stop the DHCP client you should monitor the state changes
using IP_DHCPC_AddStateChangeHook() and react to the messages
DHCPC_STATE_INIT and DHCPC_STATE_RESTARTING that signal fallbacks
caused by server timeout or no server being available at all.
You should then halt the DHCP client service from the callback.
Possible values for Mode
Mode | Description |
DHCPC_RESET_CONFIG | Reset interface to avoid using old settings longer than
necessary as they might interfere with other DHCP clients in this network. Default. |
DHCPC_USE_STATIC_CONFIG | Setup previous static configuration, if any, as fallback
configuration to remain accessible. |
DHCPC_USE_DHCP_CONFIG | Keep previously received DHCP configuration. Not recommended
as it might interfere with other DHCP clients in this network. |
IP_DHCPC_ConfigOnLinkDown()
Description
Configures behavior regarding currently set parameters of an
interface when the DHCP client is activated on this interface
and the link goes down.
Prototype
int IP_DHCPC_ConfigOnLinkDown(int IFaceId,
U32 Timeout,
U8 Mode);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Timeout | Timeout to wait before reacting on link down [ms]. |
Mode | Mode to configure. |
Return value
= 0 | O.K. |
≠ 0 | Error, no memory ? |
Additional information
This function shall be called before activating the DHCP client
for an interface using IP_DHCPC_Activate().
Possible values for Mode
Mode | Description |
DHCPC_RESET_CONFIG | Reset interface when link goes down on this interface
to avoid using old settings longer than necessary as
the target might be connected to another network.
Default. |
DHCPC_USE_STATIC_CONFIG | Setup previous static configuration, if any, as fallback
configuration on link down to allow a quick start once
the link goes up again. |
DHCPC_USE_DHCP_CONFIG | Keep previously received DHCP configuration on link
down as long as the configuration is not declined or a
new configuration is received once link on this interface is up again. |
IP_DHCPC_ConfigUniBcStartMode()
Description
Configures if the client will start with unicast or broadcast
messages first and enables automatic mode switching.
Prototype
int IP_DHCPC_ConfigUniBcStartMode(int IFaceId,
U8 Mode);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Mode | 0: Start with unicasts first. 1: Start with broadcasts first. |
Return value
= 0 | O.K. |
≠ 0 | Error, no memory ? |
Additional information
This function shall be called before activating the DHCP client
for an interface using IP_DHCPC_Activate() .
The mode switch will be applied after a couple of retries have
been sent for the same message.
The number of retries can be configured using IP_DHCPC_SetTimeout() .
IP_DHCPC_GetState()
Description
Returns the state of the DHCP client.
Prototype
unsigned IP_DHCPC_GetState(int IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
= 0 | DHCP client not in use. |
> 0 | DHCP client in use. |
IP_DHCPC_GetOptionRequestList()
Description
Retrieves the current list of DHCP options to request from a server.
Prototype
int IP_DHCPC_GetOptionRequestList(int IFaceId,
U8 * pBuffer,
unsigned BufferSize);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pBuffer | Pointer to buffer where to store up to BufferSize DHCP options that are requested from a server. Can be NULL to determine the size of the buffer required to retrieve all options in use. |
BufferSize | Maximum amount of options to retrieve. |
Return value
< 0 | Request list disabled via compile switch or error, no memory ? |
≥ 0 | Number of U8 DHCP options returned or would be returned if BufferSize would be sufficient. A list with zero entries is valid if it has been set via config. |
Additional information
For more information about the actual DHCP options please refer
to RFC 1533 .
For an example please refer to IP_DHCPC_SetOnOptionCallback() .
IP_DHCPC_Halt()
Description
Stops DHCP client activity for the given network interface.
Prototype
int IP_DHCPC_Halt(int IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
= 0 | O.K. |
≠ 0 | Error, no memory ? |
IP_DHCPC_Renew()
Description
Sends a REQUEST with the currently in use DHCP configuration to
the DHCP server to check if the configuration is still valid.
Prototype
int IP_DHCPC_Renew(int IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
= 0 | O.K. |
≠ 0 | Error, no memory ? |
IP_DHCPC_SendDeclineAndHalt()
Description
Sends a DECLINE to the DHCP server and halts the DHCP client.
Prototype
int IP_DHCPC_SendDeclineAndHalt(int IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
Additional information
Please refer to IP_DHCPC_Decline() for more information.
IP_DHCPC_SendDeclineAndResetIP()
Description
Sends a DECLINE to the DHCP server without halting the DHCP client.
The IP address of the interface is cleared.
Prototype
int IP_DHCPC_SendDeclineAndResetIP(int IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
Additional information
Can be used to reject a previously accepted address from a DHCP
server. A reason to do so would be that despite this address
seemed free before, now an address collision for example via
ACD has been detected.
The DHCP client needs to be in BOUND state, otherwise no decline
is sent as we do not own the address.
IP_DHCPC_SetCallback()
Description
This function allows the caller to set a callback for an interface.
Prototype
int IP_DHCPC_SetCallback(int IFaceId,
int ( *routine)(int IFaceId , int State ));
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
routine | Callback functions which should be called with every status changes. |
Return value
= 0 | O.K. |
≠ 0 | Error, no memory ? |
Additional information
The callback is called with every status change.
This mechanism is provided so that the caller can do some processing
when the interface is up (like doing initializations or blinking
LEDs, etc.).
IP_DHCPC_SetClientId()
Description
Sets the DHCP client id for the specified interface.
Should be called prior to IP_DHCPC_Activate()
Prototype
int IP_DHCPC_SetClientId( int IFaceId,
const U8 * pClientId,
unsigned ClientIdLen);
Parameters
Parameter | Description |
IFaceId | Zero based interface index. |
pClientId | Pointer to ClientId to use in negotiation. Will not be copied. |
ClientIdLen | Length of client ID. |
Return value
= 0 | O.K. |
≠ 0 | Error, no memory ? |
Additional information
Typically a DHCP server will recognize a client based on its
MAC address. A client ID can be included by the client when
communicating with the server for identification if needed.
Please be aware that one byte is prepend that contains the
type of the ID. The client ID will not be copied into the
stack, therefore you need to make sure that the memory will
be available even after the call.
Bad example
U8 ClientID[7]; // 1 byte type + 6 bytes MAC address.
ClientID[0] = 0x01; // Type = Ethernet.
IP_GetHWAddr(0, &ClientID[1], sizeof(ClientID) - 1);
IP_DHCPC_SetClientId(0, ClientID, sizeof(ClientID));
Good example
static U8 ClientID[7]; // 1 byte type + 6 bytes MAC address.
ClientID[0] = 0x01; // Type = Ethernet.
IP_GetHWAddr(0, &ClientID[1], sizeof(ClientID) - 1);
IP_DHCPC_SetClientId(0, ClientID, sizeof(ClientID));
IP_DHCPC_SetOnOptionCallback()
Description
Sets a callback that gets notified about received DHCP options.
Prototype
void IP_DHCPC_SetOnOptionCallback(IP_DHCPC_ON_OPTION_FUNC * pf);
Parameters
Parameter | Description |
pf | Callback to execute for each DHCP option received. |
Example
#define DHCP_NTP_OPTION_TYPE (42u)
static U8 _DhcpReqList[16]; // Default is ~4 U8 options.
/*********************************************************************
*
* _OnDhcpOption()
*
* Function description
* Callback executed for every DHCP option received.
*
* Parameters
* IFaceId: Zero-based interface index.
* pInfo : Further information of type IP_DHCPC_ON_OPTION_INFO
* about the DHCP option parsed.
*
* Additional information
* Once all options are parsed the end marker (option type 0xFF) is
* reported as well for an easy to detect end of the list from
* within the callback. No end is signaled if there was an abort
* that can be detected by looking at pInfo->Status .
*/
static void _OnDhcpOption(unsigned IFaceId, IP_DHCPC_ON_OPTION_INFO* pInfo) {
U32 Addr;
IP_USE_PARA(IFaceId);
if (pInfo->Status == 0u) { // Not a parser error ?
if (pInfo->Type == DHCP_NTP_OPTION_TYPE) {
//
// Multiple U32 IPv4 addresses of NTP servers might be returned.
//
IP_Logf_Application( "NTP servers retrieved via DHCP:");
do {
//
// Get the IPv4 address of an NTP server in network endianness (BE)
// as our printf formatter %i for an IPv4 expects it that way.
//
memcpy(&Addr, pInfo->pVal, 4);
IP_Logf_Application(" - %i", Addr);
pInfo->Len -= 4u;
} while (pInfo->Len != 0u);
}
}
}
/*********************************************************************
*
* _AskDhcpForNtpServers()
*
* Function description
* When sending a request to a DHCP server, also ask it for NTP servers.
* To be called from IP_X_Config() before activating the DHCP client.
*
* Parameters:
* IFaceId: Zero-based interface index.
*/
static void _AskDhcpForNtpServers(unsigned IFaceId) {
int NumOptions;
//
// Get old (default list).
//
NumOptions = IP_DHCPC_GetOptionRequestList(IFaceId, &_DhcpReqList[0], sizeof(_DhcpReqList));
if (NumOptions >= 0) { // Successfully retrieved current list ?
if (NumOptions < (int)sizeof(_DhcpReqList)) { // Do we have space for one more option ?
//
// Assume that the NTP option 42 is not in the list and add it.
// If unsure, add code to look through the options present
// and only add the option if it is not already in there.
//
_DhcpReqList[NumOptions++] = DHCP_NTP_OPTION_TYPE;
//
// Set new list.
//
IP_DHCPC_SetOptionRequestList(IFaceId, (const U8*)&_DhcpReqList[0], (unsigned)NumOptions);
//
// Set callback that gets notified about received options.
//
IP_DHCPC_SetOnOptionCallback(_OnDhcpOption);
}
}
}
IP_DHCPC_SetOptionRequestList()
Description
Sets the list of DHCP options to request from a server.
Prototype
int IP_DHCPC_SetOptionRequestList( int IFaceId,
const U8 * pOptions,
unsigned NumOptions);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pOptions | Pointer to array with U8 DHCP options that shall be requested from a server when sending a REQUEST . The memory has to remain valid after the call. Can be NULL for empty list but might prevent the DHCP client from proper functioning. |
NumOptions | Number of options at pOptions . |
Return value
< 0 | Request list disabled via compile switch or error, no memory ? |
= 0 | O.K. |
Additional information
Best practice to add your own DHCP options is to read back the
current list of options with IP_DHCPC_GetOptionRequestList()
and then add the desired options that are missing.
To set an empty list (whether this makes sense or not) set
pOptions ≠ NULL and NumOptions = 0 .
For an example please refer to IP_DHCPC_SetOnOptionCallback() .
IP_DHCPC_SetTimeout()
Description
Sets timeout parameters for DHCP requests.
RFC2131 demands exponential retransmission times (doubling
retransmission time with each retry), but in practice it may
make more sense to work with a fixed, non-exponential timeout.
Prototype
void IP_DHCPC_SetTimeout(int IFaceId,
U32 Timeout,
U32 MaxTries,
unsigned Exponential);
Parameters
Parameter | Description |
IFaceId | Interface index. |
Timeout | Value of the timeout [ms]. |
MaxTries | Maximum number or attempts. |
Exponential | Value used to delay new attempts. |
Data structures
IP_DHCPC_ON_OPTION_INFO
Description
Returns information about the next DHCP option to be processed.
Type definition
typedef struct {
const U8 * pVal;
int Status;
U8 Type;
U8 Len;
} IP_DHCPC_ON_OPTION_INFO;
Structure members
Member | Description |
pVal | Value of the DHCP option. |
Status | = 0: O.K. < 0: Parse error, abort of parser. |
Type | DHCP option type. Please refer to RFC 1533 for further information. |
Len | Length of the option value. |
IP_DHCPC_ON_OPTION_FUNC
Description
Callback executed for every DHCP option received.
Type definition
typedef void (IP_DHCPC_ON_OPTION_FUNC)(unsigned IFaceId,
IP_DHCPC_ON_OPTION_INFO * pInfo);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pInfo | Further information of type IP_DHCPC_ON_OPTION_INFO about the DHCP option parsed. |
Additional information
Once all options are parsed, the end marker (option type 0xFF) is
reported as well for an easy to detect end of the list from
within the callback. No end is signaled if there was an abort
that can be detected by looking at pInfo->Status .
DHCP server (Add-on)
The emNet implementation of the DHCP server is an optional extension to
emNet. It allows setting up a Dynamic Host Control Protocol (DHCP) server that
seamlessly integrates with emNet. All API functions are described in this chapter.
DHCP Backgrounds
DHCP stands for Dynamic Host Configuration Protocol. It is designed to ease configuration
management of large networks by allowing the network administrator to collect all the
IP hosts “soft” configuration information into a single computer. This
includes IP address, name, gateway, and default servers. Refer to
[RFC 2131] - DHCP - Dynamic Host Configuration Protocol for detailed information
about all settings which can be assigned with DHCP.
Further information can be found in the chapter DHCP backgrounds in
the description of the DHCP client.
API functions
IP_DHCPS_ConfigDNSAddr()
Description
Configures one or more DNS addr. to assign to clients.
Prototype
int IP_DHCPS_ConfigDNSAddr(unsigned IFIndex,
U32 * paDNSAddr,
U8 NumServers);
Parameters
Parameter | Description |
IFIndex | Zero-based interface index of the server to configure. |
paDNSAddr | Array of U32 IPv4 addresses of DNS servers to use (host order). |
NumServers | Number of DNS servers in array. |
Return value
0 | O.K. |
IP_ERR_MISC | Error, server already started. |
IP_ERR_PARAM | Error, wrong interface. |
Additional information
Configuring DNS server settings is optional. If no DNS servers
are configured no DNS servers will be assigned to clients.
Needs to be called before activating the DHCP server for this
interface with IP_DHCPS_Start().
Example
U32 aDNSAddr[2];
//
// Setup DNS addr. as needed.
//
aDNSAddr[0] = IP_BYTES2ADDR(192, 168, 12, 1);
aDNSAddr[1] = IP_BYTES2ADDR(192, 168, 12, 2);
IP_DHCPS_ConfigDNSAddr(0, &aDNSAddr[0], 2);
IP_DHCPS_ConfigPool(0, IP_BYTES2ADDR(192, 168, 12, 11), 0xFFFF0000, 20);
IP_DHCPS_Init(0);
IP_DHCPS_Start(0);
IP_DHCPS_ConfigGWAddr()
Description
Configures the default gateway to be assign to clients.
Prototype
int IP_DHCPS_ConfigGWAddr(unsigned IFIndex,
U32 GWAddr);
Parameters
Parameter | Description |
IFIndex | Zero-based interface index of the server to configure. |
GWAddr | Default gateway IP address in host order. |
Return value
0 | O.K. |
IP_ERR_MISC | Error, server already started. |
IP_ERR_PARAM | Error, wrong interface. |
Additional information
Configuring a gateway setting is optional. If no gateway is
configured no gateway will be assigned to clients.
Needs to be called before activating the DHCP server for this
interface with IP_DHCPS_Start().
Example
IP_DHCPS_ConfigGWAddr(0, IP_BYTES2ADDR(192, 168, 12, 1));
IP_DHCPS_ConfigPool(0, IP_BYTES2ADDR(192, 168, 12, 11), 0xFFFF0000, 20);
IP_DHCPS_Init(0);
IP_DHCPS_Start(0);
IP_DHCPS_ConfigMaxLeaseTime()
Description
Configures the maximum lease time that a client will be granted
to use the achieved configuration.
Prototype
int IP_DHCPS_ConfigMaxLeaseTime(unsigned IFIndex,
U32 Seconds);
Parameters
Parameter | Description |
IFIndex | Zero-based interface index. |
Seconds | Maximum lease time in seconds. Default 7200s => 2h. Up to 4294967 seconds, converted into ms this is the maximum we can store in an U32. 0xFFFFFFFF to grant infinite if asked for. |
Return value
0 | O.K. |
IP_ERR_MISC | Error, server already started. |
IP_ERR_PARAM | Error, wrong interface or value for lease time invalid. |
Additional information
Optional. Needs to be called before activating the DHCP server for
this interface with IP_DHCPS_Start().
Example
IP_DHCPS_ConfigMaxLeaseTime(0, 7200);
IP_DHCPS_ConfigPool(0, IP_BYTES2ADDR(192, 168, 12, 11), 0xFFFF0000, 20);
IP_DHCPS_Init(0);
IP_DHCPS_Start(0);
IP_DHCPS_ConfigPool()
Description
Configures the IP address pool that can be assigned to DHCP clients.
Prototype
int IP_DHCPS_ConfigPool(unsigned IFIndex,
U32 StartIPAddr,
U32 SNMask,
U32 PoolSize);
Parameters
Parameter | Description |
IFIndex | Zero-based interface index of the server to configure. |
StartIPAddr | First IP address of the pool in host order. |
SNMask | Subnet mask in host order. |
PoolSize | Number of addresses in the pool starting from StartIPAddr. The pool size has to be at least 1. |
Return value
0 | O.K. |
IP_ERR_MISC | Error, server already started. |
IP_ERR_PARAM | Error, wrong interface. |
Additional information
Optional. Needs to be called before activating the DHCP server for
this interface with IP_DHCPS_Start().
Example
IP_DHCPS_ConfigPool(0, IP_BYTES2ADDR(192, 168, 12, 11), 0xFFFF0000, 20);
IP_DHCPS_Init(0);
IP_DHCPS_Start(0);
IP_DHCPS_Halt()
Description
Stops DHCP server activity for the passed interface.
Prototype
void IP_DHCPS_Halt(unsigned IFIndex);
Parameters
Parameter | Description |
IFIndex | Zero-based interface index. |
IP_DHCPS_Init()
Description
Initializes the DHCP server for the specified interface.
Prototype
int IP_DHCPS_Init(unsigned IFIndex);
Parameters
Parameter | Description |
IFIndex | Zero-based interface index. |
Return value
0 | O.K. |
IP_ERR_MISC | Error, server already initialized. |
IP_ERR_NOMEM | Error, not enough memory. |
IP_ERR_PARAM | Error, wrong interface. |
Additional information
This function is obsolete. Its functionality has been implemented
into IP_DHCPS_ConfigPool() as this needs to be called anyhow.
This function is a dummy for the moment, so it does not hurt to
call it like before.
IP_DHCPS_SetReservedAddresses()
Description
Sets a configuration for IP addresses to reserve for specific
MAC addresses or HostNames (or both).
Prototype
int IP_DHCPS_SetReservedAddresses( unsigned IFIndex,
const IP_DHCPS_RESERVE_ADDR * paAddr,
unsigned NumAddr);
Parameters
Parameter | Description |
IFIndex | Zero-based interface index. |
paAddr | Pointer to array of IP_DHCPS_RESERVE_ADDR addresses. |
NumAddr | Number of addresses at paAddr . |
Return value
Additional information
For the moment the global configuration for subnet mask, gateway
and DNS for the server on this interface is used.
IP addresses to be reserved are not limited to addresses of the
configured pool. Of course addresses need to be within the
configured subnet to work as expected.
Example
const IP_DHCPS_RESERVE_ADDR _aReserved[] = {
// HW addr. , IP addr., , HostName
{(const U8*)"\x00\x0C\x29\x76\xE7\x0B", IP_BYTES2ADDR(192,168,12,20), NULL}, // Reserve by HW addr. only.
{(const U8*)"\x00\x22\xC7\xAF\xFC\x25", IP_BYTES2ADDR(192,168,12,16), "oliver"}, // Reserve by HW addr. AND Hostname (both have to match).
{NULL , IP_BYTES2ADDR(192,168,12,17), "sven"}, // Reserve by Hostname first (or only).
{(const U8*)"\x00\x22\xC7\xAF\xFC\x30", IP_BYTES2ADDR(192,168,12,17), NULL}, // Reserve by HW addr. second.
{(const U8*)"\xB8\x27\xEB\xC7\x96\x5F", IP_BYTES2ADDR(192,168,20,55), NULL}, // Reserve by HW addr. only.
};
static void _StartServer(void) {
IP_DHCPS_ConfigPool(0, IP_BYTES2ADDR(192, 168, 12, 11), IP_BYTES2ADDR(255, 255, 0, 0), 20);
IP_DHCPS_Init(0);
IP_DHCPS_SetReservedAddresses(0, _aReserved, SEGGER_COUNTOF(_aReserved));
IP_DHCPS_Start(0);
}
IP_DHCPS_SetVendorOptionsCallback()
Description
This function sets a callback that is executed when sending
response to a client and the client has sent a vendor class
identifier (DHCP option 60). It can be used to add vendor
specific options to a DHCP response to a client.
Prototype
void IP_DHCPS_SetVendorOptionsCallback(IP_DHCPS_GET_VENDOR_OPTION_FUNC * pf);
Parameters
Example
/*********************************************************************
*
* _cbDHCPs_AddVendorOptions()
*
* Function description
* Adds DHCP vendor specific options to our server replies.
*
* Parameters
* IFaceId : Zero-based interface index.
* pInfo : Further information about the vendor of the client.
* ppOption: Pointer to the pointer where to add further options.
* The dereferenced pointer needs to be incremented
* by the number of bytes added. Type and length bytes
* need to be added by the callback as well.
* NumBytes: Number of free bytes that can be used to store
* options from the callback.
*/
static void _cbDHCPs_AddVendorOptions(unsigned IFaceId, IP_DHCPS_VENDOR_OPTION_INFO* pInfo, U8** ppOption, unsigned NumBytes) {
U8* pVendorClassId;
U8* pOption;
unsigned VendorClassIdLen;
IP_USE_PARA(IFaceId);
pOption = *ppOption; // Get the location where to add our options aka borrow the pointer.
//
// Parse the vendor class id.
//
pVendorClassId = pInfo->pVendorClassId; // Points to the type which should always be DHCP option 60.
pVendorClassId++; // proceed to the length field.
VendorClassIdLen = (unsigned)*pVendorClassId++; // Get the length byte and proceed to the actual non-terminated vendor string.
//
// Check if the vendor class identifier is known to us.
//
if ((IP_MEMCMP(pVendorClassId, "MSFT 5.0", VendorClassIdLen) == 0) &&
(NumBytes >= 8u)) { // Also check if we have enough space to add the option.
//
// Identified a Microsoft device that supports vendor-specific options.
// More information about this can be found at the following location:
// * https://msdn.microsoft.com/en-us/library/cc227279.aspx
//
// Information about the vendor-specific options supported for Microsoft
// devices can be found here:
// * [1] https://msdn.microsoft.com/en-us/library/cc227275.aspx
// * [2] https://msdn.microsoft.com/en-us/library/cc227276.aspx
//
// A common task is to disable NetBIOS (over TCP/IP) via DHCP
// if your clients primarily use other techniques and you want
// to speed up discovery of them by name. Typically one method
// will be tested after each other which means that each method
// used costs additional time before your desired discovery
// method finally might be used.
//
*pOption++ = 43u; // Add an option field of type 43 "Vendor-Specific Information".
*pOption++ = 6u; // Add length field with value 6 for the actual 6 bytes vendor-specific content.
*pOption++ = 0x01; // [1] "Microsoft Disable NetBIOS Option (section 2.2.2.1)"
*pOption++ = 0x04; // [2] "Vendor-specific Option Length"
IP_StoreU32BE(pOption, 0x00000002uL); // [2] "Vendor-specific Option Data" "Disables NetBIOS over TCP/IP for that network interface."
pOption += 4;
}
*ppOption = pOption; // Write back the borrowed pointer so the DHCP server internal code knows where to continue.
}
void main(void) {
...
IP_DHCPS_SetVendorOptionsCallback(_cbDHCPs_AddVendorOptions);
...
}
IP_DHCPS_Start()
Description
Starts the DHCP server for the specified interface.
Prototype
int IP_DHCPS_Start(unsigned IFIndex);
Parameters
Parameter | Description |
IFIndex | Zero-based interface index. |
Return value
0 | O.K. |
IP_ERR_MISC | Error, server already started or not initialized/configured. |
IP_ERR_NOMEM | Error, not enough memory. |
IP_ERR_PARAM | Error, wrong interface. |
Additional information
IP_DHCPS_Init() and IP_DHCPS_ConfigPool() needs to be called
before activating the DHCP server for an interface in order
to set at least the minimum configurations.
Data structures
IP_DHCPS_RESERVE_ADDR
Description
Reserves a DHCP IPv4 address via HW address, hostname or both.
Type definition
typedef struct {
const U8 * pHWAddr;
U32 IPAddr;
const char * sHostName;
} IP_DHCPS_RESERVE_ADDR;
Structure members
Member | Description |
pHWAddr | Client HW/MAC address to reserve to. Can be NULL. |
IPAddr | IPv4 address to reserve in host endianness. Does not need to be from the DHCP pool itself. |
sHostName | Client hostname to reserve to. Can be NULL. |
IP_DHCPS_GET_VENDOR_OPTION_INFO
Description
Returns information about the vendor specific identifier
received with DHCP option 60.
Type definition
typedef struct {
U8 * pVendorClassId;
} IP_DHCPS_GET_VENDOR_OPTION_INFO;
Structure members
Member | Description |
pVendorClassId | Pointer to the DHCP option 60 field received from a client including type and length bytes. A typical example would be Type: 60, Len: 8 and Value: ’M’ ’S’ ’F’ ’T’ ’ ’ ’5’ ’.’ ’0’ for a Microsoft client that supports vendor specific DHCP option 43 commands. |
IP_DHCPS_GET_VENDOR_OPTION_FUNC
Description
Inserts a vendor specific configuration for DHCP option 43.
Type definition
typedef void (IP_DHCPS_GET_VENDOR_OPTION_FUNC)
(unsigned IFaceId,
IP_DHCPS_GET_VENDOR_OPTION_INFO * pInfo,
U8 ** ppOption,
unsigned NumBytes);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pInfo | Further information of type IP_DHCPS_GET_VENDOR_OPTION_INFO about the vendor of the client. |
ppOption | Pointer to the pointer where to add further options. The dereferenced pointer needs to be incremented by the number of bytes added. Type and length bytes need to be added by the callback as well. |
NumBytes | Number of free bytes that can be used to store options from the callback. |
Resource usage
The ROM usage depends on the compiler options, the compiler version and the used
CPU. The memory requirements of the DHCP server modules presented in the tables
below have been measured on an ARM7 and a Cortex-M3 system. Details about the
further configuration can be found in the sections of the specific example.
ROM usage on an ARM7 system
The following resource usage has been measured on an ARM7 system using IAR
Embedded Workbench V6.30.6, Thumb mode, no interwork, size optimization.
Addon | ROM |
emNet DHCP server | approximately 2.0 kByte |
ROM usage on a Cortex-M3 system
The following resource usage has been measured on a Cortex-M3 system using IAR
Embedded Workbench V6.30.6, size optimization.
Addon | ROM |
emNet DHCP server | approximately 2.0 kByte |
RAM usage
Addon | RAM |
emNet DHCP server | approximately 200 bytes |
mDNS Server (Add-on)
The emNet implementation of mDNS server which stands for multicast DNS server is an
optional extension to emNet. It makes your target easily discoverable and advertising
services available throughout your network.
For the target IP address identification, this add-on also replies to Microsoft LLMNR requests.
emNet mDNS
The emNet mDNS implementation is an optional extension which can be
seamlessly integrated into your TCP/IP application.
It allows your target to be easily identified with a small memory footprint.
The mDNS server module implements the relevant parts of the following RFCs.
Document | Download |
Multicast DNS |
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc6762.txt |
Link-Local Multicast Name Resolution (LLMNR) |
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc4795.txt |
DNS-Based Service Discovery |
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc6763.txt |
A DNS RR for specifying the location of services (DNS SRV) |
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc2782.txt |
The following table shows the contents of the emNet root directory:
Directory | Content |
Application | Contains an example application that run’s
a simple mDNS server example. |
IP | Contains the mDNS server file, IP_DISCOVER.c. |
Feature list
- Low memory footprint.
- Makes your target easily discoverable.
- Easy to implement.
Requirements
TCP/IP stack
The emNet mDNS server implementation requires the emNet TCP/IP stack.
Multicast DNS background
Multicast DNS allows to find devices in an environment without the support of an
actual DNS server. A DNS request is sent to a specific multicast address on a
specific port. Servers are listening on this multicast address and handling the
requests.
Multicast DNS handles only local systems and doen’t replace a real DNS for request
outside the local network.
Hostname resolution
In order to get the IP address of a target by its name, two records could be
sent:
- A: To get the IPv4 address.
- AAAA: To get the IPv6 address.
Apple and Microsoft are both proposing a similar solution but using different
multicast IP addresses and ports.
The Add-on is handling both specifications for A and AAAA requests.
The hostname is set in the configuration structure:
static const IP_DNS_SERVER_CONFIG _Config = {
.sHostname = "mytarget.local",
.TTL = 120,
.NumConfig = 3, // Could be 0 for name resolution only
.apSDConfig = _SDConfig, // DNS-SD config, could be NULL.
};
Service discovery (mDNS-SD)
The add-on also provides the definition of some services through additional
records:
- PTR: Pointer record.
- SRV: Service record.
- TXT: Text record.
The service discovery is only available through the Apple multicast address (use of Bonjour), or
equivalent on linux machines (like avahi).
For example, if a target runs a web server, a possible configuration is:
static const IP_DNS_SERVER_SD_CONFIG _SDConfig[] = {
{
.Type = IP_DNS_SERVER_TYPE_PTR,
.Flags = IP_DNS_SERVER_FLAG_FLUSH,
.TTL = 0,
.Config = {
.PTR = {
.sName = "_http._tcp.local",
.sDomainName = "myserver._http._tcp.local"
}
}
},
{
.Type = IP_DNS_SERVER_TYPE_SRV,
.Flags = IP_DNS_SERVER_FLAG_FLUSH,
.TTL = 0,
.Config = {
.SRV = {
.sName = "myserver._http._tcp.local",
.Priority = 0,
.Weight = 0,
.Port = 80,
.sTarget = "mytarget.local"
}
}
},
{
.Type = IP_DNS_SERVER_TYPE_TXT,
.Flags = IP_DNS_SERVER_FLAG_FLUSH,
.TTL = 0,
.Config = {
.TXT = {
.sName = "myserver._http._tcp.local",
.sTXT = "PATH=/"
}
}
}
};
PTR record:
The PTR record indicates that an HTTP server runs at “myserver._http._tcp.local”
SRV record:
The SRV record gives indication on the port number (80) and the actual local target name (mytarget)
TXT record:
The TXT record gives additional information, for example the path to the web server.
It is possible to add A and AAAA records, but they are not needed if the target name corresponds to
the target host name.
API functions
IP_MDNS_SERVER_Start()
Description
Starts the LLMNR/mDNS DNS-SD discovery service.
Prototype
int IP_MDNS_SERVER_Start(const IP_DNS_SERVER_CONFIG * pConfig);
Parameters
Parameter | Description |
pConfig | Pointer to the configuration array. |
Return value
Example
Configuration should define local names.
static const IP_DNS_SERVER_CONFIG _Config = {
.sHostname = "mytarget.local",
.TTL = 120,
.NumConfig = 0, // No DNS-SD configuration.
.apSDConfig = NULL
};
IP_MDNS_SERVER_Start(&_Config);
IP_MDNS_SERVER_Stop()
Description
Stops the LLMNR/mDNS DNS-SD discovery service.
Prototype
int IP_MDNS_SERVER_Stop(void);
Return value
Data structures
Structure IP_DNS_SERVER_CONFIG
Description
This is the main configuration of the mDNS server.
Prototype
typedef struct {
const char* sHostname;
U32 TTL;
unsigned NumConfig;
const IP_DNS_SERVER_SD_CONFIG* apSDConfig;
} IP_DNS_SERVER_CONFIG;
Member | Description |
sHostname | Pointer on a null terminated string corresponding to
the host name (for example “mytarget.local”) |
TTL | Time to live in seconds. If set to 0 a default value defined in DNS_TTL_INIT is used. |
NumConfig | Number of mDNS-SD configuration pointed by apSDConfig. Could be 0. |
apSDConfig | Array of mDNS-SD configuration. Could be NULL if NumConfig is 0. |
Structure IP_DNS_SERVER_SD_CONFIG
Description
Configuration of a mDNS-SD entry.
Prototype
typedef struct {
U32 TTL;
union {
IP_DNS_SERVER_A A;
#if IP_SUPPORT_IPV6
IP_DNS_SERVER_AAAA AAAA;
#endif
IP_DNS_SERVER_PTR PTR;
IP_DNS_SERVER_SRV SRV;
IP_DNS_SERVER_TXT TXT;
} Config;
U8 Type;
U8 Flags;
} IP_DNS_SERVER_SD_CONFIG;
Flags | Description |
IP_DNS_SERVER_FLAG_FLUSH | Sets the FLUSH bit when sending a response that contains this entry.
The FLUSH bit should be set on all unique resources like the primary host name
or in general A and AAAA records. Unique entries in repsonses are meant to FLUSH all
previously returned configurations.
We do not set this flag automatically for ANY entry (not even A and AAAA) to allow
maximum freedom in your configuration. |
Structure IP_DNS_SERVER_A
Description
Description of a A record entry (IPv4 IP address). This is not needed to have
an entry for the host name. An ’A’ request with the host name gets
automatically a reply with the current IP address of the interface on
which the request is received.
If the field IPAddr is set to 0, the IP address of the host will be used
automatically.
Prototype
typedef struct {
char* sName;
IP_ADDR IPAddr;
} IP_DNS_SERVER_A;
Member | Description |
sName | Null terminated string of the server name. |
IPAddr | IPv4 address of the server name. |
Structure IP_DNS_SERVER_AAAA
Description
Description of a AAAA record entry (IPv6 IP address). This is not needed to have
an entry for the host name. An ’AAAA’ request with the host name gets
automatically a reply with the current IP address of the interface on
which the request is received.
If the field aIPAddrV6 is completely set to 0 (the 16 bytes are all 0), the IP address
of the host will be used automatically.
Prototype
typedef struct {
char* sName;
U8 aIPAddrV6[IPV6_ADDR_LEN];
} IP_DNS_SERVER_AAAA;
Member | Description |
sName | Null terminated string of the server name. |
aIPAddrV6 | IPv6 address of the server name. |
Structure IP_DNS_SERVER_PTR
Description
Description of a PTR record entry. This could either convert an IP address into a server name,
for example 1.0.168.192.in-addr.arpa into myserver.local.
Or this could be used to indicate the server that provides a service (like _http._tcp.local).
Prototype
typedef struct {
char* sName;
char* sDomainName;
} IP_DNS_SERVER_PTR;
Member | Description |
sName | Null terminating string defining the entry that is requested. (what appears in the request). |
sDomainName | Null terminating string. This is the reply. If set to NULL, the sHostname of the main
config IP_DNS_SERVER_CONFIG is used. |
Structure IP_DNS_SERVER_SRV
Description
Description of a SRV record entry. This describes which server provides a service and additional information
like priority, port, …
Prototype
typedef struct {
char* sName;
U16 Priority;
U16 Weight;
U16 Port;
char* sTarget; // If NULL, hostname will be used.
} IP_DNS_SERVER_SRV;
Member | Description |
sName | Null terminating string defining the entry that is requested, Service, Protocol and
Name are concatenated. (what appears in the request). |
Priority | Priority value: 0 is the heigher priority. |
Weight | Weight to balance between equivalent servers with the same priority. |
Port | Port providing the service. |
sTarget | Null terminating string. This is the server name. If set to NULL, the sHostname of the main
config IP_DNS_SERVER_CONFIG is used. |
Structure IP_DNS_SERVER_TXT
Description
Description of a TXT record entry. This describes some textual parameters. There could be many TXT records
for the same name defining many parameters, but in this case, they should be placed next to one another in
the configuration structure.
Prototype
typedef struct {
char* sName;
char* sTXT;
} IP_DNS_SERVER_TXT;
Member | Description |
sName | Null terminating string defining the entry that is requested. (what appears in the request). |
sTXT | Null terminating string defining one text entry.
For example “Version=1” |
Resource usage
The ROM usage depends on the compiler options, the compiler version and the used
CPU. The memory requirements of the CoAP client/server presented in the tables below
have been measured on a Cortex-M4 system with the default configuration.
ROM usage on a Cortex-M4 system
The following resource usage has been measured on a Cortex-M4 system using
SEGGER Embedded Studio, size optimized.
Addon | ROM |
emNet mDNS server | approximately 3.1 kBytes |
RAM usage
The add-on uses a small internal table for the multicast UDP management.
Addon | RAM |
emNet mDNS server | approximately 0.2 kBytes |
DNS Server (Add-on)
This add-on provides a simple DNS server which allows for a server to handle the DNS requests it
receives. This could be used to gives the IP address of the target as a reply to a server enquiry.
It is ideally coupled with the DHCP server (Add-on).
emNet DNS server
The emNet DNS implementation is an optional extension which can be
seamlessly integrated into your TCP/IP application.
The DNS server module implements the relevant parts of the following RFCs.
Document | Download |
DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION |
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc1035.txt |
DNS-Based Service Discovery |
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc6763.txt |
A DNS RR for specifying the location of services (DNS SRV) |
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc2782.txt |
The following table shows the contents of the emNet root directory:
Directory | Content |
IP | Contains the mDNS server file, IP_DISCOVER.c. |
Feature list
- Low memory footprint.
- Makes your target easily discoverable.
- Easy to implement.
Requirements
TCP/IP stack
The emNet DNS server implementation requires the emNet TCP/IP stack.
Implementation
The emNet simple DNS server used the same mechanism and configuration as the mDNS Server (Add-on).
Thus the structures and parameters won’t be described further in this chapter.
The only difference is that target name definition are not local anymore since a DNS is faked. Thus the “.local”
extension is not needed anymore.
API functions
IP_DNS_SERVER_Start()
Description
Starts the simple DNS service.
Prototype
int IP_DNS_SERVER_Start(const IP_DNS_SERVER_CONFIG * pConfig);
Parameters
Parameter | Description |
pConfig | Pointer to the fake DNS configuration. |
Return value
0 | OK. |
-1 | Error. Could not open connection(s) or DNS service not supported (IP_SUPPORT_FAKE_DNS = 0). |
Example
Configuration should define local names.
static const IP_DNS_SERVER_CONFIG _Config = {
.sHostname = "mytarget.eth",
.TTL = 120,
.NumConfig = 0, // No DNS-SD configuration.
.apSDConfig = NULL
};
IP_DNS_SERVER_Start(&_Config);
IP_DNS_SERVER_Stop()
Description
Stops the simple DNS service.
Prototype
int IP_DNS_SERVER_Stop(void);
Return value
Resource usage
The ROM usage depends on the compiler options, the compiler version and the used
CPU. The memory requirements of the CoAP client/server presented in the tables below
have been measured on a Cortex-M4 system with the default configuration.
In addition to the existing mDNS server add-on, the DNS server add-on adds
approximately 0.2 kBytes of ROM.
AutoIP
All functions which are required to add AutoIP to your application are described in
this chapter.
emNet AutoIP backgrounds
The emNet AutoIP module adds the dynamic configuration of IPv4 Link-Local
addresses to emNet. This functionality is better known as AutoIP. Therefore, this
term will be used in this document.
The AutoIP implementation covers the relevant parts of the following RFCs:
RFC# | Description |
[RFC 3972] | Dynamic Configuration of IPv4 Link-Local Addresses.
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc3972.txt |
In general AutoIP is a method to negotiate a IPv4 address in a network without the
utilization of a server such as a DHCP server. AutoIP will try to use IPv4 addresses
out of a reserved pool from the addresses 169.254.1.0 to 169.254.254.255 to find a
free IP that is not used by any other network participant at this time.
To achieve this goal AutoIP sends ARP probes into the network to ask if the addr. to
be used is already in use. This is determined by an ARP reply for the requested
address. Upon an address conflict AutoIP will generate a new address to use and will
retry to use it by sending ARP probes again.
API functions
IP_AutoIP_Activate()
Description
Activates AutoIP negotiation for the specified interface.
Prototype
void IP_AutoIP_Activate(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero based interface index. |
Additional information
Activating the dynamic configuration of IPv4 Link-Local addresses
means that an additional timer will be added to the stack. This
timer will be called every second to check the status of the
address configuration. With the AutoIP activation an IP address
for the dynamic configuration will be created. The IPv4 prefix
169.254/16 is registered with the IANA for this purpose. This
means that the stack will generate an IP address similar to
169.254.xxx.xxx. The subnet mask of is always 255.255.0.0.
In emNet debug builds terminal I/O output can be enabled. AutoIP outputs status
information in the terminal I/O window if the stack is configured to so
(IP_MTYPE_AUTOIP added to the log filter mask). Please refer to IP_SetLogFilter
and IP_AddLogFilter for further information about the
enabling terminal I/O. If terminal I/O is enabled the output of a the program start
should be similar to the following lines:
0:000 MainTask - INIT: Init started. Version 2.00.06
0:000 MainTask - DRIVER: Found PHY with Id 0x2000 at addr 0x1
0:000 MainTask - INIT: Link is down
0:000 MainTask - INIT: Init completed
0:000 IP_Task - INIT: IP_Task started
0:000 IP_RxTask - INIT: IP_RxTask started
3:000 IP_Task - LINK: Link state changed: Full duplex, 100 MHz
9:000 IP_Task - AutoIP: 169.254.240.240 checked, no conflicts
9:000 IP_Task - AutoIP: IFaceId 0: Using IP: 169.254.240.240.
IP_AutoIP_Halt()
Description
Stops AutoIP activity for the passed interface.
Prototype
int IP_AutoIP_Halt(unsigned IFaceId,
char KeepIP);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
KeepIP | Flag to indicate if the used IP address should be stored for the next start of AutoIP. 0 means do not keep the IP, 1 means keep the IP address for the next AutoIP start. |
Return value
0 | Ok. AutoIP stopped. IP address cleared. |
IP | Ok. AutoIP stopped. The IP address (for example 0xA9FExxxx) has been kept. |
-1 | Error. Illegal interface number. |
Additional information
The function stops the AutoIP module. The IP address which was
used during AutoIP was activated, can be kept to speed up the
configuration process after reactivating AutoIP. If the IP address
will not be kept, AutoIP creates a new IP address after the
reactivation.
IP_AutoIP_SetUserCallback()
Description
This function allows the caller to set a callback for an interface.
The callback is called with every status change.
Prototype
void IP_AutoIP_SetUserCallback(unsigned IFaceId,
IP_AUTOIP_INFORM_USER_FUNC * pfInformUser);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pfInformUser | Pointer to a user function of type IP_AUTOIP_INFORM_USER_FUNC which is called when a status change occurs. |
Additional information
This mechanism is provided so that the caller can do some processing
when the interface is up (like doing initializations or blinking
LEDs, etc.).
IP_AUTOIP_INFORM_USER_FUNC is defined as follows:
typedef void (IP_AUTOIP_INFORM_USER_FUNC)(U32 IFaceId, U32 Status);
IP_AutoIP_SetStartIP()
Description
Sets the IP address which will be used for the first configuration
try.
Prototype
void IP_AutoIP_SetStartIP(unsigned IFaceId,
U32 IPAddr);
Parameters
Parameter | Description |
IFaceId | Zero based interface index. |
IPAddr | 4-byte IPv4 address. |
Additional information
A call of this function is normally not required, but in some
cases it can be useful to set the IP address which should be used
as startingpoint of the AutoIP functionality.
Resource usage
The ROM usage depends on the compiler options, the compiler version and the used
CPU. The memory requirements of the AutoIP module presented in the tables below
have been measured on an ARM7 and a Cortex-M3 system. Details about the further
configuration can be found in the sections of the specific example.
ROM usage on an ARM7 system
The following resource usage has been measured on an ARM7 system using IAR
Embedded Workbench V6.30.6, Thumb mode, no interwork, size optimization.
Addon | ROM |
emNet AutoIP module | approximately 1.1 kByte |
ROM usage on a Cortex-M3 system
The following resource usage has been measured on a Cortex-M3 system using IAR
Embedded Workbench V6.30.6, size optimization.
Addon | ROM |
emNet AutoIP module | approximately 1.0 kByte |
RAM usage
Addon | RAM |
emNet AutoIP module | approximately 0.7 kByte |
Address Collision Detection (ACD)
All functions which are required to add Address Collision Detection (ACD) to your
application are described in this chapter.
emNet ACD module
The emNet ACD module allows to detect and react to IPv4 address collisions on the network.
The typical case is that one or more hosts on the network use the same IPv4 address. To
detect other hosts using the same IP address, ACD can use passive listening for ARP packets
sent by hosts as well as active probing for the IP address.
The ACD module implements the relevant parts of the following Request For Comments (RFC).
RFC# | Description |
[RFC 5227] | IPv4 Address Conflict Detection
Direct download: https://datatracker.ietf.org/doc/html/rfc5227 |
API functions
Function | Description |
IP_ACD_Activate() | Activates the address conflict detection (ACD) for the specified interface. |
IP_ACD_ActivateEx() | Activates the address conflict detection (ACD) for the specified interface and allows extended configuration. |
IP_ACD_Config() | Configures the address conflict detection (ACD) behavior for startup and in case of conflicts. |
IP_ACD_EndAnnounce() | Ends sending further announce messages when in IP_ACD_STATE_ANNOUNCE_SEND_GARP state. |
IP_ACD_Halt() | De-Activates the address conflict detection (ACD) for the specified interface. |
IP_ACD_UpdateBackgroundPeriod() | Updates the “BackgroundPeriod” when in IP_ACD_STATE_ACTIVE_* state. |
IP_ACD_Activate()
Description
Activates the address conflict detection (ACD) for the specified
interface.
Prototype
int IP_ACD_Activate(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
= 0 | ACD activated and free IP found (does not mean the initial IP was good). |
= 1 | No IP address set when ACD was activated. |
< 0 | Error, no memory. |
Additional information
Activating the address conflict detection module means that a
hook into the ARP module of the stack will be activated that
allows the user to take action if an IPv4 address conflict on
the network has been discovered.
When the ACD module is started it will check if the currently
used IP address is in conflict with any other host on the
network by sending ARP probes to find hosts with the same
IPv4 address.
It is the responsibility of the application to make sure that
ACTIVATE is only called when the interface is UP. As ACD only
makes sense for an interface in state UP, the ACTIVATE call
might actively wait for the interface state to change.
To allow the user to take action on those conflicts it is necessary to use
IP_ACD_Config() before activating ACD.
In emNet debug builds terminal I/O output can be enabled. ACD outputs status
information in the terminal I/O window if the stack is configured to so (IP_MTYPE_ACD
added to the log filter mask). Please refer to IP_SetLogFilter and
IP_AddLogFilter for further information about the enabling terminal I/O.
IP_ACD_ActivateEx()
Description
Activates the address conflict detection (ACD) for the specified
interface and allows extended configuration.
Prototype
int IP_ACD_ActivateEx( unsigned IFaceId,
IP_ACD_ON_INFO_FUNC * pfOnInfo,
const IP_ACD_EX_CONFIG * pConfig,
unsigned NonBlocking);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pfOnInfo | Callback of type IP_ACD_ON_INFO_FUNC to be notified about state changes and events. |
pConfig | Pointer to configuration of type IP_ACD_EX_CONFIG . |
NonBlocking | 0: Call is blocking and waits for the operations to finish. 1: Call is non-blocking and returns instantly. |
Return value
= 0 | ACD activated and free IP found (does not mean the initial IP was good). |
= 1 | No IP address set when ACD was activated. |
< 0 | Error, no memory. |
Additional information
Activating the address conflict detection module means that a
hook into the ARP module of the stack will be activated that
allows the user to take action if an IPv4 address conflict on
the network has been discovered.
When the ACD module is started it will check if the currently
used IP address is in conflict with any other host on the
network by sending ARP probes to find hosts with the same
IPv4 address.
It is the responsibility of the application to make sure that
ACTIVATE is only called when the interface is UP. As ACD only
makes sense for an interface in state UP, the ACTIVATE call
might actively wait for the interface state to change.
IP_ACD_Config()
Description
Configures the address conflict detection (ACD) behavior for
startup and in case of conflicts.
Prototype
int IP_ACD_Config( unsigned IFaceId,
unsigned NumProbes,
unsigned DefendInterval,
const ACD_FUNC * pAPI);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
NumProbes | Number of ARP probes to send upon activating ACD before declaring the actual used IP address to be free to be used. |
DefendInterval | Interval [ms] in which the currently active IP address is being known as defended after taking action. |
pAPI | Pointer to callback table of type ACD_FUNC . |
Return value
= 0 | O.K. |
< 0 | Error, no memory. |
IP_ACD_EndAnnounce()
Description
Ends sending further announce messages when in
IP_ACD_STATE_ANNOUNCE_SEND_GARP state.
Prototype
void IP_ACD_EndAnnounce(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Additional information
This routine is designed to be called either from the ACD
information callback or from another place in the application
to end an ongoing sending of announce messages early when in
the IP_ACD_STATE_ANNOUNCE_SEND_GARP state. Ending the
IP_ACD_STATE_ANNOUNCE_SEND_GARP state early might be necessary
for example when implementing EtherNet/IP “QuickConnect” and
communication is established while still sending announce messages.
At the moment using this routine is limited to the
IP_ACD_STATE_ANNOUNCE_SEND_GARP state and is internally checked.
If important to your application you should ensure that this is
the case in your application as this internal check might be
subject to change in the future.
Calling this routine sends the state machine into ACTIVE or PASSIVE
mode. In ACTIVE mode it is possible to influence the time before
sending the first probe by overriding the proposed delay in the
info callback for the IP_ACD_STATE_ACTIVE_WAIT_BEFORE_BG_PROBES
state.
IP_ACD_Halt()
Description
De-Activates the address conflict detection (ACD) for the
specified interface.
Prototype
void IP_ACD_Halt(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
IP_ACD_UpdateBackgroundPeriod()
Description
Updates the “BackgroundPeriod” when in IP_ACD_STATE_ACTIVE_* state.
Prototype
void IP_ACD_UpdateBackgroundPeriod(unsigned IFaceId,
unsigned BackgroundPeriod);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
BackgroundPeriod | Background period in milliseconds. |
Additional information
This routine is designed to be called either from the ACD
information callback or from another place in the application
to modify the period used when sending background probes in
ACTIVE mode in the IP_ACD_STATE_ACTIVE_* states.
At the moment using this routine is limited to the
IP_ACD_STATE_ACTIVE_* states and is internally checked.
If important to your application you should ensure that this is
the case in your application as this internal check might be
subject to change in the future.
Calling this routine sends the state machine into ACTIVE mode
and ends states such as IP_ACD_STATE_ACTIVE_WAIT_BEFORE_BG_PROBES
if the state machine is currently in this state.
Changing the background probing period can be used to enter or
leave the EtherNet/IP “SemiActiveProbe” mode.
Data structures
Structure ACD_FUNC
Description
Used to store function pointers to the user defined callbacks to take several actions
upon detecting an IP address conflict.
Prototype
typedef struct {
U32 (*pfRenewIPAddr)(unsigned IFace);
int (*pfDefend) (unsigned IFace);
int (*pfRestart) (unsigned IFace);
} ACD_FUNC;
Member | Description |
pfRenewIPAddr | Function pointer to a user defined routine that is used to generate a
new IPv4 address if there is a collision detected during ACD activation. |
pfDefend | Function pointer to a user defined routine that is used to let the
user implement his own defend strategy. Can be NULL. |
pfRestart | Function pointer to a user defined routine that should reconfigure
the IP address used by the stack and optionally re-activates ACD. |
IP_ACD_EX_CONFIG
Description
Used to configure the extended ACD functionality.
Type definition
typedef struct {
U32 IPAddr;
unsigned BackgroundPeriod;
unsigned NumProbes;
unsigned DefendInterval;
unsigned NumAnnouncements;
unsigned AnnounceInterval;
U8 AssignAddressManually;
IP_ACD_STATE InitState;
} IP_ACD_EX_CONFIG;
Structure members
Member | Description |
IPAddr | IPv4 start address to use in host endianness. |
BackgroundPeriod | Period [ms] in which ACD will send probes running in the background. |
NumProbes | Number of ARP probes to send upon activating ACD before declaring the actual used IP address to be free to be used. 0 to use default. |
DefendInterval | Interval [ms] in which the currently active IP address is being known as defended after taking action. 0 to use default. |
NumAnnouncements | Number of announcements to send when using a free address. The address can already be used at this point. 0 to use default. |
AnnounceInterval | Time [ms] between announcements to send. 0 to use default. |
AssignAddressManually | Configures if probed address is assigned automatically to the interface if free. 0: Off (default), address is automatically to the interface, using the existing subnet mask. 1: On, address is only reported via the IP_ACD_INFO.IPAddr member in the IP_ACD_STATE_INIT_WAIT_BEFORE_ANNOUNCE state. The user needs to manually assign it to the interface along with the desired subnet mask. Assigning an address manually might affect ACD effectiveness on virtual interfaces such as being used for multiple addresses on one single physical interface. ARP/ACD might not be able to correctly select the virtual interface for some operations until the address has finally been assigned to the interface. |
InitState | Initial state for the ACD state machine upon activating ACD. The following states are supported: IP_ACD_STATE_DISABLED Default behavior starting ACD listening for potential conflicts at the beginning. IP_ACD_STATE_ANNOUNCE_SEND_GARP Skips the initial listening phase and starts by directly sending the first the first announcement. This can be used to implement EtherNet/IP “QuickConnect” behavior. |
IP_ACD_ANNOUNCE_INFO
Description
Returns information about the latest ACD announce about using
a free and previously probed address.
Type definition
typedef struct {
unsigned AnnouncementsLeft;
} IP_ACD_ANNOUNCE_INFO;
Structure members
Member | Description |
AnnouncementsLeft | Number of announements left to send. |
IP_ACD_COLLISION_INFO
Description
Returns information about the latest ACD collision.
Type definition
typedef struct {
IP_PACKET * pPacket;
U32 DefendTimeout;
unsigned ProbesLeft;
} IP_ACD_COLLISION_INFO;
Structure members
Member | Description |
pPacket | Pointer to the packet that caused the collision (pPacket->pData points to the ARP header). |
DefendTimeout | System timestamp of when the defend window ends. |
ProbesLeft | Number of INIT probes left to send. |
IP_ACD_WAIT_INFO
Description
Returns information about a delay/wait before the next step.
This can be a delay before sending the very first probe for INIT
or a delay between each probe sent during the INIT phase.
Type definition
typedef struct {
unsigned WaitMin;
unsigned volatile WaitTime;
unsigned WaitMax;
} IP_ACD_WAIT_INFO;
Structure members
Member | Description |
WaitMin | Suggested minimum wait time [ms]. |
WaitTime | Wait time before the next state that is used (does not have to obey min./max. suggestion). This value can be overwritten and is evaluated after returning from the callback. |
WaitMax | Suggested maximum wait time [ms] |
Additional information
The stack makes suggestions using the structure members as well
as presenting the actual value that will be used in the WaitTime
member. You can overwrite the WaitTime member as it is then
evaluated after returning from the callback and its new value
value is then used.
IP_ACD_INFO
Description
Returns information about the current ACD status. The ACD info
callback parameter State has to be evaluated for further
information if there is more info about the new state and what
part of the union is the information to look at.
Type definition
typedef struct {
U32 IPAddr;
IP_ACD_STATE State;
IP_ACD_STATE OldState;
IP_ACD_LOSE_DEFEND_ADDRESS Defend;
IP_ACD_KEEP_DISCARD_PACKET DiscardPacket;
} IP_ACD_INFO;
Structure members
Member | Description |
IPAddr | IPv4 address (in host endianness) that gets assigned to the interface or would be assigned to the interface if IP_ACD_EX_CONFIG.AssignAddressManually is NOT used. Currently only valid with the IP_ACD_STATE_INIT_WAIT_BEFORE_ANNOUNCE state. |
State | Type of information and what part of the union to look at. The State member is followed by a union that might not be correctly displayed or completely missing in the manual. The following information describes this union part: IP_ACD_STATE_EVENT_COLLISION: Information about the latest ACD collision can be found in pInfo->Data.Collision in form of IP_ACD_COLLISION_INFO . |
OldState | Previous state. Might be the same as new state depending on actions executed in callbacks. If filtering is needed, this needs to be implemented in the application. When counting events like how many announcements have been sent, the OldState should be used for filtering as this reports the event handled immediately before or after reporting the state (change). |
Defend | Suggestion from the stack whether to defend the IP address on a collision after INIT or not. This value is evaluated after returning from the callback. = IP_ACD_LOSE_ADDRESS : Lose the address (typically if this is not the first conflict with a host and is within the defend window. = IP_ACD_DEFEND_ADDRESS: Defend the address (anyhow). |
DiscardPacket | Suggestion from the stack whether to keep or discard a packet contained in the state specific information structure (e.g. IP_ACD_COLLISION_INFO). This value is evaluated after returning from the callback. = IP_ACD_KEEP_PACKET : Packet is kept and forwarded to the ARP module for further handling. = IP_ACD_DISCARD_PACKET: Packet is discarded (e.g. to avoid ARP cache poisoning). |
IP_ACD_ON_INFO_FUNC
Description
Callback executed whenever updated ACD information is available.
Type definition
typedef void (IP_ACD_ON_INFO_FUNC)(unsigned IFaceId,
IP_ACD_INFO * pInfo);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pInfo | Further information of type IP_ACD_INFO about the actual information available. |
Additional information
Calling API like an ACTIVATE from the callback might produce
another callback message. It is the responsibility of the application
to avoid infinite recursion. Typically this is no problem as calling
ACTIVATE again from the callback reporting the ACTIVATE state makes
no sense.
EtherNet/IP usage
The standard ACD behavior and timers are typically sufficient to raise notifications in a
regular network and detect configuration problems in non critical environments. Other
environments and protocols used might be subject to more strict parameters to detect
configuration problems faster and allow to react to them in a more prioritized way than
just notifying about the potential problem on the network.
EtherNet/IP is such an environment/protocol that in its basic principles makes use of ACD
as is but extends it by some specific behavior here and there. This section explains how
to configure the ACD module for some of these EtherNet/IP specific requirements.
EtherNet/IP QuickConnect
QuickConnect capable devices power up in less than 300 ms and are able to establish a
network connection in less than 200 ms. A QuickConnect is for example used when replacing
tools in an EtherNet/IP network that need to be back to production basically instantaneous.
In QuickConnect mode ACD is not started in its slow probing initial state but shall be
doing quick negotions with the network to decide if there is a collision or not. A typical
configuration is to directly start announcing the IP that is to be used to the network
in a quick paced manner to make sure this is received as early as possible by other hosts
that might be subject to collision with the QuickConnect device entering the network.
The rapid announcing of its address is stopped early when detecting I/O communication with
the device, confirming that based on network topology and switch ARP tables, communication
ends up with this device after all.
EtherNet/IP QuickConnect example
QuickConnect configuration example sending 40 ARP announcements with a period of 25 ms
before switching into active background probing with a period of 1 second.
static unsigned _ACD_IFaceId = 0u;
static IP_ACD_STATE _ACD_State;
/*********************************************************************
*
* ACD configuration
*/
static IP_ACD_EX_CONFIG _ACD_Config = {
...
.BackgroundPeriod = 1000u,
.NumAnnouncements = 40u,
.AnnounceInterval = 25u,
.InitState = IP_ACD_STATE_ANNOUNCE_SEND_GARP,
...
};
/*********************************************************************
*
* _cbOnInfo()
*
* Function description
* Callback executed whenever updated ACD information is available.
*
* Parameters
* IFaceId : Zero-based interface index.
* pInfo : Further information of type IP_ACD_INFO about the actual
* information available.
*
* Additional information
* Calling API like an ACTIVATE from the callback might produce
* another callback message. It is the responsibility of the application
* to avoid infinite recursion. Typically this is no problem as calling
* ACTIVATE again from the callback reporting the ACTIVATE state makes
* no sense.
*/
static void _ACD_cbOnInfo(unsigned IFaceId, IP_ACD_INFO* pInfo) {
IP_USE_PARA(IFaceId);
_ACD_State = pInfo->State;
}
/*********************************************************************
*
* _EIP_cbOnIO()
*
* Function description
* Callback executed upon EtherNet/IP I/O communication.
*
* Additional information
* This callback is executed when detecting I/O communication and
* is used to end the QuickConnect rapid announcement phase early.
*/
static void _EIP_cbOnIO(void) {
if (_ACD_State == IP_ACD_STATE_ANNOUNCE_SEND_GARP) {
IP_ACD_EndAnnounce(_ACD_IFaceId);
}
}
/*********************************************************************
*
* MainTask
*/
void MainTask(void) {
...
IP_Init();
...
//
// Wait for Link-UP.
//
...
IP_ACD_ActivateEx(_ACD_IFaceId, _ACD_cbOnInfo, &_ACD_Config, 0u);
...
}
EtherNet/IP SemiActiveProbe
If an interface is already successfully established and doing its background probing and another
interface of this device reaches link-UP state, the device shall enter the so called
SemiActiveProbe state. As the device has the same IP address for its multiple EtherNet/IP
interfaces, it shall probe if it sees itself due to a wrong network topology.
A typical probing algorithm is to send two ARP probes with a period of 200 ms in the form of
DELAY => PROBE => DELAY => PROBE . Once done, the device shall return to its regular ACD
background probing cycle.
EtherNet/IP SemiActiveProbe example
SemiActiveProbe example sending two short probes with a period of 200 ms before returning back
to its original background probing with a period of 1 second.
static unsigned _ACD_IFaceId = 0u;
static unsigned _ACD_SemiActiveProbesLeft;
static IP_HOOK_ON_LINK_CHANGE _ACD_LinkChangeHook;
static IP_ACD_STATE _ACD_State;
/*********************************************************************
*
* ACD configuration
*/
static IP_ACD_EX_CONFIG _ACD_Config = {
...
.BackgroundPeriod = 1000u,
...
};
/*********************************************************************
*
* _cbOnInfo()
*
* Function description
* Callback executed whenever updated ACD information is available.
*
* Parameters
* IFaceId : Zero-based interface index.
* pInfo : Further information of type IP_ACD_INFO about the actual
* information available.
*
* Additional information
* Calling API like an ACTIVATE from the callback might produce
* another callback message. It is the responsibility of the application
* to avoid infinite recursion. Typically this is no problem as calling
* ACTIVATE again from the callback reporting the ACTIVATE state makes
* no sense.
*/
static void _ACD_cbOnInfo(unsigned IFaceId, IP_ACD_INFO* pInfo) {
IP_USE_PARA(IFaceId);
_ACD_State = pInfo->State;
//
// Handle SemiActiveProbe mode.
// Use the OldState to avoid reacting to the transition into
// the SemiActiveProbe mode. Reacting to the OldState means
// to react to the end of the first 200 ms delay and sending
// the first SemiActiveProbe .
//
if (pInfo->OldState == IP_ACD_STATE_ACTIVE_SEND_BG_PROBES) {
//
// Are we in SemiActiveProbe mode ?
//
if (_ACD_SemiActiveProbesLeft != 0u) {
_ACD_SemiActiveProbesLeft--;
//
// Is this the last probe to send with SemiActiveProbe long period ?
//
if (_ACD_SemiActiveProbesLeft == 0u) {
//
// Return back to the regular background probing period.
//
IP_ACD_UpdateBackgroundPeriod(_ACD_IFaceId, 1000u);
}
}
}
}
/*********************************************************************
*
* _ACD_cbOnLinkChange()
*
* Function description
* Callback executed whenever the link state of an interface changes.
*
* Parameters
* IFaceId : Zero-based interface index.
* Duplex : Link duplex:
* * 0: Duplex unknown or Auto-Neg. incomplete.
* * 1: Half-Duplex.
* * 2: Full-Duplex
* Speed : Link speed:
* * == 0: Unknown, typically link-DOWN.
* * > 0: Speeds of up to one gigabit are returned in Hertz.
*/
static void _ACD_cbOnLinkChange(unsigned IFaceId, U32 Duplex, U32 Speed) {
IP_USE_PARA(Duplex);
//
// This is NOT our primary ACD monitored interface ?
//
if (IFaceId != _ACD_IFaceId) {
//
// This is a link-UP event ?
//
if (Speed != 0u) {
//
// Our ACD monitored interface is in background probing mode ?
//
if (_ACD_State == IP_ACD_STATE_ACTIVE_SEND_BG_PROBES) {
//
// Prepare to execute SemiActiveProbe
// - 200ms
// - Probe
// - 200ms
// - Probe
// - Back to background probing.
//
_ACD_SemiActiveProbesLeft = 2u;
IP_ACD_UpdateBackgroundPeriod(_ACD_IFaceId, 200u);
}
}
}
}
/*********************************************************************
*
* MainTask
*/
void MainTask(void) {
...
IP_Init();
IP_AddLinkChangeHook(&_ACD_LinkChangeHook, _ACD_cbOnLinkChange);
...
//
// Wait for Link-UP.
//
...
IP_ACD_ActivateEx(_ACD_IFaceId, _ACD_cbOnInfo, &_ACD_Config, 0u);
...
}
Resource usage
The ROM usage depends on the compiler options, the compiler version and the used
CPU. The memory requirements of the AutoIP module presented in the tables below
have been measured on an ARM7 and a Cortex-M3 system. Details about the further
configuration can be found in the sections of the specific example.
ROM usage on an ARM7 system
The following resource usage has been measured on an ARM7 system using IAR
Embedded Workbench V6.30.6, Thumb mode, no interwork, size optimization.
Addon | ROM |
emNet ACD module | approximately 0.4 kByte |
ROM usage on a Cortex-M3 system
The following resource usage has been measured on a Cortex-M3 system using IAR
Embedded Workbench V6.30.6, size optimization.
Addon | ROM |
emNet ACD module | approximately 0.4 kByte |
RAM usage
Addon | RAM |
emNet ACD module | approximately 50 Bytes |
UPnP (Add-on)
The emNet implementation of UPnP which stand for Universal Plug and Play is an optional extension to emNet.
It allows making your target easily discoverable and advertising services available on your target throughout your network.
emNet UPnP
The emNet UPnP implementation is an optional extension which can be seamlessly integrated into your TCP/IP application.
It combines the possibility to implemented UPnP services in a most flexible way by allowing to specify content to be sent upon
UPnP requests completely generated by the application with a small memory footprint.
The UPnP module implements the relevant parts of the UPnP documentation released by the UPnP Forum.
Document | Download |
UPnP Device Architecture 1.0 |
Direct download: http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.0.pdf |
The following table shows the contents of the emNet root directory:
Directory | Content |
Application | Contains the example application to run the UPnP implementation with emNet and emNet Web server add-on. |
IP | Contains the UPnP source file, IP_UPnP.c. |
Feature list
- Low memory footprint.
- Advertising your services on the network
- Easy to implement
Requirements
TCP/IP stack
The emNet UPnP implementation requires the emNet TCP/IP stack and is designed to be used with the emNet Web server add-on.
Backgrounds
UPnP is designed to provide services throughout a network without interaction of the user.
It is designed to use standardized protocols such as IP, TCP, UDP, Multicast, HTTP and XML for communication and to distribute services provided by a device.
UPnP can be used to advertise services provided by a device across the network such as where to find the web interface for the device advertising.
Newer operating systems support UPnP from scratch and will show UPnP devices available across a network and may provide easy access to a device by simply
selecting the discovered UPnP device.
A typical usage would be to advertise media accessible on a media storage on the network and opening a file browser window to the resource upon opening the UPnP entry discovered.
Using UPnP to advertise your service in the network
The default UPnP XML file advertised is upnp.xml.
A solution providing UPnP content has to serve a file called upnp.xml containing valid UPnP descriptors via a web server.
The sample OS_IP_Webserver_UPnP.c provides a sample configuration for advertising a web server page that will open if the UPnP client clicks on the discovered UPnP device.
A discovered UPnP device will typically be shown in the network neighborhood of your operating system.
A discovered device found by a Windows OS is shown in the picture below:
The example below shows the most important excerpts from the OS_IP_Webserver_UPnP.c sample that are necessary to setup a UPnP device in your network.
/* Excerpt from OS_IP_Webserver_UPnP.c */
//
// UPnP
//
#define UPNP_FRIENDLY_NAME "SEGGER UPnP Demo"
#define UPNP_MANUFACTURER "SEGGER Microcontroller GmbH"
#define UPNP_MANUFACTURER_URL "http://www.segger.com"
#define UPNP_MODEL_DESC "SEGGER emWeb server with UPnP"
#define UPNP_MODEL_NAME "SEGGER UPnP Demo"
#define UPNP_MODEL_URL "http://www.segger.com/emweb"
The sample uses VFile hooks as described in IP_WEBS_AddVFileHook() to provide dynamically serving the necessary XML files for UPnP without the need
for a real file system or further processing through the web server.
/* Excerpt from OS_IP_Webserver_UPnP.c */
/*********************************************************************
*
* Types
*
**********************************************************************
*/
typedef struct {
const char * sFileName;
const char * pData;
unsigned NumBytes;
} VFILE_LIST;
/* Excerpt from OS_IP_Webserver_UPnP.c */
/*********************************************************************
*
* Static const
*
**********************************************************************
*/
//
// UPnP, virtual files
//
static const char _acFile_dummy_xml[] =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n"
"<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">\r\n"
"<specVersion>\r\n"
"<major>1</major>\r\n"
"<minor>0</minor>\r\n"
"</specVersion>\r\n"
"<serviceStateTable>\r\n"
"<stateVariable>\r\n"
"<name>Dummy</name>\r\n"
"<dataType>i1</dataType>\r\n"
"</stateVariable>\r\n"
"</serviceStateTable>\r\n"
"</scpd>";
//
// UPnP, virtual files list
//
static const VFILE_LIST _VFileList[] = {
"/dummy.xml", _acFile_dummy_xml, sizeof(_acFile_dummy_xml) - 1, // Do not count in the null terminator of the string
NULL , NULL , NULL
};
/* Excerpt from OS_IP_Webserver_UPnP.c */
//
// UPnP webserver VFile hook
//
static WEBS_VFILE_HOOK _UPnP_VFileHook;
Several helper functions are provided in the sample to easily generate a valid XML file for advertising a service using UPnP.
/* Excerpt from Webserver_DynContent.c */
//
// UPnP
//
#define UPNP_FRIENDLY_NAME "SEGGER UPnP Demo"
#define UPNP_MANUFACTURER "SEGGER Microcontroller GmbH"
#define UPNP_MANUFACTURER_URL "http://www.segger.com"
#define UPNP_MODEL_DESC "SEGGER emWeb server with UPnP"
#define UPNP_MODEL_NAME "SEGGER UPnP Demo"
#define UPNP_MODEL_URL "http://www.segger.com/emweb"
/* Excerpt from OS_IP_Webserver_UPnP.c */
/*********************************************************************
*
* Static code
*
**********************************************************************
*/
/*********************************************************************
*
* _UPnP_GetURLBase
*
* Function description
* This function copies the information needed for the URLBase parameter
* into the given buffer and returns a pointer to the start of the buffer
* for easy readable code.
*
* Parameters
* IFaceId - Zero-based interface index.
* pBuffer - Pointer to the buffer that can be temporarily used to
* store the requested data.
* NumBytes - Size of the given buffer used for checks
*
* Return value
* Pointer to the start of the buffer used for storage.
*/
static const char* _UPnP_GetURLBase(unsigned IFaceId, char* pBuffer, unsigned NumBytes) {
#define URL_BASE_PREFIX "http://"
char * p;
p = pBuffer;
*p = '\0'; // Just to be on the safe if the buffer is too small
strncpy(pBuffer, URL_BASE_PREFIX, NumBytes);
p += (sizeof(URL_BASE_PREFIX) - 1);
NumBytes -= (sizeof(URL_BASE_PREFIX) - 1);
IP_PrintIPAddr(p, IP_GetIPAddr(IFaceId), NumBytes);
return pBuffer;
}
/*********************************************************************
*
* _UPnP_GetModelNumber
*
* Function description
* This function copies the information needed for the ModelNumber parameter
* into the given buffer and returns a pointer to the start of the buffer
* for easy readable code.
*
* Parameters
* IFaceId - Zero-based interface index.
* pBuffer - Pointer to the buffer that can be temporarily used to
* store the requested data.
* NumBytes - Size of the given buffer used for checks
*
* Return value
* Pointer to the start of the buffer used for storage.
*/
static const char* _UPnP_GetModelNumber(unsigned IFaceId, char* pBuffer,
unsigned NumBytes) {
U8 aHWAddr[6];
if (NumBytes <= 12) {
*pBuffer = '\0'; // Just to be on the safe if the buffer is too small
} else {
IP_GetHWAddr(IFaceId, aHWAddr, sizeof(aHWAddr));
SEGGER_snprintf(pBuffer,
NumBytes,
"%02X%02X%02X%02X%02X%02X",
aHWAddr[0],
aHWAddr[1],
aHWAddr[2],
aHWAddr[3],
aHWAddr[4],
aHWAddr[5]);
}
return pBuffer;
}
/*********************************************************************
*
* _UPnP_GetSN
*
* Function description
* This function copies the information needed for the SerialNumber parameter
* into the given buffer and returns a pointer to the start of the buffer
* for easy readable code.
*
* Parameters
* IFaceId - Zero-based interface index.
* pBuffer - Pointer to the buffer that can be temporarily used to
* store the requested data.
* NumBytes - Size of the given buffer used for checks
*
* Return value
* Pointer to the start of the buffer used for storage.
*/
static const char * _UPnP_GetSN(unsigned IFaceId, char * pBuffer, unsigned NumBytes) {
U8 aHWAddr[6];
if (NumBytes <= 12) {
*pBuffer = '\0'; // Just to be on the safe if the buffer is too small
} else {
IP_GetHWAddr(IFaceId, aHWAddr, sizeof(aHWAddr));
SEGGER_snprintf(pBuffer,
NumBytes,
"%02X%02X%02X%02X%02X%02X",
aHWAddr[0],
aHWAddr[1],
aHWAddr[2],
aHWAddr[3],
aHWAddr[4],
aHWAddr[5]);
}
return pBuffer;
}
/*********************************************************************
*
* _UPnP_GetUDN
*
* Function description
* This function copies the information needed for the UDN parameter
* into the given buffer and returns a pointer to the start of the buffer
* for easy readable code.
*
* Parameters
* IFaceId - Zero-based interface index.
* pBuffer - Pointer to the buffer that can be temporarily used to
* store the requested data.
* NumBytes - Size of the given buffer used for checks
*
* Return value
* Pointer to the start of the buffer used for storage.
*/
static const char * _UPnP_GetUDN(unsigned IFaceId, char * pBuffer, unsigned NumBytes) {
#define UDN_PREFIX "uuid:95232DE0-3AF7-11E2-81C1-"
char * p;
U8 aHWAddr[6];
p = pBuffer;
*pBuffer = '\0'; // Just to be on the safe if the buffer is too small
strncpy(pBuffer, UDN_PREFIX, NumBytes);
p += (sizeof(UDN_PREFIX) - 1);
NumBytes -= (sizeof(UDN_PREFIX) - 1);
if (NumBytes > 12) {
IP_GetHWAddr(IFaceId, aHWAddr, sizeof(aHWAddr));
SEGGER_snprintf(p,
NumBytes,
"%02X%02X%02X%02X%02X%02X",
aHWAddr[0],
aHWAddr[1],
aHWAddr[2],
aHWAddr[3],
aHWAddr[4],
aHWAddr[5]);
}
return pBuffer;
}
/*********************************************************************
*
* _UPnP_GetPresentationURL
*
* Function description
* This function copies the information needed for the presentation URL parameter
* into the given buffer and returns a pointer to the start of the buffer
* for easy readable code.
*
* Parameters
* IFaceId - Zero-based interface index.
* pBuffer - Pointer to the buffer that can be temporarily used to
* store the requested data.
* NumBytes - Size of the given buffer used for checks
*
* Return value
* Pointer to the start of the buffer used for storage.
*/
static const char* _UPnP_GetPresentationURL(unsigned IFaceId,
char* pBuffer,
unsigned NumBytes) {
#define PRESENTATION_URL_PREFIX "http://"
#define PRESENTATION_URL_POSTFIX "/index.htm"
char * p;
int i;
p = pBuffer;
*p = '\0'; // Just to be on the safe if the buffer is too small
strncpy(pBuffer, PRESENTATION_URL_PREFIX, NumBytes);
p += (sizeof(PRESENTATION_URL_PREFIX) - 1);
NumBytes -= (sizeof(PRESENTATION_URL_PREFIX) - 1);
i = IP_PrintIPAddr(p, IP_GetIPAddr(IFaceId), NumBytes);
p += i;
NumBytes -= i;
strncat(pBuffer, PRESENTATION_URL_POSTFIX, NumBytes);
return pBuffer;
}
/*********************************************************************
*
* _UPnP_GenerateSend_upnp_xml
*
* Function description
* Send the content for the requested file using the callback provided.
*
* Parameters
* IFaceId - Zero-based interface index.
* pContextIn - Send context of the connection processed for
* forwarding it to the callback used for output.
* pf - Function pointer to the callback that has to be
* for sending the content of the VFile.
* pContextOut - Out context of the connection processed.
* pData - Pointer to the data that will be sent
* NumBytes - Number of bytes to send from pData. If NumBytes
* is passed as 0 the send function will run a strlen()
* on pData expecting a string.
*
* Notes
* (1) The data does not need to be sent in one call of the callback
* routine. The data can be sent in blocks of data and will be
* flushed out automatically at least once returning from this
* routine.
*/
static void _UPnP_GenerateSend_upnp_xml(unsigned IFaceId,
void * pContextIn,
void (*pf) (void * pContextOut,
const char * pData,
unsigned NumBytes)) {
char ac[128];
pf(pContextIn, "<?xml version=\"1.0\"?>\r\n"
"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\r\n"
"<specVersion>\r\n"
"<major>1</major>\r\n"
"<minor>0</minor>\r\n"
"</specVersion>\r\n", 0);
pf(pContextIn, "<URLBase>", 0);
pf(pContextIn, _UPnP_GetURLBase(IFaceId, ac, sizeof(ac)), 0);
pf(pContextIn, "</URLBase>\r\n", 0);
pf(pContextIn, "<device>\r\n"
"<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>
\r\n", 0);
pf(pContextIn, "<friendlyName>", 0);
pf(pContextIn, _UPnP_GetFriendlyName(IFaceId, ac, sizeof(ac)), 0);
pf(pContextIn, "</friendlyName>\r\n", 0);
pf(pContextIn, "<manufacturer>" UPNP_MANUFACTURER "</manufacturer>\r\n", 0);
pf(pContextIn, "<manufacturerURL>" UPNP_MANUFACTURER_URL "</manufacturerURL>
\r\n", 0);
pf(pContextIn, "<modelDescription>" UPNP_MODEL_DESC "</modelDescription>
\r\n", 0);
pf(pContextIn, "<modelName>" UPNP_MODEL_NAME "</modelName>\r\n", 0);
pf(pContextIn, "<modelNumber>", 0);
pf(pContextIn, _UPnP_GetModelNumber(IFaceId, ac, sizeof(ac)), 0);
pf(pContextIn, "</modelNumber>\r\n", 0);
pf(pContextIn, "<modelURL>" UPNP_MODEL_URL "</modelURL>\r\n", 0);
pf(pContextIn, "<serialNumber>", 0);
pf(pContextIn, _UPnP_GetSN(IFaceId, ac, sizeof(ac)), 0);
pf(pContextIn, "</serialNumber>\r\n", 0);
pf(pContextIn, "<UDN>", 0);
pf(pContextIn, _UPnP_GetUDN(IFaceId, ac, sizeof(ac)), 0);
pf(pContextIn, "</UDN>\r\n", 0);
pf(pContextIn, "<serviceList>\r\n"
"<service>\r\n"
"<serviceType>urn:schemas-upnp-org:service:Dummy:1
</serviceType>\r\n"
"<serviceId>urn:upnp-org:serviceId:Dummy</serviceId>\r\n"
"<SCPDURL>/dummy.xml</SCPDURL>\r\n"
"<controlURL>/</controlURL>\r\n"
"<eventSubURL></eventSubURL>\r\n"
"</service>\r\n"
"</serviceList>\r\n", 0);
pf(pContextIn, "<presentationURL>", 0);
pf(pContextIn, _UPnP_GetPresentationURL(IFaceId, ac, sizeof(ac)), 0);
pf(pContextIn, "</presentationURL>\r\n", 0);
pf(pContextIn, "</device>\r\n"
"</root>", 0);
}
The callbacks for providing a virtual file using a VFile hook allow providing dynamically created content for every file requested from the web server as soon as possible.
A file served from a VFile hook will not be processed further by the web server code.
/* Excerpt from Webserver_DynContent.c */
/*********************************************************************
*
* Static code
*
**********************************************************************
*/
/*********************************************************************
*
* _UPnP_CheckVFile
*
* Function description
* Check if we have content that we can deliver for the requested
* file using the VFile hook system.
*
* Parameters
* sFileName - Name of the file that is requested
* pIndex - Pointer to a variable that has to be filled with
* the index of the entry found in case of using a
* filename<=>content list.
* Alternative all comparisons can be done using the
* filename. In this case the index is meaningless
* and does not need to be returned by this routine.
*
* Return value
* 0 - We do not have content to send for this filename,
* fall back to the typical methods for retrieving
* a file from the web server.
* 1 - We have content that can be sent using the VFile
* hook system.
*/
static int _UPnP_CheckVFile(const char * sFileName, unsigned * pIndex) {
unsigned i;
//
// Generated VFiles
//
if (strcmp(sFileName, "/upnp.xml") == 0) {
return 1;
}
//
// Static VFiles
//
for (i = 0; i < SEGGER_COUNTOF(_VFileList); i++) {
if (strcmp(sFileName, _VFileList[i].sFileName) == 0) {
*pIndex = i;
return 1;
}
}
return 0;
}
/*********************************************************************
*
* _UPnP_SendVFile
*
* Function description
* Send the content for the requested file using the callback provided.
*
* Parameters
* pContextIn - Send context of the connection processed for
* forwarding it to the callback used for output.
* Index - Index of the entry of a filename<=>content list
* if used. Alternative all comparisons can be done
* using the filename. In this case the index is
* meaningless. If using a filename<=>content list
* this is faster than searching again.
* sFileName - Name of the file that is requested. In case of
* working with the Index this is meaningless.
* pf - Function pointer to the callback that has to be
* for sending the content of the VFile.
* pContextOut - Out context of the connection processed.
* pData - Pointer to the data that will be sent
* NumBytes - Number of bytes to send from pData. If NumBytes
* is passed as 0 the send function will run a strlen()
* on pData expecting a string.
*/
static void _UPnP_SendVFile(void * pContextIn,
unsigned Index,
const char * sFileName,
void (*pf) (void * pContextOut,
const char * pData,
unsigned NumBytes)) {
struct sockaddr_in LocalAddr;
U32 IPAddr;
long hSock;
int IFaceId;
int Len;
(void)sFileName;
//
// Generated VFiles
//
if (strcmp(sFileName, "/upnp.xml") == 0) {
//
// Retrieve socket that is used by connection.
//
hSock = (long)IP_WEBS_GetConnectInfo((WEBS_OUTPUT*)pContextIn);
Len = sizeof(LocalAddr);
getsockname(hSock, (struct sockaddr*)&LocalAddr, &Len);
IPAddr = ntohl(LocalAddr.sin_addr.s_addr);
IFaceId = IP_FindIFaceByIP(&IPAddr, sizeof(IPAddr));
if (IFaceId >= 0) { // Only send back if we have found the interface.
_UPnP_GenerateSend_upnp_xml(IFaceId, pContextIn, pf);
}
return;
}
//
// Static VFiles
//
pf(pContextIn, _VFileList[Index].pData, _VFileList[Index].NumBytes);
}
All that is needed to be added to your application in order to provide the necessary
XML files through emNet Web server and starting UPnP advertising are the following lines:
/* Excerpt from OS_IP_Webserver_UPnP.c */
//
// Activate UPnP with VFile hook for needed XML files
//
IP_WEBS_AddVFileHook(&_UPnP_VFileHook, &_UPnP_VFileAPI);
IP_UPNP_Activate(INTERFACE, NULL);
API functions
Function | Description |
IP_UPNP_Activate() | Activates UPnP by joining an IGMP group and advertising that we are now available with services. |
IP_UPNP_Activate()
Description
Activates UPnP by joining an IGMP group and advertising that
we are now available with services.
Prototype
int IP_UPNP_Activate( unsigned IFaceId,
const char * sUDN);
Parameters
Parameter | Description |
IFaceId | Zero-base interface index. |
sUDN | String containing a unique descriptor name. (Optional, can be NULL.) |
Return value
= 0 | O.K. |
≠ 0 | Error, UPnP not started. |
Additional information
If sUDN is NULL, the unique descriptor name will be generated
from the HW address of the interface.
Resource usage
The ROM usage depends on the compiler options, the compiler version and the used CPU.
The memory requirements of the AutoIP module presented in the tables below have been measured on an ARM7 and a Cortex-M3 system.
Details about the further configuration can be found in the sections of the specific example.
The pure size of the UPnP add-on has been measured as the size of the services provided may vary.
ROM usage on an ARM7 system
The following resource usage has been measured on an ARM7 system using IAR Embedded Workbench V6.30.6, Thumb mode, no interwork, size optimization.
Addon | ROM |
emNet UPnP | approximately 2.2 kByte |
ROM usage on a Cortex-M3 system
The following resource usage has been measured on a Cortex-M3 system using IAR Embedded Workbench V6.30.6, size optimization.
Addon | ROM |
emNet UPnP | approximately 2.0 kByte |
RAM usage
Addon | RAM |
emNet UPnP | approximately 170 Bytes |
VLAN
The emNet implementation of VLAN which stand for Virtual LAN allows separating
your network into multiple networks without the need to separate it physically. This
chapter will show you how easily VLAN access can be setup on your target.
emNet VLAN
The emNet VLAN implementation allows a fast and easy implement of VLAN on
your target. emNet VLAN support supports a basic VLAN tag specifying only a
VLAN ID.
Feature list
- Low memory footprint.
- Easy to implement.
- Software based solution without the need for a driver to support VLAN tags.
Backgrounds
VLAN technology can be used to separate multiple devices operating on the same
physical network into completely separated networks without seeing each other.
A typical usage would be to have 2 departments separated from each other but using
the same infrastructure such as a shared switch or router. Only devices using the
same VLAN ID will be able to see each other.
For this to happen 4 bytes are added in front of the packet type field in the Ethernet
frame pushing the original packet type field back by 4 bytes. The Ethernet frame will
still be of a maximum length 1518 bytes including CRC what means that instead of a
maximum of 1500 bytes that can be transferred the amount of bytes that can be
transferred per Ethernet frame will shrink to 1496 bytes per packet. VLAN tagged
packets are typically forwarded by any switch as they are as the type field has been
simply replaced and in most cases only the destination MAC, source MAC and packet
type is checked. In this case the packet is simply of an unknown protocol and will be
forwarded by the switch.
The picture below shows the structure of an Ethernet frame once without using a
VLAN tag and once with using a VLAN tag being assigned to VLAN ID #2.
API functions
IP_VLAN_AddInterface()
Description
Adds a VLAN interface to the stack.
Prototype
int IP_VLAN_AddInterface(unsigned HWIFace,
U16 VLANId);
Parameters
Parameter | Description |
HWIFace | Zero-based index of an available network interface to be used as physical interface for the VLAN pseudo interface. |
VLANId | 12 bits VLAN ID that the new interface will recognize. The priority bits can be set here as well. They will be included when sending packets on this interface. The priority bits for received packets are ignored. |
Return value
≥ 0 | Zero-based interface index of the newly created interface. |
< 0 | Error. |
Additional information
Optional configuration of the maximum number of interfaces
that can be added to the system using IP_ConfigMaxIFaces()
needs to be done before adding any interface and must not
be changed later.
Resource usage
The ROM usage depends on the compiler options, the compiler version and the used
CPU. The memory requirements of the AutoIP module presented in the tables below
have been measured on an ARM7 and a Cortex-M3 system. Details about the further
configuration can be found in the sections of the specific example.
ROM usage on an ARM7 system
The following resource usage has been measured on an ARM7 system using IAR
Embedded Workbench V6.30.6, Thumb mode, no interwork, size optimization.
Addon | ROM |
emNet VLAN | approximately 1.2 kByte |
ROM usage on a Cortex-M3 system
The following resource usage has been measured on a Cortex-M3 system using IAR
Embedded Workbench V6.30.6, size optimization.
Addon | ROM |
emNet VLAN | approximately 1.0 kByte |
RAM usage
Addon | RAM |
emNet VLAN | approximately 16 Bytes |
Tail Tagging (Add-on)
The emNet support for the Micrel Tail Tagging feature that is available in many
Micrel Switch PHYs is an optional extension to emNet. It can be used to extend a
typical single Ethernet port CPU with more full featured ports without having to redesign
a complete hardware or even changing to a completely other CPU with more
Ethernet ports. This chapter contains information about Tail Tagging and how to add
it to your hardware and software.
emNet Tail Tagging support
The emNet Tail Tagging implementation is an optional extension which can be
easily added to extend your hardware using a Micrel Switch PHY with Tail Tagging
support instead of a single port PHY. It allows you to extend your single Ethernet port
(also single Ethernet controller) CPU to as many ports that can be managed like a
real network interface (Ethernet controller) in emNet even with different
hardware addresses.
The following table shows the contents of the emNet root directory:
Directory | Content |
BSP | Contains sample configurations for hardware that already uses
emNet Tail Tagging support. |
IP | Contains the Tail Tagging sources, IP_MICREL_TAIL_TAGGING.c and the PHY
driver for various Micrel Switch PHYs
IP_PHY_MICREL_SWITCH.c. |
Feature list
- Extend virtually any single port CPU to n manageable interfaces at low cost.
- Use the fast MII/RMII interface of your CPU and internal Ethernet controller
instead of slower interfaces like SPI with external Ethernet controllers.
- Link status of each port can be monitored independent.
- Keep your existing design and known and preferred CPU.
- Each Tail Tagging interface can have its own hardware address.
- Low memory footprint.
- Seamless integration with the emNet stack.
Use cases
The benefits of Tail Tagging are that it can be used to extend a single port Ethernet
CPU to multiple, manageable physical ports where each port can be managed independently
and can even have its own hardware address assign.
This can be used for various purposes when building hardware and software with special
requirements. Some use cases are:
- Building a multhoming hardware that shall be fail safe on the network by providing
multiple network paths that at the same time shall act as completely independent
interfaces with full control.
- Building a low cost Router, Gateway or Bridge device interfacing multiple
networks.
- Building a device that requires network separation features and at the same time
is still able to use other techniques like VLAN/prioritizing via VLAN. VLAN can be
used in a similar way than Tail Tagging but can not provide both features (VLAN
and port separation) at the same time.
Requirements
The following requirements regarding software and hardware need to be met.
Software requirements
The emNet Tail Tagging implementation requires the emNet TCP/IP stack and
a PHY driver for a Micrel Switch PHY that supports the Tail Tagging feature.
Hardware requirements
Of course a Micrel Switch PHY supporting Tail Tagging needs to be present on your
hardware as well. The big advantage of using Tail Tagging instead of other methods
like adding external Ethernet controllers is its simplicity that comes without any
known downsides.
Single MAC unit CPU, single port design
The typical hardware design for an Ethernet capable hardware with the MAC unit
inside the CPU is shown below. It consists of a CPU with a single internal MAC unit
connected to an external single port PHY that can interface one port to the network.
The Ethernet data is transferred between MAC and PHY while the MDIO interface
(typically also accessed via registers of the MAC) is used to access the PHY to configure
it and periodically check the link status.
Single MAC unit CPU, switch PHY with Tail Tagging design
For Tail Tagging only a few simple changes to the hardware are necessary. The main
difference is that configuration is no longer done via the MDIO interface but instead
is done using an extra interface like SPI or SMI. This is due to a restricted set of
registers that are available via the MDIO standard.
Typically the same registers that can be accessed via MDIO can be accessed via SPI
or SMI as well, along many other registers not available via MDIO.
Using a Switch PHY with Tail Tagging not only allows you to connect multiple hosts
but also allows you to fully control each external port/connector like it would be an
additional expensive and external Ethernet controller.
Backgrounds
The Tail Tagging feature available in many Micrel Switch PHYs is a clever way to pass
information between the PHY and the TCP/IP stack on which port of the Switch a
packet has been received or to which port(s) it should be delivered when the TCP/IP
stack sends data to the network.
Contents of a Tail Tagging frame
The picture below shows the content of a frame that is received from the Switch in
the host or is sent from the host to the Switch.
When the Switch has the Tail Tagging feature enabled all ports of the Switch will be
used in this mode.
Receiving a frame with Tail Tagging
With Tail Tagging each Ethernet frame that is received will be added with a byte
between the Ethernet data received in the frame and the checksum of the Ethernet
frame itself. This step is unseen by the Ethernet controller as the frame checksum
that is built by the sender above all the Ethernet data in the frame is altered by the
PHY as well to represent the correct checksum of the original Ethernet data in the
frame plus the byte that has been added. Due to the correct checksum the Ethernet
controller does not have to be aware of Tail Tagging at all.
emNet can then extract the information from which port the data has been
received from the Tail Tagging byte and can assign the packet to the correct Tail Tagging
interface in the system. The Tail Tagging byte is stripped in this process leaving
only the original data that can then be transferred to upper layer protocols.
Sending a frame with Tail Tagging
Sending works similar than receiving a frame. Before the Ethernet frame is queued
with the Ethernet controller for transmitting it to the PHY, a Tail Tagging byte is
appended at the end of the data to send (and before the frame checksum if calculated
and added by the Ethernet driver itself). This byte contains the information to
which external PHY ports the packet shall be delivered and sent out to the network.
The whole process is again unseen by the Ethernet controller as it is only aware that
the data to be sent is one byte more in total like if one byte more would be sent by
an upper layer protocol.
Optimal MTU and buffer sizes
A Tail Tagging interface in emNet is a virtual interface that uses a hardware interface
for data transfer. As Tail Tagging requires to store one additional byte that is
unknown to upper layer protocols the Tail Tagging byte is automatically subtracted
from the MTU that has been configured for the hardware interface.
While simply using the original MTU - 1 is a safe and easy way it has the downside
that the maximum MTU of an Ethernet packet is now 1499 bytes instead of 1500
bytes and might lead to slight fragmentation and small delays with hardware and
other hosts that are optimized for MTUs of 1500 bytes.
To overcome this effect the MTU (and typically connected with it the size of the big
packet buffers) in IP_X_Config() should not be configured to 1500 bytes but instead
configured to 1501 bytes if it is known that Tail Tagging will be used.
If a mix of Tail Tagging and non Tail Tagging interfaces will be used (dual Ethernet
controller in CPU, one using only single port and the other connected to a Switch
using Tail Tagging) the MTU should be set accordingly for each of these interfaces
using IP_SetMTU().
API functions
IP_MICREL_TAIL_TAGGING_AddInterface()
Description
Adds a virtual interface to the stack using the Micrel Tail
Tagging feature to separate switch ports.
Prototype
int IP_MICREL_TAIL_TAGGING_AddInterface(unsigned HWIFaceId,
U8 InTag,
U8 OutTag);
Parameters
Parameter | Description |
HWIFaceId | Zero-based interface index of the interface used as hardware interface. |
InTag | Tag byte according to Micrel documentation to compare with an incoming (switch to target) Tail Tagging byte. |
OutTag | Tag byte according to Micrel documentation to append for an outgoing (target to switch) packet on this interface. Multiple bits can be set to allow sending to multiple ports at the same time. |
Return value
≥ 0 | Zero-based interface index of the newly created interface. |
< 0 | Error. |
Additional information
Optional configuration of the maximum number of interfaces
that can be added to the system using IP_ConfigMaxIFaces()
needs to be done before adding any interface and must not
be changed later.
Example
/*********************************************************************
* (c) SEGGER Microcontroller GmbH *
* The Embedded Experts *
* www.segger.com *
**********************************************************************
-------------------------- END-OF-HEADER -----------------------------
File : IP_Config_K66_SEGGER_embOS_IP_SwitchBoard_ETH.c
Purpose : Configuration file for TCP/IP with Freescale Kinetis K66
*/
#include "IP.h"
#include "IP_NI_KINETIS.h"
#include "BSP_IP.h"
#include "IP_PHY_MICREL_SWITCH.h"
/*********************************************************************
*
* Configuration
*
**********************************************************************
*/
#define DRIVER &IP_Driver_K64 // Driver used for target.
#define TARGET_NAME "emPowerV2_1" // Target name used for DHCP client.
#define HW_ADDR "\x00\x22\xC7\xDD\xFF\x22" // MAC addr. used for target.
#define NUM_PORTS 3 // Number of switch ports used for Tail-Tagging. 0: Plain switch mode.
#if (NUM_PORTS == 0) // Keep memory for one port.
#define ALLOC_SIZE (1 * 0x6000) // Size of memory dedicated to the stack in bytes.
#else
#define ALLOC_SIZE (NUM_PORTS * 0x6000) // Size of memory dedicated to the stack in bytes. Very rough calculation.
#endif
/*********************************************************************
*
* Defines, fixed
*
**********************************************************************
*/
#define SIM_SCGC5 (*(volatile U32 *)(0x40048038)) // System Clock Gating Control Register 5
#define SIM_SCGC6 (*(volatile U32 *)(0x4004803C)) // System Clock Gating Control Register 6
#define SIM_SCGC6_SPI0_MASK (1uL << 12)
#define SIM_SCGC6_SPI1_MASK (1uL << 13)
#define SIM_SCGC5_PORTB_MASK (1uL << 10)
#define SIM_SCGC5_PORTC_MASK (1uL << 11)
#define PORTB_BASE_ADDR (0x4004A000)
#define PORTB_PCR10 (*(volatile U32 *)(PORTB_BASE_ADDR + 0x0028)) // Pin Control Register 10
#define PORTB_PCR11 (*(volatile U32 *)(PORTB_BASE_ADDR + 0x002C)) // Pin Control Register 11
#define PORTB_PCR16 (*(volatile U32 *)(PORTB_BASE_ADDR + 0x0040)) // Pin Control Register 16
#define PORTB_PCR17 (*(volatile U32 *)(PORTB_BASE_ADDR + 0x0044)) // Pin Control Register 17
#define PORTC_BASE_ADDR (0x4004B000)
#define PORTC_PCR4 (*(volatile U32 *)(PORTC_BASE_ADDR + 0x0010)) // Pin Control Register 4
#define PORTC_PCR5 (*(volatile U32 *)(PORTC_BASE_ADDR + 0x0014)) // Pin Control Register 5
#define PORTC_PCR6 (*(volatile U32 *)(PORTC_BASE_ADDR + 0x0018)) // Pin Control Register 6
#define PORTC_PCR7 (*(volatile U32 *)(PORTC_BASE_ADDR + 0x001C)) // Pin Control Register 7
#define SPI0_BASE_ADDR (0x4002C000)
#define SPI1_BASE_ADDR (0x4002D000)
#define SPI_MCR (*(volatile U32 *)(SPI1_BASE_ADDR + 0x00))
#define SPI_CTAR0 (*(volatile U32 *)(SPI1_BASE_ADDR + 0x0C))
#define SPI_SR (*(volatile U32 *)(SPI1_BASE_ADDR + 0x2C))
#define SPI_PUSHR (*(volatile U32 *)(SPI1_BASE_ADDR + 0x34))
#define SPI_POPR (*(volatile U32 *)(SPI1_BASE_ADDR + 0x38))
#define SPI_PUSHR_CONT_BIT (1uL << 31) // Continued CS
#define SPI_PUSHR_EOQ_BIT (1uL << 27) // End of queue
#define SPI_PUSHR_PCS_BIT (1uL << 16) // Activate CS#0
#define SPI_MCR_HALT_BIT (1uL << 0) // Halt bit
#define SPI_SR_EOQF_BIT (1uL << 28) // End of queue full in SR
#define SPI_SR_TCF_BIT (1uL << 31) // Transfer complete
#define SPI_SR_RFDF_BIT (1uL << 17) // RX Fifo drain flag
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
#ifdef __ICCARM__
static __no_init U32 _aPool[ALLOC_SIZE / 4];
#else
// #if (defined(__GNUC__) || defined(__SEGGER_CC__))
// static U32 _aPool[ALLOC_SIZE / 4] __attribute__ ((section ("IP_RAM"))); // This is the memory area used by the stack.
// #else
static U32 _aPool[ALLOC_SIZE / 4];
// #endif
#endif
/*********************************************************************
*
* Local functions
*
**********************************************************************
*/
/*********************************************************************
*
* _InitPhyIF()
*
* Function description
* Initializes the interface to the switch.
*/
static void _InitPhyIF(void) {
U32 v;
v = SIM_SCGC5;
v |= SIM_SCGC5_PORTB_MASK; // Enable clock for Port B
SIM_SCGC5 = v;
v = SIM_SCGC6;
v |= SIM_SCGC6_SPI1_MASK; // Enable clock for SPI1
SIM_SCGC6 = v;
//
// Set PTB10 (SPI1_PCS0) alternate function 2.
//
PORTB_PCR10 = 0x00000200;
//
// Set PTB11 (SPI1_SCK) alternate function 2.
//
PORTB_PCR11 = 0x00000200;
//
// Set PTB16 (SPI1_SOUT) alternate function 2.
//
PORTB_PCR16 = 0x00000200;
//
// Set PTB17 (SPI1_SIN) alternate function 2.
//
PORTB_PCR17 = 0x00000200;
//
// Setup SPI parameters.
//
SPI_MCR = 0
| (1uL << 31) // Master mode
| (1uL << 27) // Freeze in debug mode
| (1uL << 16) // 1 = The inactive state of Peripheral chip select is high
| (0uL << 13) // 0 = TX FIFO is enabled
| (0uL << 12) // 0 = RX FIFO is enabled
| (1uL << 0) // 0 = Start transfer
;
SPI_CTAR0 = 0
| (0uL << 31) // Double baud rate
| (7uL << 27) // Frame size (7 + 1)
| (0uL << 26) // CPOL
| (0uL << 25) // CPHA
| (0uL << 24) // 0 = MSB first
| (1uL << 22) // PCSSCK
| (1uL << 20) // PASC
| (3uL << 12) // CSSCK
| (3uL << 0) // Baud rate scaler
;
//
// Grant switch some time to completely power up.
//
IP_OS_Delay(100);
}
/*********************************************************************
*
* _ReadWriteSPIByte()
*
* Function description
* Writes one byte via SPI and receives one byte in exchange.
*
* Parameters
* Data: Byte to write on line + settings.
*
* Return value
* Byte read from line.
*/
static U8 _ReadWriteSPI(U32 Data) {
U8 v;
SPI_PUSHR = SPI_PUSHR_PCS_BIT | Data; // Push data + activation of CS0
while ((SPI_SR & SPI_SR_TCF_BIT) == 0x0); // Wait for transfer complete indication
SPI_SR |= SPI_SR_TCF_BIT; // Reset transfer complete indication
v = SPI_POPR; // Pop the read queue
//
return v;
}
/*********************************************************************
*
* _ReadSPIReg()
*
* Function description
* Reads a byte from a register.
*
* Parameters
* pContext: Context of the PHY driver.
* Reg : Address of the register to read.
*
* Return value
* value read from register.
*/
static unsigned _ReadSPIReg(IP_PHY_CONTEXT_EX* pContext, unsigned Reg) {
U8 v;
IP_USE_PARA(pContext);
SPI_MCR &= ~SPI_MCR_HALT_BIT; // Activate SPI
while ((SPI_SR & (1uL << 30)) == 0x0); // Wait for ready indication
//
_ReadWriteSPI( 0
| SPI_PUSHR_CONT_BIT // Continuous CS signal
| (0x03 << 5) ); // Read command
_ReadWriteSPI( 0
| SPI_PUSHR_CONT_BIT // Continuous CS signal
| (Reg << 1) ); // Register to read
v = _ReadWriteSPI( 0
| SPI_PUSHR_EOQ_BIT // End of Queue to transmit
| 0xff ); // Any value
//
SPI_MCR |= SPI_MCR_HALT_BIT; // Halt SPI
//
return (v & 0xFF);
}
/*********************************************************************
*
* _WriteSPIReg()
*
* Function description
* Writes a byte to a register.
*
* Parameters
* pContext: Context of the PHY driver.
* Reg : Address of the register to read.
* v : Data to write.
*/
static void _WriteSPIReg(IP_PHY_CONTEXT_EX* pContext, unsigned Reg, unsigned v) {
IP_USE_PARA(pContext);
SPI_MCR &= ~SPI_MCR_HALT_BIT; // Activate SPI
while ((SPI_SR & (1uL << 30)) == 0x0); // Wait for ready indication
//
_ReadWriteSPI( 0
| SPI_PUSHR_CONT_BIT // Continuous CS signal
| (0x02 << 5) ); // Write command
_ReadWriteSPI( 0
| SPI_PUSHR_CONT_BIT // Continuous CS signal
| (Reg << 1) ); // Register to read
_ReadWriteSPI( 0
| SPI_PUSHR_EOQ_BIT // End of Queue to transmit
| (v & 0xFF) ); // Value to write
//
SPI_MCR |= SPI_MCR_HALT_BIT; // Halt SPI
}
/*********************************************************************
*
* _ConfigPHY()
*
* Function description
* Callback executed during the PHY init of the stack to configure
* PHY settings once the hardware interface has been initialized.
*
* Parameters
* IFaceId: Zero-based interface index.
*/
static void _ConfigPHY(unsigned IFaceId) {
#if (NUM_PORTS == 0)
IP_USE_PARA(IFaceId);
#else
if (IFaceId == 0) { // Host interface ?
//
// Activate Tail Tagging. Needs to be done for the interface of the
// host port. Enabling it multiple times does not hurt.
//
IP_PHY_MICREL_SWITCH_ConfigTailTagging(IFaceId, 1); // 0: Off, 1: On.
} else {
//
// Configure the physical zero-based port number on the switch for this interface.
// In this sample the port number is always one lower than the interface ID.
// This should be the first configuration to set as other functions might depend
// on the port number set here internally.
//
IP_PHY_MICREL_SWITCH_AssignPortNumber(IFaceId, IFaceId - 1);
//
// Tx switch functionality and switch address learning.
// For our Tail Tagging implementation for port multiplication we
// want to disable the switch functionality for Tx as this would
// send back incoming packets form one port to another creating
// an infinite loop if both ports are in the same network.
//
IP_PHY_MICREL_SWITCH_ConfigRxEnable(IFaceId, 1);
IP_PHY_MICREL_SWITCH_ConfigTxEnable(IFaceId, 0);
IP_PHY_MICREL_SWITCH_ConfigLearnDisable(IFaceId, 1);
}
#endif
}
/*********************************************************************
*
* Local API structures
*
**********************************************************************
*/
static const IP_PHY_MICREL_SWITCH_ACCESS PhyAccess = {
_ReadSPIReg, // pfReadReg
_WriteSPIReg // pfWriteReg
};
/*********************************************************************
*
* Global functions
*
**********************************************************************
*/
/*********************************************************************
*
* IP_X_Config()
*
* Function description
* This function is called by the IP stack during IP_Init().
*
* Typical memory/buffer configurations:
* Microcontroller system, minimum size optimized
* #define ALLOC_SIZE 0x1000 // 4KBytes RAM.
* mtu = 576; // 576 is minimum acc. to RFC, 1500 is max. for Ethernet.
* IP_SetMTU(0, mtu); // Maximum Transmission Unit is 1500 for Ethernet by default.
* IP_AddBuffers(4, 256); // Small buffers.
* IP_AddBuffers(2, mtu + 16); // Big buffers. Size should be mtu + 16 byte for Ethernet header (2 bytes type, 2*6 bytes MAC, 2 bytes padding).
* IP_ConfTCPSpace(2 * (mtu - 40), 1 * (mtu - 40)); // Define the TCP Tx and Rx window size. At least Tx space for 2*(mtu-40) for two full TCP packets is needed.
*
* Microcontroller system, size optimized
* #define ALLOC_SIZE 0x3000 // 12KBytes RAM.
* mtu = 576; // 576 is minimum acc. to RFC, 1500 is max. for Ethernet.
* IP_SetMTU(0, mtu); // Maximum Transmission Unit is 1500 for Ethernet by default.
* IP_AddBuffers(8, 256); // Small buffers.
* IP_AddBuffers(4, mtu + 16); // Big buffers. Size should be mtu + 16 byte for Ethernet header (2 bytes type, 2*6 bytes MAC, 2 bytes padding).
* IP_ConfTCPSpace(2 * (mtu - 40), 2 * (mtu - 40)); // Define the TCP Tx and Rx window size. At least Tx space for 2*(mtu-40) for two full TCP packets is needed.
*
* Microcontroller system, speed optimized or multiple connections
* #define ALLOC_SIZE 0x6000 // 24 KBytes RAM.
* mtu = 1500; // 576 is minimum acc. to RFC, 1500 is max. for Ethernet.
* IP_SetMTU(0, mtu); // Maximum Transmission Unit is 1500 for Ethernet by default.
* IP_AddBuffers(12, 256); // Small buffers.
* IP_AddBuffers(6, mtu + 16); // Big buffers. Size should be mtu + 16 byte for Ethernet header (2 bytes type, 2*6 bytes MAC, 2 bytes padding).
* IP_ConfTCPSpace(3 * (mtu - 40), 3 * (mtu - 40)); // Define the TCP Tx and Rx window size. At least Tx space for 2*(mtu-40) for two full TCP packets is needed.
*
* System with lots of RAM
* #define ALLOC_SIZE 0x20000 // 128 KBytes RAM.
* mtu = 1500; // 576 is minimum acc. to RFC, 1500 is max. for Ethernet.
* IP_SetMTU(0, mtu); // Maximum Transmission Unit is 1500 for Ethernet by default.
* IP_AddBuffers(50, 256); // Small buffers.
* IP_AddBuffers(50, mtu + 16); // Big buffers. Size should be mtu + 16 byte for Ethernet header (2 bytes type, 2*6 bytes MAC, 2 bytes padding).
* IP_ConfTCPSpace(8 * (mtu - 40), 8 * (mtu - 40)); // Define the TCP Tx and Rx window size. At least Tx space for 2*(mtu-40) for two full TCP packets is needed.
*/
void IP_X_Config(void) {
int mtu;
int IFaceId;
int HWIFaceId;
#if (NUM_PORTS != 0)
int i;
#endif
U8 abHWAddr[6];
char acTargetName[sizeof(TARGET_NAME)];
_InitPhyIF(); // Initialize the interface for the switch configuration.
IP_AssignMemory(_aPool, sizeof(_aPool)); // Assigning memory should be the first thing.
IP_ConfigMaxIFaces(NUM_PORTS + 1); // Configure max. number of ports to be available.
HWIFaceId = IP_AddEtherInterface(DRIVER); // Add driver for your hardware.
#if (NUM_PORTS == 0)
IFaceId = HWIFaceId;
#endif
IP_BSP_SetAPI(HWIFaceId, &BSP_IP_Api); // Set BSP callbacks for hardware access. Only required for HW interface.
IP_NI_ConfigPHYMode(HWIFaceId, 1); // Configure PHY Mode: 0: MII, 1: RMII; For required hardware changes for RMII, please refer to your board manual
//
// Add PHY driver for the host port of the switch.
// The PHY driver for the host port manages global
// configurations like filter settings and other
// things that are not setup for each port separately.
//
IP_PHY_AddDriver(HWIFaceId, &IP_PHY_Driver_Micrel_Switch_KSZ8895_HostPort, &PhyAccess, &_ConfigPHY);
//
// Define log and warn filter.
// Note: The terminal I/O emulation might affect the timing of your
// application, since most debuggers need to stop the target
// for every terminal I/O output unless you use another
// implementation such as DCC or SWO.
//
IP_SetWarnFilter(0xFFFFFFFF); // 0xFFFFFFFF: Do not filter: Output all warnings.
IP_SetLogFilter(0
| IP_MTYPE_APPLICATION // Output application messages.
| IP_MTYPE_INIT // Output all messages from init.
| IP_MTYPE_LINK_CHANGE // Output a message if link status changes.
| IP_MTYPE_PPP // Output all PPP/PPPoE related messages.
| IP_MTYPE_DHCP // Output general DHCP status messages.
#if IP_SUPPORT_IPV6
| IP_MTYPE_IPV6 // Output IPv6 address related messages
#endif
// | IP_MTYPE_DHCP_EXT // Output additional DHCP messages.
// | IP_MTYPE_CORE // Output log messages from core module.
// | IP_MTYPE_ALLOC // Output log messages for memory allocation.
// | IP_MTYPE_DRIVER // Output log messages from driver.
// | IP_MTYPE_ARP // Output log messages from ARP layer.
// | IP_MTYPE_IP // Output log messages from IP layer.
// | IP_MTYPE_TCP_CLOSE // Output a log messages if a TCP connection has been closed.
// | IP_MTYPE_TCP_OPEN // Output a log messages if a TCP connection has been opened.
// | IP_MTYPE_TCP_IN // Output TCP input logs.
// | IP_MTYPE_TCP_OUT // Output TCP output logs.
// | IP_MTYPE_TCP_RTT // Output TCP round trip time (RTT) logs.
// | IP_MTYPE_TCP_RXWIN // Output TCP RX window related log messages.
// | IP_MTYPE_TCP // Output all TCP related log messages.
// | IP_MTYPE_UDP_IN // Output UDP input logs.
// | IP_MTYPE_UDP_OUT // Output UDP output logs.
// | IP_MTYPE_UDP // Output all UDP related messages.
// | IP_MTYPE_ICMP // Output ICMP related log messages.
// | IP_MTYPE_NET_IN // Output network input related messages.
// | IP_MTYPE_NET_OUT // Output network output related messages.
// | IP_MTYPE_DNS // Output all DNS related messages.
// | IP_MTYPE_SOCKET_STATE // Output socket status messages.
// | IP_MTYPE_SOCKET_READ // Output socket read related messages.
// | IP_MTYPE_SOCKET_WRITE // Output socket write related messages.
// | IP_MTYPE_SOCKET // Output all socket related messages.
);
//
// Add protocols to the stack (that do not require an interface parameter).
//
IP_TCP_Add();
IP_UDP_Add();
IP_ICMP_Add();
//
// Run-time configuration that needs to be set as it will
// be passed to virtual interfaces from the HW interface.
//
mtu = 1500; // 576 is minimum acc. to RFC, 1500 is max. for Ethernet.
IP_SetMTU(HWIFaceId, mtu); // Maximum Transmission Unit is 1500 for Ethernet by default.
//
// Configure each switch port (not connected to the host CPU).
//
IP_MEMCPY(&abHWAddr[0], (const U8*)HW_ADDR, 6);
IP_MEMCPY(&acTargetName[0], TARGET_NAME, sizeof(TARGET_NAME));
#if (NUM_PORTS != 0)
for (i = 0; i < NUM_PORTS; i++) {
IFaceId = IP_MICREL_TAIL_TAGGING_AddInterface(HWIFaceId, i, (1 << 6) | (1 << i)); // Add Tail Tagging interface for switch port, enable switch engine override.
#endif
IP_SetHWAddrEx(IFaceId, (const U8*)&abHWAddr[0], 6); // Set MAC addr. for switch port: Needs to be unique for production units.
#if (NUM_PORTS != 0)
abHWAddr[5]++; // Increase last byte of HW addr. for next switch port.
acTargetName[sizeof(TARGET_NAME) - 1]++; // Increase last character of the target name for next switch port.
IP_PHY_AddDriver(IFaceId, &IP_PHY_Driver_Micrel_Switch_KSZ8895, &PhyAccess, &_ConfigPHY); // Add PHY driver for Micrel switch PHY to the interface.
#endif
IP_DHCPC_Activate(IFaceId, TARGET_NAME, NULL, NULL); // Activate DHCP client for this interface.
//
// Add IPv6 support to the stack and enable it for the interface.
//
#if IP_SUPPORT_IPV6
IP_IPV6_Add(IFaceId);
#endif
#if (NUM_PORTS != 0)
}
#endif
//
// Run-time configure buffers.
// The default setup will do for most cases.
//
#if (NUM_PORTS == 0)
IP_AddBuffers((1 * 12), 256); // Small buffers.
IP_AddBuffers((1 * 6), mtu + 16); // Big buffers. Size should be mtu + 16 byte for ethernet header (2 bytes type, 2*6 bytes MAC, 2 bytes padding)
#else
IP_AddBuffers((NUM_PORTS * 12), 256); // Small buffers.
IP_AddBuffers((NUM_PORTS * 6), mtu + 16); // Big buffers. Size should be mtu + 16 byte for ethernet header (2 bytes type, 2*6 bytes MAC, 2 bytes padding)
#endif
IP_ConfTCPSpace(3 * (mtu - 40), 3 * (mtu - 40)); // Define the TCP Tx and Rx window size
IP_SOCKET_SetDefaultOptions(0
// | SO_TIMESTAMP // Send TCP timestamp to optimize the round trip time measurement. Normally not used in LAN.
| SO_KEEPALIVE // Enable keepalives by default for TCP sockets.
);
}
/****** End Of File *************************************************/
Resource usage
The ROM usage depends on the compiler options, the compiler version and the used
CPU. The memory requirements of the Tail Tagging module presented in the tables
below have been measured on a Cortex-M4 system. Details about the further configuration
can be found in the sections of the specific example.
ROM usage on a Cortex-M4 system
The following resource usage has been measured on a Cortex-M4 system using
SEGGER Embedded Studio V2.12, size optimization.
Addon | ROM |
emNet Tail Tagging | approximately 0.4 kByte |
RAM usage
All required RAM is taken from the RAM that has been assigned to emNet using IP_AddMemory().
Only a few bytes are required.
WiFi support
emNet WiFi support is an easy way to add the IEEE 802.11 standard also known
as WiFi or WLAN to your project. It allows not only an easy start using WiFi in a new
product but also allows adding WiFi support to existing projects already using
emNet interfaces like LAN, PPP, USBD RNDIS/ECM or any other in short time.
All functions that are required to add WiFi to your application and some background
information about WiFi hardware that can be used with emNet is described in this
chapter.
emNet WiFi support
The emNet WiFi support allows adding different WiFi hardware in the same way as
any other interface that can be added. The configuration and accessibility is bundled
in an easy to understand API regardless of the underlying API of the WiFi hardware.
This not only allows an easy start for adding WiFi to your project but comes in handy
if you plan to exchange WiFi hardware in the future.
Feature list
- Unified API regardless of the WiFi module used.
- Easily add WiFi support as another interface to existing emNet LAN solutions.
- No need for re-certification by using already WiFi certified modules.
- Access Point support (depends on the module).
- Protocol support not limited to protocols that are TCP/UDP based.
- Support for various host interfaces like UART/SPI/SDIO/RMII (depends on the module).
- Low memory footprint (emNet WiFi software components).
- Seamless integration with the emNet stack.
Requirements
Software requirements
The emNet WiFi support requires the emNet TCP/IP stack, the emNet
module (family) specific WiFi driver and typically a vendor SDK for the specific WiFi
module (family).
The vendor SDK should feature a Hardware Abstraction Layer (HAL) that needs to be
filled in with your interface specific hardware routines.
For WiFi modules that do not need an SDK, a HAL is provided by the emNet WiFi
module specific driver, allowing to interface to various host interfaces supported by
the WiFi module.
Hardware requirements
The emNet WiFi support can be used with virtually any module that is able to
communicate with the host MCU and providing full Ethernet packet access. For communication
with the host MCU typically an SPI interface is required. Other interfaces
such as UART, SDIO, I2C or RMII might be supported by the module as well.
Different WiFi add-on boards for easy evaluation on the emPower eval board are
available. The porting of the module specific hardware layer has already been done
for these modules for the emPower eval board and are shipped with the drivers as
example, can be found in the corresponding eval package.
Background information
This chapter does not cover the IEEE 802.11 standard as this would be too much
information and required information about the standard itself can be easily found on
the Internet. The background information referenced herein shall help to understand
the level of implementation the emNet WiFi support offers.
Definition of a WiFi module
A WiFi module typically describes a small form factor board that basically consists of
two components:
- An RF (Radio Frequency) module
- A companion MCU
WiFi modules are in fact external (Ethernet) controllers. The companion MCU is used
to interface the RF module to actually establish WiFi communication. This is
controlled by providing vendor specific commands to the companion MCU from the host
MCU using one of the supported host interfaces of the WiFi module.
As each vendor is using its own command set, there is no common API that can be
used across different modules, at least not between different vendors. Typically
command sets are kept compatible within a product family of a vendor. This makes
various modules compatible with the same SDK provided from the vendor.
Typically WiFi modules come with their own TCP/IP stack on board. This makes them
easy to use for smaller projects like a weather station that periodically sends its data
to a server. While these internal TCP/IP stacks might already come with some
features like a small web server, they are also limited to the features of the built-in
commands and protocols.Benefits of using WiFi modules
Benefits of using WiFi modules
While the WiFi circuitry could be directly integrated with your PCB there are various
benefits from using an available WiFi module instead of your own implementation:
- No re-certification: Typically the WiFi modules available are already certified by
the Wi-Fi Alliance. This saves a lot of time and costs otherwise spent for a
certification process of your own designed WiFi circuitry.
- Using a design that has proven to be working.
- Easy to evaluate/no need for prototyping in regards to the WiFi circuitry.
- Can easily extend existing solutions using a free standard peripheral interface
like SPI without redesigning the whole hardware.
- Offloading crypto operations necessary for encryption like WPA2 to the companion MCU.
Besides the hardware designing and evaluation aspects, the biggest benefit is without
doubt the elimination of a re-certification process which might be time and cost
intensive. Typically the modules are completely certified when using an integrated
antenna or are certified when being used with a selection of one or more antennas
specified by the module vendor.
Module internal vs. external TCP/IP stack
While most WiFi modules come with their own internal TCP/IP stack on the companion
MCU, they are typically limited in usage to their built-in commands. This usually
means only having access to a limited amount of TCP and UDP sockets that can be
used to implement higher level protocols based on these two base protocols.
While only having a limited amount of TCP and UDP sockets might be enough for
some small projects, this concept lacks control and extensibility. To allow more control
and extensibility an external TCP/IP stack like emNet needs to be used. This
allows having control over the complete Ethernet frame of the packet to implement
protocols on a lower level such as ARP or VLAN.
It is often referred to as pass-through-mode or bypass-mode to give an external
stack full control over the whole Ethernet frame. It disables the processing by the
module internal TCP/IP stack and exchanges the complete Ethernet frame with the
TCP/IP stack on the host MCU.
Supported WiFi modules
The intention of WiFi support for emNet is to allow extending an already
established product with WiFi in a flexible and easy way. At the same time it shall be an
easy to use solution for new projects. Features shall not depend on module features
in the first place and shall be extensible at any time. emNet supports only
modules that are able to exchange complete Ethernet frames with the host MCU using a
so called pass-through-mode or bypass-mode to fulfill this goal.
Being able to access the whole Ethernet frame, emNet is not only able to use TCP
and UDP based high level protocols but allows low level protocols via WiFi as well.
Using this solution, existing and future add-ons can be used via WiFi the same way
they would be with a cable based solution.
API functions
IP_WIFI_AddAssociateChangeHook()
Description
Adds a function to the IP_HOOK_ON_WIFI_ASSOCIATE_CHANGE list.
Prototype
void IP_WIFI_AddAssociateChangeHook(IP_HOOK_ON_WIFI_ASSOCIATE_CHANGE * pHook,
IP_WIFI_pfOnAssociateChange pf);
Parameters
Parameter | Description |
pHook | Pointer to hook structure to link. |
pf | Pointer to function to call on change. |
IP_WIFI_AddClientNotificationHook()
Description
Adds a function to the IP_HOOK_ON_WIFI_CLIENT_NOTIFICATION list.
This list is notified when a client connects or disconnect when
in access point mode.
Prototype
void IP_WIFI_AddClientNotificationHook(IP_HOOK_ON_WIFI_CLIENT_NOTIFICATION * pHook,
IP_WIFI_pfOnClientNotification pf);
Parameters
Parameter | Description |
pHook | Pointer to hook structure to link. |
pf | Pointer to function to call on notification. |
IP_WIFI_AddInterface()
Description
Adds a WiFi interface to the stack.
Prototype
int IP_WIFI_AddInterface(const IP_HW_DRIVER * pDriver);
Parameters
Parameter | Description |
pDriver | Pointer to IP_HW_DRIVER API table. |
Return value
≥ 0 | Zero-based interface index of the newly created interface. |
< 0 | Error. |
Additional information
Optional configuration of the maximum number of interfaces
that can be added to the system using IP_ConfigMaxIFaces()
needs to be done before adding any interface and must not
be changed later.
IP_DTASK_AddExecDoneHook()
Description
Adds a callback that gets executed once the Driver Task handler
is done.
Prototype
void IP_DTASK_AddExecDoneHook(unsigned IFaceId,
IP_HOOK_ON_DTASK_EXEC_DONE * pHook,
IP_ON_DTASK_EXEC_DONE_FUNC * pf);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pHook | Pointer to hook structure to link. |
pf | Pointer to function to call on change. |
Additional information
A callback that signals the end of the ISR handler routine is required when using level
sensitive interrupts that only signal a task like the WiFi/DTask ISR task to run. The following
example demonstrates why this is necessary:
- Interrupt line gets high.
- Level sensitive interrupt is fired.
- Signaling the WiFi ISR task to run.
- Clearing the interrupt pending flag (could have been done before 3. as well).
- The interrupt is still pending as typically the interrupt line on WiFi modules only
gets low after all messages have been received. For this the WiFi/DTask ISR Task would
need to run but we are stuck at 2. as the level sensitive interrupt constantly
fires.
Solution:
After 2. simply disable the interrupt. Once all messages we are aware of have been
processed the WiFi/DTask ISR task will run to wait until it is signaled again. Before actually
waiting the callback gets executed telling us that now is the right moment to clear
the pending interrupt flag and re-enabling the interrupt itself as most likely the
interrupt line is now low and we are not instantly back in the interrupt. Of course it might
happen that we are almost instantly back the interrupt as new messages are ready at
the module to be received.
IP_WIFI_AddSignalChangeHook()
Description
Adds a function to the IP_HOOK_ON_WIFI_SIGNAL_CHANGE list.
Prototype
void IP_WIFI_AddSignalChangeHook(IP_HOOK_ON_WIFI_SIGNAL_CHANGE * pHook,
IP_WIFI_pfOnSignalChange pf);
Parameters
Parameter | Description |
pHook | Pointer to hook structure to link. |
pf | Pointer to function to call on change. |
IP_WIFI_ConfigAllowedChannels()
Description
Configures the channels that are allowed to be used for network
scan and associate requests.
Prototype
int IP_WIFI_ConfigAllowedChannels( unsigned IFaceId,
const U8 * paChannel,
U8 NumChannels);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
paChannel | Pointer to a list of allowed channels. |
NumChannels | Number of channels in list. |
Return value
Additional information
Allowed channels are a subset of the configured regulatory domain.
IP_DTASK_ConfigAlwaysSignaled()
Description
Keeps the interface in signaled state to be polled each time
regardless if there really was a signal or not.
Prototype
void IP_DTASK_ConfigAlwaysSignaled(unsigned IFaceId,
char OnOff);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
OnOff | 0 : Off. Other: On. |
IP_DTASK_GetTimeout()
Description
Retrieves the timeout [ms] after which the Driver Task should
polls the driver interrupt routine even if it has not been
signaled.
Prototype
unsigned IP_DTASK_GetTimeout(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
Previously configured timeout [ms].
Additional information
At the moment the IFaceId parameter is ignored and the timeout
value is used for all interfaces.
This routine can be used to set the timeout in a central place
such as from IP_X_Config() and retrieve it wherever necessary.
IP_DTASK_SetTimeout()
Description
Sets the timeout [ms] after which the Driver Task polls the
driver interrupt routine even if it has not been signaled.
Prototype
void IP_DTASK_SetTimeout(unsigned IFaceId,
unsigned Timeout);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Timeout | Timeout [ms]. |
Additional information
At the moment the IFaceId parameter is ignored and the timeout
value is used for all interfaces.
IP_WIFI_Connect()
Description
Connects to a selected SSID or starts as access point.
Prototype
int IP_WIFI_Connect( unsigned IFaceId,
const IP_WIFI_CONNECT_PARAMS * pParams,
U32 Timeout);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pParams | Pointer to structure that contains connection parameters. |
Timeout | Timeout before considering connect attempt failed [ms]. |
Return value
IP_WIFI_Disconnect()
Description
Disconnects from any connected network or stops the access point
mode.
Prototype
int IP_WIFI_Disconnect(unsigned IFaceId,
U32 Timeout);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Timeout | Timeout before considering disconnect attempt failed [ms]. |
Return value
IP_DTASK_Task()
Description
Task that polls the handler routine of some drivers.
Prototype
void IP_DTASK_Task(void);
Additional information
This task is required to be implementing into your project for
some drivers to work. This is typically the case for external
Ethernet controllers. An example for typical task stack usage
is defined by TASK_STACK_SIZE_IP_DRIVER_TASK .
For best performance this task should be given a task priority
higher than any other IP stack related application task and
even the IP_Task() or its API alternatives IP_TASK_Init(),
IP_TASK_Exec() and IP_TASK_WaitForEvent() . It however must not
have a higher or the same priority than the IP_RxTask() or its
API alternatives IP_RXTASK_Init(), IP_RXTASK_Exec() and
IP_RXTASK_WaitForEvent() .
For more information regarding task priorities, please refer to
Tasks and interrupt usage .
After startup, this routine settles into a loop, handling
driver events. This loop sleeps until signaled by an event.
Alternatively it can be configured to wake up and poll the
drivers periodically using IP_DTASK_ConfigTimeout() and
IP_DTASK_ConfigAlwaysSignaled() .
In case of de-initializing the stack with IP_DeInit(), it is
possible to leave the loop gracefully by using IP_ShutDown() .
IP_DTASK_Init()
Description
Initializes the DriverTask context.
Prototype
void IP_DTASK_Init(void);
Additional information
For best performance the IP_DTASK_* API should be called with
a task priority higher than any other IP stack related
application task and even the IP_Task() or its API alternatives
IP_TASK_Init(), IP_TASK_Exec() and IP_TASK_WaitForEvent() .
Example
/*********************************************************************
*
* _IP_DTASK_Task()
*
* Function description
* Application specific implementation of IP_DTASK_Task() .
*
* Additional information
* Allows to insert your own code like feeding a watchdog
* in-between the separate steps that would be executed by the
* original task API provided by the stack.
*/
static void _IP_DTASK_Task(void) {
unsigned Timeout;
//
// Initialize.
//
IP_DTASK_Init();
//
// Get the timeout configured for example during IP_X_Config() .
// If not configured, the default is returned which is 0 and
// means to wait INFINITE .
//
Timeout = IP_DTASK_GetTimeout(0u); // Get timeout for interface #0 .
//
// Task-loop.
//
for (;;) {
//
// Wait with timeout [ms] for the next event to be signaled.
// Typically the signal is triggered by an interrupt from an
// external controller that notifies us that the previous
// operation is now finished and the next can be started.
//
IP_DTASK_WaitForEvent(Timeout);
//
// Process the event.
//
IP_DTASK_ExecAll();
}
}
IP_DTASK_Exec()
Description
Executes the handler routine of the driver for a specific interface.
Prototype
void IP_DTASK_Exec(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface ID. |
Additional information
This routine is an alternative to using the IP_DTASK_Task() .
It allows finer control over the internal steps done in
IP_DTASK_Task() . This can be utilized for example to feed a
watchdog from the same task periodically.
Note
This routine is not intended to be used when using
IP_DTASK_Task() instead.
For best performance the IP_DTASK_* API should be called with
a task priority higher than any other IP stack related
application task and even the IP_Task() or its API alternatives
IP_TASK_Init(), IP_TASK_Exec() and IP_TASK_WaitForEvent() .
IP_DTASK_ExecAll()
Description
Executes the handler routine of the driver for all interfaces.
Prototype
void IP_DTASK_ExecAll(void);
Additional information
This routine is an alternative to using the IP_DTASK_Task() .
It allows finer control over the internal steps done in
IP_DTASK_Task() . This can be utilized for example to feed a
watchdog from the same task periodically.
Note
This routine is not intended to be used when using
IP_DTASK_Task() instead.
For best performance the IP_DTASK_* API should be called with
a task priority higher than any other IP stack related
application task and even the IP_Task() or its API alternatives
IP_TASK_Init(), IP_TASK_Exec() and IP_TASK_WaitForEvent() .
IP_DTASK_WaitForEvent()
Description
Waits for an event for the DriverTask to be signaled.
Prototype
unsigned IP_DTASK_WaitForEvent(unsigned Timeout);
Parameters
Parameter | Description |
Timeout | Timeout [ms] to wait for an event. 0 for INFINITE . |
Return value
= 0 | An event was signaled. |
≠ 0 | Timeout. |
Additional information
This routine is an alternative to using the IP_DTASK_Task() .
It allows finer control over the internal steps done in
IP_DTASK_Task() . This can be utilized for example to feed a
watchdog from the same task periodically.
Note
This routine is not intended to be used when using
IP_DTASK_Task() instead.
For best performance the IP_DTASK_* API should be called with
a task priority higher than any other IP stack related
application task and even the IP_Task() or its API alternatives
IP_TASK_Init(), IP_TASK_Exec() and IP_TASK_WaitForEvent() .
IP_WIFI_Scan()
Description
Scans for available wireless networks.
Prototype
int IP_WIFI_Scan( unsigned IFaceId,
U32 Timeout,
IP_WIFI_pfScanResult pf,
const char * sSSID,
U8 Channel);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Timeout | Timeout before aborting the scan [ms]. |
pf | Callback to be used for each single result. |
sSSID | SSID to find. May be NULL to scan all available networks. |
Channel | Selected channel to scan. 0 means all channels. |
Return value
Additional information
If an SSID to find has been set the result callback will report
the connection parameters only for the selected SSID.
Without a given SSID a list of available networks and their
parameters will be returned.
A network scan means that the module needs to set one of its
antennas into monitoring mode, listening for beacon frames with
SSIDs regularly sent by Access Points.
If a module has only one antenna, a scan might not be possible
while being connected, typically also returning an error for this
API call.
IP_WIFI_Security2String()
Description
Converts the numeric security value to a readable text.
Prototype
char *IP_WIFI_Security2String(U8 Security);
Parameters
Parameter | Description |
Security | Numeric security value. |
Return value
Pointer to string of the security.
IP_DTASK_Signal()
Description
Signals the Driver Task to poll the handler routine of the driver.
Prototype
void IP_DTASK_Signal(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Data structures
Structure IP_WIFI_CONNECT_PARAMS
Description
Used to configure parameters for connecting to an Access Point or starting your own Access Point.
Prototype
typedef struct {
const char* sSSID;
const char* sWPAPass;
const IP_WIFI_WEP_KEY* paWEPKey;
U8 abBSSID[6];
U8 NumWEPKeys;
U8 WEPActiveKeyIndex;
U8 Mode;
U8 Security;
U8 Channel;
} IP_WIFI_CONNECT_PARAMS;
Member | Description |
sSSID | SSID to connect to or to open when in Access point mode. |
sWPAPass | WPA(2) passphrase to use. |
paWEPKey | Array of pointers to binary WEP keys. |
abBSSID | HW address of the access point to connect to. |
NumWEPKeys | Number of WEP keys configured in paWEPKey. |
WEPActiveKeyIndex | 0..3: Index of WEP key to be used for sending, typically index 0 . |
Mode | IP_WIFI_MODE_INFRASTRUCTURE or IP_WIFI_MODE_ACCESS_POINT (if supported by the driver and moodule). |
Security | Security used or security to use if we are starting an Access Point.
IP_WIFI_SECURITY_OPEN or IP_WIFI_SECURITY_WEP_OPEN or IP_WIFI_SECURITY_WEP_SHARED or IP_WIFI_SECURITY_WPA_TKIP or IP_WIFI_SECURITY_WPA_AES or IP_WIFI_SECURITY_WPA_WPA2_MIXED or IP_WIFI_SECURITY_WPA2_AES. |
Channel | Channel to use for connect or starting an Access Point. When connecting 0 means any. |
Network interface drivers
emNet has been designed to cooperate with any kind of hardware. To use specific
hardware with emNet, a so-called network interface driver for that hardware is
required. The network interface driver consists of basic functions for accessing the
hardware and a global table that holds pointers to these functions.
To use emNet, a network interface driver matching the target hardware is
required. The code size of a network interface driver depends on the hardware and is
typically between 1 and 3 kBytes. The driver handles both the MAC (media access
control) unit as well as the PHY (Physical interface). We recommend using drivers
written and tested by SEGGER. However, it is possible to write your own driver. This
is explained in section Writing your own driver.
The driver interface has been designed to allow support of internal and external
Ethernet controllers (EMACs). It also allows to take full advantage of hardware features
such as MAC address filtering and checksum computation in hardware.
MAC address filtering
The stack passes a list of MAC addresses to the driver. The driver is responsible for
making sure that all packets from all MAC addresses specified are passed to the
stack. It can do so with “precise filtering” if the hardware has sufficient filters for the
given number of MAC addresses. If more MAC addresses are passed to the driver
than hardware filters are available, the driver can use a hash filter if available in
hardware or switch to promiscuous mode.
This is a very flexible solution which allows making best use of the hardware filtering
capabilities on all known Ethernet controllers. It also allows simple implementations
to simply switch to promiscuous mode.
Checksum computation in hardware
When the interface is initialized, the stack queries the capabilities of the driver. If the
hardware can compute IP, TCP, UDP, ICMP checksums, it can indicates this to the
stack. In this case, the stack does not compute these checksums, improving throughput
and reducing CPU load.
Ethernet CRC computation
Every Ethernet packet includes a 32-bit trailing CRC. In most cases, the Ethernet
controller is capable of computing the CRC. The drivers take advantage of this. The
CRC is computed in the driver only if the hardware does not support CRC computation.
Available network interface drivers
Network interface drivers are optional components to emNet.
Network interface drivers are already available for popular hardware and a list could be found on our website
.
Configuring the driver
The interface with the corresponding driver should be added to the configuration function
IP_X_Config() with a call to IP_AddEtherInterface().
Depending on the hardware, it could be needed to configure the PHY mode for RMII with
IP_NI_ConfigPHYMode(). As the default configuration is MII, the call is optional
and requested only to use RMII.
Some drivers provides also configuration functions, for example to configure the number
of buffer used, specify registers base address, …
BSP configuration
Drivers are calling BSP function in order to configure hardware access:
- Old driver are using functions like BSP_ETH_Init() and BSP_ETH_InstallISR()
which are implemented in BSP.c.
- New and updated drivers are using the structure BSP_IP_API implemented
in BSP_IP.c. See Structure BSP_IP_API for more details. This structure
needs to be set as BSP access API with the function IP_BSP_SetAPI().
Driver configuration example
The following code is an excerpt of IP_X_Config(). Reference to IP_X_Config for a complete example.
IFaceId = IP_AddEtherInterface(DRIVER); // Add driver for your hardware.
IP_BSP_SetAPI(IFaceId, &BSP_IP_Api); // Set BSP callbacks for hardware access.
IP_SetHWAddrEx(IFaceId, (const U8*)HW_ADDR, 6); // MAC addr.: Needs to be unique.
IP_NI_ConfigPHYMode(IFaceId, 1); // Configure PHY Mode: 0: MII, 1: RMII .
Writing your own driver
If you are going to use emNet with your own hardware, you may have to write
your own network interface driver. This section describes which functions are
required and how to integrate your own network interface driver into emNet.
Note: We strongly recommend contacting SEGGER if you need to have a driver
for a particular piece of hardware which is not yet supported. Writing a driver is a
difficult task which requires a thorough understanding of Ethernet, MAC, and PHY.
Network interface driver structure
emNet uses a simple structure with function pointers to call the appropriate
driver function for a device. Use the supplied template IP_NI_Template.c for the
implementation.
Data structure
typedef struct {
int (*pfInit) (unsigned Unit);
int (*pfSendPacket) (unsigned Unit);
int (*pfGetPacketSize) (unsigned Unit);
int (*pfReadPacket) (unsigned Unit, U8 * pDest, unsigned NumBytes);
void (*pfTimer) (unsigned Unit);
int (*pfControl) (unsigned Unit, int Cmd, void * p);
void (*pfEnDisableRxInt) (unsigned Unit, unsigned OnOff);
} IP_HW_DRIVER;
Elements of IP_HW_DRIVER
Element | Meaning |
pfInit | Pointer to the initialization function. |
pfSendPacket | Pointer to the send packet function. |
pfGetPacketSize | Pointer to the get packet size function. |
pfReadPacket | Pointer to the read packet function. |
pfTimer | Optional: Pointer to the timer function.
The routine is called from the stack periodically |
pfControl | Pointer to the control function. |
pfEnDisableRxInt | Optional: Pointer to enable/disable Rx interrupts. |
Example
/* Sample implementation taken from the driver for FREESCALE Kinetis */
/*********************************************************************
*
* Driver API Table
*
**********************************************************************
*/
const IP_HW_DRIVER IP_Driver_Kinetis = {
_Init,
_SendPacketIfTxIdle,
_GetPacketSize,
_ReadPacket,
_Timer,
_Control,
_EnDisableRxInt
};
Device driver functions
This section provides descriptions of the network interface driver functions required
by emNet. Note that the names used for these functions are not really relevant
for emNet because the stack accesses them through a structure of function pointers.
Function | Description |
_Init() | General initialization function of the driver. |
_SendPacketIfTxIdle() | Send the next packet in the send queue if transmitter is idle. |
_GetPacketSize() | Reads buffer descriptors to find out if a packet has been received. |
_ReadPacket() | Reads the first packet in the buffer. |
_Timer() | Timer function called by the networking task, IP_Task(), once per second. |
_Control() | This function is used to implement additional driver specific control functions.
It can be empty. |
_EnDisableRxInt() | Utility function to enable or disable receive interrupts. It can be empty. |
Driver template
The driver template IP_NI_TEMPLATE.c is supplied in the folder Sample\IP\Driver\Template\.
Example
/*********************************************************************
* (c) SEGGER Microcontroller GmbH & Co. KG *
* The Embedded Experts *
* www.segger.com *
**********************************************************************
-------------------------- END-OF-HEADER -----------------------------
File : IP_NI_TEMPLATE.c
Purpose : Network interface driver template.
*/
#include "IP_Int.h"
#include "IP_NI_TEMPLATE.h"
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
//None
/*********************************************************************
*
* Defines, fixed
*
**********************************************************************
*/
#define MAC_ISR_STATUS (*(volatile U32*)(0x00000000))
#define MAC_ISR_STATUS_RX_MASK (1uL << 0)
#define MAC_ISR_STATUS_TX_MASK (1uL << 1)
/*********************************************************************
*
* Types, local
*
**********************************************************************
*/
#if IP_DEBUG
typedef struct {
U32 TxSendCnt;
U32 TxIntCnt;
U32 TxErrCnt;
U32 RxIntCnt;
U32 RxCnt;
U32 RxErrCnt;
} IP_NI_STATS;
#define INC(Cnt) _Stats.Cnt++
#else
#define INC(Cnt)
#endif
/*********************************************************************
*
* Prototypes
*
**********************************************************************
*/
static unsigned _PHY_ReadReg (IP_PHY_CONTEXT* pContext, unsigned RegIndex);
static void _PHY_WriteReg(IP_PHY_CONTEXT* pContext, unsigned RegIndex, unsigned v);
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
static const IP_PHY_ACCESS _PHY_Access = {
_PHY_ReadReg, // pfRead
_PHY_WriteReg // pfWrite
};
static const IP_PHY_DRIVER* _pPHY_Driver = &IP_PHY_Generic; // Use generic PHY driver as default.
static IP_PHY_CONTEXT _PHY_Context;
static IP_NI_STATS _Stats;
static char _TxIsBusy;
static char _IsInited;
/*********************************************************************
*
* Local functions
*
**********************************************************************
*/
/*********************************************************************
*
* _PHY_ReadReg()
*
* Function description
* Reads from a PHY register.
*
* Parameters
* pContext: Pointer to PHY context of IP_PHY_CONTEXT .
* RegIndex: Register index to access.
*
* Return value
* Data read from PHY.
*/
static unsigned _PHY_ReadReg(IP_PHY_CONTEXT* pContext, unsigned RegIndex) {
unsigned Addr;
unsigned v;
Addr = pContext->Addr;
IP_USE_PARA(Addr);
IP_USE_PARA(RegIndex);
//
// Read data from PHY.
//
v = 0;
return v;
}
/*********************************************************************
*
* _PHY_WriteReg()
*
* Function description
* Writes to a PHY register.
*
* Parameters
* pContext: Pointer to PHY context of IP_PHY_CONTEXT .
* RegIndex: Register index to access.
* v : Data to write to register.
*/
static void _PHY_WriteReg(IP_PHY_CONTEXT* pContext, unsigned RegIndex, unsigned v) {
unsigned Addr;
Addr = pContext->Addr;
IP_USE_PARA(Addr);
IP_USE_PARA(RegIndex);
//
// Write data to PHY.
//
IP_USE_PARA(v);
}
/*********************************************************************
*
* _SetFilter()
*
* Function description
* Sets the MAC filter(s).
* The stack tells the driver which addresses should go through
* the filter. The number of addresses can generally be unlimited.
* In most cases, only one address is set.
* However, if the NI is in multiple nets at the same time or if
* multicast is used, multiple addresses can be set.
*
* Parameters
* pFilter: Filters to set.
*
* Return value
* == 0: O.K.
*
* Additional information
* In general, precise filtering is used as far as supported by
* the hardware. If more addresses need to be filtered than
* precise address filters are available, then a hash filter
* should be used. Alternatively the MAC can be switched to
* promiscuous mode for simple implementations.
*/
static int _SetFilter(IP_NI_CMD_SET_FILTER_DATA* pFilter) {
const U8* pAddrData; // Pointer to 6 byte filter addresses.
unsigned u;
unsigned NumAddr;
NumAddr = pFilter->NumAddr;
pAddrData = pFilter->pHWAddr;
for (u = 0; u < NumAddr; u++) {
//
// Set filter.
//
pAddrData += 6; // Proceed to next filter addr.
}
IP_USE_PARA(pAddrData);
return 0; // O.K.
}
/*********************************************************************
*
* _UpdateMACSettings()
*
* Function description
* Updates the speed & duplex settings of the MAC.
* Needs to be called whenever speed and duplex settings change.
*
* Parameters
* Duplex : Duplex configuration to set:
* * IP_DUPLEX_UNKNOWN
* * IP_DUPLEX_HALF
* * IP_DUPLEX_FULL
* Speed : Speed configuration to set:
* * IP_SPEED_UNKNOWN
* * IP_SPEED_10MHZ
* * IP_SPEED_100MHZ
* * IP_SPEED_1GHZ
*/
static void _UpdateMACSettings(U32 Duplex, U32 Speed) {
IP_USE_PARA(Duplex);
IP_USE_PARA(Speed);
//
// Update MAC configuration.
//
}
/*********************************************************************
*
* _UpdateLinkState()
*
* Function description
* Reads link state information from PHY and updates MAC if
* necessary. Should be called regularly to make sure that the
* MAC is notified if the link changes.
*/
static void _UpdateLinkState(void) {
U32 Duplex;
U32 Speed;
_pPHY_Driver->pfGetLinkState(&_PHY_Context, &Duplex, &Speed);
if (IP_NI_SetLinkState(0, Duplex, Speed)) { // Notify interface #0 about the current settings. Return value indicates if there was a change from the last settings.
_UpdateMACSettings(Duplex, Speed); // Reconfigure the MAC if the settings are confirmed to be different.
}
}
/*********************************************************************
*
* _SendPacket()
*
* Function description
* Sends the next packet in the Tx FIFO.
* Function is called from a task via function pointer in driver
* API table or from Tx-interrupt. Locking is done using TxIsBusy.
*/
static void _SendPacket(void) {
void* pPacket; // Pointer to raw packet data to send.
unsigned NumBytes; // Size of raw packet data to send.
//
// Check if we can send more.
//
NumBytes = IP_GetNextOutPacketFast(&pPacket);
if (NumBytes == 0) { // No more packets to send ?
_TxIsBusy = 0; // Unlock TxIsBusy to allow sending from task.
return;
}
IP_LOG((IP_MTYPE_DRIVER, "DRIVER: Sending packet: %d bytes", NumBytes));
INC(TxSendCnt);
//
// Send packet.
//
IP_USE_PARA(pPacket);
}
/*********************************************************************
*
* _ISR_Handler
*
* Function description
* This is the interrupt service routine for the NI (MAC).
* It handles all interrupts (Rx, Tx, Error).
*/
static void _ISR_Handler(void) {
U32 v;
v = 0; // Dummy status for this sample. Interrupt without any flags should never occur.
//
// Read interrupt status.
//
v = MAC_ISR_STATUS; // Read interrupt status.
MAC_ISR_STATUS = v; // Clear flags if interrupts are write-to-clear.
//
// Handle Rx.
//
if (v & MAC_ISR_STATUS_RX_MASK) {
INC(RxIntCnt);
IP_OnRx();
}
//
// Handle Tx.
//
if (v & MAC_ISR_STATUS_TX_MASK) {
INC(TxIntCnt);
if (_TxIsBusy) {
IP_RemoveOutPacket(); // Remove last sent packet from FIFO.
_SendPacket(); // Try to send more.
} else {
IP_WARN_INTERNAL((IP_MTYPE_DRIVER, "DRIVER: Tx complete interrupt, but no packet sent."));
}
}
}
/*********************************************************************
*
* _cbInit()
*
* Function description
* General initialization function of the driver.
* Called by the stack in the initialization phase, typically
* before any other driver function.
* Function is called from a task via function pointer in Driver
* API table.
*
* Parameters
* IFaceId : Zero-based interface index.
*
* Return value
* == 0: O.K.
* != 0: Error.
*/
static int _cbInit(unsigned IFaceId) {
BSP_IP_INSTALL_ISR_PARA ISRPara;
//
// Initialize port pins.
//
IP_BSP_Init(IFaceId);
//
// Setup either MII (default) or RMII mode if MAC needs to know.
//
if (_PHY_Context.UseRMII != 0) {
//
// Set to RMII mode.
//
} else {
//
// Set to MII mode.
//
}
//
// Init PHY and update link state.
//
_pPHY_Driver->pfInit(&_PHY_Context);
_UpdateLinkState();
//
// Set ISR routine.
//
IP_MEMSET(&ISRPara, 0, sizeof(ISRPara));
ISRPara.pfISR = _ISR_Handler;
IP_BSP_InstallISR(IFaceId, &ISRPara);
//
// Init and configure the MAC and start Rx & Tx.
//
_IsInited = 1;
return 0; // O.K.
}
/*********************************************************************
*
* _cbSendPacketFromTask()
*
* Function description
* Sends the next packet in the Tx FIFO. Called from a task
* via function pointer in Driver API table.
*
* Parameters
* IFaceId: Zero-based interface index.
*
* Return value
* == 0: O.K.
* != 0: Error.
*/
static int _cbSendPacketFromTask(unsigned IFaceId) {
IP_USE_PARA(IFaceId);
if (_TxIsBusy == 0) { // Allowed to send from task ?
_TxIsBusy = 1; // Further send operations will be done via ISR.
_SendPacket();
}
return 0; // O.K.
}
/*********************************************************************
*
* _cbGetPacketSize()
*
* Function description
* Reads buffer descriptors in order to find out if a packet has
* been received. Different error conditions are checked and
* handled. Function is called from a task via function pointer
* in Driver API table if IP_RxTask is running or directly from
* the Rx ISR.
*
* Parameters
* IFaceId: Zero-based interface index.
*
* Return value
* > 0: Required size for packet buffer to store the received data.
* == 0: No further received.
*/
static int _cbGetPacketSize(unsigned IFaceId) {
IP_USE_PARA(IFaceId);
//
// Check for size of next frame received and return
// its size or 0 in case there is no next frame.
//
return 0;
}
/*********************************************************************
*
* _cbReadPacket()
*
* Function description
* Reads one frame received into a packet buffer.
* NumBytes is the number of bytes as retrieved by _cbGetPacketSize().
* Function is called from a task via function pointer in Driver
* API table.
*
* Parameters
* IFaceId : Zero-based interface index.
* pDest : Pointer to buffer where to copy the packet content. Can
* be NULL which means discard data.
* NumBytes: Number of bytes to copy from received packet.
*
* Return value
* == 0: O.K.
* != 0: Error.
*/
static int _cbReadPacket(unsigned IFaceId, U8* pDest, unsigned NumBytes) {
IP_USE_PARA(IFaceId);
INC(RxCnt);
if (pDest != NULL) { // Copy data into packet buffer ?
IP_LOG((IP_MTYPE_DRIVER, "Packet: %d Bytes --- Read.", NumBytes));
} else { // No free packet buffer, discard data.
IP_LOG((IP_MTYPE_DRIVER, "Packet: %d Bytes --- Discarded.", NumBytes));
}
return 0; // O.K.
}
/*********************************************************************
*
* _cbTimer()
*
* Function description
* Timer function called by the IP_Task once per second.
* Function is called from a task via function pointer in Driver
* API table.
*
* Parameters
* IFaceId: Zero-based interface index.
*/
static void _cbTimer(unsigned IFaceId) {
IP_USE_PARA(IFaceId);
_UpdateLinkState();
}
/*********************************************************************
*
* _GetCaps()
*
* Function description
* Fills a structure with information about the capabilities
* like number of supported precise filters, support of
* hash filtering, support of promiscuous mode.
*
* Parameters
* pCaps: Pointer to an element of type IP_NI_CMD_GET_CAPS_EX_DATA .
*
* Return value
* == 0: O.K.
*/
static int _GetCaps (IP_NI_CMD_GET_CAPS_EX_DATA* pCaps) {
// pCaps->NumPreciseFilter = 1; // Number of supported precise filters.
// pCaps->HasHashFilter = 1; // Hash filter supported? 0: Not supported, 1: Supported.
// pCaps->HasPromiscuousMode = 1; // Promiscuous mode supported? 0: Not supported, 1: Supported.
// pCaps->PacketDataShiftCnt = 0; // ShiftCnt for ideal packet data alignment. Could avoid a memcpy into an extra buffer that is aligned.
IP_USE_PARA(pCaps);
return 0;
}
/*********************************************************************
*
* _cbControl()
*
* Function description
* This routine allows extending the function table dynamically for
* several operations.
*
* Parameters
* IFaceId: Zero-based interface index.
* Cmd : Command to execute. Most common commands are:
* * IP_NI_CMD_SET_FILTER
* * IP_NI_CMD_GET_CAPS
* * IP_NI_CMD_SET_PHY_ADDR
* * IP_NI_CMD_SET_PHY_MODE
* * IP_NI_CMD_POLL
* * IP_NI_CMD_SET_SUPPORTED_DUPLEX_MODES
* * IP_NI_CMD_GET_CAPS_EX
* p : Pointer to data processed by command.
*
* Return value
* >= 0: O.K.
* == -1: Error or command not supported.
*/
static int _cbControl(unsigned IFaceId, int Cmd, void* p) {
int r;
IP_USE_PARA(IFaceId);
r = -1; // Assume command is not supported.
switch (Cmd) {
case IP_NI_CMD_SET_FILTER:
r = _SetFilter((IP_NI_CMD_SET_FILTER_DATA*)p);
break;
case IP_NI_CMD_GET_CAPS:
r = 0
// | IP_NI_CAPS_WRITE_IP_CHKSUM // Driver capable of inserting the IP-checksum into an outgoing packet ?
// | IP_NI_CAPS_WRITE_UDP_CHKSUM // Driver capable of inserting the UDP-checksum into an outgoing packet ?
// | IP_NI_CAPS_WRITE_TCP_CHKSUM // Driver capable of inserting the TCP-checksum into an outgoing packet ?
// | IP_NI_CAPS_WRITE_ICMP_CHKSUM // Driver capable of inserting the ICMP-checksum into an outgoing packet ?
// | IP_NI_CAPS_CHECK_IP_CHKSUM // Driver capable of computing and comparing the IP-checksum of an incoming packet ?
// | IP_NI_CAPS_CHECK_UDP_CHKSUM // Driver capable of computing and comparing the UDP-checksum of an incoming packet ?
// | IP_NI_CAPS_CHECK_TCP_CHKSUM // Driver capable of computing and comparing the TCP-checksum of an incoming packet ?
// | IP_NI_CAPS_CHECK_ICMP_CHKSUM // Driver capable of computing and comparing the ICMP-checksum of an incoming packet ?
// | IP_NI_CAPS_WRITE_ICMPV6_CHKSUM // Driver capable of inserting the ICMP-checksum into an outgoing packet ?
;
break;
case IP_NI_CMD_SET_PHY_ADDR:
if (_IsInited != 0) {
break;
}
_PHY_Context.Addr = (U8)(int)p;
r = 0; // O.K.
break;
case IP_NI_CMD_SET_PHY_MODE:
if (_IsInited != 0) {
break;
}
_PHY_Context.UseRMII = (U8)(int)p;
r = 0; // O.K.
break;
case IP_NI_CMD_POLL:
//
// Poll MAC (typically once per ms) in cases where MAC does not trigger an interrupt.
//
_ISR_Handler();
break;
case IP_NI_CMD_SET_SUPPORTED_DUPLEX_MODES:
if (_IsInited != 0) {
break;
}
_PHY_Context.SupportedModes = (U16)(int)p;
r = 0; // O.K.
break;
#if IP_ALLOW_DEINIT
case IP_NI_CMD_DEINIT:
//
// Stop Rx & Tx.
// Make sure that the Rx & Tx interrupts are disabled.
// De-initialize the MAC.
//
IP_BSP_DeInit(IFaceId);
r = 0; // O.K.
break;
#endif
case IP_NI_CMD_GET_CAPS_EX:
r = _GetCaps((IP_NI_CMD_GET_CAPS_EX_DATA*)p);
break;
}
return r;
}
/*********************************************************************
*
* Global functions
*
**********************************************************************
*/
//None
/*********************************************************************
*
* Driver API Table
*
**********************************************************************
*/
const IP_HW_DRIVER IP_Driver_Template = {
_cbInit, // pfInit
_cbSendPacketFromTask, // pfSendPacket
_cbGetPacketSize, // pfGetPacketSize
_cbReadPacket, // pfReadPacket
_cbTimer, // pfTimer
_cbControl, // pfControl
NULL // pfEnDisableRxInt
};
/*************************** End of file ****************************/
PHY drivers
emNet has been designed to cooperate with any kind of hardware. Typically
almost any PHY is compatible with the emNet generic PHY driver as almost all
standard PHYs are compliant to the IEEE 802.3u standard which also defines the first
6 standard registers and their bits that are used by the generic PHY driver. However
there are some PHYs that might require additional setup or do not comply with IEEE
802.3u as it is expected by the generic PHY driver. To use them, a so-called PHY
driver for that hardware is required that is aware of how the specific PHY can be
accessed.
To use emNet with a PHY that can not be used with the generic PHY driver, a specific
PHY driver matching the target hardware is required. The code size of a PHY
driver depends on the hardware but is typically only requires a couple of hundred
bytes.
The PHY driver interface has been designed to allow support of generic features like
checking the link state as well as being able to extend each specific driver with
unique features only available for a specific hardware.
When is a specific PHY driver required?
A specific PHY driver is typically not required for any standard PHY on the market.
However it might be required for the following reasons:
- The PHY registers do not (fully) comply with the IEEE 802.3u standard for the six
first registers.
- The PHY requires additional setup that can not be provided using the reset hook
of the generic PHY driver.
- A PHY or (managed) Switch PHY shall be used that includes multiple PHYs that
shall be treated like autonomous PHYs for link checking on each port.
- Any other special solution that simply can not be covered by a generic PHY driver.
Available PHY drivers
emNet comes with a generic PHY driver that fits virtually any standard single port
PHY that is on the market. PHY drivers for devices that are not compatible to the
IEEE 802.3u standard, require additional setup or special solutions are optional components
to emNet.
The following PHY drivers are available and described in detail with their API:
To add a PHY driver to emNet, IP_PHY_AddDriver() should be called from within
IP_X_Config() with the proper identifier. Refer to IP_PHY_AddDriver
for detailed information.
Generic driver
The emNet generic PHY driver fits virtually any standard single port PHY that
complies with the IEEE 802.3u standard and is the default driver that comes with
emNet and is used when no other PHY driver is added for an interface that
requires PHY support.
Warning
Even if a PHY complies with the IEEE 802.3u standard it might require additional handling that can not be provided by the generic PHY driver and therefore might require a specific PHY driver in this case.
Resource usage
The following resource usage has been measured on a Cortex-M4 system using
SEGGER Embedded Studio V2.12, size optimization.
ROM | RAM |
approximately 0.8KBytes | 0K Bytes |
All required RAM is taken from the RAM that has been assigned to emNet using
IP_AddMemory(). Only a few bytes are required.
Generic PHY driver API functions
The table below lists the available API functions for this driver:
IP_PHY_GENERIC_RemapAccess()
Description
This function allows remapping the access routines of a PHY
interface. An example would be to use the access routines of
interface #0 for interface #1 as well.
Prototype
void IP_PHY_GENERIC_RemapAccess(unsigned IFaceId,
unsigned AccessIFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index to assign an access API. |
AccessIFaceId | Zero-based interface index from where to use the access API. |
Additional information
The purpose to use the same MDIO interface for multiple PHY
interfaces is that there are dual PHYs out there like the
TI DP83849I that use only one MDIO interface and address their
internal dual PHY via the PHY addr.
It is only possible to remap from an already initialized
interface to a new one which means AccessIFaceId needs to be
higher than IFaceId.
Micrel Switch PHY driver
Due to the nature of a Switch PHY it contains multiple ports that can not be handled
in a generic way. Therefore a driver that is aware of the specific hardware is required.
The emNet PHY driver for Micrel Switch PHYs supports automatically starting the
Switch engine (autostart is disabled if used with a management interface like SMI or
SPI) and allows further specific configuration for various purposes.
Supported devices
The following is a list of supported devices and their labels:
PHY driver | Identifier |
KSZ8794 | IP_PHY_Driver_Micrel_Switch_KSZ8794[_HostPort] |
KSZ8863 | IP_PHY_Driver_Micrel_Switch_KSZ8863[_HostPort] |
KSZ8895 | IP_PHY_Driver_Micrel_Switch_KSZ8895[_HostPort] |
Resource usage
The following resource usage has been measured on a Cortex-M4 system using
SEGGER Embedded Studio V2.12, size optimization.
ROM | RAM |
approximately 0.2KBytes | 0K Bytes |
All required RAM is taken from the RAM that has been assigned to emNet using
IP_AddMemory(). Only a few bytes are required.
Micrel Switch PHY driver API functions
The table below lists the available API functions for this driver:
IP_PHY_MICREL_SWITCH_AssignPortNumber()
Description
This function assigns the physical switch port number to an
interface.
Prototype
void IP_PHY_MICREL_SWITCH_AssignPortNumber(unsigned IFaceId,
unsigned Port);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Port | Zero-based physical port number on the switch. |
IP_PHY_MICREL_SWITCH_ConfigLearnDisable()
Description
This function can set the learn disable config for a specific
port to enabled/disabled.
Prototype
void IP_PHY_MICREL_SWITCH_ConfigLearnDisable(unsigned IFaceId,
unsigned OnOff);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
OnOff | 0: Switch addr. learning for the port enabled. 1: Switch addr. learning for the port disabled. |
IP_PHY_MICREL_SWITCH_ConfigRxEnable()
Description
This function can set Rx (network to switch) for a specific port
to enabled/disabled.
Prototype
void IP_PHY_MICREL_SWITCH_ConfigRxEnable(unsigned IFaceId,
unsigned OnOff);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
OnOff | 0: Rx for the port disabled. 1: Rx for the port enabled. |
IP_PHY_MICREL_SWITCH_ConfigTailTagging()
Description
This function switches Tail Tagging on/off.
Prototype
void IP_PHY_MICREL_SWITCH_ConfigTailTagging(unsigned IFaceId,
unsigned OnOff);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
OnOff | 0: Tail Tagging off. 1: Tail Tagging on. |
Additional information
Needs to be used with the interface of the host port of the switch.
It is enough to set it for one port of the switch as the bit to
change is in a register that is shared between all ports.
Tail Tagging needs to be supported by the stack as well and a Tail
Tagging aware interface has to be added to the stack.
IP_PHY_MICREL_SWITCH_ConfigTxEnable()
Description
This function can set Tx (switch to network) for a specific port
to enabled/disabled.
Prototype
void IP_PHY_MICREL_SWITCH_ConfigTxEnable(unsigned IFaceId,
unsigned OnOff);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
OnOff | 0: Tx for the port disabled. 1: Tx for the port enabled. |
IP_PHY_MICREL_SWITCH_ConfigUseInternalRmiiClock()
Description
This function selects the clock source for the RMII host port.
The default is to use the externally provided clock.
Prototype
void IP_PHY_MICREL_SWITCH_ConfigUseInternalRmiiClock(unsigned IFaceId,
unsigned OnOff);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
OnOff | 0: Use external clock. 1: Use internal clock. |
Additional information
This setting is only relevant for parts that allow a clock selection.
The correct clock selection depends on the hardware layout.
Details can be found in the datasheet of the switch e.g. in
a chapter called “RMII INTERFACE OPERATION” for the KSZ8863 .
Marvell 88E1111 Fiber PHY driver
Although the the Marvell 88E1111 PHY in copper mode is supported out of the box by
the Generic driver, this PHY supports a Fiber mode as well. The Fiber
mode requires a different handling and therefore requires a separate driver to handle
this mode.
Resource usage
The following resource usage has been measured on a Cortex-M4 system using
SEGGER Embedded Studio V2.12, size optimization.
ROM | RAM |
approximately 0.8 kBytes | 0K Bytes |
All required RAM is taken from the RAM that has been assigned to emNet using
IP_AddMemory(). Only a few bytes are required.
WiFi drivers
emNet allows to easily add WiFi (IEEE 802.11) support to your project. Using one
of the supported WiFi modules and available driver for it allows a WiFi interface to be
added in nearly the same easy way as adding any other emNet interface.
As almost each WiFi module uses a different API and a more or less complete documentation
of it, integration can become very time consuming. The emNet WiFi
drivers provide an unified API to different WiFi modules that allows an easy integration
into your project in short time.
This chapter lists drivers that require special configuration or come with their own
extended API that allows a configuration beyond the regular emNet API.
There are two different types of WiFi drivers used with emNet:
- Network Interface WiFi drivers
- WiFi PHY bridges
Both types make use of the same API for your application but a re different in their
how they provide WiFi support in terms of their hardware.
Network Interface WiFi drivers
The typical form of an emNet WiFi driver is used in the same way as a regular
Network Interface (NI) driver. It basically works like an external Ethernet controller,
typically using communication via a peripheral interface like SPI. Other common
interfaces used are I2C, UART or SDIO.
To the stack itself this is just another interface that is added like it would be for an
integrated or external Ethernet controller.
Using a free peripheral interface this solution can not only be used to build a new
hardware but can be used to upgrade existing solutions with WiFi as well.
While providing WiFi support by the simple usage of a peripheral interface like SPI,
often an SDK of the WiFi module vendor is required for communication with the module
using vendor specific commands. In some cases using the WiFi modules of a vendor
is even prohibited without the vendor SDK.
This type of driver is added to the stack like a regular driver by calling
IP_WIFI_AddInterface().
WiFi PHY bridges
Some WiFi solutions offer to convert a regular Ethernet device into a WiFi solution by
providing a bridge device. For a regular cable based setup a copper cable PHY would
be connected to the Ethernet MAC of the MCU (or an external MAC). Instead of the
copper cable PHY a WiFi bridge can be connected, replacing the PHY. These devices
are providing a so-called MAC(of the MCU)-to-MAC(of the WiFi module) mode and are
interfaced via (R)MII the same way as a regular PHY would be.
Ethernet communication takes place using (R)MII and therefore requires an Ethernet
MAC to be present. A second configuration interface like SPI or UART is required as
well as (R)MII is used for Ethernet data only.
Using this solution an existing design can be converted to a WiFi solution by basically
exchanging the PHY. The separation of the Ethernet data and configuration has the
chance to reach higher transfer speeds than a single unidirectional interface handling
Ethernet and configuration at the same time.
Like any other PHY driver an Ethernet controller and its driver is still required. This
means that first an Ethernet driver has to be added calling IP_AddEtherInterface()
and then the driver of the WiFi PHY bridge has to be added and assigned to
this interface by calling IP_PHY_AddDriver().
List of special WiFi drivers
Several WiFi drivers are available for emNet to provide an unified emNet WiFi
API to the vendor specific API. The vendor specific API is different between vendors
and might even be different for modules from the same vendor. In general all drivers
are added to the stack in the same way:
To add a WiFi driver to emNet, IP_WIFI_AddInterface() should be
called from within IP_X_Config() with the proper identifier.
To add a WiFi PHY bridge driver to emNet, IP_PHY_AddDriver() on page 132
should be called from within IP_X_Config() with the proper identifier.
Depending on the module and driver they might require additional configuration or
provide additional features. These additional configuration functions are listed here.
The following WiFi drivers are described in detail with their API:
ConnectOne IW
The emNet ConnectOne IW driver supports all WiFi<->LAN bridges sharing the
same AT+i command set which basically are all WiFi modules named “iW-*” using the
CO2144 or the older CO2128 core CPU.
Hardware access abstraction
The ConnectOne IW driver requires a hardware access API to be passed to
IP_PHY_AddDriver() to send/receive configuration data via SPI or UART.
A sample for a SPI connection is shipped with the driver as reference implementation.
typedef struct {
void (*pfHWReset) (unsigned IFaceId);
int (*pfSendATCommand)(unsigned IFaceId, U32 Timeout, const char* sCmd);
int (*pfClrBuf) (unsigned IFaceId, U32 Timeout, char IgnoreSpiInt);
int (*pfLoadLine) (unsigned IFaceId, U32 Timeout);
int (*pfReadLine) (unsigned IFaceId, U32 Timeout, char* pBuffer,
unsigned BufferSize);
} IP_PHY_WIFI_CONNECTONE_IW_ACCESS;
Member | Description |
pfHWReset | Reset the WiFi module. Shall only return after the module
reset has been successfully asserted and deasserted.
Only used in case of an error. The module shall be manually
hardware reset once during startup. |
pfSendATCommand | Sends the given AT+i command to the module. CR&LF are
included in the string to send. |
pfClrBuf | Reads data from the module until SPI_INT gets deasserted.
If IgnoreSpiInt is set the module could be in an unknown
state after an error and the SPI_INT line might no longer be
reliable. In this case just try to read data for some time to
clear all data left in the module for a fresh start. |
pfLoadLine | Reads in data in chunks as sent by the WiFi module until the
buffer is full or a complete line is in the buffer.
A static buffer is expected to be used to first assemble the
chunks into a complete message. |
pfReadLine | Checks if a complete line is in static buffer and copies it to
the provided buffer. |
ConnectOne IW driver API functions
The table below lists the available API functions for this driver:
IP_PHY_WIFI_CONNECTONE_IW_ConfigSPI()
Description
Sets the SPI_INT port the module uses to signal an event.
Prototype
void IP_PHY_WIFI_CONNECTONE_IW_ConfigSPI(unsigned IFaceId,
char SPIConfig);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
SPIConfig | SPI_INT port configuration as mentioned in the AT+i command documentation. |
Redpine Signals RS9113
The emNet Redpine Signals RS9113 driver supports the RS9113 Connect-io-n and
WiseConnect family and modules compatible.
Redpine Signals RS9113 driver API functions
The table below lists the available API functions for this driver:
IP_NI_WIFI_REDPINE_RS9113_ConfigAntenna()
Description
Selects the internal or external antenna and configures
the gain for 2.4GHz and 5GHz modes.
Prototype
int IP_NI_WIFI_REDPINE_RS9113_ConfigAntenna(unsigned IFaceId,
U8 Antenna,
U8 Gain_24GHz,
U8 Gain_5GHz);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Antenna | 0: Internal antenna 1: External antenna |
Gain_24GHz | 0..10 (according to RS9113 API documentation) |
Gain_5GHz | 0..10 (according to RS9113 API documentation) |
Return value
Additional information
The value that can be configured for the antenna gain is not
explained in detail in the RS9113 API documentation. The values
are passed to the module without modification.
IP_NI_WIFI_REDPINE_RS9113_ConfigRegion()
Description
Selects a world region and allowed channel configuration.
Prototype
int IP_NI_WIFI_REDPINE_RS9113_ConfigRegion(unsigned IFaceId,
U8 Region);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Region | IP_NI_WIFI_REDPINE_RS9113_REGION_AUTO_DETECT IP_NI_WIFI_REDPINE_RS9113_REGION_US IP_NI_WIFI_REDPINE_RS9113_REGION_EUROPE IP_NI_WIFI_REDPINE_RS9113_REGION_JAPAN IP_NI_WIFI_REDPINE_RS9113_REGION_WORLD |
Return value
Additional information
Has to be called during init.
For a list of channels that are enabled for each region, please
refer to the RS9113 API documentation and search for “Region_code”.
IP_NI_WIFI_REDPINE_RS9113_SetAccessPointParameters()
Description
Configures access point parameters. If not called, default
values are used.
Prototype
void IP_NI_WIFI_REDPINE_RS9113_SetAccessPointParameters
( unsigned IFaceId,
const IP_NI_WIFI_RS9113_AP_CONFIG * pParams);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pParams | Pointer to the parameters structure. |
Additional information
For details on the parameters value refer to the RS9113 API
documentation of the function rsi_set_ap_config().
IP_NI_WIFI_REDPINE_RS9113_SetSpiSpeedChangeCallback()
Description
Sets a callback to be executed when the SPI interface can be
used in high speed mode (above 25MHz) or when it is reset due
to a module reset to recover from an error.
Prototype
void IP_NI_WIFI_REDPINE_RS9113_SetSpiSpeedChangeCallback
(unsigned IFaceId,
IP_NI_WIFI_REDPINE_RS9113_pfOnSpiSpeedChange pf);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pf | Callback to execute on a change. |
IP_NI_WIFI_REDPINE_RS9113_SetUpdateCallback()
Description
Sets a callback to be executed during boot that updates the
module firmware.
Prototype
void IP_NI_WIFI_REDPINE_RS9113_SetUpdateCallback
(unsigned IFaceId,
IP_NI_WIFI_REDPINE_RS9113_pfUpdateModule pf);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pf | Callback to execute the update. |
Configuring emNet
emNet can be used without changing any of the compile-time flags. All compile-time
configuration flags are preconfigured with valid values, which match the
requirements of most applications. Network interface drivers can be added at runtime.
The default configuration of emNet can be changed via compile-time flags which
can be added to IP_Conf.h. IP_Conf.h is the main configuration file for the TCP/IP
stack.
Runtime configuration
Every driver folder includes a configuration file with implementations of runtime
configuration functions explained in this chapter. These functions can be customized.
IP_X_Config()
Description
Helper function to prepare and configure the TCP/IP stack.
Prototype
void IP_X_Config(void);
Additional information
This function is called by the startup code of the TCP/IP stack from IP_Init(). Refer
to IP_Init for more information.
Example
/*********************************************************************
* SEGGER MICROCONTROLLER SYSTEME GmbH *
* Solutions for real time microcontroller applications *
**********************************************************************
* *
* (c) 2007 SEGGER Microcontroller Systeme GmbH *
* *
* Internet: www.segger.com Support: support@segger.com *
* *
**********************************************************************
----------------------------------------------------------------------
File : IP_Config_Template_ETH.c
Purpose : Configuration file template
---------------------------END-OF-HEADER------------------------------
*/
#include "IP.h"
#include "IP_NI_TEMPLATE.h"
/*********************************************************************
*
* Configuration
*
**********************************************************************
*/
#define ALLOC_SIZE 0x6000 // Size of memory dedicated to the stack in bytes.
#define DRIVER &IP_Driver_Template // Driver used for target.
#define TARGET_NAME "TARGET" // Target name used for DHCP client.
#define HW_ADDR "\x00\x22\xC7\xFF\xFF\xFF" // MAC addr. used for target.
#define USE_DHCP 1 // Use DHCP client or static IP configuration.
//
// The following parameters are only used when the DHCP client is not active.
//
#define IP_ADDR IP_BYTES2ADDR(192, 168, 2, 252)
#define SUBNET_MASK IP_BYTES2ADDR(255, 255, 255, 0)
#define GW_ADDR IP_BYTES2ADDR(192, 168, 2, 1)
#define DNS_ADDR IP_BYTES2ADDR(192, 168, 2, 1)
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
static U32 _aPool[ALLOC_SIZE / 4]; // This is the memory area used by the stack.
/*********************************************************************
*
* Global functions
*
**********************************************************************
*/
/*********************************************************************
*
* IP_X_Config()
*
* Function description
* This function is called by the IP stack during IP_Init().
*
* Notes
* Typical memory/buffer configurations:
* Microcontroller system, minimum size optimized
* #define ALLOC_SIZE 0x1000 // 4KBytes RAM.
* mtu = 576; // 576 is minimum acc. to RFC, 1500 is max. for Ethernet.
* IP_SetMTU(0, mtu); // Maximum Transmission Unit is 1500 for Ethernet by default.
* IP_AddBuffers(4, 256); // Small buffers.
* IP_AddBuffers(2, mtu + 16); // Big buffers. Size should be mtu + 16 byte for Ethernet header (2 bytes type, 2*6 bytes MAC, 2 bytes padding).
* IP_ConfTCPSpace(2 * (mtu - 40), 1 * (mtu - 40)); // Define the TCP Tx and Rx window size. At least Tx space for 2*(mtu-40) for two full TCP packets is needed.
*
* Microcontroller system, size optimized
* #define ALLOC_SIZE 0x3000 // 12KBytes RAM.
* mtu = 576; // 576 is minimum acc. to RFC, 1500 is max. for Ethernet.
* IP_SetMTU(0, mtu); // Maximum Transmission Unit is 1500 for Ethernet by default.
* IP_AddBuffers(8, 256); // Small buffers.
* IP_AddBuffers(4, mtu + 16); // Big buffers. Size should be mtu + 16 byte for Ethernet header (2 bytes type, 2*6 bytes MAC, 2 bytes padding).
* IP_ConfTCPSpace(2 * (mtu - 40), 2 * (mtu - 40)); // Define the TCP Tx and Rx window size. At least Tx space for 2*(mtu-40) for two full TCP packets is needed.
*
* Microcontroller system, speed optimized or multiple connections
* #define ALLOC_SIZE 0x6000 // 24 KBytes RAM.
* mtu = 1500; // 576 is minimum acc. to RFC, 1500 is max. for Ethernet.
* IP_SetMTU(0, mtu); // Maximum Transmission Unit is 1500 for Ethernet by default.
* IP_AddBuffers(12, 256); // Small buffers.
* IP_AddBuffers(6, mtu + 16); // Big buffers. Size should be mtu + 16 byte for Ethernet header (2 bytes type, 2*6 bytes MAC, 2 bytes padding).
* IP_ConfTCPSpace(3 * (mtu - 40), 3 * (mtu - 40)); // Define the TCP Tx and Rx window size. At least Tx space for 2*(mtu-40) for two full TCP packets is needed.
*
* System with lots of RAM
* #define ALLOC_SIZE 0x20000 // 128 KBytes RAM.
* mtu = 1500; // 576 is minimum acc. to RFC, 1500 is max. for Ethernet.
* IP_SetMTU(0, mtu); // Maximum Transmission Unit is 1500 for Ethernet by default.
* IP_AddBuffers(50, 256); // Small buffers.
* IP_AddBuffers(50, mtu + 16); // Big buffers. Size should be mtu + 16 byte for Ethernet header (2 bytes type, 2*6 bytes MAC, 2 bytes padding).
* IP_ConfTCPSpace(8 * (mtu - 40), 8 * (mtu - 40)); // Define the TCP Tx and Rx window size. At least Tx space for 2*(mtu-40) for two full TCP packets is needed.
*/
void IP_X_Config(void) {
int mtu;
int IFaceId;
IP_AssignMemory(_aPool, sizeof(_aPool)); // Assigning memory should be the first thing.
IFaceId = IP_AddEtherInterface(DRIVER); // Add driver for your hardware.
IP_SetHWAddrEx(IFaceId, (const U8*)HW_ADDR, 6); // MAC addr.: Needs to be unique for production units.
//
// Configure the PHY interface mode (optional):
// - IP_PHY_MODE_MII : MII, typically default if not explicitly configured.
// - IP_PHY_MODE_RMII: RMII
// Can be set/overwritten from BSP_IP pfGetMiiMode() callback.
//
// IP_NI_ConfigPHYMode(IFaceId, IP_PHY_MODE_RMII);
//
// Use DHCP client or define IP address, subnet mask,
// gateway address and DNS server according to the
// requirements of your application.
//
#if USE_DHCP
IP_DHCPC_Activate(IFaceId, TARGET_NAME, NULL, NULL); // Activate DHCP client.
#else
IP_SetAddrMaskEx(IFaceId, IP_ADDR, SUBNET_MASK); // Assign IP addr. and subnet mask.
IP_SetGWAddr(IFaceId, GW_ADDR); // Set gateway addr.
IP_DNS_SetServer(DNS_ADDR); // Set DNS server addr.
#endif
//
// Run-time configure buffers.
// The default setup will do for most cases.
//
mtu = 1500 ; // 576 is minimum acc. to RFC, 1500 is max. for Ethernet
IP_SetMTU(IFaceId, mtu); // Maximum Transmission Unit is 1500 for ethernet by default
IP_AddBuffers(12, 256); // Small buffers.
IP_AddBuffers(6, mtu + 16); // Big buffers. Size should be mtu + 16 byte for ethernet header (2 bytes type, 2*6 bytes MAC, 2 bytes padding)
IP_ConfTCPSpace(3 * (mtu-40), 3 * (mtu-40)); // Define the TCP Tx and Rx window size
IP_SOCKET_SetDefaultOptions(0
// | SO_TIMESTAMP // Send TCP timestamp to optimize the round trip time measurement. Normally not used in LAN.
| SO_KEEPALIVE // Enable keepalives by default for TCP sockets.
);
//
// Define log and warn filter.
// Note: The terminal I/O emulation might affect the timing of your
// application, since most debuggers need to stop the target
// for every terminal I/O output unless you use another
// implementation such as DCC or SWO.
//
IP_SetWarnFilter(0xFFFFFFFF); // 0xFFFFFFFF: Do not filter: Output all warnings.
IP_SetLogFilter(0
| IP_MTYPE_APPLICATION // Output application messages.
| IP_MTYPE_INIT // Output all messages from init.
| IP_MTYPE_LINK_CHANGE // Output a message if link status changes.
| IP_MTYPE_PPP // Output all PPP/PPPoE related messages.
| IP_MTYPE_DHCP // Output general DHCP status messages.
#if IP_SUPPORT_IPV6
| IP_MTYPE_IPV6 // Output IPv6 address related messages
#endif
// | IP_MTYPE_DHCP_EXT // Output additional DHCP messages.
// | IP_MTYPE_CORE // Output log messages from core module.
// | IP_MTYPE_ALLOC // Output log messages for memory allocation.
// | IP_MTYPE_DRIVER // Output log messages from driver.
// | IP_MTYPE_ARP // Output log messages from ARP layer.
// | IP_MTYPE_IP // Output log messages from IP layer.
// | IP_MTYPE_TCP_CLOSE // Output a log messages if a TCP connection has been closed.
// | IP_MTYPE_TCP_OPEN // Output a log messages if a TCP connection has been opened.
// | IP_MTYPE_TCP_IN // Output TCP input logs.
// | IP_MTYPE_TCP_OUT // Output TCP output logs.
// | IP_MTYPE_TCP_RTT // Output TCP round trip time (RTT) logs.
// | IP_MTYPE_TCP_RXWIN // Output TCP RX window related log messages.
// | IP_MTYPE_TCP // Output all TCP related log messages.
// | IP_MTYPE_UDP_IN // Output UDP input logs.
// | IP_MTYPE_UDP_OUT // Output UDP output logs.
// | IP_MTYPE_UDP // Output all UDP related messages.
// | IP_MTYPE_ICMP // Output ICMP related log messages.
// | IP_MTYPE_NET_IN // Output network input related messages.
// | IP_MTYPE_NET_OUT // Output network output related messages.
// | IP_MTYPE_DNS // Output all DNS related messages.
// | IP_MTYPE_SOCKET_STATE // Output socket status messages.
// | IP_MTYPE_SOCKET_READ // Output socket read related messages.
// | IP_MTYPE_SOCKET_WRITE // Output socket write related messages.
// | IP_MTYPE_SOCKET // Output all socket related messages.
);
//
// Add protocols to the stack.
//
IP_TCP_Add();
IP_UDP_Add();
IP_ICMP_Add();
#if IP_SUPPORT_IPV6
IP_IPV6_Add(IFaceId);
#endif
}
/*************************** End of file ****************************/
Driver handling
IP_X_Config() is called at initialization of the TCP/IP stack. It is called by the IP stack
during IP_Init(). IP_X_Config() should help to bundle the process of adding and configuring the driver.
Memory and buffer assignment
The total memory requirements of the TCP/IP stack can basically be computed as the
sum of the following components:
Description | ROM |
IP-Stack core app. | 200 bytes |
Sockets | n * app. 200 bytes |
UDP connection | n * app. 100 bytes |
TCP/ connection | n * app. 200 bytes + RAM for TCP Window |
RAM for TCP window
The data for the TCP window is stored in packet buffers. The number of packet
buffers required for best performance per socket is typically:
(WindowSize / PacketBufferSize)
This amount of buffers (and RAM for these buffers) is needed for every
simultaneously active TCP connection, where “active” means sending & receiving data.
If a connection is used bidirectional for sending & receiving data at the same time, enough
buffers should be added to be able to support the full TxWindowsSize and RxWindowSize at the same time.
Note
The configuration mentioned above is not necessary if not all of your connections
are using their maximum WindowSize all the time to reach the best speed possible.
The TCP protocol can freely assign free packet buffers in the system to all socket buffers.
Therefore it is not necessary to reserve the maximum number of packet buffers for all sockets
that could be used at the same time if you can afford retransmits and their delays of typically ~200ms.
On a shortage, especially when failing to get a buffer for adding received data to a socket
buffer (data gets discarded in the TCP layer), the TCP protocol is able to cope with this
situation by not ACKing the data and having the peer retransmit it again, giving the
application a chance to free some buffers in the meantime.
Required buffers
Most of the RAM used by the stack is used for packet buffers. Packet buffers are used
to hold incoming and outgoing packets and data in receive and transmit windows of
TCP connections.
Example configuration - Extremely small (4 kBytes)
This configuration is the smallest available or at least very close. It is intended to be
used on MCUs with very little RAM and can be used for applications which are
designed for a very low amount of traffic.
#define ALLOC_SIZE 0x1000 // 4 kBytes RAM
mtu = 576; // 576 is minimum acc.
// to RFC, 1500 is max. for Ethernet
IP_SetMTU(0, mtu); // Maximum Transmission Unit is 1500
// for Ethernet by default
IP_AddBuffers(4, 256); // Small buffers.
IP_AddBuffers(2, mtu + 16); // Big buffers. Size should be mtu
// + 16 byte for Ethernet header
// (2 bytes type, 2*6 bytes MAC,
// 2 bytes padding)
IP_ConfTCPSpace(2 * (mtu-40), 1 * (mtu-40)); // Define TCP Tx and Rx window size
Example configuration - Small (12 kBytes)
This configuration is a small configuration intended to be used on MCUs with little
RAM and can be used for applications which are designed for a medium amount of
traffic.
#define ALLOC_SIZE 0x3000 // 12 kBytes RAM
mtu = 576; // 576 is minimum acc.
// to RFC, 1500 is max. for Ethernet
IP_SetMTU(0, mtu); // Maximum Transmission Unit is 1500
// for Ethernet by default
IP_AddBuffers(8, 256); // Small buffers.
IP_AddBuffers(4, mtu + 16); // Big buffers. Size should be mtu
// + 16 byte for Ethernet header
// (2 bytes type, 2*6 bytes MAC,
// 2 bytes padding)
IP_ConfTCPSpace(2 * (mtu-40), 2 * (mtu-40)); // Define TCP Tx and Rx window size
Example configuration - Normal (24 kBytes)
This configuration is a typical configuration for many MCUs that have a fair amount of
internal RAM. It can be used for applications which are designed for a higher amount
of traffic and/or multiple client connections.
#define ALLOC_SIZE 0x6000 // 24 kBytes RAM
mtu = 1500; // 576 is minimum acc. to RFC,
// 500 is max. for Ethernet
IP_SetMTU(0, mtu); // Maximum Transmission Unit is 1500
// for Ethernet by default
IP_AddBuffers(12, 256); // Small buffers.
IP_AddBuffers(6, mtu + 16); // Big buffers. Size should be mtu
// + 16 byte for Ethernet header
// (2 bytes type, 2*6 bytes MAC,
// 2 bytes padding)
IP_ConfTCPSpace(3 * (mtu-40), 3 * (mtu-40)); // Define TCP Tx and Rx window size
Example configuration - Large (128 kBytes)
This configuration is a large configuration intended to be used on MCUs with many
external RAM. It can be used for applications which are designed for a high amount
of traffic and multiple client/server connections at the same time.
#define ALLOC_SIZE 0x20000 // 128 kBytes RAM
mtu = 1500; // 576 is minimum acc. to RFC,
// 1500 is max. for Ethernet
IP_SetMTU(0, mtu); // Maximum Transmission Unit is 1500
// for Ethernet by default
IP_AddBuffers(50, 256); // Small buffers.
IP_AddBuffers(50, mtu + 16); // Big buffers. Size should be mtu
// + 16 byte for Ethernet header
// (2 bytes type, 2*6 bytes MAC,
// 2 bytes padding)
IP_ConfTCPSpace(8 * (mtu-40), 8 * (mtu-40)); // Define TCP Tx and Rx window size
Warning
Do not configure “1 * (mtu-40)” (only one one packet) for the TxWindowSize
if TCP delayed ACKs are enabled (default). This might lead to a delay of ~200ms before
the peer ACKs the sent data as it will wait for its retransmit delay time (default ~200ms)
for at least a second packet to arrive.
If you intend to run a super small configuration with only one packet for the
TxWindowSize, please disable delayed ACK support in the stack by configuring the
define IP_SUPPORT_TCP_DELAYED_ACK to 0.
Compile-time configuration
The following types of configuration macros exist:
Binary switches "B"
Switches can have a value of either 0 or 1, for deactivated and activated respectively.
Actually, anything other than 0 works, but 1 makes it easier to read a configuration
file. These switches can enable or disable a certain functionality or behavior.
Switches are the simplest form of configuration macros.
Numerical values "N"
Numerical values are used somewhere in the code in place of a numerical constant. A
typical example is the configuration of the sector size of a storage medium.
Function replacements "F"
Macros can basically be treated like regular functions although certain limitations
apply, as a macro is still put into the code as simple text replacement. Function
replacements are mainly used to add specific functionality to a module which is
highly hardware-dependent. This type of macro is always declared using brackets
(and optional parameters).
Compile-time configuration switches
T y p e | Symbolic name | Default | Description |
B | IP_IS_BIGENDIAN | -- | Macro to define if a big endian target is used. |
B | IP_SUPPORT_STATS | 0 | Macro used as default value for all
IP_SUPPORT_STATS_* defines.
Leave this to 0 if you want to
enable only specific stats defines. |
B | IP_SUPPORT_STATS_IFACE | IP_SUPPORT _STATS | Macro to define if the emNet
interface statistics should be available. |
N | IP_DEBUG | 0 | Macro to define the debug level of
the emNet build. Refer to
Debug level for a
description of the different debug
level. |
B | IP_SUPPORT_PROFILE | 0 | Macro to define if the emNet
API profiling support for SystemView is used.
For more information regarding
SystemView please refer to . |
B | IP_SUPPORT_PROFILE_END_CALL | 0 | Macro to define if the emNet
API profiling support for SystemView recognizes the exact end of
functions as well.
For more information regarding
SystemView please refer to . |
B | IP_SUPPORT_PROFILE_FIFO | 0 | Macro to define if the emNet
profiling support for SystemView recognizes stack internal
FIFO operations as well.
For more information regarding
SystemView please refer to . |
B | IP_SUPPORT_PROFILE_PACKET | 0 | Macro to define if the emNet
profiling support for SystemView recognizes stack internal
packet buffer alloc/free operations as well.
For more information regarding
SystemView please refer to . |
N | IP_PHY_AFTER_RESET_DELAY | 3 | Delay [ms] between (soft) resetting the PHY and further communication with it. |
B | IP_SUPPORT_IPV4 | 1 | Enables support for IPv4. Disabling IPv4 support
removes many IPv4 exclusive code passages. This
can be used for example if you have enabled IPv6
and do not need/want IPv4 at all. |
B | IP_SUPPORT_IPV6 | 0 | Enables support for IPv6. Requires the IPv6 add-on. |
B | IP_SUPPORT_TCP_DELAYED_ACK | 1 | Enables support for TCP delayed ACKs. |
N | IP_TCP_RETRANS_MIN | 210 | Minimum time [ms] between retransmits for segments
that have not been ACKed. The real retransmit time
is calculated from the round-trip-time but will stay
between the min./max. values. |
N | IP_TCP_RETRANS_MAX | 3000 | Maximum time [ms] between retransmits for segments
that have not been ACKed. The real retransmit time
is calculated from the round-trip-time but will stay
between the min./max. values. |
N | IP_TCP_RETRANS_NUM | 6 | Number of retransmits for segments that have not
been ACKed. The retransmit time is calculated from
the round-trip-time but limited to the min./max. values. |
N | IP_TCP_KEEPALIVE_MAX_REPS | 8 | Maximum repeats of keepalive probes before dropping the connection.
Keepalives need to be enabled on the socket with SO_KEEPALIVE (default). |
N | IP_TCP_KEEPALIVE_INIT | 10000 | Timeout [ms] during the three-way-handshake connect after which
keepalive probing will be started. This is not a total connect timeout.
Keepalives need to be enabled on the socket with SO_KEEPALIVE (default). |
N | IP_TCP_KEEPALIVE_IDLE | 10000 | Timeout [ms] with no segment exchange after which
keepalive probing will be started.
Keepalives need to be enabled on the socket with SO_KEEPALIVE (default). |
N | IP_TCP_KEEPALIVE_PERIOD | 10000 | Time [ms] between keepalive probes sent.
Keepalives need to be enabled on the socket with SO_KEEPALIVE (default). |
F | IP_CKSUM | IP_cksum (C-routine in IP stack) | Macro to define an optimized
checksum routine to speed up the
stack. An optimized checksum
routine is typically implemented in
assembly language.
Optimized versions for the GNU,
IAR and ADS compilers are supplied. |
F | IP_MEMCPY | memcpy (C-routine in standard C-library) | Macro to define an optimized
memcpy routine to speed up the
stack. An optimized memcpy
routine is typically implemented in
assembly language.
Optimized version for the IAR
compiler is supplied. |
F | IP_MEMSET | memset (C-routine in standard C-library) | Macro to define an optimized
memset routine to speed up the
stack. An optimized memset
routine is typically implemented in
assembly language. |
F | IP_MEMMOVE | memmove (C-routine in standard C-library) | Macro to define an optimized
memmove routine to speed up the
stack. An optimized memmove
routine is typically implemented in
assembly language. |
F | IP_MEMCMP | memcmp (C-routine in standard C-library) | Macro to define an optimized
memcmp routine to speed up the
stack. An optimized memcmp
routine is typically implemented in
assembly language. |
Debug level
emNet can be configured to display debug information at higher debug levels to
locate a problem (Error) or potential problem. To display information, emNet uses
the logging routines (see chapter Debugging on page 845). These routines can be
blank, they are not required for the functionality of emNet. In a target system,
they are typically not required in a release (production) build, since a production
build typically uses a lower debug level.
If (IP_DEBUG = 0): used for release builds. Includes no debug options.
If (IP_DEBUG = 1): IP_PANIC() is mapped to IP_Panic().
If (IP_DEBUG ≥ 2): IP_PANIC() is mapped to IP_Panic() and logging support is activated.
Internet Protocol version 6 (IPv6) (Add-on)
The emNet implementation of the Internet Protocol version 6 (IPv6) allows you a
fast and easy transition from IPv4 only applications to dual IPv4 and IPv6 applications.
emNet IPv6
The emNet IPv6 add-on is an optional extension which can be seamlessly
integrated into your TCP/IP application. It combines a maximum of performance with a
small memory footprint.
The following table shows the contents of the emNet IPv6 add-on root directory:
Directory | Content |
Application\ | Contains the example application to test
the IPv6 implementation. |
Config\ | Contains the emNet IPv6 related configuration files. |
Inc\ | Contains the required include files. |
IP\ | Contains the IPv6 sources:
IPV6_DNSC.c
IPV6_ICMPv6.c
IPV6_ICMPv6_MLD.c
IPV6_ICMPv6_NDP.c
IPV6_Int.h
IPV6_IPv6.c
IPV6_IPv6.h
IPV6_TCP.c
IPV6_TCP_Rx.c
IPV6_TCP_Sock.c
IPV6_TCP_Tx.c
IPV6_UDP.c
IPV6_UDP_Sock.c |
Feature list
- Low memory footprint
- Easy to implement
- Internet Protocol version 6 (IPv6)
- Internet Control Message Protocol (ICMPv6)
- Neighbor Discovery Protocol (NDP)
- Multicast Listener Discovery (MLD)
- Stateless Address autoconfiguration (SLAAC)
- Standard socket interface
- No configuration required
IPv6 backgrounds
IPv6 is a network layer protocol. It is the most recent version of the Internet Protocol
and is intended to replace IPv4 in the near future. The name IPv6 is commonly used
generic term for an Internet protocol suite and summarizes the following protocols:
- Internet Protocol version 6 (IPv6)
- Internet Control Message Protocol (ICMPv6)
- Neighbor Discovery Protocol (NDP)
- Multicast Listener Discovery (MLD)
The IPv6 has a larger address space, supports stateless address autoconfiguration
and makes extensive use of multicasting. The IPv6 protocol header is designed to
simplify processing by routers and is extensible for new requirements.
The IPv6 header has a fixed length of 40 bytes and does not include any option. Contrary
to IPv4, options are stored in extension headers. The benefit of this separation
is that a router never needs to parse the header so that the processing is more efficient
although the header size is at least twice the size of an IPv4 header.
The most conspicuous difference between IPv4 and IPv6 is the length of the address.
The length of an IPv6 address is 128 bits, compared to 32 bits in IPv4. The address
space therefore has 2^128 addresses. Today public IPv4 addresses have become relatively
scarce. This problem can be solved by using IPv6.
The IPv6 header contains the Internet Protocol version, traffic classification options
the length of the payload, the optional extension or payload which follows the header,
a hop limit and the source and destination addresses.
IPv4 Header
IPv6 Header
Compared to the IPv4 header, the number of header elements is simplified. Unnecessary or ambiguous elements such as header checksum or IHL removed.
Other elements like Time to live, which is in practice used as hop limit, are renamed.
IPv6 address types
There are three types of IPv6 addresses:
- Unicast
- Multicast
- Anycast
IPv6 addresses are represented as eight groups of four hexadecimal digits separated
by colons.
For example: fe80:0000:0000:0000:0222:c7ff:feff:ff23 is a link local unicast
address.
IPv6 addresses may be abbreviated to shorter notations. The following rules for
abbreviation are defined by RFC 5952
“A Recommendation for IPv6 Address Text Representation”.
- One or more leading zeros from any groups of hexadecimal digits are removed;
this is usually done to either all or none of the leading zeros. For example, the
group 0222 is converted to 222.
- Consecutive sections of zeros are replaced with a double colon (::). The double
colon can only be used once in an address, as multiple use would render the
address indeterminate.
Using the recommended rules for abbreviation the textual representation of the
example IPv6 address can be simplified to fe80::222:c7ff:feff:ff23.
Link-local unicast addresses
An IPv6 link-local unicast address is always automatically configured for each interface.
It is required for Neighbor Discovery and DHCPv6 processes. A link-local
address is also useful in single-link networks with no router. It can be used to
communicate between hosts on a single-link. IPv6 link-local addresses will never be
forwarded by an IPv6 router.
The first 64 bits are link-local address prefix. Prefixes for IPv6 subnets are expressed
in the same way as Classless Inter-Domain Routing (CIDR) notation for IPv4. An IPv6
prefix is written in address/prefix-length notation. The prefix for link-local addresses
is always fe80::/64.
The second 64 bits are the interface identifier. The interface identifier is a modified
EUI-64 identifier. Please refer to the appendix of RFC 4291
“IP Version 6 Addressing Architecture” for further information.
Global unicast addresses
IPv6 global unicast addresses are the counterpart to IPv4 public addresses. They are
globally routable and reachable on the IPv6 Internet.
RFC 3587 defines global addresses that are currently being used on the IPv6 Inter-
net. According to RFC 3587 an IPv6 global unicast address consists of of four parts:
- Fixed high-order bits - 3 bits: 001
- Global routing prefix - 45 bits: Together with the three high-order bits builds
the global routing prefix the site prefix. A site is an autonomously operating net-
work that is connected to the IPv6 Internet. A site prefix identifies an individual
site of an organization, so that routers can forward IPv6 traffic matching the 48-
bit prefix to the routers of the organization’s site.
- Subnet ID - 16 bits: Used to identify subnets within an organization’s site.
- Interface ID - 64 bits: Normally, the interface identifier is a modified EUI-64
identifier.
Further reading for IPv6
This chapter explains the usage of the emNet IPv6 add-on. It describes all
functions which are required to build a network application using IPv6. For a deeper
understanding about how the protocols of the Internet protocol suite works use the
following references.
The following Request for Comments (RFC) define the relevant protocols of the Internet
protocol suite and have been used to build the emNet IPv6 add-on. They contain
all required technical specifications. The listed books are simpler to read as the
RFCs and give a general survey about the interconnection of the different protocols.
RFC# | Description |
[RFC 2460] | Internet Protocol, Version 6 (IPv6) Specification
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc2460.txt |
[RFC 2464] | Transmission of IPv6 Packets over Ethernet Networks
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc2464.txt |
[RFC 2710] | Multicast Listener Discovery (MLD) for IPv6
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc2710.txt |
[RFC 3306] | Unicast-Prefix-based IPv6 Multicast Addresses
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc3306.txt |
[RFC 3587] | IPv6 Global Unicast Address Format
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc3587.txt |
[RFC 3590] | Source Address Selection for the Multicast Listener Discovery (MLD) Protocol
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc3590.txt |
[RFC 3810] | Multicast Listener Discovery Version 2 (MLDv2) for IPv6
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc3810.txt |
[RFC 4291] | IP Version 6 Addressing Architecture
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc4291.txt |
[RFC 4443] | Internet Control Message Protocol (ICMPv6) for the Internet Protocol Version 6 (IPv6) Specification
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc4443.txt |
[RFC 4861] | Neighbor Discovery for IP version 6 (IPv6)
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc4861.txt |
[RFC 4862] | IPv6 Stateless Address Autoconfiguration
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc4862.txt |
[RFC 5952] | A Recommendation for IPv6 Address Text Representation
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc5952.txt |
- [Hagen] - IPv6 Essentials, Silvia Hagen
ISBN: 978-1449319212
- [Davies] - Understanding IPv6, Joseph Davies
ISBN: 978-0735659148
Include IPv6 to your emNet start project
Integration of emNet is a relatively simple process, which consists of the follow-
ing steps:
- Step 1: Open an emNet project and compile it.
- Step 2: Add emNet IPv6 add-on to the start project.
- Step 3: Build the project and test it.
The following steps presume that you use a project with the recommended project
structure. If your project structure differs, keep in mind that you potentially have to
add additional directories to your include path.
Open an emNet project and compile it
To add the emNet IPv6 add-on to your project, you need a running emNet
project. For a step by step tutorial to setup an emNet project refer to
Running emNet on target hardware.
Add the emNet IPv6 add-on to the start project
Add all source files in the following directory to your project:
The emNet IPv6 add-on default configuration is preconfigured with valid values,
which matches the requirements of the most applications.
Enable IPv6 support
To enable the IPv6 support, you have to add the following define to your IP_Conf.h:
#define IP_SUPPORT_IPV6 1
Build the project. It should compile without error and warnings.
To include IPv6 in your application you need to add the IPv6 related protocols by
calling IP_IPV6_Add() in the function IP_X_Config() as shown below:
void IP_X_Config(void) {
int mtu;
int IFaceId;
...
IFaceId = IP_AddEtherInterface(DRIVER); // Add driver for your hardware.
...
//
// Add protocols to the stack.
//
IP_TCP_Add();
IP_UDP_Add();
IP_ICMP_Add();
#if IP_SUPPORT_IPV6
IP_IPV6_Add(IFaceId);
#endif
Refer to Configuring emNet for more information on IP_X_Config().
The link-local IPv6 address will be generated automatically during initialization.
Please ensure that the MAC address of your target is unique in your network
segment, since it is used to build the interface identifier part of the IPv6
address.
The Maximum Transmission Unit (MTU) is the largest number of payload bytes that
can be sent in a packet. A typical value for Ethernet is 1500, since the maximum size
of an Ethernet packet is 1518 bytes. Since Ethernet uses 12 bytes for MAC
addresses, 2 bytes for type and 4 bytes for CRC, 1500 bytes “payload” remain.
As opposed to IPv4, which requires at least 576 bytes as MTU, RFC2460 defines that
IPv6 has to use at least 1280 bytes. If you do not use the Ethernet maximum of 1500
bytes, check in your IP_X_Config() that the MTU size is not smaller as 1280 bytes.
The TCP transmit and receive window sizes, configured with IP_ConfTCPSpace(),
should also be checked. An IPv4 header without options is 20 bytes. Together with
the TCP header the payload of a normal TCP/Ipv4 packet can be up to 1460 bytes.
It is a good approach to calculate the sizes of the transmit window and receive
window with the following formula: x * (MTU - (IP header size + TCP header size))
x is the number of big packets, which are available for each TCP connection.
emNet sample configurations up to emNet version 2.20 always include a call
of IP_ConfTCPSpace() and computes a matching window sizes for IPv4 targets with
this formula.
Example
IP_ConfTCPSpace(3 * (Mtu - 40), 3 * (Mtu - 40)); // Define TCP Tx and Rx window size
Since the IPv6 header is 40 bytes, the payload of a normal TCP/IPv6 packet is limited
to a maximum of 1440 bytes (Max. Ethernet MTU - (IPv6 header size + TCP header
size), 1500 - (40 + 20)). You need to change the transmit window and receive window
sizes to ensure the best possible TCP performance.
Example
IP_ConfTCPSpace(3 * (Mtu - 60), 3 * (Mtu - 60)); // Define TCP Tx and Rx window size
Enable terminal output for IPv6 messages
In debug builds of emNet, logging messages can be used. IP_SetLogFilter()
sets a mask that defines which logging messages should be logged. To output IPv6
related logging messages the message type IP_MTYPE_IPV6 needs to be added.
Example
IP_SetLogFilter(IP_MTYPE_INIT // Output all messages from init
| IP_MTYPE_LINK_CHANGE // Output a msg if link status changes
| IP_MTYPE_DHCP // Output general DHCP status messages
| IP_MTYPE_IPV6 // Output IPv6 status messages
);
Select the start application
For testing of your emNet IPv6 add-on integration, start with the code found in
the folder Application. Add one of the applications to your project (for example
OS_IP_SimpleServer_IPv6.c)
Build the project and test it
Build the project. It should compile without errors and warnings. If you encounter
any problem during the build process, check your include path and your project configuration
settings. To test the project, download the output into your target and
start the application.
A target which uses IPv4 and IPv6 should output similar logging messages as shown
below:
0:000 MainTask - INIT: Init started.
0:000 MainTask - DRIVER: Found PHY with Id 0x2000 at addr 0x1
0:000 MainTask - INIT: Link is down
0:000 MainTask - INIT: Init completed
0:000 IP_Task - INIT: IP_Task started
3:000 IP_Task - LINK: Link state changed: Full duplex, 100MHz
3:400 IP_Task - NDP: Link-local IPv6 addr.: FE80:0000:0000:0000:0222:C7FF:FEFF:FF22 added to IFace: 0
4:000 IP_Task - DHCPc: Sending discover!
5:002 IP_Task - DHCPc: IFace 0: Offer: IP: 192.168.1.12, Mask: 255.255.255.0, GW: 192.168.1.1.
6:000 IP_Task - DHCPc: IP addr. checked, no conflicts
6:000 IP_Task - DHCPc: Sending Request.
6:001 IP_Task - DHCPc: IFace 0: Using IP: 192.168.1.12, Mask: 255.255.255.0, GW: 192.168.1.1.
ICMPv6 is always activated. This means that you can ping your target. Open the
command line interface of your operating system and enter ping <TargetAddress>,
to check if the stack runs on your target. The target should answer all pings without
any error.
Configuration
The emNet IPv6 add-on can be used without changing any of the compile time
flags. All compile time configuration flags are preconfigured with valid values, which
match the requirements of most applications.
IPv6 Compile time configuration
The following types of configuration macros exist:
Binary switches "B"
Switches can have a value of either 0 or 1, for deactivated and activated respectively.
Actually, anything other than 0 works, but 1 makes it easier to read a configuration
file. These switches can enable or disable a certain functionality or behavior.
Switches are the simplest form of configuration macros.
Numerical values "N"
Numerical values are used somewhere in the source code in place of a numerical constant.
A typical example is the configuration of the sector size of a storage medium.
Alias "A"
A macro which operates like a simple text substitute. An example would be the define
U8 , which the preprocessor would replace with unsigned char.
Function replacements "F"
Macros can basically be treated like regular functions although certain limitations
apply, as a macro is still put into the source code as simple text replacement. Function
replacements are mainly used to add specific functionality to a module which is
highly hardware-dependent. This type of macro is always declared using brackets
(and optional parameters).
IPv6 Compile time configuration switches
Type | Symbolic name | Default | Description |
B | IP_SUPPORT_IPV6 | 0 | Enables support for IPv6. Refer to
IP_IPV6_Add for further information
about enabling IPv6. |
N | IP_NDP_MAX_ENTRIES | 5 | Maximum number of stored NDP entries. |
N | IP_IPV6_DNS_MAX_IPV6_SERVER | 1 | Maximum number of available IPv6 DNS servers. |
IPv6 Runtime configuration
Please refer to IP_IPV6_Add for detailed information about runtime
configuration.
IPv6 API functions
IP_IPV6_Add()
Description
Adds IPv6 to the stack and initializes the specified interface.
Prototype
void IP_IPV6_Add(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Additional information
The call of IP_IPV6_Add() adds and initializes all required IPv6
protocols to the stack. This means that Internet Control Message
Protocol version 6 (ICMPv6), Multicast Listener Discovery (MLD)
and Neighbor Discovery Protocol (NDP) are added and initialized.
Part of the initialization is the generation of a link-local
address, since all IPv6 hosts require such an address. The
link-local address is derived from the MAC address of an
interface and the link-local prefix FE80::/64. The uniqueness
of the address on the subnet is tested using the Duplicate
Address Detection (DAD) method.
Note: You need to set the compile time switch IP_SUPPORT_IPV6
to 1 to enable the stack to work in dual stack mode supporting
IPv4 and IPv6.
Example
void IP_X_Config(void) {
int Mtu;
IP_AssignMemory(_aDrvPool, sizeof(_aDrvPool)); // Assigning memory should
// be the first thing
IP_AddEtherInterface(&IP_Driver_STM32F207); // Add Ethernet driver for your
// hardware
IP_SetHWAddr("\x00\x22\xC7\xFF\xFF\x22"); // MAC addr: Needs to be
// unique for production units
IP_DHCPC_Activate(0, "TARGET", NULL, NULL); // Request an IPv4 address
//
// Run-time configure buffers.
// The default setup will do for most cases.
//
Mtu = 1500; // 576 is minimum for IPv4,
// 1280 is minimum for IPv6,
// 1500 is max. for Ethernet
IP_SetMTU(0, Mtu);
IP_AddBuffers(12, 256); // Small buffers.
IP_AddBuffers(6, Mtu + 16); // Big buffers.
IP_ConfTCPSpace(3 * (Mtu - 60), 3 * (Mtu - 60)); // Define TCP Tx and Rx window size
//
// Define log and warn filter
//
IP_SetWarnFilter(0xFFFFFFFF); // 0xFFFFFFFF: Do not filter:
// Output all warnings.
IP_SetLogFilter(IP_MTYPE_INIT // Output all messages from init
| IP_MTYPE_LINK_CHANGE // Output a msg if link status changes
| IP_MTYPE_DHCP // Output general DHCP status messages
| IP_MTYPE_IPV6 // Output all IPv6 status messages
);
//
// Add protocols to the stack
//
IP_UDP_Add(); // Add transport protocol: UDP.
IP_TCP_Add(); // Add transport protocol: TCP.
IP_ICMP_Add(); // Add ICMPv4.
IP_IPV6_Add(0); // Add IPv6, includes ICMPv6, MLD and NDP on interface 0.
}
IP_IPV6_AddUnicastAddr()
Description
Adds an additional IPv6 unicast (or anycast) address to the interface.
Prototype
int IP_IPV6_AddUnicastAddr( unsigned IFaceId,
const U8 * pAddr);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pAddr | Pointer to the 16 byte IPv6 address which should be added to the network interface. |
Return value
0 | OK. IPv6 address added to the network interface. |
1 | Error. IPv6 address could not be added to the network interface. |
Additional information
Normally, a link-local address (prefix FE80::/64) derived from the
MAC address of the interface has been set during initialization
of the stack.
IP_IPV6_ChangeDefaultConfig()
Description
Changes the default IPv6 configuration of the stack.
Prototype
void IP_IPV6_ChangeDefaultConfig(unsigned IFaceId,
unsigned Option,
unsigned OnOff);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Option | Option to enable/disable. |
OnOff | 1: Enable option 0: Disable option |
Additional information
In most situations, the default configuration of the stack
needs no changes. To adapt the behavior of the stack for the
needs of some special use cases, the default behavior can be
changed.
Options
Option | Description |
IPV6_GENERATE_LINK_LOCAL_ADDR | Generate a link-local address fe80::/64 |
IPV6_ICMPV6_MLD_ADD_DEF_ADDR | Add multicast addresses ALL-Nodes and All-Router to the interface. |
IPV6_USE_SLAAC | Use Stateless Address Autoconfiguration (SLAAC). |
IPV6_USE_ROUTER_ADVERTISMENTS | Use configuration options supplied through Router Advertisements. |
IP_IPV6_GetIPv6Addr()
Description
Returns an IPv6 address and optionally the number of configured
IPv6 address of the selected interface.
Prototype
void IP_IPV6_GetIPv6Addr(unsigned IFaceId,
U8 AddrId,
IPV6_ADDR * pIPv6Addr,
U8 * pNumAddr);
Parameters
Parameter | Description |
IFaceId | Zero-based interface identifier. |
AddrId | Address index. |
pIPv6Addr | IPv6 address for the result (Could be NULL). |
pNumAddr | Number of configured IPv6 addresses (Could be NULL). |
IP_IPV6_GetIPPacketInfo()
Description
Returns the start address of the data part of an IPv6 packet.
Prototype
U8 *IP_IPV6_GetIPPacketInfo(IP_PACKET * pPacket);
Parameters
Parameter | Description |
pPacket | Pointer to an IP_PACKET . |
Return value
≠ NULL | Start address of the data part of the IPv6 packet. |
= NULL | Error. |
Example
/*********************************************************************
*
* _pfOnRxICMP
*/
static int _pfOnRxICMP(IP_PACKET* pPacket) {
const U8* pData;
pData = IP_IPV6_GetIPPacketInfo(pPacket);
if(*pData == 128u) {
printf("ICMPv6 echo request received!\n");
}
if(*pData == 129u) {
printf("ICMPv6 echo reply received!\n");
}
return 0;
}
IP_IPV6_ParseIPv6Addr()
Description
Transforms an IPv6 address separated by colons into a
byte stream (big endian byte order).
Prototype
int IP_IPV6_ParseIPv6Addr(const char * sHost,
IPV6_ADDR * pIPv6Addr);
Parameters
Parameter | Description |
sHost | Pointer to the IPv6 address string to parse. |
pIPv6Addr | Pointer to an IPv6 address structure to store the converted byte stream. |
Return value
0 | OK. |
-1 | Error. Not every character in address are hexa values (0-f) or colons (:). |
-2 | Error. Too many characters for 16bit block. |
-3 | Error. Illegal number of colons in a row (“:::”) |
-4 | Error. “::” is used twice. |
-5 | Error. Address string to long. |
-6 | Error. Too many colons. |
-7 | Error. Parameter invalid |
Additional information
IPv6 addresses are represented in eight 16-bit blocks. Each 16-bit
block is converted to a 4-digit hexadecimal number and separated
by colons.
For example: 2001:0db8:0000:0000:0001:0000:0234:0001.
The representation can be simplified by suppressing the leading
zeros within each 16-bit block.
For example: 2001:db8:0:0:1:0:234:1.
IPv6 addresses that contain long sequences of zeros can be further
simplified. A single contiguous sequence of 16-bit blocks set to 0
in the colon hexadecimal format can be compressed to “::”.
For example: 2001:db8::1:0:234:1.
Example
static void _ParseAndPrintIPv6Addr (void) {
IPV6_ADDR IPv6Addr;
IP_IPV6_ParseIPv6Addr(&IPv6Addr, "2001:db8::1:0:234:1");
IP_Logf_Application("IPv6 addr.: %n", IPv6Addr.Union.aU8);
}
Output:
IPv6 addr.: 2001:0DB8:0000:0000:0001:0000:0234:0001
IP_IPV6_SetDefHopLimit()
Description
Adds a default hop limit to the interface.
Prototype
int IP_IPV6_SetDefHopLimit(unsigned IFaceId,
U8 HopLimit);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
HopLimit | Hop limit that should be used as default. |
Return value
0 | Ok. Hop limit set. |
1 | Error. |
IP_IPV6_SetGateway()
Description
Sets the gateway server address of the selected interface.
Prototype
int IP_IPV6_SetGateway( unsigned IFaceId,
const char * sIFaceAddr,
const char * sRouterAddr);
Parameters
Parameter | Description |
IFaceId | Interface identifier |
sIFaceAddr | IPv6 address string (interface IP). For example “2001:4860:4860::4444” |
sRouterAddr | IPv6 address string (router IP). For example “2001:4860:4860::8888” |
Return value
< 0 | Error. Gateway address format invalid. |
= 0 | Could not add gateway. - IPv6 not enabled on the selected interface or gateway is already in list or required memory could not allocated. |
= 1 | Gateway added. |
IP_IPV6_SetLinkLocalUnicastAddr()
Description
Adds a link local unicast address to the interface.
Prototype
void IP_IPV6_SetLinkLocalUnicastAddr(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface identifier. |
IP_IPV6_INFO_GetConnectionInfo()
Description
Retrieves the connection information for a connection handle.
The connetion handle is typically obtained via a call to
IP_INFO_GetConnectionList().
Prototype
int IP_IPV6_INFO_GetConnectionInfo(IP_CONNECTION_HANDLE hConn,
IP_IPV6_CONNECTION * pConInfo);
Parameters
Parameter | Description |
hConn | Connection handle. |
pConInfo | Pointer on an IP_CONNECTION structure that will be filled. |
Return value
0 | OK, Information retrieved |
1 | Error, typically because the connection pointer is no longer in list |
IP_ICMPV6_AddRxHook()
Description
This function adds a callback that is executed upon receiving
an ICMPv6 packet.
Prototype
void IP_ICMPV6_AddRxHook(IP_HOOK_ON_ICMPV6 * pHook,
IP_ON_ICMPV6_FUNC * pf,
void * pUserContext);
Parameters
Parameter | Description |
pHook | Pointer to static element of IP_HOOK_ON_ICMPV4 that can be internally used by the stack. |
pf | Function pointer to the callback to execute. |
pUserContext | User defined context top pass to the callback. |
Example
static IP_HOOK_ON_ICMPV6 _Hook;
/*********************************************************************
*
* _cbOnRx()
*
* Function description
* Callback executed when an ICMPv6 packet is received.
*
* Parameters
* IFaceId : Zero-based interface index.
* pPacket : Packet that has been received.
* pUserContext: User context given when adding the hook.
* p : Reserved for future extensions of this API.
*
* Return value
* == IP_OK : Packet has been handled (freed or reused).
* == IP_OK_TRY_OTHER_HANDLER: Packet is untouched and stack shall try another handler.
*
* Additional information
* The callback can remove its own hook using IP_ICMPV6_RemoveRxHook() .
*/
static int _cbOnRx(unsigned IFaceId,
IP_PACKET* pPacket,
void* pUserContext,
void* p) {
const U8* pData;
IP_USE_PARA(IFaceId);
IP_USE_PARA(pUserContext);
IP_USE_PARA(p);
pData = IP_IPV6_GetIPPacketInfo(pPacket);
if(*pData == IP_ICMPV6_TYPE_ECHO_REQUEST) {
IP_Logf_Application("ICMPv6 echo request received!");
}
if(*pData == IP_ICMPV6_TYPE_ECHO_REPLY) {
IP_Logf_Application("ICMPv6 echo reply received!");
}
//
// Optional: Remove the hook once no longer needed.
//
IP_ICMPV6_RemoveRxHook(SEGGER_PTR2PTR(IP_HOOK_ON_ICMPV6, pUserContext));
return IP_OK_TRY_OTHER_HANDLER; // Let the stack handle the message.
}
/*********************************************************************
*
* MainTask()
*
* Function description
* Main task executed by the RTOS to create further resources and
* running the main application.
*/
void MainTask(void) {
IP_Init();
//
// Add a hook that gets notified about received ICMP messages.
// In this example the pointer to the hook item itself is passed as
// user context to demonstrate the hook removing itself.
//
IP_ICMPV6_AddRxHook(&_Hook, _cbOnRx, &_Hook);
...
}
IP_ICMPV6_RemoveRxHook()
Description
This function removes a hook function from the
IP_HOOK_ON_ICMPV6 list.
Prototype
void IP_ICMPV6_RemoveRxHook(IP_HOOK_ON_ICMPV6 * pHook);
Parameters
Parameter | Description |
pHook | Element of type IP_HOOK_ON_ICMPV6 to remove from list. |
IP_ICMPV6_MLD_AddMulticastAddr()
Description
Adds an additional multicast address to the given interface.
Prototype
int IP_ICMPV6_MLD_AddMulticastAddr(unsigned IFaceId,
IPV6_ADDR * pMultiCAddr);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pMultiCAddr | Pointer to the 16 byte IPv6 multicast address which should be added to the network interface. |
Return value
1 | OK. IPv6 multicast address added to the network interface. |
0 | Error. IPv6 multicast address could not be added to the network interface. |
Additional information
The IPv6 multicast addresses All-Routers (FF01:0:0:0:0:0:0:2)
and All-Nodes (FF01:0:0:0:0:0:0:1) are always automatically
added to the network interface, since they are required for
correct functioning of the IPv6 implementation.
IP_ICMPV6_MLD_RemoveMulticastAddr()
Description
Removes a multicast address from the given interface.
Prototype
int IP_ICMPV6_MLD_RemoveMulticastAddr(unsigned IFaceId,
IPV6_ADDR * pIPv6Addr);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pIPv6Addr | Pointer to the 16 byte IPv6 multicast address which should be removed. |
Return value
1 | OK. IPv6 multicast address removed from the network interface. |
0 | Error. IPv6 multicast address could not be removed. |
IP_ICMPV6_NDP_SetDNSSLCallback()
Description
Sets a callback to allow processing of DNS Search List Option. (For further information to the DNS Search List Option refert to [6], section 5.2.
Prototype
void IP_ICMPV6_NDP_SetDNSSLCallback
(unsigned IFaceId,
void ( *pfHandleDNSSLOpt)(unsigned IFaceId , U8 * pData , unsigned NumBytes , U32 Lifetime ));
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pfHandleDNSSLOpt | Callback with more information. |
IP_IPV6_ResolveHost()
Description
Resolves an IP addr. given as text string into an actual IP addr.
Prototype
int IP_IPV6_ResolveHost( unsigned IFaceId,
const char * sHost,
IPV6_ADDR * pIPv6Addr,
U32 ms);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
sHost | Host name string to resolve. |
pIPv6Addr | Pointer where to store the resolved IP addr. in network byte order. |
ms | Timeout for DNS request [ms] if the request can not be sent immediately. |
Return value
O.K. : = 0
Error: < 0
IPv6 internal functions, variables and data-structures
emNet internal functions, variables and data-structures are not explained here as
they are in no way required to use emNet. Your application should not rely on any
of the internal elements, as only the documented API functions are guaranteed to
remain unchanged in future versions of emNet.
The following data-structures are meant for public usage together with the documented API.
IP_ON_ICMPV6_FUNC
Description
Callback executed when an ICMPv6 packet is received.
Type definition
typedef int (IP_ON_ICMPV6_FUNC)(unsigned IFaceId,
IP_PACKET * pPacket,
void * pUserContext,
void * p);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pPacket | Packet that has been received. |
pUserContext | User context given when adding the hook. |
p | Reserved for future extensions of this API. |
Return value
IP_OK | Packet has been handled (freed or reused). |
IP_OK_TRY_OTHER_HANDLER | Packet is untouched and stack shall try another handler. |
Additional information
The callback can remove its own hook using IP_ICMPV6_RemoveRxHook() .
IPv6 Socket API extensions
The socket interface was developed for Unix in the early 1980s and has also been
implemented on a wide variety of non-Unix systems. Today it is the de facto standard
Application Program Interface (API) for TCP/IP applications.
With the new version of the Internet protocol some changes were required to support
IPv6. RFC 3493 “Basic Socket Interface Extensions for IPv6” describes the
recommended extensions to the socket API.
In the current version of the emNet IPv6 add-on are the following extensions
included.
Structures
Structures | Description |
sockaddr_in6 | Structure to handle IPv6 addresses. |
Socket options
Socket options | Description |
IPV6_JOIN_GROUP | Join an IPv6 multicast group on a specified local interface. |
IPV6_LEAVE_GROUP | Leave an IPv6 multicast group on a specified local interface. |
Structure sockaddr_in6
Description
Structure to handle IPv6 addresses.
Prototype
typedef struct sockaddr_in6 {
U16 sin6_family;
U16 sin6_port;
U32 sin6_flowinfo;
IPV6_ADDR sin6_addr;
U32 sin6_scope_id;
} SOCKADDR_IN6;
Member | Description |
sin6_family | Protocol family ( AF_INET6 ). |
sin6_port | Transport layer port stored in network byte order. |
sin6_flowinfo | Flow information. |
sin6_addr | 16-bytes IPv6 address. |
sin6_scope_id | Set of interfaces for a scope. |
This structure is required to pass IPv6 addresses to socket interface functions like
accept(), bind(), connect(), recvfrom() and sendto(). For further information
about usage, please refer to Porting an IPv4 application to IPv6 and
IPv6 API functions for details about the usage of the socket API functions.
Porting an IPv4 application to IPv6
TCP/IP applications written using the socket API have in the past enjoyed a high
degree of portability. This portability was kept in mind while the socket API was
extended to support IPv6. Complete compatibility for existing IPv4 applications is
always ensured.
Besides smaller enhancements like some new socket options, a new socket address
structure has been added to carry IPv6 addresses.
The following sections demonstrate, using the supplied IPv4 example applications,
which parts have to be changed to communicate via IPv6. All examples are also part
of the emNet IPv6 add-on shipment.
Porting an IPv4 server application to IPv6
The main difference between an IPv4 and an IPv6 socket application lay in the
functions which pass a socket address structure as a parameter. The relevant functions
are accept(), bind(), connect(), recvfrom() and sendto().
The prototype of the sockaddr_in6 structure is shown below.
typedef struct sockaddr_in6 {
U16 sin6_family; // AF_INET6
U16 sin6_port; // Transport layer port stored in network byte order.
U32 sin6_flowinfo; // IPv6 flow information
IPV6_ADDR sin6_addr; // IPv6 address
U32 sin6_scope_id; // Set of interfaces for a scope
} SOCKADDR_IN6;
The sockaddr_in6 structure is 28 bytes. For further information, please refer to
Structure sockaddr_in6.
emNet IPv6 add-on comes with three version of OS_IP_SimpleServer.
File | Description |
OS_IP_SimpleServer.c | IPv4 version of the simple TCP server
example. Server listens on port 23 for IPv4 clients. |
OS_IP_SimpleServer_IPv6.c | IPv6 version of the simple TCP server
example. Server listens on port 23 for IPv6 clients. |
OS_IP_SimpleServer_IPv4_IPv6.c | Dual stack version of the simple TCP
server example. Server listens on port 23 for IPv4 and IPv6 clients. |
TCP/IPv4 server sample code
Listen to a port
The supplied example OS_IP_SimpleServer.c is a simple Telnet server listening on
port 23 that outputs the current system time for each character received. It uses
bind() to assign a socket address to a socket and accept() to create a new
connected socket. To assign a socket address to a socket a sockaddr structure needs to
be initialized and used as parameter for bind().
The following excerpt of IP_OS_SimpleServer.c shows a code snippet, which creates
an IPv4 socket, binds it to TCP port 23 and sets it into listening state.
/*********************************************************************
*
* _ListenAtTcpAddr()
*
* Function description
* Creates a socket for port 23 and sets it into listening state.
* The only step left is to call accept() to actually wait for a
* a client to connect.
*
* Return value
* O.K. : Socket handle.
* Error: SOCKET_ERROR.
*/
static int _ListenAtTcpAddr(void) {
struct sockaddr_in Addr;
int hSock;
int r;
hSock = socket(AF_INET, SOCK_STREAM, 0);
if (hSock != SOCKET_ERROR) {
IP_MEMSET(&Addr, 0, sizeof(Addr));
Addr.sin_family = AF_INET;
Addr.sin_port = htons(23);
Addr.sin_addr.s_addr = INADDR_ANY;
r = bind(hSock, (struct sockaddr*)&Addr, sizeof(Addr));
if (r != 0) {
hSock = SOCKET_ERROR;
} else {
r = listen(hSock, 1);
if (r != 0) {
hSock = SOCKET_ERROR;
}
}
}
return hSock;
}
The socket creation is done with the following line of code:
hSock = socket(AF_INET, SOCK_STREAM, 0);
AF_INET is the address family for IPv4. The rest of the code snippet fills the
sockaddr_in structure and pass it, together with the size of the sockaddr_in structure, to bind().
The IPv4 socket address structures sockaddr_in and sockaddr have a size of 16
bytes. For further information about the sockaddr_in structure, please refer to sockaddr_in.
Accept connection
The following excerpt of IP_OS_SimpleServer.c shows a code snippet, which accepts
connections using the socket returned by the call of _ListenAtTcpAddr().
/*********************************************************************
*
* _TelnetTask()
*
* Function description
* Creates a parent socket and handles clients that connect to the
* server. This sample can handle one client at the same time. Each
* client that connects creates a child socket that is then passed
* to the process routine to detach client handling from the server
* functionality.
*/
static void _TelnetTask(void) {
struct sockaddr Addr;
int AddrLen;
int hSockParent;
int hSockChild;
AddrLen = sizeof(Addr);
while (1) {
//
// Try until we get a valid parent socket.
//
hSockParent = _ListenAtTcpAddr();
if (hSockParent == SOCKET_ERROR) {
OS_Delay(5000);
continue; // Error, try again.
}
while (1) {
//
// Try until we get a valid child socket.
// Typically accept() will only return when
// a valid client has connected.
//
hSockChild = accept(hSockParent, &Addr, &AddrLen);
if (hSockChild == SOCKET_ERROR) {
continue; // Error, try again.
}
IP_Logf_Application("New client (%i) accepted.", Addr.sin_addr.s_addr);
_Process(hSockChild); // Process the client.
closesocket(hSockChild); // Close connection to client from our side (too).
}
}
}
accept() returns a new connected socket which is used to transfer data between the
emNet host and the client. The optional output parameters pAddr and pAddrlen
of accept() are still only used for debugging purposes. We output the IPv4 address
of the client after connecting to our host. The output should be similar to the following:
Telnet - New client (192.168.11.29) accepted.
The new connected socket is passed to the function _Process() which handles the
data transmission. When the process returns, the socket will be closed and the host
can process further client requests.
For further information about accept(), please refer to accept.
Required changes to port the TCP/IPv4 server sample code to TCP/IPv6
To port these simple telnet style server to IPv6, _ListenAtTCPAddr() and
_TelnetTask() has to be modified. The rest of the example IP_OS_SimpleServer.c
keeps untouched.
Listen to a port
_ListenAtTcpAddr() needs to create an IPv6 socket instead of an IPv4 socket and
the sockaddr_in structure has to replaced by a sockaddr_in6 structure.
The socket creation changes from:
hSock = socket(AF_INET, SOCK_STREAM, 0);
to:
hSock = socket(AF_INET6, SOCK_STREAM, 0);
AF_INET6 is the address family for IPv6.
The modified function _ListenAtTcpAddr() looks like the code snippet below.
/*********************************************************************
*
* _ListenAtTcpAddr()
*
* Function description
* Creates a socket for port SERVER_PORT and sets it into listening
* state. The only step left is to call accept() to actually wait for
* a client to connect.
*
* Return value
* O.K. : Socket handle.
* Error: SOCKET_ERROR .
*/
static int _ListenAtTcpAddr(void) {
struct sockaddr_in6 Addr;
int hSock;
int r;
hSock = socket(AF_INET6, SOCK_STREAM, 0);
if (hSock != SOCKET_ERROR) {
Addr.sin6_family = AF_INET6;
Addr.sin6_port = htons(23);
Addr.sin6_flowinfo = 0;
IP_MEMSET(&Addr.sin6_addr.Union.aU8[0], 0, IPV6_ADDR_LEN);
Addr.sin6_scope_id = 0;
r = bind(hSock, (struct sockaddr*)&Addr, sizeof(Addr));
if (r != 0) {
hSock = SOCKET_ERROR;
} else {
r = listen(hSock, 1);
if (r != 0) {
hSock = SOCKET_ERROR;
}
}
}
return hSock;
}
Compared to the IPv4 version of these function, AF_INET6 is used to specify the
address family to create an IPv6 socket. The port number is still 23 and the address
element sin6_addr is set to zero, which means that the socket will be bound to all
available interfaces. The new elements, sin6_flowinfo and sin6_scope, are set to
zero.
Accept connection
The function _TelnetTask() is nearly untouched. The only change is the
sockaddr_in6 structure instead of the sockaddr structure used in the IPv4 code.
/*********************************************************************
*
* _TelnetTask()
*
* Function description
* Creates a parent socket and handles clients that connect to the
* server. This sample can handle one client at the same time. Each
* client that connects creates a child socket that is then passed
* to the process routine to detach client handling from the server
* functionality.
*/
static void _TelnetTask(void) {
struct sockaddr_in6 Addr;
int AddrLen;
int hSockParent;
int hSockChild;
AddrLen = sizeof(Addr);
while (1) {
//
// Try until we get a valid parent socket.
//
hSockParent = _ListenAtTcpAddr();
if (hSockParent == SOCKET_ERROR) {
OS_Delay(5000);
continue; // Error, try again.
}
while (1) {
//
// Try until we get a valid child socket.
// Typically accept() will only return when
// a valid client has connected.
//
hSockChild = accept(hSockParent, (struct sockaddr*)&Addr, &AddrLen);
if (hSockChild == SOCKET_ERROR) {
continue; // Error, try again.
}
IP_Logf_Application("New client (%n) accepted.", Addr.sin6_addr.Union.aU8);
_Process(hSockChild); // Process the client.
closesocket(hSockChild); // Close connection to client from our side (too).
}
}
}
The optional output parameters pAddr and pAddrlen of accept() are still only used
for debugging purposes. We output the IPv6 address of the client after connecting to
our host. The output should be similar to the following:
Telnet - New client (FE80:0000:0000:0000:76D4:35FF:FE8B:5BE5) accepted.
The supplied example OS_IP_SimpleServer_IPv6.c includes all the mentioned
changes. You should start with this example to comprehend the code changes.
Dual stack TCP server sample code
The emNet IPv6 add-on provides IPv4 and IPv6 protocol stacks in the same net-
work node. This means that emNet together with the IPv6 add-on is the ideal
starting point to implement applications which can facilitate native communications
between nodes using either IPv4 or IPv6 or both.
In the transition phase from IPv4 to IPv6 most server applications need to accept
connections from IPv4 clients and from IPv6 clients. The supplied example application
OS_IP_SimpleServer_IPv4_IPv6.c demonstrates a possible way to implement
such a TCP server application.
The supplied example OS_IP_SimpleServer_IPv4_IPv6.c is a simple Telnet server
listening on port 23 that outputs the current system time for each character
received.
The following excerpt of IP_OS_SimpleServer_IPv4_IPv6.c shows a code snippet,
which creates an IPv4 socket and an IPv6 socket, binds both to TCP port 23 and sets
both into listening state. To enhance readability of the example code socket creation
and binding are implemented as functions.
/*********************************************************************
*
* _ListenAtTcpPort()
*
* Function description
* Creates a socket, binds it to a port and sets the socket into
* listening state.
*
* Parameter
* IPProtVer - Protocol family which should be used (PF_INET or PF_INET6).
* Port - Port which should be to wait for connections.
*
* Return value
* O.K. : Socket handle.
* Error: SOCKET_ERROR.
*/
static int _ListenAtTcpPort(unsigned IPProtVer, U16 Port) {
int hSock;
int r;
//
// Create socket
//
hSock = _CreateSocket(IPProtVer);
if (hSock != SOCKET_ERROR) {
//
// Bind it to the port
//
r = _BindAtTcpPort(IPProtVer, hSock, Port);
//
// Start listening on the socket.
//
if (r != 0) {
hSock = SOCKET_ERROR;
} else {
r = listen(hSock, 1);
if (r != 0) {
hSock = SOCKET_ERROR;
}
}
}
return hSock;
}
The function used to create either an IPv4 or an IPv6 socket is listed below:
/*********************************************************************
*
* _CreateSocket()
*
* Function description
* Creates a socket for the requested protocol family.
*
* Parameter
* IPProtVer - Protocol family which should be used (PF_INET or PF_INET6).
*
* Return value
* O.K. : Socket handle.
* Error: SOCKET_ERROR .
*/
static int _CreateSocket(unsigned IPProtVer) {
int hSock;
hSock = SOCKET_ERROR;
//
// Create IPv6 socket
//
if (IPProtVer == PF_INET6) {
hSock = socket(AF_INET6, SOCK_STREAM, 0);
}
//
// Create IPv4 socket
//
if (IPProtVer == PF_INET) {
hSock = socket(AF_INET, SOCK_STREAM, 0);
}
return hSock;
}
The function used to bind either an IPv4 or an IPv6 socket is listed below:
/*********************************************************************
*
* _BindAtTcpPort()
*
* Function description
* Binds a socket to a port.
*
* Parameter
* IPProtVer - Protocol family which should be used (PF_INET or PF_INET6).
* hSock - Socket handle
* Port - Port which should be to wait for connections.
*
* Return value
* O.K. : Socket handle.
* Error: SOCKET_ERROR .
*/
static int _BindAtTcpPort(unsigned IPProtVer, int hSock, U16 LPort) {
int r;
//
// Bind it to the port
//
if (IPProtVer == PF_INET6) {
struct sockaddr_in6 Addr;
IP_MEMSET(&Addr, 0, sizeof(Addr));
Addr.sin6_family = AF_INET6;
Addr.sin6_port = htons(LPort);
Addr.sin6_flowinfo = 0;
IP_MEMSET(&Addr.sin6_addr, 0, 16);
Addr.sin6_scope_id = 0;
r = bind(hSock, (struct sockaddr*)&Addr, sizeof(Addr));
}
if (IPProtVer == PF_INET) {
struct sockaddr_in Addr;
IP_MEMSET(&Addr, 0, sizeof(Addr));
Addr.sin_family = AF_INET;
Addr.sin_port = htons(LPort);
Addr.sin_addr.s_addr = INADDR_ANY;
r = bind(hSock, (struct sockaddr*)&Addr, sizeof(Addr));
}
return r;
}
To handle client requests on both sockets within one task select() is used. For further
information to select(), please refer to select.
To accept connections on both sockets the listening IPv4 socket and the listening
IPv6 socket are added to the read set. select() returns if data is available on one of
these sockets and accept() is called to handle the new connection.
/*********************************************************************
*
* _TelnetTask()
*
* Function description
* Creates a parent socket and handles clients that connect to the
* server. This sample can handle one client at the same time. Each
* client that connects creates a child socket that is then passed
* to the process routine to detach client handling from the server
* functionality.
*/
static void _TelnetTask(void) {
IP_fd_set ReadFds;
int hSockParent4;
int hSockParent6;
int hSockChild;
int r;
//
// Try until we get a valid IPv4 parent socket and a valid IPv6 parent socket.
//
while (1) {
hSockParent4 = _ListenAtTcpPort(PF_INET, SERVER_PORT);
if (hSockParent4 == SOCKET_ERROR) {
OS_Delay(2000);
continue; // Error, try again.
}
break;
}
while (1) {
hSockParent6 = _ListenAtTcpPort(PF_INET6, SERVER_PORT);
if (hSockParent6 == SOCKET_ERROR) {
closesocket(hSockParent4);
OS_Delay(2000);
continue; // Error, try again.
}
break;
}
//
// Wait for a connection on one of the both sockets and process the data
// requests after accepting the connection.
//
while (1) {
IP_FD_ZERO(&ReadFds); // Clear the set
IP_FD_SET(hSockParent4, &ReadFds); // Add IPv4 socket to the set
IP_FD_SET(hSockParent6, &ReadFds); // Add IPv6 socket to the set
r = select(&ReadFds, NULL, NULL, 5000); // Check for activity. Wait 5 seconds
if (r <= 0) {
continue;
}
//
// Check if the IPv4 socket is ready
//
if (IP_FD_ISSET(hSockParent4, &ReadFds)) {
hSockChild = accept(hSockParent4, NULL, NULL);
if (hSockChild == SOCKET_ERROR) {
continue; // Error, try again.
}
IP_Logf_Application("New IPv4 client accepted.");
}
//
// Check if the IPv6 socket is ready
//
else if (IP_FD_ISSET(hSockParent6, &ReadFds)) {
hSockChild = accept(hSockParent6, NULL, NULL);
if (hSockChild == SOCKET_ERROR) {
continue; // Error, try again.
}
IP_Logf_Application("New IPv6 client accepted.");
}
_Process(hSockChild); // Process the client.
closesocket(hSockChild); // Close connection to client from our side (too).
}
}
The supplied example OS_IP_SimpleServer_IPv4_IPv6.c is a good starting point to
test the reachability of your embedded host via IPv4 and IPv6.
Resource usage
The ROM usage depends on the compiler options, the compiler version and the used
CPU. The memory requirements of the IPv6 modules presented in the tables below
have been measured on a Cortex-M3 system. Details about the further configuration
can be found in the sections of the specific example.
IPv6 ROM usage
The resource usage of the IPv6 add-on has been measured on a Cortex-M3 system
size optimization.
Addon | ROM |
emNet IPv6 | approximately 8.0 kBytes |
The stated ROM usage is only the additional space that is required to add IPv6 to the
emNet IPv4 stack. The total ROM usage for emNet running IPv4 and IPv6 is
approximately 28 kBytes.
RAM usage
The total memory requirements of the IPv6 add-on can basically be computed as the
sum of the following components:
Description | RAM |
IPv6 add-on | approximately 200 bytes |
Unicast address | n * approximately 48 bytes |
Multicast address | n * approximately 28 bytes |
NDP entry | n * 52 bytes |
An IPv6 target with two unicast addresses, four Multicast address and five NDP
entries needs approximately 660 bytes additional RAM. For detailed information about the
configuration and the memory requirements for each TCP/UDP connection, refer to
Configuring emNet.
The required memory is taken from the memory pool of the stack. For further information
about how to increase the memory pool, refer to IP_AssignMemory.
SMTP client (Add-on)
The emNet SMTP client is an optional extension to emNet. The SMTP client can
be used with emNet or with a different TCP/IP stack. All functions that are
required to add the SMTP client task to your application are described in this chapter.
emNet SMTP client
The emNet SMTP client is an optional extension which can be seamlessly
integrated into your TCP/IP application. It combines a maximum of performance with a
small memory footprint. The SMTP client allows an embedded system to send emails
with dynamically generated content. The RAM usage of the SMTP client module has
been kept to a minimum by smart buffer handling.
The SMTP client implements the relevant parts of the following Request For Comments (RFC).
RFC# | Description |
[RFC 821] | Simple Mail Transfer Protocol
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc821.txt |
[RFC 974] | Mail routing and the domain system
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc974.txt |
[RFC 2554] | SMTP Service Extension for Authentication
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc2554.txt |
[RFC 5321] | Simple Mail Transfer Protocol
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc5321.txt |
The following table shows the contents of the emNet SMTP client root directory:
Directory | Content |
.\Application\ | Contains the example application to run
the SMTP client with emNet. |
.\Config\ | Contains the SMTP client configuration file.
Refer to SMTP client configuration for detailed information. |
.\Inc\ | Contains the required include files. |
.\IP\ | Contains the SMTP client sources,
IP_SMTPC.c and IP_SMTPC.h. |
.\Windows\SMTPC\ | Contains the source, the project files and
an executable to run emNet SMTP
client on a Microsoft Windows host. |
Feature list
- Low memory footprint.
- Independent of the TCP/IP stack: any stack with sockets can be used.
- Support for attachments (multipart items).
- Supports AUTH TLS (with additional SSL/TLS stack) for secure connections.
- Independent of the SSL/TLS stack: any sockets based stack can be used.
- Example applications included.
- Project for executable on PC for Microsoft Visual Studio included.
Requirements
TCP/IP stack
The emNet SMTP client requires a TCP/IP stack. It is optimized for emNet, but
any RFC-compliant TCP/IP stack can be used. The shipment includes a Win32 simulation,
which uses the standard Winsock API and an implementation which uses the
socket API of emNet.
In addition to insecure connections the emNet SMTP client API allows to secure
the connection by using an additional SSL/TLS stack if the server is capable of the
STARTTLS command.
Multi tasking
The SMTP client needs to run as a separate thread. Therefore, a multi tasking system
is required to use the emNet SMTP client.
SMTP backgrounds
The Simple Mail Transfer Protocol is a text based communication protocol for
electronic mail transmission across IP networks.
Using SMTP, an emNet application can transfer mail to an SMTP servers on the
same network or to SMTP servers in other networks via a relay or gateway server
accessible to both networks. When the emNet SMTP client has a message to
transmit, it establishes a TCP connection to an SMTP server and transmits after the
handshaking the message content.
The handshaking mechanism includes normally an authentication process. The RFC’s
define the following four different authentication schemes:
- PLAIN
- LOGIN
- CRAM-MD5
- NTLM
In the current version, the emNet SMTP client supports only PLAIN and LOGIN authentication.
The following listing shows a typical SMTP session:
S: 220 srv.sample.com ESMTP
C: HELO
S: 250 srv.sample.com
C: AUTH LOGIN
S: 334 VXNlcm5hbWU6
C: c3BzZXk29IulbkY29tZcZXIbtZ
S: 334 UGFzc3dvcmQ6
C: UlblhFz7ZlblsZlZQ==
S: 235 go ahead
C: Mail from:<user0@sample.com>
S: 250 ok
C: Rcpt to:<user1@sample.com>
S: 250 ok
C: Rcpt to:<user2@sample.com>
S: 250 ok
C: Rcpt to:<user3@sample.com>
S: 250 ok
C: DATA
S: 354 go ahead
C: Message-ID: <1000.2234@sample.com>
C: From: "User0" <User0@sample.com>
C: TO: "User1" <User1@sample.com>
C: CC: "User2" <User2@sample.com>, "User3" <User3@sample.com>
C: Subject: Testmail
C: Date: 1 Jan 2008 00:00 +0100
C:
C: This is a test!
C:
C: .
S: 250 ok 1231221612 qp 3364
C: quit
S: 221 srv.sample.com
Secure connections
Most modern mail servers support secure connections or might even refuse insecure
connections at all. There are two ways of establishing secure connections with a mail
server by utilizing an additional SSL/TLS stack:
- Establishing an SMTPS SSL/TLS connection on port 465 where the whole connection
from the first data byte sent to the last byte is secured. This method is deprecated
but still widely in use.
- Establish a regular insecure connection on port 25 and try to upgrade it to a
secure connection using the STARTTLS command.
While the second method (starting insecure and trying to upgrade) might look less
secure it is not. The security of this method is defined by the configured fallback
mechanism used via the SecPolicy that can be found in Structure IP_SMTPC_MTA.
If the client is not allowed to use an insecure connection as fallback this method is as
safe as encrypting the whole connection from start to end. An advantage of this
method is that most firewalls will allow traffic on port 25 and existing firewall rules
do not have to changed for secure/insecure connections.
For an example on how to use secure connections please refer to the
IP_SendMail_Secure.c sample.
Attachments
Mail attachments are multipart items that are added to a mail. Multipart items in a
mail are not limited to attachments only but this is the most common form they are
used.
The emNet SMTPC client allows to easily add attachments to a mail by providing
an array of IP_SMTPC_MULTIPART_ITEM items that configure the attachments to add.
For more information about the item structure please refer to
Structure IP_SMTPC_MULTIPART_API.
Creating a list of attachments
Each item is sent via a callback that needs to be implemented by the application.
Multiple items can share the same callback. To differentiate between two items that
use the same callback a user context element can be set in the
IP_SMTPC_MULTIPART_ITEM. This context can be a simple index or a pointer to more
information about the item to send like a string with a path of a file to send from a
file system.
The content type set for the item defines how the receiver will treat this attachment.
The following is only a short excerpt of possible content types (MIME types) that can
be used but. However all depend on being known by the receiver to be fully under-
stood:
File extension | Content type (MIME type) |
.jpg | “image/jpeg” |
.txt | “text/plain” |
.zip | “application/x-compressed” |
One extension might be known under multiple MIME types. The sender usually
chooses the MIME type that is known to the system for this extension. Therefore an
attachment might not be correctly recognized by the receiver as this type of file
under all circumstances.
Adding the attachments to the mail
To actually add the items to the mail the list has to be assigned to the message to
send. This is done by filling in the sBoundary, paMultipartItem and
NumMultipartItems parameters of the IP_SMTPC_MESSAGE structure that defines the message to
send. For more information about the structure defining a message please refer to
Structure IP_SMTPC_MESSAGE.
A sample of adding two text files as attachment can be found in the IP_SendMail.c
sample.
SMTP client configuration
The emNet SMTP client can be used without changing any of the compile time
flags. All compile time configuration flags are preconfigured with valid values, which
match the requirements of most applications.
The following types of configuration macros exist:
Binary switches "B"
Switches can have a value of either 0 or 1, for deactivated and activated respectively.
Actually, anything other than 0 works, but 1 makes it easier to read a configuration
file. These switches can enable or disable a certain functionality or behavior.
Switches are the simplest form of configuration macros.
Numerical values "N"
Numerical values are used somewhere in the source code in place of a numerical constant.
A typical example is the configuration of the sector size of a storage medium.
Alias "A"
A macro which operates like a simple text substitute. An example would be the define
U8, which the preprocessor would replace with unsigned char.
Function replacements "F"
Macros can basically be treated like regular functions although certain limitations
apply, as a macro is still put into the source code as simple text replacement. Function
replacements are mainly used to add specific functionality to a module which is
highly hardware-dependent. This type of macro is always declared using brackets
(and optional parameters).
SMTP client compile time configuration switches
Type | Symbolic name | Default | Description |
F | SMTPC_WARN | -- | Defines a function to output
warnings. In debug configurations (DEBUG = 1) SMTPC_WARN
maps to IP_Warnf_Application(). |
F | SMTPC_LOG | -- | Defines a function to output logging messages.
In debug configurations (DEBUG = 1) SMTPC_LOG maps to
IP_Logf_Application(). |
N | SMTPC_SERVER_PORT | 25 | Defines the port where the SMTP
server is listening. |
N | SMTPC_IN_BUFFER_SIZE | 256 | Defines the size of the input
buffer. The input buffer is used to
store the SMTP replies of the
SMTP server. |
N | SMTPC_AUTH_USER_BUFFER_SIZE | 48 | Defines the size of the buffer
used for the Base-64 encoded user name. |
N | SMTPC_AUTH_PASS_BUFFER_SIZE | 48 | Defines the size of the buffer
used for the Base-64 encoded password. |
API functions
Function | Description |
IP_SMTPC_Send() | Sends an email to one or multiple recipients. |
IP_SMTPC_Send()
Description
Sends an email to one or multiple recipients.
Prototype
int IP_SMTPC_Send(const IP_SMTPC_API * pIP_API,
const IP_SMTPC_MAIL_ADDR * paMailAddr,
int NumMailAddr,
const IP_SMTPC_MESSAGE * pMessage,
const IP_SMTPC_MTA * pMTA,
const IP_SMTPC_APPLICATION * pApplication);
Parameters
Parameter | Description |
pIP_API | Pointer to an IP_STMPC_API structure. |
paMailAddr | Pointer to an array of IP_SMTPC_MAIL_ADDR structures. The first element of the array has to be filled with the data of the sender (FROM). The order of the following data sets for recipients (TO), carbon copies (CC) and blind carbon copies (BCC) is not relevant. |
NumMailAddr | Number of email addresses. |
pMessage | Pointer to an array of IP_SMTPC_MESSAGE structures. |
pMTA | Pointer to an array of IP_SMTPC_MTA structures. |
pApplication | Pointer to an array of IP_SMTPC_APPLICATION structures. |
Return value
Data structures
Structure IP_SMTPC_API
Description
Structure with pointers to the required socket interface functions.
Prototype
typedef struct {
SMTPC_SOCKET (*pfConnect) (char * SrvAddr);
void (*pfDisconnect)(SMTPC_SOCKET Socket);
int (*pfSend) (const char * pData,
int Len,
SMTPC_SOCKET Socket);
int (*pfReceive) (char * pData,
int Len,
SMTPC_SOCKET Socket);
int (*pfUpgrade) (SMTPC_SOCKET hSock,
const char * sServer);
void (*pfDowngrade) (SMTPC_SOCKET hSock);
} IP_SMTPC_API;
Member | Description |
pfConnect | Pointer to the connect function (for example, connect()). |
pfDisconnect | Pointer to the disconnect function (for example, closesocket()). |
pfSend | Pointer to a send function (for example, send()). |
pfReceive | Pointer to a receive function (for example, recv()). |
pfUpgrade | Pointer to a callback function to upgrade an insecure connection to a
secure connection using an SSL/TLS stack. |
pfDowngrade | Pointer to a callback function to downgrade a secure connection to
an insecure connection (after work is done) using an SSL/TLS stack. |
Example
/*********************************************************************
*
* _Connect
*
* Function description
* Creates a socket and opens a TCP connection to the mail host.
*/
static SMTPC_SOCKET _Connect(char * SrvAddr) {
long IP;
long Sock;
struct hostent * pHostEntry;
struct sockaddr_in sin;
int r;
//
// Convert host into mail host
//
pHostEntry = gethostbyname(SrvAddr);
if (pHostEntry == NULL) {
SMTPC_LOG(("gethostbyname failed: %s\r\n", SrvAddr));
return NULL;
}
IP = *(unsigned*)(*pHostEntry->h_addr_list);
//
// Create socket and connect to mail server
//
Sock = socket(AF_INET, SOCK_STREAM, 0);
if(Sock == -1) {
SMTPC_LOG(("Could not create socket!"));
return NULL;
}
IP_MEMSET(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(SERVER_PORT);
sin.sin_addr.s_addr = IP;
r = connect(Sock, (struct sockaddr*)&sin, sizeof(sin));
if(r == SOCKET_ERROR) {
SMTPC_LOG(("\nSocket error :"));
return NULL;
}
SMTPC_LOG(("APP: Connected.\r\n"));
return (SMTPC_SOCKET)Sock;
}
/*********************************************************************
*
* _Disconnect
*
* Function description
* Closes a socket.
*/
static void _Disconnect(SMTPC_SOCKET Socket) {
closesocket((long)Socket);
}
/*********************************************************************
*
* _Send
*
* Function description
* Sends data via socket interface.
*/
static int _Send(const char * buf, int len, void * pConnectionInfo) {
return send((long)pConnectionInfo, buf, len, 0);
}
/*********************************************************************
*
* _Recv
*
* Function description
* Receives data via socket interface.
*/
static int _Recv(char * buf, int len, void * pConnectionInfo) {
return recv((long)pConnectionInfo, buf, len, 0);
}
static const IP_SMTPC_API _IP_Api = {
_Connect,
_Disconnect,
_Send,
_Recv
};
Structure IP_SMTPC_APPLICATION
Description
Structure with pointers to application related functions.
Prototype
typedef struct {
U32 (*pfGetTimeDate) (void);
int (*pfCallback)(int Stat, void *p);
const char * sDomain; // email domain
const char * sTimezone; // Time zone.
} IP_SMTPC_APPLICATION;
Member | Description |
pfGetTimeDate | Pointer to the function which returns the current system time. Used
to set the correct date and time of the email. |
pfCallback | Pointer to status callback function. Can be NULL. |
sDomain | Domain name. For example, sample.com. According to RFC 821 the
maximum total length of a domain name or number is 64 characters. |
sTimezone | Time zone. The zone specifies the offset from Coordinated Universal
Time (UTC). Offset from UTC is passed as string: “+0100”. Can be NULL. |
Example
*********************************************************************
*
* _GetTimeDate
*/
static U32 _GetTimeDate(void) {
U32 r;
U16 Sec, Min, Hour;
U16 Day, Month, Year;
Sec = 0; // 0 based. Valid range: 0..59
Min = 0; // 0 based. Valid range: 0..59
Hour = 0; // 0 based. Valid range: 0..23
Day = 1; // 1 based. Means that 1 is 1.
// Valid range is 1..31 (depending on month)
Month = 1; // 1 based. Means that January is 1. Valid range is 1..12.
Year = 28; // 1980 based. Means that 2008 would be 28.
r = Sec / 2 + (Min << 5) + (Hour << 11);
r |= (U32)(Day + (Month << 5) + (Year << 9)) << 16;
return r;
}
*********************************************************************
*
* _Application
*/
static const SMTPC_APPLICATION _Application = {
_GetTimeDate,
NULL,
"sample.com", // Your domain.
NULL
};
Structure IP_SMTPC_MAIL_ADDR
Description
Structure to store an email address.
Prototype
typedef struct {
const char * sName;
const char * sAddr;
int Type;
} IP_SMTPC_MAIL_ADDR;
Member | Description |
sName | Name of the recipient (for example, “Foo Bar”). Can be NULL. |
sAddr | email address of the recipient (for example, “foo@bar.com”). |
Type | Type of the email address. |
Valid values for parameter Type
Value | Description |
SMTPC_REC_TYPE_FROM | email address of the sender (FROM). |
SMTPC_REC_TYPE_TO | email address of the recipient (TO). |
SMTPC_REC_TYPE_CC | email address of a recipient which should
get a carbon copy (CC) of the email. |
SMTPC_REC_TYPE_BC | email address of a recipient which should
get a blind carbon copy (BCC) of the email. |
Additional information
The structure is used to store the data sets of the sender and all recipients.
IP_SMTPC_Send() gets a pointer to an array of IP_SMTPC_MAIL_ADDR structures as
parameter. The first element of these array has to be filled with the data of the
sender (FROM). The order of the following data sets for Recipients (TO), Carbon Copies (CC)
and Blind Carbon Copies (BCC) is not relevant. For detailed information
about IP_SMTPC_Send() refer to IP_SMTPC_Send.
The sName could also be a UTF-8 encoded string. For example, to send
“Лев Толстой”
define sName as
"\xD0\x9B\xD0\xB5\xD0\xB2\x20\xD0\xA2\xD0\xBE\xD0\xBB\xD1\x81\xD1\x82\xD0\xBE\xD0\xB9"
For more details on UTF-8 encoding refer for example to
https://en.wikipedia.org/wiki/Utf8.
Example
/*********************************************************************
*
* Mailer
*/
static void _Mailer(void) {
SMTPC_MAIL_ADDR MailAddr[4];
SMTPC_MTA Mta;
SMTPC_MESSAGE Message;
IP_MEMSET(&MailAddr, 0, sizeof(MailAddr));
//
// Sender
//
MailAddr[0].sName = 0; // for example, "Your name";
MailAddr[0].sAddr = 0; // for example, "user@foobar.com";
MailAddr[0].Type = SMTPC_REC_TYPE_FROM;
//
// Recipient(s)
//
MailAddr[1].sName = 0; // "Recipient";
MailAddr[1].sAddr = 0; // "recipient@foobar.com";
MailAddr[1].Type = SMTPC_REC_TYPE_TO;
MailAddr[2].sName = 0; // "CC Recp 1";
MailAddr[2].sAddr = 0; // "cc1@foobar.com";
MailAddr[2].Type = SMTPC_REC_TYPE_CC;
MailAddr[3].sName = 0; // "BCC Recp 1"
MailAddr[3].sAddr = 0; // "bcc1@foobar.com";;
MailAddr[3].Type = SMTPC_REC_TYPE_BCC;
//
// Message
//
Message.sSubject = "SMTP message sent via emNet SMTP client";
Message.sBody = "emNet SMTP client - www.segger.com";
//
// Fill mail transfer agent structure
//
Mta.sServer = 0; // for example, "mail.foobar.com";
Mta.sUser = 0; // for example, "user@foobar.com";
Mta.sPass = 0; // for example, "password";
//
// Check if sample is configured!
//
if(Mta.sServer == 0) {
SMTPC_WARN(("You have to enter valid SMTP server, sender and recipient(s).\r\n"));
while(1);
}
//
// Wait until link is up. This can take 2-3 seconds if PHY has been reset.
//
while (IP_IFaceIsReady() == 0) {
OS_Delay(100);
}
SMTPC_Send(&_IP_Api, &MailAddr[0], 4, &Message, &Mta, &_Application);
while(1);
}
Structure IP_SMTPC_MULTIPART_API
Description
Structure containing functions for sending multipart content (attachments).
Prototype
typedef struct {
void (*pfSend)( IP_SMTPC_CONTEXT* pContext,
const char* pData,
unsigned NumBytes);
} IP_SMTPC_MULTIPART_API;
Member | Description |
pfSend | Callback for sending multipart content in chunks. |
- pContext | SMTPc context. |
- pData | Data to send. |
- NumBytes | Amount of data to send. |
Structure IP_SMTPC_MULTIPART_ITEM
Description
Structure to store multipart items to be added to the mail.
Prototype
typedef struct IP_SMTPC_MULTIPART_ITEM_STRUCT IP_SMTPC_MULTIPART_ITEM;
struct IP_SMTPC_MULTIPART_ITEM_STRUCT {
const char* sFilename;
const void* pUserContext;
const char* sContentType;
void (*pfSendItem)( IP_SMTPC_CONTEXT* pContext,
const IP_SMTPC_MULTIPART_ITEM* pItem,
const IP_SMTPC_MULTIPART_API* pAPI ));
};
Member | Description |
sFilename | Filename suggested to client in case the multipart item is an attachment. |
pUserContext | User context passed to pfSendItem callback. Can be used to pass a
file path or other application information to the callback. |
sContentType | Value for the “Content-Type: ” field of the multipart item. Examples
for a text file attachment are: “text/plain” or “text/plain; name=Test.txt” . |
pfSendItem | Callback for sending the content of a multipart item without having
to know its length upfront. |
- pContext | SMTPc context. |
- pItem | Item to send. |
pAPI | API for sending data in chunks. |
Structure IP_SMTPC_MESSAGE
Description
Structure to store the subject and the text and attachments of the email.
Prototype
typedef struct {
const char* sSubject;
const char* sBody;
const char* sBoundary;
const IP_SMTPC_MULTIPART_ITEM* paMultipartItem;
unsigned NumMultipartItems;
} IP_SMTPC_MESSAGE;
Member | Description |
sSubject | Subject of the message to send. Could be UTF-8 encoded string. |
sBody | Content of the message to send. Could be UTF-8 encoded string. |
sBoundary | Boundary to use for multipart encoding (e.g. when using
attachments). Can be NULL if (NumMultipartItems = 0). |
paMultipartItem | Pointer to list of items (attachments) to multipart encode with
the message. Can be NULL if (NumMultipartItems = 0). |
NumMultipartItems | Number of multipart items that can be found at paMultipartItem. |
Structure IP_SMTPC_MTA
Description
Structure to store the server address and the login information.
Prototype
typedef struct {
const char * sServer;
const char * sUser;
const char * sPass;
U8 SecPolicy;
} IP_SMTPC_MTA;
Member | Description |
sServer | Server address (for example, “mail.foobar.com”). |
sUser | Account user name (for example, “foo@bar.com”). Can be NULL. |
sPass | Account password (for example, “password”). Can be NULL. |
SecPolicy | Security policy to use:
- SMTPC_SEC_POLICY_ALLOW_INSECURE (default)
- SMTPC_SEC_POLICY_SECURE_ONLY |
Additional information
The parameters sUser and sPass have to be NULL if no authentication is used by the
server. If sUser is set in the application code, the client tries to use authentication.
This means that the client sends the AUTH LOGIN or AUTH PLAIN command to the server.
If the server does not support authentication, he will return an error code and the client
closes the session.
The parameter SecPolicy defines the fallback behavior in case secure connections
are supported by using an additional SSL/TLS stack and providing callbacks for the
function pointers for pfUpgrade and pfDowngrade in the Structure IP_SMTPC_API.
SMTPC_SEC_POLICY_ALLOW_INSECURE (default) will allow a fallback to an insecure
connection to be used in case no SSL/TLS stack is available or the server does not
offer the AUTH TLS extension.
If a secure connection is possible as the server offers the AUTH TLS connection a
secure connection will be established.
SMTPC_SEC_POLICY_SECURE_ONLY forces the SMTP client to insist on a secure connection
and will refuse to proceed using an insecure connection.
Resource usage
The ROM usage depends on the compiler options, the compiler version and the used
CPU. The memory requirements of the SMTP client presented in the tables below
have been measured on a Cortex-M4 system. Details about the further
configuration can be found in the sections of the specific example.
Configuration used
#define SMTPC_OUT_BUFFER_SIZE 256
#define SMTPC_IN_BUFFER_SIZE 256
#define SMTPC_AUTH_USER_BUFFER_SIZE 48
#define SMTPC_AUTH_PASS_BUFFER_SIZE 48
ROM usage on a Cortex-M4 system
The following resource usage has been measured on a Cortex-M4 system using SEGGER
Embedded Studio V3.10e, size optimization.
Addon | ROM |
emNet SMTP client | approximately 2.7 kBytes |
RAM usage
Addon | RAM |
emNet SMTP client buffers w/o task stack | approximately 600 Bytes |
The RAM requirement for the work buffers on the task stack is approximately 600
bytes for the mentioned configuration. Only the bigger buffer size of
SMTPC_AUTH_USER_BUFFER_SIZE or SMTPC_AUTH_PASS_BUFFER_SIZE is used for a single buffer.
emFTP server (Add-on)
The emFTP server is an optional extension to the emNet TCP/IP stack. The emFTP server can be used with emNet or with a different TCP/IP stack.
All functions which are required to add a FTP server task to your application are described in this chapter.
emFTP server
The emFTP server is an optional extension which adds the FTP protocol to the
stack. FTP stands for File Transfer Protocol. It is the basic mechanism for moving files
between machines over TCP/IP based networks such as the Internet. FTP is a
client/server protocol, meaning that one machine, the client, initiates a file transfer by
contacting another machine, the server and making requests. The server must be operating
before the client initiates his requests. Generally a client communicates with
one server at a time, while most servers are designed to work with multiple simultaneous
clients.
The emFTP server implements the relevant parts of the following RFCs.
RFC# | Description |
[RFC 959] | FTP - File Transfer Protocol Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc959.txt |
The following table shows the contents of the emFTP server root directory:
Directory | Content |
.\Application\ | Contains the example application to run the FTP server with emNet. |
.\Config\ | Contains the FTP server configuration file. |
.\Inc\ | Contains the required include files. |
.\IP\ | Contains the FTP server sources. |
.\IP\FS\ | Contains the sources for the file system abstraction layer and the read-only file system. Refer to File system abstraction layer for detailed information. |
.\Windows\FTPserver\ | Contains the source, the project files and an executable to run emFTP server on a Microsoft Windows host. |
Feature list
- Low memory footprint.
- Multiple connections supported.
- Independent of the file system: Any file system can be used.
- Independent of the TCP/IP stack: Any stack with sockets can be used.
- Demo application included.
- Project for executable on PC for Microsoft Visual Studio included.
Requirements
TCP/IP stack
The emFTP server requires a TCP/IP stack. It is optimized for emNet, but
any RFC-compliant TCP/IP stack can be used. The shipment includes a Win32 simulation,
which uses the standard Winsock API and two implementations which use the
socket API of emNet (with or without TLS secured connection).
Multi tasking
The FTP server needs to run as a separate thread. Therefore, a multi tasking system is required to use the emFTP server.
FTP basics
The File Transfer Protocol (FTP) is an application layer protocol. FTP is an unusual
service in that it utilizes two ports, a ’Data’ port and a ’CMD’ (command) port. Traditionally
these are port 21 for the command port and port 20 for the data port. FTP
can be used in two modes, active and passive. Depending on the mode, the data port
is not always on port 20.
When an FTP client contacts a server, a TCP connection is established between the
two machines. The server does a passive open (a socket is listen) when it begins
operation; thereafter clients can connect with the server via active opens. This TCP
connection persists for as long as the client maintains a session with the server,
(usually determined by a human user) and is used to convey commands from the client
to the server, and the server replies back to the client. This connection is referred
to as the FTP command connection.
The FTP commands from the client to the server consist of short sets of ASCII characters,
followed by optional command parameters. For example, the FTP command to
display the current working directory is PWD (Print Working Directory). All commands
are terminated by a carriage return-linefeed sequence (CRLF) (ASCII 10,13; or Ctrl-J,
Ctrl-M). The servers replies consist of a 3 digit code (in ASCII) followed by some
explanatory text. Generally codes in the 200s are success and 500s are failures. See
the RFC for a complete guide to reply codes. Most FTP clients support a verbose
mode which will allow the user to see these codes as commands progress.
If the FTP command requires the server to move a large piece of data (like a file), a
second TCP connection is required to do this. This is referred to as the FTP data connection
(as opposed to the aforementioned command connection). In active mode
the data connection is opened by the server back to a listening client. In passive
mode the client opens also the data connection. The data connection persists only for
transporting the required data. It is closed as soon as all the data has been sent.
FTP security could be guarantied by a secured connection (TLS). Server could behave as
implicit server: the connection is secured from the start (generally port 990 is used).
Or it could behave as an implicit server: the connection is started normally (generally
port 21 is used) and updated through the AUTH command.
Active mode FTP
In active mode FTP the client connects from a random unprivileged port P (P > 1023) to the FTP server’s command port, port 21.
Then, the client starts listening to port P+1 and sends the FTP command PORT P+1 to the FTP server.
The server will then connect back to the client’s specified data port from its local data port, which is port 20.
Passive mode FTP
In passive mode FTP the client connects from a random unprivileged port P (P > 1023) to the FTP server’s command port, port 21.
In opposite to an active mode FTP connection where the client opens a passive port for data transmission and waits for the connection from server-side,
the client sends in passive mode the “PASV” command to the server and expects an answer with the information on which port the server is listening for the data connection.
After receiving this information, the client connects to the specified data port of the server from its local data port.
FTP reply codes
Every FTP command is answered by one or more reply codes defined in [RFC 959]. A
reply is an acknowledgment (positive or negative) sent from server to user via the
control connection in response to FTP commands. The general form of a reply is a 3-digit
completion code (including error codes) followed by Space <SP>, followed by
one line of text and terminated by carriage return line feed <CRLF>. The codes are
for use by programs and the text is usually intended for human users.
The first digit of the reply code defines the class of response. There are 5 values for
the first digit:
- 1yz: Positive preliminary reply
- 2yz: Positive completion reply
- 3yz: Positive intermediate reply
- 4yz: Transient negative Completion reply
- 5yz: Permanent negative Completion reply
The second digit of the reply code defines the group of the response.
- x0z: Syntax - Syntax errors, syntactically correct commands that don’t fit any
functional category, unimplemented or superfluous commands.
- x1z: Information - These are replies to requests for information, such as status
or help.
- x2z: Connections - Replies referring to the control and data connections.
- x3z: Authentication and accounting - Replies for the login process and accounting
procedures.
- x4z: Unspecified as yet.
- x5z: File system - These replies indicate the status of the Server file system vis-
a-vis the requested transfer or other file system action.
The third digit gives a finer gradation of meaning in each of the function categories,
specified by the second digit.
Supported FTP commands
emFTP server supports a subset of the defined FTP commands.
Refer to [RFC 959] for a complete detailed description of the FTP commands.
The following FTP commands are implemented:
FTP commands | Description |
CDUP | Change to parent directory |
CWD | Change working directory |
DELE | Delete |
LIST | List |
MKD | Make directory |
NLST | Name list |
NOOP | No operation |
PASS | Password |
PASV | Passive |
PORT | Data port |
PWD | Print the current working directory |
QUIT | Logout |
RETR | Retrieve |
RMD | Remove directory |
RNFR | Rename from |
RNTO | Rename to |
SIZE | Size of file |
STOR | Store |
SYST | System |
TYPE | Transfer type |
USER | User name |
XCUP | Change to parent directory |
XMKD | Make directory |
XPWD | Print the current working directory |
XRMD | Remove directory |
AUTH | Authentication mechanism (TLS) |
PBSZ | Protection buffer size |
PROT | Data channel protection level. |
Using the emFTP server sample
Ready to use examples for Microsoft Windows and emNet are supplied. If you use
another TCP/IP stack the sample OS_IP_FTPServer.c has to be adapted. The sample
application opens a port which listens on port 21 until an incoming connection is
detected. If a connection has been established IP_FTPS_Process() handles the client
request in an extra task, so that the server is further listening on port 21. The
example application requires a file system to make data files available. Refer to
File system abstraction layer for detailed information.
Using the emFTP server Windows sample
If you have MS Visual C++ 6.00 or any later version available, you will be able to
work with a Windows sample project using emFTP server. If you do not have
the Microsoft compiler, an precompiled executable of the FTP server is also supplied.
The base directory of the Windows sample application is C:\FTP\.
Building the emFTP server sample program
Open the workspace Start_FTPServer.dsw with MS Visual Studio (for example,
double-clicking it). There is no further configuration necessary. You should be able to
build the application without any error or warning message.
The server uses the IP address of the host PC on which it runs. Open a FTP client and
connect by entering the IP address of the host (127.0.0.1) to connect to the FTP
server. The server accepts anonymous logins. You can also login with the user name
“Admin” and the password “Secret”.
Running the emFTP server example on target hardware
The emFTP server sample application should always be the first step to check
the proper function of the emFTP server with your target hardware.
Add all source files located in the following directories (and their subdirectories) to
your project and update the include path:
- Application
- Config
- Inc
- IP
- IP\IP_FS\[NameOfUsedFileSystem]
It is recommended that you keep the provided folder structure.
The sample application can be used on the most targets without the need for changing
any of the configuration flags. The server processes two connections using the
default configuration.
Note: Two connections mean that the target can handle up one target. A target
requires always two connection, one for the command transfer and one for the data
transfers. Every connection is handled in an separate task. Therefore, the FTP server
uses up to three tasks in the default configuration. One task which listens on port 21
and accepts connections and two tasks to process the accepted connection. To modify
the number of connections only the macro MAX_CONNECTIONS has to be modified.
Access control
The emFTP server supports a fine-grained access permission scheme. Access
permissions can be defined on user-basis for every directory and every file. The
access permission of a directory or a file is a combination of the following attributes:
visible, readable and writable. To control the access permission four callback
functions have be implemented in the user application. The callback functions are defined
in the structure FTPS_ACCESS_CONTROL. For detailed information about these
structure, refer to Structure FTPS_ACCESS_CONTROL.
pfFindUser()
Description
Callback function which checks if the user is valid.
Prototype
int (*pfFindUser) ( const char * sUser );
Parameters
Parameter | Description |
sUser | User name. |
Return value
= 0 - UserID invalid or unknown
> 0 - UserID, no password required
< 0 - UserID, password required
Example
enum {
USER_ID_ANONYMOUS = 1,
USER_ID_ADMIN
};
/*********************************************************************
*
* _FindUser
*
* Function description
* Callback function for user management.
* Checks if user name is valid.
*
* Return value
* 0 UserID invalid or unknown
* > 0 UserID, no password required
* < 0 - UserID, password required
*/
static int _FindUser (const char * sUser) {
if (strcmp(sUser, "Admin") == 0) {
return - USER_ID_ADMIN;
}
if (strcmp(sUser, "anonymous") == 0) {
return USER_ID_ANONYMOUS;
}
return 0;
}
pfCheckPass()
Description
Callback function which checks if the password is valid.
Prototype
int (*pfCheckPass) ( int UserId,
const char * sPass );
Parameters
Parameter | Description |
UserId | Id number |
Pass | Password string. |
Return value
= 0 - UserID known, password valid.
= 1 - UserID unknown or password invalid
Example
enum {
USER_ID_ANONYMOUS = 1,
USER_ID_ADMIN
};
/*********************************************************************
*
* _CheckPass
*
* Function description
* Callback function for user management.
* Checks user password.
*
* Return value
* 0 UserID know, password valid
* 1 UserID unknown or password invalid
*/
static int _CheckPass (int UserId, const char * sPass) {
if ((UserId == USER_ID_ADMIN) && (strcmp(sPass, "Secret") == 0)) {
return 0;
} else {
return 1;
}
}
pfGetDirInfo()
Description
Callback function which checks the permissions of the connected user for every directory.
Prototype
int (*pfGetDirInfo) ( int UserId,
const char * sDirIn,
char * pDirOut,
int SizeOfDirOut );
Parameters
Parameter | Description |
UserId | Id number |
sDirIn | Directory to check permission for |
pDirOut | Directory that can be accessed |
SizeOfDirOut | Size of buffer addressed by pDirOut |
Return value
Returns a combination of the following:
IP_FTPS_PERM_VISIBLE Directory is visible as a directory entry.
IP_FTPS_PERM_READ Directory can be read/entered.
IP_FTPS_PERM_WRITE Directory can be written to.
Example
/* Excerpt from IP_FTPServer.h */
#define IP_FTPS_PERM_VISIBLE (1 << 0)
#define IP_FTPS_PERM_READ (1 << 1)
#define IP_FTPS_PERM_WRITE (1 << 2)
/* Excerpt from OS_IP_FTPServer.c */
/*********************************************************************
*
* _GetDirInfo
*
* Function description
* Callback function for permission management.
* Checks directory permissions.
*
* Return value
* Returns a combination of the following:
* IP_FTPS_PERM_VISIBLE - Directory is visible as a directory entry
* IP_FTPS_PERM_READ - Directory can be read/entered
* IP_FTPS_PERM_WRITE - Directory can be written to
*
* Parameters
* UserId - User ID returned by _FindUser()
* sDirIn - Full directory path and with trailing slash
* sDirOut - Reserved for future use
* DirOutSize - Reserved for future use
*
* Notes
* In this sample configuration anonymous user is allowed to do anything.
* Samples for folder permissions show how to set permissions for different
* folders and users. The sample configures permissions for the following
* directories:
* - /READONLY/: This directory is read only and can not be written to.
* - /VISIBLE/ : This directory is visible from the folder it is located
* in but can not be accessed.
* - /ADMIN/ : This directory can only be accessed by the user "Admin".
*/
static int _GetDirInfo(int UserId, const char* sDirIn, char* sDirOut, int DirOutSize) {
int Perm;
(void)sDirOut;
(void)DirOutSize;
Perm = IP_FTPS_PERM_VISIBLE | IP_FTPS_PERM_READ | IP_FTPS_PERM_WRITE;
if (strcmp(sDirIn, "/READONLY/") == 0) {
Perm = IP_FTPS_PERM_VISIBLE | IP_FTPS_PERM_READ;
}
if (strcmp(sDirIn, "/VISIBLE/") == 0) {
Perm = IP_FTPS_PERM_VISIBLE;
}
if (strcmp(sDirIn, "/ADMIN/") == 0) {
if (UserId != USER_ID_ADMIN) {
return 0; // Only Admin is allowed for this directory
}
}
return Perm;
}
pfGetFileInfo()
Description
Callback function which checks the permissions of the connected user for every file.
Prototype
int (*pfGetFileInfo) ( int UserId,
const char * sFileIn,
char * pFileOut,
int SizeOfFileOut );
Parameters
Parameter | Description |
UserId | Id number |
sFileIn | File to check permission for |
pFileOut | File that can be accessed |
SizeOfFileOut | Size of buffer addressed by pFileOut |
Return value
Returns a combination of the following:
IP_FTPS_PERM_VISIBLE File is visible as a file entry.
IP_FTPS_PERM_READ File can be read.
IP_FTPS_PERM_WRITE File can be written to.
Additional information
Providing a function for file permissions is optional. If using permissions on directory
level is sufficient for your needs pfGetFileInfo may be declared NULL in the
FTPS_ACCESS_CONTROL function table.
Example
/* Excerpt from IP_FTPServer.h */
#define IP_FTPS_PERM_VISIBLE (1 << 0)
#define IP_FTPS_PERM_READ (1 << 1)
#define IP_FTPS_PERM_WRITE (1 << 2)
/* Excerpt from OS_IP_FTPServer.c */
/*********************************************************************
*
* _GetFileInfo
*
* Function description
* Callback function for permission management.
* Checks file permissions.
*
* Return value
* Returns a combination of the following:
* IP_FTPS_PERM_VISIBLE - File is visible as a file entry
* IP_FTPS_PERM_READ - File can be read
* IP_FTPS_PERM_WRITE - File can be written to
*
* Parameters
* UserId - User ID returned by _FindUser()
* sFileIn - Full path to the file
* sFileOut - Reserved for future use
* FileOutSize - Reserved for future use
*
* Notes
* In this sample configuration all file accesses are allowed. File
* permissions are checked against directory permissions. Therefore it
* is not necessary to limit permissions on files that reside in a
* directory that already limits access.
* Setting permissions works the same as for _GetDirInfo() .
*/
static int _GetFileInfo(int UserId, const char* sFileIn, char* sFileOut, int FileOutSize) {
int Perm;
(void)UserId;
(void)sFileIn;
(void)sFileOut;
(void)FileOutSize;
Perm = IP_FTPS_PERM_VISIBLE | IP_FTPS_PERM_READ | IP_FTPS_PERM_WRITE;
return Perm;
}
Configuration
The emNet FTP server can be used without changing any of the compile time
flags. All compile time configuration flags are preconfigured with valid values, which
match the requirements of most applications.
The following types of configuration macros exist:
Binary switches "B"
Switches can have a value of either 0 or 1, for deactivated and activated respectively.
Actually, anything other than 0 works, but 1 makes it easier to read a configuration
file. These switches can enable or disable a certain functionality or behavior.
Switches are the simplest form of configuration macros.
Numerical values "N"
Numerical values are used somewhere in the source code in place of a numerical constant.
A typical example is the configuration of the sector size of a storage medium.
Alias "A"
A macro which operates like a simple text substitute. An example would be the define
U8, which the preprocessor would replace with unsigned char.
Function replacements "F"
Macros can basically be treated like regular functions although certain limitations
apply, as a macro is still put into the source code as simple text replacement. Function
replacements are mainly used to add specific functionality to a module which is
highly hardware-dependent. This type of macro is always declared using brackets
(and optional parameters).
emFTP server compile time configuration switches
Type | Symbolic name | Default | Description |
F | FTPS_WARN | -- | Defines a function to output warnings.
In debug configurations (DEBUG = 1) FTPS_WARN maps to IP_Warnf_Application(). |
F | FTPS_LOG | -- | Defines a function to output logging messages.
In debug configurations (DEBUG = 1) FTPS_LOG maps to IP_Logf_Application(). |
N | FTPS_BUFFER_SIZE | 512 | Defines the size of the send and receive buffer of the FTP server. |
N | FTPS_MAX_PATH | 128 | Defines the maximum length of the buffer used for the path string. |
N | FTPS_MAX_PATH_DIR | 128 | Defines the maximum length of the buffer used for the directory string. |
N | FTPS_MAX_FILE_NAME | 13 | Defines the maximum length of the buffer used for a filename string. |
emFTP server runtime configuration
The input buffer, the output buffer, the path buffer, the directory buffer and the filename buffer
are runtime configurable.
Up to version 3.14 the compile time switches FTPS_AUTH_BUFFER_SIZE, FTPS_MAX_PATH,
FTPS_MAX_PATH_DIR, FTPS_MAX_FILE_NAME and FTPS_ERR_BUFFER_SIZE were used to configure the
sizes of the buffers. These compile time switches are still available to guarantee compatibility to
previous versions and are used as default values for the buffer sizes in applications where the runtime
configuration function IP_FTPS_ConfigBufSizes() is not called.
The compile time switches FTPS_AUTH_BUFFER_SIZE and FTPS_ERR_BUFFER_SIZE are no longer required.
For further information, please refer to IP_FTPS_ConfigBufSizes.
emFTP server system time
The FTP server requires a system time for the transmission of a complete file timestamp.
FTP servers send only a piece of the timestamp of a file, either month, day
and year or month, day and time. For the decision which pieces of the timestamp
has to be transmitted, it compares the year of the current system time with the year
which is stored in the timestamp of the file. Depending on the result of this comparison
either the year or the time will be send. The following two examples show the
output for both cases.
Example
- If the value for year in the timestamp of the file is smaller then the value for year in
the current system time, year will be sent:
-rw-r--r-- 1 root 2000 Jan 1 2007 PAKET00.TXT
In this case, the FTP client leaves this column empty or fills the missing time with
00:00. The following screenshot shows the output of the Microsoft Windows command
line FTP client:
- If the value for year in the timestamp of the file is identical to the value for year
in the current system time, the time (HH:MM) will be sent:
-rw-r--r-- 1 root 1000 Jul 29 11:04 PAKET01.TXT
In this case, the FTP client leaves this column empty or fills the missing year with
the current year. The following screenshot shows the output of the Microsoft
Windows command line FTP client:
In the example, the value for the current time and date is defined to 1980-01-01
00:00. Therefore, the output will be similar to example 1., since no real time clock
(RTC) has been implemented. Refer to pfGetTimeDate() for detailed
information.
pfGetTimeDate()
Description
Returns the current system time.
Prototype
int (*pfGetTimeDate) ( void );
Return value
Current system time. If no real time clock is implemented, it should return
0x00210000 (1980-01-01 00:00)
Additional information
The format of the time is arranged as follows:
Bit 0-4: 2-second count (0-29)
Bit 5-10: Minutes (0-59)
Bit 11-15: Hours (0-23)
Bit 16-20: Day of month (1-31)
Bit 21-24: Month of year (1-12)
Bit 25-31: Number of years since1980 (0-127)
This function pointer is used in the FTPS_APPLICATION structure. Refer to
Structure FTPS_APPLICATION for further information.
Example
static U32 _GetTimeDate(void) {
U32 r;
U16 Sec, Min, Hour;
U16 Day, Month, Year;
Sec = 0; // 0 based. Valid range: 0..59
Min = 0; // 0 based. Valid range: 0..59
Hour = 0; // 0 based. Valid range: 0..23
Day = 1; // 1 based. Means that 1 is 1.
// Valid range is 1..31 (depending on month)
Month = 1; // 1 based. Means that January is 1. Valid range is 1..12.
Year = 28; // 1980 based. Means that 2008 would be 28.
r = Sec / 2 + (Min << 5) + (Hour << 11);
r |= (U32)(Day + (Month << 5) + (Year << 9)) << 16;
return r;
}
API functions
IP_FTPS_ConfigBufSizes()
Description
Sets the buffer size used by the FTP server tasks.
Prototype
void IP_FTPS_ConfigBufSizes(FTPS_BUFFER_SIZES * pBufferSizes);
Parameters
Parameter | Description |
pBufferSizes | Configuration of buffer sizes. |
For detailed information about the structure type FTPS_BUFFER_SIZES refer to
Structure FTPS_BUFFER_SIZES.
IP_FTPS_CountRequiredMem()
Description
Counts the memory required for one thread. This can be used to
determine the total required memory pool size for a configuration.
Prototype
U32 IP_FTPS_CountRequiredMem(FTPS_CONTEXT * pContext);
Parameters
Parameter | Description |
pContext | Context keeping track of configured settings. Can be NULL. |
Return value
Amount of memory required for internals to handle one thread.
Additional information
In addition to the memory requirement calculated for the FTP
server internals, some additional memory might be required for
managing a memory pool.
IP_FTPS_Init()
Description
Initializes the application specific FTP server context.
This context is specific to one connection.
Has to be called if IP_FTPS_ProcessEx() is used for the task
processing.
Prototype
void IP_FTPS_Init( FTPS_CONTEXT * pContext,
const IP_FTPS_API * pIP_API,
const IP_FS_API * pFS_API,
const FTPS_APPLICATION * pApplication,
const FTPS_SYS_API * pSYS_API);
Parameters
Parameter | Description |
pContext | Pointer to the FTP server application context. This keeps track of configured settings. |
pIP_API | Function table with API functions necessary for IP operations. |
pFS_API | Function table with API functions for file system operations. |
pApplication | FTP server application settings. |
pSYS_API | Function table with API functions necessary for system operations. |
Additional information
The structure type IP_FTPS_API contains mappings of the required
socket functions to the actual IP stack. This is required because
the socket functions are slightly different on different systems.
For detailed information about the used structure types, please refer to:
IP_FTPS_Process()
Description
Thread functionality of the FTP server.
Initializes and starts the FTP server. Returns when the
connection is closed or a fatal error occurs.
Prototype
int IP_FTPS_Process(const IP_FTPS_API * pIP_API,
FTPS_SOCKET hCtrlSock,
const IP_FS_API * pFS_API,
const FTPS_APPLICATION * pApplication);
Parameters
Parameter | Description |
pIP_API | Function table with API functions necessary for IP operations. |
hCtrlSock | Handle of the control socket. |
pFS_API | Function table with API functions for file system operations. |
pApplication | FTP server application settings. |
Return value
Additional information
New implementations should use IP_FTPS_ConfigBufSizes(),
IP_FTPS_Init() and IP_FTPS_ProcessEx() instead of IP_FTPS_Process() .
The structure type IP_FTPS_API contains mappings of the required
socket functions to the actual IP stack. This is required because
the socket functions are slightly different on different systems.
The hCtrlSock is the socket which was created when the client has
been connected to the command port (usually port 21).
For detailed information about the structure type IP_FS_API refer to
File system abstraction layer. For detailed information about the structure
type FTPS_APPLICATION refer to Structure FTPS_APPLICATION.
IP_FTPS_ProcessEx()
Description
Thread functionality of the FTP server.
Returns when the connection is closed or a fatal error occurs.
Prototype
int IP_FTPS_ProcessEx(FTPS_CONTEXT * pContext,
FTPS_SOCKET hCtrlSock);
Parameters
Parameter | Description |
pContext | Pointer to the FTP server application context. This keeps track of configured settings. |
hCtrlSock | Handle of the control socket. |
Return value
Additional information
The hCtrlSock is the socket which was created when the client has
been connected to the command port (usually port 21).
IP_FTPS_OnConnectionLimit()
Description
Sends the indication that the connection limit is reached.
Prototype
void IP_FTPS_OnConnectionLimit(const IP_FTPS_API * pIP_API,
FTPS_SOCKET hCtrlSock);
Parameters
Parameter | Description |
pIP_API | Function table with API functions necessary for IP operations. |
hCtrlSock | Handle of the control socket. |
Additional information
The structure type IP_FTPS_API contains mappings of the required
socket functions to the actual IP stack. This is required because
the socket functions are slightly different on different systems.
The hCtrlSock is the socket which was created when the client has
been connected to the command port (usually port 21).
IP_FTPS_SetSignOnMsg()
Description
Sets the sign on message for the FTP server.
Prototype
void IP_FTPS_SetSignOnMsg(const char * sSignOnMsg);
Parameters
Parameter | Description |
sSignOnMsg | The “sign on” message. |
Additional information
If not set with this function, the default sign on message from
the FTPS_SIGN_ON_MSG define will be used.
IP_FTPS_IsDataSecured()
Description
Indicates if the data connection is also secured.
Prototype
int IP_FTPS_IsDataSecured(const FTPS_CONTEXT * pContext);
Parameters
Parameter | Description |
pContext | Pointer to the FTP context. |
Return value
0 | Data connection is not secured. |
1 | Data connection is secured. |
Additional information
If pContext is NULL, it is assumed that data are secured too.
IP_FTPS_AllowOnlySecured()
Description
Makes the server allowing only secured connections in explicit
mode (FTPES). When this API is called, the command connection
shall be secured. If the flag DataOnOff is set, data connection
shall also be secured.
Prototype
void IP_FTPS_AllowOnlySecured(FTPS_CONTEXT * pContext,
unsigned DataOnOff);
Parameters
Parameter | Description |
pContext | Pointer to the FTP context. |
DataOnOff | Flag to indicate if the data connection shall be also secured. |
IP_FTPS_SetImplicitMode()
Description
Indicates to the server that implicit mode (FTPS) is active.
Prototype
void IP_FTPS_SetImplicitMode(FTPS_CONTEXT * pContext);
Parameters
Parameter | Description |
pContext | Pointer to the FTP context. |
IP_FTPS_UseRenameToFullPath()
Description
Makes the server use the full path with the IP_FS layer for a
rename operation.
Prototype
void IP_FTPS_UseRenameToFullPath(FTPS_CONTEXT * pContext);
Parameters
Parameter | Description |
pContext | Pointer to the FTP context. |
Additional information
By default many filesystems expect only the new name to be given
in a rename operation and might even fail if given a full path.
This routine allows the full path of the new name to be given to
the IP_FS layer if this is required with your filesystem.
IP_FTPS_SetSignOnMsgCallback()
Description
Sets a callback that gets executed to send a sign on message
to a new client.
Prototype
void IP_FTPS_SetSignOnMsgCallback(FTPS_CONTEXT * pContext,
FTPS_SEND_SIGN_ON_MSG_FUNC * pf);
Parameters
Parameter | Description |
pContext | Pointer to the FTP context. |
pf | Callback to set. |
Additional information
This API has to be called after IP_FTPS_Init() .
Example
/*********************************************************************
*
* _cbSendSignOnMessage()
*
* Function description
* Sends a custom sign on message to a client.
*
* Parameters
* pOutput: Connection context.
* Code : The three digit status code of the message.
* p : Reserved for future extensions of this API.
*
* Additional information
* A sign on message can consist of multiple lines and has to be
* in the following format (the value 220 is assumed as Code):
*
* 220-A multi line response starts with the code and a hyphen.\r\n
* Further lines do not need to use the code in front.\r\n
* All lines provided by the callback need to end with CRLF.\r\n
* Lines can start with one or multiple whitespaces.\r\n
* 220 The last line is indicated by the code followed by a whitespace.\r\n
*/
static void _cbSendSignOnMessage(FTPS_OUTPUT* pOutput, unsigned Code, void* p) {
FTPS_USE_PARA(p);
//
// A sign on message can be dynamically generated using a formatted
// output. The message can also be generated using multiple calls to
// IP_FTPS_Send* API calls.
// Please do not forget to add the CRLF at each end of line.
//
IP_FTPS_SendFormattedString(pOutput, "%u-Welcome to emFTP server\r\n"
" This is an example of a multi line sign on message generated via callback.\r\n"
"%u It simply works!\r\n", Code, Code);
}
void main(void) {
...
IP_FTPS_Init(&FTPSContext, &_IP_API, _pFS_API, &_Application, &_Sys_API);
IP_FTPS_SetSignOnMsgCallback(&FTPSContext, _cbSendSignOnMessage);
...
}
Description
Sends a string with placeholders that will be filled using
SEGGER_vsnprintfEx() for one line of a sign on message.
Prototype
int IP_FTPS_SendFormattedString( FTPS_OUTPUT * pOutput,
const char * sFormat,
...);
Parameters
Parameter | Description |
pOutput | Connection context. |
sFormat | Formatted string that might contain placeholders. |
Return value
Number of characters (without termination) that would have been
stored if the buffer had been large enough.
Additional information
Allows sending a string containing placeholders without the
need to have the final string created into a temporary buffer
in the application. The output buffer is used directly which
saves a buffer and avoids unnecessary copy operations from
the application to the output buffer.
This routine is only meant to be used from within a callback
that has been set using IP_FTPS_SetSignOnMsgCallback() .
IP_FTPS_SendMem()
Description
Sends data via the control connection.
Prototype
int IP_FTPS_SendMem( FTPS_OUTPUT * pOutput,
const U8 * pData,
unsigned NumBytes);
Parameters
Parameter | Description |
pOutput | Connection context. |
pData | Pointer to a memory location to send. |
NumBytes | Number of bytes to send. |
Return value
Additional information
This routine is only meant to be used from within a callback
that has been set using IP_FTPS_SetSignOnMsgCallback() .
IP_FTPS_SendString()
Description
Sends a zero-terminated string via the control connection.
Prototype
int IP_FTPS_SendString( FTPS_OUTPUT * pOutput,
const char * s);
Parameters
Parameter | Description |
pOutput | Connection context. |
s | String to send. |
Return value
Additional information
This routine is only meant to be used from within a callback
that has been set using IP_FTPS_SetSignOnMsgCallback() .
IP_FTPS_SendUnsigned()
Description
Sends an unsigned value via the control connection.
Prototype
int IP_FTPS_SendUnsigned(FTPS_OUTPUT * pOutput,
unsigned v,
unsigned Base,
int NumDigits);
Parameters
Parameter | Description |
pOutput | Connection context. |
v | Value to send. |
Base | Numerical base of the value v. |
NumDigits | Number of digits to send. 0 can be used as a wildcard. |
Return value
Additional information
This routine is only meant to be used from within a callback
that has been set using IP_FTPS_SetSignOnMsgCallback() .
Data structures
Structure IP_FTPS_API
Description
This structure contains the pointer to the socket functions which are required to use the FTP server.
Prototype
typedef struct {
int (*pfSend) (const unsigned char* pData, int Len,
FTPS_SOCKET hSock);
int (*pfReceive) ( unsigned char* pData, int Len,
FTPS_SOCKET hSock);
FTPS_SOCKET (*pfConnect) (FTPS_SOCKET hCtrlSock, U16 Port);
void (*pfDisconnect)(FTPS_SOCKET hDataSock);
FTPS_SOCKET (*pfListen) (FTPS_SOCKET hCtrlSock, U16* pPort, U8* pIPAddr);
int (*pfAccept) (FTPS_SOCKET hCtrlSock, FTPS_SOCKET* phDataSocket);
int (*pfSetSecure) (FTPS_SOCKET Socket, FTPS_SOCKET Clone);
} IP_FTPS_API;
Member | Description |
pfSend | Callback function that sends data to the client on socket level. |
pfReceive | Callback function that receives data from the client on socket level. |
pfConnect | Callback function that handles the connect back to a FTP client on
socket level if not using passive mode. |
pfDisconnect | Callback function that disconnects a connection to the FTP client on
socket level if not using passive mode. |
pfListen | Callback function that binds the server to a port and addr. |
pfAccept | Callback function that accepts incoming connections. |
pfSetSecure | Callback function that sets a FTPS_SOCKET (input command connection) as secured
and eventually clone it for the output command connection. Could be NULL if TLS
security is not supported. |
Structure FTPS_ACCESS_CONTROL
Description
This structure contains the pointer to the access control callback functions.
Prototype
typedef struct {
int (*pfFindUser) (const char* sUser);
int (*pfCheckPass) (int UserId, const char* sPass);
int (*pfGetDirInfo) (int UserId, const char* sDirIn , char* sDirOut ,
int SizeOfDirOut);
int (*pfGetFileInfo)(int UserId, const char* sFileIn, char* sFileOut,
int SizeOfFileOut);
} FTPS_ACCESS_CONTROL;
Member | Description |
pfFindUser | Callback function that checks if the user is valid. |
pfCheckPass | Callback function that checks if the password is valid. |
pfGetDirInfo | Callback function that checks the permissions of the connected user
for every directory. |
pfGetFileInfo | Callback function that checks the permissions of the connected user
for every file. May be NULL if directory permissions are sufficient for
your needs. |
Example
Refer to Access control for an example.
FTPS_BUFFER_SIZES
Description
Contains the configuration for the buffer to allocate when using
IP_FTPS_ProcessEx() .
Type definition
typedef struct {
U32 NumBytesInBuf;
U32 NumBytesInBufBeforeFlush;
U32 NumBytesOutBuf;
U32 NumBytesCwdNameBuf;
U32 NumBytesPathNameBuf;
U32 NumBytesDirNameBuf;
U32 NumBytesFileNameBuf;
} FTPS_BUFFER_SIZES;
Structure members
Member | Description |
NumBytesInBuf | Size of Rx buffer. By default FTPS_BUFFER_SIZE . |
NumBytesInBufBeforeFlush | Number of bytes to collect in Rx buffer before they are written to the filesystem. 0 : Disabled (default). Chunks regardless of their size read will be written directly to the filesystem. NumBytes: Typically the same as NumBytesInBuf and should be a multiple of the block size used by your filesystem e.g. 2k sectors for NAND or SD-card. The data receive function will be called multiple times until the InBuffer gets saturated for the flush or the last chunk of data (connection close) has been read. |
NumBytesOutBuf | Size of Tx buffer. By default FTPS_BUFFER_SIZE . |
NumBytesCwdNameBuf | Size of buffer used for the Current Working Directory. By default FTPS_MAX_PATH_DIR . |
NumBytesPathNameBuf | Size of buffer used for paths (directory + filename). By default FTPS_MAX_PATH . |
NumBytesDirNameBuf | Size of buffer used for dir(ectory) names (directory without filename). By default FTPS_MAX_PATH . |
NumBytesFileNameBuf | Size of buffer used for filenames. By default FTPS_MAX_FILE_NAME . |
Structure FTPS_SYS_API
Description
This structure contains the pointers to system functions which are required to use the emFTP server with IP_FTPS_Init() and IP_FTPS_ProcessEx().
Prototype
typedef struct {
void* (*pfAlloc)(U32 NumBytesReq);
void (*pfFree) (void* p);
} IP_FTPS_API;
Member | Description |
pfAlloc | Callback function that allocates memory for buffers as configured using IP_FTPS_ConfigBufSizes(). |
pfFree | Callback function that frees previously allocated resources. |
Structure FTPS_APPLICATION
Description
Used to store application specific parameters.
Prototype
typedef struct {
FTPS_ACCESS_CONTROL* pAccess;
U32 (*pfGetTimeDate) (void);
} FTPS_APPLICATION;
Member | Description |
pAccess | Pointer to the FTPS_ACCESS_APPLCIATION structure. |
pfGetTimeDate | Pointer to the function which returns the current system time. |
Additional information
For additional information to structure FTPS_ACCESS_APPLICATION refer to
Structure FTPS_ACCESS_CONTROL. For additional information to function
pointer pfGetTimeDate() refer to emFTP server system time.
Example
/* Excerpt from OS_IP_FTPServer.c */
/*********************************************************************
*
* FTPS_ACCESS_CONTROL
*
* Description
* User/pass data table
*/
static FTPS_ACCESS_CONTROL _Access_Control = {
_FindUser,
_CheckPass,
_GetDirInfo
};
*********************************************************************
*
* _GetTimeDate
*/
static U32 _GetTimeDate(void) {
U32 r;
U16 Sec, Min, Hour;
U16 Day, Month, Year;
Sec = 0; // 0 based. Valid range: 0..59
Min = 0; // 0 based. Valid range: 0..59
Hour = 0; // 0 based. Valid range: 0..23
Day = 1; // 1 based. Means that 1 is 1.
// Valid range is 1..31 (depending on month)
Month = 1; // 1 based. Means that January is 1. Valid range is 1..12.
Year = 28; // 1980 based. Means that 2008 would be 28.
r = Sec / 2 + (Min << 5) + (Hour << 11);
r |= (U32)(Day + (Month << 5) + (Year << 9)) << 16;
return r;
}
*********************************************************************
*
* FTPS_APPLICATION
*
* Description
* Application data table, defines all application specifics
* used by the FTP server
*/
static const FTPS_APPLICATION _Application = {
&_Access_Control,
_GetTimeDate
};
FTPS_SEND_SIGN_ON_MSG_FUNC
Description
Callback executed for sending a sign on message for a new client.
Type definition
typedef void (FTPS_SEND_SIGN_ON_MSG_FUNC)(FTPS_OUTPUT * pOutput,
unsigned Code,
void * p);
Parameters
Parameter | Description |
pOutput | Connection context. |
Code | The three digit status code of the message. |
p | Reserved for future extensions of this API. |
Additional information
A sign on message can consist of multiple lines and has to be
in the following format (the value 220 is assumed as Code):
220-A multi line response starts with the code and a hyphen.\r\n
Further lines do not need to use the code in front.\r\n
All lines provided by the callback need to end with CRLF.\r\n
Lines can start with one or multiple whitespaces.\r\n
220 The last line is indicated by the code followed by a whitespace.\r\n
Resource usage
The ROM usage depends on the compiler options, the compiler version and the used
CPU. The memory requirements of the FTP server presented in the tables below have
been measured on a Cortex-M4 system. Details about the further configuration
can be found in the sections of the specific example.
Configuration used
#define FTPS_BUFFER_SIZE 512
#define FTPS_MAX_PATH 128
#define FTPS_MAX_PATH_DIR 128
#define FTPS_MAX_FILE_NAME 13
ROM usage on a Cortex-M4 system
The following resource usage has been measured on a Cortex-M4 system using
SEGGER’s Embedded Studio V3.12 using GCC version 6.2.1 20161205 (release) [ARM/embedded-6-branch revision 243739] (arm-none-eabi) with size optimization.
Addon | ROM |
emFTP server | approximately 7.3 kBytes |
RAM usage
Using the legacy API IP_FTPS_Process(), almost all of the RAM used by the FTP server is taken from task stacks.
For new implementations IP_FTPS_ProcessEx() should be used, which allocates memory using a callback, keeping the
task stack requirement low.
The amount of RAM required for every child task depends on the configuration of your server. The table below shows
typical RAM requirements for your task stacks.
Task | Description | RAM |
ParentTask | Listens for incoming connections. | approximately 500 bytes including TCP/IP task stack. |
ChildTask | Handles a request. | approximately 1800 bytes for the FTP server including TCP/IP stack (excluding filesystem). |
Note: The emFTP server requires at least 1 child task.
The approximately RAM usage for the FTP server buffers can be calculated by adding up all buffer sizes configured using
IP_FTPS_ConfigBufSizes(). The function IP_FTPS_CountRequiredMem() can be used to retrieve the required memory for the
buffers for one child task for the current configuration.
The FTP server sample is designed to help you to find the correct configuration by using IP_FTPS_CountRequiredMem().
In addition the sample warns you about an insufficient memory configuration.
emFTP client (Add-on)
The emFTP client is an optional extension to the emNet TCP/IP stack. The emFTP client can be used with emNet or with a different TCP/IP stack.
All functions which are required to add a emFTP client to your application are described in this chapter.
emFTP client
The emFTP client is an optional extension which adds the client part of FTP protocol to the stack.
FTP stands for File Transfer Protocol. It is the basic mechanism for moving files between machines over TCP/IP based networks such as the Internet.
FTP is a client/server protocol, meaning that one machine, the client, initiates a file transfer by contacting another machine, the server and making requests.
The FTP client implements the relevant parts of the following RFCs.
RFC# | Description |
[RFC 959] | FTP - File Transfer Protocol Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc959.txt |
The following table shows the contents of the emFTP client root directory:
Directory | Content |
.\Application\ | Contains the example application to run the FTP client with emNet. |
.\Config\ | Contains the FTP client configuration file. |
.\Inc\ | Contains the required include files. |
.\IP\ | Contains the FTP client sources. |
.\IP\FS\ | Contains the sources for the file system abstraction layer and the read-only file system. Refer to File system abstraction layer for detailed information. |
.\Windows\FTPclient\ | Contains the source, the project files and an executable to run emFTP client on a Microsoft Windows host. |
Feature list
- Low memory footprint.
- Multiple connections supported.
- Independent of the file system: Any file system can be used.
- Independent of the TCP/IP stack: Any stack with sockets can be used.
- Demo application included.
- Project for executable on PC for Microsoft Visual Studio included.
Requirements
TCP/IP stack
The emFTP client requires a TCP/IP stack. It is optimized for emNet, but
any RFC-compliant TCP/IP stack can be used. The shipment includes a Win32 simulation,
which uses the standard Winsock API and an implementation which uses the
socket API of emNet.
FTP basics
The File Transfer Protocol (FTP) is an application layer protocol. FTP is an unusual
service in that it utilizes two ports, a ’Data’ port and a ’CMD’ (command) port. Traditionally
these are port 21 for the command port and port 20 for the data port. FTP
can be used in two modes, active and passive. Depending on the mode, the data port
is not always on port 20.
When an FTP client contacts a server, a TCP connection is established between the
two machines. The server does a passive open (a socket is listen) when it begins
operation; thereafter clients can connect with the server via active opens. This TCP
connection persists for as long as the client maintains a session with the server,
(usually determined by a human user) and is used to convey commands from the client
to the server, and the server replies back to the client. This connection is referred
to as the FTP command connection.
The FTP commands from the client to the server consist of short sets of ASCII characters,
followed by optional command parameters. For example, the FTP command to
display the current working directory is PWD (Print Working Directory). All commands
are terminated by a carriage return-linefeed sequence (CRLF) (ASCII 10,13; or Ctrl-J,
Ctrl-M). The servers replies consist of a 3 digit code (in ASCII) followed by some
explanatory text. Generally codes in the 200s are success and 500s are failures. See
the RFC for a complete guide to reply codes. Most FTP clients support a verbose
mode which will allow the user to see these codes as commands progress.
If the FTP command requires the server to move a large piece of data (like a file), a
second TCP connection is required to do this. This is referred to as the FTP data connection
(as opposed to the aforementioned command connection). In active mode
the data connection is opened by the server back to a listening client. In passive
mode the client opens also the data connection. The data connection persists only for
transporting the required data. It is closed as soon as all the data has been sent.
Active mode FTP
In active mode FTP the client connects from a random unprivileged port P (P > 1023) to the FTP server’s command port, port 21.
Then, the client starts listening to port P+1 and sends the FTP command PORT P+1 to the FTP server.
The server will then connect back to the client’s specified data port from its local data port, which is port 20.
Passive mode FTP for the client
In passive mode FTP the client connects from a random unprivileged port P (P > 1023) to the FTP server’s command port, port 21.
In opposite to an active mode FTP connection where the client opens a passive port for data transmission and waits for the connection from server-side,
the client sends in passive mode the “PASV” command to the server and expects an answer with the information on which port the server is listening for the data connection.
After receiving this information, the client connects to the specified data port of the server from its local data port.
Connection security
When a SSL stack is present (for example emSSL),
the connection could be secured. To do so the value of the Mode parameter of the API IP_FTPC_Connect()
could be added with FTPC_MODE_EXPLICIT_TLS_REQUIRED or FTPC_MODE_IMPLICIT_TLS_REQUIRED.
FTP implicit mode
When a server works in implicit mode, every connections are secured from the start.
It uses a different port than the regular 21 (usually 990). Thus the client has to
connect to the right port and upgrade the connection to a secure one.
FTP explicit mode
When a server works in explicit mode, the connection start normally as in plain mode.
Then the client sends a PROT command to request an upgrade of the connection.
When the connection is secured, the exchange goes on with user and password
as usual.
Supported FTP client commands
emFTP client supports a subset of the defined FTP commands. Refer to
[RFC 959] for a complete detailed description of the FTP commands. The following FTP
commands are implemented:
FTP commands | Description |
CDUP | Change to parent directory |
CWD | Change working directory |
LIST | List directory |
MKD | Make directory |
PASS | Password |
PWD | Print the current working directory |
RETR | Retrieve |
RMD | Remove directory |
STOR | Store |
APPE | Append |
TYPE | Transfer type |
USER | User name |
PROT | Set protection behavior. |
PBSZ | Set protection buffer size. |
Configuration
The emFTP client can be used without changing any of the compile time flags.
All compile time configuration flags are preconfigured with valid values, which match
the requirements of most applications.
The following types of configuration macros exist:
Binary switches "B"
Switches can have a value of either 0 or 1, for deactivated and activated respectively.
Actually, anything other than 0 works, but 1 makes it easier to read a configuration
file. These switches can enable or disable a certain functionality or behavior.
Switches are the simplest form of configuration macros.
Numerical values "N"
Numerical values are used somewhere in the source code in place of a numerical constant.
A typical example is the configuration of the sector size of a storage medium.
Alias "A"
A macro which operates like a simple text substitute. An example would be the define
U8, which the preprocessor would replace with unsigned char.
Function replacements "F"
Macros can basically be treated like regular functions although certain limitations
apply, as a macro is still put into the source code as simple text replacement. Function
replacements are mainly used to add specific functionality to a module which is
highly hardware-dependent. This type of macro is always declared using brackets
(and optional parameters).
FTP client compile time configuration switches
Type | Symbolic name | Default | Description |
F | FTPc_WARN | -- | Defines a function to output warnings.
In debug configurations (DEBUG = 1) FTPc_WARN maps to IP_Warnf_Application(). |
F | FTPc_LOG | -- | Defines a function to output logging messages.
In debug configurations (DEBUG = 1) FTPc_LOG maps to IP_Logf_Application() . |
N | FTPC_BUFFER_SIZE | 512 | Defines the size of the in and the out buffer of the FTP client.
This means that the client requires the defined number of bytes for each buffer.
For example, FTPC_BUFFER_SIZE = 512 means 1024 bytes RAM requirement. |
N | FTPC_CTRL_BUFFER_SIZE | 256 | Defines the maximum length of the buffer used for the control channel. |
N | FTPC_SERVER_REPLY_BUFFER_SIZE | 128 | Defines the maximum length of the buffer used for the server reply strings.
This buffer is only required and used in debug builds.
In release builds the memory will not be allocated. |
API functions
IP_FTPC_Connect()
Description
Connects to a FTP server. The complete login process including
the authentication is handled by this function.
Prototype
int IP_FTPC_Connect( IP_FTPC_CONTEXT * pContext,
const char * sServer,
const char * sUser,
const char * sPass,
unsigned PortCmd,
unsigned Mode);
Parameters
Parameter | Description |
pContext | Pointer to a structure of type IP_FTPC_CONTEXT. |
sServer | Dot-decimal IP address of a FTP server, for example “192.168.11.55”. |
sUser | User name if required for the authentication. Can be NULL. |
sPass | Password if required for the authentication. Can be NULL. |
PortCmd | Port number in listening mode on the FTP server. Generally servers are using 21. |
Mode | FTP transfer mode. Mode is a mask describing the connection mode and the security. Mask is as follow with default (0) set to FTPC_MODE_ACTIVE and FTPC_MODE_PLAIN_FTP: FTPC_MODE_ACTIVE or FTPC_MODE_PASSIVE. FTPC_MODE_PLAIN_FTP or FTPC_MODE_EXPLICIT_TLS_REQUIRED or FTPC_MODE_IMPLICIT_TLS_REQUIRED. |
Return value
0 | Success. |
1 | Error. Illegal parameter (pContext = NULL). |
-1 | Error during the process of connection establishment. |
Additional information
The function IP_FTPC_Init() must be called before a call IP_FTPC_Connect().
Note: In the current version of emNet, the FTP client supports only passive
mode FTP.
Example
Refer to IP_FTPC_ExecCmd for an example application which uses
IP_FTPC_Connect().
IP_FTPC_Disconnect()
Description
Closes an established connection to a FTP server.
Prototype
int IP_FTPC_Disconnect(IP_FTPC_CONTEXT * pContext);
Parameters
Parameter | Description |
pContext | Pointer to a structure of type IP_FTPC_CONTEXT. |
Return value
0 | Success. |
1 | Error. Illegal parameter (pContext = NULL) |
Example
Refer to IP_FTPC_ExecCmd for an example application which uses
IP_FTPC_Disconnect().
IP_FTPC_ExecCmd()
Description
Executes a FTP command to the FTP server.
Prototype
int IP_FTPC_ExecCmd( IP_FTPC_CONTEXT * pContext,
IP_FTPC_CMD Cmd,
const char * sPara);
Parameters
Parameter | Description |
pContext | Pointer to a structure of type IP_FTPC_CONTEXT. |
Cmd | The command to perform. |
sPara | String with the required parameters for the command. Depending on the command, this parameter can be NULL. |
Return value
0 | Succes. |
1 | Error. Illegal parameter (pContext = NULL). |
-1 | Error during command execution. |
Valid values for parameter Cmd
Valid values | Description |
FTPC_CMD_CDUP | The command CDUP (Change to Parent Directory). sPara is NULL. |
FTPC_CMD_CWD | The command CWD (Change Working Directory). sPara is the
path to the directory that should be accessed. |
FTPC_CMD_LIST | The command LIST (List current directory content). sPara can be NULL
to list the current directory. sPara can be used to specify a
directory to list that is not the current working directory. |
FTPC_CMD_MKD | The command MKD (Make directory). sPara is the name of the
directory that should be created. |
FTPC_CMD_PASS | The command PASS (Set password). sPara is the password. |
FTPC_CMD_PWD | The command PWD (Print Working Directory). sPara is NULL. |
FTPC_CMD_RETR | The command RETR (Retrieve). sPara is the name of the file that
should be received from the server. The FTP client creates a
file on the used storage medium and stores the retrieved file. |
FTPC_CMD_RMD | The command RMD (Remove directory). sPara is the name of
the directory that should be removed. |
FTPC_CMD_STOR | The command STOR (Store). sPara is the name of the file that
should be stored on the server. The FTP client opens the file and
transmits it to the FTP server. |
FTPC_CMD_APPE | The command APPE (Append). sPara is the name of the file that
should be appended on the server. The FTP client opens the file and
transmits the content to append to the end of the file to the FTP server. |
FTPC_CMD_TYPE | The command TYPE (Transfer type). sPara is the transfer type. |
FTPC_CMD_USER | The command USER (Set username). sPara is the username. |
FTPC_CMD_DELE | The command DELE (delete file). sPara is the name of the file to delete. |
FTPC_CMD_PROT | The command PROT (set protection behavior). sPara is the value to set. |
FTPC_CMD_PBSZ | The command PBSZ (set protection buffer size). sPara is the
value to set (typically 0). |
Additional information
IP_FTPC_Init() and IP_FTPC_Connect() have to be called before
IP_FTPC_ExecCmd(). Refer to IP_FTPC_Init for detailed information
about how to initialize the FTP client and refer to IP_FTPC_Connect for
detailed information about how to establish a connection to a FTP server.
IP_FTPC_ExecCmd() sends a command to the server and handles everything what is
required on FTP client side. The commands which are listed in section Supported FTP
client commands on page 663, but not explained here, are normally not directly
called from the user application. There is no need to call IP_ExecCmd() with these
commands. The FTP client uses these commands internally and sends them to the
server if required. For example, the call of IP_FTPC_Connect() sends the the commands
USER, PASS and SYST to the server and process the server replies for each of
the commands, an explicit call of IP_FTPC_Exec() with one of these commands is not
required.
Example
/* Excerpt from the example application OS_IP_FTPClient.c */
/*********************************************************************
*
* MainTask
*
* Note:
* The size of the stack of this task should be at least
* 1200 bytes + FTPC_CTRL_BUFFER_SIZE + 2 * FTPC_BUFFER_SIZE.
*/
void MainTask(void);
void MainTask(void) {
IP_FTPC_CONTEXT FTPConnection;
U8 acCtrlIn[FTPC_CTRL_BUFFER_SIZE];
U8 acDataIn[FTPC_BUFFER_SIZE];
U8 acDataOut[FTPC_BUFFER_SIZE];
int r;
//
// Initialize the IP stack
//
IP_Init();
OS_CREATETASK(&_TCB, "IP_Task", IP_Task , 150, _IPStack); // Start the IP_Task
//
// Check if target is configured
//
while (IP_IFaceIsReady() == 0) {
BSP_ToggleLED(1);
OS_Delay(50);
}
//
// FTP client task
//
while (1) {
BSP_SetLED(0);
//
// Initialize FTP client context
//
memset(&FTPConnection, 0, sizeof(FTPConnection));
//
// Initialize the FTP client
//
IP_FTPC_Init(&FTPConnection, &_IP_Api, &IP_FS_FS, acCtrlIn, sizeof(acCtrlIn),
acDataIn, sizeof(acDataIn), acDataOut, sizeof(acDataOut));
//
// Connect to the FTP server
//
r = IP_FTPC_Connect(&FTPConnection, "192.168.199.164", "Admin", "Secret",
21, FTPC_MODE_PASSIVE);
if (r == FTPC_ERROR) {
FTPC_LOG(("APP: Could not connect to FTP server.\r\n"));
goto Disconnect;
}
//
// Change from root directory into directory "Test"
//
r = IP_FTPC_ExecCmd(&FTPConnection, FTPC_CMD_CWD, "/Test/");
if (r == FTPC_ERROR) {
FTPC_LOG(("APP: Could not change working directory.\r\n"));
goto Disconnect;
}
//
// Upload the file "Readme.txt
//
r = IP_FTPC_ExecCmd(&FTPConnection, FTPC_CMD_STOR, "Readme.txt");
if (r == FTPC_ERROR) {
FTPC_LOG(("APP: Could not upload data file.\r\n"));
goto Disconnect;
}
//
// Change back to root directory.
//
r = IP_FTPC_ExecCmd(&FTPConnection, FTPC_CMD_CDUP, NULL);
if (r == FTPC_ERROR) {
FTPC_LOG(("APP: Change to parent directory failed.\r\n"));
goto Disconnect;
}
//
// Disconnect.
//
Disconnect:
IP_FTPC_Disconnect(&FTPConnection);
FTPC_LOG(("APP: Done.\r\n"));
BSP_ClrLED(0);
OS_Delay (10000);
}
}
IP_FTPC_ExecCmdEx()
Description
Executes a FTP command to the FTP server.
Prototype
int IP_FTPC_ExecCmdEx(IP_FTPC_CONTEXT * pContext,
IP_FTPC_CMD Cmd,
IP_FTPC_CMD_CONFIG * pConfig);
Parameters
Parameter | Description |
pContext | Pointer to a structure of type IP_FTPC_CONTEXT. |
Cmd | The command to perform. |
pConfig | Extended configuration of type IP_FTPC_CMD_CONFIG for the command to execute. The old parameter sPara of IP_FTPC_ExecCmd() can also be used via the member IP_FTPC_CMD_CONFIG.sPara . |
Return value
0 | Succes. |
1 | Error. Illegal parameter (pContext = NULL). |
-1 | Error during command execution. |
IP_FTPC_Init()
Description
Initializes the context of the FTP client.
Prototype
int IP_FTPC_Init( IP_FTPC_CONTEXT * pContext,
const IP_FTPC_API * pIP_API,
const IP_FS_API * pFS_API,
U8 * pCtrlBuffer,
unsigned NumBytesCtrl,
U8 * pDataInBuffer,
unsigned NumBytesDataIn,
U8 * pDataOutBuffer,
unsigned NumBytesDataOut);
Parameters
Parameter | Description |
pContext | Pointer to a structure of type IP_FTPC_CONTEXT. |
pIP_API | Pointer to a structure of type IP_FTPC_API. |
pFS_API | Pointer to the filesystem API. Can be NULL if only using commands that do not depend on a filesystem are used. Exmaples for this would be the STOR(e) or APPE(nd) command being used with IP_FTPC_ExecCmdEx() and input from a buffer instead from a file. |
pCtrlBuffer | Pointer to the buffer used for the control channel information. |
NumBytesCtrl | Size of the control buffer in bytes. |
pDataInBuffer | Pointer to the buffer used to receive data from the server. |
NumBytesDataIn | Size of the receive buffer in bytes. |
pDataOutBuffer | Pointer to the buffer used to transmit data to the server. |
NumBytesDataOut | Size of the transmit buffer in bytes. |
Return value
0 | Success. |
1 | Invalid parameters. |
Additional information
IP_FTPC_Init() must be called before any other FTP client function will be called. For
detailed information about the structure type IP_FS_API refer to
File system abstraction layer. For detailed information about the structure
type IP_FTPC_API refer to Structure IP_FTPC_API.
Example
Refer to IP_FTPC_ExecCmd for an example application which uses
IP_FTPC_Init().
IP_FTPC_InitEx()
Description
Initializes the context of the FTP client.
Prototype
int IP_FTPC_InitEx( IP_FTPC_CONTEXT * pContext,
const IP_FTPC_API * pIP_API,
const IP_FS_API * pFS_API,
U8 * pCtrlBuffer,
unsigned NumBytesCtrl,
U8 * pDataInBuffer,
unsigned NumBytesDataIn,
U8 * pDataOutBuffer,
unsigned NumBytesDataOut,
const IP_FTPC_APPLICATION * pApplication);
Parameters
Parameter | Description |
pContext | Pointer to a structure of type IP_FTPC_CONTEXT. |
pIP_API | Pointer to a structure of type IP_FTPC_API. |
pFS_API | Pointer to the filesystem API. Can be NULL if only using commands that do not depend on a filesystem are used. Exmaples for this would be the STOR(e) or APPE(nd) command being used with IP_FTPC_ExecCmdEx() and input from a buffer instead from a file. |
pCtrlBuffer | Pointer to the buffer used for the control channel information. |
NumBytesCtrl | Size of the control buffer in bytes. |
pDataInBuffer | Pointer to the buffer used to receive data from the server. |
NumBytesDataIn | Size of the receive buffer in bytes. |
pDataOutBuffer | Pointer to the buffer used to transmit data to the server. |
NumBytesDataOut | Size of the transmit buffer in bytes. |
pApplication | Pointer to a structure of type IP_FTPC_APPLICATION. |
Return value
0 | Success. |
1 | Invalid parameters. |
Data structures
Structure IP_FTPC_API
Description
This structure contains the pointer to the socket functions which are required to use
the FTP client.
Prototype
typedef struct {
FTPC_SOCKET (*pfConnect) (const char * SrvAddr, unsigned SrvPort);
void (*pfDisconnect) (FTPC_SOCKET Socket);
int (*pfSend) (const char * pData, int Len,
FTPC_SOCKET Socket);
int (*pfReceive) (char * pData, int Len, FTPC_SOCKET Socket);
int (*pfSetSecure) (FTPC_SOCKET Socket, FTPC_SOCKET Clone);
} IP_FTPC_API;
Member | Description |
pfConnect | Callback function that handles the connect to a FTP server on socket level. |
pfDisconnect | Callback function that disconnects a connection to the FTP server on
socket level. |
pfSend | Callback function that sends data to the FTP server on socket level. |
pfReceive | Callback function that receives data from the FTP server on socket level. |
pfSetSecure | Callback function to configure the socket as secured and eventually clone
it (Clone might be NULL). This is used when secured connections with
SSL are supported. Set this pointer to NULL if no security is present. |
Structure IP_FTPC_APPLICATION
Description
This structure contains a callback that will be called for every received lines when getting a reply
from the server.
Prototype
typedef struct {
void (*pfReply)(IP_FTPC_CONTEXT* pContext,
unsigned Cmd,
const char* sResponse,
unsigned ResponseLength,
unsigned IsLineComplete);
} IP_FTPC_APPLICATION;
Member | Description |
pfReply | Callback. |
pfReply\pContext | Pointer on the FTP client context. |
pfReply\Cmd | Command id. |
pfReply\sResponse | Server reply. |
pfReply\sResponseLength | Server reply length. |
pfReply\IsLineComplete | Last line indication. |
IP_FTPC_CMD_CONFIG
Description
Configuration structure used with IP_FTPC_ExecCmdEx() for
extended functionality.
Type definition
typedef struct {
const char * sPara;
const char * sLocalPath;
const char * sRemotePath;
U8 * pData;
unsigned NumBytes;
} IP_FTPC_CMD_CONFIG;
Structure members
Member | Description |
sPara | Same as sPara with old IP_FTPC_ExecCmd() for backwards compatibility. Can be NULL if not required for command or sLocalPath and/or sRemotePath are used. |
sLocalPath | Local path (terminated string) to use with command. Can be NULL if not supported by command (or makes no sense). Overrides sPara . Can be used with the following commands: FTPC_CMD_STOR FTPC_CMD_APPE FTPC_CMD_RETR |
sRemotePath | Remote path (terminated string) to use with command. Can be NULL if not supported by command (or makes no sense). Overrides sPara . Can be used with the following commands: FTPC_CMD_LIST FTPC_CMD_CWD FTPC_CMD_STOR FTPC_CMD_APPE FTPC_CMD_RETR FTPC_CMD_MKD FTPC_CMD_RMD FTPC_CMD_DELE |
pData | Indicates that input data shall be taken from the buffer at pData instead of a filesystem. Can be NULL if using a filesystem and reading is intended to be done from a filename given by sPara . Can be used with the following commands: FTPC_CMD_STOR FTPC_CMD_APPE |
NumBytes | Number of bytes to input starting from pData . |
Resource usage
The ROM usage depends on the compiler options, the compiler version and the used
CPU. The memory requirements of the FTP client presented in the tables below have
been measured on an ARM7 and a Cortex-M3 system. Details about the further
configuration can be found in the sections of the specific example.
Configuration used
#define FTPC_BUFFER_SIZE 512
#define FTPC_CTRL_BUFFER_SIZE 256
#define FTPC_SERVER_REPLY_BUFFER_SIZE 128 // Only required in debug builds
// with enabled logging.
ROM usage on an ARM7 system
The following resource usage has been measured on an ARM7 system using IAR
Embedded Workbench V6.30.6, Thumb mode, no interwork, size optimization.
Addon | ROM |
emFTP client | approximately 2.0 kBytes |
ROM usage on a Cortex-M3 system
The following resource usage has been measured on a Cortex-M3 system using IAR
Embedded Workbench V6.30.6, size optimization.
Addon | ROM |
emFTP client | approximately 1.7 kBytes |
RAM usage
Almost all of the RAM used by the web server is taken from task stacks. The amount
of RAM required for every child task depends on the configuration of your client. The
table below shows typical RAM requirements for your task stacks.
Build | Description | RAM |
Release | A task used for the FTP client without debugging features
and disabled debug outputs. | approximately 500 bytes |
The approximately task stack size required for the FTP client can be calculated as fol-
lows:
TaskStackSize = 2 * FTPC_BUFFER_SIZE + FTPC_CTRL_BUFFER_SIZE
Build | Description | RAM |
Debug | A task used for the FTP client with debugging features
and enabled debug outputs. | approximately 500 bytes |
The approximately task stack size required for the FTP client can be calculated as follows:
TaskStackSize = 2 * FTPC_BUFFER_SIZE + FTPC_CTRL_BUFFER_SIZE + FTPC_SERVER_REPLY_BUFFER_SIZE
TFTP client/server
The TFTP (Trivial File Transfer Protocol) is an extension to the TCP/IP stack. All functions
which are required to add a TFTP client or a TFPT server to your application are
described in this chapter.
emNet TFTP
The emNet TFTP is an extension which adds the TFTP protocol to the stack. TFTP
stands for Trivial File Transfer Protocol. It is the basic mechanism for moving files via
UDP between machines over IP based networks. TFTP is a client/server protocol,
meaning that one machine, the client, initiates a file transfer by contacting another
machine, the server and making requests. The server must be operating before the
client initiates his requests.
The TFTP server implements the relevant parts of the following RFCs.
RFC# | Description |
[RFC 1350] | TFTP - THE TFTP PROTOCOL (REVISION 2)
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc1350.txt |
Feature list
- Low memory footprint.
- Independent of the file system: Any file system can be used.
- Independent of the TCP/IP stack: Any stack with sockets can be used.
- Demo application included.
TFTP basics
The Trivial File Transfer Protocol (TFTP) is an application layer protocol.
When a TFTP client contacts a server, a UDP command is sent to the servers port.
The traditional port is 69. The command sent is either a read or a write request. The
client will send data always to the servers port whereas the server will respond with
data to the port on that the client is sending.
The TFTP requests are sent in a RFC conform format.
Using the TFTP samples
Ready to use examples for emNet are supplied. The sample applications are configured
to work with each other but can be used with any TFTP client/server with
minimal modification. The example applications requires a file system to make data
files available. Refer to File system abstraction layer on page 868 for detailed information.
Running the TFTP server example on target hardware
The emNet TFTP sample applications should always be the first step to check the
proper function of the TFTP client/server with your target hardware.
Add all source files located in the following directories (and their subdirectories) to
your project and update the include path:
- Application
- Config
- Inc
- IP
- IP\IP_FS\[NameOfUsedFileSystem]
It is recommended that you keep the provided folder structure.
The sample applications can be used on the most targets without the need for
changing any of the configuration flags.
API functions
IP_TFTP_InitContext()
Description
Initializes the context for storing connection parameters of a
TFTP client/server.
Prototype
int IP_TFTP_InitContext( TFTP_CONTEXT * pContext,
unsigned IFace,
const IP_FS_API * pFS_API,
char * pBuffer,
int BufferSize,
U16 ServerPort);
Parameters
Parameter | Description |
pContext | Pointer to a structure of type TFTP_CONTEXT. |
IFace | Zero-based interface index. |
pFS_API | Pointer to the used file system API. |
pBuffer | Pointer to buffer for storing transfer data. Needs to be big enough to hold the biggest TFTP message (512 bytes payload + 4 bytes TFTP header). |
BufferSize | Size of buffer assigned with pBuffer. |
ServerPort | Port of the server. Can be 0 if the structure is used to connect as a client or if the default TFTP port (69) should be used. |
Return value
= 0 | Success. |
< 0 | Error, typically buffer too small or no buffer set. |
Additional information
A static structure of TFTP_CONTEXT needs to be supplied by the
application to provide space to store connection parameters.
IP_TFTP_RecvFile()
Description
Requests a file from a TFTP server.
Prototype
int IP_TFTP_RecvFile( TFTP_CONTEXT * pContext,
unsigned IFace,
U32 IPAddr,
U16 Port,
const char * sFileName,
int Mode);
Parameters
Parameter | Description |
pContext | Pointer to a structure of type TFTP_CONTEXT. |
IFace | Zero-based interface index. |
IPAddr | IP addresse of TFTP server. |
Port | Port of TFTP server listening. |
sFileName | Name of the file to retrieve from server. |
Mode | TFTP_MODE_OCTET. |
Return value
Additional information
A static structure of TFTP_CONTEXT needs to initialized with
IP_TFTP_InitContext() before using it with this function.
IP_TFTP_SendFile()
Description
Sends a data file to a TFTP server.
Prototype
int IP_TFTP_SendFile( TFTP_CONTEXT * pContext,
unsigned IFace,
U32 IPAddr,
U16 Port,
const char * sFileName,
int Mode);
Parameters
Parameter | Description |
pContext | Pointer to a structure of type TFTP_CONTEXT. |
IFace | Zero-based interface index. |
IPAddr | IP addresse of TFTP server. |
Port | Port of TFTP server listening. |
sFileName | Name of file to send to server. |
Mode | TFTP_MODE_OCTET. |
Return value
Additional information
A static structure of TFTP_CONTEXT needs to initialized with
IP_TFTP_InitContext() before using it with this function.
IP_TFTP_ServerTask()
Description
TFTP server task that can be be started in a separate task.
Prototype
void IP_TFTP_ServerTask(void * pPara);
Parameters
Parameter | Description |
pPara | Cast pointer to a structure of type TFTP_CONTEXT. |
Additional information
A static structure of TFTP_CONTEXT needs to initialized with
IP_TFTP_InitContext() before using it with this function. The
task does never return.
Resource usage
The ROM usage depends on the compiler options, the compiler version and the used
CPU. The memory requirements of the TFTP client/server presented in the tables
below have been measured on an ARM7 and a Cortex-M3 system. Details about the
further configuration can be found in the sections of the specific example.
ROM usage on an ARM7 system
The following resource usage has been measured on an ARM7 system using IAR
Embedded Workbench V6.30.6, Thumb mode, no interwork, size optimization.
Addon | ROM |
emNet TFTP client | approximately 1.2 kBytes |
emNet TFTP server | approximately 1.2 kBytes |
ROM usage on a Cortex-M3 system
The following resource usage has been measured on a Cortex-M3 system using IAR
Embedded Workbench V6.30.6, size optimization.
Addon | ROM |
emNet TFTP client | approximately 1.2 kBytes |
emNet TFTP server | approximately 1.2 kBytes |
RAM usage
Each connection requires approximately 550 bytes of RAM that split into space for
the required transfer buffer (app. 516 bytes) and the space for TFTP_CONTEXT.
PPP / PPPoE (Add-on)
The emNet implementation of the Point to Point Protocol (PPP) is an optional
extension to emNet. It can be used to establish a PPP connection over Ethernet
(PPPoE) or using modem to connect via telephone carrier. All functions that are
required to add PPP/PPPoE to your application are described in this chapter.
emNet PPP/PPPoE
The emNet PPP implementation is an optional extension which can be seamlessly
integrated into your TCP/IP application. It combines a maximum of performance with
a small memory footprint. The PPP implementation allows an embedded system to
connect via Point to Point Protocol to a network.
The PPP module implements the relevant parts of the following Request For
Comments (RFC).
RFC# | Description |
[RFC 1334] | PPP Authentication Protocols
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc1334.txt |
[RFC 1661] | The Point-to-Point Protocol (PPP)
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc1661.txt |
[RFC 1994] | PPP Challenge Handshake Authentication Protocol (CHAP)
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc1994.txt |
[RFC 2516] | A Method for Transmitting PPP Over Ethernet (PPPoE)
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc2516.txt |
The following table shows the contents of the emNet root directory:
Directory | Content |
.\Application\ | Contains the example application to run
the PPP implementation with emNet. |
.\Crypto\ | Contains the required files when using MD5 based CHAP authentication. |
.\Inc\ | Contains the required include files. |
.\IP\ | Contains the PPP sources, IP_PPP.c,
IP_PPP_CCP.c, IP_PPP_CHAP.c, IP_PPP_Int.h,
IP_PPP_IPCP.c, IP_PPP_LCP.c,
IP_PPP_Line.c, IP_PPP_PAP.c and
IP_PPPoE.c. Additionally to the main
source code files of the PPP add-on an
example implementation for the connection
of a modem via USART
(IP_Modem_UART.c) is supplied. |
Feature list
- Low memory footprint.
- Support PAP authentication protocol
- Support CHAP authentication protocol
- Support for PPP over Ethernet.
Requirements
TCP/IP stack
The emNet PPP implementation requires the emNet TCP/IP stack. Your modem
has to be able to be configured to respond in the format:
"<CR><LF><Response>"
PPP backgrounds
The Point to Point Protocol is a link layer protocol for establishing a direct connection
between two network nodes.
Using PPP, an emNet application can establish a PPP connection to a PPP server.
The handshaking mechanism includes normally an authentication process. The
current version of emNet supports the the following authentication schemes:
- PAP - Password Authentication Protocol
- CHAP - Challenge Handshake Authentication Protocol
API functions
PPPoE functions
IP_PPPOE_AddInterface()
Description
Adds a PPPoE interface.
Prototype
int IP_PPPOE_AddInterface(unsigned HWIFaceId);
Parameters
Parameter | Description |
HWIFaceId | Zero-based interface index to be used as underlying hardware interface. |
Return value
≥ 0 | Zero-based interface index of the newly created interface. |
< 0 | Error. |
Additional information
Optional configuration of the maximum number of interfaces
that can be added to the system using IP_ConfigMaxIFaces()
needs to be done before adding any interface and must not
be changed later.
IP_PPPOE_ConfigRetries()
Description
Configures the number of times to resend a lost message before
breaking the connection.
Prototype
void IP_PPPOE_ConfigRetries(unsigned IFaceId,
U32 NumTries,
U32 Timeout);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
NumTries | Number of times the stack will resend the message. |
Timeout | Timeout in ms before a resend is triggered. |
IP_PPPOE_Reset()
Description
Resets a PPPoE session.
The PPPoE layer is closed by sending a PADT if connected.
Also resets the PPP connection state, but does not send any more PPP packets.
Prototype
void IP_PPPOE_Reset(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
IP_PPPOE_SetAuthInfo()
Description
Sets the authentication information for the PPPoE connection.
Prototype
void IP_PPPOE_SetAuthInfo( unsigned IFaceId,
const char * sUser,
const char * sPass);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
sUser | PPPoE user name. |
sPass | PPPoE user password. |
IP_PPPOE_SetUserCallback()
Description
Sets a callback function to inform the user about a status
change.
Prototype
void IP_PPPOE_SetUserCallback(U32 IFaceId,
IP_PPPOE_INFORM_USER_FUNC * pfInformUser);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pfInformUser | Pointer to a user function of type IP_PPPOE_INFORM_USER_FUNC. which is called when a status change occurs. |
Additional information
Callback function will only be added if IP_PPPOE_AddInterface()
has been called before.
IP_PPPOE_INFORM_USER_FUNC is defined as follows:
typedef void (IP_PPPOE_INFORM_USER_FUNC)(U32 IFaceId, U32 Status);
PPP functions
IP_PPP_AddInterface()
Description
Adds a PPP driver.
Prototype
int IP_PPP_AddInterface(const IP_PPP_LINE_DRIVER * pLineDriver,
int ModemIndex);
Parameters
Parameter | Description |
pLineDriver | Pointer to a structure IP_PPP_LINE_DRIVER. |
ModemIndex | Modem index; Fixed to 0. |
Return value
≥ 0 | Zero-based interface index of the newly created interface. |
< 0 | Error. |
Additional information
Optional configuration of the maximum number of interfaces
that can be added to the system using IP_ConfigMaxIFaces()
needs to be done before adding any interface and must not
be changed later.
IP_PPP_CHAP_AddWithMD5()
Description
Adds support for the CHAP authentication protocol with MD5
algorithm to the stack.
Prototype
void IP_PPP_CHAP_AddWithMD5(const IP_PPP_MD5_API * pAPI);
Parameters
Parameter | Description |
pAPI | Pointer to MD5 APi of type IP_PPP_MD5_API . |
Additional information
Typically most modern ISPs are happy with the insecure PAP
authentication protocol or even suggest it to us directly.
In most modern use cases the client is identified for example
by its SIM card number and often the ISP does not even care
what is sent for username and password. Todays security is
typically implemented on higher protocols like TLS on top of TCP.
If unsure if required or if you need to be compatible with the
one or two providers that absolutely need CHAP these days, you
should add this protocol. If not, you should leave it out for
a smaller memory footprint.
IP_PPP_OnRx()
Description
Receives one or more characters from the hardware.
Uses IP_PPP_OnRxChar() to receive the characters one by one.
Prototype
void IP_PPP_OnRx(IP_PPP_CONTEXT * pContext,
U8 * pData,
int NumBytes);
Parameters
Parameter | Description |
pContext | Pointer to a Structure IP_PPP_CONTEXT. |
pData | Pointer to a buffer which is storing the received data. |
NumBytes | Number of bytes to receive. |
IP_PPP_OnRxChar()
Description
Receives a character from the hardware (typ. modem).
Checks if the received character is an escape character, removes
the escape character if required and stores the character into
packet buffer. When a complete packet is received, it is given
to the stack.
Prototype
void IP_PPP_OnRxChar(IP_PPP_CONTEXT * pContext,
U8 Data);
Parameters
Parameter | Description |
pContext | Pointer to a structure IP_PPP_CONTEXT. |
Data | 1 received character. |
IP_PPP_OnTxChar()
Description
Sends a character via PPP. The function checks if the character
needs an escape character for the HDLC framing and sends the
escape character if required.
Prototype
int IP_PPP_OnTxChar(unsigned Unit);
Parameters
Parameter | Description |
Unit | Zero-based interface index. |
Return value
0 | More data has been sent. Keep Tx interrupt enabled. |
1 | No more data to send. Disable Tx interrupt if necessary. |
IP_PPP_SetUserCallback()
Description
Sets a callback function to inform the user about a status
change.
Prototype
void IP_PPP_SetUserCallback(U32 IFaceId,
IP_PPP_INFORM_USER_FUNC * pfInformUser);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pfInformUser | Pointer to a user function of type IP_PPP_INFORM_USER_FUNC which is called when a status change occurs. |
Additional information
Callback function will only be added if IP_PPP_AddInterface()
has been called before.
IP_PPP_INFORM_USER_FUNC is defined as follows:
typedef void (IP_PPP_INFORM_USER_FUNC)(U32 IFaceId, U32 Status);
Modem functions
IP_MODEM_Connect()
Description
Initializes a PPP connect on a modem using the passed AT command.
Prototype
int IP_MODEM_Connect(const char * sATCommand);
Parameters
Parameter | Description |
sATCommand | AT command string to dial up a connection. Must not use <CR> at the end of the dial string. Typically this is the command “ATD” followed by a dial number. |
Return value
Example
IP_MODEM_Connect("ATD*99***1#");
IP_MODEM_Disconnect()
Description
Disconnects the connection established with a modem on a specific interface.
Prototype
void IP_MODEM_Disconnect(unsigned IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Example
IP_MODEM_Disconnect(0);
IP_MODEM_GetResponse()
Description
Retrieves a pointer to the responses received since the last
sent AT command.
It is able to copy the response into a provided buffer if necessary.
Prototype
char *IP_MODEM_GetResponse(unsigned IFaceId,
char * pBuffer,
unsigned NumBytes,
unsigned * pNumBytesInBuffer);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
pBuffer | Pointer to the buffer where the response shall be copied to. May be NULL. |
NumBytes | Size of the buffer pointed to by pBuffer. |
pNumBytesInBuffer | Number of bytes in receive buffer. May be NULL. |
Return value
= NULL | No response in buffer. The last response might have already been cleared to receive the response for the next command. |
≠ NULL | Pointer to buffer that holds the last response received. Beginning <CR><LF> is skipped. |
Example
U8 aBuffer[256];
unsigned NumBytesReceived;
IP_MODEM_SendString(0, "AT");
IP_MODEM_GetResponse(0, &aBuffer[0], sizeof(aBuffer), &NumBytesReceived);
IP_MODEM_SendString()
Description
Sends an AT command to the modem without waiting for an answer.
Prototype
void IP_MODEM_SendString( unsigned IFaceId,
const char * sCmd);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
sCmd | AT command to be sent. |
Additional information
This routine is meant for sending simple AT commands to the
modem that do not need to be checked for their response.
It is not designed to be used with IP_MODEM_GetResponse().
If you intend to process the modem response please use
IP_MODEM_SendStringEx() instead.
IP_MODEM_SendStringEx()
Description
Sends an AT command to the modem and waits for the expected
response with a timeout or checks for responses received in
multpiple parts.
Prototype
int IP_MODEM_SendStringEx( unsigned IFaceId,
const char * sCmd,
const char * sResponse,
unsigned Timeout,
unsigned RecvBufOffs);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
sCmd | AT command to be sent. May be NULL. |
sResponse | Expected response without <CR><LF> in front. May be NULL. |
Timeout | Timeout to wait for any response in ms. |
RecvBufOffs | Can be used to check for a response that is sent in multiple parts. |
Return value
0 | OK, correct response received. |
1 | Timeout. |
2 | Wrong response received. |
Additional information
Sending a new command with IP_MODEM_SendString() clears the
buffer of previous received responses.
RecvBufOffs can be used to check for responses that are sent
by the modem in multiple responses. If not passed ’0’ the
receive buffer will not be cleared to not clear out already
received following responses from the previously sent command.
RecvBufOffs id the offset in bytes from the beginning of the
first received response. Being able to receive responses that
are sent in multiple parts is necessary as some command may be
responded with a confirm for the command sent itself and respond
with a second message after an undefined time.
Example sending a command and checking for its response with a timeout
IP_MODEM_SendStringEx(0, "AT", "OK", 100, 0);
Example for checking the SIM status of a GSM modem
int r;
//
// Check if the modem is waiting for a SIM PIN to be entered
//
r = IP_MODEM_SendStringEx(0, "AT+CPIN?\r", "+CPIN: SIM PIN", 1000, 0);
if (r == 0) {
//
// The modem is waiting for the PIN to be entered
//
IP_MODEM_SendString(0, "AT^SSET=1\r"); // Enable "^SSIM READY" response once
// the SIM data has been read
IP_OS_Delay(100);
//
// Enter SIM PIN. The OK response will arrive quickly. The modem then
// reads data from the SIM.
//
IP_MODEM_SendStringEx(0, "AT+CPIN="1234"\r", "OK", 15000, 0);
//
// After receiving the "OK" response for the command the modem will need an
// undefined time to read data from the SIM. The modem sends the response
// "^SSIM READY" once it has finished. We will receive the response at an
// 6 byte offset (OK<CR><LF><CR><LF>^SSIM READY).
//
IP_MODEM_SendStringEx(0, NULL, "^SSIM READY", 15000, 6);
} else {
//
// The modem does not seem to wait for a PIN, check if the modem
// reports "READY". This means no PIN is set for the SIM card. In this case
// the modem responds with "+CPIN: READY" that will be located at offset 0
// in the receive buffer.
//
if (IP_MEMCMP(IP_MODEM_GetResponse(0, NULL, 0, NULL), "+CPIN: READY", 12) != 0) {
IP_Panic("Unrecognized response from modem.");
}
}
IP_MODEM_SetAuthInfo()
Description
Sets authentication information if needed for the connection to
establish.
Prototype
void IP_MODEM_SetAuthInfo( unsigned IFaceId,
const char * sUser,
const char * sPass);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
sUser | String containing the user name to be used. |
sPass | String containing the password to be used. |
Additional information
Setting a user name and a password is only necessary when
required by your ISP.
Example
IP_MODEM_SetAuthInfo(0, "User", "Pass");
IP_MODEM_SetConnectTimeout()
Description
Sets the connect timeout to wait for a requested connection with
IP_MODEM_Connect() to be established.
Prototype
void IP_MODEM_SetConnectTimeout(unsigned IFaceId,
unsigned ms);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
ms | Timeout in ms. Default 15s. |
Example
IP_MODEM_SetConnectTimeout(0, 30000);
IP_MODEM_SetInitCallback()
Description
Sets a callback that is used to initialize the modem before
actually starting the connection attempt. The callback is called
from IP_MODEM_Connect().
Prototype
void IP_MODEM_SetInitCallback(void ( *pfInit)());
Parameters
Parameter | Description |
pfInit | Void callback routine for intialization of the modem before connecting. |
Example
static void _InitModem(void) {
IP_MODEM_SendString(0, "AT");
}
IP_MODEM_SetInitCallback(_InitModem);
IP_MODEM_Connect("ATD*99***1#");
IP_MODEM_SetInitString()
Description
Sets an initialization string that is sent to the modem before
actually starting the connection attempt. In case
IP_MODEM_SetInitCallback() is used the init string is not sent.
Prototype
void IP_MODEM_SetInitString(const char * sInit);
Parameters
Parameter | Description |
sInit | Command to be sent to the modem before connecting. |
Example
IP_MODEM_SetInitString("ATE0V1");
IP_MODEM_Connect("ATD*99***1#");
IP_MODEM_SetUartConfig()
Description
Sets the configuration to be used with the BSP_UART_* API.
Prototype
void IP_MODEM_SetUartConfig(unsigned int Unit,
unsigned long Baudrate,
unsigned char NumDataBits,
unsigned char Parity,
unsigned char NumStopBits);
Parameters
Parameter | Description |
Unit | Index of UART unit to use. |
Baudrate | Baudrate [Hz] to use. |
NumDataBits | Number of data bits to use. |
Parity | Parity of type BSP_UART_PARITY_* . |
NumStopBits | Number of stop bits to use. |
Additional information
By default the IP_MODEM_* API calls BSP_UART_Init() with all
parameters like unit and baudrate set to zero as these parameters
were originally not present. When they eventually became
available, zero parameters meant using the modules default
values. Unfortunately the default values are not loaded by
all BSP_UART implementation or a different unit than unit #0
is planned to be used. To avoid changing the complete API of
IP_MODEM module, the parameters can now be set using this API.
BSP_UART_Init() previously was also called with the interface
id as unit number. This is now also changed to use either zero
for default or the configured value from this routine.
IP_MODEM_SetSwitchToCmdDelay()
Description
Sets the delay that is applied before and after the “+++ATH”
command that is used to switch back the modem from data to
command mode.
Prototype
void IP_MODEM_SetSwitchToCmdDelay(unsigned IFaceId,
unsigned ms);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
ms | Timeout in ms between sending “+++” and “ATH”. |
Additional information
Sending “+++ATH” to switch back to command mode and then hanging
up the connection is fine to be sent in one message. For
some modem this does not apply. They need some time to switch
back to command mode before accepting “ATH” for hanging up.
Data structures
Structure IP_PPP_CONTEXT
Description
A structure which stores the information about the PPP connection.
Prototype
typedef struct IP_PPP_CONTEXT {
PPP_SEND_FUNC * pfSend;
PPP_TERM_FUNC * pfTerm;
PPP_INFORM_USER_FUNC * pfInformUser;
void * pSendContext;
int NumBytesPrepend;
U8 IFaceId;
struct {
U32 NumTries;
I32 Timeout;
} Config;
struct {
U8 Id;
U8 aOptCnt[MAX_OPT];
PPP_LCP_STATE AState;
PPP_LCP_STATE PState;
RESEND_INFO Resend;
U16 MRU;
U32 ACCM;
U32 OptMask;
} LCP;
struct {
U8 Id;
U8 aOptCnt[MAX_OPT];
PPP_CCP_STATE AState;
PPP_CCP_STATE PState;
RESEND_INFO Resend;
U32 OptMask;
} CCP;
struct {
U8 Id;
U8 aOptCnt[MAX_OPT];
PPP_IPCP_STATE AState;
PPP_IPCP_STATE PState;
RESEND_INFO Resend;
IP_ADDR IpAddr;
IP_ADDR aDNSServer[IP_MAX_DNS_SERVERS];
U32 OptMask;
} IPCP;
struct {
U8 UserLen;
U8 abUser[64];
U8 PassLen;
U8 abPass[64];
U16 Prot;
U32 Data;
PPP_AUTH_STATE State;
RESEND_INFO Resend;
U32 OptMask;
} Auth;
IP_PPP_LINE_DRIVER * pLineDriver;
} IP_PPP_CONTEXT;
Member | Description |
pfSend | Pointer to a function which sends a packet. |
pfTerm | Pointer to a function which terminates the connection. |
pfInformUser | Pointer to a callback function which informs the user about a
status change of the connection. |
pSendContext | Pointer to a user callback function which is triggered when a
status change of the PPP connection occurs. |
NumBytesPrepend | The size of the PPP header to be prepended when sending packets. |
IFaceId | Internal index number of the interface. |
Config.NumTries | Defines the number of times the stack tries to initialize a
connection via PADI before giving up. Can be set via
IP_PPPOE_ConfigRetries(), the default is 5. |
Config.Timeout | Sets the timeout between PADI configuration retries in ms, the
default is 2000. |
LCP.Id | Sequential ID number of the LCP packet. |
LCP.aOptCnt | An array of supported LPC options. |
LCP.AState | An enum of type PPP_LCP_STATE. Indicates the active status
of the LPC connection. |
LCP.PState | An enum of type PPP_LCP_STATE. Indicates the passive status
(modem side) of the LPC connection. |
LCP.Resend | A structure of type RESEND_INFO. |
LCP.MRU | Maximum-Receive-Unit. |
LCP.ACCM | Async-Control-Character-Map. |
LCP.OptMask | Mask to identify the options which should be added to the LCP
packet. |
CCP.Id | Sequential ID number of the CCP packet. |
CCP.aOptCnt | An array of supported CCP options. |
CCP.AState | An enum of type PPP_CCP_STATE. Indicates the active status
of the CCP connection. |
CCP.PState | An enum of type PPP_CCP_STATE. Indicates the passive status
(modem side) of the LPC connection. |
CCP.Resend | A structure of type RESEND_INFO. |
CCP.OptMask | Mask to identify the options which should be added to the CCP
packet. |
IPCP.Id | Sequential ID number of the IPCP packet. |
IPCP.aOptCnt | An array of supported IPCP options. |
IPCP.AState | An enum of type PPP_IPCP_STATE. Indicates the active status
of the LPC connection. |
IPCP.PState | An enum of type PPP_IPCP_STATE. Indicates the passive
status (modem side) of the LPC connection. |
IPCP.Resend | A structure of type RESEND_INFO. |
IPCP.IpAddr | An IP_ADDR to store the IP address of the PPP interface. |
IPCP.aDNSServer | An IP_ADDR to store the IP address of the PPP interface. |
IPCP.OptMask | Mask to identify the options which should be added to the IPCP
packet. |
Auth.UserLen | Length of the user name, is being set internally. |
Auth.abUser | User name for the PPPoE connection. |
Auth.PassLen | Length of the user password, is being set internally. |
Auth.abPass | User password for the PPPoE connection. |
Auth.Prot | Defines the PPP authentication protocol, is set typically to
PPP_PROT_PAP. |
Auth.State | An enum of type PPP_AUTH_STATE. |
Auth.Resend | A structure of type RESEND_INFO. |
pLineDriver | Pointer to a structure of type IP_PPP_LINE_DRIVER |
Structure RESEND_INFO
Description
A structure which stores the resend condition for different stages of the PPP connection.
Prototype
typedef struct {
IP_PACKET * pPacket;
I32 Timeout;
I32 InitialTimeout;
U32 RemTries;
#if IP_DEBUG
const char * sPacketName;
#endif
} RESEND_INFO;
Member | Description |
pPacket | Pointer to an IP_PACKET structure. |
Timeout | Timeout in ms before a resend is triggered. |
InitialTimeout | Initial timeout in ms before a resend is triggered. Saved to be
able to reset Timeout to it’s original state. |
RemTries | Counter for the remaining number of retries. |
sPacketName | (Only with IP_DEBUG ≥ 1.) Custom name assigned to the
packet. |
Structure IP_PPP_LINE_DRIVER
Description
Structure with pointers to application related functions.
Prototype
typedef struct {
void (*pfInit) (struct IP_PPP_CONTEXT * pPPPContext);
void (*pfSend) (U8 Data);
void (*pfSendNext) (U8 Data);
void (*pfTerminate) (U8 IFaceId);
void (*pfOnPacketCompletion) (void);
} IP_PPP_LINE_DRIVER;
Member | Description |
pfInit | Pointer to a function which initializes the PPP connection. |
pfSend | Pointer to a function which sends the first byte. |
pfSendNext | Pointer to a function which sends the next byte. Typically
called from an interrupt that confirms that the last byte has
been sent. |
pfTerminate | Pointer to a function which terminates the connection. |
pfOnPacketCompletion | Optional. Called when packet is complete. Normally used for
packet oriented PPP interfaces GPRS or USB modems. |
PPPoE resource usage
The ROM usage depends on the compiler options, the compiler version and the used
CPU. The memory requirements of the PPP/PPPoE modules presented in the tables
below have been measured on an ARM7 and a Cortex-M3 system. Details about the
further configuration can be found in the sections of the specific example.
The resource usage of a typical PPPoE scenario with 1 WAN interface has been measured.
ROM usage on an ARM7 system
The following resource usage has been measured on an ARM7 system using IAR
Embedded Workbench V6.30.6, Thumb mode, no interwork, size optimization.
Addon | ROM |
emNet PPP used for PPPoE | approximately 7.0 kBytes |
ROM usage on a Cortex-M3 system
The following resource usage has been measured on a Cortex-M3 system using IAR
Embedded Workbench V6.30.6, size optimization.
Addon | ROM |
emNet PPP used for PPPoE | approximately 6.5 kBytes |
RAM usage
Addon | RAM |
emNet PPP used for PPPoE | approximately 100 Bytes |
PPP resource usage
The ROM usage depends on the compiler options, the compiler version and the used
CPU. The memory requirements of the PPP modules presented in the tables below
have been measured on an ARM7 system. Details about the further configuration can
be found in the sections of the specific example.
The resource usage of a typical PPP scenario without network interface and one
modem connected via RS232 has been measured.
ROM usage on an ARM7 system
The following resource usage has been measured on an ARM7 system using IAR
Embedded Workbench V6.30.6, Thumb mode, no interwork, size optimization.
Addon | ROM |
emNet PPP used for PPPoE | approximately 7.0 kBytes |
RAM usage
Addon | RAM |
emNet PPP used for PPPoE | approximately 0.5 kBytes |
NetBIOS (Add-on)
The emNet implementation of the Network Basic Input/Output System Protocol
(NetBIOS) is an optional extension to emNet. It can be used to resolve NetBIOS
names in a local area network. All functions that are required to add NetBIOS to your
application are described in this chapter.
emNet NetBIOS
The emNet NetBIOS implementation is an optional extension which can be seamlessly
integrated into your application. It combines a maximum of performance with a
small memory footprint. The NetBIOS implementation allows an embedded system to
resolve NetBIOS names in the local area network.
The NetBIOS module implements the relevant parts of the following Request For
Comments (RFC).
RFC# | Description |
[RFC 1001] | NetBIOS Concepts and methods
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc1001.txt |
[RFC 1002] | NetBIOS Detailed Specifications
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc1002.txt |
The following table shows the contents of the emNet root directory:
Directory | Content |
.\Application\ | Contains the example application to run
the NetBIOS implementation with emNet. |
.\Inc\ | Contains the required include files. |
.\IP\ | Contains the NetBIOS sources IP_Netbios.c. |
Feature list
- Low memory footprint.
- Seamless integration with the emNet stack.
- Client based NetBIOS name resolution.
Requirements
TCP/IP stack
The emNet NetBIOS implementation requires the emNet TCP/IP stack.
NetBIOS backgrounds
The Network Basic Input/Output System protocol is an API on top of the TCP/IP protocol,
it provides a way of communication between separate computers within a local
arena network via the session layer.
Using NetBIOS, an emNet application can resolve a NetBIOS name to an IP
adress in the local area network.
API functions
IP_NETBIOS_Init()
Description
Initializes the NetBIOS Name Service client.
Prototype
int IP_NETBIOS_Init( U32 IFaceId,
const IP_NETBIOS_NAME * paHostnames,
U16 LPort);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
paHostnames | Pointer to an array of Structure IP_NETBIOS_NAME. Expects last index to be filled with zero. |
LPort | Local port used for listening. Typically 137. If parameter LPort is 0, 137 will be used. |
Return value
< 0 | Error, invalid NetBIOS name. |
> 0 | Ok, Number of valid NetBIOS names assigned to the target. |
IP_NETBIOS_Start()
Description
Starts the NetBIOS client
Creates an UDP socket to receive NetBIOS Name Service requests.
Prototype
int IP_NETBIOS_Start(U32 IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Return value
= 0 | Error, could not create an UDP socket. |
> 0 | OK, number of the socket which is used for the NetBIOS Name Service. |
IP_NETBIOS_Stop()
Description
Stops the NetBIOS client
Closes the UDP socket.
Prototype
void IP_NETBIOS_Stop(U32 IFaceId);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
Structure IP_NETBIOS_NAME
Description
A structure which stores the information about the NetBIOS name.
Prototype
typedef struct IP_NETBIOS_NAME {
char * sName;
U8 NumBytes;
} IP_NETBIOS_NAME;
Member | Description |
sName | Pointer to a string which stores the NetBIOS name. |
NumBytes | Length of the NetBIOS name without termination. |
Resource usage
The ROM usage depends on the compiler options, the compiler version and the used
CPU. The memory requirements of the NetBIOS module presented in the tables below
have been measured on an ARM7 and a Cortex-M3 system. Details about the further
configuration can be found in the sections of the specific example.
ROM usage on an ARM7 system
The following resource usage has been measured on an ARM7 system using IAR
Embedded Workbench V6.30.6, Thumb mode, no interwork, size optimization.
Addon | ROM |
emNet NetBIOS module | approximately 0.8 kBytes |
ROM usage on a Cortex-M3 system
The following resource usage has been measured on a Cortex-M3 system using IAR
Embedded Workbench V6.30.6, size optimization.
Addon | ROM |
emNet NetBIOS module | approximately 0.7 kBytes |
RAM usage
Addon | RAM |
emNet NetBIOS module | approximately 26 bytes |
SNTP client (Add-on)
The emNet implementation of the Simple Network Time Protocol (SNTP) client is
an optional extension to emNet. It can be used to request a timestamp with the
current time from a NTP server. All functions that are required to add SNTP client
functionality to your application are described in this chapter.
emNet SNTP client
The emNet SNTP client implementation is an optional extension which can be
seamlessly integrated into your application. It combines a maximum of performance
with a small memory footprint. The SNTP client implementation allows an embedded
system to use real timestamps from a remote NTP server without using a RTC or to
initialize a RTC. The SNTP protocol is based on SNTP v4.
The SNTP client module implements the relevant parts of the following Request For
Comments (RFC).
RFC# | Description |
[RFC 4330] | Simple Network Time Protocol (SNTP) Version 4 for IPv4, IPv6 and OSI
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc4330.txt |
[RFC 1305] | Network Time Protocol (Version 3) - Specification, Implementation and Analysis
Direct download: ftp://ftp.rfc-editor.org/in-notes/rfc1305.txt |
The following table shows the contents of the emNet SNTP client root directory:
Directory | Content |
.\IP\ | Contains the SNTPc sources IP_SNTPC.c. |
Feature list
- Low memory footprint.
- Seamless integration with the emNet stack.
- Time synchronization with a remote NTP server.
Requirements
TCP/IP stack
The emNet SNTPc implementation requires the emNet TCP/IP stack.
SNTP backgrounds
The SNTP protocol is an API on top of the TCP/IP protocol, it provides a way of
synchronizing the target time with a local or remote NTP server over the network.
Using SNTP, an emNet application can synchronize its time with a NTP server
either in the local network or in a remote network to use a timestamp with the current
date and time or to initialize its own RTC with a good start value.
The NTP timestamp
The NTP timestamp used
is represented by a 64-bit value consisting of two 32-bit
fields. The first 32-bit field contains the complete seconds passed since January 1st
1900. The second 32-bit field contains fractions of a second in 232 picoseconds.
More information about the NTP timestamp can be found in RFC 1305.
The epoch problem (year 2036 problem)
The NTP timestamp reserves only 32-bit for full seconds passed which equals a little
bit more than 136 years. As the NTP time is based on January 1st 1900 this means
that the timestamp will overlap back to 0 some time in 2036. A timestamp older than
a reference timestamp can be interpreted as valid time as well as long as it does not
count up to the reference timestamp.
Based on this solution there are several possible ways of extending this period even
more:
- The simplest solution to extend the timestamp to be used for around 136 years is
for the target to remember the date it was built or has its firmware changed and
can then use this timestamp as reference extending the NTP timestamp for further 136 years.
- Storing the current year in non volatile memory using it as reference in which
epoch the target runs.
- Using other sources as reference for the epoch such as timestamps from other
sources.
API functions
IP_SNTPC_ConfigAcceptNoSyncSource()
Description
Configures if a timestamp from that indicates it originates
from a source that is not synchronized is accepted.
Prototype
void IP_SNTPC_ConfigAcceptNoSyncSource(U8 OnOff);
Parameters
Parameter | Description |
OnOff | = 0: Disabled (default). = 1: Enabled, accept all timestamps sources. |
IP_SNTPC_ConfigTimeout()
Description
Configures the maximum time to wait for a response from a NTP server
Prototype
void IP_SNTPC_ConfigTimeout(unsigned ms);
Parameters
Parameter | Description |
ms | Timeout in ms. |
IP_SNTPC_GetTimeStampFromServer()
Description
Requests the actual time from a NTP server. Server is passed
via punctual IP addresse or DNS name.
Prototype
int IP_SNTPC_GetTimeStampFromServer( unsigned IFaceId,
const char * sServer,
IP_NTP_TIMESTAMP * pTimestamp);
Parameters
Parameter | Description |
IFaceId | Zero-based interface index. |
sServer | String containing either dotted decimal IP address (129.250.35.251) or DNS name (us.pool.ntp.org) of NTP server. |
pTimestamp | Pointer where to store the received timestamp. |
Return value
= 0 | IP_SNTPC_STATE_NO_ANSWER, Request sent but no answer from server received within timeout. |
= 1 | IP_SNTPC_STATE_UPDATED, Timestamp updated from server response. |
= 2 | IP_SNTPC_STATE_KOD, Server sent Kiss-Of-Death and wants us to use another server. |
< 0 | Other, Error |
Structure IP_NTP_TIMESTAMP
Description
A structure which stores the timestamp from a NTP request.
Prototype
typedef struct IP_NTP_TIMESTAMP {
U32 Seconds;
U32 Fractions;
} IP_NTP_TIMESTAMP;
Member | Description |
Seconds | Seconds passed since start of epoch, typically January 1st 1900. |
Fractions | Fractions of a second in 232 picoseconds. |
Resource usage
The ROM usage depends on the compiler options, the compiler version and the used
CPU. The memory requirements of the SNTP module presented in the tables below
have been measured on an ARM7 and a Cortex-M3 system. Details about the further
configuration can be found in the sections of the specific example.
ROM usage on an ARM7 system
The following resource usage has been measured on an ARM7 system using IAR
Embedded Workbench V6.30.6, Thumb mode, no interwork, size optimization.
Addon | ROM |
emNet SNTP client | approximately 0.5 kBytes |
ROM usage on a Cortex-M3 system
The following resource usage has been measured on a Cortex-M3 system using IAR
Embedded Workbench V6.30.6, size optimization.
Addon | ROM |
emNet SNTP client | approximately 0.5 kBytes |
RAM usage
Addon | RAM |
emNet SNTP client | approximately 24 Bytes |
PTP Ordinary Clock (Add-on)
The emNet implementation of the Precision Time Protocol (PTP) is an optional
extension to emNet. Its primary purpose is to synchronize an embedded system to
a master clock in a local network. In addition a simple master functionality
can be provided for other PTP slaves in case no better master is available in
the network. All functions that are required to add PTP functionality to your
application are described in this chapter.
emNet PTP OC
The emNet PTP implementation is an optional extension which can be seamlessly
integrated into your application. It combines a maximum of performance with a small
memory footprint. This implementation covers PTP version 2, primarily for ordinary
slave-only clocks with the Delay/Response mechanism. Only one PTP interface is
supported at this time.
The PTP interface can be used as a slave, master or starting as slave/master with
the master being disabled later on when a master with a better clock source enters
the network.
The PTP module implements the mandatory parts of the following IEEE Standard.
IEEE-Std | Description |
[1588-2008] | IEEE Standard for a Precision Clock Synchronization Protocol for
Networked Measurement and Control Systems.
A copy could be ordered here:
http://www.nist.gov/el/isd/ieee/ieee1588.cfm |
The following table shows the contents of the emNet root directory:
Directory | Content |
.\IP\ | Contains the PTP Ordinary Clock add-on sources.
If available and purchased, a driver for hardware timestamps
for a specific network interface IP_DRIVER_NAME_PTP.c
might be included as well. |
emNet PTP OC slave
The PTPv2 protocol allows an embedded system to have a precise synchronization
with a master clock present in its local network. This master clock periodically
sends timing related messages. The slave can use the received timestamp together
with other synchronization messages to the master to calculate an accurate offset
to the timestamp that is periodically sent by the master.
emNet PTP OC master
The emNet PTP implementation primarily targets the PTP slave role as this is the
typical role that will be assigned to an embedded target. Most embedded targets
do not qualify for a good PTP master as they are not able to provide a clock that
qualifies as stable enough for a serious PTP clock source compared to commercial
PTP grandmaster clocks that typically sync to a high precision time source like GPS.
emNet therefore only provides a “Simple PTP Master”. While it can be used to provide
any PTP master for a network at all, it should not be considered a serious master
clock source for precision above multiple microseconds, of course under the assumption
that the master can provide a timestamp that accurate at all.
Hardware timestamp support
By default the emNet PTP implementation uses software timestamps that rely on the precision
of the system tick, typically provided by an RTOS via the OS abstraction layer. This tick
source typically provides around 1 millisecond precision. On top of the timer precision
the code run-time to collect the timestamp and assign it to a specific packet has to be
taken into account. The precision might be further downgraded by interrupts and modern
CPU features such as pipelining and caches that make a precise code run-time unpredictable.
Some hardwares support PTP timestamps to be taken automatically based on a dedicated PTP
timer unit that then is capable of providing a much better and constant time source compared
to software timestamps. Hardware timestamps can easily reach a precision in the order of
nanoseconds if the PTP hardware timer allows it. To utilize the PTP timer unit, a PTP driver
suitable for the specific device and/or Ethernet controller needs to be added.
Warning
Software and hardware timestamping can not be combined due to API restrictions. Typically
this is also not necessary as master and slave timestamping works in the same way and can
therefore be used for both purposes, even at the same time.
Typically only the timestamps are provided by hardware with the actual PTP logic remaining
in software in the stack. External PTP units like the Renesas EtherC PTP unit provide their
own PTP logic that does more than just provide timestamps and can not be easily combined with
a software logic. Therefore it is currently not possible combine EtherC PTP hardware timestamp
for slave purposes with a software master logic.
Feature list
- Low memory footprint.
- Seamless integration with the emNet stack.
- Time synchronization with a remote PTP master clock.
- Providing a “Simple PTP Master” for the network.
Requirements
TCP/IP stack
The emNet PTP implementation requires the emNet TCP/IP stack. Although
it is working with a complete software solution, a hardware supporting PTP
and an associated driver is needed to reach a higher precision.
PTP background
The PTP protocol is an API on top of the UDP/IP protocol or plain Ethernet.
It provides a way of synchronizing the target with a master clock over the local network.
PTP can be used with different protocols. This implementation currently supports
PTP over UDP IPv4, PTP over Ethernet and PTP over UDP IPv6 (If IPv6 add-on is
present). PTP messages are sent using multicast messages:
- Over UDP IPv4: mutilcast IP address is 224.0.1.129.
- Over Ethernet: multicast MAC address is 01:1B:19:00:00:00.
- Over UDP IPv6: multicast IP address is FF0X::181 (In this implementation X is
set to 2 which corresponds to link-local multicast).
In case more than one master clock is present in the local network, a decision needs to be
done which clock is the best master clock. This decision is done by comparing the parameters
periodically sent by every master clock. The best master clock is then used as the reference
called the GrandMaster clock.
Parameters that define a clock (like priority, description, …) can be obtained (and for
some parameters modified) using “Management” messages. See the IEEE1588-2008
specification for more details. (The emNet PTP implementation currently does not support “Management” messages)
Using PTP, an emNet system can synchronize its time with a PTP master clock in
its local network by obtaining the transmission/reception timestamp of a series of
messages between the master and the slave. With these timestamps, the slave is
able to compute the time offset and the propagation time between both clocks.
This series of messages for the Delay/Response mechanism occurs periodically in
order to correct the deviation of the slave time with respect to the master.