forked from Qortal/Brooklyn
533 lines
11 KiB
C
533 lines
11 KiB
C
/* =========================================================================
|
|
* $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.c $
|
|
* $Revision: #4 $
|
|
* $Date: 2010/11/04 $
|
|
* $Change: 1621692 $
|
|
*
|
|
* Synopsys Portability Library Software and documentation
|
|
* (hereinafter, "Software") is an Unsupported proprietary work of
|
|
* Synopsys, Inc. unless otherwise expressly agreed to in writing
|
|
* between Synopsys and you.
|
|
*
|
|
* The Software IS NOT an item of Licensed Software or Licensed Product
|
|
* under any End User Software License Agreement or Agreement for
|
|
* Licensed Product with Synopsys or any supplement thereto. You are
|
|
* permitted to use and redistribute this Software in source and binary
|
|
* forms, with or without modification, provided that redistributions
|
|
* of source code must retain this notice. You may not view, use,
|
|
* disclose, copy or distribute this file or any information contained
|
|
* herein except pursuant to this license grant from Synopsys. If you
|
|
* do not agree with this notice, including the disclaimer below, then
|
|
* you are not authorized to use the Software.
|
|
*
|
|
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
|
|
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
|
|
* SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
* DAMAGE.
|
|
* ========================================================================= */
|
|
#ifdef DWC_CCLIB
|
|
|
|
#include "dwc_cc.h"
|
|
|
|
typedef struct dwc_cc
|
|
{
|
|
uint32_t uid;
|
|
uint8_t chid[16];
|
|
uint8_t cdid[16];
|
|
uint8_t ck[16];
|
|
uint8_t *name;
|
|
uint8_t length;
|
|
DWC_CIRCLEQ_ENTRY(dwc_cc) list_entry;
|
|
} dwc_cc_t;
|
|
|
|
DWC_CIRCLEQ_HEAD(context_list, dwc_cc);
|
|
|
|
/** The main structure for CC management. */
|
|
struct dwc_cc_if
|
|
{
|
|
dwc_mutex_t *mutex;
|
|
char *filename;
|
|
|
|
unsigned is_host:1;
|
|
|
|
dwc_notifier_t *notifier;
|
|
|
|
struct context_list list;
|
|
};
|
|
|
|
#ifdef DEBUG
|
|
static inline void dump_bytes(char *name, uint8_t *bytes, int len)
|
|
{
|
|
int i;
|
|
DWC_PRINTF("%s: ", name);
|
|
for (i=0; i<len; i++) {
|
|
DWC_PRINTF("%02x ", bytes[i]);
|
|
}
|
|
DWC_PRINTF("\n");
|
|
}
|
|
#else
|
|
#define dump_bytes(x...)
|
|
#endif
|
|
|
|
static dwc_cc_t *alloc_cc(void *mem_ctx, uint8_t *name, uint32_t length)
|
|
{
|
|
dwc_cc_t *cc = dwc_alloc(mem_ctx, sizeof(dwc_cc_t));
|
|
if (!cc) {
|
|
return NULL;
|
|
}
|
|
DWC_MEMSET(cc, 0, sizeof(dwc_cc_t));
|
|
|
|
if (name) {
|
|
cc->length = length;
|
|
cc->name = dwc_alloc(mem_ctx, length);
|
|
if (!cc->name) {
|
|
dwc_free(mem_ctx, cc);
|
|
return NULL;
|
|
}
|
|
|
|
DWC_MEMCPY(cc->name, name, length);
|
|
}
|
|
|
|
return cc;
|
|
}
|
|
|
|
static void free_cc(void *mem_ctx, dwc_cc_t *cc)
|
|
{
|
|
if (cc->name) {
|
|
dwc_free(mem_ctx, cc->name);
|
|
}
|
|
dwc_free(mem_ctx, cc);
|
|
}
|
|
|
|
static uint32_t next_uid(dwc_cc_if_t *cc_if)
|
|
{
|
|
uint32_t uid = 0;
|
|
dwc_cc_t *cc;
|
|
DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
|
|
if (cc->uid > uid) {
|
|
uid = cc->uid;
|
|
}
|
|
}
|
|
|
|
if (uid == 0) {
|
|
uid = 255;
|
|
}
|
|
|
|
return uid + 1;
|
|
}
|
|
|
|
static dwc_cc_t *cc_find(dwc_cc_if_t *cc_if, uint32_t uid)
|
|
{
|
|
dwc_cc_t *cc;
|
|
DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
|
|
if (cc->uid == uid) {
|
|
return cc;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static unsigned int cc_data_size(dwc_cc_if_t *cc_if)
|
|
{
|
|
unsigned int size = 0;
|
|
dwc_cc_t *cc;
|
|
DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
|
|
size += (48 + 1);
|
|
if (cc->name) {
|
|
size += cc->length;
|
|
}
|
|
}
|
|
return size;
|
|
}
|
|
|
|
static uint32_t cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
|
|
{
|
|
uint32_t uid = 0;
|
|
dwc_cc_t *cc;
|
|
|
|
DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
|
|
if (DWC_MEMCMP(cc->chid, chid, 16) == 0) {
|
|
uid = cc->uid;
|
|
break;
|
|
}
|
|
}
|
|
return uid;
|
|
}
|
|
static uint32_t cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
|
|
{
|
|
uint32_t uid = 0;
|
|
dwc_cc_t *cc;
|
|
|
|
DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
|
|
if (DWC_MEMCMP(cc->cdid, cdid, 16) == 0) {
|
|
uid = cc->uid;
|
|
break;
|
|
}
|
|
}
|
|
return uid;
|
|
}
|
|
|
|
/* Internal cc_add */
|
|
static int32_t cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
|
|
uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
|
|
{
|
|
dwc_cc_t *cc;
|
|
uint32_t uid;
|
|
|
|
if (cc_if->is_host) {
|
|
uid = cc_match_cdid(cc_if, cdid);
|
|
}
|
|
else {
|
|
uid = cc_match_chid(cc_if, chid);
|
|
}
|
|
|
|
if (uid) {
|
|
DWC_DEBUGC("Replacing previous connection context id=%d name=%p name_len=%d", uid, name, length);
|
|
cc = cc_find(cc_if, uid);
|
|
}
|
|
else {
|
|
cc = alloc_cc(mem_ctx, name, length);
|
|
cc->uid = next_uid(cc_if);
|
|
DWC_CIRCLEQ_INSERT_TAIL(&cc_if->list, cc, list_entry);
|
|
}
|
|
|
|
DWC_MEMCPY(&(cc->chid[0]), chid, 16);
|
|
DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
|
|
DWC_MEMCPY(&(cc->ck[0]), ck, 16);
|
|
|
|
DWC_DEBUGC("Added connection context id=%d name=%p name_len=%d", cc->uid, name, length);
|
|
dump_bytes("CHID", cc->chid, 16);
|
|
dump_bytes("CDID", cc->cdid, 16);
|
|
dump_bytes("CK", cc->ck, 16);
|
|
return cc->uid;
|
|
}
|
|
|
|
/* Internal cc_clear */
|
|
static void cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
|
|
{
|
|
while (!DWC_CIRCLEQ_EMPTY(&cc_if->list)) {
|
|
dwc_cc_t *cc = DWC_CIRCLEQ_FIRST(&cc_if->list);
|
|
DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
|
|
free_cc(mem_ctx, cc);
|
|
}
|
|
}
|
|
|
|
dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
|
|
dwc_notifier_t *notifier, unsigned is_host)
|
|
{
|
|
dwc_cc_if_t *cc_if = NULL;
|
|
|
|
/* Allocate a common_cc_if structure */
|
|
cc_if = dwc_alloc(mem_ctx, sizeof(dwc_cc_if_t));
|
|
|
|
if (!cc_if)
|
|
return NULL;
|
|
|
|
#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
|
|
DWC_MUTEX_ALLOC_LINUX_DEBUG(cc_if->mutex);
|
|
#else
|
|
cc_if->mutex = dwc_mutex_alloc(mtx_ctx);
|
|
#endif
|
|
if (!cc_if->mutex) {
|
|
dwc_free(mem_ctx, cc_if);
|
|
return NULL;
|
|
}
|
|
|
|
DWC_CIRCLEQ_INIT(&cc_if->list);
|
|
cc_if->is_host = is_host;
|
|
cc_if->notifier = notifier;
|
|
return cc_if;
|
|
}
|
|
|
|
void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if)
|
|
{
|
|
#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
|
|
DWC_MUTEX_FREE(cc_if->mutex);
|
|
#else
|
|
dwc_mutex_free(mtx_ctx, cc_if->mutex);
|
|
#endif
|
|
cc_clear(mem_ctx, cc_if);
|
|
dwc_free(mem_ctx, cc_if);
|
|
}
|
|
|
|
static void cc_changed(dwc_cc_if_t *cc_if)
|
|
{
|
|
if (cc_if->notifier) {
|
|
dwc_notify(cc_if->notifier, DWC_CC_LIST_CHANGED_NOTIFICATION, cc_if);
|
|
}
|
|
}
|
|
|
|
void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
|
|
{
|
|
DWC_MUTEX_LOCK(cc_if->mutex);
|
|
cc_clear(mem_ctx, cc_if);
|
|
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
|
cc_changed(cc_if);
|
|
}
|
|
|
|
int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
|
|
uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
|
|
{
|
|
uint32_t uid;
|
|
|
|
DWC_MUTEX_LOCK(cc_if->mutex);
|
|
uid = cc_add(mem_ctx, cc_if, chid, cdid, ck, name, length);
|
|
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
|
cc_changed(cc_if);
|
|
|
|
return uid;
|
|
}
|
|
|
|
void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id, uint8_t *chid,
|
|
uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
|
|
{
|
|
dwc_cc_t* cc;
|
|
|
|
DWC_DEBUGC("Change connection context %d", id);
|
|
|
|
DWC_MUTEX_LOCK(cc_if->mutex);
|
|
cc = cc_find(cc_if, id);
|
|
if (!cc) {
|
|
DWC_ERROR("Uid %d not found in cc list\n", id);
|
|
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
|
return;
|
|
}
|
|
|
|
if (chid) {
|
|
DWC_MEMCPY(&(cc->chid[0]), chid, 16);
|
|
}
|
|
if (cdid) {
|
|
DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
|
|
}
|
|
if (ck) {
|
|
DWC_MEMCPY(&(cc->ck[0]), ck, 16);
|
|
}
|
|
|
|
if (name) {
|
|
if (cc->name) {
|
|
dwc_free(mem_ctx, cc->name);
|
|
}
|
|
cc->name = dwc_alloc(mem_ctx, length);
|
|
if (!cc->name) {
|
|
DWC_ERROR("Out of memory in dwc_cc_change()\n");
|
|
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
|
return;
|
|
}
|
|
cc->length = length;
|
|
DWC_MEMCPY(cc->name, name, length);
|
|
}
|
|
|
|
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
|
|
|
cc_changed(cc_if);
|
|
|
|
DWC_DEBUGC("Changed connection context id=%d\n", id);
|
|
dump_bytes("New CHID", cc->chid, 16);
|
|
dump_bytes("New CDID", cc->cdid, 16);
|
|
dump_bytes("New CK", cc->ck, 16);
|
|
}
|
|
|
|
void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id)
|
|
{
|
|
dwc_cc_t *cc;
|
|
|
|
DWC_DEBUGC("Removing connection context %d", id);
|
|
|
|
DWC_MUTEX_LOCK(cc_if->mutex);
|
|
cc = cc_find(cc_if, id);
|
|
if (!cc) {
|
|
DWC_ERROR("Uid %d not found in cc list\n", id);
|
|
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
|
return;
|
|
}
|
|
|
|
DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
|
|
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
|
free_cc(mem_ctx, cc);
|
|
|
|
cc_changed(cc_if);
|
|
}
|
|
|
|
uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if, unsigned int *length)
|
|
{
|
|
uint8_t *buf, *x;
|
|
uint8_t zero = 0;
|
|
dwc_cc_t *cc;
|
|
|
|
DWC_MUTEX_LOCK(cc_if->mutex);
|
|
*length = cc_data_size(cc_if);
|
|
if (!(*length)) {
|
|
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
|
return NULL;
|
|
}
|
|
|
|
DWC_DEBUGC("Creating data for saving (length=%d)", *length);
|
|
|
|
buf = dwc_alloc(mem_ctx, *length);
|
|
if (!buf) {
|
|
*length = 0;
|
|
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
|
return NULL;
|
|
}
|
|
|
|
x = buf;
|
|
DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
|
|
DWC_MEMCPY(x, cc->chid, 16);
|
|
x += 16;
|
|
DWC_MEMCPY(x, cc->cdid, 16);
|
|
x += 16;
|
|
DWC_MEMCPY(x, cc->ck, 16);
|
|
x += 16;
|
|
if (cc->name) {
|
|
DWC_MEMCPY(x, &cc->length, 1);
|
|
x += 1;
|
|
DWC_MEMCPY(x, cc->name, cc->length);
|
|
x += cc->length;
|
|
}
|
|
else {
|
|
DWC_MEMCPY(x, &zero, 1);
|
|
x += 1;
|
|
}
|
|
}
|
|
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
|
|
|
return buf;
|
|
}
|
|
|
|
void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *data, uint32_t length)
|
|
{
|
|
uint8_t name_length;
|
|
uint8_t *name;
|
|
uint8_t *chid;
|
|
uint8_t *cdid;
|
|
uint8_t *ck;
|
|
uint32_t i = 0;
|
|
|
|
DWC_MUTEX_LOCK(cc_if->mutex);
|
|
cc_clear(mem_ctx, cc_if);
|
|
|
|
while (i < length) {
|
|
chid = &data[i];
|
|
i += 16;
|
|
cdid = &data[i];
|
|
i += 16;
|
|
ck = &data[i];
|
|
i += 16;
|
|
|
|
name_length = data[i];
|
|
i ++;
|
|
|
|
if (name_length) {
|
|
name = &data[i];
|
|
i += name_length;
|
|
}
|
|
else {
|
|
name = NULL;
|
|
}
|
|
|
|
/* check to see if we haven't overflown the buffer */
|
|
if (i > length) {
|
|
DWC_ERROR("Data format error while attempting to load CCs "
|
|
"(nlen=%d, iter=%d, buflen=%d).\n", name_length, i, length);
|
|
break;
|
|
}
|
|
|
|
cc_add(mem_ctx, cc_if, chid, cdid, ck, name, name_length);
|
|
}
|
|
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
|
|
|
cc_changed(cc_if);
|
|
}
|
|
|
|
uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
|
|
{
|
|
uint32_t uid = 0;
|
|
|
|
DWC_MUTEX_LOCK(cc_if->mutex);
|
|
uid = cc_match_chid(cc_if, chid);
|
|
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
|
return uid;
|
|
}
|
|
uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
|
|
{
|
|
uint32_t uid = 0;
|
|
|
|
DWC_MUTEX_LOCK(cc_if->mutex);
|
|
uid = cc_match_cdid(cc_if, cdid);
|
|
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
|
return uid;
|
|
}
|
|
|
|
uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id)
|
|
{
|
|
uint8_t *ck = NULL;
|
|
dwc_cc_t *cc;
|
|
|
|
DWC_MUTEX_LOCK(cc_if->mutex);
|
|
cc = cc_find(cc_if, id);
|
|
if (cc) {
|
|
ck = cc->ck;
|
|
}
|
|
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
|
|
|
return ck;
|
|
|
|
}
|
|
|
|
uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id)
|
|
{
|
|
uint8_t *retval = NULL;
|
|
dwc_cc_t *cc;
|
|
|
|
DWC_MUTEX_LOCK(cc_if->mutex);
|
|
cc = cc_find(cc_if, id);
|
|
if (cc) {
|
|
retval = cc->chid;
|
|
}
|
|
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
|
|
|
return retval;
|
|
}
|
|
|
|
uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id)
|
|
{
|
|
uint8_t *retval = NULL;
|
|
dwc_cc_t *cc;
|
|
|
|
DWC_MUTEX_LOCK(cc_if->mutex);
|
|
cc = cc_find(cc_if, id);
|
|
if (cc) {
|
|
retval = cc->cdid;
|
|
}
|
|
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
|
|
|
return retval;
|
|
}
|
|
|
|
uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length)
|
|
{
|
|
uint8_t *retval = NULL;
|
|
dwc_cc_t *cc;
|
|
|
|
DWC_MUTEX_LOCK(cc_if->mutex);
|
|
*length = 0;
|
|
cc = cc_find(cc_if, id);
|
|
if (cc) {
|
|
*length = cc->length;
|
|
retval = cc->name;
|
|
}
|
|
DWC_MUTEX_UNLOCK(cc_if->mutex);
|
|
|
|
return retval;
|
|
}
|
|
|
|
#endif /* DWC_CCLIB */
|