You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sems/apps/diameter_client/lib_dbase/diameter_msg.c

403 lines
10 KiB

/*
* 2003-04-07 created by bogdan
*
* Copyright (C) 2002-2003 FhG Fokus
* Copyright (C) 2007-2009 IPTEGO GmbH
*
* This file is part of disc, a free diameter server/client.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// define EXTRA_DEBUG
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include "mem.h"
#include "log.h"
#include "diameter_msg.h"
#include "avp.h"
#define get_3bytes(_b) \
((((unsigned int)(_b)[0])<<16)|(((unsigned int)(_b)[1])<<8)| \
(((unsigned int)(_b)[2])))
#define get_4bytes(_b) \
((((unsigned int)(_b)[0])<<24)|(((unsigned int)(_b)[1])<<16)| \
(((unsigned int)(_b)[2])<<8)|(((unsigned int)(_b)[3])))
#define set_3bytes(_b,_v) \
{(_b)[0]=((_v)&0x00ff0000)>>16;(_b)[1]=((_v)&0x0000ff00)>>8; \
(_b)[2]=((_v)&0x000000ff);}
#define set_4bytes(_b,_v) \
{(_b)[0]=((_v)&0xff000000)>>24;(_b)[1]=((_v)&0x00ff0000)>>16; \
(_b)[2]=((_v)&0x0000ff00)>>8;(_b)[3]=((_v)&0x000000ff);}
int AAAAVPBuildBuffer(AAA_AVP *avp, unsigned char *dest) {
unsigned char* p = dest;
if (!avp || !dest) {
ERROR("trying to build msg buffer from/to NULL avp");
return 0;
}
/* AVP HEADER */
/* avp code */
set_4bytes(p,avp->code);
p +=4;
/* flags */
(*p++) = (unsigned char)avp->flags;
/* avp length */
set_3bytes(p, (AVP_HDR_SIZE(avp->flags)+avp->data.len) );
p += 3;
/* vendor id */
if ((avp->flags&0x80)!=0) {
set_4bytes(p,avp->vendorId);
p +=4;
}
/* data */
memcpy( p, avp->data.s, avp->data.len);
p += to_32x_len( avp->data.len );
return p-dest;
}
/* from a AAAMessage structure, a buffer to be send is build
*/
AAAReturnCode AAABuildMsgBuffer( AAAMessage *msg )
{
unsigned char *p;
AAA_AVP *avp;
AAA_AVP *mem; // group member
/* first let's compute the length of the buffer */
msg->buf.len = AAA_MSG_HDR_SIZE; /* AAA message header size */
/* count and add the avps */
for(avp=msg->avpList.head;avp;avp=avp->next) {
msg->buf.len += AVP_HDR_SIZE(avp->flags)+ to_32x_len( avp->data.len );
}
// DBG("xxxx len=%d\n",msg->buf.len);
/* allocate some memory */
msg->buf.s = (char*)ad_malloc( msg->buf.len );
if (!msg->buf.s) {
ERROR("ERROR:AAABuildMsgBuffer: no more free memory!\n");
goto error;
}
memset(msg->buf.s, 0, msg->buf.len);
/* fill in the buffer */
p = (unsigned char*)msg->buf.s;
/* DIAMETER HEADER */
/* message length */
((unsigned int*)p)[0] =htonl(msg->buf.len);
/* Diameter Version */
*p = 1;
p += VER_SIZE + MESSAGE_LENGTH_SIZE;
/* command code */
((unsigned int*)p)[0] = htonl(msg->commandCode);
/* flags */
*p = (unsigned char)msg->flags;
p += FLAGS_SIZE + COMMAND_CODE_SIZE;
/* application-ID */
((unsigned int*)p)[0] = htonl(msg->applicationId);
p += APPLICATION_ID_SIZE;
/* hop by hop id */
((unsigned int*)p)[0] = msg->hopbyhopId;
p += HOP_BY_HOP_IDENTIFIER_SIZE;
/* end to end id */
((unsigned int*)p)[0] = msg->endtoendId;
p += END_TO_END_IDENTIFIER_SIZE;
/* AVPS */
for(avp=msg->avpList.head;avp;avp=avp->next) {
/* AVP HEADER */
/* avp code */
set_4bytes(p,avp->code);
p +=4;
/* flags */
(*p++) = (unsigned char)avp->flags;
/* avp length */
set_3bytes(p, (AVP_HDR_SIZE(avp->flags)+avp->data.len) );
p += 3;
/* vendor id */
if ((avp->flags&0x80)!=0) {
set_4bytes(p,avp->vendorId);
p +=4;
}
/* data */
if (!avp->groupedHead) {
memcpy( p, avp->data.s, avp->data.len);
p += to_32x_len( avp->data.len );
} else {
// group members
for(mem=avp->groupedHead;mem;mem=mem->next)
p+=AAAAVPBuildBuffer(mem, p);
}
}
if ((char*)p-msg->buf.s!=msg->buf.len) {
ERROR("BUG: build_buf_from_msg: mismatch between len and buf!\n");
ad_free( msg->buf.s );
msg->buf.s = 0;
msg->buf.len = 0;
goto error;
}
// DBG("Message: %.*s\n", msg->buf.len, msg->buf.s);
return AAA_ERR_SUCCESS;
error:
return -1;
}
/* frees a message allocated through AAANewMessage()
*/
AAAReturnCode AAAFreeMessage(AAAMessage **msg)
{
AAA_AVP *avp_t;
AAA_AVP *avp;
/* param check */
if (!msg || !(*msg))
goto done;
/* free the avp list */
avp = (*msg)->avpList.head;
while (avp) {
avp_t = avp;
avp = avp->next;
/*free the avp*/
AAAFreeAVP(&avp_t);
}
/* free the buffer (if any) */
if ( (*msg)->buf.s )
ad_free( (*msg)->buf.s );
/* free the AAA msg */
ad_free(*msg);
msg = 0;
done:
return AAA_ERR_SUCCESS;
}
/* Sets the proper result_code into the Result-Code AVP; thus avp must already
* exists into the reply message */
AAAReturnCode AAASetMessageResultCode(
AAAMessage *message,
AAAResultCode resultCode)
{
if ( !is_req(message) && message->res_code) {
*((unsigned int*)(message->res_code->data.s)) = htonl(resultCode);
return AAA_ERR_SUCCESS;
}
return AAA_ERR_FAILURE;
}
/* This function convert message to message structure */
AAAMessage* AAATranslateMessage( unsigned char* source, unsigned int sourceLen,
int attach_buf)
{
unsigned char *ptr;
AAAMessage *msg;
unsigned char version;
unsigned int msg_len;
AAA_AVP *avp;
unsigned int avp_code;
unsigned char avp_flags;
unsigned int avp_len;
unsigned int avp_vendorID;
unsigned int avp_data_len;
/* check the params */
if( !source || !sourceLen || sourceLen<AAA_MSG_HDR_SIZE) {
ERROR("ERROR:AAATranslateMessage: could not decipher "
"received message - wrong size (%d)!\n", sourceLen);
goto error;
}
/* inits */
msg = 0;
avp = 0;
ptr = source;
/* alloc a new message structure */
msg = (AAAMessage*)ad_malloc(sizeof(AAAMessage));
if (!msg) {
ERROR("ERROR:AAATranslateMessage: no more free memory!!\n");
goto error;
}
memset(msg,0,sizeof(AAAMessage));
/* get the version */
version = (unsigned char)*ptr;
ptr += VER_SIZE;
if (version!=1) {
ERROR("ERROR:AAATranslateMessage: invalid version [%d]in "
"AAA msg\n",version);
goto error;
}
/* message length */
msg_len = get_3bytes( ptr );
ptr += MESSAGE_LENGTH_SIZE;
if (msg_len>sourceLen) {
ERROR("ERROR:AAATranslateMessage: AAA message len [%d] bigger then"
" buffer len [%d]\n",msg_len,sourceLen);
goto error;
}
/* command flags */
msg->flags = *ptr;
ptr += FLAGS_SIZE;
/* command code */
msg->commandCode = get_3bytes( ptr );
ptr += COMMAND_CODE_SIZE;
/* application-Id */
msg->applicationId = get_4bytes( ptr );
ptr += APPLICATION_ID_SIZE;
/* Hop-by-Hop-Id */
msg->hopbyhopId = *((unsigned int*)ptr);
ptr += HOP_BY_HOP_IDENTIFIER_SIZE;
/* End-to-End-Id */
msg->endtoendId = *((unsigned int*)ptr);
ptr += END_TO_END_IDENTIFIER_SIZE;
/* start decoding the AVPS */
while (ptr < source+msg_len) {
if (ptr+AVP_HDR_SIZE(0x80)>source+msg_len){
ERROR("ERROR:AAATranslateMessage: source buffer to short!! "
"Cannot read the whole AVP header!\n");
goto error;
}
/* avp code */
avp_code = get_4bytes( ptr );
ptr += AVP_CODE_SIZE;
/* avp flags */
avp_flags = (unsigned char)*ptr;
ptr += AVP_FLAGS_SIZE;
/* avp length */
avp_len = get_3bytes( ptr );
ptr += AVP_LENGTH_SIZE;
if (avp_len<1) {
ERROR("ERROR:AAATranslateMessage: invalid AVP len [%d]\n",
avp_len);
goto error;
}
/* avp vendor-ID */
avp_vendorID = 0;
if (avp_flags&AAA_AVP_FLAG_VENDOR_SPECIFIC) {
avp_vendorID = get_4bytes( ptr );
ptr += AVP_VENDOR_ID_SIZE;
}
/* data length */
avp_data_len = avp_len-AVP_HDR_SIZE(avp_flags);
/*check the data length */
if ( source+msg_len<ptr+avp_data_len) {
ERROR("ERROR:AAATranslateMessage: source buffer to short!! "
"Cannot read a whole data for AVP!\n");
goto error;
}
/* create the AVP */
avp = AAACreateAVP( avp_code, avp_flags, avp_vendorID, (char*)ptr,
avp_data_len, AVP_DONT_FREE_DATA);
if (!avp)
goto error;
/* link the avp into aaa message to the end */
AAAAddAVPToMessage( msg, avp, msg->avpList.tail);
ptr += to_32x_len( avp_data_len );
}
/* link the buffer to the message */
if (attach_buf) {
msg->buf.s = (char*)source;
msg->buf.len = msg_len;
}
//AAAPrintMessage( msg );
return msg;
error:
ERROR("ERROR:AAATranslateMessage: message conversion droped!!\n");
AAAFreeMessage(&msg);
return 0;
}
/* create a new minimal AAA message */
AAAMessage* AAAInMessage(AAACommandCode commandCode, AAAApplicationId appId)
{
AAAMessage *msg;
/* we allocate a new AAAMessage structure and set it to 0 */
msg = (AAAMessage*)ad_malloc(sizeof(AAAMessage));
if (!msg)
{
ERROR("diameter_authorize(): no more free memory!\n");
return NULL;
}
memset(msg, 0, sizeof(AAAMessage));
/* command code */
msg->commandCode = commandCode;
/* application ID */
msg->applicationId = appId;
/* it's a new request -> set the flag */
msg->flags = 0x80;
return msg;
}
AAAMessage* AAAMessageSetReply(AAAMessage* msg) {
msg->flags &= (!0x80);
return msg;
}
/* print as debug all info contained by an aaa message + AVPs
*/
void AAAPrintMessage( AAAMessage *msg)
{
char buf[1024];
AAA_AVP *avp;
/* print msg info */
DBG("DEBUG: AAA_MESSAGE - %p\n",msg);
DBG("\tCode = %u\n",msg->commandCode);
DBG("\tFlags = %x\n",msg->flags);
/*print the AVPs */
avp = msg->avpList.head;
while (avp) {
AAAConvertAVPToString(avp,buf,1024);
DBG("\n%s\n",buf);
avp=avp->next;
}
}