1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11 /**************************************************************************/
12 /**************************************************************************/
13 /** */
14 /** NetX SNTP Client Component */
15 /** */
16 /** Simple Network Time Protocol (SNTP) */
17 /** */
18 /**************************************************************************/
19 /**************************************************************************/
20
21 /**************************************************************************/
22 /* */
23 /* APPLICATION INTERFACE DEFINITION RELEASE */
24 /* */
25 /* nxd_sntp_client.c PORTABLE C */
26 /* 6.1 */
27 /* AUTHOR */
28 /* */
29 /* Yuxin Zhou, Microsoft Corporation */
30 /* */
31 /* DESCRIPTION */
32 /* */
33 /* This file defines the NetX Simple Network Time Protocol (SNTP) */
34 /* Client component, including all data types and external references. */
35 /* It is assumed that tx_api.h, tx_port.h, nx_api.h, and nx_port.h, */
36 /* have already been included. */
37 /* */
38 /* RELEASE HISTORY */
39 /* */
40 /* DATE NAME DESCRIPTION */
41 /* */
42 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
43 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
44 /* resulting in version 6.1 */
45 /* */
46 /**************************************************************************/
47
48 #define NX_SNTP_SOURCE_CODE
49
50 /* Force error checking to be disabled in this module */
51
52 #ifndef NX_DISABLE_ERROR_CHECKING
53 #define NX_DISABLE_ERROR_CHECKING
54 #endif
55
56 #include "nx_api.h"
57 #include "nx_udp.h"
58
59 #include "nx_ipv4.h"
60 #include "nxd_sntp_client.h"
61 #ifdef FEATURE_NX_IPV6
62 #include "nx_ipv6.h"
63 #endif
64
65
66 #include <ctype.h>
67
68 extern TX_THREAD *_tx_thread_current_ptr;
69 extern TX_THREAD _tx_timer_thread;
70 extern volatile ULONG _tx_thread_system_state;
71
72 TX_EVENT_FLAGS_GROUP nx_sntp_client_events;
73
74 /* Define internal time variables for offsets between
75 receipt of SNTP packet and application to
76 SNTP Client local time. */
77 static ULONG send_timerticks = 0;
78 static ULONG receive_timerticks = 0;
79 static ULONG process_timerticks = 0;
80
81
82 /**************************************************************************/
83 /* */
84 /* FUNCTION RELEASE */
85 /* */
86 /* _nxe_sntp_client_create PORTABLE C */
87 /* 6.2.1 */
88 /* AUTHOR */
89 /* */
90 /* Yuxin Zhou, Microsoft Corporation */
91 /* */
92 /* DESCRIPTION */
93 /* */
94 /* This function performs error checking on the SNTP client create */
95 /* service. */
96 /* */
97 /* INPUT */
98 /* */
99 /* client_ptr Pointer to client struct */
100 /* ip_ptr Pointer to client IP instance */
101 /* iface_index Index of SNTP network interface */
102 /* packet_pool_ptr Pointer to client packet pool */
103 /* socket_ptr Pointer to client UDP socket */
104 /* leap_second_handler Pointer to leap second handler */
105 /* random_number_generator Random number generator callback */
106 /* */
107 /* OUTPUT */
108 /* */
109 /* NX_PTR_ERROR Invalid pointer parameter */
110 /* NX_INVALID_INTERFACE Invalid network interface */
111 /* status Actual completion status */
112 /* */
113 /* CALLS */
114 /* */
115 /* _nx_sntp_client_create Actual SNTP client create service */
116 /* */
117 /* CALLED BY */
118 /* */
119 /* Application Code */
120 /* */
121 /* RELEASE HISTORY */
122 /* */
123 /* DATE NAME DESCRIPTION */
124 /* */
125 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
126 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
127 /* resulting in version 6.1 */
128 /* 03-08-2023 Wenhui Xie Modified comment(s), */
129 /* checked the client ID, */
130 /* resulting in version 6.2.1 */
131 /* */
132 /**************************************************************************/
_nxe_sntp_client_create(NX_SNTP_CLIENT * client_ptr,NX_IP * ip_ptr,UINT iface_index,NX_PACKET_POOL * packet_pool_ptr,UINT (* leap_second_handler)(NX_SNTP_CLIENT * client_ptr,UINT indicator),UINT (* kiss_of_death_handler)(NX_SNTP_CLIENT * client_ptr,UINT code),VOID (random_number_generator)(struct NX_SNTP_CLIENT_STRUCT * client_ptr,ULONG * rand))133 UINT _nxe_sntp_client_create(NX_SNTP_CLIENT *client_ptr, NX_IP *ip_ptr, UINT iface_index, NX_PACKET_POOL *packet_pool_ptr,
134 UINT (*leap_second_handler)(NX_SNTP_CLIENT *client_ptr, UINT indicator),
135 UINT (*kiss_of_death_handler)(NX_SNTP_CLIENT *client_ptr, UINT code),
136 VOID (random_number_generator)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, ULONG *rand))
137 {
138
139 UINT status;
140
141
142 /* Check for invalid input pointers. */
143 if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (client_ptr == NX_NULL) || (packet_pool_ptr == NX_NULL))
144 {
145
146 /* Return error status. */
147 return(NX_PTR_ERROR);
148 }
149
150 /* Check for the client ID. */
151 if ((client_ptr == NX_NULL) || (client_ptr -> nx_sntp_client_id == NXD_SNTP_ID))
152 {
153
154 /* Return error status. */
155 return(NX_PTR_ERROR);
156 }
157
158 /* Check for invalid network interface input. */
159 if (iface_index >= NX_MAX_PHYSICAL_INTERFACES)
160 {
161
162 return NX_INVALID_INTERFACE;
163 }
164
165 /* Call the actual client create service. */
166 status = _nx_sntp_client_create(client_ptr, ip_ptr, iface_index, packet_pool_ptr,
167 leap_second_handler, kiss_of_death_handler, random_number_generator);
168
169 /* Return completion status. */
170 return(status);
171 }
172
173
174 /**************************************************************************/
175 /* */
176 /* FUNCTION RELEASE */
177 /* */
178 /* _nx_sntp_client_create PORTABLE C */
179 /* 6.1 */
180 /* AUTHOR */
181 /* */
182 /* Yuxin Zhou, Microsoft Corporation */
183 /* */
184 /* DESCRIPTION */
185 /* */
186 /* This function creates a SNTP client with the input NetX and SNTP */
187 /* parameters. Note the host application must initialize and start the */
188 /* SNTP client using the nx_sntp_broadcast/unicast_initialize and */
189 /* nx_sntp_run_broadcast/unicast services to receive SNTP time updates.*/
190 /* */
191 /* INPUT */
192 /* */
193 /* client_ptr Pointer to client struct */
194 /* ip_ptr Pointer to client IP instance */
195 /* iface_index Index of SNTP network interface */
196 /* packet_pool_ptr Pointer to client packet pool */
197 /* socket_ptr Pointer to client UDP socket */
198 /* leap_second_handler Pointer to leap second handler */
199 /* random_number_generator Random number generator callback */
200 /* */
201 /* OUTPUT */
202 /* */
203 /* status Actual completion status */
204 /* NX_SUCCESS Successful completion status */
205 /* NX_SNTP_INSUFFICIENT_PACKET_PAYLOAD */
206 /* Invalid packet pool payload */
207 /* */
208 /* CALLED BY */
209 /* */
210 /* Application Code */
211 /* */
212 /* CALLS */
213 /* */
214 /* tx_timer_create Create ThreadX timer service */
215 /* tx_timer_delete Delete ThreadX timer service */
216 /* tx_mutex_create Create ThreadX mutex service */
217 /* tx_mutex_delete Delete ThreadX mutex service */
218 /* nx_udp_socket_create Create the SNTP Client socket */
219 /* nx_udp_socket_delete Delete the SNTP Client socket */
220 /* nx_udp_socket_bind Bind the SNTP Client to SNTP port */
221 /* */
222 /* RELEASE HISTORY */
223 /* */
224 /* DATE NAME DESCRIPTION */
225 /* */
226 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
227 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
228 /* resulting in version 6.1 */
229 /* */
230 /**************************************************************************/
_nx_sntp_client_create(NX_SNTP_CLIENT * client_ptr,NX_IP * ip_ptr,UINT iface_index,NX_PACKET_POOL * packet_pool_ptr,UINT (* leap_second_handler)(NX_SNTP_CLIENT * client_ptr,UINT indicator),UINT (* kiss_of_death_handler)(NX_SNTP_CLIENT * client_ptr,UINT code),VOID (random_number_generator)(struct NX_SNTP_CLIENT_STRUCT * client_ptr,ULONG * rand))231 UINT _nx_sntp_client_create(NX_SNTP_CLIENT *client_ptr, NX_IP *ip_ptr, UINT iface_index, NX_PACKET_POOL *packet_pool_ptr,
232 UINT (*leap_second_handler)(NX_SNTP_CLIENT *client_ptr, UINT indicator),
233 UINT (*kiss_of_death_handler)(NX_SNTP_CLIENT *client_ptr, UINT code),
234 VOID (random_number_generator)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, ULONG *rand))
235 {
236
237 UINT status;
238
239
240 /* Null the members of NX_SNTP_CLIENT. */
241 memset(client_ptr, 0, sizeof(NX_SNTP_CLIENT));
242
243 /* Set the Client ID to indicate the SNTP client thread is ready. */
244 client_ptr -> nx_sntp_client_id = NXD_SNTP_ID;
245
246 /* Set the IP instance. */
247 client_ptr -> nx_sntp_client_ip_ptr = ip_ptr;
248
249 /* Set the SNTP network interface. */
250 client_ptr -> nx_sntp_client_interface_index = iface_index;
251
252 /* Check for minimal packet size requirement. */
253 #ifndef NX_DISABLE_IPV4
254 if (packet_pool_ptr -> nx_packet_pool_payload_size <
255 (sizeof(NX_IPV4_HEADER) + sizeof(NX_UDP_HEADER) + NX_SNTP_CLIENT_PACKET_DATA_SIZE))
256 {
257
258 return NX_SNTP_INSUFFICIENT_PACKET_PAYLOAD;
259 }
260 #endif /* NX_DISABLE_IPV4 */
261
262
263 /* This only assures IPv4 packets will work. We do not know yet if the Client expects to receive
264 SNTP packets over ipv6 networks. When sending packets, the SNTP Client will have set its
265 SNTP server from which the IP type will be determined. However, for receiving packets,
266 it is up to the host to ensure its packet payload will be large enough for IPv6 packets:
267
268 sizeof(NX_IPV6_HEADER) + sizeof(NX_UDP_HEADER) + NX_SNTP_CLIENT_PACKET_DATA_SIZE)
269 40 bytes 8 bytes 48 bytes
270 */
271
272 client_ptr -> nx_sntp_client_packet_pool_ptr = packet_pool_ptr;
273
274 /* Create a udp socket to receive SNTP time data. */
275 status = nx_udp_socket_create(client_ptr -> nx_sntp_client_ip_ptr, &(client_ptr -> nx_sntp_client_udp_socket),
276 NX_SNTP_CLIENT_UDP_SOCKET_NAME, NX_IP_NORMAL,
277 NX_FRAGMENT_OKAY, NX_SNTP_CLIENT_TIME_TO_LIVE,
278 NX_SNTP_CLIENT_MAX_QUEUE_DEPTH);
279
280 /* Check for error. */
281 if (status != NX_SUCCESS)
282 {
283
284 return status;
285 }
286
287 /* Register a receive notify callback. */
288 status = nx_udp_socket_receive_notify(&(client_ptr -> nx_sntp_client_udp_socket), _nx_sntp_client_receive_notify);
289
290 /* Check for errors. */
291 if (status != NX_SUCCESS)
292 {
293
294 nx_udp_socket_delete(&(client_ptr -> nx_sntp_client_udp_socket));
295
296 return status;
297 }
298
299 /* Set callback for leap second handler (optional). */
300 client_ptr -> leap_second_handler = leap_second_handler;
301
302 /* Set callback for kiss of death server packet handler (optional). */
303 client_ptr -> kiss_of_death_handler = kiss_of_death_handler;
304
305 /* Set callback for random number generator (Only applicable for unicast clients
306 configured for random wait on startup). */
307 client_ptr -> random_number_generator = random_number_generator;
308
309 /* Create the SNTP update timeout timer. */
310 status = tx_timer_create(&client_ptr -> nx_sntp_update_timer, "SNTP Client Update Timer",
311 _nx_sntp_client_update_timeout_entry, (ULONG)client_ptr,
312 (NX_IP_PERIODIC_RATE * NX_SNTP_UPDATE_TIMEOUT_INTERVAL),
313 (NX_IP_PERIODIC_RATE * NX_SNTP_UPDATE_TIMEOUT_INTERVAL), TX_NO_ACTIVATE);
314
315 /* Check for error. */
316 if (status != TX_SUCCESS)
317 {
318
319 /* Delete the UDP socket. */
320 nx_udp_socket_delete(&(client_ptr -> nx_sntp_client_udp_socket));
321
322 /* Return error status. */
323 return(status);
324 }
325
326 /* Create the SNTP mutex. */
327 status = tx_mutex_create(&(client_ptr -> nx_sntp_client_mutex), "NetX SNTP Client Mutex", TX_NO_INHERIT);
328
329 /* Determine if the semaphore creation was successful. */
330 if (status != NX_SUCCESS)
331 {
332
333 /* Delete the UDP socket. */
334 nx_udp_socket_delete(&(client_ptr -> nx_sntp_client_udp_socket));
335
336 /* Delete the timer. */
337 tx_timer_delete(&(client_ptr -> nx_sntp_update_timer));
338
339 /* No, return error status. */
340 return(status);
341 }
342
343 /* Create the SNTP event flag group. */
344 status = tx_event_flags_create(&nx_sntp_client_events, "NetX SNTP Client Events");
345
346 /* Check the return status. */
347 if (status != NX_SUCCESS)
348 {
349
350 /* Delete the UDP socket. */
351 nx_udp_socket_delete(&(client_ptr -> nx_sntp_client_udp_socket));
352
353 /* Delete the timer. */
354 tx_timer_delete(&(client_ptr -> nx_sntp_update_timer));
355
356 /* Delete the Client mutex. */
357 tx_mutex_delete(&client_ptr -> nx_sntp_client_mutex);
358
359 /* Error present, return error code. */
360 return(status);
361 }
362
363 /* Create the SNTP Client processing thread. */
364 status = tx_thread_create(&(client_ptr -> nx_sntp_client_thread), "NetX SNTP Client", _nx_sntp_client_thread_entry, (ULONG)client_ptr,
365 client_ptr -> nx_sntp_client_thread_stack, NX_SNTP_CLIENT_THREAD_STACK_SIZE,
366 NX_SNTP_CLIENT_THREAD_PRIORITY, NX_SNTP_CLIENT_PREEMPTION_THRESHOLD, 1, TX_DONT_START);
367
368 /* Determine if the thread creation was successful. */
369 if (status != NX_SUCCESS)
370 {
371
372 /* Delete the mutex. */
373 tx_mutex_delete(&(client_ptr -> nx_sntp_client_mutex));
374
375 /* Delete the UDP socket. */
376 nx_udp_socket_delete(&(client_ptr -> nx_sntp_client_udp_socket));
377
378 /* Delete the timer. */
379 tx_timer_delete(&(client_ptr -> nx_sntp_update_timer));
380
381 /* Delete the event flag group. */
382 tx_event_flags_delete(&nx_sntp_client_events);
383
384 /* No, return error status. */
385 return(status);
386 }
387
388 return(NX_SUCCESS);
389 }
390
391
392 /**************************************************************************/
393 /* */
394 /* FUNCTION RELEASE */
395 /* */
396 /* _nxe_sntp_client_delete PORTABLE C */
397 /* 6.1 */
398 /* AUTHOR */
399 /* */
400 /* Yuxin Zhou, Microsoft Corporation */
401 /* */
402 /* DESCRIPTION */
403 /* */
404 /* This function checks for errors on the client delete service. */
405 /* */
406 /* INPUT */
407 /* */
408 /* client_ptr Pointer to SNTP Client */
409 /* */
410 /* OUTPUT */
411 /* */
412 /* NX_PTR_ERROR Invalid pointer parameter */
413 /* status Actual completion status */
414 /* */
415 /* CALLS */
416 /* */
417 /* _nx_sntp_client_delete Actual SNTP client delete service*/
418 /* */
419 /* CALLED BY */
420 /* */
421 /* Application Code */
422 /* */
423 /* RELEASE HISTORY */
424 /* */
425 /* DATE NAME DESCRIPTION */
426 /* */
427 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
428 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
429 /* resulting in version 6.1 */
430 /* */
431 /**************************************************************************/
_nxe_sntp_client_delete(NX_SNTP_CLIENT * client_ptr)432 UINT _nxe_sntp_client_delete(NX_SNTP_CLIENT *client_ptr)
433 {
434
435 UINT status;
436
437
438 /* Check for the validity of input parameter. */
439 if ((client_ptr == NX_NULL) || (client_ptr -> nx_sntp_client_id != NXD_SNTP_ID))
440 {
441
442 /* Return error status. */
443 return(NX_PTR_ERROR);
444 }
445
446 /* Check if this function is called from the appropriate thread. */
447 NX_THREADS_ONLY_CALLER_CHECKING
448
449 /* Call the actual client create service. */
450 status = _nx_sntp_client_delete(client_ptr);
451
452 /* Return completion status. */
453 return(status);
454 }
455
456
457 /**************************************************************************/
458 /* */
459 /* FUNCTION RELEASE */
460 /* */
461 /* _nx_sntp_client_delete PORTABLE C */
462 /* 6.2.1 */
463 /* AUTHOR */
464 /* */
465 /* Yuxin Zhou, Microsoft Corporation */
466 /* */
467 /* DESCRIPTION */
468 /* */
469 /* This function deletes a previously created SNTP Client and releases */
470 /* ThreadX and NetX resources held by the Client. */
471 /* */
472 /* Note that it is the application's responsibility to delete/release */
473 /* the Client packet pool. */
474 /* */
475 /* INPUT */
476 /* */
477 /* client_ptr Pointer to Client struct */
478 /* */
479 /* OUTPUT */
480 /* */
481 /* NX_SUCCESS Successful completion status */
482 /* */
483 /* CALLS */
484 /* */
485 /* tx_timer_delete Delete ThreadX timer service */
486 /* tx_mutex_delete Delete ThreadX mutex service */
487 /* tx_timer_deactivate Deschedule ThreadX timer */
488 /* nx_udp_socket_unbind Release NetX UDP socket port */
489 /* nx_udp_socket_delete Delete NetX UDP socket */
490 /* */
491 /* CALLED BY */
492 /* */
493 /* Application Code */
494 /* */
495 /* RELEASE HISTORY */
496 /* */
497 /* DATE NAME DESCRIPTION */
498 /* */
499 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
500 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
501 /* resulting in version 6.1 */
502 /* 03-08-2023 Wenhui Xie Modified comment(s), */
503 /* cleared the client ID, */
504 /* resulting in version 6.2.1 */
505 /* */
506 /**************************************************************************/
_nx_sntp_client_delete(NX_SNTP_CLIENT * client_ptr)507 UINT _nx_sntp_client_delete(NX_SNTP_CLIENT *client_ptr)
508 {
509
510 /* Clear the client ID. */
511 client_ptr -> nx_sntp_client_id = 0;
512
513 /* Suspend the SNTP Client thread. */
514 tx_thread_suspend(&client_ptr -> nx_sntp_client_thread);
515
516 /* Terminate SNTP Client thread. */
517 tx_thread_terminate(&client_ptr -> nx_sntp_client_thread);
518
519 /* Delete SNTP Client thread. */
520 tx_thread_delete(&client_ptr -> nx_sntp_client_thread);
521
522 /* Delete the Client mutex. */
523 tx_mutex_delete(&client_ptr -> nx_sntp_client_mutex);
524
525 /* Deactivate SNTP update timer. */
526 tx_timer_deactivate(&(client_ptr -> nx_sntp_update_timer));
527
528 /* Delete the update timer. */
529 tx_timer_delete(&(client_ptr -> nx_sntp_update_timer));
530
531 /* Make sure the socket is in an unbound state. */
532 nx_udp_socket_unbind(&(client_ptr -> nx_sntp_client_udp_socket));
533
534 /* Ok to delete the UDP socket. */
535 nx_udp_socket_delete(&(client_ptr -> nx_sntp_client_udp_socket));
536
537 /* Delete the Client event flags group. */
538 tx_event_flags_delete(&nx_sntp_client_events);
539
540 /* Return success status. */
541 return(NX_SUCCESS);
542 }
543
544
545 /**************************************************************************/
546 /* */
547 /* FUNCTION RELEASE */
548 /* */
549 /* _nx_sntp_client_update_timeout_entry PORTABLE C */
550 /* 6.1 */
551 /* AUTHOR */
552 /* */
553 /* Yuxin Zhou, Microsoft Corporation */
554 /* */
555 /* DESCRIPTION */
556 /* */
557 /* This function decrements the Client's time remaining since it last */
558 /* received a time update. */
559 /* */
560 /* INPUT */
561 /* */
562 /* client_ptr Pointer to Client */
563 /* */
564 /* OUTPUT */
565 /* */
566 /* None */
567 /* */
568 /* CALLS */
569 /* */
570 /* None */
571 /* */
572 /* CALLED BY */
573 /* */
574 /* ThreadX ThreadX timer callback */
575 /* */
576 /* RELEASE HISTORY */
577 /* */
578 /* DATE NAME DESCRIPTION */
579 /* */
580 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
581 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
582 /* resulting in version 6.1 */
583 /* */
584 /**************************************************************************/
_nx_sntp_client_update_timeout_entry(ULONG info)585 VOID _nx_sntp_client_update_timeout_entry(ULONG info)
586 {
587
588 NX_SNTP_CLIENT *client_ptr;
589
590
591 client_ptr = (NX_SNTP_CLIENT *)info;
592
593 /* Is the Client's time remaining large enough to decrement by the timeout interval? */
594 if (client_ptr -> nx_sntp_update_time_remaining >= (NX_IP_PERIODIC_RATE * NX_SNTP_UPDATE_TIMEOUT_INTERVAL))
595 {
596
597 /* Yes; ok to decrement time remaining. */
598 client_ptr -> nx_sntp_update_time_remaining -= (NX_IP_PERIODIC_RATE * NX_SNTP_UPDATE_TIMEOUT_INTERVAL);
599 }
600 else
601 {
602 /* No, set the time remaining to NULL. */
603 client_ptr -> nx_sntp_update_time_remaining = 0;
604 }
605
606 /* Update time elapsed. */
607 client_ptr -> nx_sntp_client_local_ntp_time_elapsed += NX_SNTP_UPDATE_TIMEOUT_INTERVAL;
608
609 /* Is the client operating in unicast? */
610 if (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE)
611 {
612
613 /* Yes; Update the time remaining till it is time to poll the SNTP server. */
614 if (client_ptr -> nx_sntp_client_unicast_poll_interval >= (NX_IP_PERIODIC_RATE * NX_SNTP_UPDATE_TIMEOUT_INTERVAL))
615 {
616 client_ptr -> nx_sntp_client_unicast_poll_interval -= (NX_IP_PERIODIC_RATE * NX_SNTP_UPDATE_TIMEOUT_INTERVAL);
617 }
618 else
619 {
620
621 /* Time is up. Client should send out another update request. */
622 client_ptr -> nx_sntp_client_unicast_poll_interval = 0;
623 }
624 }
625 return;
626 }
627
628
629 /**************************************************************************/
630 /* */
631 /* FUNCTION RELEASE */
632 /* */
633 /* _nx_sntp_client_create_time_request_packet PORTABLE C */
634 /* 6.1 */
635 /* AUTHOR */
636 /* */
637 /* Yuxin Zhou, Microsoft Corporation */
638 /* */
639 /* DESCRIPTION */
640 /* */
641 /* This function converts NTP time data from the input buffer into a */
642 /* unicast time data and copies into the supplied packet buffer. */
643 /* */
644 /* INPUT */
645 /* */
646 /* client_ptr Pointer to Client */
647 /* packet_ptr Pointer to time update packet */
648 /* time_message_ptr Pointer to time request */
649 /* */
650 /* OUTPUT */
651 /* */
652 /* NX_SUCCESS Successful completion status */
653 /* */
654 /* CALLS */
655 /* */
656 /* None */
657 /* */
658 /* CALLED BY */
659 /* */
660 /* _nx_sntp_client_send_unicast_request Send unicast request to server */
661 /* */
662 /* RELEASE HISTORY */
663 /* */
664 /* DATE NAME DESCRIPTION */
665 /* */
666 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
667 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
668 /* resulting in version 6.1 */
669 /* */
670 /**************************************************************************/
_nx_sntp_client_create_time_request_packet(NX_SNTP_CLIENT * client_ptr,NX_PACKET * packet_ptr,NX_SNTP_TIME_MESSAGE * time_message_ptr)671 UINT _nx_sntp_client_create_time_request_packet(NX_SNTP_CLIENT *client_ptr, NX_PACKET *packet_ptr,
672 NX_SNTP_TIME_MESSAGE *time_message_ptr)
673 {
674 NX_PARAMETER_NOT_USED(client_ptr);
675
676 if (40u > ((ULONG)(packet_ptr -> nx_packet_data_end) - (ULONG)(packet_ptr -> nx_packet_append_ptr)))
677 {
678 return(NX_SIZE_ERROR);
679 }
680
681 /* Clear packet data. */
682 memset(packet_ptr -> nx_packet_append_ptr, 0, 40);
683
684 *(packet_ptr -> nx_packet_append_ptr) = (UCHAR)(time_message_ptr -> flags);
685
686 /* Skip to transmit time; all other fields are not used for a client unicast request. */
687 packet_ptr -> nx_packet_append_ptr += 40;
688 packet_ptr -> nx_packet_length += 40;
689
690 /* Copy the transmit time stamp from time request into the packet buffer. */
691 time_message_ptr -> transmit_time.seconds = time_message_ptr -> transmit_time_stamp[0];
692 time_message_ptr -> transmit_time.fraction = time_message_ptr -> transmit_time_stamp[1];
693
694 /* Now copy the data to the buffer. */
695 *((ULONG*)(packet_ptr -> nx_packet_append_ptr)) = (ULONG)(time_message_ptr -> transmit_time.seconds);
696 *((ULONG*)(packet_ptr -> nx_packet_append_ptr + 4)) = (ULONG)(time_message_ptr -> transmit_time.fraction);
697
698 /* Change endian to network order. */
699 NX_CHANGE_ULONG_ENDIAN(*((ULONG*)(packet_ptr -> nx_packet_append_ptr)));
700 NX_CHANGE_ULONG_ENDIAN(*((ULONG*)(packet_ptr -> nx_packet_append_ptr + 4)));
701
702 packet_ptr -> nx_packet_append_ptr += 8;
703 packet_ptr -> nx_packet_length += 8;
704
705 /* Return completion status. */
706 return NX_SUCCESS;
707 }
708
709
710 /**************************************************************************/
711 /* */
712 /* FUNCTION RELEASE */
713 /* */
714 /* _nxde_sntp_client_initialize_unicast PORTABLE C */
715 /* 6.1 */
716 /* AUTHOR */
717 /* */
718 /* Yuxin Zhou, Microsoft Corporation */
719 /* */
720 /* DESCRIPTION */
721 /* */
722 /* This function performs error checking for the service that */
723 /* initializes the Client for unicast service. */
724 /* */
725 /* INPUT */
726 /* */
727 /* client_ptr Pointer to Client struct */
728 /* unicast_time_server Pointer to unicast server */
729 /* */
730 /* OUTPUT */
731 /* */
732 /* NX_PTR_ERROR Invalid pointer input */
733 /* status Actual completion status */
734 /* */
735 /* CALLS */
736 /* */
737 /* None */
738 /* */
739 /* CALLED BY */
740 /* */
741 /* Application Code */
742 /* */
743 /* RELEASE HISTORY */
744 /* */
745 /* DATE NAME DESCRIPTION */
746 /* */
747 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
748 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
749 /* resulting in version 6.1 */
750 /* */
751 /**************************************************************************/
_nxde_sntp_client_initialize_unicast(NX_SNTP_CLIENT * client_ptr,NXD_ADDRESS * unicast_time_server)752 UINT _nxde_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *unicast_time_server)
753 {
754
755 UINT status;
756
757
758 /* Check pointer input. */
759 if ((client_ptr == NX_NULL) || (unicast_time_server == NX_NULL))
760 {
761
762 /* Return error status. */
763 return NX_PTR_ERROR;
764 }
765
766 /* Check if this function is called from the appropriate thread. */
767 NX_THREADS_ONLY_CALLER_CHECKING
768
769 /* Call the actual Client for initialize unicast service. */
770 status = _nxd_sntp_client_initialize_unicast(client_ptr, unicast_time_server);
771
772 /* Return completion status. */
773 return status;
774 }
775
776
777 /**************************************************************************/
778 /* */
779 /* FUNCTION RELEASE */
780 /* */
781 /* _nxd_sntp_client_initialize_unicast PORTABLE C */
782 /* 6.1 */
783 /* AUTHOR */
784 /* */
785 /* Yuxin Zhou, Microsoft Corporation */
786 /* */
787 /* DESCRIPTION */
788 /* */
789 /* This function sets up the Client to operate in unicast mode with the*/
790 /* supplied IPv4 or IPv6 SNTP server as the primary (current) server. */
791 /* */
792 /* For adding IPv4 and IPv6 SNTP servers to the unicast server list, */
793 /* use the nxd_sntp_client_duo_add_unicast_server_to_list service. */
794 /* */
795 /* INPUT */
796 /* */
797 /* client_ptr Pointer to Client struct */
798 /* unicast_poll_interval Interval between update requests */
799 /* unicast_time_server Pointer to unicast server */
800 /* */
801 /* OUTPUT */
802 /* */
803 /* NX_SUCCESS Successful completion status */
804 /* NX_SNTP_PARAM_ERROR Invalid server list input */
805 /* */
806 /* CALLS */
807 /* */
808 /* memset Copy data to area of memory */
809 /* */
810 /* CALLED BY */
811 /* */
812 /* Application Code */
813 /* */
814 /* RELEASE HISTORY */
815 /* */
816 /* DATE NAME DESCRIPTION */
817 /* */
818 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
819 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
820 /* resulting in version 6.1 */
821 /* */
822 /**************************************************************************/
_nxd_sntp_client_initialize_unicast(NX_SNTP_CLIENT * client_ptr,NXD_ADDRESS * unicast_time_server)823 UINT _nxd_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *unicast_time_server)
824 {
825
826
827 /* Set the Client polling interval. */
828 client_ptr -> nx_sntp_client_unicast_poll_interval = (NX_SNTP_CLIENT_UNICAST_POLL_INTERVAL * NX_IP_PERIODIC_RATE);
829
830 /* Initialize the number of times we've increased the backoff rate to zero. */
831 client_ptr -> nx_sntp_client_backoff_count = 0;
832
833 /* Clear the Client's current server IP. */
834 memset(&client_ptr -> nx_sntp_server_ip_address, 0, sizeof(NXD_ADDRESS));
835
836 #ifdef FEATURE_NX_IPV6
837 /* Set as the Client's unicast server. */
838 COPY_NXD_ADDRESS(unicast_time_server, &client_ptr -> nx_sntp_unicast_time_server);
839
840 /* Set as the Client's current SNTP server. */
841 COPY_NXD_ADDRESS(unicast_time_server, &client_ptr -> nx_sntp_server_ip_address);
842 #else
843 /* Set as the Client's unicast server. */
844 client_ptr -> nx_sntp_unicast_time_server.nxd_ip_version = NX_IP_VERSION_V4;
845 client_ptr -> nx_sntp_unicast_time_server.nxd_ip_address.v4 = unicast_time_server -> nxd_ip_address.v4;
846
847 /* Set as the Client's current SNTP server. */
848 client_ptr -> nx_sntp_server_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
849 client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v4 = unicast_time_server -> nxd_ip_address.v4;
850
851 #endif /* FEATURE_NX_IPV6 */
852
853
854 /* Set the Client operational mode to unicast mode. */
855 client_ptr -> nx_sntp_client_protocol_mode = UNICAST_MODE;
856
857 /* Indicate the Client task is ready to run! */
858 client_ptr -> nx_sntp_client_unicast_initialized = NX_TRUE;
859
860 /* Initialize the server status as good (receiving updates). */
861 client_ptr -> nx_sntp_valid_server_status = NX_TRUE;
862
863 return NX_SUCCESS;
864 }
865
866
867 /**************************************************************************/
868 /* */
869 /* FUNCTION RELEASE */
870 /* */
871 /* _nxe_sntp_client_initialize_unicast PORTABLE C */
872 /* 6.1 */
873 /* AUTHOR */
874 /* */
875 /* Yuxin Zhou, Microsoft Corporation */
876 /* */
877 /* DESCRIPTION */
878 /* */
879 /* This function checks for errors on the initialize Client for unicast*/
880 /* service. */
881 /* */
882 /* INPUT */
883 /* */
884 /* client_ptr Pointer to Client struct */
885 /* unicast_time_server SNTP unicast server to use */
886 /* */
887 /* OUTPUT */
888 /* */
889 /* NX_PTR_ERROR Invalid pointer input */
890 /* NX_INVALID_PARAMETERS Invalid non pointer input */
891 /* status Actual completion status */
892 /* */
893 /* CALLS */
894 /* */
895 /* None */
896 /* */
897 /* CALLED BY */
898 /* */
899 /* Application Code */
900 /* */
901 /* RELEASE HISTORY */
902 /* */
903 /* DATE NAME DESCRIPTION */
904 /* */
905 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
906 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
907 /* resulting in version 6.1 */
908 /* */
909 /**************************************************************************/
_nxe_sntp_client_initialize_unicast(NX_SNTP_CLIENT * client_ptr,ULONG unicast_time_server)910 UINT _nxe_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, ULONG unicast_time_server)
911 {
912
913 #ifndef NX_DISABLE_IPV4
914 UINT status;
915
916 /* Check input parameters. */
917 if (client_ptr == NX_NULL)
918 {
919
920 /* Return error status. */
921 return NX_PTR_ERROR;
922 }
923
924 if (unicast_time_server == 0x0)
925 {
926 return NX_INVALID_PARAMETERS;
927 }
928
929 /* Check if this function is called from the appropriate thread. */
930 NX_THREADS_ONLY_CALLER_CHECKING
931
932
933 /* Call the actual Client for initialize unicast service. */
934 status = _nx_sntp_client_initialize_unicast(client_ptr, unicast_time_server);
935
936 /* Return completion status. */
937 return status;
938 #else
939 NX_PARAMETER_NOT_USED(client_ptr);
940 NX_PARAMETER_NOT_USED(unicast_time_server);
941
942 return(NX_NOT_SUPPORTED);
943 #endif /* NX_DISABLE_IPV4 */
944 }
945
946
947 /**************************************************************************/
948 /* */
949 /* FUNCTION RELEASE */
950 /* */
951 /* _nx_sntp_client_initialize_unicast PORTABLE C */
952 /* 6.1 */
953 /* AUTHOR */
954 /* */
955 /* Yuxin Zhou, Microsoft Corporation */
956 /* */
957 /* DESCRIPTION */
958 /* */
959 /* This function converts the input address to the NetX Duo address */
960 /* format and calls the 'duo' equivalent service, nxd_sntp_client_ */
961 /* _initialize_unicast. */
962 /* */
963 /* INPUT */
964 /* */
965 /* client_ptr Pointer to Client struct */
966 /* unicast_time_server SNTP unicast server to use */
967 /* */
968 /* OUTPUT */
969 /* */
970 /* status Actual completion status */
971 /* */
972 /* CALLS */
973 /* _nxd_sntp_client_initialize_unicast */
974 /* Duo initialize unicast service */
975 /* */
976 /* CALLED BY */
977 /* */
978 /* Application Code */
979 /* */
980 /* RELEASE HISTORY */
981 /* */
982 /* DATE NAME DESCRIPTION */
983 /* */
984 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
985 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
986 /* resulting in version 6.1 */
987 /* */
988 /**************************************************************************/
_nx_sntp_client_initialize_unicast(NX_SNTP_CLIENT * client_ptr,ULONG unicast_time_server)989 UINT _nx_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, ULONG unicast_time_server)
990 {
991
992 #ifndef NX_DISABLE_IPV4
993 UINT status;
994 NXD_ADDRESS duo_unicast_time_server;
995
996
997
998 duo_unicast_time_server.nxd_ip_address.v4 = unicast_time_server;
999 duo_unicast_time_server.nxd_ip_version = NX_IP_VERSION_V4;
1000
1001 status = _nxd_sntp_client_initialize_unicast(client_ptr, &duo_unicast_time_server);
1002
1003 return status;
1004 #else
1005 NX_PARAMETER_NOT_USED(client_ptr);
1006 NX_PARAMETER_NOT_USED(unicast_time_server);
1007
1008 return(NX_NOT_SUPPORTED);
1009 #endif /* NX_DISABLE_IPV4 */
1010 }
1011
1012
1013 /**************************************************************************/
1014 /* */
1015 /* FUNCTION RELEASE */
1016 /* */
1017 /* _nxe_sntp_client_run_unicast PORTABLE C */
1018 /* 6.1 */
1019 /* AUTHOR */
1020 /* */
1021 /* Yuxin Zhou, Microsoft Corporation */
1022 /* */
1023 /* DESCRIPTION */
1024 /* */
1025 /* This function performs error checking on the run unicast service. */
1026 /* */
1027 /* INPUT */
1028 /* */
1029 /* client_ptr Pointer to Client */
1030 /* */
1031 /* OUTPUT */
1032 /* */
1033 /* NX_PTR_ERROR Invalid pointer input */
1034 /* status Actual completion status */
1035 /* */
1036 /* CALLS */
1037 /* _nx_sntp_client_run_unicast Actual run unicast service */
1038 /* */
1039 /* CALLED BY */
1040 /* */
1041 /* Application Code */
1042 /* */
1043 /* RELEASE HISTORY */
1044 /* */
1045 /* DATE NAME DESCRIPTION */
1046 /* */
1047 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1048 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1049 /* resulting in version 6.1 */
1050 /* */
1051 /**************************************************************************/
_nxe_sntp_client_run_unicast(NX_SNTP_CLIENT * client_ptr)1052 UINT _nxe_sntp_client_run_unicast(NX_SNTP_CLIENT *client_ptr)
1053 {
1054
1055 UINT status;
1056
1057 /* Check for invalid pointer input. */
1058 if (client_ptr == NX_NULL)
1059 {
1060
1061 /* Return pointer error. */
1062 return NX_PTR_ERROR;
1063 }
1064
1065 /* Check if this function is called from the appropriate thread. */
1066 NX_THREADS_ONLY_CALLER_CHECKING
1067
1068 /* Call the actual run unicast service. */
1069 status = _nx_sntp_client_run_unicast(client_ptr);
1070
1071 /* Return actual completion status. */
1072 return status;
1073 }
1074
1075
1076 /**************************************************************************/
1077 /* */
1078 /* FUNCTION RELEASE */
1079 /* */
1080 /* _nx_sntp_client_run_unicast PORTABLE C */
1081 /* 6.1 */
1082 /* AUTHOR */
1083 /* */
1084 /* Yuxin Zhou, Microsoft Corporation */
1085 /* */
1086 /* DESCRIPTION */
1087 /* */
1088 /* This function starts the SNTP Client for unicast SNTP processing */
1089 /* by activating the SNTP timer and main processing thread. The Client */
1090 /* is checked for being initialized for unicast SNTP and if it is */
1091 /* not, the function returns an error status. */
1092 /* */
1093 /* INPUT */
1094 /* */
1095 /* client_ptr Pointer to Client */
1096 /* */
1097 /* OUTPUT */
1098 /* */
1099 /* NX_SNTP_CLIENT_NOT_INITIALIZED Client initialized flag not set */
1100 /* NX_SNTP_CLIENT_ALREADY_STARTED Client already started */
1101 /* status Actual completion status */
1102 /* */
1103 /* CALLS */
1104 /* */
1105 /* tx_timer_activate Start the ThreadX timer */
1106 /* tx_thread_resume Resume the specified thread */
1107 /* */
1108 /* CALLED BY */
1109 /* */
1110 /* Application Code */
1111 /* */
1112 /* RELEASE HISTORY */
1113 /* */
1114 /* DATE NAME DESCRIPTION */
1115 /* */
1116 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1117 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1118 /* resulting in version 6.1 */
1119 /* */
1120 /**************************************************************************/
_nx_sntp_client_run_unicast(NX_SNTP_CLIENT * client_ptr)1121 UINT _nx_sntp_client_run_unicast(NX_SNTP_CLIENT *client_ptr)
1122 {
1123
1124 UINT status;
1125 ULONG startup_ticks;
1126
1127
1128 status = tx_mutex_get(&client_ptr -> nx_sntp_client_mutex, TX_WAIT_FOREVER);
1129
1130 /* Check for error. */
1131 if (status != NX_SUCCESS)
1132 {
1133
1134 return status;
1135 }
1136
1137 /* Determine if SNTP has already been started. */
1138 if (client_ptr -> nx_sntp_client_started)
1139 {
1140
1141 /* Error SNTP has already been started. */
1142
1143 /* Release the SNTP mutex. */
1144 tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex));
1145
1146 /* Return completion status. */
1147 return(NX_SNTP_CLIENT_ALREADY_STARTED);
1148 }
1149
1150 /* Verify the client is ready to start receiving time data. */
1151 if (client_ptr -> nx_sntp_client_unicast_initialized == NX_FALSE)
1152 {
1153
1154 tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex));
1155
1156 /* Return the error condition. */
1157 return NX_SNTP_CLIENT_NOT_INITIALIZED;
1158 }
1159
1160 /* Should the first time request sleep for a random timeout? */
1161 if ((NX_SNTP_CLIENT_RANDOMIZE_ON_STARTUP == NX_TRUE) && (client_ptr -> random_number_generator))
1162 {
1163
1164 /* Yes, generate a random number of ticks to sleep.*/
1165 (client_ptr -> random_number_generator)(client_ptr, &startup_ticks);
1166
1167 /* Sleep for the random length. */
1168 tx_thread_sleep(startup_ticks);
1169 }
1170
1171 /* Set status that the first update is expected. */
1172 client_ptr -> nx_sntp_client_first_update_pending = NX_TRUE;
1173
1174 /* Initialize missed broadcasts and bad time updates from server. */
1175 client_ptr -> nx_sntp_client_invalid_time_updates = 0;
1176
1177
1178 /* Set the maximum timeout to the full count. */
1179 client_ptr -> nx_sntp_update_time_remaining = (NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE);
1180
1181 /* Activate SNTP update timer. */
1182 status = tx_timer_activate(&(client_ptr -> nx_sntp_update_timer));
1183
1184 /* Check for error. Ignore timer is already active error. */
1185 if (status != TX_SUCCESS && status != TX_ACTIVATE_ERROR)
1186 {
1187
1188 tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex));
1189
1190 /* Return the error condition. */
1191 return status;
1192 }
1193
1194 /* Bind the UDP socket to the IP port. */
1195 status = nx_udp_socket_bind(&(client_ptr -> nx_sntp_client_udp_socket), NX_SNTP_CLIENT_UDP_PORT, NX_WAIT_FOREVER);
1196
1197 /* Check for error. */
1198 if (status != NX_SUCCESS)
1199 {
1200
1201 /* Deactivate SNTP update timer. */
1202 tx_timer_deactivate(&(client_ptr -> nx_sntp_update_timer));
1203
1204 tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex));
1205
1206 return status;
1207 }
1208
1209 status = tx_thread_resume(&(client_ptr -> nx_sntp_client_thread));
1210
1211 /* Start the SNTP Client thread. */
1212 if (status != NX_SUCCESS)
1213 {
1214
1215 /* Release the socket port. */
1216 nx_udp_socket_unbind(&(client_ptr -> nx_sntp_client_udp_socket));
1217
1218 /* Deactivate SNTP update timer. */
1219 tx_timer_deactivate(&(client_ptr -> nx_sntp_update_timer));
1220
1221 tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex));
1222
1223 return status;
1224 }
1225
1226 /* The client thread is successfully started, so set the started flag to true. */
1227 client_ptr -> nx_sntp_client_started = NX_TRUE;
1228
1229 /* Clear the sleep flag. */
1230 client_ptr -> nx_sntp_client_sleep_flag = NX_FALSE;
1231
1232 /* Set poll interval to 0 to send request immediately. */
1233 client_ptr -> nx_sntp_client_unicast_poll_interval = 0;
1234
1235 tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex));
1236
1237 return NX_SUCCESS;
1238 }
1239
1240
1241 /**************************************************************************/
1242 /* */
1243 /* FUNCTION RELEASE */
1244 /* */
1245 /* _nx_sntp_client_run_unicast PORTABLE C */
1246 /* 6.1 */
1247 /* AUTHOR */
1248 /* */
1249 /* Yuxin Zhou, Microsoft Corporation */
1250 /* */
1251 /* DESCRIPTION */
1252 /* */
1253 /* This function checks if the SNTP client has received a packet, and if*/
1254 /* so processes it for valid SNTP data and resets the timeouts */
1255 /* for sending (polling) and receiving updates. If no packet received it*/
1256 /* checks if the timeout to receive an update has expired. If so, it */
1257 /* sends out another SNTP request. */
1258 /* */
1259 /* When a timeout expires, the poll interval is increased as per */
1260 /* RFC guidelines until it exceeds the maximum time without an update. */
1261 /* An error flag is set, and it is up to the host application to */
1262 /* change its unicast SNTP server. */
1263 /* */
1264 /* INPUT */
1265 /* */
1266 /* client_ptr Pointer to Client */
1267 /* */
1268 /* OUTPUT */
1269 /* */
1270 /* None */
1271 /* */
1272 /* CALLS */
1273 /* */
1274 /* _nx_sntp_client_reset_current_time_message */
1275 /* Save time update before next update */
1276 /* _nx_sntp_client_receive_time_update */
1277 /* Receive server update packets */
1278 /* _nx_sntp_client_process_time_data */
1279 /* Process time data in server update */
1280 /* */
1281 /* CALLED BY */
1282 /* */
1283 /* Application Code */
1284 /* */
1285 /* RELEASE HISTORY */
1286 /* */
1287 /* DATE NAME DESCRIPTION */
1288 /* */
1289 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1290 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1291 /* resulting in version 6.1 */
1292 /* */
1293 /**************************************************************************/
_nx_sntp_client_process_unicast(NX_SNTP_CLIENT * client_ptr)1294 VOID _nx_sntp_client_process_unicast(NX_SNTP_CLIENT *client_ptr)
1295 {
1296
1297 UINT status;
1298 ULONG sntp_events;
1299
1300
1301 /* Check for a receive event. */
1302 status = tx_event_flags_get(&nx_sntp_client_events, NX_SNTP_CLIENT_RECEIVE_EVENT, TX_OR_CLEAR, &sntp_events, TX_NO_WAIT);
1303
1304 if (status == NX_SUCCESS)
1305 {
1306
1307 /* Listen for a server update packet. */
1308 status = _nx_sntp_client_receive_time_update(client_ptr, TX_NO_WAIT);
1309
1310 if (status == NX_SUCCESS)
1311 {
1312
1313 /* Process the server update packet and apply to local time if valid. */
1314 status = _nx_sntp_client_process_update_packet(client_ptr);
1315
1316 /* Check for error. */
1317 if (status != NX_SUCCESS)
1318 {
1319 return;
1320 }
1321
1322 /* Reset the Client poll timeout to the original poll interval. */
1323 client_ptr -> nx_sntp_client_unicast_poll_interval = (NX_SNTP_CLIENT_UNICAST_POLL_INTERVAL * NX_IP_PERIODIC_RATE);
1324
1325 /* Reset the Client timeout for maximum time lapse without a valid update. */
1326 client_ptr -> nx_sntp_update_time_remaining = (NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE);
1327
1328 /* Indicate the client has received at least one valid time update with the current server. */
1329 client_ptr -> nx_sntp_client_first_update_pending = NX_FALSE;
1330
1331 client_ptr -> nx_sntp_client_backoff_count = 0;
1332 /* Set the server status as good (receiving updates). */
1333 client_ptr -> nx_sntp_valid_server_status = NX_TRUE;
1334
1335 return;
1336 }
1337 }
1338
1339 /* Has the timeout expired on the maximum lapse without a valid update? */
1340 if (client_ptr -> nx_sntp_update_time_remaining == 0)
1341 {
1342
1343 /* Yes, it has. Set the server status as no longer valid. */
1344 client_ptr -> nx_sntp_valid_server_status = NX_FALSE;
1345 }
1346
1347 /* Is it time to send another SNTP request? */
1348 if (client_ptr -> nx_sntp_client_unicast_poll_interval == 0)
1349 {
1350
1351
1352 /* Save the last server message before the next update. We need this for comparing time data. */
1353 _nx_sntp_client_reset_current_time_message(client_ptr);
1354
1355 /* Create and send a unicast request . */
1356 _nx_sntp_client_send_unicast_request(client_ptr);
1357
1358
1359 /* Check if we have received an update since the previous unicast poll. */
1360 if ((NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE - client_ptr -> nx_sntp_update_time_remaining) >
1361 (NX_SNTP_CLIENT_UNICAST_POLL_INTERVAL * NX_IP_PERIODIC_RATE))
1362 {
1363
1364 /* No we have not. Increase the count of times we've increased the back off rate. */
1365 client_ptr -> nx_sntp_client_backoff_count++;
1366
1367 client_ptr -> nx_sntp_client_unicast_poll_interval =
1368 NX_IP_PERIODIC_RATE * NX_SNTP_CLIENT_UNICAST_POLL_INTERVAL * NX_SNTP_CLIENT_EXP_BACKOFF_RATE * client_ptr -> nx_sntp_client_backoff_count;
1369 }
1370 else
1371 {
1372
1373 /* Reset the polling interval to it's normal value. */
1374 client_ptr -> nx_sntp_client_unicast_poll_interval = NX_SNTP_CLIENT_UNICAST_POLL_INTERVAL * NX_IP_PERIODIC_RATE;
1375 }
1376
1377 /* Check that the poll interval does not exceed the maximum lapse without a valid update. */
1378 if (client_ptr -> nx_sntp_client_unicast_poll_interval > (NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE))
1379 {
1380
1381 /* Set the poll interval equal to that lapse. */
1382 client_ptr -> nx_sntp_client_unicast_poll_interval = (NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE);
1383 }
1384 }
1385
1386 /* Nothing to do but wait...*/
1387 }
1388
1389
1390 /**************************************************************************/
1391 /* */
1392 /* FUNCTION RELEASE */
1393 /* */
1394 /* _nxde_sntp_client_initialize_broadcast PORTABLE C */
1395 /* 6.1 */
1396 /* AUTHOR */
1397 /* */
1398 /* Yuxin Zhou, Microsoft Corporation */
1399 /* */
1400 /* DESCRIPTION */
1401 /* */
1402 /* This function performs error checking on the initialize Client for */
1403 /* IPv4 broadcast time updates service. */
1404 /* */
1405 /* INPUT */
1406 /* */
1407 /* client_ptr Pointer to Client */
1408 /* multicast_server_address Multicast server address */
1409 /* broadcast_time_server Broadcast server address */
1410 /* */
1411 /* OUTPUT */
1412 /* */
1413 /* NX_PTR_ERROR Invalid pointer input */
1414 /* NX_SNTP_PARAM_ERROR Invalid non pointer input */
1415 /* status Actual completion status */
1416 /* */
1417 /* CALLS */
1418 /* _nxd_sntp_client_initialize_duo_broadcast */
1419 /* Initialize broadcast Client service*/
1420 /* CALLED BY */
1421 /* */
1422 /* Application Code */
1423 /* */
1424 /* RELEASE HISTORY */
1425 /* */
1426 /* DATE NAME DESCRIPTION */
1427 /* */
1428 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1429 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1430 /* resulting in version 6.1 */
1431 /* */
1432 /**************************************************************************/
_nxde_sntp_client_initialize_broadcast(NX_SNTP_CLIENT * client_ptr,NXD_ADDRESS * multicast_server_address,NXD_ADDRESS * broadcast_server_address)1433 UINT _nxde_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *multicast_server_address, NXD_ADDRESS *broadcast_server_address)
1434 {
1435
1436 UINT status;
1437
1438
1439 /* Check for invalid pointer input. */
1440 if (client_ptr == NX_NULL)
1441 {
1442
1443 /* Return pointer error. */
1444 return NX_PTR_ERROR;
1445 }
1446
1447 /* Check for missing broadcast server input. */
1448 if ((multicast_server_address == NX_NULL) && (broadcast_server_address == NX_NULL))
1449 {
1450
1451 /* Return pointer error. */
1452 return NX_PTR_ERROR;
1453 }
1454
1455 /* Check for illegal broadcast address in IPv6. */
1456 if ((broadcast_server_address != NX_NULL) && (broadcast_server_address -> nxd_ip_version == NX_IP_VERSION_V6))
1457 {
1458
1459 return NX_SNTP_PARAM_ERROR;
1460 }
1461
1462 /* Check if this function is called from the appropriate thread. */
1463 NX_THREADS_ONLY_CALLER_CHECKING
1464
1465 /* Call the actual initialize client for broadcast time update service. */
1466 status = _nxd_sntp_client_initialize_broadcast(client_ptr, multicast_server_address, broadcast_server_address);
1467
1468 /* Return completion status. */
1469 return status;
1470 }
1471
1472 /**************************************************************************/
1473 /* */
1474 /* FUNCTION RELEASE */
1475 /* */
1476 /* _nxd_sntp_client_initialize_broadcast PORTABLE C */
1477 /* 6.1 */
1478 /* AUTHOR */
1479 /* */
1480 /* Yuxin Zhou, Microsoft Corporation */
1481 /* */
1482 /* DESCRIPTION */
1483 /* */
1484 /* This function sets up the Client to operate in broadcast mode with */
1485 /* either an IPv6 or an IPv4 broadcast server. */
1486 /* */
1487 /* INPUT */
1488 /* */
1489 /* client_ptr Pointer to Client */
1490 /* multicast_server_address Multicast server address */
1491 /* broadcast_time_server Broadcast server address */
1492 /* */
1493 /* OUTPUT */
1494 /* */
1495 /* NX_SUCCESS Successful completion status */
1496 /* */
1497 /* CALLS */
1498 /* */
1499 /* */
1500 /* CALLED BY */
1501 /* */
1502 /* Application Code */
1503 /* */
1504 /* RELEASE HISTORY */
1505 /* */
1506 /* DATE NAME DESCRIPTION */
1507 /* */
1508 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1509 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1510 /* resulting in version 6.1 */
1511 /* */
1512 /**************************************************************************/
_nxd_sntp_client_initialize_broadcast(NX_SNTP_CLIENT * client_ptr,NXD_ADDRESS * multicast_server_address,NXD_ADDRESS * broadcast_server_address)1513 UINT _nxd_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *multicast_server_address, NXD_ADDRESS *broadcast_server_address)
1514 {
1515
1516
1517 /* Clear Client's current server IP. */
1518 memset(&client_ptr -> nx_sntp_server_ip_address, 0, sizeof(NXD_ADDRESS));
1519
1520 /* Was a multicast IP was supplied? */
1521 if (multicast_server_address != NX_NULL)
1522 {
1523
1524 #ifdef FEATURE_NX_IPV6
1525 /* Set the Client multicast server. */
1526 COPY_NXD_ADDRESS(multicast_server_address, &client_ptr -> nx_sntp_multicast_server_address);
1527
1528 /* Set this as the Client's current SNTP server. */
1529 COPY_NXD_ADDRESS(multicast_server_address, &client_ptr -> nx_sntp_server_ip_address);
1530 #else
1531 /* Set the Client multicast server. */
1532 client_ptr -> nx_sntp_multicast_server_address.nxd_ip_version = NX_IP_VERSION_V4;
1533 client_ptr -> nx_sntp_multicast_server_address.nxd_ip_address.v4 = multicast_server_address -> nxd_ip_address.v4;
1534
1535 /* Set this as the Client's current SNTP server. */
1536 client_ptr -> nx_sntp_server_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
1537 client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v4 = multicast_server_address -> nxd_ip_address.v4;
1538
1539 #endif /* FEATURE_NX_IPV6 */
1540 }
1541
1542 /* No multicast address supplied, so was a broadcast address specified? This must be an IPv4 address
1543 since IPv6 does not support broadcast. */
1544 else if ((broadcast_server_address != NX_NULL) && (broadcast_server_address -> nxd_ip_version == NX_IP_VERSION_V4))
1545 {
1546
1547
1548 #ifdef FEATURE_NX_IPV6
1549 /* Set the Client broadcast server. */
1550 COPY_NXD_ADDRESS(broadcast_server_address, &client_ptr -> nx_sntp_broadcast_time_server);
1551
1552 /* Set this as the Client's current SNTP server. */
1553 COPY_NXD_ADDRESS(broadcast_server_address, &client_ptr -> nx_sntp_server_ip_address);
1554 #else
1555 /* Set the Client broadcast server. */
1556 client_ptr -> nx_sntp_broadcast_time_server.nxd_ip_version = NX_IP_VERSION_V4;
1557 client_ptr -> nx_sntp_broadcast_time_server.nxd_ip_address.v4 = broadcast_server_address -> nxd_ip_address.v4;
1558
1559 /* Set this as the Client's current SNTP server. */
1560 client_ptr -> nx_sntp_server_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
1561 client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v4 = broadcast_server_address -> nxd_ip_address.v4;
1562
1563 #endif /* FEATURE_NX_IPV6 */
1564 }
1565
1566 /* Set client to work in broadcast (non unicast) mode. */
1567 client_ptr -> nx_sntp_client_protocol_mode = BROADCAST_MODE;
1568
1569 /* Indicate the client task is ready to run! */
1570 client_ptr -> nx_sntp_client_broadcast_initialized = NX_TRUE;
1571
1572 /* Initialize the server status as good (receiving updates) even though it has
1573 not received one with the current server. */
1574 client_ptr -> nx_sntp_valid_server_status = NX_TRUE;
1575
1576 return NX_SUCCESS;
1577 }
1578
1579
1580 /**************************************************************************/
1581 /* */
1582 /* FUNCTION RELEASE */
1583 /* */
1584 /* _nxe_sntp_client_initialize_broadcast PORTABLE C */
1585 /* 6.1 */
1586 /* AUTHOR */
1587 /* */
1588 /* Yuxin Zhou, Microsoft Corporation */
1589 /* */
1590 /* DESCRIPTION */
1591 /* */
1592 /* This function performs error checking on the initialize Client for */
1593 /* broadcast time updates service. Note that broadcast and multicast */
1594 /* services are only available for IPv4 SNTP communcations. For */
1595 /* multicast service, the host IP instance must be enabled for IGMP. */
1596 /* */
1597 /* INPUT */
1598 /* */
1599 /* client_ptr Pointer to Client */
1600 /* multicast_server_address Server multicast address */
1601 /* broadcast_server_aaddres Broadcast server address */
1602 /* */
1603 /* OUTPUT */
1604 /* */
1605 /* NX_PTR_ERROR Invalid pointer input */
1606 /* NX_INVALID_PARAMETERS Invalid non pointer input */
1607 /* status Actual completion status */
1608 /* */
1609 /* CALLS */
1610 /* _nx_sntp_client_initialize_broadcast */
1611 /* Actual initialize broadcast service*/
1612 /* CALLED BY */
1613 /* */
1614 /* Application Code */
1615 /* */
1616 /* RELEASE HISTORY */
1617 /* */
1618 /* DATE NAME DESCRIPTION */
1619 /* */
1620 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1621 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1622 /* resulting in version 6.1 */
1623 /* */
1624 /**************************************************************************/
_nxe_sntp_client_initialize_broadcast(NX_SNTP_CLIENT * client_ptr,ULONG multicast_server_address,ULONG broadcast_server_address)1625 UINT _nxe_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, ULONG multicast_server_address, ULONG broadcast_server_address)
1626 {
1627
1628 #ifndef NX_DISABLE_IPV4
1629 UINT status;
1630
1631
1632 /* Check for invalid pointer input. */
1633 if (client_ptr == NX_NULL)
1634 {
1635
1636 /* Return pointer error. */
1637 return NX_PTR_ERROR;
1638 }
1639
1640 if ((multicast_server_address == 0x0) && (broadcast_server_address == 0x0))
1641 {
1642
1643 return NX_INVALID_PARAMETERS;
1644 }
1645
1646 /* Check if this function is called from the appropriate thread. */
1647 NX_THREADS_ONLY_CALLER_CHECKING
1648
1649 /* Call the actual initialize client for broadcast time update service. */
1650 status = _nx_sntp_client_initialize_broadcast(client_ptr, multicast_server_address, broadcast_server_address);
1651
1652 /* Return completion status. */
1653 return status;
1654 #else
1655 NX_PARAMETER_NOT_USED(client_ptr);
1656 NX_PARAMETER_NOT_USED(multicast_server_address);
1657 NX_PARAMETER_NOT_USED(broadcast_server_address);
1658
1659 return(NX_NOT_SUPPORTED);
1660 #endif /* NX_DISABLE_IPV4 */
1661 }
1662
1663
1664 /**************************************************************************/
1665 /* */
1666 /* FUNCTION RELEASE */
1667 /* */
1668 /* _nx_sntp_client_initialize_broadcast PORTABLE C */
1669 /* 6.1 */
1670 /* AUTHOR */
1671 /* */
1672 /* Yuxin Zhou, Microsoft Corporation */
1673 /* */
1674 /* DESCRIPTION */
1675 /* */
1676 /* This function converts the IPv4 addresses to the NetX Duo address */
1677 /* format and calls the 'duo' equivalent service, nxd_sntp_client_ */
1678 /* _initialize_broadcast. */
1679 /* */
1680 /* INPUT */
1681 /* */
1682 /* client_ptr Pointer to Client */
1683 /* multicast_server_address Server multicast address */
1684 /* broadcast_server_address Broadcast server address */
1685 /* */
1686 /* OUTPUT */
1687 /* */
1688 /* status Actual completion status */
1689 /* */
1690 /* CALLS */
1691 /* */
1692 /* _nxd_sntp_client_initialize_broadcast */
1693 /* Duo initialize broadcast service */
1694 /* */
1695 /* CALLED BY */
1696 /* */
1697 /* Application Code */
1698 /* */
1699 /* RELEASE HISTORY */
1700 /* */
1701 /* DATE NAME DESCRIPTION */
1702 /* */
1703 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1704 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1705 /* resulting in version 6.1 */
1706 /* */
1707 /**************************************************************************/
_nx_sntp_client_initialize_broadcast(NX_SNTP_CLIENT * client_ptr,ULONG multicast_server_address,ULONG broadcast_server_address)1708 UINT _nx_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, ULONG multicast_server_address, ULONG broadcast_server_address)
1709 {
1710
1711 #ifndef NX_DISABLE_IPV4
1712 UINT status;
1713 NXD_ADDRESS server_address;
1714
1715
1716 /* Was a multicast IP was supplied? */
1717 if (multicast_server_address != 0x0)
1718 {
1719
1720 server_address.nxd_ip_address.v4 = multicast_server_address;
1721 server_address.nxd_ip_version = NX_IP_VERSION_V4;
1722 status = _nxd_sntp_client_initialize_broadcast(client_ptr, &server_address, NX_NULL);
1723 }
1724
1725 /* Was a broadcast SNTP server specified? */
1726 else if (broadcast_server_address != 0x0)
1727 {
1728
1729 server_address.nxd_ip_address.v4 = broadcast_server_address;
1730 server_address.nxd_ip_version = NX_IP_VERSION_V4;
1731 status = _nxd_sntp_client_initialize_broadcast(client_ptr, NX_NULL, &server_address);
1732 }
1733 else
1734 return NX_INVALID_PARAMETERS;
1735
1736 return status;
1737 #else
1738 NX_PARAMETER_NOT_USED(client_ptr);
1739 NX_PARAMETER_NOT_USED(multicast_server_address);
1740 NX_PARAMETER_NOT_USED(broadcast_server_address);
1741
1742 return(NX_NOT_SUPPORTED);
1743 #endif /* NX_DISABLE_IPV4 */
1744 }
1745
1746
1747 /**************************************************************************/
1748 /* */
1749 /* FUNCTION RELEASE */
1750 /* */
1751 /* _nxe_sntp_client_stop PORTABLE C */
1752 /* 6.1 */
1753 /* AUTHOR */
1754 /* */
1755 /* Yuxin Zhou, Microsoft Corporation */
1756 /* */
1757 /* DESCRIPTION */
1758 /* */
1759 /* This function performs error checking on the SNTP client thread stop*/
1760 /* service. */
1761 /* */
1762 /* INPUT */
1763 /* */
1764 /* client_ptr Pointer to SNTP Client instance*/
1765 /* */
1766 /* OUTPUT */
1767 /* */
1768 /* status Completion status */
1769 /* */
1770 /* CALLS */
1771 /* */
1772 /* nx_sntp_client_sto Actual stop SNTP service */
1773 /* */
1774 /* CALLED BY */
1775 /* */
1776 /* Application Code */
1777 /* */
1778 /* RELEASE HISTORY */
1779 /* */
1780 /* DATE NAME DESCRIPTION */
1781 /* */
1782 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1783 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1784 /* resulting in version 6.1 */
1785 /* */
1786 /**************************************************************************/
_nxe_sntp_client_stop(NX_SNTP_CLIENT * client_ptr)1787 UINT _nxe_sntp_client_stop(NX_SNTP_CLIENT *client_ptr)
1788 {
1789
1790 UINT status;
1791
1792
1793 /* Check for invalid pointer input. */
1794 if (client_ptr == NX_NULL)
1795 {
1796
1797 /* Return pointer error. */
1798 return NX_PTR_ERROR;
1799 }
1800
1801 status = _nx_sntp_client_stop(client_ptr);
1802
1803 return status;
1804 }
1805
1806
1807 /**************************************************************************/
1808 /* */
1809 /* FUNCTION RELEASE */
1810 /* */
1811 /* _nx_sntp_client_stop PORTABLE C */
1812 /* 6.1 */
1813 /* AUTHOR */
1814 /* */
1815 /* Yuxin Zhou, Microsoft Corporation */
1816 /* */
1817 /* DESCRIPTION */
1818 /* */
1819 /* This function halts the SNTP Client thread and returns the SNTP */
1820 /* Client to an initial state. */
1821 /* */
1822 /* INPUT */
1823 /* */
1824 /* client_ptr Pointer to SNTP Client instance*/
1825 /* */
1826 /* OUTPUT */
1827 /* */
1828 /* status Completion status */
1829 /* */
1830 /* CALLS */
1831 /* */
1832 /* nx_udp_socket_unbind Unbind the SNTP UDP socket */
1833 /* tx_thread_preemption_change Change the thread preemption */
1834 /* tx_thread_suspend Suspend SNTP processing */
1835 /* tx_thread_wait_abort Remove any thread suspension */
1836 /* tx_mutex_get Get the SNTP mutex */
1837 /* tx_mutex_put Release the SNTP mutex */
1838 /* */
1839 /* CALLED BY */
1840 /* */
1841 /* Application Code */
1842 /* */
1843 /* RELEASE HISTORY */
1844 /* */
1845 /* DATE NAME DESCRIPTION */
1846 /* */
1847 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1848 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1849 /* resulting in version 6.1 */
1850 /* */
1851 /**************************************************************************/
_nx_sntp_client_stop(NX_SNTP_CLIENT * client_ptr)1852 UINT _nx_sntp_client_stop(NX_SNTP_CLIENT *client_ptr)
1853 {
1854
1855 UINT current_preemption;
1856
1857
1858 /* Get the SNTP mutex. */
1859 tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER);
1860
1861 /* Determine if the SNTP client is started. */
1862 if (client_ptr -> nx_sntp_client_started == NX_FALSE)
1863 {
1864
1865 /* Release the SNTP mutex. */
1866 tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex));
1867
1868 /* SNTP client is not started so it can't be stopped. */
1869 return(NX_SNTP_CLIENT_NOT_STARTED);
1870 }
1871
1872 /* Clear the started flag here to ensure other threads can't issue a stop while
1873 this stop is in progress. */
1874 client_ptr -> nx_sntp_client_started = NX_FALSE;
1875
1876 /* Indicate the client needs to be re-initialized to run again. */
1877 client_ptr -> nx_sntp_client_unicast_initialized = NX_FALSE;
1878 client_ptr -> nx_sntp_client_broadcast_initialized = NX_FALSE;
1879
1880 /* Disable preemption for critical section. */
1881 tx_thread_preemption_change(tx_thread_identify(), 0, ¤t_preemption);
1882
1883 /* Loop to wait for the SNTP Client thread to be in a position to be stopped. */
1884 while (client_ptr -> nx_sntp_client_sleep_flag != NX_TRUE)
1885 {
1886
1887 /* Release the SNTP mutex. */
1888 tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex));
1889
1890 /* Sleep temporarily. */
1891 tx_thread_sleep(1);
1892
1893 /* Get the SNTP mutex. */
1894 tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER);
1895 }
1896
1897 /* Clear the sleep flag. */
1898 client_ptr -> nx_sntp_client_sleep_flag = NX_FALSE;
1899
1900 /* Get rid of any previous server message. */
1901 memset(&(client_ptr -> nx_sntp_previous_server_time_message), 0, sizeof(NX_SNTP_TIME_MESSAGE));
1902
1903 /* Get rid of the current server message if there is one. */
1904 memset(&(client_ptr -> nx_sntp_current_server_time_message), 0, sizeof(NX_SNTP_TIME_MESSAGE));
1905
1906 /* Deactivate SNTP update timer. */
1907 tx_timer_deactivate(&(client_ptr -> nx_sntp_update_timer));
1908
1909 /* Suspend the SNTP Client thread. */
1910 tx_thread_suspend(&(client_ptr -> nx_sntp_client_thread));
1911
1912 /* Abort the wait on the SNTP Client thread. */
1913 tx_thread_wait_abort(&(client_ptr -> nx_sntp_client_thread));
1914
1915 /* Unbind the port. */
1916 nx_udp_socket_unbind(&(client_ptr -> nx_sntp_client_udp_socket));
1917
1918 /* Restore preemption. */
1919 tx_thread_preemption_change(tx_thread_identify(), current_preemption, ¤t_preemption);
1920
1921 /* Release the SNTP mutex. */
1922 tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex));
1923
1924 /* Return completion status. */
1925 return(NX_SUCCESS);
1926 }
1927
1928
1929 /**************************************************************************/
1930 /* */
1931 /* FUNCTION RELEASE */
1932 /* */
1933 /* _nxe_sntp_client_run_broadcast PORTABLE C */
1934 /* 6.1 */
1935 /* AUTHOR */
1936 /* */
1937 /* Yuxin Zhou, Microsoft Corporation */
1938 /* */
1939 /* DESCRIPTION */
1940 /* */
1941 /* This function performs error checking on the run broadcast service. */
1942 /* */
1943 /* INPUT */
1944 /* */
1945 /* client_ptr Pointer to Client */
1946 /* */
1947 /* OUTPUT */
1948 /* */
1949 /* status Actual completion status */
1950 /* NX_PTR_ERROR Invalid pointer input */
1951 /* */
1952 /* CALLS */
1953 /* */
1954 /* _nx_sntp_client_run_broadcast Actual run broadcast service */
1955 /* */
1956 /* CALLED BY */
1957 /* */
1958 /* Application Code */
1959 /* */
1960 /* RELEASE HISTORY */
1961 /* */
1962 /* DATE NAME DESCRIPTION */
1963 /* */
1964 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1965 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1966 /* resulting in version 6.1 */
1967 /* */
1968 /**************************************************************************/
_nxe_sntp_client_run_broadcast(NX_SNTP_CLIENT * client_ptr)1969 UINT _nxe_sntp_client_run_broadcast(NX_SNTP_CLIENT *client_ptr)
1970 {
1971
1972 UINT status;
1973
1974
1975 /* Check for pointer error. */
1976 if (client_ptr == NX_NULL)
1977 {
1978
1979 /* Return error status. */
1980 return NX_PTR_ERROR;
1981 }
1982
1983 /* Verify this is called from thread context only. */
1984 NX_THREADS_ONLY_CALLER_CHECKING
1985
1986 /* Call the actual run broadcast service. */
1987 status = _nx_sntp_client_run_broadcast(client_ptr);
1988
1989 /* Return completion status. */
1990 return status;
1991 }
1992
1993
1994 /**************************************************************************/
1995 /* */
1996 /* FUNCTION RELEASE */
1997 /* */
1998 /* _nx_sntp_client_run_broadcast PORTABLE C */
1999 /* 6.1 */
2000 /* AUTHOR */
2001 /* */
2002 /* Yuxin Zhou, Microsoft Corporation */
2003 /* */
2004 /* DESCRIPTION */
2005 /* */
2006 /* This function starts the SNTP Client for broadcast SNTP processing */
2007 /* by activating the SNTP timer and main processing thread. The Client */
2008 /* is checked for being initialized for broadcast SNTP and if it is */
2009 /* not, the function returns an error status. */
2010 /* */
2011 /* INPUT */
2012 /* */
2013 /* client_ptr Pointer to Client */
2014 /* */
2015 /* OUTPUT */
2016 /* */
2017 /* NX_SNTP_CLIENT_NOT_INITIALIZED Client initialized flag not set */
2018 /* NX_SNTP_CLIENT_ALREADY_STARTED Client already started */
2019 /* status Actual completion status */
2020 /* */
2021 /* CALLS */
2022 /* */
2023 /* tx_timer_activate Start the ThreadX timer */
2024 /* tx_thread_resume Resume the specified thread */
2025 /* */
2026 /* CALLED BY */
2027 /* */
2028 /* Application Code */
2029 /* */
2030 /* RELEASE HISTORY */
2031 /* */
2032 /* DATE NAME DESCRIPTION */
2033 /* */
2034 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2035 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2036 /* resulting in version 6.1 */
2037 /* */
2038 /**************************************************************************/
_nx_sntp_client_run_broadcast(NX_SNTP_CLIENT * client_ptr)2039 UINT _nx_sntp_client_run_broadcast(NX_SNTP_CLIENT *client_ptr)
2040 {
2041
2042 UINT status;
2043
2044
2045 /* Get the SNTP mutex. */
2046 tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER);
2047
2048 /* Determine if SNTP has already been started. */
2049 if (client_ptr -> nx_sntp_client_started)
2050 {
2051
2052 /* Error SNTP has already been started. */
2053
2054 /* Release the SNTP mutex. */
2055 tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex));
2056
2057 /* Return completion status. */
2058 return(NX_SNTP_CLIENT_ALREADY_STARTED);
2059 }
2060
2061 /* Verify the client is ready to start receiving time data. */
2062 if (client_ptr -> nx_sntp_client_broadcast_initialized == NX_FALSE)
2063 {
2064
2065 tx_mutex_put(&client_ptr -> nx_sntp_client_mutex);
2066
2067 /* Return error condition. */
2068 return NX_SNTP_CLIENT_NOT_INITIALIZED;
2069 }
2070
2071
2072 /* Set the maximum timeout to the full count. */
2073 client_ptr -> nx_sntp_update_time_remaining = (NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE);
2074
2075 /* Activate the SNTP update timer. */
2076 status = tx_timer_activate(&(client_ptr -> nx_sntp_update_timer));
2077
2078 /* Check for error. Ignore timer is already active error. */
2079 if (status != TX_SUCCESS && status != TX_ACTIVATE_ERROR)
2080 {
2081
2082 tx_mutex_put(&client_ptr -> nx_sntp_client_mutex);
2083
2084 /* Return the error condition. */
2085 return status;
2086 }
2087
2088 /* Bind the UDP socket to the IP port. */
2089 status = nx_udp_socket_bind(&(client_ptr -> nx_sntp_client_udp_socket), NX_SNTP_CLIENT_UDP_PORT, NX_WAIT_FOREVER);
2090
2091 /* Check for error. */
2092 if (status != NX_SUCCESS)
2093 {
2094
2095 /* Deactivate SNTP update timer. */
2096 tx_timer_deactivate(&(client_ptr -> nx_sntp_update_timer));
2097
2098 tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex));
2099
2100 return status;
2101 }
2102
2103 /* Set status that the first update is expected. */
2104 client_ptr -> nx_sntp_client_first_update_pending = NX_TRUE;
2105
2106 status = tx_thread_resume(&(client_ptr -> nx_sntp_client_thread));
2107
2108 if (status != NX_SUCCESS)
2109 {
2110
2111 /* Release the socket port. */
2112 nx_udp_socket_unbind(&(client_ptr -> nx_sntp_client_udp_socket));
2113
2114 /* Deactivate SNTP update timer. */
2115 tx_timer_deactivate(&(client_ptr -> nx_sntp_update_timer));
2116
2117 tx_mutex_put(&client_ptr -> nx_sntp_client_mutex);
2118
2119 return status;
2120 }
2121
2122 /* Clear the sleep flag. */
2123 client_ptr -> nx_sntp_client_sleep_flag = NX_FALSE;
2124
2125 client_ptr -> nx_sntp_client_started = NX_TRUE;
2126
2127 tx_mutex_put(&client_ptr -> nx_sntp_client_mutex);
2128
2129 return NX_SUCCESS;
2130 }
2131
2132
2133 /**************************************************************************/
2134 /* */
2135 /* FUNCTION RELEASE */
2136 /* */
2137 /* _nx_sntp_client_process_broadcast PORTABLE C */
2138 /* 6.1 */
2139 /* AUTHOR */
2140 /* */
2141 /* Yuxin Zhou, Microsoft Corporation */
2142 /* */
2143 /* DESCRIPTION */
2144 /* */
2145 /* This function checks if the SNTP client has received a packet, and if*/
2146 /* so processes it for valid SNTP data and resets the timeouts */
2147 /* for receiving the next update. */
2148 /* */
2149 /* If the invalid packet update count exceeds the maximum allowed */
2150 /* updates, or no valid packet is received within the maximum interval, */
2151 /* an error flag is set, and it is up to the host application to change */
2152 /* its broadcast SNTP server. */
2153 /* */
2154 /* INPUT */
2155 /* */
2156 /* client_ptr Pointer to Client */
2157 /* */
2158 /* OUTPUT */
2159 /* */
2160 /* None */
2161 /* */
2162 /* CALLS */
2163 /* */
2164 /* _nx_sntp_client_reset_current_time_message */
2165 /* Save time update before next update */
2166 /* _nx_sntp_client_receive_time_update */
2167 /* Receive server update packets */
2168 /* _nx_sntp_client_process_time_data */
2169 /* Process time data in server update */
2170 /* */
2171 /* CALLED BY */
2172 /* */
2173 /* Application Code */
2174 /* */
2175 /* RELEASE HISTORY */
2176 /* */
2177 /* DATE NAME DESCRIPTION */
2178 /* */
2179 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2180 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2181 /* resulting in version 6.1 */
2182 /* */
2183 /**************************************************************************/
_nx_sntp_client_process_broadcast(NX_SNTP_CLIENT * client_ptr)2184 VOID _nx_sntp_client_process_broadcast(NX_SNTP_CLIENT *client_ptr)
2185 {
2186
2187 UINT status;
2188 ULONG sntp_events;
2189
2190
2191 /* Check for a receive event. */
2192 status = tx_event_flags_get(&nx_sntp_client_events, NX_SNTP_CLIENT_RECEIVE_EVENT, TX_OR_CLEAR, &sntp_events, TX_NO_WAIT);
2193
2194 if (status == NX_SUCCESS)
2195 {
2196
2197 /* Save this server time update before receiving the next server time update. */
2198 _nx_sntp_client_reset_current_time_message(client_ptr);
2199
2200 /* Listen for a server update packet. */
2201 status = _nx_sntp_client_receive_time_update(client_ptr, TX_NO_WAIT);
2202
2203 if (status == NX_SUCCESS)
2204 {
2205
2206 /* Process the server update packet and apply to local time if valid. */
2207 status = _nx_sntp_client_process_update_packet(client_ptr);
2208
2209 /* Check for error. */
2210 if (status != NX_SUCCESS)
2211 {
2212
2213 /* Have we exceeded the max number of invalid or missed updates from this server? */
2214 if (client_ptr -> nx_sntp_client_invalid_time_updates > NX_SNTP_CLIENT_INVALID_UPDATE_LIMIT)
2215 {
2216
2217 /* Yes, set the server status as no longer valid. */
2218 client_ptr -> nx_sntp_valid_server_status = NX_FALSE;
2219 }
2220
2221 return;
2222 }
2223
2224 /* Reset the Client timeout for receiving broadcast updates, zero out invalid update count. */
2225 client_ptr -> nx_sntp_update_time_remaining = (NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE);
2226
2227 client_ptr -> nx_sntp_client_invalid_time_updates = 0;
2228
2229 /* Set the server status as good (receiving updates). */
2230 client_ptr -> nx_sntp_valid_server_status = NX_TRUE;
2231
2232 /* Indicate the client has received at least one valid time update with the current server. */
2233 client_ptr -> nx_sntp_client_first_update_pending = NX_FALSE;
2234
2235 return;
2236 }
2237 }
2238
2239 /* Has the timeout for receiving the next time update expired? */
2240 if (client_ptr -> nx_sntp_update_time_remaining == 0)
2241 {
2242
2243 /* Yes, set the server status as no longer valid. */
2244 client_ptr -> nx_sntp_valid_server_status = NX_FALSE;
2245 }
2246
2247 /* Nothing to do but wait...*/
2248 return;
2249 }
2250
2251
2252 /**************************************************************************/
2253 /* */
2254 /* FUNCTION RELEASE */
2255 /* */
2256 /* _nx_sntp_client_send_unicast_request PORTABLE C */
2257 /* 6.1 */
2258 /* AUTHOR */
2259 /* */
2260 /* Yuxin Zhou, Microsoft Corporation */
2261 /* */
2262 /* DESCRIPTION */
2263 /* */
2264 /* This function allocates a packet from the Client packet pool,creates*/
2265 /* a time request time message, transfers the request message into the */
2266 /* packet buffer, and sends the packet via the Client UDP socket. It */
2267 /* then releases the packet back to the packet pool. */
2268 /* */
2269 /* INPUT */
2270 /* */
2271 /* client_ptr Pointer to Client */
2272 /* */
2273 /* OUTPUT */
2274 /* */
2275 /* status Actual completion status */
2276 /* */
2277 /* CALLS */
2278 /* */
2279 /* memset Clear specified area of memory */
2280 /* nx_packet_allocate Allocate packet from packet pool */
2281 /* nx_packet_release Release packet back to packet pool */
2282 /* nx_udp_socket_send Transmit packet via UDP socket */
2283 /* _nx_sntp_client_utility_convert_time_to_UCHAR */
2284 /* Copy NX_SNTP_TIME data into a */
2285 /* UCHAR[4] time stamp field */
2286 /* _nx_sntp_client_create_time_request_packet */
2287 /* Create packet with time request data*/
2288 /* */
2289 /* CALLED BY */
2290 /* */
2291 /* _nx_sntp_client_run_unicast Send and receive unicast time data */
2292 /* */
2293 /* RELEASE HISTORY */
2294 /* */
2295 /* DATE NAME DESCRIPTION */
2296 /* */
2297 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2298 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2299 /* resulting in version 6.1 */
2300 /* */
2301 /**************************************************************************/
_nx_sntp_client_send_unicast_request(NX_SNTP_CLIENT * client_ptr)2302 UINT _nx_sntp_client_send_unicast_request(NX_SNTP_CLIENT *client_ptr)
2303 {
2304
2305 NX_PACKET *packet_ptr;
2306 UINT status;
2307 NX_SNTP_TIME_MESSAGE *unicast_request;
2308 NX_SNTP_TIME local_time;
2309
2310
2311 /* Lock access to the SNTP Client while we create a unicast request. */
2312 tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER);
2313
2314 unicast_request = &(client_ptr -> nx_sntp_current_time_message_request);
2315
2316 /* Clear the time request. */
2317 memset(unicast_request, 0, sizeof(NX_SNTP_TIME_MESSAGE));
2318
2319 /* Add client version to the time request flags. */
2320 unicast_request -> flags = NX_SNTP_CLIENT_NTP_VERSION << 3;
2321
2322 /* Set the Client association (mode) in the last three bits of the flag field. */
2323 unicast_request -> flags |= PROTOCOL_MODE_CLIENT;
2324
2325 /* Release the mutex before a potentially blocking call. */
2326 tx_mutex_put(&client_ptr -> nx_sntp_client_mutex);
2327
2328 /* Allocate a packet from the Client pool. */
2329 status = nx_packet_allocate(client_ptr -> nx_sntp_client_packet_pool_ptr, &packet_ptr, NX_UDP_PACKET, NX_SNTP_CLIENT_PACKET_TIMEOUT);
2330
2331 /* Check for error. */
2332 if (status != NX_SUCCESS)
2333 {
2334
2335 /* Return error status. */
2336 return status;
2337 }
2338
2339 /* Reacquire the lock to SNTP Client while we process request. */
2340 tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER);
2341
2342 /* Check for minimal packet size requirement. */
2343
2344
2345 /* IPv6 packets require more space for the IPv6 header. */
2346 if (client_ptr -> nx_sntp_server_ip_address.nxd_ip_version == NX_IP_VERSION_V6)
2347 {
2348
2349 #ifndef FEATURE_NX_IPV6
2350 nx_packet_release(packet_ptr);
2351
2352 /* Release the mutex. */
2353 tx_mutex_put(&client_ptr -> nx_sntp_client_mutex);
2354
2355 return NX_SNTP_INVALID_IP_ADDRESS;
2356 #else
2357
2358 if (client_ptr -> nx_sntp_client_packet_pool_ptr -> nx_packet_pool_payload_size <
2359 (sizeof(NX_IPV6_HEADER) + sizeof(NX_UDP_HEADER) + NX_SNTP_CLIENT_PACKET_DATA_SIZE))
2360 {
2361
2362 nx_packet_release(packet_ptr);
2363
2364 /* Release the mutex. */
2365 tx_mutex_put(&client_ptr -> nx_sntp_client_mutex);
2366
2367 return NX_SNTP_INSUFFICIENT_PACKET_PAYLOAD;
2368 }
2369 #endif /* FEATURE_NX_IPV6 */
2370 }
2371 else /* IPv4 */
2372 {
2373
2374 #ifdef NX_DISABLE_IPV4
2375 nx_packet_release(packet_ptr);
2376
2377 /* Release the mutex. */
2378 tx_mutex_put(&client_ptr -> nx_sntp_client_mutex);
2379
2380 return NX_SNTP_INVALID_IP_ADDRESS;
2381 #else
2382
2383 if (client_ptr -> nx_sntp_client_packet_pool_ptr -> nx_packet_pool_payload_size <
2384 (sizeof(NX_IPV4_HEADER) + sizeof(NX_UDP_HEADER) + NX_SNTP_CLIENT_PACKET_DATA_SIZE))
2385 {
2386
2387 nx_packet_release(packet_ptr);
2388
2389 /* Release the mutex. */
2390 tx_mutex_put(&client_ptr -> nx_sntp_client_mutex);
2391
2392 return NX_SNTP_INSUFFICIENT_PACKET_PAYLOAD;
2393 }
2394 #endif /* NX_DISABLE_IPV4 */
2395 }
2396
2397
2398 /* Convert the local time into the request's transmit time stamp field. */
2399 local_time.seconds = client_ptr -> nx_sntp_client_local_ntp_time.seconds +
2400 client_ptr -> nx_sntp_client_local_ntp_time_elapsed;
2401 local_time.fraction = client_ptr -> nx_sntp_client_local_ntp_time.fraction;
2402 _nx_sntp_client_utility_convert_time_to_UCHAR(&local_time, unicast_request, TRANSMIT_TIME);
2403
2404 /* Create the request packet with the unicast request message. */
2405 status = _nx_sntp_client_create_time_request_packet(client_ptr, packet_ptr, unicast_request);
2406
2407 /* Check for error. */
2408 if (status != NX_SUCCESS)
2409 {
2410
2411 /* Release the packet. */
2412 nx_packet_release(packet_ptr);
2413
2414
2415 /* Release the mutex. */
2416 tx_mutex_put(&client_ptr -> nx_sntp_client_mutex);
2417
2418 /* Return error status. */
2419 return status;
2420 }
2421
2422 /* Release the lock. we're done with the SNTP Client data. */
2423 tx_mutex_put(&client_ptr -> nx_sntp_client_mutex);
2424
2425 /* Send the time request packet. */
2426 status = nxd_udp_socket_send(&(client_ptr -> nx_sntp_client_udp_socket), packet_ptr, &client_ptr -> nx_sntp_server_ip_address, NX_SNTP_SERVER_UDP_PORT);
2427
2428
2429 /* Check for error. */
2430 if (status != NX_SUCCESS)
2431 {
2432
2433 /* Release the packet. */
2434 nx_packet_release(packet_ptr);
2435
2436 return status;
2437 }
2438
2439 send_timerticks = tx_time_get();
2440
2441 /* Return completion status. */
2442 return status;
2443 }
2444
2445
2446 /**************************************************************************/
2447 /* */
2448 /* FUNCTION RELEASE */
2449 /* */
2450 /* _nx_sntp_client_receive_time_update PORTABLE C */
2451 /* 6.3.0 */
2452 /* AUTHOR */
2453 /* */
2454 /* Yuxin Zhou, Microsoft Corporation */
2455 /* */
2456 /* DESCRIPTION */
2457 /* */
2458 /* This function receives UDP data on the Client socket with specified */
2459 /* wait (timeout option). Received packets are checked for valid */
2460 /* and sender IP and port. Packet data is then extracted and stored */
2461 /* in the specified time message. The packet is released regardless of */
2462 /* validity of packet received. */
2463 /* */
2464 /* INPUT */
2465 /* */
2466 /* client_ptr Pointer to Client */
2467 /* timeout Wait option to receive packet */
2468 /* */
2469 /* OUTPUT */
2470 /* status Actual completion status */
2471 /* */
2472 /* CALLS */
2473 /* */
2474 /* nx_udp_socket_receive Listen for packets on UDP socket */
2475 /* nx_packet_release Release packet back to packet pool*/
2476 /* tx_mutex_get Obtain exclusive lock on list */
2477 /* memset Clear specified area of memory */
2478 /* _nx_sntp_client_add_server_ULONG_to_list */
2479 /* Add sender address to Client list */
2480 /* _nx_sntp_client_utility_convert_LONG_to_IP */
2481 /* Convert IP to string for display */
2482 /* _nx_sntp_client_extract_time_message_from_packet */
2483 /* Extract packet data to time message*/
2484 /* */
2485 /* CALLED BY */
2486 /* */
2487 /* _nx_sntp_client_run_unicast Send and receive server time updates*/
2488 /* _nx_sntp_client_run_broadcast Listen for server update broadcasts */
2489 /* */
2490 /* RELEASE HISTORY */
2491 /* */
2492 /* DATE NAME DESCRIPTION */
2493 /* */
2494 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2495 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
2496 /* added support for disabling */
2497 /* message check, */
2498 /* resulting in version 6.1 */
2499 /* 07-29-2022 Yuxin Zhou Modified comment(s), and */
2500 /* corrected the port check, */
2501 /* resulting in version 6.1.12 */
2502 /* 10-31-2023 Tiejun Zhou Modified comment(s), and */
2503 /* fixed packet chain issue, */
2504 /* resulting in version 6.3.0 */
2505 /* */
2506 /**************************************************************************/
_nx_sntp_client_receive_time_update(NX_SNTP_CLIENT * client_ptr,ULONG timeout)2507 UINT _nx_sntp_client_receive_time_update(NX_SNTP_CLIENT *client_ptr, ULONG timeout)
2508 {
2509
2510 UINT status;
2511 UINT length;
2512 NX_PACKET *receive_packet;
2513 #ifndef NX_SNTP_CLIENT_MESSAGE_CHECK_DISABLE
2514 UINT sender_port;
2515 NX_UDP_HEADER *udp_header_ptr;
2516 NXD_ADDRESS source_ip_address, destination_ip_address;
2517 #endif /* NX_SNTP_CLIENT_MESSAGE_CHECK_DISABLE */
2518
2519 /* Loop to receive packets. */
2520 for(;;)
2521 {
2522
2523 /* Indicate the SNTP Client can be stopped while the SNTP client waits for a packet. */
2524 client_ptr -> nx_sntp_client_sleep_flag = NX_TRUE;
2525
2526 /* Wait to receive packets on the Client UDP socket. */
2527 status = nx_udp_socket_receive(&(client_ptr -> nx_sntp_client_udp_socket), &receive_packet, timeout * NX_IP_PERIODIC_RATE);
2528
2529 /* Indicate the SNTP Client can not be stopped. */
2530 client_ptr -> nx_sntp_client_sleep_flag = NX_FALSE;
2531
2532 /* Check for error. */
2533 if (status != NX_SUCCESS)
2534 {
2535
2536 /* Return error status. */
2537 return status;
2538 }
2539
2540 #ifndef NX_SNTP_CLIENT_MESSAGE_CHECK_DISABLE
2541 /* Check the sender port in the UDP packet header. */
2542 udp_header_ptr = (NX_UDP_HEADER *)(receive_packet -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER));
2543 sender_port = (UINT)udp_header_ptr -> nx_udp_header_word_0 >> NX_SHIFT_BY_16;
2544
2545 /* Check if this is the server port the Client expects. */
2546 if (sender_port != NX_SNTP_SERVER_UDP_PORT)
2547 {
2548
2549 /* No, reject the packet. */
2550 nx_packet_release(receive_packet);
2551
2552 continue;
2553 }
2554
2555
2556 /* If this an IPv6 packet? An SNTP client with an IPv6 SNTP server will only accept IPv6 packets. */
2557 if ((receive_packet -> nx_packet_ip_version == NX_IP_VERSION_V6) &&
2558 (client_ptr -> nx_sntp_server_ip_address.nxd_ip_version == NX_IP_VERSION_V6))
2559 {
2560
2561 #ifndef FEATURE_NX_IPV6
2562 nx_packet_release(receive_packet);
2563 continue;
2564 #else
2565 NX_IPV6_HEADER *ipv6_header_ptr;
2566
2567 /* Pick up the IPv6 header from the packet. */
2568 ipv6_header_ptr = (NX_IPV6_HEADER *) (receive_packet -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER) - sizeof(NX_IPV6_HEADER));
2569
2570 /* Copy sender address into a local variable. */
2571 COPY_IPV6_ADDRESS(ipv6_header_ptr -> nx_ip_header_source_ip, &(source_ip_address.nxd_ip_address.v6[0]));
2572 source_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
2573
2574 /* Copy destination address into a local variable. */
2575 COPY_IPV6_ADDRESS(ipv6_header_ptr -> nx_ip_header_destination_ip, &(destination_ip_address.nxd_ip_address.v6[0]));
2576 destination_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
2577
2578 if (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE)
2579 {
2580
2581 /* Does the source address match the expected server address? */
2582 if (!CHECK_IPV6_ADDRESSES_SAME(&client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v6[0], &source_ip_address.nxd_ip_address.v6[0]))
2583 {
2584
2585 /* No further need for the receive packet. Release back to the client pool. */
2586 nx_packet_release(receive_packet);
2587
2588 /* Set update time to null. */
2589 memset(&(client_ptr -> nx_sntp_server_update_time), 0, sizeof(NX_SNTP_TIME));
2590
2591 continue;
2592 }
2593 }
2594 else /* Multicast mode */
2595 {
2596
2597 /* Define the all hosts multicast address. */
2598 NXD_ADDRESS All_Hosts_Multicast;
2599 All_Hosts_Multicast.nxd_ip_version = NX_IP_VERSION_V6;
2600 All_Hosts_Multicast.nxd_ip_address.v6[0] = 0xff020000;
2601 All_Hosts_Multicast.nxd_ip_address.v6[1] = 0x00000000;
2602 All_Hosts_Multicast.nxd_ip_address.v6[2] = 0x00000000;
2603 All_Hosts_Multicast.nxd_ip_address.v6[3] = 0x00000001;
2604
2605 /* Does the source address match the expected server address )? */
2606 if (!CHECK_IPV6_ADDRESSES_SAME(&client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v6[0], &source_ip_address.nxd_ip_address.v6[0]))
2607 {
2608
2609 /* No further need for the receive packet. Release back to the client pool. */
2610 nx_packet_release(receive_packet);
2611
2612 /* Set update time to null. */
2613 memset(&(client_ptr -> nx_sntp_server_update_time), 0, sizeof(NX_SNTP_TIME));
2614
2615 continue;
2616 }
2617
2618 /* Does the destination address match the expected server address (all hosts address FF02::1)? */
2619 if (!CHECK_IPV6_ADDRESSES_SAME(&destination_ip_address.nxd_ip_address.v6[0], &All_Hosts_Multicast.nxd_ip_address.v6[0]))
2620 {
2621
2622 /* No further need for the receive packet. Release back to the client pool. */
2623 nx_packet_release(receive_packet);
2624
2625 /* Set update time to null. */
2626 memset(&(client_ptr -> nx_sntp_server_update_time), 0, sizeof(NX_SNTP_TIME));
2627
2628 continue;
2629 }
2630
2631 }
2632 #endif /* FEATURE_NX_IPV6 */
2633
2634 }
2635 /* Otherwise is this an IPv4 packet and is the SNTP client set for IPv4? */
2636 else if ((receive_packet -> nx_packet_ip_version == NX_IP_VERSION_V4) &&
2637 (client_ptr -> nx_sntp_server_ip_address.nxd_ip_version == NX_IP_VERSION_V4))
2638 {
2639 #ifdef NX_DISABLE_IPV4
2640 nx_packet_release(receive_packet);
2641 continue;
2642 #else
2643
2644 NX_IPV4_HEADER *ipv4_header_ptr;
2645
2646 ipv4_header_ptr = (NX_IPV4_HEADER *) (receive_packet -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER) - sizeof(NX_IPV4_HEADER));
2647
2648 /* Copy into a local variable. */
2649 source_ip_address.nxd_ip_address.v4 = ipv4_header_ptr -> nx_ip_header_source_ip;
2650 source_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
2651
2652 /* Copy into a local variable. */
2653 destination_ip_address.nxd_ip_address.v4 = ipv4_header_ptr -> nx_ip_header_destination_ip;
2654 destination_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
2655
2656 if (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE)
2657 {
2658 /* Compare the sender address with the Client's current sntp server. */
2659 if (source_ip_address.nxd_ip_address.v4 != client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v4)
2660 {
2661 /* This is an untrusted server or the client had a broadcast server already,
2662 reject this packet and return an error condition. */
2663
2664 /* No further need for the receive packet. Release back to the client pool. */
2665 nx_packet_release(receive_packet);
2666
2667 continue;
2668 }
2669 }
2670 else /* BROADCAST_MODE */
2671 {
2672
2673 ULONG network_mask;
2674 UINT iface_index;
2675
2676 /* Compare the sender address with the Client's current sntp server. */
2677 if (source_ip_address.nxd_ip_address.v4 != client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v4)
2678 {
2679
2680 /* This is an untrusted server or the client had a broadcast server already,
2681 reject this packet and return an error condition. */
2682
2683 /* No further need for the receive packet. Release back to the client pool. */
2684 nx_packet_release(receive_packet);
2685
2686 continue;
2687 }
2688
2689 /* Set a local variable on the SNTP network index. */
2690 iface_index = client_ptr -> nx_sntp_client_interface_index;
2691
2692 /* Set a local variable to the network mask. */
2693 network_mask = client_ptr -> nx_sntp_client_ip_ptr -> nx_ip_interface[iface_index].nx_interface_ip_network_mask;
2694
2695 /* Now verify this is a broadcast packet. */
2696 if ((destination_ip_address.nxd_ip_address.v4 & ~network_mask) != ~network_mask)
2697 {
2698 /* This is not a broadcast packet on the local network. */
2699
2700 /* No further need for the receive packet. Release back to the client pool. */
2701 nx_packet_release(receive_packet);
2702
2703 continue;
2704 }
2705 }
2706 #endif /* NX_DISABLE_IPV4 */
2707 }
2708 else
2709 {
2710 /* Not interested, discard the packet. */
2711 nx_packet_release(receive_packet);
2712
2713 continue;
2714 }
2715
2716 #endif /* NX_SNTP_CLIENT_MESSAGE_CHECK_DISABLE */
2717
2718 /* Check that the packet has the proper length for an NTP message. */
2719 length = receive_packet -> nx_packet_length;
2720
2721 /* Verify the packet data contains at least the minimum time update data,
2722 but no more than the max size with authentication data appended. */
2723
2724 if ((length < NX_SNTP_TIME_MESSAGE_MIN_SIZE) || (length > NX_SNTP_TIME_MESSAGE_MAX_SIZE))
2725 {
2726
2727 /* No further need for the receive packet. Release back to the client pool. */
2728 nx_packet_release(receive_packet);
2729
2730 continue;
2731 }
2732
2733 #ifndef NX_DISABLE_PACKET_CHAIN
2734 /* Ignore packet chain. */
2735 if (receive_packet -> nx_packet_next)
2736 {
2737
2738 /* No further need for the receive packet. Release back to the client pool. */
2739 nx_packet_release(receive_packet);
2740
2741 continue;
2742 }
2743 #endif /* NX_DISABLE_PACKET_CHAIN */
2744
2745 memset(&(client_ptr -> nx_sntp_current_server_time_message), 0, sizeof(NX_SNTP_TIME_MESSAGE));
2746
2747 /* Extract time message data from packet data into time message. */
2748 _nx_sntp_client_extract_time_message_from_packet(client_ptr, receive_packet);
2749
2750 /* No further need for the receive packet. Release back to the client pool. */
2751 nx_packet_release(receive_packet);
2752
2753 return NX_SUCCESS;
2754 }
2755 }
2756
2757
2758 /**************************************************************************/
2759 /* */
2760 /* FUNCTION RELEASE */
2761 /* */
2762 /* _nx_sntp_client_extract_time_message_from_packet PORTABLE C */
2763 /* 6.1.10 */
2764 /* AUTHOR */
2765 /* */
2766 /* Yuxin Zhou, Microsoft Corporation */
2767 /* */
2768 /* DESCRIPTION */
2769 /* */
2770 /* This function extracts time data from an SNTP server packet and */
2771 /* copies the information into the specified time message buffer. */
2772 /* */
2773 /* INPUT */
2774 /* */
2775 /* client_ptr Pointer to SNTP Client */
2776 /* packet_ptr Pointer to server packet */
2777 /* */
2778 /* OUTPUT */
2779 /* */
2780 /* NX_SUCCESS Successful completion status */
2781 /* */
2782 /* CALLS */
2783 /* */
2784 /* memcpy Copy data to area of memory */
2785 /* */
2786 /* CALLED BY */
2787 /* */
2788 /* _nx_sntp_client_receive_time_update Process SNTP server packets */
2789 /* */
2790 /* RELEASE HISTORY */
2791 /* */
2792 /* DATE NAME DESCRIPTION */
2793 /* */
2794 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2795 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
2796 /* verified memcpy use cases, */
2797 /* resulting in version 6.1 */
2798 /* 01-31-2022 Yuxin Zhou Modified comment(s), corrected*/
2799 /* the Reference Identifier, */
2800 /* resulting in version 6.1.10 */
2801 /* */
2802 /**************************************************************************/
_nx_sntp_client_extract_time_message_from_packet(NX_SNTP_CLIENT * client_ptr,NX_PACKET * packet_ptr)2803 UINT _nx_sntp_client_extract_time_message_from_packet(NX_SNTP_CLIENT *client_ptr, NX_PACKET *packet_ptr)
2804 {
2805
2806 ULONG *ntp_word_0;
2807 NX_SNTP_TIME_MESSAGE *time_message_ptr;
2808
2809
2810 time_message_ptr = &(client_ptr -> nx_sntp_current_server_time_message);
2811
2812 process_timerticks = tx_time_get();
2813
2814 memset(time_message_ptr, 0, sizeof(NX_SNTP_TIME_MESSAGE));
2815
2816 /* Pickup the pointer to the head of the UDP packet. */
2817 ntp_word_0 = (ULONG *)packet_ptr -> nx_packet_prepend_ptr;
2818 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2819
2820 /* Extract fields from the first 32 bits of the time message. */
2821 time_message_ptr -> flags = (*ntp_word_0 & 0xFF000000UL) >> 24;
2822
2823 time_message_ptr -> peer_clock_stratum = (*ntp_word_0 & 0x00FF0000UL) >> 16;
2824
2825 time_message_ptr -> peer_poll_interval = (*ntp_word_0 & 0x0000FF00UL) >> 8;
2826
2827 time_message_ptr -> peer_clock_precision = (*ntp_word_0 & 0x00000000FFUL);
2828
2829 /* Advance to the next 32 bit field and extract the root delay field. */
2830 ntp_word_0++;
2831 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2832
2833 time_message_ptr -> root_delay = (ULONG)(*ntp_word_0);
2834
2835 /* Advance to the next 32 bit field and extract the clock dispersion field. */
2836 ntp_word_0++;
2837 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2838
2839 time_message_ptr -> clock_dispersion= *ntp_word_0;
2840
2841 /* Advance to the next 32 bit field and extract the reference clock ID field. */
2842 ntp_word_0++;
2843 memcpy(time_message_ptr -> reference_clock_id, ntp_word_0, 4); /* Use case of memcpy is verified. */
2844
2845 /* Advance to the next field (64 bit field) and extract the reference time stamp field. */
2846 ntp_word_0++;
2847 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2848 time_message_ptr -> reference_clock_update_time_stamp[0] = *ntp_word_0;
2849
2850 ntp_word_0++;
2851 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2852 time_message_ptr -> reference_clock_update_time_stamp[1] = *ntp_word_0;
2853
2854 /* If a non zero reference time was supplied, separate out seconds and fraction. */
2855 if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(time_message_ptr -> reference_clock_update_time_stamp), 8) == NX_FALSE)
2856 {
2857
2858 time_message_ptr -> reference_clock_update_time.seconds = time_message_ptr -> reference_clock_update_time_stamp[0];
2859
2860 time_message_ptr -> reference_clock_update_time.fraction = time_message_ptr -> reference_clock_update_time_stamp[1];
2861 }
2862
2863 /* Copy the first 32 bits into the originate time stamp seconds field. */
2864 ntp_word_0++;
2865 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2866 time_message_ptr -> originate_time_stamp[0] = *ntp_word_0;
2867
2868 /* Copy the next 32 bits into the originate time stamp fraction field. */
2869 ntp_word_0++;
2870 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2871 time_message_ptr -> originate_time_stamp[1] = *ntp_word_0;
2872
2873 /* If an originate time was supplied, separate out seconds and fraction. */
2874 if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(time_message_ptr -> originate_time_stamp), 8) == NX_FALSE)
2875 {
2876
2877 time_message_ptr -> originate_time.seconds = time_message_ptr -> originate_time_stamp[0];
2878
2879 time_message_ptr -> originate_time.fraction = time_message_ptr -> originate_time_stamp[1];
2880 }
2881
2882
2883 /* Copy the first 32 bits into the receive time stamp seconds field. */
2884 ntp_word_0++;
2885 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2886 time_message_ptr -> receive_time_stamp[0] = *ntp_word_0;
2887
2888 /* Copy the next 32 bits into the receive time stamp fraction field. */
2889 ntp_word_0++;
2890 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2891 time_message_ptr -> receive_time_stamp[1] = *ntp_word_0;
2892
2893 /* If an receive time was supplied, separate out seconds and fraction. */
2894 if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(time_message_ptr -> receive_time_stamp), 8) == NX_FALSE)
2895 {
2896
2897 time_message_ptr -> receive_time.seconds = time_message_ptr -> receive_time_stamp[0];
2898 time_message_ptr -> receive_time.fraction = time_message_ptr -> receive_time_stamp[1];
2899 }
2900
2901 /* Copy the first 32 bits into the transmit time stamp seconds field. */
2902 ntp_word_0++;
2903 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2904 time_message_ptr -> transmit_time_stamp[0] = *ntp_word_0;
2905
2906 /* Copy the next 32 bits into the transmit time stamp fraction field. */
2907 ntp_word_0++;
2908 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2909 time_message_ptr -> transmit_time_stamp[1] = *ntp_word_0;
2910
2911 /* If an transmit time was supplied, separate out seconds and fraction. */
2912 if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(time_message_ptr -> transmit_time_stamp), 8) == NX_FALSE)
2913 {
2914
2915 time_message_ptr -> transmit_time.seconds = time_message_ptr -> transmit_time_stamp[0];
2916
2917 time_message_ptr -> transmit_time.fraction = time_message_ptr -> transmit_time_stamp[1];
2918
2919 }
2920
2921 /* Return completion status. */
2922 return NX_SUCCESS;
2923 }
2924
2925
2926 /**************************************************************************/
2927 /* */
2928 /* FUNCTION RELEASE */
2929 /* */
2930 /* _nx_sntp_client_reset_current_time_message PORTABLE C */
2931 /* 6.1 */
2932 /* AUTHOR */
2933 /* */
2934 /* Yuxin Zhou, Microsoft Corporation */
2935 /* */
2936 /* DESCRIPTION */
2937 /* */
2938 /* This function saves the current time message from the server to */
2939 /* the previous time message field, and clears the current time message*/
2940 /* field. */
2941 /* */
2942 /* INPUT */
2943 /* */
2944 /* client_ptr Pointer to Client */
2945 /* */
2946 /* OUTPUT */
2947 /* */
2948 /* NX_SUCCESS Successful completion status */
2949 /* */
2950 /* CALLS */
2951 /* */
2952 /* memset Clear specified area of memory */
2953 /* memcpy Copy data to area of memory */
2954 /* */
2955 /* CALLED BY */
2956 /* */
2957 /* _nx_sntp_client_receive_time_update Process received update packets */
2958 /* */
2959 /* RELEASE HISTORY */
2960 /* */
2961 /* DATE NAME DESCRIPTION */
2962 /* */
2963 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2964 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
2965 /* verified memcpy use cases, */
2966 /* resulting in version 6.1 */
2967 /* */
2968 /**************************************************************************/
_nx_sntp_client_reset_current_time_message(NX_SNTP_CLIENT * client_ptr)2969 UINT _nx_sntp_client_reset_current_time_message(NX_SNTP_CLIENT *client_ptr)
2970 {
2971
2972 /* Does the client have a non NULL current server time update? */
2973 if (client_ptr -> nx_sntp_current_server_time_message.flags)
2974 {
2975
2976 /* Yes, copy to the previous time update. */
2977 memcpy(&client_ptr -> nx_sntp_previous_server_time_message, &client_ptr -> nx_sntp_current_server_time_message, sizeof(NX_SNTP_TIME_MESSAGE)); /* Use case of memcpy is verified. */
2978
2979 /* Clear the current time update data. */
2980 memset(&(client_ptr -> nx_sntp_current_server_time_message), 0, sizeof(NX_SNTP_TIME_MESSAGE));
2981
2982 }
2983
2984 /* Clear the current time update request. */
2985 memset(&(client_ptr -> nx_sntp_current_time_message_request), 0, sizeof(NX_SNTP_TIME_MESSAGE));
2986
2987 return NX_SUCCESS;
2988 }
2989
2990
2991 /**************************************************************************/
2992 /* */
2993 /* FUNCTION RELEASE */
2994 /* */
2995 /* _nx_sntp_client_process_update_packet PORTABLE C */
2996 /* 6.1 */
2997 /* AUTHOR */
2998 /* */
2999 /* Yuxin Zhou, Microsoft Corporation */
3000 /* */
3001 /* DESCRIPTION */
3002 /* */
3003 /* This function processes SNTP time data received in a server update */
3004 /* packet, applies sanity checks, calculates round trip time, and */
3005 /* updates the Client time with the SNTP server time. */
3006 /* */
3007 /* INPUT */
3008 /* */
3009 /* client_ptr Pointer to Client */
3010 /* */
3011 /* OUTPUT */
3012 /* */
3013 /* NX_SUCCESS Successful completion status */
3014 /* NX_SNTP_BAD_SERVER_ROOT_DISPERSION Server dispersion too high */
3015 /* receive_status Actual packet receive status */
3016 /* */
3017 /* CALLS */
3018 /* */
3019 /* memcmp Copy data to area of memory */
3020 /* _nx_sntp_client_apply_sanity_checks Apply sanity checks to update */
3021 /* _nx_sntp_client_check_server_clock_dispersion */
3022 /* Check server clock dispersion */
3023 /* _nx_sntp_client_calculate_roundtrip */
3024 /* Compute roundtrip time to server*/
3025 /* _nx_sntp_client_process_time_data Apply server time to local time */
3026 /* */
3027 /* CALLED BY */
3028 /* */
3029 /* _nx_sntp_client_process_unicast Process unicast SNTP data */
3030 /* _nx_sntp_client_process_broadcast Process broadcast SNTP data */
3031 /* */
3032 /* RELEASE HISTORY */
3033 /* */
3034 /* DATE NAME DESCRIPTION */
3035 /* */
3036 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3037 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3038 /* resulting in version 6.1 */
3039 /* */
3040 /**************************************************************************/
_nx_sntp_client_process_update_packet(NX_SNTP_CLIENT * client_ptr)3041 UINT _nx_sntp_client_process_update_packet(NX_SNTP_CLIENT *client_ptr)
3042 {
3043
3044 UINT status;
3045
3046 /* Apply client's set of sanity checks on the data. */
3047 status = _nx_sntp_client_apply_sanity_checks(client_ptr);
3048
3049 /* Check for sanity check errors. */
3050 if (status != NX_SUCCESS)
3051 {
3052
3053 /* Count these as bad updates from the server. */
3054 client_ptr -> nx_sntp_client_invalid_time_updates++;
3055
3056 /* Ok to continue Client task. */
3057 return status;
3058 }
3059
3060 /* Check server clock dispersion (if any reported) in first update
3061 from current server for unicast clients. */
3062 if ((client_ptr -> nx_sntp_client_first_update_pending == NX_TRUE) && (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE))
3063 {
3064
3065 status = _nx_sntp_client_check_server_clock_dispersion(client_ptr);
3066
3067 /* Is the server clock variance acceptable? */
3068 if (status != NX_SUCCESS)
3069 {
3070
3071 /* Return the error status. */
3072 return status;
3073 }
3074 }
3075
3076 /* At this point we have received a valid server response. */
3077
3078 /* Clear the count of (consecutive) bad time updates received from this server. */
3079 client_ptr -> nx_sntp_client_invalid_time_updates = 0;
3080
3081 /* Apply server time to local device time. */
3082 status = _nx_sntp_client_process_time_data(client_ptr);
3083
3084 /* Check for error. */
3085 if (status != NX_SUCCESS)
3086 {
3087
3088 /* Return the error condition*/
3089 return status;
3090 }
3091
3092 /* If the Client is configured with a time update callback, call it now. */
3093 if (client_ptr -> nx_sntp_client_time_update_notify)
3094 {
3095
3096 client_ptr -> nx_sntp_client_time_update_notify(&(client_ptr -> nx_sntp_current_server_time_message),
3097 &(client_ptr -> nx_sntp_client_local_ntp_time));
3098 }
3099
3100 return status;
3101 }
3102
3103
3104 /**************************************************************************/
3105 /* */
3106 /* FUNCTION RELEASE */
3107 /* */
3108 /* _nx_sntp_client_duplicate_update_check PORTABLE C */
3109 /* 6.1 */
3110 /* AUTHOR */
3111 /* */
3112 /* Yuxin Zhou, Microsoft Corporation */
3113 /* */
3114 /* DESCRIPTION */
3115 /* */
3116 /* This function performs a comparison of time values between two */
3117 /* time messages to verify they are not duplicates. Duplicate updates */
3118 /* can be a form of denial of service/clogging attack on a host. */
3119 /* */
3120 /* INPUT */
3121 /* */
3122 /* timeA_msg_ptr Pointer to first time update */
3123 /* timeB_msg_ptr Pointer to second time update */
3124 /* is_a_dupe Result of comparison */
3125 /* */
3126 /* OUTPUT */
3127 /* */
3128 /* NX_SUCCESS Successful completion status */
3129 /* */
3130 /* CALLS */
3131 /* */
3132 /* memcmp Copy data to area of memory */
3133 /* */
3134 /* CALLED BY */
3135 /* */
3136 /* _nx_sntp_client_apply_sanity_checks Verify received SNTP data */
3137 /* */
3138 /* RELEASE HISTORY */
3139 /* */
3140 /* DATE NAME DESCRIPTION */
3141 /* */
3142 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3143 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3144 /* resulting in version 6.1 */
3145 /* */
3146 /**************************************************************************/
_nx_sntp_client_duplicate_update_check(NX_SNTP_TIME_MESSAGE * timeA_msg_ptr,NX_SNTP_TIME_MESSAGE * timeB_msg_ptr,UINT * is_a_dupe)3147 UINT _nx_sntp_client_duplicate_update_check(NX_SNTP_TIME_MESSAGE *timeA_msg_ptr,
3148 NX_SNTP_TIME_MESSAGE *timeB_msg_ptr,
3149 UINT *is_a_dupe)
3150 {
3151
3152 *is_a_dupe = NX_FALSE;
3153
3154 if ( (!memcmp(timeA_msg_ptr -> transmit_time_stamp,
3155 timeB_msg_ptr -> transmit_time_stamp, 8)) &&
3156 (!memcmp(timeA_msg_ptr -> receive_time_stamp,
3157 timeB_msg_ptr -> receive_time_stamp, 8)) &&
3158 (!memcmp(timeA_msg_ptr -> originate_time_stamp,
3159 timeB_msg_ptr -> originate_time_stamp, 8)) &&
3160 (!memcmp(timeA_msg_ptr -> reference_clock_update_time_stamp,
3161 timeB_msg_ptr -> reference_clock_update_time_stamp, 8)) &&
3162 (!memcmp(timeA_msg_ptr -> reference_clock_id,
3163 timeB_msg_ptr -> reference_clock_id, 4)) &&
3164 (timeA_msg_ptr -> root_delay == timeB_msg_ptr -> root_delay) &&
3165 (timeA_msg_ptr -> clock_dispersion == timeB_msg_ptr -> clock_dispersion)
3166 )
3167 {
3168
3169 *is_a_dupe = NX_TRUE;
3170 }
3171
3172 return NX_SUCCESS;
3173 }
3174
3175
3176 /**************************************************************************/
3177 /* */
3178 /* FUNCTION RELEASE */
3179 /* */
3180 /* _nx_sntp_client_apply_sanity_checks PORTABLE C */
3181 /* 6.1 */
3182 /* AUTHOR */
3183 /* */
3184 /* Yuxin Zhou, Microsoft Corporation */
3185 /* */
3186 /* DESCRIPTION */
3187 /* */
3188 /* This function checks for invalid SNTP data received from server. */
3189 /* */
3190 /* INPUT */
3191 /* */
3192 /* client_ptr Pointer to Client */
3193 /* */
3194 /* OUTPUT */
3195 /* */
3196 /* NX_SNTP_DUPE_SERVER_PACKET Duplicate server packet received */
3197 /* NX_SNTP_INVALID_SERVER_MODE Server mode won't work with Client */
3198 /* NX_SNTP_INVALID_NTP_VERSION Server NTP version won't work with */
3199 /* Client NTP version. */
3200 /* NX_SNTP_SERVER_CLOCK_NOT_SYNC Server is not ready to send updates*/
3201 /* NX_SNTP_INVALID_SERVER_STRATUM Server stratum not acceptable */
3202 /* NX_SNTP_NULL_SERVER_TIMESTAMP Invalid or NULL timestamp in update*/
3203 /* status Actual completion status */
3204 /* */
3205 /* CALLS */
3206 /* */
3207 /* memcmp Copy data into area of memory */
3208 /* _nx_sntp_client_duplicate_update_check */
3209 /* Check for duplicate updates service*/
3210 /* _nx_sntp_client_utility_get_msec_diff */
3211 /* Check for time difference in msecs */
3212 /* */
3213 /* CALLED BY */
3214 /* */
3215 /* _nx_sntp_client_run_broadcast Receive broadcast SNTP updates */
3216 /* _nx_sntp_client_run_unicast Send and receive SNTP updates */
3217 /* */
3218 /* RELEASE HISTORY */
3219 /* */
3220 /* DATE NAME DESCRIPTION */
3221 /* */
3222 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3223 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3224 /* resulting in version 6.1 */
3225 /* */
3226 /**************************************************************************/
_nx_sntp_client_apply_sanity_checks(NX_SNTP_CLIENT * client_ptr)3227 UINT _nx_sntp_client_apply_sanity_checks(NX_SNTP_CLIENT *client_ptr)
3228 {
3229
3230
3231 UINT status;
3232 UINT mode;
3233 UINT leap_second_indicator;
3234 UINT server_ntp_version;
3235 UINT is_a_dupe_check;
3236 ULONG msecs;
3237 NX_SNTP_TIME_MESSAGE *server_time_msg_ptr;
3238
3239 server_time_msg_ptr = &(client_ptr -> nx_sntp_current_server_time_message);
3240
3241 /* Was a previous response received from the server? */
3242 if (client_ptr -> nx_sntp_previous_server_time_message.flags)
3243 {
3244
3245 /* Yes; perform a duplicate packet check. */
3246 status = _nx_sntp_client_duplicate_update_check(&(client_ptr -> nx_sntp_current_server_time_message),
3247 &(client_ptr -> nx_sntp_previous_server_time_message),
3248 &is_a_dupe_check);
3249 /* Check for error. */
3250 if (status != NX_SUCCESS)
3251 {
3252
3253 /* Return error status. */
3254 return status;
3255 }
3256
3257 /* Is this a duplicate packet (e.g. possible 'clogging' attack)? */
3258 if (is_a_dupe_check)
3259 {
3260
3261 return NX_SNTP_DUPE_SERVER_PACKET;
3262 }
3263 }
3264
3265 /* Get the association type from the server. */
3266 mode = server_time_msg_ptr ->flags & 0x07;
3267
3268 /* Is the server of the correct association for a unicast client? */
3269 if ((mode != PROTOCOL_MODE_SERVER_UNICAST) && (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE))
3270 {
3271
3272 /* Return error status. */
3273 return NX_SNTP_INVALID_SERVER_MODE;
3274 }
3275 /* Is the server of the correct association for a broadcast client? */
3276 else if ((mode != PROTOCOL_MODE_SERVER_BROADCAST) && (client_ptr -> nx_sntp_client_protocol_mode == BROADCAST_MODE))
3277 {
3278
3279 /* Return error status. */
3280 return NX_SNTP_INVALID_SERVER_MODE;
3281 }
3282
3283 /* Extract server's NTP version from the flags field. */
3284 server_ntp_version = (server_time_msg_ptr -> flags & 0x38) >> 3;
3285
3286 /* As per NTP protocol, check if the server reply has the same SNTP version that
3287 the Client sent in its unicast request. */
3288 if ((server_ntp_version != NX_SNTP_CLIENT_NTP_VERSION) && (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE))
3289 {
3290
3291 /* Return the error condition. */
3292 return NX_SNTP_INVALID_NTP_VERSION;
3293 }
3294 /* If broadcast, verify the server SNTP version is compatible with the Client. */
3295 else if ((server_ntp_version < NX_SNTP_CLIENT_MIN_NTP_VERSION) && (client_ptr -> nx_sntp_client_protocol_mode == BROADCAST_MODE))
3296 {
3297
3298 /* Return the error condition. */
3299 return NX_SNTP_INVALID_NTP_VERSION;
3300 }
3301
3302 /* Get the leap second indicator from the flags field. */
3303 leap_second_indicator = (server_time_msg_ptr -> flags & 0xC0) >> 6;
3304
3305 /* Is the server clock not yet synchronized? */
3306 if (leap_second_indicator == 3)
3307 {
3308 /* Return the error condition. */
3309 return NX_SNTP_SERVER_CLOCK_NOT_SYNC;
3310 }
3311
3312 /* Has the server sent a 'kiss of death' (stratum = 0) packet? */
3313 if (server_time_msg_ptr -> peer_clock_stratum == 0)
3314 {
3315
3316 /* Does the Client have a kiss of death handler? */
3317 if (client_ptr -> kiss_of_death_handler)
3318 {
3319 UINT code_id;
3320
3321 /* Convert the message to code.*/
3322 _nx_sntp_client_utility_convert_refID_KOD_code(server_time_msg_ptr -> reference_clock_id, &code_id);
3323
3324 /* Yes, let the handler deal with this server response. */
3325 status = (client_ptr -> kiss_of_death_handler)(client_ptr, code_id);
3326
3327 /* Is it ok to continue with this server? */
3328 if (status != NX_SUCCESS)
3329 {
3330
3331 /* No, it is not. Return the error condition. */
3332 return status;
3333 }
3334 }
3335 else
3336 {
3337 /* It is not ok to continue. Return the error condition. */
3338 return NX_SNTP_KOD_SERVER_NOT_AVAILABLE;
3339 }
3340 }
3341
3342 /* Is the server stratum a valid stratum ? */
3343 else if (server_time_msg_ptr -> peer_clock_stratum & STRATUM_RESERVED)
3344 {
3345
3346 /* Return error status. */
3347 return NX_SNTP_INVALID_SERVER_STRATUM;
3348
3349 }
3350 /* Does the server stratum acceptable to the Client? */
3351 else if (server_time_msg_ptr -> peer_clock_stratum > NX_SNTP_CLIENT_MIN_SERVER_STRATUM)
3352 {
3353
3354 /* Return error status. */
3355 return NX_SNTP_INVALID_SERVER_STRATUM;
3356 }
3357
3358 /* Is the Client operating in unicast mode? */
3359 if (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE)
3360 {
3361 UINT pos_diff = NX_TRUE;
3362
3363 /* Yes; Are any server time stamps NULL? */
3364
3365 /* Special case: the client has not set its local time. Only check server's receive and transmit time. */
3366 if (client_ptr -> nx_sntp_client_local_ntp_time.seconds == 0)
3367 {
3368 if ((_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> receive_time_stamp), 8) == NX_TRUE) ||
3369 (_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> transmit_time_stamp), 8) == NX_TRUE))
3370 {
3371
3372 /* Return error status. */
3373 return NX_SNTP_INVALID_TIMESTAMP;
3374 }
3375
3376 }
3377 else
3378 {
3379 /* Check all server time stamps to be non null. */
3380 if ((_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> originate_time_stamp), 8) == NX_TRUE) ||
3381 (_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> receive_time_stamp), 8) == NX_TRUE) ||
3382 (_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> transmit_time_stamp), 8) == NX_TRUE))
3383 {
3384
3385 /* Return error status. */
3386 return NX_SNTP_INVALID_TIMESTAMP;
3387 }
3388
3389 }
3390
3391 /* Get the time difference server transmit time - server receive time. */
3392 status = _nx_sntp_client_utility_get_msec_diff(&(server_time_msg_ptr -> receive_time),
3393 &(server_time_msg_ptr -> transmit_time),
3394 &msecs, &pos_diff);
3395
3396 /* Is the server transmit time <= server receive time [physically not possible]? */
3397 if (status != NX_SUCCESS)
3398 {
3399
3400 /* Yes; Return the error condition. */
3401 return status;
3402 }
3403 else if (pos_diff == NX_FALSE)
3404 {
3405
3406 /* treat as an error in this case. */
3407 return NX_SNTP_INVALID_TIMESTAMP;
3408 }
3409 }
3410 /* Client is in broadcast mode. */
3411 else
3412 {
3413
3414 /* Is the broadcast server transmit time stamp is NULL? */
3415 if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> transmit_time_stamp), 8) == NX_TRUE)
3416
3417 {
3418
3419 /* Return the error status. */
3420 return NX_SNTP_INVALID_TIMESTAMP;
3421 }
3422 }
3423
3424 /* Is there an impending leap second adjustment? */
3425 if ((leap_second_indicator == 1) || (leap_second_indicator == 2))
3426 {
3427
3428 /* Does the Client have a leap second handler?*/
3429 if (client_ptr -> leap_second_handler)
3430 {
3431
3432 /* Yes, invoke the leap second handler for impending leap second event. */
3433 (client_ptr -> leap_second_handler)(client_ptr, leap_second_indicator);
3434 }
3435 }
3436
3437 /* Return successful completion status. */
3438 return NX_SUCCESS;
3439 }
3440
3441
3442 /**************************************************************************/
3443 /* */
3444 /* FUNCTION RELEASE */
3445 /* */
3446 /* _nx_sntp_client_check_server_clock_dispersion PORTABLE C */
3447 /* 6.1 */
3448 /* AUTHOR */
3449 /* */
3450 /* Yuxin Zhou, Microsoft Corporation */
3451 /* */
3452 /* DESCRIPTION */
3453 /* */
3454 /* This function checks server clock dispersion extracted from server */
3455 /* time message in 32 bit representation: */
3456 /* sum of 1/(2 ^ bit) of bits 16-31 in the time message format */
3457 /* and compares it against the Client's dispersion tolerance. */
3458 /* */
3459 /* If NX_SNTP_CLIENT_MAX_ROOT_DISPERSION is set to zero, the function */
3460 /* simply returns a successful result but does no calculations. */
3461 /* */
3462 /* INPUT */
3463 /* */
3464 /* client_ptr Pointer to Client */
3465 /* */
3466 /* OUTPUT */
3467 /* */
3468 /* NX_SUCCESS dispersion is acceptable */
3469 /* NX_SNTP_BAD_SERVER_ROOT_DISPERSION dispersion is too large */
3470 /* */
3471 /* CALLS */
3472 /* */
3473 /* None */
3474 /* */
3475 /* CALLED BY */
3476 /* */
3477 /* _nx_sntp_client_process_update_packet */
3478 /* Process time data in update packets */
3479 /* */
3480 /* RELEASE HISTORY */
3481 /* */
3482 /* DATE NAME DESCRIPTION */
3483 /* */
3484 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3485 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3486 /* resulting in version 6.1 */
3487 /* */
3488 /**************************************************************************/
3489
_nx_sntp_client_check_server_clock_dispersion(NX_SNTP_CLIENT * client_ptr)3490 UINT _nx_sntp_client_check_server_clock_dispersion(NX_SNTP_CLIENT *client_ptr)
3491 {
3492
3493 #if (NX_SNTP_CLIENT_MAX_ROOT_DISPERSION != 0)
3494 UINT mask = 0x8000;
3495 UINT bit = 1;
3496 ULONG divisor;
3497 ULONG dispersion_usecs;
3498
3499 /* Check for zero clock dispersion reported in server update. */
3500 if (client_ptr -> nx_sntp_current_server_time_message.clock_dispersion == 0)
3501 {
3502
3503 /* Return successful status. */
3504 return NX_SUCCESS;
3505 }
3506
3507 /* Get the most significant 16 bits of dispersion field and convert to microseconds.*/
3508 dispersion_usecs = (client_ptr -> nx_sntp_current_server_time_message.clock_dispersion >> 16) * 1000000;
3509
3510 /* Compare seconds in the most significant 16 bits against the Client dispersion tolerance. */
3511 if (dispersion_usecs > NX_SNTP_CLIENT_MAX_ROOT_DISPERSION)
3512 {
3513
3514 /* Yes, indicate that server clock dispersion exceeds tolerance. */
3515 return NX_SNTP_BAD_SERVER_ROOT_DISPERSION;
3516 }
3517
3518 /* Compare fraction from least significant 16 bits; sum of (1 / 2 ^ bit field) of lower 16 bits. */
3519
3520 /* Get the lower 16 bits. */
3521 client_ptr -> nx_sntp_current_server_time_message.clock_dispersion =
3522 client_ptr -> nx_sntp_current_server_time_message.clock_dispersion & 0xFFFF;
3523
3524 /* Compute the dispersion. */
3525 while(mask)
3526 {
3527 if (mask & client_ptr -> nx_sntp_current_server_time_message.clock_dispersion)
3528 {
3529 divisor = (ULONG)(1 << bit);
3530 if ((divisor < 1000000) && (divisor > 0))
3531 {
3532 dispersion_usecs += 1000000/divisor;
3533 }
3534 }
3535 bit++;
3536 mask >>= 1;
3537 }
3538
3539 /* Is the computed clock dispersion more than the max tolerance? */
3540 if (dispersion_usecs > NX_SNTP_CLIENT_MAX_ROOT_DISPERSION)
3541 {
3542 /* Yes, indicate that server clock dispersion exceeds tolerance. */
3543 return NX_SNTP_BAD_SERVER_ROOT_DISPERSION;
3544 }
3545 #else
3546 NX_PARAMETER_NOT_USED(client_ptr);
3547 #endif /* (NX_SNTP_CLIENT_MAX_ROOT_DISPERSION != 0) */
3548
3549 /* Return successful computation. */
3550 return NX_SUCCESS;
3551 }
3552
3553
3554 /**************************************************************************/
3555 /* */
3556 /* FUNCTION RELEASE */
3557 /* */
3558 /* _nx_sntp_client_thread_entry PORTABLE C */
3559 /* 6.1 */
3560 /* AUTHOR */
3561 /* */
3562 /* Yuxin Zhou, Microsoft Corporation */
3563 /* */
3564 /* DESCRIPTION */
3565 /* */
3566 /* This function is the processing thread for the SNTP Client. It */
3567 /* executes periodic SNTP tasks with SNTP Client mutex protection, then*/
3568 /* briefly sleeps to allow the host application to call SNTP Client */
3569 /* services. */
3570 /* */
3571 /* INPUT */
3572 /* */
3573 /* sntp_instance Pointer to SNTP instance */
3574 /* */
3575 /* OUTPUT */
3576 /* */
3577 /* None */
3578 /* */
3579 /* CALLS */
3580 /* */
3581 /* _nx_sntp_client_process Main SNTP processing function */
3582 /* tx_thread_sleep Sleep for specified time */
3583 /* tx_mutex_get Get the SNTP mutex */
3584 /* tx_mutex_put Release the SNTP mutex */
3585 /* tx_thread_preemption_change Change thread preemption */
3586 /* */
3587 /* CALLED BY */
3588 /* */
3589 /* ThreadX */
3590 /* */
3591 /* RELEASE HISTORY */
3592 /* */
3593 /* DATE NAME DESCRIPTION */
3594 /* */
3595 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3596 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3597 /* resulting in version 6.1 */
3598 /* */
3599 /**************************************************************************/
_nx_sntp_client_thread_entry(ULONG sntp_instance)3600 VOID _nx_sntp_client_thread_entry(ULONG sntp_instance)
3601 {
3602
3603 NX_SNTP_CLIENT *client_ptr;
3604 UINT status;
3605 UINT current_preemption;
3606
3607
3608 /* Setup the SNTP pointer. */
3609 client_ptr = (NX_SNTP_CLIENT *) sntp_instance;
3610
3611 /* Enter while loop. */
3612 do
3613 {
3614
3615 /* Loop for obtaining the SNTP mutex. */
3616 do
3617 {
3618
3619 /* Get the SNTP mutex. */
3620 status = tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER);
3621
3622 } while (status != TX_SUCCESS);
3623
3624 /* Perform periodic tasks for the SNTP Client. */
3625 _nx_sntp_client_process(client_ptr);
3626
3627 /* Release the SNTP mutex. */
3628 tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex));
3629
3630 /* Disable preemption for critical section. */
3631 tx_thread_preemption_change(tx_thread_identify(), 0, ¤t_preemption);
3632
3633 /* Indicate the SNTP Client process is idle. */
3634 client_ptr -> nx_sntp_client_sleep_flag = NX_TRUE;
3635
3636 /* Sleep for timer interval. */
3637 tx_thread_sleep(NX_SNTP_CLIENT_SLEEP_INTERVAL);
3638
3639 /* Clear flag to indicate SNTP thread is not in a position to be stopped. */
3640 client_ptr -> nx_sntp_client_sleep_flag = NX_FALSE;
3641
3642 /* Restore original preemption. */
3643 tx_thread_preemption_change(tx_thread_identify(), current_preemption, ¤t_preemption);
3644
3645
3646 } while (1);
3647 }
3648
3649
3650 /**************************************************************************/
3651 /* */
3652 /* FUNCTION RELEASE */
3653 /* */
3654 /* _nx_sntp_client_receive_notify PORTABLE C */
3655 /* 6.1 */
3656 /* AUTHOR */
3657 /* */
3658 /* Yuxin Zhou, Microsoft Corporation */
3659 /* */
3660 /* DESCRIPTION */
3661 /* */
3662 /* This function sets the socket receive callback for the SNTP Client */
3663 /* UDP socket. It sets a flag for the SNTP Client thread to know there*/
3664 /* is a packet waiting to be processed. */
3665 /* */
3666 /* INPUT */
3667 /* */
3668 /* socket_ptr Pointer to Client UDP socket */
3669 /* */
3670 /* OUTPUT */
3671 /* */
3672 /* None */
3673 /* */
3674 /* CALLS */
3675 /* */
3676 /* tx_event_flags_set Sets a receive event */
3677 /* */
3678 /* CALLED BY */
3679 /* */
3680 /* ThreadX */
3681 /* */
3682 /* RELEASE HISTORY */
3683 /* */
3684 /* DATE NAME DESCRIPTION */
3685 /* */
3686 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3687 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3688 /* resulting in version 6.1 */
3689 /* */
3690 /**************************************************************************/
_nx_sntp_client_receive_notify(NX_UDP_SOCKET * socket_ptr)3691 VOID _nx_sntp_client_receive_notify(NX_UDP_SOCKET *socket_ptr)
3692 {
3693 NX_PARAMETER_NOT_USED(socket_ptr);
3694
3695 /* Wakeup all threads that are attempting to perform a receive or that had their select satisfied. */
3696 tx_event_flags_set(&nx_sntp_client_events, NX_SNTP_CLIENT_RECEIVE_EVENT, TX_OR);
3697
3698 receive_timerticks = tx_time_get();
3699
3700 return;
3701 }
3702
3703
3704 /**************************************************************************/
3705 /* */
3706 /* FUNCTION RELEASE */
3707 /* */
3708 /* _nx_sntp_client_process PORTABLE C */
3709 /* 6.1 */
3710 /* AUTHOR */
3711 /* */
3712 /* Yuxin Zhou, Microsoft Corporation */
3713 /* */
3714 /* DESCRIPTION */
3715 /* */
3716 /* This function is called periodically by the SNTP client thread, and */
3717 /* depending on the CLient mode (unicast or broadcast) calls the */
3718 /* unicast or broadcast process function. */
3719 /* */
3720 /* INPUT */
3721 /* */
3722 /* client_ptr Pointer to the SNTP client */
3723 /* */
3724 /* OUTPUT */
3725 /* */
3726 /* None */
3727 /* */
3728 /* CALLS */
3729 /* */
3730 /* _nx_sntp_client_process_unicast Process unicast tasks */
3731 /* _nx_sntp_client_process_broadcast Process broadcast tasks */
3732 /* */
3733 /* CALLED BY */
3734 /* */
3735 /* ThreadX */
3736 /* */
3737 /* RELEASE HISTORY */
3738 /* */
3739 /* DATE NAME DESCRIPTION */
3740 /* */
3741 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3742 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3743 /* resulting in version 6.1 */
3744 /* */
3745 /**************************************************************************/
_nx_sntp_client_process(NX_SNTP_CLIENT * client_ptr)3746 VOID _nx_sntp_client_process(NX_SNTP_CLIENT *client_ptr)
3747 {
3748
3749
3750 /* Is the client using unicast or unicast to receive updates? */
3751 if (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE)
3752 {
3753 /* Call the unicast process function. */
3754 _nx_sntp_client_process_unicast(client_ptr);
3755 }
3756 else
3757 {
3758
3759 /* Call the broadcast process function. */
3760 _nx_sntp_client_process_broadcast(client_ptr);
3761 }
3762
3763 return;
3764 }
3765
3766
3767 /**************************************************************************/
3768 /* */
3769 /* FUNCTION RELEASE */
3770 /* */
3771 /* _nx_sntp_client_process_time_data PORTABLE C */
3772 /* 6.1 */
3773 /* AUTHOR */
3774 /* */
3775 /* Yuxin Zhou, Microsoft Corporation */
3776 /* */
3777 /* DESCRIPTION */
3778 /* */
3779 /* This function applies the server time data to client local time taking*/
3780 /* into account the round trip time. Time updates are checked for a max */
3781 /* time offset set by the Client max_time_adjustment parameter. */
3782 /* */
3783 /* INPUT */
3784 /* */
3785 /* client_ptr Pointer to Client */
3786 /* */
3787 /* OUTPUT */
3788 /* */
3789 /* NX_SUCCESS Successful completion status */
3790 /* NX_SNTP_INVALID_SERVER_UPDATE_TIME No time of server update recorded*/
3791 /* status Actual completion status */
3792 /* */
3793 /* CALLS */
3794 /* */
3795 /* memset Clear specified area of memory */
3796 /* memcpy Copy data to area of memory */
3797 /* _nx_sntp_client_utility_add_msecs_to_ntp_time */
3798 /* Add msec to NTP time fraction field*/
3799 /* _nx_sntp_client_utility_get_msec_diff */
3800 /* Compute time difference in msecs */
3801 /* _nx_sntp_client_utility_add_msecs_to_ntp_time */
3802 /* Add time in msecs to an NTP time */
3803 /* */
3804 /* CALLED BY */
3805 /* */
3806 /* _nx_sntp_client_run_broadcast Listen and process broadcast updates*/
3807 /* _nx_sntp_client_process_update_packet */
3808 /* Process update SNTP packets */
3809 /* */
3810 /* RELEASE HISTORY */
3811 /* */
3812 /* DATE NAME DESCRIPTION */
3813 /* */
3814 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3815 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
3816 /* verified memcpy use cases, */
3817 /* resulting in version 6.1 */
3818 /* */
3819 /**************************************************************************/
_nx_sntp_client_process_time_data(NX_SNTP_CLIENT * client_ptr)3820 UINT _nx_sntp_client_process_time_data(NX_SNTP_CLIENT *client_ptr)
3821 {
3822
3823 UINT status;
3824 UINT ignore_max_adjustment_limit;
3825 ULONG elapsed_msecs_difference;
3826 UINT adjustment;
3827 NX_SNTP_TIME local_time;
3828
3829
3830 /* Copy the received time update to the update time just received from the server. */
3831 memcpy(&client_ptr -> nx_sntp_server_update_time, &client_ptr -> nx_sntp_current_server_time_message.transmit_time, sizeof(NX_SNTP_TIME)); /* Use case of memcpy is verified. */
3832
3833 /* Check if the client is configured for round trip time calculation. */
3834 if (NX_SNTP_CLIENT_RTT_REQUIRED == NX_TRUE)
3835 {
3836
3837 /* Compute roundtrip delay. */
3838 _nx_sntp_client_calculate_roundtrip(&(client_ptr -> nx_sntp_client_roundtrip_time_msec));
3839
3840 /* Has the client computed a valid round trip time? */
3841 if (client_ptr -> nx_sntp_client_roundtrip_time_msec)
3842 {
3843
3844 /* Yes, Add 1/2 round trip to server's reported time. */
3845 status =_nx_sntp_client_utility_add_msecs_to_ntp_time(&(client_ptr -> nx_sntp_current_server_time_message.transmit_time),
3846 ((client_ptr -> nx_sntp_client_roundtrip_time_msec) / 2));
3847
3848 if (status != NX_SUCCESS)
3849 {
3850
3851 /* Cannot use this time update. */
3852 return status;
3853 }
3854 }
3855 }
3856
3857 /* Is this the first update? */
3858 if (client_ptr -> nx_sntp_client_first_update_pending == NX_TRUE)
3859 {
3860 /* Check Client configuration if we ignore max adjustment limit on first update. */
3861 ignore_max_adjustment_limit = NX_SNTP_CLIENT_IGNORE_MAX_ADJUST_STARTUP;
3862 }
3863 else
3864 ignore_max_adjustment_limit = NX_FALSE;
3865
3866 /* If not ignoring the max adjustment, deal with time difference between client and server. */
3867 if (ignore_max_adjustment_limit == NX_FALSE)
3868 {
3869 UINT pos_diff = NX_TRUE;
3870
3871 /* Compute difference of server update packet minus the client's local time. It is reasonable
3872 to assume that the Client time is 'behind' the server time because it is updated by the
3873 server time. */
3874 local_time.seconds = client_ptr -> nx_sntp_client_local_ntp_time.seconds +
3875 client_ptr -> nx_sntp_client_local_ntp_time_elapsed;
3876 local_time.fraction = client_ptr -> nx_sntp_client_local_ntp_time.fraction;
3877 status = _nx_sntp_client_utility_get_msec_diff(&local_time,
3878 &(client_ptr -> nx_sntp_server_update_time),
3879 &elapsed_msecs_difference, &pos_diff);
3880
3881
3882 /* Note that a positive difference vs negative difference is not an error. */
3883 if (status != NX_SUCCESS)
3884 {
3885
3886 /* Cannot use this time update. */
3887 return status;
3888 }
3889
3890 /* Is the difference less than the client's minimum adjustment? */
3891 if (elapsed_msecs_difference > NX_SNTP_CLIENT_MIN_TIME_ADJUSTMENT)
3892 {
3893
3894 /* The adjustment is larger than the Client's minimum adjustment. */
3895
3896 /* Set the local clock to the server time only if 1)we are ignoring the maximum adjustment on startup,
3897 or 2) the difference is within the Client's max time adjustment. */
3898 if (elapsed_msecs_difference > NX_SNTP_CLIENT_MAX_TIME_ADJUSTMENT)
3899 {
3900 /* Cannot use this time update. */
3901 return NX_SNTP_INVALID_TIME;
3902 }
3903 }
3904 }
3905
3906 /* Ok to update client local time. */
3907 memcpy(&client_ptr -> nx_sntp_client_local_ntp_time, &client_ptr -> nx_sntp_current_server_time_message.transmit_time, sizeof(NX_SNTP_TIME)); /* Use case of memcpy is verified. */
3908 client_ptr -> nx_sntp_client_local_ntp_time_elapsed = 0;
3909
3910 /* Apply a correction to server's time for internal SNTP Client delays e.g. periodic task intervals. */
3911 adjustment = ((process_timerticks - receive_timerticks) * 1000) / NX_IP_PERIODIC_RATE;
3912
3913 status = _nx_sntp_client_utility_add_msecs_to_ntp_time(&(client_ptr -> nx_sntp_client_local_ntp_time), (LONG)adjustment);
3914
3915 /* Done processing time update. */
3916 return status;
3917 }
3918
3919
3920 /**************************************************************************/
3921 /* */
3922 /* FUNCTION RELEASE */
3923 /* */
3924 /* _nx_sntp_client_calculate_roundtrip PORTABLE C */
3925 /* 6.1 */
3926 /* AUTHOR */
3927 /* */
3928 /* Yuxin Zhou, Microsoft Corporation */
3929 /* */
3930 /* DESCRIPTION */
3931 /* */
3932 /* This function computes roundtrip based on the elapsed time from */
3933 /* sending the unicast request to receiving the SNTP response. */
3934 /* */
3935 /* INPUT */
3936 /* */
3937 /* roundtrip_time round trip time computation */
3938 /* */
3939 /* OUTPUT */
3940 /* */
3941 /* NX_SUCCESS Valid time computations result */
3942 /* */
3943 /* CALLS */
3944 /* */
3945 /* None */
3946 /* */
3947 /* CALLED BY */
3948 /* */
3949 /* _nx_sntp_client_process_update_packet */
3950 /* Process server update packet */
3951 /* */
3952 /* RELEASE HISTORY */
3953 /* */
3954 /* DATE NAME DESCRIPTION */
3955 /* */
3956 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3957 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3958 /* resulting in version 6.1 */
3959 /* */
3960 /**************************************************************************/
_nx_sntp_client_calculate_roundtrip(LONG * roundtrip_time)3961 UINT _nx_sntp_client_calculate_roundtrip(LONG *roundtrip_time)
3962 {
3963
3964 ULONG x;
3965
3966
3967 /* Initialize invalid results. */
3968 *roundtrip_time = 0;
3969
3970 /* Compute the roundtrip as the time the packet left the SNTP Client
3971 to the time it received a response from the SNTP server. */
3972
3973 /* Check for wrapped timer value. */
3974 if (send_timerticks > receive_timerticks)
3975 {
3976 /* The time has wrapped. */
3977 x = 0xFFFFFFFF - send_timerticks;
3978 *roundtrip_time = (LONG)(receive_timerticks + x);
3979 }
3980 else
3981 {
3982 *roundtrip_time = (LONG)(receive_timerticks - send_timerticks);
3983 }
3984
3985 /* Convert to milliseconds. */
3986 *roundtrip_time = (LONG)((ULONG)(*roundtrip_time) * NX_SNTP_MILLISECONDS_PER_TICK);
3987
3988 /* Return successful completion. */
3989 return NX_SUCCESS;
3990 }
3991
3992
3993 /**************************************************************************/
3994 /* */
3995 /* FUNCTION RELEASE */
3996 /* */
3997 /* _nxe_sntp_client_get_local_time PORTABLE C */
3998 /* 6.1 */
3999 /* AUTHOR */
4000 /* */
4001 /* Yuxin Zhou, Microsoft Corporation */
4002 /* */
4003 /* DESCRIPTION */
4004 /* */
4005 /* This function performs error checking for the get local time service.*/
4006 /* */
4007 /* INPUT */
4008 /* */
4009 /* client_ptr Pointer to SNTP Client */
4010 /* seconds Pointer to SNTP seconds */
4011 /* fraction Local time fraction component */
4012 /* buffer Pointer for time in string format */
4013 /* */
4014 /* OUTPUT */
4015 /* */
4016 /* status Completion status */
4017 /* */
4018 /* CALLS */
4019 /* */
4020 /* _nx_sntp_client_get_local_time Get local time service */
4021 /* */
4022 /* CALLED BY */
4023 /* */
4024 /* Application Code */
4025 /* */
4026 /* RELEASE HISTORY */
4027 /* */
4028 /* DATE NAME DESCRIPTION */
4029 /* */
4030 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4031 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4032 /* resulting in version 6.1 */
4033 /* */
4034 /**************************************************************************/
_nxe_sntp_client_get_local_time(NX_SNTP_CLIENT * client_ptr,ULONG * seconds,ULONG * fraction,CHAR * buffer)4035 UINT _nxe_sntp_client_get_local_time(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer)
4036 {
4037
4038 UINT status;
4039
4040
4041 /* Check input pointer parameters. */
4042 if ((client_ptr == NX_NULL) || (seconds == NX_NULL) || (fraction == NX_NULL))
4043 {
4044
4045 /* Return pointer error. */
4046 return NX_PTR_ERROR;
4047 }
4048
4049 /* Check if this function is called from the appropriate thread. */
4050 NX_THREADS_ONLY_CALLER_CHECKING
4051
4052 /* Call the actual service. */
4053 status = _nx_sntp_client_get_local_time(client_ptr, seconds, fraction, buffer);
4054
4055 /* Return completion status. */
4056 return status;
4057 }
4058
4059
4060 /**************************************************************************/
4061 /* */
4062 /* FUNCTION RELEASE */
4063 /* */
4064 /* _nx_sntp_client_get_local_time PORTABLE C */
4065 /* 6.1 */
4066 /* AUTHOR */
4067 /* */
4068 /* Yuxin Zhou, Microsoft Corporation */
4069 /* */
4070 /* DESCRIPTION */
4071 /* */
4072 /* This function retrieves the current SNTP Client local time and */
4073 /* returns the data in seconds and fractions, and if a non zero */
4074 /* buffer pointer is supplied, a string containing the data in ASCII. */
4075 /* */
4076 /* INPUT */
4077 /* */
4078 /* client_ptr Pointer to SNTP Client */
4079 /* seconds Pointer to SNTP seconds */
4080 /* fraction Local time fraction component */
4081 /* buffer Pointer for time in string format */
4082 /* */
4083 /* OUTPUT */
4084 /* */
4085 /* status Completion status */
4086 /* */
4087 /* CALLS */
4088 /* */
4089 /* _nx_utility_string_length_check Check string length */
4090 /* _nx_sntp_client_get_local_time_extended */
4091 /* Get local time service */
4092 /* */
4093 /* CALLED BY */
4094 /* */
4095 /* Application Code */
4096 /* */
4097 /* RELEASE HISTORY */
4098 /* */
4099 /* DATE NAME DESCRIPTION */
4100 /* */
4101 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4102 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4103 /* resulting in version 6.1 */
4104 /* */
4105 /**************************************************************************/
_nx_sntp_client_get_local_time(NX_SNTP_CLIENT * client_ptr,ULONG * seconds,ULONG * fraction,CHAR * buffer)4106 UINT _nx_sntp_client_get_local_time(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer)
4107 {
4108
4109 UINT status;
4110
4111 status = _nx_sntp_client_get_local_time_extended(client_ptr, seconds, fraction, buffer, NX_MAX_STRING_LENGTH);
4112
4113 return status;
4114 }
4115
4116 /**************************************************************************/
4117 /* */
4118 /* FUNCTION RELEASE */
4119 /* */
4120 /* _nxe_sntp_client_get_local_time_extended PORTABLE C */
4121 /* 6.1 */
4122 /* AUTHOR */
4123 /* */
4124 /* Yuxin Zhou, Microsoft Corporation */
4125 /* */
4126 /* DESCRIPTION */
4127 /* */
4128 /* This function performs error checking for the get extended local */
4129 /* time service. */
4130 /* */
4131 /* INPUT */
4132 /* */
4133 /* client_ptr Pointer to SNTP Client */
4134 /* seconds Pointer to SNTP seconds */
4135 /* fraction Local time fraction component */
4136 /* buffer Pointer for time in string format */
4137 /* buffer_size Size of buffer */
4138 /* */
4139 /* OUTPUT */
4140 /* */
4141 /* status Completion status */
4142 /* */
4143 /* CALLS */
4144 /* */
4145 /* _nx_sntp_client_get_local_time_extended */
4146 /* Get extended local time service */
4147 /* */
4148 /* CALLED BY */
4149 /* */
4150 /* Application Code */
4151 /* */
4152 /* RELEASE HISTORY */
4153 /* */
4154 /* DATE NAME DESCRIPTION */
4155 /* */
4156 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4157 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4158 /* resulting in version 6.1 */
4159 /* */
4160 /**************************************************************************/
_nxe_sntp_client_get_local_time_extended(NX_SNTP_CLIENT * client_ptr,ULONG * seconds,ULONG * fraction,CHAR * buffer,UINT buffer_size)4161 UINT _nxe_sntp_client_get_local_time_extended(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer, UINT buffer_size)
4162 {
4163
4164 UINT status;
4165
4166
4167 /* Check input pointer parameters. */
4168 if ((client_ptr == NX_NULL) || (seconds == NX_NULL) || (fraction == NX_NULL))
4169 {
4170
4171 /* Return pointer error. */
4172 return NX_PTR_ERROR;
4173 }
4174
4175 /* Check if this function is called from the appropriate thread. */
4176 NX_THREADS_ONLY_CALLER_CHECKING
4177
4178 /* Call the actual service. */
4179 status = _nx_sntp_client_get_local_time_extended(client_ptr, seconds, fraction, buffer, buffer_size);
4180
4181 /* Return completion status. */
4182 return status;
4183 }
4184
4185
4186 /**************************************************************************/
4187 /* */
4188 /* FUNCTION RELEASE */
4189 /* */
4190 /* _nx_sntp_client_get_local_time_extended PORTABLE C */
4191 /* 6.1.8 */
4192 /* AUTHOR */
4193 /* */
4194 /* Yuxin Zhou, Microsoft Corporation */
4195 /* */
4196 /* DESCRIPTION */
4197 /* */
4198 /* This function retrieves the current SNTP Client local time and */
4199 /* returns the data in seconds and fractions, and if a non zero */
4200 /* buffer pointer is supplied, a string containing the data in ASCII. */
4201 /* */
4202 /* INPUT */
4203 /* */
4204 /* client_ptr Pointer to SNTP Client */
4205 /* seconds Pointer to SNTP seconds */
4206 /* fraction Local time fraction component */
4207 /* buffer Pointer for time in string format */
4208 /* buffer_size Size of buffer */
4209 /* */
4210 /* OUTPUT */
4211 /* */
4212 /* status Completion status */
4213 /* */
4214 /* CALLS */
4215 /* */
4216 /* _nx_sntp_client_utility_fraction_to_usecs */
4217 /* Convert NTP fraction to usecs */
4218 /* _nx_utility_uint_to_string Converts number to ascii text */
4219 /* */
4220 /* CALLED BY */
4221 /* */
4222 /* Application Code */
4223 /* */
4224 /* RELEASE HISTORY */
4225 /* */
4226 /* DATE NAME DESCRIPTION */
4227 /* */
4228 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4229 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
4230 /* verified memmove use cases, */
4231 /* resulting in version 6.1 */
4232 /* 08-02-2021 Yuxin Zhou Modified comment(s), */
4233 /* improved the logic of */
4234 /* converting number to string,*/
4235 /* resulting in version 6.1.8 */
4236 /* */
4237 /**************************************************************************/
_nx_sntp_client_get_local_time_extended(NX_SNTP_CLIENT * client_ptr,ULONG * seconds,ULONG * fraction,CHAR * buffer,UINT buffer_size)4238 UINT _nx_sntp_client_get_local_time_extended(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer, UINT buffer_size)
4239 {
4240
4241 ULONG usecs;
4242 UINT offset = 0;
4243 UINT length = 0;
4244
4245 *seconds = client_ptr -> nx_sntp_client_local_ntp_time.seconds;
4246 *fraction = client_ptr -> nx_sntp_client_local_ntp_time.fraction;
4247
4248 if (buffer != NX_NULL)
4249 {
4250
4251 /* Convert SNTP fraction component into microseconds. */
4252 _nx_sntp_client_utility_fraction_to_usecs(client_ptr -> nx_sntp_client_local_ntp_time.fraction, &usecs);
4253
4254 /* Decrease length for terminal zero. */
4255 buffer_size--;
4256
4257 /* Create a string with just the time. */
4258 /* Format: "Time: %lu.%06lu sec.\r\n" */
4259 if (buffer_size < 6)
4260 {
4261 return(NX_SIZE_ERROR);
4262 }
4263 buffer[offset++] = 'T';
4264 buffer[offset++] = 'i';
4265 buffer[offset++] = 'm';
4266 buffer[offset++] = 'e';
4267 buffer[offset++] = ':';
4268 buffer[offset++] = ' ';
4269 length = _nx_utility_uint_to_string(client_ptr -> nx_sntp_client_local_ntp_time.seconds,
4270 10, &buffer[offset], buffer_size - offset);
4271 if (length == 0)
4272 {
4273 return(NX_SIZE_ERROR);
4274 }
4275 offset += length;
4276 if ((buffer_size - offset) < 14)
4277 {
4278 return(NX_SIZE_ERROR);
4279 }
4280 buffer[offset++] = '.';
4281 length = _nx_utility_uint_to_string(usecs, 10, &buffer[offset], buffer_size - offset);
4282 if (length == 0)
4283 {
4284 return(NX_SIZE_ERROR);
4285 }
4286
4287 if (length < 6)
4288 {
4289
4290 /* Append zeroes. */
4291 memmove(&buffer[offset + (6 - length)], &buffer[offset], length); /* Use case of memmove is verified. */
4292 memset(&buffer[offset], '0', (6 - length));
4293 }
4294
4295 offset += 6;
4296 buffer[offset++] = ' ';
4297 buffer[offset++] = 's';
4298 buffer[offset++] = 'e';
4299 buffer[offset++] = 'c';
4300 buffer[offset++] = '.';
4301 buffer[offset++] = '\r';
4302 buffer[offset++] = '\n';
4303 buffer[offset] = '\0';
4304 }
4305
4306 return NX_SUCCESS;
4307 }
4308
4309
4310 /**************************************************************************/
4311 /* */
4312 /* FUNCTION RELEASE */
4313 /* */
4314 /* _nx_sntp_client_utility_convert_time_to_UCHAR PORTABLE C */
4315 /* 6.1 */
4316 /* AUTHOR */
4317 /* */
4318 /* Yuxin Zhou, Microsoft Corporation */
4319 /* */
4320 /* DESCRIPTION */
4321 /* */
4322 /* This function converts time from the ULONG seconds and msecs in the */
4323 /* NX_SNTP_TIME data to the 32 bit UCHAR seconds and fraction fields in*/
4324 /* the NTP time message. The caller specifies which time stamp in the */
4325 /* NTP time message (transmit,receive, origination, or reference clock)*/
4326 /* and that field is converted over. */
4327 /* */
4328 /* INPUT */
4329 /* */
4330 /* time_ptr Pointer to NX_SNTP_TIME time */
4331 /* time_message_ptr Pointer to NTP (UCHAR) time */
4332 /* which_stamp Which time stamp to convert */
4333 /* */
4334 /* OUTPUT */
4335 /* */
4336 /* NX_SNTP_PARAM_ERROR Invalid time stamp requested */
4337 /* NX_SUCCESS Successful completion status */
4338 /* */
4339 /* CALLS */
4340 /* */
4341 /* memset Clear specified area of memory */
4342 /* */
4343 /* CALLED BY */
4344 /* */
4345 /* _nx_sntp_client_send_unicast_request */
4346 /* Create a time request and transmit it*/
4347 /* */
4348 /* RELEASE HISTORY */
4349 /* */
4350 /* DATE NAME DESCRIPTION */
4351 /* */
4352 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4353 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4354 /* resulting in version 6.1 */
4355 /* */
4356 /**************************************************************************/
_nx_sntp_client_utility_convert_time_to_UCHAR(NX_SNTP_TIME * time_ptr,NX_SNTP_TIME_MESSAGE * time_message_ptr,UINT which_stamp)4357 UINT _nx_sntp_client_utility_convert_time_to_UCHAR(NX_SNTP_TIME *time_ptr,
4358 NX_SNTP_TIME_MESSAGE *time_message_ptr, UINT which_stamp)
4359 {
4360
4361 ULONG *buffer;
4362
4363 /* Copy the buffer to the requested time stamp field. */
4364 switch (which_stamp)
4365 {
4366
4367 case REFERENCE_TIME:
4368 buffer = time_message_ptr -> reference_clock_update_time_stamp;
4369 break;
4370
4371 case ORIGINATE_TIME:
4372 buffer = time_message_ptr -> originate_time_stamp;
4373 break;
4374
4375 case RECEIVE_TIME:
4376 buffer = time_message_ptr -> receive_time_stamp;
4377 break;
4378
4379 case TRANSMIT_TIME:
4380 buffer = time_message_ptr -> transmit_time_stamp;
4381 break;
4382
4383 default:
4384 /* Invalid time stamp. Return as error. */
4385 return NX_SNTP_PARAM_ERROR;
4386 }
4387
4388 /* Copy NX_SNTP_TIME seconds and fraction to the buffer. */
4389 *(buffer) = time_ptr -> seconds;
4390 *(buffer + 1) = time_ptr -> fraction;
4391
4392 /* Return successful completion. */
4393 return NX_SUCCESS;
4394 }
4395
4396 /* The conventional civil timescale used in most parts of the world is based on Coordinated Universal Time (UTC),
4397 which replaced Greenwich Mean Time (GMT) many years ago. UTC is based on International Atomic Time (TAI),
4398 which is derived from hundreds of cesium oscillators in the national standards laboratories of many regions.
4399 Deviations of UTC from TAI are implemented in the form of leap seconds, which occur at intervals from a
4400 few months to serveral years. */
4401
4402
4403 /**************************************************************************/
4404 /* */
4405 /* FUNCTION RELEASE */
4406 /* */
4407 /* _nx_sntp_client_utility_convert_seconds_to_date PORTABLE C */
4408 /* 6.1 */
4409 /* AUTHOR */
4410 /* */
4411 /* Yuxin Zhou, Microsoft Corporation */
4412 /* */
4413 /* DESCRIPTION */
4414 /* */
4415 /* This function computes the month, day, and time in an NTP time based */
4416 /* on the known number of seconds at 1/1/1999 since 1/1/1900 (the NTP */
4417 /* time epoch) and the current NTP time. The caller must indicated the */
4418 /* year of the NTP time to convert to simplify the computation. The data*/
4419 /* is written to an NX_SNTP_DATE_TIME object from which the call can */
4420 /* extract date and time data, or call the NetX SNTP API to display the */
4421 /* data/time string. */
4422 /* */
4423 /* INPUT */
4424 /* */
4425 /* current_NTP_time_ptr Pointer to NTP time */
4426 /* current_year Year in the NTP time data */
4427 /* current_date_time_ptr Pointer to date time object */
4428 /* */
4429 /* OUTPUT */
4430 /* */
4431 /* NX_SUCCESS Successful completion status */
4432 /* NX_SNTP_ERROR_CONVERTING_DATETIME Internal error converting time */
4433 /* NX_SNTP_UNABLE_TO_CONVERT_DATETIME Insufficient data for converting */
4434 /* */
4435 /* CALLS */
4436 /* */
4437 /* _nx_sntp_client_utility_convert_fraction_to_msecs */
4438 /* Converts the 32 bit fraction field*/
4439 /* in an NTP time to milliseconds */
4440 /* */
4441 /* CALLED BY */
4442 /* */
4443 /* Application */
4444 /* */
4445 /* RELEASE HISTORY */
4446 /* */
4447 /* DATE NAME DESCRIPTION */
4448 /* */
4449 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4450 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
4451 /* fixed leap year calculation,*/
4452 /* resulting in version 6.1 */
4453 /* */
4454 /**************************************************************************/
_nx_sntp_client_utility_convert_seconds_to_date(NX_SNTP_TIME * current_NTP_time_ptr,UINT current_year,NX_SNTP_DATE_TIME * current_date_time_ptr)4455 UINT _nx_sntp_client_utility_convert_seconds_to_date(NX_SNTP_TIME *current_NTP_time_ptr, UINT current_year,
4456 NX_SNTP_DATE_TIME *current_date_time_ptr)
4457 {
4458
4459 /* Check if there is a base number of seconds set. */
4460 #if (NTP_SECONDS_AT_01011999 == 0)
4461
4462 /* No, so we cannot convert time into months and years. */
4463 return NX_SNTP_UNABLE_TO_CONVERT_DATETIME;
4464 #else
4465
4466 UINT seconds_diff;
4467 UINT years_diff;
4468 UINT leapyears_diff;
4469 UINT leaps;
4470 UINT seconds_of_year;
4471 UINT seconds_into_currentyear;
4472 UINT seconds_into_currentmonth;
4473 UINT seconds_into_currentday;
4474 UINT seconds_into_currenthour;
4475
4476 memset(current_date_time_ptr, 0, sizeof(NX_SNTP_DATE_TIME));
4477
4478 do
4479 {
4480
4481 current_date_time_ptr -> year = current_year;
4482
4483 seconds_diff = current_NTP_time_ptr -> seconds - NTP_SECONDS_AT_01011999;
4484
4485 years_diff = current_year - 1999;
4486
4487 /* Figure out number of leap years since 1999 not including the current year. */
4488 leapyears_diff = (current_year - 1 - 1996) >> 2;
4489
4490 /* Determine if this is a leap year. */
4491 leaps = (current_year - 1996) & 3;
4492
4493 /* Check if this is a leap year. */
4494 if (leaps == 0 )
4495 {
4496 /* It is! */
4497 current_date_time_ptr -> leap_year = NX_TRUE;
4498 seconds_of_year = SECONDS_PER_LEAPYEAR;
4499 }
4500 else
4501 {
4502
4503 /* Not a leap year. Clear the leap year flag. */
4504 current_date_time_ptr -> leap_year = NX_FALSE;
4505 seconds_of_year = SECONDS_PER_NONLEAPYEAR;
4506 }
4507
4508 /* Compute number of seconds into the current year e.g. as of 01/01 at midnite by subtracting
4509 the total number of seconds since 1/1/1999 up to the end of the previous year. Remember to compute
4510 the leapyear seconds at a different rate. */
4511 seconds_into_currentyear = seconds_diff - ((years_diff - leapyears_diff) * SECONDS_PER_NONLEAPYEAR)
4512 - (leapyears_diff * SECONDS_PER_LEAPYEAR);
4513
4514 current_year++;
4515
4516 }while(seconds_into_currentyear > seconds_of_year);
4517
4518 /* Initialize month to January till we find out what the month is. */
4519 current_date_time_ptr -> month = JANUARY;
4520
4521 while (1)
4522 {
4523
4524 /* Does the number of seconds goes past January? */
4525 if (seconds_into_currentyear >= SEC_IN_JAN)
4526 {
4527
4528 /* Yes, reset month to Feb and subtract seconds in January. */
4529 current_date_time_ptr -> month = FEBRUARY;
4530 seconds_into_currentyear -= SEC_IN_JAN;
4531 }
4532 /* No, we're done going month to month. */
4533 else break;
4534
4535 /* Handle February differently because it is a leap month. */
4536 if (current_date_time_ptr -> leap_year)
4537 {
4538
4539 /* This is a leap year so Feb has 29 days. */
4540 if (seconds_into_currentyear >= SEC_IN_LEAPFEB)
4541 {
4542 current_date_time_ptr -> month = MARCH;
4543 seconds_into_currentyear -= SEC_IN_LEAPFEB;
4544 }
4545 else break;
4546
4547 }
4548 else
4549 {
4550 /* Not a leap year, Feb has the usual 28 days. */
4551 if (seconds_into_currentyear >= SEC_IN_NONLEAPFEB)
4552 {
4553 current_date_time_ptr -> month = MARCH;
4554 seconds_into_currentyear -= SEC_IN_NONLEAPFEB;
4555 }
4556 else break;
4557
4558 }
4559
4560 /* Repeat for each month for the rest of the year. */
4561
4562 if (seconds_into_currentyear >= SEC_IN_MAR)
4563 {
4564 current_date_time_ptr -> month = APRIL;
4565 seconds_into_currentyear -= SEC_IN_MAR;
4566 }
4567 else break;
4568
4569 if (seconds_into_currentyear >= SEC_IN_APR)
4570 {
4571 current_date_time_ptr -> month = MAY;
4572 seconds_into_currentyear -= SEC_IN_APR;
4573 }
4574 else break;
4575
4576 if (seconds_into_currentyear >= SEC_IN_MAY)
4577 {
4578 current_date_time_ptr -> month = JUNE;
4579 seconds_into_currentyear -= SEC_IN_MAY;
4580 }
4581 else break;
4582
4583 if (seconds_into_currentyear >= SEC_IN_JUN)
4584 {
4585 current_date_time_ptr -> month = JULY;
4586 seconds_into_currentyear -= SEC_IN_JUN;
4587 }
4588 else break;
4589
4590 if (seconds_into_currentyear >= SEC_IN_JUL)
4591 {
4592 current_date_time_ptr -> month = AUGUST;
4593 seconds_into_currentyear -= SEC_IN_JUL;
4594 }
4595 else break;
4596
4597 if (seconds_into_currentyear >= SEC_IN_AUG)
4598 {
4599 current_date_time_ptr -> month = SEPTEMBER;
4600 seconds_into_currentyear -= SEC_IN_AUG;
4601 }
4602 else break;
4603
4604 if (seconds_into_currentyear >= SEC_IN_SEP)
4605 {
4606 current_date_time_ptr -> month = OCTOBER;
4607 seconds_into_currentyear -= SEC_IN_SEP;
4608 }
4609 else break;
4610
4611 if (seconds_into_currentyear >= SEC_IN_OCT)
4612 {
4613 current_date_time_ptr -> month = NOVEMBER;
4614 seconds_into_currentyear -= SEC_IN_OCT;
4615 }
4616 else break;
4617
4618 if (seconds_into_currentyear >= SEC_IN_NOV)
4619 {
4620 current_date_time_ptr -> month = DECEMBER;
4621 seconds_into_currentyear -= SEC_IN_NOV;
4622 }
4623 else break;
4624
4625 /* We should not have more than the seconds in december or there is an error. */
4626 if (seconds_into_currentyear > SEC_IN_DEC)
4627 {
4628
4629 /* Return the error status. */
4630 return NX_SNTP_ERROR_CONVERTING_DATETIME;
4631 }
4632 else break;
4633 }
4634
4635 /* Time is now in the current month. */
4636 seconds_into_currentmonth = seconds_into_currentyear;
4637
4638 /* Compute how many complete days the time goes into the current month and
4639 add one for the current day. */
4640 current_date_time_ptr -> day = seconds_into_currentmonth/SECONDS_PER_DAY + 1;
4641
4642 /* Compute the number of seconds into the current day. */
4643 seconds_into_currentday = seconds_into_currentmonth % SECONDS_PER_DAY;
4644
4645 /* Compute the number of complete hours into the current day we are. */
4646 current_date_time_ptr -> hour = seconds_into_currentday/SECONDS_PER_HOUR;
4647
4648 /* Compute the number of seconds into the current hour. */
4649 seconds_into_currenthour = seconds_into_currentday % SECONDS_PER_HOUR;
4650
4651 /* Break this down into minutes. */
4652 current_date_time_ptr -> minute = seconds_into_currenthour/SECONDS_PER_MINUTE;
4653
4654 /* Finally the remainder is the seconds. */
4655 current_date_time_ptr -> second = seconds_into_currenthour % SECONDS_PER_MINUTE;
4656
4657 /* Convert time fraction field into milliseconds. */
4658 _nx_sntp_client_utility_convert_fraction_to_msecs((ULONG *)(&(current_date_time_ptr -> millisecond)), current_NTP_time_ptr);
4659
4660 return NX_SUCCESS;
4661 #endif
4662 }
4663
4664
4665 /**************************************************************************/
4666 /* */
4667 /* FUNCTION RELEASE */
4668 /* */
4669 /* _nxe_sntp_client_utility_display_date_time PORTABLE C */
4670 /* 6.1 */
4671 /* AUTHOR */
4672 /* */
4673 /* Yuxin Zhou, Microsoft Corporation */
4674 /* */
4675 /* DESCRIPTION */
4676 /* */
4677 /* This function performs error checking services on the display date */
4678 /* time service. */
4679 /* */
4680 /* INPUT */
4681 /* */
4682 /* client_ptr Pointer to SNTP Client */
4683 /* buffer Pointer to string buffer */
4684 /* length Size of the string buffer */
4685 /* */
4686 /* OUTPUT */
4687 /* */
4688 /* NX_PTR_ERROR Invalid pointer input */
4689 /* NX_SNTP_PARAM_ERROR Invalid non pointer input */
4690 /* status Actual completion status */
4691 /* */
4692 /* CALLS */
4693 /* */
4694 /* _nx_sntp_client_utility_display_date_time */
4695 /* Actual display date/time service */
4696 /* */
4697 /* CALLED BY */
4698 /* */
4699 /* Application */
4700 /* */
4701 /* RELEASE HISTORY */
4702 /* */
4703 /* DATE NAME DESCRIPTION */
4704 /* */
4705 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4706 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4707 /* resulting in version 6.1 */
4708 /* */
4709 /**************************************************************************/
_nxe_sntp_client_utility_display_date_time(NX_SNTP_CLIENT * client_ptr,CHAR * buffer,UINT length)4710 UINT _nxe_sntp_client_utility_display_date_time(NX_SNTP_CLIENT *client_ptr, CHAR *buffer, UINT length)
4711 {
4712
4713 UINT status;
4714
4715
4716 /* Check for invalid pointer input. */
4717 if ((client_ptr == NX_NULL) || (buffer == NX_NULL))
4718 {
4719
4720 /* Return pointer error. */
4721 return NX_PTR_ERROR;
4722 }
4723
4724 /* Check for invalid parameter input. */
4725 if (length == 0)
4726 {
4727
4728 /* Return parameter error. */
4729 return NX_SNTP_PARAM_ERROR;
4730 }
4731
4732 /* Call the actual display time service. */
4733 status = _nx_sntp_client_utility_display_date_time(client_ptr, buffer, length);
4734
4735 /* Return completion status. */
4736 return status;
4737 }
4738
4739
4740
4741 /**************************************************************************/
4742 /* */
4743 /* FUNCTION RELEASE */
4744 /* */
4745 /* _nxe_sntp_client_request_unicast_time PORTABLE C */
4746 /* 6.1 */
4747 /* AUTHOR */
4748 /* */
4749 /* Yuxin Zhou, Microsoft Corporation */
4750 /* */
4751 /* DESCRIPTION */
4752 /* */
4753 /* This function performs error checking for the service that */
4754 /* forwards a unicast request from the SNTP Client application. */
4755 /* */
4756 /* INPUT */
4757 /* */
4758 /* client_ptr Pointer to Client struct */
4759 /* wait_option Time to wait for response (ticks) */
4760 /* */
4761 /* OUTPUT */
4762 /* */
4763 /* NX_PTR_ERROR Invalid pointer input */
4764 /* status Actual completion status */
4765 /* */
4766 /* CALLED BY */
4767 /* */
4768 /* Application Code */
4769 /* */
4770 /* RELEASE HISTORY */
4771 /* */
4772 /* DATE NAME DESCRIPTION */
4773 /* */
4774 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4775 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4776 /* resulting in version 6.1 */
4777 /* */
4778 /**************************************************************************/
_nxe_sntp_client_request_unicast_time(NX_SNTP_CLIENT * client_ptr,UINT wait_option)4779 UINT _nxe_sntp_client_request_unicast_time(NX_SNTP_CLIENT *client_ptr, UINT wait_option)
4780 {
4781
4782 UINT status;
4783
4784 /* Check for invalid pointer input. */
4785 if (client_ptr == NX_NULL)
4786 {
4787 return NX_PTR_ERROR;
4788 }
4789
4790 status = _nx_sntp_client_request_unicast_time(client_ptr, wait_option);
4791
4792 return status;
4793 }
4794
4795
4796 /**************************************************************************/
4797 /* */
4798 /* FUNCTION RELEASE */
4799 /* */
4800 /* _nx_sntp_client_request_unicast_time PORTABLE C */
4801 /* 6.1 */
4802 /* AUTHOR */
4803 /* */
4804 /* Yuxin Zhou, Microsoft Corporation */
4805 /* */
4806 /* DESCRIPTION */
4807 /* */
4808 /* This function sends a unicast request regardless if the SNTP Client */
4809 /* is configured for unicast or broadcast mode. After sending the */
4810 /* request, the function waits for the specified time for a response. */
4811 /* */
4812 /* If received, the SNTP Server response is processed as it normally is*/
4813 /* for valid SNTP data, and applied to the SNTP Client's notion of time*/
4814 /* "local time". */
4815 /* */
4816 /* This will not interfere with subsequent unicast requests in unicast */
4817 /* mode, or the processing of periodic updates in broadcast mode. */
4818 /* */
4819 /* INPUT */
4820 /* */
4821 /* client_ptr Pointer to Client struct */
4822 /* wait_option Time to wait for response (ticks) */
4823 /* */
4824 /* OUTPUT */
4825 /* */
4826 /* NX_PTR_ERROR Invalid pointer input */
4827 /* status Actual completion status */
4828 /* */
4829 /* CALLED BY */
4830 /* */
4831 /* Application Code */
4832 /* */
4833 /* RELEASE HISTORY */
4834 /* */
4835 /* DATE NAME DESCRIPTION */
4836 /* */
4837 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4838 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4839 /* resulting in version 6.1 */
4840 /* */
4841 /**************************************************************************/
_nx_sntp_client_request_unicast_time(NX_SNTP_CLIENT * client_ptr,UINT wait_option)4842 UINT _nx_sntp_client_request_unicast_time(NX_SNTP_CLIENT *client_ptr, UINT wait_option)
4843 {
4844
4845 UINT status;
4846
4847
4848 /* Make sure the client is started. */
4849 if (!client_ptr -> nx_sntp_client_started)
4850 {
4851 return NX_SNTP_CLIENT_NOT_STARTED;
4852 }
4853
4854 /* Create and send a unicast request. */
4855 status = _nx_sntp_client_send_unicast_request(client_ptr);
4856
4857 if (status != NX_SUCCESS)
4858 {
4859 return status;
4860 }
4861
4862 /* Wait to receive a response. */
4863 status = _nx_sntp_client_receive_time_update(client_ptr, wait_option);
4864
4865 /* If we got a valid SNTP packet, process the data. */
4866 if (status == NX_SUCCESS)
4867 {
4868
4869 /* Process the server update packet and apply to local time if valid. */
4870 status = _nx_sntp_client_process_update_packet(client_ptr);
4871 }
4872
4873 tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex));
4874 /* Return completion status. */
4875 return status;
4876 }
4877
4878 /**************************************************************************/
4879 /* */
4880 /* FUNCTION RELEASE */
4881 /* */
4882 /* _nx_sntp_client_utility_display_date_time PORTABLE C */
4883 /* 6.2.0 */
4884 /* AUTHOR */
4885 /* */
4886 /* Yuxin Zhou, Microsoft Corporation */
4887 /* */
4888 /* DESCRIPTION */
4889 /* */
4890 /* This function converts an NTP time data into a month-date-year time, */
4891 /* including seconds and second fraction string. It is intended as a */
4892 /* human readable representation of NTP time. The caller must supply a */
4893 /* pointer to a buffer large enough (40 chars is enough) to hold the */
4894 /* string and define the NX_SNTP_CURRENT_YEAR parameter, usually as the */
4895 /* current year. */
4896 /* */
4897 /* INPUT */
4898 /* */
4899 /* client_ptr Pointer to SNTP Client */
4900 /* buffer Pointer to string buffer */
4901 /* length Size of the string buffer */
4902 /* */
4903 /* OUTPUT */
4904 /* */
4905 /* NX_SUCCESS Successful completion status */
4906 /* NX_SNTP_INVALID_DATETIME_BUFFER Buffer not large enough */
4907 /* NX_SNTP_ERROR_CONVERTING_DATETIME Internal error converting NTP time*/
4908 /* status Convert seconds completion status */
4909 /* */
4910 /* CALLS */
4911 /* _nx_sntp_client_utility_convert_seconds_to_date */
4912 /* Converts seconds to year, month */
4913 /* _nx_utility_uint_to_string Converts number to ascii text */
4914 /* */
4915 /* CALLED BY */
4916 /* */
4917 /* Application */
4918 /* */
4919 /* RELEASE HISTORY */
4920 /* */
4921 /* DATE NAME DESCRIPTION */
4922 /* */
4923 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4924 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4925 /* resulting in version 6.1 */
4926 /* 08-02-2021 Yuxin Zhou Modified comment(s), */
4927 /* improved the logic of */
4928 /* converting number to string,*/
4929 /* resulting in version 6.1.8 */
4930 /* 10-31-2022 Yuxin Zhou Modified comment(s), fixed */
4931 /* the typo of August string, */
4932 /* resulting in version 6.2.0 */
4933 /* */
4934 /**************************************************************************/
_nx_sntp_client_utility_display_date_time(NX_SNTP_CLIENT * client_ptr,CHAR * buffer,UINT length)4935 UINT _nx_sntp_client_utility_display_date_time(NX_SNTP_CLIENT *client_ptr, CHAR *buffer, UINT length)
4936 {
4937
4938 UINT status;
4939 UINT offset;
4940 UINT return_length;
4941 NX_SNTP_DATE_TIME DisplayTime;
4942 const CHAR *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
4943 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
4944
4945
4946 #ifndef NX_SNTP_CURRENT_YEAR
4947 return NX_SNTP_ERROR_CONVERTING_DATETIME;
4948 #else
4949
4950 /* Verify the client has set a local time. */
4951 if (client_ptr -> nx_sntp_client_local_ntp_time.seconds == 0)
4952 {
4953 return NX_SNTP_ERROR_CONVERTING_DATETIME;
4954 }
4955
4956 status = _nx_sntp_client_utility_convert_seconds_to_date(&(client_ptr -> nx_sntp_client_local_ntp_time), NX_SNTP_CURRENT_YEAR, &DisplayTime);
4957 if (status != NX_SUCCESS)
4958 {
4959 return status;
4960 }
4961
4962 /* Check if we have a long enough buffer. */
4963 if (length < 5)
4964 {
4965
4966 /* Return the error status. */
4967 return NX_SNTP_INVALID_DATETIME_BUFFER;
4968 }
4969
4970 /* Decrease length for terminal zero. */
4971 length--;
4972
4973 /* Substitute numeric month to name of the month. */
4974 if ((DisplayTime.month < JANUARY) || (DisplayTime.month > DECEMBER))
4975 {
4976 return NX_SNTP_ERROR_CONVERTING_DATETIME;
4977 }
4978 buffer[0] = months[DisplayTime.month - JANUARY][0];
4979 buffer[1] = months[DisplayTime.month - JANUARY][1];
4980 buffer[2] = months[DisplayTime.month - JANUARY][2];
4981 buffer[3] = ' ';
4982 offset = 4;
4983
4984 /* Write in the rest of the data as numeric from the Date Time objext. */
4985 return_length = _nx_utility_uint_to_string(DisplayTime.day, 10, &buffer[offset], length - offset);
4986 offset += return_length;
4987 if ((return_length == 0) || ((length - offset) < 2))
4988 {
4989 return NX_SNTP_ERROR_CONVERTING_DATETIME;
4990 }
4991 buffer[offset++] = ',';
4992 buffer[offset++] = ' ';
4993 return_length = _nx_utility_uint_to_string(DisplayTime.year, 10, &buffer[offset], length - offset);
4994 offset += return_length;
4995 if ((return_length == 0) || ((length - offset) < 1))
4996 {
4997 return NX_SNTP_ERROR_CONVERTING_DATETIME;
4998 }
4999 buffer[offset++] = ' ';
5000 return_length = _nx_utility_uint_to_string(DisplayTime.hour, 10, &buffer[offset], length - offset);
5001 offset += return_length;
5002 if ((return_length == 0) || ((length - offset) < 1))
5003 {
5004 return NX_SNTP_ERROR_CONVERTING_DATETIME;
5005 }
5006 buffer[offset++] = ':';
5007 return_length = _nx_utility_uint_to_string(DisplayTime.minute, 10, &buffer[offset], length - offset);
5008 offset += return_length;
5009 if ((return_length == 0) || ((length - offset) < 1))
5010 {
5011 return NX_SNTP_ERROR_CONVERTING_DATETIME;
5012 }
5013 buffer[offset++] = ':';
5014 return_length = _nx_utility_uint_to_string(DisplayTime.second, 10, &buffer[offset], length - offset);
5015 offset += return_length;
5016 if ((return_length == 0) || ((length - offset) < 1))
5017 {
5018 return NX_SNTP_ERROR_CONVERTING_DATETIME;
5019 }
5020 buffer[offset++] = '.';
5021 return_length = _nx_utility_uint_to_string(DisplayTime.millisecond, 10, &buffer[offset], length - offset);
5022 offset += return_length;
5023 if ((return_length == 0) || ((length - offset) < 5))
5024 {
5025 return NX_SNTP_ERROR_CONVERTING_DATETIME;
5026 }
5027 buffer[offset++] = ' ';
5028 buffer[offset++] = 'U';
5029 buffer[offset++] = 'T';
5030 buffer[offset++] = 'C';
5031 buffer[offset++] = ' ';
5032 buffer[offset] = '\0';
5033
5034 #endif
5035
5036 return NX_SUCCESS;
5037 }
5038
5039
5040 /**************************************************************************/
5041 /* */
5042 /* FUNCTION RELEASE */
5043 /* */
5044 /* _nx_sntp_client_utility_add_msecs_to_ntp_time PORTABLE C */
5045 /* 6.1 */
5046 /* AUTHOR */
5047 /* */
5048 /* Yuxin Zhou, Microsoft Corporation */
5049 /* */
5050 /* DESCRIPTION */
5051 /* */
5052 /* This function adds msecs (not necessarily a positive value and not */
5053 /* limited to less than a second) to an NTP time value. Msecs cannot be */
5054 /* added directly to the fraction field in the NTP time field because */
5055 /* this field is represented in fixed point notation. Arithmetic */
5056 /* overflow and loss of sign errors as a result of adding numbers are */
5057 /* handled as errors. */
5058 /* */
5059 /* INPUT */
5060 /* */
5061 /* timeA_ptr Pointer to NTP time operand */
5062 /* msecs_to_add Time (msecs) to add */
5063 /* */
5064 /* OUTPUT */
5065 /* */
5066 /* NX_SUCCESS Successful completion status */
5067 /* NX_SNTP_OVERFLOW_ERROR Overflow result adding numbers */
5068 /* NX_SNTP_INVALID_TIME An invalid result (e.g. negative */
5069 /* time) from adding numbers */
5070 /* status Actual completion status */
5071 /* */
5072 /* CALLS */
5073 /* */
5074 /* None */
5075 /* */
5076 /* CALLED BY */
5077 /* */
5078 /* _nx_sntp_client_process_time_data Apply server time to local time */
5079 /* */
5080 /* RELEASE HISTORY */
5081 /* */
5082 /* DATE NAME DESCRIPTION */
5083 /* */
5084 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5085 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5086 /* resulting in version 6.1 */
5087 /* */
5088 /**************************************************************************/
5089
_nx_sntp_client_utility_add_msecs_to_ntp_time(NX_SNTP_TIME * timeA_ptr,LONG msecs_to_add)5090 UINT _nx_sntp_client_utility_add_msecs_to_ntp_time(NX_SNTP_TIME *timeA_ptr, LONG msecs_to_add)
5091 {
5092
5093 UINT status;
5094 ULONG timeA_usec;
5095 LONG seconds;
5096 LONG usecs;
5097
5098
5099 /* Separate msecs_to_add into seconds and milliseconds. */
5100 seconds = msecs_to_add / 1000;
5101 usecs = (msecs_to_add % 1000) * 1000;
5102
5103 /* Are we adding a positive number? */
5104 if (msecs_to_add > 0)
5105 {
5106 /* Yes; check for overflow before trying to add seconds to the TimeA operand. */
5107 status = _nx_sntp_client_utility_addition_overflow_check(timeA_ptr -> seconds, (ULONG)seconds);
5108
5109 /* Check for error (overflow). */
5110 if (status != NX_SUCCESS)
5111 {
5112
5113 /* Return the error condition. */
5114 return status;
5115 }
5116 }
5117 /* Check if a negative number larger than the timeA operand is being added (creates negative time!)*/
5118 else if (timeA_ptr -> seconds < (ULONG)abs(seconds))
5119 {
5120
5121 /* Yes; return the error condition. */
5122 return NX_SNTP_INVALID_TIME;
5123 }
5124
5125 /* Ok to add seconds to the NTP time seconds. */
5126 timeA_ptr -> seconds += (ULONG)seconds;
5127
5128 /* Next get the usecs from the timeA operand (always positive and < 1000000). */
5129 _nx_sntp_client_utility_fraction_to_usecs(timeA_ptr -> fraction, &timeA_usec);
5130
5131 /* In case usecs is < 0, we might have to perform a carry. */
5132 if ((usecs + (LONG)timeA_usec) < 0)
5133 {
5134 /* Perform a carry by subtracting a second from timeA seconds...*/
5135 timeA_ptr -> seconds--;
5136
5137 /* And adding it to the usecs of timeA. */
5138 timeA_usec += 1000000;
5139 }
5140
5141 /* OK to add the usecs up. */
5142 usecs += (LONG)timeA_usec;
5143
5144 /* Check for a positive carry over into seconds. */
5145 if (usecs >= 1000000)
5146 {
5147 /* Yes there's a carry; check for possibility of overflow
5148 before adding carry (unlikely for another 30 years). */
5149 if (timeA_ptr -> seconds == 0xFFFFFFFF)
5150 {
5151
5152 return NX_SNTP_OVERFLOW_ERROR;
5153 }
5154
5155 /* OK to increment the seconds. */
5156 timeA_ptr -> seconds++;
5157
5158 /* Set milliseconds to remainder. */
5159 usecs = usecs % 1000000;
5160 }
5161
5162 /* Convert usecs to the fixed point notation fraction and store in TimeA fraction. */
5163 status = _nx_sntp_client_utility_usecs_to_fraction((ULONG)usecs, &(timeA_ptr ->fraction));
5164
5165 /* Return completion status. */
5166 return status;
5167 }
5168
5169
5170 /**************************************************************************/
5171 /* */
5172 /* FUNCTION RELEASE */
5173 /* */
5174 /* _nxe_sntp_client_receiving_updates PORTABLE C */
5175 /* 6.1 */
5176 /* AUTHOR */
5177 /* */
5178 /* Yuxin Zhou, Microsoft Corporation */
5179 /* */
5180 /* DESCRIPTION */
5181 /* */
5182 /* This function performs error checking for the get SNTP get receive */
5183 /* status service. */
5184 /* */
5185 /* INPUT */
5186 /* */
5187 /* client_ptr Pointer to SNTP client instance */
5188 /* receive_status Pointer to server status */
5189 /* */
5190 /* OUTPUT */
5191 /* */
5192 /* NX_PTR_ERROR Invalid input status */
5193 /* status Actual completion status */
5194 /* */
5195 /* CALLS */
5196 /* */
5197 /* _nx_sntp_client_receiving_updates */
5198 /* Actual get server status service */
5199 /* */
5200 /* CALLED BY */
5201 /* */
5202 /* Application Code */
5203 /* */
5204 /* RELEASE HISTORY */
5205 /* */
5206 /* DATE NAME DESCRIPTION */
5207 /* */
5208 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5209 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5210 /* resulting in version 6.1 */
5211 /* */
5212 /**************************************************************************/
_nxe_sntp_client_receiving_updates(NX_SNTP_CLIENT * client_ptr,UINT * receive_status)5213 UINT _nxe_sntp_client_receiving_updates(NX_SNTP_CLIENT *client_ptr, UINT *receive_status)
5214 {
5215
5216 UINT status;
5217
5218 /* Check for the validity of input parameter. */
5219 if ((client_ptr == NX_NULL) || (receive_status == NX_NULL))
5220 {
5221
5222 /* Return error status. */
5223 return(NX_PTR_ERROR);
5224 }
5225
5226 status = _nx_sntp_client_receiving_updates(client_ptr, receive_status);
5227
5228 return status;
5229 }
5230
5231 /**************************************************************************/
5232 /* */
5233 /* FUNCTION RELEASE */
5234 /* */
5235 /* _nx_sntp_client_receiving_updates PORTABLE C */
5236 /* 6.1 */
5237 /* AUTHOR */
5238 /* */
5239 /* Yuxin Zhou, Microsoft Corporation */
5240 /* */
5241 /* DESCRIPTION */
5242 /* */
5243 /* This function returns the status of the Client SNTP server. If the */
5244 /* client has not received a valid update within the NX_SNTP_CLIENT_MAX_*/
5245 /* _TIME_LAPSE interval or if the number of invalid updates received by */
5246 /* the client exceeds the NX_SNTP_CLIENT_INVALID_UPDATE_LIMIT limit, */
5247 /* the status is set to NX_FALSE. If the Client has not yet received */
5248 /* its first valid update from the current SNTP server, status is set to*/
5249 /* false. */
5250 /* */
5251 /* INPUT */
5252 /* */
5253 /* client_ptr Pointer to SNTP client instance */
5254 /* receive_status Pointer to receive_status */
5255 /* NX_FALSE: not receiving updates */
5256 /* NX_TRUE: receiving valid updates */
5257 /* */
5258 /* OUTPUT */
5259 /* */
5260 /* NX_PTR_ERROR Invalid input status */
5261 /* status Actual completion status */
5262 /* */
5263 /* CALLS */
5264 /* */
5265 /* tx_mutex_get Get the SNTP mutex */
5266 /* tx_mutex_put Release the SNTP mutex */
5267 /* */
5268 /* CALLED BY */
5269 /* */
5270 /* Application Code */
5271 /* */
5272 /* RELEASE HISTORY */
5273 /* */
5274 /* DATE NAME DESCRIPTION */
5275 /* */
5276 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5277 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5278 /* resulting in version 6.1 */
5279 /* */
5280 /**************************************************************************/
_nx_sntp_client_receiving_updates(NX_SNTP_CLIENT * client_ptr,UINT * receive_status)5281 UINT _nx_sntp_client_receiving_updates(NX_SNTP_CLIENT *client_ptr, UINT *receive_status)
5282 {
5283
5284
5285 /* Get the SNTP mutex. */
5286 tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER);
5287
5288 /* Verify the client's SNTP server is valid, and the Client has received at least one valid udpate from it. */
5289 *receive_status = ((client_ptr -> nx_sntp_valid_server_status == NX_TRUE) && (client_ptr -> nx_sntp_client_first_update_pending == NX_FALSE));
5290
5291 /* Release the SNTP mutex. */
5292 tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex));
5293
5294 /* Return completion status. */
5295 return(NX_SUCCESS);
5296
5297 }
5298
5299
5300 /**************************************************************************/
5301 /* */
5302 /* FUNCTION RELEASE */
5303 /* */
5304 /* _nxe_sntp_client_set_local_time PORTABLE C */
5305 /* 6.1 */
5306 /* AUTHOR */
5307 /* */
5308 /* Yuxin Zhou, Microsoft Corporation */
5309 /* */
5310 /* DESCRIPTION */
5311 /* */
5312 /* This function performs error checking for the set client local time */
5313 /* service. */
5314 /* */
5315 /* INPUT */
5316 /* */
5317 /* client_ptr Pointer to SNTP Client */
5318 /* seconds Local time seconds component */
5319 /* fraction Local time fraction component */
5320 /* */
5321 /* OUTPUT */
5322 /* */
5323 /* status Actual completion status */
5324 /* NX_PTR_ERROR Invalid pointer input */
5325 /* */
5326 /* CALLS */
5327 /* */
5328 /* _nx_sntp_client_set_local_time Actual set client local time service*/
5329 /* */
5330 /* CALLED BY */
5331 /* */
5332 /* Application Code */
5333 /* */
5334 /* RELEASE HISTORY */
5335 /* */
5336 /* DATE NAME DESCRIPTION */
5337 /* */
5338 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5339 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5340 /* resulting in version 6.1 */
5341 /* */
5342 /**************************************************************************/
_nxe_sntp_client_set_local_time(NX_SNTP_CLIENT * client_ptr,ULONG seconds,ULONG fraction)5343 UINT _nxe_sntp_client_set_local_time(NX_SNTP_CLIENT *client_ptr, ULONG seconds, ULONG fraction)
5344 {
5345
5346 UINT status;
5347
5348
5349 /* Check for invalid input. */
5350 if (client_ptr == NX_NULL)
5351 {
5352 return NX_PTR_ERROR;
5353 }
5354
5355 /* Call the actual service. */
5356 status = _nx_sntp_client_set_local_time(client_ptr, seconds, fraction);
5357
5358 /* Return completion status. */
5359 return status;
5360 }
5361
5362
5363 /**************************************************************************/
5364 /* */
5365 /* FUNCTION RELEASE */
5366 /* */
5367 /* _nx_sntp_client_set_local_time PORTABLE C */
5368 /* 6.1 */
5369 /* AUTHOR */
5370 /* */
5371 /* Yuxin Zhou, Microsoft Corporation */
5372 /* */
5373 /* DESCRIPTION */
5374 /* */
5375 /* This function takes the seconds and fraction input from the caller */
5376 /* (or more accurately the independent time clock source, and applies it*/
5377 /* to the SNTP client local time. */
5378 /* */
5379 /* In between SNTP server updates, it is expected that the SNTP Client */
5380 /* host application will update the SNTP client local time from the */
5381 /* independent time source (e.g. real time clock on board) and then */
5382 /* use the SNTP Server time updates to correct the local time for drifts*/
5383 /* from the correct time. */
5384 /* */
5385 /* It can also set the SNTP Client's base time before starting up the */
5386 /* SNTP Client. If the host application cannot obtain a base time, the */
5387 /* SNTP Client will take the first SNTP update as the absolute time. If */
5388 /* the host application does have a real time clock or independent time */
5389 /* keeper, the SNTP client can set a large enough max adjustment that */
5390 /* any Server time udpate will be accepted to the SNTP Client. This */
5391 /* leaves the SNTP Client completely dependent on the network and SNTP */
5392 /* Server, plus it is vulnerable to rogue SNTP packets. */
5393 /* */
5394 /* INPUT */
5395 /* */
5396 /* client_ptr Pointer to SNTP Client */
5397 /* seconds Local time seconds component */
5398 /* fraction Local time fraction component */
5399 /* */
5400 /* OUTPUT */
5401 /* */
5402 /* NX_SUCCESS Successful completion status */
5403 /* */
5404 /* CALLS */
5405 /* */
5406 /* None */
5407 /* */
5408 /* CALLED BY */
5409 /* */
5410 /* Application Code */
5411 /* */
5412 /* RELEASE HISTORY */
5413 /* */
5414 /* DATE NAME DESCRIPTION */
5415 /* */
5416 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5417 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5418 /* resulting in version 6.1 */
5419 /* */
5420 /**************************************************************************/
_nx_sntp_client_set_local_time(NX_SNTP_CLIENT * client_ptr,ULONG seconds,ULONG fraction)5421 UINT _nx_sntp_client_set_local_time(NX_SNTP_CLIENT *client_ptr, ULONG seconds, ULONG fraction)
5422 {
5423
5424
5425 client_ptr -> nx_sntp_client_local_ntp_time.seconds = seconds;
5426 client_ptr -> nx_sntp_client_local_ntp_time.fraction = fraction;
5427 client_ptr -> nx_sntp_client_local_ntp_time_elapsed = 0;
5428
5429 /* Return completion status. */
5430 return NX_SUCCESS;
5431 }
5432
5433
5434 /**************************************************************************/
5435 /* */
5436 /* FUNCTION RELEASE */
5437 /* */
5438 /* _nxe_sntp_client_set_time_update_notify PORTABLE C */
5439 /* 6.1 */
5440 /* AUTHOR */
5441 /* */
5442 /* Yuxin Zhou, Microsoft Corporation */
5443 /* */
5444 /* DESCRIPTION */
5445 /* */
5446 /* This function performs error checking for the set time update */
5447 /* callback service. */
5448 /* */
5449 /* INPUT */
5450 /* */
5451 /* client_ptr Pointer to Client struct */
5452 /* time_update_cb Pointer to callback when Client */
5453 /* receives an SNTP update */
5454 /* */
5455 /* OUTPUT */
5456 /* */
5457 /* NX_SUCCESS Successful completion status */
5458 /* NX_PTR_ERROR Invalid pointer input */
5459 /* */
5460 /* CALLS */
5461 /* */
5462 /* _nx_sntp_client_set_time_update_notify */
5463 /* */
5464 /* CALLED BY */
5465 /* */
5466 /* Application */
5467 /* */
5468 /* RELEASE HISTORY */
5469 /* */
5470 /* DATE NAME DESCRIPTION */
5471 /* */
5472 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5473 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5474 /* resulting in version 6.1 */
5475 /* */
5476 /**************************************************************************/
_nxe_sntp_client_set_time_update_notify(NX_SNTP_CLIENT * client_ptr,VOID (time_update_cb)(NX_SNTP_TIME_MESSAGE * time_update_ptr,NX_SNTP_TIME * local_time))5477 UINT _nxe_sntp_client_set_time_update_notify(NX_SNTP_CLIENT *client_ptr,
5478 VOID (time_update_cb)(NX_SNTP_TIME_MESSAGE *time_update_ptr, NX_SNTP_TIME *local_time))
5479 {
5480
5481 UINT status;
5482
5483
5484 /* Check for valid input. */
5485 if ((client_ptr == NX_NULL) || (time_update_cb == NX_NULL))
5486 {
5487 return NX_PTR_ERROR;
5488 }
5489
5490 status = _nx_sntp_client_set_time_update_notify(client_ptr, time_update_cb);
5491
5492 return status;
5493 }
5494
5495 /**************************************************************************/
5496 /* */
5497 /* FUNCTION RELEASE */
5498 /* */
5499 /* _nx_sntp_client_set_time_update_notify PORTABLE C */
5500 /* 6.1 */
5501 /* AUTHOR */
5502 /* */
5503 /* Yuxin Zhou, Microsoft Corporation */
5504 /* */
5505 /* DESCRIPTION */
5506 /* */
5507 /* This function notifies the application of a valid SNTP time update. */
5508 /* */
5509 /* INPUT */
5510 /* */
5511 /* client_ptr Pointer to Client struct */
5512 /* time_update_cb Pointer to callback when Client */
5513 /* receives an SNTP update */
5514 /* */
5515 /* OUTPUT */
5516 /* */
5517 /* NX_SUCCESS Successful completion status */
5518 /* */
5519 /* CALLS */
5520 /* */
5521 /* None */
5522 /* */
5523 /* CALLED BY */
5524 /* */
5525 /* Application */
5526 /* */
5527 /* RELEASE HISTORY */
5528 /* */
5529 /* DATE NAME DESCRIPTION */
5530 /* */
5531 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5532 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5533 /* resulting in version 6.1 */
5534 /* */
5535 /**************************************************************************/
_nx_sntp_client_set_time_update_notify(NX_SNTP_CLIENT * client_ptr,VOID (time_update_cb)(NX_SNTP_TIME_MESSAGE * time_update_ptr,NX_SNTP_TIME * local_time))5536 UINT _nx_sntp_client_set_time_update_notify(NX_SNTP_CLIENT *client_ptr,
5537 VOID (time_update_cb)(NX_SNTP_TIME_MESSAGE *time_update_ptr, NX_SNTP_TIME *local_time))
5538 {
5539
5540
5541 client_ptr -> nx_sntp_client_time_update_notify = time_update_cb;
5542
5543 return NX_SUCCESS;
5544 }
5545
5546
5547
5548
5549 /**************************************************************************/
5550 /* */
5551 /* FUNCTION RELEASE */
5552 /* */
5553 /* _nx_sntp_client_utility_get_msec_diff PORTABLE C */
5554 /* 6.1 */
5555 /* AUTHOR */
5556 /* */
5557 /* Yuxin Zhou, Microsoft Corporation */
5558 /* */
5559 /* DESCRIPTION */
5560 /* */
5561 /* This function computes the difference in milliseconds between two */
5562 /* NTP times, receiving an NTP packet, and transmitting it back. */
5563 /* The logic calculates the difference in the seconds component and */
5564 /* converts it to milliseconds. It converts the fraction to useconds */
5565 /* and calculates that difference. Useconds are rounded to the nearest */
5566 /* millisecond. This logic assumes the transmit time occurs after */
5567 /* receive time. */
5568 /* */
5569 /* The net difference is the difference in milliseconds from the */
5570 /* fractions added to (or subtracted from) the difference in */
5571 /* milliseconds from the seconds component. */
5572 /* */
5573 /* Note that the conversion of useconds to milliseconds may result */
5574 /* in the two times' difference to be zero, when they are actually */
5575 /* different by useconds. */
5576 /* */
5577 /* INPUT */
5578 /* */
5579 /* timeReceived_ptr NTP time of received message */
5580 /* timeTransmit_ptr NTP time of transmitted message */
5581 /* total_difference_msecs Millseconds of difference in time */
5582 /* pos_diff True if Transmit Time >= */
5583 /* Receive Time */
5584 /* */
5585 /* OUTPUT */
5586 /* */
5587 /* NX_SUCCESS Valid transmit/receive times */
5588 /* NX_SNTP_OVERFLOW_ERROR Overflow result */
5589 /* NX_SNTP_INVALID_TIME Transmit time<receive time seconds */
5590 /* */
5591 /* CALLS */
5592 /* */
5593 /* _nx_sntp_client_utility_convert_fraction_to_msecs */
5594 /* Convert fraction to milliseconds */
5595 /* */
5596 /* CALLED BY */
5597 /* */
5598 /* _nx_sntp_client_apply_sanity_checks */
5599 /* Apply sanity checks to time data */
5600 /* _nx_sntp_client_process_time_data */
5601 /* Apply server time to local time */
5602 /* */
5603 /* RELEASE HISTORY */
5604 /* */
5605 /* DATE NAME DESCRIPTION */
5606 /* */
5607 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5608 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5609 /* resulting in version 6.1 */
5610 /* */
5611 /**************************************************************************/
_nx_sntp_client_utility_get_msec_diff(NX_SNTP_TIME * timeReceived_ptr,NX_SNTP_TIME * timeTransmit_ptr,ULONG * total_difference_msecs,UINT * pos_diff)5612 UINT _nx_sntp_client_utility_get_msec_diff(NX_SNTP_TIME *timeReceived_ptr, NX_SNTP_TIME *timeTransmit_ptr, ULONG *total_difference_msecs, UINT *pos_diff)
5613 {
5614
5615 ULONG usecsReceived, usecsTransmit;
5616 ULONG msecsReceived, msecsTransmit;
5617 ULONG seconds_difference_in_msecs;
5618 ULONG temp;
5619
5620
5621 /* Check for overflow with a very large positive difference result. */
5622 if (timeReceived_ptr -> seconds > timeTransmit_ptr -> seconds)
5623 {
5624
5625 /* Use a temporary variable to store the difference in the seconds. */
5626 temp = timeReceived_ptr -> seconds - timeTransmit_ptr -> seconds;
5627 *pos_diff = NX_FALSE;
5628 }
5629 else
5630 {
5631
5632 /* Reverse the operand to get the absolute difference in the seconds. */
5633 temp = timeTransmit_ptr -> seconds -timeReceived_ptr -> seconds;
5634 *pos_diff = NX_TRUE;
5635 }
5636
5637 /* Check for overflow when converting seconds to milliseconds
5638 (0x3E8 = 1000). */
5639 if (temp > (0xFFFFFFFF / 0x3E8))
5640 {
5641
5642 /* Return error status. */
5643 return NX_SNTP_OVERFLOW_ERROR;
5644 }
5645
5646 /* Convert to msecs. */
5647 seconds_difference_in_msecs = temp * 1000;
5648
5649 /* Convert the Received time fraction to usecs and msecs. */
5650 _nx_sntp_client_utility_fraction_to_usecs(timeReceived_ptr -> fraction, &usecsReceived);
5651
5652 msecsReceived = usecsReceived / 1000;
5653
5654 if (usecsReceived % 1000 >= 500)
5655 msecsReceived++;
5656
5657 /* Convert the Transmit Time fraction to usecs and msecs. */
5658 _nx_sntp_client_utility_fraction_to_usecs(timeTransmit_ptr -> fraction, &usecsTransmit);
5659
5660 msecsTransmit = usecsTransmit / 1000;
5661
5662 if (usecsTransmit % 1000 >= 500)
5663 msecsTransmit++;
5664
5665 /* Get the difference of the two time stamps' fraction in milliseconds. */
5666 if (timeReceived_ptr -> seconds == timeTransmit_ptr -> seconds)
5667 {
5668
5669 /* Determine the absolute difference in the millisecond component. */
5670 if (usecsTransmit >= usecsReceived)
5671 {
5672
5673 *total_difference_msecs = msecsTransmit - msecsReceived;
5674 }
5675 else
5676 {
5677
5678 /* Transmit time usecs < Received time usecs. */
5679 *pos_diff = NX_FALSE;
5680 *total_difference_msecs = msecsReceived - msecsTransmit;
5681 }
5682 }
5683 else
5684 {
5685
5686 /* Consider the case where the transmit time seconds is greater. */
5687 if (timeTransmit_ptr -> seconds > timeReceived_ptr -> seconds)
5688 {
5689
5690 if ( usecsTransmit >= usecsReceived)
5691 {
5692
5693 /* This will add to the total milliseconds' difference. */
5694 *total_difference_msecs = seconds_difference_in_msecs + (msecsTransmit - msecsReceived);
5695 }
5696 else /* (usecsReceived > usecsTransmit) */
5697 {
5698
5699 /* This will subtract from the total milliseconds' difference . */
5700 *total_difference_msecs = seconds_difference_in_msecs - (msecsReceived - msecsTransmit);
5701 }
5702 }
5703
5704 /* Consider the case where the transmit time seconds is less. */
5705 else
5706 {
5707
5708 if (usecsReceived >= usecsTransmit)
5709 {
5710
5711 /* This will add to the total milliseconds' difference. */
5712 *total_difference_msecs = seconds_difference_in_msecs + (msecsReceived - msecsTransmit);
5713 }
5714 else /* (usecsTransmit > usecsReceived) */
5715 {
5716
5717 /* This will subtract from the total milliseconds' difference . */
5718 *total_difference_msecs = seconds_difference_in_msecs - (msecsTransmit - msecsReceived);
5719 }
5720 }
5721 }
5722
5723 /* Return successful completion status. */
5724 return NX_SUCCESS;
5725
5726 }
5727
5728 /**************************************************************************/
5729 /* */
5730 /* FUNCTION RELEASE */
5731 /* */
5732 /* _nx_sntp_client_utility_is_zero_data PORTABLE C */
5733 /* 6.1 */
5734 /* AUTHOR */
5735 /* */
5736 /* Yuxin Zhou, Microsoft Corporation */
5737 /* */
5738 /* DESCRIPTION */
5739 /* */
5740 /* This function tests each byte (UCHAR) of data to be non zero. The */
5741 /* return value indicates if the entire data is zero. */
5742 /* */
5743 /* INPUT */
5744 /* */
5745 /* data Pointer to first byte of data */
5746 /* size Number of bytes in data */
5747 /* */
5748 /* OUTPUT */
5749 /* */
5750 /* NX_TRUE Each byte of data is zero */
5751 /* NX_FALSE At least one byte is non zero */
5752 /* */
5753 /* CALLS */
5754 /* */
5755 /* None */
5756 /* */
5757 /* CALLED BY */
5758 /* */
5759 /* _nx_sntp_client_apply_sanity_checks Checks SNTP server reply validity*/
5760 /* */
5761 /* RELEASE HISTORY */
5762 /* */
5763 /* DATE NAME DESCRIPTION */
5764 /* */
5765 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5766 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5767 /* resulting in version 6.1 */
5768 /* */
5769 /**************************************************************************/
_nx_sntp_client_utility_is_zero_data(UCHAR * data,UINT size)5770 UINT _nx_sntp_client_utility_is_zero_data(UCHAR *data, UINT size)
5771 {
5772
5773 UINT i;
5774 UINT is_zero;
5775
5776
5777 /* Initialize local variables. */
5778 i = 0;
5779 is_zero = NX_TRUE;
5780
5781 while(i < size)
5782 {
5783
5784 if (*data != 0x0)
5785 {
5786
5787 is_zero = NX_FALSE;
5788 break;
5789 }
5790
5791 data += sizeof(UCHAR);
5792 i++;
5793 }
5794
5795 return is_zero;
5796 }
5797
5798
5799 /**************************************************************************/
5800 /* */
5801 /* FUNCTION RELEASE */
5802 /* */
5803 /* _nx_sntp_client_utility_convert_fraction_to_msecs PORTABLE C */
5804 /* 6.1 */
5805 /* AUTHOR */
5806 /* */
5807 /* Yuxin Zhou, Microsoft Corporation */
5808 /* */
5809 /* DESCRIPTION */
5810 /* */
5811 /* This function converts the fraction in an NTP time to milliseconds. */
5812 /* */
5813 /* INPUT */
5814 /* */
5815 /* milliseconds Pointer to milliseconds converted */
5816 /* time_ptr Pointer to an NTP time */
5817 /* */
5818 /* OUTPUT */
5819 /* */
5820 /* NX_SUCCESS Successful completion */
5821 /* */
5822 /* CALLS */
5823 /* */
5824 /* _nx_sntp_client_utility_fraction_to_usecs */
5825 /* Convert fraction to usecs */
5826 /* */
5827 /* CALLED BY */
5828 /* */
5829 /* _nx_sntp_client_utility_display_NTP_time */
5830 /* Display NTP time in seconds */
5831 /* */
5832 /* RELEASE HISTORY */
5833 /* */
5834 /* DATE NAME DESCRIPTION */
5835 /* */
5836 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5837 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5838 /* resulting in version 6.1 */
5839 /* */
5840 /**************************************************************************/
_nx_sntp_client_utility_convert_fraction_to_msecs(ULONG * milliseconds,NX_SNTP_TIME * time_ptr)5841 UINT _nx_sntp_client_utility_convert_fraction_to_msecs(ULONG *milliseconds, NX_SNTP_TIME *time_ptr)
5842 {
5843
5844 ULONG usecs;
5845
5846
5847 /* Convert to usecs first. */
5848 _nx_sntp_client_utility_fraction_to_usecs(time_ptr ->fraction, &usecs);
5849
5850 /* Then convert to milliseconds. */
5851 *milliseconds = usecs / 1000;
5852
5853 /* Round up if greater than 500 usecs left over*/
5854 if (usecs % 1000 >= 500)
5855 {
5856
5857 (*milliseconds)++;
5858 }
5859
5860 /* Return successful completion. */
5861 return NX_SUCCESS;
5862 }
5863
5864
5865 /**************************************************************************/
5866 /* */
5867 /* FUNCTION RELEASE */
5868 /* */
5869 /* _nxe_sntp_client_utility_usecs_to_fraction PORTABLE C */
5870 /* 6.1 */
5871 /* AUTHOR */
5872 /* */
5873 /* Yuxin Zhou, Microsoft Corporation */
5874 /* */
5875 /* DESCRIPTION */
5876 /* */
5877 /* This function performs error checking on the utility to convert */
5878 /* microseconds to fraction. */
5879 /* */
5880 /* INPUT */
5881 /* */
5882 /* usecs Microseconds to convert */
5883 /* fraction Pointer to converted fraction */
5884 /* */
5885 /* OUTPUT */
5886 /* */
5887 /* NX_SNTP_INVALID_TIME Invalid SNTP data input */
5888 /* status Actual completion status */
5889 /* */
5890 /* CALLS */
5891 /* */
5892 /* _nx_sntp_client_utility_usecs_to_fraction */
5893 /* Actual usecs conversion service */
5894 /* */
5895 /* CALLED BY */
5896 /* */
5897 /* Application code */
5898 /* */
5899 /* RELEASE HISTORY */
5900 /* */
5901 /* DATE NAME DESCRIPTION */
5902 /* */
5903 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5904 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5905 /* resulting in version 6.1 */
5906 /* */
5907 /**************************************************************************/
_nxe_sntp_client_utility_usecs_to_fraction(ULONG usecs,ULONG * fraction)5908 UINT _nxe_sntp_client_utility_usecs_to_fraction(ULONG usecs, ULONG *fraction)
5909 {
5910
5911 UINT status;
5912
5913
5914 if ((usecs == 0) || (fraction == NX_NULL))
5915 {
5916
5917 return NX_SNTP_INVALID_TIME;
5918 }
5919
5920 status = _nx_sntp_client_utility_usecs_to_fraction(usecs, fraction);
5921
5922 return status;
5923 }
5924
5925
5926 /**************************************************************************/
5927 /* */
5928 /* FUNCTION RELEASE */
5929 /* */
5930 /* _nx_sntp_client_utility_usecs_to_fraction PORTABLE C */
5931 /* 6.1 */
5932 /* AUTHOR */
5933 /* */
5934 /* Yuxin Zhou, Microsoft Corporation */
5935 /* */
5936 /* DESCRIPTION */
5937 /* */
5938 /* This function converts microseconds to a time stamp fraction. It is */
5939 /* primarily an intermediary function used in the process of converting */
5940 /* millliseconds to fixed point time fraction data. */
5941 /* */
5942 /* This conversion scheme is limited to microseconds less than 1000000. */
5943 /* */
5944 /* INPUT */
5945 /* */
5946 /* usecs Microseconds to convert */
5947 /* fraction Fraction to converted fraction */
5948 /* */
5949 /* OUTPUT */
5950 /* */
5951 /* NX_SUCCESS Successful completion status */
5952 /* NX_SNTP_OVERFLOW_ERROR Overflow error status */
5953 /* */
5954 /* CALLS */
5955 /* */
5956 /* None */
5957 /* */
5958 /* CALLED BY */
5959 /* */
5960 /* _nx_sntp_client_utility_msecs_to_fraction */
5961 /* Convert milliseconds to fixed point*/
5962 /* */
5963 /* RELEASE HISTORY */
5964 /* */
5965 /* DATE NAME DESCRIPTION */
5966 /* */
5967 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5968 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5969 /* resulting in version 6.1 */
5970 /* */
5971 /**************************************************************************/
_nx_sntp_client_utility_usecs_to_fraction(ULONG usecs,ULONG * fraction)5972 UINT _nx_sntp_client_utility_usecs_to_fraction(ULONG usecs, ULONG *fraction)
5973 {
5974
5975 ULONG _frac = usecs * 3962;
5976
5977
5978 *fraction = (usecs * 4294) + (_frac >> 12);
5979
5980 if((_frac & 4095) >= 2048)
5981 *fraction = *fraction + 1;
5982
5983 /* Successful completion. */
5984 return NX_SUCCESS;
5985 }
5986
5987
5988 /**************************************************************************/
5989 /* */
5990 /* FUNCTION RELEASE */
5991 /* */
5992 /* _nxe_sntp_client_utility_msecs_to_fraction PORTABLE C */
5993 /* 6.1 */
5994 /* AUTHOR */
5995 /* */
5996 /* Yuxin Zhou, Microsoft Corporation */
5997 /* */
5998 /* DESCRIPTION */
5999 /* */
6000 /* This function performs error checking on the utility to convert */
6001 /* milliseconds to fraction. */
6002 /* */
6003 /* INPUT */
6004 /* */
6005 /* msecs Milliseconds to convert */
6006 /* fraction Pointer to converted fraction */
6007 /* */
6008 /* OUTPUT */
6009 /* */
6010 /* NX_SNTP_INVALID_TIME Invalid SNTP data input */
6011 /* status Actual completion status */
6012 /* */
6013 /* CALLS */
6014 /* */
6015 /* _nx_sntp_client_utility_msecs_to_fraction */
6016 /* Actual msecs conversion service */
6017 /* */
6018 /* CALLED BY */
6019 /* */
6020 /* Application code */
6021 /* */
6022 /* RELEASE HISTORY */
6023 /* */
6024 /* DATE NAME DESCRIPTION */
6025 /* */
6026 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6027 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
6028 /* resulting in version 6.1 */
6029 /* */
6030 /**************************************************************************/
_nxe_sntp_client_utility_msecs_to_fraction(ULONG msecs,ULONG * fraction)6031 UINT _nxe_sntp_client_utility_msecs_to_fraction(ULONG msecs, ULONG *fraction)
6032 {
6033
6034 UINT status;
6035
6036
6037 if ((msecs == 0) || (fraction == NX_NULL))
6038 {
6039
6040 return NX_SNTP_INVALID_TIME;
6041 }
6042
6043 status = _nx_sntp_client_utility_msecs_to_fraction(msecs, fraction);
6044
6045 return status;
6046 }
6047
6048
6049 /**************************************************************************/
6050 /* */
6051 /* FUNCTION RELEASE */
6052 /* */
6053 /* _nx_sntp_client_utility_msecs_to_fraction PORTABLE C */
6054 /* 6.1 */
6055 /* AUTHOR */
6056 /* */
6057 /* Yuxin Zhou, Microsoft Corporation */
6058 /* */
6059 /* DESCRIPTION */
6060 /* */
6061 /* This function converts milliseconds to fixed point notation used in */
6062 /* the NTP time fraction field. This will not accept msecs >= 1000 */
6063 /* because that number cannot be represented in an NTP time fraction. */
6064 /* */
6065 /* INPUT */
6066 /* */
6067 /* msecs Milliseconds to convert */
6068 /* fraction Pointer to converted fraction */
6069 /* */
6070 /* OUTPUT */
6071 /* */
6072 /* NX_SUCCESS Successful completion status */
6073 /* NX_SNTP_OVERFLOW_ERROR Overflow result */
6074 /* status Actual completion status */
6075 /* */
6076 /* CALLS */
6077 /* */
6078 /* _nx_sntp_client_utility_usecs_to_fraction */
6079 /* Convert usecs to fixed point */
6080 /* */
6081 /* CALLED BY */
6082 /* */
6083 /* _nx_sntp_client_utility_add_msecs_to_ntp_time */
6084 /* Add msecs to an NTP time data */
6085 /* _nx_sntp_client_utility_add_NTPtime */
6086 /* Add two NTP time fields */
6087 /* */
6088 /* RELEASE HISTORY */
6089 /* */
6090 /* DATE NAME DESCRIPTION */
6091 /* */
6092 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6093 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
6094 /* resulting in version 6.1 */
6095 /* */
6096 /**************************************************************************/
_nx_sntp_client_utility_msecs_to_fraction(ULONG msecs,ULONG * fraction)6097 UINT _nx_sntp_client_utility_msecs_to_fraction(ULONG msecs, ULONG *fraction)
6098 {
6099
6100 UINT status;
6101 ULONG usecs;
6102
6103
6104 /* Check for possible overflow. */
6105 if (msecs > 1000)
6106 {
6107
6108 /* Return error condition. */
6109 return NX_SNTP_OVERFLOW_ERROR;
6110 }
6111
6112 /* Convert msecs to usecs first. */
6113 usecs = msecs * 1000;
6114
6115 /* Convert usecs to fraction. */
6116 status = _nx_sntp_client_utility_usecs_to_fraction(usecs, fraction);
6117
6118 /* Check for error. */
6119 if (status != NX_SUCCESS)
6120 {
6121
6122 /* Return the error status. */
6123 return status;
6124 }
6125
6126 /* Successful completion. */
6127 return NX_SUCCESS;
6128 }
6129
6130
6131 /**************************************************************************/
6132 /* */
6133 /* FUNCTION RELEASE */
6134 /* */
6135 /* _nxe_sntp_client_utility_fraction_to_usecs PORTABLE C */
6136 /* 6.1 */
6137 /* AUTHOR */
6138 /* */
6139 /* Yuxin Zhou, Microsoft Corporation */
6140 /* */
6141 /* DESCRIPTION */
6142 /* */
6143 /* This function performs error checking on the utility to convert */
6144 /* fraction to microseconds. */
6145 /* */
6146 /* INPUT */
6147 /* */
6148 /* fraction Fraction to convert */
6149 /* usecs Pointer to converted microseconds */
6150 /* */
6151 /* OUTPUT */
6152 /* */
6153 /* status Actual completion status */
6154 /* */
6155 /* CALLS */
6156 /* */
6157 /* _nx_sntp_client_utility_fraction_to_usecs */
6158 /* Actual usecs conversion service */
6159 /* */
6160 /* CALLED BY */
6161 /* */
6162 /* Application code */
6163 /* */
6164 /* RELEASE HISTORY */
6165 /* */
6166 /* DATE NAME DESCRIPTION */
6167 /* */
6168 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6169 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
6170 /* resulting in version 6.1 */
6171 /* */
6172 /**************************************************************************/
_nxe_sntp_client_utility_fraction_to_usecs(ULONG fraction,ULONG * usecs)6173 UINT _nxe_sntp_client_utility_fraction_to_usecs(ULONG fraction, ULONG *usecs)
6174 {
6175
6176 UINT status;
6177
6178
6179 if (usecs == NX_NULL)
6180 {
6181 return NX_SNTP_INVALID_TIME;
6182 }
6183
6184 status = _nx_sntp_client_utility_fraction_to_usecs(fraction, usecs);
6185
6186 return status;
6187 }
6188
6189
6190 /**************************************************************************/
6191 /* */
6192 /* FUNCTION RELEASE */
6193 /* */
6194 /* _nx_sntp_client_utility_fraction_to_usecs PORTABLE C */
6195 /* 6.1 */
6196 /* AUTHOR */
6197 /* */
6198 /* Yuxin Zhou, Microsoft Corporation */
6199 /* */
6200 /* DESCRIPTION */
6201 /* */
6202 /* This function converts a time stamp fraction to microseconds. It is */
6203 /* primarily an intermediary function used in the process of converting */
6204 /* fixed point time fraction data to msecs. */
6205 /* */
6206 /* INPUT */
6207 /* */
6208 /* fraction Fraction to convert to usecs */
6209 /* usecs Pointer to ucsecs from fraction */
6210 /* */
6211 /* OUTPUT */
6212 /* */
6213 /* None */
6214 /* */
6215 /* CALLS */
6216 /* */
6217 /* None */
6218 /* */
6219 /* CALLED BY */
6220 /* */
6221 /* _nx_sntp_client_get_local_time_extended */
6222 /* Get extended local time */
6223 /* _nx_sntp_client_utility_convert_fraction_to_msecs */
6224 /* Convert time fraction to msecs */
6225 /* */
6226 /* RELEASE HISTORY */
6227 /* */
6228 /* DATE NAME DESCRIPTION */
6229 /* */
6230 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6231 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
6232 /* resulting in version 6.1 */
6233 /* */
6234 /**************************************************************************/
_nx_sntp_client_utility_fraction_to_usecs(ULONG fraction,ULONG * usecs)6235 UINT _nx_sntp_client_utility_fraction_to_usecs(ULONG fraction, ULONG *usecs)
6236 {
6237
6238 ULONG value, segment;
6239 int i;
6240
6241 value = 0;
6242
6243 for(i = 2; i < 32; i+=6)
6244 {
6245 segment = (fraction >> i) & 0x3F;
6246
6247 if((value & 0x3F) >= 32)
6248 value = (value >> 6) + segment * 15625 + 1;
6249 else
6250 value = (value >> 6) + segment * 15625;
6251 }
6252 *usecs = value;
6253
6254 return(NX_SUCCESS);
6255 }
6256
6257
6258 /**************************************************************************/
6259 /* */
6260 /* FUNCTION RELEASE */
6261 /* */
6262 /* _nx_sntp_client_utility_convert_refID_KOD_code PORTABLE C */
6263 /* 6.1 */
6264 /* AUTHOR */
6265 /* */
6266 /* Yuxin Zhou, Microsoft Corporation */
6267 /* */
6268 /* DESCRIPTION */
6269 /* */
6270 /* This function converts the reference ID field in a NTP time message */
6271 /* data to a known Kiss of Death reference_id. */
6272 /* */
6273 /* Note the Kiss of Death reference_id list is subject to change. This */
6274 /* is current as of 4/01/2007. */
6275 /* */
6276 /* INPUT */
6277 /* */
6278 /* reference_id Pointer to the reference ID to convert */
6279 /* code_id Pointer to converted code */
6280 /* */
6281 /* OUTPUT */
6282 /* */
6283 /* NX_SUCCESS Successful completion status */
6284 /* */
6285 /* CALLS */
6286 /* */
6287 /* memcmp Copy data to specified area of memory */
6288 /* */
6289 /* CALLED BY */
6290 /* */
6291 /* Application Code (e.g. the Client kiss of death handler callback) */
6292 /* */
6293 /* RELEASE HISTORY */
6294 /* */
6295 /* DATE NAME DESCRIPTION */
6296 /* */
6297 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6298 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
6299 /* resulting in version 6.1 */
6300 /* */
6301 /**************************************************************************/
_nx_sntp_client_utility_convert_refID_KOD_code(UCHAR * reference_id,UINT * code_id)6302 UINT _nx_sntp_client_utility_convert_refID_KOD_code(UCHAR *reference_id, UINT *code_id)
6303 {
6304
6305 /* This is the internal list of Kiss of Death codes and their meaning. */
6306
6307
6308 /* Compare the reference_id to each known reference_id and if it matches return the reference_id ID. */
6309 if (!memcmp(reference_id, ANYCAST, 4))
6310 {
6311 *code_id = NX_SNTP_KOD_ANYCAST;
6312 }
6313 else if (!memcmp(reference_id, AUTH_FAIL, 4))
6314 {
6315 *code_id = NX_SNTP_KOD_AUTH_FAIL;
6316 }
6317 else if (!memcmp(reference_id, AUTOKEY_FAIL, 4))
6318 {
6319 *code_id = NX_SNTP_KOD_AUTOKEY_FAIL;
6320 }
6321 else if (!memcmp(reference_id, BROADCAST, 4))
6322 {
6323 *code_id = NX_SNTP_KOD_BROADCAST;
6324 }
6325 else if (!memcmp(reference_id, CRYP_FAIL, 4))
6326 {
6327 *code_id = NX_SNTP_KOD_CRYP_FAIL;
6328 }
6329 else if (!memcmp(reference_id, DENY, 4))
6330 {
6331 *code_id = NX_SNTP_KOD_DENY;
6332 }
6333 else if (!memcmp(reference_id, DROP, 4))
6334 {
6335 *code_id = NX_SNTP_KOD_DROP;
6336 }
6337 else if (!memcmp(reference_id, DENY_POLICY, 4))
6338 {
6339 *code_id = NX_SNTP_KOD_DENY_POLICY;
6340 }
6341 else if (!memcmp(reference_id, NOT_INIT, 4))
6342 {
6343 *code_id = NX_SNTP_KOD_NOT_INIT;
6344 }
6345 else if (!memcmp(reference_id, MANYCAST, 4))
6346 {
6347 *code_id = NX_SNTP_KOD_MANYCAST;
6348 }
6349 else if (!memcmp(reference_id, NO_KEY, 4))
6350 {
6351 *code_id = NX_SNTP_KOD_NO_KEY;
6352 }
6353 else if (!memcmp(reference_id, RATE, 4))
6354 {
6355 *code_id = NX_SNTP_KOD_RATE;
6356 }
6357 else if (!memcmp(reference_id, RMOT, 4))
6358 {
6359 *code_id = NX_SNTP_KOD_RMOT;
6360 }
6361 else if (!memcmp(reference_id, STEP, 4))
6362 {
6363 *code_id = NX_SNTP_KOD_STEP;
6364 }
6365 else
6366 {
6367 /* Set reference_id ID to generic KOD 'other' reference_id. */
6368 *code_id = NX_SNTP_KISS_OF_DEATH_PACKET;
6369 }
6370
6371 /* Return successful completion. */
6372 return NX_SUCCESS;
6373 }
6374
6375
6376 /**************************************************************************/
6377 /* */
6378 /* FUNCTION RELEASE */
6379 /* */
6380 /* _nx_sntp_client_utility_addition_overflow_check PORTABLE C */
6381 /* 6.1 */
6382 /* AUTHOR */
6383 /* */
6384 /* Yuxin Zhou, Microsoft Corporation */
6385 /* */
6386 /* DESCRIPTION */
6387 /* */
6388 /* This function performs a simple platform independent check for */
6389 /* overflow when adding two operands. */
6390 /* */
6391 /* INPUT */
6392 /* */
6393 /* temp1 First addition operand */
6394 /* temp2 Second addition operand */
6395 /* */
6396 /* OUTPUT */
6397 /* */
6398 /* NX_SNTP_OVERFLOW_ERROR Overflow result adding time */
6399 /* NX_SUCCESS Successful completion status */
6400 /* */
6401 /* CALLS */
6402 /* */
6403 /* None */
6404 /* */
6405 /* CALLED BY */
6406 /* */
6407 /* _nx_sntp_client_utility_add_msecs_to_ntp_time */
6408 /* Add msecs to an NTP time */
6409 /* _nx_sntp_client_utility_add_NTPtime */
6410 /* Add two NTP times */
6411 /* */
6412 /* RELEASE HISTORY */
6413 /* */
6414 /* DATE NAME DESCRIPTION */
6415 /* */
6416 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6417 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
6418 /* resulting in version 6.1 */
6419 /* */
6420 /**************************************************************************/
_nx_sntp_client_utility_addition_overflow_check(ULONG temp1,ULONG temp2)6421 UINT _nx_sntp_client_utility_addition_overflow_check(ULONG temp1, ULONG temp2)
6422 {
6423
6424 ULONG sum_lower_16, sum_upper_16;
6425 UINT carry;
6426
6427
6428 carry = 0;
6429
6430 /* Add the lower 16 bits. */
6431 sum_lower_16 = (temp1 & NX_LOWER_16_MASK) + (temp2 & NX_LOWER_16_MASK);
6432
6433 /* Check for carry. */
6434 if (sum_lower_16 & NX_CARRY_BIT)
6435 {
6436
6437 /* Use variable to add the carry to the upper 16 bits.*/
6438 carry = 1;
6439 }
6440
6441 /* Add the upper 16 bits. */
6442 sum_upper_16 = (temp1 >> NX_SHIFT_BY_16) + (temp2 >> NX_SHIFT_BY_16) + carry;
6443
6444 /* Check for carry. */
6445 if (sum_upper_16 & NX_CARRY_BIT)
6446 {
6447
6448 /* This indicates an overflow. Return as an error. */
6449 return NX_SNTP_OVERFLOW_ERROR;
6450 }
6451
6452 /* Ok to add operands!*/
6453 return NX_SUCCESS;
6454 }