Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Before Posting...
Please check out the Community Guidelines in the Announcements and Administration Category.

wdf remote target ioctl status success. But not expected data in the output buffer

GunasekaranGunasekaran Member Posts: 11

I am trying to create & send IOCTL request to remote target synchronously. I am getting the status as success but the output buffer is empty.

Please find the attached code that I am using for the same. I have been struck with this issues for last 3-4 days and I dont know what I am missing. Any help or direction to debug would be great.

Notes:
1. I am opening the target in PnP callback routine
2. I am new to Windows driver development

Opening the target

    devExt = GetDeviceExtension(Device);
    DbgPrint("Opened %wZ\n", devExt->symbolicName);

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, TARGET_DEVICE_INFO);
    status = WdfIoTargetCreate(devExt->WdfDevice, &attributes, &ioTarget);
    if (!NT_SUCCESS(status)) {
        DbgPrint("WdfIoTargetCreate failed 0x%x\n", status);
        return status;
    }

    targetDeviceInfo = GetTargetDeviceInfo(ioTarget);
    targetDeviceInfo->DeviceExtension = devExt;

    WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME( &openParams,
        SymbolicLink,
        FILE_WRITE_ACCESS | FILE_READ_ACCESS);

    openParams.ShareAccess = FILE_SHARE_WRITE | FILE_SHARE_READ;
    openParams.EvtIoTargetQueryRemove = EvtIoTargetQueryRemove;
    openParams.EvtIoTargetRemoveCanceled = EvtIoTargetRemoveCanceled;
    openParams.EvtIoTargetRemoveComplete = EvtIoTargetRemoveComplete;

    status = WdfIoTargetOpen(ioTarget, &openParams);
    if (!NT_SUCCESS(status)) {
        WdfObjectDelete(ioTarget);
        DbgPrint("SST Target open failed\n");
        return status;
    }

    *Target = ioTarget;
    devExt->TargetDevice = ioTarget;
    DbgPrint("Target Device 0x%p, PDO 0x%p, Fileobject 0x%p, Filehandle 0x%p\n",
        WdfIoTargetWdmGetTargetDeviceObject(ioTarget),
        WdfIoTargetWdmGetTargetPhysicalDevice(ioTarget),
        WdfIoTargetWdmGetTargetFileObject(ioTarget),
    WdfIoTargetWdmGetTargetFileHandle(ioTarget));

    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.ParentObject = ioTarget;

status = WdfRequestCreate(&attributes,
    ioTarget,
    &targetDeviceInfo->IOCTLRequest);

if (!NT_SUCCESS(status)) {
    WdfObjectDelete(ioTarget);
    return status;
}

Sending the request

   WDF_OBJECT_ATTRIBUTES attributes;
   TARGET_DEVICE_INFO *targetInfo = GetTargetDeviceInfo(devExt->TargetDevice);
   WDFMEMORY ipMemory, opMemory;
   PVOID ipAddr, opAddr;
   WDF_MEMORY_DESCRIPTOR ipMemDescp, opMemDescp;
   status = WdfMemoryCreate(&attributes, NonPagedPoolNx, '4LeM',
    sizeof(hdr) + sizeof(hsk), &ipMemory, &ipAddr);
status = WdfMemoryCreate(&attributes, NonPagedPoolNx, '5LeM',
    sizeof(hdr) + sizeof(hsk), &opMemory, &opAddr);

status |= WdfMemoryCopyFromBuffer(ipMemory, 0, &hdr, sizeof(hdr)); //Filling the input data
status |= WdfMemoryCopyFromBuffer(ipMemory, sizeof(hdr), &hsk, sizeof(hsk));//Filling the input data
if (!NT_SUCCESS(status)) {
    DbgPrint("Mem copy failed\n");
    WdfObjectDelete(ipMemory);
    WdfObjectDelete(opMemory);
    return status;
}
WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&ipMemDescp, ipMemory, 0);
WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&opMemDescp, opMemory, 0);
WDF_REQUEST_SEND_OPTIONS options;
WDF_REQUEST_SEND_OPTIONS_INIT(&options, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);
WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options, WDF_REL_TIMEOUT_IN_MS(1000));

