static ngx_int_t ngx_quic_handle_ack_frame(ngx_connection_t *c,
ngx_quic_header_t *pkt, ngx_quic_ack_frame_t *f);
+static ngx_int_t ngx_quic_handle_ack_frame_range(ngx_connection_t *c,
+ ngx_quic_namespace_t *ns, uint64_t min, uint64_t max);
static ngx_int_t ngx_quic_handle_crypto_frame(ngx_connection_t *c,
ngx_quic_header_t *pkt, ngx_quic_crypto_frame_t *frame);
static ngx_int_t ngx_quic_handle_stream_frame(ngx_connection_t *c,
ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
ngx_quic_ack_frame_t *ack)
{
- ngx_uint_t found, min;
- ngx_queue_t *q, range;
- ngx_quic_frame_t *f;
+ ssize_t n;
+ u_char *pos, *end;
+ uint64_t gap, range;
+ ngx_uint_t i, min, max;
ngx_quic_namespace_t *ns;
ns = &c->quic->ns[ngx_quic_ns(pkt->level)];
"ngx_quic_handle_ack_frame in namespace %d",
ngx_quic_ns(pkt->level));
+ /*
+ * TODO: If any computed packet number is negative, an endpoint MUST
+ * generate a connection error of type FRAME_ENCODING_ERROR.
+ * (19.3.1)
+ */
+
if (ack->first_range > ack->largest) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"invalid first range in ack frame");
}
min = ack->largest - ack->first_range;
+ max = ack->largest;
+
+ if (ngx_quic_handle_ack_frame_range(c, ns, min, max) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ /* 13.2.3. Receiver Tracking of ACK Frames */
+ if (ns->largest < max) {
+ ns->largest = max;
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "updated largest received: %ui", max);
+ }
+
+ pos = ack->ranges_start;
+ end = ack->ranges_end;
+
+ for (i = 0; i < ack->range_count; i++) {
+
+ n = ngx_quic_parse_ack_range(pkt, pos, end, &gap, &range);
+ if (n == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+ pos += n;
+
+ if (gap >= min) {
+ ngx_log_error(NGX_LOG_INFO, c->log, 0,
+ "invalid range %ui in ack frame", i);
+ return NGX_ERROR;
+ }
+
+ max = min - 1 - gap;
+
+ if (range > max + 1) {
+ ngx_log_error(NGX_LOG_INFO, c->log, 0,
+ "invalid range %ui in ack frame", i);
+ return NGX_ERROR;
+ }
+
+ min = max - range + 1;
+
+ if (ngx_quic_handle_ack_frame_range(c, ns, min, max) != NGX_OK) {
+ return NGX_ERROR;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_quic_handle_ack_frame_range(ngx_connection_t *c, ngx_quic_namespace_t *ns,
+ uint64_t min, uint64_t max)
+{
+ ngx_uint_t found;
+ ngx_queue_t *q, range;
+ ngx_quic_frame_t *f;
found = 0;
f = ngx_queue_data(q, ngx_quic_frame_t, queue);
- if (f->pnum >= min && f->pnum <= ack->largest) {
+ if (f->pnum >= min && f->pnum <= max) {
q = ngx_queue_next(q);
ngx_queue_remove(&f->queue);
ngx_quic_free_frame(c, f);
if (!found) {
- if (ack->largest <= ns->pnum) {
+ if (max <= ns->pnum) {
/* duplicate ACK or ACK for non-ack-eliciting frame */
- goto done;
+ return NGX_OK;
}
ngx_log_error(NGX_LOG_INFO, c->log, 0,
return NGX_ERROR;
}
-done:
-
- /* 13.2.3. Receiver Tracking of ACK Frames */
- if (ns->largest < ack->largest) {
- ns->largest = ack->largest;
- ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
- "updated largest received: %ui", ns->largest);
- }
-
return NGX_OK;
}
ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
ngx_quic_frame_t *f)
{
- u_char *p;
- uint8_t flags;
- uint64_t varint;
+ u_char *p;
+ uint8_t flags;
+ uint64_t varint;
+ ngx_uint_t i;
flags = pkt->flags;
p = start;
return NGX_ERROR;
}
- if (f->u.ack.range_count) {
- p = ngx_quic_parse_int(p, end, &f->u.ack.ranges[0]);
+ f->u.ack.ranges_start = p;
+
+ /* process all ranges to get bounds, values are ignored */
+ for (i = 0; i < f->u.ack.range_count; i++) {
+ p = ngx_quic_parse_int_multi(p, end, &varint, &varint, NULL);
if (p == NULL) {
ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
- "failed to parse ack frame first range");
+ "failed to parse ack frame range %ui", i);
return NGX_ERROR;
}
}
- if (f->type == NGX_QUIC_FT_ACK_ECN) {
- ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
- "TODO: parse ECN ack frames");
- /* TODO: add parsing of such frames */
- return NGX_ERROR;
- }
+ f->u.ack.ranges_end = p;
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
"ACK: { largest=%ui delay=%ui count=%ui first=%ui}",
f->u.ack.range_count,
f->u.ack.first_range);
+ if (f->type == NGX_QUIC_FT_ACK_ECN) {
+
+ p = ngx_quic_parse_int_multi(p, end, &f->u.ack.ect0,
+ &f->u.ack.ect1, &f->u.ack.ce, NULL);
+ if (p == NULL) {
+ ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
+ "failed to parse ack frame ECT counts", i);
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
+ "ACK ECN counters: %ui %ui %ui",
+ f->u.ack.ect0, f->u.ack.ect1, f->u.ack.ce);
+ }
+
break;
case NGX_QUIC_FT_PING:
}
+ssize_t
+ngx_quic_parse_ack_range(ngx_quic_header_t *pkt, u_char *start, u_char *end,
+ uint64_t *gap, uint64_t *range)
+{
+ u_char *p;
+
+ p = start;
+
+ p = ngx_quic_parse_int(p, end, gap);
+ if (p == NULL) {
+ ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
+ "failed to parse ack frame gap");
+ return NGX_ERROR;
+ }
+
+ p = ngx_quic_parse_int(p, end, range);
+ if (p == NULL) {
+ ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
+ "failed to parse ack frame range");
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
+ "ACK range: gap %ui range %ui", *gap, *range);
+
+ return p - start;
+}
+
+
ssize_t
ngx_quic_create_frame(u_char *p, ngx_quic_frame_t *f)
{