Mercurial > hg > waaad
view waaad/peer-dpr_dpa.c @ 401:860f41038ea2
Updated copyright information
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Tue, 02 Jun 2009 15:10:55 +0900 |
parents | 316bb3f38d04 |
children |
line wrap: on
line source
/********************************************************************************************************* * Software License Agreement (BSD License) * * Author: Sebastien Decugis <sdecugis@nict.go.jp> * * * * Copyright (c) 2009, WIDE Project and NICT * * All rights reserved. * * * * Redistribution and use of this software in source and binary forms, with or without modification, are * * permitted provided that the following conditions are met: * * * * * Redistributions of source code must retain the above * * copyright notice, this list of conditions and the * * following disclaimer. * * * * * Redistributions in binary form must reproduce the above * * copyright notice, this list of conditions and the * * following disclaimer in the documentation and/or other * * materials provided with the distribution. * * * * * Neither the name of the WIDE Project or NICT nor the * * names of its contributors may be used to endorse or * * promote products derived from this software without * * specific prior written permission of WIDE Project and * * NICT. * * * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *********************************************************************************************************/ /* Peers facility. * * DPR / DPA messages management * * See peer-api.h and peer.h for more information on the functions * */ #include "waaad-internal.h" #include "peer-internal.h" /* Dictionary objects for PSM */ static dict_object_t * dict_DPR = NULL; static dict_object_t * dict_DPA = NULL; int _peer_dpr_dpa_init(void) { CHECK_FCT( dict_search( DICT_COMMAND, CMD_BY_NAME, "Disconnect-Peer-Request", &dict_DPR, ENOENT) ); CHECK_FCT( dict_search( DICT_COMMAND, CMD_BY_NAME, "Disconnect-Peer-Answer", &dict_DPA, ENOENT) ); return 0; } int _peer_dpr_dpa_fini(void) { /* nothing special to do */ return 0; } /***********************************************************************/ /* Diameter Base Protocol: Disconnect-Peer messages */ /***********************************************************************/ /* Create a DPR message */ int _peer_dpr_create( _peer_t * peer, msg_t ** dpr, uint32_t cause ) { TRACE_ENTRY("%p %p %u", peer, dpr, cause); /* NULL is not allowed */ CHECK_PARAMS( peer && dpr && cause ); /* Create an empty DPR */ CHECK_FCT( msg_new( dict_DPR, 0, dpr ) ); /* Add standard Origin-Host, Origin-Realm and Origin-State-Id AVPs */ CHECK_FCT( msg_add_origin( *dpr, 1 ) ); /* Add the Disconnect-Cause AVP */ { dict_object_t * dict = NULL; msg_avp_t * avp = NULL; avp_value_t val; /* Find the model for this AVP */ CHECK_FCT( dict_search( DICT_AVP, AVP_BY_NAME, "Disconnect-Cause", &dict, ENOENT ) ); /* Create the AVP */ CHECK_FCT( msg_avp_new( dict, 0, &avp ) ); /* Set its value */ memset(&val, 0, sizeof(val)); val.u32 = cause; CHECK_FCT( msg_avp_setvalue( avp, &val ) ); /* Add it to the message */ CHECK_FCT( msg_avp_add( *dpr, MSG_BRW_LAST_CHILD, avp ) ); } /* Set the DPR header: end-to-end id ( hop-by-hop is set when sending ) */ { msg_data_t * dpr_data = NULL; CHECK_FCT( msg_data( *dpr, &dpr_data ) ); dpr_data->msg_eteid = msg_get_eteid(); } /* Make sure the DPR message is valid -- mostly for debug here... */ CHECK_FCT( msg_parse_rules( *dpr, NULL ) ); /* The DPR is now ready */ TRACE_DEBUG(FULL, "DPR Ready"); msg_dump_walk(FULL, *dpr); return 0; } /* Parse a received DPR */ int _peer_dpr_parse( msg_t * dpr, _peer_t * peer ) { msg_avp_t * avp = NULL; CHECK_PARAMS( VALIDATE_PEER( peer ) && dpr ); CHECK_FCT( msg_browse(dpr, MSG_BRW_FIRST_CHILD, &avp, NULL) ); /* Now loop on all AVPs -- we will break when last AVP was parsed */ while (avp) { msg_avp_data_t * avpdata; CHECK_FCT( msg_avp_data( avp, &avpdata ) ); if (avpdata->avp_flags & AVP_FLAG_VENDOR) { /* Ignore all vendor-specific AVPs in DPR ... because we don't support any currently */ TRACE_DEBUG(FULL, "Ignored a vendor AVP in DPR"); msg_dump_one(FULL, avp); goto next; } if (avpdata->avp_data == NULL) { /* Ignore if the data is not set -- this is more like a sanity check */ TRACE_DEBUG(FULL, "Ignored an AVP with unset value in DPR"); msg_dump_one(FULL, avp); ASSERT(0); /* To check if this really happens, and understand why... */ goto next; } switch (avpdata->avp_code) { case AC_ORIGIN_HOST: /* Origin-Host */ /* Verify that the advertized Origin-Host is conform to the peer name */ if (strncasecmp(peer->p_diamid, (char *)avpdata->avp_data->os.data, avpdata->avp_data->os.len)) { log_error("DPR Received from '%s' with invalid Origin-Host value.\n", peer->p_diamid); msg_dump_one(0, avp); return EBADMSG; } break; case AC_ORIGIN_REALM: /* Origin-Realm */ /* Verify that the advertized Origin-Realm is conform to the peer realm */ if (strncasecmp(peer->p_realm, (char *)avpdata->avp_data->os.data, avpdata->avp_data->os.len)) { log_error("DPR Received with invalid Origin-Realm value.\n"); msg_dump_one(0, avp); return EBADMSG; } break; case AC_ORIGIN_STATE_ID: /* Origin-State-Id */ /* Check if the remote peer has lost its state, in which case we must close the connection */ if ( peer->p_orstate != avpdata->avp_data->u32 ) { /* The easiest way here is to return an error, this should never happen anyway */ log_error("DPR received from '%s' with a new Origin-State-Id value.\n", peer->p_diamid); msg_dump_one(0, avp); return EBADMSG; } break; case AC_DISCONNECT_CAUSE: /* Disconnect-Cause */ switch (avpdata->avp_data->u32) { case ACV_DC_REBOOTING: /* REBOOTING */ /* we will just try reconnection afterwards, as if no DPR was received */ break; case ACV_DC_BUSY: /* BUSY */ case ACV_DC_NOT_FRIEND: /* DO_NOT_WANT_TO_TALK_TO_YOU */ /* We add the flag to the peer so that the PSM does not attempt reconnecting */ peer->p_flags |= PEERFL_DISABLE_AFTER_SHUTDOWN; break; default: /* unknown cause... ignore */ log_normal("Received DPR from '%s' with unkown cause (%u).\n", peer->p_diamid, avpdata->avp_data->u32); } break; default: /* Other AVP */ TRACE_DEBUG(FULL, "Ignored AVP in DPR"); msg_dump_one(FULL, avp); } next: /* Go to next AVP */ CHECK_FCT( msg_browse(avp, MSG_BRW_NEXT, &avp, NULL) ); } return 0; } /* Create an answer */ int _peer_dpa_create( _peer_t * peer, msg_t ** dpa, uint32_t eteid, uint32_t hbhid ) { TRACE_ENTRY("%p %p %u %u", peer, dpa, eteid, hbhid); /* NULL is not allowed */ CHECK_PARAMS( dpa ); /* Create an empty DPA */ CHECK_FCT( msg_new( dict_DPA, 0, dpa ) ); /* Note: the Result-Code AVP will be added later outside this function */ /* Add standard Origin-Host, Origin-Realm and Origin-State-Id AVPs */ CHECK_FCT( msg_add_origin( *dpa, 1 ) ); /* Set the DPA header: end-to-end id */ { msg_data_t * dpa_data = NULL; CHECK_FCT( msg_data( *dpa, &dpa_data ) ); dpa_data->msg_eteid = eteid; dpa_data->msg_hbhid = hbhid; } return 0; } /* Parse a received answer */ int _peer_dpa_parse( msg_t * dpa, _peer_t * peer ) { msg_avp_t * avp = NULL; uint32_t errorcode = 0; CHECK_PARAMS( VALIDATE_PEER( peer ) && dpa ); CHECK_FCT( msg_browse(dpa, MSG_BRW_FIRST_CHILD, &avp, NULL) ); /* Now loop on all AVPs -- we will break when last AVP was parsed */ while (avp) { msg_avp_data_t * avpdata; CHECK_FCT( msg_avp_data( avp, &avpdata ) ); if (avpdata->avp_flags & AVP_FLAG_VENDOR) { /* Ignore all vendor-specific AVPs ... because we don't support any currently */ TRACE_DEBUG(FULL, "Ignored a vendor AVP in DPA"); msg_dump_one(FULL, avp); goto next; } if (avpdata->avp_data == NULL) { /* Ignore if the data is not set -- this is more like a sanity check */ TRACE_DEBUG(FULL, "Ignored an AVP with unset value in DPA"); msg_dump_one(FULL, avp); ASSERT(0); /* To check if this really happens, and understand why... */ goto next; } switch (avpdata->avp_code) { case AC_ORIGIN_HOST: /* Origin-Host */ /* Check that the remote peer is what we expect */ if (strncasecmp(peer->p_diamid, (char *)avpdata->avp_data->os.data, avpdata->avp_data->os.len)) { log_error("The DPA received from peer '%s' contains invalid Origin-Host (bad IP?), resetting connection", peer->p_diamid); msg_dump_one(0, avp); return EBADMSG; } break; case AC_ORIGIN_REALM: /* Origin-Realm */ /* Verify that the advertized Origin-Realm is conform to the peer realm */ if (strncasecmp(peer->p_realm, (char *)avpdata->avp_data->os.data, avpdata->avp_data->os.len)) { log_error("DPA received with invalid Origin-Realm value.\n"); msg_dump_one(0, avp); return EBADMSG; } break; case AC_ORIGIN_STATE_ID: /* Origin-State-Id */ /* Check if the remote peer has lost its state, in which case we must close the connection */ if ( peer->p_orstate != avpdata->avp_data->u32 ) { /* The easiest way here is to return an error, this should never happen anyway */ log_error("DPA received from '%s' with a new Origin-State-Id value.\n", peer->p_diamid); msg_dump_one(0, avp); return EBADMSG; } break; case AC_RESULT_CODE: /* Result-Code */ errorcode = avpdata->avp_data->u32; break; case AC_ERROR_MESSAGE: /* Error-Message */ log_normal("The DPA received from peer '%s' contains an Error-Message AVP", peer->p_diamid); msg_dump_one(INFO, avp); break; default: /* Other AVP */ TRACE_DEBUG(FULL, "Ignored AVP in DPA"); msg_dump_one(FULL, avp); } next: /* Go to next AVP */ CHECK_FCT( msg_browse(avp, MSG_BRW_NEXT, &avp, NULL) ); } /* Ok, now check the error code */ if ( errorcode != ER_DIAMETER_SUCCESS ) { /* We do not allow another error code here */ log_error("Received DPA with Result-Code value %u from %s.\n", errorcode, peer->p_diamid); return EBADMSG; } return 0; }