status = WdfIoTargetFormatRequestForIoctl(devExt->TargetDevice, targetInfo->IOCTLRequest, IOCTL_CODE, ipMemory,
    NULL, opMemory, NULL);
DbgPrint("Format status 0x%x\n", status);
if (NT_SUCCESS(status)) {
    WdfRequestSetCompletionRoutine(targetInfo->IOCTLRequest,
        IoctlRequestCompletionRoutine,
        targetInfo);
    BOOLEAN ret = WdfRequestSend(targetInfo->IOCTLRequest, devExt->TargetDevice,
        &options);
    if (!ret) {
        status = WdfRequestGetStatus(targetInfo->IOCTLRequest);
        DbgPrint("Request status 0x%x\n", status);
    }
}

Completion Routine

    targetInfo = GetTargetDeviceInfo(Target);
status = WdfRequestGetStatus(Request);
DbgPrint("Get Request status 0x%x\n", status);
DbgPrint("Ioctl buffer 0x%p\n", CompletionParams->Parameters.Ioctl.Output.Buffer);
DbgPrint("Control code 0x%x\n", CompletionParams->Parameters.Ioctl.IoControlCode);
DbgPrint("Ioctl buffer length 0x%d\n", CompletionParams->Parameters.Ioctl.Output.Length);

