summaryrefslogtreecommitdiff
path: root/accel-pppd
diff options
context:
space:
mode:
Diffstat (limited to 'accel-pppd')
-rw-r--r--accel-pppd/ctrl/l2tp/l2tp.c195
1 files changed, 174 insertions, 21 deletions
diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c
index 13eb695..66658d9 100644
--- a/accel-pppd/ctrl/l2tp/l2tp.c
+++ b/accel-pppd/ctrl/l2tp/l2tp.c
@@ -248,6 +248,8 @@ static void __l2tp_session_free(void *data)
__l2tp_session_free(). */
return;
case STATE_WAIT_ICCN:
+ case STATE_WAIT_OCRP:
+ case STATE_WAIT_OCCN:
case STATE_ESTB:
__sync_sub_and_fetch(&stat_starting, 1);
break;
@@ -992,17 +994,16 @@ out_err:
return -1;
}
-/*static int l2tp_send_OCRQ(struct l2tp_conn_t *conn)
+static int l2tp_send_OCRQ(struct l2tp_sess_t *sess)
{
struct l2tp_packet_t *pack;
- pack = l2tp_packet_alloc(2, Message_Type_Outgoing_Call_Request, &conn->lac_addr);
+ pack = l2tp_packet_alloc(2, Message_Type_Outgoing_Call_Request,
+ &sess->paren_conn->lac_addr);
if (!pack)
return -1;
-
- pack->hdr.sid = htons(conn->peer_sid);
- if (l2tp_packet_add_int16(pack, Assigned_Session_ID, conn->sess.sid, 1))
+ if (l2tp_packet_add_int16(pack, Assigned_Session_ID, sess->sid, 1))
goto out_err;
if (l2tp_packet_add_int32(pack, Call_Serial_Number, 0, 1))
goto out_err;
@@ -1017,23 +1018,20 @@ out_err:
if (l2tp_packet_add_string(pack, Called_Number, "", 1))
goto out_err;
- if (l2tp_send(conn, pack, 0))
+ if (l2tp_send(sess->paren_conn, pack, 0))
return -1;
- if (!conn->timeout_timer.tpd)
- triton_timer_add(&conn->ctx, &conn->timeout_timer, 0);
+ if (!sess->timeout_timer.tpd)
+ triton_timer_add(&sess->sctx, &sess->timeout_timer, 0);
else
- triton_timer_mod(&conn->timeout_timer, 0);
-
- conn->state2 = STATE_WAIT_OCRP;
-
+ triton_timer_mod(&sess->timeout_timer, 0);
+
return 0;
out_err:
l2tp_packet_free(pack);
return -1;
-}*/
-
+}
static int l2tp_recv_SCCRQ(struct l2tp_serv_t *serv, struct l2tp_packet_t *pack, struct in_pktinfo *pkt_info)
{
@@ -1243,26 +1241,103 @@ static int l2tp_recv_ICCN(struct l2tp_sess_t *sess, struct l2tp_packet_t *pack)
return 0;
}
-static int l2tp_recv_OCRP(struct l2tp_sess_t *sess, struct l2tp_packet_t *pack)
+static int l2tp_recv_OCRP(struct l2tp_sess_t *sess, struct l2tp_packet_t *pack)
{
- if (sess->state2 != STATE_WAIT_OCRP) {
+ struct l2tp_attr_t *assigned_sid = NULL;
+ struct l2tp_attr_t *unknown_attr = NULL;
+ struct l2tp_attr_t *attr = NULL;
+
+ if (sess->state1 != STATE_WAIT_OCRP) {
log_ppp_warn("l2tp: unexpected OCRP\n");
- return 0;
+ return -1;
}
- sess->state2 = STATE_WAIT_OCCN;
+ list_for_each_entry(attr, &pack->attrs, entry) {
+ switch(attr->attr->id) {
+ case Message_Type:
+ break;
+ case Assigned_Session_ID:
+ assigned_sid = attr;
+ break;
+ default:
+ if (attr->M)
+ unknown_attr = attr;
+ else
+ log_ppp_warn("l2tp: OCRP:"
+ " unknown attribute %i\n",
+ attr->attr->id);
+ break;
+ }
+ }
+
+ if (assigned_sid == NULL) {
+ log_ppp_error("l2tp: OCRP: missing mandatory AVP:"
+ " Assigned Session ID\n");
+ l2tp_session_disconnect(sess, 2, 6);
+ return -1;
+ }
+
+ /* Set peer_sid as soon as possible so that CDN
+ will be sent to the right tunnel in case of error */
+ sess->peer_sid = assigned_sid->val.uint16;
+
+ if (unknown_attr) {
+ log_ppp_error("l2tp: OCRP: unknown mandatory attribute %i\n",
+ unknown_attr->attr->id);
+ l2tp_session_disconnect(sess, 2, 8);
+ return -1;
+ }
+
+ sess->state1 = STATE_WAIT_OCCN;
return 0;
}
static int l2tp_recv_OCCN(struct l2tp_sess_t *sess, struct l2tp_packet_t *pack)
{
- if (sess->state2 != STATE_WAIT_OCCN) {
+ struct l2tp_attr_t *unknown_attr = NULL;
+ struct l2tp_attr_t *attr = NULL;
+
+ if (sess->state1 != STATE_WAIT_OCCN) {
log_ppp_warn("l2tp: unexpected OCCN\n");
return 0;
}
- sess->state2 = STATE_ESTB;
+ triton_timer_del(&sess->timeout_timer);
+
+ list_for_each_entry(attr, &pack->attrs, entry) {
+ switch (attr->attr->id) {
+ case Message_Type:
+ case TX_Speed:
+ case Framing_Type:
+ break;
+ default:
+ if (attr->M)
+ unknown_attr = attr;
+ else
+ log_ppp_warn("l2tp: OCCN:"
+ " unknown attribute %i\n",
+ attr->attr->id);
+ break;
+ }
+ }
+
+ if (unknown_attr) {
+ log_ppp_error("l2tp: OCCN: unknown mandatory attribute %i\n",
+ unknown_attr->attr->id);
+ l2tp_session_disconnect(sess, 2, 8);
+ return -1;
+ }
+
+ sess->state1 = STATE_ESTB;
+
+ if (l2tp_session_connect(sess) < 0) {
+ l2tp_session_disconnect(sess, 2, 4);
+ return -1;
+ }
+
+ if (l2tp_send_ZLB(sess->paren_conn) < 0)
+ return -1;
return 0;
}
@@ -1286,6 +1361,44 @@ static int l2tp_recv_SLI(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack)
return 0;
}
+static void l2tp_session_outcall(void *data)
+{
+ struct l2tp_sess_t *sess = data;
+
+ if (l2tp_send_OCRQ(sess) < 0) {
+ log_ppp_error("l2tp: impossible to place call:"
+ " error while sending OCRQ\n");
+ return;
+ }
+ sess->state1 = STATE_WAIT_OCRP;
+}
+
+static void l2tp_tunnel_create_session(void *data)
+{
+ struct l2tp_conn_t *conn = data;
+ struct l2tp_sess_t *sess = NULL;
+
+ if (conn->state != STATE_ESTB) {
+ log_ppp_error("l2tp: impossible to place call:"
+ " tunnel is not connected\n");
+ return;
+ }
+
+ sess = l2tp_tunnel_alloc_session(conn);
+ if (sess == NULL) {
+ log_ppp_error("l2tp: impossible to place call:"
+ " no more session available\n");
+ return;
+ }
+ if (l2tp_tunnel_confirm_session(sess) < 0) {
+ log_ppp_error("l2tp: impossible to place call:"
+ " session initialisation failed\n");
+ l2tp_tunnel_cancel_session(sess);
+ return;
+ }
+ triton_context_call(&sess->sctx, l2tp_session_outcall, sess);
+}
+
static void l2tp_session_recv(void *data)
{
struct triton_context_t *ctx = triton_context_self();
@@ -1600,6 +1713,43 @@ static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt,
return CLI_CMD_OK;
}
+static int l2tp_create_session_exec(const char *cmd, char * const *fields,
+ int fields_cnt, void *client)
+{
+ struct l2tp_conn_t *conn = NULL;
+ long int tid;
+ int res;
+
+ if (fields_cnt != 5)
+ return CLI_CMD_SYNTAX;
+
+ if (strcmp("tid", fields[3]) != 0)
+ return CLI_CMD_SYNTAX;
+
+ if (u_readlong(&tid, fields[4], 1, L2TP_MAX_TID - 1) < 0)
+ return CLI_CMD_INVAL;
+
+ pthread_mutex_lock(&l2tp_lock);
+ conn = l2tp_conn[tid];
+ if (conn) {
+ triton_context_call(&conn->ctx,
+ l2tp_tunnel_create_session, conn);
+ res = CLI_CMD_OK;
+ } else
+ res = CLI_CMD_INVAL;
+ pthread_mutex_unlock(&l2tp_lock);
+
+ return res;
+}
+
+static void l2tp_create_session_help(char * const *fields, int fields_cnt,
+ void *client)
+{
+ cli_send(client,
+ "l2tp create session tid <tid>"
+ " - place new call in tunnel <tid>\r\n");
+}
+
void __export l2tp_get_stat(unsigned int **starting, unsigned int **active)
{
*starting = &stat_starting;
@@ -1678,7 +1828,10 @@ static void l2tp_init(void)
start_udp_server();
cli_register_simple_cmd2(&show_stat_exec, NULL, 2, "show", "stat");
-
+ cli_register_simple_cmd2(l2tp_create_session_exec,
+ l2tp_create_session_help, 3,
+ "l2tp", "create", "session");
+
triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);
}