Exemple #1
0
static
void
LibTCPEmptyQueue(PCONNECTION_ENDPOINT Connection)
{
    PLIST_ENTRY Entry;
    PQUEUE_ENTRY qp = NULL;

    ReferenceObject(Connection);

    while (!IsListEmpty(&Connection->PacketQueue))
    {
        Entry = RemoveHeadList(&Connection->PacketQueue);
        qp = CONTAINING_RECORD(Entry, QUEUE_ENTRY, ListEntry);

        /* We're in the tcpip thread here so this is safe */
        pbuf_free(qp->p);

        ExFreeToNPagedLookasideList(&QueueEntryLookasideList, qp);
    }

    DereferenceObject(Connection);
}
Exemple #2
0
/*
 * FUNCTION: Searches through address file entries to find the first match
 * ARGUMENTS:
 *     Address       = IP address
 *     Port          = Port number
 *     Protocol      = Protocol number
 *     SearchContext = Pointer to search context
 * RETURNS:
 *     Pointer to address file, NULL if none was found
 */
PADDRESS_FILE AddrSearchFirst(
    PIP_ADDRESS Address,
    USHORT Port,
    USHORT Protocol,
    PAF_SEARCH SearchContext)
{
    KIRQL OldIrql;
    
    SearchContext->Address  = Address;
    SearchContext->Port     = Port;
    SearchContext->Protocol = Protocol;

    TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);

    SearchContext->Next = AddressFileListHead.Flink;

    if (!IsListEmpty(&AddressFileListHead))
        ReferenceObject(CONTAINING_RECORD(SearchContext->Next, ADDRESS_FILE, ListEntry));

    TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);

    return AddrSearchNext(SearchContext);
}
Exemple #3
0
DLC_STATUS
LlcOpenStation(
    IN PBINDING_CONTEXT pBindingContext,
    IN PVOID hClientHandle,
    IN USHORT ObjectAddress,
    IN UCHAR ObjectType,
    IN USHORT OpenOptions,
    OUT PVOID* phStation
    )

/*++

Routine Description:

    The primitive opens a LLC SAP exclusively for the upper protocol
    driver. The upper protocol must provide the storage for the
    SAP object. The correct size of the object has been defined in the
    characteristics table of the LLC driver.

    The first call to a new adapter initializes also the NDIS interface
    and allocates internal data structures for the new adapter.

Arguments:

    pBindingContext - binding context of the llc client
    hClientHandle   - The client protocol gets this handle in all indications
                      of the SAP
    ObjectAddress   - LLC SAP number or dix
    ObjectType      - type of the created object
    OpenOptions     - various open options set for the new object
    phStation       - returned opaque handle

Special:  Must be called IRQL < DPC (at least when direct station opened)

Return Value:

    DLC_STATUS
        Success - STATUS_SUCCESS
        Failure - DLC_STATUS_NO_MEMORY
                  DLC_STATUS_INVALID_SAP_VALUE
                  DLC_STATUS_INVALID_OPTION
                  DLC_STATUS_INVALID_STATION_ID

--*/

