windows-nt/Source/XPSP1/NT/net/rras/ipx/ipxwan/protocol.c
2020-09-26 16:20:57 +08:00

1916 lines
45 KiB
C

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
protocol.c
Abstract:
ipxwan protocol processing
Author:
Stefan Solomon 02/14/1996
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
PCHAR Workstationp = "WORKSTATION";
PCHAR NumberedRip = "NUMBERED RIP";
PCHAR UnnumberedRip = "UNNUMBERED RIP";
PCHAR OnDemand = "ON DEMAND, STATIC ROUTING";
DWORD
GeneratePacket(PACB acbp,
PUCHAR ipxhdrp,
UCHAR PacketType);
ULONG
GetRole(PUCHAR hdrp,
PACB acbp);
DWORD
StartSlaveTimer(PACB acbp);
DWORD
ProcessInformationResponsePacket(PACB acbp,
PUCHAR rcvhdrp);
DWORD
MakeTimerRequestPacket(PACB acbp,
PUCHAR rcvhdrp,
PUCHAR hdrp);
DWORD
MakeTimerResponsePacket(PACB acbp,
PUCHAR rcvhdrp,
PUCHAR hdrp);
DWORD
MakeInformationRequestPacket(PACB acbp,
PUCHAR rcvhdrp,
PUCHAR hdrp);
DWORD
MakeInformationResponsePacket(PACB acbp,
PUCHAR rcvhdrp,
PUCHAR hdrp);
DWORD
MakeNakPacket(PACB acbp,
PUCHAR rcvhdrp,
PUCHAR hdrp);
DWORD
SendReXmitPacket(PACB acbp,
PWORK_ITEM wip);
VOID
fillpadding(PUCHAR padp,
ULONG len);
//** AcbFailure **
// after this macro is called, clean-up for this adapter is done as follows:
// ipxcp will delete the route (as in ndiswan route to ipx stack)
// this will trigger an adapter deleted indication which will call StopIpxwanProtocol
// this last call will flush the timer queue
// when all pending work items are freed the adapter gets deleted
#define AcbFailure(acbp) Trace(IPXWAN_TRACE, "IPXWAN Configuration failed for adapter %d\n", (acbp)->AdapterIndex);\
(acbp)->OperState = OPER_STATE_DOWN;\
IpxcpConfigDone((acbp)->ConnectionId, NULL, NULL, NULL, FALSE);
UCHAR allffs[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
UCHAR allzeros[] = { 0, 0, 0, 0, 0, 0 };
#define ERROR_IGNORE_PACKET 1
#define ERROR_DISCONNECT 2
#define ERROR_GENERATE_NAK 3
/*++
Function: StartIpxwanProtocol
Descr: Called when an adapter is created.
Starts IPXWAN negotiation on this adapter.
Remark: >> called with the adapter lock held <<
--*/
VOID
StartIpxwanProtocol(PACB acbp)
{
PWORK_ITEM wip;
Trace(IPXWAN_TRACE, "StartIpxwanProtocol: Entered for adapter # %d\n", acbp->AdapterIndex);
// initialize the IPXWAN states
acbp->OperState = OPER_STATE_UP;
acbp->AcbLevel = ACB_TIMER_LEVEL;
acbp->AcbRole = ACB_UNKNOWN_ROLE;
// initialize the IPXWAN database
acbp->InterfaceType = IpxcpGetInterfaceType(acbp->ConnectionId);
if((acbp->InterfaceType == IF_TYPE_STANDALONE_WORKSTATION_DIALOUT) ||
(acbp->InterfaceType == IF_TYPE_ROUTER_WORKSTATION_DIALOUT)) {
memset(acbp->InternalNetNumber, 0, 4);
}
else
{
IpxcpGetInternalNetNumber(acbp->InternalNetNumber);
}
acbp->IsExtendedNodeId = FALSE;
acbp->SupportedRoutingTypes = 0;
// set the routing type and node id to be sent in timer request
switch(acbp->InterfaceType) {
case IF_TYPE_WAN_ROUTER:
case IF_TYPE_PERSONAL_WAN_ROUTER:
if(EnableUnnumberedWanLinks) {
memset(acbp->WNodeId, 0, 4);
acbp->IsExtendedNodeId = TRUE;
memcpy(acbp->ExtendedWNodeId, acbp->InternalNetNumber, 4);
SET_UNNUMBERED_RIP(acbp->SupportedRoutingTypes);
}
else
{
memcpy(acbp->WNodeId, acbp->InternalNetNumber, 4);
SET_NUMBERED_RIP(acbp->SupportedRoutingTypes);
}
break;
case IF_TYPE_WAN_WORKSTATION:
memcpy(acbp->WNodeId, acbp->InternalNetNumber, 4);
SET_WORKSTATION(acbp->SupportedRoutingTypes);
SET_NUMBERED_RIP(acbp->SupportedRoutingTypes);
break;
case IF_TYPE_ROUTER_WORKSTATION_DIALOUT:
case IF_TYPE_STANDALONE_WORKSTATION_DIALOUT:
memset(acbp->WNodeId, 0, 4);
SET_WORKSTATION(acbp->SupportedRoutingTypes);
break;
default:
Trace(IPXWAN_TRACE, "StartIpxwanProtocol: adpt# %d, Invalid interface type, DISCONNECT",
acbp->AdapterIndex);
SS_ASSERT(FALSE);
AcbFailure(acbp);
break;
}
// init negotiated values
acbp->RoutingType = 0;
memset(acbp->Network, 0, 4);
memset(acbp->LocalNode, 0, 6);
memset(acbp->RemoteNode, 0, 6);
// no net number allocated yet
acbp->AllocatedNetworkIndex = INVALID_NETWORK_INDEX;
if(GeneratePacket(acbp, NULL, TIMER_REQUEST) != NO_ERROR) {
Trace(IPXWAN_TRACE, "StartIpxwanProtocol: adpt# %d, ERROR: cannot generate TIMER_REQUEST, DISCONNECT\n",
acbp->AdapterIndex);
AcbFailure(acbp);
}
else
{
Trace(IPXWAN_TRACE, "StartIpxwanProtocol: adpt# %d, Sent TIMER_REQUEST\n",
acbp->AdapterIndex);
}
}
/*++
Function: StopIpxwanProtocol
Descr: Called when an adapter is deleted.
Stops IPXWAN negotiation if still going.
Remark: >> called with the adapter lock held <<
--*/
VOID
StopIpxwanProtocol(PACB acbp)
{
Trace(IPXWAN_TRACE, "StopIpxwanProtocol: Entered for adapter # %d\n", acbp->AdapterIndex);
acbp->OperState = OPER_STATE_DOWN;
// remove all work items referencing this acb from the timer queue
StopWiTimer(acbp);
// free allocated wan net if any
if(acbp->AllocatedNetworkIndex != INVALID_NETWORK_INDEX) {
IpxcpReleaseWanNetNumber(acbp->AllocatedNetworkIndex);
}
}
/*++
Function: IpxwanConfigDone
Descr: remove items referencing this acb from the timer queue
sets the new configured values in the ipx stack
Remark: >> called with the adapter lock held <<
--*/
VOID
IpxwanConfigDone(PACB acbp)
{
DWORD rc;
IPXWAN_INFO IpxwanInfo;
StopWiTimer(acbp);
memcpy(IpxwanInfo.Network, acbp->Network, 4);
memcpy(IpxwanInfo.LocalNode, acbp->LocalNode, 6);
memcpy(IpxwanInfo.RemoteNode, acbp->RemoteNode, 6);
rc = IpxWanSetAdapterConfiguration(acbp->AdapterIndex,
&IpxwanInfo);
if(rc != NO_ERROR) {
Trace(IPXWAN_TRACE, "IpxwanConfigDone: Error %d in IpxWanSetAdapterConfiguration\n",
rc);
AcbFailure(acbp);
SS_ASSERT(FALSE);
}
else
{
IpxcpConfigDone(acbp->ConnectionId,
acbp->Network,
acbp->LocalNode,
acbp->RemoteNode,
TRUE);
Trace(IPXWAN_TRACE,"\n*** IPXWAN final configuration ***");
Trace(IPXWAN_TRACE," Network: %.2x%.2x%.2x%.2x\n",
acbp->Network[0],
acbp->Network[1],
acbp->Network[2],
acbp->Network[3]);
Trace(IPXWAN_TRACE," LocalNode: %.2x%.2x%.2x%.2x%.2x%.2x",
acbp->LocalNode[0],
acbp->LocalNode[1],
acbp->LocalNode[2],
acbp->LocalNode[3],
acbp->LocalNode[4],
acbp->LocalNode[5]);
Trace(IPXWAN_TRACE," RemoteNode: %.2x%.2x%.2x%.2x%.2x%.2x",
acbp->RemoteNode[0],
acbp->RemoteNode[1],
acbp->RemoteNode[2],
acbp->RemoteNode[3],
acbp->RemoteNode[4],
acbp->RemoteNode[5]);
}
}
/*++
Function: ProcessReceivedPacket
Descr:
Remark: >> called with the adapter lock held <<
--*/
VOID
ProcessReceivedPacket(PACB acbp,
PWORK_ITEM wip)
{
PUCHAR ipxhdrp; // ipx header
PUCHAR wanhdrp; // ipx wan header
PUCHAR opthdrp; // option header
DWORD rc = NO_ERROR;
USHORT pktlen;
ULONG role;
USHORT rcvsocket;
PCHAR Slavep = "SLAVE";
PCHAR Masterp = "MASTER";
if(acbp->OperState == OPER_STATE_DOWN) {
return;
}
// validate packet
ipxhdrp = wip->Packet;
// check the packet length
GETSHORT2USHORT(&pktlen, ipxhdrp + IPXH_LENGTH);
if(pktlen > MAX_IPXWAN_PACKET_LEN) {
// bad length packet
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: Reject packet because of invalid length %d\n", pktlen);
return;
}
// check remote socket and confidence id
GETSHORT2USHORT(&rcvsocket, ipxhdrp + IPXH_SRCSOCK);
if(rcvsocket != IPXWAN_SOCKET) {
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: Reject packet because of invalid socket %x\n", rcvsocket);
return;
}
wanhdrp = ipxhdrp + IPXH_HDRSIZE;
if(memcmp(wanhdrp + WIDENTIFIER,
IPXWAN_CONFIDENCE_ID,
4)) {
// no confidence
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: Reject packet because of invalid confidence id\n");
return;
}
switch(*(wanhdrp + WPACKET_TYPE)) {
case TIMER_REQUEST:
role = GetRole(ipxhdrp, acbp);
switch(role) {
case ACB_SLAVE_ROLE:
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: Rcvd TIMER_REQUEST adpt# %d, local role %s",
acbp->AdapterIndex,
Slavep);
acbp->AcbRole = ACB_SLAVE_ROLE;
acbp->RoutingType = 0;
if(acbp->AcbLevel != ACB_TIMER_LEVEL) {
acbp->AcbLevel = ACB_TIMER_LEVEL;
}
rc = GeneratePacket(acbp, ipxhdrp, TIMER_RESPONSE);
switch(rc) {
case NO_ERROR:
acbp->AcbLevel = ACB_INFO_LEVEL;
// start the slave timeout
if(StartSlaveTimer(acbp) != NO_ERROR) {
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: DISCONNECT adpt# %d: cannot start slave timer",
acbp->AdapterIndex);
AcbFailure(acbp);
}
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: TIMER_RESPONSE sent OK on adpt # %d",
acbp->AdapterIndex);
break;
case ERROR_DISCONNECT:
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: DISCONNECT: Error generating TIMER_RESPONSE on adpt# %d",
acbp->AdapterIndex);
AcbFailure(acbp);
break;
case ERROR_IGNORE_PACKET:
default:
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: Ignore received TIMER_REQUEST on adpt# %d",
acbp->AdapterIndex);
break;
}
case ACB_MASTER_ROLE:
if(acbp->AcbLevel != ACB_TIMER_LEVEL) {
// ignore
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: ignore TIMER_REQUEST on adpt# %d because not at TIMER LEVEL",
acbp->AdapterIndex);
return;
}
else
{
acbp->AcbRole = ACB_MASTER_ROLE;
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: Rcvd TIMER_REQUEST adpt# %d, local role %s",
acbp->AdapterIndex,
Masterp);
}
break;
default:
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: DISCONNECT adpt# %d: Unknown role with rcvd TIMER_REQUEST",
acbp->AdapterIndex);
AcbFailure(acbp);
}
break;
case TIMER_RESPONSE:
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: Rcvd TIMER_RESPONSE on adpt# %d",
acbp->AdapterIndex);
// validate
if((acbp->AcbRole == ACB_SLAVE_ROLE) ||
!(acbp->AcbLevel == ACB_TIMER_LEVEL)) {
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: Rcvd TIMER_RESPONSE, DISCONNECT adpt# %d: role not MASTER or state not TIMER LEVEL",
acbp->AdapterIndex);
AcbFailure(acbp);
}
else if(*(wanhdrp + WSEQUENCE_NUMBER) == acbp->ReXmitSeqNo) {
// rfc 1634 - link delay calculation
acbp->LinkDelay = (USHORT)((GetTickCount() - acbp->TReqTimeStamp) * 6);
rc = GeneratePacket(acbp, ipxhdrp, INFORMATION_REQUEST);
switch(rc) {
case NO_ERROR:
acbp->AcbLevel = ACB_INFO_LEVEL;
acbp->AcbRole = ACB_MASTER_ROLE;
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: INFORMATION_REQUEST sent OK on adpt # %d",
acbp->AdapterIndex);
break;
case ERROR_DISCONNECT:
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: DISCONNECT adpt# %d: Error generating INFORMATION_REQUEST",
acbp->AdapterIndex);
AcbFailure(acbp);
break;
case ERROR_IGNORE_PACKET:
default:
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: Ignore received TIMER_RESPONSE on adpt# %d",
acbp->AdapterIndex);
break;
}
}
else
{
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: Ignore TIMER RESPONSE and adpt# %d, non-matching seq no",
acbp->AdapterIndex);
}
break;
case INFORMATION_REQUEST:
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: Rcvd INFORMATION_REQUEST on adpt# %d",
acbp->AdapterIndex);
if((acbp->AcbLevel == ACB_INFO_LEVEL) && (acbp->AcbRole == ACB_SLAVE_ROLE)) {
rc = GeneratePacket(acbp, ipxhdrp, INFORMATION_RESPONSE);
switch(rc) {
case NO_ERROR:
acbp->AcbLevel = ACB_CONFIGURED_LEVEL;
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: INFORMATION_RESPONSE sent OK on adpt # %d",
acbp->AdapterIndex);
IpxwanConfigDone(acbp);
// stop the slave timer
StopWiTimer(acbp);
break;
case ERROR_DISCONNECT:
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: DISCONNECT adpt# %d: Error processing rcvd INFORMATION_REQUEST",
acbp->AdapterIndex);
AcbFailure(acbp);
break;
case ERROR_IGNORE_PACKET:
default:
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: Ignore rcvd INFORMATION_REQUEST on adpt# %d",
acbp->AdapterIndex);
break;
}
}
else
{
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: DISCONNECT on rcvd INFORMATION_REQUEST on adpt# %d\nState not INFO LEVEL or Role not SLAVE\n",
acbp->AdapterIndex);
AcbFailure(acbp);
}
break;
case INFORMATION_RESPONSE:
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: Rcvd INFORMATION_RESPONSE on adpt# %d",
acbp->AdapterIndex);
if((acbp->AcbLevel == ACB_INFO_LEVEL) && (acbp->AcbRole == ACB_MASTER_ROLE)) {
if(*(wanhdrp + WSEQUENCE_NUMBER) == acbp->ReXmitSeqNo) {
rc = ProcessInformationResponsePacket(acbp, wip->Packet);
switch(rc) {
case NO_ERROR:
acbp->AcbLevel = ACB_CONFIGURED_LEVEL;
IpxwanConfigDone(acbp);
break;
case ERROR_DISCONNECT:
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: DISCONNECT adpt# %d: Error processing rcvd INFORMATION_RESPONSE",
acbp->AdapterIndex);
AcbFailure(acbp);
break;
case ERROR_IGNORE_PACKET:
default:
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: Ignore rcvd INFORMATION_RESPONSE on adpt# %d",
acbp->AdapterIndex);
break;
}
}
}
else
{
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: DISCONNECT on rcvd INFORMATION_RESPONSE on adpt# %d\nState not INFO LEVEL or Role not MASTER\n",
acbp->AdapterIndex);
AcbFailure(acbp);
}
break;
case NAK:
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: Rcvd NAK on adpt# %d, DISCONNECT\n",
acbp->AdapterIndex);
AcbFailure(acbp);
break;
default:
Trace(IPXWAN_TRACE, "ProcessReceivedPacket: Rcvd unknown packet on adpt# %d, IGNORE\n",
acbp->AdapterIndex);
break;
}
}
/*++
Function: ProcessReXmitPacket
Descr:
Remark: >> called with the adapter lock held <<
--*/
VOID
ProcessReXmitPacket(PWORK_ITEM wip)
{
PACB acbp;
UCHAR WPacketType;
DWORD rc;
PCHAR PacketTypep;
acbp = wip->acbp;
if(acbp->OperState != OPER_STATE_UP) {
FreeWorkItem(wip);
return;
}
WPacketType = *(wip->Packet + IPXH_HDRSIZE + WPACKET_TYPE);
if(!((acbp->AcbLevel == ACB_TIMER_LEVEL) && (WPacketType == TIMER_REQUEST)) &&
!((acbp->AcbLevel == ACB_INFO_LEVEL) && (WPacketType == INFORMATION_REQUEST))) {
FreeWorkItem(wip);
return;
}
switch(wip->WiState) {
case WI_SEND_COMPLETED:
StartWiTimer(wip, REXMIT_TIMEOUT);
acbp->RefCount++;
break;
case WI_TIMEOUT_COMPLETED:
switch(WPacketType) {
case TIMER_REQUEST:
PacketTypep = "TIMER_REQUEST";
break;
case INFORMATION_REQUEST:
default:
PacketTypep = "INFORMATION_REQUEST";
break;
}
if(acbp->ReXmitCount) {
Trace(IPXWAN_TRACE, "ProcessReXmitPacket: Re-send %s on adpt# %d\n",
PacketTypep,
acbp->AdapterIndex);
if(SendReXmitPacket(acbp, wip) != NO_ERROR) {
Trace(IPXWAN_TRACE, "ProcessReXmitPacket: failed to send on adpt# %d, DISCONNECT\n",
acbp->AdapterIndex);
AcbFailure(acbp);
}
}
else
{
Trace(IPXWAN_TRACE, "ProcessReXmitPacket: Exhausted retry limit for sending %s on adpt# %d, DISCONNECT\n",
PacketTypep,
acbp->AdapterIndex);
AcbFailure(acbp);
}
break;
default:
SS_ASSERT(FALSE);
break;
}
}
/*++
Function: ProcessTimeout
Descr:
Remark: >> called with the adapter lock held <<
--*/
VOID
ProcessTimeout(PWORK_ITEM wip)
{
PACB acbp;
UCHAR WPacketType;
DWORD rc;
acbp = wip->acbp;
FreeWorkItem(wip);
if(acbp->OperState != OPER_STATE_UP) {
return;
}
if((acbp->AcbRole == ACB_SLAVE_ROLE) && (acbp->AcbLevel != ACB_CONFIGURED_LEVEL)) {
AcbFailure(acbp);
}
}
/*++
Function: SendReXmitPacket
Descr: adjusts the rexmit count and seq no and sends the packet
Remark: >> called with adapter lock held <<
--*/
DWORD
SendReXmitPacket(PACB acbp,
PWORK_ITEM wip)
{
DWORD rc;
// set the wi rexmit fields
acbp->ReXmitCount--;
acbp->ReXmitSeqNo++;
*(wip->Packet + IPXH_HDRSIZE + WSEQUENCE_NUMBER) = acbp->ReXmitSeqNo;
rc = SendSubmit(wip);
if(rc == NO_ERROR) {
acbp->RefCount++;
}
acbp->TReqTimeStamp = GetTickCount();
return rc;
}
/*++
Function: GeneratePacket
Descr: allocate the work item,
constructs the response packet to the received packet (if any)
send the response as a rexmit packet or as a one time send packet
Returns: NO_ERROR
ERROR_IGNORE_PACKET - ignore the received packet
ERROR_DISCONNECT - disconnect the adapter because of fatal error
Remark: >> called with the adapter lock held <<
--*/
DWORD
GeneratePacket(PACB acbp,
PUCHAR ipxhdrp,
UCHAR PacketType)
{
DWORD rc;
ULONG WiType;
PWORK_ITEM wip;
if((wip = AllocateWorkItem(SEND_PACKET_TYPE)) == NULL) {
return ERROR_DISCONNECT;
}
switch(PacketType) {
case TIMER_REQUEST:
rc = MakeTimerRequestPacket(acbp, ipxhdrp, wip->Packet);
break;
case TIMER_RESPONSE:
rc = MakeTimerResponsePacket(acbp, ipxhdrp, wip->Packet);
break;
case INFORMATION_REQUEST:
rc = MakeInformationRequestPacket(acbp, ipxhdrp, wip->Packet);
break;
case INFORMATION_RESPONSE:
rc = MakeInformationResponsePacket(acbp, ipxhdrp, wip->Packet);
break;
default:
rc = ERROR_DISCONNECT;
break;
}
if(rc == NO_ERROR) {
// no error making the packet -> try to send it
wip->AdapterIndex = acbp->AdapterIndex;
wip->WiState = WI_INIT;
switch(PacketType) {
case TIMER_REQUEST:
case INFORMATION_REQUEST:
// re-xmit packet type
wip->ReXmitPacket = TRUE;
// create a reference to the adapter CB
wip->acbp = acbp;
acbp->ReXmitCount = MAX_REXMIT_COUNT;
acbp->ReXmitSeqNo = 0xFF;
if(SendReXmitPacket(acbp, wip) != NO_ERROR) {
rc = ERROR_DISCONNECT;
}
break;
case TIMER_RESPONSE:
case INFORMATION_RESPONSE:
default:
// one time send
wip->ReXmitPacket = FALSE;
if(SendSubmit(wip) != NO_ERROR) {
rc = ERROR_DISCONNECT;
}
break;
}
}
if(rc != NO_ERROR) {
// error making or trying to send the packet
if(rc != ERROR_GENERATE_NAK) {
FreeWorkItem(wip);
}
else
{
// if we were requested to generate a NAK packet instead, try to it it
MakeNakPacket(acbp, ipxhdrp, wip->Packet);
wip->ReXmitPacket = FALSE;
if(SendSubmit(wip) != NO_ERROR) {
FreeWorkItem(wip);
rc = ERROR_DISCONNECT;
}
else
{
rc = ERROR_IGNORE_PACKET;
}
}
}
return rc;
}
ULONG
GetRole(PUCHAR hdrp,
PACB acbp)
{
ULONG RemoteWNodeId;
ULONG LocalWNodeId;
PUCHAR ipxwanhdrp = hdrp + IPXH_HDRSIZE;
PUCHAR optp;
USHORT optlen;
BOOL IsRemoteExtendedNodeId = FALSE;
ULONG RemoteExtendedWNodeId;
ULONG LocalExtendedWNodeId;
ULONG i;
GETLONG2ULONG(&LocalWNodeId, acbp->WNodeId);
GETLONG2ULONG(&RemoteWNodeId, ipxwanhdrp + WNODE_ID);
if((LocalWNodeId == 0) && (RemoteWNodeId == 0)) {
// check if received timer request has the extended node id option
for(optp = ipxwanhdrp + IPXWAN_HDRSIZE, i=0;
i < *(ipxwanhdrp + WNUM_OPTIONS);
i++)
{
if(*(optp + WOPTION_NUMBER) == EXTENDED_NODE_ID_OPTION) {
IsRemoteExtendedNodeId = TRUE;
GETLONG2ULONG(&RemoteExtendedWNodeId, optp + WOPTION_DATA);
break;
}
GETSHORT2USHORT(&optlen, optp + WOPTION_DATA_LEN);
optp += OPTION_HDRSIZE + optlen;
}
if(acbp->IsExtendedNodeId && IsRemoteExtendedNodeId) {
GETLONG2ULONG(&LocalExtendedWNodeId, acbp->ExtendedWNodeId);
if(LocalExtendedWNodeId > RemoteExtendedWNodeId) {
return ACB_MASTER_ROLE;
}
else if(LocalExtendedWNodeId < RemoteExtendedWNodeId) {
return ACB_SLAVE_ROLE;
}
else
{
return ACB_UNKNOWN_ROLE;
}
}
else if(acbp->IsExtendedNodeId) {
return ACB_MASTER_ROLE;
}
else if(IsRemoteExtendedNodeId) {
return ACB_SLAVE_ROLE;
}
else
{
return ACB_UNKNOWN_ROLE;
}
}
else if(LocalWNodeId > RemoteWNodeId) {
return ACB_MASTER_ROLE;
}
else if(LocalWNodeId < RemoteWNodeId) {
return ACB_SLAVE_ROLE;
}
else
{
return ACB_UNKNOWN_ROLE;
}
}
/*++
Function: MakeTimerRequestPacket
Descr:
Arguments: acbp - ptr to adapter CB
hdrp - ptr to the new packet to be made
--*/
DWORD
MakeTimerRequestPacket(PACB acbp,
PUCHAR rcvhdrp,
PUCHAR hdrp)
{
PUCHAR ipxwanhdrp;
PUCHAR optp;
USHORT padlen = TIMER_REQUEST_PACKET_LENGTH;
// set IPX Header
memcpy(hdrp + IPXH_CHECKSUM, allffs, 2);
PUTUSHORT2SHORT(hdrp + IPXH_LENGTH, TIMER_REQUEST_PACKET_LENGTH);
*(hdrp + IPXH_XPORTCTL) = 0;
*(hdrp + IPXH_PKTTYPE) = IPX_PACKET_EXCHANGE_TYPE;
memcpy(hdrp + IPXH_DESTNET, allzeros, 4);
memcpy(hdrp + IPXH_DESTNODE, allffs, 6);
PUTUSHORT2SHORT(hdrp + IPXH_DESTSOCK, IPXWAN_SOCKET);
memcpy(hdrp + IPXH_SRCNET, allzeros, 4);
memcpy(hdrp + IPXH_SRCNODE, allzeros, 6);
PUTUSHORT2SHORT(hdrp + IPXH_DESTSOCK, IPXWAN_SOCKET);
// set IPXWAN Header
ipxwanhdrp = hdrp + IPXH_HDRSIZE;
memcpy(ipxwanhdrp + WIDENTIFIER, IPXWAN_CONFIDENCE_ID, 4);
*(ipxwanhdrp + WPACKET_TYPE) = TIMER_REQUEST;
memcpy(ipxwanhdrp + WNODE_ID, acbp->WNodeId, 4);
// the sequence number is written when the packet gets sent
*(ipxwanhdrp + WNUM_OPTIONS) = 0;
padlen -= (IPXH_HDRSIZE + IPXWAN_HDRSIZE);
// set OPTIONS
optp = ipxwanhdrp + IPXWAN_HDRSIZE;
if(IS_WORKSTATION(acbp->SupportedRoutingTypes)) {
(*(ipxwanhdrp + WNUM_OPTIONS))++;
*(optp + WOPTION_NUMBER) = ROUTING_TYPE_OPTION;
*(optp + WACCEPT_OPTION) = YES;
PUTUSHORT2SHORT(optp + WOPTION_DATA_LEN, ROUTING_TYPE_DATA_LEN);
*(optp + WOPTION_DATA) = WORKSTATION_ROUTING_TYPE;
optp += OPTION_HDRSIZE + ROUTING_TYPE_DATA_LEN;
padlen -= (OPTION_HDRSIZE + ROUTING_TYPE_DATA_LEN);
}
if(IS_NUMBERED_RIP(acbp->SupportedRoutingTypes)) {
(*(ipxwanhdrp + WNUM_OPTIONS))++;
*(optp + WOPTION_NUMBER) = ROUTING_TYPE_OPTION;
*(optp + WACCEPT_OPTION) = YES;
PUTUSHORT2SHORT(optp + WOPTION_DATA_LEN, ROUTING_TYPE_DATA_LEN);
*(optp + WOPTION_DATA) = NUMBERED_RIP_ROUTING_TYPE;
optp += OPTION_HDRSIZE + ROUTING_TYPE_DATA_LEN;
padlen -= (OPTION_HDRSIZE + ROUTING_TYPE_DATA_LEN);
}
if(IS_UNNUMBERED_RIP(acbp->SupportedRoutingTypes)) {
(*(ipxwanhdrp + WNUM_OPTIONS))++;
*(optp + WOPTION_NUMBER) = ROUTING_TYPE_OPTION;
*(optp + WACCEPT_OPTION) = YES;
PUTUSHORT2SHORT(optp + WOPTION_DATA_LEN, ROUTING_TYPE_DATA_LEN);
*(optp + WOPTION_DATA) = UNNUMBERED_RIP_ROUTING_TYPE;
optp += OPTION_HDRSIZE + ROUTING_TYPE_DATA_LEN;
padlen -= (OPTION_HDRSIZE + ROUTING_TYPE_DATA_LEN);
}
if(acbp->IsExtendedNodeId) {
(*(ipxwanhdrp + WNUM_OPTIONS))++;
*(optp + WOPTION_NUMBER) = EXTENDED_NODE_ID_OPTION;
*(optp + WACCEPT_OPTION) = YES;
PUTUSHORT2SHORT(optp + WOPTION_DATA_LEN, EXTENDED_NODE_ID_DATA_LEN);
memcpy(optp + WOPTION_DATA, acbp->ExtendedWNodeId, EXTENDED_NODE_ID_DATA_LEN);
optp += OPTION_HDRSIZE + EXTENDED_NODE_ID_DATA_LEN;
padlen -= (OPTION_HDRSIZE + EXTENDED_NODE_ID_DATA_LEN);
}
// PAD
padlen -= OPTION_HDRSIZE;
(*(ipxwanhdrp + WNUM_OPTIONS))++;
*(optp + WOPTION_NUMBER) = PAD_OPTION;
*(optp + WACCEPT_OPTION) = YES;
PUTUSHORT2SHORT(optp + WOPTION_DATA_LEN, padlen);
fillpadding(optp + WOPTION_DATA, padlen);
return NO_ERROR;
}
/*++
Function: MakeTimerResponsePacket
Descr:
Arguments: acbp - ptr to adapter CB
rcvhdrp - ptr to the received TIMER_REQUEST packet
hdrp - ptr to the new packet to be made
--*/
DWORD
MakeTimerResponsePacket(PACB acbp,
PUCHAR rcvhdrp,
PUCHAR hdrp)
{
USHORT rcvlen;
USHORT optlen;
PUCHAR ipxwanhdrp;
PUCHAR optp;
ULONG RemoteWNodeId;
ULONG i;
Trace(IPXWAN_TRACE, "MakeTimerResponsePacket: Entered adapter # %d", acbp->AdapterIndex);
// check received packet length
GETSHORT2USHORT(&rcvlen, rcvhdrp + IPXH_LENGTH);
if(rcvlen < TIMER_REQUEST_PACKET_LENGTH) {
return ERROR_IGNORE_PACKET;
}
memcpy(hdrp, rcvhdrp, rcvlen);
// set IPX Header
memcpy(hdrp + IPXH_CHECKSUM, allffs, 2);
PUTUSHORT2SHORT(hdrp + IPXH_LENGTH, TIMER_REQUEST_PACKET_LENGTH);
*(hdrp + IPXH_XPORTCTL) = 0;
*(hdrp + IPXH_PKTTYPE) = IPX_PACKET_EXCHANGE_TYPE;
memcpy(hdrp + IPXH_DESTNET, allzeros, 4);
memcpy(hdrp + IPXH_DESTNODE, allffs, 6);
PUTUSHORT2SHORT(hdrp + IPXH_DESTSOCK, IPXWAN_SOCKET);
memcpy(hdrp + IPXH_SRCNET, allzeros, 4);
memcpy(hdrp + IPXH_SRCNODE, allzeros, 6);
PUTUSHORT2SHORT(hdrp + IPXH_DESTSOCK, IPXWAN_SOCKET);
// set IPXWAN Header
ipxwanhdrp = hdrp + IPXH_HDRSIZE;
*(ipxwanhdrp + WPACKET_TYPE) = TIMER_RESPONSE;
GETLONG2ULONG(&RemoteWNodeId, ipxwanhdrp + WNODE_ID);
memcpy(ipxwanhdrp + WNODE_ID, acbp->InternalNetNumber, 4);
// parse each option in the received timer request packet
for(optp = ipxwanhdrp + IPXWAN_HDRSIZE, i=0;
i < *(ipxwanhdrp + WNUM_OPTIONS);
i++, optp += OPTION_HDRSIZE + optlen)
{
GETSHORT2USHORT(&optlen, optp + WOPTION_DATA_LEN);
switch(*(optp + WOPTION_NUMBER)) {
case ROUTING_TYPE_OPTION:
if(optlen != ROUTING_TYPE_DATA_LEN) {
return ERROR_GENERATE_NAK;
}
if((*(optp + WOPTION_DATA) == WORKSTATION_ROUTING_TYPE) &&
(IS_WORKSTATION(acbp->SupportedRoutingTypes)) &&
(acbp->RoutingType == 0) &&
(*(optp + WACCEPT_OPTION) == YES)) {
SET_WORKSTATION(acbp->RoutingType);
Trace(IPXWAN_TRACE, "MakeTimerResponsePacket: adapter # %d, accept routing type: %s",
acbp->AdapterIndex,
Workstationp);
}
else if((*(optp + WOPTION_DATA) == UNNUMBERED_RIP_ROUTING_TYPE) &&
(IS_UNNUMBERED_RIP(acbp->SupportedRoutingTypes)) &&
(acbp->RoutingType == 0) &&
(*(optp + WACCEPT_OPTION) == YES)) {
SET_UNNUMBERED_RIP(acbp->RoutingType);
Trace(IPXWAN_TRACE, "MakeTimerResponsePacket: adapter # %d, accept routing type: %s",
acbp->AdapterIndex,
UnnumberedRip);
}
else if((*(optp + WOPTION_DATA) == NUMBERED_RIP_ROUTING_TYPE) &&
(acbp->RoutingType == 0) &&
(*(optp + WACCEPT_OPTION) == YES)) {
if(IS_NUMBERED_RIP(acbp->SupportedRoutingTypes)) {
SET_NUMBERED_RIP(acbp->RoutingType);
Trace(IPXWAN_TRACE, "MakeTimerResponsePacket: adapter # %d, accept routing type: %s",
acbp->AdapterIndex,
NumberedRip);
}
else if((IS_UNNUMBERED_RIP(acbp->SupportedRoutingTypes)) &&
RemoteWNodeId) {
// the local router cannot assign net numbers but it
// accepts the numbered rip type because the remote router
// claims it can assign a net number (because remote node id is not null).
SET_NUMBERED_RIP(acbp->RoutingType);
Trace(IPXWAN_TRACE, "MakeTimerResponsePacket: adapter # %d, accept routing type: %s",
acbp->AdapterIndex,
NumberedRip);
}
else
{
*(optp + WACCEPT_OPTION) = NO;
Trace(IPXWAN_TRACE, "MakeTimerResponsePacket: adapter # %d, decline routing type: %d",
acbp->AdapterIndex,
*(optp + WOPTION_NUMBER));
}
}
else
{
*(optp + WACCEPT_OPTION) = NO;
Trace(IPXWAN_TRACE, "MakeTimerResponsePacket: adapter # %d, decline routing type: %d",
acbp->AdapterIndex,
*(optp + WOPTION_DATA));
}
break;
case EXTENDED_NODE_ID_OPTION:
if(optlen != EXTENDED_NODE_ID_DATA_LEN) {
return ERROR_GENERATE_NAK;
}
*(optp + WACCEPT_OPTION) = YES;
Trace(IPXWAN_TRACE, "MakeTimerResponsePacket: adapter # %d, accept extended node id",
acbp->AdapterIndex);
break;
case PAD_OPTION:
*(optp + WACCEPT_OPTION) = YES;
Trace(IPXWAN_TRACE, "MakeTimerResponsePacket: adapter # %d, accept padding",
acbp->AdapterIndex);
break;
default:
*(optp + WACCEPT_OPTION) = NO;
Trace(IPXWAN_TRACE, "MakeTimerResponsePacket: adapter # %d, decline option number %d",
acbp->AdapterIndex,
*(optp + WOPTION_NUMBER));
break;
}
}
// check if we have agreed on a routing type
if(!acbp->RoutingType) {
Trace(IPXWAN_TRACE, "MakeTimerResponsePacket: adapter # %d, negotiation failed: no routing type accepted",
acbp->AdapterIndex);
return ERROR_DISCONNECT;
}
return NO_ERROR;
}
/*++
Function: MakeInformationRequestPacket
Descr:
Arguments: acbp - ptr to adapter CB
rcvhdrp - ptr to the received TIMER_RESPONSE packet
hdrp - ptr to the new packet to be made
--*/
DWORD
MakeInformationRequestPacket(PACB acbp,
PUCHAR rcvhdrp,
PUCHAR hdrp)
{
PUCHAR optp;
USHORT optlen;
PUCHAR rcvipxwanhdrp, ipxwanhdrp;
ULONG rt_options_count = 0;
USHORT pktlen = 0;
ULONG i;
ULONG ComputerNameLen;
CHAR ComputerName[49];
memset(ComputerName, 0, 49);
Trace(IPXWAN_TRACE, "MakeInformationRequestPacket: Entered for adpt# %d", acbp->AdapterIndex);
rcvipxwanhdrp = rcvhdrp + IPXH_HDRSIZE;
// establish the routing type
for(optp = rcvipxwanhdrp + IPXWAN_HDRSIZE, i=0;
i < *(rcvipxwanhdrp + WNUM_OPTIONS);
i++, optp += OPTION_HDRSIZE + optlen)
{
GETSHORT2USHORT(&optlen, optp + WOPTION_DATA_LEN);
if(*(optp + WOPTION_NUMBER) == ROUTING_TYPE_OPTION) {
rt_options_count++;
if(optlen != ROUTING_TYPE_DATA_LEN) {
Trace(IPXWAN_TRACE, "MakeInformationRequestPacket: Invalid ROUTING TYPE data len, make NAK for adpt# %d", acbp->AdapterIndex);
return ERROR_GENERATE_NAK;
}
if((*(optp + WOPTION_DATA) == WORKSTATION_ROUTING_TYPE) &&
(IS_WORKSTATION(acbp->SupportedRoutingTypes)) &&
(acbp->RoutingType == 0) &&
(*(optp + WACCEPT_OPTION) == YES)) {
SET_WORKSTATION(acbp->RoutingType);
Trace(IPXWAN_TRACE, "MakeInformationRequestPacket: adpt# %d, accept routing type: %s",
acbp->AdapterIndex,
Workstationp);
}
else if((*(optp + WOPTION_DATA) == UNNUMBERED_RIP_ROUTING_TYPE) &&
(IS_UNNUMBERED_RIP(acbp->SupportedRoutingTypes)) &&
(acbp->RoutingType == 0) &&
(*(optp + WACCEPT_OPTION) == YES)) {
SET_UNNUMBERED_RIP(acbp->RoutingType);
Trace(IPXWAN_TRACE, "MakeInformationRequestPacket: adpt# %d, accept routing type: %s",
acbp->AdapterIndex,
UnnumberedRip);
}
else if((*(optp + WOPTION_DATA) == NUMBERED_RIP_ROUTING_TYPE) &&
(acbp->RoutingType == 0) &&
(IS_NUMBERED_RIP(acbp->SupportedRoutingTypes)) &&
(*(optp + WACCEPT_OPTION) == YES)) {
SET_NUMBERED_RIP(acbp->RoutingType);
Trace(IPXWAN_TRACE, "MakeInformationRequestPacket: adpt# %d, accept routing type: %s",
acbp->AdapterIndex,
NumberedRip);
}
}
}
// there should be one and only one routing type option in the timer response
if(rt_options_count != 1) {
Trace(IPXWAN_TRACE, "MakeInformationRequestPacket: adpt# %d negotiation failed, no/too many routing options",
acbp->AdapterIndex);
return ERROR_DISCONNECT;
}
//
//*** MASTER: Set the common network number and the local node number ***
//
if(IS_UNNUMBERED_RIP(acbp->RoutingType)) {
memset(acbp->Network, 0, 4);
}
else
{
// call ipxcp to get a net number
if(IpxcpGetWanNetNumber(acbp->Network,
&acbp->AllocatedNetworkIndex,
acbp->InterfaceType) != NO_ERROR) {
Trace(IPXWAN_TRACE, "MakeInformationRequestPacket: adpt# %d negotiation failed, cannot allocate net number",
acbp->AdapterIndex);
return ERROR_DISCONNECT;
}
}
memset(acbp->LocalNode, 0, 6);
memcpy(acbp->LocalNode, acbp->InternalNetNumber, 4);
// set IPX Header
pktlen = IPXH_HDRSIZE + IPXWAN_HDRSIZE + OPTION_HDRSIZE + RIP_SAP_INFO_EXCHANGE_DATA_LEN;
memcpy(hdrp + IPXH_CHECKSUM, allffs, 2);
*(hdrp + IPXH_XPORTCTL) = 0;
*(hdrp + IPXH_PKTTYPE) = IPX_PACKET_EXCHANGE_TYPE;
memcpy(hdrp + IPXH_DESTNET, allzeros, 4);
memcpy(hdrp + IPXH_DESTNODE, allffs, 6);
PUTUSHORT2SHORT(hdrp + IPXH_DESTSOCK, IPXWAN_SOCKET);
memcpy(hdrp + IPXH_SRCNET, allzeros, 4);
memcpy(hdrp + IPXH_SRCNODE, allzeros, 6);
PUTUSHORT2SHORT(hdrp + IPXH_DESTSOCK, IPXWAN_SOCKET);
// set IPXWAN Header
ipxwanhdrp = hdrp + IPXH_HDRSIZE;
memcpy(ipxwanhdrp + WIDENTIFIER, IPXWAN_CONFIDENCE_ID, 4);
*(ipxwanhdrp + WPACKET_TYPE) = INFORMATION_REQUEST;
memcpy(ipxwanhdrp + WNODE_ID, acbp->InternalNetNumber, 4);
// the sequence number is written when the packet gets sent
*(ipxwanhdrp + WNUM_OPTIONS) = 1;
// set OPTIONS
optp = ipxwanhdrp + IPXWAN_HDRSIZE;
*(optp + WOPTION_NUMBER) = RIP_SAP_INFO_EXCHANGE_OPTION;
*(optp + WACCEPT_OPTION) = YES;
PUTUSHORT2SHORT(optp + WOPTION_DATA_LEN, RIP_SAP_INFO_EXCHANGE_DATA_LEN);
PUTUSHORT2SHORT(optp + WAN_LINK_DELAY, acbp->LinkDelay);
memcpy(optp + COMMON_NETWORK_NUMBER, acbp->Network, 4);
memset(optp + ROUTER_NAME, 0, 48);
ComputerNameLen = 48;
if(!GetComputerName(optp + ROUTER_NAME,
&ComputerNameLen)) {
// failed to get machine name
return ERROR_DISCONNECT;
}
memcpy(ComputerName, optp + ROUTER_NAME, ComputerNameLen);
Trace(IPXWAN_TRACE, "MakeInformationRequestPacket: adpt# %d, Delay %d\nCommon Net %.2x%.2x%.2x%.2x\nRouterName: %s\n",
acbp->AdapterIndex,
acbp->LinkDelay,
acbp->Network[0],
acbp->Network[1],
acbp->Network[2],
acbp->Network[3],
ComputerName);
//
//*** MASTER: Set the remote node number ***
//
if(acbp->InterfaceType == IF_TYPE_WAN_WORKSTATION) {
// if the remote machine is a connecting wksta we should provide it with a node
// number
pktlen += OPTION_HDRSIZE + NODE_NUMBER_DATA_LEN;
(*(ipxwanhdrp + WNUM_OPTIONS))++;
optp += OPTION_HDRSIZE + RIP_SAP_INFO_EXCHANGE_DATA_LEN;
*(optp + WOPTION_NUMBER) = NODE_NUMBER_OPTION;
*(optp + WACCEPT_OPTION) = YES;
PUTUSHORT2SHORT(optp + WOPTION_DATA_LEN, NODE_NUMBER_DATA_LEN);
if(IpxcpGetRemoteNode(acbp->ConnectionId, optp + WOPTION_DATA) != NO_ERROR) {
return ERROR_DISCONNECT;
}
memcpy(acbp->RemoteNode, optp + WOPTION_DATA, 6);
Trace(IPXWAN_TRACE, "MakeInformationRequestPacket: adpt# %d add NIC Address Option: %.2x%.2x%.2x%.2x%.2x%.2x\n",
acbp->RemoteNode[0],
acbp->RemoteNode[1],
acbp->RemoteNode[2],
acbp->RemoteNode[3],
acbp->RemoteNode[4],
acbp->RemoteNode[5]);
}
else
{
// remote machine is a router -> its node number is derived from its internal net
memset(acbp->RemoteNode, 0, 6);
memcpy(acbp->RemoteNode, rcvipxwanhdrp + WNODE_ID, 4);
}
PUTUSHORT2SHORT(hdrp + IPXH_LENGTH, pktlen);
return NO_ERROR;
}
/*++
Function: MakeInformationResponsePacket
Descr:
Arguments: acbp - ptr to adapter CB
rcvhdrp - ptr to the received INFORMATION_REQUEST packet
hdrp - ptr to the new packet to be made
--*/
DWORD
MakeInformationResponsePacket(PACB acbp,
PUCHAR rcvhdrp,
PUCHAR hdrp)
{
USHORT rcvlen;
USHORT optlen;
PUCHAR ipxwanhdrp;
PUCHAR optp;
UCHAR RcvWNodeId[4];
ULONG RipSapExchangeOptionCount = 0;
ULONG NodeNumberOptionCount = 0;
UCHAR LocalNode[6];
ULONG i;
ULONG ComputerNameLen=48;
Trace(IPXWAN_TRACE, "MakeInformationResponsePacket: Entered adpt# %d", acbp->AdapterIndex);
memset(LocalNode, 0, 6);
// get received packet length
GETSHORT2USHORT(&rcvlen, rcvhdrp + IPXH_LENGTH);
if(rcvlen < IPXH_HDRSIZE + IPXWAN_HDRSIZE + OPTION_HDRSIZE + RIP_SAP_INFO_EXCHANGE_DATA_LEN) {
// malformed packet
return ERROR_IGNORE_PACKET;
}
memcpy(hdrp, rcvhdrp, rcvlen);
// set IPX Header
memcpy(hdrp + IPXH_CHECKSUM, allffs, 2);
*(hdrp + IPXH_XPORTCTL) = 0;
*(hdrp + IPXH_PKTTYPE) = IPX_PACKET_EXCHANGE_TYPE;
memcpy(hdrp + IPXH_DESTNET, allzeros, 4);
memcpy(hdrp + IPXH_DESTNODE, allffs, 6);
PUTUSHORT2SHORT(hdrp + IPXH_DESTSOCK, IPXWAN_SOCKET);
memcpy(hdrp + IPXH_SRCNET, allzeros, 4);
memcpy(hdrp + IPXH_SRCNODE, allzeros, 6);
PUTUSHORT2SHORT(hdrp + IPXH_DESTSOCK, IPXWAN_SOCKET);
// set IPXWAN Header
ipxwanhdrp = hdrp + IPXH_HDRSIZE;
*(ipxwanhdrp + WPACKET_TYPE) = INFORMATION_RESPONSE;
memcpy(RcvWNodeId, ipxwanhdrp + WNODE_ID, 4);
memcpy(ipxwanhdrp + WNODE_ID, acbp->InternalNetNumber, 4);
// parse each option in the received information request packet
for(optp = ipxwanhdrp + IPXWAN_HDRSIZE, i=0;
i < *(ipxwanhdrp + WNUM_OPTIONS);
i++, optp += OPTION_HDRSIZE + optlen)
{
GETSHORT2USHORT(&optlen, optp + WOPTION_DATA_LEN);
switch(*(optp + WOPTION_NUMBER)) {
case RIP_SAP_INFO_EXCHANGE_OPTION:
if(RipSapExchangeOptionCount++) {
// more then one rip/sap exchange option
Trace(IPXWAN_TRACE, "MakeInformationResponsePacket: adpt# %d, ERROR: more then 1 RIP_SAP_EXCHANGE_OPTION in rcvd INFORAMTION_REQUEST\n",
acbp->AdapterIndex);
return ERROR_DISCONNECT;
}
if(optlen != RIP_SAP_INFO_EXCHANGE_DATA_LEN) {
Trace(IPXWAN_TRACE, "MakeInformationResponsePacket: adpt# %d, ERROR: bad length RIP_SAP_EXCHANGE_OPTION in rcvd INFORAMTION_REQUEST\n",
acbp->AdapterIndex);
return ERROR_GENERATE_NAK;
}
if(*(optp + WACCEPT_OPTION) != YES) {
Trace(IPXWAN_TRACE, "MakeInformationResponsePacket: adpt# %d, ERROR: ACCEPT==NO RIP_SAP_EXCHANGE_OPTION in rcvd INFORAMTION_REQUEST\n",
acbp->AdapterIndex);
return ERROR_DISCONNECT;
}
GETSHORT2USHORT(&acbp->LinkDelay, optp + WAN_LINK_DELAY);
// validate routing type and common net number
if((IS_NUMBERED_RIP(acbp->RoutingType)) &&
!memcmp(optp + COMMON_NETWORK_NUMBER, allzeros, 4)) {
// negotiation error
Trace(IPXWAN_TRACE, "MakeInformationResponsePacket: adpt# %d, ERROR: NUMBERED RIP Routing but Network==0 in rcvd INFORAMTION_REQUEST\n",
acbp->AdapterIndex);
return ERROR_DISCONNECT;
}
if((IS_UNNUMBERED_RIP(acbp->RoutingType)) &&
memcmp(optp + COMMON_NETWORK_NUMBER, allzeros, 4)) {
// negotiation error
Trace(IPXWAN_TRACE, "MakeInformationResponsePacket: adpt# %d, ERROR: ON DEMAND Routing but Network!=0 in rcvd INFORAMTION_REQUEST\n",
acbp->AdapterIndex);
return ERROR_DISCONNECT;
}
// check we were handed a unique net number
if(memcmp(optp + COMMON_NETWORK_NUMBER, allzeros, 4)) {
switch(acbp->InterfaceType) {
case IF_TYPE_WAN_ROUTER:
case IF_TYPE_PERSONAL_WAN_ROUTER:
case IF_TYPE_ROUTER_WORKSTATION_DIALOUT:
if(IpxcpIsRoute(optp + COMMON_NETWORK_NUMBER)) {
Trace(IPXWAN_TRACE, "MakeInformationResponsePacket: adpt# %d, ERROR: Network not unique in rcvd INFORAMTION_REQUEST\n",
acbp->AdapterIndex);
return ERROR_DISCONNECT;
}
break;
default:
break;
}
}
//
//*** SLAVE: Set the common net number and the remote node ***
//
memcpy(acbp->Network, optp + COMMON_NETWORK_NUMBER, 4);
Trace(IPXWAN_TRACE, "MakeInformationResponsePacket: adpt# %d, Recvd Common Network Number %.2x%.2x%.2x%.2x\n",
acbp->AdapterIndex,
acbp->Network[0],
acbp->Network[1],
acbp->Network[2],
acbp->Network[3]);
// make the remote node number from its remote WNODE ID field
memset(acbp->RemoteNode, 0, 6);
memcpy(acbp->RemoteNode, RcvWNodeId, 4);
// give our router name
memset(optp + ROUTER_NAME, 0, 48);
if(!GetComputerName(optp + ROUTER_NAME, &ComputerNameLen)) {
// failed to get machine name
return ERROR_DISCONNECT;
}
break;
case NODE_NUMBER_OPTION:
if(NodeNumberOptionCount++) {
Trace(IPXWAN_TRACE, "MakeInformationResponsePacket: adpt# %d, ERROR: more than 1 NODE_NUMBER_OPTION in rcvd INFORMATION_REQUEST\n",
acbp->AdapterIndex);
return ERROR_DISCONNECT;
}
if(optlen != NODE_NUMBER_DATA_LEN) {
Trace(IPXWAN_TRACE, "MakeInformationResponsePacket: adpt# %d, ERROR: bad length for NODE_NUMBER_OPTION in rcvd INFORMATION_REQUEST\n",
acbp->AdapterIndex);
return ERROR_GENERATE_NAK;
}
if(*(optp + WACCEPT_OPTION) != YES) {
Trace(IPXWAN_TRACE, "MakeInformationResponsePacket: adpt# %d, ERROR: ACCEPT==NO for NODE_NUMBER_OPTION in rcvd INFORMATION_REQUEST\n",
acbp->AdapterIndex);
return ERROR_DISCONNECT;
}
memcpy(LocalNode, optp + WOPTION_DATA, 6);
break;
default:
*(optp + WACCEPT_OPTION) = NO;
break;
}
}
//
//*** SLAVE: Set local node ***
//
if(NodeNumberOptionCount) {
memcpy(acbp->LocalNode, LocalNode, 6);
}
else
{
// make the local node from our internal net
memset(acbp->LocalNode, 0, 6);
memcpy(acbp->LocalNode, acbp->InternalNetNumber, 4);
}
return NO_ERROR;
}
/*++
Function: MakeNakPacket
Descr:
Arguments: acbp - ptr to adapter CB
rcvhdrp - ptr to the received UNKNOWN packet
hdrp - ptr to the new packet to be made
--*/
DWORD
MakeNakPacket(PACB acbp,
PUCHAR rcvhdrp,
PUCHAR hdrp)
{
USHORT rcvlen;
PUCHAR ipxwanhdrp;
// get received packet length
GETSHORT2USHORT(&rcvlen, rcvhdrp + IPXH_LENGTH);
memcpy(hdrp, rcvhdrp, rcvlen);
// set IPXWAN Header
ipxwanhdrp = hdrp + IPXH_HDRSIZE;
*(ipxwanhdrp + WPACKET_TYPE) = NAK;
return NO_ERROR;
}
/*++
Function: ProcessInformationResponsePacket
Descr:
Arguments: acbp - ptr to adapter CB
rcvhdrp - ptr to the received INFORMATION_RESPONSE packet
--*/
DWORD
ProcessInformationResponsePacket(PACB acbp,
PUCHAR rcvhdrp)
{
USHORT rcvlen;
USHORT optlen;
PUCHAR ipxwanhdrp;
PUCHAR optp;
ULONG RipSapExchangeOptionCount = 0;
ULONG i;
Trace(IPXWAN_TRACE, "ProcessInformationResponsePacket: Entered adpt# %d", acbp->AdapterIndex);
// get received packet length
GETSHORT2USHORT(&rcvlen, rcvhdrp + IPXH_LENGTH);
if(rcvlen < IPXH_HDRSIZE + IPXWAN_HDRSIZE + OPTION_HDRSIZE + RIP_SAP_INFO_EXCHANGE_DATA_LEN) {
// malformed packet
return ERROR_IGNORE_PACKET;
}
ipxwanhdrp =rcvhdrp + IPXH_HDRSIZE;
// parse each option in the received information response packet
for(optp = ipxwanhdrp + IPXWAN_HDRSIZE, i=0;
i < *(ipxwanhdrp + WNUM_OPTIONS);
i++, optp += OPTION_HDRSIZE + optlen)
{
GETSHORT2USHORT(&optlen, optp + WOPTION_DATA_LEN);
switch(*(optp + WOPTION_NUMBER)) {
case RIP_SAP_INFO_EXCHANGE_OPTION:
if(RipSapExchangeOptionCount++) {
// more then one rip/sap exchange option
Trace(IPXWAN_TRACE, "ProcessInformationResponsePacket: adpt# %d, ERROR: more then 1 RIP_SAP_INFO_EXCHANGE_OPTION in rcvd INFORMATION_RESPONSE\n",
acbp->AdapterIndex);
return ERROR_DISCONNECT;
}
if(optlen != RIP_SAP_INFO_EXCHANGE_DATA_LEN) {
Trace(IPXWAN_TRACE, "ProcessInformationResponsePacket: adpt# %d, ERROR: bad length RIP_SAP_EXCHANGE_OPTION in rcvd INFORMATION_RESPONSE\n",
acbp->AdapterIndex);
return ERROR_GENERATE_NAK;
}
if(*(optp + WACCEPT_OPTION) != YES) {
Trace(IPXWAN_TRACE, "ProcessInformationResponsePacket: adpt# %d, ERROR: ACCEPT==NO RIP_SAP_EXCHANGE_OPTION in rcvd INFORMATION_RESPONSE\n",
acbp->AdapterIndex);
return ERROR_DISCONNECT;
}
if(memcmp(optp + COMMON_NETWORK_NUMBER, acbp->Network, 4)) {
// we don't agree on the common net number
Trace(IPXWAN_TRACE, "ProcessInformationResponsePacket: adpt# %d, ERROR: Different common net returned\n",
acbp->AdapterIndex);
return ERROR_DISCONNECT;
}
break;
case NODE_NUMBER_OPTION:
if(optlen != NODE_NUMBER_DATA_LEN) {
Trace(IPXWAN_TRACE, "ProcessInformationResponsePacket: adpt# %d, ERROR: bad length NODE_NUMBER_OPTION in rcvd INFORMATION_REQUEST\n",
acbp->AdapterIndex);
return ERROR_GENERATE_NAK;
}
if(*(optp + WACCEPT_OPTION) != YES) {
Trace(IPXWAN_TRACE, "ProcessInformationResponsePacket: adpt# %d, ERROR: ACCEPT==NO NODE_NUMBER_OPTION in rcvd INFORMATION_RESPONSE\n",
acbp->AdapterIndex);
return ERROR_DISCONNECT;
}
// check that it coincides with the number we assigned
if(memcmp(optp + WOPTION_DATA, acbp->RemoteNode, 6)) {
Trace(IPXWAN_TRACE, "ProcessInformationResponsePacket: adpt# %d, ERROR: Different remote node number returned\n",
acbp->AdapterIndex);
return ERROR_DISCONNECT;
}
break;
default:
Trace(IPXWAN_TRACE, "ProcessInformationResponsePacket: adpt# %d, ERROR: Unrequested option in rcvd INFORMATION_RESPONSE\n",
acbp->AdapterIndex);
return ERROR_DISCONNECT;
break;
}
}
if(!RipSapExchangeOptionCount) {
Trace(IPXWAN_TRACE, "ProcessInformationResponsePacket: adpt# %d, ERROR: RIP_SAP_EXCHANGE_OPTION missing from rcvd INFORMATION_RESPONSE\n",
acbp->AdapterIndex);
return ERROR_DISCONNECT;
}
return NO_ERROR;
}
VOID
fillpadding(PUCHAR padp,
ULONG len)
{
ULONG i;
for(i=0; i<len; i++)
{
*(padp + i) = (UCHAR)i;
}
}
/*++
Function: StartSlaveTimer
Descr: A timer is started when the slave gets its role (i.e. slave) and sends
a timer response. This insures the slave won't wait forever to receive
an information request.
Remark: >> called with the adapter lock held <<
--*/
DWORD
StartSlaveTimer(PACB acbp)
{
PWORK_ITEM wip;
if((wip = AllocateWorkItem(WITIMER_TYPE)) == NULL) {
return ERROR_DISCONNECT;
}
wip->acbp = acbp;
StartWiTimer(wip, SLAVE_TIMEOUT);
acbp->RefCount++;
return NO_ERROR;
}