- Notifications
You must be signed in to change notification settings - Fork 8.2k
net: sntp: implement SNTP server library #96040
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
base: main
Are you sure you want to change the base?
Conversation
37cb0d0 to 1cb30ca Compare | ret = sendto(data->sock, &sntp_reply, sizeof(struct sntp_pkt), 0, &client_addr, | ||
| client_addr_len); |
Check failure
Code scanning / SonarCloud
POSIX functions should not be called with arguments that trigger buffer overflows High
1cb30ca to 187609c Compare 187609c to ff6765a Compare Implementation of SNTP server functionality (RFC 5905) Zephyr software example is also provided. Signed-off-by: Lothar Felten <lothar.felten@gmail.com>
ff6765a to eecfced Compare | @jukkar can probably comment on this, but shouldn't we use a socket service for this? |
|
| char recv_buffer[SNTP_SERVER_RX_BUFFER_SIZE]; | ||
| }; | ||
| | ||
| static struct sntp_pkt sntp_reply; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why having a global reply buffer as this prevents multiple threads to send data at the same time? Can't we allocate this from stack in each receive function?
| return ret; | ||
| } | ||
| | ||
| static void sntp_udp4_thread(void) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we could use socket service API here to avoid these IPv4 and IPv6 threads and save some memory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I'll look into the socket service API and I'll rewrite the code.
Yes, I think so. Noticed your comment after giving mine about the same issue. |
| while (ret == 0) { | ||
| sntp_process_packet(&data_ipv4); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
infinite loop
| while (ret == 0) { | |
| sntp_process_packet(&data_ipv4); | |
| while (ret == 0) { | |
| ret = sntp_process_packet(&data_ipv4); |
| endif # SNTP client | ||
| | ||
| config SNTP_SERVER | ||
| bool "SNTP client support" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| bool "SNTP client support" | |
| bool "SNTP server support" |
| sntp_reply.orig_tm_s = pkt->tx_tm_s; | ||
| sntp_reply.orig_tm_f = pkt->tx_tm_f; | ||
| sntp_reply.rx_tm_s = htonl(systime.tv_sec + OFFSET_1970_JAN_1); | ||
| sntp_reply.rx_tm_f = htonl((systime.tv_nsec)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NTP timestamps use a 32-bit fractional second in units of 2⁻³² seconds, not nanoseconds.
Need to convert, something like:
uint32_t frac = (uint32_t)((((uint64_t)systime.tv_nsec) << 32) / 1000000000ULL); sntp_reply.rx_tm_f = htonl(frac);| return ret; | ||
| } | ||
| sntp_reply.tx_tm_s = htonl(systime.tv_sec + OFFSET_1970_JAN_1); | ||
| sntp_reply.tx_tm_f = htonl((systime.tv_nsec)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
| return 0; | ||
| } | ||
| tp.tv_sec = t.seconds; | ||
| tp.tv_nsec = t.fraction / 1000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
again, wrong handling of the fractional part, I think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements SNTP server functionality (RFC 5905) with automatic IPv4/IPv6 thread management and includes a complete example application.
- Introduces SNTP server library that can handle client time requests on both IPv4 and IPv6
- Refactors existing SNTP code to separate client and server components with shared constants
- Provides configuration options for server thread stack size and priority
Reviewed Changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| subsys/net/lib/sntp/sntp_server.c | Core SNTP server implementation with packet processing and socket handling |
| subsys/net/lib/sntp/sntp_pkt.h | Shared SNTP constants moved from client code |
| subsys/net/lib/sntp/sntp.c | Refactored to use shared constants and make packet dump function public |
| subsys/net/lib/sntp/Kconfig | Configuration options for SNTP client/server separation |
| subsys/net/lib/sntp/CMakeLists.txt | Build system updates for conditional compilation |
| samples/net/sockets/sntp_server/* | Complete example application demonstrating SNTP server usage |
| samples/net/cloud/aws_iot_mqtt/prj.conf | Updated to use new SNTP_CLIENT config |
| include/zephyr/net/sntp_server.h | Public API header for SNTP server functionality |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| sntp_reply.li = SNTP_LEAP_INDICATOR_CLOCK_INVALID; | ||
| sntp_reply.mode = SNTP_MODE_SERVER; | ||
| sntp_reply.stratum = SNTP_STRATUM_KOD; | ||
| sntp_reply.mode = SNTP_MODE_SERVER; |
Copilot AI Sep 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate assignment of sntp_reply.mode on line 48 and 50. Remove the redundant assignment on line 50.
| sntp_reply.mode = SNTP_MODE_SERVER; |
| sntp_reply.mode = SNTP_MODE_SERVER; | ||
| sntp_reply.stratum = SNTP_STRATUM_KOD; | ||
| sntp_reply.mode = SNTP_MODE_SERVER; | ||
| strncpy((char *)(&sntp_reply.ref_id), "X", sizeof(sntp_reply.ref_id)); |
Copilot AI Sep 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strncpy does not guarantee null termination. Use strlcpy or ensure null termination manually to prevent potential buffer overrun issues.
| strncpy((char *)(&sntp_reply.ref_id), "X", sizeof(sntp_reply.ref_id)); | |
| strncpy((char *)(&sntp_reply.ref_id), "X", sizeof(sntp_reply.ref_id)); | |
| ((char *)&sntp_reply.ref_id)[sizeof(sntp_reply.ref_id) - 1] = '\0'; |
| int sntp_server_clock_source(unsigned char *refid, unsigned char stratum, char precision) | ||
| { | ||
| sntp_reply.stratum = stratum; | ||
| strncpy((char *)(&sntp_reply.ref_id), refid, sizeof(sntp_reply.ref_id)); |
Copilot AI Sep 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strncpy does not guarantee null termination. Use strlcpy or ensure null termination manually to prevent potential buffer overrun issues.
| strncpy((char *)(&sntp_reply.ref_id), refid, sizeof(sntp_reply.ref_id)); | |
| strncpy((char *)(&sntp_reply.ref_id), refid, sizeof(sntp_reply.ref_id)); | |
| ((char *)&sntp_reply.ref_id)[sizeof(sntp_reply.ref_id) - 1] = '\0'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The sample changes should be separated to two separate commits, one for server sample and the other for aws changes. The actual sntp server changes should also be in separate commit. So in total three commits in the PR.
| | ||
| LOG_INF("waiting for network"); | ||
| wait_for_network(); | ||
| ret = sntp_simple("ptbtime1.ptb.de", SYS_FOREVER_MS, &t); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The address of the server should be set via kconfig option. The server sample can have its own Kconfig file where the server name can be stored (see examples how to do this in other network samples). Note that the server name should be empty by default so that user is forced to set it according to his/hers network setup.




Implementation of SNTP server functionality (RFC 5905)
Zephyr software example is also provided.