#include "./include/radius_pub.h"
#include "./include/radius_inc.h"

static unsigned char USER_PASSWORD_PADDING[16] = 
{
	0x00,	0x00, 0x00,	0x00, 0x00,	0x00, 0x00,	0x00,
	0x00,	0x00, 0x00,	0x00, 0x00,	0x00, 0x00,	0x00
};

RADIUS_PID *radius_get_pid_ptr(int pid)
{
	if ((pid < 0) || (pid >= RADIUS_MAX_NUM_OF_PID))
		return NULL;

	return &radius_pid[pid];
}

int radius_init_pid(int pid)
{
	RADIUS_PID		*pid_pt;

	if ((pid_pt = radius_get_pid_ptr(pid)) == NULL)
		return -1;

	memset(pid_pt, 0, sizeof(RADIUS_PID));

	return 0;
}

int radius_init_udp_socket(struct sockaddr_in saddr, int multicast)
{
	int     sock;
	long    sockBuf = 40*1024; 
	int     on = 1, timeout = 20;

	sock = socket(AF_INET, SOCK_DGRAM, 0);

	if (sock < 0)
	{    
		fprintf(stderr, "Socket() failed\n");
		return -1;
	}

	if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &sockBuf, sizeof(sockBuf)) != 0)
	{ 
		fprintf(stderr, "RADIUS set socket buffer failed\n");
		close(sock);
		return -1;
	}

	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on,sizeof(on)) != 0)
	{
		fprintf(stderr, "RADIUS set addr reusable failed\n");
		close(sock);
		return -1;
	}

	if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &timeout, sizeof(timeout)) != 0)
	{
		fprintf(stderr, "RADIUS set keepalive failed\n");
		close(sock);
		return -1;
	}

	if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0)
	{
		fprintf(stderr, "RADIUS set nonblock failed\n");
		close(sock);
		return -1;
	}

	if (bind(sock, (struct sockaddr *) &saddr, sizeof(struct sockaddr)) < 0)
	{
		fprintf(stderr, "RADIUS binding failed, port: %d\n", htons(saddr.sin_port));
		close(sock);
		return -1;
	}

	return sock;
}


int radius_init_socket(void)
{
	WORD	access_port = RADIUS_ACCESS_PORT;
	WORD	account_port = RADIUS_ACCOUNTING_PORT;
	WORD	disconnect_port = RADIUS_DISCONNECT_PORT;
	struct sockaddr_in		sinAddr;

	memset(&sinAddr, 0, sizeof(struct sockaddr));
	sinAddr.sin_family = AF_INET;
	sinAddr.sin_port = htons(access_port);
	sinAddr.sin_addr.s_addr = GetLocalIP();
	memset(&(sinAddr.sin_zero), 0, 8);
    
	radius_udp_access_socket_fd = radius_init_udp_socket(sinAddr, 0);

	if (radius_udp_access_socket_fd < 0)
	{
		printf("RADIUS get ACCESS UDP Socket(%d) failed\n", access_port);
		return -1;
	}

	memset(&sinAddr, 0, sizeof(struct sockaddr));
	sinAddr.sin_family = AF_INET;
	sinAddr.sin_port = htons(account_port);
	sinAddr.sin_addr.s_addr = GetLocalIP();
	memset(&(sinAddr.sin_zero), 0, 8);
    
	radius_udp_account_socket_fd = radius_init_udp_socket(sinAddr, 0);

	if (radius_udp_account_socket_fd < 0)
	{
		printf("RADIUS get ACCOUNT UDP Socket(%d) failed\n", account_port);
		return -1;
	}

	memset(&sinAddr, 0, sizeof(struct sockaddr));
	sinAddr.sin_family = AF_INET;
	sinAddr.sin_port = htons(disconnect_port);
	sinAddr.sin_addr.s_addr = GetLocalIP();
	memset(&(sinAddr.sin_zero), 0, 8);
    
	radius_udp_disconnect_socket_fd = radius_init_udp_socket(sinAddr, 0);

	if (radius_udp_disconnect_socket_fd < 0)
	{
		printf("RADIUS get DISCONNECT UDP Socket(%d) failed\n", disconnect_port);
		return -1;
	}

	return 0;
}

int radius_get_sock_fd_according_msg_type(BYTE msg_type)
{
	switch (msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
	case RADIUS_MSG_TYPE_ACCESS_REJECT:
	case RADIUS_MSG_TYPE_ACCESS_CHALLENGE:
		return radius_udp_access_socket_fd;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
	case RADIUS_MSG_TYPE_ACCOUNTING_RESPONSE:
		return radius_udp_account_socket_fd;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
	case RADIUS_MSG_TYPE_DISCONNECT_ACK:
	case RADIUS_MSG_TYPE_DISCONNECT_NAK:
		return radius_udp_disconnect_socket_fd;
	default:
		return -1;
	}
}

int radius_set_udp_dest_addr(struct sockaddr_in *dst_addr, RADIUS_ADDR *addr)
{
	if ((addr->addr.ipV4 == 0) || (addr->port == 0))
	{
		radius_log_err("%s: ip=0x%X, port=%d\r\n", __FUNCTION__, addr->addr.ipV4, addr->port);
		return -1;
	}

	memset(dst_addr, 0, sizeof(struct sockaddr));

	dst_addr->sin_family = AF_INET;

	dst_addr->sin_port = htons(addr->port);

	dst_addr->sin_addr.s_addr = addr->addr.ipV4;

	memset(&(dst_addr->sin_zero), 0, 8);
    
	return 0;
}


char radius_hex_to_ch(char uHex)
{
	return ((uHex) + (((uHex) > 9)? 'A'-10 : '0'));
}

char *radius_get_msg_str(BYTE msg_type)
{
	switch (msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		sprintf(radius_msg_type_str, "ACCESS REQUEST");
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		sprintf(radius_msg_type_str, "ACCESS ACCEPT");
		break;
	case RADIUS_MSG_TYPE_ACCESS_REJECT:
		sprintf(radius_msg_type_str, "ACCESS REJECT");
		break;
	case RADIUS_MSG_TYPE_ACCESS_CHALLENGE:
		sprintf(radius_msg_type_str, "ACCESS CHALLENGE");
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		sprintf(radius_msg_type_str, "ACCOUNTING REQUEST");
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_RESPONSE:
		sprintf(radius_msg_type_str, "ACCOUNTING RESPONSE");
		break;
	case RADIUS_MSG_TYPE_STATUS_SERVER:
		sprintf(radius_msg_type_str, "STATUS SERVER");
		break;
	case RADIUS_MSG_TYPE_STATUS_CLIENT:
		sprintf(radius_msg_type_str, "STATUS CLIENT");
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		sprintf(radius_msg_type_str, "DISCONNECT REQUEST");
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_ACK:
		sprintf(radius_msg_type_str, "DISCONNECT ACK");
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_NAK:
		sprintf(radius_msg_type_str, "DISCONNECT NAK");
		break;
	case RADIUS_MSG_TYPE_COA_REQUEST:
		sprintf(radius_msg_type_str, "COA REQUEST");
		break;
	case RADIUS_MSG_TYPE_COA_ACK:
		sprintf(radius_msg_type_str, "COA ACK");
		break;
	case RADIUS_MSG_TYPE_COA_NAK:
		sprintf(radius_msg_type_str, "COA NAK");
		break;
	default:
		sprintf(radius_msg_type_str, "Unknown msg type=%d", msg_type);
		break;
	}

	return radius_msg_type_str;
}

int radius_msg_to_fmt(const BYTE *bcd, int bcd_len, char *str, int str_buff_size)
{
	register  int	i, len = 0;
	int			str_len;

	str_len = (bcd_len / 16) * 49;

	if( (bcd_len % 16) > 8)
	{
		str_len +=8*3 +1;  	
	} 

	str_len += (bcd_len % 8) * 3 +1 + 2 ; //add "\r\n" at end

	if (str_len >= str_buff_size )
	{
		radius_log_err("%s:sprint bcd string buffer flow\r\n", __FUNCTION__);
		return -1;
	}

	for (i = 0; i <= bcd_len-1; i++)
	{
		str[len++] = radius_hex_to_ch((bcd[i] & 0xF0) >> 4  );
		str[len++] = radius_hex_to_ch(bcd[i] & 0x0F);
		str[len++] = ' ';

		if ( 0 == ( (i+1) % 16 )  && i)
		{
			str[len++] = '\n';
		}
		else if ( 0 == ( (i+1) % 8 ) )
		{
			str[len++] = ' ';
		}
	}

	if ( 0 != ( len % 49 ) )
	{
		str[len++] = ' ';
	}

	str[len++] = '\r';
	str[len++] = '\n';
	str[len++] = '\0';

	return len;
}

RADIUS_NAS_INFO *radius_get_nas_info_ptr(int id)
{
	if ((id < 0) || (id >= RADIUS_MAX_NUM_OF_NAS))
		return NULL;

	return &radius_nas_info[id];
}

int radius_accord_ip_search_nas_info(DWORD nas_ip)
{
	int					i;
	RADIUS_NAS_INFO	*nas_info_ptr;

	for (i = 0; i < RADIUS_MAX_NUM_OF_NAS; i++)
	{
		nas_info_ptr = radius_get_nas_info_ptr(i);

		if ((nas_info_ptr->flag != 1) || (nas_info_ptr->nas_ip != nas_ip))
			continue;

		return i;
	}

	return -1;
}

int radius_get_pid()
{
	int				i;
	int				pid = radius_pid_select;
	RADIUS_PID		*pid_ptr;

	if (pid >= RADIUS_MAX_NUM_OF_PID)
	{
		pid = 0;
	}

	for (i = 0; i < RADIUS_MAX_NUM_OF_PID; i++)
	{
		pid_ptr = radius_get_pid_ptr(pid);

		if (pid_ptr->flag == 1)
		{
			pid = (pid + 1) % RADIUS_MAX_NUM_OF_PID;

			continue;
		}

		radius_init_pid(pid);

		pid_ptr->flag = 1;

		radius_pid_select = (pid + 1) % RADIUS_MAX_NUM_OF_PID;

		return pid;
	}

	return -1;
}

int radius_match_response_pid(BYTE msg_type, BYTE identifier, BYTE *authenticator)
{
	int				i;
	RADIUS_PID		*pid_ptr;

	for (i = 0; i < RADIUS_MAX_NUM_OF_PID; i++)
	{
		pid_ptr = radius_get_pid_ptr(i);

		if ((pid_ptr->flag != 1) || (pid_ptr->type != RADIUS_PID_TYPE_IND))
		{
			continue;
		}

		if ((pid_ptr->identifier != identifier) || (pid_ptr->trans_req_msg_type != msg_type)  ||  (memcmp(pid_ptr->authenticator, authenticator, RADIUS_MAX_LEN_OF_AUTH) != 0))
		{
			continue;
		}

		pid_ptr->rv_msg_flag = msg_type;

		radius_p_fsm(i);

		return i;
	}

	return -1;
}

int radius_calculate_authenticator(BYTE *auth, const BYTE *msg, int msg_len, BYTE *share_key)
{
	int		len;
	BYTE	raw[RADIUS_MAX_LEN_OF_MSG] = "";

	memcpy(raw, msg, msg_len);

	memcpy(raw + msg_len, share_key, strlen((char*)share_key));

	len = msg_len + strlen((char*)share_key);

	radius_get_md5_hex((char*)auth, (char*)raw, len);

	return 0;
}

int radius_calculate_chap_password(BYTE *auth, BYTE chap_id, const BYTE *password, const BYTE *chap_challenge, int chap_len)
{
	int		len;
	BYTE	raw[RADIUS_MAX_LEN_OF_MSG] = "";

	raw[0] = chap_id;
	len = 1;
	
	memcpy(raw + len, password, strlen((char*)password));
	len += strlen((char*)password);

	memcpy(raw + len, chap_challenge, chap_len);
	len += chap_len;

	radius_get_md5_hex((char*)auth, (char*)raw, len);

	return 0;
}

int radius_match_response_authenticator_with_request(BYTE *request_auth, BYTE *response_auth, BYTE *msg, int msg_len, BYTE *share_key)
{
	BYTE		tmp_ptr[RADIUS_MAX_LEN_OF_MSG] = "";
	BYTE		rep_auth[RADIUS_MAX_LEN_OF_AUTH] = "";

	memcpy(tmp_ptr, msg, msg_len);

	memcpy(tmp_ptr + 4, request_auth, RADIUS_MAX_LEN_OF_AUTH);

	radius_calculate_authenticator(rep_auth, tmp_ptr, msg_len, share_key);

	if (memcmp(rep_auth, response_auth, RADIUS_MAX_LEN_OF_AUTH) != 0)
		return -1;

	return 0;
}

int radius_match_request_pid(BYTE msg_type, BYTE identifier, BYTE *authenticator, BYTE *msg, int msg_len, BYTE *share_key)
{
	int				i;
	RADIUS_PID		*pid_ptr;
	BYTE			corresponsd_msg;

	switch (msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
	case RADIUS_MSG_TYPE_ACCESS_REJECT:
	case RADIUS_MSG_TYPE_ACCESS_CHALLENGE:
		corresponsd_msg = RADIUS_MSG_TYPE_ACCESS_REQUEST;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_RESPONSE:
		corresponsd_msg = RADIUS_MSG_TYPE_ACCOUNTING_REQUEST;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_ACK:
	case RADIUS_MSG_TYPE_DISCONNECT_NAK:
		corresponsd_msg = RADIUS_MSG_TYPE_DISCONNECT_REQUEST;
		break;
	default:
		return -1;
	}

	for (i = 0; i < RADIUS_MAX_NUM_OF_PID; i++)
	{
		pid_ptr = radius_get_pid_ptr(i);

		if ((pid_ptr->flag != 1) || (pid_ptr->type != RADIUS_PID_TYPE_REQ))
		{
			continue;
		}
		if (pid_ptr->identifier != identifier)
		{
			continue;
		}
		if (pid_ptr->sd_msg_type != corresponsd_msg)
		{
			radius_log_warn("%s: sd_msg_type = %s, type = %s\r\n", __FUNCTION__, \
				radius_get_msg_str(pid_ptr->sd_msg_type), radius_get_msg_str(corresponsd_msg));
			continue;
		}
		if (radius_match_response_authenticator_with_request(pid_ptr->authenticator, authenticator, msg, msg_len, share_key) < 0)
		{
			radius_log_warn("%s: match authenticator err!\r\n", __FUNCTION__);
			continue;
		}

		//(pid_ptr->trans_req_msg_type != corresponsd_msg)
		/*if ((pid_ptr->identifier != identifier) || (pid_ptr->sd_msg_type != corresponsd_msg) || \
			(radius_match_response_authenticator_with_request(pid_ptr->authenticator, authenticator, msg, msg_len, share_key) < 0))
		{
			continue;
		}*/

		return i;
	}

	return -1;
}

int radius_parse_attr_user_name(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_USER_NAME		*user_name;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_warn("%s: msg type=%s user name length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return 0;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		user_name = &msg_pdu->msg.access_request.user_name;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		user_name = &msg_pdu->msg.access_accept.user_name;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		user_name = &msg_pdu->msg.accounting_request.user_name;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		user_name = &msg_pdu->msg.disconnect_request.user_name;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with user name\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(user_name->user_name.value, flw_ptr, length);

	user_name->user_name.type = RADIUS_ATTRIBUTE_TYPE_USER_NAME;

	user_name->user_name.length = length;

	user_name->flag = 1;

	return 0;
}

int radius_parse_attr_user_password(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_USER_PASSWORD	*user_password;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s user password length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		user_password = &msg_pdu->msg.access_request.user_password;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with user password\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(user_password->user_password.value, flw_ptr, length);

	user_password->user_password.type = RADIUS_ATTRIBUTE_TYPE_USER_PASSWORD;

	user_password->user_password.length = length;

	user_password->flag = 1;

	return 0;
}

int radius_parse_attr_chap_password(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_CHAP_PASSWORD	*chap_password;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s chap password length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		chap_password = &msg_pdu->msg.access_request.chap_password;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with chap password\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(chap_password->chap_password.value, flw_ptr, length);

	chap_password->chap_password.type = RADIUS_ATTRIBUTE_TYPE_CHAP_PASSWORD;

	chap_password->chap_password.length = length;

	chap_password->flag = 1;

	return 0;
}

int radius_parse_attr_nas_ip_addr(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_NAS_IP_ADDRESS	*nas_ip_addr;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s nas ip addr length=%d", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		nas_ip_addr = &msg_pdu->msg.access_request.nas_ip_addr;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		nas_ip_addr = &msg_pdu->msg.accounting_request.nas_ip_addr;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		nas_ip_addr = &msg_pdu->msg.disconnect_request.nas_ip_addr;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with nas ip addr\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	nas_ip_addr->nas_ip_addr.value = flw_ptr[3] << 24 | flw_ptr[2] << 16 | flw_ptr[1] << 8 | flw_ptr[0];

	nas_ip_addr->nas_ip_addr.type = RADIUS_ATTRIBUTE_TYPE_NAS_IP_ADDRESS;

	nas_ip_addr->nas_ip_addr.length = length;

	nas_ip_addr->flag = 1;

	return 0;
}

int radius_parse_attr_nas_port(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_NAS_PORT		*nas_port;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s nas port length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		nas_port = &msg_pdu->msg.access_request.nas_port;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		nas_port = &msg_pdu->msg.accounting_request.nas_port;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		nas_port = &msg_pdu->msg.disconnect_request.nas_port;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with nas port\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	nas_port->nas_port.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	nas_port->nas_port.type = RADIUS_ATTRIBUTE_TYPE_NAS_PORT;

	nas_port->nas_port.length = length;

	nas_port->flag = 1;

	return 0;
}

int radius_parse_attr_service_type(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_SERVICE_TYPE		*service_type;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s service type length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		service_type = &msg_pdu->msg.access_request.service_type;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		service_type = &msg_pdu->msg.access_accept.service_type;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		service_type = &msg_pdu->msg.accounting_request.service_type;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		service_type = &msg_pdu->msg.disconnect_request.service_type;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_NAK:
		service_type = &msg_pdu->msg.disconnect_nak.service_type;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg withc service type\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	service_type->service_type.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	service_type->service_type.type = RADIUS_ATTRIBUTE_TYPE_SERVICE_TYPE;

	service_type->service_type.length = length;

	service_type->flag = 1;

	return 0;
}

int radius_parse_attr_framed_protocol(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_FRAMED_PROTOCOL		*framed_protocol;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s framed protocol length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		framed_protocol = &msg_pdu->msg.access_request.framed_protocol;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		framed_protocol = &msg_pdu->msg.access_accept.framed_protocol;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		framed_protocol = &msg_pdu->msg.accounting_request.framed_protocol;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with framed protocol\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	framed_protocol->framed_protocol.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	framed_protocol->framed_protocol.type =RADIUS_ATTRIBUTE_TYPE_FRAMED_PROTOCOL;

	framed_protocol->framed_protocol.length = length;

	framed_protocol->flag = 1;

	return 0;
}

int radius_parse_attr_framed_ip_addr(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_FRAMED_IP_ADDR		*framed_ip_addr;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s framed ip addr length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		framed_ip_addr = &msg_pdu->msg.access_request.framed_ip_addr;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		framed_ip_addr = &msg_pdu->msg.access_accept.framed_ip_addr;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		framed_ip_addr = &msg_pdu->msg.accounting_request.framed_ip_addr;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		framed_ip_addr = &msg_pdu->msg.disconnect_request.framed_ip_addr;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with framed ip addr\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}
	
	framed_ip_addr->framed_ip_addr.value = flw_ptr[3] << 24 | flw_ptr[2] << 16 | flw_ptr[1] << 8 | flw_ptr[0];

	framed_ip_addr->framed_ip_addr.type = RADIUS_ATTRIBUTE_TYPE_FRAMED_IP_ADDR;

	framed_ip_addr->framed_ip_addr.length = length;

	framed_ip_addr->flag = 1;

	return 0;
}

int radius_parse_attr_framed_ip_netmask(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_FRAMED_IP_NETMASK	*framed_ip_netmask;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s framed ip netmask length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		framed_ip_netmask = &msg_pdu->msg.access_request.framed_ip_netmask;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		framed_ip_netmask = &msg_pdu->msg.access_accept.framed_ip_netmask;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		framed_ip_netmask = &msg_pdu->msg.accounting_request.framed_ip_netmask;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with framed ip netmask\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	framed_ip_netmask->framed_ip_netmask.value = flw_ptr[3] << 24 | flw_ptr[2] << 16 | flw_ptr[1] << 8 | flw_ptr[0];

	framed_ip_netmask->framed_ip_netmask.length = length;

	framed_ip_netmask->framed_ip_netmask.type = RADIUS_ATTRIBUTE_TYPE_FRAMED_IP_NETMASK;

	framed_ip_netmask->flag = 1;

	return 0;
}

