Navigation


Changeset 43:2db15632a63d in freeDiameter


Ignore:
Timestamp:
Nov 25, 2009, 7:07:09 PM (14 years ago)
Author:
Sebastien Decugis <sdecugis@nict.go.jp>
Branch:
default
Phase:
public
Message:

Added a large part of connection establishment logic, to test

Files:
1 added
14 edited

Legend:

Unmodified
Added
Removed
  • freeDiameter/CMakeLists.txt

    r37 r43  
    1010SET(FD_COMMON_SRC
    1111        fD.h
     12        apps.c
    1213        cnxctx.h
    1314        config.c
  • freeDiameter/cnxctx.c

    r38 r43  
    997997       
    998998        /* The magic function does it all */
    999         CHECK_FCT( fd_fifo_move( &conn->cc_incoming, alt_fifo, &conn->cc_alt ) );
     999        CHECK_FCT( fd_fifo_move( conn->cc_incoming, alt_fifo, &conn->cc_alt ) );
    10001000       
    10011001        return 0;
     
    11141114       
    11151115        CHECK_PARAMS_DO(conn, return);
     1116       
     1117        /* Avoid sending further events to the alt fifo */
     1118        conn->cc_alt = NULL;
    11161119
    11171120        /* In case of TLS, stop receiver thread, then close properly the gnutls session */
  • freeDiameter/dict_base_proto.c

    r1 r43  
    211211                {
    212212                        struct dict_application_data data  = { 0xffffffff, "Relay"                              };
     213                        #if AI_RELAY != 0xffffffff
     214                        #error "AI_RELAY definition mismatch"
     215                        #endif
    213216                        CHECK_dict_new( DICT_APPLICATION, &data , NULL, NULL);
    214217                }
     
    907910                        struct dict_object      *       type;
    908911                        struct dict_type_data           tdata = { AVP_TYPE_UNSIGNED32,  "Enumerated*(Inband-Security-Id)"       , NULL, NULL};
    909                         struct dict_enumval_data        t_0 = { "NO_INBAND_SECURITY",           { .u32 = 0 }};
    910                         struct dict_enumval_data        t_1 = { "TLS",                  { .u32 = 1 }};
     912                        struct dict_enumval_data        t_0 = { "NO_INBAND_SECURITY",           { .u32 = ACV_ISI_NO_INBAND_SECURITY }};
     913                        struct dict_enumval_data        t_1 = { "TLS",                  { .u32 = ACV_ISI_TLS }};
    911914                        struct dict_avp_data            data = {
    912915                                        299,                                    /* Code */
  • freeDiameter/dispatch.c

    r10 r43  
    3636#include "fD.h"
    3737
     38/* Add an application into the peer's supported apps */
    3839int fd_disp_app_support ( struct dict_object * app, struct dict_object * vendor, int auth, int acct )
    3940{
     41        application_id_t aid = 0;
    4042        vendor_id_t      vid = 0;
    41         application_id_t aid = 0;
    42         struct fd_list * li;
    43         int skip = 0;
    4443       
    4544        TRACE_ENTRY("%p %p %d %d", app, vendor, auth, acct);
     
    5453                aid = data.application_id;
    5554        }
    56        
    57        
    58         /* Now insert in the list ordered by appid. Avoid duplicates */
    59         for (li = &fd_g_config->cnf_apps; li->next != &fd_g_config->cnf_apps; li = li->next) {
    60                 struct fd_app * na = (struct fd_app *)(li->next);
    61                 if (na->appid < aid)
    62                         continue;
    63                
    64                 if (na->appid > aid)
    65                         break;
    66                
    67                 /* Otherwise, we merge with existing entry -- ignore vendor id in this case */
    68                 skip = 1;
    69                
    70                 if (auth)
    71                         na->flags.auth = 1;
    72                 if (acct)
    73                         na->flags.acct = 1;
    74                 break;
     55
     56        if (vendor) {
     57                enum dict_object_type type = 0;
     58                struct dict_vendor_data data;
     59                CHECK_FCT( fd_dict_gettype(vendor, &type) );
     60                CHECK_PARAMS( type == DICT_VENDOR );
     61                CHECK_FCT( fd_dict_getval(vendor, &data) );
     62                vid = data.vendor_id;
    7563        }
    7664       
    77         if (!skip) {                   
    78                 struct fd_app  * new = NULL;
    79 
    80                 if (vendor) {
    81                         enum dict_object_type type = 0;
    82                         struct dict_vendor_data data;
    83                         CHECK_FCT( fd_dict_gettype(vendor, &type) );
    84                         CHECK_PARAMS( type == DICT_VENDOR );
    85                         CHECK_FCT( fd_dict_getval(vendor, &data) );
    86                         vid = data.vendor_id;
    87                 }
    88        
    89                 CHECK_MALLOC( new = malloc(sizeof(struct fd_app)) );
    90                 memset(new, 0, sizeof(struct fd_app));
    91                 fd_list_init(&new->chain, NULL);
    92                 new->flags.auth = (auth ? 1 : 0);
    93                 new->flags.acct = (acct ? 1 : 0);
    94                 new->vndid = vid;
    95                 new->appid = aid;
    96                 fd_list_insert_after(li, &new->chain);
    97         }
    98        
    99         return 0;
     65        return fd_app_merge(&fd_g_config->cnf_apps, aid, vid, auth, acct);
    10066}
  • freeDiameter/endpoints.c

    r38 r43  
    126126                struct fd_endpoint * ep = (struct fd_endpoint *)li;
    127127                ep->flags &= ~flags;
     128                if (ep->flags == 0) {
     129                        li = li->prev;
     130                        fd_list_unlink(&ep->chain);
     131                        free(ep);
     132                }
    128133        }
    129134       
  • freeDiameter/fD.h

    r40 r43  
    6767#endif /* DPR_TIMEOUT */
    6868
     69/* The Vendor-Id to advertise in CER/CEA */
     70#ifndef MY_VENDOR_ID
     71#define MY_VENDOR_ID    0       /* Reserved value to tell it must be ignored */
     72#endif /* MY_VENDOR_ID */
     73
     74
     75
    6976/* Configuration */
    7077int fd_conf_init();
     
    145152        /* Data for transitional states before the peer is in OPEN state */
    146153        struct {
    147                 struct cnxctx * p_initiator;    /* Connection before CEA is received */
    148154                struct cnxctx * p_receiver;     /* Only used in case of election */
    149                 pthread_t       p_ini_thr;
     155                struct msg    * p_cer;          /* Only used in case of election */
     156               
     157                pthread_t       p_ini_thr;      /* Initiator thread for establishing a connection */
    150158                struct fd_list  p_connparams;   /* The list of connection attempts, see p_cnx.c */
    151159        };
     
    265273int fd_p_ce_handle_newCER(struct msg ** msg, struct fd_peer * peer, struct cnxctx ** cnx, int valid);
    266274int fd_p_ce_handle_newcnx(struct fd_peer * peer, struct cnxctx * initiator);
    267 int fd_p_ce_winelection(struct fd_peer * peer);
     275int fd_p_ce_process_receiver(struct fd_peer * peer);
     276void fd_p_ce_clear_cnx(struct fd_peer * peer, struct cnxctx ** cnx_kept);
    268277int fd_p_dw_handle(struct msg ** msg, int req, struct fd_peer * peer);
    269278int fd_p_dw_timeout(struct fd_peer * peer);
     279int fd_p_dw_reopen(struct fd_peer * peer);
    270280int fd_p_dp_handle(struct msg ** msg, int req, struct fd_peer * peer);
    271281int fd_p_dp_initiate(struct fd_peer * peer);
  • freeDiameter/p_ce.c

    r40 r43  
    4141static int set_peer_cnx(struct fd_peer * peer, struct cnxctx **cnx)
    4242{
    43         TODO("Save *cnx into peer->p_cnxctx");
    44         TODO("Set fifo of *cnx to peer->p_events");
    45         TODO("If connection is already TLS, read the credentials");
    46         TODO("Read the remote endpoints");
    47        
    48         return ENOTSUP;
    49 }
    50 
    51 static int process_valid_CEA(struct fd_peer * peer, struct msg ** cea)
    52 {
    53         /* Save info from the CEA into the peer */
    54        
    55         /* Handshake if needed */
    56        
    57         /* Save credentials if needed */
    58        
    59         TODO("...");
    60         return ENOTSUP;
    61        
     43        CHECK_PARAMS( peer->p_cnxctx == NULL );
     44       
     45        /* Save the connection in peer */
     46        peer->p_cnxctx = *cnx;
     47        *cnx = NULL;
     48       
     49        /* Set the events to be sent to the PSM */
     50        CHECK_FCT( fd_cnx_recv_setaltfifo(peer->p_cnxctx, peer->p_events) );
     51       
     52        /* Read the credentials if possible */
     53        if (fd_cnx_getTLS(peer->p_cnxctx)) {
     54                CHECK_FCT( fd_cnx_getcred(peer->p_cnxctx, &peer->p_hdr.info.runtime.pir_cert_list, &peer->p_hdr.info.runtime.pir_cert_list_size) );
     55        }
     56       
     57        /* Read the endpoints, maybe used to reconnect to the peer later */
     58        CHECK_FCT( fd_cnx_getendpoints(peer->p_cnxctx, NULL, &peer->p_hdr.info.pi_endpoints) );
     59       
     60        /* Read the protocol */
     61        peer->p_hdr.info.runtime.pir_proto = fd_cnx_getproto(peer->p_cnxctx);
     62       
     63        return 0;
     64}
     65
     66/* Delete the peer connection, and cleanup associated information */
     67void fd_p_ce_clear_cnx(struct fd_peer * peer, struct cnxctx ** cnx_kept)
     68{
     69        peer->p_hdr.info.runtime.pir_cert_list = NULL;
     70        peer->p_hdr.info.runtime.pir_cert_list_size = 0;
     71        peer->p_hdr.info.runtime.pir_proto = 0;
     72       
     73        if (peer->p_cnxctx) {
     74                if (cnx_kept != NULL) {
     75                        *cnx_kept = peer->p_cnxctx;
     76                } else {
     77                        fd_cnx_destroy(peer->p_cnxctx);
     78                }
     79                peer->p_cnxctx = NULL;
     80        }
     81}
     82
     83/* Election: compare the Diameter Ids, return true if the election is won */
     84static __inline__ int election_result(struct fd_peer * peer)
     85{
     86        int ret = (strcasecmp(peer->p_hdr.info.pi_diamid, fd_g_config->cnf_diamid) < 0);
     87        if (ret) {
     88                TRACE_DEBUG(INFO, "Election WON against peer '%s'", peer->p_hdr.info.pi_diamid);
     89        } else {
     90                TRACE_DEBUG(INFO, "Election LOST against peer '%s'", peer->p_hdr.info.pi_diamid);
     91        }
     92        return ret;
     93}
     94
     95/* Add AVPs about local information in a CER or CEA */
     96static int add_CE_info(struct msg *msg, struct cnxctx * cnx, int isi_tls, int isi_none)
     97{
     98        struct dict_object * dictobj = NULL;
     99        struct avp * avp = NULL;
     100        union avp_value val;
     101        struct fd_list *li, local_ep = FD_LIST_INITIALIZER(local_ep);
     102       
     103        /* Add the Origin-* AVPs */
     104        CHECK_FCT( fd_msg_add_origin ( msg, 1 ) );
     105       
     106        /* Find the model for Host-IP-Address AVP */
     107        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Host-IP-Address", &dictobj, ENOENT )  );
     108               
     109        /* Get the list of endpoints */
     110        CHECK_FCT(  fd_cnx_getendpoints(cnx, &local_ep, NULL) );
     111       
     112        /* Add the AVP(s) -- not sure what is the purpose... We could probably only add the primary one ? */
     113        for (li = local_ep.next; li != &local_ep; li = li->next) {
     114                struct fd_endpoint * ep = (struct fd_endpoint *)li;
     115               
     116                CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp ) );
     117                CHECK_FCT( fd_msg_avp_value_encode ( &ep->ss, avp ) );
     118                CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
     119        }
     120       
     121       
     122        /* Vendor-Id, Product-Name, and Firmware-Revision AVPs */
     123        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Vendor-Id", &dictobj, ENOENT )  );
     124        CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp ) );
     125        val.u32 = MY_VENDOR_ID;
     126        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
     127        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
     128       
     129        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Product-Name", &dictobj, ENOENT )  );
     130        CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp ) );
     131        val.os.data = (unsigned char *)FD_PROJECT_NAME;
     132        val.os.len = strlen(FD_PROJECT_NAME);
     133        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
     134        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
     135       
     136        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Firmware-Revision", &dictobj, ENOENT )  );
     137        CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp ) );
     138        val.u32 = (uint32_t)(FD_PROJECT_VERSION_MAJOR * 10000 + FD_PROJECT_VERSION_MINOR * 100 + FD_PROJECT_VERSION_REV);
     139        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
     140        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
     141       
     142       
     143        /* Add the Inband-Security-Id AVP if needed */
     144        if (isi_tls || isi_none) {
     145                CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Inband-Security-Id", &dictobj, ENOENT )  );
     146               
     147                if (isi_none) {
     148                        CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp ) );
     149                        val.u32 = ACV_ISI_NO_INBAND_SECURITY;
     150                        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
     151                        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
     152                }
     153               
     154                if (isi_tls) {
     155                        CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp ) );
     156                        val.u32 = ACV_ISI_TLS;
     157                        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
     158                        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
     159                }
     160        }
     161       
     162        /* List of local applications */
     163        {
     164                struct dict_object * dictobj_auth = NULL;
     165                struct dict_object * dictobj_acct = NULL;
     166                struct dict_object * dictobj_vid = NULL;
     167               
     168                CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Vendor-Specific-Application-Id", &dictobj, ENOENT )  );
     169                CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Vendor-Id", &dictobj_vid, ENOENT )  );
     170                CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Auth-Application-Id", &dictobj_auth, ENOENT )  );
     171                CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Acct-Application-Id", &dictobj_acct, ENOENT )  );
     172               
     173                for (li = fd_g_config->cnf_apps.next; li != &fd_g_config->cnf_apps; li = li->next) {
     174                        struct fd_app * a = (struct fd_app *)(li);
     175
     176                        if (a->flags.auth) {
     177                                CHECK_FCT( fd_msg_avp_new ( dictobj_auth, 0, &avp ) );
     178                                val.u32 = a->appid;
     179                                CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
     180                                if (a->vndid != 0) {
     181                                        struct avp * avp2 = NULL;
     182                                        CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp2 ) );
     183                                        CHECK_FCT( fd_msg_avp_add( avp2, MSG_BRW_LAST_CHILD, avp ) );
     184                                        avp = avp2;
     185                                        CHECK_FCT( fd_msg_avp_new ( dictobj_vid, 0, &avp2 ) );
     186                                        val.u32 = a->vndid;
     187                                        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
     188                                        CHECK_FCT( fd_msg_avp_add( avp, MSG_BRW_LAST_CHILD, avp2 ) );
     189                                }
     190                                CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
     191                        }
     192                        if (a->flags.acct) {
     193                                CHECK_FCT( fd_msg_avp_new ( dictobj_acct, 0, &avp ) );
     194                                val.u32 = a->appid;
     195                                CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
     196                                if (a->vndid != 0) {
     197                                        struct avp * avp2 = NULL;
     198                                        CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp2 ) );
     199                                        CHECK_FCT( fd_msg_avp_add( avp2, MSG_BRW_LAST_CHILD, avp ) );
     200                                        avp = avp2;
     201                                        CHECK_FCT( fd_msg_avp_new ( dictobj_vid, 0, &avp2 ) );
     202                                        val.u32 = a->vndid;
     203                                        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
     204                                        CHECK_FCT( fd_msg_avp_add( avp, MSG_BRW_LAST_CHILD, avp2 ) );
     205                                }
     206                                CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
     207                        }
     208                }
     209               
     210                /* do not forget the relay application */
     211                if (! fd_g_config->cnf_flags.no_fwd) {
     212                        CHECK_FCT( fd_msg_avp_new ( dictobj_auth, 0, &avp ) );
     213                        val.u32 = AI_RELAY;
     214                        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
     215                        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
     216                }
     217        }
     218       
     219        /* Add the list of supported vendors */
     220        {
     221                uint32_t * array = fd_dict_get_vendorid_list(fd_g_config->cnf_dict);
     222                if (array) {
     223                        int i = 0;
     224                        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Supported-Vendor-Id", &dictobj, ENOENT )  );
     225                       
     226                        while (array[i] != 0) {
     227                                CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp ) );
     228                                val.u32 = array[i];
     229                                CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
     230                                CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
     231                                i++;
     232                        }
     233                       
     234                        free(array);
     235                }
     236        }
     237       
     238        return 0;
     239}
     240
     241/* Remove any information saved from a previous CER/CEA exchange */
     242static void cleanup_remote_CE_info(struct fd_peer * peer)
     243{
     244        free(peer->p_hdr.info.runtime.pir_realm);
     245        peer->p_hdr.info.runtime.pir_realm = NULL;
     246        peer->p_hdr.info.runtime.pir_vendorid = 0;
     247        peer->p_hdr.info.runtime.pir_orstate = 0;
     248        free(peer->p_hdr.info.runtime.pir_prodname);
     249        peer->p_hdr.info.runtime.pir_prodname = NULL;
     250        peer->p_hdr.info.runtime.pir_firmrev = 0;
     251        peer->p_hdr.info.runtime.pir_relay = 0;
     252        peer->p_hdr.info.runtime.pir_isi = 0;
     253        while (!FD_IS_LIST_EMPTY(&peer->p_hdr.info.runtime.pir_apps)) {
     254                struct fd_list * li = peer->p_hdr.info.runtime.pir_apps.next;
     255                fd_list_unlink(li);
     256                free(li);
     257        }
     258       
     259        fd_ep_clearflags( &peer->p_hdr.info.pi_endpoints, EP_FL_ADV /* Remove previously advertised endpoints */ );
     260}
     261
     262/* Extract information sent by the remote peer and save it in our peer structure */
     263static int save_remote_CE_info(struct msg * msg, struct fd_peer * peer, char ** error_code)
     264{
     265        struct avp * avp = NULL;
     266       
     267        cleanup_remote_CE_info(peer);
     268       
     269        CHECK_FCT( fd_msg_browse( msg, MSG_BRW_FIRST_CHILD, &avp, NULL) );
     270       
     271        /* Loop on all AVPs and save what we are interrested into */
     272        while (avp) {
     273                struct avp_hdr * hdr;
     274
     275                CHECK_FCT(  fd_msg_avp_hdr( avp, &hdr )  );
     276
     277                if (hdr->avp_flags & AVP_FLAG_VENDOR) {
     278                        /* Ignore all vendor-specific AVPs in CER/CEA because we don't support any currently */
     279                        TRACE_DEBUG(FULL, "Ignored a vendor AVP in CER / CEA");
     280                        fd_msg_dump_one(FULL, avp);
     281                        goto next;
     282                }
     283
     284                switch (hdr->avp_code) {
     285                        case AC_ORIGIN_HOST: /* Origin-Host */
     286                                if (hdr->avp_value == NULL) {
     287                                        /* This is a sanity check */
     288                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
     289                                        fd_msg_dump_one(NONE, avp);
     290                                        ASSERT(0); /* To check if this really happens, and understand why... */
     291                                        goto next;
     292                                }
     293                               
     294                                /* We check that the value matches what we know, otherwise disconnect the peer */
     295                                if (strncasecmp(hdr->avp_value->os.data, peer->p_hdr.info.pi_diamid, hdr->avp_value->os.len)) {
     296                                        TRACE_DEBUG(INFO, "Received a message with Origin-Host set to '%.*s' while expecting '%s'\n",
     297                                                        hdr->avp_value->os.len, hdr->avp_value->os.data, peer->p_hdr.info.pi_diamid);
     298                                        *error_code = "DIAMETER_UNKNOWN_PEER";
     299                                        return EINVAL;
     300                                }
     301
     302                                break;
     303               
     304                        case AC_ORIGIN_REALM: /* Origin-Realm */
     305                                if (hdr->avp_value == NULL) {
     306                                        /* This is a sanity check */
     307                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
     308                                        fd_msg_dump_one(NONE, avp);
     309                                        ASSERT(0); /* To check if this really happens, and understand why... */
     310                                        goto next;
     311                                }
     312                               
     313                                /* In case of multiple AVPs */
     314                                if (peer->p_hdr.info.runtime.pir_realm) {
     315                                        TRACE_DEBUG(INFO, "Ignored multiple instances of the Origin-Realm AVP");
     316                                        goto next;
     317                                }
     318                               
     319                                /* Save the value -- we don't change the case to avoid risking breaking UTF-8 with poor tolower() impls. */
     320                                CHECK_MALLOC(  peer->p_hdr.info.runtime.pir_realm = calloc( hdr->avp_value->os.len + 1, 1 )  );
     321                                memcpy(peer->p_hdr.info.runtime.pir_realm, hdr->avp_value->os.data, hdr->avp_value->os.len);
     322                                break;
     323
     324                        case AC_HOST_IP_ADDRESS: /* Host-IP-Address */
     325                                if (hdr->avp_value == NULL) {
     326                                        /* This is a sanity check */
     327                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
     328                                        fd_msg_dump_one(NONE, avp);
     329                                        ASSERT(0); /* To check if this really happens, and understand why... */
     330                                        goto next;
     331                                }
     332                                {
     333                                        sSS     ss;
     334
     335                                        /* Get the sockaddr value */
     336                                        memset(&ss, 0, sizeof(ss));
     337                                        CHECK_FCT( fd_msg_avp_value_interpret( avp, &ss) );
     338
     339                                        /* Save this endpoint in the list as advertized */
     340                                        CHECK_FCT( fd_ep_add_merge( &peer->p_hdr.info.pi_endpoints, (sSA *)&ss, sizeof(sSS), EP_FL_ADV ) );
     341                                }
     342                                break;
     343
     344                        case AC_VENDOR_ID: /* Vendor-Id */
     345                                if (hdr->avp_value == NULL) {
     346                                        /* This is a sanity check */
     347                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
     348                                        fd_msg_dump_one(NONE, avp);
     349                                        ASSERT(0); /* To check if this really happens, and understand why... */
     350                                        goto next;
     351                                }
     352                               
     353                                /* In case of multiple AVPs */
     354                                if (peer->p_hdr.info.runtime.pir_vendorid) {
     355                                        TRACE_DEBUG(INFO, "Ignored multiple instances of the Vendor-Id AVP");
     356                                        goto next;
     357                                }
     358                               
     359                                peer->p_hdr.info.runtime.pir_vendorid = hdr->avp_value->u32;
     360                                break;
     361
     362                        case AC_PRODUCT_NAME: /* Product-Name */
     363                                if (hdr->avp_value == NULL) {
     364                                        /* This is a sanity check */
     365                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
     366                                        fd_msg_dump_one(NONE, avp);
     367                                        ASSERT(0); /* To check if this really happens, and understand why... */
     368                                        goto next;
     369                                }
     370                               
     371                                /* In case of multiple AVPs */
     372                                if (peer->p_hdr.info.runtime.pir_prodname) {
     373                                        TRACE_DEBUG(INFO, "Ignored multiple instances of the Product-Name AVP");
     374                                        goto next;
     375                                }
     376
     377                                CHECK_MALLOC( peer->p_hdr.info.runtime.pir_prodname = calloc( hdr->avp_value->os.len + 1, 1 )  );
     378                                memcpy(peer->p_hdr.info.runtime.pir_prodname, hdr->avp_value->os.data, hdr->avp_value->os.len);
     379                                break;
     380
     381                        case AC_ORIGIN_STATE_ID: /* Origin-State-Id */
     382                                if (hdr->avp_value == NULL) {
     383                                        /* This is a sanity check */
     384                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
     385                                        fd_msg_dump_one(NONE, avp);
     386                                        ASSERT(0); /* To check if this really happens, and understand why... */
     387                                        goto next;
     388                                }
     389                               
     390                                /* In case of multiple AVPs */
     391                                if (peer->p_hdr.info.runtime.pir_orstate) {
     392                                        TRACE_DEBUG(INFO, "Ignored multiple instances of the Origin-State-Id AVP");
     393                                        goto next;
     394                                }
     395                               
     396                                peer->p_hdr.info.runtime.pir_orstate = hdr->avp_value->u32;
     397                                break;
     398
     399                        case AC_SUPPORTED_VENDOR_ID: /* Supported-Vendor-Id */
     400                                if (hdr->avp_value == NULL) {
     401                                        /* This is a sanity check */
     402                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
     403                                        fd_msg_dump_one(NONE, avp);
     404                                        ASSERT(0); /* To check if this really happens, and understand why... */
     405                                        goto next;
     406                                }
     407                               
     408                                TRACE_DEBUG(FULL, "'%s' supports a subset of vendor %d features.", peer->p_hdr.info.pi_diamid, hdr->avp_value->u32);
     409                                break;
     410
     411                        case AC_VENDOR_SPECIFIC_APPLICATION_ID: /* Vendor-Specific-Application-Id (grouped)*/
     412                                {
     413                                        struct avp * inavp = NULL;
     414                                        application_id_t aid = 0;
     415                                        vendor_id_t vid = 0;
     416                                        int auth = 0;
     417                                        int acct = 0;
     418
     419                                        /* get the first child AVP */
     420                                        CHECK_FCT(  fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &inavp, NULL)  );
     421
     422                                        while (inavp) {
     423                                                struct avp_hdr * inhdr;
     424                                                CHECK_FCT(  fd_msg_avp_hdr( inavp, &inhdr )  );
     425
     426                                                if (inhdr->avp_flags & AVP_FLAG_VENDOR) {
     427                                                        TRACE_DEBUG(FULL, "Ignored a vendor AVP inside Vendor-Specific-Application-Id AVP");
     428                                                        fd_msg_dump_one(FULL, avp);
     429                                                        goto innext;
     430                                                }
     431
     432                                                if (inhdr->avp_value == NULL) {
     433                                                        /* This is a sanity check */
     434                                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
     435                                                        fd_msg_dump_one(NONE, avp);
     436                                                        ASSERT(0); /* To check if this really happens, and understand why... */
     437                                                        goto innext;
     438                                                }
     439                                                switch (inhdr->avp_code) {
     440                                                        case AC_VENDOR_ID: /* Vendor-Id */
     441                                                                vid = inhdr->avp_value->u32;
     442                                                                break;
     443                                                        case AC_AUTH_APPLICATION_ID: /* Auth-Application-Id */
     444                                                                aid = inhdr->avp_value->u32;
     445                                                                auth += 1;
     446                                                                break;
     447                                                        case AC_ACCT_APPLICATION_ID: /* Acct-Application-Id */
     448                                                                aid = inhdr->avp_value->u32;
     449                                                                acct += 1;
     450                                                                break;
     451                                                        /* ignore other AVPs */
     452                                                }
     453
     454                                        innext:                 
     455                                                /* Go to next in AVP */
     456                                                CHECK_FCT( fd_msg_browse(inavp, MSG_BRW_NEXT, &inavp, NULL) );
     457                                        }
     458                                       
     459                                        if (auth + acct != 1) {
     460                                                TRACE_DEBUG(FULL, "Invalid Vendor-Specific-Application-Id AVP received, ignored");
     461                                                fd_msg_dump_one(FULL, avp);
     462                                        } else {
     463                                                /* Add an entry in the list */
     464                                                CHECK_FCT( fd_app_merge(&peer->p_hdr.info.runtime.pir_apps, aid, vid, auth, acct) );
     465                                        }
     466                                }
     467                                break;
     468
     469                        case AC_AUTH_APPLICATION_ID: /* Auth-Application-Id */
     470                                if (hdr->avp_value == NULL) {
     471                                        /* This is a sanity check */
     472                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
     473                                        fd_msg_dump_one(NONE, avp);
     474                                        ASSERT(0); /* To check if this really happens, and understand why... */
     475                                        goto next;
     476                                }
     477                               
     478                                if (hdr->avp_value->u32 == AI_RELAY) {
     479                                        peer->p_hdr.info.runtime.pir_relay = 1;
     480                                } else {
     481                                        CHECK_FCT( fd_app_merge(&peer->p_hdr.info.runtime.pir_apps, hdr->avp_value->u32, 0, 1, 0) );
     482                                }
     483                                break;
     484
     485                        case AC_ACCT_APPLICATION_ID: /* Acct-Application-Id */
     486                                if (hdr->avp_value == NULL) {
     487                                        /* This is a sanity check */
     488                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
     489                                        fd_msg_dump_one(NONE, avp);
     490                                        ASSERT(0); /* To check if this really happens, and understand why... */
     491                                        goto next;
     492                                }
     493                               
     494                                if (hdr->avp_value->u32 == AI_RELAY) {
     495                                        peer->p_hdr.info.runtime.pir_relay = 1;
     496                                } else {
     497                                        /* Not clear if the relay application can be inside this AVP... */
     498                                        CHECK_FCT( fd_app_merge(&peer->p_hdr.info.runtime.pir_apps, hdr->avp_value->u32, 0, 0, 1) );
     499                                }
     500                                break;
     501
     502                        case AC_FIRMWARE_REVISION: /* Firmware-Revision */
     503                                if (hdr->avp_value == NULL) {
     504                                        /* This is a sanity check */
     505                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
     506                                        fd_msg_dump_one(NONE, avp);
     507                                        ASSERT(0); /* To check if this really happens, and understand why... */
     508                                        goto next;
     509                                }
     510                               
     511                                peer->p_hdr.info.runtime.pir_firmrev = hdr->avp_value->u32;
     512                                break;
     513
     514                        case AC_INBAND_SECURITY_ID: /* Inband-Security-Id */
     515                                if (hdr->avp_value == NULL) {
     516                                        /* This is a sanity check */
     517                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
     518                                        fd_msg_dump_one(NONE, avp);
     519                                        ASSERT(0); /* To check if this really happens, and understand why... */
     520                                        goto next;
     521                                }
     522                                ASSERT( hdr->avp_value->u32 < 32 ); /* if false, we have to change the code bellow */
     523                                peer->p_hdr.info.runtime.pir_isi |= (1 << hdr->avp_value->u32);
     524                                break;
     525                }
     526
     527next:                   
     528                /* Go to next AVP */
     529                CHECK_FCT( fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL) );
     530        }
     531       
     532        return 0;
     533}
     534
     535/* Create a CER message for sending */
     536static int create_CER(struct fd_peer * peer, struct cnxctx * cnx, struct msg ** cer)
     537{
     538        struct dict_object * dictobj = NULL;
     539        int isi_tls = 0;
     540        int isi_none = 0;
     541       
     542        /* Find CER dictionary object and create an instance */
     543        CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &dictobj, ENOENT ) );
     544        CHECK_FCT( fd_msg_new ( dictobj, MSGFL_ALLOC_ETEID, cer ) );
     545       
     546        /* Do we need Inband-Security-Id AVPs ? */
     547        if (!fd_cnx_getTLS(cnx)) {
     548                isi_none = peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE; /* we add it event if the peer does not use the old mechanism */
     549                isi_tls  = peer->p_hdr.info.config.pic_flags.sec & PI_SEC_TLS_OLD;
     550        }
     551       
     552        /* Add the information about the local peer */
     553        CHECK_FCT( add_CE_info(*cer, cnx, isi_tls, isi_none) );
     554       
     555        /* Done! */
     556        return 0;
     557}
     558
     559
     560/* Continue with the initiator side */
     561static int to_waitcea(struct fd_peer * peer, struct cnxctx * cnx)
     562{
     563        /* We sent a CER on the connection, set the event queue so that we receive the CEA */
     564        CHECK_FCT( set_peer_cnx(peer, &cnx) );
     565       
     566        /* Change state and reset the timer */
     567        CHECK_FCT( fd_psm_change_state(peer, STATE_WAITCEA) );
     568        fd_psm_next_timeout(peer, 0, CEA_TIMEOUT);
     569       
     570        return 0;
     571}
     572
     573/* Reject an incoming connection attempt */
     574static void receiver_reject(struct cnxctx * recv_cnx, struct msg ** cer, char * rescode, char * errormsg)
     575{
     576        /* Create and send the CEA with appropriate error code */
     577        CHECK_FCT_DO( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, cer, MSGFL_ANSW_ERROR ), goto destroy );
     578        CHECK_FCT_DO( fd_msg_rescode_set(*cer, rescode, errormsg, NULL, 1 ), goto destroy );
     579        CHECK_FCT_DO( fd_out_send(cer, recv_cnx, NULL), goto destroy );
     580       
     581        /* And now destroy this connection */
     582destroy:
     583        fd_cnx_destroy(recv_cnx);
     584        if (*cer) {
     585                fd_msg_free(*cer);
     586                *cer = NULL;
     587        }
     588}
     589
     590/* We have established a new connection to the remote peer, send CER and eventually process the election */
     591int fd_p_ce_handle_newcnx(struct fd_peer * peer, struct cnxctx * initiator)
     592{
     593        struct msg * cer = NULL;
     594       
     595        /* Send CER on the new connection */
     596        CHECK_FCT( create_CER(peer, initiator, &cer) );
     597        CHECK_FCT( fd_out_send(&cer, initiator, peer) );
     598       
     599        /* Are we doing an election ? */
     600        if (peer->p_hdr.info.runtime.pir_state == STATE_WAITCNXACK_ELEC) {
     601                if (election_result(peer)) {
     602                        /* Close initiator connection */
     603                        fd_cnx_destroy(initiator);
     604
     605                        /* Process with the receiver side */
     606                        CHECK_FCT( fd_p_ce_process_receiver(peer) );
     607
     608                } else {
     609
     610                        /* Answer an ELECTION LOST to the receiver side */
     611                        receiver_reject(peer->p_receiver, &peer->p_cer, "ELECTION_LOST", NULL);
     612                        peer->p_receiver = NULL;
     613                        CHECK_FCT( to_waitcea(peer, initiator) );
     614                }
     615        } else {
     616                /* No election (yet) */
     617                CHECK_FCT( to_waitcea(peer, initiator) );
     618        }
     619       
     620        return 0;
    62621}
    63622
     
    65624int fd_p_ce_msgrcv(struct msg ** msg, int req, struct fd_peer * peer)
    66625{
     626        char * ec;
    67627        TRACE_ENTRY("%p %p", msg, peer);
    68628        CHECK_PARAMS( msg && *msg && CHECK_PEER(peer) );
     
    78638               
    79639                /* Set the error code */
    80                 CHECK_FCT( fd_msg_rescode_set(*msg, "DIAMETER_COMMAND_UNSUPPORTED", "No CER in current state", NULL, 1 ) );
     640                CHECK_FCT( fd_msg_rescode_set(*msg, "DIAMETER_COMMAND_UNSUPPORTED", "No CER allowed in current state", NULL, 1 ) );
    81641
    82642                /* msg now contains an answer message to send back */
    83643                CHECK_FCT_DO( fd_out_send(msg, peer->p_cnxctx, peer), /* In case of error the message has already been dumped */ );
    84 
    85644        }
    86645       
    87646        /* If the state is not WAITCEA, just discard the message */
    88         if ((req) || (peer->p_hdr.info.runtime.pir_state != STATE_WAITCEA)) {
     647        if (req || (peer->p_hdr.info.runtime.pir_state != STATE_WAITCEA)) {
    89648                if (*msg) {
    90649                        fd_log_debug("Received CER/CEA message while in state '%s', discarded.\n", STATE_STR(peer->p_hdr.info.runtime.pir_state));
     
    97656        }
    98657       
    99         /* Ok, now we can accept the CEA */
    100         TODO("process_valid_CEA");
    101        
    102         return ENOTSUP;
     658        /* Save info from the CEA into the peer */
     659        CHECK_FCT_DO( save_remote_CE_info(*msg, peer, &ec), goto cleanup );
     660       
     661        /* Handshake if needed, start clear otherwise */
     662        if ( ! fd_cnx_getTLS(peer->p_cnxctx) ) {
     663                int todo = peer->p_hdr.info.config.pic_flags.sec & peer->p_hdr.info.runtime.pir_isi ;
     664               
     665                if (todo == PI_SEC_NONE) {
     666                        /* Ok for clear connection */
     667                        TRACE_DEBUG(INFO, "No TLS protection negotiated with peer '%s'.", peer->p_hdr.info.pi_diamid);
     668                        CHECK_FCT( fd_cnx_start_clear(peer->p_cnxctx, 1) );
     669                } else {
     670                       
     671                        fd_psm_change_state(peer, STATE_OPEN_HANDSHAKE);
     672                        CHECK_FCT_DO( fd_cnx_handshake(peer->p_cnxctx, GNUTLS_CLIENT, peer->p_hdr.info.config.pic_priority, NULL),
     673                                {
     674                                        /* Handshake failed ...  */
     675                                        fd_log_debug("TLS Handshake failed with peer '%s', resetting the connection\n", peer->p_hdr.info.pi_diamid);
     676                                        goto cleanup;
     677                                } );
     678
     679                        /* Retrieve the credentials */
     680                        CHECK_FCT( fd_cnx_getcred(peer->p_cnxctx, &peer->p_hdr.info.runtime.pir_cert_list, &peer->p_hdr.info.runtime.pir_cert_list_size) );
     681                }
     682        }
     683       
     684        /* Move to next state */
     685        if (peer->p_flags.pf_cnx_pb) {
     686                fd_psm_change_state(peer, STATE_REOPEN );
     687                CHECK_FCT( fd_p_dw_reopen(peer) );
     688        } else {
     689                fd_psm_change_state(peer, STATE_OPEN );
     690                fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw);
     691        }
     692       
     693        return 0;
     694       
     695cleanup:
     696        fd_p_ce_clear_cnx(peer, NULL);
     697
     698        /* Send the error to the peer */
     699        CHECK_FCT( fd_event_send(peer->p_events, FDEVP_CNX_ERROR, 0, NULL) );
     700
     701        return 0;
     702}
     703
     704/* Handle the receiver side after winning an election (or timeout on initiator side) */
     705int fd_p_ce_process_receiver(struct fd_peer * peer)
     706{
     707        char * ec = NULL;
     708        struct msg * msg = NULL;
     709        int isi = 0;
     710       
     711        TRACE_ENTRY("%p", peer);
     712       
     713        CHECK_FCT( set_peer_cnx(peer, &peer->p_receiver) );
     714        msg = peer->p_cer;
     715        peer->p_cer = NULL;
     716       
     717        /* Parse the content of the received CER */
     718        CHECK_FCT_DO( save_remote_CE_info(msg, peer, &ec), goto error_abort );
     719       
     720        /* Validate the peer if needed */
     721        if (peer->p_flags.pf_responder) {
     722                int res = fd_peer_validate( peer );
     723                if (res < 0) {
     724                        ec = "DIAMETER_UNKNOWN_PEER";
     725                        goto error_abort;
     726                }
     727                CHECK_FCT( res );
     728        }
     729       
     730        /* Do we send ISI back ? */
     731        if ( ! fd_cnx_getTLS(peer->p_cnxctx) ) {
     732                if (peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE)
     733                        isi = PI_SEC_NONE; /* Maybe we should also look at peer->p_hdr.info.runtime.pir_isi here ? */
     734                else
     735                        isi = PI_SEC_TLS_OLD;
     736        }
     737       
     738        /* Reply a CEA */
     739        CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &msg, 0 ) );
     740        CHECK_FCT( fd_msg_rescode_set(msg, "DIAMETER_SUCCESS", NULL, NULL, 1 ) );
     741        CHECK_FCT( add_CE_info(msg, peer->p_cnxctx, isi & PI_SEC_TLS_OLD, isi & PI_SEC_NONE) );
     742        CHECK_FCT( fd_out_send(&msg, peer->p_cnxctx, peer) );
     743       
     744        /* Handshake if needed */
     745        if (isi & PI_SEC_TLS_OLD) {
     746                fd_psm_change_state(peer, STATE_OPEN_HANDSHAKE);
     747                CHECK_FCT_DO( fd_cnx_handshake(peer->p_cnxctx, GNUTLS_SERVER, peer->p_hdr.info.config.pic_priority, NULL),
     748                        {
     749                                /* Handshake failed ...  */
     750                                fd_log_debug("TLS Handshake failed with peer '%s', resetting the connection\n", peer->p_hdr.info.pi_diamid);
     751                                goto cleanup;
     752                        } );
     753               
     754                /* Retrieve the credentials */
     755                CHECK_FCT( fd_cnx_getcred(peer->p_cnxctx, &peer->p_hdr.info.runtime.pir_cert_list, &peer->p_hdr.info.runtime.pir_cert_list_size) );
     756               
     757                /* Call second validation callback if needed */
     758                if (peer->p_cb2) {
     759                        TRACE_DEBUG(FULL, "Calling second validation callback for %s", peer->p_hdr.info.pi_diamid);
     760                        CHECK_FCT_DO( (*peer->p_cb2)( &peer->p_hdr.info ),
     761                                {
     762                                        TRACE_DEBUG(INFO, "Validation callback rejected the peer %s after handshake", peer->p_hdr.info.pi_diamid);
     763                                        CHECK_FCT( fd_psm_terminate( peer ) );
     764                                        return 0;
     765                                }  );
     766                }
     767               
     768        } else {
     769                if ( ! fd_cnx_getTLS(peer->p_cnxctx) ) {
     770                        TRACE_DEBUG(INFO, "No TLS protection negotiated with peer '%s'.", peer->p_hdr.info.pi_diamid);
     771                        CHECK_FCT( fd_cnx_start_clear(peer->p_cnxctx, 1) );
     772                }
     773        }
     774               
     775        /* Move to OPEN or REOPEN state */
     776        if (peer->p_flags.pf_cnx_pb) {
     777                fd_psm_change_state(peer, STATE_REOPEN );
     778                CHECK_FCT( fd_p_dw_reopen(peer) );
     779        } else {
     780                fd_psm_change_state(peer, STATE_OPEN );
     781                fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw);
     782        }
     783       
     784        return 0;
     785
     786error_abort:
     787        if (ec) {
     788                /* Create the error message */
     789                CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &msg, MSGFL_ANSW_ERROR ) );
     790
     791                /* Set the error code */
     792                CHECK_FCT( fd_msg_rescode_set(msg, ec, NULL, NULL, 1 ) );
     793
     794                /* msg now contains an answer message to send back */
     795                CHECK_FCT_DO( fd_out_send(&msg, peer->p_cnxctx, peer), /* In case of error the message has already been dumped */ );
     796        }
     797       
     798cleanup:
     799        if (msg) {
     800                fd_msg_free(msg);
     801        }
     802        fd_p_ce_clear_cnx(peer, NULL);
     803
     804        /* Send the error to the peer */
     805        CHECK_FCT( fd_event_send(peer->p_events, FDEVP_CNX_ERROR, 0, NULL) );
     806
     807        return 0;
    103808}
    104809
     
    108813        switch (peer->p_hdr.info.runtime.pir_state) {
    109814                case STATE_CLOSED:
    110                         TODO("Handle the CER, validate the peer if needed (and set expiry), set the alt_fifo in the connection, reply a CEA, eventually handshake (OPEN_HANDSHAKE), move to OPEN or REOPEN state");
    111                         /* In case of error : DIAMETER_UNKNOWN_PEER */
     815                        peer->p_receiver = *cnx;
     816                        *cnx = NULL;
     817                        peer->p_cer = *msg;
     818                        *msg = NULL;
     819                        CHECK_FCT( fd_p_ce_process_receiver(peer) );
    112820                        break;
    113821
    114822                case STATE_WAITCNXACK:
    115                         TODO("Save the parameters in the peer, move to STATE_WAITCNXACK_ELEC");
     823                        /* Save the parameters in the peer, move to STATE_WAITCNXACK_ELEC */
     824                        peer->p_receiver = *cnx;
     825                        *cnx = NULL;
     826                        peer->p_cer = *msg;
     827                        *msg = NULL;
     828                        CHECK_FCT( fd_psm_change_state(peer, STATE_WAITCNXACK_ELEC) );
    116829                        break;
    117830                       
    118831                case STATE_WAITCEA:
    119                         TODO("Election");
     832                        if (election_result(peer)) {
     833                               
     834                                /* Close initiator connection (was already set as principal) */
     835                                fd_p_ce_clear_cnx(peer, NULL);
     836                               
     837                                /* and go on with the receiver side */
     838                                peer->p_receiver = *cnx;
     839                                *cnx = NULL;
     840                                peer->p_cer = *msg;
     841                                *msg = NULL;
     842                                CHECK_FCT( fd_p_ce_process_receiver(peer) );
     843
     844                        } else {
     845
     846                                /* Answer an ELECTION LOST to the receiver side and continue */
     847                                receiver_reject(*cnx, msg, "ELECTION_LOST", "Please answer my CER instead, you won the election.");
     848                                *cnx = NULL;
     849                        }
    120850                        break;
    121851
    122852                default:
    123                         TODO("Reply with error CEA");
    124                         TODO("Close the connection");
    125                         /* reject_incoming_connection */
    126 
    127         }
    128                                
    129        
    130         return ENOTSUP;
    131 }
    132 
    133 static int do_election(struct fd_peer * peer)
    134 {
    135         TODO("Compare diameter Ids");
    136        
    137         /* ELECTION_LOST error code ?*/
    138        
    139         TODO("If we lost the election, we close the received connection and go to WAITCEA");
    140         TODO("If we won the election, we close initiator cnx, then call fd_p_ce_winelection");
    141        
    142        
    143 }
    144 
    145 /* We have established a new connection to the remote peer, send CER and eventually do election */
    146 int fd_p_ce_handle_newcnx(struct fd_peer * peer, struct cnxctx * initiator)
    147 {
    148         /* if not election */
    149         TODO("Set the connection as peer's (setaltfifo)");
    150         TODO("Send CER");
    151         TODO("Move to WAITCEA");
    152         TODO("Change timer to CEA_TIMEOUT");
    153        
    154         /* if election */                               
    155         TODO("Send CER on cnx");
    156         TODO("Do the election");
    157        
    158         return ENOTSUP;
    159 }
    160 
    161 /* Handle the receiver side after winning an election (or timeout on initiator side) */
    162 int fd_p_ce_winelection(struct fd_peer * peer)
    163 {
    164         TODO("Move the receiver side connection to peer principal, set the altfifo");
    165         TODO("Then handle the received CER");
    166 }
     853                        receiver_reject(*cnx, msg, "DIAMETER_UNABLE_TO_COMPLY", "Invalid state to receive a new connection attempt");
     854                        *cnx = NULL;
     855        }
     856                               
     857        return 0;
     858}
  • freeDiameter/p_cnx.c

    r39 r43  
    246246                                return NULL;
    247247                        } );
     248        } else {
     249                /* Prepare to receive the next message */
     250                CHECK_FCT_DO( fd_cnx_start_clear(cnx, 0), goto fatal_error );
    248251        }
    249252       
  • freeDiameter/p_dw.c

    r40 r43  
    5454        return ENOTSUP;
    5555}
    56                
     56
     57/* Handle DW exchanges after the peer has come alive again */
     58int fd_p_dw_reopen(struct fd_peer * peer)
     59{
     60        TODO("...");
     61       
     62        return ENOTSUP;
     63}
     64
     65
  • freeDiameter/p_psm.c

    r42 r43  
    250250        fd_p_cnx_abort(peer, terminate);
    251251       
    252         if (peer->p_cnxctx) {
    253                 fd_cnx_destroy(peer->p_cnxctx);
    254                 peer->p_cnxctx = NULL;
    255         }
    256        
    257         if (peer->p_initiator) {
    258                 fd_cnx_destroy(peer->p_initiator);
    259                 peer->p_initiator = NULL;
    260         }
     252        fd_p_ce_clear_cnx(peer, NULL);
    261253       
    262254        if (peer->p_receiver) {
     
    594586                struct cnxctx * cnx = ev_data;
    595587               
    596                 /* Release the resources of the thread */
     588                /* Release the resources of the connecting thread */
    597589                CHECK_POSIX_DO( pthread_join( peer->p_ini_thr, NULL), /* ignore, it is not a big deal */);
    598590                peer->p_ini_thr = (pthread_t)NULL;
     
    642634                               
    643635                                /* Handle receiver side */
    644                                 CHECK_FCT_DO( fd_p_ce_winelection(peer), goto psm_end );
     636                                CHECK_FCT_DO( fd_p_ce_process_receiver(peer), goto psm_end );
    645637                                break;
    646638                }
  • include/freeDiameter/freeDiameter.h

    r42 r43  
    336336                int             pir_relay;      /* The remote peer advertized the relay application */
    337337                struct fd_list  pir_apps;       /* applications advertised by the remote peer, except relay (pi_flags.relay) */
     338                int             pir_isi;        /* Inband-Security-Id advertised (PI_SEC_* bits) */
    338339               
    339340                int             pir_proto;      /* The L4 protocol currently used with the peer (IPPROTO_TCP or IPPROTO_SCTP) */
     
    423424 * after the CER is received. An extension must register such callback with peer_validate_register.
    424425 *
    425  *   If (info->pi_flags.sec == PI_SEC_TLS_OLD) the extension may instruct the daemon explicitely
    426  * to not use TLS by clearing info->pi_flags.inband_tls -- only if inband_none is set.
    427  *
    428  *   If (info->pi_flags.sec == PI_SEC_TLS_OLD) and info->pi_flags.inband_tls is set,
     426 *   The callback can learn if the peer has sent Inband-Security-Id AVPs in runtime.pir_isi fields.
     427 * It can also learn if a handshake has already been performed in runtime.pir_cert_list field.
     428 * The callback must set the value of config.pic_flags.sec appropriately to allow a connection without TLS.
     429 *
     430 *   If the old TLS mechanism is used,
    429431 * the extension may also need to check the credentials provided during the TLS
    430432 * exchange (remote certificate). For this purpose, it may set the address of a new callback
    431433 * to be called once the handshake is completed. This new callback receives the information
    432  * structure as parameter (with pi_sec_data set) and returns 0 if the credentials are correct,
     434 * structure as parameter (with pir_cert_list set) and returns 0 if the credentials are correct,
    433435 * or an error code otherwise. If the error code is received, the connection is closed and the
    434436 * peer is destroyed.
     
    545547void fd_ep_dump( int indent, struct fd_list * eps );
    546548
     549/***************************************/
     550/*   Applications lists helpers        */
     551/***************************************/
     552
     553int fd_app_merge(struct fd_list * list, application_id_t aid, vendor_id_t vid, int auth, int acct);
     554int fd_app_find_common(struct fd_list * target, struct fd_list * reference);
     555int fd_app_gotcommon(struct fd_list * apps);
     556
    547557#endif /* _FREEDIAMETER_H */
  • include/freeDiameter/libfreeDiameter.h

    r34 r43  
    718718 }
    719719                 
    720  
    721720*/
     721               
     722/* Special function: */
     723uint32_t * fd_dict_get_vendorid_list(struct dictionary * dict);
    722724         
    723725/*
     
    13291331               
    13301332/* Define some hard-coded values */
     1333/* Application */
     1334#define AI_RELAY                        0xffffffff
     1335
    13311336/* Commands Codes */
    13321337#define CC_CAPABILITIES_EXCHANGE        257
     
    13691374#define AC_ORIGIN_REALM                 296
    13701375#define AC_INBAND_SECURITY_ID           299
     1376#define ACV_ISI_NO_INBAND_SECURITY              0
     1377#define ACV_ISI_TLS                             1
    13711378
    13721379/* Error codes */
     
    24262433 *
    24272434 * PARAMETERS:
    2428  *  old         : Location of a FIFO that is to be emptied and deleted.
     2435 *  old         : Location of a FIFO that is to be emptied.
    24292436 *  new         : A FIFO that will receive the old data.
    24302437 *  loc_update  : if non NULL, a place to store the pointer to new FIFO atomically with the move.
    24312438 *
    24322439 * DESCRIPTION:
    2433  *  Delete a queue and move its content to another one atomically.
     2440 *  Empties a queue and move its content to another one atomically.
    24342441 *
    24352442 * RETURN VALUE:
     
    24372444 *  EINVAL      : A parameter is invalid.
    24382445 */
    2439 int fd_fifo_move ( struct fifo ** old, struct fifo * new, struct fifo ** loc_update );
     2446int fd_fifo_move ( struct fifo * old, struct fifo * new, struct fifo ** loc_update );
    24402447
    24412448/*
  • libfreeDiameter/dictionary.c

    r7 r43  
    15291529       
    15301530       
    1531         /* Initialize the sentinel for applciations */
     1531        /* Initialize the sentinel for applications */
    15321532        init_object( &new->dict_applications, DICT_APPLICATION );
    15331533        new->dict_applications.data.application.application_name = "Diameter Common Messages";
  • libfreeDiameter/fifo.c

    r25 r43  
    183183}
    184184
    185 /* Move the content of old into new, and update loc_update atomically */
    186 int fd_fifo_move ( struct fifo ** old, struct fifo * new, struct fifo ** loc_update )
     185/* Move the content of old into new, and update loc_update atomically. We leave the old queue empty but valid */
     186int fd_fifo_move ( struct fifo * old, struct fifo * new, struct fifo ** loc_update )
    187187{
    188188        struct fifo * q;
     
    190190       
    191191        TRACE_ENTRY("%p %p %p", old, new, loc_update);
    192         CHECK_PARAMS( old && CHECK_FIFO( *old ) && CHECK_FIFO( new ));
    193        
    194         q = *old;
    195         CHECK_PARAMS( ! q->data );
     192        CHECK_PARAMS( CHECK_FIFO( old ) && CHECK_FIFO( new ));
     193       
     194        CHECK_PARAMS( ! old->data );
    196195        if (new->high) {
    197196                TODO("Implement support for thresholds in fd_fifo_move...");
     
    199198       
    200199        /* Update loc_update */
    201         *old = NULL;
    202200        if (loc_update)
    203201                *loc_update = new;
    204202       
    205203        /* Lock the queues */
    206         CHECK_POSIX(  pthread_mutex_lock( &q->mtx )  );
     204        CHECK_POSIX(  pthread_mutex_lock( &old->mtx )  );
    207205        CHECK_POSIX(  pthread_mutex_lock( &new->mtx )  );
    208206       
    209207        /* Any waiting thread on the old queue returns an error */
    210         q->eyec = 0xdead;
    211         while (q->thrs) {
    212                 CHECK_POSIX(  pthread_cond_signal(&q->cond)  );
    213                 CHECK_POSIX(  pthread_mutex_unlock( &q->mtx ));
     208        old->eyec = 0xdead;
     209        while (old->thrs) {
     210                CHECK_POSIX(  pthread_cond_signal(&old->cond)  );
     211                CHECK_POSIX(  pthread_mutex_unlock( &old->mtx ));
    214212                pthread_yield();
    215                 CHECK_POSIX(  pthread_mutex_lock( &q->mtx )  );
     213                CHECK_POSIX(  pthread_mutex_lock( &old->mtx )  );
    216214                ASSERT( ++loops < 10 ); /* detect infinite loops */
    217215        }
    218216       
    219217        /* Move all data from old to new */
    220         fd_list_move_end( &new->list, &q->list );
    221         if (q->count && (!new->count)) {
     218        fd_list_move_end( &new->list, &old->list );
     219        if (old->count && (!new->count)) {
    222220                CHECK_POSIX(  pthread_cond_signal(&new->cond)  );
    223221        }
    224         new->count += q->count;
    225        
    226         /* Destroy old */
    227         CHECK_POSIX(  pthread_mutex_unlock( &q->mtx )  );
    228         CHECK_POSIX(  pthread_cond_destroy( &q->cond )  );
    229         CHECK_POSIX(  pthread_mutex_destroy( &q->mtx )  );
    230         free(q);
    231        
    232         /* Unlock new, we're done */
     222        new->count += old->count;
     223       
     224        /* Reset old */
     225        old->count = 0;
     226        old->eyec = FIFO_EYEC;
     227       
     228        /* Unlock, we're done */
    233229        CHECK_POSIX(  pthread_mutex_unlock( &new->mtx )  );
     230        CHECK_POSIX(  pthread_mutex_unlock( &old->mtx )  );
    234231       
    235232        return 0;
Note: See TracChangeset for help on using the changeset viewer.