mirror of
https://github.com/openbsd/src.git
synced 2025-01-03 06:45:37 -08:00
Prepare buffer for both receive and transmit side so that a client can
use them separately. Actually a version of CISCO does and expects the peer does the same. Also fix some typos.
This commit is contained in:
parent
af7e9c1be8
commit
eda8c420d4
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: l2tp.h,v 1.12 2015/12/05 16:10:31 yasuoka Exp $ */
|
||||
/* $OpenBSD: l2tp.h,v 1.13 2020/06/09 02:39:27 yasuoka Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2009 Internet Initiative Japan Inc.
|
||||
@ -30,7 +30,7 @@
|
||||
/*@file
|
||||
* header file for the L2TP module
|
||||
*/
|
||||
/* $Id: l2tp.h,v 1.12 2015/12/05 16:10:31 yasuoka Exp $ */
|
||||
/* $Id: l2tp.h,v 1.13 2020/06/09 02:39:27 yasuoka Exp $ */
|
||||
|
||||
/************************************************************************
|
||||
* Protocol Constants
|
||||
@ -357,6 +357,10 @@ typedef struct _l2tp_ctrl {
|
||||
uint16_t snd_una;
|
||||
/** next send sequence number */
|
||||
uint16_t snd_nxt;
|
||||
/** last send sequence number */
|
||||
uint16_t snd_last;
|
||||
/** last send ack number */
|
||||
uint16_t snd_lastnr;
|
||||
/** receive sequence number */
|
||||
uint16_t rcv_nxt;
|
||||
/** peer's IP address */
|
||||
@ -375,6 +379,7 @@ typedef struct _l2tp_ctrl {
|
||||
*/
|
||||
/** bytes available in send buffer. it is a list of length #winsz */
|
||||
bytebuffer **snd_buffers;
|
||||
int snd_buffercnt;
|
||||
/** sending buffer for ZLB */
|
||||
bytebuffer *zlb_buffer;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: l2tp_ctrl.c,v 1.23 2019/05/10 01:29:31 guenther Exp $ */
|
||||
/* $OpenBSD: l2tp_ctrl.c,v 1.24 2020/06/09 02:39:27 yasuoka Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2009 Internet Initiative Japan Inc.
|
||||
@ -26,7 +26,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
/**@file Control connection processing functions for L2TP LNS */
|
||||
/* $Id: l2tp_ctrl.c,v 1.23 2019/05/10 01:29:31 guenther Exp $ */
|
||||
/* $Id: l2tp_ctrl.c,v 1.24 2020/06/09 02:39:27 yasuoka Exp $ */
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
@ -66,26 +66,28 @@
|
||||
|
||||
#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
static int l2tp_ctrl_init (l2tp_ctrl *, l2tpd *, struct sockaddr *, struct sockaddr *, void *);
|
||||
static void l2tp_ctrl_reload (l2tp_ctrl *);
|
||||
static int l2tp_ctrl_send_disconnect_notify (l2tp_ctrl *);
|
||||
static int l2tp_ctrl_init(l2tp_ctrl *, l2tpd *, struct sockaddr *, struct sockaddr *, void *);
|
||||
static void l2tp_ctrl_reload(l2tp_ctrl *);
|
||||
static int l2tp_ctrl_send_disconnect_notify(l2tp_ctrl *);
|
||||
#if 0
|
||||
static void l2tp_ctrl_purge_ipsec_sa (l2tp_ctrl *);
|
||||
static void l2tp_ctrl_purge_ipsec_sa(l2tp_ctrl *);
|
||||
#endif
|
||||
static void l2tp_ctrl_timeout (int, short, void *);
|
||||
static int l2tp_ctrl_resend_una_packets (l2tp_ctrl *);
|
||||
static void l2tp_ctrl_destroy_all_calls (l2tp_ctrl *);
|
||||
static int l2tp_ctrl_disconnect_all_calls (l2tp_ctrl *, int);
|
||||
static void l2tp_ctrl_reset_timeout (l2tp_ctrl *);
|
||||
static inline int l2tp_ctrl_txwin_size (l2tp_ctrl *);
|
||||
static inline int l2tp_ctrl_txwin_is_full (l2tp_ctrl *);
|
||||
static int l2tp_ctrl_recv_SCCRQ (l2tp_ctrl *, u_char *, int, l2tpd *, struct sockaddr *);
|
||||
static int l2tp_ctrl_send_StopCCN (l2tp_ctrl *, int);
|
||||
static int l2tp_ctrl_recv_StopCCN (l2tp_ctrl *, u_char *, int);
|
||||
static void l2tp_ctrl_send_SCCRP (l2tp_ctrl *);
|
||||
static int l2tp_ctrl_send_HELLO (l2tp_ctrl *);
|
||||
static int l2tp_ctrl_send_ZLB (l2tp_ctrl *);
|
||||
static inline const char *l2tp_ctrl_state_string (l2tp_ctrl *);
|
||||
static void l2tp_ctrl_timeout(int, short, void *);
|
||||
static int l2tp_ctrl_resend_una_packets(l2tp_ctrl *, bool);
|
||||
static void l2tp_ctrl_destroy_all_calls(l2tp_ctrl *);
|
||||
static int l2tp_ctrl_disconnect_all_calls(l2tp_ctrl *, int);
|
||||
static void l2tp_ctrl_reset_timeout(l2tp_ctrl *);
|
||||
static int l2tp_ctrl_txwin_size(l2tp_ctrl *);
|
||||
static bool l2tp_ctrl_txwin_is_full(l2tp_ctrl *);
|
||||
static bool l2tp_ctrl_in_peer_window(l2tp_ctrl *, uint16_t);
|
||||
static bool l2tp_ctrl_in_our_window(l2tp_ctrl *, uint16_t);
|
||||
static int l2tp_ctrl_recv_SCCRQ(l2tp_ctrl *, u_char *, int, l2tpd *, struct sockaddr *);
|
||||
static int l2tp_ctrl_send_StopCCN(l2tp_ctrl *, int);
|
||||
static int l2tp_ctrl_recv_StopCCN(l2tp_ctrl *, u_char *, int);
|
||||
static void l2tp_ctrl_send_SCCRP(l2tp_ctrl *);
|
||||
static int l2tp_ctrl_send_HELLO(l2tp_ctrl *);
|
||||
static int l2tp_ctrl_send_ZLB(l2tp_ctrl *);
|
||||
static const char *l2tp_ctrl_state_string(l2tp_ctrl *);
|
||||
|
||||
#ifdef L2TP_CTRL_DEBUG
|
||||
#define L2TP_CTRL_ASSERT(x) ASSERT(x)
|
||||
@ -158,13 +160,20 @@ l2tp_ctrl_init(l2tp_ctrl *_this, l2tpd *_l2tpd, struct sockaddr *peer,
|
||||
|
||||
/* prepare send buffer */
|
||||
_this->winsz = L2TPD_DEFAULT_SEND_WINSZ;
|
||||
if ((_this->snd_buffers = calloc(_this->winsz, sizeof(bytebuffer *)))
|
||||
== NULL) {
|
||||
/*
|
||||
* _this->winsz is informed as our receive window size. Also
|
||||
* MIN(_this->winsz, _this->peer_winsiz) is used for the size of
|
||||
* transmit side window. We need winsz * 2 sized buffer so that a
|
||||
* stingy client can fill both of window separately.
|
||||
*/
|
||||
_this->snd_buffercnt = _this->winsz * 2;
|
||||
if ((_this->snd_buffers = calloc(_this->snd_buffercnt,
|
||||
sizeof(bytebuffer *))) == NULL) {
|
||||
l2tpd_log(_l2tpd, LOG_ERR,
|
||||
"calloc() failed in %s(): %m", __func__);
|
||||
goto fail;
|
||||
}
|
||||
for (i = 0; i < _this->winsz; i++) {
|
||||
for (i = 0; i < _this->snd_buffercnt; i++) {
|
||||
if ((bytebuf = bytebuffer_create(L2TPD_SND_BUFSIZ)) == NULL) {
|
||||
l2tpd_log(_l2tpd, LOG_ERR,
|
||||
"bytebuffer_create() failed in %s(): %m", __func__);
|
||||
@ -332,7 +341,7 @@ cleanup:
|
||||
|
||||
/* free send buffer */
|
||||
if (_this->snd_buffers != NULL) {
|
||||
for (i = 0; i < _this->winsz; i++)
|
||||
for (i = 0; i < _this->snd_buffercnt; i++)
|
||||
bytebuffer_destroy(_this->snd_buffers[i]);
|
||||
free(_this->snd_buffers);
|
||||
_this->snd_buffers = NULL;
|
||||
@ -565,7 +574,7 @@ l2tp_ctrl_timeout(int fd, short evtype, void *ctx)
|
||||
}
|
||||
/* resend if required */
|
||||
if (need_resend)
|
||||
l2tp_ctrl_resend_una_packets(_this);
|
||||
l2tp_ctrl_resend_una_packets(_this, true);
|
||||
l2tp_ctrl_reset_timeout(_this);
|
||||
}
|
||||
|
||||
@ -599,7 +608,7 @@ l2tp_ctrl_send(l2tp_ctrl *_this, const void *msg, int len)
|
||||
|
||||
/* resend una packets */
|
||||
static int
|
||||
l2tp_ctrl_resend_una_packets(l2tp_ctrl *_this)
|
||||
l2tp_ctrl_resend_una_packets(l2tp_ctrl *_this, bool resend)
|
||||
{
|
||||
uint16_t seq;
|
||||
bytebuffer *bytebuf;
|
||||
@ -608,9 +617,14 @@ l2tp_ctrl_resend_una_packets(l2tp_ctrl *_this)
|
||||
|
||||
nsend = 0;
|
||||
for (seq = _this->snd_una; SEQ_LT(seq, _this->snd_nxt); seq++) {
|
||||
bytebuf = _this->snd_buffers[seq % _this->winsz];
|
||||
if (!l2tp_ctrl_in_peer_window(_this, seq))
|
||||
break;
|
||||
if (SEQ_LT(seq, _this->snd_last) && !resend)
|
||||
continue;
|
||||
bytebuf = _this->snd_buffers[seq % _this->snd_buffercnt];
|
||||
header = bytebuffer_pointer(bytebuf);
|
||||
header->nr = htons(_this->rcv_nxt);
|
||||
_this->snd_lastnr = _this->rcv_nxt;
|
||||
#ifdef L2TP_CTRL_DEBUG
|
||||
if (debuglevel >= 3) {
|
||||
l2tp_ctrl_log(_this, DEBUG_LEVEL_3, "RESEND seq=%u",
|
||||
@ -931,23 +945,24 @@ l2tp_ctrl_input(l2tpd *_this, int listener_index, struct sockaddr *peer,
|
||||
l2tp_ctrl_log(ctrl, LOG_INFO, "RecvZLB");
|
||||
|
||||
if (SEQ_GT(hdr.nr, ctrl->snd_una)) {
|
||||
if (hdr.nr == ctrl->snd_nxt ||
|
||||
SEQ_LT(hdr.nr, ctrl->snd_nxt))
|
||||
ctrl->snd_una = hdr.nr;
|
||||
else {
|
||||
/* a new ack arrived */
|
||||
if (SEQ_GT(hdr.nr, ctrl->snd_nxt)) {
|
||||
/* ack is proceeded us */
|
||||
l2tp_ctrl_log(ctrl, LOG_INFO,
|
||||
"Received message has bad Nr field: "
|
||||
"%u < %u.", hdr.ns, ctrl->snd_nxt);
|
||||
/* XXX Drop with ZLB? */
|
||||
"%u < %u", ctrl->snd_nxt, hdr.nr);
|
||||
goto fail;
|
||||
}
|
||||
ctrl->snd_una = hdr.nr;
|
||||
/* peer window is moved. send out pending packets */
|
||||
l2tp_ctrl_resend_una_packets(ctrl, false);
|
||||
}
|
||||
if (l2tp_ctrl_txwin_size(ctrl) <= 0) {
|
||||
/* no waiting ack */
|
||||
if (ctrl->hello_wait_ack != 0) {
|
||||
/*
|
||||
* Reset Hello state, as an ack for the Hello
|
||||
* is recived.
|
||||
* is received.
|
||||
*/
|
||||
ctrl->hello_wait_ack = 0;
|
||||
ctrl->hello_io_time = curr_time;
|
||||
@ -960,7 +975,7 @@ l2tp_ctrl_input(l2tpd *_this, int listener_index, struct sockaddr *peer,
|
||||
}
|
||||
if (hdr.ns != ctrl->rcv_nxt) {
|
||||
/* there are remaining packet */
|
||||
if (l2tp_ctrl_resend_una_packets(ctrl) <= 0) {
|
||||
if (l2tp_ctrl_resend_una_packets(ctrl, true) <= 0) {
|
||||
/* resend or sent ZLB */
|
||||
l2tp_ctrl_send_ZLB(ctrl);
|
||||
}
|
||||
@ -977,11 +992,12 @@ l2tp_ctrl_input(l2tpd *_this, int listener_index, struct sockaddr *peer,
|
||||
if (pktlen <= 0)
|
||||
return; /* ZLB */
|
||||
|
||||
if (l2tp_ctrl_txwin_is_full(ctrl)) {
|
||||
L2TP_CTRL_DBG((ctrl, LOG_DEBUG,
|
||||
"Received message cannot be handled. "
|
||||
"Transmission window is full."));
|
||||
l2tp_ctrl_send_ZLB(ctrl);
|
||||
if (!l2tp_ctrl_in_our_window(ctrl, hdr.ns)) {
|
||||
l2tp_ctrl_log(ctrl, LOG_WARNING,
|
||||
"received message is outside of window. "
|
||||
"ns=%d window=%u:%u",
|
||||
hdr.ns, ctrl->snd_lastnr,
|
||||
(uint16_t)(ctrl->snd_lastnr + ctrl->winsz - 1));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1051,20 +1067,13 @@ l2tp_ctrl_input(l2tpd *_this, int listener_index, struct sockaddr *peer,
|
||||
break;
|
||||
receive_stop_ccn:
|
||||
case L2TP_AVP_MESSAGE_TYPE_StopCCN:
|
||||
if (l2tp_ctrl_recv_StopCCN(ctrl, pkt, pktlen) == 0) {
|
||||
if (l2tp_ctrl_resend_una_packets(ctrl) <= 0)
|
||||
l2tp_ctrl_send_ZLB(ctrl);
|
||||
l2tp_ctrl_stop(ctrl, 0);
|
||||
return;
|
||||
}
|
||||
l2tp_ctrl_log(ctrl, LOG_ERR, "Received bad StopCCN");
|
||||
l2tp_ctrl_recv_StopCCN(ctrl, pkt, pktlen);
|
||||
l2tp_ctrl_send_ZLB(ctrl);
|
||||
l2tp_ctrl_stop(ctrl, 0);
|
||||
return;
|
||||
|
||||
case L2TP_AVP_MESSAGE_TYPE_HELLO:
|
||||
if (l2tp_ctrl_resend_una_packets(ctrl) <= 0)
|
||||
l2tp_ctrl_send_ZLB(ctrl);
|
||||
l2tp_ctrl_send_ZLB(ctrl);
|
||||
return;
|
||||
case L2TP_AVP_MESSAGE_TYPE_CDN:
|
||||
case L2TP_AVP_MESSAGE_TYPE_ICRP:
|
||||
@ -1116,24 +1125,45 @@ bad_packet:
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int
|
||||
static int
|
||||
l2tp_ctrl_txwin_size(l2tp_ctrl *_this)
|
||||
{
|
||||
uint16_t sz;
|
||||
|
||||
sz = _this->snd_nxt - _this->snd_una;
|
||||
|
||||
L2TP_CTRL_ASSERT(sz <= _this->winsz);
|
||||
L2TP_CTRL_ASSERT(sz <= _this->buffercnt);
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
static inline int
|
||||
static bool
|
||||
l2tp_ctrl_txwin_is_full(l2tp_ctrl *_this)
|
||||
{
|
||||
return (l2tp_ctrl_txwin_size(_this) >= _this->winsz)? 1 : 0;
|
||||
return (l2tp_ctrl_txwin_size(_this) >= _this->snd_buffercnt)? 1 : 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
l2tp_ctrl_in_peer_window(l2tp_ctrl *_this, uint16_t seq)
|
||||
{
|
||||
uint16_t off;
|
||||
int winsz;
|
||||
|
||||
winsz = MINIMUM(_this->winsz, _this->peer_winsz);
|
||||
off = seq - _this->snd_una;
|
||||
|
||||
return ((off < winsz)? true : false);
|
||||
}
|
||||
|
||||
static bool
|
||||
l2tp_ctrl_in_our_window(l2tp_ctrl *_this, uint16_t seq)
|
||||
{
|
||||
uint16_t off;
|
||||
|
||||
off = seq - _this->snd_lastnr;
|
||||
|
||||
return ((off < _this->winsz)? true : false);
|
||||
}
|
||||
/* send control packet */
|
||||
int
|
||||
l2tp_ctrl_send_packet(l2tp_ctrl *_this, int call_id, bytebuffer *bytebuf)
|
||||
@ -1141,6 +1171,7 @@ l2tp_ctrl_send_packet(l2tp_ctrl *_this, int call_id, bytebuffer *bytebuf)
|
||||
struct l2tp_header *hdr;
|
||||
int rval;
|
||||
time_t curr_time;
|
||||
uint16_t seq;
|
||||
|
||||
curr_time = get_monosec();
|
||||
|
||||
@ -1156,13 +1187,17 @@ l2tp_ctrl_send_packet(l2tp_ctrl *_this, int call_id, bytebuffer *bytebuf)
|
||||
hdr->session_id = htons(call_id);
|
||||
|
||||
hdr->s = 1;
|
||||
hdr->ns = htons(_this->snd_nxt);
|
||||
seq = _this->snd_nxt;
|
||||
hdr->ns = htons(seq);
|
||||
hdr->nr = htons(_this->rcv_nxt);
|
||||
|
||||
if (bytebuffer_remaining(bytebuf) > sizeof(struct l2tp_header))
|
||||
/* Not ZLB */
|
||||
_this->snd_nxt++;
|
||||
|
||||
if (!l2tp_ctrl_in_peer_window(_this, seq))
|
||||
return (0);
|
||||
|
||||
L2TP_CTRL_DBG((_this, DEBUG_LEVEL_2,
|
||||
"SEND C ns=%u nr=%u snd_nxt=%u snd_una=%u rcv_nxt=%u ",
|
||||
ntohs(hdr->ns), htons(hdr->nr),
|
||||
@ -1180,7 +1215,9 @@ l2tp_ctrl_send_packet(l2tp_ctrl *_this, int call_id, bytebuffer *bytebuf)
|
||||
L2TP_CTRL_DBG((_this, LOG_DEBUG, "sendto() failed: %m"));
|
||||
}
|
||||
|
||||
_this->snd_lastnr = _this->rcv_nxt;
|
||||
_this->last_snd_ctrl = curr_time;
|
||||
_this->snd_last = seq;
|
||||
|
||||
return (rval == bytebuffer_remaining(bytebuf))? 0 : 1;
|
||||
}
|
||||
@ -1201,6 +1238,7 @@ l2tp_ctrl_recv_SCCRQ(l2tp_ctrl *_this, u_char *pkt, int pktlen, l2tpd *_l2tpd,
|
||||
strlcpy(hostname, "(no hostname)", sizeof(hostname));
|
||||
strlcpy(vendorname, "(no vendorname)", sizeof(vendorname));
|
||||
|
||||
_this->peer_winsz = 4; /* default is 4 in RFC 2661 */
|
||||
firmrev = 0;
|
||||
protover = 0;
|
||||
protorev = 0;
|
||||
@ -1303,6 +1341,9 @@ l2tp_ctrl_recv_SCCRQ(l2tp_ctrl *_this, u_char *pkt, int pktlen, l2tpd *_l2tpd,
|
||||
_this->peer_tunnel_id, protover, protorev, _this->peer_winsz,
|
||||
hostname, vendorname, firmrev);
|
||||
|
||||
if (_this->peer_winsz == 0)
|
||||
_this->peer_winsz = 1;
|
||||
|
||||
return 0;
|
||||
not_acceptable:
|
||||
size_check_failed:
|
||||
@ -1578,7 +1619,7 @@ l2tp_ctrl_send_HELLO(l2tp_ctrl *_this)
|
||||
|
||||
if ((bytebuf = l2tp_ctrl_prepare_snd_buffer(_this, 1)) == NULL) {
|
||||
l2tp_ctrl_log(_this, LOG_ERR,
|
||||
"sending SCCRP failed: no buffer.");
|
||||
"sending HELLO failed: no buffer.");
|
||||
return 1;
|
||||
}
|
||||
avp = (struct l2tp_avp *)buf;
|
||||
@ -1635,7 +1676,7 @@ l2tp_ctrl_prepare_snd_buffer(l2tp_ctrl *_this, int with_seq)
|
||||
l2tp_ctrl_log(_this, LOG_INFO, "sending buffer is full.");
|
||||
return NULL;
|
||||
}
|
||||
bytebuf = _this->snd_buffers[_this->snd_nxt % _this->winsz];
|
||||
bytebuf = _this->snd_buffers[_this->snd_nxt % _this->snd_buffercnt];
|
||||
bytebuffer_clear(bytebuf);
|
||||
if (with_seq)
|
||||
bytebuffer_put(bytebuf, BYTEBUFFER_PUT_DIRECT,
|
||||
|
Loading…
Reference in New Issue
Block a user