Sample Code

Windows Driver Samples/ Bluetooth Echo L2CAP Profile Driver/ C++/ bthsrv/ sys/ sdp.c/

/*++

Copyright (c) Microsoft Corporation.  All rights reserved.

    THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
    KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
    PURPOSE.

Module Name:

    Sdp.c

Abstract:

    Contains functionality for publishing and freeing SDP record
    
Environment:

    Kernel mode only


--*/

#include "clisrv.h"
#include "sdp.h"

#if defined(EVENT_TRACING)
#include "sdp.tmh"
#endif

NTSTATUS
AddSeqAttribute(
    _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface,
    _In_ PSDP_TREE_ROOT_NODE Tree,
    _In_ USHORT AttribId,
    _Out_ PSDP_NODE * Seq
    );

NTSTATUS
AppendSeqNode(
    _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface,
    _In_ PSDP_NODE containerNode,
    _Out_ PSDP_NODE * Node
    );

NTSTATUS
AppendNodeUint16(
    _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface,
    _In_ PSDP_NODE ContainerNode,
    _In_ UINT16 Value
    );

NTSTATUS
AppendNodeUuid128(
    _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface,
    _In_ PSDP_NODE ContainerNode,
    _In_ const GUID * Value
    );

NTSTATUS
AppendNodeUuid16(
    _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface,
    _In_ PSDP_NODE ContainerNode,
    _In_ UINT16 Value
    );


NTSTATUS
AddSeqAttribute(
    _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface,
    _In_ PSDP_TREE_ROOT_NODE Tree,
    _In_ USHORT AttribId,
    _Out_ PSDP_NODE * Seq
    )
{
    NTSTATUS status;
    PSDP_NODE seq; 

    seq = SdpNodeInterface->SdpCreateNodeSequence(
        POOLTAG_BTHECHOSAMPLE
        );
    
    if (NULL == seq)
    {
        status = STATUS_INSUFFICIENT_RESOURCES;

        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "Creating sequence failed, returning status code %!STATUS!\n", status);
        
        goto exit;
    }

    status = SdpNodeInterface->SdpAddAttributeToTree(Tree, AttribId, seq, POOLTAG_BTHECHOSAMPLE);
    if(!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "SdpAddAttributeToTree failed, Status code %!STATUS!\n", status);

        //
        // If we failed to add attribute to tree use ExFreePool to free it
        //
        ExFreePool(seq);

        goto exit;
    }

    *Seq = seq;
exit:
    return status;
}

NTSTATUS
AppendSeqNode(
    _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface,
    _In_ PSDP_NODE containerNode,
    _Out_ PSDP_NODE * Node
    )
{
    NTSTATUS status;
    PSDP_NODE node;

    node = SdpNodeInterface->SdpCreateNodeSequence(POOLTAG_BTHECHOSAMPLE);
    if(node == NULL)
    {
        status = STATUS_INSUFFICIENT_RESOURCES;
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "SdpCreateNodeSequence failed, returning status code %!STATUS!\n", status);
        goto exit;
    }
    
    status = SdpNodeInterface->SdpAppendNodeToContainerNode(
        containerNode,
        node
        );

    //
    // SdpAppendNodeToContainerNode doesn't fail due to resource reasons
    // Make sure we passed valid parameters and container node
    //

    NT_ASSERT(NT_SUCCESS(status));

    *Node = node;
exit:
    return status;
}

NTSTATUS
AppendNodeUint16(
    _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface,
    _In_ PSDP_NODE ContainerNode,
    _In_ UINT16 Value
    )
{
    NTSTATUS status;
    PSDP_NODE node;
    
    node = SdpNodeInterface->SdpCreateNodeUint16(Value, POOLTAG_BTHECHOSAMPLE);
    if(node == NULL)
    {
        status = STATUS_INSUFFICIENT_RESOURCES;

        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "Creating NodeUint16 failed, returning status code %!STATUS!\n", status);

        goto exit;
    }

    status = SdpNodeInterface->SdpAppendNodeToContainerNode(
        ContainerNode,
        node
        );

    if(!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP,
            "SdpAppendNodeToContainerNode failed, returning status code %!STATUS!\n", status);
        ExFreePool(node);
        node = NULL;
        goto exit;
    }

    //
    // Make sure we passed valid parameters and container node
    //
    
    NT_ASSERT(NT_SUCCESS(status));

exit:
    return status;
}

