Ethernet / TCP-IP - Training Suite

01 - LWIP Introduction LwIP Distribution protocols 2 Application protocols • SNMP, Application • DNS client, Domain Names Network mgt Configuration Layer • DHCP client, DNS () SNMP DHCP (c)

Transport protocols Transport UDP TCP • UDP, Layer • TCP, Internet ICMP IP IGMP Layer Internet Protocols ARP

• ICMP, • IGMP, STM32F407 PPP PHY Network Datalink Protocols Interface Layer • ARP, • PPP LwIP Architecture 3

dhcp.c, dns.c Application layer udp.c tcp.c

ip.c

netif.c Network Interface layer LwIP 4

RAW API Netconn / Socket API RTOS No need Need Control based on Pcb socket Close to the windows or Linux Calling methods Callback socket APIs Structure Core APIs Higher level APIs  Lower memory devices  Higher memory devices  Application without RTOS  Porting of protocols or Application  Developers has more control application coming from Linux/windows complexity ++ + Memory -- + LwIP Architecture 5

dhcp.c, dns.c Application layer udp.c tcp.c Transport layer

ip.c Internet layer

netif.c Network Interface layer Network Interface 6 Network Interface 7 Network Interface 8 Network Interface 9

• Driver Function called by the network device driver to pass a packet up the TCP/IP stack • Input

• linkoutput send a packet on the interface • link_callback

This function is called when the netif link is set to up or down Add Network Interface 10

int network_init(void) { ip4_addr_t addr; ip4_addr_t netmask; ip4_addr_t gw; uint32_t start; struct netif *netif_add(struct netif *netif, const ip4_addr_t *ipaddr, tcpip_init(NULL, NULL); const ip4_addr_t *netmask, /* IP default settings, to be overridden by DHCP */ const ip4_addr_t *gw, void *state, IP4_ADDR(&addr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3); netif_init_fn init, IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, netif_input_fn input) GW_ADDR3); IP4_ADDR(&netmask, MASK_ADDR0, MASK_ADDR1, MASK_ADDR2, MASK_ADDR3);

/* add the network interface */ netif_add(&Netif, &addr, &netmask, &gw, NULL, ðernetif_init, ðernet_input);

/* register the default network interface */ netif_set_default(&Netif);

netif_set_up(&Netif);

#ifdef USE_DHCP dhcp_start(&Netif); #endif

start = HAL_GetTick(); …… return 0; } Network Interface Driver 11

Function Description Low_level_init Calls the Ethernet driver functions to initialize the STM32 Ethernet peripheral Low_level_output Calls the Ethernet driver functions to send an Ethernet packet Low_level_input Calls the Ethernet driver functions to receive an Ethernet packet Ethernetif_init Initialized the network interface structure(netif) and calls low_level_init to initialize the Ethernet peripheral Ethernetif_input Calls low_level_input to receive a packet then provide it to the LWIP stack Ethernet_input Process received ethernet frames Ethernet / TCP-IP - Training Suite

02 - lwIP Memory Management Dynamically allocated memory 13 • Lwip : Heap + Pools

• Heap (two options) • C standard library • lwIP’s custom heap-based (default), need to reverse some memory • Used for what (PBUF_RAM, tcp argument )

• Memp pools • make for fast and efficient memory allocation • Used for what (PCB, PBUF_POOLS & ROM…) • Need to reverse some memory Heap 14

ram_heap next lfree Next = prev MEM_SIZE_ALIGNED struct mem Prev = 0 Used = 1

Used = 0

next MEM_SIZE (lwipopts.h) prev used

MEM_SIZE_ALIGNED Next = Ram_end MEM_SIZE_ALIGNED next Prev = prev MEM_SIZE_ALIGNED Used = 1 Used = 1

mem_init() mem_malloc() 参考《嵌入式网络那些事LwIP协议深度剖析与实战演练》 mem_free() memp_init(); memp_malloc(); 15 Struct memp_desc Memp pools memp_free() size Memp_pools[] num UDP_PCB 0x20006AC8 第一个空闲块 base TCP_PCB 0x20006AA8 tab 0x20006A88 TCP_PCB_LISTEN 0x20006A68

…… NULL

PBUF_REF/ROM 608 Define by PBUF_POOL_BUFSIZE 16 Define by PBUF_POOL 0x20003 PBUF_POOL_SIZE 538 0x20006 BEC 0x200058D8 608 Define in memp_std.h bytes 0x20005678

