1 /****************************************************************************** 2 * 3 * Copyright (C) 2010-2013 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 * 22 * This file contains the LLCP Service Discovery 23 * 24 ******************************************************************************/ 25 26 #include <string.h> 27 #include "gki.h" 28 #include "nfc_target.h" 29 #include "bt_types.h" 30 #include "llcp_api.h" 31 #include "llcp_int.h" 32 #include "llcp_defs.h" 33 34 /******************************************************************************* 35 ** 36 ** Function llcp_sdp_proc_data 37 ** 38 ** Description Do nothing 39 ** 40 ** 41 ** Returns void 42 ** 43 *******************************************************************************/ 44 void llcp_sdp_proc_data (tLLCP_SAP_CBACK_DATA *p_data) 45 { 46 /* 47 ** Do nothing 48 ** llcp_sdp_proc_SNL () is called by link layer 49 */ 50 } 51 52 /******************************************************************************* 53 ** 54 ** Function llcp_sdp_check_send_snl 55 ** 56 ** Description Enqueue Service Name Lookup PDU into sig_xmit_q for transmitting 57 ** 58 ** 59 ** Returns void 60 ** 61 *******************************************************************************/ 62 void llcp_sdp_check_send_snl (void) 63 { 64 UINT8 *p; 65 66 if (llcp_cb.sdp_cb.p_snl) 67 { 68 LLCP_TRACE_DEBUG0 ("SDP: llcp_sdp_check_send_snl ()"); 69 70 llcp_cb.sdp_cb.p_snl->len += LLCP_PDU_HEADER_SIZE; 71 llcp_cb.sdp_cb.p_snl->offset -= LLCP_PDU_HEADER_SIZE; 72 73 p = (UINT8 *) (llcp_cb.sdp_cb.p_snl + 1) + llcp_cb.sdp_cb.p_snl->offset; 74 UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (LLCP_SAP_SDP, LLCP_PDU_SNL_TYPE, LLCP_SAP_SDP )); 75 76 GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, llcp_cb.sdp_cb.p_snl); 77 llcp_cb.sdp_cb.p_snl = NULL; 78 } 79 } 80 81 /******************************************************************************* 82 ** 83 ** Function llcp_sdp_add_sdreq 84 ** 85 ** Description Add Service Discovery Request into SNL PDU 86 ** 87 ** 88 ** Returns void 89 ** 90 *******************************************************************************/ 91 static void llcp_sdp_add_sdreq (UINT8 tid, char *p_name) 92 { 93 UINT8 *p; 94 UINT16 name_len = (UINT16) strlen (p_name); 95 96 p = (UINT8 *) (llcp_cb.sdp_cb.p_snl + 1) + llcp_cb.sdp_cb.p_snl->offset + llcp_cb.sdp_cb.p_snl->len; 97 98 UINT8_TO_BE_STREAM (p, LLCP_SDREQ_TYPE); 99 UINT8_TO_BE_STREAM (p, (1 + name_len)); 100 UINT8_TO_BE_STREAM (p, tid); 101 ARRAY_TO_BE_STREAM (p, p_name, name_len); 102 103 llcp_cb.sdp_cb.p_snl->len += LLCP_SDREQ_MIN_LEN + name_len; 104 } 105 106 /******************************************************************************* 107 ** 108 ** Function llcp_sdp_send_sdreq 109 ** 110 ** Description Send Service Discovery Request 111 ** 112 ** 113 ** Returns LLCP_STATUS 114 ** 115 *******************************************************************************/ 116 tLLCP_STATUS llcp_sdp_send_sdreq (UINT8 tid, char *p_name) 117 { 118 tLLCP_STATUS status; 119 UINT16 name_len; 120 UINT16 available_bytes; 121 122 LLCP_TRACE_DEBUG2 ("llcp_sdp_send_sdreq (): tid=0x%x, ServiceName=%s", tid, p_name); 123 124 /* if there is no pending SNL */ 125 if (!llcp_cb.sdp_cb.p_snl) 126 { 127 llcp_cb.sdp_cb.p_snl = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID); 128 129 if (llcp_cb.sdp_cb.p_snl) 130 { 131 llcp_cb.sdp_cb.p_snl->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE + LLCP_PDU_HEADER_SIZE; 132 llcp_cb.sdp_cb.p_snl->len = 0; 133 } 134 } 135 136 if (llcp_cb.sdp_cb.p_snl) 137 { 138 available_bytes = GKI_get_buf_size (llcp_cb.sdp_cb.p_snl) 139 - BT_HDR_SIZE - llcp_cb.sdp_cb.p_snl->offset 140 - llcp_cb.sdp_cb.p_snl->len; 141 142 name_len = (UINT16) strlen (p_name); 143 144 /* if SDREQ parameter can be added in SNL */ 145 if ( (available_bytes >= LLCP_SDREQ_MIN_LEN + name_len) 146 &&(llcp_cb.sdp_cb.p_snl->len + LLCP_SDREQ_MIN_LEN + name_len <= llcp_cb.lcb.effective_miu) ) 147 { 148 llcp_sdp_add_sdreq (tid, p_name); 149 status = LLCP_STATUS_SUCCESS; 150 } 151 else 152 { 153 /* send pending SNL PDU to LM */ 154 llcp_sdp_check_send_snl (); 155 156 llcp_cb.sdp_cb.p_snl = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID); 157 158 if (llcp_cb.sdp_cb.p_snl) 159 { 160 llcp_cb.sdp_cb.p_snl->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE + LLCP_PDU_HEADER_SIZE; 161 llcp_cb.sdp_cb.p_snl->len = 0; 162 163 llcp_sdp_add_sdreq (tid, p_name); 164 165 status = LLCP_STATUS_SUCCESS; 166 } 167 else 168 { 169 status = LLCP_STATUS_FAIL; 170 } 171 } 172 } 173 else 174 { 175 status = LLCP_STATUS_FAIL; 176 } 177 178 /* if LM is waiting for PDUs from upper layer */ 179 if ( (status == LLCP_STATUS_SUCCESS) 180 &&(llcp_cb.lcb.symm_state == LLCP_LINK_SYMM_LOCAL_XMIT_NEXT) ) 181 { 182 llcp_link_check_send_data (); 183 } 184 185 return status; 186 } 187 188 /******************************************************************************* 189 ** 190 ** Function llcp_sdp_add_sdres 191 ** 192 ** Description Add Service Discovery Response into SNL PDU 193 ** 194 ** 195 ** Returns void 196 ** 197 *******************************************************************************/ 198 static void llcp_sdp_add_sdres (UINT8 tid, UINT8 sap) 199 { 200 UINT8 *p; 201 202 p = (UINT8 *) (llcp_cb.sdp_cb.p_snl + 1) + llcp_cb.sdp_cb.p_snl->offset + llcp_cb.sdp_cb.p_snl->len; 203 204 UINT8_TO_BE_STREAM (p, LLCP_SDRES_TYPE); 205 UINT8_TO_BE_STREAM (p, LLCP_SDRES_LEN); 206 UINT8_TO_BE_STREAM (p, tid); 207 UINT8_TO_BE_STREAM (p, sap); 208 209 llcp_cb.sdp_cb.p_snl->len += 2 + LLCP_SDRES_LEN; /* type and length */ 210 } 211 212 /******************************************************************************* 213 ** 214 ** Function llcp_sdp_send_sdres 215 ** 216 ** Description Send Service Discovery Response 217 ** 218 ** 219 ** Returns LLCP_STATUS 220 ** 221 *******************************************************************************/ 222 static tLLCP_STATUS llcp_sdp_send_sdres (UINT8 tid, UINT8 sap) 223 { 224 tLLCP_STATUS status; 225 UINT16 available_bytes; 226 227 LLCP_TRACE_DEBUG2 ("llcp_sdp_send_sdres (): tid=0x%x, SAP=0x%x", tid, sap); 228 229 /* if there is no pending SNL */ 230 if (!llcp_cb.sdp_cb.p_snl) 231 { 232 llcp_cb.sdp_cb.p_snl = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID); 233 234 if (llcp_cb.sdp_cb.p_snl) 235 { 236 llcp_cb.sdp_cb.p_snl->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE + LLCP_PDU_HEADER_SIZE; 237 llcp_cb.sdp_cb.p_snl->len = 0; 238 } 239 } 240 241 if (llcp_cb.sdp_cb.p_snl) 242 { 243 available_bytes = GKI_get_buf_size (llcp_cb.sdp_cb.p_snl) 244 - BT_HDR_SIZE - llcp_cb.sdp_cb.p_snl->offset 245 - llcp_cb.sdp_cb.p_snl->len; 246 247 /* if SDRES parameter can be added in SNL */ 248 if ( (available_bytes >= 2 + LLCP_SDRES_LEN) 249 &&(llcp_cb.sdp_cb.p_snl->len + 2 + LLCP_SDRES_LEN <= llcp_cb.lcb.effective_miu) ) 250 { 251 llcp_sdp_add_sdres (tid, sap); 252 status = LLCP_STATUS_SUCCESS; 253 } 254 else 255 { 256 /* send pending SNL PDU to LM */ 257 llcp_sdp_check_send_snl (); 258 259 llcp_cb.sdp_cb.p_snl = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID); 260 261 if (llcp_cb.sdp_cb.p_snl) 262 { 263 llcp_cb.sdp_cb.p_snl->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE + LLCP_PDU_HEADER_SIZE; 264 llcp_cb.sdp_cb.p_snl->len = 0; 265 266 llcp_sdp_add_sdres (tid, sap); 267 268 status = LLCP_STATUS_SUCCESS; 269 } 270 else 271 { 272 status = LLCP_STATUS_FAIL; 273 } 274 } 275 } 276 else 277 { 278 status = LLCP_STATUS_FAIL; 279 } 280 281 /* if LM is waiting for PDUs from upper layer */ 282 if ( (status == LLCP_STATUS_SUCCESS) 283 &&(llcp_cb.lcb.symm_state == LLCP_LINK_SYMM_LOCAL_XMIT_NEXT) ) 284 { 285 llcp_link_check_send_data (); 286 } 287 288 return status; 289 } 290 291 /******************************************************************************* 292 ** 293 ** Function llcp_sdp_get_sap_by_name 294 ** 295 ** Description Search SAP by service name 296 ** 297 ** 298 ** Returns SAP if success 299 ** 300 *******************************************************************************/ 301 UINT8 llcp_sdp_get_sap_by_name (char *p_name, UINT8 length) 302 { 303 UINT8 sap; 304 tLLCP_APP_CB *p_app_cb; 305 306 for (sap = LLCP_SAP_SDP; sap <= LLCP_UPPER_BOUND_SDP_SAP; sap++) 307 { 308 p_app_cb = llcp_util_get_app_cb (sap); 309 310 if ( (p_app_cb) 311 &&(p_app_cb->p_app_cback) 312 &&(strlen((char*)p_app_cb->p_service_name) == length) 313 &&(!strncmp((char*)p_app_cb->p_service_name, p_name, length)) ) 314 { 315 return (sap); 316 } 317 } 318 return 0; 319 } 320 321 /******************************************************************************* 322 ** 323 ** Function llcp_sdp_return_sap 324 ** 325 ** Description Report TID and SAP to requester 326 ** 327 ** 328 ** Returns void 329 ** 330 *******************************************************************************/ 331 static void llcp_sdp_return_sap (UINT8 tid, UINT8 sap) 332 { 333 UINT8 i; 334 335 LLCP_TRACE_DEBUG2 ("llcp_sdp_return_sap (): tid=0x%x, SAP=0x%x", tid, sap); 336 337 for (i = 0; i < LLCP_MAX_SDP_TRANSAC; i++) 338 { 339 if ( (llcp_cb.sdp_cb.transac[i].p_cback) 340 &&(llcp_cb.sdp_cb.transac[i].tid == tid) ) 341 { 342 (*llcp_cb.sdp_cb.transac[i].p_cback) (tid, sap); 343 344 llcp_cb.sdp_cb.transac[i].p_cback = NULL; 345 } 346 } 347 } 348 349 /******************************************************************************* 350 ** 351 ** Function llcp_sdp_proc_deactivation 352 ** 353 ** Description Report SDP failure for any pending request because of deactivation 354 ** 355 ** 356 ** Returns void 357 ** 358 *******************************************************************************/ 359 void llcp_sdp_proc_deactivation (void) 360 { 361 UINT8 i; 362 363 LLCP_TRACE_DEBUG0 ("llcp_sdp_proc_deactivation ()"); 364 365 for (i = 0; i < LLCP_MAX_SDP_TRANSAC; i++) 366 { 367 if (llcp_cb.sdp_cb.transac[i].p_cback) 368 { 369 (*llcp_cb.sdp_cb.transac[i].p_cback) (llcp_cb.sdp_cb.transac[i].tid, 0x00); 370 371 llcp_cb.sdp_cb.transac[i].p_cback = NULL; 372 } 373 } 374 375 /* free any pending SNL PDU */ 376 if (llcp_cb.sdp_cb.p_snl) 377 { 378 GKI_freebuf (llcp_cb.sdp_cb.p_snl); 379 llcp_cb.sdp_cb.p_snl = NULL; 380 } 381 382 llcp_cb.sdp_cb.next_tid = 0; 383 } 384 385 /******************************************************************************* 386 ** 387 ** Function llcp_sdp_proc_snl 388 ** 389 ** Description Process SDREQ and SDRES in SNL 390 ** 391 ** 392 ** Returns LLCP_STATUS 393 ** 394 *******************************************************************************/ 395 tLLCP_STATUS llcp_sdp_proc_snl (UINT16 sdu_length, UINT8 *p) 396 { 397 UINT8 type, length, tid, sap, *p_value; 398 399 LLCP_TRACE_DEBUG0 ("llcp_sdp_proc_snl ()"); 400 401 if ((llcp_cb.lcb.agreed_major_version < LLCP_MIN_SNL_MAJOR_VERSION)|| 402 ((llcp_cb.lcb.agreed_major_version == LLCP_MIN_SNL_MAJOR_VERSION)&&(llcp_cb.lcb.agreed_minor_version < LLCP_MIN_SNL_MINOR_VERSION))) 403 { 404 LLCP_TRACE_DEBUG0 ("llcp_sdp_proc_snl(): version number less than 1.1, SNL not supported."); 405 return LLCP_STATUS_FAIL; 406 } 407 while (sdu_length >= 2) /* at least type and length */ 408 { 409 BE_STREAM_TO_UINT8 (type, p); 410 BE_STREAM_TO_UINT8 (length, p); 411 412 switch (type) 413 { 414 case LLCP_SDREQ_TYPE: 415 if ( (length > 1) /* TID and sevice name */ 416 &&(sdu_length >= 2 + length) ) /* type, length, TID and service name */ 417 { 418 p_value = p; 419 BE_STREAM_TO_UINT8 (tid, p_value); 420 sap = llcp_sdp_get_sap_by_name ((char*) p_value, (UINT8) (length - 1)); 421 llcp_sdp_send_sdres (tid, sap); 422 } 423 else 424 { 425 LLCP_TRACE_ERROR1 ("llcp_sdp_proc_snl (): bad length (%d) in LLCP_SDREQ_TYPE", length); 426 } 427 break; 428 429 case LLCP_SDRES_TYPE: 430 if ( (length == LLCP_SDRES_LEN) /* TID and SAP */ 431 &&(sdu_length >= 2 + length) ) /* type, length, TID and SAP */ 432 { 433 p_value = p; 434 BE_STREAM_TO_UINT8 (tid, p_value); 435 BE_STREAM_TO_UINT8 (sap, p_value); 436 llcp_sdp_return_sap (tid, sap); 437 } 438 else 439 { 440 LLCP_TRACE_ERROR1 ("llcp_sdp_proc_snl (): bad length (%d) in LLCP_SDRES_TYPE", length); 441 } 442 break; 443 444 default: 445 LLCP_TRACE_WARNING1 ("llcp_sdp_proc_snl (): Unknown type (0x%x) is ignored", type); 446 break; 447 } 448 449 if (sdu_length >= 2 + length) /* type, length, value */ 450 { 451 sdu_length -= 2 + length; 452 p += length; 453 } 454 else 455 { 456 break; 457 } 458 } 459 460 if (sdu_length) 461 { 462 LLCP_TRACE_ERROR0 ("llcp_sdp_proc_snl (): Bad format of SNL"); 463 return LLCP_STATUS_FAIL; 464 } 465 else 466 { 467 return LLCP_STATUS_SUCCESS; 468 } 469 } 470