1 /****************************************************************************** 2 * 3 * Copyright (C) 2008-2012 Broadcom Corporation 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19 /****************************************************************************** 20 * 21 * this file contains the main GATT server attributes access request 22 * handling functions. 23 * 24 ******************************************************************************/ 25 26 #include "bt_target.h" 27 28 #include "gatt_api.h" 29 #include "gatt_int.h" 30 31 #if BLE_INCLUDED == TRUE 32 33 #define GATTP_MAX_NUM_INC_SVR 0 34 #define GATTP_MAX_CHAR_NUM 2 35 #define GATTP_MAX_ATTR_NUM (GATTP_MAX_CHAR_NUM * 2 + GATTP_MAX_NUM_INC_SVR + 1) 36 #define GATTP_MAX_CHAR_VALUE_SIZE 50 37 38 #ifndef GATTP_ATTR_DB_SIZE 39 #define GATTP_ATTR_DB_SIZE GATT_DB_MEM_SIZE(GATTP_MAX_NUM_INC_SVR, GATTP_MAX_CHAR_NUM, GATTP_MAX_CHAR_VALUE_SIZE) 40 #endif 41 42 static void gatt_profile_request_cback (UINT16 conn_id, UINT32 trans_id, UINT8 op_code, tGATTS_DATA *p_data); 43 static void gatt_profile_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected, tGATT_DISCONN_REASON reason); 44 45 static tGATT_CBACK gatt_profile_cback = 46 { 47 gatt_profile_connect_cback, 48 NULL, 49 NULL, 50 NULL, 51 gatt_profile_request_cback 52 } ; 53 54 /******************************************************************************* 55 ** 56 ** Function gatt_profile_find_conn_id_by_bd_addr 57 ** 58 ** Description The function searches all LCB with macthing bd address 59 ** 60 ** Returns total number of clcb found. 61 ** 62 *******************************************************************************/ 63 UINT16 gatt_profile_find_conn_id_by_bd_addr(BD_ADDR bda) 64 { 65 UINT8 i_clcb; 66 tGATT_PROFILE_CLCB *p_clcb = NULL; 67 68 for (i_clcb = 0, p_clcb= gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS; i_clcb++, p_clcb++) 69 { 70 if (p_clcb->in_use && p_clcb->connected && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN)) 71 { 72 return p_clcb->conn_id; 73 } 74 } 75 76 return GATT_INVALID_CONN_ID; 77 } 78 79 /******************************************************************************* 80 ** 81 ** Function gatt_profile_find_clcb_by_bd_addr 82 ** 83 ** Description The function searches all LCBs with macthing bd address. 84 ** 85 ** Returns Pointer to the found link conenction control block. 86 ** 87 *******************************************************************************/ 88 tGATT_PROFILE_CLCB *gatt_profile_find_clcb_by_bd_addr(BD_ADDR bda) 89 { 90 UINT8 i_clcb; 91 tGATT_PROFILE_CLCB *p_clcb = NULL; 92 93 for (i_clcb = 0, p_clcb= gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS; i_clcb++, p_clcb++) 94 { 95 if (p_clcb->in_use && p_clcb->connected && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN)) 96 { 97 return p_clcb; 98 } 99 } 100 101 return p_clcb; 102 } 103 104 /******************************************************************************* 105 ** 106 ** Function gatt_profile_clcb_alloc 107 ** 108 ** Description The function allocates a GATT profile connection link control block 109 ** 110 ** Returns NULL if not found. Otherwise pointer to the connection link block. 111 ** 112 *******************************************************************************/ 113 tGATT_PROFILE_CLCB *gatt_profile_clcb_alloc (UINT16 conn_id, BD_ADDR bda) 114 { 115 UINT8 i_clcb = 0; 116 tGATT_PROFILE_CLCB *p_clcb = NULL; 117 118 for (i_clcb = 0, p_clcb= gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS; i_clcb++, p_clcb++) 119 { 120 if (!p_clcb->in_use) 121 { 122 p_clcb->in_use = TRUE; 123 p_clcb->conn_id = conn_id; 124 p_clcb->connected = TRUE; 125 memcpy (p_clcb->bda, bda, BD_ADDR_LEN); 126 break; 127 } 128 } 129 return p_clcb; 130 } 131 /******************************************************************************* 132 ** 133 ** Function gatt_profile_clcb_dealloc 134 ** 135 ** Description The function deallocates a GATT profile connection link control block 136 ** 137 ** Returns NTrue the deallocation is successful 138 ** 139 *******************************************************************************/ 140 BOOLEAN gatt_profile_clcb_dealloc (UINT16 conn_id) 141 { 142 UINT8 i_clcb = 0; 143 tGATT_PROFILE_CLCB *p_clcb = NULL; 144 145 for (i_clcb = 0, p_clcb= gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS; i_clcb++, p_clcb++) 146 { 147 if (p_clcb->in_use && p_clcb->connected && (p_clcb->conn_id == conn_id)) 148 { 149 memset(p_clcb, 0, sizeof(tGATT_PROFILE_CLCB)); 150 return TRUE; 151 } 152 } 153 return FALSE; 154 } 155 156 157 /******************************************************************************* 158 ** 159 ** Function gatt_profile_request_cback 160 ** 161 ** Description GATT profile attribute access request callback. 162 ** 163 ** Returns void. 164 ** 165 *******************************************************************************/ 166 static void gatt_profile_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE type, 167 tGATTS_DATA *p_data) 168 { 169 UINT8 status = GATT_INVALID_PDU; 170 tGATTS_RSP rsp_msg ; 171 BOOLEAN ignore = FALSE; 172 173 memset(&rsp_msg, 0, sizeof(tGATTS_RSP)); 174 175 switch (type) 176 { 177 case GATTS_REQ_TYPE_READ: 178 status = GATT_READ_NOT_PERMIT; 179 break; 180 181 case GATTS_REQ_TYPE_WRITE: 182 status = GATT_WRITE_NOT_PERMIT; 183 break; 184 185 case GATTS_REQ_TYPE_WRITE_EXEC: 186 case GATT_CMD_WRITE: 187 ignore = TRUE; 188 GATT_TRACE_EVENT0("Ignore GATT_REQ_EXEC_WRITE/WRITE_CMD" ); 189 break; 190 191 case GATTS_REQ_TYPE_MTU: 192 GATT_TRACE_EVENT1("Get MTU exchange new mtu size: %d", p_data->mtu); 193 ignore = TRUE; 194 break; 195 196 default: 197 GATT_TRACE_EVENT1("Unknown/unexpected LE GAP ATT request: 0x%02x", type); 198 break; 199 } 200 201 if (!ignore) 202 GATTS_SendRsp (conn_id, trans_id, status, &rsp_msg); 203 204 } 205 206 /******************************************************************************* 207 ** 208 ** Function gatt_profile_connect_cback 209 ** 210 ** Description Gatt profile connection callback. 211 ** 212 ** Returns void 213 ** 214 *******************************************************************************/ 215 static void gatt_profile_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, 216 BOOLEAN connected, tGATT_DISCONN_REASON reason) 217 { 218 GATT_TRACE_EVENT5 ("gatt_profile_connect_cback: from %08x%04x connected:%d conn_id=%d reason = 0x%04x", 219 (bda[0]<<24)+(bda[1]<<16)+(bda[2]<<8)+bda[3], 220 (bda[4]<<8)+bda[5], connected, conn_id, reason); 221 222 if (connected) 223 { 224 if (gatt_profile_clcb_alloc(conn_id, bda) == NULL) 225 { 226 GATT_TRACE_ERROR0 ("gatt_profile_connect_cback: no_resource"); 227 return; 228 } 229 } 230 else 231 { 232 gatt_profile_clcb_dealloc(conn_id); 233 } 234 235 } 236 237 /******************************************************************************* 238 ** 239 ** Function gatt_profile_db_init 240 ** 241 ** Description Initializa the GATT profile attribute database. 242 ** 243 *******************************************************************************/ 244 void gatt_profile_db_init (void) 245 { 246 tBT_UUID app_uuid = {LEN_UUID_128, {0}}; 247 tBT_UUID uuid = {LEN_UUID_16, {UUID_SERVCLASS_GATT_SERVER}}; 248 UINT16 service_handle = 0; 249 tGATT_STATUS status; 250 251 /* Fill our internal UUID with a fixed pattern 0x81 */ 252 memset (&app_uuid.uu.uuid128, 0x81, LEN_UUID_128); 253 254 255 /* Create a GATT profile service */ 256 gatt_cb.gatt_if = GATT_Register(&app_uuid, &gatt_profile_cback); 257 GATT_StartIf(gatt_cb.gatt_if); 258 259 service_handle = GATTS_CreateService (gatt_cb.gatt_if , &uuid, 0, GATTP_MAX_ATTR_NUM, TRUE); 260 /* add Service Changed characteristic 261 */ 262 uuid.uu.uuid16 = gatt_cb.gattp_attr.uuid = GATT_UUID_GATT_SRV_CHGD; 263 gatt_cb.gattp_attr.service_change = 0; 264 gatt_cb.gattp_attr.handle = 265 gatt_cb.handle_of_h_r = GATTS_AddCharacteristic(service_handle, &uuid, 0, GATT_CHAR_PROP_BIT_INDICATE); 266 267 GATT_TRACE_DEBUG1 ("gatt_profile_db_init: handle of service changed%d", 268 gatt_cb.handle_of_h_r ); 269 270 /* start service 271 */ 272 status = GATTS_StartService (gatt_cb.gatt_if, service_handle, GATTP_TRANSPORT_SUPPORTED ); 273 274 GATT_TRACE_DEBUG2 ("gatt_profile_db_init: gatt_if=%d start status%d", 275 gatt_cb.gatt_if, status); 276 } 277 278 #endif /* BLE_INCLUDED */ 279