/************************************************************************/ /* 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); }