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