diff options
author | YASUOKA Masahiko <yasuoka@cvs.openbsd.org> | 2020-06-09 02:39:28 +0000 |
---|---|---|
committer | YASUOKA Masahiko <yasuoka@cvs.openbsd.org> | 2020-06-09 02:39:28 +0000 |
commit | c9a6859998aa29f4bdf8f17d1447a91406d67cff (patch) | |
tree | da56fd9e1b387b98bd6b35556ff7a348a4c924b3 /usr.sbin/npppd | |
parent | 5709cb5079267632609944db68f781bf592cde87 (diff) |
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.
Diffstat (limited to 'usr.sbin/npppd')
-rw-r--r-- | usr.sbin/npppd/l2tp/l2tp.h | 9 | ||||
-rw-r--r-- | usr.sbin/npppd/l2tp/l2tp_ctrl.c | 153 |
2 files changed, 104 insertions, 58 deletions
diff --git a/usr.sbin/npppd/l2tp/l2tp.h b/usr.sbin/npppd/l2tp/l2tp.h index cc8a4f283e7..732eded7ae7 100644 --- a/usr.sbin/npppd/l2tp/l2tp.h +++ b/usr.sbin/npppd/l2tp/l2tp.h @@ -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; diff --git a/usr.sbin/npppd/l2tp/l2tp_ctrl.c b/usr.sbin/npppd/l2tp/l2tp_ctrl.c index 710a0431d00..a116537a4ea 100644 --- a/usr.sbin/npppd/l2tp/l2tp_ctrl.c +++ b/usr.sbin/npppd/l2tp/l2tp_ctrl.c @@ -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, |