Comments

  • Tim_RobertsTim_Roberts Member - All Emails Posts: 12,980

    Are you sending this to a driver that you created? How did you create the IOCTL_CODE? One potential cause is that you didn't realize that ioctl code numbers have fields that define how the memory is transferred.

    Tim Roberts, [email protected]
    Providenza & Boekelheide, Inc.

  • GunasekaranGunasekaran Member Posts: 11
    edited January 4

    I am send it to a OEM driver. Not written by me. Here's the code.

    #define IOCTL_CODE CTL_CODE( 0x8000, 0x123, METHOD_BUFFERED, (FILE_READ_ACCESS | FILE_WRITE_ACCESS))

  • Shane_CorbinShane_Corbin Member Posts: 239

    I think you forgot to associate the IOCTL_request with your WDF memory object before formatting the IOCTL. Before calling WdfMemoryCreate(), try attributes.ParentObject = targetInfo->IOCTLRequest.

    Loosely the process is:

    • Open the IoTarget
    • Create a WDF request to be sent to the IoTarget
    • Stuff the request in a WDF memory object
    • Format the request for IOCTL to send to the target
    • Optionally set additional request options (synch, timeout, etc.)
    • Send the request
  • Tim_RobertsTim_Roberts Member - All Emails Posts: 12,980

    When you say "the output buffer is empty", do you mean the output buffer pointer is null, or do you mean the buffer contains all zeros? The framework stores the output buffer pointer in the UserBuffer field in the IRP. If your lower-level driver messes with that field, it would cause problems. What driver are you calling, exactly?

    Was the code you posted an exact cut-and-paste from your code? You never called WDF_OBJECT_ATTRIBUTES_INIT on your "attributes" structure. And if you don't need any, you can just pass WDF_NO_OBJECT_ATTRIBUTES.

    Tim Roberts, [email protected]
    Providenza & Boekelheide, Inc.

  • GunasekaranGunasekaran Member Posts: 11

    @Tim_Roberts , I have this piece of code before WDFMemoryCreate

    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
    attributes.ParentObject = targetInfo->IOCTLRequest;
    

    By Output buffer empty I mean that It contains Junk data (sometimes Zeros) instead of expected data. I am calling a OEM driver for which I dont have source code and have only API documentation. And as per documentation, I am supposed to get some data when I make that IOCTL call which I am not getting.

    One doubt, Is there anything like that can allow only certain device can talk to the remote target?

  • Peter_Viscarola_(OSR)Peter_Viscarola_(OSR) Administrator Posts: 7,223

    It contains Junk data (sometimes Zeros) instead of expected data.

    But a non-zero value for the Information field? Do you check that?

    BTW... that’s some pretty ugly code. Do you really do all those functions, including calling WdfMemoryCreate without checking the return status?

    Is there anything like that can allow only certain device can talk to the remote target?

    Well, sure. You can always apply an ACL to the device. But, if this were the case, the WdfTargetOpen would fail, not the I/O.

    Peter

    Peter Viscarola
    OSR
    @OSRDrivers

  • GunasekaranGunasekaran Member Posts: 11
    edited January 5

    @Peter_Viscarola_(OSR) , Sorry about the coding and I will add check at each step. Though I did check the status using WinDBG. I have checked the information field it's Zero. What else might go wrong?

    Thanks for the information about ACL.

    I have one more question. I am supposed to get IOCTL call to my driver from the target when I make this IOCTL call to the target. But I am not getting it. Is there any tool which I can look at all the IOCTL calls made to my driver and call made by my driver so that I can verify both the sides?

  • Jan_BottorffJan_Bottorff Member - All Emails Posts: 471
    via Email
    I'm not closely following this thread, but I believe your previous message said you were using buffered I/O IOCTl's. From the called driver, are you setting he information field to the number of bytes you want copied back to the caller? You said the information field is zero, which would mean you want zero bytes copied back to the caller.

    Jan
  • Peter_Viscarola_(OSR)Peter_Viscarola_(OSR) Administrator Posts: 7,223

    From the called driver, are you setting he information field

    An awesome, and a common, bug. But the driver he’s calling isn’t his. Unfortunately.

    have checked the information field it's Zero

    So... yeah. That means you’re getting back zero bytes in response to your IOCTL.

    I am supposed to get IOCTL call to my driver from the target

    Is the request succeeding? What does WdfRequestSend return? What’s the returned status in the IOSB? Is your completion routine being called? Please try to provide us with a clear and complete picture of what’s happening. Rememebr, we’re not in your office with you, looking over your shoulder (though it sure would make things easier)!

    Peter

    Peter Viscarola
    OSR
    @OSRDrivers

  • GunasekaranGunasekaran Member Posts: 11

    @Peter_Viscarola_(OSR)
    I checked with DriverMon & IRPTrace tool and I can see that the request is being received by the Target device.

    Request is getting succeeded. status is 0x00

    Completion routine is being called. Please find the debug log (Print value is present after "//") in completion routine.

    targetInfo = GetTargetDeviceInfo(Target);
    status = WdfRequestGetStatus(Request);
    DbgPrint("Get Request status 0x%x\n", status); //0x00
    DbgPrint("Completion info 0x%x\n", CompletionParams->IoStatus.Information);//0x00
    DbgPrint("Ioctl buffer 0x%p\n", CompletionParams->Parameters.Ioctl.Output.Buffer);//0x0000197623705BA8
    DbgPrint("Control code 0x%x\n", CompletionParams->Parameters.Ioctl.IoControlCode);//IOCTL_CODE passed during request
    DbgPrint("Ioctl buffer length 0x%d\n", CompletionParams->Parameters.Ioctl.Output.Length);//0x0
    

    PS: Sorry for the delayed response. Was down with fever.

  • Tim_RobertsTim_Roberts Member - All Emails Posts: 12,980
    via Email
    Gunasekaran wrote:
    > I checked with DriverMon & IRPTrace tool and I can see that the request is being received by the Target device.
    >
    > Request is getting succeeded. status is 0x00
    >
    > Completion routine is being called. Please find the debug log (Print value is present after "//") in completion routine.
    > ...
    > DbgPrint("Ioctl buffer length 0x%d\n", CompletionParams->Parameters.Ioctl.Output.Length);//0x0

    It's suspicious that the Output.Length is 0.  That should still be set
    to the size of your output buffer.  Forgive the silly question, but are
    you quite sure this ioctl is supposed to have both input data and output
    data?  Is this a real hardware device (what kind?), or is this a
    software device?

    Tim Roberts, [email protected]
    Providenza & Boekelheide, Inc.

  • GunasekaranGunasekaran Member Posts: 11

    @Tim_Roberts. I am sure because when I send the IOCTL with output buffer as NULL or empty, I am getting INVALID_PARAMETER error. It's a Software driver.

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Upcoming OSR Seminars
Developing Minifilters 29 July 2019 OSR Seminar Space
Writing WDF Drivers 23 Sept 2019 OSR Seminar Space
Kernel Debugging 21 Oct 2019 OSR Seminar Space
Internals & Software Drivers 18 Nov 2019 Dulles, VA