iPXE
ntp.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27#include <stdint.h>
28#include <string.h>
29#include <errno.h>
30#include <time.h>
31#include <ipxe/malloc.h>
32#include <ipxe/refcnt.h>
33#include <ipxe/iobuf.h>
34#include <ipxe/xfer.h>
35#include <ipxe/open.h>
36#include <ipxe/retry.h>
37#include <ipxe/timer.h>
38#include <ipxe/time.h>
39#include <ipxe/tcpip.h>
40#include <ipxe/dhcp.h>
41#include <ipxe/settings.h>
42#include <ipxe/ntp.h>
43
44/** @file
45 *
46 * Network Time Protocol
47 *
48 */
49
50/** An NTP client */
51struct ntp_client {
52 /** Reference count */
53 struct refcnt refcnt;
54 /** Job control interface */
55 struct interface job;
56 /** Data transfer interface */
58 /** Retransmission timer */
60};
61
62/**
63 * Close NTP client
64 *
65 * @v ntp NTP client
66 * @v rc Reason for close
67 */
68static void ntp_close ( struct ntp_client *ntp, int rc ) {
69
70 /* Stop timer */
71 stop_timer ( &ntp->timer );
72
73 /* Shut down interfaces */
74 intf_shutdown ( &ntp->xfer, rc );
75 intf_shutdown ( &ntp->job, rc );
76}
77
78/**
79 * Send NTP request
80 *
81 * @v ntp NTP client
82 * @ret rc Return status code
83 */
84static int ntp_request ( struct ntp_client *ntp ) {
85 struct ntp_header hdr;
86 int rc;
87
88 DBGC ( ntp, "NTP %p sending request\n", ntp );
89
90 /* Construct header */
91 memset ( &hdr, 0, sizeof ( hdr ) );
93 hdr.transmit.seconds = htonl ( time ( NULL ) + NTP_EPOCH );
94 hdr.transmit.fraction = htonl ( NTP_FRACTION_MAGIC );
95
96 /* Send request */
97 if ( ( rc = xfer_deliver_raw ( &ntp->xfer, &hdr,
98 sizeof ( hdr ) ) ) != 0 ) {
99 DBGC ( ntp, "NTP %p could not send request: %s\n",
100 ntp, strerror ( rc ) );
101 return rc;
102 }
103
104 return 0;
105}
106
107/**
108 * Handle NTP response
109 *
110 * @v ntp NTP client
111 * @v iobuf I/O buffer
112 * @v meta Data transfer metadata
113 * @ret rc Return status code
114 */
115static int ntp_deliver ( struct ntp_client *ntp, struct io_buffer *iobuf,
116 struct xfer_metadata *meta ) {
117 struct ntp_header *hdr;
118 struct sockaddr_tcpip *st_src;
119 int32_t delta;
120 int rc;
121
122 /* Check source port */
123 st_src = ( ( struct sockaddr_tcpip * ) meta->src );
124 if ( st_src->st_port != htons ( NTP_PORT ) ) {
125 DBGC ( ntp, "NTP %p received non-NTP packet:\n", ntp );
126 DBGC_HDA ( ntp, 0, iobuf->data, iob_len ( iobuf ) );
127 goto ignore;
128 }
129
130 /* Check packet length */
131 if ( iob_len ( iobuf ) < sizeof ( *hdr ) ) {
132 DBGC ( ntp, "NTP %p received malformed packet:\n", ntp );
133 DBGC_HDA ( ntp, 0, iobuf->data, iob_len ( iobuf ) );
134 goto ignore;
135 }
136 hdr = iobuf->data;
137
138 /* Check mode */
139 if ( ( hdr->flags & NTP_FL_MODE_MASK ) != NTP_FL_MODE_SERVER ) {
140 DBGC ( ntp, "NTP %p received non-server packet:\n", ntp );
141 DBGC_HDA ( ntp, 0, iobuf->data, iob_len ( iobuf ) );
142 goto ignore;
143 }
144
145 /* Check magic value */
146 if ( hdr->originate.fraction != htonl ( NTP_FRACTION_MAGIC ) ) {
147 DBGC ( ntp, "NTP %p received unrecognised packet:\n", ntp );
148 DBGC_HDA ( ntp, 0, iobuf->data, iob_len ( iobuf ) );
149 goto ignore;
150 }
151
152 /* Check for Kiss-o'-Death packets */
153 if ( ! hdr->stratum ) {
154 DBGC ( ntp, "NTP %p received kiss-o'-death:\n", ntp );
155 DBGC_HDA ( ntp, 0, iobuf->data, iob_len ( iobuf ) );
156 rc = -EPROTO;
157 goto close;
158 }
159
160 /* Calculate clock delta */
161 delta = ( ntohl ( hdr->receive.seconds ) -
162 ntohl ( hdr->originate.seconds ) );
163 DBGC ( ntp, "NTP %p delta %d seconds\n", ntp, delta );
164
165 /* Adjust system clock */
166 time_adjust ( delta );
167
168 /* Success */
169 rc = 0;
170
171 close:
172 ntp_close ( ntp, rc );
173 ignore:
174 free_iob ( iobuf );
175 return 0;
176}
177
178/**
179 * Handle data transfer window change
180 *
181 * @v ntp NTP client
182 */
183static void ntp_window_changed ( struct ntp_client *ntp ) {
184
185 /* Start timer to send initial request */
186 start_timer_nodelay ( &ntp->timer );
187}
188
189/** Data transfer interface operations */
196
197/** Data transfer interface descriptor */
199 INTF_DESC_PASSTHRU ( struct ntp_client, xfer, ntp_xfer_op, job );
200
201/** Job control interface operations */
203 INTF_OP ( intf_close, struct ntp_client *, ntp_close ),
204};
205
206/** Job control interface descriptor */
208 INTF_DESC_PASSTHRU ( struct ntp_client, job, ntp_job_op, xfer );
209
210/**
211 * Handle NTP timer expiry
212 *
213 * @v timer Retransmission timer
214 * @v fail Failure indicator
215 */
216static void ntp_expired ( struct retry_timer *timer, int fail ) {
217 struct ntp_client *ntp =
218 container_of ( timer, struct ntp_client, timer );
219
220 /* Shut down client if we have failed */
221 if ( fail ) {
222 ntp_close ( ntp, -ETIMEDOUT );
223 return;
224 }
225
226 /* Otherwise, restart timer and (re)transmit request */
227 start_timer ( &ntp->timer );
228 ntp_request ( ntp );
229}
230
231/**
232 * Start NTP client
233 *
234 * @v job Job control interface
235 * @v hostname NTP server
236 * @ret rc Return status code
237 */
238int start_ntp ( struct interface *job, const char *hostname ) {
239 struct ntp_client *ntp;
240 union {
241 struct sockaddr_tcpip st;
242 struct sockaddr sa;
243 } server;
244 int rc;
245
246 /* Allocate and initialise structure*/
247 ntp = zalloc ( sizeof ( *ntp ) );
248 if ( ! ntp ) {
249 rc = -ENOMEM;
250 goto err_alloc;
251 }
252 ref_init ( &ntp->refcnt, NULL );
253 intf_init ( &ntp->job, &ntp_job_desc, &ntp->refcnt );
254 intf_init ( &ntp->xfer, &ntp_xfer_desc, &ntp->refcnt );
255 timer_init ( &ntp->timer, ntp_expired, &ntp->refcnt );
256 set_timer_limits ( &ntp->timer, NTP_MIN_TIMEOUT, NTP_MAX_TIMEOUT );
257
258 /* Open socket */
259 memset ( &server, 0, sizeof ( server ) );
260 server.st.st_port = htons ( NTP_PORT );
261 if ( ( rc = xfer_open_named_socket ( &ntp->xfer, SOCK_DGRAM, &server.sa,
262 hostname, NULL ) ) != 0 ) {
263 DBGC ( ntp, "NTP %p could not open socket: %s\n",
264 ntp, strerror ( rc ) );
265 goto err_open;
266 }
267
268 /* Attach parent interface, mortalise self, and return */
269 intf_plug_plug ( &ntp->job, job );
270 ref_put ( &ntp->refcnt );
271 return 0;
272
273 err_open:
274 ntp_close ( ntp, rc );
275 ref_put ( &ntp->refcnt );
276 err_alloc:
277 return rc;
278}
279
280/** IPv4 NTP server setting */
281const struct setting ntp_setting __setting ( SETTING_IP4_EXTRA, ntp ) = {
282 .name = "ntp",
283 .description = "NTP server",
284 .tag = DHCP_NTP_SERVERS,
285 .type = &setting_type_ipv4,
286};
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
struct golan_inbox_hdr hdr
Message header.
Definition CIB_PRM.h:0
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
signed int int32_t
Definition stdint.h:17
uint8_t meta
Metadata flags.
Definition ena.h:3
Error codes.
#define SOCK_DGRAM
Definition socket.h:30
#define DBGC(...)
Definition compiler.h:505
#define DBGC_HDA(...)
Definition compiler.h:506
#define DHCP_NTP_SERVERS
NTP servers.
Definition dhcp.h:90
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ETIMEDOUT
Connection timed out.
Definition errno.h:670
#define EPROTO
Protocol error.
Definition errno.h:625
#define ENOMEM
Not enough space.
Definition errno.h:535
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
#define SETTING_IP4_EXTRA
IPv4 additional settings.
Definition settings.h:67
#define ntohl(value)
Definition byteswap.h:135
#define htonl(value)
Definition byteswap.h:134
#define htons(value)
Definition byteswap.h:136
Dynamic Host Configuration Protocol.
Configuration settings.
#define __setting(setting_order, name)
Declare a configuration setting.
Definition settings.h:57
Transport-network layer interface.
Time source.
iPXE timers
String functions.
void * memset(void *dest, int character, size_t len) __nonnull
Date and time.
void intf_close(struct interface *intf, int rc)
Close an object interface.
Definition interface.c:250
void intf_plug_plug(struct interface *a, struct interface *b)
Plug two object interfaces together.
Definition interface.c:108
void intf_shutdown(struct interface *intf, int rc)
Shut down an object interface.
Definition interface.c:279
#define INTF_DESC_PASSTHRU(object_type, intf, operations, passthru)
Define an object interface descriptor with pass-through interface.
Definition interface.h:98
static void intf_init(struct interface *intf, struct interface_descriptor *desc, struct refcnt *refcnt)
Initialise an object interface.
Definition interface.h:204
#define INTF_OP(op_type, object_type, op_func)
Define an object interface operation.
Definition interface.h:33
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
I/O buffers.
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:160
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:662
Dynamic memory allocation.
static int ntp_request(struct ntp_client *ntp)
Send NTP request.
Definition ntp.c:84
static struct interface_descriptor ntp_xfer_desc
Data transfer interface descriptor.
Definition ntp.c:198
static void ntp_window_changed(struct ntp_client *ntp)
Handle data transfer window change.
Definition ntp.c:183
static struct interface_operation ntp_job_op[]
Job control interface operations.
Definition ntp.c:202
static struct interface_descriptor ntp_job_desc
Job control interface descriptor.
Definition ntp.c:207
static void ntp_close(struct ntp_client *ntp, int rc)
Close NTP client.
Definition ntp.c:68
static int ntp_deliver(struct ntp_client *ntp, struct io_buffer *iobuf, struct xfer_metadata *meta)
Handle NTP response.
Definition ntp.c:115
static void ntp_expired(struct retry_timer *timer, int fail)
Handle NTP timer expiry.
Definition ntp.c:216
static struct interface_operation ntp_xfer_op[]
Data transfer interface operations.
Definition ntp.c:190
int start_ntp(struct interface *job, const char *hostname)
Start NTP client.
Definition ntp.c:238
Network Time Protocol.
#define NTP_FL_LI_UNKNOWN
Leap second indicator: unknown.
Definition ntp.h:73
#define NTP_MAX_TIMEOUT
NTP maximum retransmission timeout.
Definition ntp.h:106
#define NTP_MIN_TIMEOUT
NTP minimum retransmission timeout.
Definition ntp.h:100
#define NTP_FL_VN_1
NTP version: 1.
Definition ntp.h:76
#define NTP_FRACTION_MAGIC
NTP fraction of a second magic value.
Definition ntp.h:94
#define NTP_PORT
NTP port.
Definition ntp.h:18
#define NTP_EPOCH
NTP timestamp for start of Unix epoch.
Definition ntp.h:88
#define NTP_FL_MODE_SERVER
NTP mode: server.
Definition ntp.h:82
#define NTP_FL_MODE_CLIENT
NTP mode: client.
Definition ntp.h:79
#define NTP_FL_MODE_MASK
NTP mode mask.
Definition ntp.h:85
int ntp(const char *hostname)
Get time and date via NTP.
Definition ntpmgmt.c:46
Data transfer interface opening.
Reference counting.
#define ref_put(refcnt)
Drop reference to object.
Definition refcnt.h:107
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition refcnt.h:65
int xfer_open_named_socket(struct interface *xfer, int semantics, struct sockaddr *peer, const char *name, struct sockaddr *local)
Open named socket.
Definition resolv.c:403
void start_timer(struct retry_timer *timer)
Start timer.
Definition retry.c:94
void stop_timer(struct retry_timer *timer)
Stop timer.
Definition retry.c:118
Retry timers.
static void start_timer_nodelay(struct retry_timer *timer)
Start timer with no delay.
Definition retry.h:100
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
An object interface descriptor.
Definition interface.h:56
An object interface operation.
Definition interface.h:18
An object interface.
Definition interface.h:125
A persistent I/O buffer.
Definition iobuf.h:38
void * data
Start of data.
Definition iobuf.h:53
An NTP client.
Definition ntp.c:51
struct interface job
Job control interface.
Definition ntp.c:55
struct interface xfer
Data transfer interface.
Definition ntp.c:57
struct refcnt refcnt
Reference count.
Definition ntp.c:53
struct retry_timer timer
Retransmission timer.
Definition ntp.c:59
An NTP header.
Definition ntp.h:47
A retry timer.
Definition retry.h:22
A setting.
Definition settings.h:24
TCP/IP socket address.
Definition tcpip.h:76
uint16_t st_port
TCP/IP port.
Definition tcpip.h:82
Generalized socket address structure.
Definition socket.h:97
A timer.
Definition timer.h:29
Data transfer metadata.
Definition xfer.h:23
struct sockaddr_tcpip st
Definition syslog.c:58
struct sockaddr sa
Definition syslog.c:57
static struct evtchn_close * close
Definition xenevent.h:24
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition xfer.c:195
void xfer_window_changed(struct interface *intf)
Report change of flow control window.
Definition xfer.c:147
int xfer_deliver_raw(struct interface *intf, const void *data, size_t len)
Deliver datagram as raw data without metadata.
Definition xfer.c:289
Data transfer interfaces.