……

0x20003538 Base address NULL LwIP Buffer management 16

• Requirements: Pbuf struct • Can operate no fixed length buffer freely • Can add data to the head and tail (e.g. tcp to ip) • Can remove data from buffer (e.g. ip to tcp) • For performance, avoid copying LwIP Buffer management (Avoid copying) 17 LwIP has 4 types of packet buffer structure :

• PBUF_RAM

• PBUF_ROM/REF

• PBUF_POOL

Data in non- volatile memory Variable size in RAM Fixed Fixed Fixed size in size in size in RAM RAM RAM Pbuf function 18

• pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)

size of the pbuf’s how and where the pbuf define header size payload should be allocated

• pbuf_free(struct pbuf *p) UDP Rx flow and Buffer Management example 19

The pointer to the PBUF_POOL is provided to the TCP-IP Stack

The User application has to Free the PBUF_POOL Buffer at the end of the processing

The pointer to the PBUF_POOL is provided to the TCP-IP Stack

1. The packet is first received by the DMA netif->input() into dedicated buffers. 2. The Packet is the copied in a PBUF_POOL allocated by the driver UDP Tx flow and Buffer Management example A PBUF_RAM buffer is allocated 20 by the user application

The User application has to Free the PBUF_RAM Buffer after the sending process The pointer to the PBUF_RAM is provided to the TCP-IP Stack

1. The Packet is the copied from the PBUF_RAM buffer into a dedicated buffer of the driver. 2. The packet is send by the DMA Memory footprint and module configuration 21

• Target: decide the number of your code size and RAM usage

• Principle: depending on your application

• Ways: • Simple configuration • Advanced configuration Simple Configuration (lwipopt.h) 22 • Which API do you use? RAW / NETCONN / SOCKET

• Which protocols do you use? TCP / UDP / DHCP / SNMP

• How to configure the memory to fit your application? • Heap memory: mainly used to send #define MEM_SIZE • Memp pools memory: mainly used to receive #define PBUF_POOL_SIZE #define PBUF_POOL_BUFSIZE • Protocol control block #define MEMP_NUM_UDP_PCB //max number of simultaneous UDP structure #define MEMP_NUM_TCP_PCB .. #define MEMP_NUM_TCP_PCB_LISTEN … Advanced configuration (opt.h) 23

• #include “lwipopt.h”

• Configurations: • Memory allocation algorithm • The options of all supported protocols • Timeout • Debug • If you need to configure these options, you must know what you do. Ethernet / TCP-IP - Training Suite

03 - lwIP PCB Structure UDP Data Structure 25

udp.h #define UDP_HLEN 8 struct udp_hdr { PACK_STRUCT_FIELD(u16_t src); PACK_STRUCT_FIELD(u16_t dest); /* src/dest UDP ports */ PACK_STRUCT_FIELD(u16_t len); PACK_STRUCT_FIELD(u16_t chksum); } PACK_STRUCT_STRUCT; #define IP_PCB \ IP_PCB_ISIPV6_MEMBER \ struct udp_pcb { /* ip addresses in network byte order */ \ IP_PCB; /* Common members of all PCB types */ ip_addr_t local_ip; \ ip_addr_t remote_ip; \ struct udp_pcb *next; /* Protocol specific PCB members */ /* Socket options */ \ u8_t so_options; \ u8_t flags; /* Type Of Service */ \ u8_t tos; \ /** ports are in host byte order */ /* Time To Live */ \ u16_t local_port, remote_port; u8_t ttl \ /* link layer address resolution hint */ \ /** receive callback function */ IP_PCB_ADDRHINT udp_recv_fn recv; /** user-supplied argument for the recv callback */ struct ip_pcb { void *recv_arg; /* Common members of all PCB types */ }; IP_PCB; }; UDP PCB Chain 26 udp_pcbs Local_ip =192.168.1.37 Local_ip =0 Local_ip =192.168.1.37 Remote_ip =192.168.1.1 Remote_ip =192.168.1.3 Remote_ip =0 …… …… …… next next next Local_port = 7 Local_port = 69 Local_port = 123 Remote_port = 1234 Remote_port = 4321 Remote_port = 0 recv recv recv …… …… ……

void proc1(void *arg, struct udp_pcb *pcb , struct pbuf *p, struct ip_addr *addr , u16_t port) { …… }

