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