//
//  bt_sdp_server.c
//
//  Bluetooth Protocol Stack - SDP Server
//  Copyright (C) 2013-2018 Toyohiko Togashi tog001@nifty.com
//
//
//  This program is free software; you can redistribute it and/or modify it under the terms of the
//  GNU General Public License as published by the Free Software Foundation; either version 3
//  of the License, or (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
//  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//  See the GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License along with this program.
//  If not, see <http://www.gnu.org/licenses/>
//
//
//  Reference:
//      Bluetooth SIG (www.bluetooth.com)
//          BLUETOOTH SPECIFICATION Version 2.0 + EDR
//          Volume 3: Core System Package [Host volume]
//          PartB: Service Discovery Protocol (SDP) Specification
//
//  Update history
//  ---------- ----- -------------------------------------------
//  2013.02.01 v0.0  First cording
//  2013.04.21 v0.1  Commit
//  2015.02.06 v0.3a Separated from bt_sdp_server.c
//  2015.02.06 v0.3a Appended the SDP record of PnP Information and GATT
//  2015.02.06 v0.3a Securely it tried to do search processing(but not support AttributeIDList condition)
//  2017.01.03 v0.3e argument handle -> cb_channel
//  2017.03.10 v0.4  Supported an AVDTP (The new "bt_sdp_data.c" is independent of the master record)
//  2018.02.10 v0.4a Bug fix (Bad message is ServiceAttributeResponse AttributeList)
//
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "bt_spec_sdp.h"
//#include "bt_spec_gatt.h"             // DEL 2017.03.10
//#include "bt_spec_l2cap.h"            // DEL 2017.03.10
#include "bt_l2cap_cb_channel.h"        // Channel manage table     ADD 2017.01.03
#include "bt_sdp_server.h"              // ADD 2017.03.10

//#define DEBUG
#define MAX(a,b)    ((a) > (b) ? (a) : (b))
#define MIN(a,b)    ((a) < (b) ? (a) : (b))

//
//  Debug
//
#ifdef DEBUG
#include <stdio.h>                      // Debug
#define DEBUGP(...)     printf(__VA_ARGS__)
#else
#define DEBUGP(...)
#endif

