Files
m241Neelima/components/ip_net2-6.9/ipl2tp/src/ipl2tp_avp.c
T
2026-07-30 11:19:44 +05:30

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
****************************************************************************
*/