1 /****************************************************************************** 2 * 3 * Copyright (C) 2010-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 source code for some utility functions to help parse 22 * and build NFC Data Exchange Format (NDEF) messages for Connection 23 * Handover 24 * 25 ******************************************************************************/ 26 27 #include <string.h> 28 #include "ndef_utils.h" 29 30 /******************************************************************************* 31 ** 32 ** Static Local Functions 33 */ 34 static UINT8 *ndef_get_bt_oob_record (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size, 35 char *p_id_str); 36 37 /******************************************************************************* 38 ** 39 ** Static data 40 */ 41 42 /* Handover Request Record Type */ 43 static UINT8 hr_rec_type[HR_REC_TYPE_LEN] = { 0x48, 0x72 }; /* "Hr" */ 44 45 /* Handover Select Record Type */ 46 static UINT8 hs_rec_type[HS_REC_TYPE_LEN] = { 0x48, 0x73 }; /* "Hs" */ 47 48 /* Handover Carrier recrod Type */ 49 static UINT8 hc_rec_type[HC_REC_TYPE_LEN] = { 0x48, 0x63 }; /* "Hc" */ 50 51 /* Collision Resolution Record Type */ 52 static UINT8 cr_rec_type[CR_REC_TYPE_LEN] = { 0x63, 0x72 }; /* "cr" */ 53 54 /* Alternative Carrier Record Type */ 55 static UINT8 ac_rec_type[AC_REC_TYPE_LEN] = { 0x61, 0x63 }; /* "ac" */ 56 57 /* Error Record Type */ 58 static UINT8 err_rec_type[ERR_REC_TYPE_LEN] = { 0x65, 0x72, 0x72 }; /* "err" */ 59 60 /* Bluetooth OOB Data Type */ 61 static UINT8 *p_bt_oob_rec_type = (UINT8 *) "application/vnd.bluetooth.ep.oob"; 62 63 /******************************************************************************* 64 ** 65 ** Function NDEF_MsgCreateWktHr 66 ** 67 ** Description This function creates Handover Request Record with version. 68 ** 69 ** Returns NDEF_OK if all OK 70 ** 71 *******************************************************************************/ 72 tNDEF_STATUS NDEF_MsgCreateWktHr (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size, 73 UINT8 version ) 74 { 75 tNDEF_STATUS status; 76 77 NDEF_MsgInit (p_msg, max_size, p_cur_size); 78 79 /* Add record with version */ 80 status = NDEF_MsgAddRec (p_msg, max_size, p_cur_size, 81 NDEF_TNF_WKT, hr_rec_type, HR_REC_TYPE_LEN, 82 NULL, 0, &version, 1); 83 84 return (status); 85 } 86 87 /******************************************************************************* 88 ** 89 ** Function NDEF_MsgCreateWktHs 90 ** 91 ** Description This function creates Handover Select Record with version. 92 ** 93 ** Returns NDEF_OK if all OK 94 ** 95 *******************************************************************************/ 96 tNDEF_STATUS NDEF_MsgCreateWktHs (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size, 97 UINT8 version ) 98 { 99 tNDEF_STATUS status; 100 101 NDEF_MsgInit (p_msg, max_size, p_cur_size); 102 103 /* Add record with version */ 104 status = NDEF_MsgAddRec (p_msg, max_size, p_cur_size, 105 NDEF_TNF_WKT, hs_rec_type, HS_REC_TYPE_LEN, 106 NULL, 0, &version, 1); 107 108 return (status); 109 } 110 111 /******************************************************************************* 112 ** 113 ** Function NDEF_MsgAddWktHc 114 ** 115 ** Description This function adds Handover Carrier Record. 116 ** 117 ** Returns NDEF_OK if all OK 118 ** 119 *******************************************************************************/ 120 tNDEF_STATUS NDEF_MsgAddWktHc (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size, 121 char *p_id_str, UINT8 ctf, 122 UINT8 carrier_type_len, UINT8 *p_carrier_type, 123 UINT8 carrier_data_len, UINT8 *p_carrier_data) 124 { 125 tNDEF_STATUS status; 126 UINT8 payload[256], *p, id_len; 127 UINT32 payload_len; 128 129 if (carrier_type_len + carrier_data_len + 2 > 256) 130 { 131 return (NDEF_MSG_INSUFFICIENT_MEM); 132 } 133 134 p = payload; 135 136 UINT8_TO_STREAM (p, (ctf & 0x07)); 137 UINT8_TO_STREAM (p, carrier_type_len); 138 ARRAY_TO_STREAM (p, p_carrier_type, carrier_type_len); 139 ARRAY_TO_STREAM (p, p_carrier_data, carrier_data_len); 140 141 payload_len = (UINT32) carrier_type_len + carrier_data_len + 2; 142 143 id_len = (UINT8) strlen (p_id_str); 144 145 status = NDEF_MsgAddRec (p_msg, max_size, p_cur_size, 146 NDEF_TNF_WKT, hc_rec_type, HC_REC_TYPE_LEN, 147 (UINT8*) p_id_str, id_len, payload, payload_len); 148 return (status); 149 } 150 151 /******************************************************************************* 152 ** 153 ** Function NDEF_MsgAddWktAc 154 ** 155 ** Description This function adds Alternative Carrier Record. 156 ** 157 ** Returns NDEF_OK if all OK 158 ** 159 *******************************************************************************/ 160 tNDEF_STATUS NDEF_MsgAddWktAc (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size, 161 UINT8 cps, char *p_carrier_data_ref_str, 162 UINT8 aux_data_ref_count, char *p_aux_data_ref_str[]) 163 { 164 tNDEF_STATUS status; 165 UINT32 payload_len; 166 UINT8 ref_str_len, xx; 167 UINT8 *p_rec, *p; 168 169 /* get payload length first */ 170 171 /* CPS, length of carrier data ref, carrier data ref, Aux data reference count */ 172 payload_len = 3 + (UINT8) strlen (p_carrier_data_ref_str); 173 for (xx = 0; xx < aux_data_ref_count; xx++) 174 { 175 /* Aux Data Reference length (1 byte) */ 176 payload_len += 1 + (UINT8) strlen (p_aux_data_ref_str[xx]); 177 } 178 179 /* reserve memory for payload */ 180 status = NDEF_MsgAddRec (p_msg, max_size, p_cur_size, 181 NDEF_TNF_WKT, ac_rec_type, AC_REC_TYPE_LEN, 182 NULL, 0, NULL, payload_len); 183 184 if (status == NDEF_OK) 185 { 186 /* get AC record added at the end */ 187 p_rec = NDEF_MsgGetLastRecInMsg (p_msg); 188 189 /* get start pointer of reserved payload */ 190 p = NDEF_RecGetPayload (p_rec, &payload_len); 191 192 /* Add Carrier Power State */ 193 UINT8_TO_BE_STREAM (p, cps); 194 195 /* Carrier Data Reference length */ 196 ref_str_len = (UINT8) strlen (p_carrier_data_ref_str); 197 198 UINT8_TO_BE_STREAM (p, ref_str_len); 199 200 /* Carrier Data Reference */ 201 ARRAY_TO_BE_STREAM (p, p_carrier_data_ref_str, ref_str_len); 202 203 /* Aux Data Reference Count */ 204 UINT8_TO_BE_STREAM (p, aux_data_ref_count); 205 206 for (xx = 0; xx < aux_data_ref_count; xx++) 207 { 208 /* Aux Data Reference length (1 byte) */ 209 ref_str_len = (UINT8) strlen (p_aux_data_ref_str[xx]); 210 211 UINT8_TO_BE_STREAM (p, ref_str_len); 212 213 /* Aux Data Reference */ 214 ARRAY_TO_BE_STREAM (p, p_aux_data_ref_str[xx], ref_str_len); 215 } 216 } 217 218 return (status); 219 } 220 221 /******************************************************************************* 222 ** 223 ** Function NDEF_MsgAddWktCr 224 ** 225 ** Description This function adds Collision Resolution Record. 226 ** 227 ** Returns NDEF_OK if all OK 228 ** 229 *******************************************************************************/ 230 tNDEF_STATUS NDEF_MsgAddWktCr (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size, 231 UINT16 random_number ) 232 { 233 tNDEF_STATUS status; 234 UINT8 data[2], *p; 235 236 p = data; 237 UINT16_TO_BE_STREAM (p, random_number); 238 239 status = NDEF_MsgAddRec (p_msg, max_size, p_cur_size, 240 NDEF_TNF_WKT, cr_rec_type, CR_REC_TYPE_LEN, 241 NULL, 0, data, 2); 242 return (status); 243 } 244 245 /******************************************************************************* 246 ** 247 ** Function NDEF_MsgAddWktErr 248 ** 249 ** Description This function adds Error Record. 250 ** 251 ** Returns NDEF_OK if all OK 252 ** 253 *******************************************************************************/ 254 tNDEF_STATUS NDEF_MsgAddWktErr (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size, 255 UINT8 error_reason, UINT32 error_data ) 256 { 257 tNDEF_STATUS status; 258 UINT8 payload[5], *p; 259 UINT32 payload_len; 260 261 p = payload; 262 263 UINT8_TO_BE_STREAM (p, error_reason); 264 265 if (error_reason == 0x02) 266 { 267 UINT32_TO_BE_STREAM (p, error_data); 268 payload_len = 5; 269 } 270 else 271 { 272 UINT8_TO_BE_STREAM (p, error_data); 273 payload_len = 2; 274 } 275 276 status = NDEF_MsgAddRec (p_msg, max_size, p_cur_size, 277 NDEF_TNF_WKT, err_rec_type, ERR_REC_TYPE_LEN, 278 NULL, 0, payload, payload_len); 279 return (status); 280 } 281 282 /******************************************************************************* 283 ** 284 ** Function NDEF_MsgAddMediaBtOob 285 ** 286 ** Description This function adds BT OOB Record. 287 ** 288 ** Returns NDEF_OK if all OK 289 ** 290 *******************************************************************************/ 291 tNDEF_STATUS NDEF_MsgAddMediaBtOob (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size, 292 char *p_id_str, BD_ADDR bd_addr) 293 { 294 tNDEF_STATUS status; 295 UINT8 payload[BD_ADDR_LEN + 2]; 296 UINT8 *p; 297 UINT8 payload_len, id_len; 298 299 p = payload; 300 301 /* length including itself */ 302 UINT16_TO_STREAM (p, BD_ADDR_LEN + 2); 303 304 /* BD Addr */ 305 BDADDR_TO_STREAM (p, bd_addr); 306 307 payload_len = BD_ADDR_LEN + 2; 308 id_len = (UINT8) strlen (p_id_str); 309 310 status = NDEF_MsgAddRec (p_msg, max_size, p_cur_size, 311 NDEF_TNF_MEDIA, p_bt_oob_rec_type, BT_OOB_REC_TYPE_LEN, 312 (UINT8*) p_id_str, id_len, payload, payload_len); 313 return (status); 314 } 315 316 /******************************************************************************* 317 ** 318 ** Function NDEF_MsgAppendMediaBtOobCod 319 ** 320 ** Description This function appends COD EIR data at the end of BT OOB Record. 321 ** 322 ** Returns NDEF_OK if all OK 323 ** 324 *******************************************************************************/ 325 tNDEF_STATUS NDEF_MsgAppendMediaBtOobCod (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size, 326 char *p_id_str, DEV_CLASS cod) 327 { 328 tNDEF_STATUS status; 329 UINT8 *p_rec; 330 UINT8 eir_data[BT_OOB_COD_SIZE + 2]; 331 UINT8 *p; 332 UINT8 eir_data_len; 333 UINT32 oob_data_len; 334 335 /* find record by Payload ID */ 336 p_rec = ndef_get_bt_oob_record (p_msg, max_size, p_cur_size, p_id_str); 337 338 if (!p_rec) 339 return (NDEF_REC_NOT_FOUND); 340 341 /* create EIR data format for COD */ 342 p = eir_data; 343 UINT8_TO_STREAM (p, BT_OOB_COD_SIZE + 1); 344 UINT8_TO_STREAM (p, BT_EIR_OOB_COD_TYPE); 345 DEVCLASS_TO_STREAM (p, cod); 346 eir_data_len = BT_OOB_COD_SIZE + 2; 347 348 /* append EIR data at the end of record */ 349 status = NDEF_MsgAppendPayload (p_msg, max_size, p_cur_size, 350 p_rec, eir_data, eir_data_len); 351 352 /* update BT OOB data length, if success */ 353 if (status == NDEF_OK) 354 { 355 /* payload length is the same as BT OOB data length */ 356 p = NDEF_RecGetPayload (p_rec, &oob_data_len); 357 UINT16_TO_STREAM (p, oob_data_len); 358 } 359 360 return (status); 361 } 362 363 /******************************************************************************* 364 ** 365 ** Function NDEF_MsgAppendMediaBtOobName 366 ** 367 ** Description This function appends Bluetooth Local Name EIR data 368 ** at the end of BT OOB Record. 369 ** 370 ** Returns NDEF_OK if all OK 371 ** 372 *******************************************************************************/ 373 tNDEF_STATUS NDEF_MsgAppendMediaBtOobName (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size, 374 char *p_id_str, BOOLEAN is_complete, 375 UINT8 name_len, UINT8 *p_name) 376 { 377 tNDEF_STATUS status; 378 UINT8 *p_rec; 379 UINT8 eir_data[256]; 380 UINT8 *p; 381 UINT8 eir_data_len; 382 UINT32 oob_data_len; 383 384 /* find record by Payload ID */ 385 p_rec = ndef_get_bt_oob_record (p_msg, max_size, p_cur_size, p_id_str); 386 387 if (!p_rec) 388 return (NDEF_REC_NOT_FOUND); 389 390 /* create EIR data format for COD */ 391 p = eir_data; 392 UINT8_TO_STREAM (p, name_len + 1); 393 394 if (is_complete) 395 { 396 UINT8_TO_STREAM (p, BT_EIR_COMPLETE_LOCAL_NAME_TYPE); 397 } 398 else 399 { 400 UINT8_TO_STREAM (p, BT_EIR_SHORTENED_LOCAL_NAME_TYPE); 401 } 402 403 ARRAY_TO_STREAM (p, p_name, name_len); 404 eir_data_len = name_len + 2; 405 406 /* append EIR data at the end of record */ 407 status = NDEF_MsgAppendPayload (p_msg, max_size, p_cur_size, 408 p_rec, eir_data, eir_data_len); 409 410 /* update BT OOB data length, if success */ 411 if (status == NDEF_OK) 412 { 413 /* payload length is the same as BT OOB data length */ 414 p = NDEF_RecGetPayload (p_rec, &oob_data_len); 415 UINT16_TO_STREAM (p, oob_data_len); 416 } 417 418 return (status); 419 } 420 421 /******************************************************************************* 422 ** 423 ** Function NDEF_MsgAppendMediaBtOobHashCRandR 424 ** 425 ** Description This function appends Hash C and Rand R at the end of BT OOB Record. 426 ** 427 ** Returns NDEF_OK if all OK 428 ** 429 *******************************************************************************/ 430 tNDEF_STATUS NDEF_MsgAppendMediaBtOobHashCRandR (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size, 431 char *p_id_str, UINT8 *p_hash_c, UINT8 *p_rand_r) 432 { 433 tNDEF_STATUS status; 434 UINT8 *p_rec; 435 UINT8 eir_data[BT_OOB_HASH_C_SIZE + BT_OOB_RAND_R_SIZE + 4]; 436 UINT8 *p; 437 UINT8 eir_data_len; 438 UINT32 oob_data_len; 439 440 /* find record by Payload ID */ 441 p_rec = ndef_get_bt_oob_record (p_msg, max_size, p_cur_size, p_id_str); 442 443 if (!p_rec) 444 return (NDEF_REC_NOT_FOUND); 445 446 /* create EIR data format */ 447 p = eir_data; 448 449 UINT8_TO_STREAM (p, BT_OOB_HASH_C_SIZE + 1); 450 UINT8_TO_STREAM (p, BT_EIR_OOB_SSP_HASH_C_TYPE); 451 ARRAY16_TO_STREAM (p, p_hash_c); 452 453 UINT8_TO_STREAM (p, BT_OOB_RAND_R_SIZE + 1); 454 UINT8_TO_STREAM (p, BT_EIR_OOB_SSP_RAND_R_TYPE); 455 ARRAY16_TO_STREAM (p, p_rand_r); 456 457 eir_data_len = BT_OOB_HASH_C_SIZE + BT_OOB_RAND_R_SIZE + 4; 458 459 /* append EIR data at the end of record */ 460 status = NDEF_MsgAppendPayload (p_msg, max_size, p_cur_size, 461 p_rec, eir_data, eir_data_len); 462 463 /* update BT OOB data length, if success */ 464 if (status == NDEF_OK) 465 { 466 /* payload length is the same as BT OOB data length */ 467 p = NDEF_RecGetPayload (p_rec, &oob_data_len); 468 UINT16_TO_STREAM (p, oob_data_len); 469 } 470 471 return (status); 472 } 473 474 /******************************************************************************* 475 ** 476 ** Function NDEF_MsgAppendMediaBtOobEirData 477 ** 478 ** Description This function appends EIR Data at the end of BT OOB Record. 479 ** 480 ** Returns NDEF_OK if all OK 481 ** 482 *******************************************************************************/ 483 tNDEF_STATUS NDEF_MsgAppendMediaBtOobEirData (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size, 484 char *p_id_str, 485 UINT8 eir_type, UINT8 data_len, UINT8 *p_data) 486 { 487 tNDEF_STATUS status; 488 UINT8 *p_rec; 489 UINT8 eir_data[256]; 490 UINT8 *p; 491 UINT8 eir_data_len; 492 UINT32 oob_data_len; 493 494 /* find record by Payload ID */ 495 p_rec = ndef_get_bt_oob_record (p_msg, max_size, p_cur_size, p_id_str); 496 497 if (!p_rec) 498 return (NDEF_REC_NOT_FOUND); 499 500 /* create EIR data format */ 501 p = eir_data; 502 UINT8_TO_STREAM (p, data_len + 1); 503 UINT8_TO_STREAM (p, eir_type); 504 ARRAY_TO_STREAM (p, p_data, data_len); 505 eir_data_len = data_len + 2; 506 507 /* append EIR data at the end of record */ 508 status = NDEF_MsgAppendPayload (p_msg, max_size, p_cur_size, 509 p_rec, eir_data, eir_data_len); 510 511 /* update BT OOB data length, if success */ 512 if (status == NDEF_OK) 513 { 514 /* payload length is the same as BT OOB data length */ 515 p = NDEF_RecGetPayload (p_rec, &oob_data_len); 516 UINT16_TO_STREAM (p, oob_data_len); 517 } 518 519 return (status); 520 } 521 522 /******************************************************************************* 523 ** 524 ** Static Local Functions 525 ** 526 *******************************************************************************/ 527 /******************************************************************************* 528 ** 529 ** Function ndef_get_bt_oob_record 530 ** 531 ** Description This function returns BT OOB record which has matched payload ID 532 ** 533 ** Returns pointer of record if found, otherwise NULL 534 ** 535 *******************************************************************************/ 536 static UINT8 *ndef_get_bt_oob_record (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size, 537 char *p_id_str) 538 { 539 UINT8 *p_rec, *p_type; 540 UINT8 id_len, tnf, type_len; 541 542 /* find record by Payload ID */ 543 id_len = (UINT8) strlen (p_id_str); 544 p_rec = NDEF_MsgGetFirstRecById (p_msg, (UINT8*) p_id_str, id_len); 545 546 if (!p_rec) 547 return (NULL); 548 549 p_type = NDEF_RecGetType (p_rec, &tnf, &type_len); 550 551 /* check type if this is BT OOB record */ 552 if ( (!p_rec) 553 ||(tnf != NDEF_TNF_MEDIA) 554 ||(type_len != BT_OOB_REC_TYPE_LEN) 555 ||(memcmp (p_type, p_bt_oob_rec_type, BT_OOB_REC_TYPE_LEN)) ) 556 { 557 return (NULL); 558 } 559 560 return (p_rec); 561 } 562 563