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 (c) SNMP DHCP (c)
Transport protocols Transport UDP TCP • UDP, Layer • TCP, Internet ICMP IP IGMP Layer Internet Protocols ARP
• ICMP, Ethernet • IGMP, STM32F407 PPP PHY Network Datalink Protocols Interface Layer • ARP, • PPP LwIP Architecture 3
dhcp.c, dns.c Application layer udp.c tcp.c Transport layer
ip.c Internet layer
netif.c Network Interface layer LwIP APIs 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 !