twr_dnet.c   [plain text]


/*
 * Copyright (c) 2010 Apple Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Portions of this software have been released under the following terms:
 *
 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC.
 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY
 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION
 *
 * To anyone who acknowledges that this file is provided "AS IS"
 * without any express or implied warranty:
 * permission to use, copy, modify, and distribute this file for any
 * purpose is hereby granted without fee, provided that the above
 * copyright notices and this notice appears in all source code copies,
 * and that none of the names of Open Software Foundation, Inc., Hewlett-
 * Packard Company or Digital Equipment Corporation be used
 * in advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.  Neither Open Software
 * Foundation, Inc., Hewlett-Packard Company nor Digital
 * Equipment Corporation makes any representations about the suitability
 * of this software for any purpose.
 *
 * Copyright (c) 2007, Novell, Inc. All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Novell Inc. nor the names of its contributors
 *     may be used to endorse or promote products derived from this
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @APPLE_LICENSE_HEADER_END@
 */

/*
**
**  NAME
**
**      twr_dnet.c
**
**  FACILITY:
**
**      Protocol Tower Services for the DECnet address family
**
**  ABSTRACT:
**
**      The protocol tower service provides routines that:
**
**      o  convert a socket address to the lower floors of
**         a protocol tower
**
**      o  convert a protocol tower to a socket address
**
**
*/

#include <commonp.h>    /* Common declarations for all RPC runtime */
#if NAF_DNET
#include <com.h>        /* Common communications services */
#include <twrp.h>	/* Private tower services */

/*
 *  Include the DECnet specific socket address
 */
#ifdef unix
#include <netdnet/dn.h>
#else
#include <dn.h>
#endif

/*
**++
**
**  ROUTINE NAME:       twr_dnet_lower_flrs_from_sa
**
**  SCOPE:              PUBLIC - declared in twr.idl
**
**  DESCRIPTION:
**
**  Creates the canonical representation of a DECnet protocol tower's
**  lower floors from a sockadddr. The canonical form can be transmitted
**  on the wire, or included in a DNA tower.
**
**  INPUTS:
**
**      sa              DECnet-specific socket address data structure.
**
**  INPUTS/OUTPUTS:     none
**
**  OUTPUTS:
**
**      lower_flrs      Returns the lower tower floors in a twr_t
**                      structure (includes the floor count as the first
**                      field of "tower_octet_string" member).
**
**      status          A value indicating the return status of the routine:
**                          twr_s_ok
**                          twr_s_unknown_sa
**
**  IMPLICIT INPUTS:    none
**
**  IMPLICIT OUTPUTS:   none
**
**  FUNCTION VALUE:     void
**
**  SIDE EFFECTS:       none
**
**--
**/

