#include "isdn_lib_intern.h" #include "isdn_lib.h" #include "string.h" #define CENTREX_ID 0xa1 #define CALLDEFLECT_ID 0xa1 /** This file covers the encoding and decoding of facility messages and facility information elements. There will be 2 Functions as Interface: fac_enc( char **ntmsg, msg_t * msg, enum facility_type type, union facility fac, struct misdn_bchannel *bc) fac_dec( unsigned char *p, Q931_info_t *qi, enum facility_type *type, union facility *fac, struct misdn_bchannel *bc); Those will either read the union facility or fill it. internally, we will have deconding and encoding functions for each facility IE. **/ /* support stuff */ static void strnncpy(unsigned char *dest, unsigned char *src, int len, int dst_len) { if (len > dst_len-1) len = dst_len-1; strncpy((char *)dest, (char *)src, len); dest[len] = '\0'; } /**********************/ /*** FACILITY STUFF ***/ /**********************/ /* IE_FACILITY */ void enc_ie_facility(unsigned char **ntmode, msg_t *msg, unsigned char *facility, int facility_len, int nt, struct misdn_bchannel *bc) { unsigned char *p; Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN); int l; if (!facility || facility_len<=0) { return; } l = facility_len; p = msg_put(msg, l+2); if (nt) *ntmode = p+1; else qi->QI_ELEMENT(facility) = p - (unsigned char *)qi - sizeof(Q931_info_t); p[0] = IE_FACILITY; p[1] = l; memcpy(p+2, facility, facility_len); } /* facility for siemens CENTEX (known parts implemented only) */ void enc_ie_facility_centrex(unsigned char **ntmode, msg_t *msg, unsigned char *cnip, int setup, int nt, struct misdn_bchannel *bc) { unsigned char centrex[256]; int i = 0; if (!cnip) return; /* centrex facility */ centrex[i++] = FACILITY_CENTREX; centrex[i++] = CENTREX_ID; /* cnip */ if (strlen((char *)cnip) > 15) { /* if (options.deb & DEBUG_PORT) */ cb_log(1,0,"%s: CNIP/CONP text too long (max 13 chars), cutting.\n", __FUNCTION__); cnip[15] = '\0'; } /* dunno what the 8 bytes mean */ if (setup) { centrex[i++] = 0x17; centrex[i++] = 0x02; centrex[i++] = 0x02; centrex[i++] = 0x44; centrex[i++] = 0x18; centrex[i++] = 0x02; centrex[i++] = 0x01; centrex[i++] = 0x09; } else { centrex[i++] = 0x18; centrex[i++] = 0x02; centrex[i++] = 0x02; centrex[i++] = 0x81; centrex[i++] = 0x09; centrex[i++] = 0x02; centrex[i++] = 0x01; centrex[i++] = 0x0a; } centrex[i++] = 0x80; centrex[i++] = strlen((char *)cnip); strcpy((char *)(¢rex[i]), (char *)cnip); i += strlen((char *)cnip); cb_log(4,0," cnip='%s'\n", cnip); /* encode facility */ enc_ie_facility(ntmode, msg, centrex, i, nt , bc); } void dec_ie_facility_centrex(unsigned char *p, Q931_info_t *qi, unsigned char *centrex, int facility_len, unsigned char *cnip, int cnip_len, int nt, struct misdn_bchannel *bc) { int i = 0; *cnip = '\0'; if (facility_len >= 2) { if (centrex[i++] != FACILITY_CENTREX) return; if (centrex[i++] != CENTREX_ID) return; } /* loop sub IEs of facility */ while(facility_len > i+1) { if (centrex[i+1]+i+1 > facility_len) { printf("%s: ERROR: short read of centrex facility.\n", __FUNCTION__); return; } switch(centrex[i]) { case 0x80: strnncpy(cnip, ¢rex[i+2], centrex[i+1], cnip_len); cb_log(4,0," CENTREX cnip='%s'\n", cnip); break; } i += 1+centrex[i+1]; } } /* facility for CALL Deflect (known parts implemented only) */ void enc_ie_facility_calldeflect(unsigned char **ntmode, msg_t *msg, unsigned char *nr, int nt, struct misdn_bchannel *bc) { unsigned char fac[256]; if (!nr) return; int len = strlen(nr); /* calldeflect facility */ /* cnip */ if (strlen((char *)nr) > 15) { /* if (options.deb & DEBUG_PORT) */ cb_log(1,0,"%s: NR text too long (max 13 chars), cutting.\n", __FUNCTION__); nr[15] = '\0'; } fac[0]=FACILITY_CALLDEFLECT; // .. fac[1]=CALLDEFLECT_ID; fac[2]=0x0f + len; // strlen destination + 15 = 26 fac[3]=0x02; fac[4]=0x01; //fac[5]=0x70; fac[5]=0x09; fac[6]=0x02; fac[7]=0x01; fac[8]=0x0d; fac[9]=0x30; fac[10]=0x07 + len; // strlen destination + 7 = 18 fac[11]=0x30; // ...hm 0x30 fac[12]=0x02+ len; // strlen destination + 2 fac[13]=0x80; // CLIP fac[14]= len; // strlen destination memcpy((unsigned char *)fac+15,nr,len); fac[15+len]=0x01; //sending complete fac[16+len]=0x01; fac[17+len]=0x80; enc_ie_facility(ntmode, msg, fac, 17+len +1 , nt , bc); } void dec_ie_facility_calldeflect(unsigned char *p, Q931_info_t *qi, unsigned char *fac, int fac_len, unsigned char *cd_nr, int nt, struct misdn_bchannel *bc) { *cd_nr = '\0'; if (fac_len >= 15) { if (fac[0] != FACILITY_CALLDEFLECT) return; if (fac[1] != CALLDEFLECT_ID) return; } else { cb_log(1,bc->port, "IE too short: FAC_CALLDEFLECT\n"); return ; } { int dest_len=fac[2]-0x0f; if (dest_len <0 || dest_len > 15) { cb_log(1,bc->port, "IE is garbage: FAC_CALLDEFLECT\n"); return ; } if (fac_len < 15+dest_len) { cb_log(1,bc->port, "IE too short: FAC_CALLDEFLECT\n"); return ; } memcpy(cd_nr, &fac[15],dest_len); cd_nr[dest_len]=0; cb_log(5,bc->port, "--> IE CALLDEFLECT NR: %s\n",cd_nr); } } void fac_enc( unsigned char **ntmsg, msg_t * msg, enum facility_type type, union facility fac, struct misdn_bchannel *bc) { switch (type) { case FACILITY_CENTREX: { int setup=0; enc_ie_facility_centrex(ntmsg, msg, fac.cnip, setup, bc->nt, bc); } break; case FACILITY_CALLDEFLECT: enc_ie_facility_calldeflect(ntmsg, msg, fac.calldeflect_nr, bc->nt, bc); break; default: cb_log(1,0,"Don't know how handle this facility: %d\n", type); } } void fac_dec( unsigned char *p, Q931_info_t *qi, enum facility_type *type, union facility *fac, struct misdn_bchannel *bc) { int i, fac_len=0; unsigned char facility[256]; if (! (bc->nt) ) { p = NULL; if (qi->QI_ELEMENT(facility)) p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(facility) + 1; } if (!p) return; fac_len = p[0]; memcpy(facility, p+1, fac_len); switch(facility[0]) { case FACILITY_CENTREX: { int cnip_len=15; dec_ie_facility_centrex(p, qi,facility, fac_len, fac->cnip, cnip_len, bc->nt, bc); *type=FACILITY_CENTREX; } break; case FACILITY_CALLDEFLECT: dec_ie_facility_calldeflect(p, qi,facility, fac_len, fac->calldeflect_nr, bc->nt, bc); *type=FACILITY_CALLDEFLECT; break; default: cb_log(3, bc->port, "Unknown Facility received: "); i = 0; while(i < fac_len) { cb_log(3, bc->port, " %02x", facility[i]); i++; } cb_log(3, bc->port, " facility\n"); *type=FACILITY_NONE; } } /*** FACILITY END **/