From: Casper Hornstrup Date: Sun, 27 Aug 2000 16:28:59 +0000 (+0000) Subject: Fixed bugs in TCP/IP driver X-Git-Tag: backups/FreeLoader@12428~588 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=abd30f9819ac295597fe9e45250c508a9f97562d Fixed bugs in TCP/IP driver svn path=/trunk/; revision=1317 --- diff --git a/reactos/drivers/net/tcpip/datalink/arp.c b/reactos/drivers/net/tcpip/datalink/arp.c index 6121918860d..3c7059eed30 100644 --- a/reactos/drivers/net/tcpip/datalink/arp.c +++ b/reactos/drivers/net/tcpip/datalink/arp.c @@ -211,12 +211,16 @@ VOID ARPReceive( Header = (PARP_HEADER)Packet->Header; /* FIXME: Ethernet only */ - if (WN2H(Header->HWType) != 1) + if (WN2H(Header->HWType) != 1) { + TI_DbgPrint(DEBUG_ARP, ("Unknown ARP hardware type (0x%X).\n", WN2H(Header->HWType))); return; + } /* Check protocol type */ - if (Header->ProtoType != ETYPE_IPv4) + if (Header->ProtoType != ETYPE_IPv4) { + TI_DbgPrint(DEBUG_ARP, ("Unknown ARP protocol type (0x%X).\n", WN2H(Header->ProtoType))); return; + } SenderHWAddress = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER)); SenderProtoAddress = (PVOID)((ULONG_PTR)SenderHWAddress + Header->HWAddrLen); @@ -226,16 +230,16 @@ VOID ARPReceive( TargetProtoAddress = (PVOID)((ULONG_PTR)SenderProtoAddress + Header->ProtoAddrLen + Header->HWAddrLen); - Address = AddrBuildIPv4(*(PULONG)(TargetProtoAddress)); + Address = AddrBuildIPv4(*((PULONG)TargetProtoAddress)); ADE = IPLocateADE(Address, ADE_UNICAST); if (!ADE) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + TI_DbgPrint(DEBUG_ARP, ("Target address (0x%X) is not mine.\n", *((PULONG)TargetProtoAddress))); return; } /* Check if we know the sender */ - AddrInitIPv4(Address, *(PULONG)(SenderProtoAddress)); + AddrInitIPv4(Address, *((PULONG)SenderProtoAddress)); NCE = NBLocateNeighbor(Address); if (NCE) { DereferenceObject(Address); @@ -269,8 +273,11 @@ VOID ARPReceive( ARP_OPCODE_REPLY); /* ARP reply */ if (NdisPacket) { PC(NdisPacket)->DLComplete = ARPTransmitComplete; - (*Interface->Transmit)(Interface->Context, NdisPacket, - MaxLLHeaderSize, SenderHWAddress, LAN_PROTO_ARP); + (*Interface->Transmit)(Interface->Context, + NdisPacket, + MaxLLHeaderSize, + SenderHWAddress, + LAN_PROTO_ARP); } } diff --git a/reactos/drivers/net/tcpip/datalink/lan.c b/reactos/drivers/net/tcpip/datalink/lan.c index d940bc615e7..d83ef259d1f 100644 --- a/reactos/drivers/net/tcpip/datalink/lan.c +++ b/reactos/drivers/net/tcpip/datalink/lan.c @@ -18,7 +18,8 @@ NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL; BOOLEAN ProtocolRegistered = FALSE; -PLAN_ADAPTER Adapters = NULL; +LIST_ENTRY AdapterListHead; +KSPIN_LOCK AdapterListLock; NDIS_STATUS NDISCall( @@ -55,12 +56,17 @@ NDIS_STATUS NDISCall( if (Adapter->State != LAN_STATE_RESETTING) { NdisRequest(&NdisStatus, Adapter->NdisHandle, &Request); - } else + } else { NdisStatus = NDIS_STATUS_NOT_ACCEPTED; + } /* Wait for NDIS to complete the request */ if (NdisStatus == NDIS_STATUS_PENDING) { - KeWaitForSingleObject(&Adapter->Event, UserRequest, KernelMode, FALSE, NULL); + KeWaitForSingleObject(&Adapter->Event, + UserRequest, + KernelMode, + FALSE, + NULL); NdisStatus = Adapter->NdisStatus; } @@ -94,7 +100,11 @@ PNDIS_PACKET AllocateTDPacket( return NULL; } - NdisAllocateBuffer(&NdisStatus, &Buffer, GlobalBufferPool, Data, Adapter->MTU); + NdisAllocateBuffer(&NdisStatus, + &Buffer, + GlobalBufferPool, + Data, + Adapter->MTU); if (NdisStatus != NDIS_STATUS_SUCCESS) { NdisFreePacket(NdisPacket); ExFreePool(Data); @@ -157,7 +167,7 @@ VOID ProtocolOpenAdapterComplete( { PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; - TI_DbgPrint(MID_TRACE, ("Called.\n")); + TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); KeSetEvent(&Adapter->Event, 0, FALSE); } @@ -175,7 +185,7 @@ VOID ProtocolCloseAdapterComplete( { PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; - TI_DbgPrint(MID_TRACE, ("Called.\n")); + TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); Adapter->NdisStatus = Status; @@ -211,6 +221,8 @@ VOID ProtocolRequestComplete( { PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; + TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); + /* Save status of request and signal an event */ Adapter->NdisStatus = Status; @@ -230,9 +242,9 @@ VOID ProtocolSendComplete( * Status = Status of the operation */ { - PLAN_ADAPTER Adapter = BindingContext; + PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; - TI_DbgPrint(MAX_TRACE, ("Called.\n")); + TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); AdjustPacket(Packet, Adapter->HeaderSize, PC(Packet)->DLOffset); @@ -260,13 +272,19 @@ VOID ProtocolTransferDataComplete( UINT PacketType; PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; + TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); + if (Status == NDIS_STATUS_SUCCESS) { PNDIS_BUFFER NdisBuffer; IP_PACKET IPPacket; - NdisGetFirstBufferFromPacket( - Packet, &NdisBuffer, &IPPacket.Header, - &IPPacket.ContigSize, &IPPacket.TotalSize); + IPPacket.NdisPacket = Packet; + + NdisGetFirstBufferFromPacket(Packet, + &NdisBuffer, + &IPPacket.Header, + &IPPacket.ContigSize, + &IPPacket.TotalSize); /* Determine which upper layer protocol that should receive this packet and pass it to the correct receive handler */ @@ -318,64 +336,89 @@ NDIS_STATUS ProtocolReceive( USHORT EType; UINT PacketType; IP_PACKET IPPacket; + PNDIS_PACKET NdisPacket; + PNDIS_BUFFER NdisBuffer; PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; PETH_HEADER EHeader = (PETH_HEADER)HeaderBuffer; - TI_DbgPrint(MAX_TRACE, ("Called.\n")); + TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); - if ((Adapter->State != LAN_STATE_STARTED) || - HeaderBufferSize < Adapter->HeaderSize) - /* Adapter is not started or the header was too small */ + if (Adapter->State != LAN_STATE_STARTED) { + TI_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n")); return NDIS_STATUS_NOT_ACCEPTED; + } + + if (HeaderBufferSize < Adapter->HeaderSize) { + TI_DbgPrint(DEBUG_DATALINK, ("Runt frame received.\n")); + return NDIS_STATUS_NOT_ACCEPTED; + } if (Adapter->Media == NdisMedium802_3) { /* Ethernet and IEEE 802.3 frames can be destinguished by looking at the IEEE 802.3 length field. This field is less than or equal to 1500 for a valid IEEE 802.3 frame - and larger than 1500 is it's a valid Ether-Type value. + and larger than 1500 is it's a valid EtherType value. See RFC 1122, section 2.3.3 for more information */ - if (((EType = EHeader->EType) != ETYPE_IPv4) && (EType != ETYPE_ARP)) + /* FIXME: Test for Ethernet and IEEE 802.3 frame */ + if (((EType = EHeader->EType) != ETYPE_IPv4) && (EType != ETYPE_ARP)) { + TI_DbgPrint(DEBUG_DATALINK, ("Not IP or ARP frame. EtherType (0x%X).\n", EType)); return NDIS_STATUS_NOT_ACCEPTED; - /* We use Ether-Type constants to destinguish packets */ + } + /* We use EtherType constants to destinguish packet types */ PacketType = EType; - } else + } else { + TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n")); /* FIXME: Support other medias */ return NDIS_STATUS_NOT_ACCEPTED; + } - if (LookaheadBufferSize < PacketSize) { - NDIS_STATUS NdisStatus; - PNDIS_PACKET NdisPacket; - UINT BytesTransferred; - - /* Get transfer data packet */ - - KeAcquireSpinLockAtDpcLevel(&Adapter->Lock); + /* Get a transfer data packet */ - NdisPacket = Adapter->TDPackets; - if (NdisPacket == (PNDIS_PACKET)NULL) { - /* We don't have a free packet descriptor. Drop the packet */ - KeReleaseSpinLockFromDpcLevel(&Adapter->Lock); - return NDIS_STATUS_SUCCESS; - } - Adapter->TDPackets = PC(NdisPacket)->Context; + KeAcquireSpinLockAtDpcLevel(&Adapter->Lock); + NdisPacket = Adapter->TDPackets; + if (NdisPacket == (PNDIS_PACKET)NULL) { + TI_DbgPrint(DEBUG_DATALINK, ("No available packet descriptors.\n")); + /* We don't have a free packet descriptor. Drop the packet */ KeReleaseSpinLockFromDpcLevel(&Adapter->Lock); + return NDIS_STATUS_SUCCESS; + } + Adapter->TDPackets = PC(NdisPacket)->Context; + + KeReleaseSpinLockFromDpcLevel(&Adapter->Lock); + + if (LookaheadBufferSize < PacketSize) { + NDIS_STATUS NdisStatus; + UINT BytesTransferred; /* Get the data */ - NdisTransferData(&NdisStatus, Adapter->NdisHandle, - MacReceiveContext, 0, PacketSize, - NdisPacket, &BytesTransferred); + NdisTransferData(&NdisStatus, + Adapter->NdisHandle, + MacReceiveContext, + 0, + PacketSize, + NdisPacket, + &BytesTransferred); if (NdisStatus != NDIS_STATUS_PENDING) ProtocolTransferDataComplete(BindingContext, - NdisPacket, NdisStatus, BytesTransferred); + NdisPacket, + NdisStatus, + BytesTransferred); return NDIS_STATUS_SUCCESS; } /* We got all the data in the lookahead buffer */ - RtlZeroMemory(&IPPacket, sizeof(IPPacket)); - IPPacket.Header = LookaheadBuffer; - IPPacket.TotalSize = PacketSize; + + IPPacket.NdisPacket = NdisPacket; + + NdisGetFirstBufferFromPacket(NdisPacket, + &NdisBuffer, + &IPPacket.Header, + &IPPacket.ContigSize, + &IPPacket.TotalSize); + + RtlCopyMemory(IPPacket.Header, LookaheadBuffer, PacketSize); switch (PacketType) { case ETYPE_IPv4: @@ -389,6 +432,14 @@ NDIS_STATUS ProtocolReceive( break; } + /* Release the packet descriptor */ + KeAcquireSpinLockAtDpcLevel(&Adapter->Lock); + + PC(NdisPacket)->Context = Adapter->TDPackets; + Adapter->TDPackets = NdisPacket; + + KeReleaseSpinLockFromDpcLevel(&Adapter->Lock); + return NDIS_STATUS_SUCCESS; } @@ -401,7 +452,7 @@ VOID ProtocolReceiveComplete( * BindingContext = Pointer to a device context (LAN_ADAPTER) */ { - TI_DbgPrint(MID_TRACE, ("Called.\n")); + TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); } @@ -419,7 +470,7 @@ VOID ProtocolStatus( * StatusBufferSize = Number of bytes in StatusBuffer */ { - TI_DbgPrint(MID_TRACE, ("Called.\n")); + TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); } @@ -431,7 +482,7 @@ VOID ProtocolStatusComplete( * BindingContext = Pointer to a device context (LAN_ADAPTER) */ { - TI_DbgPrint(MID_TRACE, ("Called.\n")); + TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); } @@ -456,7 +507,7 @@ VOID LANTransmit( PVOID Data; PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context; - TI_DbgPrint(MAX_TRACE, ("Called.\n")); + TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); /* NDIS send routines don't have an offset argument so we must offset the data in upper layers and adjust the @@ -469,13 +520,14 @@ VOID LANTransmit( switch (Adapter->Media) { case NdisMedium802_3: EHeader = (PETH_HEADER)Data; - - if (LinkAddress) + + if (LinkAddress) { /* Unicast address */ RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH); - else + } else { /* Broadcast address */ RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF); + } RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH); @@ -490,11 +542,13 @@ VOID LANTransmit( EHeader->EType = ETYPE_IPv6; break; default: -#if DBG +#ifdef DBG /* Should not happen */ TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n")); - ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_FAILURE); + ProtocolSendComplete((NDIS_HANDLE)Context, + NdisPacket, + NDIS_STATUS_FAILURE); #endif return; } @@ -504,12 +558,13 @@ VOID LANTransmit( /* FIXME: Support other medias */ break; } - + NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket); if (NdisStatus != NDIS_STATUS_PENDING) ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus); - } else + } else { ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_CLOSED); + } } @@ -532,12 +587,15 @@ VOID BindAdapter( LLIP_BIND_INFO BindInfo; ULONG Lookahead = LOOKAHEAD_SIZE; - TI_DbgPrint(MID_TRACE, ("Called.\n")); + TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); Adapter->State = LAN_STATE_OPENING; - NdisStatus = NDISCall(Adapter, NdisRequestSetInformation, - OID_GEN_CURRENT_LOOKAHEAD, &Lookahead, sizeof(ULONG)); + NdisStatus = NDISCall(Adapter, + NdisRequestSetInformation, + OID_GEN_CURRENT_LOOKAHEAD, + &Lookahead, + sizeof(ULONG)); if (NdisStatus != NDIS_STATUS_SUCCESS) { TI_DbgPrint(MID_TRACE, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus)); return; @@ -551,7 +609,7 @@ VOID BindAdapter( PC(Packet)->Context = Adapter->TDPackets; Adapter->TDPackets = Packet; if (!Packet) { - TI_DbgPrint(MID_TRACE, ("Could not allocate transfer data packet (out of resources).\n")); + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); FreeTDPackets(Adapter); return; } @@ -590,16 +648,19 @@ VOID BindAdapter( return; } - /* Reference the interface for the NTE. The reference for - the address is just passed on to the NTE */ + /* Reference the interface for the NTE. The reference + for the address is just passed on to the NTE */ ReferenceObject(IF); /* Register interface with IP layer */ IPRegisterInterface(IF); /* Set packet filter so we can send and receive packets */ - NdisStatus = NDISCall(Adapter, NdisRequestSetInformation, - OID_GEN_CURRENT_PACKET_FILTER, &Adapter->PacketFilter, sizeof(UINT)); + NdisStatus = NDISCall(Adapter, + NdisRequestSetInformation, + OID_GEN_CURRENT_PACKET_FILTER, + &Adapter->PacketFilter, + sizeof(UINT)); if (NdisStatus != NDIS_STATUS_SUCCESS) { TI_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", NdisStatus)); FreeTDPackets(Adapter); @@ -621,7 +682,7 @@ VOID UnbindAdapter( * Adapter = Pointer to LAN_ADAPTER structure */ { - TI_DbgPrint(MID_TRACE, ("Called.\n")); + TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); if (Adapter->State == LAN_STATE_STARTED) { PIP_INTERFACE IF = Adapter->Context; @@ -656,11 +717,13 @@ NDIS_STATUS LANRegisterAdapter( UINT AddressOID; UINT Speed; - TI_DbgPrint(MAX_TRACE, ("Called.\n")); + TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); IF = ExAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER)); - if (!IF) + if (!IF) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); return NDIS_STATUS_RESOURCES; + } RtlZeroMemory(IF, sizeof(LAN_ADAPTER)); @@ -676,8 +739,17 @@ NDIS_STATUS LANRegisterAdapter( MediaArray[MEDIA_ETH] = NdisMedium802_3; /* Open the adapter. */ - NdisOpenAdapter(&NdisStatus, &OpenStatus, &IF->NdisHandle, &MediaIndex, - MediaArray, MAX_MEDIA, NdisProtocolHandle, IF, AdapterName, 0, NULL); + NdisOpenAdapter(&NdisStatus, + &OpenStatus, + &IF->NdisHandle, + &MediaIndex, + MediaArray, + MAX_MEDIA, + NdisProtocolHandle, + IF, + AdapterName, + 0, + NULL); /* Wait until the adapter is opened */ if (NdisStatus == NDIS_STATUS_PENDING) @@ -713,16 +785,22 @@ NDIS_STATUS LANRegisterAdapter( } /* Get maximum frame size */ - NdisStatus = NDISCall(IF, NdisRequestQueryInformation, - OID_GEN_MAXIMUM_FRAME_SIZE, &IF->MTU, sizeof(UINT)); + NdisStatus = NDISCall(IF, + NdisRequestQueryInformation, + OID_GEN_MAXIMUM_FRAME_SIZE, + &IF->MTU, + sizeof(UINT)); if (NdisStatus != NDIS_STATUS_SUCCESS) { ExFreePool(IF); return NdisStatus; } /* Get maximum packet size */ - NdisStatus = NDISCall(IF, NdisRequestQueryInformation, - OID_GEN_MAXIMUM_TOTAL_SIZE, &IF->MaxPacketSize, sizeof(UINT)); + NdisStatus = NDISCall(IF, + NdisRequestQueryInformation, + OID_GEN_MAXIMUM_TOTAL_SIZE, + &IF->MaxPacketSize, + sizeof(UINT)); if (NdisStatus != NDIS_STATUS_SUCCESS) { TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n")); ExFreePool(IF); @@ -730,16 +808,22 @@ NDIS_STATUS LANRegisterAdapter( } /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */ - NdisStatus = NDISCall(IF, NdisRequestQueryInformation, - OID_GEN_MAXIMUM_SEND_PACKETS, &IF->MaxSendPackets, sizeof(UINT)); + NdisStatus = NDISCall(IF, + NdisRequestQueryInformation, + OID_GEN_MAXIMUM_SEND_PACKETS, + &IF->MaxSendPackets, + sizeof(UINT)); if (NdisStatus != NDIS_STATUS_SUCCESS) /* Legacy NIC drivers may not support this query, if it fails we assume it can send at least one packet per call to NdisSend(Packets) */ IF->MaxSendPackets = 1; /* Get current hardware address */ - NdisStatus = NDISCall(IF, NdisRequestQueryInformation, AddressOID, - IF->HWAddress, IF->HWAddressLength); + NdisStatus = NDISCall(IF, + NdisRequestQueryInformation, + AddressOID, + &IF->HWAddress, + IF->HWAddressLength); if (NdisStatus != NDIS_STATUS_SUCCESS) { TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n")); ExFreePool(IF); @@ -747,8 +831,11 @@ NDIS_STATUS LANRegisterAdapter( } /* Get maximum link speed */ - NdisStatus = NDISCall(IF, NdisRequestQueryInformation, - OID_GEN_LINK_SPEED, &Speed, sizeof(UINT)); + NdisStatus = NDISCall(IF, + NdisRequestQueryInformation, + OID_GEN_LINK_SPEED, + &Speed, + sizeof(UINT)); if (NdisStatus != NDIS_STATUS_SUCCESS) { TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n")); ExFreePool(IF); @@ -761,13 +848,14 @@ NDIS_STATUS LANRegisterAdapter( *Adapter = IF; /* Add adapter to the adapter list */ - IF->Next = Adapters; - Adapters = IF; + ExInterlockedInsertTailList(&AdapterListHead, + &IF->ListEntry, + &AdapterListLock); /* Bind adapter to IP layer */ BindAdapter(IF); - TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); + TI_DbgPrint(DEBUG_DATALINK, ("Leaving.\n")); return NDIS_STATUS_SUCCESS; } @@ -785,35 +873,12 @@ NDIS_STATUS LANUnregisterAdapter( { KIRQL OldIrql; NDIS_HANDLE NdisHandle; - PLAN_ADAPTER IF, PrevIF; - BOOLEAN Found = FALSE; NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - /* Search the adapter list for the specified adapter and remove it */ - IF = Adapters; - if (IF) { - if (Adapter != Adapters) { - PrevIF = IF; - while ((IF) && (!Found)) { - if (IF == Adapter) { - /* We've found the adapter, now remove it from the list */ - PrevIF->Next = IF->Next; - Found = TRUE; - } - PrevIF = IF; - IF = IF->Next; - } - } else { - Adapters = NULL; - Found = TRUE; - } - } - if (!Found) { - TI_DbgPrint(MIN_TRACE, ("Leaving (adapter was not in list).\n")); - return NDIS_STATUS_ADAPTER_NOT_FOUND; - } + TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); + + /* Unlink the adapter from the list */ + RemoveEntryList(&Adapter->ListEntry); /* Unbind adapter from IP layer */ UnbindAdapter(Adapter); @@ -827,7 +892,10 @@ NDIS_STATUS LANUnregisterAdapter( NdisCloseAdapter(&NdisStatus, NdisHandle); if (NdisStatus == NDIS_STATUS_PENDING) { KeWaitForSingleObject(&Adapter->Event, - UserRequest, KernelMode, FALSE, NULL); + UserRequest, + KernelMode, + FALSE, + NULL); NdisStatus = Adapter->NdisStatus; } } else @@ -852,27 +920,33 @@ NTSTATUS LANRegisterProtocol( NDIS_STATUS NdisStatus; NDIS_PROTOCOL_CHARACTERISTICS ProtChars; + TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); + + InitializeListHead(&AdapterListHead); + KeInitializeSpinLock(&AdapterListLock); + /* Set up protocol characteristics */ RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS)); - ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR; - ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR; - ProtChars.Name.Length = Name->Length; - ProtChars.Name.Buffer = (PVOID)Name->Buffer; - ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete; - ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete; - ProtChars.ResetCompleteHandler = ProtocolResetComplete; - ProtChars.RequestCompleteHandler = ProtocolRequestComplete; + ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR; + ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR; + ProtChars.Name.Length = Name->Length; + ProtChars.Name.Buffer = (PVOID)Name->Buffer; + ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete; + ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete; + ProtChars.ResetCompleteHandler = ProtocolResetComplete; + ProtChars.RequestCompleteHandler = ProtocolRequestComplete; ProtChars.u2.SendCompleteHandler = ProtocolSendComplete; ProtChars.u3.TransferDataCompleteHandler = ProtocolTransferDataComplete; ProtChars.u4.ReceiveHandler = ProtocolReceive; - ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete; - ProtChars.StatusHandler = ProtocolStatus; - ProtChars.StatusCompleteHandler = ProtocolStatusComplete; + ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete; + ProtChars.StatusHandler = ProtocolStatus; + ProtChars.StatusCompleteHandler = ProtocolStatusComplete; /* Try to register protocol */ - NdisRegisterProtocol( - &NdisStatus, &NdisProtocolHandle, &ProtChars, - sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + Name->Length); + NdisRegisterProtocol(&NdisStatus, + &NdisProtocolHandle, + &ProtChars, + sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + Name->Length); if (NdisStatus != NDIS_STATUS_SUCCESS) return (NTSTATUS)NdisStatus; @@ -889,11 +963,28 @@ VOID LANUnregisterProtocol( * NOTES: Does not care wether we are already registered */ { + TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); + if (ProtocolRegistered) { NDIS_STATUS NdisStatus; + PLIST_ENTRY CurrentEntry; + PLIST_ENTRY NextEntry; + PLAN_ADAPTER Current; + KIRQL OldIrql; + + KeAcquireSpinLock(&AdapterListLock, &OldIrql); + + /* Search the list and remove every adapter we find */ + CurrentEntry = AdapterListHead.Flink; + while (CurrentEntry != &AdapterListHead) { + NextEntry = CurrentEntry->Flink; + Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry); + /* Unregister it */ + LANUnregisterAdapter(Current); + CurrentEntry = NextEntry; + } - while (Adapters) - NdisStatus = LANUnregisterAdapter(Adapters); + KeReleaseSpinLock(&AdapterListLock, OldIrql); NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle); ProtocolRegistered = FALSE; diff --git a/reactos/drivers/net/tcpip/datalink/loopback.c b/reactos/drivers/net/tcpip/datalink/loopback.c index 89a07abce5d..aa4432da230 100644 --- a/reactos/drivers/net/tcpip/datalink/loopback.c +++ b/reactos/drivers/net/tcpip/datalink/loopback.c @@ -37,8 +37,8 @@ VOID RealTransmit( { KIRQL OldIrql; PNDIS_PACKET NdisPacket; + PNDIS_BUFFER NdisBuffer; IP_PACKET IPPacket; - PNDIS_BUFFER Buffer; TI_DbgPrint(MAX_TRACE, ("Called.\n")); @@ -59,10 +59,10 @@ VOID RealTransmit( IPPacket.NdisPacket = NdisPacket; NdisGetFirstBufferFromPacket(NdisPacket, - &Buffer, - &IPPacket.Header, - &IPPacket.ContigSize, - &IPPacket.TotalSize); + &NdisBuffer, + &IPPacket.Header, + &IPPacket.ContigSize, + &IPPacket.TotalSize); IPReceive(Context, &IPPacket); diff --git a/reactos/drivers/net/tcpip/include/debug.h b/reactos/drivers/net/tcpip/include/debug.h index b86b6209306..d79641c21a2 100644 --- a/reactos/drivers/net/tcpip/include/debug.h +++ b/reactos/drivers/net/tcpip/include/debug.h @@ -20,10 +20,13 @@ #define DEBUG_IRP 0x00000400 #define DEBUG_REFCOUNT 0x00000800 #define DEBUG_ADDRFILE 0x00001000 -#define DEBUG_IP 0x00002000 -#define DEBUG_ROUTER 0x00004000 -#define DEBUG_RCACHE 0x00008000 -#define DEBUG_NCACHE 0x00010000 +#define DEBUG_DATALINK 0x00002000 +#define DEBUG_ARP 0x00004000 +#define DEBUG_IP 0x00008000 +#define DEBUG_ICMP 0x00010000 +#define DEBUG_ROUTER 0x00020000 +#define DEBUG_RCACHE 0x00040000 +#define DEBUG_NCACHE 0x00080000 #define DEBUG_ULTRA 0xFFFFFFFF #ifdef DBG diff --git a/reactos/drivers/net/tcpip/include/lan.h b/reactos/drivers/net/tcpip/include/lan.h index 87b06f842e8..f61e84a779a 100644 --- a/reactos/drivers/net/tcpip/include/lan.h +++ b/reactos/drivers/net/tcpip/include/lan.h @@ -35,7 +35,7 @@ typedef struct ETH_HEADER { /* Per adapter information */ typedef struct LAN_ADAPTER { - struct LAN_ADAPTER *Next; /* Pointer to next adapter */ + LIST_ENTRY ListEntry; /* Entry on list */ KSPIN_LOCK Lock; /* Lock for this structure */ UCHAR State; /* State of the adapter */ KEVENT Event; /* Opening event */ @@ -69,7 +69,7 @@ typedef struct LAN_ADAPTER { #define LOOKAHEAD_SIZE 128 /* Ethernet types. We swap constants so we can compare values at runtime - without swapping them */ + without swapping them there */ #define ETYPE_IPv4 WH2N(0x0800) #define ETYPE_IPv6 WH2N(0x0000) /* FIXME */ #define ETYPE_ARP WH2N(0x0806) @@ -79,8 +79,6 @@ typedef struct LAN_ADAPTER { #define LAN_PROTO_IPv6 0x0001 /* Internet Protocol version 6 */ #define LAN_PROTO_ARP 0x0002 /* Address Resolution Protocol */ -extern PLAN_ADAPTER Adapters; - NDIS_STATUS LANRegisterAdapter( PNDIS_STRING AdapterName, diff --git a/reactos/drivers/net/tcpip/network/icmp.c b/reactos/drivers/net/tcpip/network/icmp.c index 297d69db64f..462292220e0 100644 --- a/reactos/drivers/net/tcpip/network/icmp.c +++ b/reactos/drivers/net/tcpip/network/icmp.c @@ -31,14 +31,12 @@ VOID SendICMPComplete( { PIP_PACKET IPPacket = (PIP_PACKET)Context; - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - TI_DbgPrint(MAX_TRACE, ("Freeing NDIS packet (%X).\n", Packet)); + TI_DbgPrint(DEBUG_ICMP, ("Freeing NDIS packet (%X).\n", Packet)); /* Free packet */ FreeNdisPacket(Packet); - TI_DbgPrint(MAX_TRACE, ("Freeing IP packet at %X.\n", IPPacket)); + TI_DbgPrint(DEBUG_ICMP, ("Freeing IP packet at %X.\n", IPPacket)); PoolFreeBuffer(IPPacket); } @@ -66,14 +64,14 @@ PIP_PACKET PrepareICMPPacket( PVOID DataBuffer; ULONG Size; - TI_DbgPrint(MAX_TRACE, ("Called. DataSize = %d.\n", DataSize)); + TI_DbgPrint(DEBUG_ICMP, ("Called. DataSize (%d).\n", DataSize)); /* Prepare ICMP packet */ IPPacket = PoolAllocateBuffer(sizeof(IP_PACKET)); if (!IPPacket) return NULL; - TI_DbgPrint(MAX_TRACE, ("IPPacket at %X.\n", IPPacket)); + TI_DbgPrint(DEBUG_ICMP, ("IPPacket at (0x%X).\n", IPPacket)); Size = MaxLLHeaderSize + sizeof(IPv4_HEADER) + sizeof(ICMP_HEADER) + DataSize; @@ -83,7 +81,7 @@ PIP_PACKET PrepareICMPPacket( return NULL; } - TI_DbgPrint(MAX_TRACE, ("Size = %d, Data at %X.\n", Size, DataBuffer)); + TI_DbgPrint(DEBUG_ICMP, ("Size (%d). Data at (0x%X).\n", Size, DataBuffer)); /* Allocate NDIS packet */ NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool); @@ -93,7 +91,7 @@ PIP_PACKET PrepareICMPPacket( return NULL; } - TI_DbgPrint(MAX_TRACE, ("NdisPacket at %X.\n", NdisPacket)); + TI_DbgPrint(MAX_TRACE, ("NdisPacket at (0x%X).\n", NdisPacket)); /* Allocate NDIS buffer for maximum link level header and ICMP packet */ NdisAllocateBuffer(&NdisStatus, &NdisBuffer, GlobalBufferPool, @@ -105,7 +103,7 @@ PIP_PACKET PrepareICMPPacket( return NULL; } - TI_DbgPrint(MAX_TRACE, ("NdisBuffer at %X.\n", NdisBuffer)); + TI_DbgPrint(MAX_TRACE, ("NdisBuffer at (0x%X).\n", NdisBuffer)); /* Link NDIS buffer into packet */ NdisChainBufferAtFront(NdisPacket, NdisBuffer); @@ -164,26 +162,24 @@ VOID ICMPReceive( PICMP_HEADER ICMPHeader; PIP_PACKET NewPacket; UINT DataSize; - ULONG Checksum; - TI_DbgPrint(MID_TRACE, ("Called.\n")); + TI_DbgPrint(DEBUG_ICMP, ("Called.\n")); ICMPHeader = (PICMP_HEADER)IPPacket->Data; - TI_DbgPrint(MID_TRACE, ("Size = %d.\n", IPPacket->TotalSize)); + TI_DbgPrint(DEBUG_ICMP, ("Size (%d).\n", IPPacket->TotalSize)); - TI_DbgPrint(MID_TRACE, ("HeaderSize = %d.\n", IPPacket->HeaderSize)); + TI_DbgPrint(DEBUG_ICMP, ("HeaderSize (%d).\n", IPPacket->HeaderSize)); - TI_DbgPrint(MID_TRACE, ("Type = %d.\n", ICMPHeader->Type)); + TI_DbgPrint(DEBUG_ICMP, ("Type (%d).\n", ICMPHeader->Type)); - TI_DbgPrint(MID_TRACE, ("Code = %d.\n", ICMPHeader->Code)); + TI_DbgPrint(DEBUG_ICMP, ("Code (%d).\n", ICMPHeader->Code)); - TI_DbgPrint(MID_TRACE, ("Checksum = %X.\n", ICMPHeader->Checksum)); + TI_DbgPrint(DEBUG_ICMP, ("Checksum (0x%X).\n", ICMPHeader->Checksum)); - /* Checksum ICMP header and data and compare */ - Checksum = DN2H(IPv4Checksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize, 0)); - if (Checksum != 0xFFFF) { - TI_DbgPrint(MIN_TRACE, ("Bad ICMP checksum (0x%X).\n", Checksum)); + /* Checksum ICMP header and data */ + if (!CorrectChecksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize)) { + TI_DbgPrint(DEBUG_ICMP, ("Bad ICMP checksum.\n")); /* Discard packet */ return; } @@ -193,8 +189,10 @@ VOID ICMPReceive( /* Reply with an ICMP echo reply message */ DataSize = IPPacket->TotalSize - IPPacket->HeaderSize - sizeof(ICMP_HEADER); NewPacket = PrepareICMPPacket(NTE, &IPPacket->SrcAddr, DataSize); - if (!NewPacket) + if (!NewPacket) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); return; + } /* Copy ICMP header and data into new packet */ RtlCopyMemory(NewPacket->Data, IPPacket->Data, DataSize + sizeof(ICMP_HEADER)); @@ -204,11 +202,11 @@ VOID ICMPReceive( ICMPTransmit(NTE, NewPacket); - TI_DbgPrint(MID_TRACE, ("Echo reply sent.\n")); + TI_DbgPrint(DEBUG_ICMP, ("Echo reply sent.\n")); return; default: - TI_DbgPrint(MID_TRACE, ("Discarded ICMP datagram of unknown type.\n")); + TI_DbgPrint(DEBUG_ICMP, ("Discarded ICMP datagram of unknown type.\n")); /* Discard packet */ break; } @@ -227,7 +225,7 @@ VOID ICMPTransmit( { PROUTE_CACHE_NODE RCN; - TI_DbgPrint(MID_TRACE, ("Called.\n")); + TI_DbgPrint(DEBUG_ICMP, ("Called.\n")); /* Calculate checksum of ICMP header and data */ ((PICMP_HEADER)IPPacket->Data)->Checksum = (USHORT) @@ -243,10 +241,10 @@ VOID ICMPTransmit( /* We're done with the RCN */ DereferenceObject(RCN); } else { - TI_DbgPrint(MIN_TRACE, ("RCN at 0x%X.\n", RCN)); + TI_DbgPrint(MIN_TRACE, ("RCN at (0x%X).\n", RCN)); /* No route to destination (or no free resources) */ - TI_DbgPrint(MIN_TRACE, ("No route to destination address 0x%X.\n", + TI_DbgPrint(DEBUG_ICMP, ("No route to destination address 0x%X.\n", IPPacket->DstAddr.Address.IPv4Address)); /* Discard packet */ FreeNdisPacket(IPPacket->NdisPacket); @@ -277,15 +275,17 @@ VOID ICMPReply( UINT DataSize; PIP_PACKET NewPacket; - TI_DbgPrint(MID_TRACE, ("Called (Type=%d, Code=%d).\n", Type, Code)); + TI_DbgPrint(DEBUG_ICMP, ("Called. Type (%d) Code (%d).\n", Type, Code)); DataSize = IPPacket->TotalSize; if ((DataSize) > (576 - sizeof(IPv4_HEADER) - sizeof(ICMP_HEADER))) DataSize = 576; NewPacket = PrepareICMPPacket(NTE, &IPPacket->SrcAddr, DataSize); - if (!NewPacket) + if (!NewPacket) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); return; + } RtlCopyMemory((PVOID)((ULONG_PTR)NewPacket->Data + sizeof(ICMP_HEADER)), IPPacket->Header, DataSize); diff --git a/reactos/drivers/net/tcpip/network/ip.c b/reactos/drivers/net/tcpip/network/ip.c index 1ea5af98582..62a321447d3 100644 --- a/reactos/drivers/net/tcpip/network/ip.c +++ b/reactos/drivers/net/tcpip/network/ip.c @@ -549,7 +549,7 @@ PADDRESS_ENTRY IPGetDefaultADE( PLIST_ENTRY CurrentADEEntry; PIP_INTERFACE CurrentIF; PADDRESS_ENTRY CurrentADE; -#if 0 +#if 1 BOOLEAN LoopbackIsRegistered = FALSE; #endif TI_DbgPrint(DEBUG_IP, ("Called. AddressType (0x%X).\n", AddressType)); @@ -560,7 +560,7 @@ PADDRESS_ENTRY IPGetDefaultADE( CurrentIFEntry = InterfaceListHead.Flink; while (CurrentIFEntry != &InterfaceListHead) { CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry); -#if 0 +#if 1 if (CurrentIF != Loopback) { #endif /* Search the address entry list and return the first appropriate ADE found */ @@ -573,13 +573,13 @@ PADDRESS_ENTRY IPGetDefaultADE( return CurrentADE; } CurrentADEEntry = CurrentADEEntry->Flink; -#if 0 +#if 1 } else LoopbackIsRegistered = TRUE; #endif CurrentIFEntry = CurrentIFEntry->Flink; } -#if 0 +#if 1 /* No address was found. Use loopback interface if available */ if (LoopbackIsRegistered) { CurrentADEEntry = Loopback->ADEListHead.Flink; @@ -671,19 +671,27 @@ PIP_INTERFACE IPCreateInterface( TI_DbgPrint(DEBUG_IP, ("Called. BindInfo (0x%X).\n", BindInfo)); +#ifdef DBG + if (BindInfo->Address) { + PUCHAR A = BindInfo->Address; + TI_DbgPrint(DEBUG_IP, ("Interface address (%02X %02X %02X %02X %02X %02X).\n", + A[0], A[1], A[2], A[3], A[4], A[5])); + } +#endif + IF = PoolAllocateBuffer(sizeof(IP_INTERFACE)); if (!IF) { TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); return NULL; } - IF->RefCount = 1; - IF->Context = BindInfo->Context; - IF->HeaderSize = BindInfo->HeaderSize; + IF->RefCount = 1; + IF->Context = BindInfo->Context; + IF->HeaderSize = BindInfo->HeaderSize; if (IF->HeaderSize > MaxLLHeaderSize) MaxLLHeaderSize = IF->HeaderSize; - IF->MinFrameSize = BindInfo->MinFrameSize; + IF->MinFrameSize = BindInfo->MinFrameSize; if (IF->MinFrameSize > MinLLFrameSize) MinLLFrameSize = IF->MinFrameSize; diff --git a/reactos/drivers/net/tcpip/network/transmit.c b/reactos/drivers/net/tcpip/network/transmit.c index 3bcdf29fc16..a69938d091e 100644 --- a/reactos/drivers/net/tcpip/network/transmit.c +++ b/reactos/drivers/net/tcpip/network/transmit.c @@ -270,8 +270,11 @@ NTSTATUS IPSendFragment( } PC(NdisPacket)->DLComplete = IPSendComplete; - (*NCE->Interface->Transmit)(NCE->Interface->Context, NdisPacket, - MaxLLHeaderSize, NCE->LinkAddress, LAN_PROTO_IPv4); + (*NCE->Interface->Transmit)(NCE->Interface->Context, + NdisPacket, + MaxLLHeaderSize, + NCE->LinkAddress, + LAN_PROTO_IPv4); return STATUS_SUCCESS; } diff --git a/reactos/drivers/net/tcpip/tcpip/main.c b/reactos/drivers/net/tcpip/tcpip/main.c index 0dab08f29b5..bbd2c66f49e 100644 --- a/reactos/drivers/net/tcpip/tcpip/main.c +++ b/reactos/drivers/net/tcpip/tcpip/main.c @@ -18,8 +18,10 @@ #ifdef DBG + /* See debug.h for debug/trace constants */ DWORD DebugTraceLevel = MIN_TRACE; + #endif /* DBG */ PDEVICE_OBJECT TCPDeviceObject = NULL; @@ -525,11 +527,11 @@ VOID TiUnload( * DriverObject = Pointer to driver object created by the system */ { -#ifdef BDG +#ifdef DBG KIRQL OldIrql; KeAcquireSpinLock(&AddressFileListLock, &OldIrql); - if (!IsListEmpty(AddressFileList)) { + if (!IsListEmpty(&AddressFileListHead)) { TI_DbgPrint(MIN_TRACE, ("Open address file objects exists.\n")); } KeReleaseSpinLock(&AddressFileListLock, OldIrql); @@ -539,9 +541,7 @@ VOID TiUnload( LoopUnregisterAdapter(NULL); /* Unregister protocol with NDIS */ -#ifdef _MSC_VER LANUnregisterProtocol(); -#endif /* Shutdown transport level protocol subsystems */ TCPShutdown(); @@ -601,13 +601,13 @@ DriverEntry( UNICODE_STRING strDeviceName; STRING strNdisDeviceName; NDIS_STATUS NdisStatus; -#ifdef _MSC_VER PLAN_ADAPTER Adapter; NDIS_STRING DeviceName; -#endif TI_DbgPrint(MAX_TRACE, ("Called.\n")); + /* FIXME: Create symbolic links in Win32 namespace */ + /* Create IP device object */ RtlInitUnicodeString(&strDeviceName, DD_IP_DEVICE_NAME); Status = IoCreateDevice(DriverObject, 0, &strDeviceName, @@ -700,22 +700,22 @@ DriverEntry( TiUnload(DriverObject); return STATUS_INSUFFICIENT_RESOURCES; } + #if 1 -#ifdef _MSC_VER /* Open underlying adapter(s) we are bound to */ /* FIXME: Get binding information from registry */ /* Put your own NDIS adapter device name here */ -#if 0 + /* ReactOS */ + NdisInitUnicodeString(&DeviceName, L"\\Device\\ne2000"); + /* NT4 */ - NdisInitUnicodeString(&DeviceName, L"\\Device\\El90x1"); -#else + //NdisInitUnicodeString(&DeviceName, L"\\Device\\El90x1"); + /* NT5 */ - NdisInitUnicodeString(&DeviceName, - L"\\Device\\{56388B49-67BB-4419-A3F4-28DF190B9149}"); -#endif + //NdisInitUnicodeString(&DeviceName, L"\\Device\\{56388B49-67BB-4419-A3F4-28DF190B9149}"); NdisStatus = LANRegisterAdapter(&DeviceName, &Adapter); if (!NT_SUCCESS(NdisStatus)) { @@ -732,7 +732,7 @@ DriverEntry( return STATUS_DEVICE_DOES_NOT_EXIST; } #endif -#endif + /* Setup network layer and transport layer entities */ EntityList = ExAllocatePool(NonPagedPool, sizeof(TDIEntityID) * 2); if (!NT_SUCCESS(Status)) { diff --git a/reactos/drivers/net/tcpip/transport/udp/udp.c b/reactos/drivers/net/tcpip/transport/udp/udp.c index 10e931b91bb..a30fa0d555d 100644 --- a/reactos/drivers/net/tcpip/transport/udp/udp.c +++ b/reactos/drivers/net/tcpip/transport/udp/udp.c @@ -351,6 +351,9 @@ VOID UDPReceive( /* FIXME: IPv6 is not supported */ return; + + default: + return; } UDPHeader = (PUDP_HEADER)IPPacket->Data; diff --git a/reactos/drivers/net/tditest/tditest/tditest.c b/reactos/drivers/net/tditest/tditest/tditest.c index 709e8f5a350..e0c57160920 100644 --- a/reactos/drivers/net/tditest/tditest/tditest.c +++ b/reactos/drivers/net/tditest/tditest/tditest.c @@ -422,8 +422,14 @@ NTSTATUS TdiQueryAddress( break; } - /* Select the first address returned */ - *Address = DN2H(IpAddress->Addr); + if (SnmpInfo.NumAddr != 1) { + /* Skip loopback address */ + *Address = DN2H(((PIPADDR_ENTRY)((ULONG)IpAddress + sizeof(IPADDR_ENTRY)))->Addr); + } else { + /* Select the first address returned */ + *Address = DN2H(IpAddress->Addr); + } + ExFreePool(IpAddress); } else { Status = STATUS_UNSUCCESSFUL;