NTSTATUS
AppendNodeUuid128(
    _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface,
    _In_ PSDP_NODE ContainerNode,
    _In_ const GUID * Value
    )
{
    NTSTATUS status;
    PSDP_NODE node;
    
    node = SdpNodeInterface->SdpCreateNodeUuid128(Value, POOLTAG_BTHECHOSAMPLE);
    if(node == NULL)
    {
        status = STATUS_INSUFFICIENT_RESOURCES;

        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "Creating NodeUuid128 failed, returning status code %!STATUS!\n", status);

        goto exit;
    }

    status = SdpNodeInterface->SdpAppendNodeToContainerNode(
        ContainerNode,
        node
        );

    if(!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP,
            "SdpAppendNodeToContainerNode failed, returning status code %!STATUS!\n", status);
        ExFreePool(node);
        node = NULL;
        goto exit;
    }

    //
    // Make sure we passed valid parameters and container node
    //
    
    NT_ASSERT(NT_SUCCESS(status));

exit:
    return status;
}

NTSTATUS
AppendNodeUuid16(
    _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface,
    _In_ PSDP_NODE ContainerNode,
    _In_ UINT16 Value
    )
{
    NTSTATUS status;
    PSDP_NODE node;
    
    node = SdpNodeInterface->SdpCreateNodeUuid16(Value, POOLTAG_BTHECHOSAMPLE);
    if(node == NULL)
    {
        status = STATUS_INSUFFICIENT_RESOURCES;

        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "Creating NodeUuid16 failed, returning status code %!STATUS!\n", status);

        goto exit;
    }

    status = SdpNodeInterface->SdpAppendNodeToContainerNode(
        ContainerNode,
        node
        );

    if(!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP,
            "SdpAppendNodeToContainerNode failed, returning status code %!STATUS!\n", status);
        ExFreePool(node);
        node = NULL;
        goto exit;
    }

    //
    // Make sure we passed valid parameters and container node
    //
    
    NT_ASSERT(NT_SUCCESS(status));

exit:
    return status;
}

NTSTATUS
CreateSdpRecord(
    _In_ PBTHDDI_SDP_NODE_INTERFACE SdpNodeInterface,
    _In_ PBTHDDI_SDP_PARSE_INTERFACE SdpParseInterface,
    _In_ const GUID * ClassId,
    _In_ LPWSTR Name,
    _In_ USHORT Psm,
    _Out_ PUCHAR * Stream,
    _Out_ ULONG * Size
    )
