From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 25-APR-1989 16:46
To:	MRGATE::"ARISIA::EVERHART"
Subj:	Ethernet addresses

Received: From KL.SRI.COM by CRVAX.SRI.COM with TCP; Tue, 25 APR 89 12:13:39 PDT
Received: from TopGun.Sdsc.Edu by KL.SRI.COM with TCP; Tue, 25 Apr 89 11:48:15 PDT
Date:    Tue, 25 Apr 89 18:47:06 GMT
From: gkn@TopGun.Sdsc.Edu (Gerard K. Newman)
Message-Id: <890425184706.2720033c@TopGun.Sdsc.Edu>
Subject: Ethernet addresses
To: info-vax@kl.sri.com
X-St-Vmsmail-To: ST%"info-vax@kl.sri.com"

The recent traffic on this list regarding the determination of an
ethernet address prompted me to write some code to do it.  In so
doing I discovered that the documentation on the ethernet drivers
in the _I/O User's Guide:  Part II_ is less than clear on the subject.

One has to issue an IO$_SENSEMODE!IO$M_CTRL against your favorite
ethernet device, and then fish up the appropriate parameter from the
list that gets returned to you.

There's a gotcha in this, in that DECnet changes the physical address
that the ethernet controller will use to AA-00-04-00-XX-YY, where XX-YY
is your DECnet address byte-swapped.  The driver returns FF-FF-FF-FF-FF-FF
for the physical address on a unit which has not been started, so what
you have to do is grab a channel, start the device, and then fish up
the characteristics.  Bogus.

At any rate, here's a little toy which will do that.  Build it with:

$ Macro ETHER_ADDR
$ Link  ETHER_ADDR

Enjoy.

gkn
----------------------------------------
Internet: GKN@SDS.SDSC.EDU
Bitnet:   GKN@SDSC
Span:     SDSC::GKN (27.1)
MFEnet:   GKN@SDS
USPS:     Gerard K. Newman
          San Diego Supercomputer Center
          P.O. Box 85608
          San Diego, CA 92138-5608
Phone:    619.534.5076

--------------------------------------------------------------------------------
$! ................... Cut between dotted lines and save. ...................
$!...........................................................................
$! VAX/VMS archive file created by VMS_SHARE V06.10 7-FEB-1989.
$!
$! VMS_SHARE was written by James Gray (Gray:OSBUSouth@Xerox.COM) from
$! VMS_SHAR by Michael Bednarek (U3369429@ucsvc.dn.mu.oz.au).
$!
$! To unpack, simply save, concatinate all parts into one file and
$! execute (@) that file.
$!
$! This archive was created by user GKN (Gerard K. Newman)
$! on 25-APR-1989 18:41:02.92.
$!
$! It contains the following 1 file:
$!        ETHER_ADDR.MAR
$!
$!============================================================================
$ SET SYMBOL/SCOPE=( NOLOCAL, NOGLOBAL )
$ VERSION = F$GETSYI( "VERSION" )
$ IF VERSION .GES "V4.4" THEN GOTO VERSION_OK
$ WRITE SYS$OUTPUT "You are running VMS ''VERSION'; ", -
    "VMS_SHARE V06.10 7-FEB-1989 requires VMS V4.4 or higher."
$ EXIT 44 ! SS$_ABORT
$VERSION_OK:
$ GOTO START
$!
$UNPACK_FILE:
$ WRITE SYS$OUTPUT "Creating ''FILE_IS'"
$ DEFINE/USER_MODE SYS$OUTPUT NL:
$ EDIT/TPU/COMMAND=SYS$INPUT/NODISPLAY/OUTPUT='FILE_IS'/NOSECTION -
    VMS_SHARE_DUMMY.DUMMY
