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.3.0 */
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 /* 10-31-2023 Tiejun Zhou Modified comment(s), and */
2504 /* fixed packet chain issue, */
2505 /* resulting in version 6.3.0 */
2506 /* */
2507 /**************************************************************************/
_nx_sntp_client_receive_time_update(NX_SNTP_CLIENT * client_ptr,ULONG timeout)2508 UINT _nx_sntp_client_receive_time_update(NX_SNTP_CLIENT *client_ptr, ULONG timeout)
2509 {
2510
2511 UINT status;
2512 UINT length;
2513 NX_PACKET *receive_packet;
2514 #ifndef NX_SNTP_CLIENT_MESSAGE_CHECK_DISABLE
2515 UINT sender_port;
2516 NX_UDP_HEADER *udp_header_ptr;
2517 NXD_ADDRESS source_ip_address, destination_ip_address;
2518 #endif /* NX_SNTP_CLIENT_MESSAGE_CHECK_DISABLE */
2519
2520 /* Loop to receive packets. */
2521 for(;;)
2522 {
2523
2524 /* Indicate the SNTP Client can be stopped while the SNTP client waits for a packet. */
2525 client_ptr -> nx_sntp_client_sleep_flag = NX_TRUE;
2526
2527 /* Wait to receive packets on the Client UDP socket. */
2528 status = nx_udp_socket_receive(&(client_ptr -> nx_sntp_client_udp_socket), &receive_packet, timeout * NX_IP_PERIODIC_RATE);
2529
2530 /* Indicate the SNTP Client can not be stopped. */
2531 client_ptr -> nx_sntp_client_sleep_flag = NX_FALSE;
2532
2533 /* Check for error. */
2534 if (status != NX_SUCCESS)
2535 {
2536
2537 /* Return error status. */
2538 return status;
2539 }
2540
2541 #ifndef NX_SNTP_CLIENT_MESSAGE_CHECK_DISABLE
2542 /* Check the sender port in the UDP packet header. */
2543 udp_header_ptr = (NX_UDP_HEADER *)(receive_packet -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER));
2544 sender_port = (UINT)udp_header_ptr -> nx_udp_header_word_0 >> NX_SHIFT_BY_16;
2545
2546 /* Check if this is the server port the Client expects. */
2547 if (sender_port != NX_SNTP_SERVER_UDP_PORT)
2548 {
2549
2550 /* No, reject the packet. */
2551 nx_packet_release(receive_packet);
2552
2553 continue;
2554 }
2555
2556
2557 /* If this an IPv6 packet? An SNTP client with an IPv6 SNTP server will only accept IPv6 packets. */
2558 if ((receive_packet -> nx_packet_ip_version == NX_IP_VERSION_V6) &&
2559 (client_ptr -> nx_sntp_server_ip_address.nxd_ip_version == NX_IP_VERSION_V6))
2560 {
2561
2562 #ifndef FEATURE_NX_IPV6
2563 nx_packet_release(receive_packet);
2564 continue;
2565 #else
2566 NX_IPV6_HEADER *ipv6_header_ptr;
2567
2568 /* Pick up the IPv6 header from the packet. */
2569 ipv6_header_ptr = (NX_IPV6_HEADER *) (receive_packet -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER) - sizeof(NX_IPV6_HEADER));
2570
2571 /* Copy sender address into a local variable. */
2572 COPY_IPV6_ADDRESS(ipv6_header_ptr -> nx_ip_header_source_ip, &(source_ip_address.nxd_ip_address.v6[0]));
2573 source_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
2574
2575 /* Copy destination address into a local variable. */
2576 COPY_IPV6_ADDRESS(ipv6_header_ptr -> nx_ip_header_destination_ip, &(destination_ip_address.nxd_ip_address.v6[0]));
2577 destination_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
2578
2579 if (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE)
2580 {
2581
2582 /* Does the source address match the expected server address? */
2583 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]))
2584 {
2585
2586 /* No further need for the receive packet. Release back to the client pool. */
2587 nx_packet_release(receive_packet);
2588
2589 /* Set update time to null. */
2590 memset(&(client_ptr -> nx_sntp_server_update_time), 0, sizeof(NX_SNTP_TIME));
2591
2592 continue;
2593 }
2594 }
2595 else /* Multicast mode */
2596 {
2597
2598 /* Define the all hosts multicast address. */
2599 NXD_ADDRESS All_Hosts_Multicast;
2600 All_Hosts_Multicast.nxd_ip_version = NX_IP_VERSION_V6;
2601 All_Hosts_Multicast.nxd_ip_address.v6[0] = 0xff020000;
2602 All_Hosts_Multicast.nxd_ip_address.v6[1] = 0x00000000;
2603 All_Hosts_Multicast.nxd_ip_address.v6[2] = 0x00000000;
2604 All_Hosts_Multicast.nxd_ip_address.v6[3] = 0x00000001;
2605
2606 /* Does the source address match the expected server address )? */
2607 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]))
2608 {
2609
2610 /* No further need for the receive packet. Release back to the client pool. */
2611 nx_packet_release(receive_packet);
2612
2613 /* Set update time to null. */
2614 memset(&(client_ptr -> nx_sntp_server_update_time), 0, sizeof(NX_SNTP_TIME));
2615
2616 continue;
2617 }
2618
2619 /* Does the destination address match the expected server address (all hosts address FF02::1)? */
2620 if (!CHECK_IPV6_ADDRESSES_SAME(&destination_ip_address.nxd_ip_address.v6[0], &All_Hosts_Multicast.nxd_ip_address.v6[0]))
2621 {
2622
2623 /* No further need for the receive packet. Release back to the client pool. */
2624 nx_packet_release(receive_packet);
2625
2626 /* Set update time to null. */
2627 memset(&(client_ptr -> nx_sntp_server_update_time), 0, sizeof(NX_SNTP_TIME));
2628
2629 continue;
2630 }
2631
2632 }
2633 #endif /* FEATURE_NX_IPV6 */
2634
2635 }
2636 /* Otherwise is this an IPv4 packet and is the SNTP client set for IPv4? */
2637 else if ((receive_packet -> nx_packet_ip_version == NX_IP_VERSION_V4) &&
2638 (client_ptr -> nx_sntp_server_ip_address.nxd_ip_version == NX_IP_VERSION_V4))
2639 {
2640 #ifdef NX_DISABLE_IPV4
2641 nx_packet_release(receive_packet);
2642 continue;
2643 #else
2644
2645 NX_IPV4_HEADER *ipv4_header_ptr;
2646
2647 ipv4_header_ptr = (NX_IPV4_HEADER *) (receive_packet -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER) - sizeof(NX_IPV4_HEADER));
2648
2649 /* Copy into a local variable. */
2650 source_ip_address.nxd_ip_address.v4 = ipv4_header_ptr -> nx_ip_header_source_ip;
2651 source_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
2652
2653 /* Copy into a local variable. */
2654 destination_ip_address.nxd_ip_address.v4 = ipv4_header_ptr -> nx_ip_header_destination_ip;
2655 destination_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
2656
2657 if (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE)
2658 {
2659 /* Compare the sender address with the Client's current sntp server. */
2660 if (source_ip_address.nxd_ip_address.v4 != client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v4)
2661 {
2662 /* This is an untrusted server or the client had a broadcast server already,
2663 reject this packet and return an error condition. */
2664
2665 /* No further need for the receive packet. Release back to the client pool. */
2666 nx_packet_release(receive_packet);
2667
2668 continue;
2669 }
2670 }
2671 else /* BROADCAST_MODE */
2672 {
2673
2674 ULONG network_mask;
2675 UINT iface_index;
2676
2677 /* Compare the sender address with the Client's current sntp server. */
2678 if (source_ip_address.nxd_ip_address.v4 != client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v4)
2679 {
2680
2681 /* This is an untrusted server or the client had a broadcast server already,
2682 reject this packet and return an error condition. */
2683
2684 /* No further need for the receive packet. Release back to the client pool. */
2685 nx_packet_release(receive_packet);
2686
2687 continue;
2688 }
2689
2690 /* Set a local variable on the SNTP network index. */
2691 iface_index = client_ptr -> nx_sntp_client_interface_index;
2692
2693 /* Set a local variable to the network mask. */
2694 network_mask = client_ptr -> nx_sntp_client_ip_ptr -> nx_ip_interface[iface_index].nx_interface_ip_network_mask;
2695
2696 /* Now verify this is a broadcast packet. */
2697 if ((destination_ip_address.nxd_ip_address.v4 & ~network_mask) != ~network_mask)
2698 {
2699 /* This is not a broadcast packet on the local network. */
2700
2701 /* No further need for the receive packet. Release back to the client pool. */
2702 nx_packet_release(receive_packet);
2703
2704 continue;
2705 }
2706 }
2707 #endif /* NX_DISABLE_IPV4 */
2708 }
2709 else
2710 {
2711 /* Not interested, discard the packet. */
2712 nx_packet_release(receive_packet);
2713
2714 continue;
2715 }
2716
2717 #endif /* NX_SNTP_CLIENT_MESSAGE_CHECK_DISABLE */
2718
2719 /* Check that the packet has the proper length for an NTP message. */
2720 length = receive_packet -> nx_packet_length;
2721
2722 /* Verify the packet data contains at least the minimum time update data,
2723 but no more than the max size with authentication data appended. */
2724
2725 if ((length < NX_SNTP_TIME_MESSAGE_MIN_SIZE) || (length > NX_SNTP_TIME_MESSAGE_MAX_SIZE))
2726 {
2727
2728 /* No further need for the receive packet. Release back to the client pool. */
2729 nx_packet_release(receive_packet);
2730
2731 continue;
2732 }
2733
2734 #ifndef NX_DISABLE_PACKET_CHAIN
2735 /* Ignore packet chain. */
2736 if (receive_packet -> nx_packet_next)
2737 {
2738
2739 /* No further need for the receive packet. Release back to the client pool. */
2740 nx_packet_release(receive_packet);
2741
2742 continue;
2743 }
2744 #endif /* NX_DISABLE_PACKET_CHAIN */
2745
2746 memset(&(client_ptr -> nx_sntp_current_server_time_message), 0, sizeof(NX_SNTP_TIME_MESSAGE));
2747
2748 /* Extract time message data from packet data into time message. */
2749 _nx_sntp_client_extract_time_message_from_packet(client_ptr, receive_packet);
2750
2751 /* No further need for the receive packet. Release back to the client pool. */
2752 nx_packet_release(receive_packet);
2753
2754 return NX_SUCCESS;
2755 }
2756 }
2757
2758
2759 /**************************************************************************/
2760 /* */
2761 /* FUNCTION RELEASE */
2762 /* */
2763 /* _nx_sntp_client_extract_time_message_from_packet PORTABLE C */
2764 /* 6.1.10 */
2765 /* AUTHOR */
2766 /* */
2767 /* Yuxin Zhou, Microsoft Corporation */
2768 /* */
2769 /* DESCRIPTION */
2770 /* */
2771 /* This function extracts time data from an SNTP server packet and */
2772 /* copies the information into the specified time message buffer. */
2773 /* */
2774 /* INPUT */
2775 /* */
2776 /* client_ptr Pointer to SNTP Client */
2777 /* packet_ptr Pointer to server packet */
2778 /* */
2779 /* OUTPUT */
2780 /* */
2781 /* NX_SUCCESS Successful completion status */
2782 /* */
2783 /* CALLS */
2784 /* */
2785 /* memcpy Copy data to area of memory */
2786 /* */
2787 /* CALLED BY */
2788 /* */
2789 /* _nx_sntp_client_receive_time_update Process SNTP server packets */
2790 /* */
2791 /* RELEASE HISTORY */
2792 /* */
2793 /* DATE NAME DESCRIPTION */
2794 /* */
2795 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2796 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
2797 /* verified memcpy use cases, */
2798 /* resulting in version 6.1 */
2799 /* 01-31-2022 Yuxin Zhou Modified comment(s), corrected*/
2800 /* the Reference Identifier, */
2801 /* resulting in version 6.1.10 */
2802 /* */
2803 /**************************************************************************/
_nx_sntp_client_extract_time_message_from_packet(NX_SNTP_CLIENT * client_ptr,NX_PACKET * packet_ptr)2804 UINT _nx_sntp_client_extract_time_message_from_packet(NX_SNTP_CLIENT *client_ptr, NX_PACKET *packet_ptr)
2805 {
2806
2807 ULONG *ntp_word_0;
2808 NX_SNTP_TIME_MESSAGE *time_message_ptr;
2809
2810
2811 time_message_ptr = &(client_ptr -> nx_sntp_current_server_time_message);
2812
2813 process_timerticks = tx_time_get();
2814
2815 memset(time_message_ptr, 0, sizeof(NX_SNTP_TIME_MESSAGE));
2816
2817 /* Pickup the pointer to the head of the UDP packet. */
2818 ntp_word_0 = (ULONG *)packet_ptr -> nx_packet_prepend_ptr;
2819 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2820
2821 /* Extract fields from the first 32 bits of the time message. */
2822 time_message_ptr -> flags = (*ntp_word_0 & 0xFF000000UL) >> 24;
2823
2824 time_message_ptr -> peer_clock_stratum = (*ntp_word_0 & 0x00FF0000UL) >> 16;
2825
2826 time_message_ptr -> peer_poll_interval = (*ntp_word_0 & 0x0000FF00UL) >> 8;
2827
2828 time_message_ptr -> peer_clock_precision = (*ntp_word_0 & 0x00000000FFUL);
2829
2830 /* Advance to the next 32 bit field and extract the root delay field. */
2831 ntp_word_0++;
2832 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2833
2834 time_message_ptr -> root_delay = (ULONG)(*ntp_word_0);
2835
2836 /* Advance to the next 32 bit field and extract the clock dispersion field. */
2837 ntp_word_0++;
2838 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2839
2840 time_message_ptr -> clock_dispersion= *ntp_word_0;
2841
2842 /* Advance to the next 32 bit field and extract the reference clock ID field. */
2843 ntp_word_0++;
2844 memcpy(time_message_ptr -> reference_clock_id, ntp_word_0, 4); /* Use case of memcpy is verified. */
2845
2846 /* Advance to the next field (64 bit field) and extract the reference time stamp field. */
2847 ntp_word_0++;
2848 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2849 time_message_ptr -> reference_clock_update_time_stamp[0] = *ntp_word_0;
2850
2851 ntp_word_0++;
2852 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2853 time_message_ptr -> reference_clock_update_time_stamp[1] = *ntp_word_0;
2854
2855 /* If a non zero reference time was supplied, separate out seconds and fraction. */
2856 if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(time_message_ptr -> reference_clock_update_time_stamp), 8) == NX_FALSE)
2857 {
2858
2859 time_message_ptr -> reference_clock_update_time.seconds = time_message_ptr -> reference_clock_update_time_stamp[0];
2860
2861 time_message_ptr -> reference_clock_update_time.fraction = time_message_ptr -> reference_clock_update_time_stamp[1];
2862 }
2863
2864 /* Copy the first 32 bits into the originate time stamp seconds field. */
2865 ntp_word_0++;
2866 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2867 time_message_ptr -> originate_time_stamp[0] = *ntp_word_0;
2868
2869 /* Copy the next 32 bits into the originate time stamp fraction field. */
2870 ntp_word_0++;
2871 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2872 time_message_ptr -> originate_time_stamp[1] = *ntp_word_0;
2873
2874 /* If an originate time was supplied, separate out seconds and fraction. */
2875 if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(time_message_ptr -> originate_time_stamp), 8) == NX_FALSE)
2876 {
2877
2878 time_message_ptr -> originate_time.seconds = time_message_ptr -> originate_time_stamp[0];
2879
2880 time_message_ptr -> originate_time.fraction = time_message_ptr -> originate_time_stamp[1];
2881 }
2882
2883
2884 /* Copy the first 32 bits into the receive time stamp seconds field. */
2885 ntp_word_0++;
2886 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2887 time_message_ptr -> receive_time_stamp[0] = *ntp_word_0;
2888
2889 /* Copy the next 32 bits into the receive time stamp fraction field. */
2890 ntp_word_0++;
2891 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2892 time_message_ptr -> receive_time_stamp[1] = *ntp_word_0;
2893
2894 /* If an receive time was supplied, separate out seconds and fraction. */
2895 if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(time_message_ptr -> receive_time_stamp), 8) == NX_FALSE)
2896 {
2897
2898 time_message_ptr -> receive_time.seconds = time_message_ptr -> receive_time_stamp[0];
2899 time_message_ptr -> receive_time.fraction = time_message_ptr -> receive_time_stamp[1];
2900 }
2901
2902 /* Copy the first 32 bits into the transmit time stamp seconds field. */
2903 ntp_word_0++;
2904 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2905 time_message_ptr -> transmit_time_stamp[0] = *ntp_word_0;
2906
2907 /* Copy the next 32 bits into the transmit time stamp fraction field. */
2908 ntp_word_0++;
2909 NX_CHANGE_ULONG_ENDIAN(*ntp_word_0);
2910 time_message_ptr -> transmit_time_stamp[1] = *ntp_word_0;
2911
2912 /* If an transmit time was supplied, separate out seconds and fraction. */
2913 if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(time_message_ptr -> transmit_time_stamp), 8) == NX_FALSE)
2914 {
2915
2916 time_message_ptr -> transmit_time.seconds = time_message_ptr -> transmit_time_stamp[0];
2917
2918 time_message_ptr -> transmit_time.fraction = time_message_ptr -> transmit_time_stamp[1];
2919
2920 }
2921
2922 /* Return completion status. */
2923 return NX_SUCCESS;
2924 }
2925
2926
2927 /**************************************************************************/
2928 /* */
2929 /* FUNCTION RELEASE */
2930 /* */
2931 /* _nx_sntp_client_reset_current_time_message PORTABLE C */
2932 /* 6.1 */
2933 /* AUTHOR */
2934 /* */
2935 /* Yuxin Zhou, Microsoft Corporation */
2936 /* */
2937 /* DESCRIPTION */
2938 /* */
2939 /* This function saves the current time message from the server to */
2940 /* the previous time message field, and clears the current time message*/
2941 /* field. */
2942 /* */
2943 /* INPUT */
2944 /* */
2945 /* client_ptr Pointer to Client */
2946 /* */
2947 /* OUTPUT */
2948 /* */
2949 /* NX_SUCCESS Successful completion status */
2950 /* */
2951 /* CALLS */
2952 /* */
2953 /* memset Clear specified area of memory */
2954 /* memcpy Copy data to area of memory */
2955 /* */
2956 /* CALLED BY */
2957 /* */
2958 /* _nx_sntp_client_receive_time_update Process received update packets */
2959 /* */
2960 /* RELEASE HISTORY */
2961 /* */
2962 /* DATE NAME DESCRIPTION */
2963 /* */
2964 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2965 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
2966 /* verified memcpy use cases, */
2967 /* resulting in version 6.1 */
2968 /* */
2969 /**************************************************************************/
_nx_sntp_client_reset_current_time_message(NX_SNTP_CLIENT * client_ptr)2970 UINT _nx_sntp_client_reset_current_time_message(NX_SNTP_CLIENT *client_ptr)
2971 {
2972
2973 /* Does the client have a non NULL current server time update? */
2974 if (client_ptr -> nx_sntp_current_server_time_message.flags)
2975 {
2976
2977 /* Yes, copy to the previous time update. */
2978 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. */
2979
2980 /* Clear the current time update data. */
2981 memset(&(client_ptr -> nx_sntp_current_server_time_message), 0, sizeof(NX_SNTP_TIME_MESSAGE));
2982
2983 }
2984
2985 /* Clear the current time update request. */
2986 memset(&(client_ptr -> nx_sntp_current_time_message_request), 0, sizeof(NX_SNTP_TIME_MESSAGE));
2987
2988 return NX_SUCCESS;
2989 }
2990
2991
2992 /**************************************************************************/
2993 /* */
2994 /* FUNCTION RELEASE */
2995 /* */
2996 /* _nx_sntp_client_process_update_packet PORTABLE C */
2997 /* 6.1 */
2998 /* AUTHOR */
2999 /* */
3000 /* Yuxin Zhou, Microsoft Corporation */
3001 /* */
3002 /* DESCRIPTION */
3003 /* */
3004 /* This function processes SNTP time data received in a server update */
3005 /* packet, applies sanity checks, calculates round trip time, and */
3006 /* updates the Client time with the SNTP server time. */
3007 /* */
3008 /* INPUT */
3009 /* */
3010 /* client_ptr Pointer to Client */
3011 /* */
3012 /* OUTPUT */
3013 /* */
3014 /* NX_SUCCESS Successful completion status */
3015 /* NX_SNTP_BAD_SERVER_ROOT_DISPERSION Server dispersion too high */
3016 /* receive_status Actual packet receive status */
3017 /* */
3018 /* CALLS */
3019 /* */
3020 /* memcmp Copy data to area of memory */
3021 /* _nx_sntp_client_apply_sanity_checks Apply sanity checks to update */
3022 /* _nx_sntp_client_check_server_clock_dispersion */
3023 /* Check server clock dispersion */
3024 /* _nx_sntp_client_calculate_roundtrip */
3025 /* Compute roundtrip time to server*/
3026 /* _nx_sntp_client_process_time_data Apply server time to local time */
3027 /* */
3028 /* CALLED BY */
3029 /* */
3030 /* _nx_sntp_client_process_unicast Process unicast SNTP data */
3031 /* _nx_sntp_client_process_broadcast Process broadcast SNTP data */
3032 /* */
3033 /* RELEASE HISTORY */
3034 /* */
3035 /* DATE NAME DESCRIPTION */
3036 /* */
3037 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3038 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3039 /* resulting in version 6.1 */
3040 /* */
3041 /**************************************************************************/
_nx_sntp_client_process_update_packet(NX_SNTP_CLIENT * client_ptr)3042 UINT _nx_sntp_client_process_update_packet(NX_SNTP_CLIENT *client_ptr)
3043 {
3044
3045 UINT status;
3046
3047 /* Apply client's set of sanity checks on the data. */
3048 status = _nx_sntp_client_apply_sanity_checks(client_ptr);
3049
3050 /* Check for sanity check errors. */
3051 if (status != NX_SUCCESS)
3052 {
3053
3054 /* Count these as bad updates from the server. */
3055 client_ptr -> nx_sntp_client_invalid_time_updates++;
3056
3057 /* Ok to continue Client task. */
3058 return status;
3059 }
3060
3061 /* Check server clock dispersion (if any reported) in first update
3062 from current server for unicast clients. */
3063 if ((client_ptr -> nx_sntp_client_first_update_pending == NX_TRUE) && (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE))
3064 {
3065
3066 status = _nx_sntp_client_check_server_clock_dispersion(client_ptr);
3067
3068 /* Is the server clock variance acceptable? */
3069 if (status != NX_SUCCESS)
3070 {
3071
3072 /* Return the error status. */
3073 return status;
3074 }
3075 }
3076
3077 /* At this point we have received a valid server response. */
3078
3079 /* Clear the count of (consecutive) bad time updates received from this server. */
3080 client_ptr -> nx_sntp_client_invalid_time_updates = 0;
3081
3082 /* Apply server time to local device time. */
3083 status = _nx_sntp_client_process_time_data(client_ptr);
3084
3085 /* Check for error. */
3086 if (status != NX_SUCCESS)
3087 {
3088
3089 /* Return the error condition*/
3090 return status;
3091 }
3092
3093 /* If the Client is configured with a time update callback, call it now. */
3094 if (client_ptr -> nx_sntp_client_time_update_notify)
3095 {
3096
3097 client_ptr -> nx_sntp_client_time_update_notify(&(client_ptr -> nx_sntp_current_server_time_message),
3098 &(client_ptr -> nx_sntp_client_local_ntp_time));
3099 }
3100
3101 return status;
3102 }
3103
3104
3105 /**************************************************************************/
3106 /* */
3107 /* FUNCTION RELEASE */
3108 /* */
3109 /* _nx_sntp_client_duplicate_update_check PORTABLE C */
3110 /* 6.1 */
3111 /* AUTHOR */
3112 /* */
3113 /* Yuxin Zhou, Microsoft Corporation */
3114 /* */
3115 /* DESCRIPTION */
3116 /* */
3117 /* This function performs a comparison of time values between two */
3118 /* time messages to verify they are not duplicates. Duplicate updates */
3119 /* can be a form of denial of service/clogging attack on a host. */
3120 /* */
3121 /* INPUT */
3122 /* */
3123 /* timeA_msg_ptr Pointer to first time update */
3124 /* timeB_msg_ptr Pointer to second time update */
3125 /* is_a_dupe Result of comparison */
3126 /* */
3127 /* OUTPUT */
3128 /* */
3129 /* NX_SUCCESS Successful completion status */
3130 /* */
3131 /* CALLS */
3132 /* */
3133 /* memcmp Copy data to area of memory */
3134 /* */
3135 /* CALLED BY */
3136 /* */
3137 /* _nx_sntp_client_apply_sanity_checks Verify received SNTP data */
3138 /* */
3139 /* RELEASE HISTORY */
3140 /* */
3141 /* DATE NAME DESCRIPTION */
3142 /* */
3143 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3144 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3145 /* resulting in version 6.1 */
3146 /* */
3147 /**************************************************************************/
_nx_sntp_client_duplicate_update_check(NX_SNTP_TIME_MESSAGE * timeA_msg_ptr,NX_SNTP_TIME_MESSAGE * timeB_msg_ptr,UINT * is_a_dupe)3148 UINT _nx_sntp_client_duplicate_update_check(NX_SNTP_TIME_MESSAGE *timeA_msg_ptr,
3149 NX_SNTP_TIME_MESSAGE *timeB_msg_ptr,
3150 UINT *is_a_dupe)
3151 {
3152
3153 *is_a_dupe = NX_FALSE;
3154
3155 if ( (!memcmp(timeA_msg_ptr -> transmit_time_stamp,
3156 timeB_msg_ptr -> transmit_time_stamp, 8)) &&
3157 (!memcmp(timeA_msg_ptr -> receive_time_stamp,
3158 timeB_msg_ptr -> receive_time_stamp, 8)) &&
3159 (!memcmp(timeA_msg_ptr -> originate_time_stamp,
3160 timeB_msg_ptr -> originate_time_stamp, 8)) &&
3161 (!memcmp(timeA_msg_ptr -> reference_clock_update_time_stamp,
3162 timeB_msg_ptr -> reference_clock_update_time_stamp, 8)) &&
3163 (!memcmp(timeA_msg_ptr -> reference_clock_id,
3164 timeB_msg_ptr -> reference_clock_id, 4)) &&
3165 (timeA_msg_ptr -> root_delay == timeB_msg_ptr -> root_delay) &&
3166 (timeA_msg_ptr -> clock_dispersion == timeB_msg_ptr -> clock_dispersion)
3167 )
3168 {
3169
3170 *is_a_dupe = NX_TRUE;
3171 }
3172
3173 return NX_SUCCESS;
3174 }
3175
3176
3177 /**************************************************************************/
3178 /* */
3179 /* FUNCTION RELEASE */
3180 /* */
3181 /* _nx_sntp_client_apply_sanity_checks PORTABLE C */
3182 /* 6.1 */
3183 /* AUTHOR */
3184 /* */
3185 /* Yuxin Zhou, Microsoft Corporation */
3186 /* */
3187 /* DESCRIPTION */
3188 /* */
3189 /* This function checks for invalid SNTP data received from server. */
3190 /* */
3191 /* INPUT */
3192 /* */
3193 /* client_ptr Pointer to Client */
3194 /* */
3195 /* OUTPUT */
3196 /* */
3197 /* NX_SNTP_DUPE_SERVER_PACKET Duplicate server packet received */
3198 /* NX_SNTP_INVALID_SERVER_MODE Server mode won't work with Client */
3199 /* NX_SNTP_INVALID_NTP_VERSION Server NTP version won't work with */
3200 /* Client NTP version. */
3201 /* NX_SNTP_SERVER_CLOCK_NOT_SYNC Server is not ready to send updates*/
3202 /* NX_SNTP_INVALID_SERVER_STRATUM Server stratum not acceptable */
3203 /* NX_SNTP_NULL_SERVER_TIMESTAMP Invalid or NULL timestamp in update*/
3204 /* status Actual completion status */
3205 /* */
3206 /* CALLS */
3207 /* */
3208 /* memcmp Copy data into area of memory */
3209 /* _nx_sntp_client_duplicate_update_check */
3210 /* Check for duplicate updates service*/
3211 /* _nx_sntp_client_utility_get_msec_diff */
3212 /* Check for time difference in msecs */
3213 /* */
3214 /* CALLED BY */
3215 /* */
3216 /* _nx_sntp_client_run_broadcast Receive broadcast SNTP updates */
3217 /* _nx_sntp_client_run_unicast Send and receive SNTP updates */
3218 /* */
3219 /* RELEASE HISTORY */
3220 /* */
3221 /* DATE NAME DESCRIPTION */
3222 /* */
3223 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3224 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3225 /* resulting in version 6.1 */
3226 /* */
3227 /**************************************************************************/
_nx_sntp_client_apply_sanity_checks(NX_SNTP_CLIENT * client_ptr)3228 UINT _nx_sntp_client_apply_sanity_checks(NX_SNTP_CLIENT *client_ptr)
3229 {
3230
3231
3232 UINT status;
3233 UINT mode;
3234 UINT leap_second_indicator;
3235 UINT server_ntp_version;
3236 UINT is_a_dupe_check;
3237 ULONG msecs;
3238 NX_SNTP_TIME_MESSAGE *server_time_msg_ptr;
3239
3240 server_time_msg_ptr = &(client_ptr -> nx_sntp_current_server_time_message);
3241
3242 /* Was a previous response received from the server? */
3243 if (client_ptr -> nx_sntp_previous_server_time_message.flags)
3244 {
3245
3246 /* Yes; perform a duplicate packet check. */
3247 status = _nx_sntp_client_duplicate_update_check(&(client_ptr -> nx_sntp_current_server_time_message),
3248 &(client_ptr -> nx_sntp_previous_server_time_message),
3249 &is_a_dupe_check);
3250 /* Check for error. */
3251 if (status != NX_SUCCESS)
3252 {
3253
3254 /* Return error status. */
3255 return status;
3256 }
3257
3258 /* Is this a duplicate packet (e.g. possible 'clogging' attack)? */
3259 if (is_a_dupe_check)
3260 {
3261
3262 return NX_SNTP_DUPE_SERVER_PACKET;
3263 }
3264 }
3265
3266 /* Get the association type from the server. */
3267 mode = server_time_msg_ptr ->flags & 0x07;
3268
3269 /* Is the server of the correct association for a unicast client? */
3270 if ((mode != PROTOCOL_MODE_SERVER_UNICAST) && (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE))
3271 {
3272
3273 /* Return error status. */
3274 return NX_SNTP_INVALID_SERVER_MODE;
3275 }
3276 /* Is the server of the correct association for a broadcast client? */
3277 else if ((mode != PROTOCOL_MODE_SERVER_BROADCAST) && (client_ptr -> nx_sntp_client_protocol_mode == BROADCAST_MODE))
3278 {
3279
3280 /* Return error status. */
3281 return NX_SNTP_INVALID_SERVER_MODE;
3282 }
3283
3284 /* Extract server's NTP version from the flags field. */
3285 server_ntp_version = (server_time_msg_ptr -> flags & 0x38) >> 3;
3286
3287 /* As per NTP protocol, check if the server reply has the same SNTP version that
3288 the Client sent in its unicast request. */
3289 if ((server_ntp_version != NX_SNTP_CLIENT_NTP_VERSION) && (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE))
3290 {
3291
3292 /* Return the error condition. */
3293 return NX_SNTP_INVALID_NTP_VERSION;
3294 }
3295 /* If broadcast, verify the server SNTP version is compatible with the Client. */
3296 else if ((server_ntp_version < NX_SNTP_CLIENT_MIN_NTP_VERSION) && (client_ptr -> nx_sntp_client_protocol_mode == BROADCAST_MODE))
3297 {
3298
3299 /* Return the error condition. */
3300 return NX_SNTP_INVALID_NTP_VERSION;
3301 }
3302
3303 /* Get the leap second indicator from the flags field. */
3304 leap_second_indicator = (server_time_msg_ptr -> flags & 0xC0) >> 6;
3305
3306 /* Is the server clock not yet synchronized? */
3307 if (leap_second_indicator == 3)
3308 {
3309 /* Return the error condition. */
3310 return NX_SNTP_SERVER_CLOCK_NOT_SYNC;
3311 }
3312
3313 /* Has the server sent a 'kiss of death' (stratum = 0) packet? */
3314 if (server_time_msg_ptr -> peer_clock_stratum == 0)
3315 {
3316
3317 /* Does the Client have a kiss of death handler? */
3318 if (client_ptr -> kiss_of_death_handler)
3319 {
3320 UINT code_id;
3321
3322 /* Convert the message to code.*/
3323 _nx_sntp_client_utility_convert_refID_KOD_code(server_time_msg_ptr -> reference_clock_id, &code_id);
3324
3325 /* Yes, let the handler deal with this server response. */
3326 status = (client_ptr -> kiss_of_death_handler)(client_ptr, code_id);
3327
3328 /* Is it ok to continue with this server? */
3329 if (status != NX_SUCCESS)
3330 {
3331
3332 /* No, it is not. Return the error condition. */
3333 return status;
3334 }
3335 }
3336 else
3337 {
3338 /* It is not ok to continue. Return the error condition. */
3339 return NX_SNTP_KOD_SERVER_NOT_AVAILABLE;
3340 }
3341 }
3342
3343 /* Is the server stratum a valid stratum ? */
3344 else if (server_time_msg_ptr -> peer_clock_stratum & STRATUM_RESERVED)
3345 {
3346
3347 /* Return error status. */
3348 return NX_SNTP_INVALID_SERVER_STRATUM;
3349
3350 }
3351 /* Does the server stratum acceptable to the Client? */
3352 else if (server_time_msg_ptr -> peer_clock_stratum > NX_SNTP_CLIENT_MIN_SERVER_STRATUM)
3353 {
3354
3355 /* Return error status. */
3356 return NX_SNTP_INVALID_SERVER_STRATUM;
3357 }
3358
3359 /* Is the Client operating in unicast mode? */
3360 if (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE)
3361 {
3362 UINT pos_diff = NX_TRUE;
3363
3364 /* Yes; Are any server time stamps NULL? */
3365
3366 /* Special case: the client has not set its local time. Only check server's receive and transmit time. */
3367 if (client_ptr -> nx_sntp_client_local_ntp_time.seconds == 0)
3368 {
3369 if ((_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> receive_time_stamp), 8) == NX_TRUE) ||
3370 (_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> transmit_time_stamp), 8) == NX_TRUE))
3371 {
3372
3373 /* Return error status. */
3374 return NX_SNTP_INVALID_TIMESTAMP;
3375 }
3376
3377 }
3378 else
3379 {
3380 /* Check all server time stamps to be non null. */
3381 if ((_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> originate_time_stamp), 8) == NX_TRUE) ||
3382 (_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> receive_time_stamp), 8) == NX_TRUE) ||
3383 (_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> transmit_time_stamp), 8) == NX_TRUE))
3384 {
3385
3386 /* Return error status. */
3387 return NX_SNTP_INVALID_TIMESTAMP;
3388 }
3389
3390 }
3391
3392 /* Get the time difference server transmit time - server receive time. */
3393 status = _nx_sntp_client_utility_get_msec_diff(&(server_time_msg_ptr -> receive_time),
3394 &(server_time_msg_ptr -> transmit_time),
3395 &msecs, &pos_diff);
3396
3397 /* Is the server transmit time <= server receive time [physically not possible]? */
3398 if (status != NX_SUCCESS)
3399 {
3400
3401 /* Yes; Return the error condition. */
3402 return status;
3403 }
3404 else if (pos_diff == NX_FALSE)
3405 {
3406
3407 /* treat as an error in this case. */
3408 return NX_SNTP_INVALID_TIMESTAMP;
3409 }
3410 }
3411 /* Client is in broadcast mode. */
3412 else
3413 {
3414
3415 /* Is the broadcast server transmit time stamp is NULL? */
3416 if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> transmit_time_stamp), 8) == NX_TRUE)
3417
3418 {
3419
3420 /* Return the error status. */
3421 return NX_SNTP_INVALID_TIMESTAMP;
3422 }
3423 }
3424
3425 /* Is there an impending leap second adjustment? */
3426 if ((leap_second_indicator == 1) || (leap_second_indicator == 2))
3427 {
3428
3429 /* Does the Client have a leap second handler?*/
3430 if (client_ptr -> leap_second_handler)
3431 {
3432
3433 /* Yes, invoke the leap second handler for impending leap second event. */
3434 (client_ptr -> leap_second_handler)(client_ptr, leap_second_indicator);
3435 }
3436 }
3437
3438 /* Return successful completion status. */
3439 return NX_SUCCESS;
3440 }
3441
3442
3443 /**************************************************************************/
3444 /* */
3445 /* FUNCTION RELEASE */
3446 /* */
3447 /* _nx_sntp_client_check_server_clock_dispersion PORTABLE C */
3448 /* 6.1 */
3449 /* AUTHOR */
3450 /* */
3451 /* Yuxin Zhou, Microsoft Corporation */
3452 /* */
3453 /* DESCRIPTION */
3454 /* */
3455 /* This function checks server clock dispersion extracted from server */
3456 /* time message in 32 bit representation: */
3457 /* sum of 1/(2 ^ bit) of bits 16-31 in the time message format */
3458 /* and compares it against the Client's dispersion tolerance. */
3459 /* */
3460 /* If NX_SNTP_CLIENT_MAX_ROOT_DISPERSION is set to zero, the function */
3461 /* simply returns a successful result but does no calculations. */
3462 /* */
3463 /* INPUT */
3464 /* */
3465 /* client_ptr Pointer to Client */
3466 /* */
3467 /* OUTPUT */
3468 /* */
3469 /* NX_SUCCESS dispersion is acceptable */
3470 /* NX_SNTP_BAD_SERVER_ROOT_DISPERSION dispersion is too large */
3471 /* */
3472 /* CALLS */
3473 /* */
3474 /* None */
3475 /* */
3476 /* CALLED BY */
3477 /* */
3478 /* _nx_sntp_client_process_update_packet */
3479 /* Process time data in update packets */
3480 /* */
3481 /* RELEASE HISTORY */
3482 /* */
3483 /* DATE NAME DESCRIPTION */
3484 /* */
3485 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3486 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3487 /* resulting in version 6.1 */
3488 /* */
3489 /**************************************************************************/
3490
_nx_sntp_client_check_server_clock_dispersion(NX_SNTP_CLIENT * client_ptr)3491 UINT _nx_sntp_client_check_server_clock_dispersion(NX_SNTP_CLIENT *client_ptr)
3492 {
3493
3494 #if (NX_SNTP_CLIENT_MAX_ROOT_DISPERSION != 0)
3495 UINT mask = 0x8000;
3496 UINT bit = 1;
3497 ULONG divisor;
3498 ULONG dispersion_usecs;
3499
3500 /* Check for zero clock dispersion reported in server update. */
3501 if (client_ptr -> nx_sntp_current_server_time_message.clock_dispersion == 0)
3502 {
3503
3504 /* Return successful status. */
3505 return NX_SUCCESS;
3506 }
3507
3508 /* Get the most significant 16 bits of dispersion field and convert to microseconds.*/
3509 dispersion_usecs = (client_ptr -> nx_sntp_current_server_time_message.clock_dispersion >> 16) * 1000000;
3510
3511 /* Compare seconds in the most significant 16 bits against the Client dispersion tolerance. */
3512 if (dispersion_usecs > NX_SNTP_CLIENT_MAX_ROOT_DISPERSION)
3513 {
3514
3515 /* Yes, indicate that server clock dispersion exceeds tolerance. */
3516 return NX_SNTP_BAD_SERVER_ROOT_DISPERSION;
3517 }
3518
3519 /* Compare fraction from least significant 16 bits; sum of (1 / 2 ^ bit field) of lower 16 bits. */
3520
3521 /* Get the lower 16 bits. */
3522 client_ptr -> nx_sntp_current_server_time_message.clock_dispersion =
3523 client_ptr -> nx_sntp_current_server_time_message.clock_dispersion & 0xFFFF;
3524
3525 /* Compute the dispersion. */
3526 while(mask)
3527 {
3528 if (mask & client_ptr -> nx_sntp_current_server_time_message.clock_dispersion)
3529 {
3530 divisor = (ULONG)(1 << bit);
3531 if ((divisor < 1000000) && (divisor > 0))
3532 {
3533 dispersion_usecs += 1000000/divisor;
3534 }
3535 }
3536 bit++;
3537 mask >>= 1;
3538 }
3539
3540 /* Is the computed clock dispersion more than the max tolerance? */
3541 if (dispersion_usecs > NX_SNTP_CLIENT_MAX_ROOT_DISPERSION)
3542 {
3543 /* Yes, indicate that server clock dispersion exceeds tolerance. */
3544 return NX_SNTP_BAD_SERVER_ROOT_DISPERSION;
3545 }
3546 #else
3547 NX_PARAMETER_NOT_USED(client_ptr);
3548 #endif /* (NX_SNTP_CLIENT_MAX_ROOT_DISPERSION != 0) */
3549
3550 /* Return successful computation. */
3551 return NX_SUCCESS;
3552 }
3553
3554
3555 /**************************************************************************/
3556 /* */
3557 /* FUNCTION RELEASE */
3558 /* */
3559 /* _nx_sntp_client_thread_entry PORTABLE C */
3560 /* 6.1 */
3561 /* AUTHOR */
3562 /* */
3563 /* Yuxin Zhou, Microsoft Corporation */
3564 /* */
3565 /* DESCRIPTION */
3566 /* */
3567 /* This function is the processing thread for the SNTP Client. It */
3568 /* executes periodic SNTP tasks with SNTP Client mutex protection, then*/
3569 /* briefly sleeps to allow the host application to call SNTP Client */
3570 /* services. */
3571 /* */
3572 /* INPUT */
3573 /* */
3574 /* sntp_instance Pointer to SNTP instance */
3575 /* */
3576 /* OUTPUT */
3577 /* */
3578 /* None */
3579 /* */
3580 /* CALLS */
3581 /* */
3582 /* _nx_sntp_client_process Main SNTP processing function */
3583 /* tx_thread_sleep Sleep for specified time */
3584 /* tx_mutex_get Get the SNTP mutex */
3585 /* tx_mutex_put Release the SNTP mutex */
3586 /* tx_thread_preemption_change Change thread preemption */
3587 /* */
3588 /* CALLED BY */
3589 /* */
3590 /* ThreadX */
3591 /* */
3592 /* RELEASE HISTORY */
3593 /* */
3594 /* DATE NAME DESCRIPTION */
3595 /* */
3596 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3597 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3598 /* resulting in version 6.1 */
3599 /* */
3600 /**************************************************************************/
_nx_sntp_client_thread_entry(ULONG sntp_instance)3601 VOID _nx_sntp_client_thread_entry(ULONG sntp_instance)
3602 {
3603
3604 NX_SNTP_CLIENT *client_ptr;
3605 UINT status;
3606 UINT current_preemption;
3607
3608
3609 /* Setup the SNTP pointer. */
3610 client_ptr = (NX_SNTP_CLIENT *) sntp_instance;
3611
3612 /* Enter while loop. */
3613 do
3614 {
3615
3616 /* Loop for obtaining the SNTP mutex. */
3617 do
3618 {
3619
3620 /* Get the SNTP mutex. */
3621 status = tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER);
3622
3623 } while (status != TX_SUCCESS);
3624
3625 /* Perform periodic tasks for the SNTP Client. */
3626 _nx_sntp_client_process(client_ptr);
3627
3628 /* Release the SNTP mutex. */
3629 tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex));
3630
3631 /* Disable preemption for critical section. */
3632 tx_thread_preemption_change(tx_thread_identify(), 0, ¤t_preemption);
3633
3634 /* Indicate the SNTP Client process is idle. */
3635 client_ptr -> nx_sntp_client_sleep_flag = NX_TRUE;
3636
3637 /* Sleep for timer interval. */
3638 tx_thread_sleep(NX_SNTP_CLIENT_SLEEP_INTERVAL);
3639
3640 /* Clear flag to indicate SNTP thread is not in a position to be stopped. */
3641 client_ptr -> nx_sntp_client_sleep_flag = NX_FALSE;
3642
3643 /* Restore original preemption. */
3644 tx_thread_preemption_change(tx_thread_identify(), current_preemption, ¤t_preemption);
3645
3646
3647 } while (1);
3648 }
3649
3650
3651 /**************************************************************************/
3652 /* */
3653 /* FUNCTION RELEASE */
3654 /* */
3655 /* _nx_sntp_client_receive_notify PORTABLE C */
3656 /* 6.1 */
3657 /* AUTHOR */
3658 /* */
3659 /* Yuxin Zhou, Microsoft Corporation */
3660 /* */
3661 /* DESCRIPTION */
3662 /* */
3663 /* This function sets the socket receive callback for the SNTP Client */
3664 /* UDP socket. It sets a flag for the SNTP Client thread to know there*/
3665 /* is a packet waiting to be processed. */
3666 /* */
3667 /* INPUT */
3668 /* */
3669 /* socket_ptr Pointer to Client UDP socket */
3670 /* */
3671 /* OUTPUT */
3672 /* */
3673 /* None */
3674 /* */
3675 /* CALLS */
3676 /* */
3677 /* tx_event_flags_set Sets a receive event */
3678 /* */
3679 /* CALLED BY */
3680 /* */
3681 /* ThreadX */
3682 /* */
3683 /* RELEASE HISTORY */
3684 /* */
3685 /* DATE NAME DESCRIPTION */
3686 /* */
3687 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3688 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3689 /* resulting in version 6.1 */
3690 /* */
3691 /**************************************************************************/
_nx_sntp_client_receive_notify(NX_UDP_SOCKET * socket_ptr)3692 VOID _nx_sntp_client_receive_notify(NX_UDP_SOCKET *socket_ptr)
3693 {
3694 NX_PARAMETER_NOT_USED(socket_ptr);
3695
3696 /* Wakeup all threads that are attempting to perform a receive or that had their select satisfied. */
3697 tx_event_flags_set(&nx_sntp_client_events, NX_SNTP_CLIENT_RECEIVE_EVENT, TX_OR);
3698
3699 receive_timerticks = tx_time_get();
3700
3701 return;
3702 }
3703
3704
3705 /**************************************************************************/
3706 /* */
3707 /* FUNCTION RELEASE */
3708 /* */
3709 /* _nx_sntp_client_process PORTABLE C */
3710 /* 6.1 */
3711 /* AUTHOR */
3712 /* */
3713 /* Yuxin Zhou, Microsoft Corporation */
3714 /* */
3715 /* DESCRIPTION */
3716 /* */
3717 /* This function is called periodically by the SNTP client thread, and */
3718 /* depending on the CLient mode (unicast or broadcast) calls the */
3719 /* unicast or broadcast process function. */
3720 /* */
3721 /* INPUT */
3722 /* */
3723 /* client_ptr Pointer to the SNTP client */
3724 /* */
3725 /* OUTPUT */
3726 /* */
3727 /* None */
3728 /* */
3729 /* CALLS */
3730 /* */
3731 /* _nx_sntp_client_process_unicast Process unicast tasks */
3732 /* _nx_sntp_client_process_broadcast Process broadcast tasks */
3733 /* */
3734 /* CALLED BY */
3735 /* */
3736 /* ThreadX */
3737 /* */
3738 /* RELEASE HISTORY */
3739 /* */
3740 /* DATE NAME DESCRIPTION */
3741 /* */
3742 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3743 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3744 /* resulting in version 6.1 */
3745 /* */
3746 /**************************************************************************/
_nx_sntp_client_process(NX_SNTP_CLIENT * client_ptr)3747 VOID _nx_sntp_client_process(NX_SNTP_CLIENT *client_ptr)
3748 {
3749
3750
3751 /* Is the client using unicast or unicast to receive updates? */
3752 if (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE)
3753 {
3754 /* Call the unicast process function. */
3755 _nx_sntp_client_process_unicast(client_ptr);
3756 }
3757 else
3758 {
3759
3760 /* Call the broadcast process function. */
3761 _nx_sntp_client_process_broadcast(client_ptr);
3762 }
3763
3764 return;
3765 }
3766
3767
3768 /**************************************************************************/
3769 /* */
3770 /* FUNCTION RELEASE */
3771 /* */
3772 /* _nx_sntp_client_process_time_data PORTABLE C */
3773 /* 6.1 */
3774 /* AUTHOR */
3775 /* */
3776 /* Yuxin Zhou, Microsoft Corporation */
3777 /* */
3778 /* DESCRIPTION */
3779 /* */
3780 /* This function applies the server time data to client local time taking*/
3781 /* into account the round trip time. Time updates are checked for a max */
3782 /* time offset set by the Client max_time_adjustment parameter. */
3783 /* */
3784 /* INPUT */
3785 /* */
3786 /* client_ptr Pointer to Client */
3787 /* */
3788 /* OUTPUT */
3789 /* */
3790 /* NX_SUCCESS Successful completion status */
3791 /* NX_SNTP_INVALID_SERVER_UPDATE_TIME No time of server update recorded*/
3792 /* status Actual completion status */
3793 /* */
3794 /* CALLS */
3795 /* */
3796 /* memset Clear specified area of memory */
3797 /* memcpy Copy data to area of memory */
3798 /* _nx_sntp_client_utility_add_msecs_to_ntp_time */
3799 /* Add msec to NTP time fraction field*/
3800 /* _nx_sntp_client_utility_get_msec_diff */
3801 /* Compute time difference in msecs */
3802 /* _nx_sntp_client_utility_add_msecs_to_ntp_time */
3803 /* Add time in msecs to an NTP time */
3804 /* */
3805 /* CALLED BY */
3806 /* */
3807 /* _nx_sntp_client_run_broadcast Listen and process broadcast updates*/
3808 /* _nx_sntp_client_process_update_packet */
3809 /* Process update SNTP packets */
3810 /* */
3811 /* RELEASE HISTORY */
3812 /* */
3813 /* DATE NAME DESCRIPTION */
3814 /* */
3815 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3816 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
3817 /* verified memcpy use cases, */
3818 /* resulting in version 6.1 */
3819 /* */
3820 /**************************************************************************/
_nx_sntp_client_process_time_data(NX_SNTP_CLIENT * client_ptr)3821 UINT _nx_sntp_client_process_time_data(NX_SNTP_CLIENT *client_ptr)
3822 {
3823
3824 UINT status;
3825 UINT ignore_max_adjustment_limit;
3826 ULONG elapsed_msecs_difference;
3827 UINT adjustment;
3828 NX_SNTP_TIME local_time;
3829
3830
3831 /* Copy the received time update to the update time just received from the server. */
3832 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. */
3833
3834 /* Check if the client is configured for round trip time calculation. */
3835 if (NX_SNTP_CLIENT_RTT_REQUIRED == NX_TRUE)
3836 {
3837
3838 /* Compute roundtrip delay. */
3839 _nx_sntp_client_calculate_roundtrip(&(client_ptr -> nx_sntp_client_roundtrip_time_msec));
3840
3841 /* Has the client computed a valid round trip time? */
3842 if (client_ptr -> nx_sntp_client_roundtrip_time_msec)
3843 {
3844
3845 /* Yes, Add 1/2 round trip to server's reported time. */
3846 status =_nx_sntp_client_utility_add_msecs_to_ntp_time(&(client_ptr -> nx_sntp_current_server_time_message.transmit_time),
3847 ((client_ptr -> nx_sntp_client_roundtrip_time_msec) / 2));
3848
3849 if (status != NX_SUCCESS)
3850 {
3851
3852 /* Cannot use this time update. */
3853 return status;
3854 }
3855 }
3856 }
3857
3858 /* Is this the first update? */
3859 if (client_ptr -> nx_sntp_client_first_update_pending == NX_TRUE)
3860 {
3861 /* Check Client configuration if we ignore max adjustment limit on first update. */
3862 ignore_max_adjustment_limit = NX_SNTP_CLIENT_IGNORE_MAX_ADJUST_STARTUP;
3863 }
3864 else
3865 ignore_max_adjustment_limit = NX_FALSE;
3866
3867 /* If not ignoring the max adjustment, deal with time difference between client and server. */
3868 if (ignore_max_adjustment_limit == NX_FALSE)
3869 {
3870 UINT pos_diff = NX_TRUE;
3871
3872 /* Compute difference of server update packet minus the client's local time. It is reasonable
3873 to assume that the Client time is 'behind' the server time because it is updated by the
3874 server time. */
3875 local_time.seconds = client_ptr -> nx_sntp_client_local_ntp_time.seconds +
3876 client_ptr -> nx_sntp_client_local_ntp_time_elapsed;
3877 local_time.fraction = client_ptr -> nx_sntp_client_local_ntp_time.fraction;
3878 status = _nx_sntp_client_utility_get_msec_diff(&local_time,
3879 &(client_ptr -> nx_sntp_server_update_time),
3880 &elapsed_msecs_difference, &pos_diff);
3881
3882
3883 /* Note that a positive difference vs negative difference is not an error. */
3884 if (status != NX_SUCCESS)
3885 {
3886
3887 /* Cannot use this time update. */
3888 return status;
3889 }
3890
3891 /* Is the difference less than the client's minimum adjustment? */
3892 if (elapsed_msecs_difference > NX_SNTP_CLIENT_MIN_TIME_ADJUSTMENT)
3893 {
3894
3895 /* The adjustment is larger than the Client's minimum adjustment. */
3896
3897 /* Set the local clock to the server time only if 1)we are ignoring the maximum adjustment on startup,
3898 or 2) the difference is within the Client's max time adjustment. */
3899 if (elapsed_msecs_difference > NX_SNTP_CLIENT_MAX_TIME_ADJUSTMENT)
3900 {
3901 /* Cannot use this time update. */
3902 return NX_SNTP_INVALID_TIME;
3903 }
3904 }
3905 }
3906
3907 /* Ok to update client local time. */
3908 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. */
3909 client_ptr -> nx_sntp_client_local_ntp_time_elapsed = 0;
3910
3911 /* Apply a correction to server's time for internal SNTP Client delays e.g. periodic task intervals. */
3912 adjustment = ((process_timerticks - receive_timerticks) * 1000) / NX_IP_PERIODIC_RATE;
3913
3914 status = _nx_sntp_client_utility_add_msecs_to_ntp_time(&(client_ptr -> nx_sntp_client_local_ntp_time), (LONG)adjustment);
3915
3916 /* Done processing time update. */
3917 return status;
3918 }
3919
3920
3921 /**************************************************************************/
3922 /* */
3923 /* FUNCTION RELEASE */
3924 /* */
3925 /* _nx_sntp_client_calculate_roundtrip PORTABLE C */
3926 /* 6.1 */
3927 /* AUTHOR */
3928 /* */
3929 /* Yuxin Zhou, Microsoft Corporation */
3930 /* */
3931 /* DESCRIPTION */
3932 /* */
3933 /* This function computes roundtrip based on the elapsed time from */
3934 /* sending the unicast request to receiving the SNTP response. */
3935 /* */
3936 /* INPUT */
3937 /* */
3938 /* roundtrip_time round trip time computation */
3939 /* */
3940 /* OUTPUT */
3941 /* */
3942 /* NX_SUCCESS Valid time computations result */
3943 /* */
3944 /* CALLS */
3945 /* */
3946 /* None */
3947 /* */
3948 /* CALLED BY */
3949 /* */
3950 /* _nx_sntp_client_process_update_packet */
3951 /* Process server update packet */
3952 /* */
3953 /* RELEASE HISTORY */
3954 /* */
3955 /* DATE NAME DESCRIPTION */
3956 /* */
3957 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3958 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3959 /* resulting in version 6.1 */
3960 /* */
3961 /**************************************************************************/
_nx_sntp_client_calculate_roundtrip(LONG * roundtrip_time)3962 UINT _nx_sntp_client_calculate_roundtrip(LONG *roundtrip_time)
3963 {
3964
3965 ULONG x;
3966
3967
3968 /* Initialize invalid results. */
3969 *roundtrip_time = 0;
3970
3971 /* Compute the roundtrip as the time the packet left the SNTP Client
3972 to the time it received a response from the SNTP server. */
3973
3974 /* Check for wrapped timer value. */
3975 if (send_timerticks > receive_timerticks)
3976 {
3977 /* The time has wrapped. */
3978 x = 0xFFFFFFFF - send_timerticks;
3979 *roundtrip_time = (LONG)(receive_timerticks + x);
3980 }
3981 else
3982 {
3983 *roundtrip_time = (LONG)(receive_timerticks - send_timerticks);
3984 }
3985
3986 /* Convert to milliseconds. */
3987 *roundtrip_time = (LONG)((ULONG)(*roundtrip_time) * NX_SNTP_MILLISECONDS_PER_TICK);
3988
3989 /* Return successful completion. */
3990 return NX_SUCCESS;
3991 }
3992
3993
3994 /**************************************************************************/
3995 /* */
3996 /* FUNCTION RELEASE */
3997 /* */
3998 /* _nxe_sntp_client_get_local_time PORTABLE C */
3999 /* 6.1 */
4000 /* AUTHOR */
4001 /* */
4002 /* Yuxin Zhou, Microsoft Corporation */
4003 /* */
4004 /* DESCRIPTION */
4005 /* */
4006 /* This function performs error checking for the get local time service.*/
4007 /* */
4008 /* INPUT */
4009 /* */
4010 /* client_ptr Pointer to SNTP Client */
4011 /* seconds Pointer to SNTP seconds */
4012 /* fraction Local time fraction component */
4013 /* buffer Pointer for time in string format */
4014 /* */
4015 /* OUTPUT */
4016 /* */
4017 /* status Completion status */
4018 /* */
4019 /* CALLS */
4020 /* */
4021 /* _nx_sntp_client_get_local_time Get local time service */
4022 /* */
4023 /* CALLED BY */
4024 /* */
4025 /* Application Code */
4026 /* */
4027 /* RELEASE HISTORY */
4028 /* */
4029 /* DATE NAME DESCRIPTION */
4030 /* */
4031 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4032 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4033 /* resulting in version 6.1 */
4034 /* */
4035 /**************************************************************************/
_nxe_sntp_client_get_local_time(NX_SNTP_CLIENT * client_ptr,ULONG * seconds,ULONG * fraction,CHAR * buffer)4036 UINT _nxe_sntp_client_get_local_time(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer)
4037 {
4038
4039 UINT status;
4040
4041
4042 /* Check input pointer parameters. */
4043 if ((client_ptr == NX_NULL) || (seconds == NX_NULL) || (fraction == NX_NULL))
4044 {
4045
4046 /* Return pointer error. */
4047 return NX_PTR_ERROR;
4048 }
4049
4050 /* Check if this function is called from the appropriate thread. */
4051 NX_THREADS_ONLY_CALLER_CHECKING
4052
4053 /* Call the actual service. */
4054 status = _nx_sntp_client_get_local_time(client_ptr, seconds, fraction, buffer);
4055
4056 /* Return completion status. */
4057 return status;
4058 }
4059
4060
4061 /**************************************************************************/
4062 /* */
4063 /* FUNCTION RELEASE */
4064 /* */
4065 /* _nx_sntp_client_get_local_time PORTABLE C */
4066 /* 6.1 */
4067 /* AUTHOR */
4068 /* */
4069 /* Yuxin Zhou, Microsoft Corporation */
4070 /* */
4071 /* DESCRIPTION */
4072 /* */
4073 /* This function retrieves the current SNTP Client local time and */
4074 /* returns the data in seconds and fractions, and if a non zero */
4075 /* buffer pointer is supplied, a string containing the data in ASCII. */
4076 /* */
4077 /* INPUT */
4078 /* */
4079 /* client_ptr Pointer to SNTP Client */
4080 /* seconds Pointer to SNTP seconds */
4081 /* fraction Local time fraction component */
4082 /* buffer Pointer for time in string format */
4083 /* */
4084 /* OUTPUT */
4085 /* */
4086 /* status Completion status */
4087 /* */
4088 /* CALLS */
4089 /* */
4090 /* _nx_utility_string_length_check Check string length */
4091 /* _nx_sntp_client_get_local_time_extended */
4092 /* Get local time service */
4093 /* */
4094 /* CALLED BY */
4095 /* */
4096 /* Application Code */
4097 /* */
4098 /* RELEASE HISTORY */
4099 /* */
4100 /* DATE NAME DESCRIPTION */
4101 /* */
4102 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4103 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4104 /* resulting in version 6.1 */
4105 /* */
4106 /**************************************************************************/
_nx_sntp_client_get_local_time(NX_SNTP_CLIENT * client_ptr,ULONG * seconds,ULONG * fraction,CHAR * buffer)4107 UINT _nx_sntp_client_get_local_time(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer)
4108 {
4109
4110 UINT status;
4111
4112 status = _nx_sntp_client_get_local_time_extended(client_ptr, seconds, fraction, buffer, NX_MAX_STRING_LENGTH);
4113
4114 return status;
4115 }
4116
4117 /**************************************************************************/
4118 /* */
4119 /* FUNCTION RELEASE */
4120 /* */
4121 /* _nxe_sntp_client_get_local_time_extended PORTABLE C */
4122 /* 6.1 */
4123 /* AUTHOR */
4124 /* */
4125 /* Yuxin Zhou, Microsoft Corporation */
4126 /* */
4127 /* DESCRIPTION */
4128 /* */
4129 /* This function performs error checking for the get extended local */
4130 /* time service. */
4131 /* */
4132 /* INPUT */
4133 /* */
4134 /* client_ptr Pointer to SNTP Client */
4135 /* seconds Pointer to SNTP seconds */
4136 /* fraction Local time fraction component */
4137 /* buffer Pointer for time in string format */
4138 /* buffer_size Size of buffer */
4139 /* */
4140 /* OUTPUT */
4141 /* */
4142 /* status Completion status */
4143 /* */
4144 /* CALLS */
4145 /* */
4146 /* _nx_sntp_client_get_local_time_extended */
4147 /* Get extended local time service */
4148 /* */
4149 /* CALLED BY */
4150 /* */
4151 /* Application Code */
4152 /* */
4153 /* RELEASE HISTORY */
4154 /* */
4155 /* DATE NAME DESCRIPTION */
4156 /* */
4157 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4158 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4159 /* resulting in version 6.1 */
4160 /* */
4161 /**************************************************************************/
_nxe_sntp_client_get_local_time_extended(NX_SNTP_CLIENT * client_ptr,ULONG * seconds,ULONG * fraction,CHAR * buffer,UINT buffer_size)4162 UINT _nxe_sntp_client_get_local_time_extended(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer, UINT buffer_size)
4163 {
4164
4165 UINT status;
4166
4167
4168 /* Check input pointer parameters. */
4169 if ((client_ptr == NX_NULL) || (seconds == NX_NULL) || (fraction == NX_NULL))
4170 {
4171
4172 /* Return pointer error. */
4173 return NX_PTR_ERROR;
4174 }
4175
4176 /* Check if this function is called from the appropriate thread. */
4177 NX_THREADS_ONLY_CALLER_CHECKING
4178
4179 /* Call the actual service. */
4180 status = _nx_sntp_client_get_local_time_extended(client_ptr, seconds, fraction, buffer, buffer_size);
4181
4182 /* Return completion status. */
4183 return status;
4184 }
4185
4186
4187 /**************************************************************************/
4188 /* */
4189 /* FUNCTION RELEASE */
4190 /* */
4191 /* _nx_sntp_client_get_local_time_extended PORTABLE C */
4192 /* 6.1.8 */
4193 /* AUTHOR */
4194 /* */
4195 /* Yuxin Zhou, Microsoft Corporation */
4196 /* */
4197 /* DESCRIPTION */
4198 /* */
4199 /* This function retrieves the current SNTP Client local time and */
4200 /* returns the data in seconds and fractions, and if a non zero */
4201 /* buffer pointer is supplied, a string containing the data in ASCII. */
4202 /* */
4203 /* INPUT */
4204 /* */
4205 /* client_ptr Pointer to SNTP Client */
4206 /* seconds Pointer to SNTP seconds */
4207 /* fraction Local time fraction component */
4208 /* buffer Pointer for time in string format */
4209 /* buffer_size Size of buffer */
4210 /* */
4211 /* OUTPUT */
4212 /* */
4213 /* status Completion status */
4214 /* */
4215 /* CALLS */
4216 /* */
4217 /* _nx_sntp_client_utility_fraction_to_usecs */
4218 /* Convert NTP fraction to usecs */
4219 /* _nx_utility_uint_to_string Converts number to ascii text */
4220 /* */
4221 /* CALLED BY */
4222 /* */
4223 /* Application Code */
4224 /* */
4225 /* RELEASE HISTORY */
4226 /* */
4227 /* DATE NAME DESCRIPTION */
4228 /* */
4229 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4230 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
4231 /* verified memmove use cases, */
4232 /* resulting in version 6.1 */
4233 /* 08-02-2021 Yuxin Zhou Modified comment(s), */
4234 /* improved the logic of */
4235 /* converting number to string,*/
4236 /* resulting in version 6.1.8 */
4237 /* */
4238 /**************************************************************************/
_nx_sntp_client_get_local_time_extended(NX_SNTP_CLIENT * client_ptr,ULONG * seconds,ULONG * fraction,CHAR * buffer,UINT buffer_size)4239 UINT _nx_sntp_client_get_local_time_extended(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer, UINT buffer_size)
4240 {
4241
4242 ULONG usecs;
4243 UINT offset = 0;
4244 UINT length = 0;
4245
4246 *seconds = client_ptr -> nx_sntp_client_local_ntp_time.seconds;
4247 *fraction = client_ptr -> nx_sntp_client_local_ntp_time.fraction;
4248
4249 if (buffer != NX_NULL)
4250 {
4251
4252 /* Convert SNTP fraction component into microseconds. */
4253 _nx_sntp_client_utility_fraction_to_usecs(client_ptr -> nx_sntp_client_local_ntp_time.fraction, &usecs);
4254
4255 /* Decrease length for terminal zero. */
4256 buffer_size--;
4257
4258 /* Create a string with just the time. */
4259 /* Format: "Time: %lu.%06lu sec.\r\n" */
4260 if (buffer_size < 6)
4261 {
4262 return(NX_SIZE_ERROR);
4263 }
4264 buffer[offset++] = 'T';
4265 buffer[offset++] = 'i';
4266 buffer[offset++] = 'm';
4267 buffer[offset++] = 'e';
4268 buffer[offset++] = ':';
4269 buffer[offset++] = ' ';
4270 length = _nx_utility_uint_to_string(client_ptr -> nx_sntp_client_local_ntp_time.seconds,
4271 10, &buffer[offset], buffer_size - offset);
4272 if (length == 0)
4273 {
4274 return(NX_SIZE_ERROR);
4275 }
4276 offset += length;
4277 if ((buffer_size - offset) < 14)
4278 {
4279 return(NX_SIZE_ERROR);
4280 }
4281 buffer[offset++] = '.';
4282 length = _nx_utility_uint_to_string(usecs, 10, &buffer[offset], buffer_size - offset);
4283 if (length == 0)
4284 {
4285 return(NX_SIZE_ERROR);
4286 }
4287
4288 if (length < 6)
4289 {
4290
4291 /* Append zeroes. */
4292 memmove(&buffer[offset + (6 - length)], &buffer[offset], length); /* Use case of memmove is verified. */
4293 memset(&buffer[offset], '0', (6 - length));
4294 }
4295
4296 offset += 6;
4297 buffer[offset++] = ' ';
4298 buffer[offset++] = 's';
4299 buffer[offset++] = 'e';
4300 buffer[offset++] = 'c';
4301 buffer[offset++] = '.';
4302 buffer[offset++] = '\r';
4303 buffer[offset++] = '\n';
4304 buffer[offset] = '\0';
4305 }
4306
4307 return NX_SUCCESS;
4308 }
4309
4310
4311 /**************************************************************************/
4312 /* */
4313 /* FUNCTION RELEASE */
4314 /* */
4315 /* _nx_sntp_client_utility_convert_time_to_UCHAR PORTABLE C */
4316 /* 6.1 */
4317 /* AUTHOR */
4318 /* */
4319 /* Yuxin Zhou, Microsoft Corporation */
4320 /* */
4321 /* DESCRIPTION */
4322 /* */
4323 /* This function converts time from the ULONG seconds and msecs in the */
4324 /* NX_SNTP_TIME data to the 32 bit UCHAR seconds and fraction fields in*/
4325 /* the NTP time message. The caller specifies which time stamp in the */
4326 /* NTP time message (transmit,receive, origination, or reference clock)*/
4327 /* and that field is converted over. */
4328 /* */
4329 /* INPUT */
4330 /* */
4331 /* time_ptr Pointer to NX_SNTP_TIME time */
4332 /* time_message_ptr Pointer to NTP (UCHAR) time */
4333 /* which_stamp Which time stamp to convert */
4334 /* */
4335 /* OUTPUT */
4336 /* */
4337 /* NX_SNTP_PARAM_ERROR Invalid time stamp requested */
4338 /* NX_SUCCESS Successful completion status */
4339 /* */
4340 /* CALLS */
4341 /* */
4342 /* memset Clear specified area of memory */
4343 /* */
4344 /* CALLED BY */
4345 /* */
4346 /* _nx_sntp_client_send_unicast_request */
4347 /* Create a time request and transmit it*/
4348 /* */
4349 /* RELEASE HISTORY */
4350 /* */
4351 /* DATE NAME DESCRIPTION */
4352 /* */
4353 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4354 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4355 /* resulting in version 6.1 */
4356 /* */
4357 /**************************************************************************/
_nx_sntp_client_utility_convert_time_to_UCHAR(NX_SNTP_TIME * time_ptr,NX_SNTP_TIME_MESSAGE * time_message_ptr,UINT which_stamp)4358 UINT _nx_sntp_client_utility_convert_time_to_UCHAR(NX_SNTP_TIME *time_ptr,
4359 NX_SNTP_TIME_MESSAGE *time_message_ptr, UINT which_stamp)
4360 {
4361
4362 ULONG *buffer;
4363
4364 /* Copy the buffer to the requested time stamp field. */
4365 switch (which_stamp)
4366 {
4367
4368 case REFERENCE_TIME:
4369 buffer = time_message_ptr -> reference_clock_update_time_stamp;
4370 break;
4371
4372 case ORIGINATE_TIME:
4373 buffer = time_message_ptr -> originate_time_stamp;
4374 break;
4375
4376 case RECEIVE_TIME:
4377 buffer = time_message_ptr -> receive_time_stamp;
4378 break;
4379
4380 case TRANSMIT_TIME:
4381 buffer = time_message_ptr -> transmit_time_stamp;
4382 break;
4383
4384 default:
4385 /* Invalid time stamp. Return as error. */
4386 return NX_SNTP_PARAM_ERROR;
4387 }
4388
4389 /* Copy NX_SNTP_TIME seconds and fraction to the buffer. */
4390 *(buffer) = time_ptr -> seconds;
4391 *(buffer + 1) = time_ptr -> fraction;
4392
4393 /* Return successful completion. */
4394 return NX_SUCCESS;
4395 }
4396
4397 /* The conventional civil timescale used in most parts of the world is based on Coordinated Universal Time (UTC),
4398 which replaced Greenwich Mean Time (GMT) many years ago. UTC is based on International Atomic Time (TAI),
4399 which is derived from hundreds of cesium oscillators in the national standards laboratories of many regions.
4400 Deviations of UTC from TAI are implemented in the form of leap seconds, which occur at intervals from a
4401 few months to serveral years. */
4402
4403
4404 /**************************************************************************/
4405 /* */
4406 /* FUNCTION RELEASE */
4407 /* */
4408 /* _nx_sntp_client_utility_convert_seconds_to_date PORTABLE C */
4409 /* 6.1 */
4410 /* AUTHOR */
4411 /* */
4412 /* Yuxin Zhou, Microsoft Corporation */
4413 /* */
4414 /* DESCRIPTION */
4415 /* */
4416 /* This function computes the month, day, and time in an NTP time based */
4417 /* on the known number of seconds at 1/1/1999 since 1/1/1900 (the NTP */
4418 /* time epoch) and the current NTP time. The caller must indicated the */
4419 /* year of the NTP time to convert to simplify the computation. The data*/
4420 /* is written to an NX_SNTP_DATE_TIME object from which the call can */
4421 /* extract date and time data, or call the NetX SNTP API to display the */
4422 /* data/time string. */
4423 /* */
4424 /* INPUT */
4425 /* */
4426 /* current_NTP_time_ptr Pointer to NTP time */
4427 /* current_year Year in the NTP time data */
4428 /* current_date_time_ptr Pointer to date time object */
4429 /* */
4430 /* OUTPUT */
4431 /* */
4432 /* NX_SUCCESS Successful completion status */
4433 /* NX_SNTP_ERROR_CONVERTING_DATETIME Internal error converting time */
4434 /* NX_SNTP_UNABLE_TO_CONVERT_DATETIME Insufficient data for converting */
4435 /* */
4436 /* CALLS */
4437 /* */
4438 /* _nx_sntp_client_utility_convert_fraction_to_msecs */
4439 /* Converts the 32 bit fraction field*/
4440 /* in an NTP time to milliseconds */
4441 /* */
4442 /* CALLED BY */
4443 /* */
4444 /* Application */
4445 /* */
4446 /* RELEASE HISTORY */
4447 /* */
4448 /* DATE NAME DESCRIPTION */
4449 /* */
4450 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4451 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
4452 /* fixed leap year calculation,*/
4453 /* resulting in version 6.1 */
4454 /* */
4455 /**************************************************************************/
_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)4456 UINT _nx_sntp_client_utility_convert_seconds_to_date(NX_SNTP_TIME *current_NTP_time_ptr, UINT current_year,
4457 NX_SNTP_DATE_TIME *current_date_time_ptr)
4458 {
4459
4460 /* Check if there is a base number of seconds set. */
4461 #if (NTP_SECONDS_AT_01011999 == 0)
4462
4463 /* No, so we cannot convert time into months and years. */
4464 return NX_SNTP_UNABLE_TO_CONVERT_DATETIME;
4465 #else
4466
4467 UINT seconds_diff;
4468 UINT years_diff;
4469 UINT leapyears_diff;
4470 UINT leaps;
4471 UINT seconds_of_year;
4472 UINT seconds_into_currentyear;
4473 UINT seconds_into_currentmonth;
4474 UINT seconds_into_currentday;
4475 UINT seconds_into_currenthour;
4476
4477 memset(current_date_time_ptr, 0, sizeof(NX_SNTP_DATE_TIME));
4478
4479 do
4480 {
4481
4482 current_date_time_ptr -> year = current_year;
4483
4484 seconds_diff = current_NTP_time_ptr -> seconds - NTP_SECONDS_AT_01011999;
4485
4486 years_diff = current_year - 1999;
4487
4488 /* Figure out number of leap years since 1999 not including the current year. */
4489 leapyears_diff = (current_year - 1 - 1996) >> 2;
4490
4491 /* Determine if this is a leap year. */
4492 leaps = (current_year - 1996) & 3;
4493
4494 /* Check if this is a leap year. */
4495 if (leaps == 0 )
4496 {
4497 /* It is! */
4498 current_date_time_ptr -> leap_year = NX_TRUE;
4499 seconds_of_year = SECONDS_PER_LEAPYEAR;
4500 }
4501 else
4502 {
4503
4504 /* Not a leap year. Clear the leap year flag. */
4505 current_date_time_ptr -> leap_year = NX_FALSE;
4506 seconds_of_year = SECONDS_PER_NONLEAPYEAR;
4507 }
4508
4509 /* Compute number of seconds into the current year e.g. as of 01/01 at midnite by subtracting
4510 the total number of seconds since 1/1/1999 up to the end of the previous year. Remember to compute
4511 the leapyear seconds at a different rate. */
4512 seconds_into_currentyear = seconds_diff - ((years_diff - leapyears_diff) * SECONDS_PER_NONLEAPYEAR)
4513 - (leapyears_diff * SECONDS_PER_LEAPYEAR);
4514
4515 current_year++;
4516
4517 }while(seconds_into_currentyear > seconds_of_year);
4518
4519 /* Initialize month to January till we find out what the month is. */
4520 current_date_time_ptr -> month = JANUARY;
4521
4522 while (1)
4523 {
4524
4525 /* Does the number of seconds goes past January? */
4526 if (seconds_into_currentyear >= SEC_IN_JAN)
4527 {
4528
4529 /* Yes, reset month to Feb and subtract seconds in January. */
4530 current_date_time_ptr -> month = FEBRUARY;
4531 seconds_into_currentyear -= SEC_IN_JAN;
4532 }
4533 /* No, we're done going month to month. */
4534 else break;
4535
4536 /* Handle February differently because it is a leap month. */
4537 if (current_date_time_ptr -> leap_year)
4538 {
4539
4540 /* This is a leap year so Feb has 29 days. */
4541 if (seconds_into_currentyear >= SEC_IN_LEAPFEB)
4542 {
4543 current_date_time_ptr -> month = MARCH;
4544 seconds_into_currentyear -= SEC_IN_LEAPFEB;
4545 }
4546 else break;
4547
4548 }
4549 else
4550 {
4551 /* Not a leap year, Feb has the usual 28 days. */
4552 if (seconds_into_currentyear >= SEC_IN_NONLEAPFEB)
4553 {
4554 current_date_time_ptr -> month = MARCH;
4555 seconds_into_currentyear -= SEC_IN_NONLEAPFEB;
4556 }
4557 else break;
4558
4559 }
4560
4561 /* Repeat for each month for the rest of the year. */
4562
4563 if (seconds_into_currentyear >= SEC_IN_MAR)
4564 {
4565 current_date_time_ptr -> month = APRIL;
4566 seconds_into_currentyear -= SEC_IN_MAR;
4567 }
4568 else break;
4569
4570 if (seconds_into_currentyear >= SEC_IN_APR)
4571 {
4572 current_date_time_ptr -> month = MAY;
4573 seconds_into_currentyear -= SEC_IN_APR;
4574 }
4575 else break;
4576
4577 if (seconds_into_currentyear >= SEC_IN_MAY)
4578 {
4579 current_date_time_ptr -> month = JUNE;
4580 seconds_into_currentyear -= SEC_IN_MAY;
4581 }
4582 else break;
4583
4584 if (seconds_into_currentyear >= SEC_IN_JUN)
4585 {
4586 current_date_time_ptr -> month = JULY;
4587 seconds_into_currentyear -= SEC_IN_JUN;
4588 }
4589 else break;
4590
4591 if (seconds_into_currentyear >= SEC_IN_JUL)
4592 {
4593 current_date_time_ptr -> month = AUGUST;
4594 seconds_into_currentyear -= SEC_IN_JUL;
4595 }
4596 else break;
4597
4598 if (seconds_into_currentyear >= SEC_IN_AUG)
4599 {
4600 current_date_time_ptr -> month = SEPTEMBER;
4601 seconds_into_currentyear -= SEC_IN_AUG;
4602 }
4603 else break;
4604
4605 if (seconds_into_currentyear >= SEC_IN_SEP)
4606 {
4607 current_date_time_ptr -> month = OCTOBER;
4608 seconds_into_currentyear -= SEC_IN_SEP;
4609 }
4610 else break;
4611
4612 if (seconds_into_currentyear >= SEC_IN_OCT)
4613 {
4614 current_date_time_ptr -> month = NOVEMBER;
4615 seconds_into_currentyear -= SEC_IN_OCT;
4616 }
4617 else break;
4618
4619 if (seconds_into_currentyear >= SEC_IN_NOV)
4620 {
4621 current_date_time_ptr -> month = DECEMBER;
4622 seconds_into_currentyear -= SEC_IN_NOV;
4623 }
4624 else break;
4625
4626 /* We should not have more than the seconds in december or there is an error. */
4627 if (seconds_into_currentyear > SEC_IN_DEC)
4628 {
4629
4630 /* Return the error status. */
4631 return NX_SNTP_ERROR_CONVERTING_DATETIME;
4632 }
4633 else break;
4634 }
4635
4636 /* Time is now in the current month. */
4637 seconds_into_currentmonth = seconds_into_currentyear;
4638
4639 /* Compute how many complete days the time goes into the current month and
4640 add one for the current day. */
4641 current_date_time_ptr -> day = seconds_into_currentmonth/SECONDS_PER_DAY + 1;
4642
4643 /* Compute the number of seconds into the current day. */
4644 seconds_into_currentday = seconds_into_currentmonth % SECONDS_PER_DAY;
4645
4646 /* Compute the number of complete hours into the current day we are. */
4647 current_date_time_ptr -> hour = seconds_into_currentday/SECONDS_PER_HOUR;
4648
4649 /* Compute the number of seconds into the current hour. */
4650 seconds_into_currenthour = seconds_into_currentday % SECONDS_PER_HOUR;
4651
4652 /* Break this down into minutes. */
4653 current_date_time_ptr -> minute = seconds_into_currenthour/SECONDS_PER_MINUTE;
4654
4655 /* Finally the remainder is the seconds. */
4656 current_date_time_ptr -> second = seconds_into_currenthour % SECONDS_PER_MINUTE;
4657
4658 /* Convert time fraction field into milliseconds. */
4659 _nx_sntp_client_utility_convert_fraction_to_msecs((ULONG *)(&(current_date_time_ptr -> millisecond)), current_NTP_time_ptr);
4660
4661 return NX_SUCCESS;
4662 #endif
4663 }
4664
4665
4666 /**************************************************************************/
4667 /* */
4668 /* FUNCTION RELEASE */
4669 /* */
4670 /* _nxe_sntp_client_utility_display_date_time PORTABLE C */
4671 /* 6.1 */
4672 /* AUTHOR */
4673 /* */
4674 /* Yuxin Zhou, Microsoft Corporation */
4675 /* */
4676 /* DESCRIPTION */
4677 /* */
4678 /* This function performs error checking services on the display date */
4679 /* time service. */
4680 /* */
4681 /* INPUT */
4682 /* */
4683 /* client_ptr Pointer to SNTP Client */
4684 /* buffer Pointer to string buffer */
4685 /* length Size of the string buffer */
4686 /* */
4687 /* OUTPUT */
4688 /* */
4689 /* NX_PTR_ERROR Invalid pointer input */
4690 /* NX_SNTP_PARAM_ERROR Invalid non pointer input */
4691 /* status Actual completion status */
4692 /* */
4693 /* CALLS */
4694 /* */
4695 /* _nx_sntp_client_utility_display_date_time */
4696 /* Actual display date/time service */
4697 /* */
4698 /* CALLED BY */
4699 /* */
4700 /* Application */
4701 /* */
4702 /* RELEASE HISTORY */
4703 /* */
4704 /* DATE NAME DESCRIPTION */
4705 /* */
4706 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4707 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4708 /* resulting in version 6.1 */
4709 /* */
4710 /**************************************************************************/
_nxe_sntp_client_utility_display_date_time(NX_SNTP_CLIENT * client_ptr,CHAR * buffer,UINT length)4711 UINT _nxe_sntp_client_utility_display_date_time(NX_SNTP_CLIENT *client_ptr, CHAR *buffer, UINT length)
4712 {
4713
4714 UINT status;
4715
4716
4717 /* Check for invalid pointer input. */
4718 if ((client_ptr == NX_NULL) || (buffer == NX_NULL))
4719 {
4720
4721 /* Return pointer error. */
4722 return NX_PTR_ERROR;
4723 }
4724
4725 /* Check for invalid parameter input. */
4726 if (length == 0)
4727 {
4728
4729 /* Return parameter error. */
4730 return NX_SNTP_PARAM_ERROR;
4731 }
4732
4733 /* Call the actual display time service. */
4734 status = _nx_sntp_client_utility_display_date_time(client_ptr, buffer, length);
4735
4736 /* Return completion status. */
4737 return status;
4738 }
4739
4740
4741
4742 /**************************************************************************/
4743 /* */
4744 /* FUNCTION RELEASE */
4745 /* */
4746 /* _nxe_sntp_client_request_unicast_time PORTABLE C */
4747 /* 6.1 */
4748 /* AUTHOR */
4749 /* */
4750 /* Yuxin Zhou, Microsoft Corporation */
4751 /* */
4752 /* DESCRIPTION */
4753 /* */
4754 /* This function performs error checking for the service that */
4755 /* forwards a unicast request from the SNTP Client application. */
4756 /* */
4757 /* INPUT */
4758 /* */
4759 /* client_ptr Pointer to Client struct */
4760 /* wait_option Time to wait for response (ticks) */
4761 /* */
4762 /* OUTPUT */
4763 /* */
4764 /* NX_PTR_ERROR Invalid pointer input */
4765 /* status Actual completion status */
4766 /* */
4767 /* CALLED BY */
4768 /* */
4769 /* Application Code */
4770 /* */
4771 /* RELEASE HISTORY */
4772 /* */
4773 /* DATE NAME DESCRIPTION */
4774 /* */
4775 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4776 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4777 /* resulting in version 6.1 */
4778 /* */
4779 /**************************************************************************/
_nxe_sntp_client_request_unicast_time(NX_SNTP_CLIENT * client_ptr,UINT wait_option)4780 UINT _nxe_sntp_client_request_unicast_time(NX_SNTP_CLIENT *client_ptr, UINT wait_option)
4781 {
4782
4783 UINT status;
4784
4785 /* Check for invalid pointer input. */
4786 if (client_ptr == NX_NULL)
4787 {
4788 return NX_PTR_ERROR;
4789 }
4790
4791 status = _nx_sntp_client_request_unicast_time(client_ptr, wait_option);
4792
4793 return status;
4794 }
4795
4796
4797 /**************************************************************************/
4798 /* */
4799 /* FUNCTION RELEASE */
4800 /* */
4801 /* _nx_sntp_client_request_unicast_time PORTABLE C */
4802 /* 6.1 */
4803 /* AUTHOR */
4804 /* */
4805 /* Yuxin Zhou, Microsoft Corporation */
4806 /* */
4807 /* DESCRIPTION */
4808 /* */
4809 /* This function sends a unicast request regardless if the SNTP Client */
4810 /* is configured for unicast or broadcast mode. After sending the */
4811 /* request, the function waits for the specified time for a response. */
4812 /* */
4813 /* If received, the SNTP Server response is processed as it normally is*/
4814 /* for valid SNTP data, and applied to the SNTP Client's notion of time*/
4815 /* "local time". */
4816 /* */
4817 /* This will not interfere with subsequent unicast requests in unicast */
4818 /* mode, or the processing of periodic updates in broadcast mode. */
4819 /* */
4820 /* INPUT */
4821 /* */
4822 /* client_ptr Pointer to Client struct */
4823 /* wait_option Time to wait for response (ticks) */
4824 /* */
4825 /* OUTPUT */
4826 /* */
4827 /* NX_PTR_ERROR Invalid pointer input */
4828 /* status Actual completion status */
4829 /* */
4830 /* CALLED BY */
4831 /* */
4832 /* Application Code */
4833 /* */
4834 /* RELEASE HISTORY */
4835 /* */
4836 /* DATE NAME DESCRIPTION */
4837 /* */
4838 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4839 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4840 /* resulting in version 6.1 */
4841 /* */
4842 /**************************************************************************/
_nx_sntp_client_request_unicast_time(NX_SNTP_CLIENT * client_ptr,UINT wait_option)4843 UINT _nx_sntp_client_request_unicast_time(NX_SNTP_CLIENT *client_ptr, UINT wait_option)
4844 {
4845
4846 UINT status;
4847
4848
4849 /* Make sure the client is started. */
4850 if (!client_ptr -> nx_sntp_client_started)
4851 {
4852 return NX_SNTP_CLIENT_NOT_STARTED;
4853 }
4854
4855 /* Create and send a unicast request. */
4856 status = _nx_sntp_client_send_unicast_request(client_ptr);
4857
4858 if (status != NX_SUCCESS)
4859 {
4860 return status;
4861 }
4862
4863 /* Wait to receive a response. */
4864 status = _nx_sntp_client_receive_time_update(client_ptr, wait_option);
4865
4866 /* If we got a valid SNTP packet, process the data. */
4867 if (status == NX_SUCCESS)
4868 {
4869
4870 /* Process the server update packet and apply to local time if valid. */
4871 status = _nx_sntp_client_process_update_packet(client_ptr);
4872 }
4873
4874 tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex));
4875 /* Return completion status. */
4876 return status;
4877 }
4878
4879 /**************************************************************************/
4880 /* */
4881 /* FUNCTION RELEASE */
4882 /* */
4883 /* _nx_sntp_client_utility_display_date_time PORTABLE C */
4884 /* 6.2.0 */
4885 /* AUTHOR */
4886 /* */
4887 /* Yuxin Zhou, Microsoft Corporation */
4888 /* */
4889 /* DESCRIPTION */
4890 /* */
4891 /* This function converts an NTP time data into a month-date-year time, */
4892 /* including seconds and second fraction string. It is intended as a */
4893 /* human readable representation of NTP time. The caller must supply a */
4894 /* pointer to a buffer large enough (40 chars is enough) to hold the */
4895 /* string and define the NX_SNTP_CURRENT_YEAR parameter, usually as the */
4896 /* current year. */
4897 /* */
4898 /* INPUT */
4899 /* */
4900 /* client_ptr Pointer to SNTP Client */
4901 /* buffer Pointer to string buffer */
4902 /* length Size of the string buffer */
4903 /* */
4904 /* OUTPUT */
4905 /* */
4906 /* NX_SUCCESS Successful completion status */
4907 /* NX_SNTP_INVALID_DATETIME_BUFFER Buffer not large enough */
4908 /* NX_SNTP_ERROR_CONVERTING_DATETIME Internal error converting NTP time*/
4909 /* status Convert seconds completion status */
4910 /* */
4911 /* CALLS */
4912 /* _nx_sntp_client_utility_convert_seconds_to_date */
4913 /* Converts seconds to year, month */
4914 /* _nx_utility_uint_to_string Converts number to ascii text */
4915 /* */
4916 /* CALLED BY */
4917 /* */
4918 /* Application */
4919 /* */
4920 /* RELEASE HISTORY */
4921 /* */
4922 /* DATE NAME DESCRIPTION */
4923 /* */
4924 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4925 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4926 /* resulting in version 6.1 */
4927 /* 08-02-2021 Yuxin Zhou Modified comment(s), */
4928 /* improved the logic of */
4929 /* converting number to string,*/
4930 /* resulting in version 6.1.8 */
4931 /* 10-31-2022 Yuxin Zhou Modified comment(s), fixed */
4932 /* the typo of August string, */
4933 /* resulting in version 6.2.0 */
4934 /* */
4935 /**************************************************************************/
_nx_sntp_client_utility_display_date_time(NX_SNTP_CLIENT * client_ptr,CHAR * buffer,UINT length)4936 UINT _nx_sntp_client_utility_display_date_time(NX_SNTP_CLIENT *client_ptr, CHAR *buffer, UINT length)
4937 {
4938
4939 UINT status;
4940 UINT offset;
4941 UINT return_length;
4942 NX_SNTP_DATE_TIME DisplayTime;
4943 const CHAR *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
4944 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
4945
4946
4947 #ifndef NX_SNTP_CURRENT_YEAR
4948 return NX_SNTP_ERROR_CONVERTING_DATETIME;
4949 #else
4950
4951 /* Verify the client has set a local time. */
4952 if (client_ptr -> nx_sntp_client_local_ntp_time.seconds == 0)
4953 {
4954 return NX_SNTP_ERROR_CONVERTING_DATETIME;
4955 }
4956
4957 status = _nx_sntp_client_utility_convert_seconds_to_date(&(client_ptr -> nx_sntp_client_local_ntp_time), NX_SNTP_CURRENT_YEAR, &DisplayTime);
4958 if (status != NX_SUCCESS)
4959 {
4960 return status;
4961 }
4962
4963 /* Check if we have a long enough buffer. */
4964 if (length < 5)
4965 {
4966
4967 /* Return the error status. */
4968 return NX_SNTP_INVALID_DATETIME_BUFFER;
4969 }
4970
4971 /* Decrease length for terminal zero. */
4972 length--;
4973
4974 /* Substitute numeric month to name of the month. */
4975 if ((DisplayTime.month < JANUARY) || (DisplayTime.month > DECEMBER))
4976 {
4977 return NX_SNTP_ERROR_CONVERTING_DATETIME;
4978 }
4979 buffer[0] = months[DisplayTime.month - JANUARY][0];
4980 buffer[1] = months[DisplayTime.month - JANUARY][1];
4981 buffer[2] = months[DisplayTime.month - JANUARY][2];
4982 buffer[3] = ' ';
4983 offset = 4;
4984
4985 /* Write in the rest of the data as numeric from the Date Time objext. */
4986 return_length = _nx_utility_uint_to_string(DisplayTime.day, 10, &buffer[offset], length - offset);
4987 offset += return_length;
4988 if ((return_length == 0) || ((length - offset) < 2))
4989 {
4990 return NX_SNTP_ERROR_CONVERTING_DATETIME;
4991 }
4992 buffer[offset++] = ',';
4993 buffer[offset++] = ' ';
4994 return_length = _nx_utility_uint_to_string(DisplayTime.year, 10, &buffer[offset], length - offset);
4995 offset += return_length;
4996 if ((return_length == 0) || ((length - offset) < 1))
4997 {
4998 return NX_SNTP_ERROR_CONVERTING_DATETIME;
4999 }
5000 buffer[offset++] = ' ';
5001 return_length = _nx_utility_uint_to_string(DisplayTime.hour, 10, &buffer[offset], length - offset);
5002 offset += return_length;
5003 if ((return_length == 0) || ((length - offset) < 1))
5004 {
5005 return NX_SNTP_ERROR_CONVERTING_DATETIME;
5006 }
5007 buffer[offset++] = ':';
5008 return_length = _nx_utility_uint_to_string(DisplayTime.minute, 10, &buffer[offset], length - offset);
5009 offset += return_length;
5010 if ((return_length == 0) || ((length - offset) < 1))
5011 {
5012 return NX_SNTP_ERROR_CONVERTING_DATETIME;
5013 }
5014 buffer[offset++] = ':';
5015 return_length = _nx_utility_uint_to_string(DisplayTime.second, 10, &buffer[offset], length - offset);
5016 offset += return_length;
5017 if ((return_length == 0) || ((length - offset) < 1))
5018 {
5019 return NX_SNTP_ERROR_CONVERTING_DATETIME;
5020 }
5021 buffer[offset++] = '.';
5022 return_length = _nx_utility_uint_to_string(DisplayTime.millisecond, 10, &buffer[offset], length - offset);
5023 offset += return_length;
5024 if ((return_length == 0) || ((length - offset) < 5))
5025 {
5026 return NX_SNTP_ERROR_CONVERTING_DATETIME;
5027 }
5028 buffer[offset++] = ' ';
5029 buffer[offset++] = 'U';
5030 buffer[offset++] = 'T';
5031 buffer[offset++] = 'C';
5032 buffer[offset++] = ' ';
5033 buffer[offset] = '\0';
5034
5035 #endif
5036
5037 return NX_SUCCESS;
5038 }
5039
5040
5041 /**************************************************************************/
5042 /* */
5043 /* FUNCTION RELEASE */
5044 /* */
5045 /* _nx_sntp_client_utility_add_msecs_to_ntp_time PORTABLE C */
5046 /* 6.1 */
5047 /* AUTHOR */
5048 /* */
5049 /* Yuxin Zhou, Microsoft Corporation */
5050 /* */
5051 /* DESCRIPTION */
5052 /* */
5053 /* This function adds msecs (not necessarily a positive value and not */
5054 /* limited to less than a second) to an NTP time value. Msecs cannot be */
5055 /* added directly to the fraction field in the NTP time field because */
5056 /* this field is represented in fixed point notation. Arithmetic */
5057 /* overflow and loss of sign errors as a result of adding numbers are */
5058 /* handled as errors. */
5059 /* */
5060 /* INPUT */
5061 /* */
5062 /* timeA_ptr Pointer to NTP time operand */
5063 /* msecs_to_add Time (msecs) to add */
5064 /* */
5065 /* OUTPUT */
5066 /* */
5067 /* NX_SUCCESS Successful completion status */
5068 /* NX_SNTP_OVERFLOW_ERROR Overflow result adding numbers */
5069 /* NX_SNTP_INVALID_TIME An invalid result (e.g. negative */
5070 /* time) from adding numbers */
5071 /* status Actual completion status */
5072 /* */
5073 /* CALLS */
5074 /* */
5075 /* None */
5076 /* */
5077 /* CALLED BY */
5078 /* */
5079 /* _nx_sntp_client_process_time_data Apply server time to local time */
5080 /* */
5081 /* RELEASE HISTORY */
5082 /* */
5083 /* DATE NAME DESCRIPTION */
5084 /* */
5085 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5086 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5087 /* resulting in version 6.1 */
5088 /* */
5089 /**************************************************************************/
5090
_nx_sntp_client_utility_add_msecs_to_ntp_time(NX_SNTP_TIME * timeA_ptr,LONG msecs_to_add)5091 UINT _nx_sntp_client_utility_add_msecs_to_ntp_time(NX_SNTP_TIME *timeA_ptr, LONG msecs_to_add)
5092 {
5093
5094 UINT status;
5095 ULONG timeA_usec;
5096 LONG seconds;
5097 LONG usecs;
5098
5099
5100 /* Separate msecs_to_add into seconds and milliseconds. */
5101 seconds = msecs_to_add / 1000;
5102 usecs = (msecs_to_add % 1000) * 1000;
5103
5104 /* Are we adding a positive number? */
5105 if (msecs_to_add > 0)
5106 {
5107 /* Yes; check for overflow before trying to add seconds to the TimeA operand. */
5108 status = _nx_sntp_client_utility_addition_overflow_check(timeA_ptr -> seconds, (ULONG)seconds);
5109
5110 /* Check for error (overflow). */
5111 if (status != NX_SUCCESS)
5112 {
5113
5114 /* Return the error condition. */
5115 return status;
5116 }
5117 }
5118 /* Check if a negative number larger than the timeA operand is being added (creates negative time!)*/
5119 else if (timeA_ptr -> seconds < (ULONG)abs(seconds))
5120 {
5121
5122 /* Yes; return the error condition. */
5123 return NX_SNTP_INVALID_TIME;
5124 }
5125
5126 /* Ok to add seconds to the NTP time seconds. */
5127 timeA_ptr -> seconds += (ULONG)seconds;
5128
5129 /* Next get the usecs from the timeA operand (always positive and < 1000000). */
5130 _nx_sntp_client_utility_fraction_to_usecs(timeA_ptr -> fraction, &timeA_usec);
5131
5132 /* In case usecs is < 0, we might have to perform a carry. */
5133 if ((usecs + (LONG)timeA_usec) < 0)
5134 {
5135 /* Perform a carry by subtracting a second from timeA seconds...*/
5136 timeA_ptr -> seconds--;
5137
5138 /* And adding it to the usecs of timeA. */
5139 timeA_usec += 1000000;
5140 }
5141
5142 /* OK to add the usecs up. */
5143 usecs += (LONG)timeA_usec;
5144
5145 /* Check for a positive carry over into seconds. */
5146 if (usecs >= 1000000)
5147 {
5148 /* Yes there's a carry; check for possibility of overflow
5149 before adding carry (unlikely for another 30 years). */
5150 if (timeA_ptr -> seconds == 0xFFFFFFFF)
5151 {
5152
5153 return NX_SNTP_OVERFLOW_ERROR;
5154 }
5155
5156 /* OK to increment the seconds. */
5157 timeA_ptr -> seconds++;
5158
5159 /* Set milliseconds to remainder. */
5160 usecs = usecs % 1000000;
5161 }
5162
5163 /* Convert usecs to the fixed point notation fraction and store in TimeA fraction. */
5164 status = _nx_sntp_client_utility_usecs_to_fraction((ULONG)usecs, &(timeA_ptr ->fraction));
5165
5166 /* Return completion status. */
5167 return status;
5168 }
5169
5170
5171 /**************************************************************************/
5172 /* */
5173 /* FUNCTION RELEASE */
5174 /* */
5175 /* _nxe_sntp_client_receiving_updates PORTABLE C */
5176 /* 6.1 */
5177 /* AUTHOR */
5178 /* */
5179 /* Yuxin Zhou, Microsoft Corporation */
5180 /* */
5181 /* DESCRIPTION */
5182 /* */
5183 /* This function performs error checking for the get SNTP get receive */
5184 /* status service. */
5185 /* */
5186 /* INPUT */
5187 /* */
5188 /* client_ptr Pointer to SNTP client instance */
5189 /* receive_status Pointer to server status */
5190 /* */
5191 /* OUTPUT */
5192 /* */
5193 /* NX_PTR_ERROR Invalid input status */
5194 /* status Actual completion status */
5195 /* */
5196 /* CALLS */
5197 /* */
5198 /* _nx_sntp_client_receiving_updates */
5199 /* Actual get server status service */
5200 /* */
5201 /* CALLED BY */
5202 /* */
5203 /* Application Code */
5204 /* */
5205 /* RELEASE HISTORY */
5206 /* */
5207 /* DATE NAME DESCRIPTION */
5208 /* */
5209 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5210 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5211 /* resulting in version 6.1 */
5212 /* */
5213 /**************************************************************************/
_nxe_sntp_client_receiving_updates(NX_SNTP_CLIENT * client_ptr,UINT * receive_status)5214 UINT _nxe_sntp_client_receiving_updates(NX_SNTP_CLIENT *client_ptr, UINT *receive_status)
5215 {
5216
5217 UINT status;
5218
5219 /* Check for the validity of input parameter. */
5220 if ((client_ptr == NX_NULL) || (receive_status == NX_NULL))
5221 {
5222
5223 /* Return error status. */
5224 return(NX_PTR_ERROR);
5225 }
5226
5227 status = _nx_sntp_client_receiving_updates(client_ptr, receive_status);
5228
5229 return status;
5230 }
5231
5232 /**************************************************************************/
5233 /* */
5234 /* FUNCTION RELEASE */
5235 /* */
5236 /* _nx_sntp_client_receiving_updates PORTABLE C */
5237 /* 6.1 */
5238 /* AUTHOR */
5239 /* */
5240 /* Yuxin Zhou, Microsoft Corporation */
5241 /* */
5242 /* DESCRIPTION */
5243 /* */
5244 /* This function returns the status of the Client SNTP server. If the */
5245 /* client has not received a valid update within the NX_SNTP_CLIENT_MAX_*/
5246 /* _TIME_LAPSE interval or if the number of invalid updates received by */
5247 /* the client exceeds the NX_SNTP_CLIENT_INVALID_UPDATE_LIMIT limit, */
5248 /* the status is set to NX_FALSE. If the Client has not yet received */
5249 /* its first valid update from the current SNTP server, status is set to*/
5250 /* false. */
5251 /* */
5252 /* INPUT */
5253 /* */
5254 /* client_ptr Pointer to SNTP client instance */
5255 /* receive_status Pointer to receive_status */
5256 /* NX_FALSE: not receiving updates */
5257 /* NX_TRUE: receiving valid updates */
5258 /* */
5259 /* OUTPUT */
5260 /* */
5261 /* NX_PTR_ERROR Invalid input status */
5262 /* status Actual completion status */
5263 /* */
5264 /* CALLS */
5265 /* */
5266 /* tx_mutex_get Get the SNTP mutex */
5267 /* tx_mutex_put Release the SNTP mutex */
5268 /* */
5269 /* CALLED BY */
5270 /* */
5271 /* Application Code */
5272 /* */
5273 /* RELEASE HISTORY */
5274 /* */
5275 /* DATE NAME DESCRIPTION */
5276 /* */
5277 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5278 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5279 /* resulting in version 6.1 */
5280 /* */
5281 /**************************************************************************/
_nx_sntp_client_receiving_updates(NX_SNTP_CLIENT * client_ptr,UINT * receive_status)5282 UINT _nx_sntp_client_receiving_updates(NX_SNTP_CLIENT *client_ptr, UINT *receive_status)
5283 {
5284
5285
5286 /* Get the SNTP mutex. */
5287 tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER);
5288
5289 /* Verify the client's SNTP server is valid, and the Client has received at least one valid udpate from it. */
5290 *receive_status = ((client_ptr -> nx_sntp_valid_server_status == NX_TRUE) && (client_ptr -> nx_sntp_client_first_update_pending == NX_FALSE));
5291
5292 /* Release the SNTP mutex. */
5293 tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex));
5294
5295 /* Return completion status. */
5296 return(NX_SUCCESS);
5297
5298 }
5299
5300
5301 /**************************************************************************/
5302 /* */
5303 /* FUNCTION RELEASE */
5304 /* */
5305 /* _nxe_sntp_client_set_local_time PORTABLE C */
5306 /* 6.1 */
5307 /* AUTHOR */
5308 /* */
5309 /* Yuxin Zhou, Microsoft Corporation */
5310 /* */
5311 /* DESCRIPTION */
5312 /* */
5313 /* This function performs error checking for the set client local time */
5314 /* service. */
5315 /* */
5316 /* INPUT */
5317 /* */
5318 /* client_ptr Pointer to SNTP Client */
5319 /* seconds Local time seconds component */
5320 /* fraction Local time fraction component */
5321 /* */
5322 /* OUTPUT */
5323 /* */
5324 /* status Actual completion status */
5325 /* NX_PTR_ERROR Invalid pointer input */
5326 /* */
5327 /* CALLS */
5328 /* */
5329 /* _nx_sntp_client_set_local_time Actual set client local time service*/
5330 /* */
5331 /* CALLED BY */
5332 /* */
5333 /* Application Code */
5334 /* */
5335 /* RELEASE HISTORY */
5336 /* */
5337 /* DATE NAME DESCRIPTION */
5338 /* */
5339 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5340 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5341 /* resulting in version 6.1 */
5342 /* */
5343 /**************************************************************************/
_nxe_sntp_client_set_local_time(NX_SNTP_CLIENT * client_ptr,ULONG seconds,ULONG fraction)5344 UINT _nxe_sntp_client_set_local_time(NX_SNTP_CLIENT *client_ptr, ULONG seconds, ULONG fraction)
5345 {
5346
5347 UINT status;
5348
5349
5350 /* Check for invalid input. */
5351 if (client_ptr == NX_NULL)
5352 {
5353 return NX_PTR_ERROR;
5354 }
5355
5356 /* Call the actual service. */
5357 status = _nx_sntp_client_set_local_time(client_ptr, seconds, fraction);
5358
5359 /* Return completion status. */
5360 return status;
5361 }
5362
5363
5364 /**************************************************************************/
5365 /* */
5366 /* FUNCTION RELEASE */
5367 /* */
5368 /* _nx_sntp_client_set_local_time PORTABLE C */
5369 /* 6.1 */
5370 /* AUTHOR */
5371 /* */
5372 /* Yuxin Zhou, Microsoft Corporation */
5373 /* */
5374 /* DESCRIPTION */
5375 /* */
5376 /* This function takes the seconds and fraction input from the caller */
5377 /* (or more accurately the independent time clock source, and applies it*/
5378 /* to the SNTP client local time. */
5379 /* */
5380 /* In between SNTP server updates, it is expected that the SNTP Client */
5381 /* host application will update the SNTP client local time from the */
5382 /* independent time source (e.g. real time clock on board) and then */
5383 /* use the SNTP Server time updates to correct the local time for drifts*/
5384 /* from the correct time. */
5385 /* */
5386 /* It can also set the SNTP Client's base time before starting up the */
5387 /* SNTP Client. If the host application cannot obtain a base time, the */
5388 /* SNTP Client will take the first SNTP update as the absolute time. If */
5389 /* the host application does have a real time clock or independent time */
5390 /* keeper, the SNTP client can set a large enough max adjustment that */
5391 /* any Server time udpate will be accepted to the SNTP Client. This */
5392 /* leaves the SNTP Client completely dependent on the network and SNTP */
5393 /* Server, plus it is vulnerable to rogue SNTP packets. */
5394 /* */
5395 /* INPUT */
5396 /* */
5397 /* client_ptr Pointer to SNTP Client */
5398 /* seconds Local time seconds component */
5399 /* fraction Local time fraction component */
5400 /* */
5401 /* OUTPUT */
5402 /* */
5403 /* NX_SUCCESS Successful completion status */
5404 /* */
5405 /* CALLS */
5406 /* */
5407 /* None */
5408 /* */
5409 /* CALLED BY */
5410 /* */
5411 /* Application Code */
5412 /* */
5413 /* RELEASE HISTORY */
5414 /* */
5415 /* DATE NAME DESCRIPTION */
5416 /* */
5417 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5418 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5419 /* resulting in version 6.1 */
5420 /* */
5421 /**************************************************************************/
_nx_sntp_client_set_local_time(NX_SNTP_CLIENT * client_ptr,ULONG seconds,ULONG fraction)5422 UINT _nx_sntp_client_set_local_time(NX_SNTP_CLIENT *client_ptr, ULONG seconds, ULONG fraction)
5423 {
5424
5425
5426 client_ptr -> nx_sntp_client_local_ntp_time.seconds = seconds;
5427 client_ptr -> nx_sntp_client_local_ntp_time.fraction = fraction;
5428 client_ptr -> nx_sntp_client_local_ntp_time_elapsed = 0;
5429
5430 /* Return completion status. */
5431 return NX_SUCCESS;
5432 }
5433
5434
5435 /**************************************************************************/
5436 /* */
5437 /* FUNCTION RELEASE */
5438 /* */
5439 /* _nxe_sntp_client_set_time_update_notify PORTABLE C */
5440 /* 6.1 */
5441 /* AUTHOR */
5442 /* */
5443 /* Yuxin Zhou, Microsoft Corporation */
5444 /* */
5445 /* DESCRIPTION */
5446 /* */
5447 /* This function performs error checking for the set time update */
5448 /* callback service. */
5449 /* */
5450 /* INPUT */
5451 /* */
5452 /* client_ptr Pointer to Client struct */
5453 /* time_update_cb Pointer to callback when Client */
5454 /* receives an SNTP update */
5455 /* */
5456 /* OUTPUT */
5457 /* */
5458 /* NX_SUCCESS Successful completion status */
5459 /* NX_PTR_ERROR Invalid pointer input */
5460 /* */
5461 /* CALLS */
5462 /* */
5463 /* _nx_sntp_client_set_time_update_notify */
5464 /* */
5465 /* CALLED BY */
5466 /* */
5467 /* Application */
5468 /* */
5469 /* RELEASE HISTORY */
5470 /* */
5471 /* DATE NAME DESCRIPTION */
5472 /* */
5473 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5474 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5475 /* resulting in version 6.1 */
5476 /* */
5477 /**************************************************************************/
_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))5478 UINT _nxe_sntp_client_set_time_update_notify(NX_SNTP_CLIENT *client_ptr,
5479 VOID (time_update_cb)(NX_SNTP_TIME_MESSAGE *time_update_ptr, NX_SNTP_TIME *local_time))
5480 {
5481
5482 UINT status;
5483
5484
5485 /* Check for valid input. */
5486 if ((client_ptr == NX_NULL) || (time_update_cb == NX_NULL))
5487 {
5488 return NX_PTR_ERROR;
5489 }
5490
5491 status = _nx_sntp_client_set_time_update_notify(client_ptr, time_update_cb);
5492
5493 return status;
5494 }
5495
5496 /**************************************************************************/
5497 /* */
5498 /* FUNCTION RELEASE */
5499 /* */
5500 /* _nx_sntp_client_set_time_update_notify PORTABLE C */
5501 /* 6.1 */
5502 /* AUTHOR */
5503 /* */
5504 /* Yuxin Zhou, Microsoft Corporation */
5505 /* */
5506 /* DESCRIPTION */
5507 /* */
5508 /* This function notifies the application of a valid SNTP time update. */
5509 /* */
5510 /* INPUT */
5511 /* */
5512 /* client_ptr Pointer to Client struct */
5513 /* time_update_cb Pointer to callback when Client */
5514 /* receives an SNTP update */
5515 /* */
5516 /* OUTPUT */
5517 /* */
5518 /* NX_SUCCESS Successful completion status */
5519 /* */
5520 /* CALLS */
5521 /* */
5522 /* None */
5523 /* */
5524 /* CALLED BY */
5525 /* */
5526 /* Application */
5527 /* */
5528 /* RELEASE HISTORY */
5529 /* */
5530 /* DATE NAME DESCRIPTION */
5531 /* */
5532 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5533 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5534 /* resulting in version 6.1 */
5535 /* */
5536 /**************************************************************************/
_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))5537 UINT _nx_sntp_client_set_time_update_notify(NX_SNTP_CLIENT *client_ptr,
5538 VOID (time_update_cb)(NX_SNTP_TIME_MESSAGE *time_update_ptr, NX_SNTP_TIME *local_time))
5539 {
5540
5541
5542 client_ptr -> nx_sntp_client_time_update_notify = time_update_cb;
5543
5544 return NX_SUCCESS;
5545 }
5546
5547
5548
5549
5550 /**************************************************************************/
5551 /* */
5552 /* FUNCTION RELEASE */
5553 /* */
5554 /* _nx_sntp_client_utility_get_msec_diff PORTABLE C */
5555 /* 6.1 */
5556 /* AUTHOR */
5557 /* */
5558 /* Yuxin Zhou, Microsoft Corporation */
5559 /* */
5560 /* DESCRIPTION */
5561 /* */
5562 /* This function computes the difference in milliseconds between two */
5563 /* NTP times, receiving an NTP packet, and transmitting it back. */
5564 /* The logic calculates the difference in the seconds component and */
5565 /* converts it to milliseconds. It converts the fraction to useconds */
5566 /* and calculates that difference. Useconds are rounded to the nearest */
5567 /* millisecond. This logic assumes the transmit time occurs after */
5568 /* receive time. */
5569 /* */
5570 /* The net difference is the difference in milliseconds from the */
5571 /* fractions added to (or subtracted from) the difference in */
5572 /* milliseconds from the seconds component. */
5573 /* */
5574 /* Note that the conversion of useconds to milliseconds may result */
5575 /* in the two times' difference to be zero, when they are actually */
5576 /* different by useconds. */
5577 /* */
5578 /* INPUT */
5579 /* */
5580 /* timeReceived_ptr NTP time of received message */
5581 /* timeTransmit_ptr NTP time of transmitted message */
5582 /* total_difference_msecs Millseconds of difference in time */
5583 /* pos_diff True if Transmit Time >= */
5584 /* Receive Time */
5585 /* */
5586 /* OUTPUT */
5587 /* */
5588 /* NX_SUCCESS Valid transmit/receive times */
5589 /* NX_SNTP_OVERFLOW_ERROR Overflow result */
5590 /* NX_SNTP_INVALID_TIME Transmit time<receive time seconds */
5591 /* */
5592 /* CALLS */
5593 /* */
5594 /* _nx_sntp_client_utility_convert_fraction_to_msecs */
5595 /* Convert fraction to milliseconds */
5596 /* */
5597 /* CALLED BY */
5598 /* */
5599 /* _nx_sntp_client_apply_sanity_checks */
5600 /* Apply sanity checks to time data */
5601 /* _nx_sntp_client_process_time_data */
5602 /* Apply server time to local time */
5603 /* */
5604 /* RELEASE HISTORY */
5605 /* */
5606 /* DATE NAME DESCRIPTION */
5607 /* */
5608 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5609 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5610 /* resulting in version 6.1 */
5611 /* */
5612 /**************************************************************************/
_nx_sntp_client_utility_get_msec_diff(NX_SNTP_TIME * timeReceived_ptr,NX_SNTP_TIME * timeTransmit_ptr,ULONG * total_difference_msecs,UINT * pos_diff)5613 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)
5614 {
5615
5616 ULONG usecsReceived, usecsTransmit;
5617 ULONG msecsReceived, msecsTransmit;
5618 ULONG seconds_difference_in_msecs;
5619 ULONG temp;
5620
5621
5622 /* Check for overflow with a very large positive difference result. */
5623 if (timeReceived_ptr -> seconds > timeTransmit_ptr -> seconds)
5624 {
5625
5626 /* Use a temporary variable to store the difference in the seconds. */
5627 temp = timeReceived_ptr -> seconds - timeTransmit_ptr -> seconds;
5628 *pos_diff = NX_FALSE;
5629 }
5630 else
5631 {
5632
5633 /* Reverse the operand to get the absolute difference in the seconds. */
5634 temp = timeTransmit_ptr -> seconds -timeReceived_ptr -> seconds;
5635 *pos_diff = NX_TRUE;
5636 }
5637
5638 /* Check for overflow when converting seconds to milliseconds
5639 (0x3E8 = 1000). */
5640 if (temp > (0xFFFFFFFF / 0x3E8))
5641 {
5642
5643 /* Return error status. */
5644 return NX_SNTP_OVERFLOW_ERROR;
5645 }
5646
5647 /* Convert to msecs. */
5648 seconds_difference_in_msecs = temp * 1000;
5649
5650 /* Convert the Received time fraction to usecs and msecs. */
5651 _nx_sntp_client_utility_fraction_to_usecs(timeReceived_ptr -> fraction, &usecsReceived);
5652
5653 msecsReceived = usecsReceived / 1000;
5654
5655 if (usecsReceived % 1000 >= 500)
5656 msecsReceived++;
5657
5658 /* Convert the Transmit Time fraction to usecs and msecs. */
5659 _nx_sntp_client_utility_fraction_to_usecs(timeTransmit_ptr -> fraction, &usecsTransmit);
5660
5661 msecsTransmit = usecsTransmit / 1000;
5662
5663 if (usecsTransmit % 1000 >= 500)
5664 msecsTransmit++;
5665
5666 /* Get the difference of the two time stamps' fraction in milliseconds. */
5667 if (timeReceived_ptr -> seconds == timeTransmit_ptr -> seconds)
5668 {
5669
5670 /* Determine the absolute difference in the millisecond component. */
5671 if (usecsTransmit >= usecsReceived)
5672 {
5673
5674 *total_difference_msecs = msecsTransmit - msecsReceived;
5675 }
5676 else
5677 {
5678
5679 /* Transmit time usecs < Received time usecs. */
5680 *pos_diff = NX_FALSE;
5681 *total_difference_msecs = msecsReceived - msecsTransmit;
5682 }
5683 }
5684 else
5685 {
5686
5687 /* Consider the case where the transmit time seconds is greater. */
5688 if (timeTransmit_ptr -> seconds > timeReceived_ptr -> seconds)
5689 {
5690
5691 if ( usecsTransmit >= usecsReceived)
5692 {
5693
5694 /* This will add to the total milliseconds' difference. */
5695 *total_difference_msecs = seconds_difference_in_msecs + (msecsTransmit - msecsReceived);
5696 }
5697 else /* (usecsReceived > usecsTransmit) */
5698 {
5699
5700 /* This will subtract from the total milliseconds' difference . */
5701 *total_difference_msecs = seconds_difference_in_msecs - (msecsReceived - msecsTransmit);
5702 }
5703 }
5704
5705 /* Consider the case where the transmit time seconds is less. */
5706 else
5707 {
5708
5709 if (usecsReceived >= usecsTransmit)
5710 {
5711
5712 /* This will add to the total milliseconds' difference. */
5713 *total_difference_msecs = seconds_difference_in_msecs + (msecsReceived - msecsTransmit);
5714 }
5715 else /* (usecsTransmit > usecsReceived) */
5716 {
5717
5718 /* This will subtract from the total milliseconds' difference . */
5719 *total_difference_msecs = seconds_difference_in_msecs - (msecsTransmit - msecsReceived);
5720 }
5721 }
5722 }
5723
5724 /* Return successful completion status. */
5725 return NX_SUCCESS;
5726
5727 }
5728
5729 /**************************************************************************/
5730 /* */
5731 /* FUNCTION RELEASE */
5732 /* */
5733 /* _nx_sntp_client_utility_is_zero_data PORTABLE C */
5734 /* 6.1 */
5735 /* AUTHOR */
5736 /* */
5737 /* Yuxin Zhou, Microsoft Corporation */
5738 /* */
5739 /* DESCRIPTION */
5740 /* */
5741 /* This function tests each byte (UCHAR) of data to be non zero. The */
5742 /* return value indicates if the entire data is zero. */
5743 /* */
5744 /* INPUT */
5745 /* */
5746 /* data Pointer to first byte of data */
5747 /* size Number of bytes in data */
5748 /* */
5749 /* OUTPUT */
5750 /* */
5751 /* NX_TRUE Each byte of data is zero */
5752 /* NX_FALSE At least one byte is non zero */
5753 /* */
5754 /* CALLS */
5755 /* */
5756 /* None */
5757 /* */
5758 /* CALLED BY */
5759 /* */
5760 /* _nx_sntp_client_apply_sanity_checks Checks SNTP server reply validity*/
5761 /* */
5762 /* RELEASE HISTORY */
5763 /* */
5764 /* DATE NAME DESCRIPTION */
5765 /* */
5766 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5767 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5768 /* resulting in version 6.1 */
5769 /* */
5770 /**************************************************************************/
_nx_sntp_client_utility_is_zero_data(UCHAR * data,UINT size)5771 UINT _nx_sntp_client_utility_is_zero_data(UCHAR *data, UINT size)
5772 {
5773
5774 UINT i;
5775 UINT is_zero;
5776
5777
5778 /* Initialize local variables. */
5779 i = 0;
5780 is_zero = NX_TRUE;
5781
5782 while(i < size)
5783 {
5784
5785 if (*data != 0x0)
5786 {
5787
5788 is_zero = NX_FALSE;
5789 break;
5790 }
5791
5792 data += sizeof(UCHAR);
5793 i++;
5794 }
5795
5796 return is_zero;
5797 }
5798
5799
5800 /**************************************************************************/
5801 /* */
5802 /* FUNCTION RELEASE */
5803 /* */
5804 /* _nx_sntp_client_utility_convert_fraction_to_msecs PORTABLE C */
5805 /* 6.1 */
5806 /* AUTHOR */
5807 /* */
5808 /* Yuxin Zhou, Microsoft Corporation */
5809 /* */
5810 /* DESCRIPTION */
5811 /* */
5812 /* This function converts the fraction in an NTP time to milliseconds. */
5813 /* */
5814 /* INPUT */
5815 /* */
5816 /* milliseconds Pointer to milliseconds converted */
5817 /* time_ptr Pointer to an NTP time */
5818 /* */
5819 /* OUTPUT */
5820 /* */
5821 /* NX_SUCCESS Successful completion */
5822 /* */
5823 /* CALLS */
5824 /* */
5825 /* _nx_sntp_client_utility_fraction_to_usecs */
5826 /* Convert fraction to usecs */
5827 /* */
5828 /* CALLED BY */
5829 /* */
5830 /* _nx_sntp_client_utility_display_NTP_time */
5831 /* Display NTP time in seconds */
5832 /* */
5833 /* RELEASE HISTORY */
5834 /* */
5835 /* DATE NAME DESCRIPTION */
5836 /* */
5837 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5838 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5839 /* resulting in version 6.1 */
5840 /* */
5841 /**************************************************************************/
_nx_sntp_client_utility_convert_fraction_to_msecs(ULONG * milliseconds,NX_SNTP_TIME * time_ptr)5842 UINT _nx_sntp_client_utility_convert_fraction_to_msecs(ULONG *milliseconds, NX_SNTP_TIME *time_ptr)
5843 {
5844
5845 ULONG usecs;
5846
5847
5848 /* Convert to usecs first. */
5849 _nx_sntp_client_utility_fraction_to_usecs(time_ptr ->fraction, &usecs);
5850
5851 /* Then convert to milliseconds. */
5852 *milliseconds = usecs / 1000;
5853
5854 /* Round up if greater than 500 usecs left over*/
5855 if (usecs % 1000 >= 500)
5856 {
5857
5858 (*milliseconds)++;
5859 }
5860
5861 /* Return successful completion. */
5862 return NX_SUCCESS;
5863 }
5864
5865
5866 /**************************************************************************/
5867 /* */
5868 /* FUNCTION RELEASE */
5869 /* */
5870 /* _nxe_sntp_client_utility_usecs_to_fraction PORTABLE C */
5871 /* 6.1 */
5872 /* AUTHOR */
5873 /* */
5874 /* Yuxin Zhou, Microsoft Corporation */
5875 /* */
5876 /* DESCRIPTION */
5877 /* */
5878 /* This function performs error checking on the utility to convert */
5879 /* microseconds to fraction. */
5880 /* */
5881 /* INPUT */
5882 /* */
5883 /* usecs Microseconds to convert */
5884 /* fraction Pointer to converted fraction */
5885 /* */
5886 /* OUTPUT */
5887 /* */
5888 /* NX_SNTP_INVALID_TIME Invalid SNTP data input */
5889 /* status Actual completion status */
5890 /* */
5891 /* CALLS */
5892 /* */
5893 /* _nx_sntp_client_utility_usecs_to_fraction */
5894 /* Actual usecs conversion service */
5895 /* */
5896 /* CALLED BY */
5897 /* */
5898 /* Application code */
5899 /* */
5900 /* RELEASE HISTORY */
5901 /* */
5902 /* DATE NAME DESCRIPTION */
5903 /* */
5904 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5905 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5906 /* resulting in version 6.1 */
5907 /* */
5908 /**************************************************************************/
_nxe_sntp_client_utility_usecs_to_fraction(ULONG usecs,ULONG * fraction)5909 UINT _nxe_sntp_client_utility_usecs_to_fraction(ULONG usecs, ULONG *fraction)
5910 {
5911
5912 UINT status;
5913
5914
5915 if ((usecs == 0) || (fraction == NX_NULL))
5916 {
5917
5918 return NX_SNTP_INVALID_TIME;
5919 }
5920
5921 status = _nx_sntp_client_utility_usecs_to_fraction(usecs, fraction);
5922
5923 return status;
5924 }
5925
5926
5927 /**************************************************************************/
5928 /* */
5929 /* FUNCTION RELEASE */
5930 /* */
5931 /* _nx_sntp_client_utility_usecs_to_fraction PORTABLE C */
5932 /* 6.1 */
5933 /* AUTHOR */
5934 /* */
5935 /* Yuxin Zhou, Microsoft Corporation */
5936 /* */
5937 /* DESCRIPTION */
5938 /* */
5939 /* This function converts microseconds to a time stamp fraction. It is */
5940 /* primarily an intermediary function used in the process of converting */
5941 /* millliseconds to fixed point time fraction data. */
5942 /* */
5943 /* This conversion scheme is limited to microseconds less than 1000000. */
5944 /* */
5945 /* INPUT */
5946 /* */
5947 /* usecs Microseconds to convert */
5948 /* fraction Fraction to converted fraction */
5949 /* */
5950 /* OUTPUT */
5951 /* */
5952 /* NX_SUCCESS Successful completion status */
5953 /* NX_SNTP_OVERFLOW_ERROR Overflow error status */
5954 /* */
5955 /* CALLS */
5956 /* */
5957 /* None */
5958 /* */
5959 /* CALLED BY */
5960 /* */
5961 /* _nx_sntp_client_utility_msecs_to_fraction */
5962 /* Convert milliseconds to fixed point*/
5963 /* */
5964 /* RELEASE HISTORY */
5965 /* */
5966 /* DATE NAME DESCRIPTION */
5967 /* */
5968 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5969 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5970 /* resulting in version 6.1 */
5971 /* */
5972 /**************************************************************************/
_nx_sntp_client_utility_usecs_to_fraction(ULONG usecs,ULONG * fraction)5973 UINT _nx_sntp_client_utility_usecs_to_fraction(ULONG usecs, ULONG *fraction)
5974 {
5975
5976 ULONG _frac = usecs * 3962;
5977
5978
5979 *fraction = (usecs * 4294) + (_frac >> 12);
5980
5981 if((_frac & 4095) >= 2048)
5982 *fraction = *fraction + 1;
5983
5984 /* Successful completion. */
5985 return NX_SUCCESS;
5986 }
5987
5988
5989 /**************************************************************************/
5990 /* */
5991 /* FUNCTION RELEASE */
5992 /* */
5993 /* _nxe_sntp_client_utility_msecs_to_fraction PORTABLE C */
5994 /* 6.1 */
5995 /* AUTHOR */
5996 /* */
5997 /* Yuxin Zhou, Microsoft Corporation */
5998 /* */
5999 /* DESCRIPTION */
6000 /* */
6001 /* This function performs error checking on the utility to convert */
6002 /* milliseconds to fraction. */
6003 /* */
6004 /* INPUT */
6005 /* */
6006 /* msecs Milliseconds to convert */
6007 /* fraction Pointer to converted fraction */
6008 /* */
6009 /* OUTPUT */
6010 /* */
6011 /* NX_SNTP_INVALID_TIME Invalid SNTP data input */
6012 /* status Actual completion status */
6013 /* */
6014 /* CALLS */
6015 /* */
6016 /* _nx_sntp_client_utility_msecs_to_fraction */
6017 /* Actual msecs conversion service */
6018 /* */
6019 /* CALLED BY */
6020 /* */
6021 /* Application code */
6022 /* */
6023 /* RELEASE HISTORY */
6024 /* */
6025 /* DATE NAME DESCRIPTION */
6026 /* */
6027 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6028 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
6029 /* resulting in version 6.1 */
6030 /* */
6031 /**************************************************************************/
_nxe_sntp_client_utility_msecs_to_fraction(ULONG msecs,ULONG * fraction)6032 UINT _nxe_sntp_client_utility_msecs_to_fraction(ULONG msecs, ULONG *fraction)
6033 {
6034
6035 UINT status;
6036
6037
6038 if ((msecs == 0) || (fraction == NX_NULL))
6039 {
6040
6041 return NX_SNTP_INVALID_TIME;
6042 }
6043
6044 status = _nx_sntp_client_utility_msecs_to_fraction(msecs, fraction);
6045
6046 return status;
6047 }
6048
6049
6050 /**************************************************************************/
6051 /* */
6052 /* FUNCTION RELEASE */
6053 /* */
6054 /* _nx_sntp_client_utility_msecs_to_fraction PORTABLE C */
6055 /* 6.1 */
6056 /* AUTHOR */
6057 /* */
6058 /* Yuxin Zhou, Microsoft Corporation */
6059 /* */
6060 /* DESCRIPTION */
6061 /* */
6062 /* This function converts milliseconds to fixed point notation used in */
6063 /* the NTP time fraction field. This will not accept msecs >= 1000 */
6064 /* because that number cannot be represented in an NTP time fraction. */
6065 /* */
6066 /* INPUT */
6067 /* */
6068 /* msecs Milliseconds to convert */
6069 /* fraction Pointer to converted fraction */
6070 /* */
6071 /* OUTPUT */
6072 /* */
6073 /* NX_SUCCESS Successful completion status */
6074 /* NX_SNTP_OVERFLOW_ERROR Overflow result */
6075 /* status Actual completion status */
6076 /* */
6077 /* CALLS */
6078 /* */
6079 /* _nx_sntp_client_utility_usecs_to_fraction */
6080 /* Convert usecs to fixed point */
6081 /* */
6082 /* CALLED BY */
6083 /* */
6084 /* _nx_sntp_client_utility_add_msecs_to_ntp_time */
6085 /* Add msecs to an NTP time data */
6086 /* _nx_sntp_client_utility_add_NTPtime */
6087 /* Add two NTP time fields */
6088 /* */
6089 /* RELEASE HISTORY */
6090 /* */
6091 /* DATE NAME DESCRIPTION */
6092 /* */
6093 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6094 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
6095 /* resulting in version 6.1 */
6096 /* */
6097 /**************************************************************************/
_nx_sntp_client_utility_msecs_to_fraction(ULONG msecs,ULONG * fraction)6098 UINT _nx_sntp_client_utility_msecs_to_fraction(ULONG msecs, ULONG *fraction)
6099 {
6100
6101 UINT status;
6102 ULONG usecs;
6103
6104
6105 /* Check for possible overflow. */
6106 if (msecs > 1000)
6107 {
6108
6109 /* Return error condition. */
6110 return NX_SNTP_OVERFLOW_ERROR;
6111 }
6112
6113 /* Convert msecs to usecs first. */
6114 usecs = msecs * 1000;
6115
6116 /* Convert usecs to fraction. */
6117 status = _nx_sntp_client_utility_usecs_to_fraction(usecs, fraction);
6118
6119 /* Check for error. */
6120 if (status != NX_SUCCESS)
6121 {
6122
6123 /* Return the error status. */
6124 return status;
6125 }
6126
6127 /* Successful completion. */
6128 return NX_SUCCESS;
6129 }
6130
6131
6132 /**************************************************************************/
6133 /* */
6134 /* FUNCTION RELEASE */
6135 /* */
6136 /* _nxe_sntp_client_utility_fraction_to_usecs PORTABLE C */
6137 /* 6.1 */
6138 /* AUTHOR */
6139 /* */
6140 /* Yuxin Zhou, Microsoft Corporation */
6141 /* */
6142 /* DESCRIPTION */
6143 /* */
6144 /* This function performs error checking on the utility to convert */
6145 /* fraction to microseconds. */
6146 /* */
6147 /* INPUT */
6148 /* */
6149 /* fraction Fraction to convert */
6150 /* usecs Pointer to converted microseconds */
6151 /* */
6152 /* OUTPUT */
6153 /* */
6154 /* status Actual completion status */
6155 /* */
6156 /* CALLS */
6157 /* */
6158 /* _nx_sntp_client_utility_fraction_to_usecs */
6159 /* Actual usecs conversion service */
6160 /* */
6161 /* CALLED BY */
6162 /* */
6163 /* Application code */
6164 /* */
6165 /* RELEASE HISTORY */
6166 /* */
6167 /* DATE NAME DESCRIPTION */
6168 /* */
6169 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6170 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
6171 /* resulting in version 6.1 */
6172 /* */
6173 /**************************************************************************/
_nxe_sntp_client_utility_fraction_to_usecs(ULONG fraction,ULONG * usecs)6174 UINT _nxe_sntp_client_utility_fraction_to_usecs(ULONG fraction, ULONG *usecs)
6175 {
6176
6177 UINT status;
6178
6179
6180 if (usecs == NX_NULL)
6181 {
6182 return NX_SNTP_INVALID_TIME;
6183 }
6184
6185 status = _nx_sntp_client_utility_fraction_to_usecs(fraction, usecs);
6186
6187 return status;
6188 }
6189
6190
6191 /**************************************************************************/
6192 /* */
6193 /* FUNCTION RELEASE */
6194 /* */
6195 /* _nx_sntp_client_utility_fraction_to_usecs PORTABLE C */
6196 /* 6.1 */
6197 /* AUTHOR */
6198 /* */
6199 /* Yuxin Zhou, Microsoft Corporation */
6200 /* */
6201 /* DESCRIPTION */
6202 /* */
6203 /* This function converts a time stamp fraction to microseconds. It is */
6204 /* primarily an intermediary function used in the process of converting */
6205 /* fixed point time fraction data to msecs. */
6206 /* */
6207 /* INPUT */
6208 /* */
6209 /* fraction Fraction to convert to usecs */
6210 /* usecs Pointer to ucsecs from fraction */
6211 /* */
6212 /* OUTPUT */
6213 /* */
6214 /* None */
6215 /* */
6216 /* CALLS */
6217 /* */
6218 /* None */
6219 /* */
6220 /* CALLED BY */
6221 /* */
6222 /* _nx_sntp_client_get_local_time_extended */
6223 /* Get extended local time */
6224 /* _nx_sntp_client_utility_convert_fraction_to_msecs */
6225 /* Convert time fraction to msecs */
6226 /* */
6227 /* RELEASE HISTORY */
6228 /* */
6229 /* DATE NAME DESCRIPTION */
6230 /* */
6231 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6232 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
6233 /* resulting in version 6.1 */
6234 /* */
6235 /**************************************************************************/
_nx_sntp_client_utility_fraction_to_usecs(ULONG fraction,ULONG * usecs)6236 UINT _nx_sntp_client_utility_fraction_to_usecs(ULONG fraction, ULONG *usecs)
6237 {
6238
6239 ULONG value, segment;
6240 int i;
6241
6242 value = 0;
6243
6244 for(i = 2; i < 32; i+=6)
6245 {
6246 segment = (fraction >> i) & 0x3F;
6247
6248 if((value & 0x3F) >= 32)
6249 value = (value >> 6) + segment * 15625 + 1;
6250 else
6251 value = (value >> 6) + segment * 15625;
6252 }
6253 *usecs = value;
6254
6255 return(NX_SUCCESS);
6256 }
6257
6258
6259 /**************************************************************************/
6260 /* */
6261 /* FUNCTION RELEASE */
6262 /* */
6263 /* _nx_sntp_client_utility_convert_refID_KOD_code PORTABLE C */
6264 /* 6.1 */
6265 /* AUTHOR */
6266 /* */
6267 /* Yuxin Zhou, Microsoft Corporation */
6268 /* */
6269 /* DESCRIPTION */
6270 /* */
6271 /* This function converts the reference ID field in a NTP time message */
6272 /* data to a known Kiss of Death reference_id. */
6273 /* */
6274 /* Note the Kiss of Death reference_id list is subject to change. This */
6275 /* is current as of 4/01/2007. */
6276 /* */
6277 /* INPUT */
6278 /* */
6279 /* reference_id Pointer to the reference ID to convert */
6280 /* code_id Pointer to converted code */
6281 /* */
6282 /* OUTPUT */
6283 /* */
6284 /* NX_SUCCESS Successful completion status */
6285 /* */
6286 /* CALLS */
6287 /* */
6288 /* memcmp Copy data to specified area of memory */
6289 /* */
6290 /* CALLED BY */
6291 /* */
6292 /* Application Code (e.g. the Client kiss of death handler callback) */
6293 /* */
6294 /* RELEASE HISTORY */
6295 /* */
6296 /* DATE NAME DESCRIPTION */
6297 /* */
6298 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6299 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
6300 /* resulting in version 6.1 */
6301 /* */
6302 /**************************************************************************/
_nx_sntp_client_utility_convert_refID_KOD_code(UCHAR * reference_id,UINT * code_id)6303 UINT _nx_sntp_client_utility_convert_refID_KOD_code(UCHAR *reference_id, UINT *code_id)
6304 {
6305
6306 /* This is the internal list of Kiss of Death codes and their meaning. */
6307
6308
6309 /* Compare the reference_id to each known reference_id and if it matches return the reference_id ID. */
6310 if (!memcmp(reference_id, ANYCAST, 4))
6311 {
6312 *code_id = NX_SNTP_KOD_ANYCAST;
6313 }
6314 else if (!memcmp(reference_id, AUTH_FAIL, 4))
6315 {
6316 *code_id = NX_SNTP_KOD_AUTH_FAIL;
6317 }
6318 else if (!memcmp(reference_id, AUTOKEY_FAIL, 4))
6319 {
6320 *code_id = NX_SNTP_KOD_AUTOKEY_FAIL;
6321 }
6322 else if (!memcmp(reference_id, BROADCAST, 4))
6323 {
6324 *code_id = NX_SNTP_KOD_BROADCAST;
6325 }
6326 else if (!memcmp(reference_id, CRYP_FAIL, 4))
6327 {
6328 *code_id = NX_SNTP_KOD_CRYP_FAIL;
6329 }
6330 else if (!memcmp(reference_id, DENY, 4))
6331 {
6332 *code_id = NX_SNTP_KOD_DENY;
6333 }
6334 else if (!memcmp(reference_id, DROP, 4))
6335 {
6336 *code_id = NX_SNTP_KOD_DROP;
6337 }
6338 else if (!memcmp(reference_id, DENY_POLICY, 4))
6339 {
6340 *code_id = NX_SNTP_KOD_DENY_POLICY;
6341 }
6342 else if (!memcmp(reference_id, NOT_INIT, 4))
6343 {
6344 *code_id = NX_SNTP_KOD_NOT_INIT;
6345 }
6346 else if (!memcmp(reference_id, MANYCAST, 4))
6347 {
6348 *code_id = NX_SNTP_KOD_MANYCAST;
6349 }
6350 else if (!memcmp(reference_id, NO_KEY, 4))
6351 {
6352 *code_id = NX_SNTP_KOD_NO_KEY;
6353 }
6354 else if (!memcmp(reference_id, RATE, 4))
6355 {
6356 *code_id = NX_SNTP_KOD_RATE;
6357 }
6358 else if (!memcmp(reference_id, RMOT, 4))
6359 {
6360 *code_id = NX_SNTP_KOD_RMOT;
6361 }
6362 else if (!memcmp(reference_id, STEP, 4))
6363 {
6364 *code_id = NX_SNTP_KOD_STEP;
6365 }
6366 else
6367 {
6368 /* Set reference_id ID to generic KOD 'other' reference_id. */
6369 *code_id = NX_SNTP_KISS_OF_DEATH_PACKET;
6370 }
6371
6372 /* Return successful completion. */
6373 return NX_SUCCESS;
6374 }
6375
6376
6377 /**************************************************************************/
6378 /* */
6379 /* FUNCTION RELEASE */
6380 /* */
6381 /* _nx_sntp_client_utility_addition_overflow_check PORTABLE C */
6382 /* 6.1 */
6383 /* AUTHOR */
6384 /* */
6385 /* Yuxin Zhou, Microsoft Corporation */
6386 /* */
6387 /* DESCRIPTION */
6388 /* */
6389 /* This function performs a simple platform independent check for */
6390 /* overflow when adding two operands. */
6391 /* */
6392 /* INPUT */
6393 /* */
6394 /* temp1 First addition operand */
6395 /* temp2 Second addition operand */
6396 /* */
6397 /* OUTPUT */
6398 /* */
6399 /* NX_SNTP_OVERFLOW_ERROR Overflow result adding time */
6400 /* NX_SUCCESS Successful completion status */
6401 /* */
6402 /* CALLS */
6403 /* */
6404 /* None */
6405 /* */
6406 /* CALLED BY */
6407 /* */
6408 /* _nx_sntp_client_utility_add_msecs_to_ntp_time */
6409 /* Add msecs to an NTP time */
6410 /* _nx_sntp_client_utility_add_NTPtime */
6411 /* Add two NTP times */
6412 /* */
6413 /* RELEASE HISTORY */
6414 /* */
6415 /* DATE NAME DESCRIPTION */
6416 /* */
6417 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6418 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
6419 /* resulting in version 6.1 */
6420 /* */
6421 /**************************************************************************/
_nx_sntp_client_utility_addition_overflow_check(ULONG temp1,ULONG temp2)6422 UINT _nx_sntp_client_utility_addition_overflow_check(ULONG temp1, ULONG temp2)
6423 {
6424
6425 ULONG sum_lower_16, sum_upper_16;
6426 UINT carry;
6427
6428
6429 carry = 0;
6430
6431 /* Add the lower 16 bits. */
6432 sum_lower_16 = (temp1 & NX_LOWER_16_MASK) + (temp2 & NX_LOWER_16_MASK);
6433
6434 /* Check for carry. */
6435 if (sum_lower_16 & NX_CARRY_BIT)
6436 {
6437
6438 /* Use variable to add the carry to the upper 16 bits.*/
6439 carry = 1;
6440 }
6441
6442 /* Add the upper 16 bits. */
6443 sum_upper_16 = (temp1 >> NX_SHIFT_BY_16) + (temp2 >> NX_SHIFT_BY_16) + carry;
6444
6445 /* Check for carry. */
6446 if (sum_upper_16 & NX_CARRY_BIT)
6447 {
6448
6449 /* This indicates an overflow. Return as an error. */
6450 return NX_SNTP_OVERFLOW_ERROR;
6451 }
6452
6453 /* Ok to add operands!*/
6454 return NX_SUCCESS;
6455 }