[comp.os.vms] Ethernet Driver Promiscuous Mode - VMS Crash

dorl@vms.macc.wisc.edu (Michael (NMI) Dorl) (05/26/87)

I had occasion to write a small program to look at what's happening on
an Ethernet using VMS.  The program assigns a channel to the Ethernet
controller and then receives either every packet or every packet with
a given protocol field going by on the network.  The program works but
the machines crashes after a short time!  

Has anyone had any similar experiences using promiscous mode on
VMS?  Is there some resource in VMS that needs expanding?  Any ideas
welcome.

The program follows.  Note that you need physical IO priv to run it
so don't flame me for posting a program that crashes VMS.

My machine crashes if I specify a protocol type of zero or 6003 (hex)
which is DECNet.  It does not crash if I specify some non-existant
protocol.  It crashes if I specify a function of TRACE or SUMMARY.
TRACE prints every packet while SUMMARY prints some statistics after
receiving 1000 packets so I don't think it has anything to do with
the printing.  I have no problem if I reduce the packet count to
some small number like 100..

-----------------------------------------------------------------------

	Implicit None

	Include '($IODef)'

	External Sys$QIOW
	Integer  Sys$QIOW

	External Sys$Assign
	Integer  Sys$Assign

        Structure /SetDef/

         Union
         Map
          Integer  *2   BFN		!  2 Number of buffers
          Integer  *4   BFN_Value	!  4

 	  Integer  *2   BUS		!  2 Maximum receive size
          Integer  *4   BUS_Value	!  4

	  Integer  *2   PRM		!  2 Promiscuous mode
	  Integer  *4   PRM_Value	!  4

	  Integer  *2   PTY		!  2 Protocol type
	  Integer  *4   PTY_Value	!  4
					! --
					! 24 bytes total length
         End Map

         Map
          Byte          All
         End Map
	 End Union

	End Structure

	Parameter Set_Lg = 24

        Structure /DescDef/

	 Integer *2 Length
	 Byte       Type
	 Byte       Class
	 Integer *4 Address

        End Structure

	Structure /IOSBDef/
	 Integer *2 Condition
	 Integer *2 Count
	 Integer *4 Specific
	End Structure

        Structure /HeaderDef/
         Byte       Destination(6)
	 Byte       Source(6)
         Integer *2 Protocol
        End Structure

C I can't find a $NMADEF anywhere so define the values I need

	Parameter NMA$C_PCLI_BFN  = 1105
	Parameter NMA$C_PCLI_BUS  = 2801
	Parameter NMA$C_PCLI_PRM  = 2840
	Parameter NMA$C_PCLI_PTY  = 2830
	Parameter NMA$C_State_On  = 0
	Parameter NMA$C_State_Off = 1

C Parameter Definitions

        Integer NAddr
        Parameter (NAddr = 100)
        Integer NProt
        Parameter (NProt = 50)

C Local Definitions

	Record /SetDef/   Set
	Record /DescDef/  Set_Desc

	Integer *4        Status, Function, I, N, DesdProtocol
	Integer *2 	  Channel

 	Record /IOSBDef/  IOSB

	Record /HeaderDef/ Header

	Byte 		  Buffer(1500)

        Byte              Address(6,NAddr)
        Integer           Source_Count(NAddr)
        Integer           Destination_Count(NAddr)
        Integer           XAddr
        Integer           Prot(NProt)
        Integer           Prot_Count(NProt)
        Integer           XProt

        Character *16     Func

        Integer J, Found

C	Begin

	Print '(A,$)', ' Protocol type (Hex) = '
	Read '(Z)', DesdProtocol
        Print '(A,Z3.3)', ' Protocol type = ', DesdProtocol

1       Print '(A,$)', ' Function = '
        Read '(A)', Func
        If (Func .eq. 'trace') Then
        Else If (Func .eq. 'summary') Then
        Else If (Func .eq. ' ') Then
          Func = 'trace'
        Else
          Print '(A)', ' Illegal function, type "trace" or "summary"'
          Goto 1
        EndIf

        XProt = 1
        Prot(1) = 0
        XAddr = 1			! Address(n,1) is default
        Do I = 1,6
          Address(I,1) = 0
        EndDo

	Set.BFN = NMA$C_PCLI_BFN 	! Number of preallocated
	Set.BFN_Value = 4		!  receive buffers	

	Set.BUS = NMA$C_PCLI_BUS	! Maximum allowable
	Set.BUS_Value = 1500		!  buffer length

	Set.PRM = NMA$C_PCLI_PRM	! Set promiscuous (all packets)
	Set.PRM_Value = NMA$C_State_On  !  mode

	Set.PTY = NMA$C_PCLI_PTY        ! Set protocol type
	Set.PTY_Value = 0

	Set_Desc.Length = Set_Lg
	Set_Desc.Type = 0
	Set_Desc.Class = 0
	Set_Desc.Address = %Loc(Set.All)

