[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [bluetooth-dev] Any Source for an SDP Client call.



Chris Johnson wrote:

> Does anyone have source showing how to issue an SDP client request? I am
> particularly interested in the ioctl commands neccessary to issue from
> SDP in order to establish the L2CAP connection and send the request.
> 
> Thanks
> Chris
> 
> 
> -
> To unsubscribe from this list: send the line "unsubscribe bluetooth-dev" in
> the body of a message to majordomo@xxxxxxx.com

I've attached a sample program that shows how to use the SDP ioctls.

Marcus

/*------------------------------------------------------------------*/
/* inq.c - This is a sample program that was written to test the    */
/* Axis 20010108 stack opening ttyBTC multiple times.  It is to be  */
/* run with 'btd' running in a separate process.  This will attempt */
/* to open the ttyBTC control tty and attempt an inquiry.           */
/*                                                                  */
/* Author: Marcus Smith                                             */
/* Date: 1/25/2001                                                  */
/* Copyright (C) 2001 RidgeRun Inc.                                 */
/*------------------------------------------------------------------*/
#include <stdlib.h>
#include <stdio.h>
#include <linux/bluetooth/btcommon.h>
#include <linux/bluetooth/sdp.h>
#include <linux/bluetooth/l2cap.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>    /* For tcflush() & TCIOFLUSH */
#include <sys/ioctl.h>  /* For ioctl. */

#define BT_CONTROL_TTY "/dev/ttyBTC"
#define UUID_PUBLIC_BROWSE_GROUP 0x1002
#define UUID_DIAL_UP_NETWORKING 0x1103
#define UUID_LAN_ACCESS_USING_PPP 0x1102

#define UUID_SERVICE_NAME_ATTRIBUTE 0x0100
#define UUID_DOCUMENTATION_URL_ATTRIBUTE 0x000a

#define SDP_ERROR_RSP 1
#define SDP_SERVICESEARCH_REQ 2
#define SDP_SERVICEATTR_REQ 4
#define SDP_SERVICESEARCHATTR_REQ 6

#define SDP_SERVICESEARCH_REQ_ERROR(x) ((x.responseLength == 0) || (x.requestResponse[0] == SDP_ERROR_RSP))
#define FORMULATE_RECORD_HANDLE_COUNT(x, y) ((x << 8) | y)
#define FORMULATE_RECORD_HANDLE(a, b, c, d) ((((int)a) << 24) | (((int)b) << 16) | (((int)c) << 8) | (int)d)

int main(int argc, char **argv)
{
   int i;
   inquiry_results *inq_res;
   int bt_cfd = -1;
   struct bt_connection conn;
   unsigned char tmp_bd[8];
   int sdpConnectionID = -1;
   unsigned int conID;

   /*-----------------------------------------------------------*/
   /* Issue the prompt for the user to input the BD address.    */
   /*-----------------------------------------------------------*/
   printf("Enter the remote BD address (xx:xx:xx:xx:xx:xx <line> \n=> ");

   if ( scanf("%x:%x:%x:%x:%x:%x %d", &tmp_bd[0], &tmp_bd[1], &tmp_bd[2], &tmp_bd[3], &tmp_bd[4], &tmp_bd[5], &tmp_bd[6]) < 6)
   {
      fprintf(stderr, "Error:  Invalid format - try again\n");
      exit(-1);
   }

   /*-----------------------------------------------------------*/
   /* Fill in the bt_connection structure before the ioctl.     */
   /*-----------------------------------------------------------*/
   memcpy(conn.bd, tmp_bd, 6);
   conn.id = CREATE_SDP_ID(tmp_bd[6] /* BT line */, 0 /* This is a no-op on the connection construction */);
   printf("Connection ID: 0x%X\n", conn.id);

   /*-----------------------------------------------------*/
   /* Open the bluetooth control tty.                     */
   /*-----------------------------------------------------*/
   if ((bt_cfd = open(BT_CONTROL_TTY, O_RDWR)) < 0 )
   { 
      perror("open_device");
      exit(1);
   }

   /*-----------------------------------------------------------*/
   /* Flush this file descriptor.                               */
   /*-----------------------------------------------------------*/
   tcflush(bt_cfd, TCIOFLUSH);

   /*-----------------------------------------------------------*/
   /* Issue the ioctl to setup the connection.                  */
   /*-----------------------------------------------------------*/
   sleep(5);
   if ( (sdpConnectionID = ioctl(bt_cfd, BTCONNECT, &conn)) < 0 )
   {
      perror("SDP connection error");
      close(bt_cfd);
      exit(-1);
   }
   
   fprintf(stderr, "Connection a success!\n");
   if ( sdpConnectionID >= 0 )
   {
      bt_sdp_request sdpRequestData;

      /*------------------------------------------------------------------*/
      /* Fill in the command buffer.                                      */
      /*------------------------------------------------------------------*/
      memset(&sdpRequestData, 0x00, sizeof(bt_sdp_request));
      fprintf(stderr, "Getting ready for the SDP Request transaction - Connection ID = %d\n", sdpConnectionID);

      /*------------------------------------------------------------------------------------*/
      /* Write out the Data Element Sequence Header, which is 0x35.                         */
      /*------------------------------------------------------------------------------------*/
      sdpRequestData.pduPayload[0] = 0x35;
    
      /*------------------------------------------------------------------------------------*/
      /* Write out the number of bytes to follow.  Since there is one UUID16_HDR and a 16   */
      /* byte UUID, there are 3 bytes following.                                            */
      /*------------------------------------------------------------------------------------*/
      sdpRequestData.pduPayload[1] = 0x03;
    
      /*------------------------------------------------------------------------------------*/
      /* Apply the UUID16_HDR and the PublicBrowseGroup.                                    */
      /*------------------------------------------------------------------------------------*/
      sdpRequestData.pduPayload[2] = 0x19;
      sdpRequestData.pduPayload[3] = (UUID_LAN_ACCESS_USING_PPP >> 8) & 0xff;
      sdpRequestData.pduPayload[4] = UUID_LAN_ACCESS_USING_PPP & 0xff;

      /* Maximum number of service record handles to be returned.  Set at 5 for now. */
      sdpRequestData.pduPayload[5] = (5 >> 8) & 0xff; /* Just to stress big endian */
      sdpRequestData.pduPayload[6] = (5 & 0xff);
      sdpRequestData.pduPayload[7] = 0;  /* Continuation state  - set to "none" */
       
      /*------------------------------------------------------------------*/
      /* Issue the sdp request.                                           */
      /*------------------------------------------------------------------*/
      sdpRequestData.pduLength = 8;
      sdpRequestData.sdpCommand = SDP_SERVICESEARCH_REQ;
      
      /*---------------------------------------------------------------------------*/
      /* Fill in the bt_sdp_request data structure.                                */
      /*---------------------------------------------------------------------------*/
      sdpRequestData.conID = CREATE_SDP_ID(tmp_bd[6] /* BT line */, sdpConnectionID /* No longer a no-op */);
   
      /* Issue the ioctl. */
      if ( ioctl(bt_cfd, BT_SDP_REQUEST, &sdpRequestData) < 0 )
      {
         perror("SDP request error");
         exit(-1);
      }
      else
      {
         unsigned long serviceRecordCount;
         unsigned long serviceRecordHandle;

         fprintf(stderr, "Successful in sdp request - Now find the attribute ServiceName\n");

         /*----------------------------------------------------------------------*/
         /* Check the return value of the previous SDP_SERVICESEARCH_REQ for     */
         /* error.                                                               */
         /*----------------------------------------------------------------------*/
         if ( SDP_SERVICESEARCH_REQ_ERROR(sdpRequestData) )
         {
            fprintf(stderr, "Last Service Search Request failed!\n");
            conID = CREATE_SDP_ID(tmp_bd[6] /* BT line */, sdpConnectionID /* No longer a no-op */);
            ioctl(bt_cfd, BTDISCONNECT, &conID);
            close(bt_cfd);
            exit(-1);
         }

         serviceRecordCount = FORMULATE_RECORD_HANDLE_COUNT(sdpRequestData.requestResponse[7], sdpRequestData.requestResponse[8]);

         if ( serviceRecordCount > 0 )
         {
            /*-----------------------------------------------------------------*/
            /* Take one of the handles and find the ServiceName Attribute.     */
            /*-----------------------------------------------------------------*/
            serviceRecordHandle = FORMULATE_RECORD_HANDLE(sdpRequestData.requestResponse[9], 
                                                          sdpRequestData.requestResponse[10],
                                                          sdpRequestData.requestResponse[11],
                                                          sdpRequestData.requestResponse[12]);

            /*-----------------------------------------------------------------*/
            /* If the serviceRecordHandle is not 0, then proceed with the      */
            /* attribute query.                                                */
            /*-----------------------------------------------------------------*/
            if ( serviceRecordHandle > 0 )
            {
               /*----------------------------------------------------------------------*/
               /* The SDP_SERVICEATTR_REQ is a multi-byte request.                     */
               /* Service Record Handle (4 bytes) - Indicates the record handle on the */
               /* server you want to query against.                                    */
               /* Maximum Attribute Count (2 bytes) - SDP server should only return at */
               /* these number of attribute bytes.                                     */
               /* Attribute ID Data Element Sequence (N bytes) - Data Element Sequence */
               /* holding all the desired attributes to find.                          */
               /*----------------------------------------------------------------------*/
               memset(&sdpRequestData, 0x00, sizeof(bt_sdp_request));

               /*----------------------------------------------------------------------*/
               /* Insert elements.                                                     */
               /*----------------------------------------------------------------------*/
               sdpRequestData.pduPayload[0] = (serviceRecordHandle >> 24) & 0xff;
               sdpRequestData.pduPayload[1] = (serviceRecordHandle >> 16) & 0xff;
               sdpRequestData.pduPayload[2] = (serviceRecordHandle >>  8) & 0xff;
               sdpRequestData.pduPayload[3] =  serviceRecordHandle        & 0xff;

               /*----------------------------------------------------------------------*/
               /* For the maximum attribute count.  Set this to 128 for now.           */
               /*----------------------------------------------------------------------*/
               sdpRequestData.pduPayload[4] = 0;
               sdpRequestData.pduPayload[5] = 128;

               /*----------------------------------------------------------------------*/
               /* Attribute IDs - Data Element sequence.                               */
               /*----------------------------------------------------------------------*/
               sdpRequestData.pduPayload[6] = 0x35;
               sdpRequestData.pduPayload[7] = 0x03;  /* DES length */
               sdpRequestData.pduPayload[8] = 0x19;
               sdpRequestData.pduPayload[9] = (UUID_SERVICE_NAME_ATTRIBUTE >> 8) & 0xff;
               sdpRequestData.pduPayload[10] = UUID_SERVICE_NAME_ATTRIBUTE  & 0xff;
               sdpRequestData.pduPayload[11] = 0x19;
               sdpRequestData.pduPayload[12] = (UUID_DOCUMENTATION_URL_ATTRIBUTE >> 8) & 0xff;
               sdpRequestData.pduPayload[13] = UUID_DOCUMENTATION_URL_ATTRIBUTE & 0xff;
               sdpRequestData.pduPayload[14] = 0;  /* Continuation state - None */
       
               /*----------------------------------------------------------------------*/
               /* Set the length and command.                                          */
               /*----------------------------------------------------------------------*/
               sdpRequestData.pduLength = 15;
               sdpRequestData.sdpCommand = SDP_SERVICEATTR_REQ;
               sdpRequestData.conID = CREATE_SDP_ID(tmp_bd[6] /* BT line */, sdpConnectionID /* No longer a no-op */);

               /*----------------------------------------------------------------------*/
               /* Issue the SDP attribute lookup.                                      */
               /*----------------------------------------------------------------------*/
               if ( ioctl(bt_cfd, BT_SDP_REQUEST, &sdpRequestData) < 0 )
               {
                  fprintf(stderr, "Can't issue a SDP_SERVICEATTR_REQ!\n");
                  conID = CREATE_SDP_ID(tmp_bd[6] /* BT line */, sdpConnectionID /* No longer a no-op */);
                  ioctl(bt_cfd, BTDISCONNECT, &conID);
                  close(bt_cfd);
                  exit(-1);
               }

            }  /* End of if serviceRecordHandle > 0 */

         }  /* End of serviceRecordCount > 0 */

      }  /* End of original ioctl() on SDP_SERVICESEARCH_REQ */
   
      /*------------------------------------------------------------------------*/
      /* Close the SDP connection.                                              */
      /*------------------------------------------------------------------------*/
      conID = CREATE_SDP_ID(tmp_bd[6] /* BT line */, sdpConnectionID /* No longer a no-op */);
      ioctl(bt_cfd, BTDISCONNECT, &conID);
      close(bt_cfd);
   }

   return 0;

}  /* End of test2 program */