3316 lines
110 KiB
C
3316 lines
110 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipl2tp_avp.c,v $ $Revision: 1.14.12.2 $
|
|
* $Source: /home/interpeak/CVSRoot/ipl2tp/src/ipl2tp_avp.c,v $
|
|
* $Author: jren $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
#include "ipl2tp_h.h"
|
|
#include "ipl2tp_avp.h"
|
|
#include "ipl2tp_attr.h"
|
|
#include "ipl2tp_trpt.h"
|
|
#include "ipl2tp_message.h"
|
|
#include "ipl2tp_pseudowire.h"
|
|
|
|
#ifdef IPMCRYPTO
|
|
#include <ip/openssl/md5.h>
|
|
#include <ip/openssl/sha.h>
|
|
#else
|
|
#include <openssl/md5.h>
|
|
#include <openssl/sha.h>
|
|
#endif
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
#define IPL2TP_AVP_PARSE_ERROUT(s,c,m) \
|
|
do { \
|
|
errout_status = (s); \
|
|
errout_code = (c); \
|
|
errout_message = (m); \
|
|
goto errout; \
|
|
} while (0)
|
|
|
|
|
|
#define IPL2TP_AVP_PARSE_MALFORMED() \
|
|
IPL2TP_AVP_PARSE_ERROUT(IPL2TP_STATUS_MALFORMED, \
|
|
IPL2TP_ERR_WRONG_LENGTH, \
|
|
"malformed")
|
|
|
|
#define IPL2TP_AVP_PARSE_CHECK_MALFORMED(x) \
|
|
do { if (x) IPL2TP_AVP_PARSE_MALFORMED(); } while (0)
|
|
|
|
|
|
#define IPL2TP_AVP_PARSE_CHECK_NOMEM(x) \
|
|
do { \
|
|
if ((x) == IP_NULL) \
|
|
IPL2TP_AVP_PARSE_ERROUT(IPL2TP_STATUS_NOMEM, \
|
|
IPL2TP_ERR_VENDOR_ERROR_LAC, \
|
|
"out of memory in"); \
|
|
} while (0)
|
|
|
|
|
|
#define IPL2TP_AVP_HANDSHAKE(hs,optional) \
|
|
(Ip_u16) ((optional) | ((hs)? IPL2TP_AVP_FLAG_NONE : IPL2TP_AVP_FLAG_MANDATORY))
|
|
|
|
|
|
#define HMAC_IPAD 0x36
|
|
#define HMAC_OPAD 0x5C
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
static Ip_u8 ipl2tp_avp_hmac_opad[64]; /* 64 '0x5C' */
|
|
static Ip_u8 ipl2tp_avp_hmac_ipad[64]; /* 64 '0x36' */
|
|
|
|
static Ipcom_once_t ipl2tp_avp_hmac_once = IPCOM_ONCE_INIT;
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_hmac_md5_setup
|
|
*===========================================================================
|
|
* Description: Initialize the MD5 HMAC I/O-pads.
|
|
* Parameters: unused - Not used.
|
|
* Returns: IPCOM_SUCCESS
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipl2tp_avp_hmac_setup(void *unused)
|
|
{
|
|
IPL2TP_UNUSED(unused);
|
|
|
|
/* Initialize the MD5 O/I-PAD speedups */
|
|
ipcom_memset(ipl2tp_avp_hmac_opad, HMAC_OPAD, sizeof(ipl2tp_avp_hmac_opad));
|
|
ipcom_memset(ipl2tp_avp_hmac_ipad, HMAC_IPAD, sizeof(ipl2tp_avp_hmac_ipad));
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_hmac_msg_digest_shared_key
|
|
*===========================================================================
|
|
* Description: Create the shared key for the message digest AVP
|
|
* Parameters: tunnel - The tunnel
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipl2tp_avp_hmac_msg_digest_shared_key(Ipl2tp_tunnel *tunnel)
|
|
{
|
|
Ip_u8 value = 2;
|
|
Ip_u8 digest[MD5_DIGEST_LENGTH];
|
|
|
|
/* Copy the shared secret to the key */
|
|
ipl2tp_util_vector_dup(&tunnel->v.v3.msg_digest_shared_key, &tunnel->attr.secret);
|
|
(void)ipl2tp_avp_hmac_md5_digest(tunnel, &value, 1, IP_NULL, IP_NULL, digest);
|
|
|
|
/* Create */
|
|
ipl2tp_util_vector_create(&tunnel->v.v3.msg_digest_shared_key, digest, MD5_DIGEST_LENGTH);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_hmac_hide_avp_shared_key
|
|
*===========================================================================
|
|
* Description: Create the shared key for the hiding and unhiding AVPs
|
|
* Parameters: tunnel - The tunnel
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipl2tp_avp_hmac_hide_avp_shared_key(Ipl2tp_tunnel *tunnel)
|
|
{
|
|
Ip_u8 value = 1; /* HMAC_MD5 value for hiding AVPs */
|
|
Ip_u8 digest[MD5_DIGEST_LENGTH];
|
|
MD5_CTX i_ctx;
|
|
MD5_CTX o_ctx;
|
|
Ipl2tp_vector secret;
|
|
Ip_size_t i;
|
|
|
|
if (tunnel->local.key.version != IPL2TP_VERSION_L2TPV3)
|
|
return;
|
|
|
|
if (tunnel->attr.secret.size == 0)
|
|
return;
|
|
|
|
/* Clear the digest */
|
|
(void)ipcom_memset(digest, 0, MD5_DIGEST_LENGTH);
|
|
|
|
/* Duplicate the secret */
|
|
secret.array = IP_NULL;
|
|
ipl2tp_util_vector_dup(&secret, &tunnel->attr.secret);
|
|
|
|
/* Sanity */
|
|
if (secret.array == IP_NULL)
|
|
return;
|
|
|
|
/* Compute the I pad. */
|
|
for (i = 0; i < secret.size; i++)
|
|
secret.array[i] ^= HMAC_IPAD;
|
|
|
|
(void)MD5_Init(&i_ctx);
|
|
(void)MD5_Update(&i_ctx, secret.array, secret.size);
|
|
(void)MD5_Update(&i_ctx, ipl2tp_avp_hmac_ipad, 64 - secret.size);
|
|
(void)MD5_Update(&i_ctx, &value, 1);
|
|
(void)MD5_Final(digest, &i_ctx);
|
|
|
|
/* Compute the O pad. */
|
|
for (i = 0; i < secret.size; i++)
|
|
secret.array[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
|
|
(void)MD5_Init(&o_ctx);
|
|
(void)MD5_Update(&o_ctx, secret.array, secret.size);
|
|
(void)MD5_Update(&o_ctx, ipl2tp_avp_hmac_opad, 64 - secret.size);
|
|
|
|
/* Outer HMAC */
|
|
(void)MD5_Update(&o_ctx, digest, MD5_DIGEST_LENGTH);
|
|
(void)MD5_Final(digest, &o_ctx);
|
|
|
|
IPL2TP_SAFE_FREE(secret.array);
|
|
|
|
/* Create */
|
|
ipl2tp_util_vector_create(&tunnel->v.v3.hide_avp_shared_key, digest, MD5_DIGEST_LENGTH);
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_hmac_md5_verify
|
|
*===========================================================================
|
|
* Description: Verify MD5 hmac for tunnel.
|
|
* Parameters: tunnel - Tunnel to create digest for
|
|
* buffer - To calculate digest over.
|
|
* size - Size of buffer
|
|
* digest - Pointer to digest.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipl2tp_avp_hmac_md5_verify(Ipl2tp_tunnel *tunnel,
|
|
void *buffer,
|
|
Ip_size_t size,
|
|
void *digest)
|
|
{
|
|
char sdigest[MD5_DIGEST_LENGTH];
|
|
|
|
ipcom_memcpy(sdigest, digest, MD5_DIGEST_LENGTH);
|
|
ipcom_memset(digest, 0, MD5_DIGEST_LENGTH);
|
|
|
|
/* */
|
|
if (ipl2tp_avp_hmac_md5_digest(tunnel,
|
|
buffer,
|
|
size,
|
|
&tunnel->remote.nonce,
|
|
&tunnel->local.nonce,
|
|
digest) == IP_FALSE)
|
|
return IP_FALSE;
|
|
|
|
/* */
|
|
return ipcom_memcmp(sdigest, digest, MD5_DIGEST_LENGTH) == 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_hmac_sha_verify
|
|
*===========================================================================
|
|
* Description: Verify SHA digest for a given tunnel
|
|
* Parameters: tunnel - Tunnel to create digest for
|
|
* buffer - To calculate digest over.
|
|
* size - Size of buffer
|
|
* digest - Pointer to digest.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipl2tp_avp_hmac_sha_verify(Ipl2tp_tunnel *tunnel,
|
|
void *buffer,
|
|
Ip_size_t size,
|
|
void *digest)
|
|
{
|
|
char sdigest[SHA_DIGEST_LENGTH];
|
|
|
|
ipcom_memcpy(sdigest, digest, SHA_DIGEST_LENGTH);
|
|
ipcom_memset(digest, 0, SHA_DIGEST_LENGTH);
|
|
|
|
/* */
|
|
if (ipl2tp_avp_hmac_sha_digest(tunnel,
|
|
buffer,
|
|
size,
|
|
&tunnel->remote.nonce,
|
|
&tunnel->local.nonce,
|
|
digest) == IP_FALSE)
|
|
return IP_FALSE;
|
|
|
|
/* */
|
|
return ipcom_memcmp(sdigest, digest, SHA_DIGEST_LENGTH) == 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_name
|
|
*===========================================================================
|
|
* Description: Get name of attribute.
|
|
* Parameters: attr_type - Attribute type
|
|
* Returns: Human readable attribute name.
|
|
*
|
|
*/
|
|
IP_STATIC CONST char *
|
|
ipl2tp_avp_name(Ip_u16 attr_type)
|
|
{
|
|
static CONST char *ipl2tp_attr_string[] =
|
|
{
|
|
"MESSAGE_TYPE", /* 0 */
|
|
"RESULT_CODE", /* 1 */
|
|
"PROTOCOL_VERSION", /* 2 */
|
|
"FRAMING_CAPABILITIES", /* 3 */
|
|
"BEARER_CAPABILITIES", /* 4 */
|
|
"TIE_BREAKER", /* 5 */
|
|
"FIRMWARE_REVISION", /* 6 */
|
|
"HOST_NAME", /* 7 */
|
|
"VENDOR_NAME", /* 8 */
|
|
"ASSIGNED_TUNNEL_ID", /* 9 */
|
|
"RECEIVE_WINDOW_SIZE", /* 10 */
|
|
"CHALLENGE", /* 11 */
|
|
"Q931_CAUSE_CODE", /* 12 */
|
|
"CHALLENGE_RESPONSE", /* 13 */
|
|
"ASSIGNED_SESSION_ID", /* 14 */
|
|
"CALL_SERIAL_NUMBER", /* 15 */
|
|
"MINIMUM_BPS", /* 16 */
|
|
"MAXIMUM_BPS", /* 17 */
|
|
"BEARER_TYPE", /* 18 */
|
|
"FRAMING_TYPE", /* 19 */
|
|
"VOID", /* 20 */
|
|
"CALLED_NUMBER", /* 21 */
|
|
"CALLING_NUMBER", /* 22 */
|
|
"SUB_ADDRESS", /* 23 */
|
|
"TX_CONNECT_SPEED", /* 24 */
|
|
"PHYSICAL_CHANNEL_ID", /* 25 */
|
|
"INITIAL_RECEIVED_LCP_CONFREQ", /* 26 */
|
|
"LAST_SENT_LCP_CONFREQ", /* 27 */
|
|
"LAST_RECEIVED_LCP_CONFREQ", /* 28 */
|
|
"PROXY_AUTHEN_TYPE", /* 29 */
|
|
"PROXY_AUTHEN_NAME", /* 30 */
|
|
"PROXY_AUTHEN_CHALLENGE", /* 31 */
|
|
"PROXY_AUTHEN_ID", /* 32 */
|
|
"PROXY_AUTHEN_RESPONSE", /* 33 */
|
|
"CALL_ERRORS", /* 34 */
|
|
"ACCM", /* 35 */
|
|
"RANDOM_VECTOR", /* 36 */
|
|
"PRIVATE_GROUP_ID", /* 37 */
|
|
"RX_CONNECT_SPEED", /* 38 */
|
|
"SEQUENCING_REQUIRED", /* 39 */
|
|
"RX MINIMUM BPS", /* 40 */
|
|
"RX MAXIMUM BPS", /* 41 */
|
|
"SERVICE CATEGORY", /* 42 */
|
|
"SERVICE NAME", /* 43 */
|
|
"CALLING_SUB_ADDRESS", /* 44 */
|
|
"VPI_VCI_IDENTIFIER", /* 45 */
|
|
"PPP_DISCONNECT_CAUSE_CODE", /* 46 */
|
|
"CCDS", /* 47 */
|
|
"SDS", /* 48 */
|
|
"LCP_WANT_OPTIONS", /* 49 */
|
|
"LCP_ALLOW_OPTIONS", /* 50 */
|
|
"LNS_LAST_SENT_LCP_CONFREQ", /* 51 */
|
|
"LNS_LAST_RECEIVED_LCP_CONFREQ", /* 52 */
|
|
"MODEM_ON_HOLD_CAPABLE", /* 53 */
|
|
"MODEM_ON_HOLD_STATUS", /* 54 */
|
|
"PPPOE_RELAY", /* 55 */
|
|
"PPPOE_RELAY_RESPONSE_CAPABILITY", /* 56 */
|
|
"PPPOE_RELAY_FORWARD_CAPABILITY", /* 57 */
|
|
"EXTENDED_VENDOR_ID", /* 58 */
|
|
"MESSAGE_DIGEST", /* 59 */
|
|
"ROUTER_ID", /* 60 */
|
|
"ASSIGNED_CONTROL_CONNECTION_ID", /* 61 */
|
|
"PSEUDOWIRE_CAPABILITIES_LIST", /* 62 */
|
|
"LOCAL_SESSION_ID", /* 63 */
|
|
"REMOTE_SESSION_ID", /* 64 */
|
|
"ASSIGNED_COOKIE", /* 65 */
|
|
"REMOTE_END_ID", /* 66 */
|
|
"APPLICATION_CODE", /* 67 */
|
|
"PSEUDOWIRE_TYPE", /* 68 */
|
|
"L2_SPECIFIC_SUBLAYER", /* 69 */
|
|
"DATA_SEQUENCING", /* 70 */
|
|
"CIRCUIT_STATUS", /* 71 */
|
|
"PREFERRED_LANGUAGE", /* 72 */
|
|
"CONTROL_MESSAGE_AUTH_NONCE", /* 73 */
|
|
"TX_CONNECT_SPEED64", /* 74 */
|
|
"RX_CONNECT_SPEED64", /* 75 */
|
|
};
|
|
|
|
return (attr_type <
|
|
(sizeof(ipl2tp_attr_string) / sizeof(ipl2tp_attr_string[0])) ?
|
|
ipl2tp_attr_string[attr_type] : "<invalid attribute>");
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_mandatory
|
|
*===========================================================================
|
|
* Description: Check if attribute is mandatory, and print error message.
|
|
* Parameters: tunnel - The tunnel
|
|
* avp - The AVP
|
|
* flags - Flags from the L2TP header.
|
|
* avp_type - Type of attribute.
|
|
* msg - Error message to print.
|
|
* Returns: IP_TRUE if mandatory.
|
|
*
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipl2tp_avp_mandatory(Ipl2tp_tunnel *tunnel,
|
|
Ipl2tp_avp *avp,
|
|
Ip_u16 flags,
|
|
Ip_u16 avp_type,
|
|
Ipl2tp_status status,
|
|
Ip_u16 err_code,
|
|
CONST char *msg)
|
|
{
|
|
if ((flags & IPL2TP_AVP_FLAG_MANDATORY) != 0)
|
|
{
|
|
if (tunnel)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
status,
|
|
IPL2TP_RES_StopCCN_GENERAL_ERROR,
|
|
err_code,
|
|
"Got an unknown mandatory attribute");
|
|
}
|
|
|
|
IPCOM_LOG3(ERR,
|
|
"%s: Got %s mandatory attribute %s",
|
|
ipl2tp_versions[avp->version],
|
|
msg,
|
|
ipl2tp_avp_name(avp_type));
|
|
return IP_TRUE;
|
|
}
|
|
|
|
IPCOM_LOG3(WARNING,
|
|
"%s: Got %s attribute %s",
|
|
ipl2tp_versions[avp->version],
|
|
msg,
|
|
ipl2tp_avp_name(avp_type));
|
|
return IP_FALSE;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_validate
|
|
*===========================================================================
|
|
* Description: Check if any compulsory AVPs are missing.
|
|
* Parameters: version - Version
|
|
* avp - AVP collection.
|
|
* hidden - Check hidden AVP's
|
|
* Returns: IPL2TP_STATUS_OK if OK.
|
|
*
|
|
*/
|
|
IP_STATIC Ipl2tp_status
|
|
ipl2tp_avp_validate(Ipl2tp_avp *avp,
|
|
int hidden)
|
|
{
|
|
CONST Ip_u8 *vector;
|
|
Ipl2tp_status status = IPL2TP_STATUS_OK;
|
|
int i;
|
|
|
|
|
|
/* Message type */
|
|
if (avp->message_type.head.ok == 0)
|
|
{
|
|
IPCOM_LOG2(WARNING,
|
|
"%s: Missing %s attribute",
|
|
ipl2tp_versions[avp->version],
|
|
ipl2tp_avp_name(IPL2TP_AVP_MESSAGE_TYPE));
|
|
return IPL2TP_STATUS_TEARDOWN;
|
|
}
|
|
|
|
/* Get compulsory vector */
|
|
vector = avp->compulsory[avp->message_type.value];
|
|
|
|
/* Check that all compulsory AVPs are present */
|
|
for (i = 0; vector[i] != IPL2TP_AVP_END; i++)
|
|
{
|
|
/*lint -e504*/
|
|
if ((hidden != 0 || (vector[i] & IPL2TP_AVP_VISIBLE) != 0) &&
|
|
BITTST(&avp->map, (vector[i] & ~IPL2TP_AVP_VISIBLE)) == 0)
|
|
{
|
|
IPCOM_LOG4(WARNING,
|
|
"%s: Missing %s attribute in %s (%d)",
|
|
ipl2tp_versions[avp->version],
|
|
ipl2tp_avp_name((Ip_u16)(vector[i] & ~IPL2TP_AVP_VISIBLE)),
|
|
ipl2tp_message_name(avp->message_type.value),
|
|
hidden);
|
|
status = IPL2TP_STATUS_TEARDOWN;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_hide
|
|
*===========================================================================
|
|
* Description: hide avp
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipl2tp_avp_hide(Ipl2tp_avp_message_header *hdr,
|
|
void *buffer,
|
|
Ip_size_t buffer_len,
|
|
Ip_u8 *secret,
|
|
Ip_size_t secret_len,
|
|
Ip_u8 *random_vector,
|
|
Ip_size_t random_vector_len)
|
|
{
|
|
Ip_u8 *data = buffer;
|
|
MD5_CTX ctx;
|
|
int buffer_pos = 0;
|
|
int digest_pos = 0;
|
|
Ip_u8 digest[MD5_DIGEST_LENGTH];
|
|
|
|
/* Compute initial digest */
|
|
(void)MD5_Init(&ctx);
|
|
(void)MD5_Update(&ctx, (Ip_u8 *)&hdr->attribute_type, 2);
|
|
(void)MD5_Update(&ctx, secret, secret_len);
|
|
(void)MD5_Update(&ctx, random_vector, random_vector_len);
|
|
(void)MD5_Final(digest, &ctx);
|
|
|
|
/* Insert value */
|
|
for (; buffer_pos < buffer_len; buffer_pos++, digest_pos++)
|
|
{
|
|
if (digest_pos == MD5_DIGEST_LENGTH)
|
|
{
|
|
/* Compute new digest */
|
|
digest_pos = 0;
|
|
(void)MD5_Init(&ctx);
|
|
(void)MD5_Update(&ctx, secret, secret_len);
|
|
(void)MD5_Update(&ctx, &data[buffer_pos] - MD5_DIGEST_LENGTH, MD5_DIGEST_LENGTH);
|
|
(void)MD5_Final(digest, &ctx);
|
|
}
|
|
data[buffer_pos] ^= digest[digest_pos];
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_unhide
|
|
*===========================================================================
|
|
* Description: unhide avp
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipl2tp_avp_unhide(Ipl2tp_avp_message_header *hdr,
|
|
void *buffer,
|
|
Ip_size_t buffer_len,
|
|
Ip_u8 *secret,
|
|
Ip_size_t secret_len,
|
|
Ip_u8 *random_vector,
|
|
Ip_size_t random_vector_len)
|
|
{
|
|
Ip_u8 *data = buffer;
|
|
MD5_CTX ctx;
|
|
int buffer_pos = 0;
|
|
int digest_pos = 0;
|
|
Ip_u8 digest[MD5_DIGEST_LENGTH];
|
|
|
|
for (buffer_pos = (buffer_len - 1) & ~0xF;
|
|
buffer_pos > 0;
|
|
buffer_pos++, digest_pos++)
|
|
{
|
|
|
|
if (digest_pos == 16 || buffer_pos == buffer_len)
|
|
{
|
|
digest_pos = 0;
|
|
buffer_pos = ((buffer_pos -1) & ~0xF) - 16;
|
|
if(buffer_pos == 0)
|
|
break;
|
|
}
|
|
if (digest_pos == 0)
|
|
{
|
|
/* Compute new digest */
|
|
(void)MD5_Init(&ctx);
|
|
(void)MD5_Update(&ctx, secret, secret_len);
|
|
(void)MD5_Update(&ctx, &data[buffer_pos] - 16, 16);
|
|
(void)MD5_Final(digest, &ctx);
|
|
}
|
|
data[buffer_pos] ^= digest[digest_pos];
|
|
}
|
|
|
|
/* Compute initial digest */
|
|
(void)MD5_Init(&ctx);
|
|
(void)MD5_Update(&ctx, (Ip_u8 *)&hdr->attribute_type, 2);
|
|
(void)MD5_Update(&ctx, secret, secret_len);
|
|
(void)MD5_Update(&ctx, random_vector, random_vector_len);
|
|
(void)MD5_Final(digest, &ctx);
|
|
|
|
for (buffer_pos = 0, digest_pos = 0;
|
|
buffer_pos < buffer_len && digest_pos != 16;
|
|
buffer_pos++, digest_pos++)
|
|
{
|
|
data[buffer_pos] ^= digest[digest_pos];
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_md5
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters: digest - MD5 digest
|
|
* dXp - data pointer
|
|
* dX1 - length of data.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipl2tp_avp_md5(Ip_u8 digest[MD5_DIGEST_LENGTH],
|
|
Ipl2tp_tunnel *tunnel,
|
|
void *tdata,
|
|
Ip_size_t tsize,
|
|
void *ddata,
|
|
Ip_size_t dsize)
|
|
{
|
|
MD5_CTX ctx;
|
|
|
|
|
|
MD5_Init(&ctx);
|
|
/* Hash the AVP type if it's present */
|
|
if (tsize != 0)
|
|
MD5_Update(&ctx, tdata, tsize);
|
|
|
|
MD5_Update(&ctx, tunnel->attr.secret.array, tunnel->attr.secret.size);
|
|
MD5_Update(&ctx, ddata, dsize);
|
|
MD5_Final(digest, &ctx);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_update
|
|
*===========================================================================
|
|
* Description: Update L2TP message with a new AVP. Uses data in
|
|
* static variable ipl2tp_avp.
|
|
* Parameters: container - Container holding the message
|
|
* type - AVP type.
|
|
* flength - Length of fixed part.
|
|
* vptr - Pointer to variable part.
|
|
* vlength - Length of variable part.
|
|
* flags - AVP flags.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void *
|
|
ipl2tp_avp_update(Ipl2tp_message *container,
|
|
Ipl2tp_avp_message_header *hdr,
|
|
struct Ip_iovec *iovec,
|
|
Ip_u16 iovec_size)
|
|
{
|
|
Ipl2tp_tunnel *tunnel = container->admin.tunnel;
|
|
Ip_u16 flags_length;
|
|
Ip_u16 avp_flags;
|
|
Ip_u16 avp_length;
|
|
Ip_u16 avp_type;
|
|
Ip_u16 vec_length = 0;
|
|
Ip_u16 hidden_length = 0;
|
|
Ip_u16 message_length;
|
|
Ip_u8 *data;
|
|
int i;
|
|
|
|
/* Get current flags */
|
|
avp_flags = (Ip_u16)(IP_GET_NTOHS(&hdr->flags_length) & 0xFC00);
|
|
/* Get the header length of this AVP */
|
|
avp_length = (Ip_u16)(IP_GET_NTOHS(&hdr->flags_length) & 0x3FF);
|
|
/* Get the AVP type */
|
|
avp_type = IP_GET_NTOHS(&hdr->attribute_type);
|
|
|
|
/* Calculate total size */
|
|
for (i = 0; i < iovec_size; i++)
|
|
vec_length += iovec[i].iov_len;
|
|
|
|
/* Use hidden AVP? */
|
|
if (tunnel->attr.hide_avp == IPL2TP_MIB_NO ||
|
|
tunnel->attr.secret.size == 0 ||
|
|
(avp_flags & IPL2TP_AVP_FLAG_HIDDEN) == 0)
|
|
{
|
|
/* No */
|
|
avp_flags &= ~IPL2TP_AVP_FLAG_HIDDEN;
|
|
}
|
|
else
|
|
{
|
|
/* Insert random vector if not previously done */
|
|
if ((container->admin.flags & IPL2TP_CONTAINER_RV) == 0)
|
|
{
|
|
Ipl2tp_avp_message_header rv_hdr;
|
|
struct Ip_iovec rv_iovec;
|
|
Ip_u8 rv_value[IPL2TP_MAX_CHALLENGE_LENGTH];
|
|
Ipl2tp_vector rv_vec;
|
|
|
|
rv_vec.array = rv_value;
|
|
ipl2tp_util_vector_random(&rv_vec, ipl2tp_avp_challenge_size());
|
|
|
|
/* Data */
|
|
rv_iovec.iov_len = rv_vec.size;
|
|
rv_iovec.iov_base = rv_value;
|
|
|
|
|
|
IPL2TP_AVP_INITIALIZE(&rv_hdr,
|
|
IPL2TP_AVP_RANDOM_VECTOR,
|
|
IPL2TP_AVP_FLAG_MANDATORY);
|
|
|
|
/* Enter random vector AVP */
|
|
container->admin.rv_value = ipl2tp_avp_update(container,
|
|
&rv_hdr,
|
|
&rv_iovec,
|
|
1);
|
|
|
|
container->admin.rv_length = (Ip_u16) rv_iovec.iov_len;
|
|
container->admin.flags |= IPL2TP_CONTAINER_RV;
|
|
}
|
|
|
|
/* Reserve two bytes and pad to 16 bytes */
|
|
hidden_length = (Ip_u16) (2 + ((2 - (avp_length + vec_length)) & (MD5_DIGEST_LENGTH - 1)));
|
|
}
|
|
|
|
IPCOM_LOG5(DEBUG,
|
|
"%s(%d,%s): Encoding %s AVP: %s",
|
|
ipl2tp_versions[tunnel->local.key.version],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr),
|
|
(avp_flags & IPL2TP_AVP_FLAG_HIDDEN ? "hidden" : "visible"),
|
|
ipl2tp_avp_name(avp_type));
|
|
|
|
/* Get lengths */
|
|
flags_length = (Ip_u16)((avp_length + hidden_length + vec_length) | avp_flags);
|
|
message_length = container->admin.size;
|
|
|
|
/* Check if overflow */
|
|
ip_assert((message_length + hidden_length + avp_length + vec_length) <=
|
|
IPL2TP_MAX_MESSAGE_SIZE);
|
|
|
|
/* Update length field */
|
|
IP_SET_HTONS(&hdr->flags_length, flags_length);
|
|
|
|
/* Update header part */
|
|
ipcom_memcpy(container->admin.start + message_length,
|
|
hdr,
|
|
avp_length);
|
|
|
|
/* Increase the message size */
|
|
message_length += avp_length;
|
|
|
|
/* Update original length */
|
|
if (avp_flags & IPL2TP_AVP_FLAG_HIDDEN)
|
|
{
|
|
IP_SET_HTONS(container->admin.start + message_length, vec_length);
|
|
message_length += sizeof(Ip_u16);
|
|
}
|
|
|
|
/* Update variable part */
|
|
data = container->admin.start + message_length;
|
|
for (i = 0; i < iovec_size; i++)
|
|
{
|
|
ipcom_memcpy(container->admin.start + message_length,
|
|
iovec[i].iov_base,
|
|
iovec[i].iov_len);
|
|
|
|
message_length += iovec[i].iov_len;
|
|
|
|
}
|
|
|
|
/* Padding */
|
|
if (hidden_length > 2)
|
|
{
|
|
message_length += (hidden_length - 2);
|
|
}
|
|
|
|
/* Hide message? */
|
|
if (avp_flags & IPL2TP_AVP_FLAG_HIDDEN)
|
|
{
|
|
/* Current AVP past current AVP header size */
|
|
Ip_u8 *base = container->admin.start + container->admin.size + avp_length;
|
|
|
|
if (tunnel->local.key.version == IPL2TP_VERSION_L2TPV3)
|
|
{
|
|
if (tunnel->v.v3.hide_avp_shared_key.size == 0)
|
|
{
|
|
/* Create the shared_key = HMAC_MD5(shared_key, 1) per RFC 3931*/
|
|
ipl2tp_avp_hmac_hide_avp_shared_key(tunnel);
|
|
}
|
|
|
|
/* V3 uses a shared_key */
|
|
ipl2tp_avp_hide(hdr,
|
|
base,
|
|
hidden_length + vec_length,
|
|
tunnel->v.v3.hide_avp_shared_key.array,
|
|
tunnel->v.v3.hide_avp_shared_key.size,
|
|
container->admin.rv_value,
|
|
container->admin.rv_length);
|
|
}
|
|
else
|
|
{
|
|
/* default V2 uses a shared_secret */
|
|
ipl2tp_avp_hide(hdr,
|
|
base,
|
|
hidden_length + vec_length,
|
|
tunnel->attr.secret.array,
|
|
tunnel->attr.secret.size,
|
|
container->admin.rv_value,
|
|
container->admin.rv_length);
|
|
}
|
|
}
|
|
|
|
/* Update container size & length fields */
|
|
container->admin.size = message_length;
|
|
IP_SET_HTONS(container->admin.length, message_length - container->admin.pre_header);
|
|
return data;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set
|
|
*===========================================================================
|
|
* Description: Set a simple AVP
|
|
* Parameters: cont - The container
|
|
* type - The type of the AVP.
|
|
* flags - The flags
|
|
* data - Data
|
|
* size - Size of data
|
|
* Returns: Where the data was stored.
|
|
*
|
|
*/
|
|
IP_STATIC Ip_u8 *
|
|
ipl2tp_avp_set(Ipl2tp_message *cont,
|
|
Ip_u16 type,
|
|
Ip_u16 flags,
|
|
void *data,
|
|
Ip_size_t size)
|
|
{
|
|
Ipl2tp_avp_message_header avp_hdr;
|
|
struct Ip_iovec avp_iovec;
|
|
|
|
/* Initialize the AVP header */
|
|
IPL2TP_AVP_INITIALIZE(&avp_hdr, type, flags);
|
|
|
|
/* Setup the io vector */
|
|
avp_iovec.iov_base = data;
|
|
avp_iovec.iov_len = size;
|
|
|
|
/* Update the AVP. */
|
|
return ipl2tp_avp_update(cont, &avp_hdr, &avp_iovec, 1);
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_parse
|
|
*===========================================================================
|
|
* Description: Parse the AVP's attached to a control channel message.
|
|
* Parameters: avp - The AVP to store the parsed data in.
|
|
* message - The pointer to the message.
|
|
* mindex - The index where to start parse AVP
|
|
* message_length - The total size of the message.
|
|
* hidden - Hidden AVP's.
|
|
* tunnel - The tunnel, if found.
|
|
* addr - The address of the sender of the message.
|
|
* Returns: IPL2TP_SUCCESS - Success.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipl2tp_status
|
|
ipl2tp_avp_parse(Ipl2tp_avp *avp,
|
|
Ip_u8 *message_base,
|
|
Ip_size_t mindex,
|
|
Ip_size_t message_length,
|
|
Ip_bool hidden,
|
|
Ipl2tp_tunnel *tunnel,
|
|
union Ip_sockaddr_union *addr)
|
|
{
|
|
Ip_u16 totlength = 1;
|
|
Ip_u16 length;
|
|
int avp_no = 0;
|
|
|
|
IPL2TP_UNUSED(addr);
|
|
|
|
/* ZLB messages gets special treatment */
|
|
if (message_length <= mindex)
|
|
{
|
|
/* Here we fake a ZLB message type */
|
|
avp->message_type.head.ok = 1;
|
|
avp->message_type.head.mandatory = 0;
|
|
avp->message_type.head.vendor_id = 0;
|
|
avp->message_type.value = ip_htons(IPL2TP_MSG_ZLB);
|
|
return IPL2TP_STATUS_OK;
|
|
}
|
|
|
|
/* Loop until end of message */
|
|
for (; totlength != 0 && mindex < message_length; mindex += totlength, avp_no++)
|
|
{
|
|
Ipl2tp_avp_message_header *unaligned = (Ipl2tp_avp_message_header *)&message_base[mindex];
|
|
Ipl2tp_avp_header *avph;
|
|
Ip_u8 *data;
|
|
Ip_u16 flags;
|
|
Ip_u32 vendor_id;
|
|
Ip_u16 avp_type;
|
|
Ipl2tp_status errout_status;
|
|
Ip_u16 errout_code;
|
|
const char *errout_message;
|
|
Ip_u32 hsize = 6;
|
|
Ip_u32 val_size;
|
|
|
|
/* Get header fields */
|
|
flags = (Ip_u16)(IP_GET_NTOHS(&unaligned->flags_length) & 0xFC00);
|
|
vendor_id = IP_GET_NTOHS(&unaligned->vendor_id);
|
|
avp_type = IP_GET_NTOHS(&unaligned->attribute_type);
|
|
|
|
/* Get length of this AVP */
|
|
totlength = length = (Ip_u16)(IP_GET_NTOHS(&unaligned->flags_length) & 0x3FF);
|
|
|
|
/* Verify if this is an 'extended' AVP */
|
|
if (vendor_id == 0 && avp_type == IPL2TP_AVP_EXTENDED_VENDOR_ID)
|
|
{
|
|
Ipl2tp_avp_ext_message_header *ext;
|
|
ext = (Ipl2tp_avp_ext_message_header *) unaligned;
|
|
|
|
/* Extract the real values */
|
|
vendor_id = IP_GET_NTOHL(&ext->vendor_id[0]);
|
|
avp_type = IP_GET_NTOHS(&ext->attribute_type);
|
|
|
|
/* We've got an extended header */
|
|
hsize = 12;
|
|
}
|
|
|
|
data = (Ip_u8 *) unaligned + hsize;
|
|
|
|
/* Remember the presence of hidden AVPs */
|
|
avp->hidden =
|
|
avp->hidden || avp_type == IPL2TP_AVP_MESSAGE_DIGEST || ((flags & IPL2TP_AVP_FLAG_HIDDEN) != 0);
|
|
|
|
if (hidden)
|
|
{
|
|
/* MUST read the random vector */
|
|
if (avp_type != IPL2TP_AVP_RANDOM_VECTOR &&
|
|
avp_type != IPL2TP_AVP_MESSAGE_DIGEST)
|
|
{
|
|
/* Don't bother with visible attributes */
|
|
if (IP_BIT_ISFALSE(flags, IPL2TP_AVP_FLAG_HIDDEN))
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Don't parse hidden attributes */
|
|
if (IP_BIT_ISSET(flags, IPL2TP_AVP_FLAG_HIDDEN))
|
|
continue;
|
|
/* Don't bother with the random vector */
|
|
if (avp_type == IPL2TP_AVP_RANDOM_VECTOR)
|
|
continue;
|
|
}
|
|
|
|
/* Check reserved bits */
|
|
if ((flags & 0x3C00) != 0)
|
|
{
|
|
IPL2TP_AVP_PARSE_ERROUT(IPL2TP_STATUS_RESERVEDNZ,
|
|
IPL2TP_ERR_OUT_OF_RANGE,
|
|
"non-zero reserved bits in");
|
|
}
|
|
|
|
|
|
/* Check that AVP length matches message length */
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED((mindex + totlength) > message_length);
|
|
|
|
/* Cannot handle vendor-specific stuff */
|
|
if (vendor_id != 0)
|
|
{
|
|
IPL2TP_AVP_PARSE_ERROUT(IPL2TP_STATUS_VENDOR,
|
|
IPL2TP_ERR_UNKNOWN_M_AVP,
|
|
"unknown vendor-specific");
|
|
}
|
|
|
|
/* Handle hidden AVPs */
|
|
if ((flags & IPL2TP_AVP_FLAG_HIDDEN) == 0)
|
|
{
|
|
IPCOM_LOG2(DEBUG,
|
|
"%s: Decoding visible AVP: %s",
|
|
ipl2tp_versions[avp->version],
|
|
ipl2tp_avp_name(avp_type));
|
|
}
|
|
else
|
|
{
|
|
int vallength = totlength - hsize;
|
|
Ip_u16 orilen;
|
|
|
|
IPCOM_LOG2(DEBUG,
|
|
"%s: Decoding hidden AVP: %s",
|
|
ipl2tp_versions[avp->version],
|
|
ipl2tp_avp_name(avp_type));
|
|
|
|
/* Check if random vector present */
|
|
if (avp->random_vector.vec.size == 0)
|
|
{
|
|
IPL2TP_AVP_PARSE_ERROUT(IPL2TP_STATUS_NORAND,
|
|
IPL2TP_ERR_VENDOR_ERROR_LAC,
|
|
"no random vector for");
|
|
}
|
|
|
|
/* Check if secret present */
|
|
if (tunnel == IP_NULL || tunnel->attr.secret.size == 0)
|
|
{
|
|
IPL2TP_AVP_PARSE_ERROUT(IPL2TP_STATUS_NOSECRET,
|
|
IPL2TP_ERR_VENDOR_ERROR_LAC,
|
|
"no shared secret for");
|
|
}
|
|
|
|
/* Length must always be at least 2 octets */
|
|
/* Check that AVP length matches message length */
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(vallength < 2);
|
|
|
|
if (tunnel->local.key.version == IPL2TP_VERSION_L2TPV3)
|
|
{
|
|
if (tunnel->v.v3.hide_avp_shared_key.size == 0)
|
|
{
|
|
/* Create the shared_key = HMAC_MD5(shared_key, 1) per RFC 3931*/
|
|
ipl2tp_avp_hmac_hide_avp_shared_key(tunnel);
|
|
}
|
|
|
|
/* V3 uses a shared_key */
|
|
ipl2tp_avp_unhide(unaligned,
|
|
data,
|
|
vallength,
|
|
tunnel->v.v3.hide_avp_shared_key.array,
|
|
tunnel->v.v3.hide_avp_shared_key.size,
|
|
avp->random_vector.vec.array,
|
|
avp->random_vector.vec.size);
|
|
}
|
|
else
|
|
{
|
|
/* default V2 uses a shared_secret */
|
|
ipl2tp_avp_unhide(unaligned,
|
|
data,
|
|
vallength,
|
|
tunnel->attr.secret.array,
|
|
tunnel->attr.secret.size,
|
|
avp->random_vector.vec.array,
|
|
avp->random_vector.vec.size);
|
|
}
|
|
|
|
/* Get original length */
|
|
orilen = IP_GET_NTOHS(data);
|
|
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(orilen > (vallength - 2));
|
|
|
|
/* Update values */
|
|
length = (Ip_u16) (orilen + hsize);
|
|
data += 2;
|
|
}
|
|
|
|
/* Length must always be at least hsize octets */
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(length < hsize);
|
|
|
|
/* Calculate the value size */
|
|
val_size = length - hsize;
|
|
|
|
/* Which AVP? */
|
|
switch (avp_type)
|
|
{
|
|
case IPL2TP_AVP_MESSAGE_TYPE:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 2);
|
|
avph = &avp->message_type.head;
|
|
avp->message_type.value = IP_GET_NTOHS(data);
|
|
|
|
if (ipl2tp_message_recognized(avp->message_type.value) == 0)
|
|
{
|
|
|
|
if (ipl2tp_avp_mandatory(tunnel, avp, flags, avp_type,
|
|
IPL2TP_STATUS_BADMTYPE, IPL2TP_ERR_VENDOR_ERROR_LAC,
|
|
"invalid message type in"))
|
|
{
|
|
return IPL2TP_STATUS_TEARDOWN;
|
|
}
|
|
|
|
/* Non-mandatory AVP means ignore the whole message */
|
|
return IPL2TP_STATUS_IGNORE;
|
|
}
|
|
break;
|
|
|
|
case IPL2TP_AVP_RANDOM_VECTOR:
|
|
avph = &avp->random_vector.head;
|
|
ipl2tp_util_vector_create(&avp->random_vector.vec,
|
|
data,
|
|
val_size);
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(avp->random_vector.vec.array);
|
|
break;
|
|
|
|
case IPL2TP_AVP_RESULT_CODE:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size < 2);
|
|
avph = &avp->result_code.head;
|
|
|
|
avp->result_code.result_code = IP_GET_NTOHS(data);
|
|
data += sizeof(Ip_u16);
|
|
|
|
avp->result_code.error_message = IP_NULL;
|
|
if (val_size >= 4)
|
|
{
|
|
/* Error code present */
|
|
avp->result_code.error_code = IP_GET_NTOHS(data);
|
|
data += sizeof(Ip_u16);
|
|
|
|
if (val_size > 4)
|
|
{
|
|
char *cp = ipl2tp_util_strdup(data, val_size - 4);
|
|
|
|
/* Error message present */
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(cp);
|
|
IPL2TP_SAFE_FREE(avp->result_code.error_message);
|
|
avp->result_code.error_message = cp;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case IPL2TP_AVP_PROTOCOL_VERSION:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 2);
|
|
avph = &avp->protocol_version.head;
|
|
avp->protocol_version.ver = *data++;
|
|
avp->protocol_version.rev = *data;
|
|
break;
|
|
|
|
case IPL2TP_AVP_FRAMING_CAPABILITIES:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 4);
|
|
avph = &avp->framing_capabilities.head;
|
|
avp->framing_capabilities.value = ipl2tp_pw_bits2framing(IP_GET_NTOHL(data));
|
|
break;
|
|
|
|
case IPL2TP_AVP_BEARER_CAPABILITIES:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 4);
|
|
avph = &avp->bearer_capabilities.head;
|
|
avp->bearer_capabilities.value = ipl2tp_pw_bits2bearer(IP_GET_NTOHL(data));
|
|
break;
|
|
|
|
case IPL2TP_AVP_TIE_BREAKER:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 8);
|
|
avph = &avp->tie_breaker.head;
|
|
ipl2tp_util_vector_create(&avp->tie_breaker.vec,
|
|
data,
|
|
val_size);
|
|
break;
|
|
|
|
case IPL2TP_AVP_FIRMWARE_REVISION:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 2);
|
|
avph = &avp->firmware_revision.head;
|
|
avp->firmware_revision.value = IP_GET_NTOHS(data);
|
|
break;
|
|
|
|
case IPL2TP_AVP_HOST_NAME:
|
|
{
|
|
char *cp = ipl2tp_util_strdup(data, val_size);
|
|
|
|
avph = &avp->host_name.head;
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(cp);
|
|
IPL2TP_SAFE_FREE(avp->host_name.value);
|
|
avp->host_name.value = cp;
|
|
break;
|
|
}
|
|
|
|
case IPL2TP_AVP_VENDOR_NAME:
|
|
{
|
|
char *cp = ipl2tp_util_strdup(data, val_size);
|
|
|
|
avph = &avp->vendor_name.head;
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(cp);
|
|
IPL2TP_SAFE_FREE(avp->vendor_name.value);
|
|
avp->vendor_name.value = cp;
|
|
break;
|
|
}
|
|
|
|
case IPL2TP_AVP_ASSIGNED_TUNNEL_ID:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 2);
|
|
avph = &avp->assigned_tunnel_id.head;
|
|
avp->assigned_tunnel_id.value = IP_GET_NTOHS(data);
|
|
break;
|
|
|
|
case IPL2TP_AVP_RECEIVE_WINDOW_SIZE:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 2);
|
|
avph = &avp->receive_window_size.head;
|
|
avp->receive_window_size.value = IP_GET_NTOHS(data);
|
|
break;
|
|
|
|
case IPL2TP_AVP_CHALLENGE:
|
|
avph = &avp->challenge.head;
|
|
ipl2tp_util_vector_create(&avp->challenge.vec,
|
|
data,
|
|
val_size);
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(avp->challenge.vec.array);
|
|
break;
|
|
|
|
case IPL2TP_AVP_CHALLENGE_RESPONSE:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != MD5_DIGEST_LENGTH);
|
|
avph = &avp->challenge_response.head;
|
|
ipl2tp_util_vector_create(&avp->challenge_response.vec,
|
|
data, MD5_DIGEST_LENGTH);
|
|
break;
|
|
|
|
case IPL2TP_AVP_Q931_CAUSE_CODE:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size < 3);
|
|
avph = &avp->q931_cause_code.head;
|
|
avp->q931_cause_code.code = IP_GET_NTOHS(data);
|
|
data += sizeof(Ip_u16);
|
|
avp->q931_cause_code.msg = *data++;
|
|
|
|
if (val_size > 3)
|
|
{
|
|
char *cp = ipl2tp_util_strdup(data, val_size - 3);
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(cp);
|
|
IPL2TP_SAFE_FREE(avp->q931_cause_code.advisory_msg);
|
|
avp->q931_cause_code.advisory_msg = cp;
|
|
}
|
|
break;
|
|
|
|
case IPL2TP_AVP_ASSIGNED_SESSION_ID:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 2);
|
|
avph = &avp->assigned_session_id.head;
|
|
avp->assigned_session_id.value = IP_GET_NTOHS(data);
|
|
break;
|
|
|
|
case IPL2TP_AVP_CALL_SERIAL_NUMBER:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 4);
|
|
avph = &avp->call_serial_number.head;
|
|
avp->call_serial_number.value = IP_GET_NTOHL(data);
|
|
break;
|
|
|
|
case IPL2TP_AVP_MINIMUM_BPS:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 4);
|
|
avph = &avp->minimum_bps.head;
|
|
avp->minimum_bps.value = IP_GET_NTOHL(data);
|
|
break;
|
|
|
|
case IPL2TP_AVP_MAXIMUM_BPS:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 4);
|
|
avph = &avp->maximum_bps.head;
|
|
avp->maximum_bps.value = IP_GET_NTOHL(data);
|
|
break;
|
|
|
|
case IPL2TP_AVP_BEARER_TYPE:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 4);
|
|
avph = &avp->bearer_type.head;
|
|
avp->bearer_type.value = ipl2tp_pw_bits2bearer(IP_GET_NTOHL(data));
|
|
break;
|
|
|
|
case IPL2TP_AVP_FRAMING_TYPE:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 4);
|
|
avph = &avp->framing_type.head;
|
|
avp->framing_type.value = ipl2tp_pw_bits2framing(IP_GET_NTOHL(data));
|
|
break;
|
|
|
|
case IPL2TP_AVP_CALLED_NUMBER:
|
|
{
|
|
char *cp = ipl2tp_util_strdup(data, val_size);
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(cp);
|
|
avph = &avp->called_number.head;
|
|
IPL2TP_SAFE_FREE(avp->called_number.value);
|
|
avp->called_number.value = cp;
|
|
break;
|
|
}
|
|
|
|
case IPL2TP_AVP_CALLING_NUMBER:
|
|
{
|
|
char *cp = ipl2tp_util_strdup(data, val_size);
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(cp);
|
|
avph = &avp->calling_number.head;
|
|
IPL2TP_SAFE_FREE(avp->calling_number.value);
|
|
avp->calling_number.value = cp;
|
|
break;
|
|
}
|
|
|
|
case IPL2TP_AVP_SUB_ADDRESS:
|
|
{
|
|
char *cp = ipl2tp_util_strdup(data, val_size);
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(cp);
|
|
avph = &avp->sub_address.head;
|
|
IPL2TP_SAFE_FREE(avp->sub_address.value);
|
|
avp->sub_address.value = cp;
|
|
break;
|
|
}
|
|
|
|
case IPL2TP_AVP_TX_CONNECT_SPEED:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 4);
|
|
avph = &avp->tx_connect_speed.head;
|
|
avp->tx_connect_speed.value = IP_GET_NTOHL(data);
|
|
break;
|
|
|
|
case IPL2TP_AVP_RX_CONNECT_SPEED:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 4);
|
|
avph = &avp->rx_connect_speed.head;
|
|
avp->rx_connect_speed.value = IP_GET_NTOHL(data);
|
|
break;
|
|
|
|
case IPL2TP_AVP_PHYSICAL_CHANNEL_ID:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 4);
|
|
avph = &avp->physical_channel_id.head;
|
|
avp->physical_channel_id.value = IP_GET_NTOHL(data);
|
|
break;
|
|
|
|
case IPL2TP_AVP_PRIVATE_GROUP_ID:
|
|
avph = &avp->private_group_id.head;
|
|
avp->private_group_id.value = ipl2tp_util_strdup(data, val_size);
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(avp->private_group_id.value);
|
|
break;
|
|
|
|
case IPL2TP_AVP_SEQUENCING_REQUIRED:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 0);
|
|
avph = &avp->sequencing_required.head;
|
|
break;
|
|
|
|
case IPL2TP_AVP_INITIAL_RECEIVED_LCP_CONFREQ:
|
|
avph = &avp->initial_received_lcp_confreq.head;
|
|
ipl2tp_util_vector_create(&avp->initial_received_lcp_confreq.vec,
|
|
data,
|
|
val_size);
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(avp->initial_received_lcp_confreq.vec.array);
|
|
break;
|
|
|
|
case IPL2TP_AVP_LAST_SENT_LCP_CONFREQ:
|
|
avph = &avp->last_sent_lcp_confreq.head;
|
|
ipl2tp_util_vector_create(&avp->last_sent_lcp_confreq.vec,
|
|
data,
|
|
val_size);
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(avp->last_sent_lcp_confreq.vec.array);
|
|
break;
|
|
|
|
case IPL2TP_AVP_LAST_RECEIVED_LCP_CONFREQ:
|
|
avph = &avp->last_received_lcp_confreq.head;
|
|
ipl2tp_util_vector_create(&avp->last_received_lcp_confreq.vec,
|
|
data,
|
|
val_size);
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(avp->last_received_lcp_confreq.vec.array);
|
|
break;
|
|
|
|
case IPL2TP_AVP_PROXY_AUTHEN_TYPE:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 2);
|
|
avph = &avp->proxy_authen_type.head;
|
|
avp->proxy_authen_type.value = IP_GET_NTOHS(data);
|
|
break;
|
|
|
|
case IPL2TP_AVP_PROXY_AUTHEN_NAME:
|
|
avph = &avp->proxy_authen_name.head;
|
|
avp->proxy_authen_name.value = ipl2tp_util_strdup(data, val_size);
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(avp->proxy_authen_name.value);
|
|
break;
|
|
|
|
case IPL2TP_AVP_PROXY_AUTHEN_CHALLENGE:
|
|
avph = &avp->proxy_authen_challenge.head;
|
|
ipl2tp_util_vector_create(&avp->proxy_authen_challenge.vec,
|
|
data,
|
|
val_size);
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(avp->proxy_authen_challenge.vec.array);
|
|
break;
|
|
|
|
case IPL2TP_AVP_PROXY_AUTHEN_ID:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 2);
|
|
avph = &avp->proxy_authen_id.head;
|
|
avp->proxy_authen_id.value = data[1];
|
|
break;
|
|
|
|
case IPL2TP_AVP_PROXY_AUTHEN_RESPONSE:
|
|
avph = &avp->proxy_authen_response.head;
|
|
ipl2tp_util_vector_create(&avp->proxy_authen_response.vec,
|
|
data,
|
|
val_size);
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(avp->proxy_authen_response.vec.array);
|
|
break;
|
|
|
|
case IPL2TP_AVP_CALL_ERRORS:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 26);
|
|
avph = &avp->call_errors.head;
|
|
data += sizeof(Ip_u16);
|
|
avp->call_errors.crc_errors = IP_GET_NTOHL(data);
|
|
data += sizeof(Ip_u32);
|
|
avp->call_errors.framing_errors = IP_GET_NTOHL(data);
|
|
data += sizeof(Ip_u32);
|
|
avp->call_errors.hardware_overruns = IP_GET_NTOHL(data);
|
|
data += sizeof(Ip_u32);
|
|
avp->call_errors.buffer_overruns = IP_GET_NTOHL(data);
|
|
data += sizeof(Ip_u32);
|
|
avp->call_errors.timeout_errors = IP_GET_NTOHL(data);
|
|
data += sizeof(Ip_u32);
|
|
avp->call_errors.alignment_errors = IP_GET_NTOHL(data);
|
|
break;
|
|
|
|
case IPL2TP_AVP_ACCM:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 10);
|
|
avph = &avp->accm.head;
|
|
data += sizeof(Ip_u16);
|
|
avp->accm.send_accm = IP_GET_NTOHL(data);
|
|
data += sizeof(Ip_u32);
|
|
avp->accm.receive_accm = IP_GET_NTOHL(data);
|
|
break;
|
|
|
|
case IPL2TP_AVP_ROUTER_ID:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 4);
|
|
avph = &avp->router_id.head;
|
|
avp->router_id.value = IP_GET_NTOHL(data);
|
|
/**/
|
|
avp->v3_seen = IP_TRUE;
|
|
break;
|
|
case IPL2TP_AVP_ASSIGNED_CONTROL_CONNECTION_ID:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 4);
|
|
avph = &avp->assigned_control_connection_id.head;
|
|
avp->assigned_control_connection_id.value = IP_GET_NTOHL(data);
|
|
/**/
|
|
avp->v3_seen = IP_TRUE;
|
|
break;
|
|
case IPL2TP_AVP_PSEUDOWIRE_CAPABILITIES_LIST:
|
|
{
|
|
Ip_size_t i;
|
|
Ip_u16 *pw_types;
|
|
avph = &avp->pseudo_wires_list.head;
|
|
ipl2tp_util_vector_create(&avp->pseudo_wires_list.vec,
|
|
data,
|
|
val_size);
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(avp->pseudo_wires_list.vec.array);
|
|
|
|
/* Convert to host byte order */
|
|
pw_types = (Ip_u16 *)avp->pseudo_wires_list.vec.array;
|
|
if (val_size > 0)
|
|
{
|
|
for (i = 0; i < avp->pseudo_wires_list.vec.size / 2; i++)
|
|
{
|
|
/* Fixup */
|
|
pw_types[i] = ip_htons(pw_types[i]);
|
|
}
|
|
}
|
|
|
|
/**/
|
|
avp->v3_seen = IP_TRUE;
|
|
}
|
|
break;
|
|
case IPL2TP_AVP_LOCAL_SESSION_ID:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 4);
|
|
avph = &avp->local_session_id.head;
|
|
avp->local_session_id.value = IP_GET_NTOHL(data);
|
|
break;
|
|
case IPL2TP_AVP_REMOTE_SESSION_ID:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 4);
|
|
avph = &avp->remote_session_id.head;
|
|
avp->remote_session_id.value = IP_GET_NTOHL(data);
|
|
break;
|
|
case IPL2TP_AVP_ASSIGNED_COOKIE:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 0 && val_size != 4 && val_size != 8);
|
|
avph = &avp->assigned_cookie.head;
|
|
if (val_size)
|
|
{
|
|
ipl2tp_util_vector_create(&avp->assigned_cookie.vec,
|
|
data,
|
|
val_size);
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(avp->assigned_cookie.vec.array);
|
|
}
|
|
break;
|
|
|
|
case IPL2TP_AVP_REMOTE_END_ID:
|
|
avph = &avp->remote_end_id.head;
|
|
ipl2tp_util_vector_create(&avp->remote_end_id.vec,
|
|
data,
|
|
val_size);
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(avp->remote_end_id.vec.array);
|
|
break;
|
|
case IPL2TP_AVP_PSEUDOWIRE_TYPE:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 2);
|
|
avph = &avp->pseudo_wire_type.head;
|
|
avp->pseudo_wire_type.value = IP_GET_NTOHS(data);
|
|
break;
|
|
case IPL2TP_AVP_L2_SPECIFIC_SUBLAYER:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 2);
|
|
avph = &avp->l2_sublayer.head;
|
|
avp->l2_sublayer.value = IP_GET_NTOHS(data);
|
|
break;
|
|
case IPL2TP_AVP_DATA_SEQUENCING:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 2);
|
|
avph = &avp->data_sequencing.head;
|
|
avp->data_sequencing.value = IP_GET_NTOHS(data);
|
|
break;
|
|
case IPL2TP_AVP_CIRCUIT_STATUS:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 2);
|
|
avph = &avp->circuit_status.head;
|
|
avp->circuit_status.value = IP_GET_NTOHS(data);
|
|
break;
|
|
case IPL2TP_AVP_PREFERRED_LANGUAGE:
|
|
{
|
|
char *cp = ipl2tp_util_strdup(data, val_size);
|
|
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(cp);
|
|
IPL2TP_SAFE_FREE(avp->preferred_language.value);
|
|
|
|
avph = &avp->preferred_language.head;
|
|
avp->preferred_language.value = cp;
|
|
break;
|
|
}
|
|
case IPL2TP_AVP_CONTROL_MESSAGE_AUTH_NONCE:
|
|
avph = &avp->authentication_nonce.head;
|
|
ipl2tp_util_vector_create(&avp->authentication_nonce.vec,
|
|
data,
|
|
val_size);
|
|
IPL2TP_AVP_PARSE_CHECK_NOMEM(avp->authentication_nonce.vec.array);
|
|
break;
|
|
case IPL2TP_AVP_TX_CONNECT_SPEED64:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 8);
|
|
avph = &avp->tx_connect_speed64.head;
|
|
IP_U64_SET(avp->tx_connect_speed64.value,
|
|
IP_GET_NTOHL(data),
|
|
IP_GET_NTOHL(data + 4));
|
|
break;
|
|
case IPL2TP_AVP_RX_CONNECT_SPEED64:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != 8);
|
|
avph = &avp->rx_connect_speed64.head;
|
|
IP_U64_SET(avp->rx_connect_speed64.value,
|
|
IP_GET_NTOHL(data),
|
|
IP_GET_NTOHL(data + 4));
|
|
break;
|
|
|
|
case IPL2TP_AVP_MESSAGE_DIGEST:
|
|
{
|
|
Ipl2tp_status message_digest = IPL2TP_STATUS_IGNORE;
|
|
|
|
/* Only treat it 'magically' when in SCCRQ */
|
|
if (avp->message_type.value == IPL2TP_MSG_SCCRQ)
|
|
{
|
|
/* We're in SCCRQ, teardown is the only option */
|
|
message_digest = IPL2TP_STATUS_TEARDOWN;
|
|
}
|
|
|
|
/* We must be directly after the message type */
|
|
if (avp_no != 1)
|
|
{
|
|
IPCOM_LOG2(INFO,
|
|
"%s: Discarding %s due to badly placed message digest",
|
|
ipl2tp_versions[avp->version],
|
|
ipl2tp_message_name(avp->message_type.value));
|
|
return message_digest;
|
|
}
|
|
|
|
avph = &avp->message_digest.head;
|
|
avp->message_digest.type = *data;
|
|
|
|
/* Done for this loop */
|
|
if (hidden == 0)
|
|
break;
|
|
|
|
switch (avp->message_digest.type)
|
|
{
|
|
case IPL2TP_MIB_AUTH_MD5:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != (MD5_DIGEST_LENGTH + 1));
|
|
/* Don't */
|
|
if (ipl2tp_avp_hmac_md5_verify(tunnel, message_base, message_length, data + 1) == IP_FALSE)
|
|
{
|
|
IPCOM_LOG2(INFO,
|
|
"%s: Discarding %s due to bad message digest",
|
|
ipl2tp_versions[avp->version],
|
|
ipl2tp_message_name(avp->message_type.value));
|
|
return message_digest;
|
|
}
|
|
else
|
|
{
|
|
IPCOM_LOG2(DEBUG,
|
|
"%s: %s good MD5 message digest",
|
|
ipl2tp_versions[avp->version],
|
|
ipl2tp_message_name(avp->message_type.value));
|
|
}
|
|
|
|
break;
|
|
case IPL2TP_MIB_AUTH_SHA:
|
|
IPL2TP_AVP_PARSE_CHECK_MALFORMED(val_size != (SHA_DIGEST_LENGTH + 1));
|
|
/* Don't */
|
|
if (ipl2tp_avp_hmac_sha_verify(tunnel, message_base, message_length, data + 1) == IP_FALSE)
|
|
{
|
|
IPCOM_LOG2(INFO,
|
|
"%s: Discarding %s due to bad message digest",
|
|
ipl2tp_versions[avp->version],
|
|
ipl2tp_message_name(avp->message_type.value));
|
|
|
|
return message_digest;
|
|
}
|
|
else
|
|
{
|
|
IPCOM_LOG2(DEBUG,
|
|
"%s: %s good SHA message digest",
|
|
ipl2tp_versions[avp->version],
|
|
ipl2tp_message_name(avp->message_type.value));
|
|
}
|
|
break;
|
|
default:
|
|
/* Unknown Hash method */
|
|
IPCOM_LOG3(INFO,
|
|
"%s: Discarding %s due to unknown hash method (%u)",
|
|
ipl2tp_versions[avp->version],
|
|
ipl2tp_message_name(avp->message_type.value),
|
|
avp->message_digest.type);
|
|
return message_digest;
|
|
}
|
|
}
|
|
break;
|
|
case IPL2TP_AVP_APPLICATION_CODE:
|
|
default:
|
|
IPL2TP_AVP_PARSE_ERROUT(IPL2TP_STATUS_BADMTYPE,
|
|
IPL2TP_ERR_UNKNOWN_M_AVP,
|
|
"unknown");
|
|
}
|
|
|
|
/* Assign header stuff if we got a valid AVP */
|
|
if (avph != IP_NULL)
|
|
{
|
|
avph->ok = 1;
|
|
avph->mandatory = (Ip_u8)((flags & IPL2TP_AVP_FLAG_MANDATORY) != 0);
|
|
avph->vendor_id = vendor_id;
|
|
BITSET(&avp->map, avp_type);
|
|
}
|
|
continue;
|
|
|
|
errout:
|
|
if (ipl2tp_avp_mandatory(tunnel, avp, flags, avp_type, errout_status,
|
|
errout_code, errout_message))
|
|
{
|
|
return IPL2TP_STATUS_TEARDOWN;
|
|
}
|
|
continue;
|
|
|
|
}
|
|
|
|
return ipl2tp_avp_validate(avp, hidden);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_delete
|
|
*===========================================================================
|
|
* Description: Free all memory allocated in an AVP.
|
|
* Parameters: avp - AVP descriptor.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_delete(Ipl2tp_avp *avp)
|
|
{
|
|
if (avp != IP_NULL)
|
|
{
|
|
IPL2TP_SAFE_FREE(avp->random_vector.vec.array);
|
|
IPL2TP_SAFE_FREE(avp->result_code.error_message);
|
|
IPL2TP_SAFE_FREE(avp->host_name.value);
|
|
IPL2TP_SAFE_FREE(avp->vendor_name.value);
|
|
IPL2TP_SAFE_FREE(avp->challenge.vec.array);
|
|
IPL2TP_SAFE_FREE(avp->q931_cause_code.advisory_msg);
|
|
IPL2TP_SAFE_FREE(avp->called_number.value);
|
|
IPL2TP_SAFE_FREE(avp->calling_number.value);
|
|
IPL2TP_SAFE_FREE(avp->sub_address.value);
|
|
IPL2TP_SAFE_FREE(avp->private_group_id.value);
|
|
IPL2TP_SAFE_FREE(avp->initial_received_lcp_confreq.vec.array);
|
|
IPL2TP_SAFE_FREE(avp->last_sent_lcp_confreq.vec.array);
|
|
IPL2TP_SAFE_FREE(avp->last_received_lcp_confreq.vec.array);
|
|
IPL2TP_SAFE_FREE(avp->proxy_authen_name.value);
|
|
IPL2TP_SAFE_FREE(avp->proxy_authen_challenge.vec.array);
|
|
IPL2TP_SAFE_FREE(avp->proxy_authen_response.vec.array);
|
|
IPL2TP_SAFE_FREE(avp->tie_breaker.vec.array);
|
|
IPL2TP_SAFE_FREE(avp->challenge_response.vec.array);
|
|
|
|
/* v3 L2TP AVP */
|
|
IPL2TP_SAFE_FREE(avp->pseudo_wires_list.vec.array);
|
|
IPL2TP_SAFE_FREE(avp->preferred_language.value);
|
|
IPL2TP_SAFE_FREE(avp->authentication_nonce.vec.array);
|
|
IPL2TP_SAFE_FREE(avp->assigned_cookie.vec.array);
|
|
IPL2TP_SAFE_FREE(avp->remote_end_id.vec.array);
|
|
|
|
|
|
IPL2TP_SAFE_FREE(avp);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_challenge_size
|
|
*===========================================================================
|
|
* Description: Calculate the length of the challenge
|
|
* Parameters:
|
|
* Returns: The length of a challenge.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_size_t
|
|
ipl2tp_avp_challenge_size(void)
|
|
{
|
|
Ip_size_t len;
|
|
|
|
#if IPL2TP_MIN_CHALLENGE_LENGTH == IPL2TP_MAX_CHALLENGE_LENGTH
|
|
len = IPL2TP_MIN_CHALLENGE_LENGTH;
|
|
#else
|
|
len = IPL2TP_MIN_CHALLENGE_LENGTH +
|
|
(ipcom_port_random() %
|
|
(IPL2TP_MAX_CHALLENGE_LENGTH - IPL2TP_MIN_CHALLENGE_LENGTH));
|
|
#endif
|
|
return len;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_challenge_init
|
|
*===========================================================================
|
|
* Description: Initialize challenge for tunnel.
|
|
* Parameters: vec - Data to create challenge in,
|
|
* tunnel - Tunnel to create challenge for
|
|
* id - ID of request.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_challenge_init(Ipl2tp_vector *vec,
|
|
Ipl2tp_tunnel *tunnel,
|
|
Ip_u8 id)
|
|
{
|
|
Ip_u8 digest[MD5_DIGEST_LENGTH];
|
|
ipl2tp_util_vector_random(vec, ipl2tp_avp_challenge_size());
|
|
|
|
/* Increment to get ID for reply */
|
|
id++;
|
|
|
|
/* Calculate and remember expected MD5 checksum */
|
|
ipl2tp_avp_md5(digest,
|
|
tunnel,
|
|
&id,
|
|
1,
|
|
vec->array,
|
|
vec->size);
|
|
|
|
|
|
/* Create a vector of the response */
|
|
ipl2tp_util_vector_create(&tunnel->expected_response,
|
|
digest,
|
|
MD5_DIGEST_LENGTH);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_challenge_response_init
|
|
*===========================================================================
|
|
* Description: Initialize challenge response for tunnel.
|
|
* Parameters: digest - Where to create the digest.
|
|
* tunnel - The tunnel we're currently working with
|
|
* avp - The AVP structure.
|
|
* Returns: IPL2TP_STATUS_OK if it went well.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipl2tp_status
|
|
ipl2tp_avp_challenge_response_init(Ipl2tp_vector *digest,
|
|
Ipl2tp_tunnel *tunnel,
|
|
Ipl2tp_avp *avp)
|
|
{
|
|
Ip_u8 id = (Ip_u8)(avp->message_type.value + 1);
|
|
Ip_u8 tmpdigest[MD5_DIGEST_LENGTH];
|
|
|
|
/* Clear */
|
|
digest->array = IP_NULL;
|
|
digest->size = 0;
|
|
|
|
/* Ignore if no challenge received */
|
|
if (avp->challenge.head.ok == 0)
|
|
{
|
|
return IPL2TP_STATUS_IGNORE;
|
|
}
|
|
|
|
/* Ignore if no secret is configured */
|
|
if (tunnel->attr.secret.size == 0)
|
|
{
|
|
IPL2TP_TUNNEL_RESULT_SET(tunnel,
|
|
IPL2TP_STATUS_BADAUTH,
|
|
IPL2TP_RES_StopCCN_NOT_AUTHORIZED,
|
|
0,
|
|
"No authentication secret configured");
|
|
|
|
IPCOM_LOG3(WARNING,
|
|
"%s(%d,%s): No authentication secret configured",
|
|
ipl2tp_versions[tunnel->local.key.version],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr));
|
|
return IPL2TP_STATUS_ERROR;
|
|
}
|
|
|
|
IPCOM_LOG3(DEBUG,
|
|
"%s(%d,%s): Responding to challenge",
|
|
ipl2tp_versions[tunnel->local.key.version],
|
|
(int)tunnel->local.key.ident,
|
|
ipl2tp_util_ntoa(&tunnel->remote.addr));
|
|
|
|
ipl2tp_avp_md5(tmpdigest,
|
|
tunnel,
|
|
&id,
|
|
1,
|
|
avp->challenge.vec.array,
|
|
avp->challenge.vec.size);
|
|
|
|
/* Create the vector */
|
|
ipl2tp_util_vector_create(digest, tmpdigest, MD5_DIGEST_LENGTH);
|
|
|
|
return IPL2TP_STATUS_OK;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_challenge_verify
|
|
*===========================================================================
|
|
* Description: Verify challenge for tunnel.
|
|
* Parameters: avp - Challenge to verify
|
|
* tunnel - Tunnel to create challenge for
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_bool
|
|
ipl2tp_avp_challenge_verify(Ipl2tp_avp *avp,
|
|
Ipl2tp_tunnel *tunnel)
|
|
{
|
|
if (avp->challenge_response.vec.size != tunnel->expected_response.size)
|
|
return IP_FALSE;
|
|
|
|
if (ipcom_memcmp(avp->challenge_response.vec.array,
|
|
tunnel->expected_response.array, MD5_DIGEST_LENGTH) != 0)
|
|
return IP_FALSE;
|
|
|
|
return IP_TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_hmac_md5_digest
|
|
*===========================================================================
|
|
* Description: Calculate MD5 digest for a given buffer and tunnel
|
|
* Parameters: tunnel - Tunnel to create digest for
|
|
* buffer - To calculate digest over.
|
|
* size - Size of buffer
|
|
* nonce1 - The first nonce
|
|
* nonce2 - The second nonce
|
|
* digest - Pointer to digest.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_bool
|
|
ipl2tp_avp_hmac_md5_digest(Ipl2tp_tunnel *tunnel,
|
|
void *buffer,
|
|
Ip_size_t size,
|
|
Ipl2tp_vector *nonce1,
|
|
Ipl2tp_vector *nonce2,
|
|
void *digest)
|
|
{
|
|
MD5_CTX i_ctx;
|
|
MD5_CTX o_ctx;
|
|
Ipl2tp_vector secret;
|
|
Ip_size_t i;
|
|
|
|
/* Only once */
|
|
if (ipcom_once(&ipl2tp_avp_hmac_once, ipl2tp_avp_hmac_setup, IP_NULL) != IPCOM_SUCCESS)
|
|
return IP_FALSE;
|
|
|
|
/**/
|
|
if (tunnel->local.key.version != IPL2TP_VERSION_L2TPV3)
|
|
return IP_FALSE;
|
|
|
|
/**/
|
|
if (tunnel->attr.secret.size == 0)
|
|
return IP_FALSE;
|
|
|
|
/**/
|
|
if (tunnel->v.v3.msg_digest_shared_key.size == 0)
|
|
{
|
|
/* Create the shared key */
|
|
ipl2tp_avp_hmac_msg_digest_shared_key(tunnel);
|
|
}
|
|
|
|
/* Clear the digest */
|
|
ipcom_memset(digest, 0, MD5_DIGEST_LENGTH);
|
|
|
|
/* Duplicate the secret */
|
|
secret.array = IP_NULL;
|
|
ipl2tp_util_vector_dup(&secret, &tunnel->v.v3.msg_digest_shared_key);
|
|
|
|
/* Sanity */
|
|
if (secret.array == IP_NULL)
|
|
return IP_FALSE;
|
|
|
|
/* Compute the I pad. */
|
|
for (i = 0; i < secret.size; i++)
|
|
secret.array[i] ^= HMAC_IPAD;
|
|
|
|
MD5_Init(&i_ctx);
|
|
MD5_Update(&i_ctx, secret.array, secret.size);
|
|
MD5_Update(&i_ctx, ipl2tp_avp_hmac_ipad, 64 - secret.size);
|
|
|
|
/* We do have a nonce */
|
|
if (nonce1 != IP_NULL && nonce1->size != 0 &&
|
|
nonce2 != IP_NULL && nonce2->size != 0)
|
|
{
|
|
/* Done deal */
|
|
MD5_Update(&i_ctx, nonce1->array, nonce1->size);
|
|
MD5_Update(&i_ctx, nonce2->array, nonce2->size);
|
|
}
|
|
|
|
MD5_Update(&i_ctx, buffer, size);
|
|
MD5_Final(digest, &i_ctx);
|
|
|
|
/* Compute the O pad. */
|
|
for (i = 0; i < secret.size; i++)
|
|
secret.array[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
|
|
MD5_Init(&o_ctx);
|
|
MD5_Update(&o_ctx, secret.array, secret.size);
|
|
MD5_Update(&o_ctx, ipl2tp_avp_hmac_opad, 64 - secret.size);
|
|
|
|
|
|
/* Outer HMAC */
|
|
MD5_Update(&o_ctx, digest, MD5_DIGEST_LENGTH);
|
|
MD5_Final(digest, &o_ctx);
|
|
|
|
IPL2TP_SAFE_FREE(secret.array);
|
|
return IP_TRUE;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_hmac_sha_digest
|
|
*===========================================================================
|
|
* Description: Calculate SHA digest for a given buffer and tunnel
|
|
* Parameters: tunnel - Tunnel to create digest for
|
|
* buffer - To calculate digest over.
|
|
* size - Size of buffer
|
|
* nonce1 - The first nonce
|
|
* nonce2 - The second nonce
|
|
* digest - Pointer to digest.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_bool
|
|
ipl2tp_avp_hmac_sha_digest(Ipl2tp_tunnel *tunnel,
|
|
void *buffer,
|
|
Ip_size_t size,
|
|
Ipl2tp_vector *nonce1,
|
|
Ipl2tp_vector *nonce2,
|
|
void *digest)
|
|
{
|
|
SHA_CTX i_ctx;
|
|
SHA_CTX o_ctx;
|
|
Ipl2tp_vector secret;
|
|
Ip_size_t i;
|
|
|
|
/* Only once */
|
|
if (ipcom_once(&ipl2tp_avp_hmac_once, ipl2tp_avp_hmac_setup, IP_NULL) != IPCOM_SUCCESS)
|
|
return IP_FALSE;
|
|
|
|
/**/
|
|
if (tunnel->local.key.version != IPL2TP_VERSION_L2TPV3)
|
|
return IP_FALSE;
|
|
|
|
/**/
|
|
if (tunnel->attr.secret.size == 0)
|
|
return IP_FALSE;
|
|
|
|
/**/
|
|
if (tunnel->v.v3.msg_digest_shared_key.size == 0)
|
|
{
|
|
/* Create the shared key */
|
|
ipl2tp_avp_hmac_msg_digest_shared_key(tunnel);
|
|
}
|
|
|
|
/* Clear the digest */
|
|
ipcom_memset(digest, 0, SHA_DIGEST_LENGTH);
|
|
|
|
/* Duplicate the secret */
|
|
secret.array = IP_NULL;
|
|
ipl2tp_util_vector_dup(&secret, &tunnel->v.v3.msg_digest_shared_key);
|
|
|
|
/* Sanity */
|
|
if (secret.array == IP_NULL)
|
|
return IP_FALSE;
|
|
|
|
/* Compute the I pad. */
|
|
for (i = 0; i < secret.size; i++)
|
|
secret.array[i] ^= HMAC_IPAD;
|
|
|
|
SHA1_Init(&i_ctx);
|
|
SHA1_Update(&i_ctx, secret.array, secret.size);
|
|
SHA1_Update(&i_ctx, ipl2tp_avp_hmac_ipad, 64 - secret.size);
|
|
|
|
/* We do have a nonce */
|
|
if (nonce1 != IP_NULL && nonce1->size != 0 &&
|
|
nonce2 != IP_NULL && nonce2->size != 0)
|
|
{
|
|
/* Done deal */
|
|
SHA1_Update(&i_ctx, nonce1->array, nonce1->size);
|
|
SHA1_Update(&i_ctx, nonce2->array, nonce2->size);
|
|
}
|
|
|
|
SHA1_Update(&i_ctx, buffer, size);
|
|
SHA1_Final(digest, &i_ctx);
|
|
|
|
/* Compute the O pad. */
|
|
for (i = 0; i < secret.size; i++)
|
|
secret.array[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
|
|
SHA1_Init(&o_ctx);
|
|
SHA1_Update(&o_ctx, secret.array, secret.size);
|
|
SHA1_Update(&o_ctx, ipl2tp_avp_hmac_opad, 64 - secret.size);
|
|
|
|
|
|
/* Outer HMAC */
|
|
SHA1_Update(&o_ctx, digest, SHA_DIGEST_LENGTH);
|
|
SHA1_Final(digest, &o_ctx);
|
|
|
|
IPL2TP_SAFE_FREE(secret.array);
|
|
return IP_TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_protocol_version
|
|
*===========================================================================
|
|
* Description: Enter protocol version AVP.
|
|
* Parameters: cont - Message container
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_protocol_version(Ipl2tp_message *cont)
|
|
{
|
|
Ip_u8 avp_data[2];
|
|
|
|
/* Initialize the data */
|
|
avp_data[0] = IPL2TP_PROTOCOL_VER;
|
|
avp_data[1] = IPL2TP_PROTOCOL_REV;
|
|
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_PROTOCOL_VERSION,
|
|
IPL2TP_AVP_FLAG_MANDATORY,
|
|
avp_data,
|
|
2);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_assigned_tunnel_id
|
|
*===========================================================================
|
|
* Description: Set assigned tunnel ID AVP.
|
|
* Parameters: cont - Message container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_assigned_tunnel_id(Ipl2tp_message *cont,
|
|
Ipl2tp_ident value)
|
|
{
|
|
Ip_u16 avp_value = ip_htons((Ip_u16)value);
|
|
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_ASSIGNED_TUNNEL_ID,
|
|
IPL2TP_AVP_FLAG_MANDATORY | IPL2TP_AVP_FLAG_HIDDEN,
|
|
&avp_value,
|
|
2);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_host_name
|
|
*===========================================================================
|
|
* Description: Enter host name AVP.
|
|
* Parameters: cont - Message container
|
|
* value - The value.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_host_name(Ipl2tp_message *cont,
|
|
CONST char *value)
|
|
{
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_HOST_NAME,
|
|
IPL2TP_AVP_FLAG_MANDATORY,
|
|
(void *)value,
|
|
(Ip_u16)(ipcom_strlen(value) + 1));
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_framing_capabilities
|
|
*===========================================================================
|
|
* Description: Enter framing capabilities AVP.
|
|
* Parameters: cont - Message container
|
|
* value - The framing capabilities
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_framing_capabilities(Ipl2tp_message *cont,
|
|
Ip_u32 value)
|
|
{
|
|
Ip_u32 bits = ip_htonl(ipl2tp_pw_framing2bits(value));
|
|
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_FRAMING_CAPABILITIES,
|
|
IPL2TP_AVP_FLAG_MANDATORY | IPL2TP_AVP_FLAG_HIDDEN,
|
|
&bits,
|
|
4);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_message_type
|
|
*===========================================================================
|
|
* Description: Enter message type AVP.
|
|
* Parameters: cont - Message container
|
|
* value - AVP Type
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_message_type(Ipl2tp_message *cont,
|
|
Ip_u16 value)
|
|
{
|
|
value = ip_htons(value);
|
|
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_MESSAGE_TYPE,
|
|
IPL2TP_AVP_FLAG_MANDATORY,
|
|
&value,
|
|
2);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_bearer_capabilities
|
|
*===========================================================================
|
|
* Description: Enter bearer capabilities AVP.
|
|
* Parameters: cont - Message container
|
|
* value - Bearer capabilities
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_bearer_capabilities(Ipl2tp_message *cont,
|
|
Ip_u32 value)
|
|
{
|
|
Ip_u32 bits = ip_htonl(ipl2tp_pw_bearer2bits(value));
|
|
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_BEARER_CAPABILITIES,
|
|
IPL2TP_AVP_FLAG_MANDATORY | IPL2TP_AVP_FLAG_HIDDEN,
|
|
&bits,
|
|
4);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_receive_window_size
|
|
*===========================================================================
|
|
* Description: Enter receive window size AVP.
|
|
* Parameters: cont - The message container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_receive_window_size(Ipl2tp_message *cont,
|
|
Ip_u16 value)
|
|
{
|
|
value = ip_htons(value);
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_RECEIVE_WINDOW_SIZE,
|
|
IPL2TP_AVP_FLAG_MANDATORY | IPL2TP_AVP_FLAG_HIDDEN,
|
|
&value,
|
|
2);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_challenge
|
|
*===========================================================================
|
|
* Description: Enter challenge AVP.
|
|
* Parameters: cont - Message container
|
|
* vec - The vector
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_challenge(Ipl2tp_message *cont,
|
|
Ipl2tp_vector *vec)
|
|
{
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_CHALLENGE,
|
|
IPL2TP_AVP_FLAG_MANDATORY | IPL2TP_AVP_FLAG_HIDDEN,
|
|
vec->array,
|
|
vec->size);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_firmware_revision
|
|
*===========================================================================
|
|
* Description: Enter firmware revision AVP.
|
|
* Parameters: cont - The message container
|
|
* value - The firmware revision.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_firmware_revision(Ipl2tp_message *cont,
|
|
Ip_u16 value)
|
|
{
|
|
value = ip_htons(value);
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_FIRMWARE_REVISION,
|
|
IPL2TP_AVP_FLAG_HIDDEN,
|
|
&value,
|
|
2);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_vendor_name
|
|
*===========================================================================
|
|
* Description: Enter vendor name AVP.
|
|
* Parameters: cont - Message container
|
|
* value - vendor name string
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_vendor_name(Ipl2tp_message *cont,
|
|
CONST char *value)
|
|
{
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_VENDOR_NAME,
|
|
IPL2TP_AVP_FLAG_HIDDEN,
|
|
(void *)value,
|
|
(Ip_u16)(ipcom_strlen(value) + 1));
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_tie_breaker
|
|
*===========================================================================
|
|
* Description: Enter tie breaker AVP.
|
|
* Parameters: cont - Message container
|
|
* vec - Data.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_tie_breaker(Ipl2tp_message *cont,
|
|
Ipl2tp_vector *vec)
|
|
{
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_TIE_BREAKER,
|
|
IPL2TP_AVP_FLAG_NONE,
|
|
vec->array,
|
|
vec->size);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_result_code
|
|
*===========================================================================
|
|
* Description: Set result code.
|
|
* Parameters: cont - Message container
|
|
* result_code - The result code
|
|
* error_code - The error code
|
|
* error_message - The error message
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_result_code(Ipl2tp_message *cont,
|
|
Ip_u16 result_code,
|
|
Ip_u16 error_code,
|
|
CONST char *error_message)
|
|
{
|
|
Ipl2tp_avp_message_header avp_hdr;
|
|
struct Ip_iovec avp_iovec[3];
|
|
Ip_u16 i = 0;
|
|
|
|
/* Initialize the AVP header */
|
|
IPL2TP_AVP_INITIALIZE(&avp_hdr,
|
|
IPL2TP_AVP_RESULT_CODE,
|
|
IPL2TP_AVP_FLAG_MANDATORY);
|
|
|
|
/* Prepare the data */
|
|
result_code = ip_htons(result_code);
|
|
|
|
/* Setup the io vector */
|
|
avp_iovec[i].iov_base = &result_code;
|
|
avp_iovec[i].iov_len = 2;
|
|
i++;
|
|
|
|
if (error_code || error_message != IP_NULL)
|
|
{
|
|
error_code = ip_htons(error_code);
|
|
|
|
avp_iovec[i].iov_base = &error_code;
|
|
avp_iovec[i].iov_len = 2;
|
|
i++;
|
|
|
|
if (error_message != IP_NULL)
|
|
{
|
|
avp_iovec[i].iov_base = (void *)error_message;
|
|
avp_iovec[i].iov_len = ipcom_strlen(error_message) + 1;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
/* Update the AVP. */
|
|
ipl2tp_avp_update(cont, &avp_hdr, avp_iovec, i);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_challenge_response
|
|
*===========================================================================
|
|
* Description: Enter challenge response AVP.
|
|
* Parameters: cont - Pointer to message.
|
|
* value - Pointer to 16 byte challenge repsonse
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_challenge_response(Ipl2tp_message *cont,
|
|
Ipl2tp_vector *value)
|
|
{
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_CHALLENGE_RESPONSE,
|
|
IPL2TP_AVP_FLAG_MANDATORY | IPL2TP_AVP_FLAG_HIDDEN,
|
|
value->array,
|
|
value->size);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_assigned_session_id
|
|
*===========================================================================
|
|
* Description: Enter assigned session ID AVP.
|
|
* Parameters: cont - Message container
|
|
* value - assigned session id
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_assigned_session_id(Ipl2tp_message *cont,
|
|
Ipl2tp_ident value)
|
|
{
|
|
Ip_u16 v16 = ip_htons((Ip_u16)value);
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_ASSIGNED_SESSION_ID,
|
|
IPL2TP_AVP_FLAG_MANDATORY | IPL2TP_AVP_FLAG_HIDDEN,
|
|
&v16,
|
|
2);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_call_serial_number
|
|
*===========================================================================
|
|
* Description: Enter call serial number AVP.
|
|
* Parameters: cont - The message container
|
|
* value - The value.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_call_serial_number(Ipl2tp_message *cont,
|
|
Ip_u32 value)
|
|
{
|
|
value = ip_htonl(value);
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_CALL_SERIAL_NUMBER,
|
|
IPL2TP_AVP_FLAG_MANDATORY | IPL2TP_AVP_FLAG_HIDDEN,
|
|
&value,
|
|
4);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_called_number
|
|
*===========================================================================
|
|
* Description: Enter called number AVP.
|
|
* Parameters: cont - The message container
|
|
* value - The value.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_called_number(Ipl2tp_message *cont,
|
|
CONST char *value)
|
|
{
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_CALLED_NUMBER,
|
|
IPL2TP_AVP_FLAG_MANDATORY | IPL2TP_AVP_FLAG_HIDDEN,
|
|
(void *)value,
|
|
(Ip_u16)(ipcom_strlen(value) + 1));
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_calling_number
|
|
*===========================================================================
|
|
* Description: Enter calling number AVP.
|
|
* Parameters: cont - Message container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_calling_number(Ipl2tp_message *cont,
|
|
CONST char *value)
|
|
{
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_CALLING_NUMBER,
|
|
IPL2TP_AVP_FLAG_MANDATORY | IPL2TP_AVP_FLAG_HIDDEN,
|
|
(void *)value,
|
|
(Ip_u16)(ipcom_strlen(value) + 1));
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_physical_channel_id
|
|
*===========================================================================
|
|
* Description: Enter physical channel ID AVP.
|
|
* Parameters: cont - The container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_physical_channel_id(Ipl2tp_message *cont,
|
|
Ip_u32 value)
|
|
{
|
|
value = ip_htonl(value);
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_PHYSICAL_CHANNEL_ID,
|
|
IPL2TP_AVP_FLAG_HIDDEN,
|
|
&value,
|
|
4);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_sub_address
|
|
*===========================================================================
|
|
* Description: Enter sub address AVP.
|
|
* Parameters: cont - The message container
|
|
* value - The value.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_sub_address(Ipl2tp_message *cont,
|
|
CONST char *value)
|
|
{
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_SUB_ADDRESS,
|
|
IPL2TP_AVP_FLAG_MANDATORY | IPL2TP_AVP_FLAG_HIDDEN,
|
|
(void *)value,
|
|
(Ip_u16)(ipcom_strlen(value) + 1));
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_framing_type
|
|
*===========================================================================
|
|
* Description: Enter framing type AVP.
|
|
* Parameters: cont - Container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_framing_type(Ipl2tp_message *cont,
|
|
Ip_u32 value)
|
|
{
|
|
Ip_u32 bits = ip_htonl(ipl2tp_pw_framing2bits(value));
|
|
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_FRAMING_TYPE,
|
|
IPL2TP_AVP_FLAG_MANDATORY | IPL2TP_AVP_FLAG_HIDDEN,
|
|
&bits,
|
|
4);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_tx_connect_speed
|
|
*===========================================================================
|
|
* Description: Enter Tx connect speed AVP.
|
|
* Parameters: cont - Container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_tx_connect_speed(Ipl2tp_message *cont,
|
|
Ip_u32 value)
|
|
{
|
|
value = ip_htonl(value);
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_TX_CONNECT_SPEED,
|
|
IPL2TP_AVP_FLAG_MANDATORY | IPL2TP_AVP_FLAG_HIDDEN,
|
|
&value,
|
|
4);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_private_group_id
|
|
*===========================================================================
|
|
* Description: Enter private group ID AVP.
|
|
* Parameters: cont - Container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_private_group_id(Ipl2tp_message *cont,
|
|
CONST char *value)
|
|
{
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_PRIVATE_GROUP_ID,
|
|
IPL2TP_AVP_FLAG_HIDDEN,
|
|
(void *)value,
|
|
(Ip_u16)(ipcom_strlen(value) + 1));
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_rx_connect_speed
|
|
*===========================================================================
|
|
* Description: Enter Rx connect speed AVP.
|
|
* Parameters: cont - Container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_rx_connect_speed(Ipl2tp_message *cont,
|
|
Ip_u32 value)
|
|
{
|
|
value = ip_htonl(value);
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_RX_CONNECT_SPEED,
|
|
IPL2TP_AVP_FLAG_HIDDEN,
|
|
&value,
|
|
4);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_sequencing_required
|
|
*===========================================================================
|
|
* Description: Enter sequencing required AVP.
|
|
* Parameters: cont - Container
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_sequencing_required(Ipl2tp_message *cont)
|
|
{
|
|
Ipl2tp_avp_message_header avp_hdr;
|
|
|
|
/* Initialize the AVP header */
|
|
IPL2TP_AVP_INITIALIZE(&avp_hdr,
|
|
IPL2TP_AVP_SEQUENCING_REQUIRED,
|
|
IPL2TP_AVP_FLAG_MANDATORY);
|
|
|
|
/* Update the AVP. */
|
|
ipl2tp_avp_update(cont, &avp_hdr, IP_NULL, 0);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_bearer_type
|
|
*===========================================================================
|
|
* Description: Enter bearer type AVP.
|
|
* Parameters: cont - Container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_bearer_type(Ipl2tp_message *cont,
|
|
Ip_u32 value)
|
|
{
|
|
Ip_u32 bits = ip_htonl(ipl2tp_pw_bearer2bits(value));
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_BEARER_TYPE,
|
|
IPL2TP_AVP_FLAG_MANDATORY | IPL2TP_AVP_FLAG_HIDDEN,
|
|
&bits,
|
|
4);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_initial_received_lcp_confreq
|
|
*===========================================================================
|
|
* Description: Enter initial received CONFREQ AVP.
|
|
* Parameters: cont - Container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_initial_received_lcp_confreq(Ipl2tp_message *cont,
|
|
CONST Ipl2tp_vector *value)
|
|
{
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_INITIAL_RECEIVED_LCP_CONFREQ,
|
|
IPL2TP_AVP_FLAG_HIDDEN,
|
|
value->array,
|
|
(Ip_u16) (value->size));
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_last_sent_lcp_confreq
|
|
*===========================================================================
|
|
* Description: Enter last sent CONFREQ AVP.
|
|
* Parameters: cont - Container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_last_sent_lcp_confreq(Ipl2tp_message *cont,
|
|
CONST Ipl2tp_vector *value)
|
|
{
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_LAST_SENT_LCP_CONFREQ,
|
|
IPL2TP_AVP_FLAG_HIDDEN,
|
|
value->array,
|
|
(Ip_u16) (value->size));
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_last_received_lcp_confreq
|
|
*===========================================================================
|
|
* Description: Enter last received CONFREQ AVP.
|
|
* Parameters: cont - Container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_last_received_lcp_confreq(Ipl2tp_message *cont,
|
|
CONST Ipl2tp_vector *value)
|
|
{
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_LAST_RECEIVED_LCP_CONFREQ,
|
|
IPL2TP_AVP_FLAG_HIDDEN,
|
|
value->array,
|
|
(Ip_u16) (value->size));
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_proxy_authen_type
|
|
*===========================================================================
|
|
* Description: Enter proxy authen type AVP.
|
|
* Parameters: cont - Container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_proxy_authen_type(Ipl2tp_message *cont,
|
|
Ip_u16 value)
|
|
{
|
|
value = ip_htons(value);
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_PROXY_AUTHEN_TYPE,
|
|
IPL2TP_AVP_FLAG_HIDDEN,
|
|
&value,
|
|
2);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_proxy_authen_name
|
|
*===========================================================================
|
|
* Description: Enter proxy authen name AVP.
|
|
* Parameters: cont - Container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_proxy_authen_name(Ipl2tp_message *cont,
|
|
CONST char *value)
|
|
{
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_PROXY_AUTHEN_NAME,
|
|
IPL2TP_AVP_FLAG_HIDDEN,
|
|
(void *)value,
|
|
(Ip_u16)(ipcom_strlen(value) + 1));
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_proxy_authen_challenge
|
|
*===========================================================================
|
|
* Description: Enter proxy authen challenge AVP.
|
|
* Parameters: cont - Container
|
|
* vec - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_proxy_authen_challenge(Ipl2tp_message *cont,
|
|
Ipl2tp_vector *vec)
|
|
{
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_PROXY_AUTHEN_CHALLENGE,
|
|
IPL2TP_AVP_FLAG_HIDDEN,
|
|
vec->array,
|
|
vec->size);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_proxy_authen_id
|
|
*===========================================================================
|
|
* Description: Enter proxy authen id AVP.
|
|
* Parameters: cont - Container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_proxy_authen_id(Ipl2tp_message *cont,
|
|
Ip_u16 value)
|
|
{
|
|
value = ip_htons(value);
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_PROXY_AUTHEN_ID,
|
|
IPL2TP_AVP_FLAG_HIDDEN,
|
|
&value,
|
|
2);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_proxy_authen_response
|
|
*===========================================================================
|
|
* Description: Enter proxy authen response AVP.
|
|
* Parameters: cont - Container
|
|
* vec - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_proxy_authen_response(Ipl2tp_message *cont,
|
|
Ipl2tp_vector *vec)
|
|
{
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_PROXY_AUTHEN_RESPONSE,
|
|
IPL2TP_AVP_FLAG_HIDDEN,
|
|
vec->array,
|
|
vec->size);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_digest
|
|
*===========================================================================
|
|
* Description: Set the digest.
|
|
* Parameters: cont - The message container
|
|
* type - Type of digest.
|
|
* hs - V2/V3 discovery?
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_digest(Ipl2tp_message *cont,
|
|
Ip_u8 type,
|
|
Ip_bool hs)
|
|
{
|
|
char buf[32];
|
|
Ip_u16 flags = IPL2TP_AVP_HANDSHAKE(hs, IPL2TP_AVP_FLAG_NONE);
|
|
Ip_u16 size = 1;
|
|
|
|
|
|
switch (type)
|
|
{
|
|
case IPL2TP_MIB_AUTH_MD5: /* MD5 */
|
|
size += MD5_DIGEST_LENGTH;
|
|
break;
|
|
case IPL2TP_MIB_AUTH_SHA:
|
|
size += SHA_DIGEST_LENGTH;
|
|
break;
|
|
default:
|
|
/* Unknown digest type */
|
|
return;
|
|
}
|
|
|
|
/* The digest must be 0 during hash */
|
|
ipcom_memset(buf, 0, size);
|
|
|
|
/* Store the buffer */
|
|
buf[0] = type;
|
|
|
|
/* Store the digest */
|
|
cont->admin.digest = ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_MESSAGE_DIGEST,
|
|
flags,
|
|
buf,
|
|
size);
|
|
/* Skip the one byte type */
|
|
cont->admin.digest = (Ip_u8 *)cont->admin.digest + 1;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_control_message_auth_nonce
|
|
*===========================================================================
|
|
* Description: Add the control message authentication nonce
|
|
* Parameters: cont - The message container
|
|
* vec - Nonce
|
|
* hs - Handshake attempt?
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_control_message_auth_nonce(Ipl2tp_message *cont,
|
|
Ipl2tp_vector *vec,
|
|
Ip_bool hs)
|
|
{
|
|
Ip_u16 flags = IPL2TP_AVP_HANDSHAKE(hs, IPL2TP_AVP_FLAG_NONE);
|
|
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_CONTROL_MESSAGE_AUTH_NONCE,
|
|
flags,
|
|
vec->array,
|
|
vec->size);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_router_id
|
|
*===========================================================================
|
|
* Description: Set the router identifier
|
|
* Parameters: cont - The message container
|
|
* value - The value
|
|
* hs - Is this a handshake attempt.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_router_id(Ipl2tp_message *cont,
|
|
Ip_u32 value,
|
|
Ip_bool hs)
|
|
{
|
|
Ip_u16 flags = IPL2TP_AVP_HANDSHAKE(hs, IPL2TP_AVP_FLAG_NONE);
|
|
value = ip_htonl(value);
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_ROUTER_ID,
|
|
flags,
|
|
&value,
|
|
4);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_assigned_control_connection_id
|
|
*===========================================================================
|
|
* Description: Set the assigned control connection identifier
|
|
* Parameters: cont - The message container
|
|
* value - The value
|
|
* hs - Is this a handshake attempt.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_assigned_control_connection_id(Ipl2tp_message *cont,
|
|
Ip_u32 value,
|
|
Ip_bool hs)
|
|
{
|
|
Ip_u16 flags = IPL2TP_AVP_HANDSHAKE(hs, IPL2TP_AVP_FLAG_HIDDEN);
|
|
value = ip_htonl(value);
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_ASSIGNED_CONTROL_CONNECTION_ID,
|
|
flags,
|
|
&value,
|
|
4);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_pseudowire_capabilities_list
|
|
*===========================================================================
|
|
* Description: Set the pseudowire capabilities AVP
|
|
* Parameters: cont - The message container
|
|
* vec - The value array
|
|
* hs - Is this a handshake attempt.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_pseudowire_capabilities_list(Ipl2tp_message *cont,
|
|
Ipl2tp_vector *vec,
|
|
Ip_bool hs)
|
|
{
|
|
Ip_u16 flags = IPL2TP_AVP_HANDSHAKE(hs, IPL2TP_AVP_FLAG_HIDDEN);
|
|
Ip_u16 pw[8];
|
|
Ip_u16 *pw_orig = (Ip_u16 *)vec->array;
|
|
Ip_size_t i;
|
|
|
|
/* Create a network byte order list */
|
|
for (i = 0; i < vec->size / 2; i++)
|
|
{
|
|
pw[i] = ip_htons(pw_orig[i]);
|
|
}
|
|
|
|
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_PSEUDOWIRE_CAPABILITIES_LIST,
|
|
flags,
|
|
pw,
|
|
vec->size);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_preferred_language
|
|
*===========================================================================
|
|
* Description: Set the preferred language AVP
|
|
* Parameters: cont - Container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_preferred_language(Ipl2tp_message *cont,
|
|
CONST char *value)
|
|
{
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_PREFERRED_LANGUAGE,
|
|
IPL2TP_AVP_FLAG_HIDDEN,
|
|
(void *)value,
|
|
(Ip_u16)(ipcom_strlen(value) + 1));
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_local_session_id
|
|
*===========================================================================
|
|
* Description: Set the local session id
|
|
* Parameters: cont - The message container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_local_session_id(Ipl2tp_message *cont,
|
|
Ip_u32 value)
|
|
{
|
|
value = ip_htonl(value);
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_LOCAL_SESSION_ID,
|
|
IPL2TP_AVP_FLAG_MANDATORY|IPL2TP_AVP_FLAG_HIDDEN,
|
|
&value,
|
|
4);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_remote_session_id
|
|
*===========================================================================
|
|
* Description: Set the remote session id
|
|
* Parameters: cont - The message container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_remote_session_id(Ipl2tp_message *cont,
|
|
Ip_u32 value)
|
|
{
|
|
value = ip_htonl(value);
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_REMOTE_SESSION_ID,
|
|
IPL2TP_AVP_FLAG_MANDATORY|IPL2TP_AVP_FLAG_HIDDEN,
|
|
&value,
|
|
4);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_remote_end_id
|
|
*===========================================================================
|
|
* Description: Set the remote end id
|
|
* Parameters: cont - The message container
|
|
* vec - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_remote_end_id(Ipl2tp_message *cont,
|
|
Ipl2tp_vector *vec)
|
|
{
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_REMOTE_END_ID,
|
|
IPL2TP_AVP_FLAG_MANDATORY|IPL2TP_AVP_FLAG_HIDDEN,
|
|
vec->array,
|
|
vec->size);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_pseudowire_type
|
|
*===========================================================================
|
|
* Description: Set the pseudowire type
|
|
* Parameters: cont - The message container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_pseudowire_type(Ipl2tp_message *cont,
|
|
Ip_u16 value)
|
|
{
|
|
value = ip_htons(value);
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_PSEUDOWIRE_TYPE,
|
|
IPL2TP_AVP_FLAG_MANDATORY|IPL2TP_AVP_FLAG_HIDDEN,
|
|
&value,
|
|
2);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_circuit_status
|
|
*===========================================================================
|
|
* Description: Set the circuit status
|
|
* Parameters: cont - The message container
|
|
* value - The value
|
|
* first - First circuit value.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_circuit_status(Ipl2tp_message *cont,
|
|
Ip_u16 value,
|
|
Ip_bool first)
|
|
{
|
|
if (value == IPL2TP_MIB_UP)
|
|
value = IPL2TP_ATTR_CIRCUIT_STATUS_ACTIVE;
|
|
else
|
|
value = 0;
|
|
|
|
/* */
|
|
if (first)
|
|
value |= IPL2TP_ATTR_CIRCUIT_STATUS_NEW;
|
|
|
|
/**/
|
|
value = ip_htons(value);
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_CIRCUIT_STATUS,
|
|
IPL2TP_AVP_FLAG_MANDATORY|IPL2TP_AVP_FLAG_HIDDEN,
|
|
&value,
|
|
2);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_assigned_cookie
|
|
*===========================================================================
|
|
* Description: Set the assigned cookie
|
|
* Parameters: cont - The message container
|
|
* vec - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_assigned_cookie(Ipl2tp_message *cont,
|
|
Ipl2tp_vector *vec)
|
|
{
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_ASSIGNED_COOKIE,
|
|
IPL2TP_AVP_FLAG_MANDATORY|IPL2TP_AVP_FLAG_HIDDEN,
|
|
vec->array,
|
|
vec->size);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_data_sequencing
|
|
*===========================================================================
|
|
* Description: Set the data sequencing mode.
|
|
* Parameters: cont - The message container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_data_sequencing(Ipl2tp_message *cont,
|
|
Ip_u16 value)
|
|
{
|
|
value = ip_htons(value);
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_DATA_SEQUENCING,
|
|
IPL2TP_AVP_FLAG_MANDATORY|IPL2TP_AVP_FLAG_HIDDEN,
|
|
&value,
|
|
2);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_l2_sublayer
|
|
*===========================================================================
|
|
* Description: Set the L2 sublayer
|
|
* Parameters: cont - The message container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_l2_sublayer(Ipl2tp_message *cont,
|
|
Ip_u16 value)
|
|
{
|
|
value = ip_htons(value);
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_L2_SPECIFIC_SUBLAYER,
|
|
IPL2TP_AVP_FLAG_MANDATORY|IPL2TP_AVP_FLAG_HIDDEN,
|
|
&value,
|
|
2);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_tx_connect_speed64
|
|
*===========================================================================
|
|
* Description: Set the 64 bit TX connect speed
|
|
* Parameters: cont - The message container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_tx_connect_speed64(Ipl2tp_message *cont,
|
|
Ip_u64 *value)
|
|
{
|
|
Ip_u8 data[8];
|
|
|
|
IP_SET_HTONL(data, IP_U64_GETHI(*value));
|
|
IP_SET_HTONL(data + 4, IP_U64_GETLO(*value));
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_TX_CONNECT_SPEED64,
|
|
IPL2TP_AVP_FLAG_HIDDEN,
|
|
data,
|
|
8);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_rx_connect_speed64
|
|
*===========================================================================
|
|
* Description: Set the 64 bit RX connect speed
|
|
* Parameters: cont - The message container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_rx_connect_speed64(Ipl2tp_message *cont,
|
|
Ip_u64 *value)
|
|
{
|
|
Ip_u8 data[8];
|
|
|
|
IP_SET_HTONL(data, IP_U64_GETHI(*value));
|
|
IP_SET_HTONL(data + 4, IP_U64_GETLO(*value));
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_RX_CONNECT_SPEED64,
|
|
IPL2TP_AVP_FLAG_HIDDEN,
|
|
data,
|
|
8);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_minimum_bps
|
|
*===========================================================================
|
|
* Description: Set the minimum bps value.
|
|
* Parameters: cont - The message container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_minimum_bps(struct Ipl2tp_message *cont,
|
|
Ip_u32 value)
|
|
{
|
|
value = ip_htonl(value);
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_MINIMUM_BPS,
|
|
IPL2TP_AVP_FLAG_MANDATORY|IPL2TP_AVP_FLAG_HIDDEN,
|
|
&value,
|
|
4);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipl2tp_avp_set_maximum_bps
|
|
*===========================================================================
|
|
* Description: Set the maximum bps value.
|
|
* Parameters: cont - The message container
|
|
* value - The value
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipl2tp_avp_set_maximum_bps(struct Ipl2tp_message *cont,
|
|
Ip_u32 value)
|
|
{
|
|
value = ip_htonl(value);
|
|
ipl2tp_avp_set(cont,
|
|
IPL2TP_AVP_MAXIMUM_BPS,
|
|
IPL2TP_AVP_FLAG_MANDATORY|IPL2TP_AVP_FLAG_HIDDEN,
|
|
&value,
|
|
4);
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|
|
|