1 /*
2  * ngtcp2
3  *
4  * Copyright (c) 2019 ngtcp2 contributors
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 #ifndef NGTCP2_PV_H
26 #define NGTCP2_PV_H
27 
28 #ifdef HAVE_CONFIG_H
29 #  include <config.h>
30 #endif /* HAVE_CONFIG_H */
31 
32 #include <ngtcp2/ngtcp2.h>
33 
34 #include "ngtcp2_cid.h"
35 #include "ngtcp2_ringbuf.h"
36 
37 /* NGTCP2_PV_MAX_ENTRIES is the maximum number of entries that
38    ngtcp2_pv can contain.  It must be power of 2. */
39 #define NGTCP2_PV_MAX_ENTRIES 8
40 /* NGTCP2_PV_NUM_PROBE_PKT is the number of probe packets containing
41    PATH_CHALLENGE sent at a time. */
42 #define NGTCP2_PV_NUM_PROBE_PKT 2
43 
44 typedef struct ngtcp2_log ngtcp2_log;
45 
46 typedef struct ngtcp2_frame_chain ngtcp2_frame_chain;
47 
48 /* NGTCP2_PV_ENTRY_FLAG_NONE indicates that no flag is set. */
49 #define NGTCP2_PV_ENTRY_FLAG_NONE 0x00
50 /* NGTCP2_PV_ENTRY_FLAG_UNDERSIZED indicates that UDP datagram which
51    contains PATH_CHALLENGE is undersized (< 1200 bytes) */
52 #define NGTCP2_PV_ENTRY_FLAG_UNDERSIZED 0x01
53 
54 typedef struct ngtcp2_pv_entry {
55   /* expiry is the timestamp when this PATH_CHALLENGE expires. */
56   ngtcp2_tstamp expiry;
57   /* flags is zero or more of NGTCP2_PV_ENTRY_FLAG_*. */
58   uint8_t flags;
59   /* data is a byte string included in PATH_CHALLENGE. */
60   uint8_t data[8];
61 } ngtcp2_pv_entry;
62 
63 void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent, const uint8_t *data,
64                           ngtcp2_tstamp expiry, uint8_t flags);
65 
66 /* NGTCP2_PV_FLAG_NONE indicates no flag is set. */
67 #define NGTCP2_PV_FLAG_NONE 0x00
68 /* NGTCP2_PV_FLAG_DONT_CARE indicates that the outcome of path
69    validation should be ignored entirely. */
70 #define NGTCP2_PV_FLAG_DONT_CARE 0x01
71 /* NGTCP2_PV_FLAG_CANCEL_TIMER indicates that the expiry timer is
72    cancelled. */
73 #define NGTCP2_PV_FLAG_CANCEL_TIMER 0x02
74 /* NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE indicates that fallback DCID is
75    available in ngtcp2_pv.  If path validation fails, fallback to the
76    fallback DCID.  If path validation succeeds, fallback DCID is
77    retired if it does not equal to the current DCID. */
78 #define NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE 0x04
79 /* NGTCP2_PV_FLAG_MTU_PROBE indicates that a validation must probe
80    least MTU that QUIC requires, which is 1200 bytes.  If it fails, a
81    path is not viable. */
82 #define NGTCP2_PV_FLAG_MTU_PROBE 0x08
83 /* NGTCP2_PV_FLAG_PREFERRED_ADDR indicates that client is migrating to
84    server's preferred address.  This flag is only used by client. */
85 #define NGTCP2_PV_FLAG_PREFERRED_ADDR 0x10
86 
87 typedef struct ngtcp2_pv ngtcp2_pv;
88 
89 /*
90  * ngtcp2_pv is the context of a single path validation.
91  */
92 struct ngtcp2_pv {
93   const ngtcp2_mem *mem;
94   ngtcp2_log *log;
95   /* dcid is DCID and path this path validation uses. */
96   ngtcp2_dcid dcid;
97   /* fallback_dcid is the usually validated DCID and used as a
98      fallback if this path validation fails. */
99   ngtcp2_dcid fallback_dcid;
100   /* ents is the ring buffer of ngtcp2_pv_entry */
101   ngtcp2_ringbuf ents;
102   /* timeout is the duration within which this path validation should
103      succeed. */
104   ngtcp2_duration timeout;
105   /* fallback_pto is PTO of fallback connection. */
106   ngtcp2_duration fallback_pto;
107   /* started_ts is the timestamp this path validation starts. */
108   ngtcp2_tstamp started_ts;
109   /* round is the number of times that probe_pkt_left is reset. */
110   size_t round;
111   /* probe_pkt_left is the number of probe packets containing
112      PATH_CHALLENGE which can be send without waiting for an
113      expiration of a previous flight. */
114   size_t probe_pkt_left;
115   /* flags is bitwise-OR of zero or more of NGTCP2_PV_FLAG_*. */
116   uint8_t flags;
117 };
118 
119 /*
120  * ngtcp2_pv_new creates new ngtcp2_pv object and assigns its pointer
121  * to |*ppv|.  This function makes a copy of |dcid|.  |timeout| is a
122  * duration within which this path validation must succeed.
123  *
124  * This function returns 0 if it succeeds, or one of the following
125  * negative error codes:
126  *
127  * NGTCP2_ERR_NOMEM
128  *     Out of memory
129  */
130 int ngtcp2_pv_new(ngtcp2_pv **ppv, const ngtcp2_dcid *dcid,
131                   ngtcp2_duration timeout, uint8_t flags, ngtcp2_log *log,
132                   const ngtcp2_mem *mem);
133 
134 /*
135  * ngtcp2_pv_del deallocates |pv|.  This function frees memory |pv|
136  * points too.
137  */
138 void ngtcp2_pv_del(ngtcp2_pv *pv);
139 
140 /*
141  * ngtcp2_pv_add_entry adds new entry with |data|.  |expiry| is the
142  * expiry time of the entry.
143  */
144 void ngtcp2_pv_add_entry(ngtcp2_pv *pv, const uint8_t *data,
145                          ngtcp2_tstamp expiry, uint8_t flags, ngtcp2_tstamp ts);
146 
147 /*
148  * ngtcp2_pv_full returns nonzero if |pv| is full of ngtcp2_pv_entry.
149  */
150 int ngtcp2_pv_full(ngtcp2_pv *pv);
151 
152 /*
153  * ngtcp2_pv_validate validates that the received |data| matches the
154  * one of the existing entry.  The flag of ngtcp2_pv_entry that
155  * matches |data| is assigned to |*pflags| if this function succeeds.
156  *
157  * This function returns 0 if it succeeds, or one of the following
158  * negative error codes:
159  *
160  * NGTCP2_ERR_PATH_VALIDATION_FAILED
161  *     path validation has failed and must be abandoned
162  * NGTCP2_ERR_INVALID_STATE
163  *     |pv| includes no entry
164  * NGTCP2_ERR_INVALID_ARGUMENT
165  *     |pv| does not have an entry which has |data| and |path|
166  */
167 int ngtcp2_pv_validate(ngtcp2_pv *pv, uint8_t *pflags, const uint8_t *data);
168 
169 /*
170  * ngtcp2_pv_handle_entry_expiry checks expiry of existing entries.
171  */
172 void ngtcp2_pv_handle_entry_expiry(ngtcp2_pv *pv, ngtcp2_tstamp ts);
173 
174 /*
175  * ngtcp2_pv_should_send_probe returns nonzero if new entry can be
176  * added by ngtcp2_pv_add_entry.
177  */
178 int ngtcp2_pv_should_send_probe(ngtcp2_pv *pv);
179 
180 /*
181  * ngtcp2_pv_validation_timed_out returns nonzero if the path
182  * validation fails because of timeout.
183  */
184 int ngtcp2_pv_validation_timed_out(ngtcp2_pv *pv, ngtcp2_tstamp ts);
185 
186 /*
187  * ngtcp2_pv_next_expiry returns the earliest expiry.
188  */
189 ngtcp2_tstamp ngtcp2_pv_next_expiry(ngtcp2_pv *pv);
190 
191 /*
192  * ngtcp2_pv_cancel_expired_timer cancels the expired timer.
193  */
194 void ngtcp2_pv_cancel_expired_timer(ngtcp2_pv *pv, ngtcp2_tstamp ts);
195 
196 #endif /* NGTCP2_PV_H */
197