/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipl2tp_api_session.c,v $ $Revision: 1.5.16.3 $ * $Source: /home/interpeak/CVSRoot/ipl2tp/src/ipl2tp_api_session.c,v $ * $Author: hxu0 $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #include "ipl2tp_h.h" #include "ipl2tp_api.h" #include "ipl2tp_api_session.h" #include "ipl2tp_avp.h" #include "ipl2tp_trpt.h" #include "ipl2tp_util.h" #include "ipl2tp_attr_h.h" #include "ipl2tp_state.h" #include "ipl2tp_message.h" #include "ipl2tp_v2_pw.h" #include "ipl2tp_v3_pw.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipl2tp_api_session_attribute_set *=========================================================================== * Description: Set session parameters * Parameters: key - Session identifier. * attr - Attribute object. * Returns: IPL2TP_STATUS_OK if success. * IPL2TP_STATUS_BADID if invalid session ID. * IPL2TP_STATUS_BADPARAM if bad attribute object. */ IP_PUBLIC Ipl2tp_status ipl2tp_api_session_attribute_set(Ipl2tp_key *key, Ipl2tp_attrobj attr) { Ipl2tp_session *session; Ipl2tp_status status; IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED); if (ipl2tp.state != IPL2TP_STATE_OPEN) { IPCOM_LOG1(ERR, "%s: IPL2TP is not opened", ipl2tp_versions[0]); status = IPL2TP_STATUS_STATE; } else if (key->ident == 0) { switch (key->version) { case IPL2TP_VERSION_L2TPV3: status = ipl2tp_attr_session_set(IP_NULL, &ipl2tp.session.v3.attr, attr); break; case IPL2TP_VERSION_L2TPV2: default: status = ipl2tp_attr_session_set(IP_NULL, &ipl2tp.session.v2.attr, attr); break; } } else if ((session = ipl2tp_state_session_get(key, IP_NULL)) == IP_NULL) { IPCOM_LOG2(ERR, "%s: Called ipl2tp_session_attribute_set() with invalid index: %d", ipl2tp_versions[key->version], (int)key->ident); status = IPL2TP_STATUS_BADID; } else { status = ipl2tp_attr_session_set(session, &session->attr, attr); } IPL2TP_AVAILABLE(); return status; } /* *=========================================================================== * ipl2tp_api_session_attribute_get *=========================================================================== * Description: Get session parameters * Parameters: key - Session identifier. * attr - Attribute object. * replies - Attribute replies. * Returns: IPL2TP_STATUS_OK if success. * IPL2TP_STATUS_BADID if invalid session ID. * IPL2TP_STATUS_BADPARAM if bad attribute object. */ IP_PUBLIC Ipl2tp_status ipl2tp_api_session_attribute_get(Ipl2tp_key *key, Ipl2tp_attrobj attr, Ipl2tp_attrobj *replies) { Ipl2tp_session *session; Ipl2tp_status status; IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED); if (ipl2tp.state != IPL2TP_STATE_OPEN) { IPCOM_LOG1(ERR, "%s: IPL2TP is not opened", ipl2tp_versions[0]); status = IPL2TP_STATUS_STATE; } else if (key->ident == 0) { switch (key->version) { case IPL2TP_VERSION_L2TPV3: status = ipl2tp_attr_session_get(IP_NULL, &ipl2tp.session.v3.attr, attr, replies); break; case IPL2TP_VERSION_L2TPV2: default: status = ipl2tp_attr_session_get(IP_NULL, &ipl2tp.session.v2.attr, attr, replies); break; } } else if ((session = ipl2tp_state_session_get(key, IP_NULL)) == IP_NULL) { IPCOM_LOG2(ERR, "%s: Called ipl2tp_session_attribute_get() with invalid index: %d", ipl2tp_versions[key->version], (int)key->ident); status = IPL2TP_STATUS_BADID; } else { status = ipl2tp_attr_session_get(session, &session->attr, attr, replies); } IPL2TP_AVAILABLE(); return status; } /* *=========================================================================== * ipl2tp_api_session_open *=========================================================================== * Description: Open a new session, either in a new tunnel or in an existing one. * Parameters: sidp - Session ID pointer. * key - Tunnel identifier. * addr - IP address. * tattr - Tunnel attributes. * sattr - Session attributes. * incoming - Is this an incoming or outgoing call? * Returns: IPL2TP_STATUS_OK if Success. * IPL2TP_STATUS_DRAIN if creation disabled. * IPL2TP_STATUS_NOMEM if out of memory. * IPL2TP_STATUS_BADPARAM if bad attribute object. */ IP_PUBLIC Ipl2tp_status ipl2tp_api_session_open(Ipl2tp_key *sidp, Ipl2tp_key *key, union Ip_sockaddr_union *addr, Ipl2tp_attrobj tattr, Ipl2tp_attrobj sattr, Ip_bool incoming) { Ipl2tp_tunnel *tunnel = IP_NULL; Ipl2tp_session *session; Ipl2tp_status status; Ipl2tp_key tkey; IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED); /* Deal with key */ if (key == IP_NULL) { key = &tkey; key->ident = 0; key->version = sidp->version; } if (ipl2tp.state != IPL2TP_STATE_OPEN) { IPCOM_LOG1(ERR, "%s: IPL2TP is not opened", ipl2tp_versions[key->version]); status = IPL2TP_STATUS_STATE; goto leave; } if (ipl2tp.admin_state == IPL2TP_MIB_DISABLED || ipl2tp.drain_tunnels == IPL2TP_MIB_YES) { IPCOM_LOG1(ERR, "%s: Session creation currently disabled", ipl2tp_versions[key->version]); status = IPL2TP_STATUS_DRAIN; goto leave; } sidp->version = key->version; /* Check if old tunnel is available */ if (((tunnel = ipl2tp_state_tunnel_get(key)) != IP_NULL && tunnel->state > IPL2TP_TSTATE_TEARDOWN) || (addr != IP_NULL && (tunnel = ipl2tp_state_tunnel_find_by_addr(addr, sidp->version))) != IP_NULL) { /* Old tunnel available */ if (tunnel->drain_tunnel == IPL2TP_MIB_YES) { IPCOM_LOG3(ERR, "%s(%d,%s): Session creation currently disabled", ipl2tp_versions[key->version], (int)tunnel->local.key.ident, ipl2tp_util_ntoa(addr)); status = IPL2TP_STATUS_DRAIN; goto leave; } else if ((session = ipl2tp_session_new(tunnel, IP_NULL, 0)) == IP_NULL) { IPCOM_LOG3(ERR, "%s(%d,%s): Out of memory when creating session", ipl2tp_versions[key->version], (int)tunnel->local.key.ident, ipl2tp_util_ntoa(addr)); status = IPL2TP_STATUS_NOMEM; goto leave; } /* Enter session properties */ session->local_open = 1; session->outgoing = (Ip_u8)(incoming? 0 : 1); if ((status = ipl2tp_attr_session_set(session, &session->attr, sattr)) != IPL2TP_STATUS_OK) { ipl2tp_session_delete(session); goto leave; } session->state = IPL2TP_SSTATE_WAIT_TUNNEL; /* Start session establishment if tunnel OK */ if (tunnel->state == IPL2TP_TSTATE_ESTABLISHED) { ipl2tp_message_rq(session); } } else { if (addr == IP_NULL) { IPCOM_LOG1(ERR, "%s: No tunnel address supplied", ipl2tp_versions[key->version]); status = IPL2TP_STATUS_ERROR; goto leave; } else if (key->version == IPL2TP_VERSION_L2TPV2 && ipl2tp.enable_v2 == IPL2TP_MIB_DISABLED) { IPCOM_LOG1(ERR, "%s: IPL2TPV2 is not enabled", ipl2tp_versions[0]); status = IPL2TP_STATUS_STATE; goto leave; } else if (key->version == IPL2TP_VERSION_L2TPV3 && ipl2tp.enable_v3 == IPL2TP_MIB_DISABLED) { IPCOM_LOG1(ERR, "%s: IPL2TPV3 is not enabled", ipl2tp_versions[0]); status = IPL2TP_STATUS_STATE; goto leave; } /* No, have to create one */ if ((tunnel = ipl2tp_tunnel_new(key->version, addr)) == IP_NULL) { IPCOM_LOG1(ERR, "%s: Out of memory when creating tunnel", ipl2tp_versions[key->version]); status = IPL2TP_STATUS_NOMEM; goto leave; } /* Enter tunnel properties */ tunnel->local_open = 1; if ((status = ipl2tp_attr_tunnel_set(tunnel, &tunnel->attr, tattr)) != IPL2TP_STATUS_OK) { ipl2tp_tunnel_delete(tunnel); goto leave; } tunnel->state = IPL2TP_TSTATE_WAIT_CTL_REPLY; /* Create session descriptor */ if ((session = ipl2tp_session_new(tunnel, IP_NULL, 0)) == IP_NULL) { IPCOM_LOG3(ERR, "%s(%d,%s): Out of memory when creating session", ipl2tp_versions[key->version], (int)tunnel->local.key.ident, ipl2tp_util_ntoa(addr)); ipl2tp_tunnel_delete(tunnel); status = IPL2TP_STATUS_NOMEM; goto leave; } /* Enter session properties */ session->local_open = 1; session->outgoing = (Ip_u8)(incoming? 0 : 1); if ((status = ipl2tp_attr_session_set(session, &session->attr, sattr)) != IPL2TP_STATUS_OK) { ipl2tp_tunnel_delete(tunnel); ipl2tp_session_delete(session); goto leave; } session->state = IPL2TP_SSTATE_WAIT_TUNNEL; /* Start tunnel establishhment */ ipl2tp_message_sccrq(tunnel); (void)ipl2tp_state_establish_tunnel_timeout_init(tunnel, 1); } if (key->ident == 0) { key->ident = tunnel->local.key.ident; } sidp->ident = session->local.key.ident; leave: IPL2TP_AVAILABLE(); return status; } /* *=========================================================================== * ipl2tp_api_session_close *=========================================================================== * Description: Close an IPL2TP session. This is performed without affecting the * tunnel in which the session resides. * Parameters: session_id - The session to close. * Returns: IPL2TP_STATUS_OK if success. * IPL2TP_STATUS_BADID if invalid session ID. */ IP_PUBLIC Ipl2tp_status ipl2tp_api_session_close(Ipl2tp_key *key) { Ipl2tp_session *session; Ipl2tp_status status = IPL2TP_STATUS_OK; IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED); if (ipl2tp.state != IPL2TP_STATE_OPEN) { IPCOM_LOG1(ERR, "%s: IPL2TP is not opened", ipl2tp_versions[key->version]); status = IPL2TP_STATUS_STATE; } else if ((session = ipl2tp_state_session_get(key, IP_NULL)) == IP_NULL) { IPCOM_LOG2(ERR, "%s: Called ipl2tp_session_close() with invalid session ID: %d", ipl2tp_versions[key->version], (int)key->ident); status = IPL2TP_STATUS_BADID; } else { IPL2TP_TUNNEL_RESULT_SET(session->tunnel, IPL2TP_STATUS_CLOSE, IPL2TP_RES_CDN_ADMINISTRATIVE, 0, "Session closed"); /* Send termination message */ ipl2tp_message_cdn(session); ipl2tp_state_session_teardown(session); } IPL2TP_AVAILABLE(); return status; } /* *=========================================================================== * ipl2tp_api_session_is_closed *=========================================================================== * Description: Determine whether the session with the given ID has been closed. * Parameters: key - Session identifier * Returns: IP_TRUE if session has been closed. * IP_FALSE if otherwise. */ IP_PUBLIC Ip_bool ipl2tp_api_session_is_closed(Ipl2tp_key *key) { if ((ipl2tp_state_session_get(key, IP_NULL)) == IP_NULL) return IP_TRUE; else return IP_FALSE; } /* *=========================================================================== * ipl2tp_api_session_next *=========================================================================== * Description: Retrieves the tunnel identifier * Parameters: tkey - The tunnel identifier * last - Last session we retrieved, or IP_NULL if first * next - [OUT] next tunnel key. * Returns: IPL2TP_STATUS_OK if next has been properly filled in. * */ IP_PUBLIC Ipl2tp_status ipl2tp_api_session_next(Ipl2tp_key *tkey, Ipl2tp_key *last, Ipl2tp_key *next) { Ipl2tp_session *sbest = IP_NULL; Ipl2tp_session *s; Ipl2tp_tunnel *tunnel; Ipl2tp_status status = IPL2TP_STATUS_ERROR; IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED); /* Find the tunnel */ if ((tunnel = ipl2tp_state_tunnel_get(tkey)) == IP_NULL) { status = IPL2TP_STATUS_BADID; goto leave; } /* Find next good session */ for (s = IPCOM_LIST_FIRST(&tunnel->session_list); s != IP_NULL; s = IPCOM_LIST_NEXT(&s->head)) { if ((last == IP_NULL || s->local.key.ident > last->ident) && (sbest == IP_NULL || s->local.key.ident < sbest->local.key.ident)) { /* Save the best candidate so far */ sbest = s; } } /* Found one? */ if (sbest) { next->ident = sbest->local.key.ident; next->version = sbest->local.key.version; status = IPL2TP_STATUS_OK; goto leave; } leave: IPL2TP_AVAILABLE(); return status; } /* *=========================================================================== * ipl2tp_api_session_attribute_query *=========================================================================== * Description: Get a singular session parameter * Parameters: key - The session key. * query - The query * replies - Where the replies are to be stored. * Returns: * */ IP_PUBLIC void ipl2tp_api_session_attribute_query(Ipl2tp_key *key, int query, Ipl2tp_attrobj *replies) { Ipl2tp_attrobj attr = IP_NULL; /* Retrieve the type */ ipl2tp_attr_add_query(&attr, query); (void)ipl2tp_api_session_attribute_get(key, attr, replies); ipl2tp_attr_delete(&attr); } /* *=========================================================================== * ipl2tp_api_session_type *=========================================================================== * Description: Human readable description of type of session * Parameters: key - The session key * Returns: The human readable description. * */ IP_PUBLIC const char * ipl2tp_api_session_type(Ipl2tp_key *key) { Ipl2tp_attr a; Ipl2tp_attrobj replies = IP_NULL; const char *type = ""; /* */ ipl2tp_api_session_attribute_query(key, IPL2TP_SATTR_RO_l2tpSessionStatsCallType, &replies); if((a = ipl2tp_attr_first(replies)) == IP_NULL) { ipl2tp_attr_delete(&replies); return type; } /* Get the first */ switch (ipl2tp_attr_idata(a)) { case IPL2TP_MIB_LAC_INCOMING: type = "locally requested(LAC) incoming"; break; case IPL2TP_MIB_LNS_INCOMING: type = "remotely requested(LAC) incoming"; break; case IPL2TP_MIB_LAC_OUTGOING: type = "remotely requested(LNS) outgoing"; break; case IPL2TP_MIB_LNS_OUTGOING: type = "locally requested(LNS) outgoing"; break; } /* Delete the variables */ ipl2tp_attr_delete(&replies); return type; } /* *=========================================================================== * ipl2tp_api_session_ppp_input *=========================================================================== * Description: Feed an incoming PPP packet to the IPL2TP engine. * Parameters: session_id The session which the packet belongs to. * buffer - PPP packet. * length - Length of PPP packet. * offset - Number of bytes before 'buffer' that may be used. * align - Alignment requirement for output buffer. * is_ip - Is this an IP packet? * Returns: IPL2TP_STATUS_OK if success. * IPL2TP_STATUS_BADID if invalid session ID. */ IP_PUBLIC Ipl2tp_status ipl2tp_api_session_ppp_input(Ipl2tp_key *key, void *buffer, int length, int offset, int align, Ip_bool is_ip) { Ipl2tp_status status; Ipl2tp_session *session; IPL2TP_UNUSED(is_ip); IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED); if (ipl2tp.state != IPL2TP_STATE_OPEN) { IPCOM_LOG1(ERR, "%s: IPL2TP is not opened", ipl2tp_versions[key->version]); status = IPL2TP_STATUS_STATE; goto leave; } /* Get session descriptor */ if ((session = ipl2tp_state_session_get(key, IP_NULL)) == IP_NULL || session->state != IPL2TP_SSTATE_ESTABLISHED) { IPCOM_LOG2(ERR, "%s: Called ipl2tp_ppp_input() with invalid session ID: %d", ipl2tp_versions[key->version], (int)key->ident); status = IPL2TP_STATUS_BADID; goto leave; } IPCOM_LOG4(DEBUG, "%s(%d,%d,%s): Receiving PPP packet", ipl2tp_versions[key->version], (int)session->tunnel->local.key.ident, (int)key->ident, ipl2tp_util_ntoa(&session->tunnel->remote.addr)); /* */ if (session->attr.pw_type != IPL2TP_ATTR_PW_TYPE_PPP) { IPCOM_LOG4(DEBUG, "%s(%d,%d,%s): Session does not have the PPP pseudowire type", ipl2tp_versions[key->version], (int)session->tunnel->local.key.ident, (int)key->ident, ipl2tp_util_ntoa(&session->tunnel->remote.addr)); status = IPL2TP_STATUS_BADPW; goto leave; } /* */ if (session->local.key.version == IPL2TP_VERSION_L2TPV2) status = ipl2tp_v2_pw_ppp_input(session,buffer,length,offset,align); else { IPCOM_LOG4(DEBUG, "%s(%d,%d,%s): Version does not support the PPP pseudowire type", ipl2tp_versions[key->version], (int)session->tunnel->local.key.ident, (int)key->ident, ipl2tp_util_ntoa(&session->tunnel->remote.addr)); status = IPL2TP_STATUS_BADPW; } leave: IPL2TP_AVAILABLE(); return status; } /* *=========================================================================== * ipl2tp_api_ethernet_input *=========================================================================== * Description: Feed an incoming Ethernet packet to the IPL2TP engine. * Parameters: key - The session which the packet belongs to. * buffer - The ethernet frame * length - Length of ethernet frame. * offset - Number of bytes before 'buffer' that may be used. * align - Alignment requirement for output buffer. * is_ip - Is this an IP packet? * Returns: IPL2TP_STATUS_OK if success. * IPL2TP_STATUS_BADID if invalid session ID. */ IP_PUBLIC Ipl2tp_status ipl2tp_api_session_ethernet_input(Ipl2tp_key *key, void *buffer, int length, int offset, int align, Ip_bool is_ip) { Ipl2tp_status status; Ipl2tp_session *session; IPL2TP_UNUSED(is_ip); IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED); if (ipl2tp.state != IPL2TP_STATE_OPEN) { IPCOM_LOG1(ERR, "%s: IPL2TP is not opened", ipl2tp_versions[key->version]); status = IPL2TP_STATUS_STATE; goto leave; } /* Get session descriptor */ if ((session = ipl2tp_state_session_get(key, IP_NULL)) == IP_NULL || session->state != IPL2TP_SSTATE_ESTABLISHED) { IPCOM_LOG2(ERR, "%s: Called ipl2tp_api_session_ethernet_input() with invalid session ID: %d", ipl2tp_versions[key->version], (int)key->ident); status = IPL2TP_STATUS_BADID; goto leave; } IPCOM_LOG4(DEBUG, "%s(%d,%d,%s): Receiving Ethernet frame", ipl2tp_versions[key->version], (int)session->tunnel->local.key.ident, (int)key->ident, ipl2tp_util_ntoa(&session->tunnel->remote.addr)); /* */ if (session->attr.pw_type != IPL2TP_ATTR_PW_TYPE_ETHERNET && session->attr.pw_type != IPL2TP_ATTR_PW_TYPE_ETHERNET_VLAN) { IPCOM_LOG4(DEBUG, "%s(%d,%d,%s): Session does not have the Ethernet or VLAN pseudowire type", ipl2tp_versions[key->version], (int)session->tunnel->local.key.ident, (int)key->ident, ipl2tp_util_ntoa(&session->tunnel->remote.addr)); status = IPL2TP_STATUS_BADPW; goto leave; } /* */ if (session->local.key.version == IPL2TP_VERSION_L2TPV3) { if (session->attr.circuit_status != IPL2TP_MIB_UP || session->v.v3.circuit_status != IPL2TP_MIB_UP) { IPCOM_LOG4(INFO, "%s(%d,%d,%s): Session circuit is not currently up, frame discarded", ipl2tp_versions[key->version], (int)session->tunnel->local.key.ident, (int)key->ident, ipl2tp_util_ntoa(&session->tunnel->remote.addr)); status = IPL2TP_STATUS_CIRCUIT_DOWN; goto leave; } status = ipl2tp_v3_pw_ethernet_input(session,buffer,length,offset,align,is_ip); } else { IPCOM_LOG4(DEBUG, "%s(%d,%d,%s): Version does not support the Ethernet or VLAN pseudowire type", ipl2tp_versions[key->version], (int)session->tunnel->local.key.ident, (int)key->ident, ipl2tp_util_ntoa(&session->tunnel->remote.addr)); status = IPL2TP_STATUS_BADPW; } leave: IPL2TP_AVAILABLE(); return status; } /* *=========================================================================== * ipl2tp_api_session_outgoing_established *=========================================================================== * Description: Inform IPL2TP about the establishment status of an outgoing * session. * Parameters: session_id - Session ID. * version - Version. * result_code - Result code as defined in RFC2661. * error_code - Error code as defined in RFC2661. * error_message - Error message for vendor-specific errors (code 6). * Returns: IPL2TP_STATUS_STATE if IPL2TP is not open. * IPL2TP_STATUS_BADID if bad session ID. */ IP_PUBLIC Ipl2tp_status ipl2tp_api_session_outgoing_established(Ipl2tp_key *key, Ip_u16 result_code, Ip_u16 error_code, CONST char *error_message) { Ipl2tp_session *session; Ipl2tp_status status = IPL2TP_STATUS_OK; IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED); if (ipl2tp.state != IPL2TP_STATE_OPEN) { IPCOM_LOG1(ERR, "%s: IPL2TP is not opened", ipl2tp_versions[0]); status = IPL2TP_STATUS_STATE; } else if ((session = ipl2tp_state_session_get(key, IP_NULL)) == IP_NULL) { IPCOM_LOG2(ERR, "%s: Called ipl2tp_api_session_outgoing_established() with invalid session ID: %d", ipl2tp_versions[key->version], (int)key->ident); status = IPL2TP_STATUS_BADID; } else do { Ipl2tp_tunnel *tunnel = session->tunnel; /* Increment session count here since a teardown will decrement */ tunnel->statistics.active_sessions++; if (session->state != IPL2TP_SSTATE_WAIT_CS_ANSWER) { IPL2TP_TUNNEL_RESULT_SET(tunnel, IPL2TP_STATUS_STATE, IPL2TP_RES_CDN_GENERAL_ERROR, IPL2TP_ERR_VENDOR_ERROR_LAC, "Session established attempted for session in non SSTATE_WAIT_CS_ANSWER state"); IPCOM_LOG4(WARNING, "%s(%d,%s): Called ipl2tp_api_session_outgoing_established() for session in %s state", ipl2tp_versions[key->version], (int)tunnel->local.key.ident, ipl2tp_util_ntoa(&tunnel->remote.addr), ipl2tp_state_sstate_name(session->state)); status = IPL2TP_STATUS_TEARDOWN; } else if (result_code != 0) { /* Failed attempt, set result codes */ IPL2TP_TUNNEL_RESULT_SET(tunnel, IPL2TP_STATUS_CLOSE, result_code, error_code, error_message); } else { int cb; /* Ready to fly */ ipl2tp_message_occn(session); ipl2tp_state_establish_session_timeout_init(session, 0); session->state = IPL2TP_SSTATE_ESTABLISHED; tunnel->statistics.total_sessions++; IPL2TP_TUNNEL_RESULT_SET(tunnel, IPL2TP_STATUS_OK, IPL2TP_OUTGOING_ESTABLISHED, 0, "Outgoing session established"); IPL2TP_AVAILABLE(); cb = IPL2TP_SAFE_ICALLBACK(session->attr.scallback, (session->attr.user_data, &session->local.key, &tunnel->last_result)); IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED); if (cb != 0) { IPL2TP_TUNNEL_RESULT_SET(tunnel, IPL2TP_STATUS_STATE, IPL2TP_RES_CDN_GENERAL_ERROR, IPL2TP_ERR_VENDOR_ERROR_LAC, "Session creation aborted"); IPCOM_LOG4(WARNING, "%s(%d,%d,%s): Session creation aborted", ipl2tp_versions[key->version], (int)tunnel->local.key.ident, (int)session->local.key.ident, ipl2tp_util_ntoa(&tunnel->remote.addr)); } else { IPCOM_LOG5(INFO, "%s(%d,%d,%s): Outgoing session established, remote id is %d", ipl2tp_versions[key->version], (int)tunnel->local.key.ident, (int)session->local.key.ident, ipl2tp_util_ntoa(&tunnel->remote.addr), (int)session->remote.key.ident); break; } } ipl2tp_message_cdn(session); ipl2tp_state_session_teardown(session); } while (0); IPL2TP_AVAILABLE(); return status; } /* *=========================================================================== * ipl2tp_api_session_incoming_established *=========================================================================== * Description: Inform IPL2TP about the establishment status of an incoming * session. * Parameters: session_id - Session ID. * version - Version. * result_code - Result code as defined in RFC2661. * error_code - Error code as defined in RFC2661. * error_message - Error message for vendor-specific errors (code 6). * Returns: IPL2TP_STATUS_STATE if IPL2TP is not open. * IPL2TP_STATUS_BADID if bad session ID. */ IP_PUBLIC Ipl2tp_status ipl2tp_api_session_incoming_established(Ipl2tp_key *key, Ip_u16 result_code, Ip_u16 error_code, CONST char *error_message) { Ipl2tp_session *session; Ipl2tp_status status = IPL2TP_STATUS_OK; IPL2TP_OCCUPIED(return IPL2TP_STATUS_OCCUPIED); if (ipl2tp.state != IPL2TP_STATE_OPEN) { IPCOM_LOG1(ERR, "%s: IPL2TP is not opened", ipl2tp_versions[0]); status = IPL2TP_STATUS_STATE; } else if ((session = ipl2tp_state_session_get(key, IP_NULL)) == IP_NULL) { IPCOM_LOG2(ERR, "%s: Called ipl2tp_api_session_incoming_established() with invalid session ID: %d", ipl2tp_versions[key->version], (int)key->ident); status = IPL2TP_STATUS_BADID; } else do { Ipl2tp_tunnel *tunnel = session->tunnel; if (session->state != IPL2TP_SSTATE_WAIT_CS_ANSWER) { IPL2TP_TUNNEL_RESULT_SET(tunnel, IPL2TP_STATUS_STATE, IPL2TP_RES_CDN_GENERAL_ERROR, IPL2TP_ERR_VENDOR_ERROR_LAC, "Session established attempted for session in non SSTATE_WAIT_CS_ANSWER state"); IPCOM_LOG4(WARNING, "%s(%d,%s): Called ipl2tp_api_session_incoming_established() for session in %s state", ipl2tp_versions[key->version], (int)tunnel->local.key.ident, ipl2tp_util_ntoa(&tunnel->remote.addr), ipl2tp_state_sstate_name(session->state)); status = IPL2TP_STATUS_TEARDOWN; } else if (result_code != 0) { /* Failed attempt, set result codes */ IPL2TP_TUNNEL_RESULT_SET(tunnel, IPL2TP_STATUS_CLOSE, result_code, error_code, error_message); } else { /* Ready to fly */ session->state = IPL2TP_SSTATE_WAIT_CONNECT; ipl2tp_state_establish_session_timeout_init(session, 1); ipl2tp_message_icrp(session); break; } ipl2tp_message_cdn(session); ipl2tp_state_session_teardown(session); } while (0); IPL2TP_AVAILABLE(); return status; } /* **************************************************************************** * END OF FILE **************************************************************************** */