/*++

*******************************************************************************
* Copyright (c) 1994-95 Digi International Inc., All Rights Reserved          *
*                                                                             *
* This  software  contains  proprietary  and  confidential   information   of *
* Digi International  Inc.   By  accepting  transfer  of this copy, Recipient *
* agrees to retain this software in  confidence,  to  prevent  disclosure  to *
* others,  and  to make no  use of this software other than that for which it *
* was delivered.  This is an unpublished copyright work  Digi   International *
* Inc.    Except   as   permitted   by  federal  law,  17 USC 117, copying is *
* strictly prohibited.                                                        *
*                                                                             *
* Digi  International  Inc.  CONFIDENTIAL  -   (Digi    International    Inc. *
* Confidential  when   combined   with   the   aggregated  modules  for  this *
* product) OBJECT CODE ONLY SOURCE MATERIALS                                  *
*                                                                             *
* (C) COPYRIGHT Digi International Inc. 1994-95                               *
*                                                                             *
* All Rights Reserved                                                         *
*                                                                             *
* US   Government   Users   Restricted   Rights   -   Use,   duplication   or *
* disclosure  restricted by GSA ADP Schedule Contract with Digi International *
* Inc.                                                                        *
*                                                                             *
*******************************************************************************

Module Name:

   arp.c

Abstract:

   This module handles spoofing of ARP messages when we're routing IP.  Routers 
   do not pass ARP packets across the FR link, so when we get an ARP request 
   packet from Ndis, we must create our own ARP reply.

Author:

   Michael Zarns

Revision History:

   $Log: /Components/Windows/NT/Sync/Lan/ARP.C $
 * 
 * 4     1/30/97 7:50a Mikez
 * Removed Wan ArpReply code.
 * 
 * 3     1/29/97 5:06p Mikez
 * Added template code for Arp support over Frame.  Untested, not used,
 * but in the source files nonetheless.
 * 
 * 2     8/13/96 10:47a Mikez
 * Fully abstracted Frame Relay code into three routines:  FrSend,
 * FrReceive and FrInit, and one AdapterObject field: RxControlLength.
 * This revision works and support Frame Relay only.
 * 
 * 1     8/05/96 2:14p Mikez
 * 
 * 2     6/28/96 6:41a Mikez
 * Implemented changes to force transmits (MiniportSends) to complete
 * synchronously and never call NdisMSendComplete.  Also, forced spoofed
 * ARP replies to be processed via the AdapterContextTimerFunction.
 * 
 * 1     3/11/96 3:15p Mikez
 * Revision 1.1  1995/08/23  07:47:19  mikez
 * Initial revision
 * 

--*/

#include "digilan.h"



/*
	Format of an Arp Request/Reply frame:

Octet
		+----------------+----------------+----------------+----------------+
  1	|  Destination MAC Address                                          |
		|                +                +----------------+----------------+
  4	|                                 | Source MAC Address              |
		+----------------+----------------+                +                |
  8	|                                                                   |
		+----------------+----------------+----------------+----------------+
  12	|      Protocol ID (0x0806)		  | Hardware Address Space (0x0001)|
		+----------------+----------------+----------------+----------------+
  16	| Protocol Address Space (0x0800) | Hw Addr Len (6)| Prot Len (4)   |
		+----------------+----------------+----------------+----------------+
  20	|   OpCode (1=Request, 2=Reply)   | Sender Hardware Address         |
		+----------------+----------------+                +                |
  24	|                                                                   |
		+----------------+----------------+----------------+----------------+
  28	|                        Sender Protocol Address                    |
		+----------------+----------------+----------------+----------------+
  32	|   Target Hardware Address                                         |
		|                                 +----------------+----------------+
  36	|                                 |  Target Protocol Address        |
		+----------------+----------------+---------------------------------+
  40	|  Target Protocol Addr (cont)    |
		+----------------+----------------+

	Where Sender and Source *always* refer to the machine sending the packet
	and Target and Destination *always* refer to the machine receiving the
	packet.
*/



VOID
DigiLanSpoofArpReply(
	PDIGILAN_LOGICAL_ADAPTER pAdapter, 
	PNDIS_PACKET pNdisPacket
	)