PUBLIC void twr_dnet_lower_flrs_from_sa
(
    sockaddr_p_t      sa,
    twr_p_t           *lower_flrs,
    unsigned32        *status
)
{
    unsigned8   protocol_id[TWR_C_NUM_DNA_LOWER_FLRS];
    unsigned16  floor_count,
                id_size = twr_c_tower_prot_id_size,
                related_data_size[TWR_C_NUM_DNA_LOWER_FLRS],
                twr_rep_16;
    unsigned32  count,
                twr_t_length,
                *related_data_ptr[TWR_C_NUM_DNA_LOWER_FLRS];
    byte_p_t    tmp_tower;

    CODING_ERROR (status);
    RPC_VERIFY_INIT ();

    if (sa->family == RPC_C_NAF_ID_DNET)
    {
        protocol_id[0] = TWR_C_FLR_PROT_ID_DNA;
        protocol_id[1] = TWR_C_FLR_PROT_ID_NSP;
        protocol_id[2] = TWR_C_FLR_PROT_ID_ROUTING;

        /*
         * Since we now know the socket address we're dealing with,
         * collect the sizes of each field to allocate memory, and
         * remember the pointers to the fields so we can copy the
         * data once we have allocated the tower string.
         */

        floor_count = TWR_C_NUM_DNA_LOWER_FLRS;

        related_data_size[0] =
        sizeof(((struct sockaddr_dn *)sa)->sdn_objnum) +
        sizeof(((struct sockaddr_dn *)sa)->sdn_objnamel) +
        ((struct sockaddr_dn *)sa)->sdn_objnamel;

        related_data_ptr[0] =
        (unsigned32 *)(&((struct sockaddr_dn *)sa)->sdn_objnum);

        /*      do we need to store flags ???
         *                related_data_size[1] =
         *                   sizeof(((struct sockaddr_dn *)sa)->sdn_flags);
         */
        related_data_size[1] = 0;

        related_data_ptr[1] =
        (unsigned32 *)(&((struct sockaddr_dn *)sa)->sdn_flags);

        related_data_size[2] =
        sizeof(((struct sockaddr_dn *)sa)->sdn_add.a_len) +
        ((struct sockaddr_dn *)sa)->sdn_add.a_len;

        related_data_ptr[2] =
        (unsigned32 *)(&((struct sockaddr_dn *)sa)->sdn_add);
    }
    else
    {
        *status = twr_s_unknown_sa;
        return;
    }

    /*
     * Allocate memory and copy the data into the proper
     * locations in each of up to three floors.
     */

    /*
     * Calculate length of tower floor.
     */

    twr_t_length = twr_c_tower_flr_count_size; /* to store floor count */

    for ( count = 0; count < floor_count; count++ )
    {
        twr_t_length += TWR_C_FLR_OVERHEAD;
        twr_t_length += related_data_size[count];
    }

    /*
     * Next allocate space for the tower structure
     */
    RPC_MEM_ALLOC (
        *lower_flrs,
        twr_p_t,
        sizeof (twr_t) + (twr_t_length - 1),
        RPC_C_MEM_TOWER,
        RPC_C_MEM_WAITOK );

    /*
     * Copy the length of the tower octet string into the tower structure
     */
    (*lower_flrs)->tower_length = twr_t_length;

    /*
     * Copy the floor information into the tower octet string
     */

    /*
     * Use a temporary for the octet string since we need
     * to increment the pointer.
     */
    tmp_tower = (*lower_flrs)->tower_octet_string;

    /*
     * Copy the number of floors into the tower octet string
     */
    twr_rep_16 = floor_count;
    RPC_RESOLVE_ENDIAN_INT16 (twr_rep_16);
    memcpy ((char *)tmp_tower, (char *)&twr_rep_16,
            twr_c_tower_flr_count_size);

    tmp_tower += twr_c_tower_flr_count_size;

    /*
     * Convert the protocol identifier size to its proper
     * representation for use in the following loop.
     */
    RPC_RESOLVE_ENDIAN_INT16 (id_size);

    for (count = 0; count < floor_count; count++)
    {
        /*
         * Copy the length of the protocol identifier field into
         * tower octet string. (Converted before the loop.)
         */
        memcpy ((char *)tmp_tower, (char *)&id_size,
                TWR_C_TOWER_FLR_LHS_COUNT_SIZE);

        tmp_tower += TWR_C_TOWER_FLR_LHS_COUNT_SIZE;

        /*
         * Copy the protocol identifier into tower octet string
         * (1 byte so no need to convert endian representation).
         */
        memcpy ((char *)tmp_tower, (char *)&(protocol_id[count]),
                twr_c_tower_prot_id_size);

        tmp_tower += twr_c_tower_prot_id_size;

        /*
         * Copy the length of the address data field into
         * tower octet string.
         */
        twr_rep_16 = related_data_size[count];
        RPC_RESOLVE_ENDIAN_INT16 (twr_rep_16);
        memcpy ((char *)tmp_tower, (char *)&twr_rep_16,
                TWR_C_TOWER_FLR_RHS_COUNT_SIZE);

        tmp_tower += TWR_C_TOWER_FLR_RHS_COUNT_SIZE;

        /*
         * If there is addressing data, copy the address data field into
         * tower octet string
         */
        if (related_data_size[count])
        {
            memcpy ((char *)tmp_tower, (char *)related_data_ptr[count],
                    related_data_size[count] );

            /*
             * Set up for the next floor.
             */
            tmp_tower += related_data_size[count];
        }
    }

    *status = twr_s_ok;
}

