libisdn
|
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 }