+NTSTATUS NTAPI
+AfdGetDisconnectOptions(PDEVICE_OBJECT DeviceObject, PIRP Irp,
+ PIO_STACK_LOCATION IrpSp)
+{
+ PFILE_OBJECT FileObject = IrpSp->FileObject;
+ PAFD_FCB FCB = FileObject->FsContext;
+ UINT BufferSize = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ if (!SocketAcquireStateLock(FCB)) return LostSocket(Irp);
+
+ if (FCB->DisconnectOptionsSize == 0)
+ return UnlockAndMaybeComplete(FCB, STATUS_INVALID_PARAMETER, Irp, 0);
+
+ ASSERT(FCB->DisconnectOptions);
+
+ if (FCB->FilledDisconnectOptions < BufferSize) BufferSize = FCB->FilledDisconnectOptions;
+
+ RtlCopyMemory(Irp->UserBuffer,
+ FCB->DisconnectOptions,
+ BufferSize);
+
+ return UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, BufferSize);
+}
+
+NTSTATUS
+NTAPI
+AfdSetDisconnectOptions(PDEVICE_OBJECT DeviceObject, PIRP Irp,
+ PIO_STACK_LOCATION IrpSp)
+{
+ PFILE_OBJECT FileObject = IrpSp->FileObject;
+ PAFD_FCB FCB = FileObject->FsContext;
+ PVOID DisconnectOptions = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+ UINT DisconnectOptionsSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+
+ if (!SocketAcquireStateLock(FCB)) return LostSocket(Irp);
+
+ if (FCB->DisconnectOptions)
+ {
+ ExFreePool(FCB->DisconnectOptions);
+ FCB->DisconnectOptions = NULL;
+ FCB->DisconnectOptionsSize = 0;
+ FCB->FilledDisconnectOptions = 0;
+ }
+
+ FCB->DisconnectOptions = ExAllocatePool(PagedPool, DisconnectOptionsSize);
+ if (!FCB->DisconnectOptions) return UnlockAndMaybeComplete(FCB, STATUS_NO_MEMORY, Irp, 0);
+
+ RtlCopyMemory(FCB->DisconnectOptions,
+ DisconnectOptions,
+ DisconnectOptionsSize);
+
+ FCB->DisconnectOptionsSize = DisconnectOptionsSize;
+
+ return UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, 0);
+}
+
+NTSTATUS
+NTAPI
+AfdSetDisconnectOptionsSize(PDEVICE_OBJECT DeviceObject, PIRP Irp,
+ PIO_STACK_LOCATION IrpSp)
+{
+ PFILE_OBJECT FileObject = IrpSp->FileObject;
+ PAFD_FCB FCB = FileObject->FsContext;
+ PUINT DisconnectOptionsSize = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+ UINT BufferSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+
+ if (!SocketAcquireStateLock(FCB)) return LostSocket(Irp);
+
+ if (BufferSize < sizeof(UINT))
+ return UnlockAndMaybeComplete(FCB, STATUS_BUFFER_TOO_SMALL, Irp, 0);
+
+ if (FCB->DisconnectOptions)
+ {
+ ExFreePool(FCB->DisconnectOptions);
+ FCB->DisconnectOptionsSize = 0;
+ FCB->FilledDisconnectOptions = 0;
+ }
+
+ FCB->DisconnectOptions = ExAllocatePool(PagedPool, *DisconnectOptionsSize);
+ if (!FCB->DisconnectOptions) return UnlockAndMaybeComplete(FCB, STATUS_NO_MEMORY, Irp, 0);
+
+ FCB->DisconnectOptionsSize = *DisconnectOptionsSize;
+
+ return UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, 0);
+}
+
+NTSTATUS NTAPI
+AfdGetDisconnectData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
+ PIO_STACK_LOCATION IrpSp)
+{
+ PFILE_OBJECT FileObject = IrpSp->FileObject;
+ PAFD_FCB FCB = FileObject->FsContext;
+ UINT BufferSize = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ if (!SocketAcquireStateLock(FCB)) return LostSocket(Irp);
+
+ if (FCB->DisconnectDataSize == 0)
+ return UnlockAndMaybeComplete(FCB, STATUS_INVALID_PARAMETER, Irp, 0);
+
+ ASSERT(FCB->DisconnectData);
+
+ if (FCB->FilledDisconnectData < BufferSize) BufferSize = FCB->FilledDisconnectData;
+
+ RtlCopyMemory(Irp->UserBuffer,
+ FCB->DisconnectData,
+ BufferSize);
+
+ return UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, BufferSize);
+}
+
+NTSTATUS
+NTAPI
+AfdSetDisconnectData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
+ PIO_STACK_LOCATION IrpSp)
+{
+ PFILE_OBJECT FileObject = IrpSp->FileObject;
+ PAFD_FCB FCB = FileObject->FsContext;
+ PVOID DisconnectData = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+ UINT DisconnectDataSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+
+ if (!SocketAcquireStateLock(FCB)) return LostSocket(Irp);
+
+ if (FCB->DisconnectData)
+ {
+ ExFreePool(FCB->DisconnectData);
+ FCB->DisconnectData = NULL;
+ FCB->DisconnectDataSize = 0;
+ FCB->FilledDisconnectData = 0;
+ }
+
+ FCB->DisconnectData = ExAllocatePool(PagedPool, DisconnectDataSize);
+ if (!FCB->DisconnectData) return UnlockAndMaybeComplete(FCB, STATUS_NO_MEMORY, Irp, 0);
+
+ RtlCopyMemory(FCB->DisconnectData,
+ DisconnectData,
+ DisconnectDataSize);
+
+ FCB->DisconnectDataSize = DisconnectDataSize;
+
+ return UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, 0);
+}
+
+NTSTATUS
+NTAPI
+AfdSetDisconnectDataSize(PDEVICE_OBJECT DeviceObject, PIRP Irp,
+ PIO_STACK_LOCATION IrpSp)
+{
+ PFILE_OBJECT FileObject = IrpSp->FileObject;
+ PAFD_FCB FCB = FileObject->FsContext;
+ PUINT DisconnectDataSize = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+ UINT BufferSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+
+ if (!SocketAcquireStateLock(FCB)) return LostSocket(Irp);
+
+ if (BufferSize < sizeof(UINT))
+ return UnlockAndMaybeComplete(FCB, STATUS_BUFFER_TOO_SMALL, Irp, 0);
+
+ if (FCB->DisconnectData)
+ {
+ ExFreePool(FCB->DisconnectData);
+ FCB->DisconnectDataSize = 0;
+ FCB->FilledDisconnectData = 0;
+ }
+
+ FCB->DisconnectData = ExAllocatePool(PagedPool, *DisconnectDataSize);
+ if (!FCB->DisconnectData) return UnlockAndMaybeComplete(FCB, STATUS_NO_MEMORY, Irp, 0);
+
+ FCB->DisconnectDataSize = *DisconnectDataSize;
+
+ return UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, 0);
+}
+