/*
**++
**
**  ROUTINE NAME:       twr_dnet_lower_flrs_to_sa
**
**  SCOPE:              PUBLIC - declared in twr.idl
**
**  DESCRIPTION:
**
**  Creates a DECnet sockaddr from the canonical representation of a
**  DECnet protocol tower's lower floors.
**
**  INPUTS:
**
**      tower_octet_string
**                      The protocol tower to convert to a sockaddr.
**
**  INPUTS/OUTPUTS:     none
**
**  OUTPUTS:
**
**      sa            Returns a pointer to the created sockaddr structure.
**
**      sa_len          Returns the length, in bytes, of the returned
**                      "sa" argument.
**
**      status          A value indicating the return status of the routine:
**                          twr_s_ok
**                          twr_s_unknown_tower
**
**  IMPLICIT INPUTS:    none
**
**  IMPLICIT OUTPUTS:   none
**
**  FUNCTION VALUE:     void
**
**  SIDE EFFECTS:       none
**
**--
**/

PUBLIC void twr_dnet_lower_flrs_to_sa
(
    byte_p_t          tower_octet_string,
    sockaddr_p_t      *sa,
    unsigned32        *sa_len,
    unsigned32        *status
)
{
    unsigned8   id;
    byte_p_t    tower;
    unsigned16  count,
                floor_count,
                id_size,
                addr_size;
    unsigned32  length;

    CODING_ERROR (status);
    RPC_VERIFY_INIT ();

    id_size = 0;

    /*
     * make sure we have a pointer to some data structure
     */
    if ( !(tower = tower_octet_string))
    {
        *status = twr_s_unknown_tower;
        return;
    }

    /*
     * Get the tower floor count
     */
    memcpy ((char *)&floor_count, (char *)tower, twr_c_tower_flr_count_size);
    RPC_RESOLVE_ENDIAN_INT16 (floor_count);

    tower += twr_c_tower_flr_count_size;

    /*
     * Skip over the (application's) upper floors while we look for the
     * beginning of the dnet-specific lower floors.
     */
    for (count = 0; count < floor_count; count++)
    {
        /*
         * Get the length of this floor's protocol id field (don't
         * advance the pointer).
         */
        memcpy ((char *)&id_size, (char *)tower,
                TWR_C_TOWER_FLR_LHS_COUNT_SIZE);
        RPC_RESOLVE_ENDIAN_INT16 (id_size);

        /*
         * Get the protocol id (don't advance the pointer).
         * Expect one byte; no need to convert.
         */
        memcpy ((char *)&id, (char *)(tower + TWR_C_TOWER_FLR_LHS_COUNT_SIZE),
                twr_c_tower_prot_id_size);

        /*
         * See if we support the protocol id.
         */
        if ( (id_size == twr_c_tower_prot_id_size) &&
             (id ==  TWR_C_FLR_PROT_ID_DNA) )
        {
            /*
             * Indicate we found the beginning of the dnet floors.
             */
            *status = twr_s_ok;

            break;
        }
        else
        {
            /*
             * Skip this floor.  Get the address size in order
             * to know how much to skip.
             */
            memcpy ((char *)&addr_size,
                    (char *)(tower + TWR_C_TOWER_FLR_LHS_COUNT_SIZE +
                            id_size), TWR_C_TOWER_FLR_RHS_COUNT_SIZE);
            RPC_RESOLVE_ENDIAN_INT16 (addr_size);

            tower += TWR_C_TOWER_FLR_LHS_COUNT_SIZE + id_size +
                     TWR_C_TOWER_FLR_RHS_COUNT_SIZE + addr_size;

            /*
             * For now, assume we don't find the floors we're looking for.
             */
            *status = twr_s_unknown_tower;
        }
    }

    if (*status != twr_s_ok)
    {
        return;
    }

    /*
     * Skip the floor's protocol id field length and protocol id
     * (now move the pointer).  We already know it's TWR_C_FLR_PROT_ID_DNA.
     */
    tower += (TWR_C_TOWER_FLR_LHS_COUNT_SIZE + id_size);

    /*
     * Allocate space for a DECnet sockaddr
     */
    length = sizeof(struct sockaddr_dn);

    RPC_MEM_ALLOC (
                   *sa,
                   sockaddr_p_t,
                   length,
                   RPC_C_MEM_SOCKADDR,
                   RPC_C_MEM_WAITOK );

    *sa_len = length;

    /*
     * make sure unused bytes are null
     */
    memset ((char *) *sa, 0, length);

    /*
     * define this as a DECnet family socket
     */
    ((struct sockaddr_dn *)(*sa))->sdn_family = RPC_C_NAF_ID_DNET;

    /*
     * Length of end user spec
     */
    memcpy ((char *)&addr_size, (char *)tower, RPC_C_TOWER_FLR_RHS_COUNT_SIZE);
    RPC_RESOLVE_ENDIAN_INT16 (addr_size);
    tower += RPC_C_TOWER_FLR_RHS_COUNT_SIZE;

    /*
     * End user spec
     */
    memcpy (&((struct sockaddr_dn *)(*sa))->sdn_objnum,
            (char *)tower,
            addr_size);

    tower += addr_size;

    /*
     * Length of host transport
     */
    memcpy ((char *)&id_size, (char *)tower,
            TWR_C_TOWER_FLR_LHS_COUNT_SIZE);
    RPC_RESOLVE_ENDIAN_INT16 (id_size);
    tower  += TWR_C_TOWER_FLR_LHS_COUNT_SIZE;

    /*
     * Transport id
     * Expect one byte; no need to convert.
     */
    memcpy ((char *)&id, (char *)tower, twr_c_tower_prot_id_size);
    tower += id_size;

    if ((id_size != twr_c_tower_prot_id_size) ||
        (id != TWR_C_FLR_PROT_ID_NSP))
    {
        *status = twr_s_unknown_tower;

        RPC_MEM_FREE (*sa, RPC_C_MEM_SOCKADDR);

        return;
    }

    /*
     * Length of sdn_flags
     */
    memcpy ((char *)&addr_size, (char *)tower, RPC_C_TOWER_FLR_RHS_COUNT_SIZE);
    RPC_RESOLVE_ENDIAN_INT16 (addr_size);
    tower += RPC_C_TOWER_FLR_RHS_COUNT_SIZE;

    /*
     * this field is probably null
     */
    if (addr_size)
    {
        memcpy ( &((struct sockaddr_dn *)(*sa))->sdn_flags,
                (char *)tower,
                addr_size);

        tower += addr_size;
    }

    /*
     * Length of routing id
     */
    memcpy ((char *)&id_size, (char *)tower,
            TWR_C_TOWER_FLR_LHS_COUNT_SIZE);
    RPC_RESOLVE_ENDIAN_INT16 (id_size);
    tower += TWR_C_TOWER_FLR_LHS_COUNT_SIZE;

    /*
     * Protocol id
     * Expect one byte, so no need to convert.
     */
    memcpy ((char *)&id, (char *)tower, twr_c_tower_prot_id_size);
    tower += id_size;

    if ( (id_size != twr_c_tower_prot_id_size) ||
         (id != TWR_C_FLR_PROT_ID_ROUTING) )
    {
        *status = twr_s_unknown_tower;

        RPC_MEM_FREE (*sa, RPC_C_MEM_SOCKADDR);

        return;
    }

    /*
     * the length of host address
     */
    memcpy ((char *)&addr_size, (char *)tower, RPC_C_TOWER_FLR_RHS_COUNT_SIZE);
    RPC_RESOLVE_ENDIAN_INT16 (addr_size);
    tower += RPC_C_TOWER_FLR_RHS_COUNT_SIZE;

    memcpy (&((struct sockaddr_dn *)(*sa))->sdn_add,
            (char *)tower,
            addr_size);

    *status = twr_s_ok;
}
#else
static int _naf_dnet_dummy_ = 0 ;
#endif /* NAF_DNET */