-
Notifications
You must be signed in to change notification settings - Fork 2.1k
examples/lwip_ipv4: add example for LWIP IPv4 client/server #21519
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
3581007
c081168
fde797f
a45d1b0
33365ca
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| # Set the name of your application: | ||
| APPLICATION = lwip_ipv4 | ||
|
|
||
| # If no BOARD is found in the environment, use this default: | ||
| BOARD ?= native | ||
|
|
||
| # This has to be the absolute path to the RIOT base directory: | ||
| RIOTBASE ?= $(CURDIR)/../../../../ | ||
|
|
||
| # Uncomment this to enable code in RIOT that does safety checking | ||
| # which is not needed in a production environment but helps in the | ||
| # development process: | ||
| DEVELHELP = 1 | ||
|
|
||
| # Change this to 0 to show compiler invocation lines by default: | ||
| QUIET ?= 1 | ||
|
|
||
| # Modules to include: | ||
| USEMODULE += shell | ||
|
|
||
| USEMODULE += netdev_default | ||
|
|
||
| #enables LWIP IPv4 stack | ||
| USEMODULE += ipv4_addr | ||
| USEMODULE += lwip_arp | ||
| USEMODULE += lwip_ipv4 | ||
|
|
||
| # If this module will be disabled, example set IPv4 192.168.100.11 address. | ||
| # Enable next two line to use DHCP | ||
| #USEMODULE += lwip_dhcp_auto | ||
| #CFLAGS += -DETHARP_SUPPORT_STATIC_ENTRIES=1 | ||
|
|
||
| #enables UDP LWIP sockets | ||
| USEMODULE += sock_udp | ||
|
|
||
| #nables ifconfig command, which allows IPv4 address configuration | ||
| USEMODULE += shell_cmds_default | ||
|
|
||
| include $(RIOTBASE)/Makefile.include |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| BOARD_INSUFFICIENT_MEMORY := \ | ||
| bluepill-stm32f030c8 \ | ||
| i-nucleo-lrwan1 \ | ||
| nucleo-c031c6 \ | ||
| nucleo-f030r8 \ | ||
| nucleo-f031k6 \ | ||
| nucleo-f042k6 \ | ||
| nucleo-l011k4 \ | ||
| nucleo-l031k6 \ | ||
| nucleo-l053r8 \ | ||
| samd10-xmini \ | ||
| slstk3400a \ | ||
| stk3200 \ | ||
| stm32c0116-dk \ | ||
| stm32c0316-dk \ | ||
| stm32f030f4-demo \ | ||
| stm32f0discovery \ | ||
| stm32g0316-disco \ | ||
| stm32l0538-disco \ | ||
| weact-g030f6 \ | ||
| # |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| # LWIP IPv4 client and server example | ||
|
|
||
| This example shows how to send and receive IPv4 UDP datagrams using LWIP | ||
| network library. | ||
|
|
||
| # Shell commands | ||
|
|
||
| The following commands are available: | ||
| - `ifconfig`: allows manual IPv4 address configuration. | ||
| - `client`: sends UDP datagram to given IPv4 address. | ||
|
|
||
| # Usage on BOARD=native | ||
|
|
||
| This instruction, using native board, utilize tap interface and allows | ||
| communication between RIOT system and host Linux. | ||
|
|
||
| In the following sections we describe how to: | ||
| - configure tap interface using RIOT `tapsetup` tool. | ||
| - send data from the Linux host to the RIOT. | ||
| - send data from the RIOT to the Linux host. | ||
|
|
||
| ## Network configuration | ||
|
|
||
| Create `tap0` interface and `tapbr0` using RIOT `tapsetup` tool. | ||
| Commands should be executed on the Linux host: | ||
|
|
||
| ``` | ||
| $sudo ./dist/tools/tapsetup/tapsetup -c 1 | ||
| $sudo ip addr add 192.168.100.100/24 dev tapbr0 | ||
| ``` | ||
|
|
||
| Compile and manually configure IPv4 address on the RIOT. | ||
|
|
||
| ``` | ||
| $make all | ||
| $./bin/native64/lwip_ipv4.elf tap0 | ||
| RIOT native interrupts/signals initialized. | ||
| TZ not set, setting UTC | ||
| RIOT native64 board initialized. | ||
| RIOT native hardware initialization complete. | ||
|
|
||
| main(): This is RIOT! (Version: 2024.04-devel-2705-g39b6f-examples-lwip_ipv4) | ||
|
|
||
| > ifconfig add ET0 192.168.100.11/24 | ||
| ifconfig add ET0 192.168.100.11/24 | ||
| > ifconfig | ||
| ifconfig | ||
| Iface ET0 HWaddr: 8e:9d:7d:a1:fd:cd Link: up State: up | ||
| Link type: wired | ||
| inet addr: 192.168.100.11 mask: 255.255.255.0 gw: 0.0.0.0 | ||
| > | ||
| ``` | ||
|
|
||
| Check connectivity from the Linux host machine to the RIOT: | ||
|
|
||
| ``` | ||
| $ping 192.168.100.11 | ||
| PING 192.168.100.11 (192.168.100.11) 56(84) bytes of data. | ||
| 64 bytes from 192.168.100.11: icmp_seq=1 ttl=255 time=0.240 ms | ||
| 64 bytes from 192.168.100.11: icmp_seq=2 ttl=255 time=0.210 ms | ||
| ... | ||
| ``` | ||
|
|
||
| ## RIOT LWIP IPv4 server | ||
|
|
||
| The server starts automatically on the RIOT: | ||
|
|
||
| ``` | ||
| main(): This is RIOT! (Version: 2024.04-devel-3275-gab2302-examples-lwip_ipv4) | ||
| {"IPv4 addresses": ["192.168.100.11"]} | ||
| Server started. | ||
| > | ||
| ``` | ||
|
|
||
| Send UDP datagram from the Linux host using `nc` tool: | ||
|
|
||
| ``` | ||
| $ nc -u 192.168.100.11 4444 | ||
| Msg from Linux | ||
| Msg from Linux | ||
| ``` | ||
|
|
||
| Observe results on the RIOT: | ||
|
|
||
| ``` | ||
| main(): This is RIOT! (Version: 2024.04-devel-3275-gab2302-examples-lwip_ipv4) | ||
| {"IPv4 addresses": ["192.168.100.11"]} | ||
| Server started. | ||
| > Received 15 bytes - Msg from Linux | ||
|
|
||
| ``` | ||
|
|
||
| ## RIOT LWIP IPv4 client | ||
|
|
||
| Run server on the Linux host using `nc` tool: | ||
|
|
||
| ``` | ||
| $ nc -ul -p 4444 | ||
| ``` | ||
|
|
||
| Send UDP datagram from the RIOT: | ||
|
|
||
| ``` | ||
| > client 192.168.100.100 4444 Msg_from_RIOT | ||
| client 192.168.100.100 4444 Msg_from_RIOT | ||
| > | ||
| ``` | ||
|
|
||
| Observe result on the Linux host: | ||
|
|
||
| ``` | ||
| $nc -ul -p 4444 | ||
| Msg_from_RIOT | ||
|
|
||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,167 @@ | ||
| /* | ||
| * SPDX-FileCopyrightText: 2025 Krzysztof Cabaj <kcabaj@gmail.com> | ||
| * SPDX-License-Identifier: LGPL-2.1-only | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup examples | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief lwip_ipv4 - sample application for demonstrating basic LWIP | ||
| * IPv4 client/server functions. | ||
| * | ||
| * @author Krzysztof Cabaj <kcabaj@gmail.com> | ||
| * | ||
| * @} | ||
| */ | ||
| #include "stdio.h" | ||
| #include "stdlib.h" | ||
| #include "shell.h" | ||
| #include "net/sock/udp.h" | ||
| #include <arpa/inet.h> | ||
| #include "thread.h" | ||
| #include "mutex.h" | ||
|
|
||
| #include "ztimer.h" | ||
| #include "lwip/netif.h" | ||
| #include <arpa/inet.h> | ||
|
|
||
| #ifndef CONFIG_CLIENT_TIMEOUT_SEC | ||
| #define CONFIG_CLIENT_TIMEOUT_SEC 3 | ||
| #endif | ||
|
|
||
| #ifndef CONFIG_DHCP_TIMEOUT_SEC | ||
| #define CONFIG_DHCP_TIMEOUT_SEC 10 | ||
| #endif | ||
|
|
||
| #ifndef SERVER_PORT | ||
| #define SERVER_PORT 4444 | ||
| #endif | ||
|
|
||
| static char server_stack[THREAD_STACKSIZE_DEFAULT]; | ||
|
|
||
| #define SERVER_PORT 4444 | ||
|
|
||
| static int _client_cmd(int argc, char **argv) | ||
| { | ||
| uint32_t dest_ip; | ||
|
|
||
| if (argc < 4) { | ||
| printf("usage: %s <destination IP> <port> <text>\n", argv[0]); | ||
| return -1; | ||
| } | ||
|
|
||
| if (inet_pton(AF_INET, argv[1], &dest_ip) != 1) { | ||
| printf("\"%s\" - is not a valid IPv4 address!\n", argv[1]); | ||
| return -1; | ||
| } | ||
|
|
||
| uint16_t port = atoi(argv[2]); | ||
| size_t data_len = strlen(argv[3]); | ||
| sock_udp_t sock; | ||
| sock_udp_ep_t remote = { .addr = { .ipv4_u32 = dest_ip }, | ||
| .family = AF_INET, | ||
| .port = port }; | ||
| int result = -1; | ||
| char buffer[64]; | ||
|
|
||
| if ((result = sock_udp_create(&sock, NULL, &remote, 0)) != 0) { | ||
| printf("sock_udp_create() failed with %d\n", result); | ||
| return -1; | ||
| } | ||
|
|
||
| if (data_len != (size_t)sock_udp_send(&sock, argv[3], data_len, NULL)) { | ||
| printf("sock_udp_send() failed with %d\n", (int)data_len); | ||
| goto out; | ||
| } | ||
|
|
||
| if ((result = sock_udp_recv(&sock, buffer, sizeof(buffer) - 1, | ||
| CONFIG_CLIENT_TIMEOUT_SEC * US_PER_SEC, &remote)) < 0) { | ||
| printf("sock_udp_recv() failed with %d\n", result); | ||
| goto out; | ||
| } | ||
|
|
||
| buffer[result] = 0; | ||
| printf("Received %d bytes - %s\n", result, buffer); | ||
|
|
||
| out: | ||
| sock_udp_close(&sock); | ||
| return result; | ||
| } | ||
|
|
||
| SHELL_COMMAND(client, "Send UDP datagram", _client_cmd); | ||
|
|
||
| void *server_thread(void *arg) | ||
| { | ||
| (void)arg; | ||
| sock_udp_t sock; | ||
| sock_udp_ep_t local = { .family = AF_INET, | ||
| .port = SERVER_PORT }; | ||
| sock_udp_ep_t remote; | ||
| int result; | ||
| int error; | ||
| char buffer[64]; | ||
|
|
||
| int res = sock_udp_create(&sock, &local, NULL, 0); | ||
| if (res) { | ||
| printf("Sock_udp_create error!\n"); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You want to print the error.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes I want to print error.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I mean print the error code you get from |
||
| printf("Server stopped.\n"); | ||
| return NULL; | ||
| } | ||
|
|
||
| printf("Server started.\n"); | ||
|
|
||
| while (1) { | ||
| if ((result = sock_udp_recv(&sock, buffer, sizeof(buffer) - 1, SOCK_NO_TIMEOUT, &remote)) < 0) { | ||
| printf("sock_udp_recv() failed with %d\n", result); | ||
| } | ||
| else { | ||
| buffer[result] = 0; | ||
| printf("Received %d bytes - %s\n", result, buffer); | ||
|
|
||
| error = sock_udp_send(&sock, buffer, result, &remote); | ||
| if (error < 0) { | ||
| printf("sock_udp_send() failed with %d\n", error); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| sock_udp_close(&sock); | ||
|
|
||
| return NULL; | ||
| } | ||
|
|
||
| #define _TEST_ADDR4_LOCAL (0x0b64a8c0U) /* 192.168.100.11 */ | ||
| #define _TEST_ADDR4_MASK (0x00ffffffU) /* 255.255.255.0 */ | ||
|
|
||
| int main(void) | ||
| { | ||
| char line_buf[SHELL_DEFAULT_BUFSIZE]; | ||
|
|
||
| sys_lock_tcpip_core(); | ||
krzysztof-cabaj marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| struct netif *iface = netif_find("ET0"); | ||
|
|
||
| #ifndef MODULE_LWIP_DHCP_AUTO | ||
| ip4_addr_t ip, subnet; | ||
| ip.addr = _TEST_ADDR4_LOCAL; | ||
| subnet.addr = _TEST_ADDR4_MASK; | ||
| netif_set_addr(iface, &ip, &subnet, NULL); | ||
| #else | ||
| printf("Waiting for DHCP address autoconfiguration ...\n"); | ||
| ztimer_sleep(ZTIMER_MSEC, CONFIG_DHCP_TIMEOUT_SEC * MS_PER_SEC); | ||
| #endif | ||
|
|
||
| /* print network addresses */ | ||
| printf("{\"IPv4 addresses\": [\""); | ||
| char buffer[16]; | ||
| inet_ntop(AF_INET, netif_ip_addr4(iface), buffer, 16); | ||
| sys_unlock_tcpip_core(); | ||
| printf("%s\"]}\n", buffer); | ||
|
|
||
| thread_create(server_stack, sizeof(server_stack), THREAD_PRIORITY_MAIN - 1, 0, server_thread, NULL, "server"); | ||
|
|
||
| shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE); | ||
|
|
||
| return 0; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.