void proc1(void *arg, struct udp_pcb *pcb , struct pbuf *p, struct ip_addr *addr , u16_t port) { …… }

Void proc1(void *arg, struct udp_pcb *pcb , struct pbuf *p, struct ip_addr *addr , u16_t port) { …… }

参考《嵌入式网络那些事LwIP协议深度剖析与实战演练》 UDP Raw API presentation …udp_new(…) 27 Create or remove an UDP Structure …udp_remove(…)

…udp_bind(…) Initialize the UDP Structure with • the device internal IP address and port …udp_connect(…) • the remote (external) IP address and port Clear remote IP address and port …udp_disconnect(…) Set a receive callback for a UDP PCB …udp_recv(…) Function to call when sending a Packet …udp_send(…) • Using the default target (external) IP address and the default interface • Using a specific target (external) IP …udp_sendto(…) address but the default interface • Using a specific target (external) IP …udp_sendto_if(…) address and a specific interface UDP Connection setup example 28 Demo_upcb = udp_new(); Create an UDP Structure if (Demo_upcb ==NULL) { //the PCB data structure cannot be allocated. return UDP_MemoryError;} Error Management

Error = udp_bind(Demo_upcb, IP_ADDR_ANY, UDP_Listen_PORT); if (Error != ERR_OK) { // the UDP Structure is alreadyInitialize binded the UDP Structure with return UDP_AlreadyBinded;• };the device internal IP address (any) • the user application internal port

Error Management udp_recv(Demo_upcb, &udp_client_callback, NULL);

Initialize the UDP Structure with the callback function (udp_client_callback) to use when a packet is received

Now your application is ready to receive data UDP Connection CallBack example 29 void udp_client_callback(void *arg, struct udp_pcb *upcb, struct pbuf *pcallback, Callback function parameter upcb : the UDP connection used struct ip_addr * , addr pcallback : the pointer to the u16_t port) received buffer { addr : the source IP address … port : the source port number

Error = pbuf_copy_partial(pcallback, UDP_Data, 4, 0); if (Error == 0) Copy data from a { CallBackError = UDP_MemoryError; PBUF_POOL, the pbuf API pbuf_free(pcallback); has to be used return; } If an error occurs, the user Error Management application has to free the buffer pbuf_free(pcallback); … After processing the receivefata, the user } application has to free the packet UDP Connection : send data example 30 Error = udp_connect(Demo_upcb, addr, port); if( Error != ERR_OK) { return UDP_ConnectionErrorInitialize; } the UDP Structure with • the target (external) IP address (any) • the target application (external) port Error Management number psend = pbuf_alloc(PBUF_TRANSPORT,len, PBUF_RAM); if (psend==NULL) Allocate a PBUF_RAM to send the data { return UDP_MemoryError; } Error Management memcpy (psend->payload, data, len); Copy data into the PBUF_RAM Send the data

Error = udp_send(Demo_upcb, psend); if (Error != ERR_OK) If an error occurs, the user application {pbuf_free(psend); has to free the packet return UDP_SendNOK; } After sending the Data, the user pbuf_free(psend); application has to free the packet Build UDP Connection 31

Memp_pools size num UDP_PCB base TCP_PCB System Reset tab NULL TCP_PCB_LISTE N

……

PBUF_REF/ROM

PBUF_POOL

Memp_std.h Build UDP Connection 32

Elements of Memp_pools size UDP_PCB pool num UDP_PCB 0x20006AC8 base 0x20006AA8 TCP_PCB LwIP init tab 0x20006A88 TCP_PCB_LISTE 0x20006A68 N NULL ……

PBUF_REF/ROM

PBUF_POOL

Memp_std.h Build UDP Connection 33

Available elements of Memp_pools size UDP_PCB pool num UDP_PCB 0x20006AC8 udp_new() base 0x20006AA8 upcb = …… 0x20006AC8 tab 0x20006A88

0x20006A68

NULL Build UDP Connection 34

Available elements of Memp_pools size UDP_PCB pool num UDP_PCB 0x20006AC8 base 0x20006AA8 upcb = …… 0x20006AC8 tab 0x20006A88

0x20006A68 Local ip …… NULL Udp_pcbs next udp_bind() NULL 0x20006AC8 …….. Build UDP Connection 35

Available elements of Memp_pools size UDP_PCB pool num UDP_PCB 0x20006AC8 base 0x20006AA8 upcb = …… 0x20006AC8 tab 0x20006A88

0x20006A68 Local ip …… NULL Udp_pcbs next udp_recv() NULL 0x20006AC8 …….. Build UDP Connection 36

Available elements of Memp_pools size UDP_PCB pool num UDP_PCB 0x20006AC8 base 0x20006AA8 upcb = …… 0x20006AC8 tab 0x20006A88

0x20006A68 Local ip …… NULL Udp_pcbs next udp_connect() NULL 0x20006AC8 …….. LwIP UDP connection flow 37

User Application or Application Layer protocols

LwIP Stack

STM32F407 Driver netif->input() TCP pcb 38

TCP TCP TCP pcb A pcb B pcb C

*next *next *next IP_PCB IP_PCB IP_PCB TCP_PCB_COMMON TCP_PCB_COMMON TCP_PCB_COMMON remote port remote port remote port flags flags flags used to do math used to do math used to do math

The single-chained lists TCP Raw API : connection functions

39 Create a TCP Structure … tcp_new(void)

Initialize the TCP Structure with the device … tcp_bind(…) internal IP address and port

… tcp_listen(…) These functions : • sets up the local port to listen for incoming connections … tcp_accept(…) • initialize the callback function to use when a new connection occurs. … tcp_connect(…) Connect to the remote host and sends the initial SYN segment which opens the connection. LwIP Server setup 40 lwIP Stack Action Application actions Application Create TCP PCB tcp_new() 1 Listener Bind port number tcp_bind() 2 Setup Create listening endpoint (new PCB allocated) tcp_listen() 3 Set accept callback tcp_accept() 4 (server)

void tcp_echoserver_init(void) { /* create new tcp pcb */ 1 tcp_echoserver_pcb = tcp_new(); if (tcp_echoserver_pcb != NULL) { err_t err; /* bind echo_pcb to port 7 (ECHO protocol) */ 2 err = tcp_bind(tcp_echoserver_pcb, IP_ADDR_ANY, 7); if (err == ERR_OK) { /* start tcp listening for echo_pcb */ 3 tcp_echoserver_pcb = tcp_listen(tcp_echoserver_pcb); /* initialize LwIP tcp_accept callback function */ 4 tcp_accept(tcp_echoserver_pcb, tcp_echoserver_accept); } else { /* deallocate the pcb */ memp_free(MEMP_TCP_PCB, tcp_echoserver_pcb); } } } LwIP Client incoming(1)

41 lwIP Stack Action Application actions SYN (allocate new PCB) SYN/ACK lwIP responds with SYN/ACK ACK (invoke accept callback) => sets new callback argument tcp_arg() 1 Server sets recv callback tcp_recv() 2 Application Server sets error/abort callback tcp_err() 3 Connection Server sets poll callback tcp_poll() 4 Setup LwIP Client incoming(2) 42 static err_t tcp_echoserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { ... /* allocate structure es to maintain tcp connection informations */ es = (struct tcp_echoserver_struct *)mem_malloc(sizeof(struct tcp_echoserver_struct)); if (es != NULL) { es->state = ES_ACCEPTED; es->pcb = newpcb; es->retries = 0; es->p = NULL;

/* pass newly allocated es structure as argument to newpcb */ 1 tcp_arg(newpcb, es);

/* initialize lwip tcp_recv callback function for newpcb */ 2 tcp_recv(newpcb, tcp_echoserver_recv);

/* initialize lwip tcp_err callback function for newpcb */ 3 tcp_err(newpcb, tcp_echoserver_error); /* initialize lwip tcp_poll callback function for newpcb */ tcp_poll(newpcb, tcp_echoserver_poll, 0); 4 ret_err = ERR_OK; } else { ... } return ret_err; } TCP Raw API : Receive & send functions

… tcp_recv(…) These functions are used to receive data : • Specify a callback function … tcp_recved(…) • inform LwIP that the data was handled

Callback function

… tcp_sent(…) These functions are used to send out data : • Specify a callback function … tcp_sndbuf(…) • Get the maximum amount of data that can be sent. … tcp_write(…) • to enqueue the data. • to force the data to be sent. … tcp_output(…) LwIP Data reception lwIP Stack Action Application actions FIN lwIP recognizes FIN, generates ACK ACK lwIP invokes server recv callback Server frees private data structures, shuts FIN tcp_close() 1 down connection Recv callback ACK lwIP processes last ACK

Data (lwIP invokes server recv callback) => Tell LwIP that the received are processed tcp_recved() 2 ACK lwIP sends ACK for received client data Return OK status 3 Recv callback

err_t Recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *pcallback, err_t err) {… pcallback = NULL

if(pcallback == NULL) { when receiving a FIN 1 tcp_close(tpcb); return ERR_OK; } Else{ The receive callback 2 tcp_recved(tpcb, pcallback->tot_len); send the ACK on exit 3 return ERR_OK; } }

44 LwIP Data sending 45 lwIP Stack Action Application actions lwIP enqueues TCP segment tcp_write(data1,len) 1 Application lwIP enqueues TCP segment tcp_write(data2, len2) 2 Data Client signals lwIP to actually generate tcp_output() sending outgoing packets 3 ACK lwIP invokes client recv callback) => lwIP sends data segments to client, incl. ACK for previously received client data Application Sent callback