b_part := CREATE_BUFFER( "{Part}", GET_INFO( COMMAND_LINE, "file_name" ) )
; s_file_spec := GET_INFO( COMMAND_LINE, "output_file" ); SET( OUTPUT_FILE
, b_part, s_file_spec ); b_errors := CREATE_BUFFER( "{Errors}" ); i_errors 
:= 0; pat_beg_1 := ANCHOR & "-+-+-+ Beginning"; pat_beg_2 := LINE_BEGIN 
& "+-+-+-+ Beginning"; pat_end := ANCHOR & "+-+-+-+-+ End"; POSITION
( BEGINNING_OF( b_part ) ); LOOP EXITIF SEARCH( SPAN( ' ' )@r_trail 
& LINE_END, FORWARD) = 0; POSITION( r_trail ); ERASE( r_trail ); ENDLOOP
; POSITION( BEGINNING_OF( b_part ) ); i_append_line := 0; LOOP EXITIF MARK
( NONE ) = END_OF( b_part ); s_x := ERASE_CHARACTER( 1 )
; IF s_x = '+' THEN r_skip := SEARCH( pat_beg_1, FORWARD, EXACT ); IF r_skip 
<> 0 THEN s_x := ''; MOVE_HORIZONTAL( -CURRENT_OFFSET ); ERASE_LINE; ENDIF
; ENDIF; IF s_x = '-' THEN r_skip := SEARCH( pat_end, FORWARD, EXACT )
; IF r_skip <> 0 THEN s_x := ''; MOVE_HORIZONTAL( -CURRENT_OFFSET ); m_skip 
:= MARK( NONE ); r_skip := SEARCH( pat_beg_2, FORWARD, EXACT ); IF r_skip 
<> 0 THEN POSITION( END_OF( r_skip ) ); MOVE_HORIZONTAL( -CURRENT_OFFSET )
; MOVE_VERTICAL( 1 ); MOVE_HORIZONTAL( -1 ); ELSE POSITION( END_OF( b_part ) 
); ENDIF; ERASE( CREATE_RANGE( m_skip, MARK( NONE ), NONE ) ); ENDIF; ENDIF
; IF s_x = 'V' THEN s_x := ''; IF i_append_line <> 0 THEN APPEND_LINE
; MOVE_HORIZONTAL( -CURRENT_OFFSET ); ENDIF; i_append_line := 1
; MOVE_VERTICAL( 1 ); ENDIF; IF s_x = 'X' THEN s_x := ''; IF i_append_line 
<> 0 THEN APPEND_LINE; MOVE_HORIZONTAL( -CURRENT_OFFSET ); ENDIF
; i_append_line := 0; MOVE_VERTICAL( 1 ); ENDIF; IF s_x <> '' THEN i_errors 
:= i_errors + 1; s_text := CURRENT_LINE; POSITION( b_errors ); COPY_TEXT
( "The following line could not be unpacked properly:" ); SPLIT_LINE
; COPY_TEXT( s_x ); COPY_TEXT( s_text ); POSITION( b_part ); MOVE_VERTICAL
( 1 ); ENDIF; ENDLOOP; POSITION( BEGINNING_OF( b_part ) ); LOOP r_x := SEARCH
( "`", FORWARD, EXACT ); EXITIF r_x = 0; POSITION( r_x ); ERASE_CHARACTER( 1 
); COPY_TEXT( ASCII( INT( ERASE_CHARACTER( 3 ) ) ) ); ENDLOOP
; IF i_errors = 0 THEN SET( NO_WRITE, b_errors, ON ); ELSE POSITION
( BEGINNING_OF( b_errors ) ); COPY_TEXT( FAO
( "The following !UL errors were detected while unpacking !AS", i_errors
, s_file_spec ) ); SPLIT_LINE; SET( OUTPUT_FILE, b_errors, "SYS$COMMAND" )
; ENDIF; EXIT; 
$ DELETE VMS_SHARE_DUMMY.DUMMY;*
$ CHECKSUM 'FILE_IS
$ WRITE SYS$OUTPUT " CHECKSUM ", -
  F$ELEMENT( CHECKSUM_IS .EQ. CHECKSUM$CHECKSUM, ",", "failed!!,passed." )
