/* Version: V1.0 * Name: xtiutil.c * Location: sys$examples: * * ABSTRACT: * * XTITUIL contains a set of routines that help you make compatible * OSF/1 address formats. These routines are documented in the * OSF/1 programming manual and used in the example programs CX,SUBX * and SX which were ported to VMS from the OSF/1 system. * * The OSF helper routines help you create and look at OSI addresses, * these are not required under VMS. Your can create your own addresses * if you wish. * * The routines: mkosi_addr * mkdna_addr * mkinet_addr * * are used to make osi,dna inet addresses for VMS XTI. They return * the size of the appropriate addressing structure and in the case * of the OSI address, the nsap is packed. * * The file vms_osi.h is required to use these example functions. This * file contains macros, constants and data structures that are used * by the OSI examples and may be of use to the XTI programmer. * * These example routines and include files are not supported by * DIGITAL, they may change from release to release. * * * ENVIRONMENT: * * VMS V6.1 */ #include #include #include #include #include #include "vms_osi.h" /* helper constants, prototype, macros */ #define u_char unsigned char /* *** Prototypes */ void vms_set_options ( struct isoco_options *, int, int, int, int, int ); int packnsap ( u_char *, u_char *); int unpacknsap ( u_char *, int, u_char * ); int mkosi_addr ( u_char *, int, u_char *, int, u_char * ); int mkdna_addr ( u_char *, int, u_char * ); int mkinet_addr ( u_char *, int, u_char *, int, u_char * ); int xti_osigetaddr ( struct sockaddr_osi *, int *, u_char *, u_char *, int *, u_char *, u_char * ); /* int xti_osimakeaddr( struct sockaddr_osi *, int, u_char, u_char *, int, u_char, u_char * ); int osf_make_address ( int, struct sockaddr_osi *, u_char, u_char *, u_char, u_char *, u_char, u_char *); int xti_make_address ( int, struct sockaddr_osi *, u_char, u_char *, u_char, u_char *, u_char, u_char *, int, u_char * ); */ /* * Start of routines for XTI helper functions. These routines are * from xti_lib.c and modified for VMS. They allow the example programs * on OSF to run on VMS. * */ /* * User callable routine to support construction of sockaddr_osi structure * given a TSAP-ID and NSAP. * * Possible Errors: EFAULT invalid sockaddr_osi structure * EDOM length of TSAP-ID or NSAP too large. * EPROTONOSUPPORT unsupport protocol identifier. */ int xti_osimakeaddr(sosi, tid, tsapidlen, tsapid, nid, naddrlen, naddr) struct sockaddr_osi *sosi; int tid; /* transport layer protocol id */ u_char tsapidlen; u_char *tsapid; int nid; /* network layer protocol id */ u_char naddrlen; u_char *naddr; { int rstatus = 0; if (!sosi) return(EFAULT); rstatus = osf_make_address( PTY_OSI, sosi, tsapidlen, tsapid, 0, 0, naddrlen, naddr); return ( rstatus); } /* * note: ** tid and nid are not needed for VMS** * * User callable routine to support extract TSAP-ID and NSAP components * from the sockaddr_osi structure. * * Possible Errors: EFAULT invalid sockaddr_osi structure * EAFNOSUPPORT invalid address family. * EINVAL sockaddr_osi structure too small. * EDOM length of TSAP-ID or NSAP too large. * EPROTONOSUPPORT unsupport protocol identifier. */ int xti_osigetaddr(sosi, tid, tsapidlen, tsapid, nid, naddrlen, naddr) struct sockaddr_osi *sosi; int *tid; /* transport layer protocol identifier */ u_char *tsapidlen; u_char *tsapid; int *nid; /* network layer protocol identifier */ u_char *naddrlen; u_char *naddr; { struct xtiaddr_osi *osibuf = (struct xtiaddr_osi *) sosi; if (!sosi) return(EFAULT); if (osibuf->osi_family != AF_OSI) return(EAFNOSUPPORT); if (tsapidlen) *tsapidlen = 0; if (naddrlen) *naddrlen = 0; /* *** Extract TSAP */ if (tsapidlen) *tsapidlen = osibuf->osi_tsel_len; if (tsapid) memmove(tsapid,osibuf->osi_tsel,osibuf->osi_tsel_len); /* *** Extract NSAP if specified by user */ if (naddrlen) *naddrlen = osibuf->osi_nsap_len; if (naddr) memmove(naddr,osibuf->osi_nsap,osibuf->osi_nsap_len); return(0); } /* *** Internal helper routine to make an OSF address, the address must *** not include the size. */ int osf_make_address( proto_type, sosi, tsaplen, tsap, portlen, port, nlen, naddr) int proto_type; struct sockaddr_osi *sosi; u_char tsaplen; u_char *tsap; u_char portlen; u_char *port; u_char nlen; u_char *naddr; { if (proto_type <= 0) return -1; /* *** Take action based on the connection type. */ switch (proto_type) { case PTY_TCP: case PTY_UDP: /* *** Initialize the internet structure. */ { struct xtiaddr_in *inbuf = (struct xtiaddr_in *) sosi; memset( sosi, '\0', sizeof(struct xtiaddr_in) ); inbuf->in_family = AF_INET; inbuf->in_port = _swapb(*port); if (nlen > 0) memmove( (void *) inbuf->in_addr, (void *) naddr, nlen); break; } case PTY_OSI: /* *** Format OSI address, the nsap is packed by caller (like osf) */ { struct xtiaddr_osi *osibuf = (struct xtiaddr_osi *) sosi; memset( sosi, '\0', sizeof(struct xtiaddr_osi) ); osibuf->osi_family = AF_OSI; osibuf->osi_nsap_len = nlen; if (nlen > 0) memmove( osibuf->osi_nsap, naddr, nlen); osibuf->osi_tsel_len = tsaplen; if (tsaplen > 0) memmove( osibuf->osi_tsel, tsap, tsaplen); break; } default: printf("OSF Format Error for: (%d)\n", proto_type); return -1; break; } return(0); } /* * Routine to make VMS XTI related addresses. The NSAP is packed for * the user and the IP binary address is changed to little indian as * is required for vots qio. * * NOTE: The OSF helper routines assume that the NSAP is packed on * entry, this is not the case in this OSI address example we do * the pack. * * return: The size of the datastructure, used for len field of * netbuf. */ int xti_make_address( proto_type, sosi, tsaplen, tsap, portlen, port, nlen, naddr, ncblen, ncb ) struct sockaddr_osi *sosi; u_char tsaplen; u_char *tsap; u_char portlen; u_char *port; u_char nlen; u_char *naddr; int ncblen; u_char *ncb; /* formatted ncb as a string */ { int r_size; if (proto_type <= 0) return -1; r_size = 0; /* return size of data structure */ /* *** Take action based on the connection type. */ switch (proto_type) { case PTY_TCP: case PTY_UDP: /* *** Initialize the internet structure. */ { struct xtiaddr_in *inbuf = (struct xtiaddr_in *) sosi; memset( sosi, '\0', sizeof(struct xtiaddr_in) ); r_size = sizeof(struct xtiaddr_in); inbuf->in_family = AF_INET; inbuf->in_port = _swapb(*port); /* should already be swapped */ if (nlen > 0) memmove( (void *) inbuf->in_addr, (void *) naddr, nlen); break; } case PTY_DNET: /* *** Format NCB for DECnet, We should have a better structure */ { struct xtiaddr_dn *pncb = (struct xtiaddr_dn *) sosi; memset( sosi, '\0', sizeof(struct xtiaddr_dn) ); r_size = sizeof(struct xtiaddr_dn); if ( ncblen > 0) memmove( pncb->dn_addr, ncb, ncblen); break; } case PTY_OSI: /* *** Format OSI address, the nsap is packed before entry (like osf) */ { struct xtiaddr_osi *osibuf = (struct xtiaddr_osi *) sosi; u_char pnsap[32]; memset( sosi, '\0', sizeof(struct xtiaddr_osi) ); memset( pnsap, '\0', sizeof(pnsap) ); r_size = sizeof(struct xtiaddr_osi); osibuf->osi_family = AF_OSI; if (nlen > 0 ) { osibuf->osi_nsap_len = packnsap(naddr,pnsap); memmove( osibuf->osi_nsap, pnsap, nlen); } osibuf->osi_tsel_len = tsaplen; if (tsaplen > 0) memmove( osibuf->osi_tsel, tsap, tsaplen); break; } default: printf("XTI Format Error for: (%d)\n", proto_type); return -1; break; } return(r_size); } /* * The routine set_vms_options is used to in the porting of the * included here. Used in CX and SX example program. * * note: * Most users would use the t_alloc to allocate a buffer for * the options. We used a static buffer just as an alternate * example. * * Parameters are values to vms supported options * 1) class 2) expedited data 3) checksum 4) extended 5) flow ctrl * * Options 4 (extended format) and 5 ( flow control) are read only */ void vms_set_options( popts, class, expedited, checksum, extended, flowctrl ) struct isoco_options *popts; int class, expedited, checksum, extended, flowctrl; { popts->class.opthdr.len = sizeof(struct t_opthdr ) + 4; popts->class.opthdr.level = ISO_TP; popts->class.opthdr.name = TCO_PREFCLASS; popts->class.opthdr.status = T_SUCCESS; popts->class.value = class; popts->expedited.opthdr.len = sizeof(struct t_opthdr ) + 4 ; popts->expedited.opthdr.level = ISO_TP; popts->expedited.opthdr.name = TCO_EXPD; popts->expedited.opthdr.status = T_SUCCESS; popts->expedited.value = expedited; popts->checksum.opthdr.len = sizeof(struct t_opthdr ) + 4; popts->checksum.opthdr.level = ISO_TP; popts->checksum.opthdr.name = TCO_CHECKSUM; popts->checksum.opthdr.status = T_SUCCESS; popts->checksum.value = checksum; /* * The OSI options TCO_FLOWCTRL and TCO_EXTFORM are readonly, that is * if you try to set them using XTI you will get a protection * error. As an example: if you supply a buffer to t_listen for the * options buffer then blindly pass this to t_accept, this would cause * a TACCES error. You have to remove the read-only options. To take * the defaults you should NOT pass a buffer for t_listen to fill in. You * would then take the defaults options in this case. * */ popts->extended.opthdr.len = sizeof(struct t_opthdr ) + 4; popts->extended.opthdr.level = ISO_TP; popts->extended.opthdr.name = TCO_EXTFORM; popts->extended.opthdr.status = T_READONLY; popts->extended.value = T_UNSPEC; popts->flowctrl.opthdr.len = sizeof(struct t_opthdr ) + 4; popts->flowctrl.opthdr.level = ISO_TP; popts->flowctrl.opthdr.name = TCO_FLOWCTRL; popts->flowctrl.opthdr.status = T_READONLY; popts->flowctrl.value = T_UNSPEC; } /* *** pack and nsap into a packed byte string 1 char per nibble *** *** *** Return: size of packed string *** -1 failure */ int packnsap( unsigned char *strNSAP, unsigned char *pckNSAP ) { unsigned char *pstr,*ppck; int rlen, i,j, nibs[2]; pstr = strNSAP; ppck = pckNSAP; for (i=0; i < (strlen(strNSAP)/2) ; i++) { for (j=0; j<2; j++ ) { if ( *pstr >= '0' && *pstr <= '9' ) nibs[j] = *pstr++ - '0'; else if ( _upcase(*pstr) >= 'A' && _upcase(*pstr) <= 'Z' ) nibs[j]= _upcase(*pstr++) - ('A' - 10); else return (-1); } ppck[i] = (nibs[0]<<4) + nibs[1]; } return (i); /* return size of packed string */ } /* * unpack nsap, this routine will probably just be used for * debugging purposes. * * status 0 - success * -1 - failure * */ int unpacknsap( pkNSAP, pklen, upkNSAP ) unsigned char *pkNSAP; int pklen; unsigned char *upkNSAP; { int i; const char hexs[] = "0123456789ABCDEF"; unsigned char *pstr = NULL; if (pklen <=0 ) return (-1); /* invalid lenth nsap lenth */ pstr = upkNSAP; for (i=0; i < pklen; i++) /* use each nibble as index */ { /* */ *pstr++ = hexs[pkNSAP[i]>>4]; /* get high nibble */ *pstr++ = hexs[pkNSAP[i]&15]; /* get low nibble (4 bits) */ } return(0); } /* *** make address routines , returns size of address structure */ /* *** make an osi address */ int mkosi_addr( abuf, tsaplen, tsap, nlen, nsap) u_char *abuf; int tsaplen; u_char *tsap; int nlen; u_char *nsap; { return( xti_make_address( PTY_OSI, SOSI( abuf), tsaplen, tsap, 0, 0, nlen, nsap, 0, 0 ) ); } /* *** make a DECnet address */ int mkdna_addr( abuf, ncblen, ncb ) u_char *abuf; int ncblen; u_char *ncb; { return( xti_make_address( PTY_DNET, SOSI( abuf), 0, 0, 0, 0, 0, 0, ncblen, ncb ) ); } /* *** make an inet address */ int mkinet_addr( abuf, plen, port, nlen, naddr ) u_char *abuf; int plen; u_char *port; int nlen; u_char *naddr; { return( xti_make_address( PTY_TCP, SOSI( abuf), 0, 0, plen, port, nlen, naddr, 0, 0 ) ); }