Example with Recopy Error = tcp_write(tpcb, "LED2", 4, TCP_WRITE_FLAG_COPY|TCP_WRITE_FLAG_MORE); 1 if(Error != ERR_OK) return Error;

2 Error = tcp_write(tpcb, " TOGGLED", 8, TCP_WRITE_FLAG_COPY); if(Error != ERR_OK) return Error;

Error = tcp_output(tpcb); 3 if(Error != ERR_OK) return Error; LwIP Data reception & sending 46 lwIP Stack Action Application actions Data (lwIP invokes server recv callback) => lwIP enqueues TCP segment tcp_write(data1,len) 1 lwIP enqueues TCP segment tcp_write(data2, len2) 2 Application Tell LwIP that the received are processed tcp_recved() 3 Receive lwIP finds queued segments to be sent Return OK status 4 lwIP sends data segments to client, incl. callback Data/ACK ACK for previously received client data

err_t Recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *pcallback, err_t err) {… if(pcallback == NULL) { reception of a FIN … } Else{ Error = tcp_write(tpcb, "LED2", 4, TCP_WRITE_FLAG_COPY|TCP_WRITE_FLAG_MORE); 1 if(Error != ERR_OK) return Error;

2 Error = tcp_write(tpcb, " TOGGLED", 8, TCP_WRITE_FLAG_COPY); if(Error != ERR_OK) return Error; 3 tcp_recved(tpcb, pcallback->tot_len); 4 return ERR_OK; } } RAW API & BSD Sockets 48

