1/****************************************************************************** 2 * 3 * Copyright (C) 2010-2014 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*******************************************************************************/ 44void 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*******************************************************************************/ 62void 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*******************************************************************************/ 91static 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*******************************************************************************/ 116tLLCP_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*******************************************************************************/ 198static 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*******************************************************************************/ 222static 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*******************************************************************************/ 301UINT8 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*******************************************************************************/ 331static 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*******************************************************************************/ 359void 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*******************************************************************************/ 395tLLCP_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