/** * Send RIP response packets to my neighbors. */ static void krip_dispatch_out() { uint32_t now = krip_get_mtime(); list_position pos; /* If _update_rime has been expired, broadcast RIP response message to neighbors. */ if (_update_time + _update_interval < now) { L_ROUTE("krip_dispatch_out(): regular advertisement on time %d", now); for (pos = list_get_head_position(_neighbor_info_list); pos; pos = list_get_next_position(pos)) { neighbor_info *ni = list_get_at(pos); if (ni->ifp->if_enabled) krip_send_response(ni, 0); } _update_time = now; } else if (_trigger) { /* If this isn't a regular update, send RIP response messages as a triggered update, and clear change_flag. Originally, we don't need _trigger flag because krip_send_response() advertises only changed entries, but I've added it for convenient logging. */ L_ROUTE("krip_dispatch_out(): triggered update!"); for (pos = list_get_head_position(_neighbor_info_list); pos; pos = list_get_next_position(pos)) { neighbor_info *ni = list_get_at(pos); if (ni->ifp->if_enabled) krip_send_response(ni, 1); } /* krip_send_response() 내에서 clear하지 않는 이유는 */ for (pos = list_get_head_position(_rip_info_list); pos; pos = list_get_next_position(pos)) { rip_info *ri = list_get_at(pos); ri->change_flag = 0; } _trigger = false; } }
/// /// Pops a scope from the stack. /// void ppimpl_pop_scope(state_t* state) { scope_t* scope; match_t* match; match_t* old; bstring name; size_t a, i; if (list_size(&state->scopes) == 0) return; scope = list_extract_at(&state->scopes, list_size(&state->scopes) - 1); // Delete text if this scope was silenced. if (!scope->active) { list_delete_range(&state->cached_output, scope->start_index, list_size(&state->cached_output) - 1); } // Delete handlers that were defined this scope. list_iterator_start(&scope->new_handlers); while (list_iterator_hasnext(&scope->new_handlers)) { name = list_iterator_next(&scope->new_handlers); for (i = 0; i < list_size(&state->handlers); i++) { old = list_get_at(&state->handlers, i); if (biseq(name, old->text.ref)) { // We need remove the old handler. // FIXME: Free the old handler. list_delete_at(&state->handlers, i); i--; } } bdestroy(name); } list_iterator_stop(&scope->new_handlers); list_destroy(&scope->new_handlers); // Restore handlers. for (a = 0; a < list_size(&scope->old_handlers); a++) { match = list_get_at(&scope->old_handlers, a); // Restore the old handler. list_append(&state->handlers, match); list_extract_at(&scope->old_handlers, a); a--; } list_destroy(&scope->old_handlers); // Free memory. free(scope); }
CK_RV card_removed(sc_reader_t * reader) { unsigned int i; struct sc_pkcs11_card *p11card = NULL; /* Mark all slots as "token not present" */ sc_log(context, "%s: card removed", reader->name); for (i=0; i < list_size(&virtual_slots); i++) { sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i); if (slot->reader == reader) { /* Save the "card" object */ if (slot->p11card) p11card = slot->p11card; slot_token_removed(slot->id); } } if (p11card) { p11card->framework->unbind(p11card); sc_disconnect_card(p11card->card); for (i=0; i < p11card->nmechanisms; ++i) { if (p11card->mechanisms[i]->free_mech_data) { p11card->mechanisms[i]->free_mech_data(p11card->mechanisms[i]->mech_data); } free(p11card->mechanisms[i]); } free(p11card->mechanisms); free(p11card); } return CKR_OK; }
int32_t ddbg_label_to_address(bstring label) { unsigned int i; struct dbg_sym* sym; struct dbg_sym_payload_label* payload_label; if (symbols != NULL) { // Search through our debugging symbols. for (i = 0; i < list_size(symbols); i++) { sym = list_get_at(symbols, i); switch (sym->type) { case DBGFMT_SYMBOL_LABEL: payload_label = (struct dbg_sym_payload_label*)sym->payload; if (biseq(payload_label->label, label)) { // The label matches, we have found our symbol entry. printd(LEVEL_DEFAULT, "Label information: %s is at 0x%04X\n", payload_label->label->data, payload_label->address); return payload_label->address; } break; default: break; } } } // If we don't find a memory address, we return -1. return -1; }
void ddbg_delete_breakpoint(bstring file, int index) { unsigned int i = 0; bool found = false; int32_t memory = ddbg_file_to_address(file, index); struct breakpoint* bk; // Did we get a valid result? if (memory == -1) { printd(LEVEL_DEFAULT, "Unable to resolve specified symbol.\n"); return; } for (i = 0; i < list_size(&breakpoints); i++) { bk = (struct breakpoint*)list_get_at(&breakpoints, i); if (bk->addr == memory) { list_delete_at(&breakpoints, i--); found = true; } } if (found == true) printd(LEVEL_DEFAULT, "Breakpoint removed at 0x%04X.\n", memory); else printd(LEVEL_DEFAULT, "There was no breakpoint at %s:%d.\n", file->data, index); }
/// /// Flips the current scope on the stack. /// void ppimpl_flip_scope(state_t* state) { scope_t* scope = list_get_at(&state->scopes, list_size(&state->scopes) - 1); bool active = scope->active; ppimpl_pop_scope(state); ppimpl_push_scope(state, !active); }
void ddbg_delete_breakpoint_identifier(bstring ident) { // TODO: In the future when C functions are supported // in the debugging symbol format, we should probably // allow removing breakpoints by C function name as well. unsigned int i = 0; bool found = false; int32_t memory = ddbg_label_to_address(ident); struct breakpoint* bk; // Did we get a valid result? if (memory == -1) { printd(LEVEL_DEFAULT, "Unable to resolve specified symbol.\n"); return; } for (i = 0; i < list_size(&breakpoints); i++) { bk = (struct breakpoint*)list_get_at(&breakpoints, i); if (bk->addr == memory) { list_delete_at(&breakpoints, i--); found = true; } } if (found == true) printd(LEVEL_DEFAULT, "Breakpoint removed at 0x%04X.\n", memory); else printd(LEVEL_DEFAULT, "There was no breakpoint on label %s.\n", ident->data); }
/// /// Adds a handler inside a scope, dealing with overridding /// existing handlers. /// void ppimpl_register(state_t* state, match_t* match) { scope_t* scope; match_t* other; size_t a; if (list_size(&state->scopes) == 0) { // Global registration. list_append(&state->handlers, match); return; } scope = list_extract_at(&state->scopes, list_size(&state->scopes) - 1); // Check to see if this is already defined. for (a = 0; a < list_size(&state->handlers); a++) { other = list_get_at(&state->handlers, a); if (biseq(other->text.ref, match->text.ref)) { // Collision; move the existing handler into // the scope's "old_handlers" list. list_append(&scope->old_handlers, other); list_extract_at(&state->handlers, a); a--; } } // Append to handlers and add the name to the scope's // new_handles so it can be cleared when the scope is // popped. list_append(&state->handlers, match); list_append(&scope->new_handlers, bstrcpy(match->text.ref)); }
void dbgfmt_update_symbol_list(list_t* symbols, uint16_t address) { unsigned int i; for (i = 0; i < list_size(symbols); i++) dbgfmt_update_symbol((struct dbg_sym*)list_get_at(symbols, i), address); }
int32_t ddbg_file_to_address(bstring file, int index) { unsigned int i; struct dbg_sym* sym; struct dbg_sym_payload_line* payload_line; if (symbols != NULL) { // Search through our debugging symbols. for (i = 0; i < list_size(symbols); i++) { sym = list_get_at(symbols, i); switch (sym->type) { case DBGFMT_SYMBOL_LINE: payload_line = (struct dbg_sym_payload_line*)sym->payload; if (binstr(payload_line->path, 0, file) != BSTR_ERR && payload_line->lineno == index) { // The filename and line number matches, we have found // our symbol entry. printd(LEVEL_DEFAULT, "Line information: %s:%u is at 0x%04X\n", payload_line->path->data, payload_line->lineno, payload_line->address); return payload_line->address; } break; default: break; } } } // If we don't find a memory address, we return -1. return -1; }
/* Called from C_WaitForSlotEvent */ CK_RV slot_find_changed(CK_SLOT_ID_PTR idp, int mask) { unsigned int i; LOG_FUNC_CALLED(context); card_detect_all(); for (i=0; i<list_size(&virtual_slots); i++) { sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i); sc_log(context, "slot 0x%lx token: %lu events: 0x%02X", slot->id, (slot->slot_info.flags & CKF_TOKEN_PRESENT), slot->events); if ((slot->events & SC_EVENT_CARD_INSERTED) && !(slot->slot_info.flags & CKF_TOKEN_PRESENT)) { /* If a token has not been initialized, clear the inserted event */ slot->events &= ~SC_EVENT_CARD_INSERTED; } sc_log(context, "mask: 0x%02X events: 0x%02X result: %d", mask, slot->events, (slot->events & mask)); if (slot->events & mask) { slot->events &= ~mask; *idp = slot->id; LOG_FUNC_RETURN(context, CKR_OK); } } LOG_FUNC_RETURN(context, CKR_NO_EVENT); }
void ddbg_breakpoints_list() { unsigned int i = 0; printd(LEVEL_DEFAULT, "%d breakpoints loaded.\n", list_size(&breakpoints)); for (i = 0; i < list_size(&breakpoints); i++) printd(LEVEL_DEFAULT, "- at 0x%04X\n", ((struct breakpoint*)list_get_at(&breakpoints, i))->addr); }
static void if_handle(state_t* state, match_t* match, bool* reprocess) { list_t* result = ppparam_get(state); struct expr* expr = NULL; uint16_t value; bstring output; bool stopped_at_else; // Ensure the parameter format is correct. if (list_size(result) == 1 && ((parameter_t*)list_get_at(result, 0))->type == EXPRESSION) { // Get the expression. expr = ((parameter_t*)list_get_at(result, 0))->expr; replace_state = state; value = expr_evaluate(expr, &if_define_replace, &dhalt_expression_exit_handler); replace_state = NULL; if (value) { output = skip_to_endif(state, true, &stopped_at_else); if (stopped_at_else) skip_to_endif(state, false, &stopped_at_else); } else { bassigncstr(output, ""); skip_to_endif(state, true, &stopped_at_else); if (stopped_at_else) { output = skip_to_endif(state, false, &stopped_at_else); } } // print the output to the pre processor input ppimpl_printf(state, "%s", output->data); } else dhalt(ERR_PP_ASM_IF_PARAMETERS_INCORRECT, ppimpl_get_location(state)); ppparam_free(result); }
static struct sc_pkcs11_slot * reader_get_slot(sc_reader_t *reader) { unsigned int i; /* Locate a slot related to the reader */ for (i = 0; i<list_size(&virtual_slots); i++) { sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i); if (slot->reader == reader) return slot; } return NULL; }
void ddbg_backtrace() { int i; struct backtrace_entry* entry; printd(LEVEL_DEFAULT, "current backtrace:\n"); for (i = list_size(&backtrace) - 1; i >= 0; i--) { entry = (struct backtrace_entry*)list_get_at(&backtrace, i); printd(LEVEL_DEFAULT, " 0x%04X called 0x%04X\n", entry->caller, entry->callee); } }
/* Internal version of C_CloseAllSessions that gets called with * the global lock held */ CK_RV sc_pkcs11_close_all_sessions(CK_SLOT_ID slotID) { CK_RV rv = CKR_OK; struct sc_pkcs11_session *session; unsigned int i; sc_log(context, "real C_CloseAllSessions(0x%lx) %d", slotID, list_size(&sessions)); for (i = 0; i < list_size(&sessions); i++) { session = list_get_at(&sessions, i); if (session->slot->id == slotID) if ((rv = sc_pkcs11_close_session(session->handle)) != CKR_OK) return rv; } return CKR_OK; }
int krip_shutdown(void) { list_position pos; if (!_enabled) return 0; /* Clean up RIP info list. */ for (pos = list_get_head_position(_rip_info_list); pos; pos = list_get_next_position(pos)) free(list_get_at(pos)); list_close(_rip_info_list); /* Clean up neighbor info list. */ for (pos = list_get_head_position(_neighbor_info_list); pos; pos = list_get_next_position(pos)) free(list_get_at(pos)); list_close(_neighbor_info_list); close(_sock); return 0; }
void dbg_lua_handle_hook(struct dbg_state* state, void* ud, freed_bstring type, uint16_t pos) { struct lua_debugst* ds; unsigned int i; char* cstr; // Convert the name to lowercase. btolower(type.ref); cstr = bstr2cstr(type.ref, '0'); printd(LEVEL_EVERYTHING, "firing hook %s.\n", cstr); // Loop through all of the modules. for (i = 0; i < list_size(&modules); i++) { ds = list_get_at(&modules, i); // Set stack top (I don't know why the top of the // stack is negative!) lua_settop(ds->state, 0); // Search handler table for entries. lua_getglobal(ds->state, HANDLER_TABLE_HOOKS_NAME); lua_getfield(ds->state, -1, cstr); if (!lua_istable(ds->state, -1)) { // No such entry. printd(LEVEL_EVERYTHING, "no matching hook for %s.\n", cstr); lua_pop(ds->state, 2); continue; } // Call the handler function. printd(LEVEL_EVERYTHING, "calling hook %s.\n", cstr); lua_getfield(ds->state, -1, HANDLER_FIELD_FUNCTION_NAME); dbg_lua_push_state(ds, state, ud); lua_pushnumber(ds->state, pos); if (lua_pcall(ds->state, 2, 0, 0) != 0) { printd(LEVEL_ERROR, "error: unable to call debugger hook handler for '%s'.\n", type.ref->data); printd(LEVEL_ERROR, "%s\n", lua_tostring(ds->state, -1)); lua_pop(ds->state, 2); continue; } } // Clean up. bcstrfree(cstr); bautodestroy(type); }
CK_RV C_InitToken(CK_SLOT_ID slotID, CK_CHAR_PTR pPin, CK_ULONG ulPinLen, CK_CHAR_PTR pLabel) { struct sc_pkcs11_session *session; struct sc_pkcs11_slot *slot; CK_RV rv; unsigned int i; sc_log(context, "C_InitToken(pLabel='%s') called", pLabel); rv = sc_pkcs11_lock(); if (rv != CKR_OK) return rv; rv = slot_get_token(slotID, &slot); if (rv != CKR_OK) { sc_log(context, "C_InitToken() get token error 0x%lX", rv); goto out; } if (!slot->p11card || !slot->p11card->framework || !slot->p11card->framework->init_token) { sc_log(context, "C_InitToken() not supported by framework"); rv = CKR_FUNCTION_NOT_SUPPORTED; goto out; } /* Make sure there's no open session for this token */ for (i=0; i<list_size(&sessions); i++) { session = (struct sc_pkcs11_session*)list_get_at(&sessions, i); if (session->slot == slot) { rv = CKR_SESSION_EXISTS; goto out; } } rv = slot->p11card->framework->init_token(slot,slot->fw_data, pPin, ulPinLen, pLabel); if (rv == CKR_OK) { /* Now we should re-bind all tokens so they get the * corresponding function vector and flags */ } out: sc_pkcs11_unlock(); sc_log(context, "C_InitToken(pLabel='%s') returns 0x%lX", pLabel, rv); return rv; }
int sc_release_context(sc_context_t *ctx) { unsigned int i; if (ctx == NULL) { return SC_ERROR_INVALID_ARGUMENTS; } SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); while (list_size(&ctx->readers)) { sc_reader_t *rdr = (sc_reader_t *) list_get_at(&ctx->readers, 0); _sc_delete_reader(ctx, rdr); } if (ctx->reader_driver->ops->finish != NULL) ctx->reader_driver->ops->finish(ctx); for (i = 0; ctx->card_drivers[i]; i++) { struct sc_card_driver *drv = ctx->card_drivers[i]; if (drv->atr_map) _sc_free_atr(ctx, drv); if (drv->dll) sc_dlclose(drv->dll); } if (ctx->preferred_language != NULL) free(ctx->preferred_language); if (ctx->mutex != NULL) { int r = sc_mutex_destroy(ctx, ctx->mutex); if (r != SC_SUCCESS) { sc_log(ctx, "unable to destroy mutex"); return r; } } if (ctx->conf != NULL) scconf_free(ctx->conf); if (ctx->debug_file && (ctx->debug_file != stdout && ctx->debug_file != stderr)) fclose(ctx->debug_file); if (ctx->debug_filename != NULL) free(ctx->debug_filename); if (ctx->app_name != NULL) free(ctx->app_name); list_destroy(&ctx->readers); sc_mem_clear(ctx, sizeof(*ctx)); free(ctx); return SC_SUCCESS; }
int destination_allowed(list_t *allowed_destinations, const char *host, const char *port) { int i; if (!allowed_destinations) return 1; for (i = 0; i < LIST_LEN(allowed_destinations); i++) { destination_t *dst = list_get_at(allowed_destinations, i); if ((!dst->host || !strcmp(dst->host, host)) && (!dst->port || !strcmp(dst->port, port))) return 1; } return 0; }
int main() { list_t l; int i; srandom(time(NULL)); list_init(&l); list_attributes_copy(&l, szelem, 1); for (i = 0; i < NELS; i++) { list_append(&l, &i); } for (i = 0; i < 1000; i++) { list_get_at(&l, random()%NELS); } return 0; }
/* Allocates an existing slot to a card */ CK_RV slot_allocate(struct sc_pkcs11_slot ** slot, struct sc_pkcs11_card * p11card) { unsigned int i; struct sc_pkcs11_slot *tmp_slot = NULL; /* Locate a free slot for this reader */ for (i=0; i< list_size(&virtual_slots); i++) { tmp_slot = (struct sc_pkcs11_slot *)list_get_at(&virtual_slots, i); if (tmp_slot->reader == p11card->reader && tmp_slot->p11card == NULL) break; } if (!tmp_slot || (i == list_size(&virtual_slots))) return CKR_FUNCTION_FAILED; sc_log(context, "Allocated slot 0x%lx for card in reader %s", tmp_slot->id, p11card->reader->name); tmp_slot->p11card = p11card; tmp_slot->events = SC_EVENT_CARD_INSERTED; *slot = tmp_slot; return CKR_OK; }
CK_RV C_InitToken(CK_SLOT_ID slotID, CK_CHAR_PTR pPin, CK_ULONG ulPinLen, CK_CHAR_PTR pLabel) { struct sc_pkcs11_session *session; struct sc_pkcs11_slot *slot; CK_RV rv; unsigned int i; rv = sc_pkcs11_lock(); if (rv != CKR_OK) return rv; rv = slot_get_token(slotID, &slot); if (rv != CKR_OK) goto out; /* Make sure there's no open session for this token */ for (i=0; i<list_size(&sessions); i++) { session = (struct sc_pkcs11_session*)list_get_at(&sessions, i); if (session->slot == slot) { rv = CKR_SESSION_EXISTS; goto out; } } if (slot->card->framework->init_token == NULL) { rv = CKR_FUNCTION_NOT_SUPPORTED; goto out; } rv = slot->card->framework->init_token(slot->card, slot->fw_data, pPin, ulPinLen, pLabel); if (rv == CKR_OK) { /* Now we should re-bind all tokens so they get the * corresponding function vector and flags */ } out: sc_pkcs11_unlock(); return rv; }
/* removes every ack'd packet from unackd_packets * should be called AFTER updating send_unack */ static void packet_t_remove(context_t *ctx) { while (list_size(ctx->unackd_packets) > 0) { packet_t *oldpack = list_get_at(ctx->unackd_packets, 0); /* update RTO given this packet */ update_rto(ctx, oldpack); /* if all the data in the packet was acknowledged, discard and delete from list */ if (ctx->send_unack >= oldpack->seq_num + (oldpack->packet_size - sizeof(STCPHeader))) { free(oldpack->packet); oldpack->packet = NULL; list_delete_at(ctx->unackd_packets, 0); } else /* this packet and all beyond it are unacknowledged */ break; } return; }
/* Handle timeouts */ static void krip_dispatch_timeout() { /* _rip_info_list에서 timeout이 현재 시간보다 작은 값을 가진 entry들을 연결이 끊어진 것으로 간주, 각각의 member들을 적절히 설정한다. */ list_position pos; uint32_t now = krip_get_mtime(); for (pos = list_get_head_position(_rip_info_list); pos; pos = list_get_next_position(pos)) { rip_info *ri = list_get_at(pos); /* metric이 0인 것들은 초기화할 때 추가되어 있던 것이거나 이미 expire된 것들이므로 넘어간다. 이렇게 해주는 이유는 svr, cli처럼 RIP가 동작하지 않는 host와의 연결에 대해선 metric 값을 일정하게 유지시켜 잘못된 routing 정보가 전파되지 않게 하기 위한 것이다. */ if (ri->timeout < now && ri->timeout != 0) { L_ROUTE("krip_dispatch_timeout(): entry for interface {%08x} has been timeout, making its metric inifinity", ri->from); ri->metric = RIP_METRIC_INFINITY; ri->change_flag = 1; ri->timeout = 0; _trigger = true; } } }
list_t* ddbg_get_symbols(uint16_t addr) { unsigned int i; struct dbg_sym* sym; struct dbg_sym_payload_line* payload_line; struct dbg_sym_payload_string* payload_string; struct dbg_sym_payload_label* payload_label; list_t* result = malloc(sizeof(list_t)); list_init(result); if (symbols != NULL) { for (i = 0; i < list_size(symbols); i++) { sym = list_get_at(symbols, i); switch (sym->type) { case DBGFMT_SYMBOL_LINE: payload_line = (struct dbg_sym_payload_line*)sym->payload; if (payload_line->address == addr) list_append(result, bformat("lineinfo:%s:%u", payload_line->path->data, payload_line->lineno)); break; case DBGFMT_SYMBOL_STRING: payload_string = (struct dbg_sym_payload_string*)sym->payload; if (payload_string->address == addr) list_append(result, bfromcstr(payload_string->data->data)); break; case DBGFMT_SYMBOL_LABEL: payload_label = (struct dbg_sym_payload_label*)sym->payload; if (payload_label->address == addr) list_append(result, bformat("label:%s", payload_label->label->data)); break; default: break; } } } return result; }
void dbg_lua_handle_hook_symbol(struct dbg_state* state, void* ud, freed_bstring symbol) { struct lua_debugst* ds; unsigned int i; // Loop through all of the modules. for (i = 0; i < list_size(&modules); i++) { ds = list_get_at(&modules, i); // Set stack top (I don't know why the top of the // stack is negative!) lua_settop(ds->state, 0); // Search handler table for entries. lua_getglobal(ds->state, HANDLER_TABLE_SYMBOLS_NAME); lua_getfield(ds->state, -1, HANDLER_ENTRY_SYMBOL_HOOK); if (!lua_istable(ds->state, -1)) { // No such entry. lua_pop(ds->state, 2); continue; } // Call the handler function. lua_getfield(ds->state, -1, HANDLER_FIELD_FUNCTION_NAME); dbg_lua_push_state(ds, state, ud); lua_pushstring(ds->state, symbol.ref->data); if (lua_pcall(ds->state, 2, 0, 0) != 0) { printd(LEVEL_ERROR, "error: unable to call debugger symbol hook handler.\n"); printd(LEVEL_ERROR, "%s\n", lua_tostring(ds->state, -1)); lua_pop(ds->state, 2); continue; } } // Clean up. bautodestroy(symbol); }
static uint16_t if_define_replace(bstring define) { // Search through all of the defines to find one where // the name matches. size_t i = 0; match_t* match; struct expr* tree; for (i = 0; i < list_size(&replace_state->handlers); i++) { match = list_get_at(&replace_state->handlers, i); if (biseq(match->text.ref, define)) { // Found a match. tree = expr_parse(match->userdata); if (tree == NULL) dhalt(ERR_PP_DEFINE_NOT_EXPRESSION, ppimpl_get_location(replace_state)); return expr_evaluate(tree, &if_define_replace, &dhalt_expression_exit_handler); } } dhalt(ERR_PP_DEFINE_NOT_FOUND, ppimpl_get_location(replace_state)); return 0; }
CK_RV card_removed(sc_reader_t * reader) { unsigned int i; struct sc_pkcs11_card *card = NULL; /* Mark all slots as "token not present" */ sc_debug(context, SC_LOG_DEBUG_NORMAL, "%s: card removed", reader->name); for (i=0; i < list_size(&virtual_slots); i++) { sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i); if (slot->reader == reader) { /* Save the "card" object */ if (slot->card) card = slot->card; slot_token_removed(slot->id); } } if (card) { card->framework->unbind(card); sc_disconnect_card(card->card); /* FIXME: free mechanisms * spaces allocated by the * sc_pkcs11_register_sign_and_hash_mechanism * and sc_pkcs11_new_fw_mechanism. * but see sc_pkcs11_register_generic_mechanisms for (i=0; i < card->nmechanisms; ++i) { // if 'mech_data' is a pointer earlier returned by the ?alloc free(card->mechanisms[i]->mech_data); // if 'mechanisms[i]' is a pointer earlier returned by the ?alloc free(card->mechanisms[i]); } */ free(card->mechanisms); free(card); } return CKR_OK; }