//
//  SDP database
//
#ifdef DELETE
const unsigned char bt_sdpMasterRecord1[] = {
  SDP_DATA_ELEMENT16_3(92),
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_ServiceRecordHandle),           SDP_DATA_UINT32_5(0x10010),
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_BrowseGroupList),               SDP_DATA_ELEMENT8_2(3),
                                                                        SDP_DATA_UUID16_3(SDP_SERVICE_CLASS_PublicBrowseRoot),
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_ServiceClassIDList),            SDP_DATA_ELEMENT8_2(3),
                                                                        SDP_DATA_UUID16_3(SDP_SERVICE_CLASS_SerialPort),
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_ServiceName),                   SDP_DATA_STRING8, 11, 'S', 'e', 'r', 'i', 'a', 'l', ' ', 'P', 'o', 'r', 't',
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_ProtocolDescriptorList),        SDP_DATA_ELEMENT8_2(12),
                                                                        SDP_DATA_ELEMENT8_2(3),         // Protocol#0
                                                                            SDP_DATA_UUID16_3(SDP_PROTOCOL_L2CAP),
                                                                        SDP_DATA_ELEMENT8_2(5),         // Protocol#1
                                                                            SDP_DATA_UUID16_3(SDP_PROTOCOL_RFCOMM),
                                                                            SDP_DATA_UINT8_2(1),        // Server Channel# 1..30
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_BluetoothProfileDescriptorList),SDP_DATA_ELEMENT8_2(8),
                                                                        SDP_DATA_ELEMENT8_2(6),         // Profile#0
                                                                            SDP_DATA_UUID16_3(SDP_SERVICE_CLASS_SerialPort),    // Supported Profiles
                                                                            SDP_DATA_UINT16_3(0x0102),  // Profile Version
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_LanguageBaseAttributeIDList),   SDP_DATA_ELEMENT8_2(9),
                                                                        SDP_DATA_UINT16, 'e', 'n',      // Language code: ISO639: english
                                                                        SDP_DATA_UINT16_3(106),         // Encode: IANA's database: UTF-8
                                                                        SDP_DATA_UINT16_3(0x0100),      // ?
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_ServiceRecordState),            SDP_DATA_UINT32_5(15),
};
const unsigned char bt_sdpMasterRecord2[] = {
  SDP_DATA_ELEMENT16_3(57),
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_ServiceRecordHandle),           SDP_DATA_UINT32_5(0x10020),
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_BrowseGroupList),               SDP_DATA_ELEMENT8_2(3),
                                                                        SDP_DATA_UUID16_3(SDP_SERVICE_CLASS_PublicBrowseRoot),
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_ServiceClassIDList),            SDP_DATA_ELEMENT8_2(3),
                                                                        SDP_DATA_UUID16_3(GATT_Services_Generic_Access_Profile),
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_ServiceName),                   SDP_DATA_STRING8, 4, 'G', 'A', 'T', 'T',
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_ProtocolDescriptorList),        SDP_DATA_ELEMENT8_2(19),
                                                                        SDP_DATA_ELEMENT8_2(6),         // Protocol#0
                                                                            SDP_DATA_UUID16_3(SDP_PROTOCOL_L2CAP),
                                                                            SDP_DATA_UINT16_3(L2CAP_PDU_PSM_ATT),
                                                                        SDP_DATA_ELEMENT8_2(9),         // Protocol#1
                                                                            SDP_DATA_UUID16_3(SDP_PROTOCOL_ATT),
                                                                            SDP_DATA_UINT16_3(0x0000),  //     Start handle
                                                                            SDP_DATA_UINT16_3(0xffff),  //     End handle
};
const unsigned char bt_sdpMasterRecord3[] = {
  SDP_DATA_ELEMENT16_3(72),
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_ServiceRecordHandle),           SDP_DATA_UINT32_5(0x10030),
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_BrowseGroupList),               SDP_DATA_ELEMENT8_2(3),
                                                                        SDP_DATA_UUID16_3(SDP_SERVICE_CLASS_PublicBrowseRoot),
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_ServiceClassIDList),            SDP_DATA_ELEMENT8_2(3),
                                                                        SDP_DATA_UUID16_3(SDP_SERVICE_CLASS_PnPInformation),
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_ServiceDescription),            SDP_DATA_STRING8, 8, 'P', 'n', 'P', ' ', 'I', 'n', 'f', 'o',
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_DID_SpecificationID),           SDP_DATA_UINT16_3(SDP_DID_SpecificationID),
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_DID_PrimaryRecord),             SDP_DATA_BOOL8_2_TRUE,
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_DID_VenderIDSource),            SDP_DATA_UINT16_3(SDP_DID_VenderIDSource_USB),
#if defined(USE_STM32F4_DISCOVERY)
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_DID_VendorID),                  SDP_DATA_UINT16_3(0x0483),  // STM
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_DID_ProductID),                 SDP_DATA_UINT16_3(0x5740),  //   STM32F407
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_DID_Version),                   SDP_DATA_UINT16_3(0x0031),  //     v0.3.1
#else
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_DID_VendorID),                  SDP_DATA_UINT16_3(0x04d8),  // Microchip
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_DID_ProductID),                 SDP_DATA_UINT16_3(0x00e0),  //   PIC32 Starter kit
    SDP_DATA_UINT16_3(SDP_ATTRIBUTE_DID_Version),                   SDP_DATA_UINT16_3(0x0031),  //
#endif
};

#define BT_SDP_MASTER_TABLE_SIZE    3

enum bt_sdp_flag {
    NOT_FOUND = 0,
    FOUND
};
struct bt_sdpMasterTable {
    unsigned char      *record;
    unsigned long       handle;
    enum bt_sdp_flag    flag;
} bt_sdpMasterTable[BT_SDP_MASTER_TABLE_SIZE] = {
    {(unsigned char *)bt_sdpMasterRecord1, 0x10010, 0},
    {(unsigned char *)bt_sdpMasterRecord2, 0x10020, 0},
    {(unsigned char *)bt_sdpMasterRecord3, 0x10030, 0},
};

int bt_sdpRecordNum = BT_SDP_MASTER_TABLE_SIZE;
#endif

