/*                                              9 April 1996.  SMS.
 *
 *   Program to get a VAX/VMS hardware Ethernet address.
 */

#include <stdio.h>
#include <string.h>

#include descrip
#include iodef
#include ssdef
#include starlet

/*
 *   Define: Hardware address parameter type code (no .h file), and
 *           Size of the device characteristics buffer.
 */

#define  HWA_PARAM_TYPE  1160
#define  SENSE_BUF_LEN  256

main()
{
    char  *buf_ptr_byte;
    char  *buf_ptr_byte_end;
    char  *eth_name;
    static  char  sense_buf[ SENSE_BUF_LEN];

/*
 *   Legal Ethernet device names.  Assign any unlisted (new) device to
 *   "ZCD$ETH_LNM" with DCL ASSIGN or DEFINE.
 */

    char  *eth_type[] =
     { "ZCD$ETH_LNM" , "EIA0:", "ERA0:", "ESA0:", "ETA0:", "EWA0:",
                       "EXA0:", "EZA0:", "XEA0:", "XQA0:"};

    short int  *buf_ptr_word;
    short int  eth_chan;
    short int  param_type;
    short int  param_type_12;

    int  eth_dev_index;
    int  i;
    int  ssstatus;

    $DESCRIPTOR( eth_name_dsc, "");

/*   IOSB for QIOW.  */

    union
    {
        short int  s[ 4];
        int  l[ 2];
    } iosb;

/*   Descriptor for device characteristics buffer.   */

    struct
    {
        int  length;
        int  *buf;
    } sense_buf_dsc = { SENSE_BUF_LEN, (int*)&sense_buf };

/*   Storage for the Ethernet hardware address.   */

    struct
    {
        unsigned char  byte[ 6];
    } hwa = { 0, 0, 0, 0, 0, 0 };


/*   Start.   */

/*   Find the first available Ethernet device.   */

    eth_dev_index = 0;
    ssstatus = 0;

    while (!(ssstatus & 1) &&
     (eth_dev_index < sizeof( eth_type)/ sizeof( int*)))
    {
        eth_name_dsc.dsc$a_pointer = eth_type[ eth_dev_index];
        eth_name_dsc.dsc$w_length = strlen( eth_name_dsc.dsc$a_pointer);
        ssstatus = sys$assign( &eth_name_dsc, &eth_chan, 0, 0);
        eth_dev_index++;
    }

/*   If sys$assign worked, try to sense the characteristics.   */

    if (ssstatus & 1)
    {
        ssstatus = sys$qiow( 0,                         /* Event flag. */
                             eth_chan,                  /* Channel. */
                             (IO$_SENSEMODE | IO$M_CTRL), /* Function. */
                             &iosb,                     /* IOSB. */
                             0,                         /* AST address. */
                             0,                         /* AST parameter. */
                             0,                         /* P1. */
                             &sense_buf_dsc,            /* P2 (buffer). */
                             0,                         /* P3. */
                             0,                         /* P4. */
                             0,                         /* P5. */
                             0);                        /* P6. */

/*   If initial status was good, use final status.   */

        if (ssstatus & 1)
        {
            ssstatus = iosb.s[ 0];
        }

/*   If sense worked, search for the hardware address field.   */

        if (ssstatus & 1)
        {
            param_type_12 = 0;
            buf_ptr_byte = (char *) &sense_buf;
            buf_ptr_byte_end = (char *) &sense_buf+ SENSE_BUF_LEN;

/*   Search while not found and more buffer.   */

            while ((param_type_12 != HWA_PARAM_TYPE) &&
            (buf_ptr_byte <= buf_ptr_byte_end))
            {
                buf_ptr_word = (short int *) buf_ptr_byte;
                param_type = *buf_ptr_word;
                param_type_12 = param_type & ((short) (1<< 12)- 1);

/*
     If found, store the hardware address.
     Otherwise, advance the pointer to the next field.
*/

                if (param_type_12 == HWA_PARAM_TYPE)
                {
                    buf_ptr_byte += 4;
                    for (i = 0; i < 6; i++)
                    {
                        hwa.byte[ i] = *( buf_ptr_byte++);
                    }
                }
                else if (param_type & ((short) (1<< 12)))
                {
/*   String field.  Skip type, length, and length-bytes.   */
                    buf_ptr_byte += 4+ *(buf_ptr_word+ 1);
                }
                else
                {
/*   Longword field.  Skip type and longword.   */
                    buf_ptr_byte += 6;
                }
            }
        }
    }

    ssstatus = sys$dassgn( eth_chan);

/*   Print the hardware address.   */

    printf( " HWA (%s) = ", eth_name_dsc.dsc$a_pointer);
    for (i = 0; i < 5; i++)
    {
        printf( "%02x-", hwa.byte[ i]);
    }
    printf( "%02x.\n", hwa.byte[ 5]);
}