{
    PADAPTER_CONTEXT pAdapterContext;
    PLLC_OBJECT pStation;
    DLC_STATUS LlcStatus = STATUS_SUCCESS;
    PVOID* ppListBase;
    ULONG PacketFilter;

#if DBG
    PDLC_FILE_CONTEXT pFileContext = (PDLC_FILE_CONTEXT)(pBindingContext->hClientContext);
#endif

    pAdapterContext = pBindingContext->pAdapterContext;

    //
    // Allocate and initialize the SAP, but do not yet connect
    // it to the adapter
    //

    ASSERT(ObjectSizes[ObjectType] != (USHORT)(-1));

    pStation = (PLLC_OBJECT)ALLOCATE_ZEROMEMORY_FILE(ObjectSizes[ObjectType]);

    if (pStation == NULL) {
        return DLC_STATUS_NO_MEMORY;
    }
    if (ObjectType == LLC_SAP_OBJECT && (ObjectAddress & 1)) {
        ObjectType = LLC_GROUP_SAP_OBJECT;
        ASSERT(phStation);
    }

    pStation->Gen.hClientHandle = hClientHandle;
    pStation->Gen.pLlcBinding = pBindingContext;
    pStation->Gen.pAdapterContext = pAdapterContext;
    pStation->Gen.ObjectType = (UCHAR)ObjectType;

    //
    // The LLC objects must be referenced whenever they should be kept alive
    // over a long operation, that opens the spin locks (especially async
    // operations)
    // The first reference is for open/close
    //

    ReferenceObject(pStation);

    //
    // These values are common for SAP, direct (and DIX objects)
    //

    pStation->Sap.OpenOptions = OpenOptions;
    pStation->Dix.ObjectAddress = ObjectAddress;

    ACQUIRE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);

    switch (pStation->Gen.ObjectType) {
    case LLC_SAP_OBJECT:

        //
        // RLF 05/13/93
        //
        // don't allow multiple applications to open the same SAP. This is
        // incompatible with OS/2 DLC
        //

        if (pAdapterContext->apSapBindings[ObjectAddress] == NULL) {
            ppListBase = (PVOID*)&(pAdapterContext->apSapBindings[ObjectAddress]);
            LlcMemCpy(&pStation->Sap.DefaultParameters,
                      &DefaultParameters,
                      sizeof(DefaultParameters)
                      );

            ALLOCATE_SPIN_LOCK(&pStation->Sap.FlowControlLock);

        } else {

            FREE_MEMORY_FILE(pStation);

            RELEASE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);

            return DLC_STATUS_INVALID_SAP_VALUE;
        }
        break;

    case LLC_GROUP_SAP_OBJECT:
        ppListBase = (PVOID*)&(pAdapterContext->apSapBindings[ObjectAddress]);

        //
        // All members of the same group/individual SAP muust have set
        // the same XID handling option
        //

        if (pAdapterContext->apSapBindings[ObjectAddress] != NULL) {
            if ((OpenOptions & LLC_EXCLUSIVE_ACCESS)
            || (pAdapterContext->apSapBindings[ObjectAddress]->OpenOptions
                  & LLC_EXCLUSIVE_ACCESS)) {
                LlcStatus = DLC_STATUS_INVALID_SAP_VALUE;
            } else if ((pAdapterContext->apSapBindings[ObjectAddress]->OpenOptions &
                  LLC_HANDLE_XID_COMMANDS) != (OpenOptions & LLC_HANDLE_XID_COMMANDS)) {
                LlcStatus = DLC_STATUS_INVALID_OPTION;
            }
        }

        ALLOCATE_SPIN_LOCK(&pStation->Sap.FlowControlLock);

        break;

    case LLC_DIRECT_OBJECT:
        ppListBase = (PVOID*)&pAdapterContext->pDirectStation;
        break;

    case LLC_DIX_OBJECT:
        if (pAdapterContext->NdisMedium != NdisMedium802_3) {
            LlcStatus = DLC_STATUS_INVALID_STATION_ID;
        } else {
            ppListBase = (PVOID*)&(pAdapterContext->aDixStations[ObjectAddress % MAX_DIX_TABLE]);
        }
        break;

#if LLC_DBG
    default:
        LlcInvalidObjectType();
        break;
#endif
    }

    if (LlcStatus == STATUS_SUCCESS) {
        pStation->Gen.pNext = *ppListBase;
        *phStation = *ppListBase = pStation;

        pAdapterContext->ObjectCount++;
    } else {

        FREE_MEMORY_FILE(pStation);

    }

    RELEASE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);

    if (LlcStatus == STATUS_SUCCESS
    && pStation->Gen.ObjectType == LLC_DIRECT_OBJECT
    && OpenOptions & DLC_RCV_MAC_FRAMES
    && !(pAdapterContext->OpenOptions & DLC_RCV_MAC_FRAMES)) {

        //
        // We enable the MAC frames, if they have once been enabled,
        // but they will never be disabled again.  The receiving
        // of MAC frames is quite exceptional case, and it is
        // not really worth of it to maintain local and global
        // Ndis flag states just because of it
        //

        PacketFilter = NDIS_PACKET_TYPE_DIRECTED
                     | NDIS_PACKET_TYPE_MULTICAST
                     | NDIS_PACKET_TYPE_FUNCTIONAL
                     | NDIS_PACKET_TYPE_MAC_FRAME;

        pAdapterContext->OpenOptions |= DLC_RCV_MAC_FRAMES;
        LlcStatus = SetNdisParameter(pAdapterContext,
                                     OID_GEN_CURRENT_PACKET_FILTER,
                                     &PacketFilter,
                                     sizeof(PacketFilter)
                                     );
    }
    return LlcStatus;
}
Exemple #4
0
/*
 * FUNCTION: Searches through address file entries to find next match
 * ARGUMENTS:
 *     SearchContext = Pointer to search context
 * RETURNS:
 *     Pointer to referenced address file, NULL if none was found
 */
