/*++ Copyright (c) 1996 Microsoft Corporation Module Name: ppp.c Abstract: This module implements routines that are used for PPP functionality Author: Shirish Koti Revision History: 11 Mar 1998 Initial Version --*/ #define ARAP_LOCALS #include #pragma hdrstop #define FILENUM PPP #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE_PPP, AllocPPPConn) #pragma alloc_text(PAGE_PPP, PPPProcessIoctl) #pragma alloc_text(PAGE_PPP, PPPRoutePacketToWan) #pragma alloc_text(PAGE_PPP, PPPTransmit) #pragma alloc_text(PAGE_PPP, PPPTransmitCompletion) #pragma alloc_text(PAGE_PPP, DerefPPPConn) #pragma alloc_text(PAGE_PPP, PPPGetDynamicAddr) #endif //*** // // Function: AllocPPPConn // Allocate a connection element and initialize fields // // Parameters: none // // Return: pointer to a newly allocated connection element // //***$ PATCPCONN AllocPPPConn( IN VOID ) { PATCPCONN pAtcpConn; KIRQL OldIrql; DBG_PPP_CHECK_PAGED_CODE(); if ( (pAtcpConn = AtalkAllocZeroedMemory(sizeof(ATCPCONN))) == NULL) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("AllocPPPConn: alloc failed\n")); return(NULL); } #if DBG pAtcpConn->Signature = ATCPCONN_SIGNATURE; #endif // RAS refcount pAtcpConn->RefCount = 1; pAtcpConn->Flags |= ATCP_DLL_SETUP_DONE; INITIALIZE_SPIN_LOCK(&pAtcpConn->SpinLock); KeInitializeEvent(&pAtcpConn->NodeAcquireEvent, NotificationEvent, FALSE); // and insert it in the list ACQUIRE_SPIN_LOCK(&RasPortDesc->pd_Lock, &OldIrql); InsertTailList(&RasPortDesc->pd_PPPConnHead, &pAtcpConn->Linkage); RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock, OldIrql); ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql); PPPConnections++; RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql); return( pAtcpConn ); } //*** // // Function: PPPProcessIoctl // This routine gets called in to process ioclts coming from ATCP // For SETUP, we allocate a connection context, get an address for // the client, get the zone and router info. // For CLOSE, we mark and dereference our connection context // // Parameters: pIrp - irp from ATCP // pSndRcvInfo - buffer from ATCP that contains all the info // IoControlCode - what does ATCP want to do // // Return: none // //***$ NTSTATUS FASTCALL PPPProcessIoctl( IN PIRP pIrp, IN OUT PARAP_SEND_RECV_INFO pSndRcvInfo, IN ULONG IoControlCode, IN PATCPCONN pIncomingAtcpConn ) { KIRQL OldIrql; PATCPINFO pAtcpInfo; PATCPCONN pAtcpConn; DWORD dwRetCode=ARAPERR_NO_ERROR; PATCP_SUPPRESS_INFO pSupprInfo; ATALK_NODEADDR ClientNode; DWORD DataLen=0; DWORD ErrCode; BOOLEAN fDerefPort=FALSE; NTSTATUS ReturnStatus=STATUS_SUCCESS; DBG_PPP_CHECK_PAGED_CODE(); pAtcpConn = pIncomingAtcpConn; switch (IoControlCode) { case IOCTL_ATCP_SETUP_CONNECTION: ErrCode = ATALK_PORT_INVALID; // put a IrpProcess refcount, so AtalkDefaultPort doesn't go away in PnP if (!AtalkReferenceDefaultPort()) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("PPPProcessIoctl: Default port gone, or going %lx not accepted (%lx)\n", pIrp,IoControlCode)); dwRetCode = ARAPERR_STACK_IS_NOT_ACTIVE; break; } fDerefPort = TRUE; // allocate connection context pAtcpConn = AllocPPPConn(); if (!pAtcpConn) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("PPPProcessIoctl: alloc failed\n")); pSndRcvInfo->StatusCode = ARAPERR_OUT_OF_RESOURCES; break; } pAtcpConn->pDllContext = pSndRcvInfo->pDllContext; dwRetCode = PPPGetDynamicAddr(pAtcpConn); if (dwRetCode != ARAPERR_NO_ERROR) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("PPPProcessIoctl: couldn't get network addr %ld (%lx)\n", dwRetCode,pAtcpConn)); dwRetCode = ARAPERR_NO_NETWORK_ADDR; // remove the creation refcount DerefPPPConn(pAtcpConn); break; } pAtcpInfo = (PATCPINFO)&pSndRcvInfo->Data[0]; ACQUIRE_SPIN_LOCK(&AtalkPortLock, &OldIrql); ACQUIRE_SPIN_LOCK_DPC(&AtalkDefaultPort->pd_Lock); if ((AtalkDefaultPort->pd_Flags & PD_PNP_RECONFIGURE) || (AtalkDefaultPort->pd_Flags & PD_CLOSING)) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("PPPProcessIoctl: PnP is ine progress\n")); dwRetCode = ARAPERR_STACK_IS_NOT_ACTIVE; RELEASE_SPIN_LOCK_DPC(&AtalkDefaultPort->pd_Lock); RELEASE_SPIN_LOCK(&AtalkPortLock, OldIrql); // remove the creation refcount DerefPPPConn(pAtcpConn); break; } // we will be returning server's address and router's address DataLen += (2*sizeof(NET_ADDR)); // copy server's net address pAtcpInfo->ServerAddr.ata_Network = AtalkDefaultPort->pd_Nodes->an_NodeAddr.atn_Network; pAtcpInfo->ServerAddr.ata_Node = AtalkDefaultPort->pd_Nodes->an_NodeAddr.atn_Node; // if we are a router, copy our own address if (AtalkDefaultPort->pd_Flags & PD_ROUTER_RUNNING) { pAtcpInfo->DefaultRouterAddr.ata_Network = AtalkDefaultPort->pd_RouterNode->an_NodeAddr.atn_Network; pAtcpInfo->DefaultRouterAddr.ata_Network = AtalkDefaultPort->pd_RouterNode->an_NodeAddr.atn_Node; } // if we know who the router on the net is, copy his address else if (AtalkDefaultPort->pd_Flags & PD_SEEN_ROUTER_RECENTLY) { pAtcpInfo->DefaultRouterAddr.ata_Network = AtalkDefaultPort->pd_ARouter.atn_Network; pAtcpInfo->DefaultRouterAddr.ata_Node = AtalkDefaultPort->pd_ARouter.atn_Node; } // hmmm: no router! else { pAtcpInfo->DefaultRouterAddr.ata_Network = 0; pAtcpInfo->DefaultRouterAddr.ata_Node = 0; } // // copy the name of the zone on which this server lives // if (AtalkDesiredZone) { pAtcpInfo->ServerZoneName[0] = AtalkDesiredZone->zn_ZoneLen; RtlCopyMemory( &pAtcpInfo->ServerZoneName[1], &AtalkDesiredZone->zn_Zone[0], AtalkDesiredZone->zn_ZoneLen ); } else if (AtalkDefaultPort->pd_DefaultZone) { pAtcpInfo->ServerZoneName[0] = AtalkDefaultPort->pd_DefaultZone->zn_ZoneLen; RtlCopyMemory( &pAtcpInfo->ServerZoneName[1], &AtalkDefaultPort->pd_DefaultZone->zn_Zone[0], AtalkDefaultPort->pd_DefaultZone->zn_ZoneLen ); } else { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("PPPProcessIoctl: Server not in any zone!!\n")); pAtcpInfo->ServerZoneName[0] = 0; } RELEASE_SPIN_LOCK_DPC(&AtalkDefaultPort->pd_Lock); RELEASE_SPIN_LOCK(&AtalkPortLock, OldIrql); DataLen += pAtcpInfo->ServerZoneName[0]; // return our context and the network addr to the dll pSndRcvInfo->AtalkContext = pAtcpConn; pSndRcvInfo->ClientAddr.ata_Network = pAtcpConn->NetAddr.atn_Network; pSndRcvInfo->ClientAddr.ata_Node = pAtcpConn->NetAddr.atn_Node; DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("PPPProcessIoctl: PPP conn %lx created, addr = %x.%x\n", pAtcpConn,pSndRcvInfo->ClientAddr.ata_Network,pSndRcvInfo->ClientAddr.ata_Node)); break; case IOCTL_ATCP_SUPPRESS_BCAST: pSupprInfo = (PATCP_SUPPRESS_INFO)&pSndRcvInfo->Data[0]; // // see what flags need to be set: suppress only RTMP only or all bcast // ACQUIRE_SPIN_LOCK(&pAtcpConn->SpinLock, &OldIrql); if (pSupprInfo->SuppressRtmp) { pAtcpConn->Flags |= ATCP_SUPPRESS_RTMP; } if (pSupprInfo->SuppressAllBcast) { pAtcpConn->Flags |= ATCP_SUPPRESS_ALLBCAST; } RELEASE_SPIN_LOCK(&pAtcpConn->SpinLock, OldIrql); break; case IOCTL_ATCP_CLOSE_CONNECTION: DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("PPPProcessIoctl: close connection received on %lx (refcount %d)\n", pAtcpConn,pAtcpConn->RefCount)); ACQUIRE_SPIN_LOCK(&pAtcpConn->SpinLock, &OldIrql); pAtcpConn->Flags &= ~(ATCP_CONNECTION_UP | ATCP_DLL_SETUP_DONE); RELEASE_SPIN_LOCK(&pAtcpConn->SpinLock, OldIrql); // PPP wants to close connection: take away the RAS refcount DerefPPPConn(pAtcpConn); break; default: ASSERT(0); break; } pSndRcvInfo->DataLen = DataLen; pSndRcvInfo->StatusCode = dwRetCode; // complete that irp ARAP_COMPLETE_IRP(pIrp, (sizeof(ARAP_SEND_RECV_INFO)+DataLen), STATUS_SUCCESS, &ReturnStatus); if (fDerefPort) { // remove that IrpProcess refcount AtalkPortDereference(AtalkDefaultPort); } return ReturnStatus; } //*** // // Function: DerefPPPConn // Decrements the refcount of the connection element by 1. If the // refcount goes to 0, releases network addr and frees it // // Parameters: pAtcpConn - connection element in question // // Return: none // //***$ VOID DerefPPPConn( IN PATCPCONN pAtcpConn ) { KIRQL OldIrql; BOOLEAN fKill = FALSE; DBG_PPP_CHECK_PAGED_CODE(); ACQUIRE_SPIN_LOCK(&pAtcpConn->SpinLock, &OldIrql); ASSERT(pAtcpConn->Signature == ATCPCONN_SIGNATURE); ASSERT(pAtcpConn->RefCount > 0); pAtcpConn->RefCount--; if (pAtcpConn->RefCount == 0) { if (!(pAtcpConn->Flags & ATCP_CONNECTION_CLOSING)) { fKill = TRUE; pAtcpConn->Flags |= ATCP_CONNECTION_CLOSING; } } RELEASE_SPIN_LOCK(&pAtcpConn->SpinLock, OldIrql); if (!fKill) { return; } // and remove from the list ACQUIRE_SPIN_LOCK(&RasPortDesc->pd_Lock, &OldIrql); RemoveEntryList(&pAtcpConn->Linkage); RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock, OldIrql); // free that memory AtalkFreeMemory(pAtcpConn); DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("DerefPPPConn: PPP connection %lx freed\n",pAtcpConn)); ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql); PPPConnections--; RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql); // if possible (i.e. if this was the last connection), unlock PPP pages AtalkUnlockPPPIfNecessary(); } //*** // // Function: FindAndRefPPPConnByAddr // Finds the corresponding connection element, given the network // address (of the remote client) // // Parameters: destNode - network addr of the destination (remote client) // pdwFlags - pointer to a dword to return Flags field // // Return: pointer to the corresponding connection element, if found // //***$ PATCPCONN FindAndRefPPPConnByAddr( IN ATALK_NODEADDR destNode, OUT DWORD *pdwFlags ) { PATCPCONN pAtcpConn=NULL; PATCPCONN pAtcpWalker; PLIST_ENTRY pList; KIRQL OldIrql; // RAS not configured? if (!RasPortDesc) { return(NULL); } ACQUIRE_SPIN_LOCK(&RasPortDesc->pd_Lock, &OldIrql); if (!(RasPortDesc->pd_Flags & PD_ACTIVE)) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("FindAndRefPPPConnByAddr: RAS not active, ignoring\n")); RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock, OldIrql); return(NULL); } pList = RasPortDesc->pd_PPPConnHead.Flink; // // walk through all the PPP clients to see if we find ours // while (pList != &RasPortDesc->pd_PPPConnHead) { pAtcpWalker = CONTAINING_RECORD(pList, ATCPCONN, Linkage); pList = pAtcpWalker->Linkage.Flink; ACQUIRE_SPIN_LOCK_DPC(&pAtcpWalker->SpinLock); if (ATALK_NODES_EQUAL(&pAtcpWalker->NetAddr, &destNode)) { pAtcpConn = pAtcpWalker; pAtcpConn->RefCount++; *pdwFlags = pAtcpWalker->Flags; RELEASE_SPIN_LOCK_DPC(&pAtcpWalker->SpinLock); break; } RELEASE_SPIN_LOCK_DPC(&pAtcpWalker->SpinLock); } RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock, OldIrql); return( pAtcpConn ); } //*** // // Function: PPPRoutePacketToWan // This routine picks up a packet from the lan, checks to see if // it must be forwarded to any of the PPP clients and does the // good deed. // // Parameters: pDestAddr - who is this packet addressed to? (potentially bcast) // pSrcAddr - who sent this packet // Protocol - what packet is it? (ATP, NBP, etc.) // packet - buffer containing the packet // PktLen - how big is the packet // broadcast - is this a broadcast packet? // pDelivered - set on return: did we forward it to any dial-in // client (set to TRUE only for directed dgrams) // // Return: none // //***$ VOID PPPRoutePacketToWan( IN ATALK_ADDR *pDestAddr, IN ATALK_ADDR *pSrcAddr, IN BYTE Protocol, IN PBYTE packet, IN USHORT PktLen, IN USHORT HopCount, IN BOOLEAN broadcast, OUT PBOOLEAN pDelivered ) { KIRQL OldIrql; PATCPCONN pAtcpConn; PATCPCONN pPrevAtcpConn; PLIST_ENTRY pConnList; ATALK_NODEADDR DestNode; ATALK_NODEADDR SourceNode; DWORD StatusCode; DWORD dwFlags; BOOLEAN fRtmpPacket=FALSE; DBG_PPP_CHECK_PAGED_CODE(); // assume for now *pDelivered = FALSE; // // if this is a unicast, see if a PPP client with this dest address exists // if (!broadcast) { DestNode.atn_Network = pDestAddr->ata_Network; DestNode.atn_Node = pDestAddr->ata_Node; // first and foremost, let's find the puppy pAtcpConn = FindAndRefPPPConnByAddr(DestNode, &dwFlags); if (pAtcpConn == NULL) { return; } // let the caller know that we found who this data was meant for *pDelivered = TRUE; // if this dude isn't ready to route data, drop this packet! if (!(dwFlags & ATCP_CONNECTION_UP)) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_WARN, ("PPPRoutePacketToWan: dropping pkt on %lx, line-up not done\n",pAtcpConn)); // remove the refcount put in by FindAndRefPPPConnByAddr DerefPPPConn(pAtcpConn); return; } // send the packet out PPPTransmit(pAtcpConn, pDestAddr, pSrcAddr, Protocol, packet, PktLen, HopCount); // remove the refcount put in by FindAndRefPPPConnByAddr DerefPPPConn(pAtcpConn); return; } // // it's a broadcast packet: must send it to all the PPP guys // if (packet[LDDP_PROTO_TYPE_OFFSET] == DDPPROTO_RTMPRESPONSEORDATA) { fRtmpPacket = TRUE; } pAtcpConn = NULL; pPrevAtcpConn = NULL; SourceNode.atn_Network = pSrcAddr->ata_Network; SourceNode.atn_Node = pSrcAddr->ata_Node; while (1) { ACQUIRE_SPIN_LOCK(&RasPortDesc->pd_Lock, &OldIrql); // // first, let's find the right connection to work on // while (1) { // if we're in the middle of the list, get to the next guy if (pAtcpConn != NULL) { pConnList = pAtcpConn->Linkage.Flink; } // we're just starting: get the guy at the head of the list else { pConnList = RasPortDesc->pd_PPPConnHead.Flink; } // finished all? if (pConnList == &RasPortDesc->pd_PPPConnHead) { RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock, OldIrql); if (pPrevAtcpConn) { DerefPPPConn(pPrevAtcpConn); } return; } pAtcpConn = CONTAINING_RECORD(pConnList, ATCPCONN, Linkage); ACQUIRE_SPIN_LOCK_DPC(&pAtcpConn->SpinLock); // if this guy sent out the broadcast, don't send it back to him! if (ATALK_NODES_EQUAL(&pAtcpConn->NetAddr, &SourceNode)) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_WARN, ("PPPRoutePacketToWan: skipping bcast from source\n")); RELEASE_SPIN_LOCK_DPC(&pAtcpConn->SpinLock); continue; } // if this dude isn't ready to route data, skip if (!(pAtcpConn->Flags & ATCP_CONNECTION_UP)) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_WARN, ("PPPRoutePacketToWan: skipping %lx because line-up not done\n",pAtcpConn)); RELEASE_SPIN_LOCK_DPC(&pAtcpConn->SpinLock); continue; } // // if this is an RTMP packet and the client doesn't want those // packets, don't send // if (fRtmpPacket && (pAtcpConn->Flags & ATCP_SUPPRESS_RTMP)) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_WARN, ("PPPRoutePacketToWan: skipping %lx because RTMP data to be suppressed\n",pAtcpConn)); RELEASE_SPIN_LOCK_DPC(&pAtcpConn->SpinLock); continue; } // if this dude wants all broadcasts suppressed, skip it if (pAtcpConn->Flags & ATCP_SUPPRESS_ALLBCAST) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_WARN, ("PPPRoutePacketToWan: skipping %lx because all bcast to be suppressed\n",pAtcpConn)); RELEASE_SPIN_LOCK_DPC(&pAtcpConn->SpinLock); continue; } // let's make sure this connection stays around till we finish pAtcpConn->RefCount++; RELEASE_SPIN_LOCK_DPC(&pAtcpConn->SpinLock); break; } RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock, OldIrql); // // remove the refcount on the previous connection we put in earlier // if (pPrevAtcpConn) { DerefPPPConn(pPrevAtcpConn); } ASSERT(pPrevAtcpConn != pAtcpConn); pPrevAtcpConn = pAtcpConn; PPPTransmit(pAtcpConn, pDestAddr, pSrcAddr, Protocol, packet, PktLen, HopCount); } } //*** // // Function: PPPTransmit // This routine sends the packet out to a PPP destination // // Parameters: pAtcpConn - PPP connection to send to // pDestAddr - who is this packet addressed to? (potentially bcast) // pSrcAddr - who sent this packet // Protocol - what packet is it? (ATP, NBP, etc.) // packet - buffer containing the packet // PktLen - how big is the packet // HopCount - hopcount in the DDP pkt as received // // Return: none // //***$ VOID FASTCALL PPPTransmit( IN PATCPCONN pAtcpConn, IN ATALK_ADDR *pDestAddr, IN ATALK_ADDR *pSrcAddr, IN BYTE Protocol, IN PBYTE packet, IN USHORT PktLen, IN USHORT HopCount ) { PBUFFER_DESC pBufCopy; PBUFFER_DESC pPktDesc; SEND_COMPL_INFO SendInfo; PBYTE pLinkDdpOptHdr; PBYTE pDgram; ATALK_ERROR error; DBG_PPP_CHECK_PAGED_CODE(); // allocate a buffer and bufdesc to copy the incoming packet (data portion) pBufCopy = AtalkAllocBuffDesc(NULL,PktLen,(BD_FREE_BUFFER | BD_CHAR_BUFFER)); if (pBufCopy == NULL) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("PPPTransmit: alloc BufDesc failed\n")); return; } // copy the data in AtalkCopyBufferToBuffDesc(packet, PktLen, pBufCopy, 0); // allocate a buffdesc to hold headers AtalkNdisAllocBuf(&pPktDesc); if (pPktDesc == NULL) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("PPPTransmit: couldn't alloc ndis bufdesc\n")); AtalkFreeBuffDesc(pBufCopy); return; } // put in the Mac header (NdisWan's header) pLinkDdpOptHdr = pPktDesc->bd_CharBuffer; AtalkNdisBuildPPPPHdr(pLinkDdpOptHdr, pAtcpConn); // make up the DDP header pDgram = pLinkDdpOptHdr + WAN_LINKHDR_LEN; *pDgram++ = (DDP_HOP_COUNT(HopCount) + DDP_MSB_LEN(PktLen + LDDP_HDR_LEN)); PUTSHORT2BYTE(pDgram, (PktLen + LDDP_HDR_LEN)); pDgram++; PUTSHORT2SHORT(pDgram, 0); pDgram += sizeof(USHORT); PUTSHORT2SHORT(pDgram, pDestAddr->ata_Network); pDgram += sizeof(USHORT); PUTSHORT2SHORT(pDgram, pSrcAddr->ata_Network); pDgram += sizeof(USHORT); *pDgram++ = pDestAddr->ata_Node; *pDgram++ = pSrcAddr->ata_Node; *pDgram++ = pDestAddr->ata_Socket; *pDgram++ = pSrcAddr->ata_Socket; *pDgram++ = Protocol; // Set length in the buffer descriptor. AtalkSetSizeOfBuffDescData(pPktDesc, WAN_LINKHDR_LEN + LDDP_HDR_LEN); // chain in this bufdesc AtalkPrependBuffDesc(pPktDesc, pBufCopy); INTERLOCKED_ADD_STATISTICS(&RasPortDesc->pd_PortStats.prtst_DataOut, AtalkSizeBuffDesc(pPktDesc), &AtalkStatsLock.SpinLock); // set up our completion info SendInfo.sc_TransmitCompletion = PPPTransmitCompletion; SendInfo.sc_Ctx1 = RasPortDesc; SendInfo.sc_Ctx2 = pBufCopy; SendInfo.sc_Ctx3 = pAtcpConn; // send the packet error = AtalkNdisSendPacket(RasPortDesc, pPktDesc, AtalkDdpSendComplete, &SendInfo); if (!ATALK_SUCCESS(error)) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("PPPTransmit: AtalkNdisSendPacket failed %ld\n",error)); AtalkDdpSendComplete(NDIS_STATUS_FAILURE, pPktDesc, &SendInfo); } } //*** // // Function: PPPTransmitCompletion // This is the completion routine for PPPTransmit, and is called // by NDIS after the packet is sent out (or failure occurs) // // Parameters: Status - how did the send go // pSendInfo - completion info // // Return: none // //***$ VOID FASTCALL PPPTransmitCompletion( IN NDIS_STATUS Status, IN PSEND_COMPL_INFO pSendInfo ) { PBUFFER_DESC pBuffDesc; DBG_PPP_CHECK_PAGED_CODE(); pBuffDesc = (PBUFFER_DESC)(pSendInfo->sc_Ctx2); ASSERT(pBuffDesc != NULL); ASSERT(pBuffDesc->bd_Flags & (BD_CHAR_BUFFER | BD_FREE_BUFFER)); if (Status != 0) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("PPPTransmitCompletion: send failed, %lx on %lx\n", Status,pSendInfo->sc_Ctx3)); } AtalkFreeBuffDesc(pBuffDesc); } //*** // // Function: PPPGetDynamicAddr // This routine gets a network address for a PPP dial-in client. // It does the same AARP logic as if it were acquiring a // node-address for the host itself. // // Parameters: pAtcpConn - the connection for which we need a network addr // // Return: ARAPERR_NO_ERROR if all went well. // //***$ DWORD PPPGetDynamicAddr( IN PATCPCONN pAtcpConn ) { ATALK_NODEADDR NetAddr; ATALK_NETWORKRANGE NetRange; BOOLEAN fFound=FALSE; KIRQL OldIrql; DWORD StatusCode=ARAPERR_STACK_NOT_UP; DBG_PPP_CHECK_PAGED_CODE(); ASSERT(AtalkDefaultPort != NULL); // // go find a node address on the default port (we'll never get this far if // default port isn't up yet) // ACQUIRE_SPIN_LOCK(&pAtcpConn->SpinLock, &OldIrql); ASSERT(!(pAtcpConn->Flags & ATCP_FINDING_NODE)); pAtcpConn->Flags |= ATCP_FINDING_NODE; RELEASE_SPIN_LOCK(&pAtcpConn->SpinLock, OldIrql); AtalkLockInitIfNecessary(); // if we are stuck in the startup range, use that range for dial-in guys, too if (WITHIN_NETWORK_RANGE(AtalkDefaultPort->pd_NetworkRange.anr_LastNetwork, &AtalkStartupNetworkRange)) { NetRange = AtalkStartupNetworkRange; } else { NetRange = AtalkDefaultPort->pd_NetworkRange; } fFound = AtalkInitAarpForNodeInRange(AtalkDefaultPort, (PVOID)pAtcpConn, TRUE, NetRange, &NetAddr); AtalkUnlockInitIfNecessary(); ACQUIRE_SPIN_LOCK(&pAtcpConn->SpinLock, &OldIrql); pAtcpConn->Flags &= ~ATCP_FINDING_NODE; if (fFound) { // store that adddr! pAtcpConn->NetAddr.atn_Network = NetAddr.atn_Network; pAtcpConn->NetAddr.atn_Node = NetAddr.atn_Node; pAtcpConn->Flags |= ATCP_NODE_IN_USE; StatusCode = ARAPERR_NO_ERROR; DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_INFO, ("PPPGetDynamicAddr: found addr for PPP client = %lx %lx\n", NetAddr.atn_Network,NetAddr.atn_Node)); } else { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("ArapGetDynamicAddr: PPP: no more network addr left?\n")); pAtcpConn->Flags &= ~ATCP_NODE_IN_USE; pAtcpConn->NetAddr.atn_Network = 0; pAtcpConn->NetAddr.atn_Node = 0; StatusCode = ARAPERR_NO_NETWORK_ADDR; } RELEASE_SPIN_LOCK(&pAtcpConn->SpinLock, OldIrql); return(StatusCode); }