/** * Runs connection loop over communication layer. * This function must run after 'communication_network_start()'operation. * * @param ctx current context */ void communication_connection_loop(Context *ctx) { ContextId id = ctx->id; if (get_connection_loop_active(ctx)) return; // connection loop already running if (!communication_is_network_started()) { ERROR(" The network layer is not initialized, call communication_network_start() first."); return; } set_connection_loop_active(ctx, 1); // activate loop flag DEBUG(" communication:Waiting for data\n"); // context may become invalid right after wait_for_data_input, // so we need so check it every loop, based on ID. while ((ctx = context_get_and_lock(id))) { if (!get_connection_loop_active(ctx)) { context_unlock(ctx); break; } communication_wait_for_data_input(ctx); communication_read_input_stream(id); context_unlock(ctx); } }
static void event_get_context(void * arg) { GetContextArgs * s = (GetContextArgs *)arg; Channel * c = s->c; Context * ctx = s->ctx; if (!is_stream_closed(c)) { int err = 0; write_stringz(&c->out, "R"); write_stringz(&c->out, s->token); if (ctx->exited) err = ERR_ALREADY_EXITED; write_errno(&c->out, err); if (err == 0) { write_context(&c->out, ctx, s->parent != 0); write_stream(&c->out, 0); } else { write_stringz(&c->out, "null"); } write_stream(&c->out, MARKER_EOM); flush_stream(&c->out); } stream_unlock(c); context_unlock(ctx); loc_free(s); }
/* add a function to a context */ int context_add_function(context_t *cont, function_t *func) { function_t *check_func = NULL; context_lock(cont); if (func->name != NULL) { /* this is a function with a name */ check_func = LIST_TO_STRUCT(function_t, list, cont->funcs.next); /* check that we don't have this function's name already */ while (check_func != NULL) { if (!string_compare(check_func->name, func->name)) { context_unlock(cont); ERROR(-ERROR_FEXIST); } check_func = LIST_TO_STRUCT(function_t, list, check_func->list.next); } /* add the function to the funcs list */ func->list.next = cont->funcs.next; func->list.prev = &cont->funcs; if (cont->funcs.next != NULL) { cont->funcs.next->prev = &func->list; } cont->funcs.next = &func->list; } else { /* this is a anonymous function */ /* add the function to the anonym list */ func->list.next = cont->anonym.next; func->list.prev = &cont->anonym; if (cont->anonym.next != NULL) { cont->anonym.next->prev = &func->list; } cont->anonym.next = &func->list; } func->cont = cont; context_unlock(cont); return 0; }
/** * Reads APDU from transport layer stream * * @param id connection context */ void communication_read_input_stream(ContextId id) { Context *ctx = context_get_and_lock(id); if (ctx != NULL) { communication_process_input_data(ctx, communication_get_apdu_stream(ctx)); context_unlock(ctx); } }
/* copy the last exception to inside or outside memory */ int context_get_last_exception(context_t *cont, exception_t *excep) { int ret; context_lock(cont); if (!cont->last_exception.had_exception) { context_unlock(cont); ERROR(-ERROR_PARAM); } ret = safe_memory_copy(excep, &cont->last_exception, sizeof(exception_t), ADDR_UNDEF, ADDR_INSIDE, 0, 0); cont->last_exception.had_exception = 0; context_unlock(cont); return ret; }
/* find an anonymous function by address */ void *context_find_anonymous(context_t *cont, byte *ptr) { function_t *func; context_lock(cont); func = LIST_TO_STRUCT(function_t, list, cont->anonym.next); while (func != NULL) { if (func->func_code == ptr) { function_get(func); context_unlock(cont); return func; } func = LIST_TO_STRUCT(function_t, list, func->list.next); } context_unlock(cont); return NULL; }
/* find a function by name */ void *context_find_function(context_t *cont, byte *name) { function_t *func; context_lock(cont); func = LIST_TO_STRUCT(function_t, list, cont->funcs.next); while (func != NULL) { if (!string_compare(func->name, (char *)name)) { function_get(func); context_unlock(cont); return func; } func = LIST_TO_STRUCT(function_t, list, func->list.next); } context_unlock(cont); return NULL; }
/* remove and delete a function from the context */ void context_free_function(function_t *func) { context_t *cont = func->cont; context_lock(cont); if (NULL == func->list.prev && NULL == func->list.next) { /* This is a race condition! The function was already removed from the context... */ context_unlock(cont); return; } func->list.prev->next = func->list.next; if (func->list.next != NULL) { func->list.next->prev = func->list.prev; } func->list.prev = NULL; func->list.next = NULL; function_put(func); context_unlock(cont); }
/* create a reply */ void context_create_reply(context_t *cont, word val, exception_t *excep) { context_lock(cont); if (NULL != excep) { memory_copy(&cont->last_exception, excep, sizeof(exception_t)); } memory_set(&cont->cmd, 0, sizeof(kplugs_command_t)); cont->cmd.val1 = val; cont->cmd.type = KPLUGS_REPLY; cont->has_answer = 1; context_unlock(cont); }
/** * Destroys a connection context, * see topic 8.1 of IEEE 11071-20601 documentation * * @param id context id * @param addr transport address (informative) */ void communication_transport_disconnect_indication(ContextId id, const char *addr) { Context *ctx = context_get_and_lock(id); if (!ctx) return; communication_fire_transport_disconnect_evt(ctx); if (disconnection_listener) disconnection_listener(ctx, addr); context_unlock(ctx); context_remove(id); }
static void event_terminate(void * x) { TerminateArgs * args = (TerminateArgs *)x; Context * ctx = args->ctx; TCFBroadcastGroup * bcg = args->bcg; LINK * qp = ctx->children.next; while (qp != &ctx->children) { Context * c = cldl2ctxp(qp); if (c->intercepted) send_event_context_resumed(&bcg->out, c); c->pending_intercept = 0; c->pending_signals |= 1 << SIGKILL; qp = qp->next; } if (ctx->intercepted) send_event_context_resumed(&bcg->out, ctx); ctx->pending_intercept = 0; ctx->pending_signals |= 1 << SIGKILL; context_unlock(ctx); loc_free(args); }
/* copy the reply back to the user */ int context_get_reply(context_t *cont, char *buf, word length) { word copy; context_lock(cont); /* return an answer if there is one */ if (cont->has_answer) { copy = (length > sizeof(kplugs_command_t)) ? sizeof(kplugs_command_t) : length; memory_copy(buf, &cont->cmd, copy); cont->has_answer = 0; } else { copy = 0; } context_unlock(cont); return (int)copy; }
/** * Called by any transcoding plug-in when a device connects * * @param plugin the transcoding plugin * @param lladdr low-level address of device (opaque at this level) * @param spec MDS attributes, at the very least must contain specialization * @param assoc_info association information in 11073 format * @param config device configuration in 11073 format * @return 0 if error, >0 if ok */ int trans_connected(TransPlugin *plugin, char *lladdr, AttributeList spec, PhdAssociationInformation assoc_info, ConfigReport config) { // create context, if any ContextId context = trans_context_get(lladdr, plugin); if (!context.plugin) { DEBUG("Transcoding: context not found for %s", lladdr); return 0; } communication_transport_connect_indication(context, lladdr); Context *ctx = context_get_and_lock(context); if (!ctx) { DEBUG("Transcoding: context struct not found"); return 0; } association_accept_data_protocol_20601_in(ctx, assoc_info, 1); del_phdassociationinformation(&assoc_info); // following call deletes config_report (if necessary) configuring_perform_configuration_in(ctx, config, NULL, 1); int i; for (i = 0; i < spec.count; i++) { AVA_Type *attribute = &spec.value[i]; mds_set_attribute(ctx->mds, attribute); } context_unlock(ctx); del_attributelist(&spec); return 1; }
/** * Called by any transcoding plug-in when measurement data is received * * @param plugin the transcoding plugin * @param lladdr low-level address of device (opaque at this level) * @param report Measurement data in 11073 format * @return 0 if error, >0 if ok */ int trans_event_report_var(TransPlugin *plugin, char *lladdr, ScanReportInfoVar report) { // passing plugin = NULL indirectly blocks creation ContextId context = trans_context_get(lladdr, NULL); if (!context.plugin) { DEBUG("Transcoded %s no context for evt report (var)", lladdr); return 0; } Context *ctx = context_get_and_lock(context); if (!ctx) { DEBUG("Transcoding: context struct not found"); return 0; } mds_event_report_dynamic_data_update_var(ctx, &report); context_unlock(ctx); del_scanreportinfovar(&report); return 1; }
static void safe_memory_get(void * parm) { MemoryCommandArgs * args = (MemoryCommandArgs *)parm; Channel * c = args->c; Context * ctx = args->ctx; if (!is_channel_closed(c)) { Trap trap; if (set_trap(&trap)) { OutputStream * out = &args->c->out; char * token = args->token; ContextAddress addr0 = args->addr; ContextAddress addr = args->addr; unsigned long size = args->size; unsigned long pos = 0; char buf[BUF_SIZE]; int err = 0; MemoryErrorInfo err_info; JsonWriteBinaryState state; memset(&err_info, 0, sizeof(err_info)); if (ctx->exiting || ctx->exited) err = ERR_ALREADY_EXITED; write_stringz(out, "R"); write_stringz(out, token); json_write_binary_start(&state, out, size); while (pos < size) { int rd = size - pos; if (rd > BUF_SIZE) rd = BUF_SIZE; /* TODO: word size, mode */ memset(buf, 0, rd); if (err == 0) { if (context_read_mem(ctx, addr, buf, rd) < 0) { err = errno; #if ENABLE_ExtendedMemoryErrorReports context_get_mem_error_info(&err_info); #endif } else { addr += rd; } } json_write_binary_data(&state, buf, rd); pos += rd; } json_write_binary_end(&state); write_stream(out, 0); write_errno(out, err); if (err == 0) { write_stringz(out, "null"); } else { write_ranges(out, addr0, (int)(addr - addr0), BYTE_CANNOT_READ, &err_info); } write_stream(out, MARKER_EOM); clear_trap(&trap); } else { trace(LOG_ALWAYS, "Exception in Memory.get: %s", errno_to_str(trap.error)); channel_close(c); } } channel_unlock(c); context_unlock(ctx); loc_free(args); }
static void event_pid_exited(pid_t pid, int status, int signal) { Context * ctx; ctx = context_find_from_pid(pid, 1); if (ctx == NULL) { ctx = find_pending(pid); if (ctx == NULL) { trace(LOG_EVENTS, "event: ctx not found, pid %d, exit status %d, term signal %d", pid, status, signal); } else { assert(ctx->ref_count == 0); ctx->ref_count = 1; if (EXT(ctx)->attach_callback != NULL) { if (status == 0) status = EINVAL; EXT(ctx)->attach_callback(status, ctx, EXT(ctx)->attach_data); } assert(list_is_empty(&ctx->children)); assert(ctx->parent == NULL); ctx->exited = 1; context_unlock(ctx); } } else { /* Note: ctx->exiting should be 1 here. However, PTRACE_EVENT_EXIT can be lost by PTRACE because of racing * between PTRACE_CONT (or PTRACE_SYSCALL) and SIGTRAP/PTRACE_EVENT_EXIT. So, ctx->exiting can be 0. */ if (EXT(ctx->parent)->pid == pid) ctx = ctx->parent; assert(EXT(ctx)->attach_callback == NULL); if (ctx->exited) { trace(LOG_EVENTS, "event: ctx %#lx, pid %d, exit status %d unexpected, stopped %d, exited %d", ctx, pid, status, ctx->stopped, ctx->exited); } else { trace(LOG_EVENTS, "event: ctx %#lx, pid %d, exit status %d, term signal %d", ctx, pid, status, signal); ctx->exiting = 1; if (ctx->stopped) send_context_started_event(ctx); if (!list_is_empty(&ctx->children)) { LINK * l = ctx->children.next; while (l != &ctx->children) { Context * c = cldl2ctxp(l); l = l->next; assert(c->parent == ctx); if (!c->exited) { c->exiting = 1; if (c->stopped) send_context_started_event(c); release_error_report(EXT(c)->regs_error); loc_free(EXT(c)->regs); EXT(c)->regs_error = NULL; EXT(c)->regs = NULL; send_context_exited_event(c); } } } release_error_report(EXT(ctx)->regs_error); loc_free(EXT(ctx)->regs); EXT(ctx)->regs_error = NULL; EXT(ctx)->regs = NULL; send_context_exited_event(ctx); } } }
static void safe_memory_fill(void * parm) { MemoryCommandArgs * args = (MemoryCommandArgs *)parm; Channel * c = args->c; Context * ctx = args->ctx; if (!is_channel_closed(c)) { Trap trap; if (set_trap(&trap)) { InputStream * inp = &c->inp; OutputStream * out = &c->out; char * token = args->token; ContextAddress addr0 = args->addr; ContextAddress addr = args->addr; unsigned long size = args->size; MemoryErrorInfo err_info; MemoryFillBuffer buf; char * tmp = NULL; int err = 0; memset(&err_info, 0, sizeof(err_info)); if (ctx->exiting || ctx->exited) err = ERR_ALREADY_EXITED; memset(&buf, 0, sizeof(buf)); buf.buf = (char *)tmp_alloc(buf.max = BUF_SIZE); if (err) json_skip_object(inp); else json_read_array(inp, read_memory_fill_array_cb, &buf); json_test_char(inp, MARKER_EOA); json_test_char(inp, MARKER_EOM); while (err == 0 && buf.pos < size && buf.pos <= buf.max / 2) { if (buf.pos == 0) { buf.buf[buf.pos++] = 0; } else { memcpy(buf.buf + buf.pos, buf.buf, buf.pos); buf.pos *= 2; } } while (err == 0 && addr < addr0 + size) { /* Note: context_write_mem() modifies buffer contents */ unsigned wr = (unsigned)(addr0 + size - addr); if (tmp == NULL) tmp = (char *)tmp_alloc(buf.pos); if (wr > buf.pos) wr = buf.pos; /* TODO: word size, mode */ memcpy(tmp, buf.buf, wr); if (context_write_mem(ctx, addr, tmp, wr) < 0) { err = errno; #if ENABLE_ExtendedMemoryErrorReports context_get_mem_error_info(&err_info); #endif } else { addr += wr; } } send_event_memory_changed(ctx, addr0, size); write_stringz(out, "R"); write_stringz(out, token); write_errno(out, err); if (err == 0) { write_stringz(out, "null"); } else { write_ranges(out, addr0, (int)(addr - addr0), BYTE_CANNOT_WRITE, &err_info); } write_stream(out, MARKER_EOM); clear_trap(&trap); } else { trace(LOG_ALWAYS, "Exception in Memory.fill: %s", errno_to_str(trap.error)); channel_close(c); } } channel_unlock(c); context_unlock(ctx); loc_free(args); }
static void safe_memory_set(void * parm) { MemoryCommandArgs * args = (MemoryCommandArgs *)parm; Channel * c = args->c; Context * ctx = args->ctx; if (!is_channel_closed(c)) { Trap trap; if (set_trap(&trap)) { InputStream * inp = &c->inp; OutputStream * out = &c->out; char * token = args->token; ContextAddress addr0 = args->addr; ContextAddress addr = args->addr; unsigned long size = 0; char buf[BUF_SIZE]; int err = 0; MemoryErrorInfo err_info; JsonReadBinaryState state; memset(&err_info, 0, sizeof(err_info)); if (ctx->exiting || ctx->exited) err = ERR_ALREADY_EXITED; json_read_binary_start(&state, inp); for (;;) { int rd = json_read_binary_data(&state, buf, sizeof(buf)); if (rd == 0) break; if (err == 0) { /* TODO: word size, mode */ if (context_write_mem(ctx, addr, buf, rd) < 0) { err = errno; #if ENABLE_ExtendedMemoryErrorReports context_get_mem_error_info(&err_info); #endif } else { addr += rd; } } size += rd; } json_read_binary_end(&state); json_test_char(inp, MARKER_EOA); json_test_char(inp, MARKER_EOM); send_event_memory_changed(ctx, addr0, size); write_stringz(out, "R"); write_stringz(out, token); write_errno(out, err); if (err == 0) { write_stringz(out, "null"); } else { write_ranges(out, addr0, (int)(addr - addr0), BYTE_CANNOT_WRITE, &err_info); } write_stream(out, MARKER_EOM); clear_trap(&trap); } else { trace(LOG_ALWAYS, "Exception in Memory.set: %s", errno_to_str(trap.error)); channel_close(c); } } channel_unlock(c); context_unlock(ctx); loc_free(args); }