Ejemplo n.º 1
0
static wiced_result_t consume_message(websocket_message_t *msg, websocket_msg_handler_t binary_msg_handler, websocket_msg_handler_t text_msg_handler, void *ctx) {
    wiced_result_t ret = WICED_ERROR;

    if (!msg->is_active) {
        return ret;
    }

    if (msg->is_text) {
        if (text_msg_handler) {
            WPRINT_LIB_INFO( ("(WebSocket) Sending text message (%u bytes) to handler.\n", (unsigned int)msg->len) );
            ret = text_msg_handler(ctx, msg->buf, msg->len);
        }
        else {
            WPRINT_LIB_INFO( ("(WebSocket) Text message (%u bytes) discarded because there is no handler.\n", (unsigned int)msg->len) );
            ret = WICED_SUCCESS;
        }
    }
    else {
        if (binary_msg_handler) {
            WPRINT_LIB_INFO( ("(WebSocket) Sending binary message (%u bytes) to handler.\n", (unsigned int)msg->len) );
            ret = binary_msg_handler(ctx, msg->buf, msg->len);
        }
        else {
            WPRINT_LIB_INFO( ("(WebSocket) Binary message (%u bytes) discarded because there is no handler.\n", (unsigned int)msg->len) );
            ret = WICED_SUCCESS;
        }
    }

    message_reset(msg);
    return ret;
}
Ejemplo n.º 2
0
static wiced_result_t print_uuid( const wiced_bt_uuid_t* uuid )
{
    if ( uuid->size == UUID_16BIT )
    {
        WPRINT_LIB_INFO( ( "%04x\n", (int)uuid->value.value_16_bit ) );
    }
    else
    {
        WPRINT_LIB_INFO( ( "%04x %04x %04x %04x %04x %04x %04x %04x\n",
                           (int)uuid->value.value_128_bit[0],
                           (int)uuid->value.value_128_bit[1],
                           (int)uuid->value.value_128_bit[2],
                           (int)uuid->value.value_128_bit[3],
                           (int)uuid->value.value_128_bit[4],
                           (int)uuid->value.value_128_bit[5],
                           (int)uuid->value.value_128_bit[6],
                           (int)uuid->value.value_128_bit[7] ) );
    }

    return WICED_BT_SUCCESS;
}
Ejemplo n.º 3
0
static wiced_result_t send_control_frame(wiced_tcp_socket_t *sock, uint8_t opcode, const char *payload, uint32_t payload_len) {
    wiced_result_t ret = WICED_ERROR;
    uint8_t frame_buf[256];
    uint32_t frame_size = 2;

    WPRINT_LIB_DEBUG( ("(WebSocket) Sending control frame with opcode 0x%02X\n", opcode) );

    if (payload_len > 125) {
        WPRINT_LIB_INFO( ("(WebSocket) Failed to send control frame: payload longer than 125 bytes\n") );
        return ret;
    }

    frame_buf[0] = (uint8_t)(0x80 | opcode);

    if (payload && payload_len > 0) {
        frame_buf[1] = (uint8_t)(0x80 | payload_len);

        /* Generate mask. */
        wiced_crypto_get_random(&frame_buf[frame_size], 4);
        frame_size += 4;

        memcpy(&frame_buf[frame_size], payload, payload_len);
        unmask_frame_payload((char *)&frame_buf[frame_size], payload_len, &frame_buf[2]);
        frame_size += payload_len;
    }
    else {
        frame_buf[1] = (uint8_t)0x80;
    }

    ret = wiced_tcp_send_buffer(sock, frame_buf, (uint16_t)frame_size);
    if (ret != WICED_SUCCESS) {
        WPRINT_LIB_INFO( ("(WebSocket) Failed to send control frame (err=%u)\n", ret) );
    }

    return ret;
}
Ejemplo n.º 4
0
wiced_result_t websocket_handshake_init(websocket_handshake_t *hs, const char *hostname, const char *path) {
    wiced_result_t ret;
    char key_buf[WEBSOCKET_KEY_BASE64_LENGTH];

    ret = generate_websocket_client_key(key_buf, sizeof(key_buf));
    if (ret != WICED_SUCCESS) {
        WPRINT_LIB_INFO( ("Failed to generate WebSocket key (err=%u)\n", ret) );
        return ret;
    }

    hs->hostname = strdup(hostname);
    hs->path = strdup(path);
    hs->key = strdup(key_buf);
    hs->headers = (https_header_t *)malloc(sizeof(https_header_t) * MAX_REQ_HEADERS);
    hs->num_headers = 0;

    return ret;
}
Ejemplo n.º 5
0
wiced_result_t open_websocket(websocket_handshake_t *hs, websocket_msg_handler_t binary_msg_handler, websocket_msg_handler_t text_msg_handler, void *ctx) {
    wiced_result_t ret;
    wiced_ip_address_t host_ip;
    wiced_tls_context_t tls_ctx;
    wiced_tcp_socket_t sock;
    wiced_tcp_stream_t stream;
    char *buf = NULL;
    uint32_t i;
    https_header_t *header;

    WPRINT_LIB_INFO( ("Starting WebSocket handshake to https://%s%s\n", hs->hostname, hs->path) );

    ret = wiced_hostname_lookup(hs->hostname, &host_ip, DNS_TIMEOUT);
    if (ret != WICED_SUCCESS) {
        WPRINT_LIB_INFO( ("DNS lookup failed for %s (err=%u)\n", hs->hostname, ret) );
        return ret;
    }

    wiced_tls_init_context(&tls_ctx, NULL, NULL);
    wiced_tcp_create_socket(&sock, WICED_STA_INTERFACE);
    wiced_tcp_enable_tls(&sock, &tls_ctx);

    {
        char ip_str[48];
        ip_to_str(&host_ip, ip_str);
        WPRINT_LIB_INFO( ("Establishing TLS connection to %s port %d\n", ip_str, HTTPS_PORT) );
    }

    ret = wiced_tcp_connect(&sock, &host_ip, HTTPS_PORT, HTTPS_CONNECT_TIMEOUT);
    if (ret != WICED_SUCCESS) {
        WPRINT_LIB_INFO( ("Failed to create TCP connection (err=%u)\n", ret) );
        wiced_tcp_delete_socket(&sock);
        return ret;
    }

    do {
        ret = wiced_tcp_stream_init(&stream, &sock);
        if (ret != WICED_SUCCESS) {
            WPRINT_LIB_INFO( ("Failed to initialize TCP stream (err=%u)\n", ret) );
            break;
        }

        buf = (char *)malloc(STREAM_BUF_SIZE);

        snprintf(buf, STREAM_BUF_SIZE, "GET %s HTTP/1.1\r\n", hs->path);
        WRITE_STREAM(stream, buf, ret);

        // Required headers.
        snprintf(buf, STREAM_BUF_SIZE,
                 "Host: %s\r\n" \
                 "Connection: upgrade\r\n" \
                 "Upgrade: websocket\r\n" \
                 "Sec-WebSocket-Key: %s\r\n" \
                 "Sec-WebSocket-Version: 13\r\n",
                 hs->hostname, hs->key);
        WRITE_STREAM(stream, buf, ret);

        // Additional headers.
        for (i = 0; i < hs->num_headers; i++) {
            header = &(hs->headers[i]);
            snprintf(buf, STREAM_BUF_SIZE, "%s: %s\r\n", header->name, header->value);
            WRITE_STREAM(stream, buf, ret);
        }

        if (i < hs->num_headers) {
            break;
        }

        strcpy(buf, "\r\n");
        WRITE_STREAM(stream, buf, ret);

        ret = wiced_tcp_stream_flush(&stream);
        if (ret != WICED_SUCCESS) {
            break;
        }

        ret = process_handshake_response(hs, &sock);

    } while (WICED_FALSE);

    if (buf) {
        free(buf);
    }

    wiced_tcp_stream_deinit(&stream);

    if (ret == WICED_SUCCESS) {
        WPRINT_LIB_INFO( ("WebSocket handshake OK\n") );
        process_frames(&sock, binary_msg_handler, text_msg_handler, ctx);
        WPRINT_LIB_INFO( ("Closing WebSocket.\n") );
    }
    else {
        WPRINT_LIB_INFO( ("WebSocket handshake failed (err=%u)\n", ret) );
    }

    wiced_tcp_disconnect(&sock);
    wiced_tcp_delete_socket(&sock);

    return ret;
}
Ejemplo n.º 6
0
static void process_frames(wiced_tcp_socket_t *sock, websocket_msg_handler_t binary_msg_handler, websocket_msg_handler_t text_msg_handler, void *ctx) {
    wiced_result_t ret;
    char *buf, *cur;
    uint32_t len;
    websocket_frame_t frame;
    websocket_message_t msg;
    wiced_bool_t exit_loop = WICED_FALSE;

    message_init(&msg);

    while (WICED_TRUE) {
        buf = NULL;
        ret = receive_data(sock, 3000, &buf, &len);

        if (ret == WICED_TIMEOUT) {
            continue;
        }

        if (ret != WICED_SUCCESS) {
            WPRINT_LIB_INFO( ("(WebSocket) Failed to read from socket (err=%u)\n", ret) );
            break;
        }

        WPRINT_LIB_DEBUG( ("(WebSocket) Received %u bytes\n", (unsigned int)len) );

        cur = buf;
        while (len > 0) {
            if (get_frame(&cur, &len, &frame) != WICED_SUCCESS) {
                WPRINT_LIB_INFO( ("(WebSocket) Failed to read frame (err=%u)\n", ret) );
                exit_loop = WICED_TRUE;
                break;
            }

            if (frame.opcode == WS_OPCODE_PING) {
                WPRINT_LIB_DEBUG( ("(WebSocket) Received PING frame.\n"));
                send_control_frame(sock, WS_OPCODE_PONG, frame.payload, frame.payload_len);
            }
            else if (frame.opcode == WS_OPCODE_PONG) {
                WPRINT_LIB_DEBUG( ("(WebSocket) Received PONG frame.\n"));
                /* Nothing to do. */
            }
            else if (frame.opcode == WS_OPCODE_CLOSE) {
                WPRINT_LIB_DEBUG( ("(WebSocket) Received CLOSE frame.\n") );
                /* Echo the CLOSE frame with the 2-byte status code. */
                if (frame.payload_len >= 2) {
                    send_control_frame(sock, WS_OPCODE_CLOSE, frame.payload, 2);
                }
                else {
                    send_control_frame(sock, WS_OPCODE_CLOSE, NULL, 0);
                }
                exit_loop = WICED_TRUE;
                break;
            }
            else if (frame.opcode == WS_OPCODE_CONTINUATION) {
                WPRINT_LIB_DEBUG( ("(WebSocket) Received CONTINUATION frame.\n") );

                if (msg.is_active) {
                    message_append(&msg, frame.payload, frame.payload_len);

                    if (frame.is_final) {
                        consume_message(&msg, binary_msg_handler, text_msg_handler, ctx);
                    }
                }
                else {
                    exit_loop = WICED_TRUE;
                    break;
                }
            }
            else if (frame.opcode == WS_OPCODE_TEXT) {
                WPRINT_LIB_DEBUG( ("(WebSocket) Received TEXT frame.\n") );

                if (msg.is_active) {
                    WPRINT_LIB_DEBUG( ("(WebSocket) A pending message already exists.\n") );
                    exit_loop = WICED_TRUE;
                    break;
                }

                message_start(&msg, WICED_TRUE, frame.payload, frame.payload_len);

                if (frame.is_final) {
                    consume_message(&msg, binary_msg_handler, text_msg_handler, ctx);
                }
            }
            else if (frame.opcode == WS_OPCODE_BINARY) {
                WPRINT_LIB_DEBUG( ("(WebSocket) Received BINARY frame.\n") );

                if (msg.is_active) {
                    WPRINT_LIB_DEBUG( ("(WebSocket) A pending message already exists.\n") );
                    exit_loop = WICED_TRUE;
                    break;
                }

                message_start(&msg, WICED_FALSE, frame.payload, frame.payload_len);

                if (frame.is_final) {
                    consume_message(&msg, binary_msg_handler, text_msg_handler, ctx);
                }
            }
            else {
                WPRINT_LIB_INFO(("(WebSocket) Received invalid opcode %02X\n", frame.opcode));
                exit_loop = WICED_TRUE;
                break;
            }
        }

        free(buf);

        if (exit_loop) {
            WPRINT_LIB_INFO( ("(WebSocket) Exiting read loop.\n") );
            break;
        }
    }

    message_deinit(&msg);
}
Ejemplo n.º 7
0
static wiced_result_t process_handshake_response(websocket_handshake_t *hs, wiced_tcp_socket_t *sock) {
    char *buf, *cur, *line, *token, *hdr_name, *hdr_val;
    uint32_t len;
    const char *val;
    https_response_t res;
    wiced_result_t ret = WICED_ERROR;

    ret = receive_data(sock, HTTPS_READ_TIMEOUT, &buf, &len);
    if (ret != WICED_SUCCESS) {
        return ret;
    }

    cur = buf;
    line = get_line(&cur);

    token = strsep(&line, " ");
    if (strcmp(token, "HTTP/1.1") && strcmp(token, "HTTP/1.0")) {
        free(buf);
        return WICED_ERROR;
    }

    token = strsep(&line, " ");
    if (!token) {
        free(buf);
        return WICED_ERROR;
    }

    https_init_response(&res);
    res.status = (uint32_t)atoi(token);

    while (cur) {
        line = get_line(&cur);

        if (*line == '\0') {
            break;
        }

        line += strspn(line, " ");
        hdr_name = strsep(&line, ":");
        if (!*hdr_name || !line) {
            /* Skip bad header line. */
            continue;
        }

        hdr_val = line + strspn(line, " ");
        if (!*hdr_val) {
            /* Skip bad header line. */
            continue;
        }

        https_add_response_header(&res, hdr_name, hdr_val);
    }

    do {
        if (res.status != 101) {
            WPRINT_LIB_INFO( ("Server returned unexpected status %u\n", (unsigned int)res.status) );
            break;
        }

        val = https_get_response_header(&res, "Connection");
        if (!val || strcasecmp(val, "upgrade")) {
            WPRINT_LIB_INFO( ("Connection header is invalid or missing.\n") );
            break;
        }

        val = https_get_response_header(&res, "Upgrade");
        if (!val || strcasecmp(val, "websocket")) {
            WPRINT_LIB_INFO( ("Upgrade header is invalid or missing.\n") );
            break;
        }

        val = https_get_response_header(&res, "Sec-WebSocket-Accept");
        if (!val || (verify_websocket_server_key(val, hs->key) != WICED_SUCCESS)) {
            WPRINT_LIB_INFO( ("Sec-WebSocket-Accept header is invalid or missing.\n") );
            break;
        }

        ret = WICED_SUCCESS;
    } while (WICED_FALSE);

    https_deinit_response(&res);
    free(buf);
    return ret;
}
Ejemplo n.º 8
0
static wiced_result_t print_type( const wiced_bt_uuid_t* uuid  )
{
    if ( uuid->size != UUID_16BIT )
    {
        WPRINT_LIB_INFO( ( "Unknown Type" ) );
        return WICED_SUCCESS;
    }

    switch ( uuid->value.value_16_bit )
    {
        case 0x2800:
        {
            WPRINT_LIB_INFO( ( "Primary Service" ) );
            break;
        }
        case 0x2801:
        {
            WPRINT_LIB_INFO( ( "Secondary Service" ) );
            break;
        }
        case 0x2802:
        {
            WPRINT_LIB_INFO( ( "Include" ) );
            break;
        }
        case 0x2803:
        {
            WPRINT_LIB_INFO( ( "Characteristic" ) );
            break;
        }
        case 0x2900:
        {
            WPRINT_LIB_INFO( ( "Characteristic Descriptor - Extended Characteristic Properties" ) );
            break;
        }
        case 0x2901:
        {
            WPRINT_LIB_INFO( ( "Characteristic Descriptor - User Description" ) );
            break;
        }
        case 0x2902:
        {
            WPRINT_LIB_INFO( ( "Characteristic Descriptor - Client Characteristic Configuration" ) );
            break;
        }
        case 0x2903:
        {
            WPRINT_LIB_INFO( ( "Characteristic Descriptor - Server Characteristic Configuration" ) );
            break;
        }
        case 0x2904:
        {
            WPRINT_LIB_INFO( ( "Characteristic Descriptor - Characteristic Presentation Format" ) );
            break;
        }
        case 0x2905:
        {
            WPRINT_LIB_INFO( ( "Characteristic Descriptor - Characteristic Aggregate Format" ) );
            break;
        }
        case 0x2A00:
        {
            WPRINT_LIB_INFO( ( "Characteristic Type - Device Name" ) );
            break;
        }
        case 0x2A01:
        {
            WPRINT_LIB_INFO( ( "Characteristic Type - Appearance" ) );
            break;
        }
        case 0x2A02:
        {
            WPRINT_LIB_INFO( ( "Characteristic Type - Peripheral Privacy Flags" ) );
            break;
        }
        case 0x2A03:
        {
            WPRINT_LIB_INFO( ( "Characteristic Type - Reconnection Address" ) );
            break;
        }
        case 0x2A04:
        {
            WPRINT_LIB_INFO( ( "Characteristic Type - Peripheral Preferred Connection Parameters" ) );
            break;
        }
        case 0x2A05:
        {
            WPRINT_LIB_INFO( ( "Service Changed" ) );
            break;
        }
        default:
        {
            WPRINT_LIB_INFO( ( "Unknown Type" ) );
            break;
        }
    }

    return WICED_BT_SUCCESS;
}
Ejemplo n.º 9
0
wiced_result_t wiced_bt_smart_attribute_print( const wiced_bt_smart_attribute_t* attribute )
{
    wiced_bt_smart_attribute_t* curr_attr = (wiced_bt_smart_attribute_t*)attribute;

    if ( attribute == NULL )
    {
        return WICED_BT_BADARG;
    }

    WPRINT_LIB_INFO( ( "----------------------------------------------------\n" ) );
    print_type( &curr_attr->type );
    WPRINT_LIB_INFO( ( "\n" ) );
    WPRINT_LIB_INFO( ( "Handle                         : %d\n", (int)curr_attr->handle ) );
    WPRINT_LIB_INFO( ( "Type                           : " ) );
    print_uuid( &curr_attr->type );
    WPRINT_LIB_INFO( ( "Permission                     : %d\n", (int)curr_attr->permission ) );
    WPRINT_LIB_INFO( ( "Value Length                   : %d\n", (int)curr_attr->value_length ) );

    if ( curr_attr->type.size == UUID_16BIT )
    {
        switch ( curr_attr->type.value.value_16_bit )
        {
            case 0x2800:
            {
                WPRINT_LIB_INFO( ( "Start Handle                   : %d\n", (int)curr_attr->value.service.start_handle ) );
                WPRINT_LIB_INFO( ( "End Handle                     : %d\n", (int)curr_attr->value.service.end_handle   ) );
                WPRINT_LIB_INFO( ( "Service UUID                   : ") );
                print_uuid( &curr_attr->value.service.uuid );
                break;
            }
            case 0x2802:
            {
                WPRINT_LIB_INFO( ( "Start Handle                   : %d\n", (int)curr_attr->value.include.included_service_handle ) );
                WPRINT_LIB_INFO( ( "End Handle                     : %d\n", (int)curr_attr->value.include.end_group_handle ) );
                WPRINT_LIB_INFO( ( "Service UUID                   : ") );
                print_uuid( &curr_attr->value.include.uuid );
                break;
            }
            case 0x2803:
            {
                WPRINT_LIB_INFO( ( "Properties                     : %d\n", (int)curr_attr->value.characteristic.properties ) );
                WPRINT_LIB_INFO( ( "Value Handle                   : %d\n", (int)curr_attr->value.characteristic.value_handle ) );
                WPRINT_LIB_INFO( ( "Value UUID                     : ") );
                print_uuid( &curr_attr->value.characteristic.uuid );
                break;
            }
            case 0x2900:
            {
                WPRINT_LIB_INFO( ( "Extended Properties            : %d\n", (int)curr_attr->value.extended_properties.properties ) );
                break;
            }
            case 0x2901:
            {
                WPRINT_LIB_INFO( ( "Extended Properties            : %s\n", curr_attr->value.user_description.string ) );
                break;
            }
            case 0x2902:
            {
                WPRINT_LIB_INFO( ( "Client Configuration           : %d\n", (int)curr_attr->value.client_config.config_bits ) );
                break;
            }
            case 0x2903:
            {
                WPRINT_LIB_INFO( ( "Server Configuration           : %d\n", (int)curr_attr->value.server_config.config_bits ) );
                break;
            }
            case 0x2904:
            {
                WPRINT_LIB_INFO( ( "Format                         : %d\n", (int)curr_attr->value.presentation_format.format ) );
                WPRINT_LIB_INFO( ( "Exponent                       : %d\n", (int)curr_attr->value.presentation_format.exponent ) );
                WPRINT_LIB_INFO( ( "Unit                           : %d\n", (int)curr_attr->value.presentation_format.unit ) );
                WPRINT_LIB_INFO( ( "Namespace                      : %d\n", (int)curr_attr->value.presentation_format.name_space ) );
                WPRINT_LIB_INFO( ( "Description                    : %d\n", (int)curr_attr->value.presentation_format.description ) );
                break;
            }
            case 0x2905:
            {
                uint32_t i;

                WPRINT_LIB_INFO( ( "List of Handles                : \n" ) );
                for ( i = 0; i < curr_attr->value_length / 2; i ++ )
                {
                    WPRINT_LIB_INFO( ( "%02d ", (int)curr_attr->value.aggregate_format.handle_list[i] ) );
                }
                WPRINT_LIB_INFO( ( "\n" ) );
                break;
            }
            case 0x2A00:
            {
                WPRINT_LIB_INFO( ( "Device Name                    : %s\n", curr_attr->value.device_name.device_name ) );
                break;
            }
            case 0x2A01:
            {
                WPRINT_LIB_INFO( ( "Appearance                     : %d\n", (int)curr_attr->value.appearance.appearance ) );
                break;
            }
            case 0x2A02:
            {
                WPRINT_LIB_INFO( ( "Peripheral Privacy Flag        : %d\n", (int)curr_attr->value.periph_privacy_flag.periph_privacy_flag ) );
                break;
            }
            case 0x2A03:
            {
                WPRINT_LIB_INFO( ( "Reconnection Address           : %02x:%02x:%02x:%02x:%02x:%02x\n",
                                   (int)curr_attr->value.reconn_address.reconn_address[0],
                                   (int)curr_attr->value.reconn_address.reconn_address[1],
                                   (int)curr_attr->value.reconn_address.reconn_address[2],
                                   (int)curr_attr->value.reconn_address.reconn_address[3],
                                   (int)curr_attr->value.reconn_address.reconn_address[4],
                                   (int)curr_attr->value.reconn_address.reconn_address[5] ) );
                break;
            }
            case 0x2A04:
            {
                WPRINT_LIB_INFO( ( "Max Connection Interval        : %d\n", (int)curr_attr->value.periph_preferred_conn_params.max_conn_interval ) );
                WPRINT_LIB_INFO( ( "Min Connection Interval        : %d\n", (int)curr_attr->value.periph_preferred_conn_params.min_conn_interval ) );
                WPRINT_LIB_INFO( ( "Slave Latency                  : %d\n", (int)curr_attr->value.periph_preferred_conn_params.slave_latency ) );
                WPRINT_LIB_INFO( ( "Supervision Timeout Multiplier : %d\n", (int)curr_attr->value.periph_preferred_conn_params.conn_supervision_timeout_multiplier ) );
                break;
            }
            default:
            {
                uint32_t i;

                WPRINT_LIB_INFO( ( "Value                          : \n" ) );
                for ( i = 0; i < curr_attr->value_length; i ++ )
                {
                    WPRINT_LIB_INFO( ( "%02x ", (int)curr_attr->value.value[i] ) );
                }
                WPRINT_LIB_INFO( ( "\n" ) );
                break;
            }
        }
    }

    WPRINT_LIB_INFO( ( "----------------------------------------------------\n" ) );
    return WICED_BT_SUCCESS;
}
wiced_result_t bt_smartbridge_att_cache_enable( uint32_t cache_count )
{
    uint32_t a;
    wiced_result_t result;
    bt_smartbridge_att_cache_manager_t* manager;

    if ( att_cache_manager != NULL )
    {
        return WICED_BT_SUCCESS;
    }

    manager = (bt_smartbridge_att_cache_manager_t*)malloc_named( "att_cache", CALCULATE_ATT_CACHE_MANAGER_SIZE( cache_count ) );
    if ( manager == NULL )
    {
        return WICED_BT_OUT_OF_HEAP_SPACE;
    }

    memset( manager, 0, CALCULATE_ATT_CACHE_MANAGER_SIZE( cache_count ) );

    att_cache_manager = manager;
    manager->count    = cache_count;

    result = bt_linked_list_init( &manager->free_list );
    if ( result != WICED_BT_SUCCESS )
    {
        WPRINT_LIB_INFO( ( "Error creating linked list\n" ) );
        goto error;
    }

    result = bt_linked_list_init( &manager->used_list );
    if ( result != WICED_BT_SUCCESS )
    {
        WPRINT_LIB_INFO( ( "Error creating linked list\n" ) );
        goto error;
    }

    result = wiced_rtos_init_mutex( &manager->mutex );
    if ( result != WICED_SUCCESS )
    {
        WPRINT_LIB_INFO( ( "Error creating mutex\n" ) );
        goto error;
    }

    /* Initialise mutexes for protecting access to cached attributes */
    for ( a = 0; a < manager->count; a++ )
    {
        result = wiced_rtos_init_mutex( &manager->pool[a].mutex );
        if ( result != WICED_BT_SUCCESS )
        {
            goto error;
        }

        /* Point node data to cached attribute instance */
        manager->pool[a].node.data = (void*)&manager->pool[a];

        /* Insert cached attribute instance into free list */
        result = bt_linked_list_insert_at_rear( &manager->free_list, &manager->pool[a].node );
        if ( result != WICED_BT_SUCCESS )
        {
            goto error;
        }
    }

    return WICED_BT_SUCCESS;

    error:
    bt_smartbridge_att_cache_disable();
    return result;
}