summaryrefslogtreecommitdiff
path: root/accel-pppd/ctrl/l2tp/l2tp.c
diff options
context:
space:
mode:
authorVladislav Grishenko <themiron@mail.ru>2013-09-27 13:56:10 +0600
committerDmitry Kozlov <xeb@mail.ru>2013-10-02 22:57:42 +0400
commit21d36db2bad56b6389873b1c10e45f36938ed5fc (patch)
treeb52235fd260af72ea429a6309b6b7c0dda315bce /accel-pppd/ctrl/l2tp/l2tp.c
parente461c5423384f21efdd1cfc8d57e2fd39f0d156e (diff)
downloadaccel-ppp-21d36db2bad56b6389873b1c10e45f36938ed5fc.tar.gz
accel-ppp-21d36db2bad56b6389873b1c10e45f36938ed5fc.zip
l2tp: introduce data packet sequencing and reorder timeout support
Signed-off-by: Vladislav Grishenko <themiron@mail.ru>
Diffstat (limited to 'accel-pppd/ctrl/l2tp/l2tp.c')
-rw-r--r--accel-pppd/ctrl/l2tp/l2tp.c113
1 files changed, 113 insertions, 0 deletions
diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c
index b4b20b72..e6fae4de 100644
--- a/accel-pppd/ctrl/l2tp/l2tp.c
+++ b/accel-pppd/ctrl/l2tp/l2tp.c
@@ -65,6 +65,8 @@ static const char *conf_host_name = "accel-ppp";
static const char *conf_secret = NULL;
static size_t conf_secret_len = 0;
static int conf_mppe = MPPE_UNSET;
+static int conf_dataseq = L2TP_DATASEQ_ALLOW;
+static int conf_reorder_timeout = 0;
static unsigned int stat_active;
static unsigned int stat_starting;
@@ -85,6 +87,9 @@ struct l2tp_sess_t
int state1;
uint16_t lns_mode:1;
uint16_t hide_avps:1;
+ uint16_t send_seq:1;
+ uint16_t recv_seq:1;
+ int reorder_timeout;
struct triton_context_t sctx;
struct triton_timer_t timeout_timer;
@@ -870,6 +875,10 @@ static struct l2tp_sess_t *l2tp_tunnel_alloc_session(struct l2tp_conn_t *conn)
sess->state1 = STATE_CLOSE;
sess->lns_mode = conn->lns_mode;
sess->hide_avps = conn->hide_avps;
+ sess->send_seq = (conf_dataseq == L2TP_DATASEQ_PREFER) ||
+ (conf_dataseq == L2TP_DATASEQ_REQUIRE);
+ sess->recv_seq = (conf_dataseq == L2TP_DATASEQ_REQUIRE);
+ sess->reorder_timeout = conf_reorder_timeout;
sess->sctx.before_switch = log_switch;
sess->sctx.close = l2tp_sess_close;
@@ -1209,6 +1218,32 @@ static int l2tp_session_connect(struct l2tp_sess_t *sess)
goto out_err;
}
+ flg = 1;
+ if (sess->send_seq &&
+ setsockopt(sess->ppp.fd, SOL_PPPOL2TP, PPPOL2TP_SO_SENDSEQ,
+ &flg, sizeof(flg))) {
+ log_session(log_error, sess, "impossible to connect session:"
+ " setsockopt(PPPOL2TP_SO_SENDSEQ) failed: %s\n",
+ strerror(errno));
+ goto out_err;
+ }
+ if (sess->recv_seq &&
+ setsockopt(sess->ppp.fd, SOL_PPPOL2TP, PPPOL2TP_SO_RECVSEQ,
+ &flg, sizeof(flg))) {
+ log_session(log_error, sess, "impossible to connect session:"
+ " setsockopt(PPPOL2TP_SO_RECVSEQ) failed: %s\n",
+ strerror(errno));
+ goto out_err;
+ }
+ if (sess->reorder_timeout &&
+ setsockopt(sess->ppp.fd, SOL_PPPOL2TP, PPPOL2TP_SO_REORDERTO,
+ &sess->reorder_timeout, sizeof(sess->reorder_timeout))) {
+ log_session(log_error, sess, "impossible to connect session:"
+ " setsockopt(PPPOL2TP_REORDERTO) failed: %s\n",
+ strerror(errno));
+ goto out_err;
+ }
+
u_inet_ntoa(conn->peer_addr.sin_addr.s_addr, addr);
peer_port = ntohs(conn->peer_addr.sin_port);
if (_asprintf(&sess->ppp.ses.chan_name, "%s:%i session %i",
@@ -1799,6 +1834,12 @@ static int l2tp_send_ICCN(struct l2tp_sess_t *sess)
" adding data to packet failed\n");
goto out_err;
}
+ if (sess->send_seq &&
+ l2tp_packet_add_octets(pack, Sequencing_Required, NULL, 0, 1) < 0) {
+ log_session(log_error, sess, "impossible to send ICCN:"
+ " adding data to packet failed\n");
+ goto out_err;
+ }
if (l2tp_session_send(sess, pack) < 0) {
log_session(log_error, sess, "impossible to send ICCN:"
@@ -1938,6 +1979,12 @@ static int l2tp_send_OCCN(struct l2tp_sess_t *sess)
" adding data to packet failed\n");
goto out_err;
}
+ if (sess->send_seq &&
+ l2tp_packet_add_octets(pack, Sequencing_Required, NULL, 0, 1) < 0) {
+ log_session(log_error, sess, "impossible to send OCCN:"
+ " adding data to packet failed\n");
+ goto out_err;
+ }
if (l2tp_session_send(sess, pack) < 0) {
log_session(log_error, sess, "impossible to send OCCN:"
@@ -2638,6 +2685,9 @@ static int l2tp_recv_ICRP(struct l2tp_sess_t *sess,
static int l2tp_recv_ICCN(struct l2tp_sess_t *sess,
const struct l2tp_packet_t *pack)
{
+ const struct l2tp_attr_t *unknown_attr = NULL;
+ const struct l2tp_attr_t *attr = NULL;
+
if (sess->state1 != STATE_WAIT_ICCN) {
log_session(log_warn, sess, "discarding unexpected ICCN\n");
return 0;
@@ -2645,6 +2695,49 @@ static int l2tp_recv_ICCN(struct l2tp_sess_t *sess,
log_session(log_info2, sess, "handling ICCN\n");
+ list_for_each_entry(attr, &pack->attrs, entry) {
+ switch (attr->attr->id) {
+ case Message_Type:
+ case Random_Vector:
+ case TX_Speed:
+ case Framing_Type:
+ case Init_Recv_LCP:
+ case Last_Sent_LCP:
+ case Last_Recv_LCP:
+ case Proxy_Authen_Type:
+ case Proxy_Authen_Name:
+ case Proxy_Authen_Challenge:
+ case Proxy_Authen_ID:
+ case Proxy_Authen_Response:
+ case Private_Group_ID:
+ case RX_Speed:
+ break;
+ case Sequencing_Required:
+ if (conf_dataseq != L2TP_DATASEQ_DENY)
+ sess->send_seq = 1;
+ break;
+ default:
+ if (attr->M)
+ unknown_attr = attr;
+ else
+ log_session(log_warn, sess,
+ "discarding unknown attribute type"
+ " %i in ICCN\n", attr->attr->id);
+ break;
+ }
+ }
+
+ if (unknown_attr) {
+ log_session(log_error, sess, "impossible to handle ICCN:"
+ " unknown mandatory attribute type %i,"
+ " disconnecting session\n",
+ unknown_attr->attr->id);
+ if (l2tp_session_disconnect(sess, 2, 8) < 0)
+ log_session(log_error, sess,
+ "session disconnection failed\n");
+ return -1;
+ }
+
sess->state1 = STATE_ESTB;
if (l2tp_session_connect(sess)) {
@@ -2906,6 +2999,10 @@ static int l2tp_recv_OCCN(struct l2tp_sess_t *sess,
case TX_Speed:
case Framing_Type:
break;
+ case Sequencing_Required:
+ if (conf_dataseq != L2TP_DATASEQ_DENY)
+ sess->send_seq = 1;
+ break;
default:
if (attr->M)
unknown_attr = attr;
@@ -3796,6 +3893,22 @@ static void load_config(void)
if (opt && atoi(opt) >= 0)
conf_hide_avps = atoi(opt) > 0;
+ opt = conf_get_opt("l2tp", "dataseq");
+ if (opt) {
+ if (strcmp(opt, "deny") == 0)
+ conf_dataseq = L2TP_DATASEQ_DENY;
+ else if (strcmp(opt, "allow") == 0)
+ conf_dataseq = L2TP_DATASEQ_ALLOW;
+ else if (strcmp(opt, "prefer") == 0)
+ conf_dataseq = L2TP_DATASEQ_PREFER;
+ else if (strcmp(opt, "require") == 0)
+ conf_dataseq = L2TP_DATASEQ_REQUIRE;
+ }
+
+ opt = conf_get_opt("l2tp", "reorder-timeout");
+ if (opt && atoi(opt) >= 0)
+ conf_reorder_timeout = atoi(opt);
+
opt = conf_get_opt("l2tp", "avp_permissive");
if (opt && atoi(opt) >= 0)
conf_avp_permissive = atoi(opt) > 0;