PADDRESS_FILE AddrSearchNext(
    PAF_SEARCH SearchContext)
{
    PLIST_ENTRY CurrentEntry;
    PIP_ADDRESS IPAddress;
    KIRQL OldIrql;
    PADDRESS_FILE Current = NULL;
    BOOLEAN Found = FALSE;
    PADDRESS_FILE StartingAddrFile;
    
    TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);

    if (SearchContext->Next == &AddressFileListHead)
    {
        TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
        return NULL;
    }

    /* Save this pointer so we can dereference it later */
    StartingAddrFile = CONTAINING_RECORD(SearchContext->Next, ADDRESS_FILE, ListEntry);

    CurrentEntry = SearchContext->Next;

    while (CurrentEntry != &AddressFileListHead) {
        Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry);

        IPAddress = &Current->Address;

        TI_DbgPrint(DEBUG_ADDRFILE, ("Comparing: ((%d, %d, %s), (%d, %d, %s)).\n",
            WN2H(Current->Port),
            Current->Protocol,
            A2S(IPAddress),
            WN2H(SearchContext->Port),
            SearchContext->Protocol,
            A2S(SearchContext->Address)));

        /* See if this address matches the search criteria */
        if ((Current->Port    == SearchContext->Port) &&
            (Current->Protocol == SearchContext->Protocol) &&
            (AddrReceiveMatch(IPAddress, SearchContext->Address))) {
            /* We've found a match */
            Found = TRUE;
            break;
        }
        CurrentEntry = CurrentEntry->Flink;
    }

    if (Found)
    {
        SearchContext->Next = CurrentEntry->Flink;

        if (SearchContext->Next != &AddressFileListHead)
        {
            /* Reference the next address file to prevent the link from disappearing behind our back */
            ReferenceObject(CONTAINING_RECORD(SearchContext->Next, ADDRESS_FILE, ListEntry));
        }

        /* Reference the returned address file before dereferencing the starting
         * address file because it may be that Current == StartingAddrFile */
        ReferenceObject(Current);
    }
    else
        Current = NULL;

    DereferenceObject(StartingAddrFile);

    TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);

    return Current;
}
Exemple #5
0
NTSTATUS DispTdiListen(
  PIRP Irp)
