1 /*
2  * Copyright (C) 2012 Smile Communications, jason.penton@smilecoms.com
3  * Copyright (C) 2012 Smile Communications, richard.good@smilecoms.com
4  *
5  * The initial version of this code was written by Dragos Vingarzan
6  * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
7  * Fruanhofer Institute. It was and still is maintained in a separate
8  * branch of the original SER. We are therefore migrating it to
9  * Kamailio/SR and look forward to maintaining it from here on out.
10  * 2011/2012 Smile Communications, Pty. Ltd.
11  * ported/maintained/improved by
12  * Jason Penton (jason(dot)penton(at)smilecoms.com and
13  * Richard Good (richard(dot)good(at)smilecoms.com) as part of an
14  * effort to add full IMS support to Kamailio/SR using a new and
15  * improved architecture
16  *
17  * NB: Alot of this code was originally part of OpenIMSCore,
18  * FhG Fokus.
19  * Copyright (C) 2004-2006 FhG Fokus
20  * Thanks for great work! This is an effort to
21  * break apart the various CSCF functions into logically separate
22  * components. We hope this will drive wider use. We also feel
23  * that in this way the architecture is more complete and thereby easier
24  * to manage in the Kamailio/SR environment
25  *
26  * This file is part of Kamailio, a free SIP server.
27  *
28  * Kamailio is free software; you can redistribute it and/or modify
29  * it under the terms of the GNU General Public License as published by
30  * the Free Software Foundation; either version 2 of the License, or
31  * (at your option) any later version
32  *
33  * Kamailio is distributed in the hope that it will be useful,
34  * but WITHOUT ANY WARRANTY; without even the implied warranty of
35  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36  * GNU General Public License for more details.
37  *
38  * You should have received a copy of the GNU General Public License
39  * along with this program; if not, write to the Free Software
40  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
41  *
42  */
43 
44 #include "diameter.h"
45 #include "diameter_api.h"
46 
47 
48 #include <stdlib.h>
49 #include <string.h>
50 #include <netinet/in.h>
51 
52 #include "utils.h"
53 #include "globals.h"
54 
55 #include "config.h"
56 #include "peermanager.h"
57 #include "diameter_epc_code_cmd.h"
58 
59 extern dp_config *config;	/**< Configuration for this diameter peer */
60 
61 
62 /**
63  * This function encodes a AAAMessage to its network representation (encoder).
64  *  From a AAAMessage structure, a buffer to be send is built.
65  * @param msg - the message to encode
66  * @returns 1 on success, -1 on error
67  * \note This function is taken from DISC http://developer.berlios.de/projects/disc/
68  */
AAABuildMsgBuffer(AAAMessage * msg)69 AAAReturnCode AAABuildMsgBuffer( AAAMessage *msg )
70 {
71 	unsigned char *p;
72 	AAA_AVP       *avp;
73 
74 	/* first let's comput the length of the buffer */
75 	msg->buf.len = AAA_MSG_HDR_SIZE; /* AAA message header size */
76 	/* count and add the avps */
77 	for(avp=msg->avpList.head;avp;avp=avp->next) {
78 		msg->buf.len += AVP_HDR_SIZE(avp->flags)+ to_32x_len( avp->data.len );
79 		//LM_DBG("AVP code: %d, data %.*s\n", avp->code, avp->data.len, avp->data.s);
80 	}
81 
82 	LM_DBG("AAABuildMsgBuffer(): len=%d\n",msg->buf.len);
83 	/* allocate some memory */
84 	msg->buf.s = (char*)shm_malloc( msg->buf.len );
85 	if (!msg->buf.s) {
86 		LM_ERR("AAABuildMsgBuffer: no more free memory!\n");
87 		goto error;
88 	}
89 	memset(msg->buf.s, 0, msg->buf.len);
90 
91 	/* fill in the buffer */
92 	p = (unsigned char*)msg->buf.s;
93 	/* DIAMETER HEADER */
94 	/* message length */
95 	((unsigned int*)p)[0] =htonl(msg->buf.len);
96 	/* Diameter Version */
97 	*p = 1;
98 	p += VER_SIZE + MESSAGE_LENGTH_SIZE;
99 	/* command code */
100 	((unsigned int*)p)[0] = htonl(msg->commandCode);
101 	/* flags */
102 	*p = (unsigned char)msg->flags;
103 	p += FLAGS_SIZE + COMMAND_CODE_SIZE;
104 	/* application-ID */
105 	((unsigned int*)p)[0] = htonl(msg->applicationId);
106 	p += APPLICATION_ID_SIZE;
107 	/* hop by hop id */
108 	((unsigned int*)p)[0] = htonl(msg->hopbyhopId);
109 	p += HOP_BY_HOP_IDENTIFIER_SIZE;
110 	/* end to end id */
111 	((unsigned int*)p)[0] = htonl(msg->endtoendId);
112 	p += END_TO_END_IDENTIFIER_SIZE;
113 
114 	/* AVPS */
115 	for(avp=msg->avpList.head;avp;avp=avp->next) {
116 		/* AVP HEADER */
117 		/* avp code */
118 		set_4bytes(p,avp->code);
119 		p +=4;
120 		/* flags */
121 		(*p++) = (unsigned char)avp->flags;
122 		/* avp length */
123 		set_3bytes(p, (AVP_HDR_SIZE(avp->flags)+avp->data.len) );
124 		p += 3;
125 		/* vendor id */
126 		if ((avp->flags&0x80)!=0) {
127 			set_4bytes(p,avp->vendorId);
128 			p +=4;
129 		}
130 		/* data */
131 		memcpy( p, avp->data.s, avp->data.len);
132 		p += to_32x_len( avp->data.len );
133 	}
134 
135 	if ((char*)p-msg->buf.s!=msg->buf.len) {
136 		LM_ERR("BUG: build_buf_from_msg: mismatch between len and buf!\n");
137 		shm_free( msg->buf.s );
138 		msg->buf.s = 0;
139 		msg->buf.len = 0;
140 		goto error;
141 	}
142 
143 	return 1;
144 error:
145 	return -1;
146 }
147 
148 
149 
150 
151 /**
152  *  Allocates a new AAAMessage.
153  * @param commandCode - the command code for this message
154  * @param applicationId - application id to be set
155  * @param sessionId - session id to be set
156  * @param request - if you want to create a response, put the request here. If you want a
157  * request, call with NULL
158  * @returns the AAAMessage* or NULL on error
159  * \note This function is taken from DISC http://developer.berlios.de/projects/disc/
160  */
AAANewMessage(AAACommandCode commandCode,AAAApplicationId applicationId,AAASession * session,AAAMessage * request)161 AAAMessage *AAANewMessage(
162 		AAACommandCode commandCode,
163 		AAAApplicationId applicationId,
164 		AAASession *session,
165 		AAAMessage *request)
166 {
167 	AAAMessage   *msg;
168 	AAA_AVP      *avp;
169 	AAA_AVP      *avp_t;
170 	str *sessionId=0;
171 #if 0
172 	unsigned int code;
173 #endif
174 	// str dest_host={"?",1};
175 	str dest_realm={"?",1};
176 
177 	msg = 0;
178 	if (!session||!session->id.s) {
179 		if (request){
180 			/* copy old session id from AVP */
181 			if (request->sessionId)
182 				sessionId = &(request->sessionId->data);
183 		}else{
184 			if (commandCode!=Code_DW)
185 				LM_DBG("AAANewMessage: param session received null and it's a request!!\n");
186 		}
187 	}else{
188 		sessionId = &(session->id);
189 	}
190 
191 	/* allocated a new AAAMessage structure and set it to 0 */
192 	msg = (AAAMessage*)shm_malloc(sizeof(AAAMessage));
193 	if (!msg) {
194 		LM_ERR("AAANewMessage: no more free memory!!\n");
195 		goto error;
196 	}
197 	memset(msg,0,sizeof(AAAMessage));
198 
199 	/* command code */
200 	msg->commandCode = commandCode;
201 	/* application ID */
202 	msg->applicationId = applicationId;
203 
204 	/*add session ID */
205 	if (sessionId){
206 		avp = AAACreateAVP( 263, 0, 0, sessionId->s, sessionId->len,
207 				AVP_DUPLICATE_DATA);
208 		if ( !avp || AAAAddAVPToMessage(msg,avp,0)!=AAA_ERR_SUCCESS) {
209 			LM_ERR("AAANewMessage: cannot create/add Session-Id avp\n");
210 			if (avp) AAAFreeAVP( &avp );
211 			goto error;
212 		}
213 		msg->sessionId = avp;
214 	}
215 
216 	/* add origin host AVP */
217 	/* changed by cristian to comply with rfc3588:
218 	 * 6.3.  Origin-Host AVP
219 	 *
220 	 *    The Origin-Host AVP (AVP Code 264) is of type
221 	 *    DiameterIdentity... */
222 	avp = AAACreateAVP( 264, 0, 0, config->fqdn.s, config->fqdn.len,
223 			AVP_DUPLICATE_DATA);
224 	if (!avp||AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) {
225 		LM_ERR("AAANewMessage: cannot create/add Origin-Host avp\n");
226 		if (avp) AAAFreeAVP( &avp );
227 		goto error;
228 	}
229 	msg->orig_host = avp;
230 	/* add origin realm AVP */
231 	avp = AAACreateAVP( 296, 0, 0, config->realm.s, config->realm.len,
232 			AVP_DUPLICATE_DATA);
233 	if (!avp||AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) {
234 		LM_ERR("AAANewMessage: cannot create/add Origin-Realm avp\n");
235 		if (avp) AAAFreeAVP( &avp );
236 		goto error;
237 	}
238 	msg->orig_realm = avp;
239 
240 	if (!request) {
241 		/* it's a new request -> set the flag */
242 		msg->flags = 0x80;
243 	} else {
244 		/* link the incoming peer to the answer */
245 		msg->in_peer = request->in_peer;
246 		/* set the P flag as in request */
247 		msg->flags |= request->flags&0x40;
248 		/**/
249 		msg->endtoendId = request->endtoendId;
250 		msg->hopbyhopId = request->hopbyhopId;
251 
252 
253 		//TODO: aon:move this information in the AAASession structure, do not add these fields for
254 
255 		if (msg->commandCode==Code_CE||msg->commandCode==Code_DP||msg->commandCode==Code_DW ||
256 				msg->commandCode==Diameter_CCR || msg->commandCode==Diameter_RAR){
257 			// Don't add Destination Host/Realm because some stacks are way to picky and will just refuse it
258 		}else{
259 
260 			/* Mirror the old originhost/realm to destinationhost/realm*/
261 			//avp = AAAFindMatchingAVP(request,0,AVP_Origin_Host,0,0);
262 			//if (avp) dest_host = avp->data;
263 			/* add destination host and destination realm */
264 			//avp = AAACreateAVP(AVP_Destination_Host,AAA_AVP_FLAG_MANDATORY,0,
265 			//	dest_host.s,dest_host.len,AVP_DUPLICATE_DATA);
266 			//if (!avp) {
267 			//		LM_ERR("ERR:AAANewMessage: Failed creating Destination Host avp\n");
268 			//		goto error;
269 			//	}
270 			//	if (AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) {
271 			//		LM_ERR("ERR:AAANewMessage: Failed adding Destination Host avp to message\n");
272 			//		AAAFreeAVP(&avp);
273 			//		goto error;
274 			//	}
275 
276 			avp = AAAFindMatchingAVP(request,0,AVP_Origin_Realm,0,0);
277 			if (avp) dest_realm = avp->data;
278 			avp = AAACreateAVP(AVP_Destination_Realm,AAA_AVP_FLAG_MANDATORY,0,
279 					dest_realm.s,dest_realm.len,AVP_DUPLICATE_DATA);
280 			if (!avp) {
281 				LM_ERR("ERR:AAANewMessage: Failed creating Destination Realm avp\n");
282 				goto error;
283 			}
284 			if (AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) {
285 				LM_ERR("ERR:AAANewMessage: Failed adding Destination Realm avp to message\n");
286 				AAAFreeAVP(&avp);
287 				goto error;
288 			}
289 		}
290 
291 		msg->res_code=0;
292 		/* mirror all the proxy-info avp in the same order */
293 		avp_t = request->avpList.head;
294 		while ( (avp_t=AAAFindMatchingAVP
295 					(request,avp_t,284,0,AAA_FORWARD_SEARCH))!=0 ) {
296 			if ( (avp=AAACloneAVP(avp_t,1))==0 || AAAAddAVPToMessage( msg, avp,
297 						msg->avpList.tail)!=AAA_ERR_SUCCESS )
298 				goto error;
299 		}
300 	}
301 
302 	return msg;
303 error:
304 	LM_ERR("AAANewMessage: failed to create a new AAA message!\n");
305 	AAAFreeMessage(&msg);
306 	return 0;
307 }
308 
309 /**
310  * Create a Diameter Request.
311  * @param app_id - application id to be set
312  * @param command_code - the command code for this message
313  * @param flags - flags to be set
314  * @param sessId - session id to be set
315  * @returns the AAAMessage* or NULL on error
316  */
AAACreateRequest(AAAApplicationId app_id,AAACommandCode command_code,AAAMsgFlag flags,AAASession * session)317 AAAMessage *AAACreateRequest(AAAApplicationId app_id,
318 		AAACommandCode command_code,
319 		AAAMsgFlag flags,
320 		AAASession *session)
321 {
322 	AAAMessage *msg;
323 	AAA_AVP      *avp;
324 
325 	msg = AAANewMessage(command_code,app_id,session,0);
326 	if (!msg) return 0;
327 	msg->hopbyhopId = next_hopbyhop();
328 	msg->endtoendId = next_endtoend();
329 	msg->flags |= flags;
330 
331 	if(session){
332 		/* add destination host and destination realm */
333 		/*if(session->dest_host.s){//TODO: check spec about removing this across the board (jason)
334 			avp = AAACreateAVP(AVP_Destination_Host,AAA_AVP_FLAG_MANDATORY,0,
335 			session->dest_host.s,session->dest_host.len,AVP_DUPLICATE_DATA);
336 			if (!avp) {
337 				LM_ERR("ERR:AAACreateRequest: Failed creating Destination Host avp\n");
338 				goto error;
339 			}
340 			if (AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) {
341 				LM_ERR("ERR:AAACreateRequest: Failed adding Destination Host avp to message\n");
342 				AAAFreeAVP(&avp);
343 				goto error;
344 			}
345 		}*/
346 
347 		if(session->dest_realm.s){
348 			avp = AAACreateAVP(AVP_Destination_Realm,AAA_AVP_FLAG_MANDATORY,0,
349 					session->dest_realm.s,session->dest_realm.len,AVP_DUPLICATE_DATA);
350 			if (!avp) {
351 				LM_ERR("ERR:AAACreateRequest: Failed creating Destination Realm avp\n");
352 				goto error;
353 			}
354 			if (AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) {
355 				LM_ERR("ERR:AAACreateRequest: Failed adding Destination Realm avp to message\n");
356 				AAAFreeAVP(&avp);
357 				goto error;
358 			}
359 		}
360 	}
361 
362 	return msg;
363 error:
364 	AAAFreeMessage(&msg);
365 	return NULL;
366 }
367 
368 /**
369  * Create a Diameter Response to a given Request.
370  * @param request - the request that this response is for
371  * @returns the AAAMessage* or NULL on error
372  */
AAACreateResponse(AAAMessage * request)373 AAAMessage *AAACreateResponse(AAAMessage *request)
374 {
375 	AAAMessage *msg;
376 	msg = AAANewMessage(request->commandCode,request->applicationId,0,request);
377 
378 	return msg;
379 }
380 
381 
382 /**
383  *  Frees a AVP List and all the members
384  * @param avpList - list to be freed
385  * @returns AAA_ERR_SUCCESS
386  */
AAAFreeAVPList(AAA_AVP_LIST * avpList)387 AAAReturnCode  AAAFreeAVPList(AAA_AVP_LIST *avpList)
388 {
389 	AAA_AVP *avp_t;
390 	AAA_AVP *avp;
391 	/* free the avp list */
392 	avp = avpList->head;
393 	while (avp) {
394 		avp_t = avp;
395 		avp = avp->next;
396 		/*free the avp*/
397 		AAAFreeAVP(&avp_t);
398 	}
399 	avpList->head = 0;
400 	avpList->tail = 0;
401 	return AAA_ERR_SUCCESS;
402 }
403 
404 /**
405  *  Frees completely a message allocated through AAANewMessage()
406  * @param msg - pointer to the pointer containing the message.
407  * @returns AAA_ERR_SUCCESS
408  */
AAAFreeMessage(AAAMessage ** msg)409 AAAReturnCode  AAAFreeMessage(AAAMessage **msg)
410 {
411 	LM_DBG("AAAFreeMessage: Freeing message (%p) %d\n",*msg,(*msg)->commandCode);
412 	/* param check */
413 	if (!msg || !(*msg))
414 		goto done;
415 
416 	/* free the avp list */
417 	AAAFreeAVPList(&((*msg)->avpList));
418 
419 	/* free the buffer (if any) */
420 	if ( (*msg)->buf.s )
421 		shm_free( (*msg)->buf.s );
422 
423 	/* free the AAA msg */
424 	shm_free(*msg);
425 	*msg = 0;
426 
427 done:
428 	return AAA_ERR_SUCCESS;
429 }
430 
431 /**
432  *  Sets the proper result_code into the Result-Code AVP; ths avp must already
433  * exists into the reply messge.
434  * @param message - the message to set the Result-Code to
435  * @param resultCode - code to set as result
436  * \note This function is taken from DISC http://developer.berlios.de/projects/disc/
437  */
AAASetMessageResultCode(AAAMessage * message,AAAResultCode resultCode)438 AAAReturnCode  AAASetMessageResultCode(
439 		AAAMessage *message,
440 		AAAResultCode resultCode)
441 {
442 	if ( !is_req(message) && message->res_code) {
443 		*((unsigned int*)(message->res_code->data.s)) = htonl(resultCode);
444 		return AAA_ERR_SUCCESS;
445 	}
446 	return AAA_ERR_FAILURE;
447 }
448 
449 
450 
451 /**
452  *  This function convert message from the network format to the AAAMessage structure (decoder).
453  * @param source - the source char buffer
454  * @param sourceLen - the length of the input buffer
455  * @param attach_buf - whether to attach the input buffer to the message
456  * @returns the AAAMessage* or NULL on error
457  * \note This function is taken from DISC http://developer.berlios.de/projects/disc/
458  */
AAATranslateMessage(unsigned char * source,unsigned int sourceLen,int attach_buf)459 AAAMessage* AAATranslateMessage( unsigned char* source, unsigned int sourceLen,
460 		int attach_buf)
461 {
462 	unsigned char *ptr;
463 	AAAMessage    *msg = 0;
464 	unsigned char version;
465 	unsigned int  msg_len;
466 	AAA_AVP       *avp;
467 	unsigned int  avp_code;
468 	unsigned char avp_flags;
469 	unsigned int  avp_len;
470 	unsigned int  avp_vendorID;
471 	unsigned int  avp_data_len;
472 
473 	/* check the params */
474 	if( !source || !sourceLen || sourceLen<AAA_MSG_HDR_SIZE) {
475 		LM_ERR("AAATranslateMessage: invalid buffered received!\n");
476 		goto error;
477 	}
478 
479 	/* inits */
480 	msg = 0;
481 	avp = 0;
482 	ptr = source;
483 
484 	/* alloc a new message structure */
485 	msg = (AAAMessage*)shm_malloc(sizeof(AAAMessage));
486 	if (!msg) {
487 		LM_ERR("AAATranslateMessage: no more free memory!!\n");
488 		goto error;
489 	}
490 	memset(msg,0,sizeof(AAAMessage));
491 
492 	/* get the version */
493 	version = (unsigned char)*ptr;
494 	ptr += VER_SIZE;
495 	if (version!=1) {
496 		LM_ERR("AAATranslateMessage: invalid version [%d]in "
497 				"AAA msg\n",version);
498 		goto error;
499 	}
500 
501 	/* message length */
502 	msg_len = get_3bytes( ptr );
503 	ptr += MESSAGE_LENGTH_SIZE;
504 	if (msg_len>sourceLen) {
505 		LM_ERR("AAATranslateMessage: AAA message len [%d] bigger then"
506 				" buffer len [%d]\n",msg_len,sourceLen);
507 		goto error;
508 	}
509 
510 	/* command flags */
511 	msg->flags = *ptr;
512 	ptr += FLAGS_SIZE;
513 
514 	/* command code */
515 	msg->commandCode = get_3bytes( ptr );
516 	ptr += COMMAND_CODE_SIZE;
517 
518 	/* application-Id */
519 	msg->applicationId = get_4bytes( ptr );
520 	ptr += APPLICATION_ID_SIZE;
521 
522 	/* Hop-by-Hop-Id */
523 	msg->hopbyhopId = ntohl(*((unsigned int*)ptr));
524 	ptr += HOP_BY_HOP_IDENTIFIER_SIZE;
525 
526 	/* End-to-End-Id */
527 	msg->endtoendId = ntohl(*((unsigned int*)ptr));
528 	ptr += END_TO_END_IDENTIFIER_SIZE;
529 
530 	/* start decoding the AVPS */
531 	while (ptr < source+msg_len) {
532 		if (ptr+AVP_HDR_SIZE(0x80)>source+msg_len){
533 			LM_ERR("AAATranslateMessage: source buffer to short!! "
534 					"Cannot read the whole AVP header!\n");
535 			goto error;
536 		}
537 		/* avp code */
538 		avp_code = get_4bytes( ptr );
539 		ptr += AVP_CODE_SIZE;
540 		/* avp flags */
541 		avp_flags = (unsigned char)*ptr;
542 		ptr += AVP_FLAGS_SIZE;
543 		/* avp length */
544 		avp_len = get_3bytes( ptr );
545 		ptr += AVP_LENGTH_SIZE;
546 		if (avp_len<1) {
547 			LM_ERR("AAATranslateMessage: invalid AVP len [%d]\n",
548 					avp_len);
549 			goto error;
550 		}
551 		/* avp vendor-ID */
552 		avp_vendorID = 0;
553 		if (avp_flags&AAA_AVP_FLAG_VENDOR_SPECIFIC) {
554 			avp_vendorID = get_4bytes( ptr );
555 			ptr += AVP_VENDOR_ID_SIZE;
556 		}
557 		/* data length */
558 		avp_data_len = avp_len-AVP_HDR_SIZE(avp_flags);
559 		/*check the data length */
560 		if ( source+msg_len<ptr+avp_data_len) {
561 			LM_ERR("AAATranslateMessage: source buffer to short!! "
562 					"Cannot read a whole data for AVP!\n");
563 			goto error;
564 		}
565 
566 		/* create the AVP */
567 		avp = AAACreateAVP( avp_code, avp_flags, avp_vendorID, (char*) ptr,
568 				avp_data_len, AVP_DONT_FREE_DATA);
569 		if (!avp)
570 			goto error;
571 
572 		/* link the avp into aaa message to the end */
573 		AAAAddAVPToMessage( msg, avp, msg->avpList.tail);
574 
575 		ptr += to_32x_len( avp_data_len );
576 	}
577 
578 	/* link the buffer to the message */
579 	if (attach_buf) {
580 		msg->buf.s = (char*) source;
581 		msg->buf.len = msg_len;
582 	}
583 
584 	msg->sessionId = AAAFindMatchingAVP(msg,0,AVP_Session_Id,0,0);
585 
586 	//AAAPrintMessage( msg );
587 	return  msg;
588 error:
589 	LM_ERR("AAATranslateMessage: message conversion dropped!!\n");
590 	AAAFreeMessage(&msg);
591 	return 0;
592 }
593 
594 
595 
596 /**
597  *  print as debug all info contained by an aaa message + AVPs
598  * @param msg - the AAAMessage to print
599  * \note This function is taken from DISC http://developer.berlios.de/projects/disc/
600  */
AAAPrintMessage(AAAMessage * msg)601 void AAAPrintMessage( AAAMessage *msg)
602 {
603 	char    buf[1024];
604 	AAA_AVP *avp;
605 
606 	/* print msg info */
607 	LM_DBG("AAA_MESSAGE - %p\n",msg);
608 	LM_DBG("\tCode = %u\n",msg->commandCode);
609 	LM_DBG("\tFlags = %x\n",msg->flags);
610 
611 	/*print the AVPs */
612 	avp = msg->avpList.head;
613 	while (avp) {
614 		AAAConvertAVPToString(avp,buf,1024);
615 		LM_DBG("\n%s\n",buf);
616 		avp=avp->next;
617 	}
618 }
619 
620 
621 
622