Navigation


source: freeDiameter/libfdcore/p_ce.c @ 688:8c3dc8584dab

Last change on this file since 688:8c3dc8584dab was 688:8c3dc8584dab, checked in by Sebastien Decugis <sdecugis@nict.go.jp>, 11 years ago

Prepared capability for messages logging to separate files / folders

File size: 34.6 KB
Line 
1/*********************************************************************************************************
2* Software License Agreement (BSD License)                                                               *
3* Author: Sebastien Decugis <sdecugis@nict.go.jp>                                                        *
4*                                                                                                        *
5* Copyright (c) 2011, WIDE Project and NICT                                                              *
6* All rights reserved.                                                                                   *
7*                                                                                                        *
8* Redistribution and use of this software in source and binary forms, with or without modification, are  *
9* permitted provided that the following conditions are met:                                              *
10*                                                                                                        *
11* * Redistributions of source code must retain the above                                                 *
12*   copyright notice, this list of conditions and the                                                    *
13*   following disclaimer.                                                                                *
14*                                                                                                        *
15* * Redistributions in binary form must reproduce the above                                              *
16*   copyright notice, this list of conditions and the                                                    *
17*   following disclaimer in the documentation and/or other                                               *
18*   materials provided with the distribution.                                                            *
19*                                                                                                        *
20* * Neither the name of the WIDE Project or NICT nor the                                                 *
21*   names of its contributors may be used to endorse or                                                  *
22*   promote products derived from this software without                                                  *
23*   specific prior written permission of WIDE Project and                                                *
24*   NICT.                                                                                                *
25*                                                                                                        *
26* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT     *
30* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS    *
31* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
33* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                                             *
34*********************************************************************************************************/
35
36#include "fdcore-internal.h"
37
38/* This file contains code to handle Capabilities Exchange messages (CER and CEA) and election process */
39
40/* Compilation option:
41 USE_CEA_BROADCAST
42        Define this to enable sending multiple copies of the CEA in case of SCTP connection.
43        This avoids a race condition when sending an application message over a different stream
44        than the CEA, it might be delivered first and thus ignored.
45*/
46
47/* Save a connection as peer's principal */
48static int set_peer_cnx(struct fd_peer * peer, struct cnxctx **cnx)
49{
50        CHECK_PARAMS( peer->p_cnxctx == NULL );
51       
52        /* Save the connection in peer */
53        peer->p_cnxctx = *cnx;
54        *cnx = NULL;
55       
56        /* Set the events to be sent to the PSM */
57        CHECK_FCT( fd_cnx_recv_setaltfifo(peer->p_cnxctx, peer->p_events) );
58       
59        /* Read the credentials if possible */
60        if (fd_cnx_getTLS(peer->p_cnxctx)) {
61                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) );
62        }
63       
64        /* Read the endpoints, maybe used to reconnect to the peer later */
65        CHECK_FCT( fd_cnx_getremoteeps(peer->p_cnxctx, &peer->p_hdr.info.pi_endpoints) );
66       
67        /* Read the protocol */
68        peer->p_hdr.info.runtime.pir_proto = fd_cnx_getproto(peer->p_cnxctx);
69       
70        return 0;
71}
72
73/* Delete the peer connection, and cleanup associated information */
74void fd_p_ce_clear_cnx(struct fd_peer * peer, struct cnxctx ** cnx_kept)
75{
76        peer->p_hdr.info.runtime.pir_cert_list = NULL;
77        peer->p_hdr.info.runtime.pir_cert_list_size = 0;
78        peer->p_hdr.info.runtime.pir_proto = 0;
79       
80        if (peer->p_cnxctx) {
81                if (cnx_kept != NULL) {
82                        *cnx_kept = peer->p_cnxctx;
83                } else {
84                        fd_cnx_destroy(peer->p_cnxctx);
85                }
86                peer->p_cnxctx = NULL;
87        }
88}
89
90/* Election: compare the Diameter Ids, return true if the election is won */
91static __inline__ int election_result(struct fd_peer * peer)
92{
93        int ret = (strcasecmp(peer->p_hdr.info.pi_diamid, fd_g_config->cnf_diamid) < 0);
94        if (ret) {
95                TRACE_DEBUG(INFO, "Election WON against peer '%s'", peer->p_hdr.info.pi_diamid);
96        } else {
97                TRACE_DEBUG(INFO, "Election LOST against peer '%s'", peer->p_hdr.info.pi_diamid);
98        }
99        return ret;
100}
101
102/* Add AVPs about local information in a CER or CEA */
103static int add_CE_info(struct msg *msg, struct cnxctx * cnx, int isi_tls, int isi_none)
104{
105        struct dict_object * dictobj = NULL;
106        struct avp * avp = NULL;
107        union avp_value val;
108        struct fd_list *li;
109       
110        /* Add the Origin-* AVPs */
111        CHECK_FCT( fd_msg_add_origin ( msg, 1 ) );
112       
113        /* Find the model for Host-IP-Address AVP */
114        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Host-IP-Address", &dictobj, ENOENT )  );
115               
116        /* Add the AVP(s) -- not sure what is the purpose... We could probably only add the primary one ? */
117        for (li = fd_g_config->cnf_endpoints.next; li != &fd_g_config->cnf_endpoints; li = li->next) {
118                struct fd_endpoint * ep = (struct fd_endpoint *)li;
119               
120                CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp ) );
121                CHECK_FCT( fd_msg_avp_value_encode ( &ep->ss, avp ) );
122                CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
123        }
124       
125        /* Vendor-Id, Product-Name, and Firmware-Revision AVPs */
126        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Vendor-Id", &dictobj, ENOENT )  );
127        CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp ) );
128        val.u32 = MY_VENDOR_ID;
129        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
130        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
131       
132        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Product-Name", &dictobj, ENOENT )  );
133        CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp ) );
134        val.os.data = (unsigned char *)FD_PROJECT_NAME;
135        val.os.len = strlen(FD_PROJECT_NAME);
136        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
137        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
138       
139        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Firmware-Revision", &dictobj, ENOENT )  );
140        CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp ) );
141        val.u32 = (uint32_t)(FD_PROJECT_VERSION_MAJOR * 10000 + FD_PROJECT_VERSION_MINOR * 100 + FD_PROJECT_VERSION_REV);
142        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
143        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
144       
145       
146        /* Add the Inband-Security-Id AVP if needed */
147        if (isi_tls || isi_none) {
148                CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Inband-Security-Id", &dictobj, ENOENT )  );
149               
150                if (isi_none) {
151                        CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp ) );
152                        val.u32 = ACV_ISI_NO_INBAND_SECURITY;
153                        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
154                        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
155                }
156               
157                if (isi_tls) {
158                        CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp ) );
159                        val.u32 = ACV_ISI_TLS;
160                        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
161                        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
162                }
163        }
164       
165        /* List of local applications */
166        {
167                struct dict_object * dictobj_auth = NULL;
168                struct dict_object * dictobj_acct = NULL;
169                struct dict_object * dictobj_vid = NULL;
170               
171                CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Vendor-Specific-Application-Id", &dictobj, ENOENT )  );
172                CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Vendor-Id", &dictobj_vid, ENOENT )  );
173                CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Auth-Application-Id", &dictobj_auth, ENOENT )  );
174                CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Acct-Application-Id", &dictobj_acct, ENOENT )  );
175               
176                for (li = fd_g_config->cnf_apps.next; li != &fd_g_config->cnf_apps; li = li->next) {
177                        struct fd_app * a = (struct fd_app *)(li);
178
179                        if (a->flags.auth) {
180                                CHECK_FCT( fd_msg_avp_new ( dictobj_auth, 0, &avp ) );
181                                val.u32 = a->appid;
182                                CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
183                                if (a->vndid != 0) {
184                                        struct avp * avp2 = NULL;
185                                        CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp2 ) );
186                                        CHECK_FCT( fd_msg_avp_add( avp2, MSG_BRW_LAST_CHILD, avp ) );
187                                        avp = avp2;
188                                        CHECK_FCT( fd_msg_avp_new ( dictobj_vid, 0, &avp2 ) );
189                                        val.u32 = a->vndid;
190                                        CHECK_FCT( fd_msg_avp_setvalue( avp2, &val ) );
191                                        CHECK_FCT( fd_msg_avp_add( avp, MSG_BRW_LAST_CHILD, avp2 ) );
192                                }
193                                CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
194                        }
195                        if (a->flags.acct) {
196                                CHECK_FCT( fd_msg_avp_new ( dictobj_acct, 0, &avp ) );
197                                val.u32 = a->appid;
198                                CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
199                                if (a->vndid != 0) {
200                                        struct avp * avp2 = NULL;
201                                        CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp2 ) );
202                                        CHECK_FCT( fd_msg_avp_add( avp2, MSG_BRW_LAST_CHILD, avp ) );
203                                        avp = avp2;
204                                        CHECK_FCT( fd_msg_avp_new ( dictobj_vid, 0, &avp2 ) );
205                                        val.u32 = a->vndid;
206                                        CHECK_FCT( fd_msg_avp_setvalue( avp2, &val ) );
207                                        CHECK_FCT( fd_msg_avp_add( avp, MSG_BRW_LAST_CHILD, avp2 ) );
208                                }
209                                CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
210                        }
211                }
212               
213                /* do not forget the relay application */
214                if (! fd_g_config->cnf_flags.no_fwd) {
215                        CHECK_FCT( fd_msg_avp_new ( dictobj_auth, 0, &avp ) );
216                        val.u32 = AI_RELAY;
217                        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
218                        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
219                }
220        }
221       
222        /* Add the list of supported vendors */
223        {
224                uint32_t * array = fd_dict_get_vendorid_list(fd_g_config->cnf_dict);
225                if (array) {
226                        int i = 0;
227                        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Supported-Vendor-Id", &dictobj, ENOENT )  );
228                       
229                        while (array[i] != 0) {
230                                CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp ) );
231                                val.u32 = array[i];
232                                CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
233                                CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
234                                i++;
235                        }
236                       
237                        free(array);
238                }
239        }
240       
241        return 0;
242}
243
244/* Remove any information saved from a previous CER/CEA exchange */
245static void cleanup_remote_CE_info(struct fd_peer * peer)
246{
247        free(peer->p_hdr.info.runtime.pir_realm);
248        peer->p_hdr.info.runtime.pir_realm = NULL;
249        peer->p_hdr.info.runtime.pir_vendorid = 0;
250        peer->p_hdr.info.runtime.pir_orstate = 0;
251        free(peer->p_hdr.info.runtime.pir_prodname);
252        peer->p_hdr.info.runtime.pir_prodname = NULL;
253        peer->p_hdr.info.runtime.pir_firmrev = 0;
254        peer->p_hdr.info.runtime.pir_relay = 0;
255        peer->p_hdr.info.runtime.pir_isi = 0;
256        while (!FD_IS_LIST_EMPTY(&peer->p_hdr.info.runtime.pir_apps)) {
257                struct fd_list * li = peer->p_hdr.info.runtime.pir_apps.next;
258                fd_list_unlink(li);
259                free(li);
260        }
261       
262        fd_ep_clearflags( &peer->p_hdr.info.pi_endpoints, EP_FL_ADV /* Remove previously advertised endpoints */ );
263}
264
265/* Extract information sent by the remote peer and save it in our peer structure */
266static int save_remote_CE_info(struct msg * msg, struct fd_peer * peer, char ** error_code, uint32_t *rc)
267{
268        struct avp * avp = NULL;
269       
270        cleanup_remote_CE_info(peer);
271       
272        CHECK_FCT( fd_msg_browse( msg, MSG_BRW_FIRST_CHILD, &avp, NULL) );
273       
274        /* Loop on all AVPs and save what we are interrested into */
275        while (avp) {
276                struct avp_hdr * hdr;
277
278                CHECK_FCT(  fd_msg_avp_hdr( avp, &hdr )  );
279
280                if (hdr->avp_flags & AVP_FLAG_VENDOR) {
281                        /* Ignore all vendor-specific AVPs in CER/CEA because we don't support any currently */
282                        TRACE_DEBUG(FULL, "Ignored a vendor AVP in CER / CEA");
283                        fd_msg_dump_one(FULL, avp);
284                        goto next;
285                }
286
287                switch (hdr->avp_code) {
288                        case AC_RESULT_CODE: /* Result-Code */
289                                if (hdr->avp_value == NULL) {
290                                        /* This is a sanity check */
291                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
292                                        fd_msg_dump_one(NONE, avp);
293                                        ASSERT(0); /* To check if this really happens, and understand why... */
294                                        goto next;
295                                }
296                               
297                                if (rc)
298                                        *rc = hdr->avp_value->u32;
299                                break;
300               
301                        case AC_ORIGIN_HOST: /* Origin-Host */
302                                if (hdr->avp_value == NULL) {
303                                        /* This is a sanity check */
304                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
305                                        fd_msg_dump_one(NONE, avp);
306                                        ASSERT(0); /* To check if this really happens, and understand why... */
307                                        goto next;
308                                }
309                               
310                                /* We check that the value matches what we know, otherwise disconnect the peer */
311                                /* here also, using strcasecmp on (supposed) UTF8 data might be bad idea... to be improved */
312                                if (strncasecmp((char *)hdr->avp_value->os.data, peer->p_hdr.info.pi_diamid, hdr->avp_value->os.len)) {
313                                        TRACE_DEBUG(INFO, "Received a message with Origin-Host set to '%.*s' while expecting '%s'\n", 
314                                                        hdr->avp_value->os.len, hdr->avp_value->os.data, peer->p_hdr.info.pi_diamid);
315                                        *error_code = "DIAMETER_UNKNOWN_PEER";
316                                        return EINVAL;
317                                }
318
319                                break;
320               
321                        case AC_ORIGIN_REALM: /* Origin-Realm */
322                                if (hdr->avp_value == NULL) {
323                                        /* This is a sanity check */
324                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
325                                        fd_msg_dump_one(NONE, avp);
326                                        ASSERT(0); /* To check if this really happens, and understand why... */
327                                        goto next;
328                                }
329                               
330                                /* In case of multiple AVPs */
331                                if (peer->p_hdr.info.runtime.pir_realm) {
332                                        TRACE_DEBUG(INFO, "Ignored multiple instances of the Origin-Realm AVP");
333                                        goto next;
334                                }
335                               
336                                /* Save the value -- we don't change the case to avoid risking breaking UTF-8 with poor tolower() impls. */
337                                CHECK_MALLOC(  peer->p_hdr.info.runtime.pir_realm = calloc( hdr->avp_value->os.len + 1, 1 )  );
338                                memcpy(peer->p_hdr.info.runtime.pir_realm, hdr->avp_value->os.data, hdr->avp_value->os.len);
339                                break;
340
341                        case AC_HOST_IP_ADDRESS: /* Host-IP-Address */
342                                if (hdr->avp_value == NULL) {
343                                        /* This is a sanity check */
344                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
345                                        fd_msg_dump_one(NONE, avp);
346                                        ASSERT(0); /* To check if this really happens, and understand why... */
347                                        goto next;
348                                }
349                                {
350                                        sSS     ss;
351
352                                        /* Get the sockaddr value */
353                                        memset(&ss, 0, sizeof(ss));
354                                        CHECK_FCT( fd_msg_avp_value_interpret( avp, &ss) );
355
356                                        /* Save this endpoint in the list as advertized */
357                                        CHECK_FCT( fd_ep_add_merge( &peer->p_hdr.info.pi_endpoints, (sSA *)&ss, sizeof(sSS), EP_FL_ADV ) );
358                                }
359                                break;
360
361                        case AC_VENDOR_ID: /* Vendor-Id */
362                                if (hdr->avp_value == NULL) {
363                                        /* This is a sanity check */
364                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
365                                        fd_msg_dump_one(NONE, avp);
366                                        ASSERT(0); /* To check if this really happens, and understand why... */
367                                        goto next;
368                                }
369                               
370                                /* In case of multiple AVPs */
371                                if (peer->p_hdr.info.runtime.pir_vendorid) {
372                                        TRACE_DEBUG(INFO, "Ignored multiple instances of the Vendor-Id AVP");
373                                        goto next;
374                                }
375                               
376                                peer->p_hdr.info.runtime.pir_vendorid = hdr->avp_value->u32;
377                                break;
378
379                        case AC_PRODUCT_NAME: /* Product-Name */
380                                if (hdr->avp_value == NULL) {
381                                        /* This is a sanity check */
382                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
383                                        fd_msg_dump_one(NONE, avp);
384                                        ASSERT(0); /* To check if this really happens, and understand why... */
385                                        goto next;
386                                }
387                               
388                                /* In case of multiple AVPs */
389                                if (peer->p_hdr.info.runtime.pir_prodname) {
390                                        TRACE_DEBUG(INFO, "Ignored multiple instances of the Product-Name AVP");
391                                        goto next;
392                                }
393
394                                CHECK_MALLOC( peer->p_hdr.info.runtime.pir_prodname = calloc( hdr->avp_value->os.len + 1, 1 )  );
395                                memcpy(peer->p_hdr.info.runtime.pir_prodname, hdr->avp_value->os.data, hdr->avp_value->os.len);
396                                break;
397
398                        case AC_ORIGIN_STATE_ID: /* Origin-State-Id */
399                                if (hdr->avp_value == NULL) {
400                                        /* This is a sanity check */
401                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
402                                        fd_msg_dump_one(NONE, avp);
403                                        ASSERT(0); /* To check if this really happens, and understand why... */
404                                        goto next;
405                                }
406                               
407                                /* In case of multiple AVPs */
408                                if (peer->p_hdr.info.runtime.pir_orstate) {
409                                        TRACE_DEBUG(INFO, "Ignored multiple instances of the Origin-State-Id AVP");
410                                        goto next;
411                                }
412                               
413                                peer->p_hdr.info.runtime.pir_orstate = hdr->avp_value->u32;
414                                break;
415
416                        case AC_SUPPORTED_VENDOR_ID: /* Supported-Vendor-Id */
417                                if (hdr->avp_value == NULL) {
418                                        /* This is a sanity check */
419                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
420                                        fd_msg_dump_one(NONE, avp);
421                                        ASSERT(0); /* To check if this really happens, and understand why... */
422                                        goto next;
423                                }
424                               
425                                TRACE_DEBUG(FULL, "'%s' supports a subset of vendor %d features.", peer->p_hdr.info.pi_diamid, hdr->avp_value->u32);
426                                break;
427
428                        case AC_VENDOR_SPECIFIC_APPLICATION_ID: /* Vendor-Specific-Application-Id (grouped)*/
429                                {
430                                        struct avp * inavp = NULL;
431                                        application_id_t aid = 0;
432                                        vendor_id_t vid = 0;
433                                        int auth = 0;
434                                        int acct = 0;
435
436                                        /* get the first child AVP */
437                                        CHECK_FCT(  fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &inavp, NULL)  );
438
439                                        while (inavp) {
440                                                struct avp_hdr * inhdr;
441                                                CHECK_FCT(  fd_msg_avp_hdr( inavp, &inhdr )  );
442
443                                                if (inhdr->avp_flags & AVP_FLAG_VENDOR) {
444                                                        TRACE_DEBUG(FULL, "Ignored a vendor AVP inside Vendor-Specific-Application-Id AVP");
445                                                        fd_msg_dump_one(FULL, avp);
446                                                        goto innext;
447                                                }
448
449                                                if (inhdr->avp_value == NULL) {
450                                                        /* This is a sanity check */
451                                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
452                                                        fd_msg_dump_one(NONE, avp);
453                                                        ASSERT(0); /* To check if this really happens, and understand why... */
454                                                        goto innext;
455                                                }
456                                                switch (inhdr->avp_code) {
457                                                        case AC_VENDOR_ID: /* Vendor-Id */
458                                                                vid = inhdr->avp_value->u32;
459                                                                break;
460                                                        case AC_AUTH_APPLICATION_ID: /* Auth-Application-Id */
461                                                                aid = inhdr->avp_value->u32;
462                                                                auth += 1;
463                                                                break;
464                                                        case AC_ACCT_APPLICATION_ID: /* Acct-Application-Id */
465                                                                aid = inhdr->avp_value->u32;
466                                                                acct += 1;
467                                                                break;
468                                                        /* ignore other AVPs */
469                                                }
470
471                                        innext:                 
472                                                /* Go to next in AVP */
473                                                CHECK_FCT( fd_msg_browse(inavp, MSG_BRW_NEXT, &inavp, NULL) );
474                                        }
475                                       
476                                        if (auth + acct != 1) {
477                                                TRACE_DEBUG(FULL, "Invalid Vendor-Specific-Application-Id AVP received, ignored");
478                                                fd_msg_dump_one(FULL, avp);
479                                        } else {
480                                                /* Add an entry in the list */
481                                                CHECK_FCT( fd_app_merge(&peer->p_hdr.info.runtime.pir_apps, aid, vid, auth, acct) );
482                                        }
483                                }
484                                break;
485
486                        case AC_AUTH_APPLICATION_ID: /* Auth-Application-Id */
487                                if (hdr->avp_value == NULL) {
488                                        /* This is a sanity check */
489                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
490                                        fd_msg_dump_one(NONE, avp);
491                                        ASSERT(0); /* To check if this really happens, and understand why... */
492                                        goto next;
493                                }
494                               
495                                if (hdr->avp_value->u32 == AI_RELAY) {
496                                        peer->p_hdr.info.runtime.pir_relay = 1;
497                                } else {
498                                        CHECK_FCT( fd_app_merge(&peer->p_hdr.info.runtime.pir_apps, hdr->avp_value->u32, 0, 1, 0) );
499                                }
500                                break;
501
502                        case AC_ACCT_APPLICATION_ID: /* Acct-Application-Id */
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                                if (hdr->avp_value->u32 == AI_RELAY) {
512                                        peer->p_hdr.info.runtime.pir_relay = 1;
513                                } else {
514                                        /* Not clear if the relay application can be inside this AVP... */
515                                        CHECK_FCT( fd_app_merge(&peer->p_hdr.info.runtime.pir_apps, hdr->avp_value->u32, 0, 0, 1) );
516                                }
517                                break;
518
519                        case AC_FIRMWARE_REVISION: /* Firmware-Revision */
520                                if (hdr->avp_value == NULL) {
521                                        /* This is a sanity check */
522                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
523                                        fd_msg_dump_one(NONE, avp);
524                                        ASSERT(0); /* To check if this really happens, and understand why... */
525                                        goto next;
526                                }
527                               
528                                peer->p_hdr.info.runtime.pir_firmrev = hdr->avp_value->u32;
529                                break;
530
531                        case AC_INBAND_SECURITY_ID: /* Inband-Security-Id */
532                                if (hdr->avp_value == NULL) {
533                                        /* This is a sanity check */
534                                        TRACE_DEBUG(NONE, "Ignored an AVP with unset value in CER/CEA");
535                                        fd_msg_dump_one(NONE, avp);
536                                        ASSERT(0); /* To check if this really happens, and understand why... */
537                                        goto next;
538                                }
539                                ASSERT( hdr->avp_value->u32 < 32 ); /* if false, we have to change the code bellow */
540                                peer->p_hdr.info.runtime.pir_isi |= (1 << hdr->avp_value->u32);
541                                break;
542                }
543
544next:                   
545                /* Go to next AVP */
546                CHECK_FCT( fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL) );
547        }
548       
549        return 0;
550}
551
552/* Create a CER message for sending */ 
553static int create_CER(struct fd_peer * peer, struct cnxctx * cnx, struct msg ** cer)
554{
555        int isi_tls = 0;
556        int isi_none = 0;
557       
558        /* Find CER dictionary object and create an instance */
559        CHECK_FCT( fd_msg_new ( fd_dict_cmd_CER, MSGFL_ALLOC_ETEID, cer ) );
560       
561        /* Do we need Inband-Security-Id AVPs ? */
562        if (!fd_cnx_getTLS(cnx)) {
563                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 */
564                isi_tls  = peer->p_hdr.info.config.pic_flags.sec & PI_SEC_TLS_OLD;
565        }
566       
567        /* Add the information about the local peer */
568        CHECK_FCT( add_CE_info(*cer, cnx, isi_tls, isi_none) );
569       
570        /* Done! */
571        return 0;
572}
573
574
575/* Continue with the initiator side */
576static int to_waitcea(struct fd_peer * peer, struct cnxctx * cnx)
577{
578        /* We sent a CER on the connection, set the event queue so that we receive the CEA */
579        CHECK_FCT( set_peer_cnx(peer, &cnx) );
580       
581        /* Change state and reset the timer */
582        CHECK_FCT( fd_psm_change_state(peer, STATE_WAITCEA) );
583        fd_psm_next_timeout(peer, 0, CEA_TIMEOUT);
584       
585        return 0;
586}
587
588/* Reject an incoming connection attempt */
589static void receiver_reject(struct cnxctx * recv_cnx, struct msg ** cer, char * rescode, char * errormsg)
590{
591        /* Create and send the CEA with appropriate error code */
592        CHECK_FCT_DO( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, cer, MSGFL_ANSW_ERROR ), goto destroy );
593        CHECK_FCT_DO( fd_msg_rescode_set(*cer, rescode, errormsg, NULL, 1 ), goto destroy );
594        CHECK_FCT_DO( fd_out_send(cer, recv_cnx, NULL, FD_CNX_ORDERED), goto destroy );
595       
596        /* And now destroy this connection */
597destroy:
598        fd_cnx_destroy(recv_cnx);
599        if (*cer) {
600                fd_msg_log(FD_MSG_LOG_DROPPED, *cer, "An error occurred while rejecting a CER.");
601                fd_msg_free(*cer);
602                *cer = NULL;
603        }
604}
605
606/* We have established a new connection to the remote peer, send CER and eventually process the election */
607int fd_p_ce_handle_newcnx(struct fd_peer * peer, struct cnxctx * initiator)
608{
609        struct msg * cer = NULL;
610       
611        /* Send CER on the new connection */
612        CHECK_FCT( create_CER(peer, initiator, &cer) );
613        CHECK_FCT( fd_out_send(&cer, initiator, peer, FD_CNX_ORDERED) );
614       
615        /* Are we doing an election ? */
616        fd_cpu_flush_cache();
617        if (peer->p_hdr.info.runtime.pir_state == STATE_WAITCNXACK_ELEC) {
618                if (election_result(peer)) {
619                        /* Close initiator connection */
620                        fd_cnx_destroy(initiator);
621
622                        /* Process with the receiver side */
623                        CHECK_FCT( fd_p_ce_process_receiver(peer) );
624
625                } else {
626
627                        /* Answer an ELECTION LOST to the receiver side */
628                        receiver_reject(peer->p_receiver, &peer->p_cer, "ELECTION_LOST", NULL);
629                        peer->p_receiver = NULL;
630                        CHECK_FCT( to_waitcea(peer, initiator) );
631                }
632        } else {
633                /* No election (yet) */
634                CHECK_FCT( to_waitcea(peer, initiator) );
635        }
636       
637        return 0;
638}
639
640/* We have received a Capabilities Exchange message on the peer connection */
641int fd_p_ce_msgrcv(struct msg ** msg, int req, struct fd_peer * peer)
642{
643        char * ec;
644        uint32_t rc = 0;
645        TRACE_ENTRY("%p %p", msg, peer);
646        CHECK_PARAMS( msg && *msg && CHECK_PEER(peer) );
647       
648        /* The only valid situation where we are called is in WAITCEA and we receive a CEA (we may have won an election) */
649       
650        /* Note : to implement Capabilities Update, we would need to change here */
651       
652        /* If it is a CER, just reply an error */
653        if (req) {
654                /* Create the error message */
655                CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, msg, MSGFL_ANSW_ERROR ) );
656               
657                /* Set the error code */
658                CHECK_FCT( fd_msg_rescode_set(*msg, "DIAMETER_COMMAND_UNSUPPORTED", "No CER allowed in current state", NULL, 1 ) );
659
660                /* msg now contains an answer message to send back */
661                CHECK_FCT_DO( fd_out_send(msg, NULL, peer, FD_CNX_ORDERED), /* In case of error the message has already been dumped */ );
662        }
663       
664        /* If the state is not WAITCEA, just discard the message */
665        fd_cpu_flush_cache();
666        if (req || (peer->p_hdr.info.runtime.pir_state != STATE_WAITCEA)) {
667                if (*msg) {
668                        fd_msg_log( FD_MSG_LOG_DROPPED, *msg, "Received CER/CEA while in '%s' state.\n", STATE_STR(peer->p_hdr.info.runtime.pir_state));
669                        CHECK_FCT_DO( fd_msg_free(*msg), /* continue */);
670                        *msg = NULL;
671                }
672               
673                return 0;
674        }
675       
676        /* Save info from the CEA into the peer */
677        CHECK_FCT_DO( save_remote_CE_info(*msg, peer, &ec, &rc), goto cleanup );
678       
679        /* Dispose of the message, we don't need it anymore */
680        CHECK_FCT_DO( fd_msg_free(*msg), /* continue */ );
681        *msg = NULL;
682       
683        /* Check the Result-Code */
684        switch (rc) {
685                case ER_DIAMETER_SUCCESS:
686                        /* No problem, we can continue */
687                        break;
688                       
689                case ER_DIAMETER_TOO_BUSY:
690                        /* Retry later */
691                        TRACE_DEBUG(INFO, "Peer %s replied a CEA with Result-Code AVP DIAMETER_TOO_BUSY, will retry later.", peer->p_hdr.info.pi_diamid);
692                        fd_psm_cleanup(peer, 0);
693                        fd_psm_next_timeout(peer, 0, 300);
694                        return 0;
695               
696                case ER_ELECTION_LOST:
697                        /* Ok, just wait for a little while for the CER to be processed on the other connection. */
698                        TRACE_DEBUG(FULL, "Peer %s replied a CEA with Result-Code AVP ELECTION_LOST, waiting for events.", peer->p_hdr.info.pi_diamid);
699                        return 0;
700               
701                default:
702                        /* In any other case, we abort all attempts to connect to this peer */
703                        TRACE_DEBUG(INFO, "Peer %s replied a CEA with Result-Code AVP %d, aborting connection attempts.", peer->p_hdr.info.pi_diamid, rc);
704                        return EINVAL;
705        }
706       
707        /* Handshake if needed, start clear otherwise */
708        if ( ! fd_cnx_getTLS(peer->p_cnxctx) ) {
709                int todo = peer->p_hdr.info.config.pic_flags.sec & peer->p_hdr.info.runtime.pir_isi ;
710                /* Special case: if the peer did not send a ISI AVP */
711                if (peer->p_hdr.info.runtime.pir_isi == 0)
712                        todo = peer->p_hdr.info.config.pic_flags.sec;
713               
714                if (todo == PI_SEC_NONE) {
715                        /* Ok for clear connection */
716                        TRACE_DEBUG(INFO, "No TLS protection negotiated with peer '%s'.", peer->p_hdr.info.pi_diamid);
717                        CHECK_FCT( fd_cnx_start_clear(peer->p_cnxctx, 1) );
718                } else {
719                       
720                        fd_psm_change_state(peer, STATE_OPEN_HANDSHAKE);
721                        CHECK_FCT_DO( fd_cnx_handshake(peer->p_cnxctx, GNUTLS_CLIENT, peer->p_hdr.info.config.pic_priority, NULL),
722                                {
723                                        /* Handshake failed ...  */
724                                        fd_log_debug("TLS Handshake failed with peer '%s', resetting the connection\n", peer->p_hdr.info.pi_diamid);
725                                        goto cleanup;
726                                } );
727
728                        /* Retrieve the credentials */
729                        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) );
730                }
731        }
732       
733        /* Move to next state */
734        if (peer->p_flags.pf_cnx_pb) {
735                fd_psm_change_state(peer, STATE_REOPEN );
736                CHECK_FCT( fd_p_dw_reopen(peer) );
737        } else {
738                fd_psm_change_state(peer, STATE_OPEN );
739                fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw);
740        }
741       
742        return 0;
743       
744cleanup:
745        fd_p_ce_clear_cnx(peer, NULL);
746
747        /* Send the error to the peer */
748        CHECK_FCT( fd_event_send(peer->p_events, FDEVP_CNX_ERROR, 0, NULL) );
749
750        return 0;
751}
752
753/* Handle the receiver side to go to OPEN state (any election is resolved) */
754int fd_p_ce_process_receiver(struct fd_peer * peer)
755{
756        char * ec = NULL;
757        struct msg * msg = NULL;
758        int isi = 0;
759        int fatal = 0;
760       
761        TRACE_ENTRY("%p", peer);
762       
763        CHECK_FCT( set_peer_cnx(peer, &peer->p_receiver) );
764        msg = peer->p_cer;
765        peer->p_cer = NULL;
766       
767        /* Parse the content of the received CER */
768        CHECK_FCT_DO( save_remote_CE_info(msg, peer, &ec, NULL), goto error_abort );
769       
770        /* Validate the peer if needed */
771        if (peer->p_flags.pf_responder) {
772                int res = fd_peer_validate( peer );
773                if (res < 0) {
774                        TRACE_DEBUG(INFO, "Rejected CER from peer '%s', validation failed (returning DIAMETER_UNKNOWN_PEER).\n", peer->p_hdr.info.pi_diamid);
775                        ec = "DIAMETER_UNKNOWN_PEER";
776                        goto error_abort;
777                }
778                CHECK_FCT( res );
779        }
780       
781        /* Check if we have common applications */
782        if ( fd_g_config->cnf_flags.no_fwd && (! peer->p_hdr.info.runtime.pir_relay) ) {
783                int got_common;
784                CHECK_FCT( fd_app_check_common( &fd_g_config->cnf_apps, &peer->p_hdr.info.runtime.pir_apps, &got_common) );
785                if (!got_common) {
786                        TRACE_DEBUG(INFO, "No common application with peer '%s', sending DIAMETER_NO_COMMON_APPLICATION", peer->p_hdr.info.pi_diamid);
787                        ec = "DIAMETER_NO_COMMON_APPLICATION";
788                        fatal = 1;
789                        goto error_abort;
790                }
791        }
792       
793        /* Do we agree on ISI ? */
794        if ( ! fd_cnx_getTLS(peer->p_cnxctx) ) {
795               
796                /* In case of responder, the validate callback must have set the config.pic_flags.sec value already */
797       
798                /* First case: we are not using old mechanism: ISI are deprecated, we ignore it. */
799                if ( ! (peer->p_hdr.info.config.pic_flags.sec & PI_SEC_TLS_OLD)) {
800                        /* Just check then that the peer configuration allows for IPsec protection */
801                        if (peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE) {
802                                isi = PI_SEC_NONE;
803                        } else {
804                                /* otherwise, we should have already been protected. Reject */
805                                TRACE_DEBUG(INFO, "Non TLS-protected CER/CEA exchanges are not allowed with this peer, rejecting.");
806                        }
807                } else {
808                        /* The old mechanism is allowed with this peer. Now, look into the ISI AVP values */
809                       
810                        /* In case no ISI was present anyway: */
811                        if (!peer->p_hdr.info.runtime.pir_isi) {
812                                TRACE_DEBUG(INFO, "Inband-Security-Id AVP is missing in received CER.");
813                                if (peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE) {
814                                        isi = PI_SEC_NONE;
815                                        TRACE_DEBUG(INFO, "IPsec protection allowed by configuration, allowing this mechanism to be used.");
816                                } else {
817                                        /* otherwise, we should have already been protected. Reject */
818                                        TRACE_DEBUG(INFO, "Rejecting the peer connection (please allow IPsec here or configure TLS in the remote peer).");
819                                }
820                        } else {
821                                /* OK, the remote peer did send the ISI AVP. */
822                                if ((peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE) && (peer->p_hdr.info.runtime.pir_isi & PI_SEC_NONE)) {
823                                        /* We have allowed IPsec */
824                                        isi = PI_SEC_NONE;
825                                } else if (peer->p_hdr.info.runtime.pir_isi & PI_SEC_TLS_OLD) {
826                                        /* We can agree on TLS */
827                                        isi = PI_SEC_TLS_OLD;
828                                } else {
829                                        TRACE_DEBUG(INFO, "Remote peer requested IPsec protection, but local configuration forbids it.");
830                                }
831                        }
832                }
833       
834                /* If we did not find an agreement */
835                if (!isi) {
836                        TRACE_DEBUG(INFO, "No common security mechanism with '%s', sending DIAMETER_NO_COMMON_SECURITY", peer->p_hdr.info.pi_diamid);
837                        ec = "DIAMETER_NO_COMMON_SECURITY";
838                        fatal = 1;
839                        goto error_abort;
840                }
841               
842                /* Do not send the ISI IPsec if we are using the new mechanism */
843                if ((isi == PI_SEC_NONE) && (! (peer->p_hdr.info.config.pic_flags.sec & PI_SEC_TLS_OLD)))
844                        isi = 0;
845        }
846       
847        /* Reply a CEA */
848        CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &msg, 0 ) );
849        CHECK_FCT( fd_msg_rescode_set(msg, "DIAMETER_SUCCESS", NULL, NULL, 0 ) );
850        CHECK_FCT( add_CE_info(msg, peer->p_cnxctx, isi & PI_SEC_TLS_OLD, isi & PI_SEC_NONE) );
851#ifdef USE_CEA_BROADCAST
852        CHECK_FCT( fd_out_send(&msg, peer->p_cnxctx, peer, (isi & PI_SEC_TLS_OLD) ? FD_CNX_ORDERED : FD_CNX_BROADCAST) ); /* Broadcast in order to avoid further messages sent over a different stream be delivered first... */
853#else /* USE_CEA_BROADCAST */
854        CHECK_FCT( fd_out_send(&msg, peer->p_cnxctx, peer, FD_CNX_ORDERED ) );
855#endif /* USE_CEA_BROADCAST */
856       
857        /* Handshake if needed */
858        if (isi & PI_SEC_TLS_OLD) {
859                fd_psm_change_state(peer, STATE_OPEN_HANDSHAKE);
860                CHECK_FCT_DO( fd_cnx_handshake(peer->p_cnxctx, GNUTLS_SERVER, peer->p_hdr.info.config.pic_priority, NULL),
861                        {
862                                /* Handshake failed ...  */
863                                fd_log_debug("TLS Handshake failed with peer '%s', resetting the connection\n", peer->p_hdr.info.pi_diamid);
864                                goto cleanup;
865                        } );
866               
867                /* Retrieve the credentials */
868                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) );
869               
870                /* Call second validation callback if needed */
871                if (peer->p_cb2) {
872                        TRACE_DEBUG(FULL, "Calling second validation callback for %s", peer->p_hdr.info.pi_diamid);
873                        CHECK_FCT_DO( (*peer->p_cb2)( &peer->p_hdr.info ),
874                                {
875                                        TRACE_DEBUG(INFO, "Validation callback rejected the peer %s after handshake", peer->p_hdr.info.pi_diamid);
876                                        CHECK_FCT( fd_psm_terminate( peer, "DO_NOT_WANT_TO_TALK_TO_YOU" ) );
877                                        return 0;
878                                }  );
879                }
880               
881        } else {
882                if ( ! fd_cnx_getTLS(peer->p_cnxctx) ) {
883                        TRACE_DEBUG(INFO, "No TLS protection negotiated with peer '%s'.", peer->p_hdr.info.pi_diamid);
884                        CHECK_FCT( fd_cnx_start_clear(peer->p_cnxctx, 1) );
885                }
886        }
887               
888        /* Move to OPEN or REOPEN state */
889        if (peer->p_flags.pf_cnx_pb) {
890                fd_psm_change_state(peer, STATE_REOPEN );
891                CHECK_FCT( fd_p_dw_reopen(peer) );
892        } else {
893                fd_psm_change_state(peer, STATE_OPEN );
894                fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw);
895        }
896       
897        return 0;
898
899error_abort:
900        if (ec) {
901                /* Create the error message */
902                CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &msg, MSGFL_ANSW_ERROR ) );
903
904                /* Set the error code */
905                CHECK_FCT( fd_msg_rescode_set(msg, ec, NULL, NULL, 1 ) );
906
907                /* msg now contains an answer message to send back */
908                CHECK_FCT_DO( fd_out_send(&msg, peer->p_cnxctx, peer, FD_CNX_ORDERED), /* In case of error the message has already been dumped */ );
909        }
910       
911cleanup:
912        if (msg) {
913                fd_msg_log(FD_MSG_LOG_DROPPED, msg, "An error occurred while processing a CER.");
914                fd_msg_free(msg);
915        }
916        fd_p_ce_clear_cnx(peer, NULL);
917
918        /* Send the error to the peer */
919        CHECK_FCT( fd_event_send(peer->p_events, fatal ? FDEVP_TERMINATE : FDEVP_CNX_ERROR, 0, NULL) );
920
921        return 0;
922}
923
924/* We have received a CER on a new connection for this peer */
925int fd_p_ce_handle_newCER(struct msg ** msg, struct fd_peer * peer, struct cnxctx ** cnx, int valid)
926{
927        fd_cpu_flush_cache();
928        switch (peer->p_hdr.info.runtime.pir_state) {
929                case STATE_CLOSED:
930                        peer->p_receiver = *cnx;
931                        *cnx = NULL;
932                        peer->p_cer = *msg;
933                        *msg = NULL;
934                        CHECK_FCT( fd_p_ce_process_receiver(peer) );
935                        break;
936
937                case STATE_WAITCNXACK:
938                        /* Save the parameters in the peer, move to STATE_WAITCNXACK_ELEC */
939                        peer->p_receiver = *cnx;
940                        *cnx = NULL;
941                        peer->p_cer = *msg;
942                        *msg = NULL;
943                        CHECK_FCT( fd_psm_change_state(peer, STATE_WAITCNXACK_ELEC) );
944                        break;
945                       
946                case STATE_WAITCEA:
947                        if (election_result(peer)) {
948                               
949                                /* Close initiator connection (was already set as principal) */
950                                fd_p_ce_clear_cnx(peer, NULL);
951                               
952                                /* and go on with the receiver side */
953                                peer->p_receiver = *cnx;
954                                *cnx = NULL;
955                                peer->p_cer = *msg;
956                                *msg = NULL;
957                                CHECK_FCT( fd_p_ce_process_receiver(peer) );
958
959                        } else {
960
961                                /* Answer an ELECTION LOST to the receiver side and continue */
962                                receiver_reject(*cnx, msg, "ELECTION_LOST", "Please answer my CER instead, you won the election.");
963                                *cnx = NULL;
964                        }
965                        break;
966
967                default:
968                        receiver_reject(*cnx, msg, "DIAMETER_UNABLE_TO_COMPLY", "Invalid state to receive a new connection attempt");
969                        *cnx = NULL;
970        }
971                               
972        return 0;
973}
Note: See TracBrowser for help on using the repository browser.