/* Cesar project {{{ * * Copyright (C) 2007 Spidcom * * <<>> * * }}} */ /** * \file probe.c * \brief The 'probe' context management functions * \ingroup host * * This file provides 'probe' function context management functions * * \todo */ #include "common/std.h" #include #include #include #include "host/fcall/fcall.h" #ifndef UNIT_TEST #include "lib/swap.h" #include "host/syscall.h" #else /* UNIT_TEST */ #include #endif /* UNIT_TEST */ /** * initialize a static probe context, called during station context creation. * \param probe probe context to initialize * \param fcall fcall which process the probe function * \return 0 if ok, -1 if failed with errno= * - EINVAL if probe or fcall is NULL */ int probe_init(probe_ctx_t *probe, fcall_ctx_t *fcall) { DBG_ASSERT(probe); DBG_ASSERT(fcall); if((probe == NULL) || (fcall == NULL)) { errno = EINVAL; return -1; } memset(probe, '\0', sizeof(probe_ctx_t)); probe->fcall = fcall; fcall_register(fcall, PROBE_ID, probe_recv, probe); return 0; } /** * probe var registering * \param probe pointer to current probe context * \param id variable string id * \param addr pointer to variable * \return 0 if ok, -1 if fail with errno= * - EINVAL if probe or id is NULL * - ENAMETOOLONG if id length is >= PROBE_ID_MAX_SIZE * - ENOSPC if max number of registred variable is reached * - EEXIST if variable is already registered */ int probe_register(probe_ctx_t *probe, char *id, int length, void *addr) { int index; DBG_ASSERT(probe); DBG_ASSERT(id); DBG_ASSERT(length > 0); DBG_ASSERT(length < FUNCTION_CALL_PARAM_MAX_SIZE); DBG_ASSERT(addr); if((probe == NULL) || (id == NULL) || (length <= 0) || (length >= FUNCTION_CALL_PARAM_MAX_SIZE) || (addr == NULL)) { errno = EINVAL; return -1; } /* check id length */ DBG_ASSERT(strlen(id) < PROBE_ID_MAX_SIZE); if(strlen(id) >= PROBE_ID_MAX_SIZE) { errno = ENAMETOOLONG; station_log(probe->fcall->sci->station, STATION_LOG_ERROR, STATION_LOGTYPE_PROBE, "%s: errno = %d because id length is invalid", __FUNCTION__, errno); return -1; } /* check if there is free place */ DBG_ASSERT(probe->var_nb < PROBE_VAR_MAX_NB); if(probe->var_nb >= PROBE_VAR_MAX_NB) { errno = ENOSPC; station_log(probe->fcall->sci->station, STATION_LOG_ERROR, STATION_LOGTYPE_PROBE, "%s: errno = %d because there is no free place", __FUNCTION__, errno); return -1; } /* check if variable is already registered */ for(index = 0; index < probe->var_nb; index++) { DBG_ASSERT(strcmp(probe->var_table[index].id, id)); if(!strcmp(probe->var_table[index].id, id)) { errno = EEXIST; station_log(probe->fcall->sci->station, STATION_LOG_ERROR, STATION_LOGTYPE_PROBE, "%s: errno = %d because variable is already registered", __FUNCTION__, errno); return -1; } } /* register the function */ strcpy(probe->var_table[probe->var_nb].id, id); probe->var_table[probe->var_nb].length = length; probe->var_table[probe->var_nb].addr = addr; /* increment the number of function */ probe->var_nb++; return 0; } /** * probe message processing function; called by fcall_recv() * must be registred to fcall layer as "probe" function id * \param fcall pointer to the current fcall context * \param param pointer to param * \param msg pointer to received message with fcall pre-processing * \return number of param if ok, -1 if failed with errno= * - EINVAL if param or msg is NULL */ int probe_recv(fcall_ctx_t *fcall, fcall_param_t **param, sci_msg_t **msg, void *data) { int index_param, index_var; probe_ctx_t *probe; static fcall_param_t param_result; probe = (probe_ctx_t *)data; DBG_ASSERT(fcall); DBG_ASSERT(param); DBG_ASSERT(*param); DBG_ASSERT(msg); DBG_ASSERT(*msg); DBG_ASSERT(probe); if((fcall == NULL) || (param == NULL) || (*param == NULL) || (msg == NULL) || (*msg == NULL) || (probe == NULL)) { errno = EINVAL; return -1; } /* init result structures */ fcall_param_init(¶m_result, (*param)->id, (*param)->msg_id); if((*param)->param_nb == 0) { /* we want all the var list */ for(index_var = 0; index_var < probe->var_nb; index_var++) { if(strlen(probe->var_table[index_var].id) > 0) { fcall_param_add( ¶m_result, *msg, probe->var_table[index_var].id, probe->var_table[index_var].length, probe->var_table[index_var].addr ); } } } else { /* normal get or set request */ /* get all param for processing */ for(index_param = 0; index_param < (*param)->param_nb; index_param++) { /* find the asked id */ for(index_var = 0; index_var < probe->var_nb; index_var++) { if(!strcmp((*param)->param_table[index_param].id, probe->var_table[index_var].id)) { /* found !*/ if((*param)->param_table[index_param].length == 0) { /* this is a get request */ station_log(fcall->sci->station, STATION_LOG_INFO, STATION_LOGTYPE_PROBE, "%s get '%s' (%d bytes @ %p)", __FUNCTION__, probe->var_table[index_var].id, probe->var_table[index_var].length, probe->var_table[index_var].addr ); fcall_param_add( ¶m_result, *msg, probe->var_table[index_var].id, probe->var_table[index_var].length, probe->var_table[index_var].addr ); station_log(fcall->sci->station, STATION_LOG_DEBUG, STATION_LOGTYPE_PROBE, "content: %02x-%02x-%02x-%02x", *((unsigned char *)probe->var_table[index_var].addr), *((unsigned char *)probe->var_table[index_var].addr + 1), *((unsigned char *)probe->var_table[index_var].addr + 2), *((unsigned char *)probe->var_table[index_var].addr + 3) ); } else if((*param)->param_table[index_param].length <= probe->var_table[index_var].length) { /* this is a set request with a correct length */ memcpy( probe->var_table[index_var].addr, (*param)->param_table[index_param].data, (*param)->param_table[index_param].length ); station_log(fcall->sci->station, STATION_LOG_INFO, STATION_LOGTYPE_PROBE, "%s set '%s' (%d bytes @ %p)", __FUNCTION__, probe->var_table[index_var].id, (*param)->param_table[index_param].length, probe->var_table[index_var].addr ); fcall_param_add( ¶m_result, *msg, probe->var_table[index_var].id, 0, NULL ); } /* do nothing else */ break; } } if(index_var >= probe->var_nb) { /* variable not registered */ (*msg)->hdr.fcall->param_nb = 0; (*msg)->hdr.fcall->flags |= FUNCTION_CALL_FLAG_FAILED; station_log(fcall->sci->station, STATION_LOG_NOTICE, STATION_LOGTYPE_PROBE, "%s var '%s' not registered", __FUNCTION__, (*param)->param_table[index_param].id ); } } } /* switch param and msg for result */ *param = ¶m_result; return param_result.param_nb; }