/*++ Copyright (c) 1997 FORE Systems, Inc. Copyright (c) 1997 Microsoft Corporation Module Name: adapter.c Abstract: Handlers for adapter events. Author: Larry Cleeton, FORE Systems (v-lcleet) Environment: Kernel mode Revision History: --*/ #include "precomp.h" #pragma hdrstop NDIS_STATUS AtmLanePnPEventHandler( IN NDIS_HANDLE ProtocolBindingContext, IN PNET_PNP_EVENT pNetPnPEvent ) /*++ Routine Description: Handler for PnP Events. Arguments: ProtocolBindingContext - Handle to protocol's adapter binding context. Actually a pointer to our adapter struct. pNetPnPEvent - Pointer to PnP Event structure describing the event. Return Value: Status of handling the event. --*/ { NDIS_STATUS Status; PATMLANE_ADAPTER pAdapter; PNET_DEVICE_POWER_STATE pPowerState = (PNET_DEVICE_POWER_STATE)pNetPnPEvent->Buffer; #if DEBUG_IRQL KIRQL EntryIrql; #endif GET_ENTRY_IRQL(EntryIrql); TRACEIN(PnPEventHandler); // Extract the adapter struct pointer - this will be NULL for // global reconfig messages. pAdapter = (PATMLANE_ADAPTER)ProtocolBindingContext; switch (pNetPnPEvent->NetEvent) { case NetEventSetPower: DBGP((1, "PnPEventHandler: NetEventSetPower\n")); switch (*pPowerState) { case NetDeviceStateD0: Status = NDIS_STATUS_SUCCESS; break; default: // // We can't suspend, so we ask NDIS to unbind us by // returning this status: // Status = NDIS_STATUS_NOT_SUPPORTED; break; } break; case NetEventQueryPower: DBGP((1, "PnPEventHandler: NetEventQueryPower succeeding\n")); Status = NDIS_STATUS_SUCCESS; break; case NetEventQueryRemoveDevice: DBGP((1, "PnPEventHandler: NetEventQueryRemoveDevice succeeding\n")); Status = NDIS_STATUS_SUCCESS; break; case NetEventCancelRemoveDevice: DBGP((1, "PnPEventHandler: NetEventCancelRemoveDevice succeeding\n")); Status = NDIS_STATUS_SUCCESS; break; case NetEventBindList: DBGP((1, "PnPEventHandler: NetEventBindList not supported\n")); Status = NDIS_STATUS_NOT_SUPPORTED; break; case NetEventMaximum: DBGP((1, "PnPEventHandler: NetEventMaximum not supported\n")); Status = NDIS_STATUS_NOT_SUPPORTED; break; case NetEventReconfigure: DBGP((1, "PnPEventHandler: NetEventReconfigure\n")); Status = AtmLaneReconfigureHandler(pAdapter, pNetPnPEvent); break; default: DBGP((1, "PnPEventHandler: Unknown event 0x%x not supported\n", pNetPnPEvent->NetEvent)); Status = NDIS_STATUS_NOT_SUPPORTED; break; } TRACEOUT(PnPEventHandler); CHECK_EXIT_IRQL(EntryIrql); return Status; } VOID AtmLaneBindAdapterHandler( OUT PNDIS_STATUS pStatus, IN NDIS_HANDLE BindContext, IN PNDIS_STRING pDeviceName, IN PVOID SystemSpecific1, IN PVOID SystemSpecific2 ) /*++ Routine Description: Handler for BindAdapter event from NDIS. Arguments: Status - Points to a variable to return the status of the bind operation. BindContext - NDIS supplied handle to be used in call to NdisCompleteBindAdapter. pDeviceName - Points to a counted, zero-terminated Unicode string naming the adapter to open. SystemSpecific1 - Registry path pointer to be used in call to NdisOpenProtocolConfiguration. SystemSpecific2 - Reserved. Return Value: None. --*/ { PATMLANE_ADAPTER pAdapter; PATMLANE_ELAN pElan; NDIS_STATUS Status; NDIS_STATUS OutputStatus; NDIS_STATUS OpenStatus; NDIS_MEDIUM Media; UINT MediumIndex; ULONG rc; #if DEBUG_IRQL KIRQL EntryIrql; #endif GET_ENTRY_IRQL(EntryIrql); TRACEIN(BindAdapterHandler); do { // // Initialize for error clean-up. // Status = NDIS_STATUS_SUCCESS; pAdapter = NULL_PATMLANE_ADAPTER; if (AtmLaneIsDeviceAlreadyBound(pDeviceName)) { DBGP((0, "BindAdapterHandler: duplicate bind to %ws\n", pDeviceName->Buffer)); Status = NDIS_STATUS_NOT_ACCEPTED; break; } // // Allocate Adapter structure. // pAdapter = AtmLaneAllocAdapter(pDeviceName, SystemSpecific1); if (NULL_PATMLANE_ADAPTER == pAdapter) { DBGP((0, "BindAdapterHandler: Allocate of adapter struct failed\n")); Status = NDIS_STATUS_RESOURCES; break; } // // Put open adapter reference on the Adapter struct. // (VOID)AtmLaneReferenceAdapter(pAdapter, "openadapter"); // // Save bind context // pAdapter->BindContext = BindContext; // // Open the Adapter. // INIT_BLOCK_STRUCT(&(pAdapter->Block)); INIT_BLOCK_STRUCT(&(pAdapter->OpenBlock)); pAdapter->Flags |= ADAPTER_FLAGS_OPEN_IN_PROGRESS; Media = NdisMediumAtm; NdisOpenAdapter( &Status, &OpenStatus, &(pAdapter->NdisAdapterHandle), &(MediumIndex), &Media, 1, pAtmLaneGlobalInfo->NdisProtocolHandle, (NDIS_HANDLE)pAdapter, pDeviceName, 0, (PSTRING)NULL); if (Status == NDIS_STATUS_PENDING) { // // Wait for completion. // Status = WAIT_ON_BLOCK_STRUCT(&(pAdapter->Block)); } if (Status != NDIS_STATUS_SUCCESS) { DBGP((0, "BindAdapterHandler: NdisOpenAdapter failed, status %x\n", Status)); break; } // // Get info from Adapter // AtmLaneGetAdapterInfo(pAdapter); // // Allow an AF notification thread to proceed now. // ACQUIRE_ADAPTER_LOCK(pAdapter); pAdapter->Flags &= ~ADAPTER_FLAGS_OPEN_IN_PROGRESS; SIGNAL_BLOCK_STRUCT(&pAdapter->OpenBlock, NDIS_STATUS_SUCCESS); RELEASE_ADAPTER_LOCK(pAdapter); break; } while (FALSE); // // If bad status then cleanup. // if (NDIS_STATUS_SUCCESS != Status) { // // Dereference the Adapter struct if it exists // if (NULL_PATMLANE_ADAPTER != pAdapter) { rc = AtmLaneDereferenceAdapter(pAdapter, "openadapter"); ASSERT(rc == 0); } DBGP((0, "BindAdapterHandler: Bad status %x\n", Status)); } // // Output Status // *pStatus = Status; TRACEOUT(BindAdapterHandler); CHECK_EXIT_IRQL(EntryIrql); return; } VOID AtmLaneUnbindAdapterHandler( OUT PNDIS_STATUS pStatus, IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE UnbindContext ) /*++ Routine Description: Handler for UnBindAdapter event from NDIS. Arguments: Status - Points to a variable to return the status of the unbind operation. ProtocolBindingContext - Specifies the handle to a protocol-allocated context area in which the protocol driver maintains per-binding runtime state. The driver supplied this handle when it called NdisOpenAdapter. UnbindContext - Specifies a handle, supplied by NDIS, that the protocol passes subsequently to NdisCompleteUnbindAdapter. Return Value: None. --*/ { PATMLANE_ADAPTER pAdapter; PATMLANE_ELAN pElan; PLIST_ENTRY p; PATMLANE_ATM_ENTRY pAtmEntry; PATMLANE_ATM_ENTRY pNextAtmEntry; PATMLANE_MAC_ENTRY pMacEntry; ULONG rc; ULONG i; BOOLEAN WasCancelled; BOOLEAN CompleteUnbind; #if DEBUG_IRQL KIRQL EntryIrql; #endif GET_ENTRY_IRQL(EntryIrql); TRACEIN(UnbindAdapterHandler); pAdapter = (PATMLANE_ADAPTER)ProtocolBindingContext; STRUCT_ASSERT(pAdapter, atmlane_adapter); DBGP((0, "UnbindAdapterHandler: pAdapter %p, UnbindContext %x\n", pAdapter, UnbindContext)); *pStatus = NDIS_STATUS_PENDING; // // Save the unbind context for a possible later call to // NdisCompleteUnbindAdapter. // ACQUIRE_ADAPTER_LOCK(pAdapter); pAdapter->UnbindContext = UnbindContext; pAdapter->Flags |= ADAPTER_FLAGS_UNBINDING; while (pAdapter->Flags & ADAPTER_FLAGS_BOOTSTRAP_IN_PROGRESS) { RELEASE_ADAPTER_LOCK(pAdapter); (VOID)WAIT_ON_BLOCK_STRUCT(&pAdapter->UnbindBlock); ACQUIRE_ADAPTER_LOCK(pAdapter); } if (IsListEmpty(&pAdapter->ElanList)) { CompleteUnbind = TRUE; } else { // // We will complete the unbind later. // pAdapter->Flags |= ADAPTER_FLAGS_UNBIND_COMPLETE_PENDING; CompleteUnbind = FALSE; } RELEASE_ADAPTER_LOCK(pAdapter); // // If there are no elans on this adapter, we are done. // if (CompleteUnbind) { AtmLaneCompleteUnbindAdapter(pAdapter); CHECK_EXIT_IRQL(EntryIrql); return; } // // Shutdown each ELAN // ACQUIRE_ADAPTER_LOCK(pAdapter); p = pAdapter->ElanList.Flink; while (p != &pAdapter->ElanList) { pElan = CONTAINING_RECORD(p, ATMLANE_ELAN, Link); STRUCT_ASSERT(pElan, atmlane_elan); ACQUIRE_ELAN_LOCK(pElan); AtmLaneReferenceElan(pElan, "tempUnbind"); RELEASE_ELAN_LOCK(pElan); p = p->Flink; } RELEASE_ADAPTER_LOCK(pAdapter); p = pAdapter->ElanList.Flink; while (p != &pAdapter->ElanList) { pElan = CONTAINING_RECORD(p, ATMLANE_ELAN, Link); STRUCT_ASSERT(pElan, atmlane_elan); // // get next pointer before elan goes away // p = p->Flink; // // Kill the ELAN // ACQUIRE_ELAN_LOCK(pElan); rc = AtmLaneDereferenceElan(pElan, "tempUnbind"); if (rc != 0) { AtmLaneShutdownElan(pElan, FALSE); } } TRACEOUT(UnbindAdapterHandler); CHECK_EXIT_IRQL(EntryIrql); return; } VOID AtmLaneCompleteUnbindAdapter( IN PATMLANE_ADAPTER pAdapter ) /*++ Routine Description: Complete the process of adapter unbinding. All Elans on this adapter are assumed to have been removed. We start it off by calling NdisCloseAdapter. Action continues in our CloseAdapterComplete routine. Arguments: pAdapter - Pointer to the adapter being unbound. Return Value: None --*/ { NDIS_STATUS Status; #if DEBUG_IRQL KIRQL EntryIrql; #endif GET_ENTRY_IRQL(EntryIrql); TRACEIN(CompleteUnbindAdapter); DBGP((3, "CompleteUnbindAdapter: pAdapter %x, AdapterHandle %x\n", pAdapter, pAdapter->NdisAdapterHandle)); ASSERT(pAdapter->NdisAdapterHandle != NULL); pAdapter->Flags |= ADAPTER_FLAGS_CLOSE_IN_PROGRESS; NdisCloseAdapter( &Status, pAdapter->NdisAdapterHandle ); if (Status != NDIS_STATUS_PENDING) { AtmLaneCloseAdapterCompleteHandler( (NDIS_HANDLE)pAdapter, Status ); } TRACEOUT(CompleteUnbindAdapter); CHECK_EXIT_IRQL(EntryIrql); return; } VOID AtmLaneOpenAdapterCompleteHandler( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status, IN NDIS_STATUS OpenErrorStatus ) /*++ Routine Description: This is called by NDIS when a previous call to NdisOpenAdapter that had pended has completed. The thread that called NdisOpenAdapter would have blocked itself, so we simply wake it up now. Arguments: ProtocolBindingContext - Our context for this adapter binding, which is a pointer to an ATMLANE Adapter structure. Status - Status of OpenAdapter OpenErrorStatus - Error code in case of failure. Return Value: None --*/ { PATMLANE_ADAPTER pAdapter; #if DEBUG_IRQL KIRQL EntryIrql; #endif GET_ENTRY_IRQL(EntryIrql); TRACEIN(OpenAdapterCompleteHandler); pAdapter = (PATMLANE_ADAPTER)ProtocolBindingContext; STRUCT_ASSERT(pAdapter, atmlane_adapter); SIGNAL_BLOCK_STRUCT(&(pAdapter->Block), Status); TRACEOUT(OpenAdapterCompleteHandler); CHECK_EXIT_IRQL(EntryIrql); return; } VOID AtmLaneCloseAdapterCompleteHandler( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status ) /*++ Routine Description: This is called by NDIS when a previous call to NdisCloseAdapter that had pended has completed. The thread that called NdisCloseAdapter would have blocked itself, so we simply wake it up now. Arguments: ProtocolBindingContext - Our context for this adapter binding, which is a pointer to an ATMLANE Adapter structure. Status - Status of CloseAdapter Return Value: None --*/ { PATMLANE_ADAPTER pAdapter; NDIS_HANDLE UnbindContext; ULONG rc; #if DEBUG_IRQL KIRQL EntryIrql; #endif GET_ENTRY_IRQL(EntryIrql); TRACEIN(CloseAdapterCompleteHandler); pAdapter = (PATMLANE_ADAPTER)ProtocolBindingContext; STRUCT_ASSERT(pAdapter, atmlane_adapter); pAdapter->Flags &= ~ADAPTER_FLAGS_CLOSE_IN_PROGRESS; pAdapter->NdisAdapterHandle = NULL; UnbindContext = pAdapter->UnbindContext; DBGP((0, "CloseAdapterComplete: pAdapter %x, UnbindContext %x\n", pAdapter, UnbindContext)); // // Dereference the Adapter (should free structure) // ACQUIRE_ADAPTER_LOCK(pAdapter); rc = AtmLaneDereferenceAdapter(pAdapter, "openadapter"); ASSERT(rc == 0); // // If NDIS had requested us to Unbind, complete the // request now. // if (UnbindContext != (NDIS_HANDLE)NULL) { NdisCompleteUnbindAdapter( UnbindContext, NDIS_STATUS_SUCCESS ); } else { // // We initiated the unbind from our Unload handler, // which would have been waiting for us to complete. // Wake up that thread now. // SIGNAL_BLOCK_STRUCT(&(pAtmLaneGlobalInfo->Block), NDIS_STATUS_SUCCESS); } TRACEOUT(CloseAdapterCompleteHandler); CHECK_EXIT_IRQL(EntryIrql); return; } VOID AtmLaneResetCompleteHandler( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status ) /*++ Routine Description: This routine is called when the miniport indicates that a Reset operation has just completed. We ignore this event. Arguments: ProtocolBindingContext - Our context for this adapter binding, which is a pointer to an ATMLANE Adapter structure. Status - Status of the reset operation. Return Value: None --*/ { PATMLANE_ADAPTER pAdapter; TRACEIN(ResetCompleteHandler); pAdapter = (PATMLANE_ADAPTER)ProtocolBindingContext; STRUCT_ASSERT(pAdapter, atmlane_adapter); DBGP((3, "Reset Complete on Adapter %x\n", pAdapter)); TRACEOUT(ResetCompleteHandler); return; } VOID AtmLaneRequestCompleteHandler( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_REQUEST pNdisRequest, IN NDIS_STATUS Status ) /*++ Routine Description: This is called by NDIS when a previous call we made to NdisRequest() has completed. We would be blocked on our adapter structure, waiting for this to happen -- wake up the blocked thread. Arguments: ProtocolBindingContext - Pointer to our Adapter structure pNdisRequest - The request that completed Status - Status of the request. Return Value: None --*/ { PATMLANE_ADAPTER pAdapter; #if DEBUG_IRQL KIRQL EntryIrql; #endif GET_ENTRY_IRQL(EntryIrql); TRACEIN(RequestCompleteHandler); pAdapter = (PATMLANE_ADAPTER)ProtocolBindingContext; STRUCT_ASSERT(pAdapter, atmlane_adapter); SIGNAL_BLOCK_STRUCT(&(pAdapter->Block), Status); TRACEOUT(RequestCompleteHandler); CHECK_EXIT_IRQL(EntryIrql); return; } VOID AtmLaneReceiveCompleteHandler( IN NDIS_HANDLE ProtocolBindingContext ) /*++ Routine Description: This is currently ignored. Arguments: ProtocolBindingContext - Our context for this adapter binding, which is a pointer to an ATMLANE Adapter structure. Return Value: None --*/ { PATMLANE_ADAPTER pAdapter; PATMLANE_ELAN pElan; PLIST_ENTRY Entry; TRACEIN(ReceiveCompleteHandler); TRACEOUT(ReceiveCompleteHandler); return; } VOID AtmLaneStatusHandler( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS GeneralStatus, IN PVOID pStatusBuffer, IN UINT StatusBufferSize ) /*++ Routine Description: This routine is called when the miniport indicates an adapter-wide status change. We ignore this. Arguments: Return Value: None --*/ { TRACEIN(StatusHandler); DBGP((3, "StatusHandler: ProtocolBindContext %x, Status %x\n", ProtocolBindingContext, GeneralStatus)); TRACEOUT(StatusHandler); return; } VOID AtmLaneStatusCompleteHandler( IN NDIS_HANDLE ProtocolBindingContext ) /*++ Routine Description: This routine is called when the miniport wants to tell us about completion of a status change (?). Ignore this. Arguments: Return Value: None --*/ { TRACEIN(StatusCompleteHandler); DBGP((3, "StatusCompleteHandler: ProtocolBindingContext %x\n", ProtocolBindingContext)); TRACEOUT(StatusCompleteHandler); return; } VOID AtmLaneCoSendCompleteHandler( IN NDIS_STATUS Status, IN NDIS_HANDLE ProtocolVcContext, IN PNDIS_PACKET pNdisPacket ) /*++ Routine Description: This routine is called by NDIS when the ATM miniport is finished with a packet we had previously sent via NdisCoSendPackets. If packet originated within ATMLANE it is freed here. If packet originated in protocol above the virtual miniport the packet must be put back in it's original condition and returned to the protocol. Arguments: Status - Status of the NdisCoSendPackets. ProtocolVcContext - Our context for the VC on which the packet was sent (i.e. pointer to ATMLANE VC). pNdisPacket - The packet whose "send" is being completed. Return Value: None --*/ { PATMLANE_VC pVc; PATMLANE_ELAN pElan; UINT TotalLength; BOOLEAN OwnerIsLane; PNDIS_BUFFER pNdisBuffer; PNDIS_PACKET pProtNdisPacket; ULONG rc; #if DEBUG_IRQL KIRQL EntryIrql; #endif GET_ENTRY_IRQL(EntryIrql); TRACEIN(CoSendCompleteHandler); TRACELOGWRITE((&TraceLog, TL_COSENDCMPLTIN, pNdisPacket, Status)); TRACELOGWRITEPKT((&TraceLog, pNdisPacket)); pVc = (PATMLANE_VC)ProtocolVcContext; STRUCT_ASSERT(pVc, atmlane_vc) ACQUIRE_VC_LOCK(pVc); pElan = pVc->pElan; STRUCT_ASSERT(pElan, atmlane_elan); rc = AtmLaneDereferenceVc(pVc, "sendpkt"); if (rc > 0) { pVc->OutstandingSends--; if ((pVc->OutstandingSends == 0) && (IS_FLAG_SET(pVc->Flags, VC_CLOSE_STATE_MASK, VC_CLOSE_STATE_CLOSING))) { DBGP((1, "CoSendComplete: Vc %p, closing call\n", pVc)); AtmLaneCloseCall(pVc); // // VC lock is released above. // } else { RELEASE_VC_LOCK(pVc); } } #if SENDLIST // // Remove packet from send list if there // NdisAcquireSpinLock(&pElan->SendListLock); { PNDIS_PACKET *ppNextPkt; BOOLEAN Found = FALSE; ppNextPkt = &(pElan->pSendList); while (*ppNextPkt != (PNDIS_PACKET)NULL) { if (*ppNextPkt == pNdisPacket) { *ppNextPkt = PSEND_RSVD(pNdisPacket)->pNextInSendList; Found = TRUE; break; } else { ppNextPkt = &(PSEND_RSVD((*ppNextPkt))->pNextInSendList); } } if (!Found) { DBGP((0, "CoSendCompleteHandler: Pkt %x Duplicate Completion\n", pNdisPacket)); NdisReleaseSpinLock(&pElan->SendListLock); goto skipit; } } NdisReleaseSpinLock(&pElan->SendListLock); #endif // SENDLIST #if PROTECT_PACKETS // // Lock the packet // ACQUIRE_SENDPACKET_LOCK(pNdisPacket); // // Mark it as having been completed by miniport. // Remember completion status. // ASSERT((PSEND_RSVD(pNdisPacket)->Flags & PACKET_RESERVED_COMPLETED) == 0); PSEND_RSVD(pNdisPacket)->Flags |= PACKET_RESERVED_COMPLETED; PSEND_RSVD(pNdisPacket)->CompletionStatus = Status; // // Complete the packet only if the call to NdisCoSendPackets // for this packet has returned. Otherwise it will be completed // when NdisCoSendPackets returns. // if ((PSEND_RSVD(pNdisPacket)->Flags & PACKET_RESERVED_COSENDRETURNED) != 0) { AtmLaneCompleteSendPacket(pElan, pNdisPacket, Status); // // packet lock released in above // } else { RELEASE_SENDPACKET_LOCK(pNdisPacket); } #else // PROTECT_PACKETS AtmLaneCompleteSendPacket(pElan, pNdisPacket, Status); #endif // PROTECT_PACKETS #if SENDLIST skipit: #endif TRACELOGWRITE((&TraceLog, TL_COSENDCMPLTOUT, pNdisPacket)); TRACEOUT(CoSendCompleteHandler); CHECK_EXIT_IRQL(EntryIrql); return; } VOID AtmLaneCoStatusHandler( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE ProtocolVcContext OPTIONAL, IN NDIS_STATUS GeneralStatus, IN PVOID pStatusBuffer, IN UINT StatusBufferSize ) /*++ Routine Description: This routine is called when the miniport indicates a status change, possibly on a VC. Ignore this. Arguments: Return Value: None --*/ { TRACEIN(CoStatusHandler); DBGP((3, "CoStatusHandler: ProtocolBindingContext %x " "ProtocolVcContext %x, Status %x\n", ProtocolBindingContext, ProtocolVcContext, GeneralStatus)); TRACEOUT(CoStatusHandler); return; } NDIS_STATUS AtmLaneSendAdapterNdisRequest( IN PATMLANE_ADAPTER pAdapter, IN PNDIS_REQUEST pNdisRequest, IN NDIS_REQUEST_TYPE RequestType, IN NDIS_OID Oid, IN PVOID pBuffer, IN ULONG BufferLength ) /*++ Routine Description: Send an NDIS (non-Connection Oriented) request to the Miniport. Initialize the NDIS_REQUEST structure, link the supplied buffer to it, and send the request. If the request does not pend, we call our completion routine from here. Arguments: pAdapter - Pointer to our Adapter structure representing the adapter to which the request is to be sent pNdisRequest - Pointer to NDIS request structure RequestType - Set/Query information Oid - OID to be passed in the request pBuffer - place for value(s) BufferLength - length of above Return Value: Status of the NdisRequest. --*/ { NDIS_STATUS Status; TRACEIN(SendAdapterNdisRequest); // // Fill in the NDIS Request structure // pNdisRequest->RequestType = RequestType; if (RequestType == NdisRequestQueryInformation) { pNdisRequest->DATA.QUERY_INFORMATION.Oid = Oid; pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer = pBuffer; pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength = BufferLength; pNdisRequest->DATA.QUERY_INFORMATION.BytesWritten = 0; pNdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BufferLength; } else { pNdisRequest->DATA.SET_INFORMATION.Oid = Oid; pNdisRequest->DATA.SET_INFORMATION.InformationBuffer = pBuffer; pNdisRequest->DATA.SET_INFORMATION.InformationBufferLength = BufferLength; pNdisRequest->DATA.SET_INFORMATION.BytesRead = 0; pNdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0; } INIT_BLOCK_STRUCT(&(pAdapter->Block)); NdisRequest( &Status, pAdapter->NdisAdapterHandle, pNdisRequest); if (Status == NDIS_STATUS_PENDING) { Status = WAIT_ON_BLOCK_STRUCT(&(pAdapter->Block)); } TRACEOUT(SendAdapterNdisRequest); return (Status); } VOID AtmLaneGetAdapterInfo( IN PATMLANE_ADAPTER pAdapter ) /*++ Routine Description: Query an adapter for hardware-specific information that we need: - burnt in hardware address (ESI part) - Max packet size - line rate Arguments: pAdapter - Pointer to ATMLANE adapter structure Return Value: None --*/ { NDIS_STATUS Status; NDIS_REQUEST NdisRequest; ULONG Value; TRACEIN(GetAdapterInfo); // // Initialize. // NdisZeroMemory(&pAdapter->MacAddress, sizeof(MAC_ADDRESS)); // // MAC Address: // Status = AtmLaneSendAdapterNdisRequest( pAdapter, &NdisRequest, NdisRequestQueryInformation, OID_ATM_HW_CURRENT_ADDRESS, (PVOID)&(pAdapter->MacAddress), sizeof(MAC_ADDRESS) ); if (NDIS_STATUS_SUCCESS != Status) { DBGP((0, "GetAdapterInfo: OID_ATM_HW_CURRENT_ADDRESS failed\n")); } else { DBGP((1, "GetAdapterInfo: ATM card MacAddr %s\n", MacAddrToString(&pAdapter->MacAddress))); } // // Max Frame Size: // Status = AtmLaneSendAdapterNdisRequest( pAdapter, &NdisRequest, NdisRequestQueryInformation, OID_ATM_MAX_AAL5_PACKET_SIZE, (PVOID)&(pAdapter->MaxAAL5PacketSize), sizeof(ULONG) ); if (NDIS_STATUS_SUCCESS != Status) { DBGP((0, "GetAdapterInfo: OID_ATM_MAX_AAL5_PACKET_SIZE failed\n")); // // Use the default. // pAdapter->MaxAAL5PacketSize = ATMLANE_DEF_MAX_AAL5_PDU_SIZE; } if (pAdapter->MaxAAL5PacketSize > ATMLANE_DEF_MAX_AAL5_PDU_SIZE) { pAdapter->MaxAAL5PacketSize = ATMLANE_DEF_MAX_AAL5_PDU_SIZE; } DBGP((1, "GetAdapterInfo: MaxAAL5PacketSize %d\n", pAdapter->MaxAAL5PacketSize)); // // Link speed: // Status = AtmLaneSendAdapterNdisRequest( pAdapter, &NdisRequest, NdisRequestQueryInformation, OID_GEN_CO_LINK_SPEED, (PVOID)(&(pAdapter->LinkSpeed)), sizeof(NDIS_CO_LINK_SPEED) ); if ((NDIS_STATUS_SUCCESS != Status) || (0 == pAdapter->LinkSpeed.Inbound) || (0 == pAdapter->LinkSpeed.Outbound)) { DBGP((0, "GetAdapterInfo: OID_GEN_CO_LINK_SPEED failed\n")); // // Default and assume data rate for 155.52Mbps SONET // pAdapter->LinkSpeed.Outbound = pAdapter->LinkSpeed.Inbound = ATM_USER_DATA_RATE_SONET_155; } DBGP((1, "GetAdapterInfo: Outbound Linkspeed %d\n", pAdapter->LinkSpeed.Outbound)); DBGP((1, "GetAdapterInfo: Inbound Linkspeed %d\n", pAdapter->LinkSpeed.Inbound)); TRACEOUT(GetAdapterInfo); return; } UINT AtmLaneCoReceivePacketHandler( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE ProtocolVcContext, IN PNDIS_PACKET pNdisPacket ) /*++ Routine Description: This is routine is called when a packet is received on a VC owned by the ATMLANE module. It is dispatched based on the VC type. Arguments: ProtocolBindingContext - Actually a pointer to our Adapter structure ProtocolVcContext - Actually a pointer to our VC structure pNdisPacket - NDIS packet being received. Return Value: 0 - if packet is a LANE Control Packet or undesired data packet. 1 - if data packet indicated up to protocol. --*/ { PATMLANE_ELAN pElan; PATMLANE_VC pVc; UINT TotalLength; // Total bytes in packet PNDIS_BUFFER pNdisBuffer; // Pointer to first buffer UINT BufferLength; UINT IsNonUnicast; // Is this to a non-unicast destn MAC addr? BOOLEAN RetainIt; // Should we hang on to this packet? static ULONG Count = 0; #if DEBUG_IRQL KIRQL EntryIrql; #endif GET_ENTRY_IRQL(EntryIrql); TRACEIN(CoReceivePacketHandler); pVc = (PATMLANE_VC)ProtocolVcContext; STRUCT_ASSERT(pVc, atmlane_vc); pElan = pVc->pElan; STRUCT_ASSERT(pElan, atmlane_elan); // if ((++Count % 10) == 0) // DBGP((0, "%d Packets Received\n", Count)); DBGP((2, "CoReceivePacketHandler: pVc %x Pkt %x\n", pVc, pNdisPacket)); TRACELOGWRITE((&TraceLog, TL_CORECVPACKET, pNdisPacket, pVc)); // // Initialize // RetainIt = FALSE; // default to discarding received packet if (ELAN_STATE_OPERATIONAL == pElan->AdminState) { switch(pVc->LaneType) { case VC_LANE_TYPE_CONFIG_DIRECT: AtmLaneConfigureResponseHandler(pElan, pVc, pNdisPacket); break; case VC_LANE_TYPE_CONTROL_DIRECT: case VC_LANE_TYPE_CONTROL_DISTRIBUTE: AtmLaneControlPacketHandler(pElan, pVc, pNdisPacket); break; case VC_LANE_TYPE_DATA_DIRECT: case VC_LANE_TYPE_MULTI_SEND: case VC_LANE_TYPE_MULTI_FORWARD: if (ELAN_STATE_OPERATIONAL == pElan->State) { RetainIt = AtmLaneDataPacketHandler(pElan, pVc, pNdisPacket); } else { DBGP((0, "%d Dropping Pkt %x cuz Elan %x state is %d\n", pElan->ElanNumber, pNdisPacket, pElan, pElan->State)); } break; default: DBGP((0, "CoReceivePacketHandler: pVc %x Type UNKNOWN!\n", pVc)); break; } } TRACEOUT(CoReceivePacketHandler); CHECK_EXIT_IRQL(EntryIrql); return (RetainIt); } VOID AtmLaneUnloadProtocol( VOID ) /*++ Routine Description: Unloads the ATMLANE protocol module. We unbind from all adapters, and deregister from NDIS as a protocol. Arguments: None. Return Value: None --*/ { NDIS_STATUS Status; PATMLANE_ADAPTER pAdapter; #if DEBUG_IRQL KIRQL EntryIrql; #endif GET_ENTRY_IRQL(EntryIrql); TRACEIN(UnloadProtocol); Status = NDIS_STATUS_SUCCESS; ACQUIRE_GLOBAL_LOCK(pAtmLaneGlobalInfo); // // Until adapter list is empty... // while (!IsListEmpty(&pAtmLaneGlobalInfo->AdapterList)) { // // Keep grabbing the first one on the list. // pAdapter = CONTAINING_RECORD( pAtmLaneGlobalInfo->AdapterList.Flink, ATMLANE_ADAPTER, Link ); STRUCT_ASSERT(pAdapter, atmlane_adapter); RELEASE_GLOBAL_LOCK(pAtmLaneGlobalInfo); DBGP((3, "UnloadProtocol: will unbind adapter %x\n", pAdapter)); INIT_BLOCK_STRUCT(&(pAtmLaneGlobalInfo->Block)); // // unbind which should delete the adapter struct // and remove it from global list // AtmLaneUnbindAdapterHandler( &Status, (NDIS_HANDLE)pAdapter, (NDIS_HANDLE)NULL // No UnbindContext ==> Don't complete NdisUnbind ); if (NDIS_STATUS_PENDING == Status) { // // Wait for the unbind to complete // (VOID)WAIT_ON_BLOCK_STRUCT(&(pAtmLaneGlobalInfo->Block)); } ACQUIRE_GLOBAL_LOCK(pAtmLaneGlobalInfo); } RELEASE_GLOBAL_LOCK(pAtmLaneGlobalInfo); FREE_GLOBAL_LOCK(pAtmLaneGlobalInfo); FREE_BLOCK_STRUCT(&(pAtmArpGlobalInfo->Block)); #if 0 AuditShutdown(); #endif if (pAtmLaneGlobalInfo->SpecialNdisDeviceHandle) { DBGP((0, "Deregistering device from UnloadProtocol\n")); Status = NdisMDeregisterDevice(pAtmLaneGlobalInfo->SpecialNdisDeviceHandle); pAtmLaneGlobalInfo->SpecialNdisDeviceHandle = NULL; ASSERT(NDIS_STATUS_SUCCESS == Status); } if (pAtmLaneGlobalInfo->NdisProtocolHandle) { DBGP((0, "UnloadProtocol: NdisDeregisterProtocol now, " "NdisProtocolHandle %x\n", pAtmLaneGlobalInfo->NdisProtocolHandle)); NdisDeregisterProtocol( &Status, pAtmLaneGlobalInfo->NdisProtocolHandle ); pAtmLaneGlobalInfo->NdisProtocolHandle = NULL; } ASSERT(NDIS_STATUS_SUCCESS == Status); TRACEIN(UnloadProtocol); CHECK_EXIT_IRQL(EntryIrql); return; } // // Dummy handlers so that a debug build won't complain // VOID AtmLaneSendCompleteHandler( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status ) { } VOID AtmLaneTransferDataCompleteHandler( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status, IN UINT BytesTransferred ) { } NDIS_STATUS AtmLaneReceiveHandler( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE MacReceiveContext, IN PVOID HeaderBuffer, IN UINT HeaderBufferSize, IN PVOID LookAheadBuffer, IN UINT LookaheadBufferSize, IN UINT PacketSize ) { return(NDIS_STATUS_FAILURE); } BOOLEAN AtmLaneIsDeviceAlreadyBound( IN PNDIS_STRING pDeviceName ) /*++ Routine Description: Check if we have already bound to a device (adapter). Arguments: pDeviceName - Points to device name to be checked. Return Value: TRUE iff we already have an Adapter structure representing this device. --*/ { PATMLANE_ADAPTER pAdapter; BOOLEAN bFound = FALSE; PLIST_ENTRY pListEntry; ACQUIRE_GLOBAL_LOCK(pAtmLaneGlobalInfo); for (pListEntry = pAtmLaneGlobalInfo->AdapterList.Flink; pListEntry != &(pAtmLaneGlobalInfo->AdapterList); pListEntry = pListEntry->Flink) { // // Keep grabbing the first one on the list. // pAdapter = CONTAINING_RECORD( pListEntry, ATMLANE_ADAPTER, Link ); if ((pDeviceName->Length == pAdapter->DeviceName.Length) && (memcmp(pDeviceName->Buffer, pAdapter->DeviceName.Buffer, pDeviceName->Length) == 0)) { bFound = TRUE; break; } } RELEASE_GLOBAL_LOCK(pAtmLaneGlobalInfo); return (bFound); }