inline int cdp_avp_get_Enumerated(AAA_AVP *avp,int32_t *data) { int32_t x=0; if (!avp || avp->data.len<4) { LOG(L_ERR,"Error decoding Enumerated from data len < 4 bytes!\n"); return 0; } x = get_4bytes(avp->data.s); if (data) *data = x; return 1; }
/** * Returns the SIP-Number-Auth-Items AVP from a Diameter message. * @param msg - the Diameter message * @returns the number or 0 on error */ inline int cxdx_get_sip_number_auth_items(AAAMessage *msg, int *data) { str s; s = cxdx_get_avp(msg, AVP_IMS_SIP_Number_Auth_Items, IMS_vendor_id_3GPP, __FUNCTION__); if (!s.s) return 0; *data = get_4bytes(s.s); return 1; }
/** * Returns the Result-Code AVP from a Diameter message. * @param msg - the Diameter message * @returns the AVP payload on success or an empty string on error */ inline int cxdx_get_result_code(AAAMessage *msg, int *data) { str s; s = cxdx_get_avp(msg, AVP_Result_Code, 0, __FUNCTION__); if (!s.s) return 0; *data = get_4bytes(s.s); return 1; }
/** * Returns the Accounting-Record-Type AVP of a Diameter message. * @param msg - the Diameter message * @returns AVP payload on success or an empty string on error */ inline int Rf_get_accounting_record_type(AAAMessage *msg, int *data) { str s; s = Rf_get_avp(msg, AVP_Accounting_Record_Type, 0, __FUNCTION__); if (!s.s) return 0; *data = get_4bytes(s.s); return 1; }
/** * Returns the Server-Assignment-Type AVP from a Diameter message. * @param msg - the Diameter message * @returns the AVP payload on success or an empty string on error */ inline int Cx_get_server_assignment_type(AAAMessage *msg, int *data) { str s; s = Cx_get_avp(msg, AVP_IMS_Server_Assignment_Type, IMS_vendor_id_3GPP, __FUNCTION__); if (!s.s) return 0; *data = get_4bytes(s.s); return 1; }
/** * Returns the User-Data-Available AVP from a Diameter message. * @param msg - the Diameter message * @returns the AVP payload on success or an empty string on error */ inline int Cx_get_userdata_available(AAAMessage *msg, int *data) { str s; s = Cx_get_avp(msg, AVP_IMS_User_Data_Already_Available, IMS_vendor_id_3GPP, __FUNCTION__); if (!s.s) return 0; *data = get_4bytes(s.s); return 1; }
/** * Returns the Authorization-Type AVP from a Diameter message. * @param msg - the Diameter message * @returns the AVP payload on success or an empty string on error */ inline int Cx_get_authorization_type(AAAMessage *msg, int *data) { str s; s = Cx_get_avp(msg, AVP_IMS_User_Authorization_Type, IMS_vendor_id_3GPP, __FUNCTION__); if (!s.s) return 0; *data = get_4bytes(s.s); return 1; }
int get_auth_session_state(AAAMessage* msg) { if (!msg) goto error; AAA_AVP* rc = AAAFindMatchingAVP(msg, 0, AVP_Auth_Session_State, 0, 0); if (!rc) goto error; return get_4bytes(rc->data.s); error: LOG(L_DBG, "ERR:get_auth_session_state(): no AAAMessage or Auth Session State not found\n"); return STATE_MAINTAINED; }
int get_result_code(AAAMessage* msg) { if (!msg) goto error; AAA_AVP* rc = AAAFindMatchingAVP(msg, 0, AVP_Result_Code, 0, 0); if (!rc) goto error; return get_4bytes(rc->data.s); error: LOG(L_INFO, "INF: no AAAMessage or Result Code not found\n"); return 0; }
inline int cdp_avp_get_Integer32(AAA_AVP *avp,int32_t *data) { int32_t x=0; if (avp->data.len<4) { LOG(L_ERR,"Error decoding Integer32 from data len < 4 bytes!\n"); return 0; } x = get_4bytes(avp->data.s); if (data) *data = x; return 1; }
/** * Retrieve the Session-Timeout, Auth-Lifetime and Auth-Grace-Period AVPs and update the session timers accordingly * @param x * @param msg */ void update_auth_session_timers(cdp_auth_session_t *x,AAAMessage *msg) { AAA_AVP *avp; uint32_t session_timeout=0,grace_period=0,auth_lifetime=0; avp = AAAFindMatchingAVP(msg,0,AVP_Auth_Grace_Period,0,0); if (avp &&avp->data.len==4){ grace_period = get_4bytes(avp->data.s); x->grace_period = grace_period; } avp = AAAFindMatchingAVP(msg,0,AVP_Authorization_Lifetime,0,0); if (avp &&avp->data.len==4) { auth_lifetime = get_4bytes(avp->data.s); switch(auth_lifetime){ case 0: x->lifetime = time(0); break; case 0xFFFFFFFF: x->lifetime = -1; break; default: x->lifetime = time(0)+auth_lifetime; } if (x->timeout!=-1 && x->timeout<x->lifetime) x->timeout = x->lifetime+x->grace_period; } avp = AAAFindMatchingAVP(msg,0,AVP_Session_Timeout,0,0); if (avp &&avp->data.len==4) { session_timeout = get_4bytes(avp->data.s); switch(session_timeout){ case 0: x->timeout = time(0)+config->default_auth_session_timeout; break; case 0xFFFFFFFF: x->timeout = -1; break; default: x->timeout = time(0)+session_timeout; } if (!x->lifetime) x->lifetime = x->timeout; } }
/** * Returns the AVP_Credit_perMbyte AVP from a Diameter message. * @param msg - the Diameter message * @returns 1 on success or 0 on error */ inline int Rf_get_Credit_perMbyte(AAAMessage *msg, int *data) { AAA_AVP *avp; avp = Rf_get_avp(msg,AVP_Credit_perMbyte,0); if (!avp) { LOG(L_ERR,"ERR:Rf_get_Credit_perMbyte: AVP_Credit_perMbyte not found\n"); return 0; } *data = get_4bytes(avp->data.s); return 1; }
/** * Returns the AVP_Accounting_Record_Number AVP from a Diameter message. * @param msg - the Diameter message * @returns 1 on success or 0 on error */ inline int Rf_get_accounting_record_type(AAAMessage *msg, int *data) { AAA_AVP *avp; avp = Rf_get_avp(msg,AVP_Accounting_Record_Type,0); if (!avp) { LOG(L_ERR,"ERR:Rf_get_accounting_record_type: AVP_Accounting_Record_Type not found\n"); return 0; } *data = get_4bytes(avp->data.s); return 1; }
/** * Returns the AVP_Credit_onceoff AVP from a Diameter message. * @param msg - the Diameter message * @returns 1 on success or 0 on error */ inline int Rf_get_Credit_onceoff(AAAMessage *msg, int *data) { AAA_AVP *avp; //str s; avp = Rf_get_avp(msg,AVP_Credit_onceoff,0); if (!avp) { LOG(L_ERR,"ERR:Rf_get_Credit_onceoff: AVP_Credit_onceoff not found\n"); return 0; } *data = get_4bytes(avp->data.s); return 1; }
void save_peer_applications(peer *p,AAAMessage *msg) { int total_cnt=0; AAA_AVP *avp,*avp_vendor,*avp2; AAA_AVP_LIST group; int id,vendor; if (p->applications) { shm_free(p->applications); p->applications = 0; p->applications_cnt = 0; } for(avp=msg->avpList.head;avp;avp = avp->next) switch (avp->code){ case AVP_Auth_Application_Id: case AVP_Acct_Application_Id: case AVP_Vendor_Specific_Application_Id: total_cnt+=2;/* wasteful, but let's skip decoding */ break; } p->applications_cnt = 0; p->applications = shm_malloc(sizeof(app_config)*total_cnt); if (!p->applications){ LM_ERR("save_peer_applications(): Error allocating %ld bytes! No applications saved...\n", (long int)(sizeof(app_config)*total_cnt)); return; } for(avp=msg->avpList.head;avp;avp = avp->next) { switch (avp->code){ case AVP_Auth_Application_Id: id = get_4bytes(avp->data.s); add_peer_application(p,id,0,DP_AUTHORIZATION); break; case AVP_Acct_Application_Id: id = get_4bytes(avp->data.s); add_peer_application(p,id,0,DP_ACCOUNTING); break; case AVP_Vendor_Specific_Application_Id: group = AAAUngroupAVPS(avp->data); avp_vendor = AAAFindMatchingAVPList(group,group.head,AVP_Vendor_Id,0,0); avp2 = AAAFindMatchingAVPList(group,group.head,AVP_Auth_Application_Id,0,0); if (avp_vendor&&avp2){ vendor = get_4bytes(avp_vendor->data.s); id = get_4bytes(avp2->data.s); add_peer_application(p,id,vendor,DP_AUTHORIZATION); } avp2 = AAAFindMatchingAVPList(group,group.head,AVP_Acct_Application_Id,0,0); if (avp_vendor&&avp2){ vendor = get_4bytes(avp_vendor->data.s); id = get_4bytes(avp2->data.s); add_peer_application(p,id,vendor,DP_ACCOUNTING); } AAAFreeAVPList(&group); break; } } }
int getUnits(AAAMessage *msg, int * used, int * service, int * group) { AAA_AVP *avp, *req_units, *value, *used_units, *service_avp, *rating_group; int units = 0; *used = 0; *service = 0; avp = cdpb.AAAFindMatchingAVP(msg,0,AVP_Multiple_Services_Credit_Control,0,0); if (avp) { AAA_AVP_LIST list, list2; list = cdp_avp->cdp->AAAUngroupAVPS(avp->data); req_units = cdpb.AAAFindMatchingAVPList(list, list.head, AVP_Requested_Service_Unit, 0, 0); if (req_units) { list2 = cdp_avp->cdp->AAAUngroupAVPS(req_units->data); value = cdpb.AAAFindMatchingAVPList(list2, list2.head, AVP_CC_Time, 0, 0); cdpb.AAAFreeAVPList(&list2); if (value) units = get_4bytes(value->data.s); cdpb.AAAFreeAVPList(&list2); } service_avp = cdpb.AAAFindMatchingAVPList(list, list.head, AVP_Service_Identifier, 0, 0); if (service_avp) { *service = get_4bytes(service_avp->data.s); } used_units = cdpb.AAAFindMatchingAVPList(list, list.head, AVP_Used_Service_Unit, 0, 0); if (used_units) { list2 = cdp_avp->cdp->AAAUngroupAVPS(used_units->data); value = cdpb.AAAFindMatchingAVPList(list2, list2.head, AVP_CC_Time, 0, 0); if (value) *used = get_4bytes(value->data.s); cdpb.AAAFreeAVPList(&list2); } rating_group = cdpb.AAAFindMatchingAVPList(list, list.head, AVP_Rating_Group, 0, 0); if (rating_group) { *group = get_4bytes(rating_group->data.s); } cdpb.AAAFreeAVPList(&list); } if (*service == 0) LM_WARN("Failed to get service-identifier\n"); return units; }
/** * Returns the AVP_Call_Record_Id AVP from a Diameter message. * @param msg - the Diameter message * @returns 1 on success or 0 on error */ inline int Rf_get_call_record_id(AAAMessage *msg, int *data) { AAA_AVP *avp; avp = Rf_get_avp(msg,AVP_Call_Record_Id,0); if (!avp) { LOG(L_ERR,"ERR:Rf_get_call_record_id: AVP_Call_Record_Id not found\n"); return 0; } *data = get_4bytes(avp->data.s); return 1; }
/** * Process a Capabilities Exchange Request. * Checks whether there are common applications. * \note Must be called with a lock on the peer. * @param p - peer identification * @param cer - the CER message * @returns the Result-Code of the operation, AAA_SUCCESS or AAA_NO_COMMON_APPLICATION */ int Process_CER(peer *p,AAAMessage *cer) { int common_app=0; AAA_AVP *avp,*avp_vendor,*avp2; AAA_AVP_LIST group; int i,id,vendor; for(avp=cer->avpList.head;avp;avp = avp->next) { switch (avp->code){ case AVP_Auth_Application_Id: id = get_4bytes(avp->data.s); for(i=0;i<config->applications_cnt;i++) if (id == config->applications[i].id && config->applications[i].vendor==0 && config->applications[i].type==DP_AUTHORIZATION) common_app++; break; case AVP_Acct_Application_Id: id = get_4bytes(avp->data.s); for(i=0;i<config->applications_cnt;i++) if (id == config->applications[i].id && config->applications[i].vendor==0 && config->applications[i].type==DP_ACCOUNTING) common_app++; break; case AVP_Vendor_Specific_Application_Id: group = AAAUngroupAVPS(avp->data); avp_vendor = AAAFindMatchingAVPList(group,group.head,AVP_Vendor_Id,0,0); avp2 = AAAFindMatchingAVPList(group,group.head,AVP_Auth_Application_Id,0,0); if (avp_vendor&&avp2){ vendor = get_4bytes(avp_vendor->data.s); id = get_4bytes(avp2->data.s); for(i=0;i<config->applications_cnt;i++) if (id == config->applications[i].id && config->applications[i].vendor==vendor && config->applications[i].type==DP_AUTHORIZATION) common_app++; } avp2 = AAAFindMatchingAVPList(group,group.head,AVP_Acct_Application_Id,0,0); if (avp_vendor&&avp2){ vendor = get_4bytes(avp_vendor->data.s); id = get_4bytes(avp2->data.s); for(i=0;i<config->applications_cnt;i++) if (id == config->applications[i].id && config->applications[i].vendor==vendor && config->applications[i].type==DP_ACCOUNTING) common_app++; } AAAFreeAVPList(&group); break; } } if (common_app!=0){ save_peer_applications(p,cer); return AAA_SUCCESS; }else return AAA_NO_COMMON_APPLICATION; }
int get_result_code(AAAMessage* msg) { AAA_AVP *avp; AAA_AVP_LIST list; list.head=0; list.tail=0; int rc=-1; if (!msg) goto error; for (avp=msg->avpList.tail;avp;avp=avp->prev) { if (avp->code==AVP_Result_Code) { rc = get_4bytes(avp->data.s); goto finish; } else if (avp->code==AVP_Experimental_Result) { list=AAAUngroupAVPS(avp->data); for(avp=list.head;avp;avp=avp->next) { if (avp->code==AVP_IMS_Experimental_Result_Code) { rc = get_4bytes(avp->data.s); AAAFreeAVPList(&list); goto finish; } } AAAFreeAVPList(&list); } } finish: return rc; error: LOG(L_ERR, "ERR:get_result_code(): no AAAMessage or Result Code not found\n"); return -1; }
int rl_list_node_deserialize_long(rlite *db, void **obj, void *context, unsigned char *data) { rl_list *list = context; rl_list_node *node = NULL; long i = 0, pos = 12; int retval; RL_CALL(rl_list_node_create, RL_OK, db, list, &node); node->size = (long)get_4bytes(data); node->left = (long)get_4bytes(&data[4]); node->right = (long)get_4bytes(&data[8]); for (i = 0; i < node->size; i++) { RL_MALLOC(node->elements[i], sizeof(long)) *(long *)node->elements[i] = get_4bytes(&data[pos]); pos += 4; } *obj = node; retval = RL_OK; cleanup: if (retval != RL_OK && node) { node->size = i; rl_list_node_destroy(db, node); } return retval; }
/** * Returns the Capabilities from the grouped AVP from a Diameter message. * @param msg - the Diameter message * @param m - array to be filled with the retrieved mandatory capabilities * @param m_cnt - size of the array above to be filled * @param o - array to be filled with the retrieved optional capabilities * @param o_cnt - size of the array above to be filled * @returns 1 on success 0 on fail */ inline int Cx_get_capabilities(AAAMessage *msg,int **m,int *m_cnt,int **o,int *o_cnt) { AAA_AVP_LIST list; AAA_AVP *avp; str grp; grp = Cx_get_avp(msg, AVP_IMS_Server_Capabilities, IMS_vendor_id_3GPP, __FUNCTION__); if (!grp.s) return 0; list = cdpb.AAAUngroupAVPS(grp); avp = list.head; *m_cnt=0; *o_cnt=0; while(avp){ if (avp->code == AVP_IMS_Mandatory_Capability) (*m_cnt)++; if (avp->code == AVP_IMS_Optional_Capability) (*o_cnt)++; avp = avp->next; } avp = list.head; *m=shm_malloc(sizeof(int)*(*m_cnt)); *o=shm_malloc(sizeof(int)*(*o_cnt)); *m_cnt=0; *o_cnt=0; while(avp){ if (avp->code == AVP_IMS_Mandatory_Capability) (*m)[(*m_cnt)++]=get_4bytes(avp->data.s); if (avp->code == AVP_IMS_Optional_Capability) (*o)[(*o_cnt)++]=get_4bytes(avp->data.s); avp = avp->next; } cdpb.AAAFreeAVPList(&list); return 1; }
str getSubscriptionId1(AAAMessage *msg, int * type) { AAA_AVP *avp, *avp_type, *avp_value; str r={0,0}; avp = cdpb.AAAFindMatchingAVP(msg,0,AVP_Subscription_Id,0,0); AAA_AVP_LIST list; list = cdp_avp->cdp->AAAUngroupAVPS(avp->data); avp_type = cdpb.AAAFindMatchingAVPList(list, list.head, AVP_Subscription_Id_Type, 0, 0); avp_value = cdpb.AAAFindMatchingAVPList(list, list.head, AVP_Subscription_Id_Data, 0, 0); if (avp_type) { *type = get_4bytes(avp_type->data.s); } else { LM_DBG("Failed finding type\n"); *type = 0; } if (avp_value==0) { LM_DBG("Failed finding value\n"); } else { r = avp_value->data; } cdpb.AAAFreeAVPList(&list); return r; }
/** * Returns the Experimental-Result-Code AVP from a Diameter message. * @param msg - the Diameter message * @returns the AVP payload on success or an empty string on error */ inline int cxdx_get_experimental_result_code(AAAMessage *msg, int *data) { AAA_AVP_LIST list; AAA_AVP *avp; str grp; grp = cxdx_get_avp(msg, AVP_IMS_Experimental_Result, 0, __FUNCTION__); if (!grp.s) return 0; list = cdpb.AAAUngroupAVPS(grp); avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_Experimental_Result_Code,0,0); if (!avp||!avp->data.s) { cdpb.AAAFreeAVPList(&list); return 0; } *data = get_4bytes(avp->data.s); cdpb.AAAFreeAVPList(&list); return 1; }
/** * Get the first connect peer that matches the routing mechanisms. * - First the Destination-Host AVP value is tried if connected (the peer does not have to * be in the routing table at all). * - Then we look for a connected peer in the specific realm for the Destination-Realm AVP * - Then we look for the first connected peer in the default routes * @param m - the Diameter message to find the destination peer for * @returns - the connected peer or null if none connected found */ peer* get_routing_peer(cdp_session_t* cdp_session, AAAMessage *m) { str destination_realm = {0, 0}, destination_host = {0, 0}; AAA_AVP *avp, *avp_vendor, *avp2; AAA_AVP_LIST group; peer *p; routing_realm *rr; int app_id = 0, vendor_id = 0; LM_DBG("getting diameter routing peer for realm: [%.*s]\n", m->dest_realm->data.len, m->dest_realm->data.s); app_id = m->applicationId; avp = AAAFindMatchingAVP(m, 0, AVP_Vendor_Specific_Application_Id, 0, AAA_FORWARD_SEARCH); if (avp) { group = AAAUngroupAVPS(avp->data); avp_vendor = AAAFindMatchingAVPList(group, group.head, AVP_Vendor_Id, 0, 0); avp2 = AAAFindMatchingAVPList(group, group.head, AVP_Auth_Application_Id, 0, 0); if (avp_vendor && avp2) { vendor_id = get_4bytes(avp_vendor->data.s); app_id = get_4bytes(avp2->data.s); } avp2 = AAAFindMatchingAVPList(group, group.head, AVP_Acct_Application_Id, 0, 0); if (avp_vendor && avp2) { vendor_id = get_4bytes(avp_vendor->data.s); app_id = get_4bytes(avp2->data.s); } AAAFreeAVPList(&group); } avp_vendor = AAAFindMatchingAVP(m, 0, AVP_Vendor_Id, 0, AAA_FORWARD_SEARCH); avp = AAAFindMatchingAVP(m, 0, AVP_Auth_Application_Id, 0, AAA_FORWARD_SEARCH); if (avp && avp_vendor) { vendor_id = get_4bytes(avp_vendor->data.s); app_id = get_4bytes(avp->data.s); } avp = AAAFindMatchingAVP(m, 0, AVP_Acct_Application_Id, 0, AAA_FORWARD_SEARCH); if (avp && avp_vendor) { vendor_id = get_4bytes(avp_vendor->data.s); app_id = get_4bytes(avp->data.s); } avp = AAAFindMatchingAVP(m, 0, AVP_Destination_Host, 0, AAA_FORWARD_SEARCH); if (avp) destination_host = avp->data; if (destination_host.len) { /* There is a destination host present in the message try and route directly there */ p = get_peer_by_fqdn(&destination_host); if (p && (p->state == I_Open || p->state == R_Open) && peer_handles_application(p, app_id, vendor_id)) { p->last_selected = time(NULL); return p; } /* the destination host peer is not connected at the moment, try a normal route then */ } avp = AAAFindMatchingAVP(m, 0, AVP_Destination_Realm, 0, AAA_FORWARD_SEARCH); if (avp) destination_realm = avp->data; if (!config->r_table) { LM_ERR("get_routing_peer(): Empty routing table.\n"); return 0; } if (destination_realm.len) { /* first search for the destination realm */ for (rr = config->r_table->realms; rr; rr = rr->next) if (rr->realm.len == destination_realm.len && strncasecmp(rr->realm.s, destination_realm.s, destination_realm.len) == 0) break; if (rr) { p = get_first_connected_route(cdp_session, rr->routes, app_id, vendor_id); if (p) return p; else LM_ERR("get_routing_peer(): No connected Route peer found for Realm <%.*s>. Trying DefaultRoutes next...\n", destination_realm.len, destination_realm.s); } } /* if not found in the realms or no destination_realm, * get the first connected host in default routes */ LM_DBG("no routing peer found, trying default route\n"); p = get_first_connected_route(cdp_session, config->r_table->routes, app_id, vendor_id); if (!p) { LM_ERR("get_routing_peer(): No connected DefaultRoute peer found for app_id %d and vendor id %d.\n", app_id, vendor_id); } return p; }
/** * Retrieve the Session-Timeout, Auth-Lifetime and Auth-Grace-Period AVPs and update the session timers accordingly * @param x * @param msg */ void update_auth_session_timers(cdp_auth_session_t *x, AAAMessage *msg) { AAA_AVP *avp; uint32_t session_timeout = 0, grace_period = 0, auth_lifetime = 0; int update_grace = 0, update_lifetime = 0; avp = AAAFindMatchingAVP(msg, 0, AVP_Auth_Grace_Period, 0, 0); if (avp && avp->data.len == 4) { grace_period = get_4bytes(avp->data.s); update_grace = 1; } else { if (!avp) { grace_period = x->last_requested_grace; } } if (update_grace) x->grace_period = grace_period; avp = AAAFindMatchingAVP(msg, 0, AVP_Authorization_Lifetime, 0, 0); if (avp && avp->data.len == 4) { auth_lifetime = get_4bytes(avp->data.s); update_lifetime = 1; } else { if (!avp) { LM_DBG("using timers from our request as there is nothing in the response (lifetime) - last requested lifetime was [%d]\n", x->last_requested_lifetime); if (x->last_requested_lifetime > 0) { update_lifetime = 1; auth_lifetime = x->last_requested_lifetime; } } } if (update_lifetime) { switch (auth_lifetime) { case 0: x->lifetime = time(0); break; case 0xFFFFFFFF: x->lifetime = -1; break; default: x->lifetime = time(0) + auth_lifetime; } if (x->timeout != -1 && x->timeout < x->lifetime) { x->timeout = x->lifetime + x->grace_period; } } avp = AAAFindMatchingAVP(msg, 0, AVP_Session_Timeout, 0, 0); if (avp && avp->data.len == 4) { session_timeout = get_4bytes(avp->data.s); switch (session_timeout) { case 0: x->timeout = time(0) + config->default_auth_session_timeout; break; case 0xFFFFFFFF: x->timeout = -1; break; default: x->timeout = time(0) + session_timeout; } if (!x->lifetime) x->lifetime = x->timeout; } }
/** * Add Session-Timeout, Auth-Lifetime and Auth-Grace-Period AVPs to outgoing messages in case they are missing * @param x * @param msg */ void add_auth_session_timers(cdp_auth_session_t *x, AAAMessage *msg) { AAA_AVP *avp; char data[4]; uint32_t v; uint32_t lifetime, timeout, grace; avp = AAAFindMatchingAVP(msg, 0, AVP_Authorization_Lifetime, 0, 0); if (!avp) { if (x->lifetime == -1) v = 0xFFFFFFFF; else { v = x->lifetime - time(0); if (v < 0) v = 0; } x->last_requested_lifetime = v; set_4bytes(data, v); avp = AAACreateAVP(AVP_Authorization_Lifetime, AAA_AVP_FLAG_MANDATORY, 0, data, 4, AVP_DUPLICATE_DATA); if (avp) AAAAddAVPToMessage(msg, avp, msg->avpList.tail); } else { if (avp->data.len == 4) { lifetime = get_4bytes(avp->data.s); switch (lifetime) { case 0: x->last_requested_lifetime = 0; break; case 0xFFFFFFFF: x->last_requested_lifetime = -1; break; default: x->last_requested_lifetime = lifetime; } } } if (x->lifetime != -1) { avp = AAAFindMatchingAVP(msg, 0, AVP_Auth_Grace_Period, 0, 0); if (!avp) { v = x->grace_period; set_4bytes(data, v); avp = AAACreateAVP(AVP_Auth_Grace_Period, AAA_AVP_FLAG_MANDATORY, 0, data, 4, AVP_DUPLICATE_DATA); if (avp) AAAAddAVPToMessage(msg, avp, msg->avpList.tail); x->last_requested_grace = v; } else { if (avp->data.len == 4) { grace = get_4bytes(avp->data.s); switch (grace) { case 0: x->last_requested_grace = 0; break; case 0xFFFFFFFF: x->last_requested_grace = -1; break; default: x->last_requested_grace = grace; } } } } avp = AAAFindMatchingAVP(msg, 0, AVP_Session_Timeout, 0, 0); if (!avp) { if (x->timeout == -1) v = 0xFFFFFFFF; else { v = x->timeout - time(0); if (v < 0) v = 0; } set_4bytes(data, v); avp = AAACreateAVP(AVP_Session_Timeout, AAA_AVP_FLAG_MANDATORY, 0, data, 4, AVP_DUPLICATE_DATA); if (avp) AAAAddAVPToMessage(msg, avp, msg->avpList.tail); x->last_requested_timeout = v; } else { if (avp->data.len == 4) { timeout = get_4bytes(avp->data.s); switch (timeout) { case 0: x->last_requested_timeout = 0; break; case 0xFFFFFFFF: x->last_requested_timeout = -1; break; default: x->last_requested_timeout = lifetime; } } } }
/* This function convert message to message structure */ AAAMessage* AAATranslateMessage( unsigned char* source, unsigned int sourceLen, int attach_buf) { unsigned char *ptr; AAAMessage *msg; unsigned char version; unsigned int msg_len; AAA_AVP *avp; unsigned int avp_code; unsigned char avp_flags; unsigned int avp_len; unsigned int avp_vendorID; unsigned int avp_data_len; /* check the params */ if( !source || !sourceLen || sourceLen<AAA_MSG_HDR_SIZE) { ERROR("ERROR:AAATranslateMessage: invalid buffered received!\n"); goto error; } /* inits */ msg = 0; avp = 0; ptr = source; /* alloc a new message structure */ msg = (AAAMessage*)ad_malloc(sizeof(AAAMessage)); if (!msg) { ERROR("ERROR:AAATranslateMessage: no more free memory!!\n"); goto error; } memset(msg,0,sizeof(AAAMessage)); /* get the version */ version = (unsigned char)*ptr; ptr += VER_SIZE; if (version!=1) { ERROR("ERROR:AAATranslateMessage: invalid version [%d]in " "AAA msg\n",version); goto error; } /* message length */ msg_len = get_3bytes( ptr ); ptr += MESSAGE_LENGTH_SIZE; if (msg_len>sourceLen) { ERROR("ERROR:AAATranslateMessage: AAA message len [%d] bigger then" " buffer len [%d]\n",msg_len,sourceLen); goto error; } /* command flags */ msg->flags = *ptr; ptr += FLAGS_SIZE; /* command code */ msg->commandCode = get_3bytes( ptr ); ptr += COMMAND_CODE_SIZE; /* application-Id */ msg->applicationId = get_4bytes( ptr ); ptr += APPLICATION_ID_SIZE; /* Hop-by-Hop-Id */ msg->hopbyhopId = *((unsigned int*)ptr); ptr += HOP_BY_HOP_IDENTIFIER_SIZE; /* End-to-End-Id */ msg->endtoendId = *((unsigned int*)ptr); ptr += END_TO_END_IDENTIFIER_SIZE; /* start decoding the AVPS */ while (ptr < source+msg_len) { if (ptr+AVP_HDR_SIZE(0x80)>source+msg_len){ ERROR("ERROR:AAATranslateMessage: source buffer to short!! " "Cannot read the whole AVP header!\n"); goto error; } /* avp code */ avp_code = get_4bytes( ptr ); ptr += AVP_CODE_SIZE; /* avp flags */ avp_flags = (unsigned char)*ptr; ptr += AVP_FLAGS_SIZE; /* avp length */ avp_len = get_3bytes( ptr ); ptr += AVP_LENGTH_SIZE; if (avp_len<1) { ERROR("ERROR:AAATranslateMessage: invalid AVP len [%d]\n", avp_len); goto error; } /* avp vendor-ID */ avp_vendorID = 0; if (avp_flags&AAA_AVP_FLAG_VENDOR_SPECIFIC) { avp_vendorID = get_4bytes( ptr ); ptr += AVP_VENDOR_ID_SIZE; } /* data length */ avp_data_len = avp_len-AVP_HDR_SIZE(avp_flags); /*check the data length */ if ( source+msg_len<ptr+avp_data_len) { ERROR("ERROR:AAATranslateMessage: source buffer to short!! " "Cannot read a whole data for AVP!\n"); goto error; } /* create the AVP */ avp = AAACreateAVP( avp_code, avp_flags, avp_vendorID, (char*)ptr, avp_data_len, AVP_DONT_FREE_DATA); if (!avp) goto error; /* link the avp into aaa message to the end */ AAAAddAVPToMessage( msg, avp, msg->avpList.tail); ptr += to_32x_len( avp_data_len ); } /* link the buffer to the message */ if (attach_buf) { msg->buf.s = (char*)source; msg->buf.len = msg_len; } //AAAPrintMessage( msg ); return msg; error: ERROR("ERROR:AAATranslateMessage: message conversion droped!!\n"); AAAFreeMessage(&msg); return 0; }
/** * Ungroup from a data buffer a list of avps * @param buf - payload to ungroup the list from * @returns the AAA_AVP_LIST or an empty one on error */ AAA_AVP_LIST AAAUngroupAVPS(str buf) { char *ptr; AAA_AVP *avp; unsigned int avp_code; unsigned char avp_flags; unsigned int avp_len; unsigned int avp_vendorID; unsigned int avp_data_len; AAA_AVP_LIST lh; lh.head=0; lh.tail=0; ptr = buf.s; /* start decoding the AVPS */ while (ptr < buf.s+buf.len) { if (ptr+AVP_HDR_SIZE(0x80)>buf.s+buf.len){ LM_ERR("hss3g_ungroup_avps: source buffer to short!! " "Cannot read the whole AVP header!\n"); goto error; } /* avp code */ avp_code = get_4bytes( ptr ); ptr += AVP_CODE_SIZE; /* avp flags */ avp_flags = (unsigned char)*ptr; ptr += AVP_FLAGS_SIZE; /* avp length */ avp_len = get_3bytes( ptr ); ptr += AVP_LENGTH_SIZE; if (avp_len<1) { LM_ERR("hss3g_ungroup_avps: invalid AVP len [%d]\n", avp_len); goto error; } /* avp vendor-ID */ avp_vendorID = 0; if (avp_flags&AAA_AVP_FLAG_VENDOR_SPECIFIC) { avp_vendorID = get_4bytes( ptr ); ptr += AVP_VENDOR_ID_SIZE; } /* data length */ avp_data_len = avp_len - AVP_HDR_SIZE(avp_flags); /*check the data length */ if ( buf.s+buf.len<ptr+avp_data_len) { LM_ERR("hss3g_ungroup_avps: source buffer to short!! " "Cannot read a whole data for AVP!\n"); goto error; } /* create the AVP */ avp = AAACreateAVP( avp_code, avp_flags, avp_vendorID, ptr, avp_data_len, AVP_DONT_FREE_DATA); if (!avp) { LM_ERR("hss3g_ungroup_avps: can't create avp for member of list\n"); goto error; } /* link the avp into aaa message to the end */ avp->next = 0; avp->prev = lh.tail; if (lh.tail) { lh.tail->next=avp; lh.tail=avp; } else { lh.tail=avp; lh.head=avp; } ptr += to_32x_len( avp_data_len ); } return lh; error: LM_CRIT("AVP:<%.*s>\n",buf.len,buf.s); return lh; }
Ro_CCA_t *Ro_parse_CCA_avps(AAAMessage *cca) { if (!cca) return 0; Ro_CCA_t *ro_cca_data = 0; mem_new(ro_cca_data, sizeof (Ro_CCR_t), pkg); multiple_services_credit_control_t *mscc = 0; mem_new(mscc, sizeof (multiple_services_credit_control_t), pkg); granted_services_unit_t *gsu = 0; mem_new(gsu, sizeof (granted_services_unit_t), pkg); final_unit_indication_t *fui = 0; mem_new(fui, sizeof (final_unit_indication_t), pkg); mscc->granted_service_unit = gsu; mscc->final_unit_action = fui; mscc->final_unit_action->action = -1; mscc->final_unit_action->redirect_server = 0; AAA_AVP_LIST* avp_list = &cca->avpList; AAA_AVP_LIST mscc_avp_list; AAA_AVP_LIST* mscc_avp_list_ptr; AAA_AVP *avp = avp_list->head; unsigned int x; while (avp != NULL) { switch (avp->code) { case AVP_CC_Request_Type: x = get_4bytes(avp->data.s); ro_cca_data->cc_request_type = x; break; case AVP_CC_Request_Number: x = get_4bytes(avp->data.s); ro_cca_data->cc_request_number = x; break; case AVP_Multiple_Services_Credit_Control: mscc_avp_list = cdp_avp->cdp->AAAUngroupAVPS(avp->data); mscc_avp_list_ptr = &mscc_avp_list; AAA_AVP *mscc_avp = mscc_avp_list_ptr->head; while (mscc_avp != NULL) { LM_DBG("MSCC AVP code is [%i] and data length is [%i]", mscc_avp->code, mscc_avp->data.len); switch (mscc_avp->code) { AAA_AVP_LIST y; AAA_AVP *z; case AVP_Granted_Service_Unit: y = cdp_avp->cdp->AAAUngroupAVPS(mscc_avp->data); z = y.head; while (z) { switch (z->code) { case AVP_CC_Time: mscc->granted_service_unit->cc_time = get_4bytes(z->data.s); break; default: LM_ERR("Unsupported Granted Service Unit with code:[%d]\n", z->code); } z = z->next; } cdp_avp->cdp->AAAFreeAVPList(&y); break; case AVP_Validity_Time: mscc->validity_time = get_4bytes(mscc_avp->data.s); break; case AVP_Result_Code: mscc->resultcode = get_4bytes(mscc_avp->data.s); break; case AVP_Final_Unit_Indication: y = cdp_avp->cdp->AAAUngroupAVPS(mscc_avp->data); z = y.head; while (z) { switch (z->code) { case AVP_Final_Unit_Action: mscc->final_unit_action->action = get_4bytes(z->data.s); break; case AVP_Redirect_Server: LM_DBG("Received redirect server\n"); redirect_server_t* redirect_server_info = 0; mem_new(redirect_server_info, sizeof (redirect_server_t), pkg); mscc->final_unit_action->redirect_server = redirect_server_info; AAA_AVP_LIST yy; AAA_AVP *zz; yy = cdp_avp->cdp->AAAUngroupAVPS(z->data); zz = yy.head; while (zz) { switch (zz->code) { case AVP_Redirect_Address_Type: LM_DBG("Received redirect address type\n"); mscc->final_unit_action->redirect_server->address_type = get_4bytes(zz->data.s); break; case AVP_Redirect_Server_Address: LM_DBG("Received redirect server address of [%.*s]\n", zz->data.len, zz->data.s); str_dup_ptr(redirect_server_info->server_address, zz->data, pkg); break; default: LM_ERR("Unsupported Redirect Server AVP with code:[%d]\n", zz->code); } zz = zz->next; cdp_avp->cdp->AAAFreeAVPList(&yy); } break; default: LM_ERR("Unsupported Final Unit Indication AVP.\n"); } z = z->next; } cdp_avp->cdp->AAAFreeAVPList(&y); } mscc_avp = mscc_avp->next; } cdp_avp->cdp->AAAFreeAVPList(mscc_avp_list_ptr); break; case AVP_Result_Code: x = get_4bytes(avp->data.s); ro_cca_data->resultcode = x; break; } avp = avp->next; } ro_cca_data->mscc = mscc; return ro_cca_data; out_of_memory: LM_ERR("out of pkg memory\n"); Ro_free_CCA(ro_cca_data); return 0; }
/** * Sends a message to the peer. * \note Must be called with a lock on the peer. * @param p - peer to send to * @param msg - message to send */ void Snd_Message(peer *p, AAAMessage *msg) { AAASession *session=0; int rcode; int send_message_before_session_sm=0; LM_DBG("Snd_Message called to peer [%.*s] for %s with code %d \n", p->fqdn.len,p->fqdn.s,is_req(msg)?"request":"response",msg->commandCode); touch_peer(p); if (msg->sessionId) session = cdp_get_session(msg->sessionId->data); if (session){ LM_DBG("There is a session of type %d\n",session->type); switch (session->type){ case AUTH_CLIENT_STATEFULL: if (is_req(msg)) { auth_client_statefull_sm_process(session,AUTH_EV_SEND_REQ,msg); session = 0; } else { if (msg->commandCode == IMS_ASA){ if (!msg->res_code){ msg->res_code = AAAFindMatchingAVP(msg,0,AVP_Result_Code,0,0); } if (!msg->res_code) { auth_client_statefull_sm_process(session,AUTH_EV_SEND_ASA_UNSUCCESS,msg); session = 0; } else { rcode = get_4bytes(msg->res_code->data.s); if (rcode>=2000 && rcode<3000) { peer_send_msg(p,msg); send_message_before_session_sm=1; auth_client_statefull_sm_process(session,AUTH_EV_SEND_ASA_SUCCESS,msg); session = 0; } else { auth_client_statefull_sm_process(session,AUTH_EV_SEND_ASA_UNSUCCESS,msg); session = 0; } } }else { auth_client_statefull_sm_process(session,AUTH_EV_SEND_ANS,msg); session = 0; } } break; case AUTH_SERVER_STATEFULL: LM_DBG("this message is matched here to see what request or reply it is\n"); if (is_req(msg)) { if (msg->commandCode== IMS_ASR) { LM_DBG("ASR\n"); auth_server_statefull_sm_process(session,AUTH_EV_SEND_ASR,msg); session = 0; } else { //would be a RAR but ok! LM_DBG("other request\n"); auth_server_statefull_sm_process(session,AUTH_EV_SEND_REQ,msg); session = 0; } } else { if (msg->commandCode == IMS_STR) { LM_DBG("STA\n"); auth_server_statefull_sm_process(session,AUTH_EV_SEND_STA,msg); session = 0; } else { LM_DBG("other reply\n"); auth_server_statefull_sm_process(session,AUTH_EV_SEND_ANS,msg); session = 0; } } break; default: break; } if (session) AAASessionsUnlock(session->hash); } if (!send_message_before_session_sm) peer_send_msg(p,msg); }