libisdn
X213.c
Go to the documentation of this file.
00001 /*
00002  * X.213 NSAP address handling (for Q.931 Calling/-ed Party Subaddress IE)
00003  *
00004  *
00005  */
00006 #ifdef HAVE_CONFIG_H
00007 #include "config.h"
00008 #endif
00009 
00010 #include <stdio.h>
00011 #include <string.h>
00012 
00013 #include "X213.h"
00014 #include "ISO3166.h"
00015 
00016 #include "utils/common.h"
00017 
00018 /**********************************************************************
00019  * Constants
00020  **********************************************************************/
00021 
00022 #define NSAP_IDI_X121_LEN               7       /* 7 octets: 14 digits */
00023 #define NSAP_IDI_ISO_DCC_LEN            2       /* 2 octets:  3 digits + padding */
00024 #define NSAP_IDI_F69_LEN                4       /* 4 octets:  8 digits */
00025 #define NSAP_IDI_E163_LEN               6       /* 6 octets: 12 digits */
00026 #define NSAP_IDI_E164_LEN               8       /* 8 octets: 15 digits + padding */
00027 #define NSAP_IDI_ISO_6523_ICD_LEN       3       /* 3 octets:  6 digits */
00028 #define NSAP_IDI_IANA_ICP_LEN           2       /* 2 octets:  4 digits */
00029 #define NSAP_IDI_ITU_T_IND_LEN          3       /* 3 octets:  6 digits */
00030 #define NSAP_IDI_LOCAL_LEN              0       /* no IDI */
00031 
00032 
00033 /**********************************************************************
00034  * Tables
00035  **********************************************************************/
00036 
00037 static const struct nsap_afi_info {
00038         const unsigned char afi;
00039         const unsigned char max_dsp_length;
00040         const nsap_idi_format_t idi_format;
00041         const nsap_dsp_syntax_t dsp_syntax;
00042 } nsap_afi_info_map[] = {
00043         { 0x36, NSAP_IDI_X121, NSAP_DSP_DECIMAL, 24 },
00044         { 0x37, NSAP_IDI_X121, NSAP_DSP_BINARY,  12 },
00045         { 0x52, NSAP_IDI_X121, NSAP_DSP_DECIMAL, 24 },
00046         { 0x53, NSAP_IDI_X121, NSAP_DSP_BINARY,  12 },
00047 
00048         { 0x38, NSAP_IDI_ISO_DCC, NSAP_DSP_DECIMAL, 35 },
00049         { 0x39, NSAP_IDI_ISO_DCC, NSAP_DSP_BINARY,  17 },
00050 
00051         { 0x40, NSAP_IDI_F69, NSAP_DSP_DECIMAL, 30 },
00052         { 0x41, NSAP_IDI_F69, NSAP_DSP_BINARY,  15 },
00053         { 0x54, NSAP_IDI_F69, NSAP_DSP_DECIMAL, 30 },
00054         { 0x55, NSAP_IDI_F69, NSAP_DSP_BINARY,  15 },
00055 
00056         { 0x42, NSAP_IDI_E163, NSAP_DSP_DECIMAL, 26 },
00057         { 0x43, NSAP_IDI_E163, NSAP_DSP_BINARY,  13 },
00058         { 0x56, NSAP_IDI_E163, NSAP_DSP_DECIMAL, 26 },
00059         { 0x57, NSAP_IDI_E163, NSAP_DSP_BINARY,  13 },
00060 
00061         { 0x44, NSAP_IDI_E164, NSAP_DSP_DECIMAL, 23 },
00062         { 0x45, NSAP_IDI_E164, NSAP_DSP_BINARY,  11 },
00063         { 0x58, NSAP_IDI_E164, NSAP_DSP_DECIMAL, 23 },
00064         { 0x59, NSAP_IDI_E164, NSAP_DSP_BINARY,  11 },
00065 
00066         { 0x46, NSAP_IDI_ISO_6523_ICD, NSAP_DSP_DECIMAL, 34 },
00067         { 0x47, NSAP_IDI_ISO_6523_ICD, NSAP_DSP_BINARY,  17 },
00068 
00069         { 0x34, NSAP_IDI_IANA_ICP, NSAP_DSP_DECIMAL, 34 },
00070         { 0x35, NSAP_IDI_IANA_ICP, NSAP_DSP_BINARY,  17 },
00071 
00072         { 0x76, NSAP_IDI_ITU_T_IND, NSAP_DSP_DECIMAL, 32 },
00073         { 0x77, NSAP_IDI_ITU_T_IND, NSAP_DSP_BINARY,  16 },
00074 
00075         { 0x48, NSAP_IDI_LOCAL, NSAP_DSP_DECIMAL,     38 },
00076         { 0x49, NSAP_IDI_LOCAL, NSAP_DSP_BINARY,      19 },
00077         { 0x50, NSAP_IDI_LOCAL, NSAP_DSP_ISO_IEC_646, 19 },
00078         { 0x51, NSAP_IDI_LOCAL, NSAP_DSP_NATIONAL,     9 },
00079 };
00080 
00081 static const struct nsap_afi_info *nsap_afi(unsigned char afi)
00082 {
00083         for (int i = 0; i < ARRAY_SIZE(nsap_afi_info_map); i++) {
00084                 if (nsap_afi_info_map[i].afi == afi)
00085                         return &nsap_afi_info_map[i];
00086         }
00087         return NULL;
00088 }
00089 
00090 static const char *nsap_idi_type(nsap_idi_format_t idi)
00091 {
00092         switch (idi) {
00093         case NSAP_IDI_X121:
00094                 return "X.121";
00095         case NSAP_IDI_ISO_DCC:
00096                 return "ISO DCC";
00097         case NSAP_IDI_F69:
00098                 return "F.69";
00099         case NSAP_IDI_E163:
00100                 return "E.163";
00101         case NSAP_IDI_E164:
00102                 return "E.164";
00103         case NSAP_IDI_ISO_6523_ICD:
00104                 return "ISO 6523-ICD";
00105         case NSAP_IDI_IANA_ICP:
00106                 return "IANA ICP";
00107         case NSAP_IDI_ITU_T_IND:
00108                 return "ITU-T IND";
00109         case NSAP_IDI_LOCAL:
00110                 return "Local";
00111         default:
00112                 return "unknown/invalid";
00113         }
00114 }
00115 
00116 
00117 static int nsap_idi_decode_x121(struct nsap_addr *nsap, char *buf, int size)
00118 {
00119         return NSAPE_NO_ERROR;
00120 }
00121 
00122 
00123 static inline int nsap_bcd2binary32(const char *buf, const int bufsize)
00124 {
00125         int value = buf[0] & 0x0f;
00126         char nibble = 0;
00127 
00128         for (int i = !0, offset = 0; offset < bufsize; i = !i) {
00129                 nibble = ((i) ? (buf[offset] >> 4) : buf[offset]) & 0x0f;
00130                 if (nibble == 0x0f)     /* padding */
00131                         break;
00132                 value = (value * 10) + nibble;
00133                 if (!(i)) offset++;
00134         }
00135         return value;
00136 }
00137 
00138 static inline int nsap_bcd2ascii(const char *inb, const int inbsize, char *outb, const int outbsize)
00139 {
00140         static const char c[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'X', 'X', 'X', 'X', 'X', 'X' };
00141         int nibble = 0, i, j;
00142 
00143         for (i = 0, j = 0; i < inbsize && j < outbsize; j++) {
00144                 nibble = ((j & 1) ? (inb[i] >> 4) : inb[i])  & 0x0f;
00145                 if (nibble == 0x0f)     /* padding */
00146                         break;
00147                 outb[j] = c[nibble];
00148                 if (j & 1) i++;
00149         }
00150         return j;
00151 }
00152 
00153 static int nsap_idi_decode_iso_dcc(struct nsap_addr *nsap, char *buf, int size)
00154 {
00155         if (size < NSAP_IDI_ISO_DCC_LEN)
00156                 return NSAPE_TOO_SHORT;
00157 
00158         nsap->nsap_a_iso_dcc.dcc = nsap_bcd2binary32(buf, NSAP_IDI_ISO_DCC_LEN);
00159 
00160         if (iso3166_by_id(nsap->nsap_a_iso_dcc.dcc, &nsap->nsap_a_iso_dcc.name, &nsap->nsap_a_iso_dcc.code) < 0)
00161                 return NSAPE_GENERR;
00162 
00163         return NSAPE_NO_ERROR;
00164 }
00165 
00166 
00167 static int nsap_idi_decode_f69(struct nsap_addr *nsap, char *buf, int size)
00168 {
00169         int offset = 0;
00170 
00171         if (size < NSAP_IDI_F69_LEN)
00172                 return NSAPE_TOO_SHORT;
00173 
00174         nsap_bcd2ascii(buf, NSAP_IDI_F69_LEN, nsap->nsap_a_f69.telex, sizeof(nsap->nsap_a_f69.telex) - 1);
00175         offset += NSAP_IDI_F69_LEN;
00176 
00177         switch (nsap->dsp) {
00178         case NSAP_DSP_BINARY:
00179                 memcpy(nsap->nsap_a_f69.value, &buf[NSAP_IDI_F69_LEN], MIN(size - NSAP_IDI_F69_LEN, sizeof(nsap->nsap_a_f69.value) - 1));
00180                 break;
00181         case NSAP_DSP_DECIMAL:
00182                 nsap_bcd2ascii(&buf[NSAP_IDI_F69_LEN], size - NSAP_IDI_F69_LEN, nsap->nsap_a_f69.value, sizeof(nsap->nsap_a_f69.value) - 1);
00183                 break;
00184         default:
00185                 return NSAPE_INVALID_FORMAT;
00186         }
00187         return NSAPE_NO_ERROR;
00188 }
00189 
00190 
00191 static int nsap_idi_decode_e163(struct nsap_addr *nsap, char *buf, int size)
00192 {
00193         if (size < NSAP_IDI_E163_LEN)
00194                 return NSAPE_TOO_SHORT;
00195 
00196         memset(&nsap->nsap_a_e163, 0, sizeof(nsap->nsap_a_e163));
00197 
00198         nsap_bcd2ascii(buf, NSAP_IDI_E163_LEN, nsap->nsap_a_e163.number, sizeof(nsap->nsap_a_e163.number) - 1);
00199 
00200         switch (nsap->dsp) {
00201         case NSAP_DSP_BINARY:
00202                 memcpy(nsap->nsap_a_e163.value, &buf[NSAP_IDI_E163_LEN], MIN(size - NSAP_IDI_E163_LEN, sizeof(nsap->nsap_a_e163.value) - 1));
00203                 break;
00204         case NSAP_DSP_DECIMAL:
00205                 nsap_bcd2ascii(&buf[NSAP_IDI_E163_LEN], size - NSAP_IDI_E163_LEN, nsap->nsap_a_e163.value, sizeof(nsap->nsap_a_e163.value) - 1);
00206                 break;
00207         default:
00208                 return NSAPE_INVALID_FORMAT;
00209         }
00210         return NSAPE_NO_ERROR;
00211 }
00212 
00213 
00214 static int nsap_idi_decode_e164(struct nsap_addr *nsap, char *buf, int size)
00215 {
00216         if (size < NSAP_IDI_E164_LEN)
00217                 return NSAPE_TOO_SHORT;
00218 
00219         memset(&nsap->nsap_a_e164, 0, sizeof(nsap->nsap_a_e164));
00220 
00221         nsap_bcd2ascii(buf, NSAP_IDI_E164_LEN, nsap->nsap_a_e164.number, sizeof(nsap->nsap_a_e164.number) - 1);
00222 
00223         switch (nsap->dsp) {
00224         case NSAP_DSP_BINARY:
00225                 memcpy(nsap->nsap_a_e164.value, &buf[NSAP_IDI_E164_LEN], MIN(size - NSAP_IDI_E164_LEN, sizeof(nsap->nsap_a_e164.value) - 1));
00226                 break;
00227         case NSAP_DSP_DECIMAL:
00228                 nsap_bcd2ascii(&buf[NSAP_IDI_E164_LEN], size - NSAP_IDI_E164_LEN, nsap->nsap_a_e164.value, sizeof(nsap->nsap_a_e164.value) - 1);
00229                 break;
00230         default:
00231                 return NSAPE_INVALID_FORMAT;
00232         }
00233         return NSAPE_NO_ERROR;
00234 }
00235 
00236 
00237 static int nsap_idi_decode_iso_6523_icd(struct nsap_addr *nsap, char *buf, int size)
00238 {
00239         int offset = 0;
00240 
00241         if (size < NSAP_IDI_ISO_6523_ICD_LEN)
00242                 return NSAPE_TOO_SHORT;
00243 
00244         memset(&nsap->nsap_a_iso_6523_icd, 0, sizeof(nsap->nsap_a_iso_6523_icd));
00245 
00246         nsap->nsap_a_iso_6523_icd.icd = nsap_bcd2binary32(&buf[offset], NSAP_IDI_ISO_6523_ICD_LEN);
00247         offset += NSAP_IDI_ISO_6523_ICD_LEN;
00248 
00249         switch (nsap->dsp) {
00250         case NSAP_DSP_BINARY:
00251                 break;
00252         case NSAP_DSP_DECIMAL:
00253                 break;
00254         default:
00255                 return NSAPE_INVALID_FORMAT;
00256         }
00257         return NSAPE_NO_ERROR;
00258 }
00259 
00260 
00261 static int nsap_idi_decode_iana_icp(struct nsap_addr *nsap, char *buf, int size)
00262 {
00263         unsigned short int icp = 0;
00264         int offset = 0;
00265 
00266         if (size < NSAP_IDI_IANA_ICP_LEN)
00267                 return NSAPE_TOO_SHORT;
00268 
00269         memset(&nsap->nsap_a_iana_icp, 0, sizeof(nsap->nsap_a_iana_icp));
00270 
00271         memcpy(&icp, &buf[offset], 2);  /* copy 4 octets of ICP */
00272         offset += 2;
00273 
00274         switch (icp) {
00275         case 0x0000:    /* IPv6 */
00276                 if (size < 18)
00277                         return NSAPE_TOO_SHORT;
00278                 nsap->nsap_a_iana_icp.family = AF_INET6;
00279                 memcpy(&nsap->nsap_a_iana_icp.icp_a_ip6, &buf[offset], 16);
00280                 break;
00281         case 0x0001:    /* IPv4 */
00282                 if (size < 6)
00283                         return NSAPE_TOO_SHORT;
00284                 nsap->nsap_a_iana_icp.family = AF_INET;
00285                 memcpy(&nsap->nsap_a_iana_icp.icp_a_ip4, &buf[offset], 4);
00286                 break;
00287         default:
00288                 nsap->nsap_a_iana_icp.family = AF_UNSPEC;
00289         }
00290         return NSAPE_NO_ERROR;
00291 }
00292 
00293 
00294 static int nsap_idi_decode_itu_t_ind(struct nsap_addr *nsap, char *buf, int size)
00295 {
00296         int offset = 0;
00297 
00298         if (size < NSAP_IDI_ITU_T_IND_LEN)
00299                 return NSAPE_TOO_SHORT;
00300 
00301         memset(&nsap->nsap_a_itu_t_ind, 0, sizeof(nsap->nsap_a_itu_t_ind));
00302 
00303         nsap->nsap_a_itu_t_ind.ind = nsap_bcd2binary32(&buf[offset], NSAP_IDI_ITU_T_IND_LEN);
00304         offset += NSAP_IDI_ITU_T_IND_LEN;
00305 
00306         switch (nsap->dsp) {
00307         case NSAP_DSP_BINARY:
00308                 break;
00309         case NSAP_DSP_DECIMAL:
00310                 break;
00311         default:
00312                 return NSAPE_INVALID_FORMAT;
00313         }
00314         return NSAPE_NO_ERROR;
00315 }
00316 
00317 
00318 static int nsap_idi_decode_local(struct nsap_addr *nsap, char *buf, int size)
00319 {
00320         switch (nsap->dsp) {
00321         case NSAP_DSP_BINARY:
00322                 break;
00323         case NSAP_DSP_DECIMAL:
00324                 break;
00325         case NSAP_DSP_ISO_IEC_646:
00326                 break;
00327         case NSAP_DSP_NATIONAL:
00328                 break;
00329         default:
00330                 return NSAPE_INVALID_FORMAT;
00331         }
00332         return NSAPE_NO_ERROR;
00333 }
00334 
00340 int nsap_afi_valid(const char afi)
00341 {
00342         return !((afi >= 0x00 && afi <= 0x0f) || afi == 0xff);
00343 }
00344 
00345 int nsap_decode(struct nsap_addr *addr, char *buf, int size)
00346 {
00347         int offset = 0;
00348         int ret = 0;
00349 
00350         const struct nsap_afi_info *afi = nsap_afi(buf[offset++]);
00351         if (!afi)
00352                 return NSAPE_NO_ERROR;
00353 
00354         addr->idi = afi->idi_format;
00355         addr->dsp = afi->dsp_syntax;
00356         addr->max_dsp_length = afi->max_dsp_length;
00357 
00358         switch (addr->idi) {
00359         case NSAP_IDI_X121:
00360                 ret = nsap_idi_decode_x121(addr, &buf[offset], size - offset);
00361                 break;
00362         case NSAP_IDI_ISO_DCC:
00363                 ret = nsap_idi_decode_iso_dcc(addr, &buf[offset], size - offset);
00364                 break;
00365         case NSAP_IDI_F69:
00366                 ret = nsap_idi_decode_f69(addr, &buf[offset], size - offset);
00367                 break;
00368         case NSAP_IDI_E163:
00369                 ret = nsap_idi_decode_e163(addr, &buf[offset], size - offset);
00370                 break;
00371         case NSAP_IDI_E164:
00372                 ret = nsap_idi_decode_e164(addr, &buf[offset], size - offset);
00373                 break;
00374         case NSAP_IDI_ISO_6523_ICD:
00375                 ret = nsap_idi_decode_iso_6523_icd(addr, &buf[offset], size - offset);
00376                 break;
00377         case NSAP_IDI_IANA_ICP:
00378                 ret = nsap_idi_decode_iana_icp(addr, &buf[offset], size - offset);
00379                 break;
00380         case NSAP_IDI_ITU_T_IND:
00381                 ret = nsap_idi_decode_itu_t_ind(addr, &buf[offset], size - offset);
00382                 break;
00383         case NSAP_IDI_LOCAL:
00384                 ret = nsap_idi_decode_local(addr, &buf[offset], size - offset);
00385                 break;
00386         default:
00387                 break;
00388         }
00389 
00390         if (ret <= 0)
00391                 return ret;
00392 
00393         offset += ret;
00394 
00395         return offset;
00396 }
00397 
00405 int nsap_print(struct nsap_addr *addr, char *buf, int size)
00406 {
00407         int offset = 0;
00408 
00409         offset += snprintf(buf, size, "%s ", nsap_idi_type(addr->idi));
00410 
00411         switch (addr->idi) {
00412         case NSAP_IDI_IANA_ICP:
00413                 switch (addr->nsap_a_iana_icp.family) {
00414 #if defined(HAVE_INET_NTOP)
00415                 case AF_INET:
00416                         strncat(&buf[offset], "IPv4: ", size - offset);
00417                         offset = strlen(buf);
00418                         inet_ntop(AF_INET, &addr->nsap_a_iana_icp.icp_a_ip4, &buf[offset], size - offset);
00419                         break;
00420                 case AF_INET6:
00421                         strncat(&buf[offset], "IPv6: ", size - offset);
00422                         offset = strlen(buf);
00423                         inet_ntop(AF_INET6, &addr->nsap_a_iana_icp.icp_a_ip6, &buf[offset], size - offset);
00424                         break;
00425 #elif defined(HAVE_GETNAMEINFO)
00426                 case AF_INET:
00427                         {
00428                                 struct sockaddr_in tmp;
00429 
00430                                 memcpy(&tmp.sin_addr, &addr->nsap_a_iana_icp.icp_a_ip4, sizeof(addr->nsap_a_iana_icp.icp_a_ip4));
00431                                 tmp.sin_family = AF_INET;
00432                                 tmp.sin_port = 0;
00433 
00434                                 strncat(&buf[offset], "IPv4: ", size - offset);
00435                                 offset = strlen(buf);
00436                                 getnameinfo((struct sockaddr *)&tmp, sizeof(tmp), &buf[offset], size - offset, NULL, 0, NI_NUMERICHOST);
00437                         }
00438                         break;
00439                 case AF_INET6:
00440                         {
00441                                 struct sockaddr_in6 tmp;
00442 
00443                                 memcpy(&tmp.sin6_addr, &addr->nsap_a_iana_icp.icp_a_ip6, sizeof(addr->nsap_a_iana_icp.icp_a_ip6));
00444                                 tmp.sin6_family = AF_INET6;
00445                                 tmp.sin6_port = 0;
00446 
00447                                 strncat(&buf[offset], "IPv6: ", size - offset);
00448                                 offset = strlen(buf);
00449                                 getnameinfo((struct sockaddr *)&tmp, sizeof(tmp), &buf[offset], size - offset, NULL, 0, NI_NUMERICHOST);
00450                         }
00451                         break;
00452 #else
00453                 /*
00454                  * Poor man's (probably endianess-broken) replacement for missing getnameinfo() and inet_ntop()
00455                  * Only added to silence the WIN32 build which keeps failing to find its getnameinfo() function provided
00456                  * by winsock2
00457                  *
00458                  * @todo        Add custom getnameinfo() and inet_ntop() autoconf checks which includes ws2tcpip.h et.al.
00459                  *              (and then remove this stuff)
00460                  */
00461                 case AF_INET:
00462                         {
00463                                 char tmp[4];
00464 
00465                                 memcpy(tmp, &addr->nsap_a_iana_icp.icp_a_ip4.s_addr, 4);
00466                                 snprintf(&buf[offset], size - offset, "IPv4: %d.%d.%d.%d", tmp[0], tmp[1], tmp[2], tmp[3]);
00467                                 offset = strlen(buf);
00468                         }
00469                         break;
00470                 case AF_INET6:
00471                         {
00472                                 short tmp[8];
00473 
00474                                 memcpy(tmp, &addr->nsap_a_iana_icp.icp_a_ip6.s6_addr, 16);
00475                                 snprintf(&buf[offset], size - offset, "IPv6: %x:%x:%x:%x:%x:%x:%x:%x",
00476                                         tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7]);
00477                                 offset = strlen(buf);
00478                         }
00479                         break;
00480 #endif
00481                 case AF_UNSPEC:
00482                         strncat(&buf[offset], "-N/A-", size - offset);
00483                         break;
00484                 }
00485                 break;
00486         case NSAP_IDI_X121:
00487                 break;
00488         case NSAP_IDI_F69:
00489                 offset += snprintf(&buf[offset], size - offset, "Authority: %s, Value: ", addr->nsap_a_f69.telex);
00490                 switch (addr->dsp) {
00491                 case NSAP_DSP_DECIMAL:
00492                         strncat(&buf[offset], addr->nsap_a_f69.value, size - offset);
00493                         offset = strlen(buf);
00494                         break;
00495                 default:
00496                         /* print hex */
00497                         break;
00498                 }
00499                 break;
00500         case NSAP_IDI_E163:
00501                 strncat(&buf[offset], "Number: ", size - offset);
00502                 offset += strlen(buf);
00503                 switch (addr->dsp) {
00504                 case NSAP_DSP_DECIMAL:
00505                         strncat(&buf[offset], addr->nsap_a_e163.value, size - offset);
00506                         offset = strlen(buf);
00507                         break;
00508                 default:
00509                         /* print hex */
00510                         break;
00511                 }
00512                 break;
00513         case NSAP_IDI_E164:
00514                 strncat(&buf[offset], "Number: ", size - offset);
00515                 offset += strlen(buf);
00516                 switch (addr->dsp) {
00517                 case NSAP_DSP_DECIMAL:
00518                         strncat(&buf[offset], addr->nsap_a_e164.value, size - offset);
00519                         offset = strlen(buf);
00520                         break;
00521                 default:
00522                         /* print hex */
00523                         break;
00524                 }
00525                 break;
00526         case NSAP_IDI_ITU_T_IND:
00527                 offset += snprintf(&buf[offset], size - offset, "IND: %6d, Value: ", addr->nsap_a_itu_t_ind.ind);
00528                 switch (addr->dsp) {
00529                 case NSAP_DSP_DECIMAL:
00530                         strncat(&buf[offset], addr->nsap_a_itu_t_ind.value, size - offset);
00531                         offset = strlen(buf);
00532                         break;
00533                 default:
00534                         /* print hex */
00535                         break;
00536                 }
00537                 break;
00538         case NSAP_IDI_ISO_DCC:
00539                 offset += snprintf(&buf[offset], size - offset, "ISO Code: %2s, Value: ", addr->nsap_a_iso_dcc.code);
00540                 switch (addr->dsp) {
00541                 case NSAP_DSP_DECIMAL:
00542                         strncat(&buf[offset], addr->nsap_a_iso_dcc.value, size - offset);
00543                         offset = strlen(buf);
00544                         break;
00545                 default:
00546                         /* print hex */
00547                         break;
00548                 }
00549                 break;
00550         case NSAP_IDI_ISO_6523_ICD:
00551         case NSAP_IDI_LOCAL:
00552                 strncat(buf, "decoding not implemented", size);
00553                 break;
00554         default:
00555                 strncat(buf, "-N/A-", size);
00556         }
00557         return NSAPE_NO_ERROR;
00558 }