This source file includes following definitions.
- opal_ifnametoaddr
- opal_ifnametoindex
- opal_ifnametokindex
- opal_ifindextokindex
- opal_ifaddrtoname
- opal_ifaddrtokindex
- opal_ifcount
- opal_ifbegin
- opal_ifnext
- opal_ifindextoaddr
- opal_ifkindextoaddr
- opal_ifindextomask
- opal_ifindextomac
- opal_ifindextomtu
- opal_ifindextoflags
- opal_ifindextoname
- opal_ifkindextoname
- opal_ifislocal
- parse_ipv4_dots
- opal_iftupletoaddr
- opal_ifisloopback
- opal_ifmatches
- opal_ifgetaliases
- opal_ifnametoaddr
- opal_ifaddrtoname
- opal_ifnametoindex
- opal_ifnametokindex
- opal_ifindextokindex
- opal_ifcount
- opal_ifbegin
- opal_ifnext
- opal_ifindextoname
- opal_ifkindextoname
- opal_ifindextoaddr
- opal_ifindextomask
- opal_ifislocal
- opal_iftupletoaddr
- opal_ifmatches
- opal_ifgetaliases
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 
  15 
  16 
  17 
  18 
  19 
  20 
  21 
  22 
  23 
  24 
  25 
  26 
  27 
  28 #include "opal_config.h"
  29 
  30 #include <string.h>
  31 #ifdef HAVE_UNISTD_H
  32 #include <unistd.h>
  33 #endif
  34 #include <errno.h>
  35 #ifdef HAVE_SYS_TYPES_H
  36 #include <sys/types.h>
  37 #endif
  38 #ifdef HAVE_SYS_SOCKET_H
  39 #include <sys/socket.h>
  40 #endif
  41 #ifdef HAVE_SYS_SOCKIO_H
  42 #include <sys/sockio.h>
  43 #endif
  44 #ifdef HAVE_SYS_IOCTL_H
  45 #include <sys/ioctl.h>
  46 #endif
  47 #ifdef HAVE_NETINET_IN_H
  48 #include <netinet/in.h>
  49 #endif
  50 #ifdef HAVE_ARPA_INET_H
  51 #include <arpa/inet.h>
  52 #endif
  53 #ifdef HAVE_NET_IF_H
  54 #include <net/if.h>
  55 #endif
  56 #ifdef HAVE_NETDB_H
  57 #include <netdb.h>
  58 #endif
  59 #ifdef HAVE_IFADDRS_H
  60 #include <ifaddrs.h>
  61 #endif
  62 #include <ctype.h>
  63 
  64 #include "opal/class/opal_list.h"
  65 #include "opal/util/if.h"
  66 #include "opal/util/net.h"
  67 #include "opal/util/output.h"
  68 #include "opal/util/argv.h"
  69 #include "opal/util/show_help.h"
  70 #include "opal/util/string_copy.h"
  71 #include "opal/constants.h"
  72 
  73 #include "opal/mca/if/base/base.h"
  74 
  75 #ifdef HAVE_STRUCT_SOCKADDR_IN
  76 
  77 #ifndef MIN
  78 #  define MIN(a,b)                ((a) < (b) ? (a) : (b))
  79 #endif
  80 
  81 
  82 
  83 
  84 
  85 
  86 int opal_ifnametoaddr(const char* if_name, struct sockaddr* addr, int length)
  87 {
  88     opal_if_t* intf;
  89 
  90     OPAL_LIST_FOREACH(intf, &opal_if_list, opal_if_t) {
  91         if (strcmp(intf->if_name, if_name) == 0) {
  92             memcpy(addr, &intf->if_addr, length);
  93             return OPAL_SUCCESS;
  94         }
  95     }
  96     return OPAL_ERROR;
  97 }
  98 
  99 
 100 
 101 
 102 
 103 
 104 
 105 int opal_ifnametoindex(const char* if_name)
 106 {
 107     opal_if_t* intf;
 108 
 109     OPAL_LIST_FOREACH(intf, &opal_if_list, opal_if_t) {
 110         if (strcmp(intf->if_name, if_name) == 0) {
 111             return intf->if_index;
 112         }
 113     }
 114     return -1;
 115 }
 116 
 117 
 118 
 119 
 120 
 121 
 122 
 123 int opal_ifnametokindex(const char* if_name)
 124 {
 125     opal_if_t* intf;
 126 
 127     OPAL_LIST_FOREACH(intf, &opal_if_list, opal_if_t) {
 128         if (strcmp(intf->if_name, if_name) == 0) {
 129             return intf->if_kernel_index;
 130         }
 131     }
 132     return -1;
 133 }
 134 
 135 
 136 
 137 
 138 
 139 
 140 
 141 int opal_ifindextokindex(int if_index)
 142 {
 143     opal_if_t* intf;
 144 
 145     OPAL_LIST_FOREACH(intf, &opal_if_list, opal_if_t) {
 146         if (if_index == intf->if_index) {
 147             return intf->if_kernel_index;
 148         }
 149     }
 150     return -1;
 151 }
 152 
 153 
 154 
 155 
 156 
 157 
 158 
 159 int opal_ifaddrtoname(const char* if_addr, char* if_name, int length)
 160 {
 161     opal_if_t* intf;
 162     int error;
 163     struct addrinfo hints, *res = NULL, *r;
 164 
 165     
 166     if (opal_if_do_not_resolve) {
 167         
 168 
 169 
 170         return OPAL_ERR_NOT_FOUND;
 171     }
 172 
 173     memset(&hints, 0, sizeof(hints));
 174     hints.ai_family = PF_UNSPEC;
 175     hints.ai_socktype = SOCK_STREAM;
 176     error = getaddrinfo(if_addr, NULL, &hints, &res);
 177 
 178     if (error) {
 179         if (NULL != res) {
 180             freeaddrinfo (res);
 181         }
 182         return OPAL_ERR_NOT_FOUND;
 183     }
 184 
 185     for (r = res; r != NULL; r = r->ai_next) {
 186         OPAL_LIST_FOREACH(intf, &opal_if_list, opal_if_t) {
 187             if (AF_INET == r->ai_family) {
 188                 struct sockaddr_in ipv4;
 189                 struct sockaddr_in *inaddr;
 190 
 191                 inaddr = (struct sockaddr_in*) &intf->if_addr;
 192                 memcpy (&ipv4, r->ai_addr, r->ai_addrlen);
 193 
 194                 if (inaddr->sin_addr.s_addr == ipv4.sin_addr.s_addr) {
 195                     opal_string_copy(if_name, intf->if_name, length);
 196                     freeaddrinfo (res);
 197                     return OPAL_SUCCESS;
 198                 }
 199             }
 200 #if OPAL_ENABLE_IPV6
 201             else {
 202                 if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6*) &intf->if_addr)->sin6_addr,
 203                     &((struct sockaddr_in6*) r->ai_addr)->sin6_addr)) {
 204                     opal_string_copy(if_name, intf->if_name, length);
 205                     freeaddrinfo (res);
 206                     return OPAL_SUCCESS;
 207                 }
 208             }
 209 #endif
 210         }
 211     }
 212     if (NULL != res) {
 213         freeaddrinfo (res);
 214     }
 215 
 216     
 217     return OPAL_ERR_NOT_FOUND;
 218 }
 219 
 220 
 221 
 222 
 223 
 224 
 225 int opal_ifaddrtokindex(const char* if_addr)
 226 {
 227     opal_if_t* intf;
 228     int error;
 229     struct addrinfo hints, *res = NULL, *r;
 230     int if_kernel_index;
 231     size_t len;
 232 
 233     memset(&hints, 0, sizeof(hints));
 234     hints.ai_family = PF_UNSPEC;
 235     hints.ai_socktype = SOCK_STREAM;
 236     error = getaddrinfo(if_addr, NULL, &hints, &res);
 237 
 238     if (error) {
 239         if (NULL != res) {
 240             freeaddrinfo (res);
 241         }
 242         return OPAL_ERR_NOT_FOUND;
 243     }
 244 
 245     for (r = res; r != NULL; r = r->ai_next) {
 246         OPAL_LIST_FOREACH(intf, &opal_if_list, opal_if_t) {
 247             if (AF_INET == r->ai_family && AF_INET == intf->af_family) {
 248                 struct sockaddr_in ipv4;
 249                 len = (r->ai_addrlen < sizeof(struct sockaddr_in)) ? r->ai_addrlen : sizeof(struct sockaddr_in);
 250                 memcpy(&ipv4, r->ai_addr, len);
 251                 if (opal_net_samenetwork((struct sockaddr*)&ipv4, (struct sockaddr*)&intf->if_addr, intf->if_mask)) {
 252                     if_kernel_index = intf->if_kernel_index;
 253                     freeaddrinfo (res);
 254                     return if_kernel_index;
 255                 }
 256             }
 257 #if OPAL_ENABLE_IPV6
 258             else if (AF_INET6 == r->ai_family && AF_INET6 == intf->af_family) {
 259                 struct sockaddr_in6 ipv6;
 260                 len = (r->ai_addrlen < sizeof(struct sockaddr_in6)) ? r->ai_addrlen : sizeof(struct sockaddr_in6);
 261                 memcpy(&ipv6, r->ai_addr, len);
 262                 if (opal_net_samenetwork((struct sockaddr*)((struct sockaddr_in6*)&intf->if_addr),
 263                                          (struct sockaddr*)&ipv6, intf->if_mask)) {
 264                     if_kernel_index = intf->if_kernel_index;
 265                     freeaddrinfo (res);
 266                     return if_kernel_index;
 267                 }
 268             }
 269 #endif
 270         }
 271     }
 272     if (NULL != res) {
 273         freeaddrinfo (res);
 274     }
 275     return OPAL_ERR_NOT_FOUND;
 276 }
 277 
 278 
 279 
 280 
 281 
 282 int opal_ifcount(void)
 283 {
 284     return opal_list_get_size(&opal_if_list);
 285 }
 286 
 287 
 288 
 289 
 290 
 291 
 292 
 293 int opal_ifbegin(void)
 294 {
 295     opal_if_t *intf;
 296 
 297     intf = (opal_if_t*)opal_list_get_first(&opal_if_list);
 298     if (NULL != intf)
 299         return intf->if_index;
 300     return (-1);
 301 }
 302 
 303 
 304 
 305 
 306 
 307 
 308 
 309 
 310 int opal_ifnext(int if_index)
 311 {
 312     opal_if_t *intf;
 313 
 314     OPAL_LIST_FOREACH(intf, &opal_if_list, opal_if_t) {
 315         if (intf->if_index == if_index) {
 316             do {
 317                 opal_if_t* if_next = (opal_if_t*)opal_list_get_next(intf);
 318                 opal_if_t* if_end =  (opal_if_t*)opal_list_get_end(&opal_if_list);
 319                 if (if_next == if_end) {
 320                     return -1;
 321                 }
 322                 intf = if_next;
 323             } while(intf->if_index == if_index);
 324             return intf->if_index;
 325         }
 326     }
 327     return (-1);
 328 }
 329 
 330 
 331 
 332 
 333 
 334 
 335 
 336 int opal_ifindextoaddr(int if_index, struct sockaddr* if_addr, unsigned int length)
 337 {
 338     opal_if_t* intf;
 339 
 340     OPAL_LIST_FOREACH(intf, &opal_if_list, opal_if_t) {
 341         if (intf->if_index == if_index) {
 342             memcpy(if_addr, &intf->if_addr, MIN(length, sizeof (intf->if_addr)));
 343             return OPAL_SUCCESS;
 344         }
 345     }
 346     return OPAL_ERROR;
 347 }
 348 
 349 
 350 
 351 
 352 
 353 
 354 int opal_ifkindextoaddr(int if_kindex, struct sockaddr* if_addr, unsigned int length)
 355 {
 356     opal_if_t* intf;
 357 
 358     OPAL_LIST_FOREACH(intf, &opal_if_list, opal_if_t) {
 359         if (intf->if_kernel_index == if_kindex) {
 360             memcpy(if_addr, &intf->if_addr, MIN(length, sizeof (intf->if_addr)));
 361             return OPAL_SUCCESS;
 362         }
 363     }
 364     return OPAL_ERROR;
 365 }
 366 
 367 
 368 
 369 
 370 
 371 
 372 
 373 int opal_ifindextomask(int if_index, uint32_t* if_mask, int length)
 374 {
 375     opal_if_t* intf;
 376 
 377     OPAL_LIST_FOREACH(intf, &opal_if_list, opal_if_t) {
 378         if (intf->if_index == if_index) {
 379             memcpy(if_mask, &intf->if_mask, length);
 380             return OPAL_SUCCESS;
 381         }
 382     }
 383     return OPAL_ERROR;
 384 }
 385 
 386 
 387 
 388 
 389 
 390 
 391 int opal_ifindextomac(int if_index, uint8_t mac[6])
 392 {
 393     opal_if_t* intf;
 394 
 395     OPAL_LIST_FOREACH(intf, &opal_if_list, opal_if_t) {
 396         if (intf->if_index == if_index) {
 397             memcpy(mac, &intf->if_mac, 6);
 398             return OPAL_SUCCESS;
 399         }
 400     }
 401     return OPAL_ERROR;
 402 }
 403 
 404 
 405 
 406 
 407 
 408 
 409 int opal_ifindextomtu(int if_index, int *mtu)
 410 {
 411     opal_if_t* intf;
 412 
 413     OPAL_LIST_FOREACH(intf, &opal_if_list, opal_if_t) {
 414         if (intf->if_index == if_index) {
 415             *mtu = intf->ifmtu;
 416             return OPAL_SUCCESS;
 417         }
 418     }
 419     return OPAL_ERROR;
 420 }
 421 
 422 
 423 
 424 
 425 
 426 
 427 int opal_ifindextoflags(int if_index, uint32_t* if_flags)
 428 {
 429     opal_if_t* intf;
 430 
 431     OPAL_LIST_FOREACH(intf, &opal_if_list, opal_if_t) {
 432         if (intf->if_index == if_index) {
 433             memcpy(if_flags, &intf->if_flags, sizeof(uint32_t));
 434             return OPAL_SUCCESS;
 435         }
 436     }
 437     return OPAL_ERROR;
 438 }
 439 
 440 
 441 
 442 
 443 
 444 
 445 
 446 
 447 int opal_ifindextoname(int if_index, char* if_name, int length)
 448 {
 449     opal_if_t *intf;
 450 
 451     OPAL_LIST_FOREACH(intf, &opal_if_list, opal_if_t) {
 452         if (intf->if_index == if_index) {
 453             opal_string_copy(if_name, intf->if_name, length);
 454             return OPAL_SUCCESS;
 455         }
 456     }
 457     return OPAL_ERROR;
 458 }
 459 
 460 
 461 
 462 
 463 
 464 
 465 
 466 int opal_ifkindextoname(int if_kindex, char* if_name, int length)
 467 {
 468     opal_if_t *intf;
 469 
 470     OPAL_LIST_FOREACH(intf, &opal_if_list, opal_if_t) {
 471         if (intf->if_kernel_index == if_kindex) {
 472             opal_string_copy(if_name, intf->if_name, length);
 473             return OPAL_SUCCESS;
 474         }
 475     }
 476     return OPAL_ERROR;
 477 }
 478 
 479 
 480 #define ADDRLEN 100
 481 bool
 482 opal_ifislocal(const char *hostname)
 483 {
 484 #if OPAL_ENABLE_IPV6
 485     char addrname[NI_MAXHOST]; 
 486 
 487 #else
 488     char addrname[ADDRLEN + 1];
 489 #endif
 490 
 491     if (OPAL_SUCCESS == opal_ifaddrtoname(hostname, addrname, ADDRLEN)) {
 492         return true;
 493     }
 494 
 495     return false;
 496 }
 497 
 498 static int parse_ipv4_dots(const char *addr, uint32_t* net, int* dots)
 499 {
 500     const char *start = addr, *end;
 501     uint32_t n[]={0,0,0,0};
 502     int i;
 503 
 504     
 505     for( i = 0; i < 4; i++ ) {
 506         n[i] = strtoul(start, (char**)&end, 10);
 507         if( end == start ) {
 508             
 509 
 510 
 511 
 512 
 513             break;
 514         }
 515         
 516         if( n[i] > 255 ) {
 517             return OPAL_ERR_NETWORK_NOT_PARSEABLE;
 518         }
 519         
 520         for( start = end; '\0' != *start; start++ )
 521             if( '.' != *start ) break;
 522     }
 523     *dots = i;
 524     *net = OPAL_IF_ASSEMBLE_NETWORK(n[0], n[1], n[2], n[3]);
 525     return OPAL_SUCCESS;
 526 }
 527 
 528 int
 529 opal_iftupletoaddr(const char *inaddr, uint32_t *net, uint32_t *mask)
 530 {
 531     int pval, dots, rc = OPAL_SUCCESS;
 532     const char *ptr;
 533 
 534     
 535     if (NULL != mask) {
 536         
 537         *mask = 0xFFFFFFFF;
 538 
 539         
 540         if (NULL != (ptr = strchr(inaddr, '/'))) {
 541             ptr = ptr + 1;  
 542             
 543             if (NULL != strchr(ptr, '.')) {
 544                 
 545                 rc = parse_ipv4_dots(ptr, mask, &dots);
 546             } else {
 547                 
 548 
 549 
 550                 pval = strtol(ptr, NULL, 10);
 551                 if ((pval > 31) || (pval < 1)) {
 552                     opal_output(0, "opal_iftupletoaddr: unknown mask");
 553                     return OPAL_ERR_NETWORK_NOT_PARSEABLE;
 554                 }
 555                 *mask = 0xFFFFFFFF << (32 - pval);
 556             }
 557         } else {
 558             
 559             for (ptr = inaddr, pval = 0; '\0'!= *ptr; ptr++) {
 560                 if ('.' == *ptr) {
 561                     pval++;
 562                 }
 563             }
 564             
 565 
 566 
 567 
 568             if (3 == pval) {
 569                 *mask = 0xFFFFFFFF;
 570             } else if (2 == pval) {         
 571                 *mask = 0xFFFFFF00;
 572             } else if (1 == pval) {  
 573                 *mask = 0xFFFF0000;
 574             } else if (0 == pval) {  
 575                 *mask = 0xFF000000;
 576             } else {
 577                 opal_output(0, "opal_iftupletoaddr: unknown mask");
 578                 return OPAL_ERR_NETWORK_NOT_PARSEABLE;
 579             }
 580         }
 581     }
 582 
 583     
 584     if (NULL != net) {
 585         
 586         rc = parse_ipv4_dots(inaddr, net, &dots);
 587     }
 588 
 589     return rc;
 590 }
 591 
 592 
 593 
 594 
 595 
 596 bool opal_ifisloopback(int if_index)
 597 {
 598     opal_if_t* intf;
 599 
 600     OPAL_LIST_FOREACH(intf, &opal_if_list, opal_if_t) {
 601         if (intf->if_index == if_index) {
 602             if ((intf->if_flags & IFF_LOOPBACK) != 0) {
 603                 return true;
 604             }
 605         }
 606     }
 607     return false;
 608 }
 609 
 610 
 611 
 612 
 613 
 614 int opal_ifmatches(int kidx, char **nets)
 615 {
 616     bool named_if;
 617     int i, rc;
 618     size_t j;
 619     int kindex;
 620     struct sockaddr_in inaddr;
 621     uint32_t addr, netaddr, netmask;
 622 
 623     
 624     if (OPAL_SUCCESS != (rc = opal_ifkindextoaddr(kidx, (struct sockaddr*)&inaddr, sizeof(inaddr)))) {
 625         return rc;
 626     }
 627     addr = ntohl(inaddr.sin_addr.s_addr);
 628 
 629     for (i=0; NULL != nets[i]; i++) {
 630         
 631 
 632 
 633         named_if = false;
 634         for (j=0; j < strlen(nets[i]); j++) {
 635             if (isalpha(nets[i][j]) && '.' != nets[i][j]) {
 636                 named_if = true;
 637                 break;
 638             }
 639         }
 640         if (named_if) {
 641             if (0 > (kindex = opal_ifnametokindex(nets[i]))) {
 642                 continue;
 643             }
 644             if (kindex == kidx) {
 645                 return OPAL_SUCCESS;
 646             }
 647         } else {
 648             if (OPAL_SUCCESS != (rc = opal_iftupletoaddr(nets[i], &netaddr, &netmask))) {
 649                 opal_show_help("help-opal-util.txt", "invalid-net-mask", true, nets[i]);
 650                 return rc;
 651             }
 652             if (netaddr == (addr & netmask)) {
 653                 return OPAL_SUCCESS;
 654             }
 655         }
 656     }
 657     
 658     return OPAL_ERR_NOT_FOUND;
 659 }
 660 
 661 void opal_ifgetaliases(char ***aliases)
 662 {
 663     opal_if_t* intf;
 664     char ipv4[INET_ADDRSTRLEN];
 665     struct sockaddr_in *addr;
 666 #if OPAL_ENABLE_IPV6
 667     char ipv6[INET6_ADDRSTRLEN];
 668     struct sockaddr_in6 *addr6;
 669 #endif
 670 
 671     
 672     *aliases = NULL;
 673 
 674     OPAL_LIST_FOREACH(intf, &opal_if_list, opal_if_t) {
 675         addr = (struct sockaddr_in*) &intf->if_addr;
 676         
 677         if ((intf->if_flags & IFF_LOOPBACK) != 0) {
 678             continue;
 679         }
 680         if (addr->sin_family == AF_INET) {
 681             inet_ntop(AF_INET, &(addr->sin_addr.s_addr), ipv4, INET_ADDRSTRLEN);
 682             opal_argv_append_nosize(aliases, ipv4);
 683         }
 684 #if OPAL_ENABLE_IPV6
 685         else {
 686             addr6 = (struct sockaddr_in6*) &intf->if_addr;
 687             inet_ntop(AF_INET6, &(addr6->sin6_addr), ipv6, INET6_ADDRSTRLEN);
 688             opal_argv_append_nosize(aliases, ipv6);
 689         }
 690 #endif
 691     }
 692 }
 693 
 694 #else 
 695 
 696 
 697 
 698 
 699 int
 700 opal_ifnametoaddr(const char* if_name,
 701                   struct sockaddr* if_addr, int size)
 702 {
 703     return OPAL_ERR_NOT_SUPPORTED;
 704 }
 705 
 706 int
 707 opal_ifaddrtoname(const char* if_addr,
 708                   char* if_name, int size)
 709 {
 710     return OPAL_ERR_NOT_SUPPORTED;
 711 }
 712 
 713 int
 714 opal_ifnametoindex(const char* if_name)
 715 {
 716     return OPAL_ERR_NOT_SUPPORTED;
 717 }
 718 
 719 int
 720 opal_ifnametokindex(const char* if_name)
 721 {
 722     return OPAL_ERR_NOT_SUPPORTED;
 723 }
 724 
 725 int
 726 opal_ifindextokindex(int if_index)
 727 {
 728     return OPAL_ERR_NOT_SUPPORTED;
 729 }
 730 
 731 int
 732 opal_ifcount(void)
 733 {
 734     return OPAL_ERR_NOT_SUPPORTED;
 735 }
 736 
 737 int
 738 opal_ifbegin(void)
 739 {
 740     return OPAL_ERR_NOT_SUPPORTED;
 741 }
 742 
 743 int
 744 opal_ifnext(int if_index)
 745 {
 746     return OPAL_ERR_NOT_SUPPORTED;
 747 }
 748 
 749 int
 750 opal_ifindextoname(int if_index, char* if_name, int length)
 751 {
 752     return OPAL_ERR_NOT_SUPPORTED;
 753 }
 754 
 755 int
 756 opal_ifkindextoname(int kif_index, char* if_name, int length)
 757 {
 758     return OPAL_ERR_NOT_SUPPORTED;
 759 }
 760 
 761 int
 762 opal_ifindextoaddr(int if_index, struct sockaddr* if_addr, unsigned int length)
 763 {
 764     return OPAL_ERR_NOT_SUPPORTED;
 765 }
 766 
 767 int
 768 opal_ifindextomask(int if_index, uint32_t* if_addr, int length)
 769 {
 770     return OPAL_ERR_NOT_SUPPORTED;
 771 }
 772 
 773 bool
 774 opal_ifislocal(const char *hostname)
 775 {
 776     return false;
 777 }
 778 
 779 int
 780 opal_iftupletoaddr(const char *inaddr, uint32_t *net, uint32_t *mask)
 781 {
 782     return 0;
 783 }
 784 
 785 int opal_ifmatches(int idx, char **nets)
 786 {
 787     return OPAL_ERR_NOT_SUPPORTED;
 788 }
 789 
 790 void opal_ifgetaliases(char ***aliases)
 791 {
 792     
 793     *aliases = NULL;
 794 }
 795 
 796 #endif 
 797