/*++

Description:

	This routine takes an ARP request packet and massages it into an ARP reply 
	packet.  This is called only from FrSend when we're routing IP because
	routers do not pass ARP packets along the Frame Relay link but NT expects
	a response to it's ARP request.

Parameters:

	pAdapter
		Address of the adapter data structure.

	pNdisPacket
		The ndis_packet defining the Arp request.

Return Value:

	None

--*/
{
	UCHAR TargetProtocolAddress[ARP_PROTOCOL_ADDR_LENGTH];
	BOOLEAN IsDestinationMyself;
	NDIS_STATUS Status;
	ULONG PacketLength;
	PDIGILAN_ETHERNET_FRAME pFrame;

	ENTER( "DigiLanSpoofArpReply" );

	NdisQueryPacket( pNdisPacket, NULL, NULL, NULL, &PacketLength );

	pFrame = DigiAllocMem( NonPagedPool, PacketLength );

	if ( !pFrame )
		LEAVE_NOVAL( "DigiLanSpoofArpReply" );

	Status = DigiGetNdisPacketData( (PVOID)pFrame, pNdisPacket, PacketLength, 0 );

	if ( !NT_SUCCESS( Status ) )
	{
		DigiFreeMem( pFrame );
		LEAVE_NOVAL( "DigiLanSpoofArpReply" );
	}

	//
	// The packet should already be a valid Arp request packet
	//

	ASSERT( sizeof( ArpCommandRequest ) == 2 );

	ASSERT( 
		DigiCompareMemory( 
			&pFrame->Payload[6], 
			ArpCommandRequest, 
			sizeof( ArpCommandRequest ) 
			) 
		);

	//
	// TCP does an initial Arp request directed at its own IP address, hoping to 
	// discover any other machine on the net already using that IP address - to
	// avoid an IP addressing conflict.  If this arp request is self-directed, 
	// just return.
	//
	IsDestinationMyself = DigiCompareMemory( &pFrame->Payload[14],
														  &pFrame->Payload[24],
														  ARP_PROTOCOL_ADDR_LENGTH
														  );
	if ( IsDestinationMyself )
	{
		DigiFreeMem( pFrame );
		LEAVE_NOVAL( "DigiLanSpoofArpReply" );
	}

	//
	// Change it to a reply packet
	//
	
	NdisMoveMemory( 
		&pFrame->Payload[6],
		ArpCommandReply,
		sizeof( ArpCommandReply ) 
		);

	//
	// Set the MAC addresses
	//

	NdisMoveMemory( 
		&pFrame->Header[ETHERNET_MAC_DEST_OFFSET],
		&pAdapter->CurrentNetworkAddress,
		ETHERNET_MAC_ADDR_SIZE
		);

	NdisMoveMemory( 
		&pFrame->Header[ETHERNET_MAC_SRC_OFFSET],
		&pAdapter->RemoteNetworkAddress,
		ETHERNET_MAC_ADDR_SIZE
		);

	//
	// Temporarily save the target protocol addr
	//

	NdisMoveMemory( 
		TargetProtocolAddress,
		&pFrame->Payload[24],
		ARP_PROTOCOL_ADDR_LENGTH 
		);

	//
	// Move the sender HW and protocol addresses to the target HW and protocol
	// address area
	//

	NdisMoveMemory( 
		&pFrame->Payload[18],
		&pFrame->Payload[8],
		ARP_PROTOCOL_ADDR_LENGTH + ETHERNET_MAC_ADDR_SIZE
		);

	//
	// Fill in the sender HW address
	//

	NdisMoveMemory( 
		&pFrame->Payload[8],
		&pAdapter->RemoteNetworkAddress,
		ETHERNET_MAC_ADDR_SIZE );

	//
	// Now stuff in the saved sender protocol address
	//

	NdisMoveMemory( 
		&pFrame->Payload[14],
		TargetProtocolAddress,
		ARP_PROTOCOL_ADDR_LENGTH );

	Status = DigiQueueIndicateReceive( pAdapter, 
	                                   (PVOID)pFrame, 
	                                   pFrame, 
	                                   PacketLength - ETHERNET_MAC_HEADER_SIZE );

	if ( !NT_SUCCESS( Status ) )
	{
		// Couldn't queue up receive indication.
		DigiDump( DIGIERRORS, 
			       ("*** DigiLan: Could not queue spoofed ARP reply!\n") );
		DigiFreeMem( pFrame );
	}
}

