/* Cesar project {{{ * * Copyright (C) 2007 Spidcom * * <<>> * * }}} */ /** * \file cp/interf/interf.c * \brief Interfaces pour l'envoie/réception de messages MME * \ingroup cp_interf */ #include "common/std.h" #include "cp/interf/interf.h" #include "cp/interf/inc/interf_private.h" /* * locale Variables */ static interf_buffer_t pool[INTERF_NB_BUFFER]; static interf_frag_msg_t frag_msg[INTERF_MAX_FRAG_MSG_SIM]; const interf_desc_t interf_desc[]= { // nb_buf, pf_add_buf, pf_send_buf, pf_rel_buf, pf_cb_rc { 8, interf_local_buf_release, interf_receive, NULL, NULL }, // CP { 88, NULL, NULL, NULL, NULL }, // SAR { 2, NULL, NULL, NULL, NULL }, // CE { 3, NULL, NULL, NULL, NULL } // HLE }; // FIFOs (STA and CCO) static interf_msg_file_t fifo[2]; static cyg_mutex_t cco_fifo_lock; // local buf ressources (for STA and CCO) static uint nb_local_buf_available; static cyg_mutex_t local_ressource_lock; static cyg_cond_t local_ressource_wait; // mbox for incomming msg static cyg_handle_t incoming_mbox_handle; static cyg_mbox incoming_mbox; // mbox for buf to release static cyg_handle_t buf_rel_mbox_handle; static cyg_mbox buf_rel_mbox; // delay in ticks for the frag MMI timeout static cyg_tick_count_t frag_MMI_time_out_delay; /***************************************************************/ /***************************************************************/ /***************************************************************/ /* "Private" functions */ /***************************************************************/ /***************************************************************/ /***************************************************************/ msg_mme_t * interf_received_frag (msg_mme_t *msg) { int i, j, checksum; msg_mme_t *first_frag; interf_buffer_t *buffer = NULL; dbg_assert ( !msg_check_wrong_mme_const_values (msg)); // check if some old messages must be removed // this can be done anywhere, but i think here is a good place. interf_msg_purge (); // now, process the received fragment // check if previous fragment has been received for (i=0; i < INTERF_MAX_FRAG_MSG_SIM ; i++) { if ( (frag_msg[i].fmsn == msg->fmi.fmsn) && (memcmp (frag_msg[i].osa,msg->osa, sizeof(msg->osa))==0) ) { // we find previous fragment, so stop searching break; } } if(i == INTERF_MAX_FRAG_MSG_SIM) { // we did not find previous fragment // so look for first empty slot for(i=0 ; i < INTERF_MAX_FRAG_MSG_SIM ; i++) { if( ! frag_msg[i].frag_counter) { // we found an empty slot frag_msg[i].fmsn = msg->fmi.fmsn; memcpy(frag_msg[i].osa, msg->osa, sizeof(msg->osa)); break; } } } if(i == INTERF_MAX_FRAG_MSG_SIM) { // obviously, there is no more space... dbg_assert_print(0, "interf.c : frag_msg array is full, loose fragment"); // and so, we loose the message interf_release_buf(msg); return NULL; } frag_msg[i].date_cyg_tick = cyg_current_time(); // message are ordered in our structure frag_msg[i].msg[msg->fmi.fn_mi] = msg; frag_msg[i].frag_counter ++; // check if message is complete and return if( frag_msg[i].frag_counter == (msg->fmi.nf_mi + 1) ) { // check if all fragment are coherent checksum = 0; for(j=0 ; jfmi.fn_mi; if(checksum != (frag_msg[i].frag_counter * msg->fmi.nf_mi / 2)) { // the message fragment are not coherent (and they will be purged later) dbg_assert_print(0, "interf.c : MME fragments incoherents\n"); return NULL; } // update the buffer structure first_frag = frag_msg[i].msg[0]; for(j=0; jnext_msg = frag_msg[i].msg[j+1]; } // the last fragment has no NextPart dbg_assert(buffer); buffer->next_msg = NULL; // reset the current slot bzero(&frag_msg[i], sizeof(interf_frag_msg_t)); // and return ptr to first part of MME return first_frag; } return NULL; } void interf_msg_add (msg_mme_dest_t dest, msg_mme_t *msg) { dbg_assert ( !msg_check_wrong_mme_const_values (msg)); dbg_assert (dest <= MSG_CCO); // if requested, take the CCO mutex if (dest == MSG_CCO) cyg_mutex_lock ( &cco_fifo_lock); if (fifo[dest].start >= INTERF_NB_BUFFER) { // this should never occur, but who knowes... dbg_assert_print (0, "interf.c : fifo %i is full\n", MSG_CCO); // and we loose the message interf_release_buf (msg); } else { fifo[dest].msg[fifo[dest].start] = msg; fifo[dest].start ++; } // if necessary, release the CCO mutex if (dest == MSG_CCO) cyg_mutex_unlock ( &cco_fifo_lock); } bool interf_msg_remove (msg_mme_dest_t dest, msg_mme_t *msg) { uint i; bool return_value = false; dbg_assert ( !msg_check_wrong_mme_const_values (msg)); dbg_assert (dest <= MSG_CCO); // if requested, take the CCO mutex if (dest == MSG_CCO) cyg_mutex_lock ( &cco_fifo_lock); // search the message index in the fifo for (i=fifo[dest].start; i>0; i--) if (fifo[dest].msg[i-1] == msg) break; // if we found the message if (i) { // first we release the buffer(s) of the removed message interf_release_buf (msg); // then we remove the message from the fifo memcpy ( &fifo[dest].msg[i-1], &fifo[dest].msg[i], sizeof(fifo[dest].msg[0]) * (fifo[dest].start - i) ); fifo[dest].start --; dbg_assert(fifo[dest].start < INTERF_NB_BUFFER); if(fifo[dest].current >= i) fifo[dest].current --; return_value = true; } // if necessary, release the CCO mutex if(dest == MSG_CCO) cyg_mutex_unlock( & cco_fifo_lock); return return_value; } void interf_local_buf_release (msg_mme_t *msg) { dbg_assert ( !msg_check_wrong_mme_const_values (msg)); cyg_mutex_lock ( &local_ressource_lock); nb_local_buf_available ++; // wake up any waiting allocators cyg_cond_signal ( &local_ressource_wait); cyg_mutex_unlock ( &local_ressource_lock); } void interf_buf_to_release (void) { interf_buffer_t *buf; msg_mme_t *msg, *next_msg; #if DEBUG int i; #endif // as we have buffer to release in the mailbox while ( (msg = cyg_mbox_tryget (buf_rel_mbox_handle)) != NULL ) { #if DEBUG dbg_assert( ! msg_check_wrong_mme_const_values(msg)); // check that the message to release is not the last part // of a fragmented message (which would cause a severe // memory leak) for(i=0; isize = 0; next_msg = buf->next_msg; buf->next_msg = NULL; interf_desc[buf->id].pf_add_buf (msg); } while (next_msg); } } /***************************************************************/ /***************************************************************/ /***************************************************************/ /* "Public" functions */ /***************************************************************/ /***************************************************************/ /***************************************************************/ E_ErrCode interf_init (void) { unsigned int i, j, k; #if DEBUG unsigned int nb_buf=0; // check parameters for(i=0; ifmi.nf_mi == 0) message_complete = true; else { msg = interf_received_frag (msg); if (msg != NULL) message_complete = true; else message_complete = false; } // if MME is not complete, then look for next message if ( !message_complete) continue; // check if it is a .CNF or .RSP type message msg_RSP_or_CNF = msg->mm_type & 0x1; // check if message is for CCO or STA and add it in corresponding fifo msg_nb = msg_get_number (msg); interf_msg_add (msg_list[msg_nb].msg_dest, msg); // TODO : set corresponding flags } } void interf_send (msg_mme_t *msg, uint msg_size, interf_id_t interf_id) { dbg_assert ( !msg_check_wrong_mme_const_values (msg)); dbg_assert (msg_size <= SAR_MSDU_PAYLOAD_MAX_SIZE); dbg_assert (interf_id < COUNT (interf_desc)); // check if padding is requested (and if yes, do so) if (msg_size < SAR_MSDU_PAYLOAD_MIN_SIZE) msg_size = SAR_MSDU_PAYLOAD_MIN_SIZE; // and then, send the message dbg_assert_print (interf_desc[interf_id].pf_send_buf, "interface not implemented\n"); interf_desc[interf_id].pf_send_buf (msg); } msg_mme_t * interf_msg_get_last (msg_mme_dest_t dest) { msg_mme_t *return_value = NULL; dbg_assert (dest < COUNT (fifo)); fifo[dest].current = fifo[dest].start; if (fifo[dest].current != 0) return_value = fifo[dest].msg[fifo[dest].current - 1]; return return_value; } msg_mme_t * interf_msg_get_last_of_type (msg_mme_dest_t dest, mm_type_t mm_type) { msg_mme_t *return_value = NULL; dbg_assert (dest < COUNT (fifo)); fifo[dest].current = fifo[dest].start; while (fifo[dest].current != 0) { if (fifo[dest].msg[fifo[dest].current - 1]->mm_type == mm_type) { return_value = fifo[dest].msg[fifo[dest].current - 1]; break; } fifo[dest].current --; } return return_value; } msg_mme_t * interf_msg_get_previous (msg_mme_dest_t dest) { msg_mme_t *return_value = NULL; dbg_assert (dest < COUNT (fifo)); if (fifo[dest].current > 1) { fifo[dest].current --; return_value = fifo[dest].msg[fifo[dest].current - 1]; } return return_value; } msg_mme_t * interf_msg_get_previous_of_type (msg_mme_dest_t dest, mm_type_t mm_type) { msg_mme_t *return_value = NULL; dbg_assert (dest < COUNT (fifo)); while (fifo[dest].current > 1) { fifo[dest].current --; if (fifo[dest].msg[fifo[dest].current - 1]->mm_type == mm_type) { return_value = fifo[dest].msg[fifo[dest].current - 1]; break; } } return return_value; } msg_mme_t * interf_msg_get_next_part (msg_mme_t *msg) { dbg_assert ( !msg_check_wrong_mme_const_values (msg)); return PARENT_OF(interf_buffer_t, msg, msg)->next_msg; } void interf_release_buf (msg_mme_t *msg) { dbg_assert ( !msg_check_wrong_mme_const_values (msg)); #if DEBUG dbg_assert(cyg_mbox_tryput(buf_rel_mbox_handle, msg)); #else cyg_mbox_put (buf_rel_mbox_handle, msg); #endif // set the flag cyg_flag_setbits (&station_flag, STATION_FLAG_BUF_REL); } msg_mme_t * interf_give_buf (void) { msg_mme_t *msg; int i; cyg_mutex_lock ( &local_ressource_lock); // if there is no buffer available, wait for one while (nb_local_buf_available == 0) cyg_cond_wait ( &local_ressource_wait); // search for an available buffer dbg_assert (INTERF_CP == 0); for (i=0; i= 1); // calculate the date before which messages has expired time_out_date = cyg_current_time (); if (time_out_date < frag_MMI_time_out_delay) return; time_out_date -= frag_MMI_time_out_delay; // check if some messages has expired for (i=0; i