C Open a channel to the DEUNA

	Status = Sys$Assign ('XEA0', Channel,,)
	If (.not. Status) Then
          Print '(A,Z)', ' Assign channel failed, status = ', Status
	  Stop
	EndIf

C Set parameters and start Ethernet channel

        Function = IO$_SetMode + IO$M_Ctrl + IO$M_StartUp
	Status = Sys$QIOW 
     $    (,			! efn
     $ 	   %Val(Channel),	! chan
     $	   %Val(Function),	! func
     $	   IOSB,		! iosb
     $	   ,			! astadr
     $	   ,			! astprm
     $	   ,			! p1
     $	   Set_Desc,		! p2
     $	   ,,,			! p3 - p6
     $	  )

	If (.not. Status) Then
  	  Print '(A,Z)', ' SetMode and startup failed, status = ',
     $      Status
	  Stop
	EndIf

	If (.not. IOSB.Condition) Then
  	  Print '(A,Z)',
     $      ' SetMode and startup failed, IOSB.Condition = ',
     $ 	    IOSB.Condition
	  Stop
	EndIf

C Monitor the Ethernet

        If (Func .eq. 'trace') Then
          Print '(2(x,A12),x,A4,x,A4,x,A)',
     $      'Source      ',
     $      'Destination ',
     $      'Prot',
     $      'Lg. ',
     $      'Data'
        EndIf

	N = 0
	Do While ((Status) .and. (N .lt. 1000))

          N = N + 1

	  Function = IO$_ReadVBlk
	  Status = Sys$QIOW 
     $      (,			! efn
     $ 	    %Val(Channel),	! chan
     $	    %Val(Function),	! func
     $	    IOSB,		! iosb
     $	    ,			! astadr
     $	    ,			! astprm
     $	    Buffer,		! p1
     $	    %Val(1500),		! p2
     $	    ,			! p3
     $      ,			! p4
     $      Header,		! p5
     $				! p6
     $	  )

	  If (Status) Then
            If ((DesdProtocol .eq. 0) .or. 
     $	        (Header.Protocol .eq. DesdProtocol)
     $         ) Then
              If (Func .eq. 'trace') Then
    	        Print '(2(x,6Z2.2),x,Z4.4,x,Z4.4,32(x,Z2.2))', 
     $            (Header.Source(I), I=6,1,-1),
     $            (Header.Destination(I), I=6,1,-1),
     $            Header.Protocol,
     $            IOSB.Count,
     $            (Buffer(I), I=1,15)
              Else
c               If (XAddr .gt. 1) Then
                  Found = 0
		  I = 2
		  Do While ((.not. Found) .and. (I .le. XAddr))
                    Do J = 1,6
                      If (Address(J,I) .ne. Header.Source(J)) Then
                        I = I + 1
			Goto 2
                      EndIf
                    EndDo
                    Found = 1
2                   Continue
		  EndDo
c               Else
c                 Found = 0
c               EndIf
                If (.not. Found) Then
                  If (I .le. NAddr) Then
                    XAddr = I
                    Do J = 1,6
                      Address(J,I) = Header.Source(J)
                    EndDo
                  Else
                    I = 1
                  EndIf
                EndIf
                Source_Count(I) = Source_Count(I) + 1

C Record protocol

                Found = 0
                I = 2
                Do While ((.not. Found) .and. (I .le. XProt))
		  If (Prot(I) .eq. Header.Protocol) Then
                    Found = 1
                  Else
                    I = I + 1
                  EndIf
                End Do
                If (.not. Found) Then
                  If (I .gt. NProt) Then
                    I = 1
                  Else
                    XProt = I
                    Prot(XProt) = Header.Protocol
                    Prot_Count(XProt) = 0
                  EndIf
                EndIf
                Prot_Count(I) = Prot_Count(I) + 1

              EndIf
	    EndIf
          Else
	    Print '(x,Z)', Status
	  EndIf

	EndDo

C Print summary if selected

        If (Func .eq. 'summary') Then
          Do I = 1, XAddr
            Print '(x,6(z2.2,x), I10, I10)',
     $        (Address(J,I), J=1,6),
     $        Source_Count(I), Destination_Count(I)
          EndDo
          Print '(x,z4.4,i10)', (Prot(I),Prot_Count(I),I=1,XProt)
        EndIf

	End