return ret;
}
-static int handle_state_transition(struct openconnect_info *vpninfo, int *timeout)
+static int handle_state_transition(struct openconnect_info *vpninfo, int dtls,
+ struct keepalive_info *kai, int *timeout)
{
struct oc_ppp *ppp = vpninfo->ppp;
time_t now = time(NULL);
switch (ppp->ppp_state) {
case PPPS_DEAD:
/* Prevent race conditions after recovering dead peer connection */
- vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = now;
+ kai->last_rx = kai->last_tx = now;
/* Drop any failed outgoing packet from previous connection;
* we need to reconfigure before we can send data packets. */
if (last_state != ppp->ppp_state) {
vpn_progress(vpninfo, PRG_DEBUG,
- _("PPP state transition from %s to %s\n"),
- ppps_names[last_state], ppps_names[ppp->ppp_state]);
+ _("PPP state transition from %s to %s on %s channel\n"),
+ ppps_names[last_state], ppps_names[ppp->ppp_state],
+ dtls ? "DTLS" : "TLS");
print_ppp_state(vpninfo, PRG_TRACE);
return 1;
}
p->ppp.hlen = p->data - ph;
}
-int ppp_mainloop(struct openconnect_info *vpninfo, int *timeout, int readable)
+static int ppp_mainloop(struct openconnect_info *vpninfo, int dtls,
+ struct keepalive_info *kai, int *timeout, int readable)
{
int ret, magic, rsv_hdr_size;
int work_done = 0;
struct oc_ppp *ppp = vpninfo->ppp;
int proto;
- if (vpninfo->ssl_fd == -1)
+ if ((dtls ? vpninfo->dtls_fd : vpninfo->ssl_fd) == -1)
goto do_reconnect;
- handle_state_transition(vpninfo, timeout);
+ handle_state_transition(vpninfo, dtls, kai, timeout);
/* FIXME: The poll() handling here is fairly simplistic. Actually,
if the SSL connection stalls it could return a WANT_WRITE error
/* Load the encap header to end up with the payload where we expect it */
eh = this->data - rsv_hdr_size;
- len = ssl_nonblock_read(vpninfo, 0, eh, receive_mtu + rsv_hdr_size);
+ len = ssl_nonblock_read(vpninfo, dtls, eh, receive_mtu + rsv_hdr_size);
if (!len)
break;
if (len < 0)
* payload_len: number of bytes in PPP *payload*
*/
- vpninfo->ssl_times.last_rx = time(NULL);
+ kai->last_rx = time(NULL);
switch (proto) {
case PPP_LCP:
goto short_pkt;
if ((ret = handle_config_packet(vpninfo, proto, pp, payload_len)) < 0)
return ret;
- else if ((ret = handle_state_transition(vpninfo, timeout)) < 0)
+ else if ((ret = handle_state_transition(vpninfo, dtls, kai, timeout)) < 0)
return ret;
break;
dump_buf_hex(vpninfo, PRG_ERR, '<', pp, payload_len);
} else {
vpn_progress(vpninfo, PRG_TRACE,
- _("Received IPv%d data packet of %d bytes\n"),
- proto == PPP_IP6 ? 6 : 4, payload_len);
+ _("Received IPv%d data packet of %d bytes over %s\n"),
+ proto == PPP_IP6 ? 6 : 4, payload_len,
+ dtls ? "DTLS" : "TLS");
if (pp != this->data) {
vpn_progress(vpninfo, PRG_TRACE,
packet we had before.... */
if ((this = vpninfo->current_ssl_pkt)) {
handle_outgoing:
- vpninfo->ssl_times.last_tx = time(NULL);
- unmonitor_write_fd(vpninfo, ssl);
+ kai->last_tx = time(NULL);
+ if (dtls)
+ unmonitor_write_fd(vpninfo, dtls);
+ else
+ unmonitor_write_fd(vpninfo, ssl);
- ret = ssl_nonblock_write(vpninfo, 0, this->data - this->ppp.hlen, this->len + this->ppp.hlen);
+ ret = ssl_nonblock_write(vpninfo, dtls, this->data - this->ppp.hlen, this->len + this->ppp.hlen);
if (ret < 0)
goto do_reconnect;
else if (!ret) {
fd to ->select_wfds if appropriate, so we can just
return and wait. Unless it's been stalled for so long
that DPD kicks in and we kill the connection. */
- switch (ka_stalled_action(&vpninfo->ssl_times, timeout)) {
+ switch (ka_stalled_action(kai, timeout)) {
case KA_DPD_DEAD:
goto peer_dead;
case KA_REKEY:
vpninfo->current_ssl_pkt = NULL;
}
- switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
+ switch (keepalive_action(kai, timeout)) {
case KA_DPD_DEAD:
peer_dead:
vpn_progress(vpninfo, PRG_ERR,
/* fall through */
case KA_REKEY:
do_reconnect:
- ret = ssl_reconnect(vpninfo);
- if (ret) {
- vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
- vpninfo->quit_reason = "PPP reconnect failed";
- return ret;
+ if (dtls) {
+ /* This leaves it in state DTLS_SLEEPING, and will allow
+ * the protocol to handle any magic required to reopen it. */
+ dtls_close(vpninfo);
+ } else {
+ ret = ssl_reconnect(vpninfo);
+ if (ret) {
+ vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
+ vpninfo->quit_reason = "PPP reconnect failed";
+ return ret;
+ }
}
return 1;
/* No need to send an explicit keepalive
if we have real data to send */
if (vpninfo->tcp_control_queue.head ||
- (vpninfo->dtls_state != DTLS_CONNECTED && ppp->ppp_state == PPPS_NETWORK && vpninfo->outgoing_queue.head))
+ (ppp->ppp_state == PPPS_NETWORK && vpninfo->outgoing_queue.head))
break;
vpn_progress(vpninfo, PRG_DEBUG, _("Send PPP discard request as keepalive\n"));
queue_config_packet(vpninfo, PPP_LCP, ++ppp->lcp.id, DISCREQ, 0, NULL);
if ((this = vpninfo->current_ssl_pkt = dequeue_packet(&vpninfo->tcp_control_queue))) {
/* XX: We pre-stash the PPP protocol field in the header for control packets */
proto = this->ppp.proto;
- handle_state_transition(vpninfo, timeout);
- } else if (vpninfo->dtls_state != DTLS_CONNECTED &&
- ppp->ppp_state == PPPS_NETWORK &&
+ handle_state_transition(vpninfo, dtls, kai, timeout);
+ } else if (ppp->ppp_state == PPPS_NETWORK &&
(this = vpninfo->current_ssl_pkt = dequeue_packet(&vpninfo->outgoing_queue))) {
/* XX: Set protocol for IP packets */
proto = (this->len && (this->data[0] & 0xf0) == 0x60) ? PPP_IP6 : PPP_IP;
if (lcp)
vpn_progress(vpninfo, PRG_TRACE,
- _("Sending PPP %s %s packet (id %d, %d bytes total)\n"),
- proto_names(proto), lcp, id, this->len + this->ppp.hlen);
+ _("Sending PPP %s %s packet over %s (id %d, %d bytes total)\n"),
+ proto_names(proto), lcp,
+ dtls ? "DTLS" : "TLS",
+ id, this->len + this->ppp.hlen);
else
vpn_progress(vpninfo, PRG_TRACE,
- _("Sending PPP %s packet (%d bytes total)\n"),
- proto_names(proto), this->len + this->ppp.hlen);
+ _("Sending PPP %s packet over %s (%d bytes total)\n"),
+ proto_names(proto),
+ dtls ? "DTLS" : "TLS",
+ this->len + this->ppp.hlen);
if (vpninfo->dump_http_traffic)
dump_buf_hex(vpninfo, PRG_TRACE, '>', this->data - this->ppp.hlen, this->len + this->ppp.hlen);
/* Work is not done if we just got rid of packets off the queue */
return work_done;
}
+
+int ppp_tcp_mainloop(struct openconnect_info *vpninfo, int *timeout, int readable)
+{
+ if (vpninfo->dtls_state >= DTLS_SLEEPING)
+ return 0;
+
+ return ppp_mainloop(vpninfo, 0, &vpninfo->ssl_times, timeout, readable);
+}