/*
 * FUNCTION: TDI_LISTEN handler
 * ARGUMENTS:
 *     Irp = Pointer to an I/O request packet
 * RETURNS:
 *     Status of operation
 */
{
  PCONNECTION_ENDPOINT Connection;
  PTDI_REQUEST_KERNEL Parameters;
  PTRANSPORT_CONTEXT TranContext;
  PIO_STACK_LOCATION IrpSp;
  NTSTATUS Status = STATUS_SUCCESS;
  KIRQL OldIrql;

  TI_DbgPrint(DEBUG_IRP, ("Called.\n"));

  IrpSp = IoGetCurrentIrpStackLocation(Irp);

  /* Get associated connection endpoint file object. Quit if none exists */

  TranContext = IrpSp->FileObject->FsContext;
  if (TranContext == NULL)
    {
      TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
      Status = STATUS_INVALID_PARAMETER;
      goto done;
    }

  Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
  if (Connection == NULL)
    {
      TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
      Status = STATUS_INVALID_PARAMETER;
      goto done;
    }

  Parameters = (PTDI_REQUEST_KERNEL)&IrpSp->Parameters;

  Status = DispPrepareIrpForCancel
      (TranContext->Handle.ConnectionContext,
       Irp,
       (PDRIVER_CANCEL)DispCancelListenRequest);

  LockObject(Connection, &OldIrql);

  if (Connection->AddressFile == NULL)
  {
     TI_DbgPrint(MID_TRACE, ("No associated address file\n"));
     UnlockObject(Connection, OldIrql);
     Status = STATUS_INVALID_PARAMETER;
     goto done;
  }

  LockObjectAtDpcLevel(Connection->AddressFile);

  /* Listening will require us to create a listening socket and store it in
   * the address file.  It will be signalled, and attempt to complete an irp
   * when a new connection arrives. */
  /* The important thing to note here is that the irp we'll complete belongs
   * to the socket to be accepted onto, not the listener */
  if( NT_SUCCESS(Status) && !Connection->AddressFile->Listener ) {
      Connection->AddressFile->Listener =
	  TCPAllocateConnectionEndpoint( NULL );

      if( !Connection->AddressFile->Listener )
	  Status = STATUS_NO_MEMORY;

      if( NT_SUCCESS(Status) ) {
          ReferenceObject(Connection->AddressFile);
	  Connection->AddressFile->Listener->AddressFile =
	      Connection->AddressFile;

	  Status = TCPSocket( Connection->AddressFile->Listener,
			      Connection->AddressFile->Family,
			      SOCK_STREAM,
			      Connection->AddressFile->Protocol );
      }

      if( NT_SUCCESS(Status) ) {
	  ReferenceObject(Connection->AddressFile->Listener);
	  Status = TCPListen( Connection->AddressFile->Listener, 1024 );
	  /* BACKLOG */
      }
  }

  if( NT_SUCCESS(Status) ) {
      Status = TCPAccept
	  ( (PTDI_REQUEST)Parameters,
	    Connection->AddressFile->Listener,
	    Connection,
	    DispDataRequestComplete,
	    Irp );
  }

  UnlockObjectFromDpcLevel(Connection->AddressFile);
  UnlockObject(Connection, OldIrql);

done:
  if (Status != STATUS_PENDING) {
      DispDataRequestComplete(Irp, Status, 0);
  } else
      IoMarkIrpPending(Irp);

  TI_DbgPrint(MID_TRACE,("Leaving %x\n", Status));

  return Status;
}
Exemple #6
0
NTSTATUS DispTdiAssociateAddress(
    PIRP Irp)