$ RETURN
$!
$START: 
$ FILE_IS = "ETHER_ADDR.MAR"
$ CHECKSUM_IS = 1164707868
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X`009.Title`009Ether_Addr`009- Report the ethernet address of a given device
X`009.Ident`009/V01.000/
X`009.Enable`009SUP
X`009.Default Displacement,Word
X`009.Subtitle`009Introduction
X
X;+
X;
X; ----- Ether_Addr:  Report the ethernet address of a given device
X;
X;
X; Facility:
X;
X;`009VAX/VMS system management.
X;
X; Abstract:
X;
X;`009This module will report the ethernet address of a given device.
X;
X; Environment:
X;
X;`009VAX/VMS native mode, VMS V4.0 or later, unprivileged user mode.
X;
X;
X;
X; Version:`009V01.000
X; Date:`009`00924-Apr-1989
X;
X; Copyright `169 1989  San Diego Supercomputer Center
X;
X; Gerard K. Newman`00924-Apr-1989
X; San Diego Supercomputer Center
X; General Atomics
X; P.O. Box 85608
X; San Diego, CA  92138-5608
X; 619.534.5076
X;
X; Internet:`009GKN@SDS.SDSC.EDU
X; BITNET:`009GKN@SDSC.BITNET
X; SPAN:`009`009SDSC::GKN (27.1)
X; MFENET:`009GKN@SDS.MFENET
X; SDSCNET:`009GKN@SDS.SDSCNET
X;
X;
X; Modifications:
X;
X;
X;-
X
X`009.Page
X`009.Subtitle`009Local definitions
X
X`009.Library "SYS$LIBRARY:LIB.MLB"`009;Get $NMADEF from here
X
X`009.NoCross`009`009`009;Save a tree
X
X`009$DCDEF`009`009`009`009;Device class & type definitions
X`009$IODEF`009`009`009`009;I/O function codes
X`009$NMADEF`009`009`009`009;Define network management tidbits
X`009$SSDEF`009`009`009`009;System service codes
X
X`009.Cross`009`009`009`009;Turn CREF back on
X
X
X.IIF`009NDF,DT$_ET_DEBNI,`009DT$_ET_DEBNI`009=`00934`009;DEBNI in 5.2
X
X
X; Local macros
X
X.Macro`009Device_Type`009Type,String,?A`009;Make a device type entry
X`009.Long`009'Type`009`009`009;Stash the type word
X`009.Enable`009LSB`009`009`009;Turn on local symbol mode
X`009.Save`009`009`009`009;Save the current PSECT
X`009.Psect`009Strings`009EXE,RD,NOWRT,PIC,SHR,PAGE
XA:`009.Ascid`009\'String\`009`009;Stash the string
X`009.Restore`009`009`009;Back to the old PSECT
X`009.Address A`009`009`009;Store a pointer to the string
X`009.Disable LSB`009`009`009;Turn off local symbol mode
X.Endm`009Device_Type`009`009`009;Done
X
X`009.Page
X`009.Subtitle`009Impure storage
X
X`009.Psect`009IMPURE_DATA`009NOEXE,RD,WRT,PIC,NOSHR,PAGE
X
X
X; Random impure data.
X
XIN_DESC:`009.Long`009128`009`009;Input buffer
X`009`009.Address IN_BUFF`009; descriptor
XOUT_DESC:`009.Long`009128`009`009;Output buffer
X`009`009.Address OUT_BUFF`009; descriptor
XIOSB:`009`009.Blkq`009`009`009;I/O status block
XFAO_ARGS:`009.Blkl`0096`009`009;FAO arguments
XDEV_CHAN:`009.Blkw`009`009`009;Channel number
X
X
X; P1 sense mode characteristics buffer.
X
XDEV_CLASS:`009.Blkb`009`009`009;Device class
XDEV_TYPE:`009.Blkb`009`009`009;Device type
XBUFF_SIZE:`009.Blkw`009`009`009;Maximum message size
X`009`009.Blkb`009`009`009;Unused
XDEV_STATUS:`009.Blkb`009`009`009;Controller status
XERR_SUMMARY:`009.Blkb`009`009`009;Error summary
X`009`009.Blkb`009`009`009;Unused
X
X
X; P2 set mode characteristics buffer
X
XP2_SET_DESC:`009.Long`009P2_SET_LENG`009;P2 set mode
X`009`009.Address P2_SET_BUFF`009; descriptor
XP2_SET_BUFF:`009.Word`009NMA$C_PCLI_PTY`009;Set the protocol type
X`009`009.Long`009`094x0660`009`009; to something useless
XP2_SET_LENG`009=`009.-P2_SET_BUFF`009;Buffer length
X
X
X; P2 sense mode characteristics buffer.
X
XP2_DESC:`009.Long`0091024`009`009;P2 buffer
X`009`009.Address P2_BUFF`009; descriptor
X
X
X; Buffers, etc.
X
XIN_BUFF:`009.Blkb`009128`009`009;Input buffer
XOUT_BUFF:`009.Blkb`009128`009`009;Output buffer
XP2_BUFF:`009.Blkb`0091024`009`009;P2 characteristics buffer
X
X`009.Page
X`009.Subtitle`009Pure storage
X
X`009.Psect`009PURE_DATA`009NOEXE,RD,NOWRT,PIC,SHR,PAGE
X
X
X; Device type table.
X
XDEVICE_TABLE:`009Device_Type`009DT$_DEUNA,<Deuna>
X`009`009Device_Type`009DT$_DEQNA,<Deqna>
X`009`009Device_Type`009DT$_ES_LANCE,<Lance>
X`009`009Device_Type`009DT$_DELUA,<Delua>
X`009`009Device_Type`009DT$_ET_DEBNA,<Debna/Debnt>
X`009`009Device_Type`009DT$_ET_DEBNI,<Debni>
X`009`009.Long`009`0090,0
X
X; Random strings.
X
XPROMPT:`009`009.Ascid`009"Device: "
XUNKNOWN:`009.Ascid`009"Unknown"
XFAO_DEVTYPE:`009.Ascid`009"Device type:`009`009!AS"
XFAO_PHYSADDR:`009.Ascid`009"DECnet address:`009`009!XB-!XB-!XB-!XB-!XB-!XB"
XFAO_HARDADDR:`009.Ascid`009"Hardware address:`009!XB-!XB-!XB-!XB-!XB-!XB"
X
X`009.Page
X`009.Subtitle`009Entry point
X
X`009.Psect`009CODE`009`009EXE,RD,NOWRT,PIC,SHR,PAGE
X
X`009.Entry`009START,`094M<>`009`009;Entry here
X
X`009MOVAQ`009P2_DESC,R6`009`009;A handy address
X
X; Loop here asking for input until error or EOF.
X
X10$:`009MOVZBL`009#128,IN_DESC`009`009;Reset the descriptor
X`009PUSHAW`009IN_DESC`009`009`009;Return the length here
X`009PUSHAQ`009PROMPT`009`009`009;Prompt with this
X`009PUSHAQ`009IN_DESC`009`009`009;Here's the input buffer
X`009CALLS`009#3,G`094LIB$GET_INPUT`009;Grab some input
X`009BLBC`009R0,20$`009`009`009;Hope for EOF
X`009PUSHAQ`009IN_DESC`009`009`009;Trim
X`009PUSHL`009(SP)`009`009`009; trailing
X`009CALLS`009#2,G`094STR$TRIM`009`009;  whitespace
X`009TSTW`009IN_DESC`009`009`009;Any input?
X`009BEQL`00910$`009`009`009;If EQL no, ask again
X
X; Lose the old I/O channel if we have one and get a new one.
X
X`009$DASSGN_S CHAN=DEV_CHAN`009`009;Lose the old channel
X`009$ASSIGN_S DEVNAM=IN_DESC,-`009;Get a new
X`009`009CHAN=DEV_CHAN`009`009; channel
X
X20$:`009BLBC`009R0,30$`009`009`009;Eh?
X
X; Crock - we have to actually start the device up with a bogus protocol
X; type in order to get the device driver to return something other than
X; FF-FF-FF-FF-FF-FF for the physical (DECnet) address.
X
X`009MOVAQ`009P2_SET_DESC,R1`009`009`009`009   ;Maintain PIC
X`009$QIOW_S`009CHAN=DEV_CHAN,-`009`009`009`009   ;Set the
X`009`009FUNC=#IO$_SETMODE!IO$M_CTRL!IO$M_STARTUP,- ; physical address
X`009`009IOSB=IOSB,-`009`009`009`009   ;  to the DECnet
X`009`009P2=R1`009`009`009`009`009   ;   default
X
X; Fish up the device characteristics.
X
X`009$QIOW_S`009CHAN=DEV_CHAN,-`009`009`009;Fish up
X`009`009FUNC=#IO$_SENSEMODE!IO$M_CTRL,-`009; the device
X`009`009IOSB=IOSB,-`009`009`009;  characteristics
X`009`009P1=DEV_CLASS,-`009`009`009;Device characteristics quadword here
X`009`009P2=R6`009`009`009`009;Special parameters here
X`009BLBC`009R0,30$`009`009`009`009;Lossage!
X`009MOVZWL`009IOSB,R0`009`009`009`009;Check here, too.
X`009BLBC`009R0,30$`009`009`009`009;Boo hiss.
X`009BSBB`009DISPLAY`009`009`009`009;Display what we got
X`009BRW`00910$`009`009`009`009;Around and around we go
X
X; Here on error or EOF.
X
X30$:`009CMPL`009#RMS$_EOF,R0`009`009;End of file?
X`009BNEQ`00940$`009`009`009;If NEQ no
X`009MOVL`009#SS$_NORMAL,R0`009`009;Shh.
X
X40$:`009RET`009`009`009`009;Done, status in R0
X
X`009.Page
X`009.Subtitle`009DISPLAY`009`009- Display device characteristics
X
X;+
X;
X; ----- DISPLAY:  Display device characteristics
X;
X;
X; This routine will display the device characteristics for whatever
X; device we've fished them up for.
X;
X; Inputs:
X;
X;`009Characteristics buffers filled in.
X;
X; Outputs:
X;
X;`009Information displayed on SYS$OUTPUT.
X;
X;-
X
XDISPLAY:`009`009`009`009;Display device characteristics
X
X`009BSBW`009BLANK_LINE`009`009;Blank line
V`009MOVAQ`009UNKNOWN,FAO_ARGS`009;Presume we don't know what kind of interfac
Xe it is
X`009MOVAL`009DEVICE_TABLE,R2`009`009;Address the device table
X
X10$:`009MOVQ`009(R2)+,R3`009`009;Fetch the next type,,address
X`009BEQL`00920$`009`009`009;If EQL we lose
X`009CMPB`009R3,DEV_TYPE`009`009;This one?
X`009BNEQ`00910$`009`009`009;If NEQ no, try the next one
X`009MOVL`009R4,FAO_ARGS`009`009;Else use this name for it
X
X20$:`009MOVAQ`009FAO_DEVTYPE,R1`009`009;Format with this string
X`009BSBW`009FAO_IT`009`009`009;Display it
X`009MOVL`009#NMA$C_PCLI_PHA,R1`009;Search for this parameter
X`009BSBB`009SEARCH_PARAM`009`009;`009...
X`009BLBC`009R0,30$`009`009`009;Eh?
X
X; Current physical address.
X
X`009TSTL`009(R3)+`009`009`009;Skip the parameter word & length word
X`009MOVAL`009FAO_ARGS,R2`009`009;Put it here
X`009MOVZBL`009(R3)+,(R2)+`009`009;Copy
X`009MOVZBL`009(R3)+,(R2)+`009`009; the
X`009MOVZBL`009(R3)+,(R2)+`009`009;  ethernet
X`009MOVZBL`009(R3)+,(R2)+`009`009;   address
X`009MOVZBL`009(R3)+,(R2)+`009`009;`009...
X`009MOVZBL`009(R3)+,(R2)+`009`009;`009...
X`009MOVAQ`009FAO_PHYSADDR,R1`009`009;Format with this string
X`009BSBB`009FAO_IT`009`009`009;Display it
X
X; Controller hardware address.
X
X`009MOVL`009#NMA$C_PCLI_HWA,R1`009;Search for
X`009BSBB`009SEARCH_PARAM`009`009; this parameter
X`009BLBC`009R0,30$`009`009`009;Eh?
X`009TSTL`009(R3)+`009`009`009;Pass up the parameter word & length word
X`009MOVAL`009FAO_ARGS,R2`009`009;Put it here
X`009MOVZBL`009(R3)+,(R2)+`009`009;Copy
X`009MOVZBL`009(R3)+,(R2)+`009`009; the
X`009MOVZBL`009(R3)+,(R2)+`009`009;  ethernet
X`009MOVZBL`009(R3)+,(R2)+`009`009;   address
X`009MOVZBL`009(R3)+,(R2)+`009`009;`009...
X`009MOVZBL`009(R3)+,(R2)+`009`009;`009...
X`009MOVAQ`009FAO_HARDADDR,R1`009`009;Format with this string
X`009BSBB`009FAO_IT`009`009`009;Display it
X`009BRB`009BLANK_LINE`009`009;Output a blank and return
X
X; Here on parameter not found.
X
X30$:`009RET`009`009`009`009;Egad!
X
X`009.Page
X`009.Subtitle`009SEARCH_PARAM`009- Search for a specified parameter
X
X;+
X;
X; ----- SEARCH_PARAM:  Search for a specified parameter
X;
X;
X; This routine will search through the P2 buffer for the specified parameter.
X;
X; Inputs:
X;
X;`009R1`009- Parameter to search for
X;`009IOSB`009- I/O status block from the sensemode QIO
X;
X; Outputs:
X;
X;`009R0`009- Status
X;`009R3`009- Pointer to the specified parameter if found
X;
X;-
X
XSEARCH_PARAM:`009`009`009`009;Search for a specified parameter
X
X`009MOVAB`009P2_BUFF,R3`009`009;Start here
X`009MOVZWL`009IOSB+2,R2`009`009;There's this much data
X`009BLEQ`00930$`009`009`009;If LEQ error
X
X10$:`009CMPZV`009#0,#12,(R3),R1`009`009;This parameter?
X`009BEQL`00940$`009`009`009;Yes, we found it
X`009MOVL`009#3*2,R0`009`009`009;Presume longword parameter
X`009BBC`009#12,(R3),20$`009`009;Branch if this is the case
X`009TSTW`009(R3)+`009`009`009;Else it's a string parameter
X`009MOVZWL`009(R3)+,R0`009`009;Fetch the length
X
X20$:`009ADDL`009R0,R3`009`009`009;Point to the next parameter
X`009SUBL`009R0,R2`009`009`009;Anything left in the buffer?
X`009BGTR`00910$`009`009`009;If GTR yes
X
X30$:`009MOVL`009#SS$_BADPARAM,R0`009;Else we didn't find it
X`009RSB`009`009`009`009;`009...
X
X40$:`009MOVL`009#SS$_NORMAL,R0`009`009;Success
X`009RSB`009`009`009`009;`009...
X
X`009.Page
X`009.Subtitle`009FAO_IT`009`009- Format and display a message
X
X;+
X;
X; ----- FAO_IT:  Format and display a message
X;
X;
X; This routine will format and display a message.
X;
X; Inputs:
X;
X;`009R1`009- FAO control string address
X;
X; Outputs:
X;
X;`009Results displayed on SYS$OUTPUT.
X;
X;-
X
XFAO_IT:`009`009`009`009`009;Format and display a message
X
X`009MOVZBL`009#128,OUT_DESC`009`009;Reset the output descriptor
X`009$FAOL_S`009CTRSTR=(R1),-`009`009;Format with this string
X`009`009OUTLEN=OUT_DESC,-`009;Return the length here
X`009`009OUTBUF=OUT_DESC,-`009;The output buffer is here
X`009`009PRMLST=FAO_ARGS`009`009;Arguments are here
X`009PUSHAQ`009OUT_DESC`009`009;Stack the descriptor address
X`009CALLS`009#1,G`094LIB$PUT_OUTPUT`009;Display it
X`009RSB`009`009`009`009;Done
X
X`009.Page
X`009.Subtitle`009BLANK_LINE`009- Output a blank line
X
X;+
X;
X; ----- BLANK_LINE:  Output a blank line
X;
X;
X; This routine will output a blank line.
X;
X; Inputs:
X;
X;`009None.
X;
X; Outputs:
X;
X;`009Blank line output.
X;
X;-
X
XBLANK_LINE:`009`009`009`009;Output a blank line
X
X`009CLRL`009OUT_DESC`009`009;Output
X`009PUSHAQ`009OUT_DESC`009`009; a
X`009CALLS`009#1,G`094LIB$PUT_OUTPUT`009;  blank
X`009RSB`009`009`009`009;   line
X
X
X
X`009.End`009START
$ GOSUB UNPACK_FILE
$ EXIT

