Files
microser/mmslib/ositcps/cosp_dec.c
2026-06-15 15:48:16 +08:00

1091 lines
37 KiB
C

/************************************************************************/
/* SISCO SOFTWARE MODULE HEADER *****************************************/
/************************************************************************/
/* (c) Copyright Systems Integration Specialists Company, Inc., */
/* 1997 - 2003, All Rights Reserved */
/* */
/* PROPRIETARY AND CONFIDENTIAL */
/* */
/* MODULE NAME : cosp_dec.c */
/* PRODUCT(S) : MOSI Stack (over TP4) */
/* */
/* MODULE DESCRIPTION : */
/* This file implements the decoding of COSP SPDUs. */
/* */
/* For information see the: */
/* ISO 8326 "Information processing systems - Open Systems */
/* Interconnection - Basic connection oriented session service */
/* definition. */
/* ISO 8327 "Information processing systems - Open Systems */
/* Interconnection - Basic connection oriented session protocol */
/* specification. */
/* ISO 8327/ADD.2 (Draft for Version2). */
/* */
/* */
/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */
/* */
/* cosp_dec_cn_ac */
/* cosp_dec_rf */
/* cosp_dec_fn_dn */
/* cosp_dec_ab */
/* cosp_dec_dt */
/* */
/* MODIFICATION LOG : */
/* Date Who Rev Comments */
/* -------- --- ------ ------------------------------------------- */
/* 08/19/03 EJV 08 Allow for ACCEPT User Data <= COSP_MAX_UDATA*/
/* 06/05/02 JRB 07 Allow Called SSEL=NULL on connect if */
/* configured SSEL=NULL. */
/* 04/26/01 EJV 06 Correction to version check in CN/AC. */
/* Corrected spelling. */
/* 09/13/99 MDE 05 Added SD_CONST modifiers */
/* 01/08/99 EJV 04 Added decoding of param 17 in FINISH SPDU. */
/* Make sure param 17 is extracted properly. */
/* 08/13/98 JRB 03 Lint cleanup. */
/* 05/27/97 JRB 7.00 MMSEASE 7.0 release. */
/* 03/20/97 EJV 02 Enhanced logging. */
/* 01/17/97 EJV 01 Created */
/************************************************************************/
#include "glbtypes.h"
#include "sysincs.h"
#ifdef DEBUG_SISCO
SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__; /* Define for SLOG mechanism */
#endif
#include "acse2.h"
#include "cosp_log.h"
#include "cosp.h"
#include "cosp_usr.h"
/*--------------------------------------*/
/* Local function prototypes */
/*--------------------------------------*/
static ST_UINT16 cosp_dec_len (ST_UCHAR *buf, ST_UINT *bytes);
static ST_RET cosp_validate_cn_ac (COSP_CN_AC *dec_par, ST_UCHAR spdu_type);
/************************************************************************/
/* cosp_dec_cn_ac */
/*----------------------------------------------------------------------*/
/* Function to decode a CONNECT or ACCEPT SPDU. */
/* Note if User Data are present in received SPDU then the length in the*/
/* dec_par->udata_len will be > 0. The dec_par->udata_ptr points into */
/* the spdu_buf (it is not an allocated pointer). */
/* */
/* Parameters: */
/* COSP_CN_AC *dec_par ptr to decoded parameters struct*/
/* char *spdu_buf Pointer to received SPDU buf */
/* ST_UINT spdu_len Length of received SPDU */
/* ST_UCHAR spdu_type SPDU type to decode (CN, AC) */
/* */
/* Return: */
/* SD_SUCCESS (0) if successful */
/* error code otherwise */
/************************************************************************/
ST_RET cosp_dec_cn_ac (COSP_CN_AC *dec_par, char *spdu_buf, ST_UINT spdu_len,
ST_UCHAR spdu_type)
{
ST_RET ret;
ST_UCHAR *dec_buf;
ST_UINT dec_len;
ST_UCHAR param_code;
ST_UINT param_len;
ST_UINT group_len;
ST_UINT len_bytes; /* number of bytes for encoded len (1 or 3) */
ST_UINT idx;
ret = SD_SUCCESS;
dec_buf = (ST_UCHAR *) spdu_buf;
dec_len = 0;
idx = 0;
/*-----------------------------------------------------*/
/* set defaults in case params are not present in SPDU */
/*-----------------------------------------------------*/
memset (dec_par, 0, sizeof (COSP_CN_AC));
dec_par->ver_num = COSP_VER1; /*!default ver is Version1 */
dec_par->ses_urequir [0]= 0x03; /* bits 9-16: 9 and 10 set */
dec_par->ses_urequir [1]= 0x49; /* bits 1-8: 1,4 and 7 set */
/* in addition memset is equivalent to following con params settings */
/* dec_par->prot_option = 0; rcv extended concatination not supported */
/* dec_par->initiator_tsdu_size = 0; SSDU segmenting from initiator not supported */
/* dec_par->responder_tsdu_size = 0; SSDU segmenting from responder not supported */
/* dec_par->loc_ssel [0] = 0; called SSEL is NULL */
/* dec_par->rem_ssel [0] = 0; calling SSEL is NULL */
/* dec_par->udata_len = 0; User Data length */
/* dec_par->udata_ptr = 0; User Data pointer (points into spdu_buf!) */
/* we will use the first while loop to avoid excesive nesting of if...else... */
while (SD_TRUE)
{
/* NOTE: we should never return back from bottom of the loop here!!! */
/* the decoded len should be comparable with spdu_len passed to this func */
dec_len = (ST_UINT) cosp_dec_len (&dec_buf [idx+1], &len_bytes);
if (dec_len + 1+len_bytes != spdu_len)
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR2 ("COSP-ERROR: Decoding CN/AC: invalid SPDU len=%u or decoded len=%u.",
spdu_len, dec_len + 1+len_bytes);
break;
}
idx += 1+len_bytes; /* 1 for SPDU code */
/* decode all connect parameters */
while (dec_len > 0)
{
param_code = dec_buf [idx];
param_len = (ST_UINT) cosp_dec_len (&dec_buf [idx+1], &len_bytes);
/* signal error if param_len is greater then decoding length left */
if (param_len + 1+len_bytes > dec_len)
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR2 ("COSP-ERROR: Decoding CN/AC: invalid parameter len=%u (length left to decode len=%u).",
param_len + 1+len_bytes, dec_len);
break;
}
dec_len -= 1+len_bytes;
idx += 1+len_bytes;
/* do not try to decode if param_len is 0 (param is empty) */
if (param_len == 0)
continue;
switch (param_code)
{
case 1: /* PGI - Connection Identifier group */
/* we will ignore this group (skip all decoding) */
break;
case 5: /* PGI - Connect/Accept Item group */
group_len = param_len;
while (group_len > 0)
{
param_code = dec_buf [idx];
param_len = (ST_UINT) cosp_dec_len (&dec_buf [idx+1], &len_bytes);
/* signal error if param_len is greater then decoding length left */
if (param_len + 1+len_bytes > group_len)
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR2 ("COSP-ERROR: Decoding CN/AC: invalid parameter len=%u (PGI-5 group length left to decode len=%u).",
param_len + 1+len_bytes, group_len);
break;
}
dec_len -= 1+len_bytes;
group_len -= 1+len_bytes;
idx += 1+len_bytes;
/* do not try to decode if param_len is 0 (param is empty) */
if (param_len == 0)
continue;
switch (param_code)
{
case 19: /* PI - Protocol Options */
if (param_len == 1)
dec_par->prot_option = dec_buf [idx];
else
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR1 ("COSP-ERROR: Decoding CN/AC: invalid PI-19 parameter len=%u (should be len=1).",
param_len);
}
break;
case 21: /* PI - TSDU Max Size */
if (param_len == 4)
{
dec_par->initiator_tsdu_size =
((ST_UINT16) dec_buf [idx] << 8) | (ST_UINT16) dec_buf [idx+1];
dec_par->responder_tsdu_size =
((ST_UINT16) dec_buf [idx+2] << 8) | (ST_UINT16) dec_buf [idx+3];
}
else
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR1 ("COSP-ERROR: Decoding CN/AC: invalid PI-21 parameter len=%u (should be len=4).",
param_len);
}
break;
case 22: /* PI - Version Number */
if (param_len == 1)
dec_par->ver_num = dec_buf [idx];
else
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR1 ("COSP-ERROR: Decoding CN/AC: invalid PI-22 parameter len=%u (should be len=1)",
param_len);
}
break;
case 23: /* PI - Initial Serial Number */
/* we will ignore this param (skip all decoding) */
break;
case 26: /* PI - Token Setting Item */
/* we will ignore this param (skip all decoding) */
break;
default:
ret = COSP_ERR_DEC_INV_PI_CODE;
COSP_LOG_ERR1 ("COSP-ERROR: Decoding CN/AC: invalid PI code=%d in PGI-5",
param_code);
} /* end of switch */
if (ret == SD_SUCCESS)
{
/* adjust processing vars by the length of param processed */
dec_len -= param_len;
group_len -= param_len;
idx += param_len;
}
else
break; /* error, exit this loop */
} /* end of while (group_len > 0) */
param_len = 0; /* dec_len & idx already adjusted */
break;
case 16: /* PI - Token Item */
if (spdu_type == COSP_SI_ACCEPT)
/* we will ignore this param (skip all decoding) */
;
else
{
ret = COSP_ERR_DEC_INV_PI_CODE;
COSP_LOG_ERR1 ("COSP-ERROR: Decoding CN/AC: invalid PI code=%d", param_code);
}
break;
case 20: /* PI - Session User Requirements param */
if (param_len == 2)
{
dec_par->ses_urequir [0]= dec_buf [idx]; /* bits 9-16 */
dec_par->ses_urequir [1]= dec_buf [idx+1]; /* bits 1-8 */
}
else
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR1 ("COSP-ERROR: Decoding CN/AC: invalid PI-20 parameter len=%u (should be len=2).",
param_len);
}
break;
case 51: /* PI - Calling Session Selector param */
if (param_len <= MAX_SSEL_LEN) /* 16 */
{
if (spdu_type == COSP_SI_CONNECT)
{
dec_par->rem_ssel [0] = (ST_UCHAR) param_len;
memcpy (&dec_par->rem_ssel [1], &dec_buf [idx], param_len);
}
else
{
/* if COSP_SI_ACCEPT then same as Calling in S-CONNECT */
dec_par->loc_ssel [0] = (ST_UCHAR) param_len;
memcpy (&dec_par->loc_ssel [1], &dec_buf [idx], param_len);
}
}
else
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR2 ("COSP-ERROR: Decoding CN/AC: invalid PI-51 parameter len=%u (should be len<=%u).",
param_len, MAX_SSEL_LEN);
}
break;
case 52: /* PI - Called(CN)/Responding(AC) Session Selector param */
if (param_len <= MAX_SSEL_LEN) /* 16 */
{
if (spdu_type == COSP_SI_CONNECT)
{
dec_par->loc_ssel [0] = (ST_UCHAR) param_len;
memcpy (&dec_par->loc_ssel [1], &dec_buf [idx], param_len);
}
else
{
/* if COSP_SI_ACCEPT then Responder SSEL */
dec_par->rem_ssel [0] = (ST_UCHAR) param_len;
memcpy (&dec_par->rem_ssel [1], &dec_buf [idx], param_len);
}
}
else
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR2 ("COSP-ERROR: Decoding CN/AC: invalid PI-52 parameter len=%u (should be len<=%u).",
param_len, MAX_SSEL_LEN);
}
break;
case 193: /* PGI - User Data - used only if len <=512 in CONNECT and */
/* len up to 65539 total SPDU size in ACCEPT (ISO 8327/DAD2) */
if ((spdu_type == COSP_SI_CONNECT && param_len <= 512) ||
(spdu_type == COSP_SI_ACCEPT && param_len <= COSP_MAX_UDATA))
{
dec_par->udata_len = param_len;
dec_par->udata_ptr = &dec_buf [idx];
}
else
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR2 ("COSP-ERROR: Decoding CN/AC: invalid PI-193 (User Data) parameter len=%u (max should be len<=%u).",
param_len, (spdu_type == COSP_SI_CONNECT) ? 512 : COSP_MAX_UDATA);
}
break;
case 194: /* PGI - Extended User Data - used if len>512 */
if (param_len <= COSP_MAX_UDATA_CON) /* and len<=10240 */
{
dec_par->udata_len = param_len;
dec_par->udata_ptr = &dec_buf [idx];
}
else
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR2 ("COSP-ERROR: Decoding CN/AC: invalid PI-194 (User Data) parameter len=%u (should be len<=%u).",
param_len, COSP_MAX_UDATA_CON);
}
break;
default:
ret = COSP_ERR_DEC_INV_PI_CODE;
COSP_LOG_ERR1 ("COSP-ERROR: Decoding CN/AC: invalid PI code=%d", param_code);
} /* end of switch */
/* adjust processing vars by the length of param processed */
if (ret == SD_SUCCESS)
{
dec_len -= param_len;
idx += param_len;
}
else
break;
} /* end while len to decode */
break; /* this is end of decoding, exit loop unconditionally */
} /* end of while (SD_TRUE) loop */
if (ret == SD_SUCCESS)
/* validate the received SPDU */
ret = cosp_validate_cn_ac (dec_par, spdu_type);
return (ret);
}
/************************************************************************/
/* cosp_dec_rf */
/*----------------------------------------------------------------------*/
/* Function to decode a REFUSE SPDU. */
/* Note if User Data are present in received SPDU then the length in the*/
/* dec_par->udata_len will be > 0. The dec_par->udata_ptr points into */
/* the spdu_buf (it is not an allocated pointer). */
/* */
/* Parameters: */
/* COSP_RF *dec_par ptr to decoded parameters struct*/
/* char *spdu_buf Pointer to received SPDU buf */
/* ST_UINT spdu_len Length of received SPDU */
/* */
/* Return: */
/* SD_SUCCESS (0) if successful */
/* error code otherwise */
/************************************************************************/
ST_RET cosp_dec_rf (COSP_RF *dec_par, char *spdu_buf, ST_UINT spdu_len)
{
ST_RET ret;
ST_UCHAR *dec_buf;
ST_UINT dec_len;
ST_UCHAR param_code;
ST_UINT param_len;
ST_UINT len_bytes; /* number of bytes for encoded len (1 or 3) */
ST_UINT idx;
ret = SD_SUCCESS;
dec_buf = (ST_UCHAR *) spdu_buf;
dec_len = 0;
idx = 0;
/*-----------------------------------------------------*/
/* set defaults in case params are not present in SPDU */
/*-----------------------------------------------------*/
memset (dec_par, 0, sizeof (COSP_RF));
dec_par->disconnect = 1; /* default disconnect transport */
dec_par->ver_num = COSP_VER1; /* default is Version1 */
dec_par->ses_urequir [0] = 0x03; /* bits 9-16: 9 and 10 set */
dec_par->ses_urequir [1] = 0x49; /* bits 1-8: 1,4 and 7 set */
/* in addition memset is equivalent to following con params settings */
/* dec_par->reason = 0; rejected by called SS (SS-user?)*/
/* dec_par->udata_len = 0; Length of User Data */
/* dec_par->udata_ptr = 0; Pointer to User Data (points into spdu_buf!) */
/* we will use the first while loop to avoid excesive nesting of if...else... */
while (SD_TRUE)
{
/* NOTE: we should never return back from bottom of the loop here!!! */
/* the decoded len should be comparable with spdu_len passed to this func */
dec_len = (ST_UINT) cosp_dec_len (&dec_buf [idx+1], &len_bytes);
if (dec_len + 1+len_bytes != spdu_len)
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR2 ("COSP-ERROR: Decoding RF: invalid SPDU len=%u or decoded len=%u.",
spdu_len, dec_len + 1+len_bytes);
break;
}
idx += 1+len_bytes; /* 1 for RF SPDU code */
/* decode all REFUSE parameters */
while (dec_len > 0)
{
param_code = dec_buf [idx];
param_len = (ST_UINT) cosp_dec_len (&dec_buf [idx+1], &len_bytes);
/* signal error if param_len is greater then decoding length left */
if (param_len + 1+len_bytes > dec_len)
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR2 ("COSP-ERROR: Decoding RF: invalid parameter len=%u (length left to decode len=%u).",
param_len + 1+len_bytes, dec_len);
break;
}
dec_len -= 1+len_bytes;
idx += 1+len_bytes;
/* do not try to decode if param_len is 0 (param is empty) */
if (param_len == 0)
continue;
switch (param_code)
{
case 1: /* PGI - Connection Identifier group */
/* we will ignore this group (skip all decoding) */
break;
case 17: /* PI - Transport Disconnect */
if (param_len == 1)
dec_par->disconnect = (ST_BOOLEAN)(dec_buf [idx] & 0x01);
else
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR1 ("COSP-ERROR: Decoding RF: invalid PI-17 parameter len=%u (should be len=1).",
param_len);
}
break;
case 20: /* PI - Session User Requirements param */
if (param_len == 2)
{
dec_par->ses_urequir [0]= dec_buf [idx]; /* bits 9-16 */
dec_par->ses_urequir [1]= dec_buf [idx+1]; /* bits 1-8 */
}
else
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR1 ("COSP-ERROR: Decoding RF: invalid PI-20 parameter len=%u (should be len=2).",
param_len);
}
break;
case 22: /* PI - Version Number */
if (param_len == 1)
dec_par->ver_num = dec_buf [idx];
else
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR1 ("COSP-ERROR: Decoding RF: invalid PI-22 parameter len=%u (should be len=1).",
param_len);
}
break;
case 50: /* PI - Reason Code param */
dec_par->reason = dec_buf [idx]; /* refuse reason code */
if (param_len > 1)
{
dec_par->udata_len = param_len-1;
dec_par->udata_ptr = &dec_buf [idx+1];
}
break;
default:
ret = COSP_ERR_DEC_INV_PI_CODE;
COSP_LOG_ERR1 ("COSP-ERROR: Decoding RF: invalid PI code=%d", param_code);
} /* end of switch */
/* adjust processing vars by the length of param processed */
if (ret == SD_SUCCESS)
{
dec_len -= param_len;
idx += param_len;
}
else
break;
} /* end while len to decode */
break; /* this is end of decoding, exit loop unconditionally */
} /* end of while (SD_TRUE) loop */
/* validate the received SPDU */
if (ret == SD_SUCCESS)
{
/* User Data may be present only if refuse reason=2 */
if (dec_par->reason != COSP_RF_REASON_U_REJECT)
if (dec_par->udata_len > 0)
{
ret = COSP_ERR_DEC_INV_RF_UDATA;
COSP_LOG_ERR1 ("COSP-ERROR: Decoding RF: User Data present (len=%u) when Refuse Reason!=2",
dec_par->udata_len);
}
}
return (ret);
}
/************************************************************************/
/* cosp_dec_fn_dn */
/*----------------------------------------------------------------------*/
/* Function to decode a FINISH or DISCONNECT SPDU. */
/* Note if User Data are present in received SPDU then the length in the*/
/* dec_par->udata_len will be > 0. The dec_par->udata_ptr points into */
/* the spdu_buf (it is not an allocated pointer). */
/* */
/* Parameters: */
/* COSP_FN_DN *dec_par Ptr to decoded parameters struct*/
/* char *spdu_buf Pointer to received SPDU buf */
/* ST_UINT spdu_len Length of received SPDU */
/* ST_UCHAR spdu_type SPDU type to decode (FN, DN) */
/* */
/* Return: */
/* SD_SUCCESS (0) if successful */
/* error code otherwise */
/************************************************************************/
ST_RET cosp_dec_fn_dn (COSP_FN_DN *dec_par, char *spdu_buf, ST_UINT spdu_len,
ST_UCHAR spdu_type)
{
ST_RET ret;
ST_UCHAR *dec_buf;
ST_UINT dec_len;
ST_UCHAR param_code;
ST_UINT param_len;
ST_UINT len_bytes; /* number of bytes for encoded len (1 or 3) */
ST_UINT idx;
ret = SD_SUCCESS;
dec_buf = (ST_UCHAR *) spdu_buf;
dec_len = 0;
idx = 0;
/*-----------------------------------------------------*/
/* set defaults in case params are not present in SPDU */
/*-----------------------------------------------------*/
memset (dec_par, 0, sizeof (COSP_FN_DN));
if (spdu_type == COSP_SI_FINISH)
dec_par->disconnect = 1; /* default disconnect transport */
/* in addition memset is equivalent to following con params settings */
/* dec_par->udata_len = 0; Length of User Data */
/* dec_par->udata_ptr = 0; Pointer to User Data (points into spdu_buf!) */
/* we will use the first while loop to avoid excesive nesting of if...else... */
while (SD_TRUE)
{
/* NOTE: we should never return back from bottom of the loop here!!! */
/* the decoded len should be comparable with spdu_len passed to this func */
dec_len = (ST_UINT) cosp_dec_len (&dec_buf [idx+1], &len_bytes);
if (dec_len + 1+len_bytes != spdu_len)
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR2 ("COSP-ERROR: Decoding FN/DN: invalid SPDU len=%u or decoded len=%u.",
spdu_len, dec_len + 1+len_bytes);
break;
}
idx += 1+len_bytes; /* 1 for FN/DN SPDU code */
/* decode all FINISH / DISCONNECT parameters */
while (dec_len > 0)
{
param_code = dec_buf [idx];
param_len = (ST_UINT) cosp_dec_len (&dec_buf [idx+1], &len_bytes);
/* signal error if param_len is greater then decoding length left */
if (param_len + 1+len_bytes > dec_len)
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR2 ("COSP-ERROR: Decoding FN/DN: invalid parameter len=%u (length left to decode len=%u).",
param_len + 1+len_bytes, dec_len);
break;
}
dec_len -= 1+len_bytes;
idx += 1+len_bytes;
/* do not try to decode if param_len is 0 (param is empty) */
if (param_len == 0)
continue;
switch (param_code)
{
case 17: /* PI - Transport Disconnect */
/* this param is valid only in FINISH SPDU */
if (spdu_type == COSP_SI_FINISH)
{
dec_par->disconnect = (ST_BOOLEAN)(dec_buf [idx] & 0x01);
if (dec_par->disconnect != 1)
{
/* we do NOT support reusing transport connection */
ret = COSP_ERR_DEC_INV_PI_CODE;
COSP_LOG_ERR1 ("COSP-ERROR: Decoding FN: PI code=%d (keep transport connection not supported)", param_code);
}
}
else
{
ret = COSP_ERR_DEC_INV_PI_CODE;
COSP_LOG_ERR1 ("COSP-ERROR: Decoding DN: invalid PI code=%d", param_code);
}
break;
case 193: /* PGI - User Data group */
dec_par->udata_len = param_len;
dec_par->udata_ptr = &dec_buf [idx];
break;
default:
ret = COSP_ERR_DEC_INV_PI_CODE;
COSP_LOG_ERR1 ("COSP-ERROR: Decoding FN/DN: invalid PI code=%d", param_code);
} /* end of switch */
/* adjust processing vars by the length of param processed */
if (ret == SD_SUCCESS)
{
dec_len -= param_len;
idx += param_len;
}
else
break;
} /* end while len to decode */
break; /* this is end of decoding, exit loop unconditionally */
} /* end of while (SD_TRUE) loop */
/* validate the received SPDU */
if (ret == SD_SUCCESS)
{
if (dec_par->udata_len == 0)
{
ret = COSP_ERR_INV_UDATA_LEN;
COSP_LOG_ERR0 ("COSP-ERROR: Decoding FN/DN: invalid User Data len=0");
}
}
return (ret);
}
/************************************************************************/
/* cosp_dec_ab */
/*----------------------------------------------------------------------*/
/* Function to decode an ABORT SPDU. */
/* Note if User Data are present in received SPDU then the length in the*/
/* dec_par->udata_len will be > 0. The dec_par->udata_ptr points into */
/* the spdu_buf (it is not an allocated pointer). */
/* */
/* Parameters: */
/* COSP_AB *dec_par Ptr to decoded parameters struct*/
/* char *spdu_buf Pointer to received SPDU buf */
/* ST_UINT spdu_len Length of received SPDU */
/* */
/* Return: */
/* SD_SUCCESS (0) if successful */
/* error code otherwise */
/************************************************************************/
ST_RET cosp_dec_ab (COSP_AB *dec_par, char *spdu_buf, ST_UINT spdu_len)
{
ST_RET ret;
ST_UCHAR *dec_buf;
ST_UINT dec_len;
ST_UCHAR param_code;
ST_UINT param_len;
ST_UINT len_bytes; /* number of bytes for encoded len (1 or 3) */
ST_UINT idx;
ret = SD_SUCCESS;
dec_buf = (ST_UCHAR *) spdu_buf;
dec_len = 0;
idx = 0;
/*-----------------------------------------------------*/
/* set defaults in case params are not present in SPDU */
/*-----------------------------------------------------*/
memset (dec_par, 0, sizeof (COSP_AB));
dec_par->disconnect = 1; /* default disconnect transport */
/* in addition memset is equivalent to following con params settings */
/* dec_par->reason = 0; undefined reason */
/* dec_par->reflect_par_len= 0; Len of implementation defined protocol err code*/
/* dec_par->reflect_par [9]= 0; Buf for implementation defined protocol err code*/
/* dec_par->udata_len = 0; Length of User Data */
/* dec_par->udata_ptr = 0; Pointer to User Data (points into spdu_buf!) */
/* we will use the first while loop to avoid excesive nesting of if...else... */
while (SD_TRUE)
{
/* NOTE: we should never return back from bottom of the loop here!!! */
/* the decoded len should be comparable with spdu_len passed to this func */
dec_len = (ST_UINT) cosp_dec_len (&dec_buf [idx+1], &len_bytes);
if (dec_len + 1+len_bytes != spdu_len)
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR2 ("COSP-ERROR: Decoding AB: invalid SPDU len=%u or decoded len=%u.",
spdu_len, dec_len + 1+len_bytes);
break;
}
idx += 1+len_bytes; /* 1 for AB SPDU code */
/* decode all ABORT parameters */
while (dec_len > 0)
{
param_code = dec_buf [idx];
param_len = (ST_UINT) cosp_dec_len (&dec_buf [idx+1], &len_bytes);
/* signal error if param_len is greater then decoding length left */
if (param_len + 1+len_bytes > dec_len)
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR2 ("COSP-ERROR: Decoding AB: invalid parameter len=%u (length left to decode len=%u).",
param_len + 1+len_bytes, dec_len);
break;
}
dec_len -= 1+len_bytes;
idx += 1+len_bytes;
/* do not try to decode if param_len is 0 (param is empty) */
if (param_len == 0)
continue;
switch (param_code)
{
case 17: /* PI - Transport Disconnect */
if (param_len == 1)
{
dec_par->disconnect = (ST_BOOLEAN) (dec_buf [idx] & 0x01);
dec_par->reason = (ST_UCHAR) (dec_buf [idx] & 0x1E);
}
else
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR1 ("COSP-ERROR: Decoding AB: invalid PI-17 parameter len=%u (should be len=1).",
param_len);
}
break;
case 49: /* PI - Reflect param */
if (param_len <= 9)
{
dec_par->reflect_par_len = param_len;
memcpy (dec_par->reflect_par, &dec_buf [idx], param_len);
}
else
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR1 ("COSP-ERROR: Decoding AB: invalid PI-49 parameter len=%u (should be len<=9).",
param_len);
}
break;
case 193: /* PGI - User Data group */
dec_par->udata_len = param_len;
dec_par->udata_ptr = &dec_buf [idx];
break;
default:
ret = COSP_ERR_DEC_INV_PI_CODE;
COSP_LOG_ERR1 ("COSP-ERROR: Decoding AB: invalid PI code=%d", param_code);
} /* end of switch */
/* adjust processing vars by the length of param processed */
if (ret == SD_SUCCESS)
{
dec_len -= param_len;
idx += param_len;
}
else
break;
} /* end while len to decode */
break; /* this is end of decoding, exit loop unconditionally */
} /* end of while (SD_TRUE) loop */
/* validate the received SPDU */
if (ret == SD_SUCCESS)
{
if (dec_par->reason == COSP_AB_REASON_PROT_ERROR)
if (dec_par->reflect_par_len == 0)
{
ret = COSP_ERR_DEC_INV_AB_RP;
COSP_LOG_ERR0 ("COSP-ERROR: Decoding AB: invalid Reflect Parameter len=0");
}
if (dec_par->reason == COSP_AB_REASON_USER_ABORT)
if (dec_par->udata_len == 0)
{
ret = COSP_ERR_INV_UDATA_LEN;
COSP_LOG_ERR0 ("COSP-ERROR: Decoding AB: invalid User Data len=0");
}
}
return (ret);
}
/************************************************************************/
/* cosp_dec_dt */
/*----------------------------------------------------------------------*/
/* Function to decode an DATA SPDU. */
/* Note if User Data are present in received SPDU then the length in the*/
/* dec_par->udata_len will be > 0. The dec_par->udata_ptr points into */
/* the spdu_buf (it is not an allocated pointer). */
/* */
/* Parameters: */
/* COSP_DT *dec_par Ptr to decoded parameters struct*/
/* char *spdu_buf Pointer to received SPDU buf */
/* ST_UINT spdu_len Length of received SPDU */
/* */
/* Return: */
/* SD_SUCCESS (0) if successful */
/* error code otherwise */
/************************************************************************/
ST_RET cosp_dec_dt (COSP_DT *dec_par, char *spdu_buf, ST_UINT spdu_len)
{
ST_RET ret;
ST_UCHAR *dec_buf;
ST_UINT dec_len;
ST_UINT len_bytes; /* number of bytes for encoded len (1 or 3) */
ST_UINT idx;
ret = SD_SUCCESS;
dec_buf = (ST_UCHAR *) spdu_buf;
dec_len = 0;
idx = 0;
/*-----------------------------------------------------*/
/* set defaults in case params are not present in SPDU */
/*-----------------------------------------------------*/
memset (dec_par, 0, sizeof (COSP_DT));
/* memset is equivalent to following con params settings */
/* dec_par->udata_len = 0; Length of User Data */
/* dec_par->udata_ptr = 0; Pointer to User Data (points into spdu_buf!) */
/*--------------------------------------------------------------------*/
/* the protocol calls for GIVE-TOKEN and DT SPDU to be concatinated */
/* even if we do not use the token mechanism. */
/*--------------------------------------------------------------------*/
dec_len = (ST_UINT) cosp_dec_len (&dec_buf [idx+1], &len_bytes);
if (dec_len == 0)
{
idx += 1+len_bytes;
/* token mechanism not used, decode DT */
if (dec_buf [idx] == COSP_SI_DATA)
{
/*------------------------------------------------------------*/
/* note that Enclosure Item PI should not be present because */
/* we do not support segmenting (see CONNECT) */
/*------------------------------------------------------------*/
/* get the params length, should be 0, we do not send/rcv any params in DT */
dec_len = (ST_UINT) cosp_dec_len (&dec_buf [idx+1], &len_bytes);
if (dec_len == 0)
{
idx += 1+len_bytes; /* 1 for DT SPDU code and 1 byte for params len LI */
dec_par->udata_len = spdu_len - (2 + 1+len_bytes);
dec_par->udata_ptr = &dec_buf [idx];
}
else
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR0 ("COSP-ERROR: Decoding DT: Decoding of parameters in DATA SPDU not supported.");
}
}
else
{
ret = COSP_ERR_DEC_INV_SPDU;
COSP_LOG_ERR1 ("COSP-ERROR: Decoding DT: Invalid SPDU code=%u detected after Token SPDU.",
(ST_UINT) dec_buf [idx]);
}
}
else
{
ret = COSP_ERR_DEC_INV_LEN;
COSP_LOG_ERR0 ("COSP-ERROR: Decoding DT: Parameters in Token SPDU not supported.");
}
return (ret);
}
/************************************************************************/
/* cosp_dec_len */
/*----------------------------------------------------------------------*/
/* Function to decode a parameter's length (8-bit or 16-bit value). */
/* */
/* Parameters: */
/* ST_UCHAR *buf Pointer to len in received SPDU buf */
/* ST_UINT *bytes Pointer where to return number of */
/* bytes for decoded field */
/* */
/* Return: */
/* ST_UINT16 the length of a parameter */
/************************************************************************/
static ST_UINT16 cosp_dec_len (ST_UCHAR *buf, ST_UINT *bytes)
{
ST_UINT16 len;
if (buf [0] == 0xFF)
{
/* len >254 high order byte low order byte */
len = ((ST_UINT16) buf [1] << 8) | (ST_UINT16) buf [2];
*bytes = 3;
}
else
{
/* len <=254 */
len = (ST_UINT16) buf [0];
*bytes = 1;
}
return (len);
}
/************************************************************************/
/* cosp_validate_cn_ac */
/*----------------------------------------------------------------------*/
/* Function to validate parameters in a CONNECT or ACCEPT SPDU. */
/* */
/* Parameters: */
/* COSP_CN_AC *dec_par ptr to decoded parameters struct*/
/* ST_UCHAR spdu_type SPDU type to validate (CN, AC) */
/* */
/* Return: */
/* SD_SUCCESS (0) if validation successful */
/* error code otherwise */
/************************************************************************/
static ST_RET cosp_validate_cn_ac (COSP_CN_AC *dec_par, ST_UCHAR spdu_type)
{
if (spdu_type == COSP_SI_CONNECT)
{
/* check if CONNECT SPDU is addressed to us */
if (memcmp (dec_par->loc_ssel, cosp_only_ssel, cosp_only_ssel [0]+1)!=0)
{
COSP_LOG_ERR1 ("COSP-ERROR: Decoding CN/AC: Invalid Called SSEL (len=%d).",
(ST_INT) dec_par->loc_ssel [0]);
COSP_LOG_ERRH((ST_INT) dec_par->loc_ssel [0], &dec_par->loc_ssel [1]);
return (COSP_ERR_DEC_INV_LOC_SSEL);
}
}
else
{
/* ACCEPT SPDU, check the local SSEL if present */
if (dec_par->loc_ssel [0] > 0)
{
if (dec_par->loc_ssel [0] != cosp_only_ssel [0] ||
memcmp (&dec_par->loc_ssel [1], &cosp_only_ssel [1], cosp_only_ssel [0])
!= 0)
{
COSP_LOG_ERR1 ("COSP-ERROR: Decoding CN/AC: Invalid Calling SSEL (len=%d).",
(ST_INT) dec_par->loc_ssel [0]);
COSP_LOG_ERRH((ST_INT) dec_par->loc_ssel [0], &dec_par->loc_ssel [1]);
return (COSP_ERR_DEC_INV_LOC_SSEL);
}
}
}
/* currently we support Version 2 of the Session Protocol */
if (spdu_type == COSP_SI_CONNECT)
{
/* CONNECT, check if one of choices is COSP_VER2 */
if ((dec_par->ver_num & COSP_VER2) == 0)
{
COSP_LOG_ERR2 ("COSP-ERROR: Decoding CN/AC: Session Protocol Version '%d' not supported (supported ver=%d).",
dec_par->ver_num, COSP_VER2);
return (COSP_ERR_DEC_INV_PROT_VER);
}
}
else
{
/* ACCEPT, make sure COSP_VER2 was accepted */
if (dec_par->ver_num != COSP_VER2)
{
COSP_LOG_ERR2 ("COSP-ERROR: Decoding CN/AC: Session Protocol Version '%d' not supported (supported ver=%d).",
dec_par->ver_num, COSP_VER2);
return (COSP_ERR_DEC_INV_PROT_VER);
}
}
/* make sure extended concatination is not set (we do not support it)*/
if (dec_par->prot_option != 0)
{
COSP_LOG_ERR0 ("COSP-ERROR: Decoding CN/AC: Extended Concatination not supported.");
return (COSP_ERR_DEC_INV_PROT_OPT);
}
/* make sure that segmenting of SSDUs was not specified */
if (dec_par->initiator_tsdu_size != 0 ||
dec_par->responder_tsdu_size != 0)
{
COSP_LOG_ERR0 ("COSP-ERROR: Decoding CN/AC: SSDUs segmenting not supported.");
return (COSP_ERR_DEC_INV_SEG);
}
if (spdu_type == COSP_SI_CONNECT)
{
/* we support only Duplex Functional Units, make sure it is available*/
if (!(dec_par->ses_urequir [1] & 0x02)) /* is bit2 set? */
{
COSP_LOG_ERR0 ("COSP-ERROR: Decoding CN/AC: Duplex Functional Unit not proposed (Session User Requirements).");
return (COSP_ERR_DEC_INV_FUN_UNITS);
}
}
else
{
/* ACCEPT, make sure only Duplex Functional Units (FU) has been selected */
if (dec_par->ses_urequir [0] != 0 || /* bits 9-16: must be 0 */
dec_par->ses_urequir [1] != 0x02) /* bits 1-8: bit2 set */
{
COSP_LOG_ERR0 ("COSP-ERROR: Decoding CN/AC: Only Duplex Functional Unit supported (Session User Requirements).");
return (COSP_ERR_DEC_INV_FUN_UNITS);
}
}
return (SD_SUCCESS);
}