Home | History | Annotate | Download | only in ndef
      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