size_t bt_sdpGetElementSize(unsigned char *element){
    size_t  s;

    switch(SDP_DATA_ELEMENT_SIZE(*element++)) {
    case SDP_DATA_ELEMENT_SIZE_8BIT:        s = 1 + 1;                          break;
    case SDP_DATA_ELEMENT_SIZE_16BIT:       s = 1 + 2;                          break;
    case SDP_DATA_ELEMENT_SIZE_32BIT:       s = 1 + 4;                          break;
    case SDP_DATA_ELEMENT_SIZE_64BIT:       s = 1 + 8;                          break;
    case SDP_DATA_ELEMENT_SIZE_128BIT:      s = 1 + 16;                         break;
    case SDP_DATA_ELEMENT_SIZE_VARIABLE_8:  s = 1 + 1 + *element;               break;
    case SDP_DATA_ELEMENT_SIZE_VARIABLE_16: s = 1 + 2 + SDP_UINT16(element);    break;
    case SDP_DATA_ELEMENT_SIZE_VARIABLE_32: s = 1 + 4 + SDP_UINT32(element);    break;
    default:                                s = 1;                              break;
    }
    return(s);
}

size_t bt_sdpGetElementDescriptorSize(unsigned char *element){
    size_t  s;

    switch(SDP_DATA_ELEMENT_SIZE(*element)) {
    case SDP_DATA_ELEMENT_SIZE_VARIABLE_8:  s = 1 + 1;  break;
    case SDP_DATA_ELEMENT_SIZE_VARIABLE_16: s = 1 + 2;  break;
    case SDP_DATA_ELEMENT_SIZE_VARIABLE_32: s = 1 + 4;  break;
    default:                                s = 1;      break;
    }
    return(s);
}

unsigned long bt_sdpGetElementUint(unsigned char *element){
    unsigned long   l;

    l = 0;
    if(SDP_DATA_ELEMENT_TYPE(*element) == SDP_DATA_ELEMENT_TYPE_UNSIGNED_INTEGER) {
        switch(SDP_DATA_ELEMENT_SIZE(*element++)) {
        case SDP_DATA_ELEMENT_SIZE_8BIT:    l = *element;               break;
        case SDP_DATA_ELEMENT_SIZE_16BIT:   l = SDP_UINT16(element);    break;
        case SDP_DATA_ELEMENT_SIZE_32BIT:   l = SDP_UINT16(element);    break;
        case SDP_DATA_ELEMENT_SIZE_64BIT:                               break;
        case SDP_DATA_ELEMENT_SIZE_128BIT:                              break;
        default:                                                        break;
        }
    };
    return(l);
}

enum bt_sdp_flag    bt_sdpFindUUID(unsigned char *element, unsigned char *uuid) {
    enum bt_sdp_flag    f;

    f = NOT_FOUND;
    if (SDP_DATA_ELEMENT_TYPE(*uuid) == SDP_DATA_ELEMENT_TYPE_UUID) {
        switch(SDP_DATA_ELEMENT_TYPE(*element)){
        case SDP_DATA_ELEMENT_TYPE_UUID:
            if ((SDP_DATA_ELEMENT_SIZE(*element) == SDP_DATA_ELEMENT_SIZE_16BIT) &&
                (SDP_DATA_ELEMENT_SIZE(*uuid)    == SDP_DATA_ELEMENT_SIZE_16BIT) &&
                (element[1] == uuid[1]) &&
                (element[2] == uuid[2])) {
                f = FOUND;
            }
            break;
        case SDP_DATA_ELEMENT_TYPE_ELEMENT_SEQUENCE:
        case SDP_DATA_ELEMENT_TYPE_ELEMENT_ALTERNATIVE:
            {
                size_t          l;
                size_t          d;
                unsigned char   *e;

                d = bt_sdpGetElementDescriptorSize(element);
                l = bt_sdpGetElementSize(element) - d;
                e = element + d;
                while(l > 0) {
                    size_t  n;

                    if ((f = bt_sdpFindUUID(e, uuid)) == FOUND) {
                        break;
                    }
                    n = bt_sdpGetElementSize(e);
                    e += n;
                    l -= n;
                }
            }
            break;
        default:
            break;
        }
    } else if (SDP_DATA_ELEMENT_TYPE(*uuid) == SDP_DATA_ELEMENT_TYPE_ELEMENT_SEQUENCE){
        {
            size_t          l;
            size_t          d;
            unsigned char   *u;

            d = bt_sdpGetElementDescriptorSize(uuid);
            l = bt_sdpGetElementSize(uuid) - d;
            u = uuid + d;
            while(l > 0) {
                size_t  n;

                if ((f = bt_sdpFindUUID(element, u)) == FOUND) {
                    break;
                }
                n = bt_sdpGetElementSize(u);
                u += n;
                l -= n;
            }
        }
    }
    return(f);
}