Client Process BSD Sockets lwIP RAW API Server Process BSD Sockets lwIP RAW API Activity Call Used Call Used Activity Call Used Call Used create a socket socket() tcp_new() create a socket socket() tcp_new() bind a socket bind a socket bind() tcp_bind() bind() tcp_bind() address(optional) address listen for incoming listen() tcp_listen() connections request a connect() tcp_connect() connection accept connection accept() tcp_accept() write() tcp_write() send data send() tcp_sent() read() receive data tcp_recv() recv() write() tcp_write() send data send() tcp_sent() read() receive data tcp_recv() recv() Disconnect shutdown() tcp_abort() Disconnect shutdown() tcp_abort() socket (optional) close() tcp_close() socket (optional) close() tcp_close() Resource 49

AN3966 LwIP TCP/IP stack demonstration for STM32F4x7xx microcontrollers AN3384 LwIP TCP/IP stack demonstration for STM32F2x7xx microcontrollers AN3102 LwIP TCP/IP stack demonstration for STM32F107xx connectivity line microcontrollers AN3968 STM32F407/STM32F417 in-application programming (IAP) over Ethernet AN3226 STM32F107 In-Application Programming (IAP) over Ethernet AN3376 STM32F2x7 In-Application Programming (IAP) over Ethernet UM1709 STM32Cube Ethernet IAP example UM1713 Developing applications on STM32Cube with LwIP TCP/IP stack Ethernet / TCP-IP - Training Suite

04 – TCP/IP solution & Tools TCP/IP solutions (1/3) 51 TCP/IP solutions (2/3) 52 TCP/IP solutions (3/3) 53 Useful tools: WireShark 54

• WireShark is • a network monitoring tool • It uses WinPcap that interfaces directly with the Network card

• Wireshark allows you to • See all the packets sent or received by the PC • Filter the packets to display only the relevant information. • The packets content is formatted for easy reading • This Software cannot send any data WireShark : how to use it 55 • Select the network interface you want to monitor WireShark : ICMP Echo Requests & Replies 56 Thank you !