#if 0 GETADR.C -- Program to acquire ethernet controller addresses COPYRIGHT (c) 1995 BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS. ALL RIGHTS RESERVED. THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION. THIS PROGRAM IS DISTRIBUTED FREE AS A DEMONSTRATION OF NETWORK ACCESS METHODS. NO WARRANTY IS EXPRESSED OR IMPLIED. Author: Chuck Newman, Digital Equipment Corp. alpha-developer@digital.com History: 18 Oct 1995 Created 20 Oct 1995 Only look at NET devices. Skip devices that don't like the SYS$QIO call 13 Nov 1995 Various minor modifications to allow this to be compiled with VAXC on OpenVMS VAX platforms Compilation command: OpenVMS Alpha: $ CC GET_ETHER+SYS$SHARE:SYS$LIB_C/LIBRARY OpenVMS VAX: $ CC GET_ETHER #endif #include #include #include #include #ifdef __DECC #include #else /* VAXC doesn't have dvsdef.h */ #define DVS$_DEVCLASS 1 #endif #ifdef __DECC #include #else /* VAXC doesn't have ints.h */ typedef unsigned short int uint16; typedef unsigned int uint32; #endif /* Don't have 64bit ints on OpenVMS VAX, so use 2 longwords */ #if defined (__VAX) || defined (VAX) typedef uint32 uint64[2]; #endif #include #include #include #include #include #include #include #ifndef __DECC /* Not there on VAXC on OpenVMS VAX */ #define SS$_NOMOREDEV 2648 #endif /* A couple of include files aren't there on OpenVMS VAX */ #if defined (__VAX) || defined (VAX) /* Following stolen from nmadef.h on OpenVMS Alpha */ #define NMA$C_PCLI_HWA 1160 /* Hardware address (NI address) */ /* Following stolen from udbdef.h on OpenVMS Alpha */ #define UCB$M_TEMPLATE 0x2000 #else #include #include #endif /* Define lots of structures, etc */ struct item_list_2 { uint32 length; unsigned char *buffer; }; struct item_list_3 { uint16 length; uint16 item_code; uint32 *buffer; uint32 *ret_length; }; struct getdvi_iosb_s { unsigned int status; unsigned int reserved; }; struct qio_iosb_s { unsigned short int status; unsigned short int msg_len; unsigned int dev_specific; }; union iosb_s { struct getdvi_iosb_s getdvi_iosb; struct qio_iosb_s qio_iosb; }; typedef unsigned char ether_addr[6]; /* Prototype for the interesting routine */ int getadr(ether_addr[], int); int main(int argc, char **argv, char **envp) { /* Declare storage for several ethernet devices */ #define INTERFACE_COUNT 32 ether_addr hardware[INTERFACE_COUNT]; int temp_int, count; int req_interfaces = INTERFACE_COUNT; if (argc > 1) req_interfaces = atoi(argv[1]); if ((count = getadr(hardware, req_interfaces)) == 0) { fprintf(stderr, "couldn't get network interface\n"); exit(1); } /* Print out the ethernet addresses */ for (temp_int = 0; temp_int < abs(count); temp_int++) { printf("Ethernet hardware address = (%02.2X-%02.2X-%02.2X-%02.2X-%02.2X-%02.2X)\n", hardware[temp_int][0], hardware[temp_int][1], hardware[temp_int][2], hardware[temp_int][3], hardware[temp_int][4], hardware[temp_int][5]); } /* See if there were more ethernet addresses than we allowed for */ if (count < 0) printf("There are more devices than those listed\n\ Call getadr with a larger buffer\n"); } #if 0 This routine accepts two parameters, and returns the count of addresses found Input 1: Area to receive ethernet addresses Input 2: Number of addresses that can fit into the area specified by Input 1. Each address takes 6 bytes. Return Value: Positive -- number of addresses returned Negative -- absolute value is number of addresses returned, but there are more addresses Zero -- no addresses, or failure #endif int getadr(ether_addr hardware[], int count) { char dev_name_buff[16]; struct dsc$descriptor_s dev_name; #if defined (__VAX) || defined (VAX) uint64 context={0,0}; #else uint64 context=0; #endif struct item_list_3 scan_char[2], dvi_char[3]; int synch_dev = DC$_SCOM; int synch_dev_len; int scan_status, return_status, index = 0; uint16 channel, bit12; uint32 event_flag, device_stat, device_char, sts_len, chr_len; /* Set aside 256 bytes for the NMA characteristics. The IO User's Reference Manual in the chapter on Local Area Network (LAN) Device Drivers says that 250 bytes should be enough */ unsigned char dev_attrs[256]; struct item_list_2 attr_desc={sizeof(dev_attrs), NULL}; union iosb_s iosb; /* Set up some structures for walking through the byte stream returned by the sensemode QIO */ #pragma member_alignment __save #pragma nomember_alignment typedef struct int_attr_s { uint16 type; uint32 value; }; typedef struct str_attr_s { uint16 type; uint16 length; /* what I'd *really* like for the following is "unsigned char value[];" */ unsigned char value[6]; }; union nma_attr_u { struct int_attr_s int_attr; struct str_attr_s str_attr; } *nma_attr; #pragma member_alignment __restore /* Set up the search string. Use a wildcard because we want all synchronous communication devices. */ struct dsc$descriptor_s sear_dev_name = { sizeof("*")-1, DSC$K_DTYPE_T, DSC$K_CLASS_S, "*"}; dev_name.dsc$w_length = sizeof(dev_name_buff)-1; dev_name.dsc$b_dtype = DSC$K_DTYPE_T; dev_name.dsc$b_class = DSC$K_CLASS_S; dev_name.dsc$a_pointer = dev_name_buff; attr_desc.buffer = dev_attrs; /* Set up the itemlist to specify synchronous communication devices. This is for the SYS$DEVICE_SCAN call */ scan_char[0].length = 4; scan_char[0].item_code = DVS$_DEVCLASS; scan_char[0].buffer = (uint32 *)&synch_dev; scan_char[0].ret_length = (uint32 *)&synch_dev_len; scan_char[1].length = 0; scan_char[1].item_code = 0; /* Set up the itemlist to request status and characteristics. This is for the SYS$GETDVI call. The device status will let us isolate template devices. The device characteristics will let us screen out mailbox devices and isolate network devices (INET0 is a mailbox device). (FYA0 is not a network device). */ dvi_char[0].length = 4; dvi_char[0].item_code = DVI$_STS; dvi_char[0].buffer = &device_stat; dvi_char[0].ret_length = &sts_len; dvi_char[1].length = 4; dvi_char[1].item_code = DVI$_DEVCHAR; dvi_char[1].buffer = &device_char; dvi_char[1].ret_length = &chr_len; dvi_char[2].length = 0; dvi_char[2].item_code = 0; /* Get an event flag */ if (return_status = lib$get_ef(&event_flag) != SS$_NORMAL) lib$signal(return_status); /* Loop on SYS$DEVICE_SCAN */ while (((scan_status = sys$device_scan( &dev_name , &dev_name.dsc$w_length , &sear_dev_name , &scan_char[0] , &context )) == SS$_NORMAL) && (index >= 0)) { dev_name.dsc$a_pointer[dev_name.dsc$w_length] = '\0'; /* Get the device status and characteristics Don't assign a channel and do the getdvi on that because you'll never get a template device that way -- use the device name */ return_status = sys$getdviw( event_flag , 0 , &dev_name , &dvi_char[0] , &iosb , 0 , 0 , 0 ); if (return_status != SS$_NORMAL) lib$signal(return_status); if (iosb.getdvi_iosb.status != SS$_NORMAL) lib$signal(iosb.getdvi_iosb.status); /* Only process non-mailbox network template devices. */ if (((device_stat & UCB$M_TEMPLATE) != 0) && ((device_char & (DEV$M_MBX | DEV$M_NET)) == DEV$M_NET)) { /* Assign a channel */ return_status = sys$assign(&dev_name, &channel, 0, 0); if (return_status != SS$_NORMAL) lib$signal(return_status); /* Do the SENSEMODE QIO to get the NMA characteristics */ return_status = sys$qiow(0 , channel , IO$_SENSEMODE | IO$M_CTRL , &iosb , 0 , 0 , 0 , &attr_desc , 0 , 0 , 0 , 0 ); /* If the QIO failed, ignore this device */ if ((return_status != SS$_NORMAL) || (iosb.qio_iosb.status != SS$_NORMAL)) { printf ("Ignoring device %s -- failure from SYS$QIO\n", dev_name.dsc$a_pointer); } else { /* Won't need that channel again */ return_status = sys$dassgn(channel); if (return_status != SS$_NORMAL) lib$signal(return_status); /* Loop through the data returned by the QIO, looking for NMA$C_PCLI_HWA */ nma_attr = (void *)attr_desc.buffer; while (((*nma_attr).int_attr.type & 0xfff) != NMA$C_PCLI_HWA) { if (((*nma_attr).int_attr.type & 0x1000) == 0) { /* Skip this packet of type Longword */ nma_attr = (void *)((char *)nma_attr + sizeof((*nma_attr).int_attr)); } else { nma_attr = (void *)((char *)nma_attr + sizeof((*nma_attr).str_attr.type) + sizeof((*nma_attr).str_attr.length) + (*nma_attr).str_attr.length); /* Skip this packet of type String */ } } /* We've found it! If there is room, same it in the buffer provided by the caller and increment the count of adapters (which we'll return) */ if (index < count) { hardware[index][0] = (*nma_attr).str_attr.value[0]; hardware[index][1] = (*nma_attr).str_attr.value[1]; hardware[index][2] = (*nma_attr).str_attr.value[2]; hardware[index][3] = (*nma_attr).str_attr.value[3]; hardware[index][4] = (*nma_attr).str_attr.value[4]; hardware[index][5] = (*nma_attr).str_attr.value[5]; index += 1; } else { /* Hmmm. No room for this adapter. Change the sign of the counter and return that so the caller knows there are more adapters */ index = -index; } /* if (index < count) */ } /* if ((return_status != SS$_NORMAL) || ... */ } /* if (((device_stat & UCB$M_TEMPLATE) != 0) ... */ } /* while (((scan_status = sys$device_scan( ... */ if (scan_status != SS$_NOMOREDEV) lib$signal(scan_status); /* Free up the event flag */ return_status = lib$free_ef(&event_flag); if (return_status != SS$_NORMAL) lib$signal(return_status); return (index); } /* int getadr(ether_addr hardware[], int count) */