/*++

Description:

    Create server SDP record

Arguments:

    SdpNodeInterface - Node interface that we obtained from bth stack
    SdpParseInterface - Parse interface that we obtained from bth stack
    ClassId - Service Class ID to publish
    Name - Service name to publish
    Psm - Server PSM
    Stream - receives the sdp record stream
    Size - receives size of sdp record stream

Return Value:

    NTSTATUS Status code.

--*/
{
    NTSTATUS status;
    PSDP_TREE_ROOT_NODE tree = NULL;
    PSDP_NODE seqClsIdList, seqProto, seqLang; 
    PSDP_NODE nodeName = NULL, nodeDesc = NULL, nodeProto; 
    UNICODE_STRING unicodeStrName;
    ANSI_STRING ansiStrName;
    PUCHAR stream = NULL;
    ULONG size;
    ULONG_PTR errorByte = 0;

    RtlInitUnicodeString(&unicodeStrName, Name);
    RtlInitAnsiString(&ansiStrName, NULL);

    status = RtlUnicodeStringToAnsiString(&ansiStrName, &unicodeStrName, TRUE);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "Creating ANSI string for service name failed, Status code %!STATUS!\n", status);

        ansiStrName.Length = 0;
        goto exit;
    }
        
    tree = SdpNodeInterface->SdpCreateNodeTree(
        POOLTAG_BTHECHOSAMPLE
        );

    if (NULL == tree)
    {
        status = STATUS_INSUFFICIENT_RESOURCES;

        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "SdpCreateNodeTree failed, returning Status code %!STATUS!\n", status);
        
        goto exit;
    }

    //
    // Add ClassIdList attribute
    //

    status = AddSeqAttribute(SdpNodeInterface, tree, SDP_ATTRIB_CLASS_ID_LIST, &seqClsIdList);
    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

    status = AppendNodeUuid128(SdpNodeInterface, seqClsIdList, ClassId);
    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

    //
    // Add protocols
    //

    //
    // L2CAP
    //
    status = AddSeqAttribute(SdpNodeInterface, tree, SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST, &seqProto);
    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

    status = AppendSeqNode(SdpNodeInterface, seqProto, &nodeProto);
    if (!NT_SUCCESS(status))
    {
        goto exit;
    }
    
    status = AppendNodeUuid16(SdpNodeInterface, nodeProto, L2CAP_PROTOCOL_UUID16);
    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

    status = AppendNodeUint16(SdpNodeInterface, nodeProto, Psm);
    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

    //
    // SDP
    //

    status = AppendSeqNode(SdpNodeInterface, seqProto, &nodeProto);
    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

    status = AppendNodeUuid16(SdpNodeInterface, nodeProto, SDP_PROTOCOL_UUID16);            
    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

    //
    // Add lang attributes
    //
    status = AddSeqAttribute(SdpNodeInterface, tree, SDP_ATTRIB_LANG_BASE_ATTRIB_ID_LIST, &seqLang);
    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

    status = AppendNodeUint16(SdpNodeInterface, seqLang, 0x656e); //TODO: find constants for these           
    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

    status = AppendNodeUint16(SdpNodeInterface, seqLang, 0x006A);            
    if (!NT_SUCCESS(status))
    {
        goto exit;
    }
    
    status = AppendNodeUint16(SdpNodeInterface, seqLang, 0x0100);            
    if (!NT_SUCCESS(status))
    {
        goto exit;
    }
    
    //
    // Add service name
    //

    nodeName = SdpNodeInterface->SdpCreateNodeString(
        ansiStrName.Buffer, 
        ansiStrName.Length, 
        POOLTAG_BTHECHOSAMPLE
        );
    if(NULL == nodeName)
    {
        status = STATUS_INSUFFICIENT_RESOURCES;

        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "Creating node for service name failed, Status code %!STATUS!\n", status);

        goto exit;
    }
    
    status = SdpNodeInterface->SdpAddAttributeToTree(
        tree, 
        LANG_DEFAULT_ID+STRING_NAME_OFFSET, 
        nodeName, 
        POOLTAG_BTHECHOSAMPLE
        );
    if(!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "SdpAddAttributeToTree for service name failed, Status code %!STATUS!\n", status);

        goto exit;
    }

    nodeName = NULL; //transferred owenership to tree
    
    nodeDesc = SdpNodeInterface->SdpCreateNodeString(
        ansiStrName.Buffer, 
        ansiStrName.Length, 
        POOLTAG_BTHECHOSAMPLE
        );
    if(NULL == nodeDesc)
    {
        status = STATUS_INSUFFICIENT_RESOURCES;

        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "Creating node for service desc failed, Status code %!STATUS!\n", status);

        goto exit;
    }
    
    status = SdpNodeInterface->SdpAddAttributeToTree(
        tree, 
        LANG_DEFAULT_ID+STRING_DESCRIPTION_OFFSET, 
        nodeDesc, 
        POOLTAG_BTHECHOSAMPLE
        );
    if(!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "SdpAddAttributeToTree for service desc failed, Status code %!STATUS!\n", status);
        
        goto exit;
    }

    nodeDesc = NULL;

    //
    // Create stream from tree
    //

    status = SdpParseInterface->SdpConvertTreeToStream(tree, &stream, &size, POOLTAG_BTHECHOSAMPLE);
    if(!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "Failed to get stream from tree for SDP record, Status code %!STATUS!\n", status);
        
        goto exit;
    }

    status = SdpParseInterface->SdpValidateStream(
        stream,
        size,
        &errorByte
        );

    if(!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "Validate stream failed for SDP record, first failure at address %p\n", (PVOID)errorByte);
        
        goto exit;
    }

    *Stream = stream;
    *Size = size;
    
exit:
    if (NULL != tree)
    {
        SdpNodeInterface->SdpFreeTree(tree);
    }

    if (NULL != nodeName)
    {
        //
        // If we failed to add attribute to tree use ExFreePool to free it
        //
        ExFreePool(nodeName);
    }
    
    if (NULL != nodeDesc)
    {
        //
        // If we failed to add attribute to tree use ExFreePool to free it
        //
        ExFreePool(nodeDesc);
    }
    
    if(0 != ansiStrName.Length)
    {
        RtlFreeAnsiString(&ansiStrName);
    }

    if (!NT_SUCCESS(status))
    {
        if (stream != NULL)
        {
            ExFreePoolWithTag(stream, POOLTAG_BTHECHOSAMPLE);
        }
    }
    
    return status;
}

VOID
FreeSdpRecord(
    PUCHAR SdpRecord
    )
{
    ExFreePoolWithTag(SdpRecord, POOLTAG_BTHECHOSAMPLE);            
}


Our Services

  • What our customers say about us?

© 2011-2025 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS