1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
|
/* IKEv2 Message ID tracking, for libreswan
*
* Copyright (C) 2019 Andrew Cagney <cagney@gnu.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <https://www.gnu.org/licenses/gpl2.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
*/
#ifndef IKEV2_MSGID_H
#define IKEV2_MSGID_H
#include <stdint.h> /* for intmax_t */
#include "monotime.h"
struct state;
struct ike_sa;
struct msg_digest;
struct v2_transition;
struct v2_transitions;
struct v2_exchange;
enum message_role;
/*
* The type INTMAX_T is chosen so that SEND and RECV are sufficiently
* big to hold both MSGID_T (unmodified) and -1 (the initial value).
* As a bonus intmax_t can easily be printed using %jd.
*
* An additional bonus is that the old v2_INVALID_MSGID ((uint32_t)-1)
* will not match -1 - cross checking code should only compare valid
* MSGIDs.
*/
struct v2_msgid_window {
monotime_t last_sent; /* sent a message */
monotime_t last_recv; /* received a message */
/*
* .sent: last outbound message sent
* .recv: last inbound message processed
* .wip: message being processed; or -1
*
* Initiator:
*
* Idle: .sent:N .recv:N .wip:-1 .state=_IRn?
* Initiating: .sent:N .recv:N .wip:N+1 .state=_IRn?
* Initiated: .sent:N+1 .recv:N .wip:-1 .state=_In+1
*
* Responder:
*
* Idle: .sent:N .recv:N .wip:-1 .state=_Rn?
* Responding: .sent:N .recv:N .wip:N+1 .state=_Rn?
* Responded: .sent:N+1 .recv:N+1 .wip:N+1 .state=_Rn+1
*
* Initiator:
*
* Response: .sent:N+1 .recv:N .wip:N+1 .state=_In+1
* (after packet has been assembled)
* Idle : .sent:N+1 .recv:N+1 .wip:-1 .state=_IRn+1
*
* XXX: should .wip be set _while_ protected and verified
* fragments are being accumulated.
*
* When retransmitting a response, the RFC says to also check
* that the fragments match. Hence .recv_frags which
* out-lives the .incomming_fragments field.
*/
intmax_t sent; /* starts with -1 */
intmax_t recv; /* starts with -1 */
unsigned recv_frags; /* number of fragments in last .recv */
intmax_t wip; /* >=0 when busy */
/*
* Fragments:
*
* Incoming fragments are accumulated and then re-assembled
* into a single message. Once assembled the structure is
* deleted. Note that this all happens before .recv and
* .recv_frags (used to detect the need to retransmit a
* response) are set.
*
* Outgoing fragments are used when retransmitting. A todo is
* to delete them after a few minutes.
*/
struct v2_incoming_fragments *incoming_fragments;
struct v2_outgoing_fragment *outgoing_fragments;
/*
* The exchange being worked on by the initiator.
*/
const struct v2_exchange *exchange;
/*
* The SA being worked on by the exchange.
*
* For instance, the larval Child SA being established by an
* IKE_AUTH; larval IKE or Child SA being established or
* rekeyd by a CREATE_CHILD_SA exchange.
*/
struct child_sa *wip_sa;
/*
* The IKE or Child SA being deleted using a Delete exchange.
* Crossing deletes and larval Child SAs mean that the
* corresponding state may not exist.
*/
so_serial_t dead_sa;
};
struct v2_msgid_windows {
monotime_t last_sent; /* sent a message */
monotime_t last_recv; /* received a message */
struct v2_msgid_window initiator;
struct v2_msgid_window responder;
struct v2_msgid_pending *pending_requests;
};
void v2_msgid_init_ike(struct ike_sa *ike);
void v2_msgid_free(struct state *st);
bool v2_msgid_request_outstanding(struct ike_sa *ike);
bool v2_msgid_request_pending(struct ike_sa *ike);
/*
* Processing has finished - recv's accepted or sent is on its way -
* update window.{recv,sent} and wip.{initiator,responder}.
*
* XXX: Should these interfaces be revamped so that they are more like
* the above?
*
* In complete_v2_state_transition(), update_recv() and update_send
* are first called so that all windows are up-to-date, and then
* schedule_next_initiator() is called to schedule any waiting
* initiators. It could probably be simpler, but probably only after
* record 'n' send has been eliminated.
*/
void v2_msgid_start(struct ike_sa *ike, const struct v2_exchange *,
const struct msg_digest *md, where_t where);
void v2_msgid_cancel(struct ike_sa *ike, const struct msg_digest *md, where_t where);
void v2_msgid_finish(struct ike_sa *ike, const struct msg_digest *md, where_t where);
/*
* This is a hack for code that forces sending an additional request
* even though the request window is full.
*/
void v2_msgid_start_record_n_send(struct ike_sa *ike, const struct v2_exchange *exchange);
/*
* Handle multiple initiators trying to send simultaneously.
*
* XXX: Suspect this code is broken.
*
* For this to work all initiators need to route their requests
* through queue_initiator(), and due to record 'n' send at least,
* this isn't true.
*
* Complicating this is how each individual initiate code path needs
* to be modified so that delays calling queue_initiator() until it is
* ready to actually send (and a message id can be assigned). Would
* it be simpler if there was a gate keeper that assigned request
* message id up front, but only when one was available?
*/
void v2_msgid_queue_exchange(struct ike_sa *ike,
struct child_sa *child/*optional*/,
const struct v2_exchange *exchange);
void v2_msgid_migrate_queue(struct ike_sa *from, struct child_sa *to);
void v2_msgid_schedule_next_initiator(struct ike_sa *ike);
void dbg_v2_msgid(struct ike_sa *ike, const char *msg, ...) PRINTF_LIKE(2);
void llog_pexpect_v2_msgid_where(where_t where, struct ike_sa *ike, const char *fmt, ...) PRINTF_LIKE(3);
#define llog_pexpect_v2_msgid(IKE, FMT, ...) llog_pexpect_v2_msgid_where(HERE, IKE, FMT, ##__VA_ARGS__)
struct v2_msgid_window *v2_msgid_window(struct ike_sa *ike, enum message_role message_role);
#endif
|