/************************************************************************/ /* SISCO SOFTWARE MODULE HEADER *****************************************/ /************************************************************************/ /* (c) Copyright Systems Integration Specialists Company, Inc., */ /* 1996-2008, All Rights Reserved. */ /* */ /* PROPRIETARY AND CONFIDENTIAL */ /* */ /* MODULE NAME : tpx_dec.c */ /* PRODUCT(S) : Lean-T Stack */ /* */ /* MODULE DESCRIPTION : */ /* This module implements the decoding of the TPDUs. */ /* */ /* For information see the: */ /* ISO 8073 "Information processing systems - Open Systems */ /* Interconnections - Connection oriented transport protocol */ /* specification. */ /* */ /* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ /* */ /* tp_decode_nsdu */ /* */ /* MODIFICATION LOG : */ /* Date Who Rev Comments */ /* -------- --- ------ ------------------------------------------- */ /* 10/23/08 JRB 11 Add casts to fix warnings. */ /* 10/22/08 JRB 10 Add many length checks & return immediately */ /* on any error. */ /* Allow any class in CR, CC (caller checks it).*/ /* Chg decode of DC, DT variable part like others*/ /* Chg tp_decode_er to really decode ER TPDU. */ /* Delete tp_decode_rj (not used in TP0 or TP4) */ /* Fix byte order in logging of dst_ref, src_ref*/ /* 11/01/07 EJV 09 Chg TSAP to TSEL in slogs. */ /* tp_log_tsdu: added mutex. */ /* 08/29/00 JRB 08 Don't return error if checksum NOT received */ /* in DR or DC (maybe not negotiated yet). */ /* 04/25/00 JRB 07 Lint cleanup. */ /* 06/08/99 JRB 06 Chg src_ref, dst_ref logs to HEX. */ /* 08/13/98 JRB 05 Lint cleanup. */ /* 01/16/98 JRB 04 Chg unrecognixed param logs to "IND" logs. */ /* 12/04/97 JRB 03 Clarify casts. Log unrecognized params. */ /* 07/31/97 JRB 02 tp_decode_cx: pass default max_tpdu_len_enc */ /* as arg because TP0/RFC1006 and TP4 need */ /* different defaults. */ /* 07/31/97 JRB 01 Created. Moved all tp_decode_* functions */ /* from tp4_dec.c to here and changed arguments */ /* so TP0 can use them too. */ /************************************************************************/ #include "glbtypes.h" #include "sysincs.h" #include "checksum.h" #include "tp4.h" #include "tp4_encd.h" #include "tp4_log.h" #ifdef DEBUG_SISCO SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__; #endif /* local functions prototypes */ static ST_BOOLEAN tp_checksum_verified (ST_UCHAR *buf, ST_UINT16 buf_len, ST_UINT16 par_pos); /************************************************************************/ /* get_hdr_len */ /* Get the total length of the TPDU header. */ /************************************************************************/ static ST_UINT16 get_hdr_len (ST_UCHAR *pdu_ptr, ST_UINT16 pdu_len, ST_UINT16 min_len) { ST_UINT16 hdr_len; if (pdu_len < min_len) return (0); /* error */ /* First byte is always header len but doesn't include itself, so add 1.*/ hdr_len = (ST_UINT16) pdu_ptr[0] + 1; if (hdr_len < min_len || hdr_len > pdu_len) return (0); /* error */ return (hdr_len); } /************************************************************************/ /* get_next_param */ /* Must have at least 2 bytes to get param len. If 2 bytes available, */ /* get param len (2nd byte) and make sure it doesn't go past end of */ /* header. */ /* WARNING: Assumes (len_proc < hdr_len). Caller must check. */ /************************************************************************/ static TP_PAR *get_next_param (ST_UCHAR *pdu_ptr, ST_UINT16 len_proc, /* num bytes already processed */ ST_UINT16 hdr_len) /* num bytes in header */ { ST_UCHAR *cur_ptr; ST_UINT16 len_left; /* num bytes remaining in header */ /* len_proc < hdr_len, so this calc can't be messed up by underflow */ len_left = hdr_len - len_proc; cur_ptr = pdu_ptr + len_proc; if (len_left < 2 || (ST_UINT16) cur_ptr[1] + 2 > len_left) /* cur_ptr[1]=param len*/ return (NULL); return ((TP_PAR *) cur_ptr); } /************************************************************************/ /* tp_decode_cx */ /*----------------------------------------------------------------------*/ /* Function used to decode a received CR or CC TPDU. Because n_unitdata */ /* may contain multiple TPDUs, the offset parameter will tell us where */ /* the CR or CC TPDU starts in the data_buf (n_unitdata). */ /* */ /* NOTE: Default value of "max_tpdu_len_enc" is passed as arg because */ /* TP4 and TP0/RFC1006 need different defaults. */ /* */ /* Parameters: */ /* TPDU_CX *tpdu_cx_rx Struct to fill in with decoded info. */ /* ST_UCHAR *pdu_ptr Pointer to TPDU. */ /* ST_UINT16 pdu_len Len of TPDU. */ /* ST_UCHAR pdu_type TP_PDU_TYPE_CR or TP_PDU_TYPE_CC */ /* ST_UCHAR max_tpdu_len_enc Binary encoded Max TPDU len */ /* */ /* Return: */ /* ST_UINT16 Length of CR or CC TPDU. */ /* 0 if decoding failed */ /* NOTE: many ways to fail so return 0 IMMEDIATELY after any error. */ /************************************************************************/ ST_UINT16 tp_decode_cx (TPDU_CX *tpdu_cx_rx, ST_UCHAR *pdu_ptr, ST_UINT16 pdu_len, ST_UCHAR pdu_type, ST_UCHAR def_max_tpdu_len_enc) { TP_FHDR_CX *pdu; ST_UINT16 len_proc; /* length of CR or CC TPDU processed */ TP_PAR *param; ST_BOOLEAN checksum_present; ST_UINT16 hdr_len; hdr_len = get_hdr_len (pdu_ptr, pdu_len, TP_FHDR_CX_LEN); if (hdr_len == 0) { TP_LOG_ERR0 ("TPDU-CR.ind or CC.ind invalid header len. TPDU Ignored."); return (0); } checksum_present = SD_FALSE; /* it is error if checksum is not */ /* present in CR or TPDU */ /* make sure the struct is cleared */ memset (tpdu_cx_rx, 0, sizeof (TPDU_CX)); pdu = (TP_FHDR_CX *) pdu_ptr; /* everything in data_buf starting from offset should be the CR or CC */ /* Set TPDU size to default in case not encoded. */ tpdu_cx_rx->max_tpdu_len_enc = def_max_tpdu_len_enc; /*----------------------------------------------------*/ /* Process the fixed part of CR or CC TPDU header */ /*----------------------------------------------------*/ tpdu_cx_rx->cdt = (ST_UCHAR) (pdu->type_cdt & TP_PDU_MASK_TYPE); /* remote CDT */ tpdu_cx_rx->loc_ref = *((ST_UINT16 *) pdu->dest_ref); /* local conn reference */ tpdu_cx_rx->rem_ref = *((ST_UINT16 *) pdu->src_ref); /* remote conn reference*/ /* get the preferred class option */ /* Class is in high nibble of class_opt. */ tpdu_cx_rx->preferred_class = pdu->class_opt >> 4; /*----------------------------------------------------*/ /* Process the variable part of CR or CC TPDU header. */ /* Extract parameters in which we are interested into */ /* the tpdu_cx_rx. */ /* The ISO 8073 states that is if a parameter is not */ /* present in CR or CC and the standard defines a */ /* default value for it, then the default value should*/ /* be used (equivalent to present parameter). */ /* Following parameters have default value: */ /* TPDU size: 128 bytes */ /* TP version 0x01 */ /* Additional options 0x01 (checksum used and */ /* support expedited */ /* data transfer) */ /*----------------------------------------------------*/ len_proc = TP_FHDR_CX_LEN; /* we processed already the fixed part */ while (len_proc < hdr_len) { if ((param = get_next_param (pdu_ptr, len_proc, hdr_len)) == NULL) { TP_LOG_ERR0 ("TPDU-CR.ind or CC.ind invalid param len. TPDU Ignored."); return (0); } switch (param->code) { case TP_PAR_CODE_TSAP_CALLING: /* copy the len & remote TSAP */ if (param->len <= MAX_TSEL_LEN) { if (pdu_type == TP_PDU_TYPE_CR) /* CR TPDU, we are called (remote TSAP in this field) */ memcpy (tpdu_cx_rx->rem_tsap, (ST_CHAR *) ¶m->len, 1 + param->len); else /* CC TPDU, we are calling (local TSAP in this field) */ memcpy (tpdu_cx_rx->loc_tsap, (ST_CHAR *) ¶m->len, 1 + param->len); } else { TP_LOG_ERR1 ("TP-ERROR: decode CR or CC TPDU failed (TSEL length %u not supported)", (unsigned) param->len); return (0); /* bad TSAP length, ignore this TPDU */ } break; case TP_PAR_CODE_TSAP_CALLED: /* copy the length and local TSAP */ if (param->len <= MAX_TSEL_LEN) { if (pdu_type == TP_PDU_TYPE_CR) /* CR TPDU, we are called (local TSAP in this field) */ memcpy (tpdu_cx_rx->loc_tsap, (ST_CHAR *) ¶m->len, 1 + param->len); else /* CC TPDU, we are calling (remote TSAP in this field) */ memcpy (tpdu_cx_rx->rem_tsap, (ST_CHAR *) ¶m->len, 1 + param->len); } else { TP_LOG_ERR1 ("TP-ERROR: decode CR or CC TPDU failed (TSEL length %u not supported)", (unsigned) param->len); return (0); /* bad TSAP length, ignore this TPDU */ } break; case TP_PAR_CODE_TPDU_SIZE: if (param->len != 1) { TP_LOG_ERR0 ("TPDU-CR.ind or CC.ind invalid param len. TPDU Ignored."); return (0); } if (param->value [0] < TP_PDU_MAX_SIZE_128 || param->value [0] > TP_PDU_MAX_SIZE_8192) { TP_LOG_ERR1 ("TP-ERROR: decode CR TPDU failed (invalid TPDU size %u)", (unsigned) param->value[0]); return (0); /* invalid TPDU size, ignore this TPDU */ } else tpdu_cx_rx->max_tpdu_len_enc = param->value [0]; break; case TP_PAR_CODE_VERSION: if (param->len != 1) { TP_LOG_ERR0 ("TPDU-CR.ind or CC.ind invalid param len. TPDU Ignored."); return (0); } if (param->value [0] != TP_VERSION) { TP_LOG_ERR1 ("TP-ERROR: decode CR TPDU failed (invalid TPDU version %u)", (unsigned) param->value[0]); return (0); /* invalid TP version, ignore this TPDU */ } break; case TP_PAR_CODE_ADD_OPTIONS: /* Following proposed protocol parameters can be in */ /* additional options (for class 4): */ /* non-use of checksum, use/non-use of expedited data. */ /* We will reject non-use of checksum and we will not */ /* support expedited data service (see encoding of CC). */ /* There is no processing needed of this parameter. */ break; case TP_PAR_CODE_CHECKSUM: checksum_present = SD_TRUE; if (!tp_checksum_verified (pdu_ptr, pdu_len, len_proc)) return (0); /* bad checksum, ignore this TPDU */ break; default: /* ignore this parameter */ TP_LOG_IND1 ("TP-WARNING: decode CR or CC TPDU: Unrecognized param code (0x%X) ignored", param->code); break; } /* end switch */ /* add len of currently processed parameter to len_proc */ len_proc += (ST_UINT16) (TP_PAR_FIX_LEN + param->len); } /* end while */ if (checksum_present==SD_FALSE && tpdu_cx_rx->preferred_class==4) { TP_LOG_ERR0 ("TP-ERROR: decode CR TPDU failed (checksum parameter not present)"); return (0); } /*----------------------------------------------------*/ /* If decoding of header successful copy user data */ /* and call proceess function. */ /*----------------------------------------------------*/ /* check if user data are present */ if (hdr_len < pdu_len) { ST_UINT16 udata_len = pdu_len - hdr_len; if ( udata_len <= TP_MAX_CONN_UDATA) { memcpy (tpdu_cx_rx->udata_buf, &pdu_ptr [hdr_len], udata_len); tpdu_cx_rx->udata_len = udata_len; } else TP_LOG_ERR1 ("TP-ERROR: invalid user data length (%u) in received CR or CC TPDU", udata_len); } return (pdu_len); } /************************************************************************/ /* tp_decode_dr */ /*----------------------------------------------------------------------*/ /* Function used to decode a received DR TPDU. Because the n_unitdata */ /* may contain multiple TPDUs, the offset parameter will tell us where */ /* the DR TPDU starts in the data_buf (n_unitdata). */ /* This function does NOT return a decode error if the checksum is */ /* not present. Use of checksum may not have been negotiated yet. */ /* */ /* Parameters: */ /* TPDU_DR *tpdu_dr_rx Struct to fill in with decoded info. */ /* ST_UCHAR *pdu_ptr Pointer to TPDU. */ /* ST_UINT16 pdu_len Len of TPDU. */ /* */ /* Return: */ /* ST_UINT16 Length of DR TPDU. */ /* 0 if decoding failed */ /* NOTE: many ways to fail so return 0 IMMEDIATELY after any error. */ /************************************************************************/ ST_UINT16 tp_decode_dr (TPDU_DR *tpdu_dr_rx, ST_UCHAR *pdu_ptr, ST_UINT16 pdu_len) { TP_FHDR_DR *pdu; ST_UINT16 len_proc; /* length of DR TPDU already processed */ TP_PAR *param; ST_UINT16 hdr_len; hdr_len = get_hdr_len (pdu_ptr, pdu_len, TP_FHDR_DR_LEN); if (hdr_len == 0) { TP_LOG_ERR0 ("TPDU-DR.ind invalid header len. TPDU Ignored."); return (0); } /* make sure the struct is cleared */ memset (tpdu_dr_rx, 0, sizeof (TPDU_DR)); pdu = (TP_FHDR_DR *) pdu_ptr; /* everything in data_buf starting from offset should be the DR TPDU */ /*--------------------------------------------*/ /* Process the fixed part of DR TPDU header */ /*--------------------------------------------*/ tpdu_dr_rx->loc_ref = *((ST_UINT16 *) pdu->dest_ref); /* local conn reference */ tpdu_dr_rx->rem_ref = *((ST_UINT16 *) pdu->src_ref); /* remote conn reference*/ tpdu_dr_rx->reason = pdu->reason; /* reson for disconnect */ /*----------------------------------------------------*/ /* Process the variable part of DR TPDU header. */ /*----------------------------------------------------*/ len_proc = TP_FHDR_DR_LEN; /* we processed already the fixed part */ while (len_proc < hdr_len) { if ((param = get_next_param (pdu_ptr, len_proc, hdr_len)) == NULL) { TP_LOG_ERR0 ("TPDU-DR.ind invalid param len. TPDU Ignored."); return (0); } switch (param->code) { case TP_PAR_CODE_CHECKSUM: if (!tp_checksum_verified (pdu_ptr, pdu_len, len_proc)) return (0); /* bad checksum, ignore this TPDU */ break; default: /* ignore other parameters */ TP_LOG_IND1 ("TP-WARNING: decode DR TPDU: Unrecognized param code (0x%X) ignored", param->code); break; } /* end switch */ /* add len of currently processed parameter to len_proc */ len_proc += (ST_UINT16) (TP_PAR_FIX_LEN + param->len); } /* end while */ return (pdu_len); } /************************************************************************/ /* tp_decode_dc */ /*----------------------------------------------------------------------*/ /* Function used to decode a received DC TPDU. */ /* This function does NOT return a decode error if the checksum is */ /* not present. Use of checksum may not have been negotiated yet. */ /* */ /* Parameters: */ /* TPDU_DC *tpdu_dc_rx Struct to fill in with decoded info. */ /* ST_UCHAR *pdu_ptr Pointer to TPDU. */ /* */ /* Return: */ /* ST_UINT16 Length of DC TPDU. */ /* 0 if decoding failed */ /* NOTE: many ways to fail so return 0 IMMEDIATELY after any error. */ /************************************************************************/ ST_UINT16 tp_decode_dc (TPDU_DC *tpdu_dc_rx, ST_UCHAR *pdu_ptr, ST_UINT16 pdu_len) { TP_FHDR_DC *pdu; TP_PAR *param; ST_UINT16 len_proc; /* length of TPDU already processed */ ST_UINT16 hdr_len; hdr_len = get_hdr_len (pdu_ptr, pdu_len, TP_FHDR_DC_LEN); if (hdr_len == 0) { TP_LOG_ERR0 ("TPDU-DC.ind invalid header len. TPDU Ignored."); return (0); } /* make sure the struct is cleared */ memset (tpdu_dc_rx, 0, sizeof (TPDU_DC)); pdu = (TP_FHDR_DC *) pdu_ptr; /*--------------------------------------------*/ /* Process the fixed part of DC TPDU header */ /*--------------------------------------------*/ tpdu_dc_rx->loc_ref = *((ST_UINT16 *) pdu->dest_ref); /* local conn reference */ tpdu_dc_rx->rem_ref = *((ST_UINT16 *) pdu->src_ref); /* remote conn reference*/ /*----------------------------------------------------*/ /* Process the variable part of DC TPDU header. */ /*----------------------------------------------------*/ len_proc = TP_FHDR_DC_LEN; /* we processed already the fixed part */ while (len_proc < hdr_len) { if ((param = get_next_param (pdu_ptr, len_proc, hdr_len)) == NULL) { TP_LOG_ERR0 ("TPDU-DC.ind invalid param len. TPDU Ignored."); return (0); } switch (param->code) { case TP_PAR_CODE_CHECKSUM: if (!tp_checksum_verified (pdu_ptr, pdu_len, len_proc)) return (0); /* bad checksum, ignore this TPDU */ break; default: /* Other parameters not allowed. */ TP_LOG_ERR1 ("TPDU-DC.ind unrecognized param code (0x%X). Protocol error.", param->code); return (0); break; } /* end switch */ /* add len of currently processed parameter to len_proc */ len_proc += (ST_UINT16) (TP_PAR_FIX_LEN + param->len); } /* end while */ return (pdu_len); } /************************************************************************/ /* tp_decode_dt */ /*----------------------------------------------------------------------*/ /* Function used to decode a received DT TPDU. */ /* */ /* Parameters: */ /* TPDU_DT *tpdu_dt_rx Struct to fill in with decoded info. */ /* ST_UCHAR *pdu_ptr Pointer to TPDU. */ /* ST_UINT16 pdu_len Len of TPDU. */ /* */ /* Return: */ /* ST_UINT16 Length of DT TPDU. */ /* 0 if decoding failed */ /* NOTE: many ways to fail so return 0 IMMEDIATELY after any error. */ /************************************************************************/ ST_UINT16 tp_decode_dt (TPDU_DT *tpdu_dt_rx, ST_UCHAR *pdu_ptr, ST_UINT16 pdu_len) { TP_FHDR_DT *pdu; ST_BOOLEAN checksum_present; ST_UINT16 hdr_len; ST_UINT16 len_proc; /* length of TPDU already processed */ TP_PAR *param; hdr_len = get_hdr_len (pdu_ptr, pdu_len, TP_FHDR_DT_LEN); if (hdr_len == 0) { TP_LOG_ERR0 ("TPDU-DT.ind invalid header len. TPDU Ignored."); return (0); } checksum_present = SD_FALSE; /* it is error if checksum is missing */ /* make sure the struct is cleared */ memset (tpdu_dt_rx, 0, sizeof (TPDU_DT)); pdu = (TP_FHDR_DT *) pdu_ptr; /*--------------------------------------------*/ /* Process the fixed part of DT TPDU header */ /*--------------------------------------------*/ /* udata is everything after the header */ tpdu_dt_rx->udata_ptr = (ST_CHAR *) pdu_ptr + hdr_len; tpdu_dt_rx->udata_len = pdu_len - hdr_len; if (pdu->eot_sn & TP_PDU_MASK_SN) tpdu_dt_rx->eot = SD_TRUE; /* set the EOF flag */ else tpdu_dt_rx->eot = SD_FALSE; tpdu_dt_rx->dst_ref = *((ST_UINT16 *) pdu->dest_ref); /* local conn reference */ tpdu_dt_rx->sn = (ST_UCHAR) (pdu->eot_sn & TP_PDU_MASK_EOF); /* sn of received TPDU */ /*----------------------------------------------------*/ /* Process the variable part of DT TPDU header. */ /*----------------------------------------------------*/ len_proc = TP_FHDR_DT_LEN; /* we processed already the fixed part */ while (len_proc < hdr_len) { if ((param = get_next_param (pdu_ptr, len_proc, hdr_len)) == NULL) { TP_LOG_ERR0 ("TPDU-DT.ind invalid param len. TPDU Ignored."); return (0); } switch (param->code) { /* Checksum is the only allowed parameter*/ case TP_PAR_CODE_CHECKSUM: checksum_present = SD_TRUE; if (!tp_checksum_verified (pdu_ptr, pdu_len, len_proc)) return (0); /* bad checksum, ignore this TPDU */ break; default: /* Other parameters not allowed. */ TP_LOG_ERR1 ("TPDU-DT.ind unrecognized param code (0x%X). Protocol error.", param->code); return (0); break; } /* end switch */ /* add len of currently processed parameter to len_proc */ len_proc += (ST_UINT16) (TP_PAR_FIX_LEN + param->len); } /* end while */ if (!checksum_present) { TP_LOG_ERR0 ("TP-ERROR: decode DT TPDU failed (checksum parameter not present)"); return (0); } return (pdu_len); } /************************************************************************/ /* tp0_decode_dt */ /*----------------------------------------------------------------------*/ /* This function is used to decode a Class 0 DT TPDU. */ /* Same as tp_decode_dt except dest_ref and Checksum NOT encoded. */ /* NOTE: many ways to fail so return 0 IMMEDIATELY after any error. */ /************************************************************************/ ST_UINT16 tp0_decode_dt (TPDU_DT *tpdu_dt_rx, ST_UCHAR *pdu_ptr, ST_UINT16 pdu_len) { TP0_FHDR_DT *tp0_fhdr_dt; ST_UINT16 hdr_len; hdr_len = get_hdr_len (pdu_ptr, pdu_len, TP0_FHDR_DT_LEN); if (hdr_len == 0) { TP_LOG_ERR0 ("TPDU-DT.ind invalid header len. TPDU Ignored."); return (0); } if (hdr_len != TP0_FHDR_DT_LEN) { /* Variable part not allowed. */ TP_LOG_ERR1 ("TPDU-DT.ind header len (%u) != 3. Protocol error.", hdr_len); return (0); } /* make sure the struct is cleared */ memset (tpdu_dt_rx, 0, sizeof (TPDU_DT)); tp0_fhdr_dt = (TP0_FHDR_DT *) pdu_ptr; /*--------------------------------------------*/ /* Process the fixed part of DT TPDU header */ /*--------------------------------------------*/ /* udata is everything after the header */ tpdu_dt_rx->udata_ptr = (ST_CHAR *) pdu_ptr + hdr_len; tpdu_dt_rx->udata_len = pdu_len - hdr_len; if (tp0_fhdr_dt->eot_sn & TP_PDU_MASK_SN) tpdu_dt_rx->eot = SD_TRUE; /* set the EOF flag */ else tpdu_dt_rx->eot = SD_FALSE; tpdu_dt_rx->sn = (ST_UCHAR) (tp0_fhdr_dt->eot_sn & TP_PDU_MASK_EOF); /* sn of received TPDU */ return (pdu_len); } /************************************************************************/ /* tp_decode_ak */ /*----------------------------------------------------------------------*/ /* Function used to decode a received AK TPDU. Because the n_unitdata */ /* may contain multiple TPDUs, the offset parameter will tell us where */ /* the AK TPDU starts in the data_buf (n_unitdata). */ /* */ /* Parameters: */ /* TPDU_AK *tpdu_ak_rx Struct to fill in with decoded info. */ /* ST_UCHAR *pdu_ptr Pointer to TPDU. */ /* */ /* Return: */ /* ST_UINT16 Length of AK TPDU. */ /* 0 if decoding failed */ /* NOTE: many ways to fail so return 0 IMMEDIATELY after any error. */ /************************************************************************/ ST_UINT16 tp_decode_ak (TPDU_AK *tpdu_ak_rx, ST_UCHAR *pdu_ptr, ST_UINT16 pdu_len) { TP_FHDR_AK *pdu; ST_UINT16 len_proc; /* length of AK TPDU already processed */ TP_PAR *param; ST_BOOLEAN checksum_present; ST_UINT16 hdr_len; hdr_len = get_hdr_len (pdu_ptr, pdu_len, TP_FHDR_AK_LEN); if (hdr_len == 0) { TP_LOG_ERR0 ("TPDU-AK.ind invalid header len. TPDU Ignored."); return (0); } checksum_present = SD_FALSE; /* it is error if checksum is missing */ /* make sure the struct is cleared */ memset (tpdu_ak_rx, 0, sizeof (TPDU_AK)); pdu = (TP_FHDR_AK *) pdu_ptr; /*--------------------------------------------*/ /* Process the fixed part of AK TPDU header */ /*--------------------------------------------*/ tpdu_ak_rx->dst_ref = *((ST_UINT16 *) pdu->dest_ref); /* local conn reference */ tpdu_ak_rx->sn = (ST_UCHAR) (pdu->sn & TP_PDU_MASK_BIT8); /* next expected DT sn */ tpdu_ak_rx->cdt = (ST_UCHAR) (pdu->type_cdt & TP_PDU_MASK_TYPE); /* remote CDT */ /*----------------------------------------------------*/ /* Process the variable part of AK TPDU. */ /*----------------------------------------------------*/ len_proc = TP_FHDR_AK_LEN; /* we processed already the fixed part */ while (len_proc < hdr_len) { if ((param = get_next_param (pdu_ptr, len_proc, hdr_len)) == NULL) { TP_LOG_ERR0 ("TPDU-AK.ind invalid param len. TPDU Ignored."); return (0); } switch (param->code) { case TP_PAR_CODE_CHECKSUM: checksum_present = SD_TRUE; if (!tp_checksum_verified (pdu_ptr, pdu_len, len_proc)) return (0); /* bad checksum, ignore this TPDU */ break; default: /* ignore other parameters */ TP_LOG_IND1 ("TP-WARNING: decode AK TPDU: Unrecognized param code (0x%X) ignored", param->code); break; } /* end switch */ /* add len of currently processed parameter to len_proc */ len_proc += (ST_UINT16) (TP_PAR_FIX_LEN + param->len); } /* end while */ if (!checksum_present) { TP_LOG_ERR0 ("TP-ERROR: decode AK TPDU failed (checksum parameter not present)"); return (0); } /* NOTE: len_proc may be less than pdu_len if multiple TPDU in NSDU. */ return (len_proc); } /************************************************************************/ /* tp_decode_er */ /*----------------------------------------------------------------------*/ /* Function used to decode a received ER TPDU. Because the n_unitdata */ /* may contain multiple TPDUs, the offset parameter will tell us where */ /* the ER TPDU starts in the data_buf (n_unitdata). */ /* */ /* Parameters: */ /* TPDU_ER *tpdu_er_rx Struct to fill in with decoded info. */ /* ST_UCHAR *pdu_ptr Pointer to TPDU. */ /* ST_UINT16 pdu_len Len of TPDU. */ /* ST_INT tp_classs Transport class (must be 0 or 4). */ /* */ /* Return: */ /* ST_UINT16 Length of ER TPDU. */ /* 0 if decoding failed */ /* NOTE: many ways to fail so return 0 IMMEDIATELY after any error. */ /************************************************************************/ ST_UINT16 tp_decode_er (TPDU_ER *tpdu_er_rx, ST_UCHAR *pdu_ptr, ST_UINT16 pdu_len, ST_INT tp_class) /* must be 0 or 4 */ { TP_FHDR_ER *pdu; ST_UINT16 len_proc; /* length of TPDU already processed */ TP_PAR *param; ST_UINT16 hdr_len; ST_BOOLEAN checksum_present; hdr_len = get_hdr_len (pdu_ptr, pdu_len, TP_FHDR_ER_LEN); if (hdr_len == 0) { TP_LOG_ERR0 ("TPDU-ER.ind invalid header len. TPDU Ignored."); return (0); } /* If class 4 (tp_class=4), checksum must be present. */ checksum_present = SD_FALSE; /* make sure the struct is cleared */ memset (tpdu_er_rx, 0, sizeof (TPDU_ER)); pdu = (TP_FHDR_ER *) pdu_ptr; /*--------------------------------------------*/ /* Process the fixed part of ER TPDU header */ /*--------------------------------------------*/ tpdu_er_rx->dst_ref = *((ST_UINT16 *) pdu->dest_ref); /* local conn reference */ tpdu_er_rx->reject_cause = pdu->reason; /*----------------------------------------------------*/ /* Process the variable part of ER TPDU header. */ /*----------------------------------------------------*/ len_proc = TP_FHDR_ER_LEN; /* we processed already the fixed part */ while (len_proc < hdr_len) { if ((param = get_next_param (pdu_ptr, len_proc, hdr_len)) == NULL) { TP_LOG_ERR0 ("TPDU-ER.ind invalid param len. TPDU Ignored."); return (0); } switch (param->code) { case TP_PAR_CODE_ER_INVAL_TPDU: /* Invalid TPDU */ /* Set ptr to Invalid TPDU part of message & set len. */ tpdu_er_rx->invalid_tpdu_ptr = ¶m->value[0]; tpdu_er_rx->invalid_tpdu_len = param->len; break; case TP_PAR_CODE_CHECKSUM: checksum_present = SD_TRUE; if (!tp_checksum_verified (pdu_ptr, pdu_len, len_proc)) return (0); /* bad checksum, ignore this TPDU */ break; default: /* Other parameters not allowed. */ TP_LOG_ERR1 ("TPDU-ER.ind unrecognized param code (0x%X). Protocol error.", param->code); return (0); break; } /* end switch */ /* add len of currently processed parameter to len_proc */ len_proc += (ST_UINT16) (TP_PAR_FIX_LEN + param->len); } /* end while */ /* For Class 0, invalid_tpdu_ptr must be set during decode. */ if (tpdu_er_rx->invalid_tpdu_ptr == NULL && tp_class == 0) { TP_LOG_ERR0 ("TPDU-ER.ind 'Invalid TPDU' not present for Class 0"); return (0); } /* For Class 4, checksum must be found during decode. */ if (!checksum_present && tp_class == 4) { TP_LOG_ERR0 ("TPDU-ER.ind checksum not present for Class 4"); return (0); } /* NOTE: len_proc may be less than pdu_len if multiple TPDU in NSDU. */ return (len_proc); } /************************************************************************/ /* tp_checksum_verified */ /*----------------------------------------------------------------------*/ /* This function is used to decode and verify the checksum parameter in */ /* TPDU. */ /* */ /* Parameters: */ /* ST_UCHAR *buf Ptr to TPDU buffer */ /* ST_UINT16 buf_len Length of the buffer (TPDU). */ /* ST_UINT16 par_pos Position of checksum parameter in TPDU. */ /* */ /* Return: */ /* ST_BOOLEAN SD_TRUE if checksum verified. */ /* SD_FALSE otherwise */ /************************************************************************/ static ST_BOOLEAN tp_checksum_verified (ST_UCHAR *buf, ST_UINT16 buf_len, ST_UINT16 par_pos) { ST_BOOLEAN verified; TP_PAR *param; /* NOTE: len checked before calling, so we know param fits in TPDU, */ /* but here we make sure param len == 2 before continuing. */ verified = SD_FALSE; param = (TP_PAR *) (&buf [par_pos]); /* point to start of param*/ if (param->code == TP_PAR_CODE_CHECKSUM) { if (param->len == 2) { /* compute the checksum of the entire TPDU, the position of the */ /* checksum first byte in the buf is computed as the difference */ /* between pointers */ verified = checksum_verified (buf, buf_len, (ST_UINT16) (param->value - buf), SD_FALSE); if (!verified) TP_LOG_ERR0 ("TP-ERROR: decode TPDU failed (verification of checksum failed)"); } else TP_LOG_ERR1 ("TP-ERROR: decode TPDU failed (invalid length=%u for checksum parameter)", param->len); } else TP_LOG_ERR0 ("TP-ERROR: decode TPDU failed (checksum parameter missing)"); return (verified); } #if defined(DEBUG_SISCO) /************************************************************************/ /* tp_log_tsdu */ /*----------------------------------------------------------------------*/ /* Function used to log Transport Service data unit. */ /* */ /* Parameters: */ /* ST_VOID *tsdu Pointer to data unit struct */ /* ST_UCHAR type TSDU type (TP_PDU_TYPE_CR, etc.) */ /* ST_UCHAR mask logging mask: */ /* TP_IND (indication) or TP_REQ (request) */ /* */ /* Return: */ /* ST_VOID none */ /* NOTE: all src_ref & dst_ref stored in network byte order. Converted */ /* to "host byte order" using "ntohs" only in this function. */ /************************************************************************/ ST_VOID tp_log_tsdu (ST_VOID *tsdu, ST_UCHAR type, ST_UCHAR mask) { char *buf; /* ptr to msg header (i.e. TPDU type) */ /* set before passing to log function */ S_LOCK_UTIL_RESOURCES (); switch (type) { case TP_PDU_TYPE_CR: case TP_PDU_TYPE_CC: { /*block*/ TPDU_CX *tpdu = (TPDU_CX *) tsdu; if (mask == TP_IND) { if (type == TP_PDU_TYPE_CR) buf = "TPDU-CR.ind:"; else buf = "TPDU-CC.ind:"; /* For IND, dst_ref is loc_ref */ TP_LOG_RI6 (mask,"%s dst_ref=0x%04X src_ref=0x%04X max_len=%4u class=%u cdt=%2u", buf, ntohs(tpdu->loc_ref), ntohs(tpdu->rem_ref), 1 << tpdu->max_tpdu_len_enc, (unsigned) tpdu->preferred_class, (unsigned) tpdu->cdt); } else { if (type == TP_PDU_TYPE_CR) buf = "TPDU-CR.req:"; else buf = "TPDU-CC.req:"; /* For REQ, dst_ref is rem_ref */ TP_LOG_RI6 (mask,"%s dst_ref=0x%04X src_ref=0x%04X max_len=%4u class=%u cdt=%2u", buf, ntohs(tpdu->rem_ref), ntohs(tpdu->loc_ref), 1 << tpdu->max_tpdu_len_enc, (unsigned) tpdu->preferred_class, (unsigned) tpdu->cdt); } TP_LOGC_RI0 (mask,"Local TSEL:"); TP_LOGHC_RI (mask,(ST_UINT) tpdu->loc_tsap [0], &tpdu->loc_tsap [1]); TP_LOGC_RI0 (mask,"Remote TSEL:"); TP_LOGHC_RI (mask,(ST_UINT) tpdu->rem_tsap [0], &tpdu->rem_tsap [1]); #if 0 TP_LOGC_RI0 (mask,"Remote MAC:"); TP_LOGHC_RI (mask,(ST_UINT) CLNP_MAX_LEN_MAC, tpdu->rem_mac); TP_LOGC_RI0 (mask,"Remote NSAP:"); TP_LOGHC_RI (mask,(ST_UINT) tpdu->rem_nsap [0], &tpdu->rem_nsap [1]); #endif TP_LOGC_RI1 (mask,"User data length: %u", tpdu->udata_len); if (tpdu->udata_len > 0) TP_LOGHC_RI (mask,(ST_UINT) tpdu->udata_len, tpdu->udata_buf); } break; case TP_PDU_TYPE_DR: case TP_PDU_TYPE_DC: { /*block*/ TPDU_DR *tpdu = (TPDU_DR *) tsdu; /* we use DR struct for both */ if (mask == TP_IND) { if (type == TP_PDU_TYPE_DR) buf = "TPDU-DR.ind:"; else buf = "TPDU-DC.ind:"; /* For IND, dst_ref is loc_ref */ TP_LOG_RI3 (mask,"%s dst_ref=0x%04X src_ref=0x%04X", buf, ntohs(tpdu->loc_ref), ntohs(tpdu->rem_ref)); } else { if (type == TP_PDU_TYPE_DR) buf = "TPDU-DR.req:"; else buf = "TPDU-DC.req:"; /* For REQ, dst_ref is rem_ref */ TP_LOG_RI3 (mask,"%s dst_ref=0x%04X src_ref=0x%04X", buf, ntohs(tpdu->rem_ref), ntohs(tpdu->loc_ref)); } if (type == TP_PDU_TYPE_DR) TP_LOGC_RI1 (mask,"Disconnect reason: 0x%2.2X", (unsigned) tpdu->reason); #if 0 TP_LOGC_RI0 (mask,"Remote MAC:"); TP_LOGHC_RI (mask,(ST_UINT) CLNP_MAX_LEN_MAC, tpdu->rem_mac); TP_LOGC_RI0 (mask,"Remote NSAP:"); TP_LOGHC_RI (mask,(ST_UINT) tpdu->rem_nsap [0], &tpdu->rem_nsap [1]); #endif } break; case TP_PDU_TYPE_DT: { /*block*/ TPDU_DT *tpdu = (TPDU_DT *) tsdu; if (mask == TP_IND) buf = "TPDU-DT.ind:"; else buf = "TPDU-DT.req:"; TP_LOG_RI4 (mask,"%s dst_ref=0x%04X sn=%3u eot=%u", buf, ntohs(tpdu->dst_ref), (unsigned) tpdu->sn, (unsigned) tpdu->eot); #if 0 TP_LOGC_RI0 (mask,"Remote MAC:"); TP_LOGHC_RI (mask,(ST_UINT) CLNP_MAX_LEN_MAC, tpdu->rem_mac); TP_LOGC_RI0 (mask,"Remote NSAP:"); TP_LOGHC_RI (mask,(ST_UINT) tpdu->rem_nsap [0], &tpdu->rem_nsap [1]); #endif TP_LOGC_RI1 (mask,"User data length: %u", tpdu->udata_len); TP_LOGHC_RI (mask,(ST_UINT) tpdu->udata_len, tpdu->udata_ptr); } break; case TP_PDU_TYPE_AK: { /*block*/ TPDU_AK *tpdu = (TPDU_AK *) tsdu; if (mask == TP_IND) buf = "TPDU-AK.ind:"; else buf = "TPDU-AK.req:"; TP_LOG_RI4 (mask,"%s dst_ref=0x%04X sn=%3u cdt=%2u", buf, ntohs(tpdu->dst_ref), (unsigned) tpdu->sn, (unsigned) tpdu->cdt); #if 0 TP_LOGC_RI0 (mask,"Remote MAC:"); TP_LOGHC_RI (mask,(ST_UINT) CLNP_MAX_LEN_MAC, tpdu->rem_mac); TP_LOGC_RI0 (mask,"Remote NSAP:"); TP_LOGHC_RI (mask,(ST_UINT) tpdu->rem_nsap [0], &tpdu->rem_nsap [1]); #endif } break; default: TP_LOG_ERR1 ("TP-ERROR: unknown TPDU type %d", type); break; } S_UNLOCK_UTIL_RESOURCES (); } #else /* function if DEBUG_SISCO not defined */ ST_VOID tp_log_tsdu (ST_VOID *tsdu, ST_UCHAR type, ST_UCHAR mask) { return; } #endif