int radius_parse_attr_framed_routing(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_FRAMED_ROUTING		*framed_routing;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s framed routing length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		framed_routing = &msg_pdu->msg.access_accept.framed_routing;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		framed_routing = &msg_pdu->msg.accounting_request.framed_routing;
	default:
		radius_log_warn("%s: msg type=%s recv msg with framed routing\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	framed_routing->framed_routing.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	framed_routing->framed_routing.length = length;

	framed_routing->framed_routing.type = RADIUS_ATTRIBUTE_TYPE_FRAMED_ROUTING;

	framed_routing->flag = 1;

	return 0;
}

int radius_parse_attr_filter_id(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	BYTE							num;
	RADIUS_FILTER_ID				*filter_id;
	RADIUS_ATTRIBUTE_FILTER_ID		*filter_id_attr;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s:msg type=%s filter id length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		filter_id = &msg_pdu->msg.access_accept.filter_id;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		filter_id = &msg_pdu->msg.accounting_request.filter_id;
	default:
		radius_log_warn("%s: msg type=%s recv msg with filter id\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	if ((num = filter_id->num) >= RADIUS_MAX_NUM_OF_FILTER_ID)
	{
		radius_log_warn("%s: recv msg type=%s, no resource for filter id\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	filter_id_attr = &filter_id->filter_id[num];

	memcpy(filter_id_attr->filter_id.value, flw_ptr, length);

	filter_id_attr->filter_id.length = length;

	filter_id_attr->filter_id.type = RADIUS_ATTRIBUTE_TYPE_FILTER_ID;

	filter_id_attr->flag = 1;

	filter_id->num++;

	return 0;
}

int radius_parse_attr_framed_mtu(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_FRAMED_MTU		*framed_mtu;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s framed mtu length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		framed_mtu = &msg_pdu->msg.access_request.framed_mtu;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		framed_mtu = &msg_pdu->msg.access_accept.framed_mtu;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		framed_mtu = &msg_pdu->msg.accounting_request.framed_mtu;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with framed mtu\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	framed_mtu->framed_mtu.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	framed_mtu->framed_mtu.length = length;

	framed_mtu->framed_mtu.type = RADIUS_ATTRIBUTE_TYPE_FRAMED_MTU;

	framed_mtu->flag = 1;

	return 0;
}

int radius_parse_attr_framed_compression(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	BYTE									num;
	RADIUS_FRAMED_COMPRESSION				*framed_compression;
	RADIUS_ATTRIBUTE_FRAMED_COMPRESSION	*framed_compression_attr;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s framed compression length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		framed_compression = &msg_pdu->msg.access_request.framed_compression;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		framed_compression = &msg_pdu->msg.access_accept.framed_compression;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		framed_compression = &msg_pdu->msg.accounting_request.framed_compression;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with framed compression\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	if ((num = framed_compression->num) >= RADIUS_MAX_NUM_OF_FRAMED_COMPRESSION)
	{
		radius_log_warn("%s: recv msg type=%s, no resource for framed compression\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	framed_compression_attr = &framed_compression->framed_compression[num];

	framed_compression_attr->framed_compression.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	framed_compression_attr->framed_compression.length = length;

	framed_compression_attr->framed_compression.type = RADIUS_ATTRIBUTE_TYPE_FRAMED_COMPRESSION;

	framed_compression_attr->flag = 1;

	framed_compression->num++;

	return 0;
}

int radius_parse_attr_login_ip_host(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	BYTE									num;
	RADIUS_LOGIN_IP_HOST					*login_ip_host;
	RADIUS_ATTRIBUTE_LOGIN_IP_HOST			*login_ip_host_attr;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s login ip host length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		login_ip_host = &msg_pdu->msg.access_request.login_ip_host;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		login_ip_host = &msg_pdu->msg.access_accept.login_ip_host;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		login_ip_host = &msg_pdu->msg.accounting_request.login_ip_host;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with login ip host\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	if ((num = login_ip_host->num) >= RADIUS_MAX_NUM_OF_LOGIN_IP_HOST)
	{
		radius_log_warn("%s: recv msg type=%s, no resource for login ip host\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	login_ip_host_attr = &login_ip_host->login_ip_host[num];

	login_ip_host_attr->login_ip_host.value = flw_ptr[3] << 24 | flw_ptr[2] << 16 | flw_ptr[1] << 8 | flw_ptr[0];

	login_ip_host_attr->login_ip_host.length = length;

	login_ip_host_attr->login_ip_host.type = RADIUS_ATTRIBUTE_TYPE_LOGIN_IP_HOST;

	login_ip_host_attr->flag = 1;

	login_ip_host->num++;

	return 0;
}

int radius_parse_attr_login_service(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_LOGIN_SERVICE		*login_service;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s login service length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		login_service = &msg_pdu->msg.access_accept.login_service;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		login_service = &msg_pdu->msg.accounting_request.login_service;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with login service\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	login_service->login_service.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	login_service->login_service.length = length;

	login_service->login_service.type = RADIUS_ATTRIBUTE_TYPE_LOGIN_SERVICE;

	login_service->flag = 1;

	return 0;
}

int radius_parse_attr_login_tcp_port(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_LOGIN_TCP_PORT		*login_tcp_port;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s login tcp port length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		login_tcp_port = &msg_pdu->msg.access_accept.login_tcp_port;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		login_tcp_port = &msg_pdu->msg.accounting_request.login_tcp_port;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with login tcp port\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	login_tcp_port->login_tcp_port.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	login_tcp_port->login_tcp_port.length = length;

	login_tcp_port->login_tcp_port.type = RADIUS_ATTRIBUTE_TYPE_LOGIN_TCP_PORT;

	login_tcp_port->flag = 1;

	return 0;
}

int radius_parse_attr_reply_message(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	BYTE									num;
	RADIUS_REPLY_MESSAGE					*reply_message;
	RADIUS_ATTRIBUTE_REPLY_MESSAGE			*reply_message_attr;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s reply message length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		reply_message = &msg_pdu->msg.access_accept.reply_message;
		break;
	case RADIUS_MSG_TYPE_ACCESS_REJECT:
		reply_message = &msg_pdu->msg.access_reject.reply_message;
		break;
	case RADIUS_MSG_TYPE_ACCESS_CHALLENGE:
		reply_message = &msg_pdu->msg.access_challenge.reply_message;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		reply_message = &msg_pdu->msg.disconnect_request.reply_message;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with reply message\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	if ((num = reply_message->num) >= RADIUS_MAX_NUM_OF_REPLY_MESSAGE)
	{
		radius_log_warn("%s: recv msg type=%s, no resource for reply message\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	reply_message_attr = &reply_message->reply_message[num];

	memcpy(reply_message_attr->reply_message.value, flw_ptr, length);

	reply_message_attr->reply_message.length = length;

	reply_message_attr->reply_message.type = RADIUS_ATTRIBUTE_TYPE_REPLY_MESSAGE;

	reply_message_attr->flag = 1;

	reply_message->num++;

	return 0;
}

int radius_parse_attr_callback_number(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_CALLBACK_NUMBER		*callback_num;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s callback number length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		callback_num = &msg_pdu->msg.access_request.callback_number;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		callback_num = &msg_pdu->msg.access_accept.callback_number;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		callback_num = &msg_pdu->msg.accounting_request.callback_number;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with callback num\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(callback_num->callback_number.value, flw_ptr, length);

	callback_num->callback_number.length = length;

	callback_num->callback_number.type = RADIUS_ATTRIBUTE_TYPE_CALLBACK_NUMBER;

	callback_num->flag = 1;

	return 0;
}

int radius_parse_attr_callback_id(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_CALLBACK_ID		*callback_id;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s callback id length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		callback_id = &msg_pdu->msg.access_accept.callback_id;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		callback_id = &msg_pdu->msg.accounting_request.callback_id;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with callback id\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(callback_id->callback_id.value, flw_ptr, length);

	callback_id->callback_id.length = length;

	callback_id->callback_id.type = RADIUS_ATTRIBUTE_TYPE_CALLBACK_ID;

	callback_id->flag = 1;

	return 0;
}

int radius_parse_attr_framed_route(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	BYTE								num;
	RADIUS_FRAMED_ROUTE				*framed_route;
	RADIUS_ATTRIBUTE_FRAMED_ROUTE		*framed_route_attr;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s framed route length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		framed_route = &msg_pdu->msg.access_accept.framed_route;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		framed_route = &msg_pdu->msg.accounting_request.framed_route;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with framed route\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	if ((num = framed_route->num) >= RADIUS_MAX_NUM_OF_FRAMED_ROUTE)
	{
		radius_log_warn("%s: recv msg type=%s, no resource for framed route\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	framed_route_attr = &framed_route->framed_route[num];

	memcpy(framed_route_attr->framed_route.value, flw_ptr, length);

	framed_route_attr->framed_route.length = length;

	framed_route_attr->framed_route.type = RADIUS_ATTRIBUTE_TYPE_FRAMED_ROUTE;

	framed_route_attr->flag = 1;

	framed_route->num++;

	return 0;
}

int radius_parse_attr_framed_ipx_network(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_FRAMED_IPX_NETWORK		*framed_ipx_network;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s framed ipx network length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		framed_ipx_network = &msg_pdu->msg.access_accept.framed_ipx_network;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		framed_ipx_network = &msg_pdu->msg.accounting_request.framed_ipx_network;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with framed ipx network\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	framed_ipx_network->framed_ipx_network.value = flw_ptr[3] << 24 | flw_ptr[2] << 16 | flw_ptr[1] << 8 | flw_ptr[0];

	framed_ipx_network->framed_ipx_network.length = length;

	framed_ipx_network->framed_ipx_network.type = RADIUS_ATTRIBUTE_TYPE_FRAMED_IPX_NETWORK;

	framed_ipx_network->flag = 1;

	return 0;
}

int radius_parse_attr_state(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_STATE		*state;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s state length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		state = &msg_pdu->msg.access_request.state;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		state = &msg_pdu->msg.access_accept.state;
		break;
	case RADIUS_MSG_TYPE_ACCESS_CHALLENGE:
		state = &msg_pdu->msg.access_challenge.state;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		state = &msg_pdu->msg.disconnect_request.state;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_ACK:
		state = &msg_pdu->msg.disconnect_ack.state;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_NAK:
		state = &msg_pdu->msg.disconnect_nak.state;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with state\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(state->state.value, flw_ptr, length);

	state->state.length = length;

	state->state.type = RADIUS_ATTRIBUTE_TYPE_STATE;

	state->flag = 1;

	return 0;
}

int radius_parse_attr_class(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	BYTE								num;
	RADIUS_CLASS						*radius_class;
	RADIUS_ATTRIBUTE_CLASS				*radius_class_attr;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s class length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		radius_class = &msg_pdu->msg.access_accept.radius_class;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		radius_class = &msg_pdu->msg.accounting_request.radius_class;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		radius_class = &msg_pdu->msg.disconnect_request.radius_class;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with class\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	if ((num = radius_class->num) >= RADIUS_MAX_NUM_OF_CLASS)
	{
		radius_log_warn("%s: recv msg type=%s, no resource for class\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	radius_class_attr = &radius_class->radius_class[num];

	memcpy(radius_class_attr->radius_class.value, flw_ptr, length);

	radius_class_attr->radius_class.length = length;

	radius_class_attr->radius_class.type = RADIUS_ATTRIBUTE_TYPE_CLASS;

	radius_class_attr->flag = 1;

	radius_class->num++;

	return 0;
}

int radius_parse_vendor_ppac_sub_attr_aic(RADIUS_VENDOR_PPAC_SUB_ATTR_AIC *aic, const BYTE *flw_ptr, BYTE length)
{
	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: aic length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	aic->aic = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	aic->flag = 1;

	return 0;
}

int radius_parse_vendor_ppac_sub_attr(RADIUS_VENDOR_ATTRIBUTE_PPAC *ppac, const BYTE *flw_ptr, BYTE length)
{
	BYTE	subtype;
	BYTE	continuation;

	continuation = flw_ptr[0];

	subtype = flw_ptr[1];

	if ((continuation & 0x80) != 0)
	{
		radius_log_warn("%s: ppac continuation=%x\r\n", __FUNCTION__, continuation);
	}

	switch (subtype)
	{
	case RADIUS_PPAC_SUBTYPE_AIC:
		if (radius_parse_vendor_ppac_sub_attr_aic(&ppac->aic, flw_ptr + 3, flw_ptr[2] - 2) < 0)
		{
			radius_log_err("%s: ppac sub attribute aic parse fail\r\n", __FUNCTION__);
			return -1;
		}
		break;
	default:
		radius_log_warn("%s: ppac unknow subtype=%d\r\n", __FUNCTION__, subtype);
		return 0;
	}

	ppac->continuation = continuation & 0x7F;

	return 0;
}

int radius_parse_vendor_stc_sub_attr(RADIUS_VENDOR_ATTRIBUTE_STC *stc, const BYTE *flw_ptr, BYTE length)
{
	BYTE	continuation;

	if (length != 5)
	{
		radius_log_err("%s: stc length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	continuation = flw_ptr[0];

	if ((continuation & 0x80) != 0)
	{
		radius_log_warn("%s: stc continuation=%x\r\n", __FUNCTION__, continuation);
	}

	stc->stc = flw_ptr[1] << 24 | flw_ptr[2] << 16 | flw_ptr[3] << 8 | flw_ptr[4];

	stc->continuation = continuation & 0x7F;

	return 0;
}

int radius_parse_vendor_ppaq_sub_attr_qid(RADIUS_VENDOR_PPAQ_SUB_ATTR_QID *qid, const BYTE *flw_ptr, BYTE length)
{
	if (length > RADIUS_TS_VALUE_LEN)
	{
		radius_log_err("%s: qid length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	memcpy(qid->qid.value, flw_ptr, length);

	qid->qid.length = length;

	qid->qid.type = RADIUS_PPAQ_SUBTYPE_QID;

	qid->flag = 1;

	return 0;
}

int radius_parse_vendor_ppaq_sub_attr_vq(RADIUS_VENDOR_PPAQ_SUB_ATTR_VQ *vq, const BYTE *flw_ptr, BYTE length)
{
	long long		i = 0;

	if ((length != 8) && (length != 12))
	{
		radius_log_err("%s: volume quota length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	i = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	vq->vq.integer = i << 32 | flw_ptr[4] << 24 | flw_ptr[5] << 16 | flw_ptr[6] << 8 | flw_ptr[7];

	vq->vq.exponent = 0;

	if (length == 12)
	{
		vq->vq.exponent = flw_ptr[8] << 24 | flw_ptr[9] << 16 | flw_ptr[10] << 8 | flw_ptr[11];
	}

	vq->vq.type = RADIUS_PPAQ_SUBTYPE_VQ;

	vq->flag = 1;

	return 0;
}

int radius_parse_vendor_ppaq_sub_attr_vt(RADIUS_VENDOR_PPAQ_SUB_ATTR_VT *vt, const BYTE *flw_ptr, BYTE length)
{
	long long		i = 0;

	if ((length != 8) && (length != 12))
	{
		radius_log_err("%s: volume threshold length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	i = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	vt->vt.integer = i << 32 | flw_ptr[4] << 24 | flw_ptr[5] << 16 | flw_ptr[6] << 8 | flw_ptr[7];

	vt->vt.exponent= 0;

	if (length == 12)
	{
		vt->vt.exponent = flw_ptr[8] << 24 | flw_ptr[9] << 16 | flw_ptr[10] << 8 | flw_ptr[11];
	}

	vt->vt.type = RADIUS_PPAQ_SUBTYPE_VT;

	vt->flag = 1;

	return 0;
}

int radius_parse_vendor_ppaq_sub_attr_dq(RADIUS_VENDOR_PPAQ_SUB_ATTR_DQ *dq, const BYTE *flw_ptr, BYTE length)
{
	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: duration quato length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	dq->dq.length = length;

	dq->dq.value =  flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	dq->dq.type = RADIUS_PPAQ_SUBTYPE_DQ;

	dq->flag = 1;

	return 0;
}

int radius_parse_vendor_ppaq_sub_attr_dt(RADIUS_VENDOR_PPAQ_SUB_ATTR_DT *dt, const BYTE *flw_ptr, BYTE length)
{
	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: duration threshold length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	dt->dt.length = length;

	dt->dt.value =  flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	dt->dt.type = RADIUS_PPAQ_SUBTYPE_DT;

	dt->flag = 1;

	return 0;
}

int radius_parse_vendor_ppaq_sub_attr_rq(RADIUS_VENDOR_PPAQ_SUB_ATTR_RQ *rq, const BYTE *flw_ptr, BYTE length)
{
	long long		i = 0;

	if ((length != 8) && (length != 12))
	{
		radius_log_err("%s: resource quota length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	i = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	rq->rq.integer = i << 32 | flw_ptr[4] << 24 | flw_ptr[5] << 16 | flw_ptr[6] << 8 | flw_ptr[7];

	rq->rq.exponent = 0;

	if (length == 12)
	{
		rq->rq.exponent = flw_ptr[8] << 24 | flw_ptr[9] << 16 | flw_ptr[10] << 8 | flw_ptr[11];
	}

	rq->rq.type = RADIUS_PPAQ_SUBTYPE_RQ;

	rq->flag = 1;

	return 0;
}

int radius_parse_vendor_ppaq_sub_attr_rt(RADIUS_VENDOR_PPAQ_SUB_ATTR_RT *rt, const BYTE *flw_ptr, BYTE length)
{
	long long		i = 0;

	if ((length != 8) && (length != 12))
	{
		radius_log_err("%s: resource threshold length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	i = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	rt->rt.integer = i << 32 | flw_ptr[4] << 24 | flw_ptr[5] << 16 | flw_ptr[6] << 8 | flw_ptr[7];

	rt->rt.exponent= 0;

	if (length == 12)
	{
		rt->rt.exponent = flw_ptr[8] << 24 | flw_ptr[9] << 16 | flw_ptr[10] << 8 | flw_ptr[11];
	}

	rt->rt.type = RADIUS_PPAQ_SUBTYPE_RQ;

	rt->flag = 1;

	return 0;
}

int radius_parse_vendor_ppaq_sub_attr_ur(RADIUS_VENDOR_PPAQ_SUB_ATTR_UR *ur, const BYTE *flw_ptr, BYTE length)
{
	if (length != 1)
	{
		radius_log_err("%s: update reason length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	ur->ur.value = flw_ptr[0];

	ur->ur.length = length;

	ur->ur.type = RADIUS_PPAQ_SUBTYPE_UR;

	ur->flag = 1;

	return 0;
}

int radius_parse_vendor_ppaq_sub_attr_ps(RADIUS_VENDOR_PPAQ_SUB_ATTR_PS *ps, const BYTE *flw_ptr, BYTE length)
{
	if ((length != 4) && (length != 16))
	{
		radius_log_err("%s: prepaid server addr length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	if (length == 4)
	{
		ps->ps.value = flw_ptr[3] << 24 | flw_ptr[2] << 16 | flw_ptr[1] << 8 | flw_ptr[0];
	}
	else
	{
		radius_log_warn("%s: prepaid server addr is ipv6 not support\r\n", __FUNCTION__);
		return 0;
	}

	ps->ps.length = length;

	ps->ps.type = RADIUS_PPAQ_SUBTYPE_PS;

	ps->flag = 1;

	return 0;
}

int radius_parse_vendor_ppaq_sub_attr_sid(RADIUS_VENDOR_PPAQ_SUB_ATTR_SID *sid, const BYTE *flw_ptr, BYTE length)
{
	if (length> RADIUS_TS_VALUE_LEN)
	{
		radius_log_err("%s: service id length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	memcpy(sid->sid.value, flw_ptr, length);

	sid->sid.length = length;

	sid->sid.type = RADIUS_PPAQ_SUBTYPE_SID;

	sid->flag = 1;

	return 0;
}

int radius_parse_vendor_ppaq_sub_attr_rgid(RADIUS_VENDOR_PPAQ_SUB_ATTR_RGID *rgid, const BYTE *flw_ptr, BYTE length)
{
	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: rating group id length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	rgid->rgid.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	rgid->rgid.length = length;

	rgid->rgid.type = RADIUS_PPAQ_SUBTYPE_RGID;

	rgid->flag = 1;

	return 0;
}

int radius_parse_vendor_ppaq_sub_attr_ta(RADIUS_VENDOR_PPAQ_SUB_ATTR_TA *ta, const BYTE *flw_ptr, BYTE length)
{
	if (length != 1)
	{
		radius_log_err("%s: termination action length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	ta->ta.value = flw_ptr[0];

	ta->ta.length = length;

	ta->ta.type = RADIUS_PPAQ_SUBTYPE_TA;

	ta->flag = 1;

	return 0;
}

int radius_parse_vendor_ppaq_sub_attr_plid(RADIUS_VENDOR_PPAQ_SUB_ATTR_PLID *plid, const BYTE *flw_ptr, BYTE length)
{
	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: pool id length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	plid->plid.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	plid->plid.length = length;

	plid->plid.type = RADIUS_PPAQ_SUBTYPE_PLID;

	plid->flag = 1;

	return 0;
}

int radius_parse_vendor_ppaq_sub_attr_pm(RADIUS_VENDOR_PPAQ_SUB_ATTR_PM *pm, const BYTE *flw_ptr, BYTE length)
{
	long long		i = 0;

	if ((length != 8) && (length != 12))
	{
		radius_log_err("%s: pool multiplier length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	i = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	pm->pm.integer = i << 32 | flw_ptr[4] << 24 | flw_ptr[5] << 16 | flw_ptr[6] << 8 | flw_ptr[7];

	pm->pm.exponent = 0;

	if (length == 12)
	{
		pm->pm.exponent = flw_ptr[8] << 24 | flw_ptr[9] << 16 | flw_ptr[10] << 8 | flw_ptr[11];
	}

	pm->pm.type = RADIUS_PPAQ_SUBTYPE_PM;

	pm->flag = 1;

	return 0;
}

int radius_parse_vendor_ppaq_sub_attr_ra(RADIUS_VENDOR_PPAQ_SUB_ATTR_RA *ra, const BYTE *flw_ptr, BYTE length)
{
	if (length != 1)
	{
		radius_log_err("%s: requested action length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	ra->ra.value = flw_ptr[0];

	ra->ra.length = length;

	ra->ra.type = RADIUS_PPAQ_SUBTYPE_RA;

	ra->flag = 1;

	return 0;
}

int radius_parse_vendor_ppaq_sub_attr_cbr(RADIUS_VENDOR_PPAQ_SUB_ATTR_CBR *cbr, const BYTE *flw_ptr, BYTE length)
{
	if (length != 1)
	{
		radius_log_err("%s: check balance result length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	cbr->cbr.value = flw_ptr[0];

	cbr->cbr.length = length;

	cbr->cbr.type = RADIUS_PPAQ_SUBTYPE_CBR;

	cbr->flag = 1;

	return 0;
}

int radius_parse_vendor_ppaq_sub_attr_ci(RADIUS_VENDOR_PPAQ_SUB_ATTR_CI *ci, const BYTE *flw_ptr, BYTE length)
{
	long long		i = 0;

	if (length < 17)// value-digits 8 bytes exponent 4 bytes currency-code 4 bytes cost unit >= 1 byte
	{
		radius_log_err("%s: cost information length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	i = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	ci->integer = i << 32 | flw_ptr[4] << 24 | flw_ptr[5] << 16 | flw_ptr[6] << 8 | flw_ptr[7];

	ci->exponent = flw_ptr[8] << 24 | flw_ptr[9] << 16 | flw_ptr[10] << 8 | flw_ptr[11];

	ci->currency_code = flw_ptr[12] << 24 | flw_ptr[13] << 16 | flw_ptr[14] << 8 | flw_ptr[15];

	memcpy(ci->cost_unit, flw_ptr + 16, length - 16);

	ci->type = RADIUS_PPAQ_SUBTYPE_CI;

	ci->flag = 1;

	return 0;
}

int radius_parse_vendor_ppaq_sub_attr(RADIUS_VENDOR_ATTRIBUTE_PPAQ *ppaq, const BYTE *flw_ptr, BYTE length)
{
	BYTE *tmp_ptr = (BYTE *)flw_ptr + 1;

	for (;;)
	{
		if ((tmp_ptr - flw_ptr) >= length)
			break;

		switch (tmp_ptr[0])
		{
		case RADIUS_PPAQ_SUBTYPE_QID:
			if (radius_parse_vendor_ppaq_sub_attr_qid(&ppaq->qid, tmp_ptr + 2, tmp_ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute qid parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_PPAQ_SUBTYPE_VQ:
			if (radius_parse_vendor_ppaq_sub_attr_vq(&ppaq->vq, tmp_ptr + 2, tmp_ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute volume quota parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_PPAQ_SUBTYPE_VT:
			if (radius_parse_vendor_ppaq_sub_attr_vt(&ppaq->vt, tmp_ptr + 2, tmp_ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute volume threshold parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_PPAQ_SUBTYPE_DQ:
			if (radius_parse_vendor_ppaq_sub_attr_dq(&ppaq->dq, tmp_ptr + 2, tmp_ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute duration quota parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_PPAQ_SUBTYPE_DT:
			if (radius_parse_vendor_ppaq_sub_attr_dt(&ppaq->dt, tmp_ptr + 2, tmp_ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute duration threshold parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_PPAQ_SUBTYPE_RQ:
			if (radius_parse_vendor_ppaq_sub_attr_rq(&ppaq->rq, tmp_ptr + 2, tmp_ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute resource quota parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_PPAQ_SUBTYPE_RT:
			if (radius_parse_vendor_ppaq_sub_attr_rt(&ppaq->rt, tmp_ptr + 2, tmp_ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute resource threshold parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_PPAQ_SUBTYPE_UR:
			if (radius_parse_vendor_ppaq_sub_attr_ur(&ppaq->ur, tmp_ptr + 2, tmp_ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute update reason parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_PPAQ_SUBTYPE_PS:
			if (radius_parse_vendor_ppaq_sub_attr_ps(&ppaq->ps, tmp_ptr + 2, tmp_ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute prepaid server parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_PPAQ_SUBTYPE_SID:
			if (radius_parse_vendor_ppaq_sub_attr_sid(&ppaq->sid, tmp_ptr + 2, tmp_ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute service id parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_PPAQ_SUBTYPE_RGID:
			if (radius_parse_vendor_ppaq_sub_attr_rgid(&ppaq->rgid, tmp_ptr + 2, tmp_ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute rating group id parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_PPAQ_SUBTYPE_TA:
			if (radius_parse_vendor_ppaq_sub_attr_ta(&ppaq->ta, tmp_ptr + 2, tmp_ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute terminate action parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_PPAQ_SUBTYPE_PLID:
			if (radius_parse_vendor_ppaq_sub_attr_plid(&ppaq->plid, tmp_ptr + 2, tmp_ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute pool id parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_PPAQ_SUBTYPE_PM:
			if (radius_parse_vendor_ppaq_sub_attr_pm(&ppaq->pm, tmp_ptr + 2, tmp_ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute pool multiplier parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_PPAQ_SUBTYPE_RA:
			if (radius_parse_vendor_ppaq_sub_attr_ra(&ppaq->ra, tmp_ptr + 2, tmp_ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute requested action parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_PPAQ_SUBTYPE_CBR:
			if (radius_parse_vendor_ppaq_sub_attr_cbr(&ppaq->cbr, tmp_ptr + 2, tmp_ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute check balance result parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_PPAQ_SUBTYPE_CI:
			if (radius_parse_vendor_ppaq_sub_attr_ci(&ppaq->ci, tmp_ptr + 2, tmp_ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute cost infromation parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		default:
			radius_log_warn("%s: ppaq unknow subtype=%d\r\n", __FUNCTION__, tmp_ptr[0]);
			break;;
		}

		tmp_ptr += tmp_ptr[1];
	}

	ppaq->continuation =  flw_ptr[0];

	return 0;
}

int radius_parse_vendor_pts_sub_attr_vuats(RADIUS_VENDOR_PTS_SUB_ATTR_VUATS * vuats, const BYTE * flw_ptr, BYTE length)
{
	long long		i = 0;

	if ((length != 8) && (length != 12))
	{
		radius_log_err("%s: volume used after tariff switch length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	i = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	vuats->vuats.integer = i << 32 | flw_ptr[4] << 24 | flw_ptr[5] << 16 | flw_ptr[6] << 8 | flw_ptr[7];

	vuats->vuats.exponent = 0;

	if (length == 12)
	{
		vuats->vuats.exponent = flw_ptr[8] << 24 | flw_ptr[9] << 16 | flw_ptr[10] << 8 | flw_ptr[11];
	}

	vuats->vuats.type = RADIUS_PTS_SUBTYPE_VUATS;

	vuats->flag = 1;

	return 0;
}

int radius_parse_vendor_pts_sub_attr_tsi(RADIUS_VENDOR_PTS_SUB_ATTR_TSI * tsi, const BYTE * flw_ptr, BYTE length)
{
	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: tariff switch interval length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	tsi->tsi.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	tsi->tsi.length = length;

	tsi->tsi.type = RADIUS_PTS_SUBTYPE_TSI;

	tsi->flag = 1;

	return 0;
}

int radius_parse_vendor_pts_sub_attr_titsu(RADIUS_VENDOR_PTS_SUB_ATTR_TITSU * titsu, const BYTE * flw_ptr, BYTE length)
{
	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: time interval after tariff switch updatel length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	titsu->titsu.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	titsu->titsu.length = length;

	titsu->titsu.type = RADIUS_PTS_SUBTYPE_TSI;

	titsu->flag = 1;

	return 0;
}

int radius_parse_vendor_pts_sub_attr(RADIUS_VENDOR_ATTRIBUTE_PTS *pts, const BYTE *flw_ptr, BYTE length)
{
	BYTE	*ptr = (BYTE *)flw_ptr + 1;

	for (;;)
	{
		if ((ptr - flw_ptr) >= length)
			break;

		switch (ptr[0])
		{
		case RADIUS_PTS_SUBTYPE_VUATS:
			if (radius_parse_vendor_pts_sub_attr_vuats(&pts->vuats, ptr + 2, ptr[1] -2) < 0)
				return -1;
			break;
		case RADIUS_PTS_SUBTYPE_TSI:
			if (radius_parse_vendor_pts_sub_attr_tsi(&pts->tsi, ptr + 2, ptr[1] - 2) < 0)
				return -1;
			break;
		case RADIUS_PTS_SUBTYPE_TITSU:
			if (radius_parse_vendor_pts_sub_attr_titsu(&pts->titsu, ptr + 2, ptr[1] - 2) < 0)
				return -1;
			break;
		default:
			radius_log_warn("%s: pst unknow subtype=%d\r\n", __FUNCTION__, ptr[0]);
			break;
		}

		ptr += ptr[1];
	}

	pts->continuation =  flw_ptr[0];

	return 0;
}

int radius_parse_vendor_3gpp_imsi(RADIUS_VENDOR_ATTRIBUTE_3GPP_IMSI *imsi, const BYTE *flw_ptr, BYTE length)
{
	if ((length < 3) || (length >= RADIUS_MAX_LEN_OF_IMSI))
	{
		radius_log_err("%s: imsi length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	memcpy(imsi->imsi, flw_ptr, length);

	return 0;
}

int radius_parse_vendor_3gpp_charging_id(RADIUS_VENDOR_ATTRIBUTE_3GPP_CID *charging_id, const BYTE *flw_ptr, BYTE length)
{
	if (length != 4)
	{
		radius_log_err("%s: charging id length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	charging_id->cid = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	return 0;
}

int radius_parse_vendor_3gpp_pdp_type(RADIUS_VENDOR_ATTRIBUTE_3GPP_PDP_TYPE *pdp_type, const BYTE *flw_ptr, BYTE length)
{
	if (length != 4)
	{
		radius_log_err("%s: pdp type length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	pdp_type->pdp_type = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 |flw_ptr[3];

	return 0;
}

int radius_parse_vendor_3gpp_cg_addr(RADIUS_VENDOR_ATTRIBUTE_3GPP_CG_ADDR *cg_addr, const BYTE *flw_ptr, BYTE length)
{
	if (length != 4)
	{
		radius_log_err("%s: cg addr length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	cg_addr->cg_addr = flw_ptr[3] << 24 | flw_ptr[2] << 16 | flw_ptr[1] << 8 | flw_ptr[0];

	return 0;
}

int radius_parse_vendor_3gpp_nqp(RADIUS_VENDOR_ATTRIBUTE_3GPP_NQP *nqp, const BYTE *flw_ptr, BYTE length)
{
	if (length > RADIUS_TS_VALUE_LEN)
	{
		radius_log_err("%s: negatiated qos profile length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	memcpy(nqp->nqp, flw_ptr, length);

	return 0;
}

int radius_parse_vendor_3gpp_sgsn_addr(RADIUS_VENDOR_ATTRIBUTE_3GPP_SGSN_ADDR *sgsn_addr, const BYTE *flw_ptr, BYTE length)
{
	if (length != 4)
	{
		radius_log_err("%s: sgsn addr length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	sgsn_addr->sgsn_addr = flw_ptr[3] << 24 | flw_ptr[2] << 16 | flw_ptr[1] << 8 | flw_ptr[0];

	return 0;
}

int radius_parse_vendor_3gpp_ggsn_addr(RADIUS_VENDOR_ATTRIBUTE_3GPP_GGSN_ADDR *ggsn_addr, const BYTE *flw_ptr, BYTE length)
{
	if (length != 4)
	{
		radius_log_err("%s: ggsn addr length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	ggsn_addr->ggsn_addr = flw_ptr[3] << 24 | flw_ptr[2] << 16 | flw_ptr[1] << 8 | flw_ptr[0];

	return 0;
}

int radius_parse_vendor_3gpp_imsi_mcc_mnc(RADIUS_VENDOR_ATTRIBUTE_3GPP_MCC_MNC *mcc_mnc, const BYTE *flw_ptr, BYTE length)
{
	if ((length < 5) || (length > 6))
	{
		radius_log_err("%s: imsi mcc mnc length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	memcpy(mcc_mnc->mcc, flw_ptr, 3);

	memcpy(mcc_mnc->mnc, flw_ptr + 3, length - 3);

	return 0;
}

int radius_parse_vendor_3gpp_ggsn_mcc_mnc(RADIUS_VENDOR_ATTRIBUTE_3GPP_GGSN_MCC_MNC *ggsn_mcc_mnc, const BYTE *flw_ptr, BYTE length)
{
	if ((length < 5) || (length > 6))
	{
		radius_log_err("%s: ggsn mcc mnc length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	memcpy(ggsn_mcc_mnc->mcc, flw_ptr, 3);

	memcpy(ggsn_mcc_mnc->mnc, flw_ptr + 3, length - 3);

	return 0;
}

int radius_parse_vendor_3gpp_nsapi(RADIUS_VENDOR_ATTRIBUTE_3GPP_NSAPI *nsapi, const BYTE *flw_ptr, BYTE length)
{
	char		tmp[RADIUS_MAX_LEN_OF_TEMP_BUF] = "";

	if (length != 1)
	{
		radius_log_err("%s: nsapi length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	memcpy(tmp, flw_ptr, 1);

	nsapi->nsapi = strtol(tmp, NULL, 16);

	return 0;
}

int radius_parse_vendor_3gpp_ssi(RADIUS_VENDOR_ATTRIBUTE_3GPP_SSI *ssi, const BYTE *flw_ptr, BYTE length)
{
	if ((length != 1) || (flw_ptr[0] != 0xFF))
	{
		radius_log_err("%s: ssi length=%d, ssi=0x%X\r\n", __FUNCTION__, length, flw_ptr[0]);
		return -1;
	}

	ssi->ssi = flw_ptr[0];

	return 0;
}

int radius_parse_vendor_3gpp_sm(RADIUS_VENDOR_ATTRIBUTE_3GPP_SM *sm, const BYTE *flw_ptr, BYTE length)
{
	char		tmp[RADIUS_MAX_LEN_OF_TEMP_BUF] = "";

	if (length != 1)
	{
		radius_log_err("%s: selection mode length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	memcpy(tmp, flw_ptr, 1);

	sm->sm = strtol(tmp, NULL, 16);

	return 0;
}

int radius_parse_vendor_3gpp_cc(RADIUS_VENDOR_ATTRIBUTE_3GPP_CC *cc, const BYTE *flw_ptr, BYTE length)
{
	if (length != 4)
	{
		radius_log_err("%s: cc length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	memcpy(cc->cc, flw_ptr, length);

	return 0;
}

int radius_parse_vendor_3gpp_sgsn_mcc_mnc(RADIUS_VENDOR_ATTRIBUTE_3GPP_SGSN_MCC_MNC *sgsn_mcc_mnc, const BYTE *flw_ptr, BYTE length)
{
	if ((length < 5) || (length > 6))
	{
		radius_log_err("%s: sgsn mcc mnc length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	memcpy(sgsn_mcc_mnc->mcc, flw_ptr, 3);

	memcpy(sgsn_mcc_mnc->mnc, flw_ptr + 3, length - 3);

	return 0;
}

int radius_parse_vendor_3gpp2_stc(RADIUS_VENDOR_ATTRIBUTE_3GPP2_STC *stc, const BYTE *flw_ptr, BYTE length)
{
	if (length != 4)
	{
		radius_log_err("%s: stc length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	stc->stc = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	return 0;
}

int radius_parse_vendor_3gpp2_ppac_sub_attr_aic(RADIUS_VENDOR_3GPP2_PPAC_SUB_ATTR_AIC *aic, const BYTE *flw_ptr, BYTE length)
{
	if (length != 4)
	{
		radius_log_err("%s: ppac aic length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	aic->aic = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	aic->flag = 1;

	return 0;
}

int radius_parse_vendor_3gpp2_ppac_sub_attr_sfs(RADIUS_VENDOR_3GPP2_PPAC_SUB_ATTR_SFS *sfs, const BYTE *flw_ptr, BYTE length)
{
	if (length != 4)
	{
		radius_log_err("%s: ppac sfs length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	sfs->sfs = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	sfs->flag = 1;

	return 0;
}

int radius_parse_vendor_3gpp2_ppac(RADIUS_VENDOR_ATTRIBUTE_3GPP2_PPAC *ppac, const BYTE *flw_ptr, BYTE length)
{
	BYTE	*ptr = (BYTE *)flw_ptr;

	for (;;)
	{
		if ((ptr - flw_ptr) >= length)
			break;

		switch (ptr[0])
		{
		case RADIUS_3GPP2_PPAC_SUBTYPE_AIC:
			if (radius_parse_vendor_3gpp2_ppac_sub_attr_aic(&ppac->aic, ptr + 2, ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppac sub attribute aic parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_3GPP2_PPAC_SUBTYPE_SFS:
			if (radius_parse_vendor_3gpp2_ppac_sub_attr_sfs(&ppac->sfs, ptr + 2, ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppac sub attribute sfs parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		default:
			radius_log_warn("%s: ppac unknow subtype=%d\r\n", __FUNCTION__, ptr[0]);
			return 0;
		}

		ptr += ptr[1];
	}

	return 0;
}

int radius_parse_vendor_3gpp2_ppaq_sub_attr_qid(RADIUS_VENDOR_3GPP2_PPAQ_SUB_ATTR_QID *qid, const BYTE *flw_ptr, BYTE length)
{
	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: qid length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	qid->qid.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	qid->qid.length = length;

	qid->qid.type = RADIUS_3GPP2_PPAQ_SUBTYPE_QID;

	qid->flag = 1;

	return 0;
}

int radius_parse_vendor_3gpp2_ppaq_sub_attr_vq(RADIUS_VENDOR_3GPP2_PPAQ_SUB_ATTR_VQ *vq, const BYTE *flw_ptr, BYTE length)
{
	long long		i = 0;
/*	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: vq length=%d\r\n", __FUNCTION__, length);
		return -1;
	}*///for 3gpp2

	if ((length != 10) && (length != 16))
	{
		radius_log_err("%s: vq length=%d\r\n", __FUNCTION__, length);
		return -1;
	}//for aricent


	if (flw_ptr[0] != RADIUS_ARICENT_VOLUME_INT)
	{
		radius_log_err("%s: vq subtype first=%d\r\n", flw_ptr[0]);
		return -1;
	}

	i = flw_ptr[2] << 24 | flw_ptr[3] << 16 | flw_ptr[4] << 8 | flw_ptr[5];

	vq->vq.integer = i << 32 | flw_ptr[6] << 24 | flw_ptr[7] << 16 | flw_ptr[8] << 8 | flw_ptr[9];	

	if (length == 16)
	{
		if (flw_ptr[10] != RADIUS_ARICENT_VOLUME_EXP)
		{
			radius_log_err("%s: vq subtype second=%d\r\n", flw_ptr[10]);
			return -1;
		}

		vq->vq.exponent = flw_ptr[12] << 24 | flw_ptr[13] << 16 | flw_ptr[14] << 8 | flw_ptr[15];
	}

//	vq->vq.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];//for 3gpp2

//	vq->vq.length = length;

	vq->vq.type = RADIUS_3GPP2_PPAQ_SUBTYPE_VQ;

	vq->flag = 1;

	return 0;
}

int radius_parse_vendor_3gpp2_ppaq_sub_attr_vqo(RADIUS_VENDOR_3GPP2_PPAQ_SUB_ATTR_VQO *vqo, const BYTE *flw_ptr, BYTE length)
{
	if (length != RADIUS_VALUE_LEN - 2)
	{
		radius_log_err("%s: vqo length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	vqo->vqo.value = flw_ptr[0] << 8 | flw_ptr[1];

	vqo->vqo.length = length;

	vqo->vqo.type = RADIUS_3GPP2_PPAQ_SUBTYPE_VQO;

	vqo->flag = 1;

	return 0;
}

int radius_parse_vendor_3gpp2_ppaq_sub_attr_vt(RADIUS_VENDOR_3GPP2_PPAQ_SUB_ATTR_VT *vt, const BYTE *flw_ptr, BYTE length)
{
	long long		i;
/*	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: vt length=%d\r\n", __FUNCTION__, length);
		return -1;
	}*/

	if ((length != 10) && (length != 16))
	{
		radius_log_err("%s: vq length=%d\r\n", __FUNCTION__, length);
		return -1;
	}//for aricent


	if (flw_ptr[0] != RADIUS_ARICENT_VOLUME_INT)
	{
		radius_log_err("%s: vt subtype first=%d\r\n", flw_ptr[0]);
		return -1;
	}

	i = flw_ptr[2] << 24 | flw_ptr[3] << 16 | flw_ptr[4] << 8 | flw_ptr[5];

	vt->vt.integer = i << 32 | flw_ptr[6] << 24 | flw_ptr[7] << 16 | flw_ptr[8] << 8 | flw_ptr[9];	

	if (length == 16)
	{
		if (flw_ptr[10] != RADIUS_ARICENT_VOLUME_EXP)
		{
			radius_log_err("%s: vt subtype second=%d\r\n", flw_ptr[10]);
			return -1;
		}

		vt->vt.exponent = flw_ptr[12] << 24 | flw_ptr[13] << 16 | flw_ptr[14] << 8 | flw_ptr[15];
	}

//	vt->vt.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

//	vt->vt.length = length;

	vt->vt.type = RADIUS_3GPP2_PPAQ_SUBTYPE_VT;

	vt->flag = 1;

	return 0;
}

int radius_parse_vendor_3gpp2_ppaq_sub_attr_vto(RADIUS_VENDOR_3GPP2_PPAQ_SUB_ATTR_VTO *vto, const BYTE *flw_ptr, BYTE length)
{
	if (length != RADIUS_VALUE_LEN - 2)
	{
		radius_log_err("%s: vqo length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	vto->vto.value = flw_ptr[0] << 8 | flw_ptr[1];

	vto->vto.length = length;

	vto->vto.type = RADIUS_3GPP2_PPAQ_SUBTYPE_VTO;

	vto->flag = 1;

	return 0;
}

int radius_parse_vendor_3gpp2_ppaq_sub_attr_dq(RADIUS_VENDOR_3GPP2_PPAQ_SUB_ATTR_DQ *dq, const BYTE *flw_ptr, BYTE length)
{
	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: dq length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	dq->dq.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	dq->dq.length = length;

	dq->dq.type = RADIUS_3GPP2_PPAQ_SUBTYPE_DQ;

	dq->flag = 1;

	return 0;
}

int radius_parse_vendor_3gpp2_ppaq_sub_attr_dt(RADIUS_VENDOR_3GPP2_PPAQ_SUB_ATTR_DT *dt, const BYTE *flw_ptr, BYTE length)
{
	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: dt length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	dt->dt.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	dt->dt.length = length;

	dt->dt.type = RADIUS_3GPP2_PPAQ_SUBTYPE_VT;

	dt->flag = 1;

	return 0;
}

int radius_parse_vendor_3gpp2_ppaq_sub_attr_ur(RADIUS_VENDOR_3GPP2_PPAQ_SUB_ATTR_UR *ur, const BYTE *flw_ptr, BYTE length)
{
	if (length != 2)
	{
		radius_log_err("%s: update reason length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	ur->ur.value = flw_ptr[0] << 8 | flw_ptr[1];

	ur->ur.length = length;

	ur->ur.type = RADIUS_3GPP2_PPAQ_SUBTYPE_UR;

	ur->flag = 1;

	return 0;
}

int radius_parse_vendor_3gpp2_ppaq_sub_attr_ps(RADIUS_VENDOR_3GPP2_PPAQ_SUB_ATTR_PS *ps, const BYTE *flw_ptr, BYTE length)
{
	if ((length != 4) && (length != 16))
	{
		radius_log_err("%s: prepaid server addr length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	if (length == 4)
	{
		ps->ps.value = flw_ptr[3] << 24 | flw_ptr[2] << 16 | flw_ptr[1] << 8 | flw_ptr[0];
	}
	else
	{
		radius_log_warn("%s: prepaid server addr is ipv6 not support\r\n", __FUNCTION__);
		return 0;
	}

	ps->ps.length = length;

	ps->ps.type = RADIUS_3GPP2_PPAQ_SUBTYPE_PS;

	ps->flag = 1;

	return 0;
}

int radius_parse_vendor_3gpp2_ppaq(RADIUS_VENDOR_ATTRIBUTE_3GPP2_PPAQ *ppaq, const BYTE *flw_ptr, BYTE length)
{
	BYTE	*ptr = (BYTE *)flw_ptr;

	for (;;)
	{
		if ((ptr - flw_ptr) >= length)
			break;

		switch (ptr[0])
		{
		case RADIUS_3GPP2_PPAQ_SUBTYPE_QID:
			if (radius_parse_vendor_3gpp2_ppaq_sub_attr_qid(&ppaq->qid, ptr + 2, ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute qid parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_3GPP2_PPAQ_SUBTYPE_VQ:
			if (radius_parse_vendor_3gpp2_ppaq_sub_attr_vq(&ppaq->vq, ptr + 2, ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute volume quota parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_3GPP2_PPAQ_SUBTYPE_VQO:
			if (radius_parse_vendor_3gpp2_ppaq_sub_attr_vqo(&ppaq->vqo, ptr + 2, ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute volume quota overflow parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_3GPP2_PPAQ_SUBTYPE_VT:
			if (radius_parse_vendor_3gpp2_ppaq_sub_attr_vt(&ppaq->vt, ptr + 2, ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute volume threshold parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_3GPP2_PPAQ_SUBTYPE_VTO:
			if (radius_parse_vendor_3gpp2_ppaq_sub_attr_vto(&ppaq->vto, ptr + 2, ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute volume threshold overflow parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_3GPP2_PPAQ_SUBTYPE_DQ:
			if (radius_parse_vendor_3gpp2_ppaq_sub_attr_dq(&ppaq->dq, ptr + 2, ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute duration quota parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_3GPP2_PPAQ_SUBTYPE_DT:
			if (radius_parse_vendor_3gpp2_ppaq_sub_attr_dt(&ppaq->dt, ptr + 2, ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute duration threshold parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_3GPP2_PPAQ_SUBTYPE_UR:
			if (radius_parse_vendor_3gpp2_ppaq_sub_attr_ur(&ppaq->ur, ptr + 2, ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute update reason parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_3GPP2_PPAQ_SUBTYPE_PS:
			if (radius_parse_vendor_3gpp2_ppaq_sub_attr_ps(&ppaq->ps, ptr + 2, ptr[1] - 2) < 0)
			{
				radius_log_err("%s: ppaq sub attribute prepaid server parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		default:
			radius_log_warn("%s: ppaq unknow subtype=%d\r\n", __FUNCTION__, ptr[0]);
			break;
		}

		ptr += ptr[1];
	}

	return 0;
}

int radius_parse_vendor_3gpp2_pts_sub_attr_qid(RADIUS_VENDOR_3GPP2_PTS_SUB_ATTR_QID *qid, const BYTE *flw_ptr, BYTE length)
{
	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: qid length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	qid->qid.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	qid->qid.length = length;

	qid->qid.type = RADIUS_3GPP2_PTS_SUBTYPE_QID;

	qid->flag = 1;

	return 0;
}

int radius_parse_vendor_3gpp2_pts_sub_attr_vuats(RADIUS_VENDOR_3GPP2_PTS_SUB_ATTR_VUATS *vuats, const BYTE *flw_ptr, BYTE length)
{
	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: vuats length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	vuats->vuats.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	vuats->vuats.length = length;

	vuats->vuats.type = RADIUS_3GPP2_PTS_SUBTYPE_VUATS;

	vuats->flag = 1;

	return 0;
}

int radius_parse_vendor_3gpp2_pts_sub_attr_vuatso(RADIUS_VENDOR_3GPP2_PTS_SUB_ATTR_VUATSO *vuatso, const BYTE *flw_ptr, BYTE length)
{
	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: vuats length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	vuatso->vuatso.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	vuatso->vuatso.length = length;

	vuatso->vuatso.type = RADIUS_3GPP2_PTS_SUBTYPE_VUATSO;

	vuatso->flag = 1;

	return 0;
}

int radius_parse_vendor_3gpp2_pts_sub_attr_tsi(RADIUS_VENDOR_3GPP2_PTS_SUB_ATTR_TSI *tsi, const BYTE *flw_ptr, BYTE length)
{
	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: tsi length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	tsi->tsi.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	tsi->tsi.length = length;

	tsi->tsi.type = RADIUS_3GPP2_PTS_SUBTYPE_TSI;

	tsi->flag = 1;

	return 0;
}

int radius_parse_vendor_3gpp2_pts_sub_attr_titus(RADIUS_VENDOR_3GPP2_PTS_SUB_ATTR_TITSU *titus, const BYTE *flw_ptr, BYTE length)
{
	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: titus length=%d\r\n", __FUNCTION__, length);
		return -1;
	}

	titus->titsu.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	titus->titsu.length = length;

	titus->titsu.type = RADIUS_3GPP2_PTS_SUBTYPE_TITSU;

	titus->flag = 1;

	return 0;
}


int radius_parse_vendor_3gpp2_pts(RADIUS_VENDOR_ATTRIBUTE_3GPP2_PTS *pts, const BYTE *flw_ptr, BYTE length)
{
	BYTE	*ptr = (BYTE *)flw_ptr;

	for (;;)
	{
		if ((ptr - flw_ptr) >= length)
			break;

		switch (ptr[0])
		{
		case RADIUS_3GPP2_PTS_SUBTYPE_QID:
			if (radius_parse_vendor_3gpp2_pts_sub_attr_qid(&pts->qid, ptr + 2, ptr[1] - 2) < 0)
			{
				radius_log_err("%s: pts sub attribute qid parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_3GPP2_PTS_SUBTYPE_VUATS:
			if (radius_parse_vendor_3gpp2_pts_sub_attr_vuats(&pts->vuats, ptr + 2, ptr[1] - 2) < 0)
			{
				radius_log_err("%s: pts sub attribute vuats parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_3GPP2_PTS_SUBTYPE_VUATSO:
			if (radius_parse_vendor_3gpp2_pts_sub_attr_vuatso(&pts->vuatso, ptr + 2, ptr[1] - 2) < 0)
			{
				radius_log_err("%s: pts sub attribute vuatso parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_3GPP2_PTS_SUBTYPE_TSI:
			if (radius_parse_vendor_3gpp2_pts_sub_attr_tsi(&pts->tsi, ptr + 2, ptr[1] - 2) < 0)
			{
				radius_log_err("%s: pts sub attribute tsi parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		case RADIUS_3GPP2_PTS_SUBTYPE_TITSU:
			if (radius_parse_vendor_3gpp2_pts_sub_attr_titus(&pts->titsu, ptr + 2, ptr[1] - 2) < 0)
			{
				radius_log_err("%s: pts sub attribute titus parse fail\r\n", __FUNCTION__);
				return -1;
			}
			break;
		default:
			radius_log_warn("%s: ppaq unknow subtype=%d\r\n", __FUNCTION__, ptr[0]);
			break;
		}

		ptr += ptr[1];
	}

	return 0;
}

int radius_parse_attr_vendor_specific_value(RADIUS_ATTRIBUTE_VENDOR_SPECIFIC *vendor_specific, const BYTE *flw_ptr, BYTE length)
{
	DWORD		vendor_id;
	BYTE		vendor_type;
	BYTE 		vendor_length;

	vendor_id = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	vendor_type = flw_ptr[4];

	vendor_length = flw_ptr[5];

	switch (vendor_id)
	{
	case RADIUS_VENDOR_ID_3GPP2:
		switch (vendor_type)
		{
		case RADIUS_VENDOR_TYPE_3GPP2_STC:
			if (radius_parse_vendor_3gpp2_stc(&vendor_specific->attribute_3gpp2.stc, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		case RADIUS_VENDOR_TYPE_3GPP2_PPAC:
			if (radius_parse_vendor_3gpp2_ppac(&vendor_specific->attribute_3gpp2.ppac, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		case RADIUS_VENDOR_TYPE_3GPP2_PPAQ:
			if (radius_parse_vendor_3gpp2_ppaq(&vendor_specific->attribute_3gpp2.ppaq, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		case RADIUS_VENDOR_TYPE_3GPP2_PTS:
			if (radius_parse_vendor_3gpp2_pts(&vendor_specific->attribute_3gpp2.pts, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		default:
			radius_log_warn("%s: vendor specific type=%d not support\r\n", __FUNCTION__, vendor_type);
			return 0;
		}
		break;
	case RADIUS_VENDOR_ID_3GPP:
		switch (vendor_type)
		{
		case RADIUS_VENDOR_TYPE_3GPP_IMSI:
			if (radius_parse_vendor_3gpp_imsi(&vendor_specific->attribute_3gpp.imsi, flw_ptr + 6, vendor_length -2) < 0)
				return -1;
			break;
		case RADIUS_VENDOR_TYPE_3GPP_CHARGING_ID:
			if (radius_parse_vendor_3gpp_charging_id(&vendor_specific->attribute_3gpp.charging_id, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		case RADIUS_VENDOR_TYPE_3GPP_PDP_TYPE:
			if (radius_parse_vendor_3gpp_pdp_type(&vendor_specific->attribute_3gpp.pdp_type, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		case RADIUS_VENDOR_TYPE_3GPP_CG_ADDR:
			if (radius_parse_vendor_3gpp_cg_addr(&vendor_specific->attribute_3gpp.cg_addr, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		case RADIUS_VENDOR_TYPE_3GPP_NQP:
			if (radius_parse_vendor_3gpp_nqp(&vendor_specific->attribute_3gpp.negotiated_qos, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		case RADIUS_VENDOR_TYPE_3GPP_SGSN_ADDR:
			if (radius_parse_vendor_3gpp_sgsn_addr(&vendor_specific->attribute_3gpp.sgsn_addr, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		case RADIUS_VENDOR_TYPE_3GPP_GGSN_ADDR:
			if (radius_parse_vendor_3gpp_ggsn_addr(&vendor_specific->attribute_3gpp.ggsn_addr, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		case RADIUS_VENDOR_TYPE_3GPP_IMSI_MCC_MNC:
			if (radius_parse_vendor_3gpp_imsi_mcc_mnc(&vendor_specific->attribute_3gpp.mcc_mnc, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		case RADIUS_VENDOR_TYPE_3GPP_GGSN_MCC_MNC:
			if (radius_parse_vendor_3gpp_ggsn_mcc_mnc(&vendor_specific->attribute_3gpp.ggsn_mcc_mnc, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		case RADIUS_VENDOR_TYPE_3GPP_NSAPI:
			if (radius_parse_vendor_3gpp_nsapi(&vendor_specific->attribute_3gpp.nsapi, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		case RADIUS_VENDOR_TYPE_3GPP_SSI:
			if (radius_parse_vendor_3gpp_ssi(&vendor_specific->attribute_3gpp.ssi, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		case RADIUS_VENDOR_TYPE_3GPP_SM:
			if (radius_parse_vendor_3gpp_sm(&vendor_specific->attribute_3gpp.sm, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		case RADIUS_VENDOR_TYPE_3GPP_CC:
			if (radius_parse_vendor_3gpp_cc(&vendor_specific->attribute_3gpp.cc, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		case RADIUS_VENDOR_TYPE_3GPP_SGSN_MCC_MNC:
			if (radius_parse_vendor_3gpp_sgsn_mcc_mnc(&vendor_specific->attribute_3gpp.sgsn_mcc_mnc, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		default:
			radius_log_warn("%s: vendor specific type=%d not support\r\n", __FUNCTION__, vendor_type);
			return 0;
		}
		break;
	case RADIUS_VENDOR_ID_WIMAX:
		switch (vendor_type)
		{
		case RADIUS_VENDOR_TYPE_PPAC:
			if (radius_parse_vendor_ppac_sub_attr(&vendor_specific->attribute.ppac, flw_ptr + 6, vendor_length - 2) < 0)//flw_ptr: vendor_id 4 bytes vendor type 1 byte vendor length 1 byte
				return -1;
			break;
		case RADIUS_VENDOR_TYPE_STC:
			if (radius_parse_vendor_stc_sub_attr(&vendor_specific->attribute.stc, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		case RADIUS_VENDOR_TYPE_PPAQ:
			if (radius_parse_vendor_ppaq_sub_attr(&vendor_specific->attribute.ppaq, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		case RADIUS_VENDOR_TYPE_PTS:
			if (radius_parse_vendor_pts_sub_attr(&vendor_specific->attribute.pts, flw_ptr + 6, vendor_length - 2) < 0)
				return -1;
			break;
		default:
			radius_log_err("%s: vendor specific type=%d unknow\r\n", __FUNCTION__, vendor_type);
			return -1;
		}
		break;
	default:
		radius_log_err("%s: vendor specific type=%d unknow\r\n", __FUNCTION__, vendor_type);
		return -1;
	}
	vendor_specific->vendor_type = vendor_type;

	vendor_specific->vendor_id = vendor_id;

	vendor_specific->flag = 1;

	return 0;
}

int radius_parse_attr_vendor_specific(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	BYTE								num;
	RADIUS_VENDOR_SPECIFIC				*vendor_specific;
	RADIUS_ATTRIBUTE_VENDOR_SPECIFIC	*vendor_specific_attr;

	if ((length < 5) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s vendor specific length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		vendor_specific = &msg_pdu->msg.access_request.vendor_specific;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		vendor_specific = &msg_pdu->msg.access_accept.vendor_specific;
		break;
	case RADIUS_MSG_TYPE_ACCESS_CHALLENGE:
		vendor_specific = &msg_pdu->msg.access_challenge.vendor_specific;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		vendor_specific = &msg_pdu->msg.accounting_request.vendor_specific;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_RESPONSE:
		vendor_specific = &msg_pdu->msg.accounting_response.vendor_specific;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		vendor_specific = &msg_pdu->msg.disconnect_request.vendor_specific;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with vendor specific\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	if ((num = vendor_specific->num) >= RADIUS_MAX_NUM_OF_VENDOR_SPECIFIC)
	{
		radius_log_warn("%s: recv msg type=%s, no resource for vendor specific\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	vendor_specific_attr = &vendor_specific->vendor_specific[num];

	if (radius_parse_attr_vendor_specific_value(vendor_specific_attr, flw_ptr, length) < 0)
	{
		radius_log_err("%s: parse vendor specific value error\r\n", __FUNCTION__);
		return -1;
	}

	vendor_specific->num++;

	return 0;
}

int radius_parse_attr_session_timeout(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_SESSION_TIMEOUT		*session_timeout;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s session timeout length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		session_timeout = &msg_pdu->msg.access_accept.session_timeout;
		break;
	case RADIUS_MSG_TYPE_ACCESS_CHALLENGE:
		session_timeout = &msg_pdu->msg.access_challenge.session_timeout;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		session_timeout = &msg_pdu->msg.accounting_request.session_timeout;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with session timeout\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	session_timeout->session_timeout.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	session_timeout->session_timeout.length = length;

	session_timeout->session_timeout.type = RADIUS_ATTRIBUTE_TYPE_SESSION_TIMEOUT;

	session_timeout->flag = 1;

	return 0;
}

int radius_parse_attr_idle_timeout(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_IDLE_TIMEOUT		*idle_timeout;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s idle timeout length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		idle_timeout = &msg_pdu->msg.access_accept.idle_timeout;
		break;
	case RADIUS_MSG_TYPE_ACCESS_CHALLENGE:
		idle_timeout = &msg_pdu->msg.access_challenge.idle_timeout;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		idle_timeout = &msg_pdu->msg.accounting_request.idle_timeout;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with idle timeout\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	idle_timeout->idle_timeout.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	idle_timeout->idle_timeout.length = length;

	idle_timeout->idle_timeout.type = RADIUS_ATTRIBUTE_TYPE_IDLE_TIMEOUT;

	idle_timeout->flag = 1;

	return 0;
}

int radius_parse_attr_termination_action(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_TERMINATION_ACTION	*termination_action;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s termination action length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		termination_action = &msg_pdu->msg.access_accept.termination_action;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		termination_action = &msg_pdu->msg.accounting_request.termination_action;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with idle timeout\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	termination_action->termination_action.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	termination_action->termination_action.length = length;

	termination_action->termination_action.type = RADIUS_ATTRIBUTE_TYPE_TERMINATION_ACTION;

	termination_action->flag = 1;

	return 0;
}
/*
int radius_parse_attr_called_station_id(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_CALLED_STATION_ID		*called_station_id;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s called station id length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		called_station_id = &msg_pdu->msg.access_request.called_station_id;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		called_station_id = &msg_pdu->msg.accounting_request.called_station_id;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		called_station_id = &msg_pdu->msg.disconnect_request.called_station_id;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with called station id\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(called_station_id->called_station_id.value, flw_ptr, length);

	called_station_id->called_station_id.length = length;

	called_station_id->called_station_id.type = RADIUS_ATTRIBUTE_TYPE_CALLED_STATION_ID;

	called_station_id->flag = 1;

	return 0;
}*/
static int radius_parse_attr_called_station_id_spit_num(RADIUS_ATTRIBUTE_CALLED_STATION_ID *called_station_id, BYTE *ptr, int length)
{
	//split called list
	int	num = 0, tmp_len = 0, len;
	char *buf = (char *)ptr;
	char *tmp;
	
	while((tmp = strstr(buf, ",")) != NULL)
	{
		tmp[0] = '\0';
		if((len = strlen(buf)) != 0 && len == (tmp - buf))
		{
			called_station_id->called.server.called_station_id[num].length = len;
			memcpy(called_station_id->called.server.called_station_id[num].value, buf, len);
			num++;
		}
		tmp_len += (tmp - buf + 1);
		buf = tmp + 1;
		if(num >= RADIUS_MAX_NUM_OF_NOWSMS_CALLED_ID)
		{
			called_station_id->called.server.num = RADIUS_MAX_NUM_OF_NOWSMS_CALLED_ID;
			radius_log_warn("%s: called count overpass the max\r\n", __FUNCTION__);
			return 0;
		}
	}
	if((len = strlen(buf)) != 0)
	{
		called_station_id->called.server.called_station_id[num].length = len;
		memcpy(called_station_id->called.server.called_station_id[num].value, buf, len);
		num++;
		tmp_len += len;
	}
	if(tmp_len != length)
	{
		radius_log_err("%s: split len=%d, length=%d\r\n", __FUNCTION__, tmp_len, length);
		return -1;
	}
	called_station_id->called.server.num = num;
	radius_log_event("%s: success! length=%d\r\n", __FUNCTION__, length);
	
	return 0;
}
int radius_parse_attr_called_station_id(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	int		num = 0, index, len;
	int		last_2, last_3;
	RADIUS_ATTRIBUTE_CALLED_STATION_ID		*called_station_id;
	char		*tmp_ptr;
	BYTE	buf[RADIUS_MAX_NUM_OF_NOWSMS_CALLED_LIST];
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	
	if(msg_pdu == NULL || flw_ptr == NULL)
		return -1;
	if((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s called station id length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}
	switch (msg_pdu->msg_type)
	{
		case RADIUS_MSG_TYPE_ACCESS_REQUEST:
			called_station_id = &msg_pdu->msg.access_request.called_station_id;
			break;
		case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
			called_station_id = &msg_pdu->msg.accounting_request.called_station_id;
			break;
		case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
			called_station_id = &msg_pdu->msg.disconnect_request.called_station_id;
			break;
		default:
			radius_log_warn("%s: msg type=%s recv msg with called station id\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
			return 0;
	}
	if(length == (tmp_flw_ptr[1]+1) && 0xFF == tmp_flw_ptr[0])
	{
		num++;
		if((tmp_ptr = strstr((char*)tmp_flw_ptr, ",")) == NULL)
		{
			if(tmp_flw_ptr[length-1] != 0xFF)
				num = 0;
		}
	}
	if(num == 0)
	{
		memcpy(called_station_id->called.server.called_station_id[0].value, flw_ptr, length);
		called_station_id->called.server.called_station_id[0].length = length;
		called_station_id->called.server.called_station_id[0].type = RADIUS_ATTRIBUTE_TYPE_CALLED_STATION_ID;
		called_station_id->called.server.num = 0;
		called_station_id->option = 1;
	}
	else		//nowsms
	{
		memset(buf, 0, RADIUS_MAX_NUM_OF_NOWSMS_CALLED_LIST);
		last_2 = RADIUS_MAX_NUM_OF_NOWSMS_CALLED_LIST - 2;	// 1298
		last_3 = RADIUS_MAX_NUM_OF_NOWSMS_CALLED_LIST - 3;	// 1297
		if(tmp_flw_ptr[length-1] == 0xFF)	//end indicator
		{
			if(called_station_id->option == 0)
			{
				memcpy(called_station_id->called.client.called_list, tmp_flw_ptr+2, length-3);
				len = length - 3;
			}
			else if(called_station_id->option == 2)
			{
				index = called_station_id->called.client.called_list[last_2];
				num = called_station_id->called.client.called_list[last_3];
				called_station_id->called.client.called_list[last_2] = 0;
				called_station_id->called.client.called_list[last_3] = 0;
				memcpy(called_station_id->called.client.called_list+RADIUS_NOWSMS_MAX_LEN_OF_PER_CALLED*(num-1), \
					tmp_flw_ptr+2, length-3);
				len = RADIUS_NOWSMS_MAX_LEN_OF_PER_CALLED*(num-1) + length - 3;
				index |= (1 << (num - 1));
				num = (1 << num) - 1;
				if(index != num)
					radius_log_warn("%s: split num(%x), index= %x error!\r\n", __FUNCTION__, num, index);
			}
			memcpy(buf, called_station_id->called.client.called_list, len);
			memset(called_station_id, 0, sizeof(RADIUS_ATTRIBUTE_CALLED_STATION_ID));
			radius_parse_attr_called_station_id_spit_num(called_station_id, buf, len);
			called_station_id->option = 1;
		}
		else
		{
			index = tmp_flw_ptr[length-1] & 0x0F;
			num = (tmp_flw_ptr[length-1] & 0xF0) >> 4;
			if(num > (RADIUS_MAX_NUM_OF_NOWSMS_CALLED_LIST / RADIUS_NOWSMS_MAX_LEN_OF_PER_CALLED + 1))
			{
				num = RADIUS_MAX_NUM_OF_NOWSMS_CALLED_LIST / RADIUS_NOWSMS_MAX_LEN_OF_PER_CALLED + 1;
				radius_log_warn("%s: split num(%d) error!\r\n", __FUNCTION__, num);
			}
			buf[last_3] = num;
			buf[last_2] = 1 << (index - 1);
			if(called_station_id->option == 0)
			{
				memcpy(buf+RADIUS_NOWSMS_MAX_LEN_OF_PER_CALLED*(index-1), tmp_flw_ptr+2, length-3);
				called_station_id->option = 2;
				memcpy(called_station_id->called.client.called_list, buf, RADIUS_MAX_NUM_OF_NOWSMS_CALLED_LIST);
			}
			else if(called_station_id->option == 2)
			{
				if((buf[last_3] == called_station_id->called.client.called_list[last_3]) && \
					((called_station_id->called.client.called_list[last_2] & buf[last_2]) != 0x1))
				{
					called_station_id->called.client.called_list[last_2] |= buf[last_2];
					memcpy(called_station_id->called.client.called_list+RADIUS_NOWSMS_MAX_LEN_OF_PER_CALLED*(index-1), \
						tmp_flw_ptr+2, length-3);
				}
			}
		}
	}
	
	return 0;
}

int radius_parse_attr_calling_station_id(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_CALLING_STATION_ID	*calling_station_id;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s calling station id length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		calling_station_id = &msg_pdu->msg.access_request.calling_station_id;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		calling_station_id = &msg_pdu->msg.accounting_request.calling_station_id;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		calling_station_id = &msg_pdu->msg.disconnect_request.calling_station_id;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with calling station id\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(calling_station_id->calling_station_id.value, flw_ptr, length);

	calling_station_id->calling_station_id.length = length;

	calling_station_id->calling_station_id.type = RADIUS_ATTRIBUTE_TYPE_CALLING_STATION_ID;

	calling_station_id->flag = 1;

	return 0;
}

int radius_parse_attr_nas_identifier(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_NAS_IDENTIFIER		*nas_identifier;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s nas identifier length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		nas_identifier = &msg_pdu->msg.access_request.nas_identifier;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		nas_identifier = &msg_pdu->msg.accounting_request.nas_identifier;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		nas_identifier = &msg_pdu->msg.disconnect_request.nas_identifier;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with nas identifier\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(nas_identifier->nas_identifier.value, flw_ptr, length);

	nas_identifier->nas_identifier.length = length;

	nas_identifier->nas_identifier.type = RADIUS_ATTRIBUTE_TYPE_NAS_IDENTIFIER;

	nas_identifier->flag = 1;

	return 0;
}

int radius_parse_attr_proxy_state(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	BYTE								num;
	RADIUS_PROXY_STATE					*proxy_state;
	RADIUS_ATTRIBUTE_PROXY_STATE		*proxy_state_attr;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s proxy state length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		proxy_state = &msg_pdu->msg.access_request.proxy_state;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		proxy_state = &msg_pdu->msg.access_accept.proxy_state;
		break;
	case RADIUS_MSG_TYPE_ACCESS_REJECT:
		proxy_state = &msg_pdu->msg.access_reject.proxy_state;
		break;
	case RADIUS_MSG_TYPE_ACCESS_CHALLENGE:
		proxy_state = &msg_pdu->msg.access_challenge.proxy_state;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		proxy_state = &msg_pdu->msg.accounting_request.proxy_state;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_RESPONSE:
		proxy_state = &msg_pdu->msg.accounting_response.proxy_state;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_ACK:
		proxy_state = &msg_pdu->msg.disconnect_ack.proxy_state;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_NAK:
		proxy_state = &msg_pdu->msg.disconnect_nak.proxy_state;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with proxy state\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	if ((num = proxy_state->num) >= RADIUS_MAX_NUM_OF_PROXY_STATE)
	{
		radius_log_warn("%s: recv msg type=%s, no resource for proxy state\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	proxy_state_attr = &proxy_state->proxy_state[num];

	memcpy(proxy_state_attr->proxy_state.value, flw_ptr, length);

	proxy_state_attr->proxy_state.length = length;

	proxy_state_attr->proxy_state.type = RADIUS_ATTRIBUTE_TYPE_PROXY_STATE;

	proxy_state_attr->flag = 1;

	proxy_state->num++;

	return 0;
}

int radius_parse_attr_login_lat_service(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_LOGIN_LAT_SERVICE		*login_lat_service;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s login lat service length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		login_lat_service = &msg_pdu->msg.access_request.login_lat_service;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		login_lat_service = &msg_pdu->msg.access_accept.login_lat_service;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		login_lat_service = &msg_pdu->msg.accounting_request.login_lat_service;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with login lat servicer\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(login_lat_service->login_lat_service.value, flw_ptr, length);

	login_lat_service->login_lat_service.length = length;

	login_lat_service->login_lat_service.type = RADIUS_ATTRIBUTE_TYPE_LOGIN_LAT_SERVICE;

	login_lat_service->flag = 1;

	return 0;
}

int radius_parse_attr_login_lat_node(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_LOGIN_LAT_NODE		*login_lat_node;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s login lat node length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		login_lat_node = &msg_pdu->msg.access_request.login_lat_node;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		login_lat_node = &msg_pdu->msg.access_accept.login_lat_node;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		login_lat_node = &msg_pdu->msg.accounting_request.login_lat_node;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with login lat node\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(login_lat_node->login_lat_node.value, flw_ptr, length);

	login_lat_node->login_lat_node.length = length;

	login_lat_node->login_lat_node.type = RADIUS_ATTRIBUTE_TYPE_LOGIN_LAT_NODE;

	login_lat_node->flag = 1;

	return 0;
}

int radius_parse_attr_login_lat_group(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_LOGIN_LAT_GROUP		*login_lat_group;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s login lat group length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		login_lat_group = &msg_pdu->msg.access_request.login_lat_group;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		login_lat_group = &msg_pdu->msg.access_accept.login_lat_group;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		login_lat_group = &msg_pdu->msg.accounting_request.login_lat_group;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with login lat group\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(login_lat_group->login_lat_group.value, flw_ptr, length);

	login_lat_group->login_lat_group.length = length;

	login_lat_group->login_lat_group.type = RADIUS_ATTRIBUTE_TYPE_LOGIN_LAT_GROUP;

	login_lat_group->flag = 1;

	return 0;
}

int radius_parse_attr_framed_appletalk_link(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_FRAMED_APPLETALK_LINK		*framed_appletalk_link;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s framed appletalk link length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		framed_appletalk_link = &msg_pdu->msg.access_accept.framed_appletalk_link;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		framed_appletalk_link = &msg_pdu->msg.accounting_request.framed_appletalk_link;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with framed appletalk link\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	framed_appletalk_link->framed_appletalk_link.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	framed_appletalk_link->framed_appletalk_link.length = length;

	framed_appletalk_link->framed_appletalk_link.type = RADIUS_ATTRIBUTE_TYPE_FRAMED_APPLETALK_LINK;

	framed_appletalk_link->flag = 1;

	return 0;
}

int radius_parse_attr_framed_appletalk_network(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	BYTE											num;
	RADIUS_FRAMED_APPLETALK_NETWORK				*framed_appletalk_network;
	RADIUS_ATTRIBUTE_FRAMED_APPLETALK_NETWORK	*framed_appletalk_network_attr;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s framed appletalk network length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		framed_appletalk_network = &msg_pdu->msg.access_accept.framed_appletalk_network;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		framed_appletalk_network = &msg_pdu->msg.accounting_request.framed_appletalk_network;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with framed appletalk network\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	if ((num = framed_appletalk_network->num) >= RADIUS_MAX_NUM_OF_FRAMED_APPLETALK_NETWORK)
	{
		radius_log_warn("%s: recv msg type=%s, no resource for framed appletalk network\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	framed_appletalk_network_attr = &framed_appletalk_network->framed_appletalk_network[num];

	framed_appletalk_network_attr->framed_appletalk_network.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	framed_appletalk_network_attr->framed_appletalk_network.length = length;

	framed_appletalk_network_attr->framed_appletalk_network.type = RADIUS_ATTRIBUTE_TYPE_FRAMED_APPLETALK_NETWORK;

	framed_appletalk_network_attr->flag = 1;

	framed_appletalk_network->num++;

	return 0;
}

int radius_parse_attr_framed_appletalk_zone(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_FRAMED_APPLETALK_ZONE	*framed_appletalk_zone;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s framed appletalk zone length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		framed_appletalk_zone = &msg_pdu->msg.access_accept.framed_appletalk_zone;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		framed_appletalk_zone = &msg_pdu->msg.accounting_request.framed_appletalk_zone;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with framed appletalk zone\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(framed_appletalk_zone->framed_appletalk_zone.value, flw_ptr, length);

	framed_appletalk_zone->framed_appletalk_zone.length = length;

	framed_appletalk_zone->framed_appletalk_zone.type = RADIUS_ATTRIBUTE_TYPE_FRAMED_APPLETALK_ZONE;

	framed_appletalk_zone->flag = 1;

	return 0;
}

int radius_parse_attr_acct_status_type(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_ACCT_STATUS_TYPE		*acct_status_type;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s acct status type length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		acct_status_type = &msg_pdu->msg.accounting_request.acct_status_type;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with acct status type\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	acct_status_type->acct_status_type.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	acct_status_type->acct_status_type.length = length;

	acct_status_type->acct_status_type.type = RADIUS_ATTRIBUTE_TYPE_ACCT_STATUS_TYPE;

	acct_status_type->flag = 1;

	return 0;
}

int radius_parse_attr_acct_delay_time(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_ACCT_DELAY_TIME	*acct_delay_time;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s acct delay time length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		acct_delay_time = &msg_pdu->msg.accounting_request.acct_delay_time;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with acct delay time\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	acct_delay_time->acct_delay_time.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	acct_delay_time->acct_delay_time.length = length;

	acct_delay_time->acct_delay_time.type = RADIUS_ATTRIBUTE_TYPE_ACCT_DELAY_TIME;

	acct_delay_time->flag = 1;

	return 0;
}

int radius_parse_attr_acct_input_octets(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_ACCT_INPUT_OCTETS	*acct_input_octets;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s acct input octets length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		acct_input_octets = &msg_pdu->msg.accounting_request.acct_input_octets;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with acct input octets\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	acct_input_octets->acct_input_octets.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	acct_input_octets->acct_input_octets.length = length;

	acct_input_octets->acct_input_octets.type = RADIUS_ATTRIBUTE_TYPE_ACCT_INPUT_OCTETS;

	acct_input_octets->flag = 1;

	return 0;
}

int radius_parse_attr_acct_output_octets(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_ACCT_OUTPUT_OCTETS	*acct_output_octets;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s acct output octets length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		acct_output_octets= &msg_pdu->msg.accounting_request.acct_output_octets;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with acct output octets\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	acct_output_octets->acct_output_octets.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	acct_output_octets->acct_output_octets.length = length;

	acct_output_octets->acct_output_octets.type = RADIUS_ATTRIBUTE_TYPE_ACCT_OUTPUT_OCTETS;

	acct_output_octets->flag = 1;

	return 0;
}

int radius_parse_attr_acct_session_id(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_ACCT_SESSION_ID	*acct_session_id;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s acct session id length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		acct_session_id= &msg_pdu->msg.access_request.acct_session_id;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		acct_session_id= &msg_pdu->msg.accounting_request.acct_session_id;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		acct_session_id = &msg_pdu->msg.disconnect_request.acct_session_id;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with acct session id\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(acct_session_id->acct_session_id.value, flw_ptr, length);

	acct_session_id->acct_session_id.length = length;

	acct_session_id->acct_session_id.type = RADIUS_ATTRIBUTE_TYPE_ACCT_SESSION_ID;

	acct_session_id->flag = 1;

	return 0;
}

int radius_parse_attr_acct_authentic(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_ACCT_AUTHENTIC	*acct_authentic;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s acct authentic length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		acct_authentic = &msg_pdu->msg.accounting_request.acct_authentic;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with acct authentic\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	acct_authentic->acct_authentic.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	acct_authentic->acct_authentic.length = length;

	acct_authentic->acct_authentic.type = RADIUS_ATTRIBUTE_TYPE_ACCT_AUTHENTIC;

	acct_authentic->flag = 1;

	return 0;
}

int radius_parse_attr_acct_session_time(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_ACCT_SESSION_TIME	*acct_session_time;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s acct session time length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		acct_session_time = &msg_pdu->msg.accounting_request.acct_session_time;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with acct session time\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	acct_session_time->acct_session_time.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	acct_session_time->acct_session_time.length = length;

	acct_session_time->acct_session_time.type = RADIUS_ATTRIBUTE_TYPE_ACCT_SESSION_TIME;

	acct_session_time->flag = 1;

	return 0;
}

int radius_parse_attr_acct_input_packets(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_ACCT_INPUT_PACKETS	*acct_input_packets;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s acct input packets length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		acct_input_packets = &msg_pdu->msg.accounting_request.acct_input_packets;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with acct input packets\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	acct_input_packets->acct_input_packets.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	acct_input_packets->acct_input_packets.length = length;

	acct_input_packets->acct_input_packets.type = RADIUS_ATTRIBUTE_TYPE_ACCT_INPUT_PACKETS;

	acct_input_packets->flag = 1;

	return 0;
}

int radius_parse_attr_acct_output_packets(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_ACCT_OUTPUT_PACKETS		*acct_output_packets;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s acct output packets length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		acct_output_packets= &msg_pdu->msg.accounting_request.acct_output_packets;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with acct output packets\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	acct_output_packets->acct_output_packets.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	acct_output_packets->acct_output_packets.length = length;

	acct_output_packets->acct_output_packets.type = RADIUS_ATTRIBUTE_TYPE_ACCT_OUTPUT_PACKETS;

	acct_output_packets->flag = 1;

	return 0;
}

int radius_parse_attr_acct_terminate_cause(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_ACCT_TERMINATE_CAUSE		*acct_terminate_cause;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s acct terminate cause length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		acct_terminate_cause= &msg_pdu->msg.accounting_request.acct_terminate_cause;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		acct_terminate_cause = &msg_pdu->msg.disconnect_request.acct_terminate_cause;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_ACK:
		acct_terminate_cause = &msg_pdu->msg.disconnect_ack.acct_terminate_cause;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with acct input packets\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	acct_terminate_cause->acct_terminate_cause.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	acct_terminate_cause->acct_terminate_cause.length = length;

	acct_terminate_cause->acct_terminate_cause.type = RADIUS_ATTRIBUTE_TYPE_ACCT_TERMINATE_CAUSE;

	acct_terminate_cause->flag = 1;

	return 0;
}

int radius_parse_attr_acct_multi_session_id(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	BYTE										num;
	RADIUS_ACCT_MULTI_SESSION_ID				*acct_multi_session_id;
	RADIUS_ATTRIBUTE_ACCT_MULTI_SESSION_ID	*acct_multi_session_id_attr;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s acct session id length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		acct_multi_session_id = &msg_pdu->msg.accounting_request.acct_multi_session_id;

		if ((num = acct_multi_session_id->num) >= RADIUS_MAX_NUM_OF_ACCT_MULTI_SESSION_ID)
		{
			radius_log_warn("%s: accounting request acct multi session id num=%d, no resource for acct multi session id\r\n", __FUNCTION__, num);
			return 0;
		}

		acct_multi_session_id_attr = &acct_multi_session_id->acct_multi_session_id[num];

		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		acct_multi_session_id_attr = &msg_pdu->msg.disconnect_request.acct_multi_session_id;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with acct multi session id\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(acct_multi_session_id_attr->acct_multi_session_id.value, flw_ptr, length);

	acct_multi_session_id_attr->acct_multi_session_id.length = length;

	acct_multi_session_id_attr->acct_multi_session_id.type = RADIUS_ATTRIBUTE_TYPE_ACCT_MULTI_SESSION_ID;

	acct_multi_session_id_attr->flag = 1;

	if (msg_pdu->msg_type == RADIUS_MSG_TYPE_ACCOUNTING_REQUEST)
	{
		acct_multi_session_id->num++;
	}

	return 0;
}

int radius_parse_attr_acct_link_count(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	BYTE								num;
	RADIUS_ACCT_LINK_COUNT			*acct_link_count;
	RADIUS_ATTRIBUTE_ACCT_LINK_COUNT	*acct_link_count_attr;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s acct link count length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		acct_link_count = &msg_pdu->msg.accounting_request.acct_link_count;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with acct link count\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	if ((num = acct_link_count->num) >= RADIUS_MAX_NUM_OF_ACCT_LINK_COUNT)
	{
		radius_log_warn("%s: msg type=%s acct link cout num=%d, no resource for acct link count\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), num);
		return 0;
	}

	acct_link_count_attr = &acct_link_count->acct_link_count[num];

	acct_link_count_attr->acct_link_count.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	acct_link_count_attr->acct_link_count.length = length;

	acct_link_count_attr->acct_link_count.type = RADIUS_ATTRIBUTE_TYPE_ACCT_LINK_COUNT;

	acct_link_count_attr->flag = 1;

	acct_link_count->num++;

	return 0;
}

int radius_parse_attr_event_timestamp(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_EVENT_TIMESTAMP		*event_timestamp;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s event timestamp length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		event_timestamp = &msg_pdu->msg.disconnect_request.event_timestamp;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_ACK:
		event_timestamp = &msg_pdu->msg.disconnect_ack.event_timestamp;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_NAK:
		event_timestamp = &msg_pdu->msg.disconnect_nak.event_timestamp;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with event timestamp\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	event_timestamp->event_timestamp.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	event_timestamp->event_timestamp.length = length;

	event_timestamp->event_timestamp.type = RADIUS_ATTRIBUTE_TYPE_EVENT_TIMESTAMP;

	event_timestamp->flag = 1;

	return 0;
}

int radius_parse_attr_chap_challenge(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_CHAP_CHALLENGE		*chap_challenge;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s chap challenge length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		chap_challenge = &msg_pdu->msg.access_request.chap_challenge;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with chap challenge\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(chap_challenge->chap_challenge.value, flw_ptr, length);

	chap_challenge->chap_challenge.length = length;

	chap_challenge->chap_challenge.type = RADIUS_ATTRIBUTE_TYPE_CHAP_CHALLENGE;

	chap_challenge->flag = 1;

	return 0;
}

int radius_parse_attr_nas_port_type(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_NAS_PORT_TYPE		*nas_port_type;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s nas port type length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		nas_port_type = &msg_pdu->msg.access_request.nas_port_type;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		nas_port_type = &msg_pdu->msg.accounting_request.nas_port_type;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		nas_port_type = &msg_pdu->msg.disconnect_request.nas_port_type;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with nas port type\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	nas_port_type->nas_port_type.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	nas_port_type->nas_port_type.length = length;

	nas_port_type->nas_port_type.type = RADIUS_ATTRIBUTE_TYPE_NAS_PORT_TYPE;

	nas_port_type->flag = 1;

	return 0;
}

int radius_parse_attr_port_limit(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_PORT_LIMIT		*port_limit;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s port limit length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		port_limit = &msg_pdu->msg.access_request.port_limit;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		port_limit = &msg_pdu->msg.access_accept.port_limit;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		port_limit= &msg_pdu->msg.accounting_request.port_limit;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with port limit\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	port_limit->port_limit.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	port_limit->port_limit.length = length;

	port_limit->port_limit.type = RADIUS_ATTRIBUTE_TYPE_PORT_LIMIT;

	port_limit->flag = 1;

	return 0;
}

int radius_parse_attr_login_lat_port(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_LOGIN_LAT_PORT	*login_lat_port;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s login lat port length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		login_lat_port = &msg_pdu->msg.access_request.login_lat_port;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		login_lat_port = &msg_pdu->msg.access_accept.login_lat_port;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		login_lat_port = &msg_pdu->msg.accounting_request.login_lat_port;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with login lat port\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(login_lat_port->login_lat_port.value, flw_ptr, length);

	login_lat_port->login_lat_port.length = length;

	login_lat_port->login_lat_port.type = RADIUS_ATTRIBUTE_TYPE_LOGIN_LAT_PORT;

	login_lat_port->flag = 1;

	return 0;
}

int radius_parse_attr_arap_password(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_ARAP_PASSWORD		*arap_password;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s arap password length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		arap_password = &msg_pdu->msg.access_request.arap_password;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with arap password\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(arap_password->arap_password.value, flw_ptr, length);

	arap_password->arap_password.length = length;

	arap_password->arap_password.type = RADIUS_ATTRIBUTE_TYPE_ARAP_PASSWORD;

	arap_password->flag = 1;

	return 0;
}

int radius_parse_attr_arap_features(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_ARAP_FEATURES		*arap_features;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s arap feature length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		arap_features = &msg_pdu->msg.access_accept.arap_features;
		break;
	case RADIUS_MSG_TYPE_ACCESS_CHALLENGE:
		arap_features = &msg_pdu->msg.access_challenge.arap_features;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with arap feature\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(arap_features->arap_features.value, flw_ptr, length);

	arap_features->arap_features.length = length;

	arap_features->arap_features.type = RADIUS_ATTRIBUTE_TYPE_ARAP_FEATURES;

	arap_features->flag = 1;

	return 0;
}

int radius_parse_attr_arap_zone_access(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_ARAP_ZONE_ACCESS		*arap_zone_access;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s arap zone access length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		arap_zone_access = &msg_pdu->msg.access_accept.arap_zone_access;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with arap zone access\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	arap_zone_access->arap_zone_access.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	arap_zone_access->arap_zone_access.length = length;

	arap_zone_access->arap_zone_access.type = RADIUS_ATTRIBUTE_TYPE_ARAP_ZONE_ACCESS;

	arap_zone_access->flag = 1;

	return 0;
}

int radius_parse_attr_arap_security(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_ARAP_SECURITY		*arap_security;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s arap security access length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		arap_security = &msg_pdu->msg.access_request.arap_security;
		break;
	case RADIUS_MSG_TYPE_ACCESS_CHALLENGE:
		arap_security = &msg_pdu->msg.access_challenge.arap_security;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with arap security access\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	arap_security->arap_security.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	arap_security->arap_security.length = length;

	arap_security->arap_security.type = RADIUS_ATTRIBUTE_TYPE_ARAP_SECURITY;

	arap_security->flag = 1;

	return 0;
}

int radius_parse_attr_arap_security_data(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	BYTE									num;
	RADIUS_ARAP_SECURITY_DATA				*arap_security_data;
	RADIUS_ATTRIBUTE_ARAP_SECURITY_DATA	*arap_security_data_attr;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s arap security data length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		arap_security_data = &msg_pdu->msg.access_request.arap_security_data;
		break;
	case RADIUS_MSG_TYPE_ACCESS_CHALLENGE:
		arap_security_data = &msg_pdu->msg.access_challenge.arap_security_data;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with arap security data\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	if ((num = arap_security_data->num) >= RADIUS_MAX_NUM_OF_ARAP_SECURITY_DATA)
	{
		radius_log_warn("%s: recv msg type=%s, no resource for arap security data\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	arap_security_data_attr = &arap_security_data->arap_security_data[num];

	memcpy(arap_security_data_attr->arap_security_data.value, flw_ptr, length);

	arap_security_data_attr->arap_security_data.length = length;

	arap_security_data_attr->arap_security_data.type = RADIUS_ATTRIBUTE_TYPE_ARAP_SECURITY_DATA;

	arap_security_data_attr->flag = 1;

	arap_security_data->num++;

	return 0;
}

int radius_parse_attr_password_retry(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_PASSWORD_RETRY	*password_retry;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s password retry length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REJECT:
		password_retry = &msg_pdu->msg.access_reject.password_retry;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with password retry\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	password_retry->password_retry.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	password_retry->password_retry.length = length;

	password_retry->password_retry.type = RADIUS_ATTRIBUTE_TYPE_PASSWORD_RETRY;

	password_retry->flag = 1;

	return 0;
}

int radius_parse_attr_prompt(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_PROMPT	*prompt;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s password retry length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_CHALLENGE:
		prompt = &msg_pdu->msg.access_challenge.prompt;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with prompt\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	prompt->prompt.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	prompt->prompt.length = length;

	prompt->prompt.type = RADIUS_ATTRIBUTE_TYPE_PROMPT;

	prompt->flag = 1;

	return 0;
}

int radius_parse_attr_connect_info(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_CONNECT_INFO		*connect_info;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s connect info length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		connect_info = &msg_pdu->msg.access_request.connect_info;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with connect info\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(connect_info->connect_info.value, flw_ptr, length);

	connect_info->connect_info.length = length;

	connect_info->connect_info.type = RADIUS_ATTRIBUTE_TYPE_CONNECT_INFO;

	connect_info->flag = 1;

	return 0;
}

int radius_parse_attr_configuration_token(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	BYTE										num;
	RADIUS_CONFIGURATION_TOKEN				*configuration_token;
	RADIUS_ATTRIBUTE_CONFIGURATION_TOKEN		*configuration_token_attr;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s configuration token length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		configuration_token = &msg_pdu->msg.access_accept.configuration_token;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with configuration token\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	if ((num = configuration_token->num) >= RADIUS_MAX_NUM_OF_CONFIGURATION_TOKEN)
	{
		radius_log_warn("%s: msg type=%s configuration token num=%d, no resource for configuration token\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), num);
		return 0;
	}

	configuration_token_attr = &configuration_token->configuration_token[num];

	memcpy(configuration_token_attr->configuration_token.value, flw_ptr, length);

	configuration_token_attr->configuration_token.length = length;

	configuration_token_attr->configuration_token.type = RADIUS_ATTRIBUTE_TYPE_CONFIGURATION_TOKEN;

	configuration_token_attr->flag = 1;

	configuration_token->num++;

	return 0;
}

int radius_parse_attr_eap_message(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	BYTE								num;
	RADIUS_EAP_MESSAGE					*eap_message;
	RADIUS_ATTRIBUTE_EAP_MESSAGE		*eap_message_attr;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s eap message length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		eap_message = &msg_pdu->msg.access_request.eap_message;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		eap_message = &msg_pdu->msg.access_accept.eap_message;
		break;
	case RADIUS_MSG_TYPE_ACCESS_REJECT:
		eap_message = &msg_pdu->msg.access_reject.eap_message;
		break;
	case RADIUS_MSG_TYPE_ACCESS_CHALLENGE:
		eap_message = &msg_pdu->msg.access_challenge.eap_message;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		eap_message = &msg_pdu->msg.disconnect_request.eap_message;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_ACK:
		eap_message_attr = &msg_pdu->msg.disconnect_ack.eap_message;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with eap message\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	if (msg_pdu->msg_type != RADIUS_MSG_TYPE_DISCONNECT_ACK)
	{
		if ((num = eap_message->num) >= RADIUS_MAX_NUM_OF_EAP_MESSAGE)
		{
			radius_log_warn("%s: msg type=%s eap message num=%d, no resource for eap message\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), num);
			return 0;
		}

		eap_message_attr = &eap_message->eap_message[num];
	}

	memcpy(eap_message_attr->eap_message.value, flw_ptr, length);

	eap_message_attr->eap_message.length = length;

	eap_message_attr->eap_message.type = RADIUS_ATTRIBUTE_TYPE_EAP_MESSAGE;

	eap_message_attr->flag = 1;

	eap_message->num++;

	return 0;
}

int radius_parse_attr_message_authenticator(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_MESSAGE_AUTHENTICATOR	*message_authenticator;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s message authenticator length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		message_authenticator = &msg_pdu->msg.access_request.message_authenticator;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		message_authenticator = &msg_pdu->msg.access_accept.message_authenticator;
		break;
	case RADIUS_MSG_TYPE_ACCESS_REJECT:
		message_authenticator = &msg_pdu->msg.access_reject.message_authenticator;
		break;
	case RADIUS_MSG_TYPE_ACCESS_CHALLENGE:
		message_authenticator = &msg_pdu->msg.access_challenge.message_authenticator;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		message_authenticator = &msg_pdu->msg.disconnect_request.message_authenticator;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_ACK:
		message_authenticator = &msg_pdu->msg.disconnect_ack.message_authenticator;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_NAK:
		message_authenticator = &msg_pdu->msg.disconnect_nak.message_authenticator;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with message authenticator\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(message_authenticator->message_authenticator.value, flw_ptr, length);

	message_authenticator->message_authenticator.length = length;

	message_authenticator->message_authenticator.type = RADIUS_ATTRIBUTE_TYPE_MESSAGE_AUTHENTICATOR;

	message_authenticator->flag = 1;

	return 0;
}

int radius_parse_attr_arap_challenge_response(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_ARAP_CHALLENGE_RESPONSE	*arap_challenge_response;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s arap challenge response length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		arap_challenge_response = &msg_pdu->msg.access_accept.arap_challenge_response;
		break;
	case RADIUS_MSG_TYPE_ACCESS_CHALLENGE:
		arap_challenge_response = &msg_pdu->msg.access_challenge.arap_challenge_response;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with arap challenge response\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(arap_challenge_response->arap_challenge_response.value, flw_ptr, length);

	arap_challenge_response->arap_challenge_response.length = length;

	arap_challenge_response->arap_challenge_response.type = RADIUS_ATTRIBUTE_TYPE_ARAP_CHALLENGE_RESPONSE;

	arap_challenge_response->flag = 1;

	return 0;
}

int radius_parse_attr_acct_interim_interval(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_ACCT_INTERIM_INTERVAL		*acct_interim_interval;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s acct interim interval length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		acct_interim_interval = &msg_pdu->msg.access_accept.acct_interim_interval;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with acct interim interval\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	acct_interim_interval->acct_interim_interval.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	acct_interim_interval->acct_interim_interval.length = length;

	acct_interim_interval->acct_interim_interval.type = RADIUS_ATTRIBUTE_TYPE_ACCT_INTERIM_INTERVAL;

	acct_interim_interval->flag = 1;

	return 0;
}

int radius_parse_attr_nas_port_id(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_NAS_PORT_ID	*nas_port_id;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s nas port id length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		nas_port_id = &msg_pdu->msg.access_request.nas_port_id;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		nas_port_id = &msg_pdu->msg.disconnect_request.nas_port_id;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with nas port id\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(nas_port_id->nas_port_id.value, flw_ptr, length);

	nas_port_id->nas_port_id.length = length;

	nas_port_id->nas_port_id.type = RADIUS_ATTRIBUTE_TYPE_NAS_PORT_ID;

	nas_port_id->flag = 1;

	return 0;
}

int radius_parse_attr_framed_pool(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_FRAMED_POOL		*framed_pool;

	if ((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s framed pool length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		framed_pool = &msg_pdu->msg.access_accept.framed_pool;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with framed pool\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(framed_pool->framed_pool.value, flw_ptr, length);

	framed_pool->framed_pool.length = length;

	framed_pool->framed_pool.type = RADIUS_ATTRIBUTE_TYPE_FRAMED_POOL;

	framed_pool->flag = 1;

	return 0;
}

int radius_parse_attr_error_cause(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	int								num;
	RADIUS_ERROR_CAUSE			*error_cause;
	RADIUS_ATTRIBUTE_ERROR_CAUSE	*error_cause_attr;

	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: msg type=%s error cause length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_DISCONNECT_ACK:
		error_cause = &msg_pdu->msg.disconnect_ack.error_cause;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_NAK:
		error_cause = &msg_pdu->msg.disconnect_nak.error_cause;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with error cause\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	if ((num = error_cause->num) >= RADIUS_MAX_NUM_OF_ERROR_CAUSE)
	{
		radius_log_warn("%s: msg type=%s error cause num=%d, no resource for error cause\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), num);
		return 0;
	}

	error_cause_attr = &error_cause->error_cause[num];

	error_cause_attr->error_cause.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];

	error_cause_attr->error_cause.length = length;

	error_cause_attr->error_cause.type = RADIUS_ATTRIBUTE_TYPE_ERROR_CAUSE;

	error_cause_attr->flag = 1;

	error_cause->num++;

	return 0;
}

/*
int radius_parse_attr_nowsms_preauth_type(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_NOWSMS_PREAUTH_TYPE	*pre_auth_type;

	if((length == 0) || (length > RADIUS_TS_VALUE_LEN))
	{
		radius_log_err("%s: msg type=%s nowsms preauth type length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		pre_auth_type = &msg_pdu->msg.access_request.pre_auth_type;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with pre auth type for nowsms\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	memcpy(pre_auth_type->pre_auth_type.value, flw_ptr+2, length);
	pre_auth_type->pre_auth_type.length = length-2;
	pre_auth_type->pre_auth_type.type = flw_ptr[0];
	pre_auth_type->flag = 1;
	pre_auth_type->type = RADIUS_ATTRIBUTE_TYPE_NOWSMS_PREAUTH_TYPE;

	return 0;
}*/
int radius_parse_attr_nowsms_preauth_type(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	RADIUS_ATTRIBUTE_NOWSMS_PREAUTH_TYPE	*pre_auth_type;

	if(length != 1)
	{
		radius_log_err("%s: msg type=%s nowsms preauth type length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		pre_auth_type = &msg_pdu->msg.access_request.pre_auth_type;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with pre auth type for nowsms\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	pre_auth_type->pre_auth_type.value = flw_ptr[0];
	pre_auth_type->pre_auth_type.length = length;
	pre_auth_type->pre_auth_type.type = RADIUS_ATTRIBUTE_TYPE_NOWSMS_PREAUTH_TYPE;
	pre_auth_type->flag = 1;

	return 0;
}

static int radius_parse_attr_nowsms_msg_count(RADIUS_ATTRIBUTE_NOWSMS_MSG_COUNT *msg_count, const BYTE *flw_ptr, BYTE length)
{
	if (length != 1)
	{
		radius_log_err("%s: nowsms msg count length=%d\r\n", __FUNCTION__, length);
		return -1;
	}
	msg_count->flag = 1;
	msg_count->msg_count.value = flw_ptr[0];
	msg_count->msg_count.length = length;
	msg_count->msg_count.type = RADIUS_ATTRIBUTE_TYPE_NOWSMS_SUB_MSGCOUNT;

	return 0;
}
static int radius_parse_attr_nowsms_msg_id(RADIUS_ATTRIBUTE_NOWSMS_MSG_ID *msg_id, const BYTE *flw_ptr, BYTE length)
{
	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: nowsms msg id length=%d\r\n", __FUNCTION__, length);
		return -1;
	}
	msg_id->flag = 1;
	msg_id->msg_id.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];
	msg_id->msg_id.length = length;
	msg_id->msg_id.type = RADIUS_ATTRIBUTE_TYPE_NOWSMS_SUB_MSGID;

	return 0;
}
static int radius_parse_attr_nowsms_size(RADIUS_ATTRIBUTE_NOWSMS_SIZE *size, const BYTE *flw_ptr, BYTE length)
{
	if (length != RADIUS_VALUE_LEN)
	{
		radius_log_err("%s: nowsms size length=%d\r\n", __FUNCTION__, length);
		return -1;
	}
	size->flag = 1;
	size->size.value = flw_ptr[0] << 24 | flw_ptr[1] << 16 | flw_ptr[2] << 8 | flw_ptr[3];
	size->size.length = length;
	size->size.type = RADIUS_ATTRIBUTE_TYPE_NOWSMS_SUB_SIZE;

	return 0;
}
int radius_parse_attr_nowsms_count_id_size(RADIUS_MSG *msg_pdu, const BYTE *flw_ptr, BYTE length)
{
	BYTE *sub_ptr;
	RADIUS_ATTRIBUTE_NOWSMS_COUNT_ID_SIZE	*count_id_size;

	if (length < 3 || length > 15)
	{
		radius_log_err("%s: msg type=%s nowsms count id size length=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type), length);
		return -1;
	}

	switch (msg_pdu->msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		count_id_size = &msg_pdu->msg.access_request.count_id_size;
		break;
	default:
		radius_log_warn("%s: msg type=%s recv msg with nowsms count id size for nowsms\r\n", __FUNCTION__, radius_get_msg_str(msg_pdu->msg_type));
		return 0;
	}

	count_id_size->type = RADIUS_ATTRIBUTE_TYPE_NOWSMS_COUNT_ID_SIZE;

	count_id_size->flag = 1;

	sub_ptr = (BYTE*)flw_ptr;
	for(;;)
	{
		if((sub_ptr - flw_ptr) >= length)
			break;
		switch(sub_ptr[0])
		{
			case RADIUS_ATTRIBUTE_TYPE_NOWSMS_SUB_MSGCOUNT:
				if(radius_parse_attr_nowsms_msg_count(&count_id_size->msg_count, sub_ptr+2, sub_ptr[1]-2) < 0)
				{
					radius_log_err("%s: nowsms sub attribute msg_count parse fail\r\n", __FUNCTION__);
					return -1;
				}
				break;
			case RADIUS_ATTRIBUTE_TYPE_NOWSMS_SUB_MSGID:
				if(radius_parse_attr_nowsms_msg_id(&count_id_size->msg_id, sub_ptr+2, sub_ptr[1]-2) < 0)
				{
					radius_log_err("%s: nowsms sub attribute msg_id parse fail\r\n", __FUNCTION__);
					return -1;
				}
				break;
			case RADIUS_ATTRIBUTE_TYPE_NOWSMS_SUB_SIZE:
				if(radius_parse_attr_nowsms_size(&count_id_size->size, sub_ptr+2, sub_ptr[1]-2) < 0)
				{
					radius_log_err("%s: nowsms sub attribute size parse fail\r\n", __FUNCTION__);
					return -1;
				}
				break;
			default:
				radius_log_warn("%s: nowsms unknow subtype=%d\r\n", __FUNCTION__, sub_ptr[0]);
				return 0;
		}
		sub_ptr += sub_ptr[1];
	}

	return 0;
}


int radius_parse_access_request_attr(BYTE *msg, int msg_len, int *msg_auth_attr_offset)
{
	BYTE			attr_type;
	BYTE			*flw_pt  = msg + 20;//attribute begin from the 20th byte of the msg

	radius_msg_pdu.msg_type = RADIUS_MSG_TYPE_ACCESS_REQUEST;

	for (;;)
	{
		if (flw_pt - msg >= msg_len)
			break;

		attr_type = flw_pt[0];

		if (radius_attr_parse_function[attr_type].parse_function != NULL)
		{
			if (radius_attr_parse_function[attr_type].parse_function(&radius_msg_pdu, flw_pt + 2, flw_pt[1] - 2) < 0)
			{
				radius_log_err("%s: parse attribute=%d fail\r\n", __FUNCTION__, attr_type);
				return -1;
			}
		}
		else
		{
			radius_log_warn("%s: no parse function for attribute=%d\r\n", __FUNCTION__, attr_type);
		}

		if (attr_type == RADIUS_ATTRIBUTE_TYPE_MESSAGE_AUTHENTICATOR)
		{
			*msg_auth_attr_offset = flw_pt - msg;
		}

		flw_pt += flw_pt[1];
	}

	if ((radius_msg_pdu.msg.access_request.nas_identifier.flag != 1) && (radius_msg_pdu.msg.access_request.nas_ip_addr.flag != 1))
	{
		radius_log_err("%s: Either NAS-IP-Address or NAS-Identifier MUST be present in an Access-Request\r\n", __FUNCTION__);
		return -1;
	}

	return 0;
}

int radius_parse_access_accept_attr(BYTE *msg, int msg_len, int *msg_auth_attr_offset)
{
	BYTE						attr_type;
	BYTE						*flw_pt  = msg + 20;//attribute begin from the 20th byte of the msg

	radius_msg_pdu.msg_type = RADIUS_MSG_TYPE_ACCESS_ACCEPT;

	for (;;)
	{
		if (flw_pt - msg >= msg_len)
			break;

		attr_type = flw_pt[0];

		if (radius_attr_parse_function[attr_type].parse_function != NULL)
		{
			if (radius_attr_parse_function[attr_type].parse_function(&radius_msg_pdu, flw_pt + 2, flw_pt[1] - 2) < 0)
			{
				radius_log_err("%s: parse attribute=%d fail\r\n", __FUNCTION__, attr_type);
				return -1;
			}
		}
		else
		{
			radius_log_warn("%s: no parse function for attribute=%d\r\n", __FUNCTION__, attr_type);
		}

		if (attr_type == RADIUS_ATTRIBUTE_TYPE_MESSAGE_AUTHENTICATOR)
		{
			*msg_auth_attr_offset = flw_pt - msg;
		}

		flw_pt += flw_pt[1];
	}

	return 0;
}

int radius_parse_access_reject_attr(BYTE *msg, int msg_len, int *msg_auth_attr_offset)
{
	BYTE						attr_type;
	BYTE						*flw_pt  = msg + 20;//attribute begin from the 20th byte of the msg

	radius_msg_pdu.msg_type = RADIUS_MSG_TYPE_ACCESS_REJECT;

	for (;;)
	{
		if (flw_pt - msg >= msg_len)
			break;

		attr_type = flw_pt[0];

		if (radius_attr_parse_function[attr_type].parse_function != NULL)
		{
			if (radius_attr_parse_function[attr_type].parse_function(&radius_msg_pdu, flw_pt + 2, flw_pt[1] - 2) < 0)
			{
				radius_log_err("%s: parse attribute=%d fail\r\n", __FUNCTION__, attr_type);
				return -1;
			}
		}
		else
		{
			radius_log_warn("%s: no parse function for attribute=%d\r\n", __FUNCTION__, attr_type);
		}

		if (attr_type == RADIUS_ATTRIBUTE_TYPE_MESSAGE_AUTHENTICATOR)
		{
			*msg_auth_attr_offset = flw_pt - msg;
		}

		flw_pt += flw_pt[1];
	}

	return 0;
}

int radius_parse_access_challenge_attr(BYTE *msg, int msg_len, int *msg_auth_attr_offset)
{
	BYTE						attr_type;
	BYTE						*flw_pt  = msg + 20;//attribute begin from the 20th byte of the msg

	radius_msg_pdu.msg_type = RADIUS_MSG_TYPE_ACCESS_CHALLENGE;

	for (;;)
	{
		if (flw_pt - msg >= msg_len)
			break;

		attr_type = flw_pt[0];

		if (radius_attr_parse_function[attr_type].parse_function != NULL)
		{
			if (radius_attr_parse_function[attr_type].parse_function(&radius_msg_pdu, flw_pt + 2, flw_pt[1] - 2) < 0)
			{
				radius_log_err("%s: parse attribute=%d fail\r\n", __FUNCTION__, attr_type);
				return -1;
			}
		}
		else
		{
			radius_log_warn("%s: no parse function for attribute=%d\r\n", __FUNCTION__, attr_type);
		}

		if (attr_type == RADIUS_ATTRIBUTE_TYPE_MESSAGE_AUTHENTICATOR)
		{
			*msg_auth_attr_offset = flw_pt - msg;
		}

		flw_pt += flw_pt[1];
	}

	return 0;
}

int radius_parse_accounting_request_attr(BYTE *msg, int msg_len)
{
	BYTE						attr_type;
	BYTE						*flw_pt  = msg + 20;//attribute begin from the 20th byte of the msg

	radius_msg_pdu.msg_type = RADIUS_MSG_TYPE_ACCOUNTING_REQUEST;

	for (;;)
	{
		if (flw_pt - msg >= msg_len)
			break;

		attr_type = flw_pt[0];

		if (radius_attr_parse_function[attr_type].parse_function != NULL)
		{
			if (radius_attr_parse_function[attr_type].parse_function(&radius_msg_pdu, flw_pt + 2, flw_pt[1] - 2) < 0)
			{
				radius_log_err("%s: parse attribute=%d fail\r\n", __FUNCTION__, attr_type);
				return -1;
			}
		}
		else
		{
			radius_log_warn("%s: no parse function for attribute=%d\r\n", __FUNCTION__, attr_type);
		}

		flw_pt += flw_pt[1];
	}

	return 0;
}

int radius_parse_accounting_response_attr(BYTE *msg, int msg_len)
{
	BYTE						attr_type;
	BYTE						*flw_pt  = msg + 20;//attribute begin from the 20th byte of the msg

	radius_msg_pdu.msg_type = RADIUS_MSG_TYPE_ACCOUNTING_RESPONSE;

	for (;;)
	{
		if (flw_pt - msg >= msg_len)
			break;

		attr_type = flw_pt[0];

		if (radius_attr_parse_function[attr_type].parse_function != NULL)
		{
			if (radius_attr_parse_function[attr_type].parse_function(&radius_msg_pdu, flw_pt + 2, flw_pt[1] - 2) < 0)
			{
				radius_log_err("%s: parse attribute=%d fail\r\n", __FUNCTION__, attr_type);
				return -1;
			}
		}
		else
		{
			radius_log_warn("%s: no parse function for attribute=%d\r\n", __FUNCTION__, attr_type);
		}

		flw_pt += flw_pt[1];
	}

	return 0;
}

int radius_parse_disconnect_request_attr(BYTE *msg, int msg_len, int *msg_auth_attr_offset)
{
	BYTE						attr_type;
	BYTE						*flw_pt  = msg + 20;//attribute begin from the 20th byte of the msg

	radius_msg_pdu.msg_type = RADIUS_MSG_TYPE_DISCONNECT_REQUEST;

	for (;;)
	{
		if (flw_pt - msg >= msg_len)
			break;

		attr_type = flw_pt[0];

		if (radius_attr_parse_function[attr_type].parse_function != NULL)
		{
			if (radius_attr_parse_function[attr_type].parse_function(&radius_msg_pdu, flw_pt + 2, flw_pt[1] - 2) < 0)
			{
				radius_log_err("%s: parse attribute=%d fail\r\n", __FUNCTION__, attr_type);
				return -1;
			}
		}
		else
		{
			radius_log_warn("%s: no parse function for attribute=%d\r\n", __FUNCTION__, attr_type);
		}

		if (attr_type == RADIUS_ATTRIBUTE_TYPE_MESSAGE_AUTHENTICATOR)
		{
			*msg_auth_attr_offset = flw_pt - msg;
		}

		flw_pt += flw_pt[1];
	}

	return 0;
}

int radius_parse_disconnect_ack_attr(BYTE *msg, int msg_len, int *msg_auth_attr_offset)
{
	BYTE						attr_type;
	BYTE						*flw_pt  = msg + 20;//attribute begin from the 20th byte of the msg

	radius_msg_pdu.msg_type = RADIUS_MSG_TYPE_DISCONNECT_ACK;

	for (;;)
	{
		if (flw_pt - msg >= msg_len)
			break;

		attr_type = flw_pt[0];

		if (radius_attr_parse_function[attr_type].parse_function != NULL)
		{
			if (radius_attr_parse_function[attr_type].parse_function(&radius_msg_pdu, flw_pt + 2, flw_pt[1] - 2) < 0)
			{
				radius_log_err("%s: parse attribute=%d fail\r\n", __FUNCTION__, attr_type);
				return -1;
			}
		}
		else
		{
			radius_log_warn("%s: no parse function for attribute=%d\r\n", __FUNCTION__, attr_type);
		}

		if (attr_type == RADIUS_ATTRIBUTE_TYPE_MESSAGE_AUTHENTICATOR)
		{
			*msg_auth_attr_offset = flw_pt - msg;
		}

		flw_pt += flw_pt[1];
	}

	return 0;
}

int radius_parse_disconnect_nak_attr(BYTE *msg, int msg_len, int *msg_auth_attr_offset)
{
	BYTE						attr_type;
	BYTE						*flw_pt  = msg + 20;//attribute begin from the 20th byte of the msg

	radius_msg_pdu.msg_type = RADIUS_MSG_TYPE_DISCONNECT_NAK;

	for (;;)
	{
		if (flw_pt - msg >= msg_len)
			break;

		attr_type = flw_pt[0];

		if (radius_attr_parse_function[attr_type].parse_function != NULL)
		{
			if (radius_attr_parse_function[attr_type].parse_function(&radius_msg_pdu, flw_pt + 2, flw_pt[1] - 2) < 0)
			{
				radius_log_err("%s: parse attribute=%d fail\r\n", __FUNCTION__, attr_type);
				return -1;
			}
		}
		else
		{
			radius_log_warn("%s: no parse function for attribute=%d\r\n", __FUNCTION__, attr_type);
		}

		if (attr_type == RADIUS_ATTRIBUTE_TYPE_MESSAGE_AUTHENTICATOR)
		{
			*msg_auth_attr_offset = flw_pt - msg;
		}

		flw_pt += flw_pt[1];
	}

	return 0;
}


int radius_parse_attribute(BYTE *msg, int msg_len, int *msg_auth_attr_offset)
{
	BYTE			msg_type;

	memset(&radius_msg_pdu, 0, sizeof(RADIUS_MSG));

	msg_type = msg[0];

	switch (msg_type)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
		if (radius_parse_access_request_attr(msg, msg_len, msg_auth_attr_offset) < 0)
			return -1;
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
		if (radius_parse_access_accept_attr(msg, msg_len, msg_auth_attr_offset) < 0)
			return -1;
		break;
	case RADIUS_MSG_TYPE_ACCESS_REJECT:
		if (radius_parse_access_reject_attr(msg, msg_len, msg_auth_attr_offset) < 0)
			return -1;
		break;
	case RADIUS_MSG_TYPE_ACCESS_CHALLENGE:
		if (radius_parse_access_challenge_attr(msg, msg_len, msg_auth_attr_offset) < 0)
			return -1;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
		if (radius_parse_accounting_request_attr(msg, msg_len) < 0)
			return -1;
		break;
	case RADIUS_MSG_TYPE_ACCOUNTING_RESPONSE:
		if (radius_parse_accounting_response_attr(msg, msg_len) < 0)
			return -1;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		if (radius_parse_disconnect_request_attr(msg, msg_len, msg_auth_attr_offset) < 0)
			return -1;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_ACK:
		if (radius_parse_disconnect_ack_attr(msg, msg_len, msg_auth_attr_offset) < 0)
			return -1;
		break;
	case RADIUS_MSG_TYPE_DISCONNECT_NAK:
		if (radius_parse_disconnect_nak_attr(msg, msg_len, msg_auth_attr_offset) < 0)
			return -1;
		break;
	default:
		radius_log_warn("%s: recv msg type=%d, not support\r\n", __FUNCTION__, msg[0]);
		return -2;
	}

	return 0;
}

int radius_udp_msg_handling(BYTE *msg, int len, RADIUS_ADDR *addr, int nas_id)
{
	int					i;
	int					pid;
	int					ret;
	BYTE				msg_code;
	BYTE				msg_type;
	int					msg_len;
	BYTE				identifier;
	char					auth_str[2] = "";
	char					tmp_str[RADIUS_MAX_LEN_OF_TEMP_BUF] = "";
	BYTE				authenticator[RADIUS_MAX_LEN_OF_AUTH] = "";
	RADIUS_PID			*pid_ptr;
	RADIUS_NAS_INFO	*nas_info_ptr;
	int					msg_auth_attr_offset = 0;

	msg_code = msg[0];

	identifier = msg[1];

	radius_log_send_recv_msg(msg, len, addr, msg_code, RADIUS_RECV_MSG_FLAG);

	if ((nas_info_ptr = radius_get_nas_info_ptr(nas_id)) == NULL)
	{
		radius_log_err("%s: nas id=%d\r\n", __FUNCTION__, nas_id);
		return -1;
	}

	if ((msg_len = ((msg[2] << 8) | msg[3])) > len)
	{
		radius_log_err("%s:msg=%s length is incorrect, recv msg len=%d, length in msg=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_code), len, msg_len);
		return -1;
	}

	if ((ret = radius_parse_attribute(msg, msg_len, &msg_auth_attr_offset)) < 0)
	{
		if (ret == -1)
			radius_log_err("%s: parse msg=%s fail\r\n", __FUNCTION__, radius_get_msg_str( msg_code));

		return -1;
	}

	memcpy(authenticator, msg + 4, RADIUS_MAX_LEN_OF_AUTH);//authenticator begin from the 4th byte of msg

	if (msg_code == RADIUS_MSG_TYPE_ACCESS_REQUEST)
	{
		if (radius_authenticate_nas(authenticator, nas_info_ptr, &radius_msg_pdu.msg.access_request, msg, msg_len, msg_auth_attr_offset) < 0)
		{
			radius_log_err("%s: authenticate nas fail\r\n", __FUNCTION__);
			return 0;
		}
		strcpy((char *)radius_msg_pdu.msg.access_request.secret, (char *)nas_info_ptr->share_key);

		// update chap authenticator
		if (radius_msg_pdu.msg.access_request.chap_challenge.flag != 1)
		{
			memcpy(radius_msg_pdu.msg.access_request.chap_challenge.chap_challenge.value,
					authenticator, RADIUS_MAX_LEN_OF_AUTH);
			radius_msg_pdu.msg.access_request.chap_challenge.chap_challenge.length = RADIUS_MAX_LEN_OF_AUTH;
			radius_msg_pdu.msg.access_request.chap_challenge.flag = 1;
		}
	}

	switch (msg_code)
	{
	case RADIUS_MSG_TYPE_ACCESS_REQUEST:
	case RADIUS_MSG_TYPE_ACCOUNTING_REQUEST:
	case RADIUS_MSG_TYPE_DISCONNECT_REQUEST:
		msg_type = RADIUS_REQUEST_MSG;

		if ((pid = radius_match_response_pid(msg_code, identifier, authenticator)) >= 0)
		{
			radius_log_warn("%s: recv msg=%s, identifier=%d, already process by pid=%d\r\n", __FUNCTION__, radius_get_msg_str(msg_type), identifier, pid);
			return 0;
		}
		break;
	case RADIUS_MSG_TYPE_ACCESS_ACCEPT:
	case RADIUS_MSG_TYPE_ACCESS_REJECT:
	case RADIUS_MSG_TYPE_ACCESS_CHALLENGE:
	case RADIUS_MSG_TYPE_ACCOUNTING_RESPONSE:
	case RADIUS_MSG_TYPE_DISCONNECT_ACK:
	case RADIUS_MSG_TYPE_DISCONNECT_NAK:
		msg_type = RADIUS_RESPONSE_MSG;

		if ((pid = radius_match_request_pid(msg_code, identifier, authenticator, msg, msg_len, nas_info_ptr->share_key)) < 0)
		{
			for (i = 0; i < RADIUS_MAX_LEN_OF_AUTH; i++)
			{
				sprintf(auth_str, "%02x", authenticator[i]);
				strcat(tmp_str, auth_str);
			}
			radius_log_err("%s: identifier=%d, authenticator=%s\r\n", __FUNCTION__, identifier, tmp_str);
			return -1;
		}
		break;
	default:
		radius_log_warn("%s: not support msg code=%d\r\n", __FUNCTION__, msg_code);
		return -1;
	}

	if (msg_type == RADIUS_REQUEST_MSG)
	{
		if ((pid = radius_get_pid()) < 0)
		{
			radius_log_err("%s: get pid fail\r\n", __FUNCTION__);
			return -1;
		}
	}

	pid_ptr = radius_get_pid_ptr(pid);

	switch (msg_type)
	{
	case RADIUS_REQUEST_MSG:
		pid_ptr->type = RADIUS_PID_TYPE_IND;
		pid_ptr->trans_req_msg_type = msg_code;
		memcpy(&pid_ptr->authenticator, authenticator, RADIUS_MAX_LEN_OF_AUTH);
		pid_ptr->identifier = identifier;
		pid_ptr->sap_index = nas_info_ptr->sap_index;
		pid_ptr->nas_id = nas_id;
		break;
	}

	memcpy(&pid_ptr->peer_addr, addr, sizeof(RADIUS_ADDR));

	pid_ptr->rv_msg_flag = msg_code;

	radius_log_event("%s: success! usr_pid=%d, pid=%d\r\n", __FUNCTION__, pid_ptr->usr_pid, pid);

	radius_p_fsm(pid);

	return 0;
}

int radius_attr_parse_init()
{
	memset(radius_attr_parse_function, 0, sizeof(RADIUS_ATTR_PARSE_FUNCTION) * RADIUS_MAX_NUM_OF_ATTRIBUTE);

	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_USER_NAME].parse_function = radius_parse_attr_user_name;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_USER_PASSWORD].parse_function = radius_parse_attr_user_password;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_CHAP_PASSWORD].parse_function = radius_parse_attr_chap_password;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_NAS_IP_ADDRESS].parse_function = radius_parse_attr_nas_ip_addr;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_NAS_PORT].parse_function = radius_parse_attr_nas_port;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_SERVICE_TYPE].parse_function = radius_parse_attr_service_type;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_FRAMED_PROTOCOL].parse_function = radius_parse_attr_framed_protocol;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_FRAMED_IP_ADDR].parse_function = radius_parse_attr_framed_ip_addr;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_FRAMED_IP_NETMASK].parse_function = radius_parse_attr_framed_ip_netmask;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_FRAMED_ROUTING].parse_function = radius_parse_attr_framed_routing;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_FILTER_ID].parse_function = radius_parse_attr_filter_id;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_FRAMED_MTU].parse_function = radius_parse_attr_framed_mtu;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_FRAMED_COMPRESSION].parse_function = radius_parse_attr_framed_compression;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_LOGIN_IP_HOST].parse_function = radius_parse_attr_login_ip_host;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_LOGIN_SERVICE].parse_function = radius_parse_attr_login_service;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_LOGIN_TCP_PORT].parse_function = radius_parse_attr_login_tcp_port;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_REPLY_MESSAGE].parse_function = radius_parse_attr_reply_message;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_CALLBACK_NUMBER].parse_function = radius_parse_attr_callback_number;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_CALLBACK_ID].parse_function = radius_parse_attr_callback_id;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_FRAMED_ROUTE].parse_function = radius_parse_attr_framed_route;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_FRAMED_IPX_NETWORK].parse_function = radius_parse_attr_framed_ipx_network;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_STATE].parse_function = radius_parse_attr_state;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_CLASS].parse_function = radius_parse_attr_class;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_VENDOR_SPECIFIC].parse_function = radius_parse_attr_vendor_specific;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_SESSION_TIMEOUT].parse_function = radius_parse_attr_session_timeout;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_IDLE_TIMEOUT].parse_function = radius_parse_attr_idle_timeout;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_TERMINATION_ACTION].parse_function = radius_parse_attr_termination_action;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_CALLED_STATION_ID].parse_function = radius_parse_attr_called_station_id;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_CALLING_STATION_ID].parse_function = radius_parse_attr_calling_station_id;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_NAS_IDENTIFIER].parse_function = radius_parse_attr_nas_identifier;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_PROXY_STATE].parse_function = radius_parse_attr_proxy_state;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_LOGIN_LAT_SERVICE].parse_function = radius_parse_attr_login_lat_service;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_LOGIN_LAT_NODE].parse_function = radius_parse_attr_login_lat_node;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_LOGIN_LAT_GROUP].parse_function = radius_parse_attr_login_lat_group;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_FRAMED_APPLETALK_LINK].parse_function = radius_parse_attr_framed_appletalk_link;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_FRAMED_APPLETALK_NETWORK].parse_function = radius_parse_attr_framed_appletalk_network;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_FRAMED_APPLETALK_ZONE].parse_function = radius_parse_attr_framed_appletalk_zone;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ACCT_STATUS_TYPE].parse_function = radius_parse_attr_acct_status_type;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ACCT_DELAY_TIME].parse_function = radius_parse_attr_acct_delay_time;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ACCT_INPUT_OCTETS].parse_function = radius_parse_attr_acct_input_octets;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ACCT_OUTPUT_OCTETS].parse_function = radius_parse_attr_acct_output_octets;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ACCT_SESSION_ID].parse_function = radius_parse_attr_acct_session_id;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ACCT_AUTHENTIC].parse_function = radius_parse_attr_acct_authentic;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ACCT_SESSION_TIME].parse_function = radius_parse_attr_acct_session_time;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ACCT_INPUT_PACKETS].parse_function = radius_parse_attr_acct_input_packets;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ACCT_OUTPUT_PACKETS].parse_function = radius_parse_attr_acct_output_packets;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ACCT_TERMINATE_CAUSE].parse_function = radius_parse_attr_acct_terminate_cause;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ACCT_MULTI_SESSION_ID].parse_function = radius_parse_attr_acct_multi_session_id;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ACCT_LINK_COUNT].parse_function = radius_parse_attr_acct_link_count;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_EVENT_TIMESTAMP].parse_function = radius_parse_attr_event_timestamp;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_CHAP_CHALLENGE].parse_function = radius_parse_attr_chap_challenge;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_NAS_PORT_TYPE].parse_function = radius_parse_attr_nas_port_type;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_PORT_LIMIT].parse_function = radius_parse_attr_port_limit;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_LOGIN_LAT_PORT].parse_function = radius_parse_attr_login_lat_port;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ARAP_PASSWORD].parse_function = radius_parse_attr_arap_password;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ARAP_FEATURES].parse_function = radius_parse_attr_arap_features;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ARAP_ZONE_ACCESS].parse_function = radius_parse_attr_arap_zone_access;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ARAP_SECURITY].parse_function = radius_parse_attr_arap_security;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ARAP_SECURITY_DATA].parse_function = radius_parse_attr_arap_security_data;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_PASSWORD_RETRY].parse_function = radius_parse_attr_password_retry;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_PROMPT].parse_function = radius_parse_attr_prompt;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_CONNECT_INFO].parse_function = radius_parse_attr_connect_info;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_CONFIGURATION_TOKEN].parse_function = radius_parse_attr_configuration_token;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_EAP_MESSAGE].parse_function = radius_parse_attr_eap_message;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_MESSAGE_AUTHENTICATOR].parse_function = radius_parse_attr_message_authenticator;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ARAP_CHALLENGE_RESPONSE].parse_function = radius_parse_attr_arap_challenge_response;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ACCT_INTERIM_INTERVAL].parse_function = radius_parse_attr_acct_interim_interval;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_NAS_PORT_ID].parse_function = radius_parse_attr_nas_port_id;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_FRAMED_POOL].parse_function = radius_parse_attr_framed_pool;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_ERROR_CAUSE].parse_function = radius_parse_attr_error_cause;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_NOWSMS_PREAUTH_TYPE].parse_function = radius_parse_attr_nowsms_preauth_type;
	radius_attr_parse_function[RADIUS_ATTRIBUTE_TYPE_NOWSMS_COUNT_ID_SIZE].parse_function = radius_parse_attr_nowsms_count_id_size;
	
	return 0;
}

int radius_generate_access_request_authenticator(BYTE *authenticator)
{
	struct timeval	tv;
	char				tmp_str[RADIUS_MAX_LEN_OF_TEMP_BUF] = "";

	gettimeofday(&tv, NULL);

	sprintf(tmp_str, "%lX%lX", tv.tv_sec, tv.tv_usec);

	radius_get_md5_hex((char*)authenticator, tmp_str, strlen(tmp_str));

	return 0;
}

int radius_encode_attr_user_name(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_USER_NAME *user_name)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)user_name->user_name.value)) == 0)
	{
		radius_log_err("%s: user name is null\r\n", __FUNCTION__);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_USER_NAME;

	memcpy(&tmp_flw_ptr[2], user_name->user_name.value, len);

	tmp_flw_ptr[1] = len + 2;

	return 0;
}

void radius_update (RADIUS_ENCRYPT_USER_PASSWORD_CONTEXT *context, BYTE *inBuf, unsigned int inLen, BYTE *share_key)
{
	int				i;
	int				mdi;
	BYTE			md5_result[RADIUS_MAX_LEN_MD5] = "";
	int				share_key_len;
	int				in_len;
	BYTE			in[RADIUS_MAX_LEN_OF_TEMP_BUF] = "";
	BYTE			md5[RADIUS_MAX_LEN_MD5];

	share_key_len = strlen((char*)share_key);

	memcpy(in, share_key, share_key_len);

	in_len = share_key_len +RADIUS_MAX_LEN_MD5;

	/*compute number of bytes mod 16*/
	mdi = (int)((context->i[0] >> 3) & 0x0F);

	/*update number of bits*/
	if ((context->i[0] + ((DWORD)inLen << 3)) < context->i[0])
		context->i[1]++;

	context->i[0] += ((DWORD)inLen << 3);
	context->i[1] += ((DWORD)inLen >> 29);

	while (inLen--) 
	{
		/* add new character to	buffer,	increment mdi */
		context->in[mdi++] = *inBuf++;
	    
		/* transform if	necessary */
		if (mdi == 0x10)
		{
			if (context->count == 0)
				memcpy(in + share_key_len, context->result, RADIUS_MAX_LEN_MD5);
			else
				memcpy(in + share_key_len, &context->result[(context->count - 1) * RADIUS_MAX_LEN_MD5], RADIUS_MAX_LEN_MD5);

			if (++context->count > 8)
				return;

			radius_get_md5_hex((char*)md5, (char*)in, in_len);

			for (i = 0; i < RADIUS_MAX_LEN_MD5; i++)
			{
				md5_result[i] = md5[i] ^ context->in[i];
			}

			memcpy(&context->result[(context->count - 1) * RADIUS_MAX_LEN_MD5], md5_result, RADIUS_MAX_LEN_MD5);

			context->result_len = context->count * RADIUS_MAX_LEN_MD5;

			mdi = 0;
		}
	}
}

void radius_final (RADIUS_ENCRYPT_USER_PASSWORD_CONTEXT *context, BYTE *share_key)
{
	DWORD		in[16];
	int			mdi;
	unsigned int	padLen;

	/* save number of	bits */
	in[14] = context->i[0];
	in[15] = context->i[1];

	/* compute number	of bytes mod 16	*/
	mdi = (int)((context->i[0] >> 3) & 0x0F);

	if (mdi == 0)
		return;

	/* pad out to	56 mod 64 */
	padLen = 16 - mdi;

	radius_update(context, USER_PASSWORD_PADDING, padLen, share_key);
}

int radius_init_user_password_context(RADIUS_ENCRYPT_USER_PASSWORD_CONTEXT *context, BYTE *authenticator)
{
	memset(context, 0, sizeof(RADIUS_ENCRYPT_USER_PASSWORD_CONTEXT));

	memcpy(context->result, authenticator, RADIUS_MAX_LEN_OF_AUTH);

	context->result_len = RADIUS_MAX_LEN_OF_AUTH;

	return 0;
}

int radius_encrypt_user_password(BYTE *encrypt_password, BYTE *password, BYTE *authenticator, BYTE *share_key)
{
	int												password_len;
	RADIUS_ENCRYPT_USER_PASSWORD_CONTEXT		encrypt_password_context;

	radius_init_user_password_context(&encrypt_password_context, authenticator);

	password_len = strlen((char*)password);

	radius_update(&encrypt_password_context, password, password_len, share_key);

	radius_final(&encrypt_password_context, share_key);

	memcpy(encrypt_password, encrypt_password_context.result, encrypt_password_context.result_len);

	return encrypt_password_context.result_len;
}

int radius_encode_attr_user_password(const BYTE *flw_ptr, BYTE *user_password, BYTE *share_key, BYTE *authenticator)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;
	BYTE	encrypt_password[RADIUS_MAX_LEN_OF_ENCRYPT_PASSWORD] = "";

	if ((len  = radius_encrypt_user_password(encrypt_password, user_password, authenticator, share_key)) < 0)
	{
		radius_log_err("%s: encrypt user password fail\r\n", __FUNCTION__);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_USER_PASSWORD;

	memcpy(&tmp_flw_ptr[2], encrypt_password, len);

	tmp_flw_ptr[1] = len + 2;

	return 0;
}

int radius_encode_attr_chap_password(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_CHAP_PASSWORD *chap_password)
{
	return 0;
}

int radius_encode_attr_nas_ip_address(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_NAS_IP_ADDRESS *nas_ip_address)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_NAS_IP_ADDRESS;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[5] = (nas_ip_address->nas_ip_addr.value >> 24) & 0xFF;
	tmp_flw_ptr[4] = (nas_ip_address->nas_ip_addr.value >> 16) & 0xFF;
	tmp_flw_ptr[3] = (nas_ip_address->nas_ip_addr.value >> 8) & 0xFF;
	tmp_flw_ptr[2] = (nas_ip_address->nas_ip_addr.value) & 0xFF;

	return 0;
}

int radius_encode_attr_nas_port(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_NAS_PORT *nas_port)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_NAS_PORT;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (nas_port->nas_port.value>> 24) & 0xFF;
	tmp_flw_ptr[3] = (nas_port->nas_port.value>> 16) & 0xFF;
	tmp_flw_ptr[4] = (nas_port->nas_port.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (nas_port->nas_port.value) & 0xFF;

	return 0;
}

int radius_encode_attr_service_type(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_SERVICE_TYPE *service_type)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_SERVICE_TYPE;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (service_type->service_type.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (service_type->service_type.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (service_type->service_type.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (service_type->service_type.value) & 0xFF;

	return 0;
}

int radius_encode_attr_framed_protocol(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_FRAMED_PROTOCOL *framed_protocol)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_FRAMED_PROTOCOL;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (framed_protocol->framed_protocol.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (framed_protocol->framed_protocol.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (framed_protocol->framed_protocol.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (framed_protocol->framed_protocol.value) & 0xFF;

	return 0;
}

int radius_encode_attr_framed_ip_addr(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_FRAMED_IP_ADDR *framed_ip_addr)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_FRAMED_IP_ADDR;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[5] = (framed_ip_addr->framed_ip_addr.value >> 24) & 0xFF;
	tmp_flw_ptr[4] = (framed_ip_addr->framed_ip_addr.value >> 16) & 0xFF;
	tmp_flw_ptr[3] = (framed_ip_addr->framed_ip_addr.value >> 8) & 0xFF;
	tmp_flw_ptr[2] = (framed_ip_addr->framed_ip_addr.value) & 0xFF;

	return 0;
}

int radius_encode_attr_framed_ip_netmask(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_FRAMED_IP_NETMASK *framed_ip_netmask)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_FRAMED_IP_NETMASK;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[5] = (framed_ip_netmask->framed_ip_netmask.value >> 24) & 0xFF;
	tmp_flw_ptr[4] = (framed_ip_netmask->framed_ip_netmask.value >> 16) & 0xFF;
	tmp_flw_ptr[3] = (framed_ip_netmask->framed_ip_netmask.value >> 8) & 0xFF;
	tmp_flw_ptr[2] = (framed_ip_netmask->framed_ip_netmask.value) & 0xFF;

	return 0;
}

int radius_encode_attr_framed_routing(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_FRAMED_ROUTING *framed_routing)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_FRAMED_ROUTING;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (framed_routing->framed_routing.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (framed_routing->framed_routing.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (framed_routing->framed_routing.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (framed_routing->framed_routing.value) & 0xFF;

	return 0;
}

int radius_encode_attr_filter_id(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_FILTER_ID *filter_id)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)filter_id->filter_id.value)) == 0)
	{
		radius_log_err("%s: filter id=%s is NULL\r\n", __FUNCTION__, filter_id->filter_id.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_FILTER_ID;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], filter_id->filter_id.value, len);

	return 0;
}

int radius_encode_filter_id(const BYTE *flw_ptr, RADIUS_FILTER_ID *filter_id)
{
	int		i;
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((filter_id->num == 0) || (filter_id->num > RADIUS_MAX_NUM_OF_FILTER_ID))
	{
		radius_log_err("%s: filter id num=%d\r\n", __FUNCTION__, filter_id->num);
		return -1;
	}

	for (i = 0; i < filter_id->num; i++)
	{
		if (radius_encode_attr_filter_id(tmp_flw_ptr, &filter_id->filter_id[i]) < 0)
		{
			radius_log_err("%s: encode attr filter id fail, filter num=%d\r\n", __FUNCTION__, i);
			return -1;
		}

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	return len;
}

int radius_encode_attr_framed_mtu(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_FRAMED_MTU *framed_mtu)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_FRAMED_MTU;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (framed_mtu->framed_mtu.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (framed_mtu->framed_mtu.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (framed_mtu->framed_mtu.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (framed_mtu->framed_mtu.value) & 0xFF;

	return 0;
}

int radius_encode_attr_framed_compression(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_FRAMED_COMPRESSION *compression)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_FRAMED_COMPRESSION;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (compression->framed_compression.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (compression->framed_compression.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (compression->framed_compression.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (compression->framed_compression.value) & 0xFF;

	return 0;
}

int radius_encode_framed_compression(const BYTE *flw_ptr, RADIUS_FRAMED_COMPRESSION *compression)
{
	int		i;
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((compression->num == 0) || (compression->num > RADIUS_MAX_NUM_OF_FRAMED_COMPRESSION))
	{
		radius_log_err("%s: framed compression num=%d\r\n", __FUNCTION__, compression->num);
		return -1;
	}

	for (i = 0; i < compression->num; i++)
	{
		if (radius_encode_attr_framed_compression(tmp_flw_ptr, &compression->framed_compression[i]) < 0)
		{
			radius_log_err("%s: encode attr framed compression fail, compression num=%d\r\n", __FUNCTION__, i);
			return -1;
		}

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	return len;
}

int radius_encode_attr_login_ip_host(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_LOGIN_IP_HOST *login_ip_host)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_LOGIN_IP_HOST;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[5] = (login_ip_host->login_ip_host.value >> 24) & 0xFF;
	tmp_flw_ptr[4] = (login_ip_host->login_ip_host.value >> 16) & 0xFF;
	tmp_flw_ptr[3] = (login_ip_host->login_ip_host.value >> 8) & 0xFF;
	tmp_flw_ptr[2] = (login_ip_host->login_ip_host.value) & 0xFF;

	return 0;
}

int radius_encode_login_ip_host(const BYTE *flw_ptr, RADIUS_LOGIN_IP_HOST *login_ip_host)
{
	int		i;
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((login_ip_host->num == 0) || (login_ip_host->num > RADIUS_MAX_NUM_OF_LOGIN_IP_HOST))
	{
		radius_log_err("%s: login ip host num=%d\r\n", __FUNCTION__, login_ip_host->num);
		return -1;
	}

	for (i = 0; i < login_ip_host->num; i++)
	{
		if (radius_encode_attr_login_ip_host(tmp_flw_ptr, &login_ip_host->login_ip_host[i]) < 0)
		{
			radius_log_err("%s: encode attr login ip host fail, login ip host num=%d\r\n", __FUNCTION__, i);
			return -1;
		}

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	return len;
}

int radius_encode_attr_login_service(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_LOGIN_SERVICE *login_service)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_LOGIN_SERVICE;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (login_service->login_service.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (login_service->login_service.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (login_service->login_service.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (login_service->login_service.value) & 0xFF;

	return 0;
}

int radius_encode_attr_login_tcp_port(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_LOGIN_TCP_PORT *login_tcp_port)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_LOGIN_TCP_PORT;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (login_tcp_port->login_tcp_port.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (login_tcp_port->login_tcp_port.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (login_tcp_port->login_tcp_port.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (login_tcp_port->login_tcp_port.value) & 0xFF;

	return 0;
}

int radius_encode_attr_reply_message(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_REPLY_MESSAGE *reply_message)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)reply_message->reply_message.value)) == 0)
	{
		radius_log_err("%s: reply message=%s is NULL\r\n", __FUNCTION__, reply_message->reply_message.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_REPLY_MESSAGE;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], reply_message->reply_message.value, len);

	return 0;
}

int radius_encode_reply_message(const BYTE *flw_ptr, RADIUS_REPLY_MESSAGE *reply_message)
{
	int		i;
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((reply_message->num == 0) || (reply_message->num > RADIUS_MAX_NUM_OF_REPLY_MESSAGE))
	{
		radius_log_err("%s: reply message num=%d\r\n", __FUNCTION__, reply_message->num);
		return -1;
	}

	for (i = 0; i < reply_message->num; i++)
	{
		if (radius_encode_attr_reply_message(tmp_flw_ptr, &reply_message->reply_message[i]) < 0)
		{
			radius_log_err("%s: encode attr reply message fail, reply message num=%d\r\n", __FUNCTION__, i);
			return -1;
		}

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	return len;
}

int radius_encode_attr_callback_num(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_CALLBACK_NUMBER *callback_num)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)callback_num->callback_number.value)) == 0)
	{
		radius_log_err("%s: callback num=%s is NULL\r\n", __FUNCTION__, callback_num->callback_number.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_CALLBACK_NUMBER;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], callback_num->callback_number.value, len);

	return 0;
}

int radius_encode_attr_callback_id(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_CALLBACK_ID *callback_id)
{
	int		len;
	BYTE	*tmp_flw_pt = (BYTE *)flw_ptr;

	if ((len = strlen((char*)callback_id->callback_id.value)) == 0)
	{
		radius_log_err("%s: callback id=%s is NULL\r\n", __FUNCTION__, callback_id->callback_id.value);
		return -1;
	}

	tmp_flw_pt[0] = RADIUS_ATTRIBUTE_TYPE_CALLBACK_ID;

	tmp_flw_pt[1] = len + 2;

	memcpy(&tmp_flw_pt[2], callback_id->callback_id.value, len);

	return 0;
}

int radius_encode_attr_framed_route(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_FRAMED_ROUTE *route)
{
	int		len;
	BYTE	*tmp_flw_pt = (BYTE *)flw_ptr;

	if ((len = strlen((char*)route->framed_route.value)) == 0)
	{
		radius_log_err("%s: framed rout=%s is NULL\r\n", __FUNCTION__, route->framed_route.value);
		return -1;
	}

	tmp_flw_pt[0] = RADIUS_ATTRIBUTE_TYPE_FRAMED_ROUTE;

	tmp_flw_pt[1] = len + 2;

	memcpy(&tmp_flw_pt[2], route->framed_route.value, len);

	return 0;
}

int radius_encode_framed_route(const BYTE *flw_ptr, RADIUS_FRAMED_ROUTE *route)
{
	int		i;
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((route->num == 0) || (route->num > RADIUS_MAX_NUM_OF_FRAMED_ROUTE))
	{
		radius_log_err("%s: framed route num=%d\r\n", __FUNCTION__, route->num);
		return -1;
	}

	for (i = 0; i < route->num; i++)
	{
		if (radius_encode_attr_framed_route(tmp_flw_ptr, &route->framed_route[i]) < 0)
		{
			radius_log_err("%s: encode attr framed route fail, framed route num=%d\r\n", __FUNCTION__, i);
			return  -1;
		}

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	return len;
}

int radius_encode_attr_framed_ipx_network(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_FRAMED_IPX_NETWORK *framed_ipx_network)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_FRAMED_IPX_NETWORK;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (framed_ipx_network->framed_ipx_network.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (framed_ipx_network->framed_ipx_network.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (framed_ipx_network->framed_ipx_network.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (framed_ipx_network->framed_ipx_network.value) & 0xFF;

	return 0;
}

int radius_encode_attr_state(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_STATE *state)
{
	int		len;
	BYTE	*tmp_flw_pt = (BYTE *)flw_ptr;

	if ((len = strlen((char*)state->state.value)) == 0)
	{
		radius_log_err("%s: state =%s is NULL\r\n", __FUNCTION__, state->state.value);
		return -1;
	}

	tmp_flw_pt[0] = RADIUS_ATTRIBUTE_TYPE_STATE;

	tmp_flw_pt[1] = len + 2;

	memcpy(&tmp_flw_pt[2], state->state.value, len);

	return 0;
}

int radius_encode_attr_class(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_CLASS *radius_class)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)radius_class->radius_class.value)) == 0)
	{
		radius_log_err("%s: radius class=%s is NULL", __FUNCTION__, radius_class->radius_class.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_CLASS;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], radius_class->radius_class.value, len);

	return 0;
}

int radius_encode_class(const BYTE *flw_ptr, RADIUS_CLASS *radius_class)
{
	int		i;
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((radius_class->num == 0) || (radius_class->num > RADIUS_MAX_NUM_OF_CLASS))
	{
		radius_log_err("%s: radius class num=%d\r\n", __FUNCTION__, radius_class->num);
		return -1;
	}

	for (i = 0; i < radius_class->num; i++)
	{
		if (radius_encode_attr_class(tmp_flw_ptr, &radius_class->radius_class[i]) < 0)
		{
			radius_log_err("%s: encode attr class fail, class num=%d\r\n", __FUNCTION__, i);
			return -1;
		}

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	return len;
}

int radius_encode_attr_vendor_3gpp2_ppac_aic(const BYTE *flw_ptr, RADIUS_VENDOR_3GPP2_PPAC_SUB_ATTR_AIC *aic)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_3GPP2_PPAC_SUBTYPE_AIC;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (aic->aic >> 24) & 0xFF;
	tmp_flw_ptr[3] = (aic->aic >> 16) & 0xFF;
	tmp_flw_ptr[4] = (aic->aic >> 8) & 0xFF;
	tmp_flw_ptr[5] = (aic->aic) & 0xFF;

	return 0;
}

int radius_encode_attr_vendor_3gpp2_ppac_sfs(const BYTE *flw_ptr, RADIUS_VENDOR_3GPP2_PPAC_SUB_ATTR_SFS *sfs)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_3GPP2_PPAC_SUBTYPE_SFS;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (sfs->sfs >> 24) & 0xFF;
	tmp_flw_ptr[3] = (sfs->sfs >> 16) & 0xFF;
	tmp_flw_ptr[4] = (sfs->sfs >> 8) & 0xFF;
	tmp_flw_ptr[5] = (sfs->sfs) & 0xFF;

	return 0;
}

int radius_encode_attr_vendor_3gpp2_ppac(const BYTE *flw_ptr, RADIUS_VENDOR_ATTRIBUTE_3GPP2_PPAC *ppac)
{
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr + 2;
	BYTE	*tmp_flw_ptr1 = (BYTE *)flw_ptr;

	if (ppac->aic.flag == 1)
	{
		radius_encode_attr_vendor_3gpp2_ppac_aic(tmp_flw_ptr, &ppac->aic);

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	if (ppac->sfs.flag == 1)
	{
		radius_encode_attr_vendor_3gpp2_ppac_sfs(tmp_flw_ptr, &ppac->sfs);

		len += tmp_flw_ptr[1];
	}

	tmp_flw_ptr1[0] = RADIUS_VENDOR_TYPE_3GPP2_PPAC;

	tmp_flw_ptr1[1] = len + 2;

	return 0;
}

int radius_encode_attr_vendor_3gpp2_stc(const BYTE *flw_ptr, RADIUS_VENDOR_ATTRIBUTE_3GPP2_STC *stc)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_VENDOR_TYPE_3GPP2_STC;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (stc->stc >> 24) & 0xFF;
	tmp_flw_ptr[3] = (stc->stc >> 16) & 0xFF;
	tmp_flw_ptr[4] = (stc->stc >> 8) & 0xFF;
	tmp_flw_ptr[5] = (stc->stc) & 0xFF;

	return 0;
}

int radius_encode_attr_vendor_3gpp2_ppaq_qid(const BYTE *flw_ptr, RADIUS_VENDOR_3GPP2_PPAQ_SUB_ATTR_QID *qid)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_3GPP2_PPAQ_SUBTYPE_QID;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (qid->qid.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (qid->qid.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (qid->qid.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (qid->qid.value) & 0xFF;

	return 0;
}

int radius_encode_attr_vendor_3gpp2_ppaq_vq(const BYTE *flw_ptr, RADIUS_VENDOR_3GPP2_PPAQ_SUB_ATTR_VQ *vq)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_3GPP2_PPAQ_SUBTYPE_VQ;

/*	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (vq->vq.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (vq->vq.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (vq->vq.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (vq->vq.value) & 0xFF;*///for 3gpp2

	tmp_flw_ptr[2] = RADIUS_ARICENT_VOLUME_INT;
	tmp_flw_ptr[3] = 10;
	tmp_flw_ptr[4] = (vq->vq.integer >> 56) & 0xFF;
	tmp_flw_ptr[5] = (vq->vq.integer >> 48) & 0xFF;
	tmp_flw_ptr[6] = (vq->vq.integer >> 40) & 0xFF;
	tmp_flw_ptr[7] = (vq->vq.integer >> 32) & 0xFF;
	tmp_flw_ptr[8] = (vq->vq.integer >> 24) & 0xFF;
	tmp_flw_ptr[9] = (vq->vq.integer >> 16) & 0xFF;
	tmp_flw_ptr[10] = (vq->vq.integer >> 8) & 0xFF;
	tmp_flw_ptr[11] = (vq->vq.integer) & 0xFF;

	if (vq->vq.exponent == 0)
	{
		tmp_flw_ptr[1] = 12;
	}
	else
	{
		tmp_flw_ptr[12] = RADIUS_ARICENT_VOLUME_EXP;
		tmp_flw_ptr[13] = 6;
		tmp_flw_ptr[14] = (vq->vq.exponent >> 24) & 0xFF;
		tmp_flw_ptr[15] = (vq->vq.exponent >> 16) & 0xFF;
		tmp_flw_ptr[16] = (vq->vq.exponent >> 8) & 0xFF;
		tmp_flw_ptr[17] = (vq->vq.exponent) & 0xFF;

		tmp_flw_ptr[1] = 18;
	}

	return 0;
}

int radius_encode_attr_vendor_3gpp2_ppaq_vqo(const BYTE *flw_ptr, RADIUS_VENDOR_3GPP2_PPAQ_SUB_ATTR_VQO *vqo)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_3GPP2_PPAQ_SUBTYPE_VQO;

	tmp_flw_ptr[1] = 4;

	tmp_flw_ptr[2] = (vqo->vqo.value >> 8) & 0xFF;
	tmp_flw_ptr[3] = (vqo->vqo.value) & 0xFF;

	return 0;
}

int radius_encode_attr_vendor_3gpp2_ppaq_vt(const BYTE *flw_ptr, RADIUS_VENDOR_3GPP2_PPAQ_SUB_ATTR_VT *vt)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_3GPP2_PPAQ_SUBTYPE_VT;

/*	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (vt->vt.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (vt->vt.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (vt->vt.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (vt->vt.value) & 0xFF;*/

	tmp_flw_ptr[2] = RADIUS_ARICENT_VOLUME_INT;
	tmp_flw_ptr[3] = 10;
	tmp_flw_ptr[4] = (vt->vt.integer >> 56) & 0xFF;
	tmp_flw_ptr[5] = (vt->vt.integer >> 48) & 0xFF;
	tmp_flw_ptr[6] = (vt->vt.integer >> 40) & 0xFF;
	tmp_flw_ptr[7] = (vt->vt.integer >> 32) & 0xFF;
	tmp_flw_ptr[8] = (vt->vt.integer >> 24) & 0xFF;
	tmp_flw_ptr[9] = (vt->vt.integer >> 16) & 0xFF;
	tmp_flw_ptr[10] = (vt->vt.integer >> 8) & 0xFF;
	tmp_flw_ptr[11] = (vt->vt.integer) & 0xFF;

	if (vt->vt.exponent == 0)
	{
		tmp_flw_ptr[1] = 12;
	}
	else
	{
		tmp_flw_ptr[12] = RADIUS_ARICENT_VOLUME_EXP;
		tmp_flw_ptr[13] = 6;
		tmp_flw_ptr[14] = (vt->vt.exponent >> 24) & 0xFF;
		tmp_flw_ptr[15] = (vt->vt.exponent >> 16) & 0xFF;
		tmp_flw_ptr[16] = (vt->vt.exponent >> 8) & 0xFF;
		tmp_flw_ptr[17] = (vt->vt.exponent) & 0xFF;

		tmp_flw_ptr[1] = 18;
	}

	return 0;
}

int radius_encode_attr_vendor_3gpp2_ppaq_vto(const BYTE *flw_ptr, RADIUS_VENDOR_3GPP2_PPAQ_SUB_ATTR_VTO *vto)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_3GPP2_PPAQ_SUBTYPE_VTO;

	tmp_flw_ptr[1] = 4;

	tmp_flw_ptr[2] = (vto->vto.value >> 8) & 0xFF;
	tmp_flw_ptr[3] = (vto->vto.value) & 0xFF;

	return 0;
}

int radius_encode_attr_vendor_3gpp2_ppaq_dq(const BYTE *flw_ptr, RADIUS_VENDOR_3GPP2_PPAQ_SUB_ATTR_DQ *dq)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_3GPP2_PPAQ_SUBTYPE_DQ;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (dq->dq.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (dq->dq.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (dq->dq.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (dq->dq.value) & 0xFF;

	return 0;
}

int radius_encode_attr_vendor_3gpp2_ppaq_dt(const BYTE *flw_ptr, RADIUS_VENDOR_3GPP2_PPAQ_SUB_ATTR_DT *dt)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_3GPP2_PPAQ_SUBTYPE_DT;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (dt->dt.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (dt->dt.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (dt->dt.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (dt->dt.value) & 0xFF;

	return 0;
}

int radius_encode_attr_vendor_3gpp2_ppaq_ur(const BYTE *flw_ptr, RADIUS_VENDOR_3GPP2_PPAQ_SUB_ATTR_UR *ur)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_3GPP2_PPAQ_SUBTYPE_UR;

	tmp_flw_ptr[1] = 4;

	tmp_flw_ptr[2] = (ur->ur.value >> 8) & 0xFF;
	tmp_flw_ptr[3] = (ur->ur.value) & 0xFF;

	return 0;
}

int radius_encode_attr_vendor_3gpp2_ppaq_ps(const BYTE *flw_ptr, RADIUS_VENDOR_3GPP2_PPAQ_SUB_ATTR_PS *ps)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_3GPP2_PPAQ_SUBTYPE_PS;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[5] = (ps->ps.value >> 24) & 0xFF;
	tmp_flw_ptr[4] = (ps->ps.value >> 16) & 0xFF;
	tmp_flw_ptr[3] = (ps->ps.value >> 8) & 0xFF;
	tmp_flw_ptr[2] = (ps->ps.value) & 0xFF;

	return 0;
}

int radius_encode_attr_vendor_3gpp2_ppaq(const BYTE *flw_ptr, RADIUS_VENDOR_ATTRIBUTE_3GPP2_PPAQ *ppaq)
{
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr + 2;
	BYTE	*tmp_flw_ptr1 = (BYTE *)flw_ptr;

	if (ppaq->qid.flag == 1)
	{
		radius_encode_attr_vendor_3gpp2_ppaq_qid(tmp_flw_ptr, &ppaq->qid);

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	if (ppaq->vq.flag == 1)
	{
		radius_encode_attr_vendor_3gpp2_ppaq_vq(tmp_flw_ptr, &ppaq->vq);

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	if (ppaq->vqo.flag == 1)
	{
		radius_encode_attr_vendor_3gpp2_ppaq_vqo(tmp_flw_ptr, &ppaq->vqo);

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	if (ppaq->vt.flag == 1)
	{
		radius_encode_attr_vendor_3gpp2_ppaq_vt(tmp_flw_ptr, &ppaq->vt);

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	if (ppaq->vto.flag == 1)
	{
		radius_encode_attr_vendor_3gpp2_ppaq_vto(tmp_flw_ptr, &ppaq->vto);

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	if (ppaq->dq.flag == 1)
	{
		radius_encode_attr_vendor_3gpp2_ppaq_dq(tmp_flw_ptr, &ppaq->dq);

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	if (ppaq->dt.flag == 1)
	{
		radius_encode_attr_vendor_3gpp2_ppaq_dt(tmp_flw_ptr, &ppaq->dt);

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	if (ppaq->ur.flag == 1)
	{
		radius_encode_attr_vendor_3gpp2_ppaq_ur(tmp_flw_ptr, &ppaq->ur);

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	if (ppaq->ps.flag == 1)
	{
		radius_encode_attr_vendor_3gpp2_ppaq_ps(tmp_flw_ptr, &ppaq->ps);

		len += tmp_flw_ptr[1];
	}

	tmp_flw_ptr1[0] = RADIUS_VENDOR_TYPE_3GPP2_PPAQ;

	tmp_flw_ptr1[1] = len + 2;

	return 0;
}

int radius_encode_attr_vendor_3gpp_imsi(const BYTE *flw_ptr, RADIUS_VENDOR_ATTRIBUTE_3GPP_IMSI *imsi)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if (((len = strlen((char*)imsi->imsi)) < 3) || (len > 15))
	{
		radius_log_err("%s:imsi=%s\r\n", __FUNCTION__, imsi->imsi);
		return -1;
	}

	memcpy(&tmp_flw_ptr[2], imsi->imsi, len);

	tmp_flw_ptr[0] = RADIUS_VENDOR_TYPE_3GPP_IMSI;

	tmp_flw_ptr[1] = len + 2;

	return 0;
}

int radius_encode_attr_vendor_3gpp_cid(const BYTE *flw_ptr, RADIUS_VENDOR_ATTRIBUTE_3GPP_CID *charing_id)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[2] = (charing_id->cid >> 24) & 0xFF;
	tmp_flw_ptr[3] = (charing_id->cid >> 16) & 0xFF;
	tmp_flw_ptr[4] = (charing_id->cid >> 8) & 0xFF;
	tmp_flw_ptr[5] = (charing_id->cid) & 0xFF;

	tmp_flw_ptr[0] = RADIUS_VENDOR_TYPE_3GPP_CHARGING_ID;

	tmp_flw_ptr[1] = 6;

	return 0;
}

int radius_encode_attr_vendor_3gpp_pdp_type(const BYTE *flw_ptr, RADIUS_VENDOR_ATTRIBUTE_3GPP_PDP_TYPE *pdp_type)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[2] = (pdp_type->pdp_type>> 24) & 0xFF;
	tmp_flw_ptr[3] = (pdp_type->pdp_type>> 16) & 0xFF;
	tmp_flw_ptr[4] = (pdp_type->pdp_type>> 8) & 0xFF;
	tmp_flw_ptr[5] = (pdp_type->pdp_type) & 0xFF;

	tmp_flw_ptr[0] = RADIUS_VENDOR_TYPE_3GPP_PDP_TYPE;

	tmp_flw_ptr[1] = 6;

	return 0;
}

int radius_encode_attr_vendor_3gpp_cg_addr(const BYTE *flw_ptr, RADIUS_VENDOR_ATTRIBUTE_3GPP_CG_ADDR *cg_addr)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[5] = (cg_addr->cg_addr>> 24) & 0xFF;
	tmp_flw_ptr[4] = (cg_addr->cg_addr>> 16) & 0xFF;
	tmp_flw_ptr[3] = (cg_addr->cg_addr>> 8) & 0xFF;
	tmp_flw_ptr[2] = (cg_addr->cg_addr) & 0xFF;

	tmp_flw_ptr[0] = RADIUS_VENDOR_TYPE_3GPP_CG_ADDR;

	tmp_flw_ptr[1] = 6;

	return 0;
}

int radius_encode_attr_vendor_3gpp_nqp(const BYTE *flw_ptr, RADIUS_VENDOR_ATTRIBUTE_3GPP_NQP *nqp)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if (((len = strlen((char*)nqp->nqp)) < 3) || (len > 25))
	{
		radius_log_err("%s:nqp=%s\r\n", __FUNCTION__, nqp->nqp);
		return -1;
	}

	memcpy(&tmp_flw_ptr[2], nqp->nqp, len);

	tmp_flw_ptr[0] = RADIUS_VENDOR_TYPE_3GPP_NQP;

	tmp_flw_ptr[1] = len + 2;

	return 0;
}

int radius_encode_attr_vendor_3gpp_sgsn_addr(const BYTE *flw_ptr, RADIUS_VENDOR_ATTRIBUTE_3GPP_SGSN_ADDR *sgsn_addr)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[5] = (sgsn_addr->sgsn_addr >> 24) & 0xFF;
	tmp_flw_ptr[4] = (sgsn_addr->sgsn_addr >> 16) & 0xFF;
	tmp_flw_ptr[3] = (sgsn_addr->sgsn_addr >> 8) & 0xFF;
	tmp_flw_ptr[2] = (sgsn_addr->sgsn_addr) & 0xFF;

	tmp_flw_ptr[0] = RADIUS_VENDOR_TYPE_3GPP_SGSN_ADDR;

	tmp_flw_ptr[1] = 6;

	return 0;
}

int radius_encode_attr_vendor_3gpp_ggsn_addr(const BYTE *flw_ptr, RADIUS_VENDOR_ATTRIBUTE_3GPP_GGSN_ADDR *ggsn_addr)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[5] = (ggsn_addr->ggsn_addr >> 24) & 0xFF;
	tmp_flw_ptr[4] = (ggsn_addr->ggsn_addr >> 16) & 0xFF;
	tmp_flw_ptr[3] = (ggsn_addr->ggsn_addr>> 8) & 0xFF;
	tmp_flw_ptr[2] = (ggsn_addr->ggsn_addr) & 0xFF;

	tmp_flw_ptr[0] = RADIUS_VENDOR_TYPE_3GPP_GGSN_ADDR;

	tmp_flw_ptr[1] = 6;

	return 0;
}

int radius_encode_attr_vendor_3gpp_mcc_mnc(const BYTE *flw_ptr, RADIUS_VENDOR_ATTRIBUTE_3GPP_MCC_MNC *mcc_mnc)
{
	int		mcc_len;
	int		mnc_len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((mcc_len = strlen((char*)mcc_mnc->mcc)) != RADIUS_MAX_LEN_OF_MCC)
	{
		radius_log_err("%s:mcc=%s\r\n", __FUNCTION__, mcc_mnc->mcc);
		return -1;
	}

	if (((mnc_len = strlen((char*)mcc_mnc->mnc)) < 2) || (mnc_len > RADIUS_MAX_LEN_OF_MNC))
	{
		radius_log_err("%s:mnc=%s\r\n", __FUNCTION__, mcc_mnc->mnc);
		return -1;
	}

	memcpy(&tmp_flw_ptr[2], mcc_mnc->mcc, mcc_len);

	memcpy(&tmp_flw_ptr[2 + mcc_len], mcc_mnc->mnc, mnc_len);

	tmp_flw_ptr[0] = RADIUS_VENDOR_TYPE_3GPP_IMSI_MCC_MNC;

	tmp_flw_ptr[1] = mcc_len + mnc_len + 2;

	return 0;
}

int radius_encode_attr_vendor_3gpp_ggsn_mcc_mnc(const BYTE *flw_ptr, RADIUS_VENDOR_ATTRIBUTE_3GPP_GGSN_MCC_MNC *ggsn_mcc_mnc)
{
	int		mcc_len;
	int		mnc_len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((mcc_len = strlen((char*)ggsn_mcc_mnc->mcc)) != RADIUS_MAX_LEN_OF_MCC)
	{
		radius_log_err("%s:mcc=%s\r\n", __FUNCTION__, ggsn_mcc_mnc->mcc);
		return -1;
	}

	if (((mnc_len = strlen((char*)ggsn_mcc_mnc->mnc)) < 2) || (mnc_len > RADIUS_MAX_LEN_OF_MNC))
	{
		radius_log_err("%s:mnc=%s\r\n", __FUNCTION__, ggsn_mcc_mnc->mnc);
		return -1;
	}

	memcpy(&tmp_flw_ptr[2], ggsn_mcc_mnc->mcc, mcc_len);

	memcpy(&tmp_flw_ptr[2 + mcc_len], ggsn_mcc_mnc->mnc, mnc_len);

	tmp_flw_ptr[0] = RADIUS_VENDOR_TYPE_3GPP_GGSN_MCC_MNC;

	tmp_flw_ptr[1] = mcc_len + mnc_len + 2;

	return 0;
}

int radius_encode_attr_vendor_3gpp_nsapi(const BYTE *flw_ptr, RADIUS_VENDOR_ATTRIBUTE_3GPP_NSAPI *nsapi)
{
	BYTE	ptr[1] = "";
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if (nsapi->nsapi > 15)
	{
		radius_log_err("%s: nsapi=%d\r\n", __FUNCTION__, nsapi->nsapi);
		return -1;
	}

	sprintf((char*)ptr, "%X", nsapi->nsapi);

	memcpy(&tmp_flw_ptr[2], ptr, 1);

	tmp_flw_ptr[0] = RADIUS_VENDOR_TYPE_3GPP_NSAPI;

	tmp_flw_ptr[1] = 3;

	return 0;
}

int radius_encode_attr_vendor_3gpp_ssi(const BYTE *flw_ptr, RADIUS_VENDOR_ATTRIBUTE_3GPP_SSI *ssi)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[2] = 0xFF;

	tmp_flw_ptr[0] = RADIUS_VENDOR_TYPE_3GPP_SSI;

	tmp_flw_ptr[1] = 3;

	return 0;
}

int radius_encode_attr_vendor_3gpp_sm(const BYTE *flw_ptr, RADIUS_VENDOR_ATTRIBUTE_3GPP_SM *sm)
{
	BYTE	ptr[1] = "";
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if (sm->sm > 15)
	{
		radius_log_err("%s: selection mode=%d\r\n", __FUNCTION__, sm->sm);
		return -1;
	}

	sprintf((char*)ptr, "%X", sm->sm);

	memcpy(&tmp_flw_ptr[2], ptr, 1);

	tmp_flw_ptr[0] = RADIUS_VENDOR_TYPE_3GPP_SM;

	tmp_flw_ptr[1] = 3;

	return 0;
}

int radius_encode_attr_vendor_3gpp_cc(const BYTE *flw_ptr, RADIUS_VENDOR_ATTRIBUTE_3GPP_CC *cc)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)cc->cc)) != 4)
	{
		radius_log_err("%s: cc=%s\r\n", __FUNCTION__, cc->cc);
		return -1;
	}

	memcpy(&tmp_flw_ptr[2], cc->cc, len);

	tmp_flw_ptr[0] = RADIUS_VENDOR_TYPE_3GPP_CC;

	tmp_flw_ptr[1] = len + 2;

	return 0;
}

int radius_encode_attr_vendor_3gpp_sgsn_mcc_mnc(const BYTE *flw_ptr, RADIUS_VENDOR_ATTRIBUTE_3GPP_SGSN_MCC_MNC *sgsn_mcc_mnc)
{
	int		mcc_len;
	int		mnc_len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((mcc_len = strlen((char*)sgsn_mcc_mnc->mcc)) != RADIUS_MAX_LEN_OF_MCC)
	{
		radius_log_err("%s:mcc=%s\r\n", __FUNCTION__, sgsn_mcc_mnc->mcc);
		return -1;
	}

	if (((mnc_len = strlen((char*)sgsn_mcc_mnc->mnc)) < 2) || (mnc_len > RADIUS_MAX_LEN_OF_MNC))
	{
		radius_log_err("%s:mnc=%s\r\n", __FUNCTION__, sgsn_mcc_mnc->mnc);
		return -1;
	}

	memcpy(&tmp_flw_ptr[2], sgsn_mcc_mnc->mcc, mcc_len);

	memcpy(&tmp_flw_ptr[2 + mcc_len], sgsn_mcc_mnc->mnc, mnc_len);

	tmp_flw_ptr[0] = RADIUS_VENDOR_TYPE_3GPP_SGSN_MCC_MNC;

	tmp_flw_ptr[1] = mcc_len + mnc_len + 2;

	return 0;
}

int radius_encode_attr_vendor_specific(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_VENDOR_SPECIFIC *vendor_specific)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;
	DWORD	vendor_id;

	switch (vendor_specific->vendor_type)
	{
	case RADIUS_VENDOR_TYPE_3GPP2_PPAC:
		if (radius_encode_attr_vendor_3gpp2_ppac(tmp_flw_ptr + 6, &vendor_specific->attribute_3gpp2.ppac) < 0)
		{
			radius_log_err("%s: encode 3gpp2 ppac fail\r\n", __FUNCTION__);
			return -1;
		}

		vendor_id = RADIUS_VENDOR_ID_3GPP2;
		break;
	case RADIUS_VENDOR_TYPE_3GPP2_STC:
		if (radius_encode_attr_vendor_3gpp2_stc(tmp_flw_ptr + 6, &vendor_specific->attribute_3gpp2.stc) < 0)
		{
			radius_log_err("%s: encode 3gpp2 stc fail\r\n", __FUNCTION__);
			return -1;
		}

		vendor_id = RADIUS_VENDOR_ID_3GPP2;
		break;
	case RADIUS_VENDOR_TYPE_3GPP2_PPAQ:
		if (radius_encode_attr_vendor_3gpp2_ppaq(tmp_flw_ptr + 6, &vendor_specific->attribute_3gpp2.ppaq) < 0)
		{
			radius_log_err("%s: encode 3gpp2 ppaq fail\r\n", __FUNCTION__);
			return -1;
		}

		vendor_id = RADIUS_VENDOR_ID_3GPP2;
		break;
	case RADIUS_VENDOR_TYPE_3GPP_IMSI:
		if (radius_encode_attr_vendor_3gpp_imsi(tmp_flw_ptr + 6, &vendor_specific->attribute_3gpp.imsi) < 0)
		{
			radius_log_err("%s: encode 3gpp imsi fail\r\n", __FUNCTION__);
			return -1;
		}

		vendor_id = RADIUS_VENDOR_ID_3GPP;
		break;
	case RADIUS_VENDOR_TYPE_3GPP_CHARGING_ID:
		if (radius_encode_attr_vendor_3gpp_cid(tmp_flw_ptr + 6, &vendor_specific->attribute_3gpp.charging_id) < 0)
		{
			radius_log_err("%s: encode 3gpp charging id fail\r\n", __FUNCTION__);
			return -1;
		}

		vendor_id = RADIUS_VENDOR_ID_3GPP;
		break;
	case RADIUS_VENDOR_TYPE_3GPP_PDP_TYPE:
		if (radius_encode_attr_vendor_3gpp_pdp_type(tmp_flw_ptr + 6, &vendor_specific->attribute_3gpp.pdp_type) < 0)
		{
			radius_log_err("%s: encode 3gpp pdp type fail\r\n", __FUNCTION__);
			return -1;
		}

		vendor_id = RADIUS_VENDOR_ID_3GPP;
		break;
	case RADIUS_VENDOR_TYPE_3GPP_CG_ADDR:
		if (radius_encode_attr_vendor_3gpp_cg_addr(tmp_flw_ptr + 6, &vendor_specific->attribute_3gpp.cg_addr) < 0)
		{
			radius_log_err("%s: encode 3gpp cg addr fail\r\n", __FUNCTION__);
			return -1;
		}

		vendor_id = RADIUS_VENDOR_ID_3GPP;
		break;
	case RADIUS_VENDOR_TYPE_3GPP_NQP:
		if (radius_encode_attr_vendor_3gpp_nqp(tmp_flw_ptr + 6, &vendor_specific->attribute_3gpp.negotiated_qos) < 0)
		{
			radius_log_err("%s: encode 3gpp negotiated qos profile fail\r\n", __FUNCTION__);
			return -1;
		}

		vendor_id = RADIUS_VENDOR_ID_3GPP;
		break;
	case RADIUS_VENDOR_TYPE_3GPP_SGSN_ADDR:
		if (radius_encode_attr_vendor_3gpp_sgsn_addr(tmp_flw_ptr + 6, &vendor_specific->attribute_3gpp.sgsn_addr) < 0)
		{
			radius_log_err("%s: encode 3gpp sgsn addr fail\r\n", __FUNCTION__);
			return -1;
		}

		vendor_id = RADIUS_VENDOR_ID_3GPP;
		break;
	case RADIUS_VENDOR_TYPE_3GPP_GGSN_ADDR:
		if (radius_encode_attr_vendor_3gpp_ggsn_addr(tmp_flw_ptr + 6, &vendor_specific->attribute_3gpp.ggsn_addr) < 0)
		{
			radius_log_err("%s: encode 3gpp ggsn addr fail\r\n", __FUNCTION__);
			return -1;
		}

		vendor_id = RADIUS_VENDOR_ID_3GPP;
		break;
	case RADIUS_VENDOR_TYPE_3GPP_IMSI_MCC_MNC:
		if (radius_encode_attr_vendor_3gpp_mcc_mnc(tmp_flw_ptr + 6, &vendor_specific->attribute_3gpp.mcc_mnc) < 0)
		{
			radius_log_err("%s: encode 3gpp imsi mcc mnc fail\r\n", __FUNCTION__);
			return -1;
		}

		vendor_id = RADIUS_VENDOR_ID_3GPP;
		break;
	case RADIUS_VENDOR_TYPE_3GPP_GGSN_MCC_MNC:
		if (radius_encode_attr_vendor_3gpp_ggsn_mcc_mnc(tmp_flw_ptr + 6, &vendor_specific->attribute_3gpp.ggsn_mcc_mnc) < 0)
		{
			radius_log_err("%s: encode 3gpp ggsn mcc mnc fail\r\n", __FUNCTION__);
			return -1;
		}

		vendor_id = RADIUS_VENDOR_ID_3GPP;
		break;
	case RADIUS_VENDOR_TYPE_3GPP_NSAPI:
		if (radius_encode_attr_vendor_3gpp_nsapi(tmp_flw_ptr + 6, &vendor_specific->attribute_3gpp.nsapi) < 0)
		{
			radius_log_err("%s: encode 3gpp nsapi fail\r\n", __FUNCTION__);
			return -1;
		}

		vendor_id = RADIUS_VENDOR_ID_3GPP;
		break;
	case RADIUS_VENDOR_TYPE_3GPP_SSI:
		if (radius_encode_attr_vendor_3gpp_ssi(tmp_flw_ptr + 6, &vendor_specific->attribute_3gpp.ssi) < 0)
		{
			radius_log_err("%s: encode 3gpp ssi fail\r\n", __FUNCTION__);
			return -1;
		}

		vendor_id = RADIUS_VENDOR_ID_3GPP;
		break;
	case RADIUS_VENDOR_TYPE_3GPP_SM:
		if (radius_encode_attr_vendor_3gpp_sm(tmp_flw_ptr + 6, &vendor_specific->attribute_3gpp.sm) < 0)
		{
			radius_log_err("%s: encode 3gpp sm fail\r\n", __FUNCTION__);
			return -1;
		}

		vendor_id = RADIUS_VENDOR_ID_3GPP;
		break;
	case RADIUS_VENDOR_TYPE_3GPP_CC:
		if (radius_encode_attr_vendor_3gpp_cc(tmp_flw_ptr + 6, &vendor_specific->attribute_3gpp.cc) < 0)
		{
			radius_log_err("%s: encode 3gpp cc fail\r\n", __FUNCTION__);
			return -1;
		}

		vendor_id = RADIUS_VENDOR_ID_3GPP;
		break;
	case RADIUS_VENDOR_TYPE_3GPP_SGSN_MCC_MNC:
		if (radius_encode_attr_vendor_3gpp_sgsn_mcc_mnc(tmp_flw_ptr + 6, &vendor_specific->attribute_3gpp.sgsn_mcc_mnc) < 0)
		{
			radius_log_err("%s: encode 3gpp sgsn mcc mnc fail\r\n", __FUNCTION__);
			return -1;
		}

		vendor_id = RADIUS_VENDOR_ID_3GPP;
		break;
	default:
		radius_log_err("%s: not support vendor type=%d\r\n", __FUNCTION__, vendor_specific->vendor_type);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_VENDOR_SPECIFIC;

	tmp_flw_ptr[1] = tmp_flw_ptr[7] + 6;

	tmp_flw_ptr[2] = (vendor_id >> 24) & 0xFF;
	tmp_flw_ptr[3] = (vendor_id >> 16) & 0xFF;
	tmp_flw_ptr[4] = (vendor_id >> 8) & 0xFF;
	tmp_flw_ptr[5] = (vendor_id) & 0xFF;

	return 0;
}

int radius_encode_vendor_specific(const BYTE *flw_ptr, RADIUS_VENDOR_SPECIFIC *vendor_specific)
{
	int		i;
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((vendor_specific->num == 0) || (vendor_specific->num > RADIUS_MAX_NUM_OF_VENDOR_SPECIFIC))
	{
		radius_log_err("%s: vendor specific num=%d\r\n", __FUNCTION__, vendor_specific->num);
		return -1;
	}

	for (i = 0; i < vendor_specific->num; i++)
	{
		if (radius_encode_attr_vendor_specific(tmp_flw_ptr, &vendor_specific->vendor_specific[i]) < 0)
		{
			radius_log_err("%s: encode vendor specific fail, vendor specific num=%d\r\n", __FUNCTION__, i);
			return -1;
		}

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	return len;
}

int radius_encode_attr_session_timeout(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_SESSION_TIMEOUT *session_timeout)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_SESSION_TIMEOUT;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (session_timeout->session_timeout.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (session_timeout->session_timeout.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (session_timeout->session_timeout.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (session_timeout->session_timeout.value) & 0xFF;

	return 0;
}

int radius_encode_attr_idle_timeout(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_IDLE_TIMEOUT *idle_timeout)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_IDLE_TIMEOUT;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (idle_timeout->idle_timeout.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (idle_timeout->idle_timeout.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (idle_timeout->idle_timeout.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (idle_timeout->idle_timeout.value) & 0xFF;

	return 0;
}

int radius_encode_attr_termination_action(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_TERMINATION_ACTION *termiantion_action)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_TERMINATION_ACTION;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (termiantion_action->termination_action.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (termiantion_action->termination_action.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (termiantion_action->termination_action.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (termiantion_action->termination_action.value) & 0xFF;

	return 0;
}
/*
int radius_encode_attr_called_station_id(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_CALLED_STATION_ID *called_station_id)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen(called_station_id->called_station_id.value)) == 0)
	{
		radius_log_err("%s: radius called station id=%s is NULL\r\n", __FUNCTION__, called_station_id->called_station_id.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_CALLED_STATION_ID;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], called_station_id->called_station_id.value, len);

	return 0;
}
int radius_encode_attr_nowsms_called_station_id(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_NOWSMS_CALLED_STATION_ID *called_station_id)
{
	int		i, num, offset;
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr+2;

	if ((called_station_id->client.len == 0) || (called_station_id->client.len > 1300))
	{
		radius_log_err("%s: client called station id len=%d\r\n", __FUNCTION__, called_station_id->client.len);
		return -1;
	}
	num = called_station_id->client.len / 250;
	offset = called_station_id->client.len % 250
	if(offset != 0)
		num++;

	for (i = 0; i < num; i++)
	{
		if(i+1 == num)
		{
			tmp_flw_ptr[1] = offset;
		}
		else
			tmp_flw_ptr[1] = 250;
		memcpy(tmp_flw_ptr+2, &called_station_id->client.called_list[i*250], tmp_flw_ptr[1]);
		tmp_flw_ptr[0] = i + 1;
		len += tmp_flw_ptr[1]+2;
		tmp_flw_ptr += tmp_flw_ptr[1]+2;
	}
	flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_CALLED_STATION_ID;
	flw_ptr[1] = len + 2;

	return len;
}*/

static int radius_encode_attr_called_list(const BYTE *flw_ptr, BYTE *called_list, BYTE length)
{
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if(length == 0 || length > RADIUS_NOWSMS_MAX_LEN_OF_PER_CALLED)
	{
		radius_log_err("%s: radius called list split length = %d, max length is 250!\r\n", __FUNCTION__, length);
		return -1;
	}
	memcpy(&tmp_flw_ptr[2], called_list, length);
	len = length + 2;
	tmp_flw_ptr[1] = len;
	tmp_flw_ptr[0] = 0xFF;

	return len;
}
int radius_encode_attr_called_station_id(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_CALLED_STATION_ID *called_station_id)
{
	int		i, num, offset;
	int		len = 0, tmp_len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;
	BYTE	*tmp_flw_ptr1, *called_list;

	if(called_station_id->option == 1)
	{
		if(called_station_id->called.server.num != 1)
		{
			radius_log_err("%s: radius server called station id max num=%d\r\n", __FUNCTION__, called_station_id->called.server.num);
			return -1;
		}
		if((len = strlen((char*)called_station_id->called.server.called_station_id[0].value)) == 0)
		{
			radius_log_err("%s: radius server called station id=%s is NULL\r\n", __FUNCTION__, called_station_id->called.server.called_station_id[0].value);
			return -1;
		}
		memcpy(&tmp_flw_ptr[2], called_station_id->called.server.called_station_id[0].value, len);
		len += 2;
		tmp_flw_ptr[1] = len;
		tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_CALLED_STATION_ID;
	}
	else
	{
		called_list = called_station_id->called.client.called_list;
		num = strlen((char*)called_list);
		if((num <= 0) || (num > RADIUS_MAX_NUM_OF_NOWSMS_CALLED_LIST))
		{
			radius_log_err("%s: radius called station id len=%d\r\n", __FUNCTION__, num);
			return -1;
		}
		offset = num % RADIUS_NOWSMS_MAX_LEN_OF_PER_CALLED;
		num = num / RADIUS_NOWSMS_MAX_LEN_OF_PER_CALLED;
		if(offset != 0)
			num++;
		for(i = 0; i < num; i ++)
		{
			tmp_flw_ptr1 = tmp_flw_ptr + 2;
			if((i+1) == num && offset != 0)
				tmp_len = offset;
			else
				tmp_len = RADIUS_NOWSMS_MAX_LEN_OF_PER_CALLED;
			if((tmp_len = radius_encode_attr_called_list(tmp_flw_ptr1, \
				called_list+i*RADIUS_NOWSMS_MAX_LEN_OF_PER_CALLED, tmp_len)) <= 0)
			{
				radius_log_err("%s: radius called list length err! i=%d\r\n", __FUNCTION__, i);
				continue;
			}
			tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_CALLED_STATION_ID;
			tmp_flw_ptr[1] = tmp_len + 3;
			tmp_flw_ptr[tmp_len+2] = ((num<<4)&0xF0) | ((i+1)&0x0F);
			len += tmp_flw_ptr[1];
			tmp_flw_ptr += tmp_flw_ptr[1];
/*			memcpy(tmp_flw_ptr1+2, &called_station_id->called.client.called_list[i*RADIUS_NOWSMS_MAX_LEN_OF_PER_CALLED], tmp_flw_ptr1[1]);
			tmp_flw_ptr1[0] = 0xFF - i;	//i + 1
			tmp_flw_ptr[1] = tmp_flw_ptr1[1] + 4;
			len += tmp_flw_ptr1[1]+2;
			tmp_flw_ptr1 += tmp_flw_ptr1[1]+2;*/
		}
		if(tmp_flw_ptr1[1] == tmp_len)
		{
			tmp_flw_ptr1[tmp_len] = 0xFF;	//end indicator
		}
	}

	return len;
}


int radius_encode_attr_calling_station_id(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_CALLING_STATION_ID *calling_station_id)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)calling_station_id->calling_station_id.value)) == 0)
	{
		radius_log_err("%s: radius calling station id=%s is NULL\r\n", __FUNCTION__, calling_station_id->calling_station_id.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_CALLING_STATION_ID;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], calling_station_id->calling_station_id.value, len);

	return 0;
}

int radius_encode_attr_nas_id(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_NAS_IDENTIFIER *nas_id)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)nas_id->nas_identifier.value)) == 0)
	{
		radius_log_err("%s: radius nas id=%s is NULL\r\n", __FUNCTION__, nas_id->nas_identifier.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_NAS_IDENTIFIER;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], nas_id->nas_identifier.value, len);

	return 0;
}

int radius_encode_attr_proxy_state(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_PROXY_STATE *proxy_state)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)proxy_state->proxy_state.value)) == 0)
	{
		radius_log_err("%s: radius proxy state=%s is NULL\r\n", __FUNCTION__, proxy_state->proxy_state.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_PROXY_STATE;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], proxy_state->proxy_state.value, len);

	return 0;
}

int radius_encode_proxy_state(const BYTE *flw_ptr, RADIUS_PROXY_STATE *proxy_state)
{
	int		i;
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((proxy_state->num == 0) || (proxy_state->num > RADIUS_MAX_NUM_OF_PROXY_STATE))
	{
		radius_log_err("%s: proxy state num=%d\r\n", __FUNCTION__, proxy_state->num);
		return -1;
	}

	for (i = 0; i < proxy_state->num; i++)
	{
		if (radius_encode_attr_proxy_state(tmp_flw_ptr, &proxy_state->proxy_state[i]) < 0)
		{
			radius_log_err("%s: encode attr proxy state fail, proxy state num=%d\r\n", __FUNCTION__, i);
			return -1;
		}

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	return len;
}

int radius_encode_attr_login_lat_service(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_LOGIN_LAT_SERVICE *login_lat_service)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)login_lat_service->login_lat_service.value)) == 0)
	{
		radius_log_err("%s: radius login lat service=%s is NULL\r\n", __FUNCTION__, login_lat_service->login_lat_service.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_LOGIN_LAT_SERVICE;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], login_lat_service->login_lat_service.value, len);

	return 0;
}

int radius_encode_attr_login_lat_node(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_LOGIN_LAT_NODE *login_lat_node)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)login_lat_node->login_lat_node.value)) == 0)
	{
		radius_log_err("%s: radius login lat node=%s is NULL\r\n", __FUNCTION__, login_lat_node->login_lat_node.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_LOGIN_LAT_NODE;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], login_lat_node->login_lat_node.value, len);

	return 0;
}

int radius_encode_attr_login_lat_group(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_LOGIN_LAT_GROUP *login_lat_group)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)login_lat_group->login_lat_group.value)) == 0)
	{
		radius_log_err("%s: radius login lat service=%s is NULL\r\n", __FUNCTION__, login_lat_group->login_lat_group.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_LOGIN_LAT_GROUP;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], login_lat_group->login_lat_group.value, len);

	return 0;
}

int radius_encode_attr_framed_appletalk_link(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_FRAMED_APPLETALK_LINK *framed_appletalk_link)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_FRAMED_APPLETALK_LINK;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (framed_appletalk_link->framed_appletalk_link.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (framed_appletalk_link->framed_appletalk_link.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (framed_appletalk_link->framed_appletalk_link.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (framed_appletalk_link->framed_appletalk_link.value) & 0xFF;

	return 0;
}
int radius_encode_attr_framed_appletalk_network(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_FRAMED_APPLETALK_NETWORK *framed_appletalk_network)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_FRAMED_APPLETALK_NETWORK;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (framed_appletalk_network->framed_appletalk_network.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (framed_appletalk_network->framed_appletalk_network.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (framed_appletalk_network->framed_appletalk_network.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (framed_appletalk_network->framed_appletalk_network.value) & 0xFF;

	return 0;
}

int radius_encode_framed_appletalk_network(const BYTE *flw_ptr, RADIUS_FRAMED_APPLETALK_NETWORK *framed_appletalk_network)
{
	int		i;
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((framed_appletalk_network->num == 0) || (framed_appletalk_network->num > RADIUS_MAX_NUM_OF_FRAMED_APPLETALK_NETWORK))
	{
		radius_log_err("%s: framed appletalk network num=%d\r\n", __FUNCTION__, framed_appletalk_network->num);
		return -1;
	}

	for (i = 0; i < framed_appletalk_network->num; i++)
	{
		if (radius_encode_attr_framed_appletalk_network(tmp_flw_ptr, &framed_appletalk_network->framed_appletalk_network[i]) < 0)
		{
			radius_log_err("%s: encode attr framed appletalk network fail, framed appletalk network num=%d\r\n", __FUNCTION__, i);
			return -1;
		}

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	return len;
}

int radius_encode_attr_framed_appletalk_zone(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_FRAMED_APPLETALK_ZONE *framed_appletalk_zone)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)framed_appletalk_zone->framed_appletalk_zone.value)) == 0)
	{
		radius_log_err("%s: radius framed appletalk zone=%s is NULL\r\n", __FUNCTION__, framed_appletalk_zone->framed_appletalk_zone.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_FRAMED_APPLETALK_ZONE;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], framed_appletalk_zone->framed_appletalk_zone.value, len);

	return 0;
}

int radius_encode_attr_acct_status_type(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_ACCT_STATUS_TYPE *acct_status_type)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_ACCT_STATUS_TYPE;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (acct_status_type->acct_status_type.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (acct_status_type->acct_status_type.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (acct_status_type->acct_status_type.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (acct_status_type->acct_status_type.value) & 0xFF;

	return 0;
}

int radius_encode_attr_acct_delay_time(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_ACCT_DELAY_TIME *acct_delay_time)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_ACCT_DELAY_TIME;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (acct_delay_time->acct_delay_time.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (acct_delay_time->acct_delay_time.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (acct_delay_time->acct_delay_time.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (acct_delay_time->acct_delay_time.value) & 0xFF;

	return 0;
}

int radius_encode_attr_acct_input_octets(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_ACCT_INPUT_OCTETS *acct_input_octets)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_ACCT_INPUT_OCTETS;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (acct_input_octets->acct_input_octets.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (acct_input_octets->acct_input_octets.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (acct_input_octets->acct_input_octets.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (acct_input_octets->acct_input_octets.value) & 0xFF;

	return 0;
}

int radius_encode_attr_acct_output_octets(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_ACCT_OUTPUT_OCTETS *acct_output_octets)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_ACCT_OUTPUT_OCTETS;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (acct_output_octets->acct_output_octets.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (acct_output_octets->acct_output_octets.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (acct_output_octets->acct_output_octets.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (acct_output_octets->acct_output_octets.value) & 0xFF;

	return 0;
}

int radius_encode_attr_acct_session_id(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_ACCT_SESSION_ID *acct_session_id)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)acct_session_id->acct_session_id.value)) == 0)
	{
		radius_log_err("%s: radius acct seesion id=%s is NULL\r\n", __FUNCTION__, acct_session_id->acct_session_id.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_ACCT_SESSION_ID;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], acct_session_id->acct_session_id.value, len);

	return 0;
}

int radius_encode_attr_acct_authentic(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_ACCT_AUTHENTIC *acct_authentic)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_ACCT_AUTHENTIC;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (acct_authentic->acct_authentic.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (acct_authentic->acct_authentic.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (acct_authentic->acct_authentic.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (acct_authentic->acct_authentic.value) & 0xFF;

	return 0;
}

int radius_encode_attr_acct_session_time(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_ACCT_SESSION_TIME *acct_session_time)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_ACCT_SESSION_TIME;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (acct_session_time->acct_session_time.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (acct_session_time->acct_session_time.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (acct_session_time->acct_session_time.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (acct_session_time->acct_session_time.value) & 0xFF;

	return 0;
}

int radius_encode_attr_acct_input_packets(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_ACCT_INPUT_PACKETS *acct_input_packets)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_ACCT_INPUT_PACKETS;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (acct_input_packets->acct_input_packets.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (acct_input_packets->acct_input_packets.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (acct_input_packets->acct_input_packets.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (acct_input_packets->acct_input_packets.value) & 0xFF;

	return 0;
}

int radius_encode_attr_acct_output_packets(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_ACCT_OUTPUT_PACKETS *acct_output_packets)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_ACCT_OUTPUT_PACKETS;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (acct_output_packets->acct_output_packets.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (acct_output_packets->acct_output_packets.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (acct_output_packets->acct_output_packets.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (acct_output_packets->acct_output_packets.value) & 0xFF;

	return 0;
}

int radius_encode_attr_acct_terminate_cause(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_ACCT_TERMINATE_CAUSE *acct_terminate_cause)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_ACCT_TERMINATE_CAUSE;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (acct_terminate_cause->acct_terminate_cause.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (acct_terminate_cause->acct_terminate_cause.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (acct_terminate_cause->acct_terminate_cause.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (acct_terminate_cause->acct_terminate_cause.value) & 0xFF;

	return 0;
}

int radius_encode_attr_acct_multi_session_id(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_ACCT_MULTI_SESSION_ID *acct_multi_session_id)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)acct_multi_session_id->acct_multi_session_id.value)) == 0)
	{
		radius_log_err("%s: radius acct multi seesion id=%s is NULL\r\n", __FUNCTION__, acct_multi_session_id->acct_multi_session_id.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_ACCT_MULTI_SESSION_ID;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], acct_multi_session_id->acct_multi_session_id.value, len);

	return 0;
}

int radius_encode_acct_multi_session_id(const BYTE *flw_ptr, RADIUS_ACCT_MULTI_SESSION_ID *acct_multi_session_id)
{
	int		i;
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((acct_multi_session_id->num == 0) || (acct_multi_session_id->num > RADIUS_MAX_NUM_OF_ACCT_MULTI_SESSION_ID))
	{
		radius_log_err("%s: acct multi session id num=%d\r\n", __FUNCTION__, acct_multi_session_id->num);
		return -1;
	}

	for (i = 0; i < acct_multi_session_id->num; i++)
	{
		if (radius_encode_attr_acct_multi_session_id(tmp_flw_ptr, &acct_multi_session_id->acct_multi_session_id[i]) < 0)
		{
			radius_log_err("%s: encode attr acct multi session id fail, acct multi session id num=%d\r\n", __FUNCTION__, i);
			return -1;
		}

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	return len;
}

int radius_encode_attr_acct_link_count(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_ACCT_LINK_COUNT *acct_link_count)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_ACCT_LINK_COUNT;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (acct_link_count->acct_link_count.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (acct_link_count->acct_link_count.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (acct_link_count->acct_link_count.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (acct_link_count->acct_link_count.value) & 0xFF;

	return 0;
}

int radius_encode_acct_link_count(const BYTE *flw_ptr, RADIUS_ACCT_LINK_COUNT *acct_link_count)
{
	int		i;
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((acct_link_count->num == 0) || (acct_link_count->num > RADIUS_MAX_NUM_OF_ACCT_LINK_COUNT))
	{
		radius_log_err("%s: acct link count num=%d\r\n", __FUNCTION__, acct_link_count->num);
		return -1;
	}

	for (i = 0; i < acct_link_count->num; i++)
	{
		if (radius_encode_attr_acct_link_count(tmp_flw_ptr, &acct_link_count->acct_link_count[i]) < 0)
		{
			radius_log_err("%s: encode attr acct link count fail, acct link count num=%d\r\n", __FUNCTION__, i);
			return -1;
		}

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	return len;
}

int radius_encode_attr_event_timestamp(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_EVENT_TIMESTAMP *event_timestamp)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_EVENT_TIMESTAMP;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (event_timestamp->event_timestamp.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (event_timestamp->event_timestamp.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (event_timestamp->event_timestamp.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (event_timestamp->event_timestamp.value) & 0xFF;

	return 0;
}

int radius_encode_attr_chap_challenge(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_CHAP_CHALLENGE *chap_challenge)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)chap_challenge->chap_challenge.value)) == 0)
	{
		radius_log_err("%s: radius chap challenge=%s is NULL\r\n", __FUNCTION__, chap_challenge->chap_challenge.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_CHAP_CHALLENGE;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], chap_challenge->chap_challenge.value, len);

	return 0;
}

int radius_encode_attr_nas_port_type(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_NAS_PORT_TYPE *nas_port_type)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_NAS_PORT_TYPE;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (nas_port_type->nas_port_type.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (nas_port_type->nas_port_type.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (nas_port_type->nas_port_type.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (nas_port_type->nas_port_type.value) & 0xFF;

	return 0;
}

int radius_encode_attr_port_limit(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_PORT_LIMIT *port_limit)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_PORT_LIMIT;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (port_limit->port_limit.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (port_limit->port_limit.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (port_limit->port_limit.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (port_limit->port_limit.value) & 0xFF;

	return 0;
}

int radius_encode_attr_login_lat_port(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_LOGIN_LAT_PORT *login_lat_port)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)login_lat_port->login_lat_port.value)) == 0)
	{
		radius_log_err("%s: radius login lat port=%s is NULL\r\n", __FUNCTION__, login_lat_port->login_lat_port.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_LOGIN_LAT_PORT;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], login_lat_port->login_lat_port.value, len);

	return 0;
}

int radius_encode_attr_arap_password(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_ARAP_PASSWORD *arap_password)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)arap_password->arap_password.value)) == 0)
	{
		radius_log_err("%s: radius arap_password=%s is NULL\r\n", __FUNCTION__, arap_password->arap_password.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_ARAP_PASSWORD;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], arap_password->arap_password.value, len);

	return 0;
}

int radius_encode_attr_arap_feature(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_ARAP_FEATURES *arap_feature)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)arap_feature->arap_features.value)) == 0)
	{
		radius_log_err("%s: radius arap_features=%s is NULL\r\n", __FUNCTION__, arap_feature->arap_features.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_ARAP_FEATURES;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], arap_feature->arap_features.value, len);

	return 0;
}

int radius_encode_attr_arap_zone_access(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_ARAP_ZONE_ACCESS *arap_zone_access)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_ARAP_ZONE_ACCESS;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (arap_zone_access->arap_zone_access.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (arap_zone_access->arap_zone_access.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (arap_zone_access->arap_zone_access.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (arap_zone_access->arap_zone_access.value) & 0xFF;

	return 0;
}

int radius_encode_attr_arap_security(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_ARAP_SECURITY *arap_security)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_ARAP_SECURITY;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (arap_security->arap_security.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (arap_security->arap_security.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (arap_security->arap_security.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (arap_security->arap_security.value) & 0xFF;

	return 0;
}

int radius_encode_attr_arap_security_data(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_ARAP_SECURITY_DATA *arap_security_data)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = arap_security_data->arap_security_data.length) == 0)
	{
		radius_log_err("%s: radius arap security data length=%d is NULL\r\n", __FUNCTION__, arap_security_data->arap_security_data.length);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_ARAP_SECURITY_DATA;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], arap_security_data->arap_security_data.value, len);

	return 0;
}

int radius_encode_arap_security_data(const BYTE *flw_ptr, RADIUS_ARAP_SECURITY_DATA *arap_security_data)
{
	int		i;
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((arap_security_data->num == 0) || (arap_security_data->num > RADIUS_MAX_NUM_OF_ARAP_SECURITY_DATA))
	{
		radius_log_err("%s: arap security data num=%d\r\n", __FUNCTION__, arap_security_data->num);
		return -1;
	}

	for (i = 0; i < arap_security_data->num; i++)
	{
		if (radius_encode_attr_arap_security_data(tmp_flw_ptr, &arap_security_data->arap_security_data[i]) < 0)
		{
			radius_log_err("%s: encode attr arap security data fail, arap security data num=%d\r\n", __FUNCTION__, i);
			return -1;
		}

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	return len;
}

int radius_encode_attr_password_retry(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_PASSWORD_RETRY *password_retry)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_PASSWORD_RETRY;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (password_retry->password_retry.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (password_retry->password_retry.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (password_retry->password_retry.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (password_retry->password_retry.value) & 0xFF;

	return 0;
}

int radius_encode_attr_prompt(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_PROMPT *prompt)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_PROMPT;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (prompt->prompt.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (prompt->prompt.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (prompt->prompt.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (prompt->prompt.value) & 0xFF;

	return 0;
}

int radius_encode_attr_connect_info(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_CONNECT_INFO *connect_info)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)connect_info->connect_info.value)) == 0)
	{
		radius_log_err("%s: radius connect info=%s is NULL\r\n", __FUNCTION__, connect_info->connect_info.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_CONNECT_INFO;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], connect_info->connect_info.value, len);

	return 0;
}

int radius_encode_attr_configuration_token(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_CONFIGURATION_TOKEN *configuration_token)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)configuration_token->configuration_token.value)) == 0)
	{
		radius_log_err("%s: radius configuration token=%s is NULL\r\n", __FUNCTION__, configuration_token->configuration_token.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_CONFIGURATION_TOKEN;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], configuration_token->configuration_token.value, len);

	return 0;
}

int radius_encode_configuration_token(const BYTE *flw_ptr, RADIUS_CONFIGURATION_TOKEN *configuration_token)
{
	int		i;
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((configuration_token->num == 0) || (configuration_token->num > RADIUS_MAX_NUM_OF_CONFIGURATION_TOKEN))
	{
		radius_log_err("%s: configuration token num=%d\r\n", __FUNCTION__, configuration_token->num);
		return -1;
	}

	for (i = 0; i < configuration_token->num; i++)
	{
		if (radius_encode_attr_configuration_token(tmp_flw_ptr, &configuration_token->configuration_token[i]) < 0)
		{
			radius_log_err("%s: encode attr configuration token fail, configuration token num=%d\r\n", __FUNCTION__, i);
			return -1;
		}

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	return len;
}

/*int radius_encode_attr_message_authenticator(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_MESSAGE_AUTHENTICATOR *message_authenticator)
{
	int		len;
	BYTE	*tmp_flw_ptr = flw_ptr;

	if ((len = strlen(configuration_token->configuration_token.value)) == 0)
	{
		radius_log_err("%s: radius configuration token=%s is NULL\r\n", __FUNCTION__, configuration_token->configuration_token.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_MESSAGE_AUTHENTICATOR;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], message_authenticator->configuration_token.value, len);

	return 0;
}*/

int radius_encode_attr_acct_interim_interval(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_ACCT_INTERIM_INTERVAL *acct_interim_interval)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_ACCT_INTERIM_INTERVAL;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (acct_interim_interval->acct_interim_interval.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (acct_interim_interval->acct_interim_interval.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (acct_interim_interval->acct_interim_interval.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (acct_interim_interval->acct_interim_interval.value) & 0xFF;

	return 0;
}

int radius_encode_attr_nas_port_id(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_NAS_PORT_ID *nas_port_id)
{
	int		len;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((len = strlen((char*)nas_port_id->nas_port_id.value)) == 0)
	{
		radius_log_err("%s: radius nas port id=%s is NULL\r\n", __FUNCTION__, nas_port_id->nas_port_id.value);
		return -1;
	}

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_NAS_PORT_ID;

	tmp_flw_ptr[1] = len + 2;

	memcpy(&tmp_flw_ptr[2], nas_port_id->nas_port_id.value, len);

	return 0;
}

int radius_encode_attr_error_cause(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_ERROR_CAUSE *error_cause)
{
	BYTE 	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_ERROR_CAUSE;

	tmp_flw_ptr[1] = 6;

	tmp_flw_ptr[2] = (error_cause->error_cause.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (error_cause->error_cause.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (error_cause->error_cause.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (error_cause->error_cause.value) & 0xFF;

	return 0;
}

int radius_encode_error_cause(const BYTE *flw_ptr, RADIUS_ERROR_CAUSE *error_cause)
{
	int		i;
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	if ((error_cause->num == 0) || (error_cause->num > RADIUS_MAX_NUM_OF_ARAP_SECURITY_DATA))
	{
		radius_log_err("%s: error cause num=%d\r\n", __FUNCTION__, error_cause->num);
		return -1;
	}

	for (i = 0; i < error_cause->num; i++)
	{
		if (radius_encode_attr_error_cause(tmp_flw_ptr, &error_cause->error_cause[i]) < 0)
		{
			radius_log_err("%s: encode attr error cause fail, error cause num=%d\r\n", __FUNCTION__, i);
			return -1;
		}

		len += tmp_flw_ptr[1];

		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	return len;
}

int radius_encode_attr_message_authenticator(BYTE *msg, const BYTE *flw_ptr, BYTE *share_key)
{
	int		len = 0;
	BYTE	message_auth[16] = "";
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_MESSAGE_AUTHENTICATOR;

	tmp_flw_ptr[1] = RADIUS_MAX_LEN_OF_MESSAGE_AUTH_ATTR + 2;

	memset(tmp_flw_ptr + 2, 0, RADIUS_MAX_LEN_OF_MESSAGE_AUTH_ATTR);

	len = tmp_flw_ptr + 18 - msg;

	msg[2] = (len >> 8) & 0xFF;
	msg[3] = (len) & 0xFF;

	radius_get_hmac_md5_hex(message_auth, msg, len, share_key, strlen((char*)share_key));

	memcpy(tmp_flw_ptr + 2, message_auth, RADIUS_MAX_LEN_OF_MESSAGE_AUTH_ATTR);

	return 0;
}

/*
int radius_encode_attr_nowsms_preauth_type(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_NOWSMS_PREAUTH_TYPE *pre_auth_type)
{
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE*)flw_ptr;

	if((len = strlen(pre_auth_type->pre_auth_type.value)) == 0)
	{
		radius_log_err("%s: radius nowsms pre auth type=%s is NULL\r\n", __FUNCTION__, pre_auth_type->pre_auth_type.value);
		return -1;
	}
	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_NOWSMS_PREAUTH_TYPE;
	tmp_flw_ptr[1] = len + 4;
	tmp_flw_ptr[2] = pre_auth_type->pre_auth_type.type;
	tmp_flw_ptr[3] = len + 2;

	memcpy(&tmp_flw_ptr[4], pre_auth_type->pre_auth_type.value, len);

	return 0;
}*/
int radius_encode_attr_nowsms_preauth_type(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_NOWSMS_PREAUTH_TYPE *pre_auth_type)
{
//	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE*)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_NOWSMS_PREAUTH_TYPE;
	tmp_flw_ptr[1] = 3;
	tmp_flw_ptr[2] = pre_auth_type->pre_auth_type.value & 0xFF;
	
	return 0;
}

static int radius_encode_attr_nowsms_msg_count(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_NOWSMS_MSG_COUNT *msg_count)
{
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_NOWSMS_SUB_MSGCOUNT;
	tmp_flw_ptr[1] = 3;
	tmp_flw_ptr[2] = msg_count->msg_count.value & 0xFF;

	return 0;
}
static int radius_encode_attr_nowsms_msg_id(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_NOWSMS_MSG_ID *msg_id)
{
	BYTE	*tmp_flw_ptr= (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_NOWSMS_SUB_MSGID;
	tmp_flw_ptr[1] = 6;
	tmp_flw_ptr[2] = (msg_id->msg_id.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (msg_id->msg_id.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (msg_id->msg_id.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (msg_id->msg_id.value) & 0xFF;

	return 0;
}
static int radius_encode_attr_nowsms_size(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_NOWSMS_SIZE *size)
{
	BYTE	*tmp_flw_ptr= (BYTE *)flw_ptr;

	tmp_flw_ptr[0] = RADIUS_ATTRIBUTE_TYPE_NOWSMS_SUB_SIZE;
	tmp_flw_ptr[1] = 6;
	tmp_flw_ptr[2] = (size->size.value >> 24) & 0xFF;
	tmp_flw_ptr[3] = (size->size.value >> 16) & 0xFF;
	tmp_flw_ptr[4] = (size->size.value >> 8) & 0xFF;
	tmp_flw_ptr[5] = (size->size.value) & 0xFF;

	return 0;
}
int radius_encode_attr_nowsms_count_id_size(const BYTE *flw_ptr, RADIUS_ATTRIBUTE_NOWSMS_COUNT_ID_SIZE *count_id_size)
{
	int		len = 0;
	BYTE	*tmp_flw_ptr = (BYTE *)flw_ptr + 2;
	BYTE	*tmp_flw_ptr1 = (BYTE *)flw_ptr;

	if(count_id_size->msg_count.flag == 1)
	{
		radius_encode_attr_nowsms_msg_count(tmp_flw_ptr, &count_id_size->msg_count);
		len += tmp_flw_ptr[1];
		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	if (count_id_size->msg_id.flag == 1)
	{
		radius_encode_attr_nowsms_msg_id(tmp_flw_ptr, &count_id_size->msg_id);
		len += tmp_flw_ptr[1];
		tmp_flw_ptr += tmp_flw_ptr[1];
	}

	if(count_id_size->size.flag == 1)
	{
		radius_encode_attr_nowsms_size(tmp_flw_ptr, &count_id_size->size);
		len += tmp_flw_ptr[1];
	}

	tmp_flw_ptr1[0] = RADIUS_ATTRIBUTE_TYPE_NOWSMS_COUNT_ID_SIZE;
	tmp_flw_ptr1[1] = len + 2;
	
	return 0;
}

int radius_encode_access_request(BYTE sap_index, BYTE *identifier, BYTE *authenticator, BYTE *msg, RADIUS_ACCESS_REQUEST *access_request, int nas_id)
{
	int				msg_len = 0;
	int				len;
	BYTE			id = radius_access_id_select;
	BYTE			*flw_ptr = msg;
	RADIUS_NAS_INFO	*nas_info_ptr;

	if ((identifier == NULL) || (authenticator == NULL) || (msg == NULL) || (access_request == NULL))
	{
		radius_log_err("%s: pointer error\r\n", __FUNCTION__);
		return -1;
	}

	if (((access_request->user_password.flag != 1) && (access_request->message_authenticator.flag != 1) \
		&& (access_request->chap_password.flag != 1) && (access_request->state.flag != 1)) 
		|| ((access_request->user_password.flag == 1) && (access_request->message_authenticator.flag == 1) \
		&& (access_request->chap_password.flag == 1)))
	{
		radius_log_err("%s: attribute error\r\n", __FUNCTION__);
		return -1;
	}
	
	if (((nas_info_ptr = radius_get_nas_info_ptr(nas_id)) == NULL) || (nas_info_ptr->flag != 1))
	{
		radius_log_err("%s: nas id=%d error\r\n", __FUNCTION__, nas_id);
		return -1;
	}

	flw_ptr[0] = RADIUS_MSG_TYPE_ACCESS_REQUEST;

	*identifier = id;

	flw_ptr[1] = id;

	flw_ptr += 4;

	radius_generate_access_request_authenticator(authenticator);

	memcpy(flw_ptr, authenticator, RADIUS_MAX_LEN_OF_AUTH);

	flw_ptr += RADIUS_MAX_LEN_OF_AUTH;

	if (access_request->user_name.flag == 1)
	{
		if (radius_encode_attr_user_name(flw_ptr, &access_request->user_name) < 0)
		{
			radius_log_err("%s: encode user name fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_request->user_password.flag == 1)
	{
		//if (radius_encode_attr_user_password(flw_ptr, radius_nas_password[sap_index], radius_nas_share_key[sap_index], authenticator) < 0)//&access_request->user_password
		if (radius_encode_attr_user_password(flw_ptr, nas_info_ptr->password, nas_info_ptr->share_key, authenticator) < 0)
		{
			radius_log_err("%s: encode user password fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

/*	if (access_request->chap_password.flag == 1)
	{
		if ((radius_encode_attr_chap_password(flw_ptr, &access_request->chap_password) < 0)
		{
			radius_log_err("%s: encode chap password fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}*/

	if (access_request->nas_ip_addr.flag == 1)
	{
		if (radius_encode_attr_nas_ip_address(flw_ptr, &access_request->nas_ip_addr) < 0)
		{
			radius_log_err("%s: encode nas ip address fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_request->nas_port.flag == 1)
	{
		if (radius_encode_attr_nas_port(flw_ptr, &access_request->nas_port) < 0)
		{
			radius_log_err("%s: encode nas port fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_request->service_type.flag == 1)
	{
		if (radius_encode_attr_service_type(flw_ptr, &access_request->service_type) < 0)
		{
			radius_log_err("%s: encode service type fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_request->framed_protocol.flag == 1)
	{
		if (radius_encode_attr_framed_protocol(flw_ptr, &access_request->framed_protocol) < 0)
		{
			radius_log_err("%s: encode framed protocol fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_request->framed_ip_addr.flag == 1)
	{
		if (radius_encode_attr_framed_ip_addr(flw_ptr, &access_request->framed_ip_addr) < 0)
		{
			radius_log_err("%s: encode framed ip addr fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_request->framed_ip_netmask.flag == 1)
	{
		if (radius_encode_attr_framed_ip_netmask(flw_ptr, &access_request->framed_ip_netmask) < 0)
		{
			radius_log_err("%s: encode framed ip netmask fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_request->framed_mtu.flag == 1)
	{
		if (radius_encode_attr_framed_mtu(flw_ptr, &access_request->framed_mtu) < 0)
		{
			radius_log_err("%s: encode framed ip mtu fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_request->framed_compression.num != 0)
	{
		if ((len = radius_encode_framed_compression(flw_ptr, &access_request->framed_compression)) < 0)
		{
			radius_log_err("%s: encode framed compression fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (access_request->login_ip_host.num != 0)
	{
		if ((len = radius_encode_login_ip_host(flw_ptr, &access_request->login_ip_host)) < 0)
		{
			radius_log_err("%s: encode login ip host fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (access_request->callback_number.flag == 1)
	{
		if (radius_encode_attr_callback_num(flw_ptr, &access_request->callback_number) < 0)
		{
			radius_log_err("%s: encode framed ip mtu fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_request->state.flag == 1)
	{
		if (radius_encode_attr_state(flw_ptr, &access_request->state) < 0)
		{
			radius_log_err("%s: encode state fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_request->vendor_specific.num != 0)
	{
		if ((len = radius_encode_vendor_specific(flw_ptr, &access_request->vendor_specific)) < 0)
		{
			radius_log_err("%s: encode vendor specific fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	//if (access_request->called_station_id.flag == 1)
	if (access_request->called_station_id.option == 1 || access_request->called_station_id.option == 2)
	{
		if ((len = radius_encode_attr_called_station_id(flw_ptr, &access_request->called_station_id)) < 0)
		{
			radius_log_err("%s: encode called station id fail\r\n", __FUNCTION__);
			return -1;
		}

		//flw_ptr += flw_ptr[1];
		flw_ptr += len;
	}

	if (access_request->calling_station_id.flag == 1)
	{
		if (radius_encode_attr_calling_station_id(flw_ptr, &access_request->calling_station_id) < 0)
		{
			radius_log_err("%s: encode calling station id fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_request->nas_identifier.flag == 1)
	{
		if (radius_encode_attr_nas_id(flw_ptr, &access_request->nas_identifier) < 0)
		{
			radius_log_err("%s: encode nas id fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_request->proxy_state.num != 0)
	{
		if ((len = radius_encode_proxy_state(flw_ptr, &access_request->proxy_state)) < 0)
		{
			radius_log_err("%s: encode proxy state fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (access_request->login_lat_service.flag == 1)
	{
		if (radius_encode_attr_login_lat_service(flw_ptr, &access_request->login_lat_service) < 0)
		{
			radius_log_err("%s: encode login lat service fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_request->login_lat_node.flag == 1)
	{
		if (radius_encode_attr_login_lat_node(flw_ptr, &access_request->login_lat_node) < 0)
		{
			radius_log_err("%s: encode login lat node fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_request->login_lat_group.flag == 1)
	{
		if (radius_encode_attr_login_lat_group(flw_ptr, &access_request->login_lat_group) < 0)
		{
			radius_log_err("%s: encode login lat group fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_request->nas_port_type.flag == 1)
	{
		if (radius_encode_attr_nas_port_type(flw_ptr, &access_request->nas_port_type) < 0)
		{
			radius_log_err("%s: encode nas port type fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_request->port_limit.flag == 1)
	{
		if (radius_encode_attr_port_limit(flw_ptr, &access_request->port_limit) < 0)
		{
			radius_log_err("%s: encode port limit fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_request->login_lat_port.flag == 1)
	{
		if (radius_encode_attr_login_lat_port(flw_ptr, &access_request->login_lat_port) < 0)
		{
			radius_log_err("%s: encode login lat port fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_request->connect_info.flag == 1)
	{
		if (radius_encode_attr_connect_info(flw_ptr, &access_request->connect_info) < 0)
		{
			radius_log_err("%s: encode connect info fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_request->nas_port_id.flag == 1)
	{
		if (radius_encode_attr_nas_port_id(flw_ptr, &access_request->nas_port_id) < 0)
		{
			radius_log_err("%s: encode nas port id fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if(access_request->pre_auth_type.flag == 1)
	{
		if(radius_encode_attr_nowsms_preauth_type(flw_ptr, &access_request->pre_auth_type) < 0)
		{
			radius_log_err("%s: encode nowsms pre auth type fail\r\n", __FUNCTION__);
			return -1;
		}
		flw_ptr += flw_ptr[1];
	}

	if(access_request->count_id_size.flag == 1)
	{
		if(radius_encode_attr_nowsms_count_id_size(flw_ptr, &access_request->count_id_size) < 0)
		{
			radius_log_err("%s: encode nowsms count id size fail\r\n", __FUNCTION__);
			return -1;
		}
		flw_ptr += flw_ptr[1];
	}

	if (access_request->message_authenticator.flag == 1)
	{
		//if (radius_encode_attr_message_authenticator(msg, flw_ptr, radius_nas_share_key[sap_index]) < 0)
		if (radius_encode_attr_message_authenticator(msg, flw_ptr, nas_info_ptr->share_key) < 0)
		{
			radius_log_err("%s: encode message authenticator fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if(access_request->acct_session_id.flag == 1)
	{
		if(radius_encode_attr_acct_session_id(flw_ptr, &access_request->acct_session_id) < 0)
		{
			radius_log_err("%s: encode acct session id fail\r\n", __FUNCTION__);
			return -1;
		}
		flw_ptr += flw_ptr[1];
	}

	msg_len = flw_ptr - msg;

	msg[2] = (msg_len >> 8) & 0xFF;
	msg[3] = (msg_len) & 0xFF;

	++radius_access_id_select;

	return msg_len;
}

int radius_encode_access_accept(BYTE identifier, BYTE *request_authenticator, BYTE *msg, RADIUS_ACCESS_ACCEPT *access_accept, int nas_id)
{
	int					len;
	int					msg_len = 0;
	BYTE 				*flw_ptr = msg;
	BYTE 				authenticator[RADIUS_MAX_LEN_OF_AUTH] = "";
	RADIUS_NAS_INFO	*nas_info_ptr;

	if ((request_authenticator == NULL) || (msg == NULL) || (access_accept == NULL))
	{
		radius_log_err("%s: pointer error\r\n", __FUNCTION__);
		return -1;
	}

	if (((nas_info_ptr = radius_get_nas_info_ptr(nas_id)) == NULL) || (nas_info_ptr->flag != 1))
	{
		radius_log_err("%s: nas id=%d error\r\n", __FUNCTION__, nas_id);
		return -1;
	}

	flw_ptr[0] = RADIUS_MSG_TYPE_ACCESS_ACCEPT;

	flw_ptr[1] = identifier;

	flw_ptr += 4;

	memcpy(flw_ptr, request_authenticator, RADIUS_MAX_LEN_OF_AUTH);

	flw_ptr += RADIUS_MAX_LEN_OF_AUTH;

	if (access_accept->user_name.flag == 1)
	{
		if (radius_encode_attr_user_name(flw_ptr, &access_accept->user_name) < 0)
		{
			radius_log_err("%s: encode user name fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->service_type.flag == 1)
	{
		if (radius_encode_attr_service_type(flw_ptr, &access_accept->service_type) < 0)
		{
			radius_log_err("%s: encode service type fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->framed_protocol.flag == 1)
	{
		if (radius_encode_attr_framed_protocol(flw_ptr, &access_accept->framed_protocol) < 0)
		{
			radius_log_err("%s: encode framed protocol fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->framed_ip_addr.flag == 1)
	{
		if (radius_encode_attr_framed_ip_addr(flw_ptr, &access_accept->framed_ip_addr) < 0)
		{
			radius_log_err("%s: encode framed ip addr fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->framed_ip_netmask.flag == 1)
	{
		if (radius_encode_attr_framed_ip_netmask(flw_ptr, &access_accept->framed_ip_netmask) < 0)
		{
			radius_log_err("%s: encode framed ip netmask fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->framed_routing.flag == 1)
	{
		if (radius_encode_attr_framed_routing(flw_ptr, &access_accept->framed_routing) < 0)
		{
			radius_log_err("%s: encode framed routing fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->filter_id.num != 0)
	{
		if ((len  = radius_encode_filter_id(flw_ptr, &access_accept->filter_id)) < 0)
		{
			radius_log_err("%s: encode filter id fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (access_accept->framed_mtu.flag == 1)
	{
		if (radius_encode_attr_framed_mtu(flw_ptr, &access_accept->framed_mtu) < 0)
		{
			radius_log_err("%s: encode framed mtu fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->framed_compression.num != 0)
	{
		if ((len  = radius_encode_framed_compression(flw_ptr, &access_accept->framed_compression)) < 0)
		{
			radius_log_err("%s: encode framed compression fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (access_accept->login_ip_host.num != 0)
	{
		if ((len  = radius_encode_login_ip_host(flw_ptr, &access_accept->login_ip_host)) < 0)
		{
			radius_log_err("%s: encode login ip host fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (access_accept->login_service.flag == 1)
	{
		if (radius_encode_attr_login_service(flw_ptr, &access_accept->login_service) < 0)
		{
			radius_log_err("%s: encode framed login service fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->login_tcp_port.flag == 1)
	{
		if (radius_encode_attr_login_tcp_port(flw_ptr, &access_accept->login_tcp_port) < 0)
		{
			radius_log_err("%s: encode framed login tcp port fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->reply_message.num != 0)
	{
		if ((len  = radius_encode_reply_message(flw_ptr, &access_accept->reply_message)) < 0)
		{
			radius_log_err("%s: encode reply message fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (access_accept->callback_number.flag == 1)
	{
		if (radius_encode_attr_callback_num(flw_ptr, &access_accept->callback_number) < 0)
		{
			radius_log_err("%s: encode callback number fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->callback_id.flag == 1)
	{
		if (radius_encode_attr_callback_id(flw_ptr, &access_accept->callback_id) < 0)
		{
			radius_log_err("%s: encode callback id fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->framed_route.num != 0)
	{
		if ((len  = radius_encode_framed_route(flw_ptr, &access_accept->framed_route)) < 0)
		{
			radius_log_err("%s: encode framed route fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (access_accept->framed_ipx_network.flag == 1)
	{
		if (radius_encode_attr_framed_ipx_network(flw_ptr, &access_accept->framed_ipx_network) < 0)
		{
			radius_log_err("%s: encode framed ipx network fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->state.flag == 1)
	{
		if (radius_encode_attr_state(flw_ptr, &access_accept->state) < 0)
		{
			radius_log_err("%s: encode state fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->radius_class.num != 0)
	{
		if ((len  = radius_encode_class(flw_ptr, &access_accept->radius_class)) < 0)
		{
			radius_log_err("%s: encode class fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (access_accept->vendor_specific.num != 0)
	{
		if ((len  = radius_encode_vendor_specific(flw_ptr, &access_accept->vendor_specific)) < 0)
		{
			radius_log_err("%s: encode vendor specific fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (access_accept->session_timeout.flag == 1)
	{
		if (radius_encode_attr_session_timeout(flw_ptr, &access_accept->session_timeout) < 0)
		{
			radius_log_err("%s: encode session timeout fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->idle_timeout.flag == 1)
	{
		if (radius_encode_attr_idle_timeout(flw_ptr, &access_accept->idle_timeout) < 0)
		{
			radius_log_err("%s: encode idle timeout fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->termination_action.flag == 1)
	{
		if (radius_encode_attr_termination_action(flw_ptr, &access_accept->termination_action) < 0)
		{
			radius_log_err("%s: encode termination action fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->proxy_state.num != 0)
	{
		if ((len  = radius_encode_proxy_state(flw_ptr, &access_accept->proxy_state)) < 0)
		{
			radius_log_err("%s: encode proxy state fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (access_accept->login_lat_service.flag == 1)
	{
		if (radius_encode_attr_login_lat_service(flw_ptr, &access_accept->login_lat_service) < 0)
		{
			radius_log_err("%s: encode login lat service fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->login_lat_node.flag == 1)
	{
		if (radius_encode_attr_login_lat_node(flw_ptr, &access_accept->login_lat_node) < 0)
		{
			radius_log_err("%s: encode login lat node fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->login_lat_group.flag == 1)
	{
		if (radius_encode_attr_login_lat_group(flw_ptr, &access_accept->login_lat_group) < 0)
		{
			radius_log_err("%s: encode login lat group fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->framed_appletalk_link.flag == 1)
	{
		if (radius_encode_attr_framed_appletalk_link(flw_ptr, &access_accept->framed_appletalk_link) < 0)
		{
			radius_log_err("%s: encode framed appletalk link fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->framed_appletalk_network.num != 0)
	{
		if ((len  = radius_encode_framed_appletalk_network(flw_ptr, &access_accept->framed_appletalk_network)) < 0)
		{
			radius_log_err("%s: encode framed appletalk network fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (access_accept->framed_appletalk_zone.flag == 1)
	{
		if (radius_encode_attr_framed_appletalk_zone(flw_ptr, &access_accept->framed_appletalk_zone) < 0)
		{
			radius_log_err("%s: encode framed appletalk zone fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->port_limit.flag == 1)
	{
		if (radius_encode_attr_port_limit(flw_ptr, &access_accept->port_limit) < 0)
		{
			radius_log_err("%s: encode port limit fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->login_lat_port.flag == 1)
	{
		if (radius_encode_attr_login_lat_port(flw_ptr, &access_accept->login_lat_port) < 0)
		{
			radius_log_err("%s: encode login lat port fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (access_accept->configuration_token.num != 0)
	{
		if ((len  = radius_encode_configuration_token(flw_ptr, &access_accept->configuration_token)) < 0)
		{
			radius_log_err("%s: encode configuration token fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (access_accept->acct_interim_interval.flag == 1)
	{
		if (radius_encode_attr_acct_interim_interval(flw_ptr, &access_accept->acct_interim_interval) < 0)
		{
			radius_log_err("%s: encode acct interim interval fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

//	if (access_accept->message_authenticator.flag == 1)
	{
		radius_encode_attr_message_authenticator(msg, flw_ptr, nas_info_ptr->share_key);

		flw_ptr += flw_ptr[1];
	}

	msg_len = flw_ptr - msg;

	msg[2] = (msg_len >> 8) & 0xFF;
	msg[3] = (msg_len) & 0xFF;

	radius_calculate_authenticator(authenticator, msg, msg_len, nas_info_ptr->share_key);

	memcpy(&msg[4], authenticator, RADIUS_MAX_LEN_OF_AUTH);

	return msg_len;
}

int radius_encode_access_reject(BYTE identifier, BYTE *request_authenticator, BYTE *msg, RADIUS_ACCESS_REJECT *access_reject, int nas_id)
{
	int		len;
	int		msg_len = 0;
	BYTE 	*flw_ptr = msg;
	BYTE 	authenticator[RADIUS_MAX_LEN_OF_AUTH] = "";
	RADIUS_NAS_INFO	*nas_info_ptr;

	if ((request_authenticator == NULL) || (msg == NULL) || (access_reject == NULL))
	{
		radius_log_err("%s: pointer error\r\n", __FUNCTION__);
		return -1;
	}

	if (((nas_info_ptr = radius_get_nas_info_ptr(nas_id)) == NULL) || (nas_info_ptr->flag != 1))
	{
		radius_log_err("%s: nas id=%d error\r\n", __FUNCTION__, nas_id);
		return -1;
	}

	flw_ptr[0] = RADIUS_MSG_TYPE_ACCESS_REJECT;

	flw_ptr[1] = identifier;

	flw_ptr += 4;

	memcpy(flw_ptr, request_authenticator, RADIUS_MAX_LEN_OF_AUTH);

	flw_ptr += RADIUS_MAX_LEN_OF_AUTH;

	if (access_reject->reply_message.num != 0)
	{
		if ((len = radius_encode_reply_message(flw_ptr, &access_reject->reply_message)) < 0)
		{
			radius_log_err("%s: encode reply message fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (access_reject->proxy_state.num != 0)
	{
		if ((len = radius_encode_proxy_state(flw_ptr, &access_reject->proxy_state)) < 0)
		{
			radius_log_err("%s: encode proxy state fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (access_reject->password_retry.flag == 1)
	{
		if (radius_encode_attr_password_retry(flw_ptr, &access_reject->password_retry) < 0)
		{
			radius_log_err("%s: encode password retry fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

//	if (access_reject->message_authenticator.flag == 1)
	{
		radius_encode_attr_message_authenticator(msg, flw_ptr, nas_info_ptr->share_key);

		flw_ptr += flw_ptr[1];
	}

	msg_len = flw_ptr - msg;

	msg[2] = (msg_len >> 8) & 0xFF;
	msg[3] = (msg_len) & 0xFF;

	radius_calculate_authenticator(authenticator, msg, msg_len, nas_info_ptr->share_key);

	memcpy(&msg[4], authenticator, RADIUS_MAX_LEN_OF_AUTH);

	return msg_len;
}

/*int radius_encode_accounting_request(BYTE *identifier, BYTE *authenticator, BYTE *msg, RADIUS_ACCOUNTING_REQUEST *accounting_request)
{
	int		len;
	int		msg_len = 0;
	BYTE 	*flw_ptr = msg;
	BYTE 	authenticator[RADIUS_MAX_LEN_OF_AUTH] = "";
	BYTE	id = radius_accounting_id_select;

	if ((identifier == NULL) || (authenticator == NULL) || (msg == NULL) || (accounting_request == NULL))
	{
		radius_log_err("%s: pointer error\r\n", __FUNCTION__);
		return -1;
	}

	flw_ptr[0] = RADIUS_MSG_TYPE_ACCOUNTING_REQUEST;

	*identifier = id;

	flw_ptr[1] = id;

	flw_ptr += 4;

	for (i = 0; i < RADIUS_MAX_LEN_OF_AUTH; i++)
	{
		flw_ptr[4 + i] = 0x00;
	}
	

	flw_ptr += RADIUS_MAX_LEN_OF_AUTH;

	if (accounting_request->user_name.flag == 1)
	{
		if (radius_encode_attr_user_name(flw_ptr, &accounting_request->user_name) < 0)
		{
			radius_log_err("%s: encode user name fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (accounting_request->nas_ip_addr.flag == 1)
	{
		if (radius_encode_attr_nas_ip_address(flw_ptr, &accounting_request->nas_ip_addr) < 0)
		{
			radius_log_err("%s: encode nas ip addr fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (accounting_request->nas_port.flag == 1)
	{
		if (radius_encode_attr_nas_port(flw_ptr, &accounting_request->nas_port) < 0)
		{
			radius_log_err("%s: encode nas port fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (accounting_request->service_type.flag == 1)
	{
		if (radius_encode_attr_service_type(flw_ptr, &accounting_request->service_type)< 0)
		{
			radius_log_err("%s: encode service type fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (accounting_request->framed_protocol.flag == 1)
	{
		if (radius_encode_attr_framed_protocol(flw_ptr, &accounting_request->framed_protocol)< 0)
		{
			radius_log_err("%s: encode framed protocol fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (accounting_request->framed_ip_addr.flag == 1)
	{
		if (radius_encode_attr_framed_ip_addr(flw_ptr, &accounting_request->framed_ip_addr)< 0)
		{
			radius_log_err("%s: encode framed ip addr fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (accounting_request->framed_ip_netmask.flag == 1)
	{
		if (radius_encode_attr_framed_ip_netmask(flw_ptr, &accounting_request->framed_ip_netmask)< 0)
		{
			radius_log_err("%s: encode framed ip netmask fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (accounting_request->framed_routing.flag == 1)
	{
		if (radius_encode_attr_framed_routing(flw_ptr, &accounting_request->framed_routing)< 0)
		{
			radius_log_err("%s: encode framed routing fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (accounting_request->filter_id.num != 0)
	{
		if ((len = radius_encode_filter_id(flw_ptr, &accounting_request->filter_id)) < 0)
		{
			radius_log_err("%s: encode filter id fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (accounting_request->vendor_specific.num != 0)
	{
		if ((len = radius_encode_vendor_specific(flw_ptr, &accounting_request->vendor_specific)) < 0)
		{
			radius_log_err("%s: encode vendor specific fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (accounting_request->proxy_state.num != 0)
	{
		if ((len = radius_encode_proxy_state(flw_ptr, &accounting_request->proxy_state)) < 0)
		{
			radius_log_err("%s: encode proxy state fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	msg_len = flw_ptr - msg;

	msg[2] = (msg_len >> 8) & 0xFF;
	msg[3] = (msg_len) & 0xFF;

	radius_calculate_authenticator(authenticator, msg, msg_len);

	memcpy(&msg[4], authenticator, RADIUS_MAX_LEN_OF_AUTH);

	++radius_accounting_id_select;

	return msg_len;
}*/

int radius_encode_accounting_response(BYTE identifier, BYTE *request_authenticator, BYTE *msg, RADIUS_ACCOUNTING_RESPONSE *accounting_response, int nas_id)
{
	int		len;
	int		msg_len = 0;
	BYTE 	*flw_ptr = msg;
	BYTE 	authenticator[RADIUS_MAX_LEN_OF_AUTH] = "";
	RADIUS_NAS_INFO	*nas_info_ptr;

	if ((request_authenticator == NULL) || (msg == NULL) || (accounting_response == NULL))
	{
		radius_log_err("%s: pointer error\r\n", __FUNCTION__);
		return -1;
	}

	if (((nas_info_ptr = radius_get_nas_info_ptr(nas_id)) == NULL) || (nas_info_ptr->flag != 1))
	{
		radius_log_err("%s: nas id=%d error\r\n", __FUNCTION__, nas_id);
		return -1;
	}

	flw_ptr[0] = RADIUS_MSG_TYPE_ACCOUNTING_RESPONSE;

	flw_ptr[1] = identifier;

	flw_ptr += 4;

	memcpy(flw_ptr, request_authenticator, RADIUS_MAX_LEN_OF_AUTH);

	flw_ptr += RADIUS_MAX_LEN_OF_AUTH;

	if (accounting_response->vendor_specific.num != 0)
	{
		if ((len = radius_encode_vendor_specific(flw_ptr, &accounting_response->vendor_specific)) < 0)
		{
			radius_log_err("%s: encode vendor specific fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (accounting_response->proxy_state.num != 0)
	{
		if ((len = radius_encode_proxy_state(flw_ptr, &accounting_response->proxy_state)) < 0)
		{
			radius_log_err("%s: encode proxy state fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	msg_len = flw_ptr - msg;

	msg[2] = (msg_len >> 8) & 0xFF;
	msg[3] = (msg_len) & 0xFF;

	radius_calculate_authenticator(authenticator, msg, msg_len, nas_info_ptr->share_key);

	memcpy(&msg[4], authenticator, RADIUS_MAX_LEN_OF_AUTH);

	return msg_len;
}

int radius_encode_disconnect_request(BYTE *identifier, BYTE *authenticator, BYTE *msg, RADIUS_DISCONNECT_REQUEST *disconnect_request, int nas_id)
{
	int				msg_len = 0;
	int				len;
	BYTE			id = radius_disconnect_id_select;
	BYTE			*flw_ptr = msg;
	RADIUS_NAS_INFO	*nas_info_ptr;

	if ((identifier == NULL) || (authenticator == NULL) || (msg == NULL) || (disconnect_request == NULL))
	{
		radius_log_err("%s: pointer error\r\n", __FUNCTION__);
		return -1;
	}

	if (((nas_info_ptr = radius_get_nas_info_ptr(nas_id)) == NULL) || (nas_info_ptr->flag != 1))
	{
		radius_log_err("%s: nas id=%d error\r\n", __FUNCTION__, nas_id);
		return -1;
	}

	flw_ptr[0] = RADIUS_MSG_TYPE_DISCONNECT_REQUEST;

	*identifier = id;

	flw_ptr[1] = id;

	flw_ptr += 4;

//	radius_generate_access_request_authenticator(authenticator);

	memset(flw_ptr, 0, RADIUS_MAX_LEN_OF_AUTH);

	flw_ptr += RADIUS_MAX_LEN_OF_AUTH;

	if (disconnect_request->user_name.flag == 1)
	{
		if (radius_encode_attr_user_name(flw_ptr, &disconnect_request->user_name) < 0)
		{
			radius_log_err("%s: encode user name fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (disconnect_request->nas_ip_addr.flag == 1)
	{
		if (radius_encode_attr_nas_ip_address(flw_ptr, &disconnect_request->nas_ip_addr) < 0)
		{
			radius_log_err("%s: encode nas ip address fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (disconnect_request->nas_port.flag == 1)
	{
		if (radius_encode_attr_nas_port(flw_ptr, &disconnect_request->nas_port) < 0)
		{
			radius_log_err("%s: encode nas port fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (disconnect_request->service_type.flag == 1)
	{
		disconnect_request->service_type.service_type.value = RADIUS_SERVICE_TYPE_AUTHORIZE_ONLY;

		if (radius_encode_attr_service_type(flw_ptr, &disconnect_request->service_type) < 0)
		{
			radius_log_err("%s: encode service type fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (disconnect_request->framed_ip_addr.flag == 1)
	{
		if (radius_encode_attr_framed_ip_addr(flw_ptr, &disconnect_request->framed_ip_addr) < 0)
		{
			radius_log_err("%s: encode framed ip addr fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (disconnect_request->reply_message.num != 0)
	{
		if ((len = radius_encode_reply_message(flw_ptr, &disconnect_request->reply_message)) < 0)
		{
			radius_log_err("%s: encode reply message fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (disconnect_request->state.flag == 1)
	{
		if (radius_encode_attr_state(flw_ptr, &disconnect_request->state) < 0)
		{
			radius_log_err("%s: encode state fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (disconnect_request->radius_class.num != 0)
	{
		if ((len = radius_encode_class(flw_ptr, &disconnect_request->radius_class)) < 0)
		{
			radius_log_err("%s: encode class fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (disconnect_request->vendor_specific.num != 0)
	{
		if ((len  = radius_encode_vendor_specific(flw_ptr, &disconnect_request->vendor_specific)) < 0)
		{
			radius_log_err("%s: encode vendor specific fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

//	if (disconnect_request->called_station_id.flag == 1)
	if (disconnect_request->called_station_id.option == 1 || disconnect_request->called_station_id.option == 2)
	{
		if ((len = radius_encode_attr_called_station_id(flw_ptr, &disconnect_request->called_station_id)) < 0)
		{
			radius_log_err("%s: encode called station id fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += len;
	}

	if (disconnect_request->calling_station_id.flag == 1)
	{
		if (radius_encode_attr_calling_station_id(flw_ptr, &disconnect_request->calling_station_id) < 0)
		{
			radius_log_err("%s: encode calling station id fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (disconnect_request->nas_identifier.flag == 1)
	{
		if (radius_encode_attr_nas_id(flw_ptr, &disconnect_request->nas_identifier) < 0)
		{
			radius_log_err("%s: encode nas id fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if (disconnect_request->message_authenticator.flag == 1)
	{
		if (radius_encode_attr_message_authenticator(msg, flw_ptr, nas_info_ptr->share_key) < 0)
		{
			radius_log_err("%s: encode message authenticator fail\r\n", __FUNCTION__);
			return -1;
		}

		flw_ptr += flw_ptr[1];
	}

	if(disconnect_request->acct_session_id.flag == 1)
	{
		if(radius_encode_attr_acct_session_id(flw_ptr, &disconnect_request->acct_session_id) < 0)
		{
			radius_log_err("%s: encode acct session id fail\r\n", __FUNCTION__);
			return -1;
		}
		flw_ptr += flw_ptr[1];
	}

	msg_len = flw_ptr - msg;

	msg[2] = (msg_len >> 8) & 0xFF;
	msg[3] = (msg_len) & 0xFF;

	radius_calculate_authenticator(authenticator, msg, msg_len, nas_info_ptr->share_key);

	memcpy(&msg[4], authenticator, RADIUS_MAX_LEN_OF_AUTH);
	
	++radius_disconnect_id_select;

	return msg_len;
}


int radius_send_msg(int pid)
{
	radius_send_udp_msg(pid);

	return 0;
}


int radius_authenticate_nas(BYTE *authenticator, RADIUS_NAS_INFO *nas_info_ptr, RADIUS_ACCESS_REQUEST * access_request, BYTE *msg, int msg_len, int msg_auth_attr_offset)
{
	struct in_addr	ip_addr;
	BYTE			encrypt_password[RADIUS_MAX_LEN_OF_ENCRYPT_PASSWORD] = "";
	BYTE			tmp_buf[RADIUS_MAX_LEN_OF_MSG] = "";
	BYTE			message_authenticator[RADIUS_MAX_LEN_OF_AUTH] = "";

	if (access_request->service_type.service_type.value == RADIUS_SERVICE_TYPE_AUTHENTICATE_ONLY)
	{
		if (access_request->user_password.flag != 1)
		{
			return -1;
		}

		radius_encrypt_user_password(encrypt_password, nas_info_ptr->password, authenticator, nas_info_ptr->share_key);

		if (memcmp(access_request->user_password.user_password.value, encrypt_password, access_request->user_password.user_password.length) != 0)
		{
			ip_addr.s_addr = nas_info_ptr->nas_ip;
			radius_log_err("%s: user password error, nas ip=%s\r\n", __FUNCTION__, inet_ntoa(ip_addr));
			return -1;
		}
	}
	else if (access_request->service_type.service_type.value == RADIUS_SERVICE_TYPE_AUTHORIZE_ONLY)
	{
		if (access_request->message_authenticator.flag != 1)
			return -1;

		memcpy(tmp_buf, msg, msg_len);

		memset(tmp_buf + msg_auth_attr_offset + 2, 0, RADIUS_MAX_LEN_OF_MESSAGE_AUTH_ATTR);

		radius_get_hmac_md5_hex(message_authenticator, tmp_buf, msg_len, nas_info_ptr->share_key, strlen((char*)nas_info_ptr->share_key));

		if (memcmp(access_request->message_authenticator.message_authenticator.value, message_authenticator, RADIUS_MAX_LEN_OF_MESSAGE_AUTH_ATTR) != 0)
		{
			ip_addr.s_addr = nas_info_ptr->nas_ip;
			radius_log_err("%s: message authenticator error, nas ip=%s\r\n", __FUNCTION__, inet_ntoa(ip_addr));
			return -1;
		}
	}

	return 0;
}

