/**************************************************************************** NAME UpgradeSavePSKeys - Save our PSKEYS DESCRIPTION Save our PSKEYS into Persistent Storage. The existing contents of the key are read first. If they chance not to exist the the value we do not control are set to 0x0000 (deemed safer than panicking or using a marker such as 0xFACE) Note that the upgrade library initialisation has guaranteed that the the pskeys fit within the 64 words allowed. Although not technically part of our API, safest if we allow for the PSKEY to be longer than we use. */ void UpgradeSavePSKeys(void) { uint16 keyCache[PSKEY_MAX_STORAGE_LENGTH]; uint16 min_key_length = UpgradeCtxGet()->upgrade_library_pskeyoffset +UPGRADE_PRIVATE_PSKEY_USAGE_LENGTH_WORDS; /* Find out how long the PSKEY is */ uint16 actualLength = PsRetrieve(UpgradeCtxGet()->upgrade_library_pskey,NULL,0); if (actualLength) { PsRetrieve(UpgradeCtxGet()->upgrade_library_pskey,keyCache,actualLength); } else { if (UpgradeCtxGet()->upgrade_library_pskeyoffset) { /* Initialise the portion of key before us */ memset(keyCache,0x0000,sizeof(keyCache)); } actualLength = min_key_length; } /* Correct for too short a key */ if (actualLength < min_key_length) { actualLength = min_key_length; } memcpy(&keyCache[UpgradeCtxGet()->upgrade_library_pskeyoffset],UpgradeCtxGetPSKeys(), UPGRADE_PRIVATE_PSKEY_USAGE_LENGTH_WORDS*sizeof(uint16)); PsStore(UpgradeCtxGet()->upgrade_library_pskey,keyCache,actualLength); }
/**************************************************************************** NAME connectionAuthGetAttribute FUNCTION This function is called to read the specified data from the specified persistent store key. The persistent store key is calulated from the specified base + the index of the specified device in TDL. RETURNS */ void connectionAuthGetAttribute(Task appTask, uint16 ps_base, const bdaddr* bd_addr, uint16 size_psdata) { /* Find device in the TDL */ uint16 index = find_trusted_device(bd_addr); if (appTask) { /* Send a message back to the application task */ MAKE_CL_MESSAGE_WITH_LEN(CL_SM_GET_ATTRIBUTE_CFM, size_psdata); message->status = fail; message->size_psdata = size_psdata; message->psdata[0] = 0; /* If an entry exists in the TDL for the specified device */ if(index) { index--; if(size_psdata) { /* Read attribute data */ if(PsRetrieve(ps_base + index, message->psdata, size_psdata)) { message->status = success; } } } MessageSend(appTask, CL_SM_GET_ATTRIBUTE_CFM, message); } }
/**************************************************************************** NAME connectionAuthSendLinkKey FUNCTION This function is called to send the link key of the specified device to the Bluestack Security Manager */ void connectionAuthSendLinkKey(const bdaddr* peer_bd_addr) { uint16 rec; TrustedDeviceRecordType record; MAKE_PRIM_T(DM_SM_LINK_KEY_REQUEST_RES); connectionConvertBdaddr_t(&prim->bd_addr, peer_bd_addr); /* Search for the device in the TDL */ rec = find_trusted_device(peer_bd_addr); /* If the device is in the TDL */ if(rec) { rec--; /* Get the link key */ (void)PsRetrieve(TRUSTED_DEVICE_LIST_BASE + rec, &record, sizeof(TrustedDeviceRecordType)); prim->valid = 1; memcpy(prim->key, record.link_key, SIZE_LINK_KEY); } else { /* Reject the request for a link key */ prim->valid = 0; memset(prim->key, 0, SIZE_LINK_KEY); } /* Send message to the Connection Manager */ VmSendDmPrim(prim); }
/**************************************************************************** NAME connectionAuthSetTrustLevel FUNCTION This function is called to set the trust level of a device stored in the trusted device list. The Blustack Security Manager is updated with the change. RETURNS TRUE is record updated, otherwise FALSE */ uint16 connectionAuthSetTrustLevel(cl_dm_bt_version version, const bdaddr* peer_bd_addr, uint16 trusted) { /* Holds the position of a device in the trusted device list (TDL) */ uint16 rec = 0; TrustedDeviceRecordType record; /* Search for the device in the TDL */ rec = find_trusted_device(peer_bd_addr); /* If the device is in the TDL */ if(rec) { rec--; /* Read the record */ (void)PsRetrieve(TRUSTED_DEVICE_LIST_BASE + rec, &record, sizeof(TrustedDeviceRecordType)); /* Update the trust level */ record.trusted = trusted; /* Store the record */ (void)PsStore(TRUSTED_DEVICE_LIST_BASE + rec, &record, sizeof(TrustedDeviceRecordType)); /* Update Bluestack Security Manager Database */ register_device(version, &record); /* Record updated */ return TRUE; } /* Record for this device does not exist */ return FALSE; }
/**************************************************************************** NAME connectionAuthGetDevice FUNCTION This function is called to add a trusted device to the persistent trusted device list. A flag indicating if the device was found is returned. */ uint16 connectionAuthGetDevice(const bdaddr *peer_bd_addr, cl_sm_link_key_type *link_key_type, uint8 *link_key, uint16 *trusted) { uint16 rec; uint16 res = FALSE; TrustedDeviceRecordType record; /* Search for the device in the TDL */ rec = find_trusted_device(peer_bd_addr); /* If the device is in the TDL */ if(rec) { rec--; /* Get the link key */ (void)PsRetrieve(TRUSTED_DEVICE_LIST_BASE + rec, &record, sizeof(TrustedDeviceRecordType)); res = TRUE; *trusted = record.trusted; *link_key_type = record.link_key_type; memcpy(link_key, record.link_key, SIZE_LINK_KEY); } return res; }
/**************************************************************************** DESCRIPTION This function will delete an entry from the trusted device index */ static uint16 delete_from_trusted_device_index(uint16 order, uint16 noDevices) { TrustedDeviceIndexType tdi; uint16 index; uint16 ok = FALSE; /* Read the TDI from persistent store */ if(PsRetrieve(TRUSTED_DEVICE_INDEX, &tdi, sizeof(tdi))) { if(order != INDEX_INVALID) { /* Delete index from TDI and reorder TDI */ for(index = order; index < (noDevices - 1); index++) tdi.order[index] = tdi.order[index+1]; /* LRU index is now invalid */ tdi.order[noDevices - 1] = 0; } /* Store persistently */ (void)PsStore(TRUSTED_DEVICE_INDEX, &tdi, sizeof(tdi)); ok = TRUE; } return ok; }
/**************************************************************************** NAME UpgradeLoadPSStore - Load PSKEY on boot DESCRIPTION Save the details of the PSKEY and offset that we were passed on initialisation, and retrieve the current values of the key. In the unlikely event of the storage not being found, we initialise our storage to 0x00 rather than panicking. */ void UpgradeLoadPSStore(uint16 dataPskey,uint16 dataPskeyStart) { union { uint16 keyCache[PSKEY_MAX_STORAGE_LENGTH]; FSTAB_COPY fstab; } stack_storage; uint16 lengthRead; UpgradeCtxGet()->upgrade_library_pskey = dataPskey; UpgradeCtxGet()->upgrade_library_pskeyoffset = dataPskeyStart; /* Worst case buffer is used, so confident we can read complete key * if it exists. If we limited to what it should be, then a longer key * would not be read due to insufficient buffer * Need to zero buffer used as the cache is on the stack. */ memset(stack_storage.keyCache,0,sizeof(stack_storage.keyCache)); lengthRead = PsRetrieve(dataPskey,stack_storage.keyCache,PSKEY_MAX_STORAGE_LENGTH); if (lengthRead) { memcpy(UpgradeCtxGetPSKeys(),&stack_storage.keyCache[dataPskeyStart], UPGRADE_PRIVATE_PSKEY_USAGE_LENGTH_WORDS*sizeof(uint16)); } else { memset(UpgradeCtxGetPSKeys(),0x0000,sizeof(UpgradeCtxGetPSKeys()) * sizeof(uint16)); } /* Load the implementation FSTAB. */ loadFstab(&stack_storage.fstab, ps_store_implementation); }
static void readPsPermanentPairing (bdaddr *bd_addr, uint16 *link_key, uint16 *link_key_status, sink_attributes *attributes) { uint16 * ps_key; /* Allocate and zero buffer to hold PS key */ ps_key = mallocPanic(BD_ADDR_SIZE + LINK_KEY_SIZE + ATTRIBUTES_SIZE + 1); memset(ps_key, 0, BD_ADDR_SIZE + LINK_KEY_SIZE + ATTRIBUTES_SIZE + 1); /* Attempt to obtain current pairing data */ PsRetrieve(CONFIG_PERMANENT_PAIRING, ps_key, BD_ADDR_SIZE + LINK_KEY_SIZE + ATTRIBUTES_SIZE + 1); /* Return any requested fields */ if (link_key_status) { *link_key_status = ps_key[STATUS_LOC]; } if (bd_addr) { memcpy(bd_addr, &ps_key[BD_ADDR_LOC], BD_ADDR_SIZE); } if (link_key) { memcpy(link_key, &ps_key[LINK_KEY_LOC], LINK_KEY_SIZE); } if (attributes) { memcpy(attributes, &ps_key[ATTRIBUTES_LOC], ATTRIBUTES_SIZE); } free(ps_key); }
void configManagerSqifPartitionsInit( void ) { /* read currently free SQIF partitions */ uint16 ret_len = 0; uint16 partition_data = 0; /* Read partition information from PS */ ret_len = PsRetrieve(PSKEY_SQIF_PARTITIONS, &partition_data, sizeof(uint16)); if(!ret_len) { /* no key present - assume all partitions are in use */ theSink.rundata->partitions_free = 0; } else { theSink.rundata->partitions_free = LOWORD(partition_data); } CONF_DEBUG(("CONF : Current SQIF partitions free 0x%x \n", theSink.rundata->partitions_free)); /* Check that the currently selected languages partition is available */ if((1<<theSink.tts_language) & theSink.rundata->partitions_free) { uint16 currentLang = theSink.tts_language; CONF_DEBUG(("CONF : Current SQIF VP partition (%u) not valid\n", currentLang)); TTSSelectTTSLanguageMode(); /* if the new selected language is the same then none could be found so disable TTS */ if (currentLang == theSink.tts_language) { theSink.tts_enabled = FALSE; CONF_DEBUG(("CONF : Disabling TTS, no valid VP partitions\n")); } } }
/**************************************************************************** DESCRIPTION This function will find the next free position in the Trusted Device List. */ static uint16 find_free_position(void) { uint16 rec,index; TrustedDeviceIndexType tdi; uint16 pos; TrustedDeviceRecordType record; /* Loop through list of trusted devices */ for(rec = 0; rec < NO_DEVICES_TO_MANAGE; rec++) { if(!PsRetrieve(TRUSTED_DEVICE_LIST_BASE + rec, &record, sizeof(TrustedDeviceRecordType))) { return (rec + 1); } } /* As the Trusted Device List is full then the position will be the one occupied by the LRU device */ (void)PsRetrieve(TRUSTED_DEVICE_INDEX, &tdi, sizeof(tdi)); /* The LRU device is either the last device in the index or if empty (0) we must traverse through the list to find the device */ index = NO_DEVICES_TO_MANAGE; do { if(tdi.order[--index]) break; } while(index); /* Record position */ pos = tdi.order[index]; if (PsRetrieve(TRUSTED_DEVICE_LIST_BASE + pos - 1, &record, sizeof(TrustedDeviceRecordType))) /* Remove from the BlueStack security datatbase */ unregister_device(&record.bd_addr); /* Remove LRU device from the TDI */ tdi.order[index] = 0; (void)PsStore(TRUSTED_DEVICE_INDEX, &tdi, sizeof(tdi)); return pos; }
/**************************************************************************** NAME connectionAuthGetAttribute FUNCTION This function is called to read the specified data from the specified persistent store key. The persistent store key is calulated from the specified base + the index of the specified device in TDL. RETURNS */ void connectionAuthGetIndexedAttribute(Task appTask, uint16 ps_base, uint16 mru_index, uint16 size_psdata) { TrustedDeviceIndexType tdi; TrustedDeviceRecordType record; { /* Send a message back to the application task */ MAKE_CL_MESSAGE_WITH_LEN(CL_SM_GET_INDEXED_ATTRIBUTE_CFM, size_psdata); message->status = fail; message->size_psdata = size_psdata; message->psdata[0] = 0; /* Read Trusted Device Index from Persistent store */ if ((mru_index < MAX_TRUSTED_DEVICES) && PsRetrieve(TRUSTED_DEVICE_INDEX, &tdi, sizeof(tdi))) { /* Read the device record from the Trusted Device List */ if (tdi.order[mru_index] && PsRetrieve((TRUSTED_DEVICE_LIST_BASE + tdi.order[mru_index] - 1), &record, sizeof(TrustedDeviceRecordType))) { /* Get Bluetooth address of device */ message->bd_addr = record.bd_addr; /* Check if application wants attribute data */ if (size_psdata != 0) { /* Read attribute data */ if(PsRetrieve(ps_base + tdi.order[mru_index]-1, message->psdata, size_psdata)) message->status = success; } else { /* No attribute data required, so just indicate success */ message->status = success; } } } /* Send confirmation back to application */ MessageSend(appTask, CL_SM_GET_INDEXED_ATTRIBUTE_CFM, message); } }
/**************************************************************************** NAME connectionAuthInit FUNCTION This function is called to initialise the Trusted Device List. All devices in the list are registered with the Bluestack Security Manager. RETURNS The number of devices registered with Bluestack */ uint16 connectionAuthInit(cl_dm_bt_version version) { uint16 registeredDevices = 0; TrustedDeviceIndexType tdi; uint16 rec; TrustedDeviceRecordType record; /* Check if we have a valid Trusted Device Index */ if(!PsRetrieve(TRUSTED_DEVICE_INDEX, &tdi, sizeof(tdi))) { /* Reset TDI to zero */ memset(&tdi, 0, sizeof(TrustedDeviceIndexType)); (void)PsStore(TRUSTED_DEVICE_INDEX, &tdi, sizeof(tdi)); /* Delete TDL */ for(rec = TRUSTED_DEVICE_LIST_BASE; rec <= TRUSTED_DEVICE_LIST_END; rec++) (void)PsStore(rec, NULL, 0); } else { /* Search through the Trusted Device List */ for(rec = 0; rec < NO_DEVICES_TO_MANAGE; rec++) { /* For all devices in the list... */ if(PsRetrieve(TRUSTED_DEVICE_LIST_BASE + rec, &record, sizeof(TrustedDeviceRecordType))) { /* Register the device with Bluestack Security Manager */ register_device(version, &record); /* Keep a count of the number of active device records */ registeredDevices++; } } } /* Return the number of devices registered with the Bluestack Security Manager */ return registeredDevices; }
/**************************************************************************** NAME get_config_id DESCRIPTION This function is called to read the configuration ID RETURNS Defaults to config 0 if the key doesn't exist */ uint16 get_config_id(uint16 key) { /* Default to CSR standard configuration */ uint16 id = 0; /* Read the configuration ID. This identifies the configuration held in constant space */ if(PsRetrieve(key, &id, sizeof(uint16))) { if(id >= last_config_id) { id = 0; } } return id; }
/**************************************************************************** DESCRIPTION This function searches for the specified peer device in the Trusted Device List (TDL). The value returned as position defines the record number of the device in TDL. -------------------------------------- |R1 | R2 | R3 | R4 | R5 | R6 | R7 | R8 | -------------------------------------- If the value returned is zero then the device does not exist in the TDL */ static uint16 find_trusted_device(const bdaddr* p_peer_addr) { uint16 rec; TrustedDeviceRecordType record; /* Loop through list of trusted devices */ for(rec = 0; rec < NO_DEVICES_TO_MANAGE; rec++) { if(PsRetrieve(TRUSTED_DEVICE_LIST_BASE + rec, &record, sizeof(TrustedDeviceRecordType))) { /* If this device is already a trusted device? */ if(BdaddrIsSame(&record.bd_addr, p_peer_addr)) return (rec + 1); } } /* Device is not in the trusted device list */ return 0; }
/**************************************************************************** NAME connectionAuthDeleteAllDevices FUNCTION This function is called to remove all trusted devices from the persistent trusted device list. A flag indicating if all the devices were successfully removed is returned. */ uint16 connectionAuthDeleteAllDevice(uint16 ps_base) { /* Flag to indicate if the devices were deleted */ uint16 deleted = FALSE; /* Trusted device list record index */ uint16 rec = 0; /* Trusted device record */ TrustedDeviceRecordType record; /* trusted device index */ TrustedDeviceIndexType tdi; /* Loop through list of trusted devices */ for(rec = 0; rec < NO_DEVICES_TO_MANAGE; rec++) { if(PsRetrieve(TRUSTED_DEVICE_LIST_BASE + rec, &record, sizeof(TrustedDeviceRecordType))) { /* Unregister with Bluestack security manager */ unregister_device(&record.bd_addr); /* Delete entry from TDL */ (void)PsStore(TRUSTED_DEVICE_LIST_BASE + rec, NULL, 0); deleted = TRUE; } /* Delete any associated attribute data */ if(ps_base) { (void)PsStore(ps_base + rec, NULL, 0); } } /* Delete TDI */ if(deleted) { memset(&tdi, 0, sizeof(TrustedDeviceIndexType)); (void)PsStore(TRUSTED_DEVICE_INDEX, &tdi, sizeof(tdi)); } return deleted; }
/**************************************************************************** NAME AuthGetPDLEntries DESCRIPTION Returns the number of paired device list (PDL) entries RETURNS bool */ bool AuthGetPDLEntries(void) { uint16 i; uint16 lNumDevices = 0; uint16 ltdi[sizeof(uint16) * MAX_PAIRED_DEVICES]; if (PsRetrieve(41 , <di , sizeof(uint16) * MAX_PAIRED_DEVICES)) { for (i = 0 ; i < MAX_PAIRED_DEVICES ; i ++) { if (ltdi[i] > lNumDevices ) { lNumDevices = ltdi[i]; } } } return lNumDevices; }
/**************************************************************************** DESCRIPTION This function searches the Trusted Device Index (TDI) for a device referenced by it's position in Trusted Device List (TDL). The TDI keeps a track of the order in which devices were connected too. Each entry in the TDI holds a reference to a record in the TDL. The TDI entries are ordered from Most Recently Used (MRU) to Least Recently Used (LRU) -------------------------------------- |Ra | Rb | Rc | Rd | Rd | Re | Rf | Rg | -------------------------------------- ^ ^ | | MRU LRU */ static uint16 search_trusted_device_index(const uint16 pos) { TrustedDeviceIndexType tdi; uint16 offset = INDEX_INVALID; /* Read the TDI from persistent store */ if(PsRetrieve(TRUSTED_DEVICE_INDEX, &tdi, sizeof(tdi))) { /* Loop through the TDI searching for an occurance of the device reference */ for(offset = 0; offset < NO_DEVICES_TO_MANAGE; offset++) { /* If the required device is found in the TDI, return it's relative position (offset) in the TDI */ if(tdi.order[offset] == pos) break; } } return offset; }
/**************************************************************************** DESCRIPTION This function updates the Trusted Device Index */ static void update_trusted_device_index(const uint16 position, const uint16 order) { TrustedDeviceIndexType tdi; uint16 index; /* Read the TDI from persistent store */ if(PsRetrieve(TRUSTED_DEVICE_INDEX, &tdi, sizeof(tdi))) { if(order != INDEX_INVALID) { /* Re-order TDI */ for(index = 0; index < order; index++) tdi.order[order - index] = tdi.order[(order - index) - 1]; } /* Update with the position of the new record in the TDL as MRU device */ tdi.order[0] = position; /* Store persistently */ (void)PsStore(TRUSTED_DEVICE_INDEX, &tdi, sizeof(tdi)); } }
static void writePsPermanentPairing (const bdaddr *bd_addr, uint16 *link_key, uint16 link_key_status, const sink_attributes *attributes) { uint16 * ps_key; /* Allocate and zero buffer to hold PS key */ ps_key = mallocPanic(BD_ADDR_SIZE + LINK_KEY_SIZE + ATTRIBUTES_SIZE + 1); memset(ps_key, 0, BD_ADDR_SIZE + LINK_KEY_SIZE + ATTRIBUTES_SIZE + 1); /* Attempt to obtain current pairing data */ PsRetrieve(CONFIG_PERMANENT_PAIRING, ps_key, BD_ADDR_SIZE + LINK_KEY_SIZE + ATTRIBUTES_SIZE + 1); /* Update supplied fields */ if (link_key_status) { ps_key[STATUS_LOC] = link_key_status; } if (bd_addr) { memcpy(&ps_key[BD_ADDR_LOC], bd_addr, BD_ADDR_SIZE); } if (link_key) { memcpy(&ps_key[LINK_KEY_LOC], link_key, LINK_KEY_SIZE); } if (attributes) { memcpy(&ps_key[ATTRIBUTES_LOC], attributes, ATTRIBUTES_SIZE); } /* Store updated pairing data */ PsStore(CONFIG_PERMANENT_PAIRING, ps_key, BD_ADDR_SIZE + LINK_KEY_SIZE + ATTRIBUTES_SIZE + 1); free(ps_key); }
/**************************************************************************** NAME connectionAuthSendSspLinkKey FUNCTION This function is called to send the link key of the specified device to the Bluestack Security Manager in mode 4. In addition to the link key this also sends the link key type */ bool connectionAuthSendSspLinkKey(const bdaddr* peer_bd_addr, bool authenticated) { uint16 rec; TrustedDeviceRecordType record; bool success; uint8* link_key; MAKE_PRIM_T(DM_SM_SSP_LINK_KEY_REQUEST_RES); connectionConvertBdaddr_t(&prim->bd_addr, peer_bd_addr); /* Search for the device in the TDL */ rec = find_trusted_device(peer_bd_addr); /* If the device is in the TDL */ if(rec) { rec--; /* Get the link key */ (void)PsRetrieve(TRUSTED_DEVICE_LIST_BASE + rec, &record, sizeof(TrustedDeviceRecordType)); /* Handle old records with no key type stored */ if(record.link_key_type == 0) record.link_key_type = cl_sm_link_key_legacy; if(authenticated) { if(record.link_key_type == cl_sm_link_key_authenticated) { prim->key_type = connectionConvertLinkKeyType_t(record.link_key_type); link_key = (uint8*) PanicUnlessMalloc(SIZE_LINK_KEY); memcpy(link_key, record.link_key, SIZE_LINK_KEY); prim->key = VmGetHandleFromPointer(link_key); success = TRUE; } else { prim->key_type = connectionConvertLinkKeyType_t(cl_sm_link_key_none); prim->key = NULL; success = FALSE; } } else { prim->key_type = connectionConvertLinkKeyType_t(record.link_key_type); link_key = (uint8*) PanicUnlessMalloc(SIZE_LINK_KEY); memcpy(link_key, record.link_key, SIZE_LINK_KEY); prim->key = VmGetHandleFromPointer(link_key); success = TRUE; } } else { /* Reject the request for a link key */ prim->key_type = connectionConvertLinkKeyType_t(cl_sm_link_key_none); prim->key = NULL; success = FALSE; } /* Send message to the Connection Manager */ VmSendDmPrim(prim); return success; }
/**************************************************************************** NAME ConfigRetrieve DESCRIPTION This function is called to read a configuration key. If the key exists in persistent store it is read from there. If it does not exist then the default is read from constant space RETURNS 0 if no data was read otherwise the length of data */ uint16 ConfigRetrieve(uint16 config_id, uint16 key_id, void* data, uint16 len) { uint16 ret_len; /* Read requested key from PS if it exists */ ret_len = PsRetrieve(key_id, data, len); /* If no key exists then read the parameters from the default configuration held in constant space */ if(!ret_len) { /* Access the required configuration */ if( default_configs[ config_id ] ) { key_type * key; /* as the default configuration structures are aligned in key_id order it is safe to set the pointer such that it treats the default config config_type structure as an array and index that via the key_id value. The following line casts the default_config pointer to the first entry in the configuration structure which will be (key_type *)&battery_config, the key_id (0 to 31) is then added to the start of the config to give the correct offset with the structure. Key then retrieves the .length and .data pointer from the configuration */ key = *((key_type**)default_configs[config_id] + key_id); /* Providing the retrieved length is not zero. */ if(key->length == 0) { /* This will indicate an error. */ ret_len = 0; } else { if(key->length == len) { /* Copy from constant space */ memmove(data, &key->data, len); ret_len = len; } else { if(key->length > len) { DEBUG(("CONF:BADLEN![%x][%x][%x]\n",key_id, key->length, len)) ; Panic() ; } else { /* (key.length < len) && (key.length != 0) here since we're comparing unsigned numbers. */ /* We have more space than the size of the key in constant space. Just copy the data for the key. The length returned will let the caller know about the length mismatch. */ /* Copy from constant space */ memmove(data, &key->data, key->length); ret_len = key->length; } } } } } else { switch(key_id) { /* PS keys where it's ok for (ret_len != len) */ case(PSKEY_CODEC_NEGOTIATION): break; case(PSKEY_CONFIG_TONES): break; default: if (ret_len != len) { DEBUG(("CONF:BADLEN![%x][%x][%x]\n",key_id, ret_len, len)) ; Panic() ; } break; } } return ret_len; }