/***************************************************************************** Eurecom OpenAirInterface 3 Copyright(c) 2012 Eurecom Source mme_api.c Version 0.1 Date 2013/02/28 Product NAS stack Subsystem Application Programming Interface Author Frederic Maurel Description Implements the API used by the NAS layer running in the MME to interact with a Mobility Management Entity *****************************************************************************/ #ifdef NAS_MME #include "mme_api.h" #include "nas_log.h" #include // memcpy /****************************************************************************/ /**************** E X T E R N A L D E F I N I T I O N S ****************/ /****************************************************************************/ /****************************************************************************/ /******************* L O C A L D E F I N I T I O N S *******************/ /****************************************************************************/ /* Maximum number of PDN connections the MME may simultaneously support */ #define MME_API_PDN_MAX 10 /* MME group identifier */ #define MME_API_MME_GID 0x0102 /* MME code */ #define MME_API_MME_CODE 0x12 /* Default APN */ static const OctetString mme_api_default_apn = { 14, (uint8_t*)("www.eurecom.fr")}; /* APN configured for emergency bearer services */ static const OctetString mme_api_emergency_apn = { 18, (uint8_t*)("www.eurecom_sos.fr")}; /* Public Land Mobile Network identifier */ static const plmn_t mme_api_plmn = {0, 2, 0xf, 8, 0, 1}; // 20810 /* Number of concecutive tracking areas */ #define MME_API_NB_TACS 4 /* Code of the first tracking area belonging to the PLMN */ #define MME_API_FIRST_TAC 0x0001 /* NAS security key */ #define MME_API_KASME "CAFECAFECAFECAFECAFECAFECAFECAFE" /* Authentication parameter RAND */ static const UInt8_t _mme_api_rand[AUTH_RAND_SIZE] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04 }; /* Authentication parameter AUTN */ static const UInt8_t _mme_api_autn[AUTH_AUTN_SIZE] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x05, 0x04, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* Authentication response parameter */ static const UInt8_t _mme_api_xres[AUTH_XRES_SIZE] = { 0x67, 0x70, 0x3a, 0x31, 0xf2, 0x2a, 0x2d, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* Network IP version capability */ enum { MME_API_IPV4_ADDR, MME_API_IPV6_ADDR, MME_API_IPV4V6_ADDR, MME_API_ADDR_MAX } _mme_api_ip_capability = MME_API_IPV4V6_ADDR; /* Pool of IPv4 addresses */ static uint8_t _mme_api_ipv4_addr[MME_API_PDN_MAX][4] = { {0xC0, 0xA8, 0x02, 0x3C}, /* 192.168.02.60 */ {0xC0, 0xA8, 0x0C, 0xBB}, /* 192.168.12.187 */ {0xC0, 0xA8, 0x0C, 0xBC}, /* 192.168.12.188 */ {0xC0, 0xA8, 0x0C, 0xBD}, /* 192.168.12.189 */ {0xC0, 0xA8, 0x0C, 0xBE}, /* 192.168.12.190 */ {0xC0, 0xA8, 0x0C, 0xBF}, /* 192.168.12.191 */ {0xC0, 0xA8, 0x0C, 0xC0}, /* 192.168.12.192 */ {0xC0, 0xA8, 0x0C, 0xC1}, /* 192.168.12.193 */ {0xC0, 0xA8, 0x0C, 0xC2}, /* 192.168.12.194 */ {0xC0, 0xA8, 0x0C, 0xC3}, /* 192.168.12.195 */ }; /* Pool of IPv6 addresses */ static uint8_t _mme_api_ipv6_addr[MME_API_PDN_MAX][8] = { /* FE80::221:70FF:C0A8:023C/64 */ {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x02, 0x3C}, /* FE80::221:70FF:C0A8:0CBB/64 */ {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBB}, /* FE80::221:70FF:C0A8:0CBC/64 */ {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBC}, /* FE80::221:70FF:C0A8:0CBD/64 */ {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBD}, /* FE80::221:70FF:C0A8:0CBE/64 */ {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBE}, /* FE80::221:70FF:C0A8:0CBF/64 */ {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBF}, /* FE80::221:70FF:C0A8:0CC0/64 */ {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xC0}, /* FE80::221:70FF:C0A8:0CC1/64 */ {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xC1}, /* FE80::221:70FF:C0A8:0CC2/64 */ {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xC2}, /* FE80::221:70FF:C0A8:0CC3/64 */ {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xC3}, }; /* Pool of IPv4v6 addresses */ static uint8_t _mme_api_ipv4v6_addr[MME_API_PDN_MAX][12] = { /* 192.168.02.60, FE80::221:70FF:C0A8:023C/64 */ {0xC0, 0xA8, 0x02, 0x3C, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x02, 0x3C}, /* 192.168.12.187, FE80::221:70FF:C0A8:0CBB/64 */ {0xC0, 0xA8, 0x0C, 0xBB, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBB}, /* 192.168.12.188, FE80::221:70FF:C0A8:0CBC/64 */ {0xC0, 0xA8, 0x0C, 0xBC, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBC}, /* 192.168.12.189, FE80::221:70FF:C0A8:0CBD/64 */ {0xC0, 0xA8, 0x0C, 0xBD, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBD}, /* 192.168.12.189, FE80::221:70FF:C0A8:0CBE/64 */ {0xC0, 0xA8, 0x0C, 0xBD, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBE}, /* 192.168.12.189, FE80::221:70FF:C0A8:0CBF/64 */ {0xC0, 0xA8, 0x0C, 0xBD, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBF}, /* 192.168.12.189, FE80::221:70FF:C0A8:0CC0/64 */ {0xC0, 0xA8, 0x0C, 0xBD, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xC0}, /* 192.168.12.189, FE80::221:70FF:C0A8:0CC1/64 */ {0xC0, 0xA8, 0x0C, 0xBD, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xC1}, /* 192.168.12.189, FE80::221:70FF:C0A8:0CC2/64 */ {0xC0, 0xA8, 0x0C, 0xBD, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xC2}, /* 192.168.12.189, FE80::221:70FF:C0A8:0CC3/64 */ {0xC0, 0xA8, 0x0C, 0xBD, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xC3}, }; static const OctetString _mme_api_pdn_addr[MME_API_ADDR_MAX][MME_API_PDN_MAX] = { { /* IPv4 network capability */ {4, _mme_api_ipv4_addr[0]}, {4, _mme_api_ipv4_addr[1]}, {4, _mme_api_ipv4_addr[2]}, {4, _mme_api_ipv4_addr[3]}, {4, _mme_api_ipv4_addr[4]}, {4, _mme_api_ipv4_addr[5]}, {4, _mme_api_ipv4_addr[6]}, {4, _mme_api_ipv4_addr[7]}, {4, _mme_api_ipv4_addr[8]}, {4, _mme_api_ipv4_addr[9]}, }, { /* IPv6 network capability */ {8, _mme_api_ipv6_addr[0]}, {8, _mme_api_ipv6_addr[1]}, {8, _mme_api_ipv6_addr[2]}, {8, _mme_api_ipv6_addr[3]}, {8, _mme_api_ipv6_addr[4]}, {8, _mme_api_ipv6_addr[5]}, {8, _mme_api_ipv6_addr[6]}, {8, _mme_api_ipv6_addr[7]}, {8, _mme_api_ipv6_addr[8]}, {8, _mme_api_ipv6_addr[9]}, }, { /* IPv4v6 network capability */ {12, _mme_api_ipv4v6_addr[0]}, {12, _mme_api_ipv4v6_addr[1]}, {12, _mme_api_ipv4v6_addr[2]}, {12, _mme_api_ipv4v6_addr[3]}, {12, _mme_api_ipv4v6_addr[4]}, {12, _mme_api_ipv4v6_addr[5]}, {12, _mme_api_ipv4v6_addr[6]}, {12, _mme_api_ipv4v6_addr[7]}, {12, _mme_api_ipv4v6_addr[8]}, {12, _mme_api_ipv4v6_addr[9]}, }, }; /* Subscribed QCI */ #define MME_API_QCI 3 /* Data bit rates */ #define MME_API_BIT_RATE_64K 0x40 #define MME_API_BIT_RATE_128K 0x48 #define MME_API_BIT_RATE_512K 0x78 #define MME_API_BIT_RATE_1024K 0x87 /* Total number of PDN connections (should not exceed MME_API_PDN_MAX) */ static int _mme_api_pdn_id = 0; /****************************************************************************/ /****************** E X P O R T E D F U N C T I O N S ******************/ /****************************************************************************/ /****************************************************************************/ /********************* L O C A L F U N C T I O N S *********************/ /****************************************************************************/ /**************************************************************************** ** ** ** Name: mme_api_get_emm_config() ** ** ** ** Description: Retreives MME configuration data related to EPS mobility ** ** management ** ** ** ** Inputs: None ** ** Others: None ** ** ** ** Outputs: None ** ** Return: RETURNok, RETURNerror ** ** Others: None ** ** ** ***************************************************************************/ int mme_api_get_emm_config(mme_api_emm_config_t* config) { LOG_FUNC_IN; config->gummei.plmn.MCCdigit1 = 2; config->gummei.plmn.MCCdigit2 = 0; config->gummei.plmn.MCCdigit3 = 8; config->gummei.plmn.MNCdigit1 = 1; config->gummei.plmn.MNCdigit2 = 0; config->gummei.plmn.MNCdigit3 = 0xf; config->gummei.MMEgid = MME_API_MME_GID; config->gummei.MMEcode = MME_API_MME_CODE; config->features = MME_API_EMERGENCY_ATTACH | MME_API_UNAUTHENTICATED_IMSI; LOG_FUNC_RETURN (RETURNok); } /**************************************************************************** ** ** ** Name: mme_api_get_config() ** ** ** ** Description: Retreives MME configuration data related to EPS session ** ** management ** ** ** ** Inputs: None ** ** Others: None ** ** ** ** Outputs: None ** ** Return: RETURNok, RETURNerror ** ** Others: None ** ** ** ***************************************************************************/ int mme_api_get_esm_config(mme_api_esm_config_t* config) { LOG_FUNC_IN; if (_mme_api_ip_capability == MME_API_IPV4_ADDR) { config->features = MME_API_IPV4; } else if (_mme_api_ip_capability == MME_API_IPV6_ADDR) { config->features = MME_API_IPV6; } else if (_mme_api_ip_capability == MME_API_IPV4V6_ADDR) { config->features = MME_API_IPV4 | MME_API_IPV6; } else { config->features = 0; } LOG_FUNC_RETURN (RETURNok); } /**************************************************************************** ** ** ** Name: mme_api_identify_guti() ** ** ** ** Description: Requests the MME to identify the UE using the specified ** ** GUTI. If the UE is known by the MME (a Mobility Manage- ** ** ment context exists for this UE in the MME), its se- ** ** curity context is returned. ** ** ** ** Inputs: guti: EPS Globally Unique Temporary UE Identity ** ** Others: None ** ** ** ** Outputs: vector: The EPS authentication vector of the UE if ** ** known by the network; NULL otherwise. ** ** Return: RETURNok, RETURNerror ** ** Others: None ** ** ** ***************************************************************************/ int mme_api_identify_guti(const GUTI_t* guti, auth_vector_t* vector) { LOG_FUNC_IN; int rc = RETURNerror; LOG_FUNC_RETURN(rc); } /**************************************************************************** ** ** ** Name: mme_api_identify_imsi() ** ** ** ** Description: Requests the MME to identify the UE using the specified ** ** IMSI. If the UE is known by the MME (a Mobility Manage- ** ** ment context exists for this UE in the MME), its se- ** ** curity context is returned. ** ** ** ** Inputs: imsi: International Mobile Subscriber Identity ** ** Others: None ** ** ** ** Outputs: vector: The EPS authentication vector of the UE if ** ** known by the network; NULL otherwise. ** ** Return: RETURNok, RETURNerror ** ** Others: None ** ** ** ***************************************************************************/ int mme_api_identify_imsi(const imsi_t* imsi, auth_vector_t* vector) { LOG_FUNC_IN; int rc = RETURNok; memcpy(vector->rand, _mme_api_rand, AUTH_RAND_SIZE); memcpy(vector->autn, _mme_api_autn, AUTH_AUTN_SIZE); memcpy(vector->xres, _mme_api_xres, AUTH_XRES_SIZE); LOG_FUNC_RETURN(rc); } /**************************************************************************** ** ** ** Name: mme_api_identify_imei() ** ** ** ** Description: Requests the MME to identify the UE using the specified ** ** IMEI. If the UE is known by the MME (a Mobility Manage- ** ** ment context exists for this UE in the MME), its se- ** ** curity context is returned. ** ** ** ** Inputs: imei: International Mobile Equipment Identity ** ** Others: None ** ** ** ** Outputs: vector: The EPS authentication vector of the UE if ** ** known by the network; NULL otherwise. ** ** Return: RETURNok, RETURNerror ** ** Others: None ** ** ** ***************************************************************************/ int mme_api_identify_imei(const imei_t* imei, auth_vector_t* vector) { LOG_FUNC_IN; int rc = RETURNerror; LOG_FUNC_RETURN(rc); } /**************************************************************************** ** ** ** Name: mme_api_new_guti() ** ** ** ** Description: Requests the MME to assign a new GUTI to the UE identi- ** ** fied by the given IMSI. ** ** ** ** Description: Requests the MME to assign a new GUTI to the UE identi- ** ** fied by the given IMSI and returns the list of consecu- ** ** tive tracking areas the UE is registered to. ** ** ** ** Inputs: imsi: International Mobile Subscriber Identity ** ** Others: None ** ** ** ** Outputs: guti: The new assigned GUTI ** ** tac: Code of the first tracking area belonging ** ** to the PLMN ** ** n_tacs: Number of concecutive tracking areas ** ** Return: RETURNok, RETURNerror ** ** Others: None ** ** ** ***************************************************************************/ int mme_api_new_guti(const imsi_t* imsi, GUTI_t* guti, tac_t* tac, int* n_tacs) { LOG_FUNC_IN; int rc = RETURNok; static unsigned int tmsi = 1; guti->gummei.plmn = mme_api_plmn; guti->gummei.MMEgid = MME_API_MME_GID; guti->gummei.MMEcode = MME_API_MME_CODE; guti->m_tmsi = tmsi++; *tac = MME_API_FIRST_TAC; *n_tacs = MME_API_NB_TACS; LOG_FUNC_RETURN(rc); } /**************************************************************************** ** ** ** Name: mme_api_subscribe() ** ** ** ** Description: Requests the MME to check whether connectivity with the ** ** requested PDN can be established using the specified APN. ** ** If accepted the MME returns PDN subscription context con- ** ** taining EPS subscribed QoS profile, the default APN if ** ** required and UE's IPv4 address and/or the IPv6 prefix. ** ** ** ** Inputs: apn: If not NULL, Access Point Name of the PDN ** ** to connect to ** ** is_emergency: TRUE if the PDN connectivity is requested ** ** for emergency bearer services ** ** Others: None ** ** ** ** Outputs: apn: If NULL, default APN or APN configured for ** ** emergency bearer services ** ** pdn_addr: PDN connection IPv4 address or IPv6 inter- ** ** face identifier to be used to build the ** ** IPv6 link local address ** ** qos: EPS subscribed QoS profile ** ** Return: RETURNok, RETURNerror ** ** Others: None ** ** ** ***************************************************************************/ int mme_api_subscribe(OctetString* apn, OctetString* pdn_addr, int is_emergency, mme_api_qos_t* qos) { LOG_FUNC_IN; int rc = RETURNok; if ( apn && (apn->length == 0) ) { /* PDN connectivity to default APN */ if (is_emergency) { apn->length = mme_api_emergency_apn.length; apn->value = mme_api_emergency_apn.value; } else { apn->length = mme_api_default_apn.length; apn->value = mme_api_default_apn.value; } } /* Assign PDN address */ if ( pdn_addr && (_mme_api_pdn_id < MME_API_PDN_MAX) ) { pdn_addr->length = _mme_api_pdn_addr[_mme_api_ip_capability][_mme_api_pdn_id].length; pdn_addr->value = _mme_api_pdn_addr[_mme_api_ip_capability][_mme_api_pdn_id].value; /* Increment the total number of PDN connections */ _mme_api_pdn_id += 1; } else { /* Maximum number of PDN connections exceeded */ rc = RETURNerror; } /* Setup EPS subscribed QoS profile */ if (qos) { qos->qci = MME_API_QCI; /* Uplink bit rate */ qos->gbr[MME_API_UPLINK] = MME_API_BIT_RATE_64K; qos->mbr[MME_API_UPLINK] = MME_API_BIT_RATE_128K; /* Downlink bit rate */ qos->gbr[MME_API_DOWNLINK] = MME_API_BIT_RATE_512K; qos->mbr[MME_API_DOWNLINK] = MME_API_BIT_RATE_1024K; } else { rc = RETURNerror; } LOG_FUNC_RETURN(rc); } /**************************************************************************** ** ** ** Name: mme_api_unsubscribe() ** ** ** ** Description: Requests the MME to release connectivity with the reques- ** ** ted PDN using the specified APN. ** ** ** ** Inputs: apn: Access Point Name of the PDN to disconnect ** ** from ** ** Others: None ** ** ** ** Outputs: None ** ** Return: RETURNok, RETURNerror ** ** Others: None ** ** ** ***************************************************************************/ int mme_api_unsubscribe(OctetString* apn) { LOG_FUNC_IN; int rc = RETURNok; /* Decrement the total number of PDN connections */ _mme_api_pdn_id -= 1; LOG_FUNC_RETURN(rc); } #endif // NAS_MME