Vista 이상 시스템에 TDI 포팅 시 주의할 점

@codemaru · June 25, 2013 · 3 min read

MS에서 Vista 이상부터 TDI 지원을 끊겠다고 했으나 Windows 8까지 TDI는 여전히 지원되고 있습니다. 하위호환성을 그렇게 쉽게 끊진 못하죠 ㅋ~ 몇 해 전 만들었던 TDI 클라이언트 드라이버가 Vista 이상에서 동작하지 않는다고 해서 오늘 디버깅을 좀 했습니다. 별거 아닌 곳에서 삽질을 좀 해서 기록을 남겨 놓습니다. 우선 문제는 다른 건 다 잘 되는데 이상하게 TdiConnectionContext만 하면 STATUS_INVALID_PARAMETER가 떨어지는 문제였습니다. 아래와 같은 코드에서 ZwCreateFile이 성공하지 못하는 상황이었죠.

struct MY_KERNEL_SOCKET *scoket;
NTSTATUS status;
IO_STATUS_BLOCK iosb = {0};
PFILE_FULL_EA_INFORMATION ea;

UNICODE_STRING name;
OBJECT_ATTRIBUTES oa;

RtlInitUnicodeString(&name, L"\\Device\\Tcp");

InitializeObjectAttributes(&oa
                              , &name
                              , OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE
                              , 0
                              , 0);

ea = ExAllocatePool(...);
if(!ea)
    return STATUS_INSUFFICIENT_RESOURCES;

ea->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
ea->EaValueLength = sizeof(*socket);

RtlCopyMemory(ea->EaName, TdiConnectionContext, ea->EaNameLength);
RtlCopyMemory(&ea->EaName[ea->EaNameLength + 1], socket, sizeof(*socket));


status = ZwCreateFile(&cfh
                        , GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE
                        , &oa
                        , &iosb
                        , NULL
                        , FILE_ATTRIBUTE_NORMAL
                        , 0
                        , FILE_OPEN_IF
                        , 0
                        , ea
                        , ea_len);

if(!NT_SUCCESS(status))
{
    // 요기서 STATUS_INVALID_PARAMETER 발생
    return status;
}

처음에 별거 아닌 문제로 보여서 그냥 구글링을 했는데, 저같은 이슈를 겪는 사용자가 의외로 없더군요. 질문은 올라와 있는데 그냥 해결됐다 고맙다 이런 답변만 있는… ㅠㅜ~ 삽질을 좀 하다 문제가 해결이 안 돼서 tdx.sys 드라이버 파일을 열었습니다. 그제야 답이 보이더군요. Windows XP까지는 TDI를 tcpip.sys에서 처리했으나, Vista 부터는 tdx.sys에서 처리하고 있습니다.

Vista         TDI            md 0
TdiConnectionContext 인지를 검사하는 루틴

Vista         TDI            md 1
점프하면 이곳으로 옵니다. EaValueLength가 4인지를 검사하고 있습니다.

Vista         TDI            md 2
64비트 운영체제의 tdx.sys, EaValueLength가 8인지를 검사하고 있습니다.

결론만 말하면 TdiConnectionContext의 EA Value로는 항상 포인터 크기의 핸들만 전달해야 합니다. XP에서는 이런 체크가 없어서 정상적으로 동작했던 것 같네요. 헐~ 아래는 MSDN 전문입니다. 교과서를 열심히 봐야 삽질이 없습니다.

For a connection endpoint, the EaName member is set to the system-defined constant TdiConnectionContext and the EA value following the EaName array is a client-supplied handle, opaque to the transport driver. The transport must save this handle and subsequently pass it back to the client’s registered event handlers for this connection.

http://msdn.microsoft.com/en-us/library/windows/hardware/ff565046(v=vs.85).aspx

이거 말고는 기존 XP 소스를 특별히 변경하지 않아도 잘 동작했습니다. 당연한 거겠지만 ㅋㅋ~

@codemaru
돌아보니 좋은 날도 있었고, 나쁜 날도 있었다. 그런 나의 모든 소소한 일상과 배움을 기록한다. 여기에 기록된 모든 내용은 한 개인의 관점이고 의견이다. 내가 속한 조직과는 1도 상관이 없다.
(C) 2001 YoungJin Shin, 0일째 운영 중