FreeCalypso > hg > fc-tourmaline
view src/gpf/ccd/pdi.c @ 304:58c7961bd0b0 default tip
TCH tap: extend DL sniffing feature to support CSD modes
Our debug feature for TCH DL sniffing reads the content of the DSP's
a_dd_0 buffer (or a_dd_1 for TCH/H subchannel 1) at appropriate times
and forwards captured bits to the host. This feature was originally
implemented for TCH/FS, TCH/EFS and TCH/HS - now extend it to cover
TCH/F data modes too.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 25 Nov 2024 23:33:27 +0000 |
parents | 4e78acac3d88 |
children |
line wrap: on
line source
/* +----------------------------------------------------------------------------- | Project : | Modul : pdi.c +----------------------------------------------------------------------------- | Copyright 2002 Texas Instruments Berlin, AG | All rights reserved. | | This file is confidential and a trade secret of Texas | Instruments Berlin, AG | The receipt of or possession of this file does not convey | any rights to reproduce or disclose its contents or to | manufacture, use, or sell anything it may describe, in | whole, or in part, without the specific written consent of | Texas Instruments Berlin, AG. +----------------------------------------------------------------------------- | Purpose : +----------------------------------------------------------------------------- */ #define PDI_C #include "typedefs.h" #include "ccdapi.h" #include "ccdtable.h" #include "ccddata.h" #include <malloc.h> #include <memory.h> #include <string.h> #include "pdi.h" #define GET_PD(m) ((m)->buf[((m)->o_buf)>>3] & 0x0f) #define GET_TI(m) ((m)->buf[((m)->o_buf)>>3] >> 4) /* Constants borrowed from grr.h */ #define CTRL_BLK_NO_OPT 1 #define CTRL_BLK_OPT 2 static T_PDI_DECODEINFO* g_DummyDecodeInfo = NULL; static T_PDI_DECODEINFO m_def_dinfo[]={ /* type */ /* attrib */ /* prim */ /* entity */ /* mt */ /* pdi_prepare_ccdmsg */ /* primmbr */ {PDI_DECODETYPE_L3PDU_N, "sdu", "PH_*", "", 0xff, NULL, NULL}, {PDI_DECODETYPE_L3PDU_N, "sdu", "MPH_*", "", 0xff, NULL, NULL}, {PDI_DECODETYPE_L3PDU_N, "sdu", "DL_*", "", 0xff, NULL, NULL}, {PDI_DECODETYPE_L3PDU, "sdu", "XX_TAP*", "", 0xff, NULL, NULL}, {PDI_DECODETYPE_NOPD, "sdu", "XX_*", "XX", 0xff, NULL, NULL}, {PDI_DECODETYPE_L3PDU, "sdu", "*", "", 0xff, NULL, NULL} }; #define DEF_DINFO_COUNT (sizeof(m_def_dinfo) / sizeof(*m_def_dinfo)) static UBYTE pdi_readmtype (T_MSGBUF* msg, UBYTE len) { UBYTE mt = msg->buf[msg->o_buf>>3] >> (8-len); msg->l_buf -= len; msg->o_buf += len; return mt; } #define PDI_MBUFLEN 1024 static struct { U16 l_buf; U16 o_buf; char buf[PDI_MBUFLEN]; } pdi_msgbuf; static int pdi_rmac_hdr (T_PDI_CCDMSG* ccdmsg, char* evalue, int evlen) { char* ptr_blk; UBYTE payload, rrbp, sp; evalue++; /* Assume it is an array and skip length delivered from ccdedit */ memcpy (pdi_msgbuf.buf, evalue, evlen > PDI_MBUFLEN ? PDI_MBUFLEN : evlen); ptr_blk = evalue; pdi_msgbuf.l_buf = evlen * 8; pdi_msgbuf.o_buf = 0; ccdmsg->mbuf = (T_MSGBUF*) &pdi_msgbuf; /* the following is borrowed from grlc_gfff.c */ payload = (ptr_blk[0] & 0xC0) >> 6; rrbp = (ptr_blk[0] & 0x30) >> 4; sp = (ptr_blk[0] & 0x08) >> 3; if (payload == CTRL_BLK_NO_OPT) { /* msg starts at byte #2 */ pdi_msgbuf.l_buf -= 8; pdi_msgbuf.o_buf += 8; } else if ((payload == CTRL_BLK_OPT) && !(ptr_blk[1] & 0x01) && !(ptr_blk[1] & 0x80) && (ptr_blk[1] & 0x02)) { /* msg starts at byte #3 */ pdi_msgbuf.l_buf -= 16; pdi_msgbuf.o_buf += 16; } else if ((payload == CTRL_BLK_OPT) && (ptr_blk[1] & 0x01) && !(ptr_blk[1] & 0x80) && (ptr_blk[1] & 0x02)) { /* msg starts at byte #4 */ pdi_msgbuf.l_buf -= 24; pdi_msgbuf.o_buf += 24; } else { return PDI_NONE; } return PDI_CCDMSG; } T_PDI_CONTEXT* CCDDATA_PREF(pdi_createDefContext)() { const T_PDI_DECODEINFO* dinfo; int dinfo_count=ccddata_get_pdi_dinfo(&dinfo); if (dinfo_count==0) { dinfo_count=DEF_DINFO_COUNT; dinfo=m_def_dinfo; } return CCDDATA_PREF(pdi_createContext)(dinfo,dinfo_count); } T_PDI_CONTEXT* CCDDATA_PREF(pdi_createContext)(const T_PDI_DECODEINFO *dinfo, unsigned int dicount) { int i; USHORT sap, opc, dir, di; USHORT pmtx; T_PDI_DECODEINFO* decodeInfo[1024]; int decodeInfoCount; int len; T_PDI_CONTEXT *context; if (context = (T_PDI_CONTEXT*)malloc(sizeof(T_PDI_CONTEXT))) { // copy dinfo if (!(context->dinfo = (T_PDI_DECODEINFO*)malloc(sizeof(T_PDI_DECODEINFO)*dicount))) { free(context); return NULL; } memcpy(context->dinfo, dinfo, sizeof(T_PDI_DECODEINFO)*dicount); // PD -> CCDENT memset(context->PdEntityTable, -1, sizeof(T_PDI_PdEntityTable)); context->PdEntityTable[PD_XX] = ccddata_get_ccdent("XX"); context->PdEntityTable[PD_CC] = ccddata_get_ccdent("CC"); context->PdEntityTable[PD_MM] = ccddata_get_ccdent("MM"); context->PdEntityTable[PD_RR] = ccddata_get_ccdent("RR"); context->PdEntityTable[PD_GMM] = ccddata_get_ccdent("GMM"); context->PdEntityTable[PD_SMS] = ccddata_get_ccdent("SMS"); context->PdEntityTable[PD_SS] = ccddata_get_ccdent("SS"); context->PdEntityTable[PD_SM] = ccddata_get_ccdent("SM"); context->PdEntityTable[PD_TST] = ccddata_get_ccdent("TST"); /* initialize mi_length */ context->mi_length = ccddata_get_mi_length (); // count pcomp i = 0; while (ccddata_get_pcomp((USHORT)i)->name != NULL) i++; context->PrimDecodeInfo = (T_PDI_DECODEINFO***)malloc(i*sizeof(T_PDI_DECODEINFO**)); memset(context->PrimDecodeInfo, 0, i*sizeof(int*)); // search all primitives for (sap = 0; sap <= ccddata_get_max_sap_num(); sap++) for (opc = 0; opc <= (USHORT)ccddata_get_max_primitive_id(); opc++) for (dir = 0; dir <= 1; dir++) if ((pmtx = ccddata_get_pmtx(sap, opc, dir)) != NO_REF) { const char* pname; pname = ccddata_get_pcomp(pmtx)->name; decodeInfoCount = 0; for (di = 0; di < dicount; di++) { int wildcard; len = strlen(context->dinfo[di].prim); if (context->dinfo[di].prim[len-1] == '*') { wildcard = 1; len--; } else { wildcard = 0; len = strlen(pname); } if (wildcard) { if (!strncmp(context->dinfo[di].prim, pname, len)) { decodeInfo[decodeInfoCount] = &context->dinfo[di]; decodeInfoCount++; } } else { if (!strcmp(context->dinfo[di].prim, pname)) { decodeInfo[decodeInfoCount] = &context->dinfo[di]; decodeInfoCount++; } } } // store decodeInfo for this primitive if (decodeInfoCount != 0) { decodeInfo[decodeInfoCount] = g_DummyDecodeInfo; decodeInfoCount++; context->PrimDecodeInfo[pmtx] = (T_PDI_DECODEINFO**) malloc(decodeInfoCount*sizeof(T_PDI_DECODEINFO*)); if (context->PrimDecodeInfo+pmtx) { memcpy(context->PrimDecodeInfo[pmtx], &decodeInfo, decodeInfoCount*sizeof(T_PDI_DECODEINFO*)); } else context->PrimDecodeInfo[pmtx] = &g_DummyDecodeInfo; } else context->PrimDecodeInfo[pmtx] = &g_DummyDecodeInfo; } // endif (pmtx != NO_REF) } return context; } void CCDDATA_PREF(pdi_destroyContext)(T_PDI_CONTEXT *context) { int i = 0; if (context==NULL) return; while (ccddata_get_pcomp((USHORT)i)->name != NULL) { if ((context->PrimDecodeInfo[i] != NULL) && (context->PrimDecodeInfo[i][0] != NULL)) free(context->PrimDecodeInfo[i]); i++; } if (context->PrimDecodeInfo != NULL) free(context->PrimDecodeInfo); free(context->dinfo); free(context); } void CCDDATA_PREF(pdi_startPrim)(T_PDI_CONTEXT *context, ULONG opc) { context->sapi = 0; if (opc & 0x80000000) { context->sap = (USHORT) (opc & 0x3fff); context->opc = (USHORT) ((opc >> 16) & 0xff); } else { context->sap = (USHORT) (((opc & 0x3f00)>>8) & 0xff); context->opc = (USHORT) (opc & 0xff); } context->dir = (UBYTE) (((opc & 0x4000)>>14) & 0x01); context->pmtx = ccddata_get_pmtx(context->sap, context->opc, context->dir); context->mtypenum = 0; } void CCDDATA_PREF(pdi_getDecodeInfo)(T_PDI_CONTEXT *context, const char *ename, char *evalue, int evlen, T_PDI *decinfo) { int i=0; T_PDI_DECODEINFO* di; decinfo->decodetype = PDI_NONE; while (di = context->PrimDecodeInfo[context->pmtx][i++]) { if ((di->type == PDI_DECODETYPE_SAPI) && (strcmp(ename, "sapi") == 0)) { context->sapi = evalue[0]; } if (!strcmp(ename, di->attrib)) { decinfo->pdi.ccdmsg.msg_type = 0xff; if (di->pdi_prepare_ccdmsg) { decinfo->decodetype = (*di->pdi_prepare_ccdmsg) (&decinfo->pdi.ccdmsg, context->mtypeval, context->mtypenum); if (decinfo->decodetype == PDI_NONE) { continue; } } switch (di->type) { case PDI_DECODETYPE_AIM: case PDI_DECODETYPE_AIM_N: case PDI_DECODETYPE_AIM_CHECK: case PDI_DECODETYPE_AIM_N_CHECK: decinfo->decodetype = PDI_CCDMSG; memcpy (pdi_msgbuf.buf, evalue, evlen > PDI_MBUFLEN ? PDI_MBUFLEN : evlen); pdi_msgbuf.l_buf = evlen * 8; pdi_msgbuf.o_buf = 0; /* first byte: don't care */ pdi_msgbuf.l_buf -= 8; pdi_msgbuf.o_buf += 8; decinfo->pdi.ccdmsg.mbuf = (T_MSGBUF*) &pdi_msgbuf; decinfo->pdi.ccdmsg.pd = GET_PD (decinfo->pdi.ccdmsg.mbuf); if (strcmp (di->entity, CCDDATA_PREF(pdi_pd2name)(decinfo->pdi.ccdmsg.pd))) { /* pd does not match the configured entity */ decinfo->decodetype = PDI_CCDMSG; continue; } else { pdi_msgbuf.l_buf -= 8; pdi_msgbuf.o_buf += 8; } //decinfo->pdi.ccdmsg.ti = GET_TI (decinfo->pdi.ccdmsg.mbuf); decinfo->pdi.ccdmsg.dir = (di->type == PDI_DECODETYPE_AIM) || (di->type == PDI_DECODETYPE_AIM_CHECK) ? context->dir : (~context->dir)&1; decinfo->pdi.ccdmsg.entity = (UBYTE)ccddata_get_ccdent(di->entity); decinfo->pdi.ccdmsg.msg_type = pdi_readmtype ( decinfo->pdi.ccdmsg.mbuf, context->mi_length[decinfo->pdi.ccdmsg.entity]); break; case PDI_DECODETYPE_L3PDU_N: case PDI_DECODETYPE_L3PDU: decinfo->decodetype = PDI_CCDMSG; decinfo->pdi.ccdmsg.pd = GET_PD ((T_MSGBUF*) evalue); decinfo->pdi.ccdmsg.ti = GET_TI ((T_MSGBUF*) evalue); decinfo->pdi.ccdmsg.dir = (di->type == PDI_DECODETYPE_L3PDU) ? context->dir : (~context->dir)&1; decinfo->pdi.ccdmsg.mbuf = (T_MSGBUF*)evalue; if (CCDDATA_PREF(pdi_getEntityByPD)(context, decinfo->pdi.ccdmsg.pd)==-1) { decinfo->decodetype = PDI_NONE; } else { decinfo->pdi.ccdmsg.entity = (UBYTE)CCDDATA_PREF(pdi_getEntityByPD)(context, decinfo->pdi.ccdmsg.pd); ((T_MSGBUF*)evalue)->o_buf += 8; ((T_MSGBUF*)evalue)->l_buf -= 8; decinfo->pdi.ccdmsg.msg_type = pdi_readmtype ((T_MSGBUF*)evalue, context->mi_length[decinfo->pdi.ccdmsg.entity]); } /* remove SSN bit */ if (!strcmp ("DL_DATA_REQ", ccddata_get_pcomp (context->pmtx)->name)) { if (decinfo->pdi.ccdmsg.pd == PD_CC || decinfo->pdi.ccdmsg.pd == PD_MM || decinfo->pdi.ccdmsg.pd == PD_SS) { decinfo->pdi.ccdmsg.msg_type &= ~0x40; } } break; case PDI_DECODETYPE_NOPD: case PDI_DECODETYPE_NOPD_N: case PDI_DECODETYPE_RR_SHORT: decinfo->decodetype = PDI_CCDMSG; decinfo->pdi.ccdmsg.pd = 0; decinfo->pdi.ccdmsg.ti = 0; decinfo->pdi.ccdmsg.dir = (di->type == PDI_DECODETYPE_NOPD) ? context->dir : (~context->dir)&1; decinfo->pdi.ccdmsg.mbuf = (T_MSGBUF*)evalue; decinfo->pdi.ccdmsg.entity = (UBYTE)ccddata_get_ccdent(di->entity); decinfo->pdi.ccdmsg.msg_type = pdi_readmtype ((T_MSGBUF*)evalue, context->mi_length[decinfo->pdi.ccdmsg.entity]); break; case PDI_DECODETYPE_NOPD_NOTYPE: case PDI_DECODETYPE_NOPD_NOTYPE_N: decinfo->decodetype = PDI_CCDMSG; decinfo->pdi.ccdmsg.pd = 0; decinfo->pdi.ccdmsg.ti = 0; decinfo->pdi.ccdmsg.dir = (di->type == PDI_DECODETYPE_NOPD_NOTYPE) ? context->dir : (~context->dir)&1; decinfo->pdi.ccdmsg.mbuf = (T_MSGBUF*)evalue; if (decinfo->pdi.ccdmsg.msg_type == 0xff) { decinfo->pdi.ccdmsg.msg_type = di->msg_type; } decinfo->pdi.ccdmsg.entity = (UBYTE)ccddata_get_ccdent(di->entity); break; case PDI_DECODETYPE_MAC_H: case PDI_DECODETYPE_MAC_H_N: case PDI_DECODETYPE_MAC_H_CHECK: case PDI_DECODETYPE_MAC_H_N_CHECK: if ((decinfo->decodetype = pdi_rmac_hdr (&decinfo->pdi.ccdmsg, evalue, evlen)) == PDI_CCDMSG) { decinfo->pdi.ccdmsg.pd = 0; decinfo->pdi.ccdmsg.ti = 0; decinfo->pdi.ccdmsg.dir = ((di->type == PDI_DECODETYPE_MAC_H) || (di->type == PDI_DECODETYPE_MAC_H_CHECK)) ? context->dir : (~context->dir)&1; decinfo->pdi.ccdmsg.entity = (UBYTE)ccddata_get_ccdent(di->entity); decinfo->pdi.ccdmsg.msg_type = pdi_readmtype (decinfo->pdi.ccdmsg.mbuf, context->mi_length[decinfo->pdi.ccdmsg.entity]); } break; case PDI_DECODETYPE_SAPI: decinfo->decodetype = PDI_NONE; if (context->sapi == 1) // only sapi1 (GMM) has data for ccd { decinfo->decodetype = PDI_CCDMSG; decinfo->pdi.ccdmsg.pd = GET_PD ((T_MSGBUF*) evalue); decinfo->pdi.ccdmsg.ti = GET_TI ((T_MSGBUF*) evalue); decinfo->pdi.ccdmsg.dir = context->dir; /* !!! TBD !!! */ /* find msg_type*/ /* !!! TBD !!! */ decinfo->pdi.ccdmsg.mbuf = (T_MSGBUF*)evalue; ((T_MSGBUF*)evalue)->o_buf += 8; ((T_MSGBUF*)evalue)->l_buf -= 8; if (CCDDATA_PREF(pdi_getEntityByPD)(context, decinfo->pdi.ccdmsg.pd)==-1) { decinfo->decodetype = PDI_NONE; } else { decinfo->pdi.ccdmsg.entity = (UBYTE)CCDDATA_PREF(pdi_getEntityByPD)(context, decinfo->pdi.ccdmsg.pd); } } break; default: decinfo->decodetype = PDI_NONE; } break; } /* endif (strcmp) */ else { if (evlen > 4 || evlen < 0 || evlen == 3) { /* don't check prim members for non base types */ continue; } /* check for prim members later needed for finding out msg type */ if (di->primmbr) { int i; for (i=0; di->primmbr[i] && context->mtypenum<PDI_MAXPMEMFORMTYPE; i++) { if (!strcmp(ename, di->primmbr[i])) { switch (evlen) { case 1: context->mtypeval[context->mtypenum++] = (ULONG) * (UBYTE*) evalue; break; case 2: context->mtypeval[context->mtypenum++] = (ULONG) * (USHORT*) evalue; break; case 4: default: context->mtypeval[context->mtypenum++] = * (ULONG*) evalue; break; } } } } } } /* endwhile */ } short CCDDATA_PREF(pdi_getEntityByPD)(const T_PDI_CONTEXT *context, unsigned char pd) { if ((pd > 16) || (context->PdEntityTable == NULL)) return -1; else return context->PdEntityTable[pd]; } const char* CCDDATA_PREF(pdi_pd2name)(unsigned char pd) { switch (pd) { case PD_XX: return "XX"; case PD_CC: return "CC"; case PD_MM: return "MM"; case PD_RR: return "RR"; case PD_GMM: return "GMM"; case PD_SMS: return "SMS"; case PD_SS: return "SS"; case PD_SM: return "SM"; case PD_TST: return "TST"; default: return "??"; } }