//------------------------------------------------------------ MLZ 01/30/97 {
#if 0

VOID
DigiIncomingArpReply(
	PDIGILAN_LOGICAL_ADAPTER pAdapter, 
	PUCHAR pArpRequest,
	ULONG Length
	)
/*++

Description:

	This routine takes an ARP request packet and massages it into an ARP reply 
	packet and sends it back out on the wire.  This is called only from 
	FrReceive.  BayNetworks AN router sends ARPs with 2 byte HW addresses 
	(instead of 6 like typical ethernet), expecting the HwAddress to identify 
	the DLCI.  We reply with a HwAddress identifying the DLCI as encoded in the 
	Q.922 address field of a Frame Relay frame.

	Q.922 Address Format:
	
		Bit Position	  8    7    6    5    4    3    2    1
							+----+----+----+----+----+----+----+----+
		Octet 1			|       DLCI                  | CR | EA |
							+--               --+----+----+----+----+
		Octet 2			|                   |FECN|BECN| DE | EA |
							+-------------------+----+----+----+----+

	Where DLCI is the Data Link Connection Identifier.  Highest 6 bits in 
	octet 1, low 4 bits in octet 2.  The rest are zeroed out.  This is used as
	the HwAddress in the Arp reply frame, format as follows:

	ARP Reply Format
							+----------------+----------------+----------------+----------------+
		Octet 0			| Hardware Address Space (0x000f) | Protocol Address Space (0x0806) |
							+----------------+----------------+----------------+----------------+
							+ HwAddr Len (2) | Proto Len (4)  |    OpCode (1=Request, 2=Reply)  |
							+----------------+----------------+----------------+----------------+
		Octet 4			|  Sender Hardware Address (DLCI) |     Sender Protocol Address     |
							+----------------+----------------+----------------+----------------+
		Octet 8			|  Sender Protocol Address (cont) |  Target Hardware Address (DLCI) |
							+----------------+----------------+----------------+----------------+
		Octet 12			|                        Target Protocol Address                    |
							+----------------+----------------+----------------+----------------+

	Where Sender *always* refer to the machine sending the packet and Target *always* refer 
	to the machine receiving the packet.

Parameters:

	pAdapter
		Address of the adapter data structure.

	pArpRequest
		Address of the incoming arp packet.

	Length
		Length of the incoming arp packet.

Return Value:

	None

--*/
{
#define FR_ARP_PACKET_SIZE  0x20
#define FR_ARP_OFFSET_SRC_HW 0x04
#define FR_ARP_OFFSET_SRC_PROTO 0x06
#define FR_ARP_OFFSET_TARGET_HW 0x0a
#define FR_ARP_OFFSET_TARGET_PROTO 0x0c

	UCHAR ArpHeaderConst[] = { 0x00, 0x0f, 0x08, 0x06, 0x02, 0x04, 0x01 };
	FRP_SendData_t SendData;
	ULONG BytesEqual;
	PUCHAR pArpReply = NULL;
	ULONG Offset;

	ENTER( "DigiIncomingArpReply" );

	// Validate incoming Arp request

	if ( Length != FR_ARP_PACKET_SIZE )
		goto IncomingArpError;

	BytesEqual = RtlCompareMemory( pArpRequest, 
	                               &ArpHeaderConst, 
	                               sizeof( ArpHeaderConst ) );

	if ( BytesEqual != sizeof( ArpHeaderConst ) )
		goto IncomingArpError;

	// Build Arp Reply 

	pArpReply = DigiAllocMem( NonPagedPool, FR_ARP_PACKET_SIZE );

	if ( !pArpReply )
	{
		DigiDump( DIGIERRORS, ("IncomingArp: couldn't alloc space for Arp reply!\n") );
		return;
	}

	// Fill in constant header info
	NdisMoveMemory( pArpReply, &ArpHeaderConst, sizeof( ArpHeaderConst ) );
	Offset = sizeof( ArpHeaderConst );

	// Sender Hardware Address
	NdisMoveMemory( pArpReply + Offset, pArpRequest +  )

	return;

IncomingArpError:;
	DigiDump( DIGIERRORS, 
	          ("DigiIncomingArp: Ignoring invalid received Arp packet!\n")  );
	return;
}
#endif
//------------------------------------------------------------ MLZ 01/30/97 }
