/*                                              9 April 1996.  SMS.

     Program to get a VAX/VMS hardware Ethernet address.

*/

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

#include <descrip.h>
#include <iodef.h>
#include <ssdef.h>
#include <starlet.h>

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

#define  ETH_TYPES  9
#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[ ETH_TYPES] =
 { "ZCD$ETH_LNM" , "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 < ETH_TYPES))
   {
   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,
                        eth_chan,
                        (IO$_SENSEMODE | IO$M_CTRL),
                        &iosb,
                        0,
                        0,
                        0,
                        &sense_buf_dsc,
                        0,
                        0,
                        0,
                        0);

/*   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]);

}