#ifdef DEBUG
unsigned char *bt_sdpDebugPrintElem(unsigned char *elem) {
	int t;
	int s;
	char *q;
	size_t l;
	unsigned int i;

	t = SDP_DATA_ELEMENT_TYPE(*elem);
	s = SDP_DATA_ELEMENT_SIZE(*elem);
	elem++;

	switch(t) {
	case SDP_DATA_ELEMENT_TYPE_UNSIGNED_INTEGER:
		switch(s){
		case SDP_DATA_ELEMENT_SIZE_8BIT:
			DEBUGP("uint=0x%02x", *elem++);
			break;
		case SDP_DATA_ELEMENT_SIZE_16BIT:
			DEBUGP("uint=0x%04x", (*elem << 8) | *(elem+1));
			elem += 2;
			break;
		case SDP_DATA_ELEMENT_SIZE_32BIT:
			DEBUGP("uint=0x%08x", (*elem << 24) | (*(elem+1) << 16) | (*(elem+2) << 8) | *(elem+3));
			elem += 4;
			break;
		case SDP_DATA_ELEMENT_SIZE_64BIT:
			DEBUGP("uint=0x");
			for(i = 0; i < 8; i++) {
				DEBUGP("%02x", *elem++);
			}
			break;
		case SDP_DATA_ELEMENT_SIZE_128BIT:
			DEBUGP("uint=0x");
			for(i = 0; i < 16; i++) {
				DEBUGP("%02x", *elem++);
			}
			break;
		default:
			printf("uintUnknownSize(%x)",s);
			break;
		}
		break;
	case SDP_DATA_ELEMENT_TYPE_SIGNED_INTEGER:
		switch(s){
		case SDP_DATA_ELEMENT_SIZE_8BIT:
			q = (char *)elem++;
			DEBUGP("int=%d", *q);
			break;
		case SDP_DATA_ELEMENT_SIZE_16BIT:
			DEBUGP("int=%d", (short)((*elem << 8) | *(elem+1)));
			elem += 2;
			break;
		case SDP_DATA_ELEMENT_SIZE_32BIT:
			DEBUGP("int=%ld", (long)((*elem << 24) | (*(elem+1) << 16) | (*(elem+2) << 8) | *(elem+3)));
			elem += 4;
			break;
		case SDP_DATA_ELEMENT_SIZE_64BIT:
			DEBUGP("int=0x");
			for(i = 0; i < 8; i++) {
				DEBUGP("%02x", *elem++);
			}
			break;
		case SDP_DATA_ELEMENT_SIZE_128BIT:
			DEBUGP("int=0x");
			for(i = 0; i < 16; i++) {
				DEBUGP("%02x", *elem++);
			}
			break;
		default:
			printf("intUnknownSize(%x)", s);
			break;
		}
		break;
	case SDP_DATA_ELEMENT_TYPE_UUID:
		switch(s){
		case SDP_DATA_ELEMENT_SIZE_16BIT:
			DEBUGP("uuid=0x%04x", *elem << 8 | *(elem+1));
			elem += 2;
			break;
		case SDP_DATA_ELEMENT_SIZE_32BIT:
			DEBUGP("uuid=0x");
			for(i = 0; i < 4; i++) {
				DEBUGP("%02x", *elem++);
			}
			break;
		case SDP_DATA_ELEMENT_SIZE_128BIT:
			DEBUGP("uuid=0x");
			for(i = 0; i < 8; i++) {
				DEBUGP("%02x", *elem++);
			}
			break;
		default:
			DEBUGP("uuidUnknownSize(%x)", s);
			break;
		}
		break;
	case SDP_DATA_ELEMENT_TYPE_TEXT:
	case SDP_DATA_ELEMENT_TYPE_URL:
		switch(s){
		case SDP_DATA_ELEMENT_SIZE_VARIABLE_8:
			l = *elem++;
			break;
		case SDP_DATA_ELEMENT_SIZE_VARIABLE_16:
			l = (*elem << 8) | *(elem+1);
			elem += 2;
			break;
		case SDP_DATA_ELEMENT_SIZE_VARIABLE_32:
			l = (*elem << 24) | (*(elem+1) << 16) | (*(elem+2) << 8) | *(elem+3);
			elem += 4;
			break;
		default:
			DEBUGP("textUnknownSize(%x)", s);
			l = 0;
			break;
		}
		DEBUGP("'");
		for(; l > 0; l--) {
			DEBUGP("%.1s", elem++);
		}
		DEBUGP("'");
		break;
	case SDP_DATA_ELEMENT_TYPE_BOOLEAN:
		DEBUGP("bool=%s", *elem++ ? "true" : "false");
		break;
	case SDP_DATA_ELEMENT_TYPE_ELEMENT_SEQUENCE:
	case SDP_DATA_ELEMENT_TYPE_ELEMENT_ALTERNATIVE:
		switch(s){
		case SDP_DATA_ELEMENT_SIZE_VARIABLE_8:
			l = *elem++;
			break;
		case SDP_DATA_ELEMENT_SIZE_VARIABLE_16:
			l = (*elem << 8) | *(elem+1);
			elem += 2;
			break;
		case SDP_DATA_ELEMENT_SIZE_VARIABLE_32:
			l = (*elem << 24) | (*(elem+1) << 16) | (*(elem+2) << 8) | *(elem+3);
			elem += 4;
			break;
		default:
			DEBUGP("elemUnknownSize(%x)",s);
			l = 0;
			break;
		}
		DEBUGP("{");
		while(l > 0) {
			size_t	ll;

			ll = bt_sdpGetElementSize(elem);
			elem = bt_sdpDebugPrintElem(elem);
			l -= ll;
			DEBUGP(" ");
		}
		DEBUGP("}");
		break;

	default:
		DEBUGP("invalid(type=%d,size=%d)", t, s);
		break;
	}

    return(elem);
}
#else
#define bt_sdpDebugPrintElem(a)
#endif // DEBUG

