/*++ 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> 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; }