/*
 * FUNCTION: TDI_ASSOCIATE_ADDRESS handler
 * ARGUMENTS:
 *     Irp = Pointer to an I/O request packet
 * RETURNS:
 *     Status of operation
 */
{
  PTDI_REQUEST_KERNEL_ASSOCIATE Parameters;
  PTRANSPORT_CONTEXT TranContext;
  PIO_STACK_LOCATION IrpSp;
  PCONNECTION_ENDPOINT Connection, LastConnection;
  PFILE_OBJECT FileObject;
  PADDRESS_FILE AddrFile = NULL;
  NTSTATUS Status;
  KIRQL OldIrql;

  TI_DbgPrint(DEBUG_IRP, ("Called.\n"));

  IrpSp = IoGetCurrentIrpStackLocation(Irp);

  /* Get associated connection endpoint file object. Quit if none exists */

  TranContext = IrpSp->FileObject->FsContext;
  if (!TranContext) {
    TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
    return STATUS_INVALID_PARAMETER;
  }

  Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
  if (!Connection) {
    TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
    return STATUS_INVALID_PARAMETER;
  }

  Parameters = (PTDI_REQUEST_KERNEL_ASSOCIATE)&IrpSp->Parameters;

  Status = ObReferenceObjectByHandle(
    Parameters->AddressHandle,
    0,
    *IoFileObjectType,
    KernelMode,
    (PVOID*)&FileObject,
    NULL);
  if (!NT_SUCCESS(Status)) {
    TI_DbgPrint(MID_TRACE, ("Bad address file object handle (0x%X): %x.\n",
      Parameters->AddressHandle, Status));
    return STATUS_INVALID_PARAMETER;
  }

  LockObject(Connection, &OldIrql);

  if (Connection->AddressFile) {
    ObDereferenceObject(FileObject);
    UnlockObject(Connection, OldIrql);
    TI_DbgPrint(MID_TRACE, ("An address file is already asscociated.\n"));
    return STATUS_INVALID_PARAMETER;
  }

  if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
    ObDereferenceObject(FileObject);
    UnlockObject(Connection, OldIrql);
    TI_DbgPrint(MID_TRACE, ("Bad address file object. Magic (0x%X).\n",
      FileObject->FsContext2));
    return STATUS_INVALID_PARAMETER;
  }

  /* Get associated address file object. Quit if none exists */

  TranContext = FileObject->FsContext;
  if (!TranContext) {
    ObDereferenceObject(FileObject);
    UnlockObject(Connection, OldIrql);
    TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
    return STATUS_INVALID_PARAMETER;
  }

  AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle;
  if (!AddrFile) {
      UnlockObject(Connection, OldIrql);
      ObDereferenceObject(FileObject);
      TI_DbgPrint(MID_TRACE, ("No address file object.\n"));
      return STATUS_INVALID_PARAMETER;
  }

  LockObjectAtDpcLevel(AddrFile);

  ReferenceObject(AddrFile);
  Connection->AddressFile = AddrFile;

  /* Add connection endpoint to the address file */
  ReferenceObject(Connection);
  if (AddrFile->Connection == NULL)
      AddrFile->Connection = Connection;
  else
  {
      LastConnection = AddrFile->Connection;
      while (LastConnection->Next != NULL)
         LastConnection = LastConnection->Next;
      LastConnection->Next = Connection;
  }

  ObDereferenceObject(FileObject);

  UnlockObjectFromDpcLevel(AddrFile);
  UnlockObject(Connection, OldIrql);

  return STATUS_SUCCESS;
}
Exemple #7
0
NTSTATUS TCPDisconnect
( PCONNECTION_ENDPOINT Connection,
  UINT Flags,
  PLARGE_INTEGER Timeout,
  PTDI_CONNECTION_INFORMATION ConnInfo,
  PTDI_CONNECTION_INFORMATION ReturnInfo,
  PTCP_COMPLETION_ROUTINE Complete,
  PVOID Context )
{
    NTSTATUS Status = STATUS_INVALID_PARAMETER;
    PTDI_BUCKET Bucket;
    KIRQL OldIrql;
    LARGE_INTEGER ActualTimeout;

    TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Called\n"));

    LockObject(Connection, &OldIrql);

    if (Connection->SocketContext)
    {
        if (Flags & TDI_DISCONNECT_RELEASE)
        {
            if (IsListEmpty(&Connection->SendRequest))
            {
                Status = TCPTranslateError(LibTCPShutdown(Connection, 0, 1));
            }
            else if (Timeout && Timeout->QuadPart == 0)
            {
                FlushSendQueue(Connection, STATUS_FILE_CLOSED, FALSE);
                TCPTranslateError(LibTCPShutdown(Connection, 0, 1));
                Status = STATUS_TIMEOUT;
            }
            else 
            {
                /* Use the timeout specified or 1 second if none was specified */
                if (Timeout)
                {
                    ActualTimeout = *Timeout;
                }
                else
                {
                    ActualTimeout.QuadPart = -1000000;
                }

                /* We couldn't complete the request now because we need to wait for outstanding I/O */
                Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
                if (!Bucket)
                {
                    UnlockObject(Connection, OldIrql);
                    return STATUS_NO_MEMORY;
                }

                Bucket->Request.RequestNotifyObject = (PVOID)Complete;
                Bucket->Request.RequestContext = Context;

                InsertTailList(&Connection->ShutdownRequest, &Bucket->Entry);

                ReferenceObject(Connection);
                if (KeCancelTimer(&Connection->DisconnectTimer))
                {
                    DereferenceObject(Connection);
                }
                KeSetTimer(&Connection->DisconnectTimer, ActualTimeout, &Connection->DisconnectDpc);

                Status = STATUS_PENDING;
            }
        }

        if ((Flags & TDI_DISCONNECT_ABORT) || !Flags)
        {
            FlushReceiveQueue(Connection, STATUS_FILE_CLOSED, FALSE);
            FlushSendQueue(Connection, STATUS_FILE_CLOSED, FALSE);
            FlushShutdownQueue(Connection, STATUS_FILE_CLOSED, FALSE);
            Status = TCPTranslateError(LibTCPShutdown(Connection, 1, 1));
        }
    }
    else
    {
        /* We already got closed by the other side so just return success */
        Status = STATUS_SUCCESS;
    }

    UnlockObject(Connection, OldIrql);

    TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Leaving. Status = 0x%x\n", Status));

    return Status;
}