//
//  Server
//
//size_t bt_sdpServer(unsigned short handle, unsigned char *inBuff, size_t inLen, unsigned char *outBuff, size_t outSize) {     // DEL 2017.01.03
size_t bt_sdpServer(struct bt_l2capChannel *ch, unsigned char *inBuff, size_t inLen, unsigned char *outBuff, size_t outSize) {  // ADD 2017.01.03
    struct bt_sdpFormat *in;
    struct bt_sdpFormat *out;
    size_t              len;

    in  = (struct bt_sdpFormat *)inBuff;
    out = (struct bt_sdpFormat *)outBuff;
    len = 0;
    if (in != NULL) {
        unsigned short  tran;
//      size_t          plen;                                               // DEL 2017.03.10

        tran = SDP_UINT16(in->TransactionID);
//      plen = SDP_UINT16(in->ParameterLength);                             // DEL 2017.03.10
        switch(in->PDU_ID) {
        case SDP_ServiceSearchRequest:
            {
                unsigned char  *ServiceSearchPattern;
                unsigned char  *MaximumServiceRecordCount; // 2byte
//              unsigned char  *ContinuationState;                          // DEL 2017.03.10
                unsigned char  *p;
                int     i;
                int     cnt;
                int     max;

                ServiceSearchPattern      = (unsigned char *)&(in->Parameter.ServiceSearchRequest.ServiceSearchPattern);
                MaximumServiceRecordCount = ServiceSearchPattern + bt_sdpGetElementSize(ServiceSearchPattern);
//              ContinuationState         = MaximumServiceRecordCount + 2;  // DEL 2017.03.10
                max = SDP_UINT16(MaximumServiceRecordCount);
                cnt = 0;
                DEBUGP("SDP: ServiceSearchRequest ServiceSearchPattern=");
                bt_sdpDebugPrintElem(ServiceSearchPattern);
                DEBUGP(" max=%d\n", max);
                for(i = 0; i < bt_sdpRecordNum; i++){
                    if ((bt_sdpMasterTable[i].flag = bt_sdpFindUUID(bt_sdpMasterTable[i].record, ServiceSearchPattern)) == FOUND) {
                        cnt++;
                    }
                }

                out->PDU_ID = SDP_ServiceSearchResponse;
                SDP_STORE16(out->TransactionID, tran);
                SDP_STORE16(out->Parameter.ServiceSearchResponse.TotalServiceRecordCount, cnt);
                SDP_STORE16(out->Parameter.ServiceSearchResponse.CurrentServiceRecordCount, MIN(cnt, max));
//              len = SDP_HEAD_SIZE + sizeof(out->Parameter.ServiceAttributeResponse);  // DEL 2018.02.10
                len = SDP_HEAD_SIZE + sizeof(out->Parameter.ServiceSearchResponse);     // ADD 2018.02.10

                p = (unsigned char *)&(out->Parameter.ServiceSearchResponse.ServiceRecordHandleList);
//              for(i = 0; i < BT_SDP_MASTER_TABLE_SIZE; i++){  // DEL 2017.03.10
                for(i = 0; i < bt_sdpRecordNum; i++){           // ADD 2017.03.10
                    if (bt_sdpMasterTable[i].flag) {
                        SDP_STORE32(p, bt_sdpMasterTable[i].handle);
                        p   += 4;
                        len += 4;
                        DEBUGP("SDP: ServiceSearchResponse hanndle=0x%08lx\n", bt_sdpMasterTable[i].handle);
                    }
                }
                *p   = 0;        // No ContinuationState
                len += 1;
                SDP_STORE16(out->ParameterLength, len - SDP_HEAD_SIZE);
            }
            break;

        case SDP_ServiceAttributeRequest:
            {
//              unsigned char  *AttributeIDList;    // DEL 2017.03.10
//              unsigned char  *ContinuationState;  // DEL 2017.03.10
                unsigned long   handle;
                unsigned char  *p;
                int             max;
                int             i;
                size_t          l;

                handle = SDP_UINT32(in->Parameter.ServiceAttributeRequest.ServiceRecordHandle);
                max    = SDP_UINT16(in->Parameter.ServiceAttributeRequest.MaximumAttributeByteCount);
//              AttributeIDList   = (unsigned char *)&(in->Parameter.ServiceAttributeRequest.AttributeIDList);  // DEL 2017.03.10
//              ContinuationState = AttributeIDList + bt_sdpGetElementSize(AttributeIDList);                    // DEL 2017.03.10
                DEBUGP("SDP: ServiceAttributeRequest handle=0x%08lx max=%d\n", handle, max);

                out->PDU_ID = SDP_ServiceAttributeResponse;
                SDP_STORE16(out->TransactionID, tran);
                len = SDP_HEAD_SIZE + sizeof(out->Parameter.ServiceAttributeResponse);
#ifdef DEL                                          // DEL START 2018.02.10
                p = (unsigned char *)&(out->Parameter.ServiceAttributeResponse.AttributeList);
                *p++ = SDP_DATA_ELEMENT16;
                *p++ = 0;   // element
                *p++ = 0;   //   size
                len += 3;
                l = 0;
                for(i = 0; i < bt_sdpRecordNum; i++){
                    if (bt_sdpMasterTable[i].handle == handle) {
                        size_t  s;
                        size_t  k;

                        s = bt_sdpGetElementSize(bt_sdpMasterTable[i].record);
                        k = len + s + 1;    // Check ContinuationState=1byte
                        if ((max > k) && (outSize > k)) {
                            memcpy(p, bt_sdpMasterTable[i].record, s);
                            p   += s;
                            l   += s;
                            len += s;
                        }
                        break;
                    }
                }
                SDP_STORE16(out->Parameter.ServiceAttributeResponse.AttributeList+1, l);        // element size
                SDP_STORE16(out->Parameter.ServiceAttributeResponse.AttributeListByteCount, l+3); // element descripter size
#else                                               // DEL END - ADD START 2018.02.10
                p = (unsigned char *)&(out->Parameter.ServiceAttributeResponse.AttributeList);
                l = 0;
                for(i = 0; i < bt_sdpRecordNum; i++){
                    if (bt_sdpMasterTable[i].handle == handle) {
                        size_t  s;
                        size_t  k;

                        s = bt_sdpGetElementSize(bt_sdpMasterTable[i].record);
                        k = len + s + 1;    // Check ContinuationState=1byte
                        if ((max > k) && (outSize > k)) {
                            memcpy(p, bt_sdpMasterTable[i].record, s);
                            p   += s;
                            l   += s;
                            len += s;
                        }
                        break;
                    }
                }
                SDP_STORE16(out->Parameter.ServiceAttributeResponse.AttributeListByteCount, l);
#endif                                              // ADD END 2018.02.10
                *p   = 0;        // No ContinuationState
                len += 1;

                SDP_STORE16(out->ParameterLength, len - SDP_HEAD_SIZE);
                DEBUGP("SDP: ServiceAttributeResponse attr=");
                bt_sdpDebugPrintElem(out->Parameter.ServiceAttributeResponse.AttributeList);
                DEBUGP("\n");
            }
            break;
        case SDP_ServiceSearchAttributeRequest:
            {
                unsigned char  *ServiceSearchPattern;
                unsigned char  *MaximumAttributeByteCount;  // 2byte
//              unsigned char  *AttributeIDList;            // DEL 2017.03.10
//              unsigned char  *ContinuationState;          // DEL 2017.03.10
                unsigned char  *p;
                size_t          max;
                size_t          l;
                int             i;

                ServiceSearchPattern      = (unsigned char *)&(in->Parameter.ServiceSearchAttributeRequest.ServiceSearchPattern);
                MaximumAttributeByteCount = ServiceSearchPattern + bt_sdpGetElementSize(ServiceSearchPattern);
//              AttributeIDList           = MaximumAttributeByteCount + 2;                         	    // DEL 2017.03.10
//              ContinuationState         = AttributeIDList + bt_sdpGetElementSize(AttributeIDList);    // DEL 2017.03.10
                max = SDP_UINT16(MaximumAttributeByteCount);
                DEBUGP("SDP: ServiceSearchAttributeRequest pattern=");
                bt_sdpDebugPrintElem(ServiceSearchPattern);
                DEBUGP(" max=%d\n", max);

                out->PDU_ID = SDP_ServiceSearchAttributeResponse;
                SDP_STORE16(out->TransactionID, tran);
                len = SDP_HEAD_SIZE + sizeof(out->Parameter.ServiceSearchAttributeResponse);

//              p = (unsigned char *)&(out->Parameter.ServiceSearchAttributeResponse.AttributeList);    // DEL 2018.02.10
                p = (unsigned char *)&(out->Parameter.ServiceSearchAttributeResponse.AttributeLists);   // ADD 2018.02.10
                *p++ = SDP_DATA_ELEMENT16;
                *p++ = 0;   // element
                *p++ = 0;   //   size
                len += 3;
                l = 0;
                for(i = 0; i < bt_sdpRecordNum; i++){
                    if (bt_sdpFindUUID(bt_sdpMasterTable[i].record, ServiceSearchPattern)) {
                        size_t  s;
                        size_t  k;

                        s = bt_sdpGetElementSize(bt_sdpMasterTable[i].record);
                        k = len + s + 1;    // Check ContinuationState=1byte
                        if ((max > k) && (outSize > k)) {
                            memcpy(p, bt_sdpMasterTable[i].record, s);
                            p   += s;
                            l   += s;
                            len += s;
                        }
                    }
                }
//              SDP_STORE16(out->Parameter.ServiceSearchAttributeResponse.AttributeList+1, l);              // element size             DEL 2018.02.10
//              SDP_STORE16(out->Parameter.ServiceSearchAttributeResponse.AttributeListByteCount, l+3);     // element descripter size  DEL 2018.02.10
                SDP_STORE16(out->Parameter.ServiceSearchAttributeResponse.AttributeLists+1, l);             // element size             ADD 2018.02.10
                SDP_STORE16(out->Parameter.ServiceSearchAttributeResponse.AttributeListsByteCount, l+3);	// element descripter size  ADD 2018.02.10
                *p   = 0;        // No ContinuationState
                len += 1;
                SDP_STORE16(out->ParameterLength, len - SDP_HEAD_SIZE);
                DEBUGP("SDP: ServiceSearchAttributeResponse attr=");
                bt_sdpDebugPrintElem(out->Parameter.ServiceSearchAttributeResponse.AttributeLists);
                DEBUGP("\n");
            }
            break;
        default:
            DEBUGP("SDP: Unsupported Request %02x\n", in->PDU_ID);
            out->PDU_ID = SDP_ErrorResponse;
            SDP_STORE16(out->TransactionID, tran);
            SDP_STORE16(out->ParameterLength, sizeof(out->Parameter.ErrorResponse));
            SDP_STORE16(out->Parameter.ErrorResponse.ErrorCode, SDP_ErrorCode_Invalid_request_syntax);
            len = SDP_HEAD_SIZE + sizeof(out->Parameter.ErrorResponse);
            break;
        }
    }
    return(len);
}
