summaryrefslogtreecommitdiffstats
path: root/private/ntos/nbt/vxd/newdns.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/nbt/vxd/newdns.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to '')
-rw-r--r--private/ntos/nbt/vxd/newdns.c1019
1 files changed, 1019 insertions, 0 deletions
diff --git a/private/ntos/nbt/vxd/newdns.c b/private/ntos/nbt/vxd/newdns.c
new file mode 100644
index 000000000..9bcf78d4b
--- /dev/null
+++ b/private/ntos/nbt/vxd/newdns.c
@@ -0,0 +1,1019 @@
+/*++
+
+Copyright (c) 1989-1996 Microsoft Corporation
+
+Module Name:
+
+ DNS.c
+
+Abstract:
+
+ VxD-specific DNS routines.
+
+ This stuff will all be obsolete when we get proper services for
+ Windows. Then we will just call Winsock for DNS name resolution.
+
+Author:
+
+ Earle R. Horton (ERH) 13-Feb-1996
+
+Revision History:
+
+--*/
+
+#include "nbtprocs.h"
+
+//----------------------------------------------------------------------------
+ ULONG
+DoDnsResolveDirect(
+ PNCB pncb,
+ PUCHAR pzDnsName,
+ PULONG pIpAddress
+)
+{
+ PDNS_DIRECT_WORK_ITEM_CONTEXT pContext;
+ PUCHAR pch;
+ tDEVICECONTEXT *pDeviceContext;
+ ULONG status;
+ CTELockHandle OldIrq;
+
+ pDeviceContext = GetDeviceContext( pncb ) ;
+
+ if ( pDeviceContext == NULL )
+ {
+ return NRC_BRIDGE ;
+ }
+
+ //
+ // If the primary DNS server is not defined, just return error.
+ // Return command timed out here.
+ //
+ if ( (!pDeviceContext->lDnsServerAddress) ||
+ ( pDeviceContext->lDnsServerAddress == LOOP_BACK) )
+ {
+ return( NRC_NOCALL );
+ }
+
+ pContext = CTEAllocMem( sizeof(DNS_DIRECT_WORK_ITEM_CONTEXT) );
+
+ if ( pContext == NULL )
+ {
+ return NRC_NORESOURCES;
+ }
+
+ CTEZeroMemory( pContext, sizeof(DNS_DIRECT_WORK_ITEM_CONTEXT) );
+
+ pContext->pDeviceContext = pDeviceContext;
+ pContext->pNCB = pncb;
+ pContext->pzDnsName = pzDnsName;
+ pContext->pIpAddress = pIpAddress;
+
+ pContext->TransactId = htons(GetTransactId() + DIRECT_DNS_NAME_QUERY_BASE );
+ pContext->pchDomainName = NbtConfig.pDomainName;
+ pContext->Flags = DNS_DIRECT_DNS_SERVER;
+
+ for ( pch = &pzDnsName[0] ; *pch++ != '\0' ; )
+ {
+ if ( pch[0] == '.' )
+ {
+ pContext->Flags |= DNS_DIRECT_NAME_HAS_DOTS;
+ pContext->pchDomainName = NULL;
+ }
+ }
+
+ //
+ // Put on the pending name queries list again so that when the query
+ // response comes in from DNS we can find the context.
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ InsertTailList(&NbtConfig.DNSDirectNameQueries,
+ &pContext->Linkage
+ );
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ status = UdpSendDNSBcastDirect( pContext,
+ (ULONG)pNbtGlobConfig->uRetryTimeout,
+ (ULONG)pNbtGlobConfig->uNumRetries
+ );
+
+ pncb->ncb_retcode = pncb->ncb_cmd_cplt = status ;
+
+ if ( status != NRC_PENDING )
+ {
+ pncb->ncb_retcode = pncb->ncb_cmd_cplt = status ;
+
+ DnsUnlinkAndCompleteDirect( pContext );
+ }
+ else
+ {
+ status = NRC_GOODRET;
+ }
+
+ return status;
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+UdpSendDNSBcastDirect(
+ IN PDNS_DIRECT_WORK_ITEM_CONTEXT pContext,
+ IN ULONG Timeout,
+ IN ULONG Retries
+)
+/*++
+
+Routine Description:
+
+ This routine sends a name query directed to the name server.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+History:
+
+ Adapted from UdpSendNSBcast() in "udpsend.c."
+
+ Earle R. Horton (earleh) March 18, 1996
+
+--*/
+{
+ NTSTATUS status;
+ tNAMEHDR *pNameHdr;
+ ULONG uLength;
+ ULONG uSentSize;
+ CTELockHandle OldIrq;
+ ULONG IpAddress;
+ tTIMERQENTRY *pTimerQEntry;
+ TDI_REQUEST TdiRequest;
+ PDNS_DIRECT_SEND_CONTEXT pSendContext;
+
+ pSendContext = CreateSendContextDirect(
+ pContext->pzDnsName,
+ pContext->pchDomainName,
+ (PVOID)&pNameHdr,
+ &uLength,
+ pContext);
+
+ if (pSendContext == NULL)
+ {
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Failed to Create Pdu to send to DNS.\n"));
+ return( NRC_NORES );
+ }
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ TdiRequest.Handle.AddressHandle = (PVOID)pContext->pDeviceContext->pNameServerFileObject;
+
+ // the completion routine is setup to free the pDgramTracker memory block
+ TdiRequest.RequestNotifyObject = SendDNSBcastDoneDirect;
+ TdiRequest.RequestContext = (PVOID)pSendContext;
+
+ // start the timer now...We didn't start it before because it could
+ // have expired during the dgram setup, perhaps before the Context was
+ // fully setup.
+ //
+ if (Timeout)
+ {
+ status = StartTimer(
+ Timeout,
+ pContext,
+ NULL,
+ DnsCompletionDirect,
+ NULL,
+ NULL,
+ (USHORT)Retries,
+ &pTimerQEntry
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ // we need to differentiate the timer failing versus lack
+ // of resources
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ CTEMemFree(pSendContext);
+
+ return( NRC_NORES );
+ }
+ //
+ // Cross link the nameaddr and the timer so we can stop the timer
+ // when the name query response occurs
+ //
+ pTimerQEntry->pCacheEntry = pContext;
+ pContext->pTimer = pTimerQEntry;
+ }
+
+ //
+ // in the event that DHCP has just removed the IP address, just cancel
+ // the request
+ //
+ if (pContext->pDeviceContext->IpAddress == 0)
+ {
+ StopTimer ( pContext->pTimer, NULL, NULL );
+ pContext->Flags |= DNS_DIRECT_CANCELLED;
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ (VOID) TdiSendDatagram(
+ &TdiRequest,
+ &pSendContext->SendInfo,
+ uLength,
+ &uSentSize,
+ &pSendContext->SendBuffer,
+ NBT_NAME_SERVICE
+ );
+
+ return( NRC_PENDING );
+}
+
+//----------------------------------------------------------------------------
+ VOID
+SendDNSBcastDoneDirect(
+ IN PVOID pSendContext,
+ IN NTSTATUS status,
+ IN ULONG lInfo
+)
+{
+ CTEMemFree(pSendContext);
+}
+
+//----------------------------------------------------------------------------
+ BOOL
+DoDnsCancelDirect(
+ PNCB pncb
+)
+{
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ PDNS_DIRECT_WORK_ITEM_CONTEXT
+ pContext;
+ CTELockHandle OldIrq;
+ BOOL RetVal = FALSE;
+
+ pHead = pEntry = &NbtConfig.DNSDirectNameQueries;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pContext = CONTAINING_RECORD(pEntry,DNS_DIRECT_WORK_ITEM_CONTEXT,Linkage);
+ if ( pContext->pNCB == pncb )
+ {
+ StopTimer ( pContext->pTimer, NULL, NULL );
+ pContext->Flags |= DNS_DIRECT_CANCELLED;
+ RetVal = TRUE;
+ break;
+ }
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ return RetVal;
+}
+
+//----------------------------------------------------------------------------
+/*++
+
+Routine Description:
+
+ This routine is called by the timer code when the timer expires. It must
+ decide if another name query should be sent to the DNS server, and if not,
+ then it completes the request.
+
+Arguments:
+
+
+Notes:
+--*/
+ VOID
+DnsCompletionDirect(
+ PVOID pvContext,
+ PVOID pvContext2,
+ tTIMERQENTRY *pTimerQEntry
+)
+{
+ PDNS_DIRECT_WORK_ITEM_CONTEXT pContext;
+ tDEVICECONTEXT *pDeviceContext;
+
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+ PCHAR pchDomainName;
+ USHORT Flags;
+ BOOL fOneMoreTry;
+
+ KdPrint(("DnsCompletion entered\r\n"));
+
+ pContext = (PDNS_DIRECT_WORK_ITEM_CONTEXT)pvContext;
+
+
+ // if the client completion routine is not set anymore, then the
+ // timer has been cancelled or completed and this routine should
+ // just clean up its buffers associated with the tracker (and return)
+ //
+ if (!pTimerQEntry)
+ {
+ // complete the request
+ LOCATION(0x52);
+ DnsUnlinkAndCompleteDirect( pContext );
+ return;
+ }
+
+
+ //
+ // to prevent a client from stopping the timer and deleting the
+ // pContext, grab the lock and check if the timer has been stopped
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ pDeviceContext = pContext->pDeviceContext;
+
+ if (pTimerQEntry->Flags & TIMER_RETIMED)
+ {
+ //
+ // Got a wait ACK from the server.
+ //
+ pTimerQEntry->Flags &= ~TIMER_RETIMED;
+ pTimerQEntry->Flags |= TIMER_RESTART;
+ //
+ // if we are not bound to this card than use a very short timeout
+ //
+ if (
+ (!pDeviceContext->pNameServerFileObject)
+ || (pContext->Flags & DNS_DIRECT_CANCELLED)
+ )
+ {
+ pTimerQEntry->DeltaTime = 10;
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return;
+ }
+
+ // If done with all the (3) retries with primary, try secondary DNS srvr
+ // If secondary not defined, or done with secondary as well, stop.
+ //
+
+ fOneMoreTry = TRUE;
+
+ if (!(--pTimerQEntry->Retries))
+ {
+ //
+ // if backup server is not defined, or if it is defined but we just
+ // finished trying backup server, go back and try primary server for
+ // "other domains"
+ // e.g. DNSDomains was defined as "msft.dom2.com,msft.dom3.com,msft.dom"
+ // We were pointing at msft.dom2.com. Now, we are done with that (and
+ // didn't get a response), so try msft.dom3.com
+ //
+ if ( ( !pDeviceContext->lDnsBackupServer ) ||
+ ( pDeviceContext->lDnsBackupServer == LOOP_BACK ) ||
+ ( pContext->Flags & DNS_DIRECT_DNS_BACKUP) )
+ {
+ //
+ // if we just got done trying primary domain name, try all the
+ // "other domains" specified
+ //
+ if (pContext->pchDomainName == NbtConfig.pDomainName)
+ {
+ pContext->pchDomainName = NbtConfig.pDNSDomains;
+ if ( pContext->pchDomainName )
+ {
+ pContext->Flags &= ~DNS_DIRECT_DNS_BACKUP;
+ pContext->Flags |= DNS_DIRECT_DNS_SERVER;
+ pTimerQEntry->Retries = NbtConfig.uNumRetries;
+ }
+ else
+ {
+ fOneMoreTry = FALSE;
+ }
+ }
+
+ //
+ // if we had already started on "other domains", advance to the
+ // next domain within "other domains"
+ //
+ else if ( pContext->pchDomainName )
+ {
+ pchDomainName = pContext->pchDomainName;
+ while( *pchDomainName != ',' && // dom names separated by comma
+ *pchDomainName != ' ' && // or space
+ *pchDomainName != '\0' )
+ {
+ pchDomainName++;
+ }
+
+ if ( *pchDomainName == '\0' )
+ fOneMoreTry = FALSE;
+ else
+ {
+ pchDomainName++;
+ pContext->pchDomainName = pchDomainName;
+ pContext->Flags &= ~DNS_DIRECT_DNS_BACKUP;
+ pContext->Flags |= DNS_DIRECT_DNS_SERVER;
+ pTimerQEntry->Retries = NbtConfig.uNumRetries;
+ }
+ }
+ else
+ {
+ fOneMoreTry = FALSE;
+ }
+ }
+
+ // ok, prepare to try the backup server
+ else
+ {
+ pTimerQEntry->Retries = NbtConfig.uNumRetries;
+
+ pContext->Flags &= ~DNS_DIRECT_DNS_SERVER;
+ pContext->Flags |= DNS_DIRECT_DNS_BACKUP;
+ }
+ }
+
+ // we aren't done yet: send one more query and restart the timer
+ if (fOneMoreTry)
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ status = UdpSendDNSBcastDirect( pContext, 0, 0 );
+
+ pTimerQEntry->Flags |= TIMER_RESTART;
+
+ KdPrint(("One more DNS query sent out\r\n"));
+ }
+
+ // yup, all done: didn't find the name!
+ else
+ {
+ pTimerQEntry->Flags |= TIMER_RESTART;
+ StopTimer(pTimerQEntry,NULL,NULL);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+}
+
+//----------------------------------------------------------------------------
+/*++
+
+Routine Description:
+
+ This routine "actually" completes the request, either by completing the
+ asociated NCB with some kind of failure, or passing it off to the
+ main NCB processing code.
+
+Arguments:
+
+
+Notes:
+--*/
+ VOID
+DnsActualCompletionDirect(
+ IN NBT_WORK_ITEM_CONTEXT * pnbtContext
+)
+{
+ PDNS_DIRECT_WORK_ITEM_CONTEXT pContext = pnbtContext->pClientContext;
+ uchar errNCB = NRC_GOODRET ;
+ NCB * pNCB = pContext->pNCB;
+
+ if ( pNCB->ncb_cmd_cplt == NRC_PENDING )
+ {
+ //
+ // Failed to resolve the name, or request was cancelled.
+ //
+ if ( pContext->pIpAddress[0] == 0 )
+ {
+ errNCB = NRC_CMDTMO;
+ }
+ else if ( pContext->Flags & DNS_DIRECT_CANCELLED )
+ {
+ errNCB = NRC_CMDCAN;
+ }
+ else
+ {
+ errNCB = VNBT_NCB_X ( pContext->pNCB, NULL, pContext->pIpAddress, NULL, 0 );
+ }
+ if ( errNCB != NRC_GOODRET )
+ {
+ pNCB->ncb_retcode = pNCB->ncb_cmd_cplt = errNCB ;
+ //
+ // call the post-routine only if the post-routine has been specified!
+ //
+ if ( pNCB->ncb_post )
+ {
+ typedef void (CALLBACK * VXDNCBPost )( void ) ;
+ VXDNCBPost ncbpost = (VXDNCBPost) pNCB->ncb_post ;
+
+ //
+ // Clients are expecting EBX to point to the NCB (instead of
+ // pushing it on the stack...). The post routine may trash
+ // ebp also, so save it.
+ //
+ _asm pushad ;
+ _asm mov ebx, pNCB ;
+ ncbpost() ;
+ _asm popad ;
+ }
+ }
+ }
+
+ CTEMemFree(pContext);
+ CTEMemFree(pnbtContext);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+DnsUnlinkAndCompleteDirect(
+ IN PDNS_DIRECT_WORK_ITEM_CONTEXT pContext
+)
+/*++
+
+Routine Description:
+
+ This routine unlinks and completes the request.
+
+Arguments:
+
+
+Notes:
+--*/
+{
+ RemoveEntryList(&pContext->Linkage);
+
+ VxdScheduleDelayedCall ( NULL,
+ pContext,
+ NULL,
+ DnsActualCompletionDirect,
+ pContext->pDeviceContext
+ );
+}
+
+//----------------------------------------------------------------------------
+ VOID
+ProcessDnsResponseDirect(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNumBytes,
+ IN USHORT OpCodeFlags
+ )
+/*++
+
+Routine Description:
+
+ This function sets the state of the name being resolved appropriately
+ depending on whether DNS sends a positive or a negative response to our
+ query; calls the client completion routine and stops any more DNS queries
+ from going.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - STATUS_SUCCESS or STATUS_UNSUCCESSFUL
+
+--*/
+{
+ NTSTATUS status;
+ tDNS_QUERYRESP UNALIGNED *pQuery;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ PDNS_DIRECT_WORK_ITEM_CONTEXT
+ pContext;
+ COMPLETIONCLIENT pClientCompletion;
+ PVOID Context;
+ PTRANSPORT_ADDRESS pSourceAddress;
+ ULONG SrcAddress;
+ ULONG IpAddress;
+ tTIMERQENTRY *pTimer = NULL;
+ CTELockHandle OldIrq1;
+ LONG lNameSize;
+ LONG lTraversedSoFar=0;
+ CHAR pJunkBuf[NETBIOS_NAME_SIZE];
+ PUCHAR pchQry;
+
+ // make sure this is a response
+
+ if ( !(OpCodeFlags & OP_RESPONSE) )
+ {
+ CDbgPrint(DBGFLAG_ERROR,("ProcessDnsResponseDirect: Bad OpCodeFlags\r\n"));
+
+ return;
+ }
+
+ pSourceAddress = (PTRANSPORT_ADDRESS)pSrcAddress;
+ SrcAddress = ntohl(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ if ( ( pContext = FindContextDirect( pNameHdr->TransactId ) ) != NULL )
+
+ {
+ pContext->Flags |= DNS_DIRECT_ANSWERED;
+ if ( pTimer = pContext->pTimer )
+ {
+ //
+ // If the response we received doesn't resolve the name, we silently return,
+ // but make sure reties is set to 1 so that when timer fires again, we don't
+ // send another name query to the same server but instead timeout the
+ // attempt on this server
+ //
+ pTimer->Retries = 1;
+ }
+ //
+ // check the pdu size for errors
+ //
+ if (lNumBytes < DNS_MINIMUM_QUERYRESPONSE)
+ {
+ CDbgPrint(DBGFLAG_ERROR,("ProcessDnsResponseDirect: Bad lNumBytes\r\n"));
+ goto done;
+ }
+
+//
+// BUGBUG: should we require authoritative responses from DNS servers?
+//
+
+ //
+ // if it's a negative response, quit now!
+ //
+ if (IS_NEG_RESPONSE(OpCodeFlags))
+ {
+ goto done;
+ }
+
+ //
+ // if there is no answer section, return!
+ //
+ if ( !pNameHdr->AnCount )
+ {
+ CDbgPrint(DBGFLAG_ERROR,("ProcessDnsResponseDirect: No answer section\r\n"));
+ goto done;
+ }
+
+ //
+ // lNameSize is the length of the entire name, excluding the length byte
+ // for the first label (including length bytes of subsequent labels) and
+ // including the trailing 0 (tNAMEHDR struc takes care for 1st byte)
+ //
+ DnsExtractName( (PCHAR)&pNameHdr->NameRR.NameLength,
+ lNumBytes,
+ pJunkBuf,
+ &lNameSize
+ );
+ pchQry = (PUCHAR)&pNameHdr->NameRR.NetBiosName[lNameSize];
+
+ lTraversedSoFar += lNameSize;
+
+ //
+ // if the Question section is returned with the response then we have
+ // a little more work to do! In this case, pQuery is pointing at the
+ // beginning of the QTYPE field (end of the QNAME)
+ //
+ if ( pNameHdr->QdCount )
+ {
+ pchQry += sizeof(tQUESTIONMODS);
+ lTraversedSoFar += sizeof(tQUESTIONMODS);
+
+ // most common case: 1st byte will be 0xC0, which means next byte points
+ // to the actual name. We don't care about the name, so we skip over
+ // both the bytes
+ //
+ if ( (*pchQry) == PTR_TO_NAME )
+ {
+ pchQry += sizeof(tDNS_LABEL);
+ lTraversedSoFar += sizeof(tDNS_LABEL);
+ }
+
+ //
+ // if some implementation doesn't optimize and copies the whole name
+ // again, skip over the length of the name
+ //
+ else
+ {
+ pchQry += (lNameSize+1); // +1 because of the 1st length byte!
+ lTraversedSoFar += (lNameSize+1);
+ }
+ }
+
+ pQuery = (tDNS_QUERYRESP *)pchQry;
+
+ //
+ // if this rr is telling us about canonical name, skip over it and go to
+ // where the ipaddr is
+ //
+ if (ntohs(pQuery->RrType) == DNS_CNAME)
+ {
+ //
+ // since this is CNAME, there is no ipaddr. Instead, the data is the
+ // canonical name whose length we are adding, and subtract ipaddr's len
+ //
+ pchQry += (sizeof(tDNS_QUERYRESP) - sizeof(ULONG));
+ pchQry += ntohs(pQuery->Length);
+ lTraversedSoFar += ntohs(pQuery->Length) + sizeof(tDNS_QUERYRESP) - sizeof(ULONG);
+
+ ASSERT(lNumBytes > lTraversedSoFar);
+
+ // most common case: 1st byte will be 0xC0, which means next byte points
+ // to the actual name. We don't care about the name, so we skip over
+ // both the bytes
+ //
+ if ( (*pchQry) == PTR_TO_NAME )
+ {
+ pchQry += sizeof(tDNS_LABEL);
+ lTraversedSoFar += sizeof(tDNS_LABEL);
+ }
+
+ //
+ // if some implementation doesn't optimize and copies the whole name
+ // again, skip over the length of the name
+ //
+ else
+ {
+ // we have already taken the name out. we are calling this routine
+ // just to see how big the canonical name is (i.e.lNameSize), to skip
+ // past it
+ //
+ DnsExtractName( pchQry,
+ lNumBytes-lTraversedSoFar,
+ pJunkBuf,
+ &lNameSize
+ );
+
+ //
+ // lNameSize is the length of the entire name, excluding the length byte
+ // for the first label (including length bytes of subsequent labels) and
+ // including the trailing 0 (tNAMEHDR struc takes care for 1st byte)
+ //
+ pchQry += lNameSize+1; // +1 for the length byte of first label
+
+ }
+
+ pQuery = (tDNS_QUERYRESP *)pchQry;
+ }
+
+ // if we came this far, it's a positive response. do the needful.
+
+ IpAddress = ntohl(pQuery->IpAddress);
+
+ if ( !NbtWouldLoopback( IpAddress ) )
+ {
+ pContext->pIpAddress[0] = IpAddress;
+ }
+ else
+ {
+ pContext->Flags |= DNS_DIRECT_CANCELLED;
+ }
+
+ //
+ // Set the backup name server to be the main name server
+ // if we got a response from it.
+ //
+ if ( SrcAddress == pContext->pDeviceContext->lDnsBackupServer )
+ {
+ pContext->pDeviceContext->lDnsBackupServer =
+ pContext->pDeviceContext->lDnsServerAddress;
+
+ pContext->pDeviceContext->lDnsServerAddress = SrcAddress;
+ }
+
+ StopTimer(pTimer,NULL,NULL);
+ }
+
+done:
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return;
+}
+
+//----------------------------------------------------------------------------
+ PDNS_DIRECT_SEND_CONTEXT
+CreateSendContextDirect(
+ IN PCHAR pName,
+ IN PCHAR pchDomainName,
+ OUT PVOID *pHdrs,
+ OUT PULONG pLength,
+ IN PDNS_DIRECT_WORK_ITEM_CONTEXT pContext
+ )
+/*++
+
+Routine Description:
+
+ This routine builds a name query pdu
+
+Arguments:
+
+
+Return Value:
+
+ PDNS_DIRECT_SEND_CONTEXT - a pointer to a data structure used for the datagram
+ send that must be freed by the datagram send completion routine
+
+--*/
+{
+ tNAMEHDR *pNameHdr;
+ ULONG uLength;
+ ULONG uDomainNameSize;
+ tGENERALRR *pGeneral;
+ CTELockHandle OldIrq;
+ PDNS_DIRECT_SEND_CONTEXT
+ pSendContext;
+
+ uDomainNameSize = domnamelen(pchDomainName) + 1; // +1 for len byte
+ if (uDomainNameSize > 1)
+ {
+ uDomainNameSize++; // for the null byte
+ }
+
+ // size is size of the namehdr structure -1 for the NetbiosName[1]
+ // + the 32 bytes for the half ascii name +
+ // scope + size of the General RR structure
+ uLength = sizeof(DNS_DIRECT_SEND_CONTEXT) - 1
+ + uDomainNameSize
+ + sizeof(ULONG)
+ + strlen(pName)
+ + 1;
+
+ // Note that this memory must be deallocated when the send completes in
+ // SendDNSBcastDoneDirect()
+ pSendContext = NbtAllocMem((USHORT)uLength ,NBT_TAG('X'));
+
+ if (pSendContext)
+ {
+ CTEZeroMemory((PVOID)pSendContext,uLength);
+
+ pNameHdr = &pSendContext->NameHdr;
+
+ pNameHdr->TransactId = pContext->TransactId;
+ pNameHdr->QdCount = 1;
+ pNameHdr->AnCount = 0;
+ pNameHdr->NsCount = 0;
+
+ *pHdrs = (PVOID)pNameHdr;
+ *pLength = uLength = uLength - ( sizeof(DNS_DIRECT_SEND_CONTEXT) - sizeof(tNAMEHDR) );
+
+ // copy the netbios name ... adding the scope too
+ if ( pContext->Flags & DNS_DIRECT_NAME_HAS_DOTS )
+ {
+ char * p;
+ for ( p = pName ; *p != '.' ; p++ );
+ p[0] = '\0';
+ pGeneral = (tGENERALRR *)DnsStoreName(
+ (PCHAR)&pNameHdr->NameRR.NameLength,
+ pName,
+ &p[1],
+ eDIRECT_DNS_NAME_QUERY);
+ p[0] = '.';
+ }
+ else
+ {
+ pGeneral = (tGENERALRR *)DnsStoreName(
+ (PCHAR)&pNameHdr->NameRR.NameLength,
+ pName,
+ pContext->pchDomainName,
+ eDIRECT_DNS_NAME_QUERY);
+ }
+
+
+ pGeneral->Question.QuestionTypeClass = htonl(QUEST_DNSINTERNET);
+
+ pNameHdr->OpCodeFlags = (FL_RECURDESIRE);
+
+ pNameHdr->ArCount = 0;
+
+ pSendContext->SendBuffer.pDgramHdr = pNameHdr;
+ pSendContext->SendBuffer.HdrLength = uLength;
+ pSendContext->SendBuffer.pBuffer = NULL;
+ pSendContext->SendBuffer.Length = 0;
+ pSendContext->SendInfo.RemoteAddressLength = sizeof(pSendContext->NameServerAddress);
+ pSendContext->SendInfo.RemoteAddress = (PTRANSPORT_ADDRESS)&pSendContext->NameServerAddress;
+ pSendContext->NameServerAddress.TAAddressCount = 1;
+ pSendContext->NameServerAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
+ pSendContext->NameServerAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
+ pSendContext->NameServerAddress.Address[0].Address[0].sin_port = htons(NbtConfig.DnsServerPort);
+ if ( pContext->Flags & DNS_DIRECT_DNS_SERVER )
+ {
+ pSendContext->NameServerAddress.Address[0].Address[0].in_addr = htonl(pContext->pDeviceContext->lDnsServerAddress);
+ }
+ else
+ {
+ pSendContext->NameServerAddress.Address[0].Address[0].in_addr = htonl(pContext->pDeviceContext->lDnsBackupServer);
+ }
+ }
+
+ return(pSendContext);
+}
+
+//----------------------------------------------------------------------------
+ PDNS_DIRECT_WORK_ITEM_CONTEXT
+FindContextDirect(
+ USHORT TransactionId
+)
+/*++
+
+Routine Description:
+
+ This routine find the DNS_DIRECT_WORK_ITEM_CONTEXT having the given
+ TransactId
+
+Arguments:
+
+
+Return Value:
+
+ PDNS_DIRECT_SEND_CONTEXT - a pointer to the pContext having the given
+ TransactId, or NULL
+
+Notes:
+
+ Called with NbtConfig.JointLock held
+
+--*/
+{
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ PDNS_DIRECT_WORK_ITEM_CONTEXT
+ pContext;
+
+ pHead = pEntry = &NbtConfig.DNSDirectNameQueries;
+
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pContext = CONTAINING_RECORD(pEntry,DNS_DIRECT_WORK_ITEM_CONTEXT,Linkage);
+ if ( pContext->TransactId == TransactionId )
+ {
+ return pContext;
+ }
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------------
+ VOID
+IpToAscii(
+ IN DWORD IpAddress,
+ IN OUT PCHAR pcAscii
+)
+/*++
+
+Routine Description:
+
+ This routine converts an IP address to a NetBIOS name.
+
+Arguments:
+
+ DWORD IP address
+ PCHAR String pointer allocated for 16 bytes
+
+Return Value:
+
+ Note
+
+Notes:
+
+ This is a gigantic hack designed to get "net use \\<dnsname>"
+ working under Windows 95 OPK2 without destabilizing the existing
+ code base over much.
+
+--*/
+{
+ PCHAR pcIpAddressBytes = ( (PCHAR) &IpAddress ) + 3;
+ PCHAR pcIp = pcAscii;
+
+ int i,j,k,l,m;
+
+ memset ( pcAscii, 0x20, NETBIOS_NAME_SIZE );
+
+ for ( i = 4 ; i-- > 0 ; )
+ {
+
+ j = *pcIpAddressBytes-- & 0x000000FF;
+ k = j/100;
+ l = (j%100)/10;
+ m = j%10;
+
+ if ( k )
+ {
+ *pcIp++ = k + '0';
+ *pcIp++ = l + '0';
+ }
+
+ else if ( l )
+ {
+ *pcIp++ = l + '0';
+ }
+
+ *pcIp++ = m + '0';
+
+ if ( i )
+ {
+ *pcIp++ = '.';
+ }
+
+ }
+
+}
+