You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1915 lines
47 KiB
1915 lines
47 KiB
/*++
|
|
|
|
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;
|
|
}
|