path: root/include
AgeCommit message (Collapse)AuthorFilesLines
2019-09-02vty: Print MM state and RAN type in show mm-contextPau Espin Pedrol1-0/+1
Value presviosuly printed as MM state is actually usually refereed as GMM state, so rename it. Change-Id: Ia06c53f0cd2a6348237ed3abeb9367d965745aba
2019-09-02Introduce FSM mm_state_iu_fsmPau Espin Pedrol4-10/+26
Implement TS 23.060 6.1.2 Mobility Management States (Iu mode) using osmocom FSM and drop old implementation. Most of the logic on each state is still kept in gprs_gmm.c, will be inserted into the FSM later. Change-Id: I4c9cf8c27194817c56e8949af0205e1cc14af317
2019-09-02Introduce FSM mm_state_gb_fsmPau Espin Pedrol4-12/+28
Implement TS 23.060 6.1.1 Mobility Management States (A/Gb mode) using osmocom FSM and drop old implementation. Most of the logic on each state is still kept in gprs_gmm.c, will be inserted into the FSM later. Change-Id: I04004423e993107374d5a3549b8a93ac169251dd
2019-09-02Split enum gprs_pmm_state into Iu and Gb counterpartsPau Espin Pedrol2-10/+16
Those two state sets are not part of the same state machine, and are used in different scenarios, so let's split them and handle them in Gb and Iu specific parts of struct sgsn_mm_ctx. This is required in order to improve related code (for instance, use osmocom fsm). Change-Id: I6100d607da316da0595886c6968704dd9ccfbde9
2019-09-02Move llc->MM/SM Gb specific glue code to its own filePau Espin Pedrol3-0/+14
Now that we have RANAP/Iu handling specificities in its own file, let's have also Gb specific glue code for messages coming from llc up to MM/SM layer in its own file. This way same entry points in gprs_gmm.c are used by Gb and Iu: gsm0408_rcv_gmm() (for MM) and gsm0408_rcv_gsm() (for SM). Change-Id: Iaf57922a0970c1d03f6f1d6337d27ae3d4aaf32c
2019-09-02Move lots of Iu/ranap specific code into its own filePau Espin Pedrol4-5/+33
RANAP related functionalities were splitted among several files (gprs_gmm.c, gprs_sgsn.c and sgsn_libgtp.c). Let's move it into its own file to shrink complexity/size of existing files. It also allows to keep a lot of conditionally enabled code (BUILD_IU) and its dependencies (osmo-iuh) together. Change-Id: I549042aaff045a378de77d657cc396ee08f22f33
2019-09-02sgsn: gtp: Drop related pdp contexts on echo timeout against GGSNPau Espin Pedrol1-0/+1
Change-Id: I7e97bac1c13a2c26203eb64e590fd75d77eb44bd
2019-09-02Introduce log helper LOGGGSN and log category DGTPPau Espin Pedrol2-0/+7
It will be used in forthcoming commits. Change-Id: I30f46f44af1d0eee324b1a995c1dad2e1315af7c
2019-08-28gtp: make echo_interval unsignedPau Espin Pedrol1-1/+1
There's no real need to use -1 to indicate echo timer as disabled, since 0 can also be used (it doesn't make sense to have a timer timeout of 0). This way code is simplified. Change-Id: I689034887188a53590eddeffda781629694eb5ed
2019-08-21vty: Introduce cs7-instance-iuPau Espin Pedrol1-0/+1
Similar to what we already have in osmo-msc. Change-Id: Iaa9e1d06dd0430848ef4f7498a3c15d13f899904
2019-08-20gprs/gprs_gmm: implement T3314. Timeout to reset MM state READY->STANDBYAlexander Couzens1-0/+4
When a MS MM state is READY its exact location is known (PCU). On Gb, T3314 (aka TS 23.060 "READY timer") sets the MM state from READY to STANDBY, where only the RA is known. Introduce a second set of timer variables, because state timer can run while another packet state timer is timing out. Related: OS#1941 Change-Id: I4ce23ebe50d141076c20c9c56990b7103cd25e55
2019-08-20Replace own timer infra with libosmocore osmo_tdefPau Espin Pedrol1-14/+2
VTY command "show timer" is also available now. Change-Id: Ia0cf5f0a49737fbc419e2ccc86312d01c6e0056e
2019-08-20Introduce and use log macros when no mm ctx availablePau Espin Pedrol2-0/+23
Change-Id: Iba22060d8646bc8ec6227684ccb91d98cb4c7be2
2019-08-15gprs_sgsn.h: Flag MM_CTX_T_GERAN_Iu as not supportedPau Espin Pedrol1-1/+3
Change-Id: I3b53a530ab25434e2b2f4d80ad70a8a5f22bfcac
2019-08-12Introduce define TLLI_UNASSIGNEDPau Espin Pedrol1-0/+3
Change-Id: Ib8be5af2a5e92a7403505b73ce4c1751832de40d
2019-08-12gprs_llc.h: Improve documentation of some structsPau Espin Pedrol1-2/+3
Change-Id: I1b45f45addc87c74f3ae109e544143a1335180de
2019-06-13sgsn: Have authentication required on by defaultPau Espin Pedrol1-0/+2
Previous commit introduced command "authentication (optional|required)", which is only meaningful if auth-policy is remote. Upon adding the cmd, it changed the default logic for remote policy to not require authentication, which broke TTCN3 tests because sgsn no longer tries to authenticate the users. Since it's actually good to enable authentication by default where possible, let's enable it by default when on auth-policy remote. In order to do so, let's simply not care about the value of variable require_authentication if auth_policy is not REMOTE. As a result, we drop parts of the previous patch and remove unneeded checks (which are only partially useful based on order of commands during VTY read). Fixes: 794f446a284ed1ac6d31eb79a8f4c874d66fc34e Change-Id: Ic707a95af178b44f08809df3d3bc8354bf34273c
2019-04-24gb_proxy: cosmetic: Use 'bool' in data structures where applicableHarald Welte1-10/+11
If we ever only use 0/1 in an 'int', we should have used 'bool'. Change-Id: I63876f52d5de87e4c99d92669270fd1f487e217c
2019-04-24gb_proxy.h: Add missing comments; improve commentsHarald Welte1-13/+46
When the patching and routing features were introduced, a lot of the new structures were not documented at the same level as the pre-existing code. Let's fix that. Change-Id: I61bdd3b1cec037bce825c234a8a274b70629adc8
2019-04-24LLC: Store the XID inside the LLC Entity, not LLC Mgmg EntityHarald Welte1-7/+7
For every logical session between a MS and the SGSN, there is one LLME (LLC Management Entity) and a set of LLEs (Logical Link Entities): One for each SAPI. The XID procedure used to establish LLC configuration values such as N201 (MTU) parameters happens on each LLE separately. The negotiated parameters only affect that one LLE (SAPI) and are not global. Still, the OsmoSGSN LLC code has the "struct llist_head *xid" member as part of the gprs_llc_llme, and not as part of the gprs_llc_lle. This list is a cache of the XID fields we have sent with the last XID request, which is used in processing the response from the MS. If two XID handshakes were to occur concurrently on two LLEs, the state between them would get messed up. It must be maintained separately for each LLE. Closes: OS#3955 Change-Id: Iaeb54ca5ac58391be45e56c2e721f531969f3a9e
2018-12-20make gsup ipa name configurable in osmo-sgsn.cfgStefan Sperling1-0/+6
Add a 'gsup ipa-name' VTY command which overrides the default IPA name used by the SGSN on the GSUP link towards the HLR. This is required for GSUP routing in multi-SGSN networks. The 'gsup ipa-name' option can only be set via the config file because changing the IPA name at run-time conflicts with active GSUP connections and routes configured in the HLR. The osmo-sgsn program must be restarted if its IPA name needs to change. Related: OS#3356 Change-Id: Ib2f65fed9f56b9718e8a9647e3f01dce69870c1f
2018-12-12remove pointless declaration of struct gsm_networkStefan Sperling1-3/+0
We were passing a NULL pointer of type struct gsm_network * to ctrl_interface_setup_dynip(). Remove the pointless declaration of this struct. Also, replace the sgsn_controlif_setup() helper function with a direct call to ctrl_interface_setup_dynip(). The helper fnuction was just a thin wrapper around the latter. Change-Id: Ib4151afa5bff01e63b462cca517fb60ac0503759 Related: OS#3356
2018-12-11Use explicit parameter for sgsn_auth_init()Max1-1/+1
This is necessary to properly test ACLs in follow-up patches. Change-Id: Ibeba371234680f33ad35afbfffce9dca185228c1
2018-12-10Constify sgsn_acl_lookup() parameterMax1-1/+1
This requires I414e67a3de733fab407161b3264d3b89070ba537 in libosmocore to avoid warning about discarded const. Change-Id: Ie92637dd900b0f9eba891d5aad0b4ba0ee69c08c
2018-11-15use enums consistently instead of falling back to intStefan Sperling2-18/+24
The two existing enums defined in gprs_sndcp_xid.h, for protocol and data compression algorithm numbers respectively, were assigned to 'int' variables when their values were copied to other structures. This prevented the compiler from checking the enum value coverage during switch statements and also tripped up Coverity scans looking for enum value mismatch problems. So instead of copying enums to ints, make use of the enums throughout. Structures which can contain values from both enums now use a union of both, forcing us to be very explicit about which set of values we are dealing with. Change-Id: I3771a5c59f4e6fee24083b3c914965baf192cbd7 Depends: If6f3598cd6da4643ff2214e21c0d21f6eff0eb67 Depends: I8444c1ed052707c76a979fb06cb018ac678defa7 Related: CID#149102
2018-10-30Remove local libgsupclient; Use libosmo-gsup-client from osmo-hlrHarald Welte3-66/+2
osmo-hlr has recently (as of Change-Id Iad227bb477d64da30dd6bfbbe1bd0c0a55be9474) a working shared library implementation of libosmo-gsup-client. We can remove the local implementation in osmo-sgsn and use the system-installed shared library instead. Change-Id: I6f542945403cf2e3ddac419186b09ec0e2d43b69
2018-10-30Allocate sgsn_instance with tallocPau Espin Pedrol1-1/+2
Change-Id: I4a83c5799f0dbd5eb762039c6cfba671f6e465be
2018-10-02gprs_gmm: Fix missing Security Command for 3G when attachingAlexander Couzens1-0/+2
Introduce a new FSM step in GMM Attach to send the Security Command to the RNC after completing the Authentication. Fixes: f7198d7dbb84 ("gprs_gmm: introduce a GMM Attach Request FSM") Change-Id: I1e12b0a32e58c6f78dba7b548f7d7016567229db
2018-09-19GTP: refactor the echo timerAlexander Couzens1-0/+1
Move the check of the echo timer into an own function. The gtp echo timer must be re-check everytime the echo-timer has been modified or deactivated via vty. Fixes the TTCN3 SGSN_Tests.TC_attach_restart_ctr_echo Change-Id: Ia33471a9a9cfc3887facb665c82094b99932052a
2018-09-19gprs_sgsn.h: fix wrong type of re-attemptsAlexander Couzens1-1/+1
The GMM ctx->gmm_att_req.auth_reattempt is used to track multiple UTMS re-sync attempt of a MS. Change-Id: I708226cec9e131dcda4234f42ed3689f4f6750e8 Fixes: f7198d7dbb84 ("gprs_gmm: introduce a GMM Attach Request FSM") Fixes: OS#3556
2018-09-13gprs_gmm: introduce a GMM Attach Request FSMAlexander Couzens4-0/+50
The old GMM Attach Request handling used a recursive function which can not handle certain states and is quite complex and hard to extend. The new FSM handles such request in a FSM and can be called multiple times. Change-Id: I58b9c17be9776a03bb2a5b21e99135cfefc8c912
2018-08-20use __FILE__, not __BASE_FILE__Neels Hofmeyr1-2/+2
The intention was to use the file's basename, but __BASE_FILE__ means "the root file that is being parsed and contains #include statements". If we had a function using __BASE_FILE__ and that was defined in an #included file, __BASE_FILE__ would indicate the first file where the #include is, and not the file where the function is defined. __BASE_FILE__ works for us because we don't ever include function definitions that log something, so __BASE_FILE__ always coincides with __FILE__ for our logging; but still __BASE_FILE__ is semantically the wrong constant. Related: OS#2740 Change-Id: Icdf7af7a31fbba9197b3711eaf102fc0ae333bcc
2018-08-17gbproxy: Add new VTY-managed timer: link-list clean-stale-timerPau Espin Pedrol1-0/+5
This timer allows periodically cleaning up stale links in link-list of each gbproxy_peer. Previous to this patch, this kind of cleanup (gbproxy_remove_stale_link_infos) was being done only as a consequence of external events being triggered, such as a message from that peer being received. It was found in a production network agreggating several BSS that some of them were offline for a longtime but gbproxy was still caching big amounts of really old link_info for the NSEI assigned to those BSS, because since they were probably turned off abruptely, no new messages were received from it which would trigger the cleanup. As a consequence, it has been observed that a timer to periodically clean up old entries (link-list max-age) is requird in case w don't receive messages from that NSEI periodically. Related: SYS#4431 Change-Id: Ic777016f6d4f0e30fb736484774ca46878f17b7a
2018-08-17gbproxy: Add VTY parameter: link stored-msgs-max-lengthPau Espin Pedrol1-0/+5
It was discovered in some prod setups that some TLLIs can maintain quite long queues of msgb in case its IMSI is not acquired and the tlli is not pruned due to link-list max-{age,length} being set to 0. As a result, the osmo-gpbroxy steadly increases the list size of maintained TLLIs, and some TLLI was found without IMSI catching already 1211 msgb. Let's allow setting a maxiumum length for the queue storing those msgb in a per TLLI base. If the limit is reached, oldest msgb are removed before adding a new one. Depends: libosmocore Change-Id I33b501e89a8f29e4aa121696bcbb13d4b83db40f Related: SYS#4297 Change-Id: I4473be8604f80302df03ffdd5a13280dc072f824
2018-08-15Drop gprs_msgb_resize_area with libosmocore replacementPau Espin Pedrol1-2/+0
gprs_msgb_resize_area was introduced in libosmocore 0.94 (f78ec5ce0d0f6038147d9b9e14d81094309ba5d5) as msgb_resize_area. Let's use that one to avoid code duplication. Change-Id: Ib80f7b2b186d87f21d63d9b0bec58175170c905c
2018-08-15Drop gprs_msgb_copy with libosmocore replacementPau Espin Pedrol1-1/+0
gprs_msgb_copy was introduced in libosmocore 0.94 (f78ec5ce0d0f6038147d9b9e14d81094309ba5d5) as bssgp_msgb_copy. Let's use that one to avoid code duplication. Change-Id: I42a65fd8e4045fafadf5694f2d8d0c5e7ab350a0
2018-07-30migrate to oap_client in libosmogsmHarald Welte4-88/+5
libosmogsm in libosmocore.git from Change-Id Ie36729996abd30b84d1c30a09f62ebc6a9794950 onwards contains oap_client.c, so we don't need our local copy here in this repo anymore. Change-Id: I7b194f98ef3f925b6178d8a8dbd9fcf2f0c6e132 Requires: libosmocore.git Change-Id Ie36729996abd30b84d1c30a09f62ebc6a9794950
2018-07-24sgsn: Fix crash using new libgtp cb_recovery2 APIPau Espin Pedrol1-1/+1
When PDP CTX CREATE ACK is received with an increased RestartCtr, cb_recovery2 is called first, which will dettach ggsn from al pdp ctx (free the pdp_t). But when giving control back from the ctrl, libgtp still uses that freed ctx and sends it back to osmo-sgsn through cb_conf(). As specs state in any case that we need to handle the message containing the increased RestartCtr as valid, we then need to avoid freeing the pdp ctx and leave handling for later in cb_conf. Depends: osmo-ggsn (libgtp) Change-Id I53e92298f2f6b84d662a3300d922e8c2ccb178bc. Change-Id: I0989c00e18ca95a099e1a312940eaac71957b444
2018-07-16Forward GGSN originated DEACT PDP CTX REQPau Espin Pedrol1-0/+1
This commit fixes TTCN3 sgsn test TC_attach_pdp_act_user_deact_mt. Change-Id: I204209c017aac8a8402cbb8d0a0200540abcc954
2018-07-16Add optional TearDownInd IE in PDP DEACT REQ towards PCUPau Espin Pedrol1-1/+1
According to 3GPP TS 24.008 Section, the tear down indicator IE maybe included in the DEACTIVATE PDP CONTEXT REQUEST message in order to indicate whether only the PDP context associated with this specific TI or all active PDP contexts sharing the same PDP address and APN as the PDP context associated with this specific TI shall be deactivated. As we don't permit/support establishing multiple PDP contexts using the same APN and PDP address, it shouldn't really make any difference. Nevertheless, we want to clear everything, so let's include it. Change-Id: Ia9bc2d0e93362a8473eac5cf4c7e8ffa41c79e5b
2018-07-13Disarm T3395 when dettaching mmctx from pdpctxPau Espin Pedrol1-0/+2
In sgsn_pdp_ctx_terminate, a pdp ctx is terminated and the mm ctx is detached. However, T3395 may still be armed and then pdpctx_timer_cb will trigger, and attempt to use the pdp->mm ctx which was already detached (set to NULL) when calling gsm48_tx_gsm_deact_pdp_req()->mmctx2msgid(). Following list of log lines shows the scenario+crash, in which osmo-sgsn is trying to deactivate the ctx all the time but the PCU doesn't ACK it, and then at some point the PDP context is forced released. osmo-sgsn/src/gprs/gprs_gmm.c:2294 MM(901700000015254/d7e9ab95) <- DEACTIVATE PDP CONTEXT REQ osmo-sgsn/src/gprs/gprs_gmm.c:1464 MM(901700000015254/d7e9ab95) -> GMM DETACH REQUEST TLLI=0xd7e9ab95 type=GPRS detach Power-off osmo-sgsn/src/gprs/gprs_gmm.c:313 MM(901700000015254/d7e9ab95) Cleaning MM context due to GPRS DETACH REQUEST osmo-sgsn/src/gprs/gprs_sgsn.c:332 MM(901700000015254/d7e9ab95) Dropping PDP context for NSAPI=5 osmo-sgsn/src/gprs/gprs_sgsn.c:434 PDP(901700000015254/0) Forcing release of PDP context osmo-sgsn/src/gprs/gprs_sndcp.c:508 SNSM-DEACTIVATE.ind (lle=0x62100001bca0, TLLI=d7e9ab95, SAPI=3, NSAPI=5) osmo-sgsn/src/gprs/sgsn_libgtp.c:310 PDP(---/0) Delete PDP Context osmo-sgsn/src/gprs/gprs_gmm.c:2294 MM(---/ffffffff) <- DEACTIVATE PDP CONTEXT REQ osmo-sgsn/src/gprs/gprs_gmm.c:305:25: runtime error: member access within null pointer of type 'const struct sgsn_mm_ctx' Program received signal SIGSEGV, Segmentation fault. 0x0000555555698c1b in mmctx2msgid (msg=0x61d0000172e0, mm=0x0) at /home/pespin/dev/sysmocom/git/osmo-sgsn/src/gprs/gprs_gmm.c:305 305 msgb_tlli(msg) = mm->gb.tlli; (gdb) bt #0 0x0000555555698c1b in mmctx2msgid (msg=0x61d0000172e0, mm=0x0) at osmo-sgsn/src/gprs/gprs_gmm.c:305 #1 0x00005555556b170a in _gsm48_tx_gsm_deact_pdp_req (mm=0x0, tid=0 '\000', sm_cause=38 '&') at osmo-sgsn/src/gprs/gprs_gmm.c:2297 #2 0x00005555556b1a2e in gsm48_tx_gsm_deact_pdp_req (pdp=0x6140000008a0, sm_cause=38 '&') at osmo-sgsn/src/gprs/gprs_gmm.c:2311 #3 0x00005555556b876c in pdpctx_timer_cb (_pdp=0x6140000008a0) at osmo-sgsn/src/gprs/gprs_gmm.c:2717 #4 0x00007ffff355eb3e in osmo_timers_update () at libosmocore/src/timer.c:257 #5 0x00007ffff356255c in osmo_select_main (polling=0) at libosmocore/src/select.c:254 #6 0x00005555556f17cb in main (argc=3, argv=0x7fffffffe298) at osmo-sgsn/src/gprs/sgsn_main.c:531 Change-Id: I2120e53ade6cabad37f9bd99e6680a453411821b
2018-07-13osmo-sgsn: ping GGSN periodically and check for restart counterPau Espin Pedrol2-0/+5
Before this commit, echo req/rsp logic was implemented in libgtp but never used in osmo-sgsn. This commit adds a timer which periodically sends a GTP ECHO Request to every GGSN if there's at least one pdpd context associated with it. This way by checking the restart counter in the ECHO Reply it can be known if the GGSN was restarted. In this case, logic already present in osmo-sgsn will terminate all pdp contexts associated with that GGSN. Change-Id: I9d714726785407859f26bbef052cd0efc28e8dae
2018-07-13Maintain per ggsn pdp ctx listPau Espin Pedrol1-4/+4
This way we can easily track all pdp context associated to a specific ggsn, which is useful to handle some scenarios, such as the one implemented in next commit, in which specs references that GSNs should ping only other GSNs with at least one pdp ctx in common. So the list of pdp ctx per GGSN is really useful too (and cheap computationally) to check if we should arm or disarm the echo procedure timer. So this commit can be seen as a preparation for next commit. Change-Id: I3bbcc0883df2bf1290ba8d4bd70db8baa494087a
2018-06-20Drop all references of unused MGCPPau Espin Pedrol1-1/+0
Change-Id: I1c023d773bf196d41b4251ca7011a82969acb613
2018-06-20Drop all references of unused SMPPPau Espin Pedrol1-1/+0
Change-Id: Iffae03fd855e6cbd99e71b9ba0d4157cb7791db2
2018-06-15gb_proxy: Add ctrl interface and nsvc-state, gbproxy-state commandsDaniel Willmann1-0/+3
This patch adds a control interface to osmo-gbproxy as well as the first two commands to query the state of each NSVC and gbproxy peer. The "nsvc-state" command replies with nsei, nsvci, local state, role, remote state of all NSVCs. The "gbproxy-state" command replies with nsei, bvci, mcc, mnc, lac, rac, and state of each peer. Entries are separated by a newline '\n' character. If there are no entries an empty list is returned. This behaviour is similar to that of the subscriber-list-active-v1 command in osmo-sgsn. $ ./osmo_ctrl.py -d -p 4263 -g nsvc-state Got message: b'GET_REPLY 23 nsvc-state 101,101,DEAD,BLOCKED,SGSN,DEAD,UNBLOCKED\n' $ ./osmo_ctrl.py -d -p 4263 -g gbproxy-state Got message: b'GET_REPLY 4871085901306801158 gbproxy-state ' Change-Id: I82c74fd0bfcb9ba4ec3619d9fdaa0cae201b3177 Ticket: OS#3281, SYS#4235 Sponsored-by: On-Waves ehf
2018-05-23gprs_gmm: make extract_subscr_msisdn extract_subscr_hlr publicAlexander Couzens1-0/+3
Change-Id: I54168e1a58dd36b38c53c13bbb5cdb4311f34410
2018-05-23gprs_gmm: make functions relating to GMM Attach Request publicAlexander Couzens1-0/+8
GMM Attach Request will be handled in it's own file and will use those functions. Change-Id: Ic90d77f7b0bacd2a8e2e409e82d676772d352749
2018-05-01GERAN: allow GSM SRES on UMTS AKA challengeNeels Hofmeyr1-1/+12
Store the established security context type (GSM or UMTS) instead of the boolean flag is_authenticated. Provide the previous boolean query with thin sgsn_mm_ctx_is_authenticated() function. Knowing which security context was established will be necessary for OS#3224, i.e. using the proper ciphering key, which is not yet tested properly, and probably not correct at this stage. This change will make new SGSN_Tests.TC_attach_umts_aka_gsm_sres pass. Related: OS#3193 OS#3224 Change-Id: I36807bad3bc55c0030d4f09cb2c369714f24bec7
2018-03-16compiler warnings: use enum ranap_nsap_addr_enc, constify local varNeels Hofmeyr1-1/+9
Use the proper enum ranap_nsap_addr_enc instead of int, and properly exclude that member when we're building without Iu support: sgsn_vty.c:1323:31: error: passing argument 2 of ‘ranap_iu_vty_init’ from incompatible pointer type [-Werror=incompatible-pointer-types] ranap_iu_vty_init(SGSN_NODE, &g_cfg->iu.rab_assign_addr_enc); Add const to a local var to silence compiler warning retrieving TLVP_VAL: gprs_gmm.c:1657:18: error: initialization discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers] uint8_t *mi = TLVP_VAL(&tp, GSM48_IE_GMM_ALLOC_PTMSI); ^~~~~~~~ Change-Id: I1168ce6425c31db3f6c3bf1f3682ae96b028c59b